xref: /reactos/dll/win32/dnsapi/record.c (revision 8a978a17)
1 /*
2  * DNS support
3  *
4  * Copyright (C) 2006 Hans Leidekker
5  *
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.
10  *
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.
15  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "precomp.h"
22 
23 #define NDEBUG
24 #include <debug.h>
25 
26 const char *dns_type_to_str( unsigned short type )
27 {
28     switch (type)
29     {
30 #define X(x)    case (x): return #x;
31     X(DNS_TYPE_ZERO)
32     X(DNS_TYPE_A)
33     X(DNS_TYPE_NS)
34     X(DNS_TYPE_MD)
35     X(DNS_TYPE_MF)
36     X(DNS_TYPE_CNAME)
37     X(DNS_TYPE_SOA)
38     X(DNS_TYPE_MB)
39     X(DNS_TYPE_MG)
40     X(DNS_TYPE_MR)
41     X(DNS_TYPE_NULL)
42     X(DNS_TYPE_WKS)
43     X(DNS_TYPE_PTR)
44     X(DNS_TYPE_HINFO)
45     X(DNS_TYPE_MINFO)
46     X(DNS_TYPE_MX)
47     X(DNS_TYPE_TEXT)
48     X(DNS_TYPE_RP)
49     X(DNS_TYPE_AFSDB)
50     X(DNS_TYPE_X25)
51     X(DNS_TYPE_ISDN)
52     X(DNS_TYPE_RT)
53     X(DNS_TYPE_NSAP)
54     X(DNS_TYPE_NSAPPTR)
55     X(DNS_TYPE_SIG)
56     X(DNS_TYPE_KEY)
57     X(DNS_TYPE_PX)
58     X(DNS_TYPE_GPOS)
59     X(DNS_TYPE_AAAA)
60     X(DNS_TYPE_LOC)
61     X(DNS_TYPE_NXT)
62     X(DNS_TYPE_EID)
63     X(DNS_TYPE_NIMLOC)
64     X(DNS_TYPE_SRV)
65     X(DNS_TYPE_ATMA)
66     X(DNS_TYPE_NAPTR)
67     X(DNS_TYPE_KX)
68     X(DNS_TYPE_CERT)
69     X(DNS_TYPE_A6)
70     X(DNS_TYPE_DNAME)
71     X(DNS_TYPE_SINK)
72     X(DNS_TYPE_OPT)
73     X(DNS_TYPE_UINFO)
74     X(DNS_TYPE_UID)
75     X(DNS_TYPE_GID)
76     X(DNS_TYPE_UNSPEC)
77     X(DNS_TYPE_ADDRS)
78     X(DNS_TYPE_TKEY)
79     X(DNS_TYPE_TSIG)
80     X(DNS_TYPE_IXFR)
81     X(DNS_TYPE_AXFR)
82     X(DNS_TYPE_MAILB)
83     X(DNS_TYPE_MAILA)
84     X(DNS_TYPE_ANY)
85     X(DNS_TYPE_WINS)
86     X(DNS_TYPE_WINSR)
87 #undef X
88     default: { static char tmp[7]; sprintf( tmp, "0x%04x", type ); return tmp; }
89     }
90 }
91 
92 static int dns_strcmpX( LPCVOID str1, LPCVOID str2, BOOL wide )
93 {
94     if (wide)
95         return lstrcmpiW( str1, str2 );
96     else
97         return lstrcmpiA( str1, str2 );
98 }
99 
100 /******************************************************************************
101  * DnsRecordCompare                        [DNSAPI.@]
102  *
103  */
104 BOOL WINAPI DnsRecordCompare( PDNS_RECORD r1, PDNS_RECORD r2 )
105 {
106     BOOL wide;
107     unsigned int i;
108 
109     DPRINT( "(%p,%p)\n", r1, r2 );
110 
111     if (r1->wType            != r2->wType            ||
112         r1->wDataLength      != r2->wDataLength      ||
113         r1->Flags.S.Section  != r2->Flags.S.Section  ||
114         r1->Flags.S.Delete   != r2->Flags.S.Delete   ||
115         r1->Flags.S.Unused   != r2->Flags.S.Unused   ||
116         r1->Flags.S.Reserved != r2->Flags.S.Reserved ||
117         r1->dwReserved       != r2->dwReserved) return FALSE;
118 
119     wide = (r1->Flags.S.CharSet == DnsCharSetUnicode || r1->Flags.S.CharSet == DnsCharSetUnknown);
120     if (dns_strcmpX( r1->pName, r2->pName, wide )) return FALSE;
121 
122     switch (r1->wType)
123     {
124     case DNS_TYPE_A:
125     {
126         if (r1->Data.A.IpAddress != r2->Data.A.IpAddress) return FALSE;
127         break;
128     }
129     case DNS_TYPE_SOA:
130     {
131         if (r1->Data.SOA.dwSerialNo   != r2->Data.SOA.dwSerialNo ||
132             r1->Data.SOA.dwRefresh    != r2->Data.SOA.dwRefresh  ||
133             r1->Data.SOA.dwRetry      != r2->Data.SOA.dwRetry    ||
134             r1->Data.SOA.dwExpire     != r2->Data.SOA.dwExpire   ||
135             r1->Data.SOA.dwDefaultTtl != r2->Data.SOA.dwDefaultTtl)
136             return FALSE;
137         if (dns_strcmpX( r1->Data.SOA.pNamePrimaryServer,
138                          r2->Data.SOA.pNamePrimaryServer, wide ) ||
139             dns_strcmpX( r1->Data.SOA.pNameAdministrator,
140                          r2->Data.SOA.pNameAdministrator, wide ))
141             return FALSE;
142         break;
143     }
144     case DNS_TYPE_PTR:
145     case DNS_TYPE_NS:
146     case DNS_TYPE_CNAME:
147     case DNS_TYPE_MB:
148     case DNS_TYPE_MD:
149     case DNS_TYPE_MF:
150     case DNS_TYPE_MG:
151     case DNS_TYPE_MR:
152     {
153         if (dns_strcmpX( r1->Data.PTR.pNameHost,
154                          r2->Data.PTR.pNameHost, wide )) return FALSE;
155         break;
156     }
157     case DNS_TYPE_MINFO:
158     case DNS_TYPE_RP:
159     {
160         if (dns_strcmpX( r1->Data.MINFO.pNameMailbox,
161                          r2->Data.MINFO.pNameMailbox, wide ) ||
162             dns_strcmpX( r1->Data.MINFO.pNameErrorsMailbox,
163                          r2->Data.MINFO.pNameErrorsMailbox, wide ))
164             return FALSE;
165         break;
166     }
167     case DNS_TYPE_MX:
168     case DNS_TYPE_AFSDB:
169     case DNS_TYPE_RT:
170     {
171         if (r1->Data.MX.wPreference != r2->Data.MX.wPreference)
172             return FALSE;
173         if (dns_strcmpX( r1->Data.MX.pNameExchange,
174                          r2->Data.MX.pNameExchange, wide ))
175             return FALSE;
176         break;
177     }
178     case DNS_TYPE_HINFO:
179     case DNS_TYPE_ISDN:
180     case DNS_TYPE_TEXT:
181     case DNS_TYPE_X25:
182     {
183         if (r1->Data.TXT.dwStringCount != r2->Data.TXT.dwStringCount)
184             return FALSE;
185         for (i = 0; i < r1->Data.TXT.dwStringCount; i++)
186         {
187             if (dns_strcmpX( r1->Data.TXT.pStringArray[i],
188                              r2->Data.TXT.pStringArray[i], wide ))
189                 return FALSE;
190         }
191         break;
192     }
193     case DNS_TYPE_NULL:
194     {
195         if (r1->Data.Null.dwByteCount != r2->Data.Null.dwByteCount)
196             return FALSE;
197         if (memcmp( r1->Data.Null.Data,
198                     r2->Data.Null.Data, r1->Data.Null.dwByteCount ))
199             return FALSE;
200         break;
201     }
202     case DNS_TYPE_AAAA:
203     {
204         for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
205         {
206             if (r1->Data.AAAA.Ip6Address.IP6Dword[i] !=
207                 r2->Data.AAAA.Ip6Address.IP6Dword[i]) return FALSE;
208         }
209         break;
210     }
211     case DNS_TYPE_KEY:
212     {
213         if (r1->Data.KEY.wFlags      != r2->Data.KEY.wFlags      ||
214             r1->Data.KEY.chProtocol  != r2->Data.KEY.chProtocol  ||
215             r1->Data.KEY.chAlgorithm != r2->Data.KEY.chAlgorithm)
216             return FALSE;
217         if (memcmp( r1->Data.KEY.Key, r2->Data.KEY.Key,
218                     r1->wDataLength - sizeof(DNS_KEY_DATA) + 1 ))
219             return FALSE;
220         break;
221     }
222     case DNS_TYPE_SIG:
223     {
224         if (dns_strcmpX( r1->Data.SIG.pNameSigner,
225                          r2->Data.SIG.pNameSigner, wide ))
226             return FALSE;
227         if (r1->Data.SIG.wTypeCovered  != r2->Data.SIG.wTypeCovered  ||
228             r1->Data.SIG.chAlgorithm   != r2->Data.SIG.chAlgorithm   ||
229             r1->Data.SIG.chLabelCount  != r2->Data.SIG.chLabelCount  ||
230             r1->Data.SIG.dwOriginalTtl != r2->Data.SIG.dwOriginalTtl ||
231             r1->Data.SIG.dwExpiration  != r2->Data.SIG.dwExpiration  ||
232             r1->Data.SIG.dwTimeSigned  != r2->Data.SIG.dwTimeSigned  ||
233             r1->Data.SIG.wKeyTag       != r2->Data.SIG.wKeyTag)
234             return FALSE;
235         if (memcmp( r1->Data.SIG.Signature, r2->Data.SIG.Signature,
236                     r1->wDataLength - sizeof(DNS_SIG_DATAA) + 1 ))
237             return FALSE;
238         break;
239     }
240     case DNS_TYPE_ATMA:
241     {
242         if (r1->Data.ATMA.AddressType != r2->Data.ATMA.AddressType)
243             return FALSE;
244         for (i = 0; i < DNS_ATMA_MAX_ADDR_LENGTH; i++)
245         {
246             if (r1->Data.ATMA.Address[i] != r2->Data.ATMA.Address[i])
247                 return FALSE;
248         }
249         break;
250     }
251     case DNS_TYPE_NXT:
252     {
253         if (dns_strcmpX( r1->Data.NXT.pNameNext,
254                          r2->Data.NXT.pNameNext, wide )) return FALSE;
255         if (r1->Data.NXT.wNumTypes != r2->Data.NXT.wNumTypes) return FALSE;
256         if (memcmp( r1->Data.NXT.wTypes, r2->Data.NXT.wTypes,
257                     r1->wDataLength - sizeof(DNS_NXT_DATAA) + sizeof(WORD) ))
258             return FALSE;
259         break;
260     }
261     case DNS_TYPE_SRV:
262     {
263         if (dns_strcmpX( r1->Data.SRV.pNameTarget,
264                          r2->Data.SRV.pNameTarget, wide )) return FALSE;
265         if (r1->Data.SRV.wPriority != r2->Data.SRV.wPriority ||
266             r1->Data.SRV.wWeight   != r2->Data.SRV.wWeight   ||
267             r1->Data.SRV.wPort     != r2->Data.SRV.wPort)
268             return FALSE;
269         break;
270     }
271     case DNS_TYPE_TKEY:
272     {
273         if (dns_strcmpX( r1->Data.TKEY.pNameAlgorithm,
274                          r2->Data.TKEY.pNameAlgorithm, wide ))
275             return FALSE;
276         if (r1->Data.TKEY.dwCreateTime    != r2->Data.TKEY.dwCreateTime     ||
277             r1->Data.TKEY.dwExpireTime    != r2->Data.TKEY.dwExpireTime     ||
278             r1->Data.TKEY.wMode           != r2->Data.TKEY.wMode            ||
279             r1->Data.TKEY.wError          != r2->Data.TKEY.wError           ||
280             r1->Data.TKEY.wKeyLength      != r2->Data.TKEY.wKeyLength       ||
281             r1->Data.TKEY.wOtherLength    != r2->Data.TKEY.wOtherLength     ||
282             r1->Data.TKEY.cAlgNameLength  != r2->Data.TKEY.cAlgNameLength   ||
283             r1->Data.TKEY.bPacketPointers != r2->Data.TKEY.bPacketPointers)
284             return FALSE;
285 
286         /* FIXME: ignoring pAlgorithmPacket field */
287         if (memcmp( r1->Data.TKEY.pKey, r2->Data.TKEY.pKey,
288                     r1->Data.TKEY.wKeyLength ) ||
289             memcmp( r1->Data.TKEY.pOtherData, r2->Data.TKEY.pOtherData,
290                     r1->Data.TKEY.wOtherLength )) return FALSE;
291         break;
292     }
293     case DNS_TYPE_TSIG:
294     {
295         if (dns_strcmpX( r1->Data.TSIG.pNameAlgorithm,
296                          r2->Data.TSIG.pNameAlgorithm, wide ))
297             return FALSE;
298         if (r1->Data.TSIG.i64CreateTime   != r2->Data.TSIG.i64CreateTime    ||
299             r1->Data.TSIG.wFudgeTime      != r2->Data.TSIG.wFudgeTime       ||
300             r1->Data.TSIG.wOriginalXid    != r2->Data.TSIG.wOriginalXid     ||
301             r1->Data.TSIG.wError          != r2->Data.TSIG.wError           ||
302             r1->Data.TSIG.wSigLength      != r2->Data.TSIG.wSigLength       ||
303             r1->Data.TSIG.wOtherLength    != r2->Data.TSIG.wOtherLength     ||
304             r1->Data.TSIG.cAlgNameLength  != r2->Data.TSIG.cAlgNameLength   ||
305             r1->Data.TSIG.bPacketPointers != r2->Data.TSIG.bPacketPointers)
306             return FALSE;
307 
308         /* FIXME: ignoring pAlgorithmPacket field */
309         if (memcmp( r1->Data.TSIG.pSignature, r2->Data.TSIG.pSignature,
310                     r1->Data.TSIG.wSigLength ) ||
311             memcmp( r1->Data.TSIG.pOtherData, r2->Data.TSIG.pOtherData,
312                     r1->Data.TSIG.wOtherLength )) return FALSE;
313         break;
314     }
315     case DNS_TYPE_WINS:
316     {
317         if (r1->Data.WINS.dwMappingFlag    != r2->Data.WINS.dwMappingFlag   ||
318             r1->Data.WINS.dwLookupTimeout  != r2->Data.WINS.dwLookupTimeout ||
319             r1->Data.WINS.dwCacheTimeout   != r2->Data.WINS.dwCacheTimeout  ||
320             r1->Data.WINS.cWinsServerCount != r2->Data.WINS.cWinsServerCount)
321             return FALSE;
322         if (memcmp( r1->Data.WINS.WinsServers, r2->Data.WINS.WinsServers,
323                     r1->wDataLength - sizeof(DNS_WINS_DATA) + sizeof(IP4_ADDRESS) ))
324             return FALSE;
325         break;
326     }
327     case DNS_TYPE_WINSR:
328     {
329         if (r1->Data.WINSR.dwMappingFlag   != r2->Data.WINSR.dwMappingFlag   ||
330             r1->Data.WINSR.dwLookupTimeout != r2->Data.WINSR.dwLookupTimeout ||
331             r1->Data.WINSR.dwCacheTimeout  != r2->Data.WINSR.dwCacheTimeout)
332             return FALSE;
333         if (dns_strcmpX( r1->Data.WINSR.pNameResultDomain,
334                          r2->Data.WINSR.pNameResultDomain, wide ))
335             return FALSE;
336         break;
337     }
338     default:
339         DPRINT1( "unknown type: %s\n", dns_type_to_str( r1->wType ) );
340         return FALSE;
341     }
342     return TRUE;
343 }
344 
345 static LPVOID dns_strcpyX( LPCVOID src, DNS_CHARSET in, DNS_CHARSET out )
346 {
347     switch (in)
348     {
349     case DnsCharSetUnicode:
350     {
351         switch (out)
352         {
353         case DnsCharSetUnicode: return dns_strdup_w( src );
354         case DnsCharSetUtf8:    return dns_strdup_wu( src );
355         case DnsCharSetAnsi:    return dns_strdup_wa( src );
356         default:
357             DPRINT1( "unhandled target charset: %d\n", out );
358             break;
359         }
360         break;
361     }
362     case DnsCharSetUtf8:
363         switch (out)
364         {
365         case DnsCharSetUnicode: return dns_strdup_uw( src );
366         case DnsCharSetUtf8:    return dns_strdup_u( src );
367         case DnsCharSetAnsi:    return dns_strdup_ua( src );
368         default:
369             DPRINT1( "unhandled target charset: %d\n", out );
370             break;
371         }
372         break;
373     case DnsCharSetAnsi:
374         switch (out)
375         {
376         case DnsCharSetUnicode: return dns_strdup_aw( src );
377         case DnsCharSetUtf8:    return dns_strdup_au( src );
378         case DnsCharSetAnsi:    return dns_strdup_a( src );
379         default:
380             DPRINT1( "unhandled target charset: %d\n", out );
381             break;
382         }
383         break;
384     default:
385         DPRINT1( "unhandled source charset: %d\n", in );
386         break;
387     }
388     return NULL;
389 }
390 
391 /******************************************************************************
392  * DnsRecordCopyEx                         [DNSAPI.@]
393  *
394  */
395 PDNS_RECORD WINAPI DnsRecordCopyEx( PDNS_RECORD src, DNS_CHARSET in, DNS_CHARSET out )
396 {
397     DNS_RECORD *dst;
398     unsigned int i, size;
399 
400     DPRINT( "(%p,%d,%d)\n", src, in, out );
401 
402     size = FIELD_OFFSET(DNS_RECORD, Data) + src->wDataLength;
403     dst = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
404     if (!dst) return NULL;
405 
406     memcpy( dst, src, size );
407 
408     if (src->Flags.S.CharSet == DnsCharSetUtf8 ||
409         src->Flags.S.CharSet == DnsCharSetAnsi ||
410         src->Flags.S.CharSet == DnsCharSetUnicode) in = src->Flags.S.CharSet;
411 
412     dst->Flags.S.CharSet = out;
413     dst->pName = dns_strcpyX( src->pName, in, out );
414     if (!dst->pName) goto error;
415 
416     switch (src->wType)
417     {
418     case DNS_TYPE_HINFO:
419     case DNS_TYPE_ISDN:
420     case DNS_TYPE_TEXT:
421     case DNS_TYPE_X25:
422     {
423         for (i = 0; i < src->Data.TXT.dwStringCount; i++)
424         {
425             dst->Data.TXT.pStringArray[i] =
426                 dns_strcpyX( src->Data.TXT.pStringArray[i], in, out );
427 
428             if (!dst->Data.TXT.pStringArray[i])
429             {
430                 while (i > 0) HeapFree( GetProcessHeap(), 0, dst->Data.TXT.pStringArray[--i] );
431                 goto error;
432             }
433         }
434         break;
435     }
436     case DNS_TYPE_MINFO:
437     case DNS_TYPE_RP:
438     {
439         dst->Data.MINFO.pNameMailbox =
440             dns_strcpyX( src->Data.MINFO.pNameMailbox, in, out );
441         if (!dst->Data.MINFO.pNameMailbox) goto error;
442 
443         dst->Data.MINFO.pNameErrorsMailbox =
444             dns_strcpyX( src->Data.MINFO.pNameErrorsMailbox, in, out );
445         if (!dst->Data.MINFO.pNameErrorsMailbox)
446         {
447             HeapFree( GetProcessHeap(), 0, dst->Data.MINFO.pNameMailbox );
448             goto error;
449         }
450         break;
451     }
452     case DNS_TYPE_AFSDB:
453     case DNS_TYPE_RT:
454     case DNS_TYPE_MX:
455     {
456         dst->Data.MX.pNameExchange =
457             dns_strcpyX( src->Data.MX.pNameExchange, in, out );
458         if (!dst->Data.MX.pNameExchange) goto error;
459         break;
460     }
461     case DNS_TYPE_NXT:
462     {
463         dst->Data.NXT.pNameNext =
464             dns_strcpyX( src->Data.NXT.pNameNext, in, out );
465         if (!dst->Data.NXT.pNameNext) goto error;
466         break;
467     }
468     case DNS_TYPE_CNAME:
469     case DNS_TYPE_MB:
470     case DNS_TYPE_MD:
471     case DNS_TYPE_MF:
472     case DNS_TYPE_MG:
473     case DNS_TYPE_MR:
474     case DNS_TYPE_NS:
475     case DNS_TYPE_PTR:
476     {
477         dst->Data.PTR.pNameHost =
478             dns_strcpyX( src->Data.PTR.pNameHost, in, out );
479         if (!dst->Data.PTR.pNameHost) goto error;
480         break;
481     }
482     case DNS_TYPE_SIG:
483     {
484         dst->Data.SIG.pNameSigner =
485             dns_strcpyX( src->Data.SIG.pNameSigner, in, out );
486         if (!dst->Data.SIG.pNameSigner) goto error;
487         break;
488     }
489     case DNS_TYPE_SOA:
490     {
491         dst->Data.SOA.pNamePrimaryServer =
492             dns_strcpyX( src->Data.SOA.pNamePrimaryServer, in, out );
493         if (!dst->Data.SOA.pNamePrimaryServer) goto error;
494 
495         dst->Data.SOA.pNameAdministrator =
496             dns_strcpyX( src->Data.SOA.pNameAdministrator, in, out );
497         if (!dst->Data.SOA.pNameAdministrator)
498         {
499             HeapFree( GetProcessHeap(), 0, dst->Data.SOA.pNamePrimaryServer );
500             goto error;
501         }
502         break;
503     }
504     case DNS_TYPE_SRV:
505     {
506         dst->Data.SRV.pNameTarget =
507             dns_strcpyX( src->Data.SRV.pNameTarget, in, out );
508         if (!dst->Data.SRV.pNameTarget) goto error;
509         break;
510     }
511     default:
512         break;
513     }
514     return dst;
515 
516 error:
517     HeapFree( GetProcessHeap(), 0, dst->pName );
518     HeapFree( GetProcessHeap(), 0, dst );
519     return NULL;
520 }
521 
522 /******************************************************************************
523  * DnsRecordListFree                       [DNSAPI.@]
524  *
525  */
526 VOID WINAPI DnsRecordListFree( PDNS_RECORD list, DNS_FREE_TYPE type )
527 {
528     DNS_RECORD *r, *next;
529     unsigned int i;
530 
531     DPRINT( "(%p,%d)\n", list, type );
532 
533     if (!list) return;
534 
535     switch (type)
536     {
537     case DnsFreeRecordList:
538     {
539         for (r = list; (list = r); r = next)
540         {
541             HeapFree( GetProcessHeap(), 0, r->pName );
542 
543             switch (r->wType)
544             {
545             case DNS_TYPE_HINFO:
546             case DNS_TYPE_ISDN:
547             case DNS_TYPE_TEXT:
548             case DNS_TYPE_X25:
549             {
550                 for (i = 0; i < r->Data.TXT.dwStringCount; i++)
551                     HeapFree( GetProcessHeap(), 0, r->Data.TXT.pStringArray[i] );
552 
553                 break;
554             }
555             case DNS_TYPE_MINFO:
556             case DNS_TYPE_RP:
557             {
558                 HeapFree( GetProcessHeap(), 0, r->Data.MINFO.pNameMailbox );
559                 HeapFree( GetProcessHeap(), 0, r->Data.MINFO.pNameErrorsMailbox );
560                 break;
561             }
562             case DNS_TYPE_AFSDB:
563             case DNS_TYPE_RT:
564             case DNS_TYPE_MX:
565             {
566                 HeapFree( GetProcessHeap(), 0, r->Data.MX.pNameExchange );
567                 break;
568             }
569             case DNS_TYPE_NXT:
570             {
571                 HeapFree( GetProcessHeap(), 0, r->Data.NXT.pNameNext );
572                 break;
573             }
574             case DNS_TYPE_CNAME:
575             case DNS_TYPE_MB:
576             case DNS_TYPE_MD:
577             case DNS_TYPE_MF:
578             case DNS_TYPE_MG:
579             case DNS_TYPE_MR:
580             case DNS_TYPE_NS:
581             case DNS_TYPE_PTR:
582             {
583                 HeapFree( GetProcessHeap(), 0, r->Data.PTR.pNameHost );
584                 break;
585             }
586             case DNS_TYPE_SIG:
587             {
588                 HeapFree( GetProcessHeap(), 0, r->Data.SIG.pNameSigner );
589                 break;
590             }
591             case DNS_TYPE_SOA:
592             {
593                 HeapFree( GetProcessHeap(), 0, r->Data.SOA.pNamePrimaryServer );
594                 HeapFree( GetProcessHeap(), 0, r->Data.SOA.pNameAdministrator );
595                 break;
596             }
597             case DNS_TYPE_SRV:
598             {
599                 HeapFree( GetProcessHeap(), 0, r->Data.SRV.pNameTarget );
600                 break;
601             }
602             default:
603                 break;
604             }
605 
606             next = r->pNext;
607             HeapFree( GetProcessHeap(), 0, r );
608         }
609         break;
610     }
611     case DnsFreeFlat:
612     case DnsFreeParsedMessageFields:
613     {
614         DPRINT1( "unhandled free type: %d\n", type );
615         break;
616     }
617     default:
618         DPRINT1( "unknown free type: %d\n", type );
619         break;
620     }
621 }
622 
623 /******************************************************************************
624  * DnsRecordSetCompare                     [DNSAPI.@]
625  *
626  */
627 BOOL WINAPI DnsRecordSetCompare( PDNS_RECORD set1, PDNS_RECORD set2,
628                                  PDNS_RECORD *diff1, PDNS_RECORD *diff2 )
629 {
630     BOOL ret = TRUE;
631     DNS_RECORD *r, *t, *u;
632     DNS_RRSET rr1, rr2;
633 
634     DPRINT( "(%p,%p,%p,%p)\n", set1, set2, diff1, diff2 );
635 
636     if (!set1 && !set2) return FALSE;
637 
638     if (diff1) *diff1 = NULL;
639     if (diff2) *diff2 = NULL;
640 
641     if (set1 && !set2)
642     {
643         if (diff1) *diff1 = DnsRecordSetCopyEx( set1, 0, set1->Flags.S.CharSet );
644         return FALSE;
645     }
646     if (!set1 && set2)
647     {
648         if (diff2) *diff2 = DnsRecordSetCopyEx( set2, 0, set2->Flags.S.CharSet );
649         return FALSE;
650     }
651 
652     DNS_RRSET_INIT( rr1 );
653     DNS_RRSET_INIT( rr2 );
654 
655     for (r = set1; r; r = r->pNext)
656     {
657         for (t = set2; t; t = t->pNext)
658         {
659             u = DnsRecordCopyEx( r, r->Flags.S.CharSet, t->Flags.S.CharSet );
660             if (!u) goto error;
661 
662             if (!DnsRecordCompare( t, u ))
663             {
664                 DNS_RRSET_ADD( rr1, u );
665                 ret = FALSE;
666             }
667             else DnsRecordListFree( u, DnsFreeRecordList );
668         }
669     }
670 
671     for (t = set2; t; t = t->pNext)
672     {
673         for (r = set1; r; r = r->pNext)
674         {
675             u = DnsRecordCopyEx( t, t->Flags.S.CharSet, r->Flags.S.CharSet );
676             if (!u) goto error;
677 
678             if (!DnsRecordCompare( r, u ))
679             {
680                 DNS_RRSET_ADD( rr2, u );
681                 ret = FALSE;
682             }
683             else DnsRecordListFree( u, DnsFreeRecordList );
684         }
685     }
686 
687     DNS_RRSET_TERMINATE( rr1 );
688     DNS_RRSET_TERMINATE( rr2 );
689 
690     if (diff1) *diff1 = rr1.pFirstRR;
691     else DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
692 
693     if (diff2) *diff2 = rr2.pFirstRR;
694     else DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
695 
696     return ret;
697 
698 error:
699     DNS_RRSET_TERMINATE( rr1 );
700     DNS_RRSET_TERMINATE( rr2 );
701 
702     DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
703     DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
704 
705     return FALSE;
706 }
707 
708 /******************************************************************************
709  * DnsRecordSetCopyEx                      [DNSAPI.@]
710  *
711  */
712 PDNS_RECORD WINAPI DnsRecordSetCopyEx( PDNS_RECORD src_set, DNS_CHARSET in, DNS_CHARSET out )
713 {
714     DNS_RRSET dst_set;
715     DNS_RECORD *src, *dst;
716 
717     DPRINT( "(%p,%d,%d)\n", src_set, in, out );
718 
719     DNS_RRSET_INIT( dst_set );
720 
721     for (src = src_set; (src_set = src); src = src_set->pNext)
722     {
723         dst = DnsRecordCopyEx( src, in, out );
724         if (!dst)
725         {
726             DNS_RRSET_TERMINATE( dst_set );
727             DnsRecordListFree( dst_set.pFirstRR, DnsFreeRecordList );
728             return NULL;
729         }
730         DNS_RRSET_ADD( dst_set, dst );
731     }
732 
733     DNS_RRSET_TERMINATE( dst_set );
734     return dst_set.pFirstRR;
735 }
736 
737 /******************************************************************************
738  * DnsRecordSetDetach                      [DNSAPI.@]
739  *
740  */
741 PDNS_RECORD WINAPI DnsRecordSetDetach( PDNS_RECORD set )
742 {
743     DNS_RECORD *r, *s;
744 
745     DPRINT( "(%p)\n", set );
746 
747     for (r = set; (set = r); r = set->pNext)
748     {
749         if (r->pNext && !r->pNext->pNext)
750         {
751             s = r->pNext;
752             r->pNext = NULL;
753             return s;
754         }
755     }
756     return NULL;
757 }
758