| /* | |
| * DNS support | |
| * | |
| * Copyright (C) 2006 Hans Leidekker | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include "wine/debug.h" | |
| #include <stdarg.h> | |
| #include <string.h> | |
| #include <sys/types.h> | |
| #ifdef HAVE_NETINET_IN_H | |
| # include <netinet/in.h> | |
| #endif | |
| #ifdef HAVE_ARPA_NAMESER_H | |
| # include <arpa/nameser.h> | |
| #endif | |
| #ifdef HAVE_RESOLV_H | |
| # include <resolv.h> | |
| #endif | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winnls.h" | |
| #include "windns.h" | |
| #include "dnsapi.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(dnsapi); | |
| const char *dns_type_to_str( unsigned short type ) | |
| { | |
| switch (type) | |
| { | |
| #define X(x) case (x): return #x; | |
| X(DNS_TYPE_ZERO) | |
| X(DNS_TYPE_A) | |
| X(DNS_TYPE_NS) | |
| X(DNS_TYPE_MD) | |
| X(DNS_TYPE_MF) | |
| X(DNS_TYPE_CNAME) | |
| X(DNS_TYPE_SOA) | |
| X(DNS_TYPE_MB) | |
| X(DNS_TYPE_MG) | |
| X(DNS_TYPE_MR) | |
| X(DNS_TYPE_NULL) | |
| X(DNS_TYPE_WKS) | |
| X(DNS_TYPE_PTR) | |
| X(DNS_TYPE_HINFO) | |
| X(DNS_TYPE_MINFO) | |
| X(DNS_TYPE_MX) | |
| X(DNS_TYPE_TEXT) | |
| X(DNS_TYPE_RP) | |
| X(DNS_TYPE_AFSDB) | |
| X(DNS_TYPE_X25) | |
| X(DNS_TYPE_ISDN) | |
| X(DNS_TYPE_RT) | |
| X(DNS_TYPE_NSAP) | |
| X(DNS_TYPE_NSAPPTR) | |
| X(DNS_TYPE_SIG) | |
| X(DNS_TYPE_KEY) | |
| X(DNS_TYPE_PX) | |
| X(DNS_TYPE_GPOS) | |
| X(DNS_TYPE_AAAA) | |
| X(DNS_TYPE_LOC) | |
| X(DNS_TYPE_NXT) | |
| X(DNS_TYPE_EID) | |
| X(DNS_TYPE_NIMLOC) | |
| X(DNS_TYPE_SRV) | |
| X(DNS_TYPE_ATMA) | |
| X(DNS_TYPE_NAPTR) | |
| X(DNS_TYPE_KX) | |
| X(DNS_TYPE_CERT) | |
| X(DNS_TYPE_A6) | |
| X(DNS_TYPE_DNAME) | |
| X(DNS_TYPE_SINK) | |
| X(DNS_TYPE_OPT) | |
| X(DNS_TYPE_UINFO) | |
| X(DNS_TYPE_UID) | |
| X(DNS_TYPE_GID) | |
| X(DNS_TYPE_UNSPEC) | |
| X(DNS_TYPE_ADDRS) | |
| X(DNS_TYPE_TKEY) | |
| X(DNS_TYPE_TSIG) | |
| X(DNS_TYPE_IXFR) | |
| X(DNS_TYPE_AXFR) | |
| X(DNS_TYPE_MAILB) | |
| X(DNS_TYPE_MAILA) | |
| X(DNS_TYPE_ANY) | |
| X(DNS_TYPE_WINS) | |
| X(DNS_TYPE_WINSR) | |
| #undef X | |
| default: { static char tmp[7]; sprintf( tmp, "0x%04x", type ); return tmp; } | |
| } | |
| } | |
| static int dns_strcmpX( LPCVOID str1, LPCVOID str2, BOOL wide ) | |
| { | |
| if (wide) | |
| return lstrcmpiW( str1, str2 ); | |
| else | |
| return lstrcmpiA( str1, str2 ); | |
| } | |
| /****************************************************************************** | |
| * DnsRecordCompare [DNSAPI.@] | |
| * | |
| */ | |
| BOOL WINAPI DnsRecordCompare( PDNS_RECORD r1, PDNS_RECORD r2 ) | |
| { | |
| BOOL wide; | |
| unsigned int i; | |
| TRACE( "(%p,%p)\n", r1, r2 ); | |
| if (r1->wType != r2->wType || | |
| r1->wDataLength != r2->wDataLength || | |
| r1->Flags.DW != r2->Flags.DW || | |
| r1->dwReserved != r2->dwReserved) return FALSE; | |
| wide = (r1->Flags.S.CharSet == DnsCharSetUnicode) ? TRUE : FALSE; | |
| if (dns_strcmpX( r1->pName, r2->pName, wide )) return FALSE; | |
| switch (r1->wType) | |
| { | |
| case DNS_TYPE_A: | |
| { | |
| if (r1->Data.A.IpAddress != r2->Data.A.IpAddress) return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_SOA: | |
| { | |
| if (r1->Data.SOA.dwSerialNo != r2->Data.SOA.dwSerialNo || | |
| r1->Data.SOA.dwRefresh != r2->Data.SOA.dwRefresh || | |
| r1->Data.SOA.dwRetry != r2->Data.SOA.dwRetry || | |
| r1->Data.SOA.dwExpire != r2->Data.SOA.dwExpire || | |
| r1->Data.SOA.dwDefaultTtl != r2->Data.SOA.dwDefaultTtl) | |
| return FALSE; | |
| if (dns_strcmpX( r1->Data.SOA.pNamePrimaryServer, | |
| r2->Data.SOA.pNamePrimaryServer, wide ) || | |
| dns_strcmpX( r1->Data.SOA.pNameAdministrator, | |
| r2->Data.SOA.pNameAdministrator, wide )) | |
| return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_PTR: | |
| case DNS_TYPE_NS: | |
| case DNS_TYPE_CNAME: | |
| case DNS_TYPE_MB: | |
| case DNS_TYPE_MD: | |
| case DNS_TYPE_MF: | |
| case DNS_TYPE_MG: | |
| case DNS_TYPE_MR: | |
| { | |
| if (dns_strcmpX( r1->Data.PTR.pNameHost, | |
| r2->Data.PTR.pNameHost, wide )) return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_MINFO: | |
| case DNS_TYPE_RP: | |
| { | |
| if (dns_strcmpX( r1->Data.MINFO.pNameMailbox, | |
| r2->Data.MINFO.pNameMailbox, wide ) || | |
| dns_strcmpX( r1->Data.MINFO.pNameErrorsMailbox, | |
| r2->Data.MINFO.pNameErrorsMailbox, wide )) | |
| return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_MX: | |
| case DNS_TYPE_AFSDB: | |
| case DNS_TYPE_RT: | |
| { | |
| if (r1->Data.MX.wPreference != r2->Data.MX.wPreference) | |
| return FALSE; | |
| if (dns_strcmpX( r1->Data.MX.pNameExchange, | |
| r2->Data.MX.pNameExchange, wide )) | |
| return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_HINFO: | |
| case DNS_TYPE_ISDN: | |
| case DNS_TYPE_TEXT: | |
| case DNS_TYPE_X25: | |
| { | |
| if (r1->Data.TXT.dwStringCount != r2->Data.TXT.dwStringCount) | |
| return FALSE; | |
| for (i = 0; i < r1->Data.TXT.dwStringCount; i++) | |
| { | |
| if (dns_strcmpX( r1->Data.TXT.pStringArray[i], | |
| r2->Data.TXT.pStringArray[i], wide )) | |
| return FALSE; | |
| } | |
| break; | |
| } | |
| case DNS_TYPE_NULL: | |
| { | |
| if (r1->Data.Null.dwByteCount != r2->Data.Null.dwByteCount) | |
| return FALSE; | |
| if (memcmp( r1->Data.Null.Data, | |
| r2->Data.Null.Data, r1->Data.Null.dwByteCount )) | |
| return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_AAAA: | |
| { | |
| for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++) | |
| { | |
| if (r1->Data.AAAA.Ip6Address.IP6Dword[i] != | |
| r2->Data.AAAA.Ip6Address.IP6Dword[i]) return FALSE; | |
| } | |
| break; | |
| } | |
| case DNS_TYPE_KEY: | |
| { | |
| if (r1->Data.KEY.wFlags != r2->Data.KEY.wFlags || | |
| r1->Data.KEY.chProtocol != r2->Data.KEY.chProtocol || | |
| r1->Data.KEY.chAlgorithm != r2->Data.KEY.chAlgorithm) | |
| return FALSE; | |
| if (memcmp( r1->Data.KEY.Key, r2->Data.KEY.Key, | |
| r1->wDataLength - sizeof(DNS_KEY_DATA) + 1 )) | |
| return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_SIG: | |
| { | |
| if (dns_strcmpX( r1->Data.SIG.pNameSigner, | |
| r2->Data.SIG.pNameSigner, wide )) | |
| return FALSE; | |
| if (r1->Data.SIG.wTypeCovered != r2->Data.SIG.wTypeCovered || | |
| r1->Data.SIG.chAlgorithm != r2->Data.SIG.chAlgorithm || | |
| r1->Data.SIG.chLabelCount != r2->Data.SIG.chLabelCount || | |
| r1->Data.SIG.dwOriginalTtl != r2->Data.SIG.dwOriginalTtl || | |
| r1->Data.SIG.dwExpiration != r2->Data.SIG.dwExpiration || | |
| r1->Data.SIG.dwTimeSigned != r2->Data.SIG.dwTimeSigned || | |
| r1->Data.SIG.wKeyTag != r2->Data.SIG.wKeyTag) | |
| return FALSE; | |
| if (memcmp( r1->Data.SIG.Signature, r2->Data.SIG.Signature, | |
| r1->wDataLength - sizeof(DNS_SIG_DATAA) + 1 )) | |
| return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_ATMA: | |
| { | |
| if (r1->Data.ATMA.AddressType != r2->Data.ATMA.AddressType) | |
| return FALSE; | |
| for (i = 0; i < DNS_ATMA_MAX_ADDR_LENGTH; i++) | |
| { | |
| if (r1->Data.ATMA.Address[i] != r2->Data.ATMA.Address[i]) | |
| return FALSE; | |
| } | |
| break; | |
| } | |
| case DNS_TYPE_NXT: | |
| { | |
| if (dns_strcmpX( r1->Data.NXT.pNameNext, | |
| r2->Data.NXT.pNameNext, wide )) return FALSE; | |
| if (r1->Data.NXT.wNumTypes != r2->Data.NXT.wNumTypes) return FALSE; | |
| if (memcmp( r1->Data.NXT.wTypes, r2->Data.NXT.wTypes, | |
| r1->wDataLength - sizeof(DNS_NXT_DATAA) + sizeof(WORD) )) | |
| return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_SRV: | |
| { | |
| if (dns_strcmpX( r1->Data.SRV.pNameTarget, | |
| r2->Data.SRV.pNameTarget, wide )) return FALSE; | |
| if (r1->Data.SRV.wPriority != r2->Data.SRV.wPriority || | |
| r1->Data.SRV.wWeight != r2->Data.SRV.wWeight || | |
| r1->Data.SRV.wPort != r2->Data.SRV.wPort) | |
| return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_TKEY: | |
| { | |
| if (dns_strcmpX( r1->Data.TKEY.pNameAlgorithm, | |
| r2->Data.TKEY.pNameAlgorithm, wide )) | |
| return FALSE; | |
| if (r1->Data.TKEY.dwCreateTime != r2->Data.TKEY.dwCreateTime || | |
| r1->Data.TKEY.dwExpireTime != r2->Data.TKEY.dwExpireTime || | |
| r1->Data.TKEY.wMode != r2->Data.TKEY.wMode || | |
| r1->Data.TKEY.wError != r2->Data.TKEY.wError || | |
| r1->Data.TKEY.wKeyLength != r2->Data.TKEY.wKeyLength || | |
| r1->Data.TKEY.wOtherLength != r2->Data.TKEY.wOtherLength || | |
| r1->Data.TKEY.cAlgNameLength != r2->Data.TKEY.cAlgNameLength || | |
| r1->Data.TKEY.bPacketPointers != r2->Data.TKEY.bPacketPointers) | |
| return FALSE; | |
| /* FIXME: ignoring pAlgorithmPacket field */ | |
| if (memcmp( r1->Data.TKEY.pKey, r2->Data.TKEY.pKey, | |
| r1->Data.TKEY.wKeyLength ) || | |
| memcmp( r1->Data.TKEY.pOtherData, r2->Data.TKEY.pOtherData, | |
| r1->Data.TKEY.wOtherLength )) return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_TSIG: | |
| { | |
| if (dns_strcmpX( r1->Data.TSIG.pNameAlgorithm, | |
| r2->Data.TSIG.pNameAlgorithm, wide )) | |
| return FALSE; | |
| if (r1->Data.TSIG.i64CreateTime != r2->Data.TSIG.i64CreateTime || | |
| r1->Data.TSIG.wFudgeTime != r2->Data.TSIG.wFudgeTime || | |
| r1->Data.TSIG.wOriginalXid != r2->Data.TSIG.wOriginalXid || | |
| r1->Data.TSIG.wError != r2->Data.TSIG.wError || | |
| r1->Data.TSIG.wSigLength != r2->Data.TSIG.wSigLength || | |
| r1->Data.TSIG.wOtherLength != r2->Data.TSIG.wOtherLength || | |
| r1->Data.TSIG.cAlgNameLength != r2->Data.TSIG.cAlgNameLength || | |
| r1->Data.TSIG.bPacketPointers != r2->Data.TSIG.bPacketPointers) | |
| return FALSE; | |
| /* FIXME: ignoring pAlgorithmPacket field */ | |
| if (memcmp( r1->Data.TSIG.pSignature, r2->Data.TSIG.pSignature, | |
| r1->Data.TSIG.wSigLength ) || | |
| memcmp( r1->Data.TSIG.pOtherData, r2->Data.TSIG.pOtherData, | |
| r1->Data.TSIG.wOtherLength )) return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_WINS: | |
| { | |
| if (r1->Data.WINS.dwMappingFlag != r2->Data.WINS.dwMappingFlag || | |
| r1->Data.WINS.dwLookupTimeout != r2->Data.WINS.dwLookupTimeout || | |
| r1->Data.WINS.dwCacheTimeout != r2->Data.WINS.dwCacheTimeout || | |
| r1->Data.WINS.cWinsServerCount != r2->Data.WINS.cWinsServerCount) | |
| return FALSE; | |
| if (memcmp( r1->Data.WINS.WinsServers, r2->Data.WINS.WinsServers, | |
| r1->wDataLength - sizeof(DNS_WINS_DATA) + sizeof(IP4_ADDRESS) )) | |
| return FALSE; | |
| break; | |
| } | |
| case DNS_TYPE_WINSR: | |
| { | |
| if (r1->Data.WINSR.dwMappingFlag != r2->Data.WINSR.dwMappingFlag || | |
| r1->Data.WINSR.dwLookupTimeout != r2->Data.WINSR.dwLookupTimeout || | |
| r1->Data.WINSR.dwCacheTimeout != r2->Data.WINSR.dwCacheTimeout) | |
| return FALSE; | |
| if (dns_strcmpX( r1->Data.WINSR.pNameResultDomain, | |
| r2->Data.WINSR.pNameResultDomain, wide )) | |
| return FALSE; | |
| break; | |
| } | |
| default: | |
| FIXME( "unknown type: %s\n", dns_type_to_str( r1->wType ) ); | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| static LPVOID dns_strcpyX( LPCVOID src, DNS_CHARSET in, DNS_CHARSET out ) | |
| { | |
| switch (in) | |
| { | |
| case DnsCharSetUnicode: | |
| { | |
| switch (out) | |
| { | |
| case DnsCharSetUnicode: return dns_strdup_w( src ); | |
| case DnsCharSetUtf8: return dns_strdup_wu( src ); | |
| case DnsCharSetAnsi: return dns_strdup_wa( src ); | |
| default: | |
| WARN( "unhandled target charset: %d\n", out ); | |
| break; | |
| } | |
| } | |
| case DnsCharSetUtf8: | |
| switch (out) | |
| { | |
| case DnsCharSetUnicode: return dns_strdup_uw( src ); | |
| case DnsCharSetUtf8: return dns_strdup_u( src ); | |
| case DnsCharSetAnsi: return dns_strdup_ua( src ); | |
| default: | |
| WARN( "unhandled target charset: %d\n", out ); | |
| break; | |
| } | |
| case DnsCharSetAnsi: | |
| switch (out) | |
| { | |
| case DnsCharSetUnicode: return dns_strdup_aw( src ); | |
| case DnsCharSetUtf8: return dns_strdup_au( src ); | |
| case DnsCharSetAnsi: return dns_strdup_a( src ); | |
| default: | |
| WARN( "unhandled target charset: %d\n", out ); | |
| break; | |
| } | |
| default: | |
| WARN( "unhandled source charset: %d\n", in ); | |
| break; | |
| } | |
| return NULL; | |
| } | |
| /****************************************************************************** | |
| * DnsRecordCopyEx [DNSAPI.@] | |
| * | |
| */ | |
| PDNS_RECORD WINAPI DnsRecordCopyEx( PDNS_RECORD src, DNS_CHARSET in, DNS_CHARSET out ) | |
| { | |
| DNS_RECORD *dst; | |
| unsigned int i, size; | |
| TRACE( "(%p,%d,%d)\n", src, in, out ); | |
| size = FIELD_OFFSET(DNS_RECORD, Data) + src->wDataLength; | |
| dst = heap_alloc_zero( size ); | |
| if (!dst) return NULL; | |
| memcpy( dst, src, size ); | |
| if (src->Flags.S.CharSet == DnsCharSetUtf8 || | |
| src->Flags.S.CharSet == DnsCharSetAnsi || | |
| src->Flags.S.CharSet == DnsCharSetUnicode) in = src->Flags.S.CharSet; | |
| dst->Flags.S.CharSet = out; | |
| dst->pName = dns_strcpyX( src->pName, in, out ); | |
| if (!dst->pName) goto error; | |
| switch (src->wType) | |
| { | |
| case DNS_TYPE_HINFO: | |
| case DNS_TYPE_ISDN: | |
| case DNS_TYPE_TEXT: | |
| case DNS_TYPE_X25: | |
| { | |
| for (i = 0; i < src->Data.TXT.dwStringCount; i++) | |
| { | |
| dst->Data.TXT.pStringArray[i] = | |
| dns_strcpyX( src->Data.TXT.pStringArray[i], in, out ); | |
| if (!dst->Data.TXT.pStringArray[i]) | |
| { | |
| while (i > 0) heap_free( dst->Data.TXT.pStringArray[--i] ); | |
| goto error; | |
| } | |
| } | |
| break; | |
| } | |
| case DNS_TYPE_MINFO: | |
| case DNS_TYPE_RP: | |
| { | |
| dst->Data.MINFO.pNameMailbox = | |
| dns_strcpyX( src->Data.MINFO.pNameMailbox, in, out ); | |
| if (!dst->Data.MINFO.pNameMailbox) goto error; | |
| dst->Data.MINFO.pNameErrorsMailbox = | |
| dns_strcpyX( src->Data.MINFO.pNameErrorsMailbox, in, out ); | |
| if (!dst->Data.MINFO.pNameErrorsMailbox) | |
| { | |
| heap_free( dst->Data.MINFO.pNameMailbox ); | |
| goto error; | |
| } | |
| break; | |
| } | |
| case DNS_TYPE_AFSDB: | |
| case DNS_TYPE_RT: | |
| case DNS_TYPE_MX: | |
| { | |
| dst->Data.MX.pNameExchange = | |
| dns_strcpyX( src->Data.MX.pNameExchange, in, out ); | |
| if (!dst->Data.MX.pNameExchange) goto error; | |
| break; | |
| } | |
| case DNS_TYPE_NXT: | |
| { | |
| dst->Data.NXT.pNameNext = | |
| dns_strcpyX( src->Data.NXT.pNameNext, in, out ); | |
| if (!dst->Data.NXT.pNameNext) goto error; | |
| break; | |
| } | |
| case DNS_TYPE_CNAME: | |
| case DNS_TYPE_MB: | |
| case DNS_TYPE_MD: | |
| case DNS_TYPE_MF: | |
| case DNS_TYPE_MG: | |
| case DNS_TYPE_MR: | |
| case DNS_TYPE_NS: | |
| case DNS_TYPE_PTR: | |
| { | |
| dst->Data.PTR.pNameHost = | |
| dns_strcpyX( src->Data.PTR.pNameHost, in, out ); | |
| if (!dst->Data.PTR.pNameHost) goto error; | |
| break; | |
| } | |
| case DNS_TYPE_SIG: | |
| { | |
| dst->Data.SIG.pNameSigner = | |
| dns_strcpyX( src->Data.SIG.pNameSigner, in, out ); | |
| if (!dst->Data.SIG.pNameSigner) goto error; | |
| break; | |
| } | |
| case DNS_TYPE_SOA: | |
| { | |
| dst->Data.SOA.pNamePrimaryServer = | |
| dns_strcpyX( src->Data.SOA.pNamePrimaryServer, in, out ); | |
| if (!dst->Data.SOA.pNamePrimaryServer) goto error; | |
| dst->Data.SOA.pNameAdministrator = | |
| dns_strcpyX( src->Data.SOA.pNameAdministrator, in, out ); | |
| if (!dst->Data.SOA.pNameAdministrator) | |
| { | |
| heap_free( dst->Data.SOA.pNamePrimaryServer ); | |
| goto error; | |
| } | |
| break; | |
| } | |
| case DNS_TYPE_SRV: | |
| { | |
| dst->Data.SRV.pNameTarget = | |
| dns_strcpyX( src->Data.SRV.pNameTarget, in, out ); | |
| if (!dst->Data.SRV.pNameTarget) goto error; | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| return dst; | |
| error: | |
| heap_free( dst->pName ); | |
| heap_free( dst ); | |
| return NULL; | |
| } | |
| /****************************************************************************** | |
| * DnsRecordListFree [DNSAPI.@] | |
| * | |
| */ | |
| VOID WINAPI DnsRecordListFree( PDNS_RECORD list, DNS_FREE_TYPE type ) | |
| { | |
| DNS_RECORD *r, *next; | |
| unsigned int i; | |
| TRACE( "(%p,%d)\n", list, type ); | |
| if (!list) return; | |
| switch (type) | |
| { | |
| case DnsFreeRecordList: | |
| { | |
| for (r = list; (list = r); r = next) | |
| { | |
| heap_free( r->pName ); | |
| switch (r->wType) | |
| { | |
| case DNS_TYPE_HINFO: | |
| case DNS_TYPE_ISDN: | |
| case DNS_TYPE_TEXT: | |
| case DNS_TYPE_X25: | |
| { | |
| for (i = 0; i < r->Data.TXT.dwStringCount; i++) | |
| heap_free( r->Data.TXT.pStringArray[i] ); | |
| break; | |
| } | |
| case DNS_TYPE_MINFO: | |
| case DNS_TYPE_RP: | |
| { | |
| heap_free( r->Data.MINFO.pNameMailbox ); | |
| heap_free( r->Data.MINFO.pNameErrorsMailbox ); | |
| break; | |
| } | |
| case DNS_TYPE_AFSDB: | |
| case DNS_TYPE_RT: | |
| case DNS_TYPE_MX: | |
| { | |
| heap_free( r->Data.MX.pNameExchange ); | |
| break; | |
| } | |
| case DNS_TYPE_NXT: | |
| { | |
| heap_free( r->Data.NXT.pNameNext ); | |
| break; | |
| } | |
| case DNS_TYPE_CNAME: | |
| case DNS_TYPE_MB: | |
| case DNS_TYPE_MD: | |
| case DNS_TYPE_MF: | |
| case DNS_TYPE_MG: | |
| case DNS_TYPE_MR: | |
| case DNS_TYPE_NS: | |
| case DNS_TYPE_PTR: | |
| { | |
| heap_free( r->Data.PTR.pNameHost ); | |
| break; | |
| } | |
| case DNS_TYPE_SIG: | |
| { | |
| heap_free( r->Data.SIG.pNameSigner ); | |
| break; | |
| } | |
| case DNS_TYPE_SOA: | |
| { | |
| heap_free( r->Data.SOA.pNamePrimaryServer ); | |
| heap_free( r->Data.SOA.pNameAdministrator ); | |
| break; | |
| } | |
| case DNS_TYPE_SRV: | |
| { | |
| heap_free( r->Data.SRV.pNameTarget ); | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| next = r->pNext; | |
| heap_free( r ); | |
| } | |
| break; | |
| } | |
| case DnsFreeFlat: | |
| case DnsFreeParsedMessageFields: | |
| { | |
| FIXME( "unhandled free type: %d\n", type ); | |
| break; | |
| } | |
| default: | |
| WARN( "unknown free type: %d\n", type ); | |
| break; | |
| } | |
| } | |
| /****************************************************************************** | |
| * DnsRecordSetCompare [DNSAPI.@] | |
| * | |
| */ | |
| BOOL WINAPI DnsRecordSetCompare( PDNS_RECORD set1, PDNS_RECORD set2, | |
| PDNS_RECORD *diff1, PDNS_RECORD *diff2 ) | |
| { | |
| BOOL ret = TRUE; | |
| DNS_RECORD *r, *t, *u; | |
| DNS_RRSET rr1, rr2; | |
| TRACE( "(%p,%p,%p,%p)\n", set1, set2, diff1, diff2 ); | |
| if (!set1 && !set2) return FALSE; | |
| if (diff1) *diff1 = NULL; | |
| if (diff2) *diff2 = NULL; | |
| if (set1 && !set2) | |
| { | |
| if (diff1) *diff1 = DnsRecordSetCopyEx( set1, 0, set1->Flags.S.CharSet ); | |
| return FALSE; | |
| } | |
| if (!set1 && set2) | |
| { | |
| if (diff2) *diff2 = DnsRecordSetCopyEx( set2, 0, set2->Flags.S.CharSet ); | |
| return FALSE; | |
| } | |
| DNS_RRSET_INIT( rr1 ); | |
| DNS_RRSET_INIT( rr2 ); | |
| for (r = set1; r; r = r->pNext) | |
| { | |
| for (t = set2; t; t = t->pNext) | |
| { | |
| u = DnsRecordCopyEx( r, r->Flags.S.CharSet, t->Flags.S.CharSet ); | |
| if (!u) goto error; | |
| if (!DnsRecordCompare( t, u )) | |
| { | |
| DNS_RRSET_ADD( rr1, u ); | |
| ret = FALSE; | |
| } | |
| else DnsRecordListFree( u, DnsFreeRecordList ); | |
| } | |
| } | |
| for (t = set2; t; t = t->pNext) | |
| { | |
| for (r = set1; r; r = r->pNext) | |
| { | |
| u = DnsRecordCopyEx( t, t->Flags.S.CharSet, r->Flags.S.CharSet ); | |
| if (!u) goto error; | |
| if (!DnsRecordCompare( r, u )) | |
| { | |
| DNS_RRSET_ADD( rr2, u ); | |
| ret = FALSE; | |
| } | |
| else DnsRecordListFree( u, DnsFreeRecordList ); | |
| } | |
| } | |
| DNS_RRSET_TERMINATE( rr1 ); | |
| DNS_RRSET_TERMINATE( rr2 ); | |
| if (diff1) *diff1 = rr1.pFirstRR; | |
| else DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList ); | |
| if (diff2) *diff2 = rr2.pFirstRR; | |
| else DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList ); | |
| return ret; | |
| error: | |
| DNS_RRSET_TERMINATE( rr1 ); | |
| DNS_RRSET_TERMINATE( rr2 ); | |
| DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList ); | |
| DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList ); | |
| return FALSE; | |
| } | |
| /****************************************************************************** | |
| * DnsRecordSetCopyEx [DNSAPI.@] | |
| * | |
| */ | |
| PDNS_RECORD WINAPI DnsRecordSetCopyEx( PDNS_RECORD src_set, DNS_CHARSET in, DNS_CHARSET out ) | |
| { | |
| DNS_RRSET dst_set; | |
| DNS_RECORD *src, *dst; | |
| TRACE( "(%p,%d,%d)\n", src_set, in, out ); | |
| DNS_RRSET_INIT( dst_set ); | |
| for (src = src_set; (src_set = src); src = src_set->pNext) | |
| { | |
| dst = DnsRecordCopyEx( src, in, out ); | |
| if (!dst) | |
| { | |
| DNS_RRSET_TERMINATE( dst_set ); | |
| DnsRecordListFree( dst_set.pFirstRR, DnsFreeRecordList ); | |
| return NULL; | |
| } | |
| DNS_RRSET_ADD( dst_set, dst ); | |
| } | |
| DNS_RRSET_TERMINATE( dst_set ); | |
| return dst_set.pFirstRR; | |
| } | |
| /****************************************************************************** | |
| * DnsRecordSetDetach [DNSAPI.@] | |
| * | |
| */ | |
| PDNS_RECORD WINAPI DnsRecordSetDetach( PDNS_RECORD set ) | |
| { | |
| DNS_RECORD *r, *s; | |
| TRACE( "(%p)\n", set ); | |
| for (r = set; (set = r); r = set->pNext) | |
| { | |
| if (r->pNext && !r->pNext->pNext) | |
| { | |
| s = r->pNext; | |
| r->pNext = NULL; | |
| return s; | |
| } | |
| } | |
| return NULL; | |
| } |