| /* |
| * 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; |
| } |
| 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; |
| } |
| 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; |
| } |
| 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; |
| } |
| } |
| |
| /****************************************************************************** |
| * DnsFree [DNSAPI.@] |
| * |
| */ |
| void WINAPI DnsFree( PVOID data, DNS_FREE_TYPE type ) |
| { |
| DnsRecordListFree( data, type ); |
| } |
| |
| /****************************************************************************** |
| * 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; |
| } |