4 * Copyright (C) 2006 Hans Leidekker
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
23 #include "wine/debug.h"
27 #include <sys/types.h>
29 #ifdef HAVE_NETINET_IN_H
30 # include <netinet/in.h>
32 #ifdef HAVE_ARPA_NAMESER_H
33 # include <arpa/nameser.h>
47 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
49 const char *dns_type_to_str( unsigned short type )
53 #define X(x) case (x): return #x;
111 default: { static char tmp[7]; sprintf( tmp, "0x%04x", type ); return tmp; }
115 static int dns_strcmpX( LPCVOID str1, LPCVOID str2, BOOL wide )
118 return lstrcmpiW( (LPCWSTR)str1, (LPCWSTR)str2 );
120 return lstrcmpiA( (LPCSTR)str1, (LPCSTR)str2 );
123 /******************************************************************************
124 * DnsRecordCompare [DNSAPI.@]
127 BOOL WINAPI DnsRecordCompare( PDNS_RECORD r1, PDNS_RECORD r2 )
132 TRACE( "(%p,%p)\n", r1, r2 );
134 if (r1->wType != r2->wType ||
135 r1->wDataLength != r2->wDataLength ||
136 r1->Flags.DW != r2->Flags.DW ||
137 r1->dwTtl != r2->dwTtl ||
138 r1->dwReserved != r2->dwReserved) return FALSE;
140 wide = (r1->Flags.S.CharSet == DnsCharSetUnicode) ? TRUE : FALSE;
141 if (dns_strcmpX( r1->pName, r2->pName, wide )) return FALSE;
147 if (r1->Data.A.IpAddress != r2->Data.A.IpAddress) return FALSE;
152 if (r1->Data.SOA.dwSerialNo != r2->Data.SOA.dwSerialNo ||
153 r1->Data.SOA.dwRefresh != r2->Data.SOA.dwRefresh ||
154 r1->Data.SOA.dwRetry != r2->Data.SOA.dwRetry ||
155 r1->Data.SOA.dwExpire != r2->Data.SOA.dwExpire ||
156 r1->Data.SOA.dwDefaultTtl != r2->Data.SOA.dwDefaultTtl)
158 if (dns_strcmpX( r1->Data.SOA.pNamePrimaryServer,
159 r2->Data.SOA.pNamePrimaryServer, wide ) ||
160 dns_strcmpX( r1->Data.SOA.pNameAdministrator,
161 r2->Data.SOA.pNameAdministrator, wide ))
174 if (dns_strcmpX( r1->Data.PTR.pNameHost,
175 r2->Data.PTR.pNameHost, wide )) return FALSE;
181 if (dns_strcmpX( r1->Data.MINFO.pNameMailbox,
182 r2->Data.MINFO.pNameMailbox, wide ) ||
183 dns_strcmpX( r1->Data.MINFO.pNameErrorsMailbox,
184 r2->Data.MINFO.pNameErrorsMailbox, wide ))
192 if (r1->Data.MX.wPreference != r2->Data.MX.wPreference)
194 if (dns_strcmpX( r1->Data.MX.pNameExchange,
195 r2->Data.MX.pNameExchange, wide ))
204 if (r1->Data.TXT.dwStringCount != r2->Data.TXT.dwStringCount)
206 for (i = 0; i < r1->Data.TXT.dwStringCount; i++)
208 if (dns_strcmpX( r1->Data.TXT.pStringArray[i],
209 r2->Data.TXT.pStringArray[i], wide ))
216 if (r1->Data.Null.dwByteCount != r2->Data.Null.dwByteCount)
218 if (memcmp( r1->Data.Null.Data,
219 r2->Data.Null.Data, r1->Data.Null.dwByteCount ))
225 for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
227 if (r1->Data.AAAA.Ip6Address.IP6Dword[i] !=
228 r2->Data.AAAA.Ip6Address.IP6Dword[i]) return FALSE;
234 if (r1->Data.KEY.wFlags != r2->Data.KEY.wFlags ||
235 r1->Data.KEY.chProtocol != r2->Data.KEY.chProtocol ||
236 r1->Data.KEY.chAlgorithm != r2->Data.KEY.chAlgorithm)
238 if (memcmp( r1->Data.KEY.Key, r2->Data.KEY.Key,
239 r1->wDataLength - sizeof(DNS_KEY_DATA) + 1 ))
245 if (dns_strcmpX( r1->Data.SIG.pNameSigner,
246 r2->Data.SIG.pNameSigner, wide ))
248 if (r1->Data.SIG.wTypeCovered != r2->Data.SIG.wTypeCovered ||
249 r1->Data.SIG.chAlgorithm != r2->Data.SIG.chAlgorithm ||
250 r1->Data.SIG.chLabelCount != r2->Data.SIG.chLabelCount ||
251 r1->Data.SIG.dwOriginalTtl != r2->Data.SIG.dwOriginalTtl ||
252 r1->Data.SIG.dwExpiration != r2->Data.SIG.dwExpiration ||
253 r1->Data.SIG.dwTimeSigned != r2->Data.SIG.dwTimeSigned ||
254 r1->Data.SIG.wKeyTag != r2->Data.SIG.wKeyTag)
256 if (memcmp( r1->Data.SIG.Signature, r2->Data.SIG.Signature,
257 r1->wDataLength - sizeof(DNS_SIG_DATAA) + 1 ))
263 if (r1->Data.ATMA.AddressType != r2->Data.ATMA.AddressType)
265 for (i = 0; i < DNS_ATMA_MAX_ADDR_LENGTH; i++)
267 if (r1->Data.ATMA.Address[i] != r2->Data.ATMA.Address[i])
274 if (dns_strcmpX( r1->Data.NXT.pNameNext,
275 r2->Data.NXT.pNameNext, wide )) return FALSE;
276 if (r1->Data.NXT.wNumTypes != r2->Data.NXT.wNumTypes) return FALSE;
277 if (memcmp( r1->Data.NXT.wTypes, r2->Data.NXT.wTypes,
278 r1->wDataLength - sizeof(DNS_NXT_DATAA) + sizeof(WORD) ))
284 if (dns_strcmpX( r1->Data.SRV.pNameTarget,
285 r2->Data.SRV.pNameTarget, wide )) return FALSE;
286 if (r1->Data.SRV.wPriority != r2->Data.SRV.wPriority ||
287 r1->Data.SRV.wWeight != r2->Data.SRV.wWeight ||
288 r1->Data.SRV.wPort != r2->Data.SRV.wPort)
294 if (dns_strcmpX( r1->Data.TKEY.pNameAlgorithm,
295 r2->Data.TKEY.pNameAlgorithm, wide ))
297 if (r1->Data.TKEY.dwCreateTime != r2->Data.TKEY.dwCreateTime ||
298 r1->Data.TKEY.dwExpireTime != r2->Data.TKEY.dwExpireTime ||
299 r1->Data.TKEY.wMode != r2->Data.TKEY.wMode ||
300 r1->Data.TKEY.wError != r2->Data.TKEY.wError ||
301 r1->Data.TKEY.wKeyLength != r2->Data.TKEY.wKeyLength ||
302 r1->Data.TKEY.wOtherLength != r2->Data.TKEY.wOtherLength ||
303 r1->Data.TKEY.cAlgNameLength != r2->Data.TKEY.cAlgNameLength ||
304 r1->Data.TKEY.bPacketPointers != r2->Data.TKEY.bPacketPointers)
307 /* FIXME: ignoring pAlgorithmPacket field */
308 if (memcmp( r1->Data.TKEY.pKey, r2->Data.TKEY.pKey,
309 r1->Data.TKEY.wKeyLength ) ||
310 memcmp( r1->Data.TKEY.pOtherData, r2->Data.TKEY.pOtherData,
311 r1->Data.TKEY.wOtherLength )) return FALSE;
316 if (dns_strcmpX( r1->Data.TSIG.pNameAlgorithm,
317 r2->Data.TSIG.pNameAlgorithm, wide ))
319 if (r1->Data.TSIG.i64CreateTime != r2->Data.TSIG.i64CreateTime ||
320 r1->Data.TSIG.wFudgeTime != r2->Data.TSIG.wFudgeTime ||
321 r1->Data.TSIG.wOriginalXid != r2->Data.TSIG.wOriginalXid ||
322 r1->Data.TSIG.wError != r2->Data.TSIG.wError ||
323 r1->Data.TSIG.wSigLength != r2->Data.TSIG.wSigLength ||
324 r1->Data.TSIG.wOtherLength != r2->Data.TSIG.wOtherLength ||
325 r1->Data.TSIG.cAlgNameLength != r2->Data.TSIG.cAlgNameLength ||
326 r1->Data.TSIG.bPacketPointers != r2->Data.TSIG.bPacketPointers)
329 /* FIXME: ignoring pAlgorithmPacket field */
330 if (memcmp( r1->Data.TSIG.pSignature, r2->Data.TSIG.pSignature,
331 r1->Data.TSIG.wSigLength ) ||
332 memcmp( r1->Data.TSIG.pOtherData, r2->Data.TSIG.pOtherData,
333 r1->Data.TSIG.wOtherLength )) return FALSE;
338 if (r1->Data.WINS.dwMappingFlag != r2->Data.WINS.dwMappingFlag ||
339 r1->Data.WINS.dwLookupTimeout != r2->Data.WINS.dwLookupTimeout ||
340 r1->Data.WINS.dwCacheTimeout != r2->Data.WINS.dwCacheTimeout ||
341 r1->Data.WINS.cWinsServerCount != r2->Data.WINS.cWinsServerCount)
343 if (memcmp( r1->Data.WINS.WinsServers, r2->Data.WINS.WinsServers,
344 r1->wDataLength - sizeof(DNS_WINS_DATA) + sizeof(IP4_ADDRESS) ))
350 if (r1->Data.WINSR.dwMappingFlag != r2->Data.WINSR.dwMappingFlag ||
351 r1->Data.WINSR.dwLookupTimeout != r2->Data.WINSR.dwLookupTimeout ||
352 r1->Data.WINSR.dwCacheTimeout != r2->Data.WINSR.dwCacheTimeout)
354 if (dns_strcmpX( r1->Data.WINSR.pNameResultDomain,
355 r2->Data.WINSR.pNameResultDomain, wide ))
360 FIXME( "unknown type: %s\n", dns_type_to_str( r1->wType ) );
366 static LPVOID dns_strcpyX( LPCVOID src, DNS_CHARSET in, DNS_CHARSET out )
370 case DnsCharSetUnicode:
374 case DnsCharSetUnicode: return dns_strdup_w( src );
375 case DnsCharSetUtf8: return dns_strdup_wu( src );
376 case DnsCharSetAnsi: return dns_strdup_wa( src );
378 WARN( "unhandled target charset: %d\n", out );
385 case DnsCharSetUnicode: return dns_strdup_uw( src );
386 case DnsCharSetUtf8: return dns_strdup_u( src );
387 case DnsCharSetAnsi: return dns_strdup_ua( src );
389 WARN( "unhandled target charset: %d\n", out );
395 case DnsCharSetUnicode: return dns_strdup_aw( src );
396 case DnsCharSetUtf8: return dns_strdup_au( src );
397 case DnsCharSetAnsi: return dns_strdup_a( src );
399 WARN( "unhandled target charset: %d\n", out );
403 WARN( "unhandled source charset: %d\n", in );
409 /******************************************************************************
410 * DnsRecordCopyEx [DNSAPI.@]
413 PDNS_RECORD WINAPI DnsRecordCopyEx( PDNS_RECORD src, DNS_CHARSET in, DNS_CHARSET out )
416 unsigned int i, size;
418 TRACE( "(%p,%d,%d)\n", src, in, out );
420 size = FIELD_OFFSET(DNS_RECORD, Data) + src->wDataLength;
421 dst = dns_zero_alloc( size );
422 if (!dst) return NULL;
424 memcpy( dst, src, size );
426 if (src->Flags.S.CharSet == DnsCharSetUtf8 ||
427 src->Flags.S.CharSet == DnsCharSetAnsi ||
428 src->Flags.S.CharSet == DnsCharSetUnicode) in = src->Flags.S.CharSet;
430 dst->Flags.S.CharSet = out;
431 dst->pName = dns_strcpyX( src->pName, in, out );
432 if (!dst->pName) goto error;
441 for (i = 0; i < src->Data.TXT.dwStringCount; i++)
443 dst->Data.TXT.pStringArray[i] =
444 dns_strcpyX( src->Data.TXT.pStringArray[i], in, out );
446 if (!dst->Data.TXT.pStringArray[i])
448 for (--i; i >= 0; i--)
449 dns_free( dst->Data.TXT.pStringArray[i] );
458 dst->Data.MINFO.pNameMailbox =
459 dns_strcpyX( src->Data.MINFO.pNameMailbox, in, out );
460 if (!dst->Data.MINFO.pNameMailbox) goto error;
462 dst->Data.MINFO.pNameErrorsMailbox =
463 dns_strcpyX( src->Data.MINFO.pNameErrorsMailbox, in, out );
464 if (!dst->Data.MINFO.pNameErrorsMailbox)
466 dns_free( dst->Data.MINFO.pNameMailbox );
475 dst->Data.MX.pNameExchange =
476 dns_strcpyX( src->Data.MX.pNameExchange, in, out );
477 if (!dst->Data.MX.pNameExchange) goto error;
482 dst->Data.NXT.pNameNext =
483 dns_strcpyX( src->Data.NXT.pNameNext, in, out );
484 if (!dst->Data.NXT.pNameNext) goto error;
496 dst->Data.PTR.pNameHost =
497 dns_strcpyX( src->Data.PTR.pNameHost, in, out );
498 if (!dst->Data.PTR.pNameHost) goto error;
503 dst->Data.SIG.pNameSigner =
504 dns_strcpyX( src->Data.SIG.pNameSigner, in, out );
505 if (!dst->Data.SIG.pNameSigner) goto error;
510 dst->Data.SOA.pNamePrimaryServer =
511 dns_strcpyX( src->Data.SOA.pNamePrimaryServer, in, out );
512 if (!dst->Data.SOA.pNamePrimaryServer) goto error;
514 dst->Data.SOA.pNameAdministrator =
515 dns_strcpyX( src->Data.SOA.pNameAdministrator, in, out );
516 if (!dst->Data.SOA.pNameAdministrator)
518 dns_free( dst->Data.SOA.pNamePrimaryServer );
525 dst->Data.SRV.pNameTarget =
526 dns_strcpyX( src->Data.SRV.pNameTarget, in, out );
527 if (!dst->Data.SRV.pNameTarget) goto error;
536 dns_free( dst->pName );
541 /******************************************************************************
542 * DnsRecordListFree [DNSAPI.@]
545 void WINAPI DnsRecordListFree( PDNS_RECORD list, DNS_FREE_TYPE type )
547 DNS_RECORD *r, *next;
550 TRACE( "(%p,%d)\n", list, type );
556 case DnsFreeRecordList:
558 for (r = list; (list = r); r = next)
560 dns_free( r->pName );
569 for (i = 0; i < r->Data.TXT.dwStringCount; i++)
570 dns_free( r->Data.TXT.pStringArray[i] );
577 dns_free( r->Data.MINFO.pNameMailbox );
578 dns_free( r->Data.MINFO.pNameErrorsMailbox );
585 dns_free( r->Data.MX.pNameExchange );
590 dns_free( r->Data.NXT.pNameNext );
602 dns_free( r->Data.PTR.pNameHost );
607 dns_free( r->Data.SIG.pNameSigner );
612 dns_free( r->Data.SOA.pNamePrimaryServer );
613 dns_free( r->Data.SOA.pNameAdministrator );
618 dns_free( r->Data.SRV.pNameTarget );
631 case DnsFreeParsedMessageFields:
633 FIXME( "unhandled free type: %d\n", type );
637 WARN( "unknown free type: %d\n", type );
642 /******************************************************************************
643 * DnsRecordSetCopyEx [DNSAPI.@]
646 PDNS_RECORD WINAPI DnsRecordSetCopyEx( PDNS_RECORD src_set, DNS_CHARSET in, DNS_CHARSET out )
649 DNS_RECORD *src, *dst;
651 TRACE( "(%p,%d,%d)\n", src_set, in, out );
653 DNS_RRSET_INIT( dst_set );
655 for (src = src_set; (src_set = src); src = src_set->pNext)
657 dst = DnsRecordCopyEx( src, in, out );
660 DNS_RRSET_TERMINATE( dst_set );
661 DnsRecordListFree( dst_set.pFirstRR, DnsFreeRecordList );
664 DNS_RRSET_ADD( dst_set, dst );
667 DNS_RRSET_TERMINATE( dst_set );
668 return dst_set.pFirstRR;