4 * Copyright (C) 2006 Hans Leidekker
5 * Copyright (C) 2021 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi
);
33 const char *debugstr_type( unsigned short type
)
37 #define X(x) case (x): return #x;
95 default: return wine_dbg_sprintf( "0x%04x", type
);
99 static const char *debugstr_section( DNS_SECTION section
)
103 case DnsSectionQuestion
: return "Question";
104 case DnsSectionAnswer
: return "Answer";
105 case DnsSectionAuthority
: return "Authority";
106 case DnsSectionAddtional
: return "Additional";
107 default: return "??";
111 static int strcmpX( LPCVOID str1
, LPCVOID str2
, BOOL wide
)
114 return lstrcmpiW( str1
, str2
);
116 return lstrcmpiA( str1
, str2
);
119 static WORD
get_word( const BYTE
**ptr
)
121 WORD ret
= ((*ptr
)[0] << 8) + (*ptr
)[1];
122 *ptr
+= sizeof(WORD
);
126 static DWORD
get_dword( const BYTE
**ptr
)
128 DWORD ret
= ((*ptr
)[0] << 24) + ((*ptr
)[1] << 16) + ((*ptr
)[2] << 8) + (*ptr
)[3];
129 *ptr
+= sizeof(DWORD
);
133 static const BYTE
*skip_name( const BYTE
*ptr
, const BYTE
*end
)
137 while (ptr
< end
&& (len
= *ptr
++))
152 if (ptr
< end
) return ptr
;
156 static const BYTE
*skip_record( const BYTE
*ptr
, const BYTE
*end
, DNS_SECTION section
)
160 if (!(ptr
= skip_name( ptr
, end
))) return NULL
;
162 ptr
+= 2; /* class */
163 if (section
!= DnsSectionQuestion
)
166 if (ptr
+ 2 > end
) return NULL
;
167 len
= get_word( &ptr
);
170 if (ptr
> end
) return NULL
;
174 static const BYTE
*get_name( const BYTE
*base
, const BYTE
*end
, const BYTE
*ptr
,
175 char name
[DNS_MAX_NAME_BUFFER_LENGTH
] )
179 const BYTE
*next
= NULL
;
182 while (ptr
< end
&& (len
= *ptr
++))
187 if (out
+ len
+ 1 >= name
+ DNS_MAX_NAME_BUFFER_LENGTH
) return NULL
;
188 if (out
> name
) *out
++ = '.';
189 memcpy( out
, ptr
, len
);
194 if (!next
) next
= ptr
+ 1;
195 if (++loop
>= end
- base
) return NULL
;
196 if (ptr
< end
) ptr
= base
+ ((len
& 0x3f) << 8) + *ptr
;
202 if (ptr
>= end
) return NULL
;
203 if (out
== name
) *out
++ = '.';
205 return next
? next
: ptr
;
208 /******************************************************************************
209 * DnsRecordCompare [DNSAPI.@]
212 BOOL WINAPI
DnsRecordCompare( PDNS_RECORD r1
, PDNS_RECORD r2
)
217 TRACE( "(%p,%p)\n", r1
, r2
);
219 if (r1
->wType
!= r2
->wType
||
220 r1
->wDataLength
!= r2
->wDataLength
||
221 r1
->Flags
.S
.Section
!= r2
->Flags
.S
.Section
||
222 r1
->Flags
.S
.Delete
!= r2
->Flags
.S
.Delete
||
223 r1
->Flags
.S
.Unused
!= r2
->Flags
.S
.Unused
||
224 r1
->Flags
.S
.Reserved
!= r2
->Flags
.S
.Reserved
||
225 r1
->dwReserved
!= r2
->dwReserved
) return FALSE
;
227 wide
= (r1
->Flags
.S
.CharSet
== DnsCharSetUnicode
|| r1
->Flags
.S
.CharSet
== DnsCharSetUnknown
);
228 if (strcmpX( r1
->pName
, r2
->pName
, wide
)) return FALSE
;
234 if (r1
->Data
.A
.IpAddress
!= r2
->Data
.A
.IpAddress
) return FALSE
;
239 if (r1
->Data
.SOA
.dwSerialNo
!= r2
->Data
.SOA
.dwSerialNo
||
240 r1
->Data
.SOA
.dwRefresh
!= r2
->Data
.SOA
.dwRefresh
||
241 r1
->Data
.SOA
.dwRetry
!= r2
->Data
.SOA
.dwRetry
||
242 r1
->Data
.SOA
.dwExpire
!= r2
->Data
.SOA
.dwExpire
||
243 r1
->Data
.SOA
.dwDefaultTtl
!= r2
->Data
.SOA
.dwDefaultTtl
)
245 if (strcmpX( r1
->Data
.SOA
.pNamePrimaryServer
, r2
->Data
.SOA
.pNamePrimaryServer
, wide
) ||
246 strcmpX( r1
->Data
.SOA
.pNameAdministrator
, r2
->Data
.SOA
.pNameAdministrator
, wide
))
259 if (strcmpX( r1
->Data
.PTR
.pNameHost
, r2
->Data
.PTR
.pNameHost
, wide
)) return FALSE
;
265 if (strcmpX( r1
->Data
.MINFO
.pNameMailbox
, r2
->Data
.MINFO
.pNameMailbox
, wide
) ||
266 strcmpX( r1
->Data
.MINFO
.pNameErrorsMailbox
, r2
->Data
.MINFO
.pNameErrorsMailbox
, wide
))
274 if (r1
->Data
.MX
.wPreference
!= r2
->Data
.MX
.wPreference
)
276 if (strcmpX( r1
->Data
.MX
.pNameExchange
, r2
->Data
.MX
.pNameExchange
, wide
))
285 if (r1
->Data
.TXT
.dwStringCount
!= r2
->Data
.TXT
.dwStringCount
)
287 for (i
= 0; i
< r1
->Data
.TXT
.dwStringCount
; i
++)
289 if (strcmpX( r1
->Data
.TXT
.pStringArray
[i
], r2
->Data
.TXT
.pStringArray
[i
], wide
))
296 if (r1
->Data
.Null
.dwByteCount
!= r2
->Data
.Null
.dwByteCount
)
298 if (memcmp( r1
->Data
.Null
.Data
,
299 r2
->Data
.Null
.Data
, r1
->Data
.Null
.dwByteCount
))
305 if (r1
->Data
.Opt
.wDataLength
!= r2
->Data
.Opt
.wDataLength
)
308 if (memcmp( r1
->Data
.Opt
.Data
,
309 r2
->Data
.Opt
.Data
, r1
->Data
.Opt
.wDataLength
))
315 for (i
= 0; i
< sizeof(IP6_ADDRESS
)/sizeof(DWORD
); i
++)
317 if (r1
->Data
.AAAA
.Ip6Address
.IP6Dword
[i
] !=
318 r2
->Data
.AAAA
.Ip6Address
.IP6Dword
[i
]) return FALSE
;
324 if (r1
->Data
.KEY
.wFlags
!= r2
->Data
.KEY
.wFlags
||
325 r1
->Data
.KEY
.chProtocol
!= r2
->Data
.KEY
.chProtocol
||
326 r1
->Data
.KEY
.chAlgorithm
!= r2
->Data
.KEY
.chAlgorithm
||
327 r1
->Data
.KEY
.wKeyLength
!= r2
->Data
.KEY
.wKeyLength
)
329 if (memcmp( r1
->Data
.KEY
.Key
, r2
->Data
.KEY
.Key
, r1
->Data
.KEY
.wKeyLength
))
335 if (strcmpX( r1
->Data
.SIG
.pNameSigner
, r2
->Data
.SIG
.pNameSigner
, wide
))
337 if (r1
->Data
.SIG
.wTypeCovered
!= r2
->Data
.SIG
.wTypeCovered
||
338 r1
->Data
.SIG
.chAlgorithm
!= r2
->Data
.SIG
.chAlgorithm
||
339 r1
->Data
.SIG
.chLabelCount
!= r2
->Data
.SIG
.chLabelCount
||
340 r1
->Data
.SIG
.dwOriginalTtl
!= r2
->Data
.SIG
.dwOriginalTtl
||
341 r1
->Data
.SIG
.dwExpiration
!= r2
->Data
.SIG
.dwExpiration
||
342 r1
->Data
.SIG
.dwTimeSigned
!= r2
->Data
.SIG
.dwTimeSigned
||
343 r1
->Data
.SIG
.wKeyTag
!= r2
->Data
.SIG
.wKeyTag
||
344 r1
->Data
.SIG
.wSignatureLength
!= r2
->Data
.SIG
.wSignatureLength
)
346 if (memcmp( r1
->Data
.SIG
.Signature
, r2
->Data
.SIG
.Signature
, r1
->Data
.SIG
.wSignatureLength
))
352 if (r1
->Data
.ATMA
.AddressType
!= r2
->Data
.ATMA
.AddressType
)
354 for (i
= 0; i
< DNS_ATMA_MAX_ADDR_LENGTH
; i
++)
356 if (r1
->Data
.ATMA
.Address
[i
] != r2
->Data
.ATMA
.Address
[i
])
363 if (strcmpX( r1
->Data
.NXT
.pNameNext
, r2
->Data
.NXT
.pNameNext
, wide
)) return FALSE
;
364 if (r1
->Data
.NXT
.wNumTypes
!= r2
->Data
.NXT
.wNumTypes
) return FALSE
;
365 if (memcmp( r1
->Data
.NXT
.wTypes
, r2
->Data
.NXT
.wTypes
,
366 r1
->wDataLength
- sizeof(DNS_NXT_DATAA
) + sizeof(WORD
) ))
372 if (strcmpX( r1
->Data
.SRV
.pNameTarget
, r2
->Data
.SRV
.pNameTarget
, wide
)) return FALSE
;
373 if (r1
->Data
.SRV
.wPriority
!= r2
->Data
.SRV
.wPriority
||
374 r1
->Data
.SRV
.wWeight
!= r2
->Data
.SRV
.wWeight
||
375 r1
->Data
.SRV
.wPort
!= r2
->Data
.SRV
.wPort
)
381 if (strcmpX( r1
->Data
.TKEY
.pNameAlgorithm
, r2
->Data
.TKEY
.pNameAlgorithm
, wide
))
383 if (r1
->Data
.TKEY
.dwCreateTime
!= r2
->Data
.TKEY
.dwCreateTime
||
384 r1
->Data
.TKEY
.dwExpireTime
!= r2
->Data
.TKEY
.dwExpireTime
||
385 r1
->Data
.TKEY
.wMode
!= r2
->Data
.TKEY
.wMode
||
386 r1
->Data
.TKEY
.wError
!= r2
->Data
.TKEY
.wError
||
387 r1
->Data
.TKEY
.wKeyLength
!= r2
->Data
.TKEY
.wKeyLength
||
388 r1
->Data
.TKEY
.wOtherLength
!= r2
->Data
.TKEY
.wOtherLength
||
389 r1
->Data
.TKEY
.cAlgNameLength
!= r2
->Data
.TKEY
.cAlgNameLength
||
390 r1
->Data
.TKEY
.bPacketPointers
!= r2
->Data
.TKEY
.bPacketPointers
)
393 /* FIXME: ignoring pAlgorithmPacket field */
394 if (memcmp( r1
->Data
.TKEY
.pKey
, r2
->Data
.TKEY
.pKey
,
395 r1
->Data
.TKEY
.wKeyLength
) ||
396 memcmp( r1
->Data
.TKEY
.pOtherData
, r2
->Data
.TKEY
.pOtherData
,
397 r1
->Data
.TKEY
.wOtherLength
)) return FALSE
;
402 if (strcmpX( r1
->Data
.TSIG
.pNameAlgorithm
, r2
->Data
.TSIG
.pNameAlgorithm
, wide
))
404 if (r1
->Data
.TSIG
.i64CreateTime
!= r2
->Data
.TSIG
.i64CreateTime
||
405 r1
->Data
.TSIG
.wFudgeTime
!= r2
->Data
.TSIG
.wFudgeTime
||
406 r1
->Data
.TSIG
.wOriginalXid
!= r2
->Data
.TSIG
.wOriginalXid
||
407 r1
->Data
.TSIG
.wError
!= r2
->Data
.TSIG
.wError
||
408 r1
->Data
.TSIG
.wSigLength
!= r2
->Data
.TSIG
.wSigLength
||
409 r1
->Data
.TSIG
.wOtherLength
!= r2
->Data
.TSIG
.wOtherLength
||
410 r1
->Data
.TSIG
.cAlgNameLength
!= r2
->Data
.TSIG
.cAlgNameLength
||
411 r1
->Data
.TSIG
.bPacketPointers
!= r2
->Data
.TSIG
.bPacketPointers
)
414 /* FIXME: ignoring pAlgorithmPacket field */
415 if (memcmp( r1
->Data
.TSIG
.pSignature
, r2
->Data
.TSIG
.pSignature
,
416 r1
->Data
.TSIG
.wSigLength
) ||
417 memcmp( r1
->Data
.TSIG
.pOtherData
, r2
->Data
.TSIG
.pOtherData
,
418 r1
->Data
.TSIG
.wOtherLength
)) return FALSE
;
423 if (r1
->Data
.WINS
.dwMappingFlag
!= r2
->Data
.WINS
.dwMappingFlag
||
424 r1
->Data
.WINS
.dwLookupTimeout
!= r2
->Data
.WINS
.dwLookupTimeout
||
425 r1
->Data
.WINS
.dwCacheTimeout
!= r2
->Data
.WINS
.dwCacheTimeout
||
426 r1
->Data
.WINS
.cWinsServerCount
!= r2
->Data
.WINS
.cWinsServerCount
)
428 if (memcmp( r1
->Data
.WINS
.WinsServers
, r2
->Data
.WINS
.WinsServers
,
429 r1
->wDataLength
- sizeof(DNS_WINS_DATA
) + sizeof(IP4_ADDRESS
) ))
435 if (r1
->Data
.WINSR
.dwMappingFlag
!= r2
->Data
.WINSR
.dwMappingFlag
||
436 r1
->Data
.WINSR
.dwLookupTimeout
!= r2
->Data
.WINSR
.dwLookupTimeout
||
437 r1
->Data
.WINSR
.dwCacheTimeout
!= r2
->Data
.WINSR
.dwCacheTimeout
)
439 if (strcmpX( r1
->Data
.WINSR
.pNameResultDomain
, r2
->Data
.WINSR
.pNameResultDomain
, wide
))
444 FIXME( "unknown type: %s\n", debugstr_type( r1
->wType
) );
450 static LPVOID
strdupX( LPCVOID src
, DNS_CHARSET in
, DNS_CHARSET out
)
454 case DnsCharSetUnicode
:
458 case DnsCharSetUnicode
: return wcsdup( src
);
459 case DnsCharSetUtf8
: return strdup_wu( src
);
460 case DnsCharSetAnsi
: return strdup_wa( src
);
462 WARN( "unhandled target charset: %d\n", out
);
470 case DnsCharSetUnicode
: return strdup_uw( src
);
471 case DnsCharSetUtf8
: return strdup( src
);
472 case DnsCharSetAnsi
: return strdup_ua( src
);
474 WARN( "unhandled target charset: %d\n", out
);
481 case DnsCharSetUnicode
: return strdup_aw( src
);
482 case DnsCharSetUtf8
: return strdup_au( src
);
483 case DnsCharSetAnsi
: return strdup( src
);
485 WARN( "unhandled target charset: %d\n", out
);
490 WARN( "unhandled source charset: %d\n", in
);
496 /******************************************************************************
497 * DnsRecordCopyEx [DNSAPI.@]
500 PDNS_RECORD WINAPI
DnsRecordCopyEx( PDNS_RECORD src
, DNS_CHARSET in
, DNS_CHARSET out
)
503 unsigned int i
, size
;
505 TRACE( "(%p,%d,%d)\n", src
, in
, out
);
507 size
= FIELD_OFFSET(DNS_RECORD
, Data
) + src
->wDataLength
;
508 dst
= malloc( size
);
509 if (!dst
) return NULL
;
511 memcpy( dst
, src
, size
);
513 if (src
->Flags
.S
.CharSet
== DnsCharSetUtf8
||
514 src
->Flags
.S
.CharSet
== DnsCharSetAnsi
||
515 src
->Flags
.S
.CharSet
== DnsCharSetUnicode
) in
= src
->Flags
.S
.CharSet
;
517 dst
->Flags
.S
.CharSet
= out
;
518 dst
->pName
= strdupX( src
->pName
, in
, out
);
519 if (!dst
->pName
) goto error
;
528 for (i
= 0; i
< src
->Data
.TXT
.dwStringCount
; i
++)
530 dst
->Data
.TXT
.pStringArray
[i
] = strdupX( src
->Data
.TXT
.pStringArray
[i
], in
, out
);
531 if (!dst
->Data
.TXT
.pStringArray
[i
])
533 while (i
> 0) free( dst
->Data
.TXT
.pStringArray
[--i
] );
542 dst
->Data
.MINFO
.pNameMailbox
= strdupX( src
->Data
.MINFO
.pNameMailbox
, in
, out
);
543 if (!dst
->Data
.MINFO
.pNameMailbox
) goto error
;
545 dst
->Data
.MINFO
.pNameErrorsMailbox
= strdupX( src
->Data
.MINFO
.pNameErrorsMailbox
, in
, out
);
546 if (!dst
->Data
.MINFO
.pNameErrorsMailbox
)
548 free( dst
->Data
.MINFO
.pNameMailbox
);
552 dst
->wDataLength
= sizeof(dst
->Data
.MINFO
);
553 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
554 (wcslen( dst
->Data
.MINFO
.pNameMailbox
) + 1) * sizeof(WCHAR
) +
555 (wcslen( dst
->Data
.MINFO
.pNameErrorsMailbox
) + 1) * sizeof(WCHAR
);
562 dst
->Data
.MX
.pNameExchange
= strdupX( src
->Data
.MX
.pNameExchange
, in
, out
);
563 if (!dst
->Data
.MX
.pNameExchange
) goto error
;
565 dst
->wDataLength
= sizeof(dst
->Data
.MX
);
566 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
567 (wcslen( dst
->Data
.MX
.pNameExchange
) + 1) * sizeof(WCHAR
);
572 dst
->Data
.NXT
.pNameNext
= strdupX( src
->Data
.NXT
.pNameNext
, in
, out
);
573 if (!dst
->Data
.NXT
.pNameNext
) goto error
;
575 dst
->wDataLength
= sizeof(dst
->Data
.NXT
);
576 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
577 (wcslen( dst
->Data
.NXT
.pNameNext
) + 1) * sizeof(WCHAR
);
589 dst
->Data
.PTR
.pNameHost
= strdupX( src
->Data
.PTR
.pNameHost
, in
, out
);
590 if (!dst
->Data
.PTR
.pNameHost
) goto error
;
592 dst
->wDataLength
= sizeof(dst
->Data
.PTR
);
593 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
594 (wcslen( dst
->Data
.PTR
.pNameHost
) + 1) * sizeof(WCHAR
);
599 dst
->Data
.SIG
.pNameSigner
= strdupX( src
->Data
.SIG
.pNameSigner
, in
, out
);
600 if (!dst
->Data
.SIG
.pNameSigner
) goto error
;
602 dst
->wDataLength
= sizeof(dst
->Data
.SIG
);
603 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
604 (wcslen( dst
->Data
.SIG
.pNameSigner
) + 1) * sizeof(WCHAR
);
609 dst
->Data
.SOA
.pNamePrimaryServer
= strdupX( src
->Data
.SOA
.pNamePrimaryServer
, in
, out
);
610 if (!dst
->Data
.SOA
.pNamePrimaryServer
) goto error
;
612 dst
->Data
.SOA
.pNameAdministrator
= strdupX( src
->Data
.SOA
.pNameAdministrator
, in
, out
);
613 if (!dst
->Data
.SOA
.pNameAdministrator
)
615 free( dst
->Data
.SOA
.pNamePrimaryServer
);
619 dst
->wDataLength
= sizeof(dst
->Data
.SOA
);
620 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
621 (wcslen( dst
->Data
.SOA
.pNamePrimaryServer
) + 1) * sizeof(WCHAR
) +
622 (wcslen( dst
->Data
.SOA
.pNameAdministrator
) + 1) * sizeof(WCHAR
);
627 dst
->Data
.SRV
.pNameTarget
= strdupX( src
->Data
.SRV
.pNameTarget
, in
, out
);
628 if (!dst
->Data
.SRV
.pNameTarget
) goto error
;
630 dst
->wDataLength
= sizeof(dst
->Data
.SRV
);
631 if (out
== DnsCharSetUnicode
) dst
->wDataLength
+=
632 (wcslen( dst
->Data
.SRV
.pNameTarget
) + 1) * sizeof(WCHAR
);
646 /******************************************************************************
647 * DnsRecordListFree [DNSAPI.@]
650 VOID WINAPI
DnsRecordListFree( PDNS_RECORD list
, DNS_FREE_TYPE type
)
652 DNS_RECORD
*r
, *next
;
655 TRACE( "(%p,%d)\n", list
, type
);
661 case DnsFreeRecordList
:
663 for (r
= list
; (list
= r
); r
= next
)
673 for (i
= 0; i
< r
->Data
.TXT
.dwStringCount
; i
++)
674 free( r
->Data
.TXT
.pStringArray
[i
] );
680 free( r
->Data
.MINFO
.pNameMailbox
);
681 free( r
->Data
.MINFO
.pNameErrorsMailbox
);
687 free( r
->Data
.MX
.pNameExchange
);
691 free( r
->Data
.NXT
.pNameNext
);
702 free( r
->Data
.PTR
.pNameHost
);
706 free( r
->Data
.SIG
.pNameSigner
);
710 free( r
->Data
.SOA
.pNamePrimaryServer
);
711 free( r
->Data
.SOA
.pNameAdministrator
);
715 free( r
->Data
.SRV
.pNameTarget
);
725 case DnsFreeParsedMessageFields
:
727 FIXME( "unhandled free type: %d\n", type
);
731 WARN( "unknown free type: %d\n", type
);
736 /******************************************************************************
740 void WINAPI
DnsFree( PVOID data
, DNS_FREE_TYPE type
)
742 DnsRecordListFree( data
, type
);
745 /******************************************************************************
746 * DnsRecordSetCompare [DNSAPI.@]
749 BOOL WINAPI
DnsRecordSetCompare( PDNS_RECORD set1
, PDNS_RECORD set2
,
750 PDNS_RECORD
*diff1
, PDNS_RECORD
*diff2
)
753 DNS_RECORD
*r
, *t
, *u
;
756 TRACE( "(%p,%p,%p,%p)\n", set1
, set2
, diff1
, diff2
);
758 if (!set1
&& !set2
) return FALSE
;
760 if (diff1
) *diff1
= NULL
;
761 if (diff2
) *diff2
= NULL
;
765 if (diff1
) *diff1
= DnsRecordSetCopyEx( set1
, 0, set1
->Flags
.S
.CharSet
);
770 if (diff2
) *diff2
= DnsRecordSetCopyEx( set2
, 0, set2
->Flags
.S
.CharSet
);
774 DNS_RRSET_INIT( rr1
);
775 DNS_RRSET_INIT( rr2
);
777 for (r
= set1
; r
; r
= r
->pNext
)
779 for (t
= set2
; t
; t
= t
->pNext
)
781 u
= DnsRecordCopyEx( r
, r
->Flags
.S
.CharSet
, t
->Flags
.S
.CharSet
);
784 if (!DnsRecordCompare( t
, u
))
786 DNS_RRSET_ADD( rr1
, u
);
789 else DnsRecordListFree( u
, DnsFreeRecordList
);
793 for (t
= set2
; t
; t
= t
->pNext
)
795 for (r
= set1
; r
; r
= r
->pNext
)
797 u
= DnsRecordCopyEx( t
, t
->Flags
.S
.CharSet
, r
->Flags
.S
.CharSet
);
800 if (!DnsRecordCompare( r
, u
))
802 DNS_RRSET_ADD( rr2
, u
);
805 else DnsRecordListFree( u
, DnsFreeRecordList
);
809 DNS_RRSET_TERMINATE( rr1
);
810 DNS_RRSET_TERMINATE( rr2
);
812 if (diff1
) *diff1
= rr1
.pFirstRR
;
813 else DnsRecordListFree( rr1
.pFirstRR
, DnsFreeRecordList
);
815 if (diff2
) *diff2
= rr2
.pFirstRR
;
816 else DnsRecordListFree( rr2
.pFirstRR
, DnsFreeRecordList
);
821 DNS_RRSET_TERMINATE( rr1
);
822 DNS_RRSET_TERMINATE( rr2
);
824 DnsRecordListFree( rr1
.pFirstRR
, DnsFreeRecordList
);
825 DnsRecordListFree( rr2
.pFirstRR
, DnsFreeRecordList
);
830 /******************************************************************************
831 * DnsRecordSetCopyEx [DNSAPI.@]
834 PDNS_RECORD WINAPI
DnsRecordSetCopyEx( PDNS_RECORD src_set
, DNS_CHARSET in
, DNS_CHARSET out
)
837 DNS_RECORD
*src
, *dst
;
839 TRACE( "(%p,%d,%d)\n", src_set
, in
, out
);
841 DNS_RRSET_INIT( dst_set
);
843 for (src
= src_set
; (src_set
= src
); src
= src_set
->pNext
)
845 dst
= DnsRecordCopyEx( src
, in
, out
);
848 DNS_RRSET_TERMINATE( dst_set
);
849 DnsRecordListFree( dst_set
.pFirstRR
, DnsFreeRecordList
);
852 DNS_RRSET_ADD( dst_set
, dst
);
855 DNS_RRSET_TERMINATE( dst_set
);
856 return dst_set
.pFirstRR
;
859 /******************************************************************************
860 * DnsRecordSetDetach [DNSAPI.@]
863 PDNS_RECORD WINAPI
DnsRecordSetDetach( PDNS_RECORD set
)
867 TRACE( "(%p)\n", set
);
869 for (r
= set
; (set
= r
); r
= set
->pNext
)
871 if (r
->pNext
&& !r
->pNext
->pNext
)
882 static unsigned int get_record_size( WORD type
, const BYTE
*data
, WORD len
)
887 return offsetof( DNS_RECORDA
, Data
.Key
.Key
[len
] );
890 return offsetof( DNS_RECORDA
, Data
.Sig
.Signature
[len
] );
898 const BYTE
*pos
= data
;
899 for (i
= 0; pos
< data
+ len
; i
++) pos
+= pos
[0] + 1;
900 return offsetof( DNS_RECORDA
, Data
.Txt
.pStringArray
[i
] );
905 return offsetof( DNS_RECORDA
, Data
.Null
.Data
[len
] );
908 return offsetof( DNS_RECORDA
, Data
.Wks
.BitMask
[len
/ 8] );
911 return offsetof( DNS_RECORDA
, Data
.Nxt
.wTypes
[len
* 8] );
914 return offsetof( DNS_RECORDA
, Data
.Wins
.WinsServers
[len
/ 4] );
917 return sizeof(DNS_RECORDA
);
921 static DNS_STATUS
extract_rdata( const BYTE
*base
, const BYTE
*end
, const BYTE
*pos
, WORD len
, WORD type
,
924 DNS_CHARSET in
= DnsCharSetUtf8
, out
= r
->Flags
.S
.CharSet
;
925 char name
[DNS_MAX_NAME_BUFFER_LENGTH
];
926 DNS_STATUS ret
= ERROR_SUCCESS
;
927 const BYTE
*rrend
= pos
+ len
;
933 if (pos
+ sizeof(DWORD
) > rrend
) return DNS_ERROR_BAD_PACKET
;
934 r
->Data
.A
.IpAddress
= *(const DWORD
*)pos
;
935 r
->wDataLength
= sizeof(DNS_A_DATA
);
939 if (pos
+ sizeof(IP6_ADDRESS
) > rrend
) return DNS_ERROR_BAD_PACKET
;
940 for (i
= 0; i
< sizeof(IP6_ADDRESS
)/sizeof(DWORD
); i
++)
942 r
->Data
.AAAA
.Ip6Address
.IP6Dword
[i
] = *(const DWORD
*)pos
;
943 pos
+= sizeof(DWORD
);
945 r
->wDataLength
= sizeof(DNS_AAAA_DATA
);
949 if (pos
+ 4 > rrend
) return DNS_ERROR_BAD_PACKET
;
950 r
->Data
.KEY
.wFlags
= get_word( &pos
);
951 r
->Data
.KEY
.chProtocol
= *pos
++;
952 r
->Data
.KEY
.chAlgorithm
= *pos
++;
953 r
->Data
.KEY
.wKeyLength
= rrend
- pos
;
954 memcpy( r
->Data
.KEY
.Key
, pos
, r
->Data
.KEY
.wKeyLength
);
955 r
->wDataLength
= offsetof( DNS_KEY_DATA
, Key
[r
->Data
.KEY
.wKeyLength
] );
960 if (!(pos
= get_name( base
, end
, pos
, name
))) return DNS_ERROR_BAD_PACKET
;
961 if (!(r
->Data
.MINFO
.pNameMailbox
= strdupX( name
, in
, out
))) return ERROR_NOT_ENOUGH_MEMORY
;
962 if (!get_name( base
, end
, pos
, name
)) return DNS_ERROR_BAD_PACKET
;
963 if (!(r
->Data
.MINFO
.pNameErrorsMailbox
= strdupX( name
, in
, out
)))
965 free( r
->Data
.MINFO
.pNameMailbox
);
966 return ERROR_NOT_ENOUGH_MEMORY
;
968 r
->wDataLength
= sizeof(DNS_MINFO_DATAA
);
974 if (pos
+ sizeof(WORD
) > rrend
) return DNS_ERROR_BAD_PACKET
;
975 r
->Data
.MX
.wPreference
= get_word( &pos
);
976 if (!get_name( base
, end
, pos
, name
)) return DNS_ERROR_BAD_PACKET
;
977 if (!(r
->Data
.MX
.pNameExchange
= strdupX( name
, in
, out
))) return ERROR_NOT_ENOUGH_MEMORY
;
978 r
->wDataLength
= sizeof(DNS_MX_DATAA
) + sizeof(DWORD
);
982 r
->Data
.Null
.dwByteCount
= len
;
983 memcpy( r
->Data
.Null
.Data
, pos
, len
);
984 r
->wDataLength
= offsetof( DNS_NULL_DATA
, Data
[len
] );
988 r
->Data
.OPT
.wDataLength
= len
;
989 r
->Data
.OPT
.wPad
= 0;
990 memcpy( r
->Data
.OPT
.Data
, pos
, len
);
991 r
->wDataLength
= offsetof( DNS_OPT_DATA
, Data
[len
] );
1002 if (!get_name( base
, end
, pos
, name
)) return DNS_ERROR_BAD_PACKET
;
1003 if (!(r
->Data
.PTR
.pNameHost
= strdupX( name
, in
, out
))) return ERROR_NOT_ENOUGH_MEMORY
;
1004 r
->wDataLength
= sizeof(DNS_PTR_DATAA
) + sizeof(DWORD
);
1008 if (pos
+ 18 > rrend
) return DNS_ERROR_BAD_PACKET
;
1009 r
->Data
.SIG
.wTypeCovered
= get_word( &pos
);
1010 r
->Data
.SIG
.chAlgorithm
= *pos
++;
1011 r
->Data
.SIG
.chLabelCount
= *pos
++;
1012 r
->Data
.SIG
.dwOriginalTtl
= get_dword( &pos
);
1013 r
->Data
.SIG
.dwExpiration
= get_dword( &pos
);
1014 r
->Data
.SIG
.dwTimeSigned
= get_dword( &pos
);
1015 r
->Data
.SIG
.wKeyTag
= get_word( &pos
);
1016 if (!(pos
= get_name( base
, end
, pos
, name
))) return DNS_ERROR_BAD_PACKET
;
1017 if (!(r
->Data
.SIG
.pNameSigner
= strdupX( name
, in
, out
))) return ERROR_NOT_ENOUGH_MEMORY
;
1018 r
->Data
.SIG
.wSignatureLength
= rrend
- pos
;
1019 memcpy( r
->Data
.SIG
.Signature
, pos
, r
->Data
.SIG
.wSignatureLength
);
1020 r
->wDataLength
= offsetof( DNS_SIG_DATAA
, Signature
[r
->Data
.SIG
.wSignatureLength
] );
1024 if (!(pos
= get_name( base
, end
, pos
, name
))) return DNS_ERROR_BAD_PACKET
;
1025 if (!(r
->Data
.SOA
.pNamePrimaryServer
= strdupX( name
, in
, out
))) return ERROR_NOT_ENOUGH_MEMORY
;
1026 if (!(pos
= get_name( base
, end
, pos
, name
))) return DNS_ERROR_BAD_PACKET
;
1027 if (!(r
->Data
.SOA
.pNameAdministrator
= strdupX( name
, in
, out
)))
1029 free( r
->Data
.SOA
.pNamePrimaryServer
);
1030 return ERROR_NOT_ENOUGH_MEMORY
;
1032 if (pos
+ 5 * sizeof(DWORD
) > rrend
) return DNS_ERROR_BAD_PACKET
;
1033 r
->Data
.SOA
.dwSerialNo
= get_dword( &pos
);
1034 r
->Data
.SOA
.dwRefresh
= get_dword( &pos
);
1035 r
->Data
.SOA
.dwRetry
= get_dword( &pos
);
1036 r
->Data
.SOA
.dwExpire
= get_dword( &pos
);
1037 r
->Data
.SOA
.dwDefaultTtl
= get_dword( &pos
);
1038 r
->wDataLength
= sizeof(DNS_SOA_DATAA
);
1042 if (pos
+ 3 * sizeof(WORD
) > rrend
) return DNS_ERROR_BAD_PACKET
;
1043 r
->Data
.SRV
.wPriority
= get_word( &pos
);
1044 r
->Data
.SRV
.wWeight
= get_word( &pos
);
1045 r
->Data
.SRV
.wPort
= get_word( &pos
);
1046 if (!get_name( base
, end
, pos
, name
)) return DNS_ERROR_BAD_PACKET
;
1047 if (!(r
->Data
.SRV
.pNameTarget
= strdupX( name
, in
, out
))) return ERROR_NOT_ENOUGH_MEMORY
;
1048 r
->wDataLength
= sizeof(DNS_SRV_DATAA
);
1051 case DNS_TYPE_HINFO
:
1055 for (i
= 0; pos
< rrend
; i
++)
1058 if (pos
+ len
+ 1 > rrend
) return DNS_ERROR_BAD_PACKET
;
1059 memcpy( name
, pos
+ 1, len
);
1061 if (!(r
->Data
.TXT
.pStringArray
[i
] = strdupX( name
, in
, out
)))
1063 while (i
> 0) free( r
->Data
.TXT
.pStringArray
[--i
] );
1064 return ERROR_NOT_ENOUGH_MEMORY
;
1068 r
->Data
.TXT
.dwStringCount
= i
;
1069 r
->wDataLength
= offsetof( DNS_TXT_DATAA
, pStringArray
[r
->Data
.TXT
.dwStringCount
] );
1079 case DNS_TYPE_WINSR
:
1081 FIXME( "unhandled type: %s\n", debugstr_type( type
));
1082 return DNS_ERROR_RCODE_NOT_IMPLEMENTED
;
1088 static DNS_STATUS
extract_record( const DNS_MESSAGE_BUFFER
*hdr
, const BYTE
*end
, const BYTE
**pos
,
1089 DNS_SECTION section
, DNS_CHARSET charset
, DNS_RECORDA
**recp
)
1092 DNS_RECORDA
*record
;
1093 char name
[DNS_MAX_NAME_BUFFER_LENGTH
];
1096 const BYTE
*base
= (const BYTE
*)hdr
;
1097 const BYTE
*ptr
= *pos
;
1099 if (!(ptr
= get_name( base
, end
, ptr
, name
))) return DNS_ERROR_BAD_PACKET
;
1101 if (ptr
+ 10 > end
) return DNS_ERROR_BAD_PACKET
;
1102 type
= get_word( &ptr
);
1103 ptr
+= sizeof(WORD
); /* class */
1104 ttl
= get_dword( &ptr
);
1105 rdlen
= get_word( &ptr
);
1106 if (ptr
+ rdlen
> end
) return DNS_ERROR_BAD_PACKET
;
1109 if (!(record
= calloc( 1, get_record_size( type
, ptr
, rdlen
) ))) return ERROR_NOT_ENOUGH_MEMORY
;
1111 record
->wType
= type
;
1112 record
->Flags
.S
.Section
= section
;
1113 record
->Flags
.S
.CharSet
= charset
;
1114 record
->dwTtl
= ttl
;
1116 if (!(record
->pName
= strdupX( name
, DnsCharSetUtf8
, charset
)))
1119 return ERROR_NOT_ENOUGH_MEMORY
;
1121 if ((ret
= extract_rdata( base
, end
, ptr
, rdlen
, type
, record
)))
1123 free( record
->pName
);
1128 TRACE( "found %s record in %s section\n", debugstr_type( record
->wType
), debugstr_section( section
) );
1129 return ERROR_SUCCESS
;
1132 static DNS_STATUS
extract_message_records( const DNS_MESSAGE_BUFFER
*buffer
, WORD len
, DNS_CHARSET charset
,
1135 DNS_STATUS ret
= ERROR_SUCCESS
;
1136 const DNS_HEADER
*hdr
= &buffer
->MessageHead
;
1137 DNS_RECORDA
*record
;
1138 const BYTE
*base
= (const BYTE
*)hdr
;
1139 const BYTE
*end
= base
+ len
;
1140 const BYTE
*ptr
= (const BYTE
*)buffer
->MessageBody
;
1143 if (hdr
->IsResponse
&& !hdr
->AnswerCount
) return DNS_ERROR_BAD_PACKET
;
1145 for (num
= 0; num
< hdr
->QuestionCount
; num
++)
1146 if (!(ptr
= skip_record( ptr
, end
, DnsSectionQuestion
))) return DNS_ERROR_BAD_PACKET
;
1148 for (num
= 0; num
< hdr
->AnswerCount
; num
++)
1150 if ((ret
= extract_record( buffer
, end
, &ptr
, DnsSectionAnswer
, charset
, &record
)))
1152 DNS_RRSET_ADD( *rrset
, (DNS_RECORD
*)record
);
1155 for (num
= 0; num
< hdr
->NameServerCount
; num
++)
1156 if (!(ptr
= skip_record( ptr
, end
, DnsSectionAuthority
))) return DNS_ERROR_BAD_PACKET
;
1158 for (num
= 0; num
< hdr
->AdditionalCount
; num
++)
1160 if ((ret
= extract_record( buffer
, end
, &ptr
, DnsSectionAddtional
, charset
, &record
))) return ret
;
1161 DNS_RRSET_ADD( *rrset
, (DNS_RECORD
*)record
);
1164 if (ptr
!= end
) ret
= DNS_ERROR_BAD_PACKET
;
1168 /******************************************************************************
1169 * DnsExtractRecordsFromMessage_UTF8 [DNSAPI.@]
1172 DNS_STATUS WINAPI
DnsExtractRecordsFromMessage_UTF8( DNS_MESSAGE_BUFFER
*buffer
, WORD len
,
1173 DNS_RECORDA
**result
)
1175 DNS_STATUS ret
= DNS_ERROR_BAD_PACKET
;
1178 if (len
< sizeof(*buffer
)) return ERROR_INVALID_PARAMETER
;
1180 DNS_RRSET_INIT( rrset
);
1181 ret
= extract_message_records( buffer
, len
, DnsCharSetUtf8
, &rrset
);
1182 DNS_RRSET_TERMINATE( rrset
);
1184 if (!ret
) *result
= (DNS_RECORDA
*)rrset
.pFirstRR
;
1185 else DnsRecordListFree( rrset
.pFirstRR
, DnsFreeRecordList
);
1190 /******************************************************************************
1191 * DnsExtractRecordsFromMessage_W [DNSAPI.@]
1194 DNS_STATUS WINAPI
DnsExtractRecordsFromMessage_W( DNS_MESSAGE_BUFFER
*buffer
, WORD len
,
1195 DNS_RECORDW
**result
)
1197 DNS_STATUS ret
= DNS_ERROR_BAD_PACKET
;
1200 if (len
< sizeof(*buffer
)) return ERROR_INVALID_PARAMETER
;
1202 DNS_RRSET_INIT( rrset
);
1203 ret
= extract_message_records( buffer
, len
, DnsCharSetUnicode
, &rrset
);
1204 DNS_RRSET_TERMINATE( rrset
);
1206 if (!ret
) *result
= (DNS_RECORDW
*)rrset
.pFirstRR
;
1207 else DnsRecordListFree( rrset
.pFirstRR
, DnsFreeRecordList
);