cmd: DIR command outputs free space for the path.
[wine.git] / dlls / dnsapi / record.c
blob01786842b738a10e5ad6dbccd9b5a7714de0387f
1 /*
2 * DNS support
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
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "windns.h"
28 #include "wine/debug.h"
29 #include "dnsapi.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
33 const char *debugstr_type( unsigned short type )
35 switch (type)
37 #define X(x) case (x): return #x;
38 X(DNS_TYPE_ZERO)
39 X(DNS_TYPE_A)
40 X(DNS_TYPE_NS)
41 X(DNS_TYPE_MD)
42 X(DNS_TYPE_MF)
43 X(DNS_TYPE_CNAME)
44 X(DNS_TYPE_SOA)
45 X(DNS_TYPE_MB)
46 X(DNS_TYPE_MG)
47 X(DNS_TYPE_MR)
48 X(DNS_TYPE_NULL)
49 X(DNS_TYPE_WKS)
50 X(DNS_TYPE_PTR)
51 X(DNS_TYPE_HINFO)
52 X(DNS_TYPE_MINFO)
53 X(DNS_TYPE_MX)
54 X(DNS_TYPE_TEXT)
55 X(DNS_TYPE_RP)
56 X(DNS_TYPE_AFSDB)
57 X(DNS_TYPE_X25)
58 X(DNS_TYPE_ISDN)
59 X(DNS_TYPE_RT)
60 X(DNS_TYPE_NSAP)
61 X(DNS_TYPE_NSAPPTR)
62 X(DNS_TYPE_SIG)
63 X(DNS_TYPE_KEY)
64 X(DNS_TYPE_PX)
65 X(DNS_TYPE_GPOS)
66 X(DNS_TYPE_AAAA)
67 X(DNS_TYPE_LOC)
68 X(DNS_TYPE_NXT)
69 X(DNS_TYPE_EID)
70 X(DNS_TYPE_NIMLOC)
71 X(DNS_TYPE_SRV)
72 X(DNS_TYPE_ATMA)
73 X(DNS_TYPE_NAPTR)
74 X(DNS_TYPE_KX)
75 X(DNS_TYPE_CERT)
76 X(DNS_TYPE_A6)
77 X(DNS_TYPE_DNAME)
78 X(DNS_TYPE_SINK)
79 X(DNS_TYPE_OPT)
80 X(DNS_TYPE_UINFO)
81 X(DNS_TYPE_UID)
82 X(DNS_TYPE_GID)
83 X(DNS_TYPE_UNSPEC)
84 X(DNS_TYPE_ADDRS)
85 X(DNS_TYPE_TKEY)
86 X(DNS_TYPE_TSIG)
87 X(DNS_TYPE_IXFR)
88 X(DNS_TYPE_AXFR)
89 X(DNS_TYPE_MAILB)
90 X(DNS_TYPE_MAILA)
91 X(DNS_TYPE_ANY)
92 X(DNS_TYPE_WINS)
93 X(DNS_TYPE_WINSR)
94 #undef X
95 default: return wine_dbg_sprintf( "0x%04x", type );
99 static const char *debugstr_section( DNS_SECTION section )
101 switch (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 )
113 if (wide)
114 return lstrcmpiW( str1, str2 );
115 else
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);
123 return ret;
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);
130 return ret;
133 static const BYTE *skip_name( const BYTE *ptr, const BYTE *end )
135 BYTE len;
137 while (ptr < end && (len = *ptr++))
139 switch (len & 0xc0)
141 case 0:
142 ptr += len;
143 continue;
144 case 0xc0:
145 ptr++;
146 break;
147 default:
148 return NULL;
150 break;
152 if (ptr < end) return ptr;
153 return NULL;
156 static const BYTE *skip_record( const BYTE *ptr, const BYTE *end, DNS_SECTION section )
158 WORD len;
160 if (!(ptr = skip_name( ptr, end ))) return NULL;
161 ptr += 2; /* type */
162 ptr += 2; /* class */
163 if (section != DnsSectionQuestion)
165 ptr += 4; /* ttl */
166 if (ptr + 2 > end) return NULL;
167 len = get_word( &ptr );
168 ptr += len;
170 if (ptr > end) return NULL;
171 return ptr;
174 static const BYTE *get_name( const BYTE *base, const BYTE *end, const BYTE *ptr,
175 char name[DNS_MAX_NAME_BUFFER_LENGTH] )
177 BYTE len;
178 char *out = name;
179 const BYTE *next = NULL;
180 int loop = 0;
182 while (ptr < end && (len = *ptr++))
184 switch (len & 0xc0)
186 case 0:
187 if (out + len + 1 >= name + DNS_MAX_NAME_BUFFER_LENGTH) return NULL;
188 if (out > name) *out++ = '.';
189 memcpy( out, ptr, len );
190 out += len;
191 ptr += len;
192 continue;
193 case 0xc0:
194 if (!next) next = ptr + 1;
195 if (++loop >= end - base) return NULL;
196 if (ptr < end) ptr = base + ((len & 0x3f) << 8) + *ptr;
197 break;
198 default:
199 return NULL;
202 if (ptr >= end) return NULL;
203 if (out == name) *out++ = '.';
204 *out = 0;
205 return next ? next : ptr;
208 /******************************************************************************
209 * DnsRecordCompare [DNSAPI.@]
212 BOOL WINAPI DnsRecordCompare( PDNS_RECORD r1, PDNS_RECORD r2 )
214 BOOL wide;
215 unsigned int i;
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;
230 switch (r1->wType)
232 case DNS_TYPE_A:
234 if (r1->Data.A.IpAddress != r2->Data.A.IpAddress) return FALSE;
235 break;
237 case DNS_TYPE_SOA:
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)
244 return FALSE;
245 if (strcmpX( r1->Data.SOA.pNamePrimaryServer, r2->Data.SOA.pNamePrimaryServer, wide ) ||
246 strcmpX( r1->Data.SOA.pNameAdministrator, r2->Data.SOA.pNameAdministrator, wide ))
247 return FALSE;
248 break;
250 case DNS_TYPE_PTR:
251 case DNS_TYPE_NS:
252 case DNS_TYPE_CNAME:
253 case DNS_TYPE_MB:
254 case DNS_TYPE_MD:
255 case DNS_TYPE_MF:
256 case DNS_TYPE_MG:
257 case DNS_TYPE_MR:
259 if (strcmpX( r1->Data.PTR.pNameHost, r2->Data.PTR.pNameHost, wide )) return FALSE;
260 break;
262 case DNS_TYPE_MINFO:
263 case DNS_TYPE_RP:
265 if (strcmpX( r1->Data.MINFO.pNameMailbox, r2->Data.MINFO.pNameMailbox, wide ) ||
266 strcmpX( r1->Data.MINFO.pNameErrorsMailbox, r2->Data.MINFO.pNameErrorsMailbox, wide ))
267 return FALSE;
268 break;
270 case DNS_TYPE_MX:
271 case DNS_TYPE_AFSDB:
272 case DNS_TYPE_RT:
274 if (r1->Data.MX.wPreference != r2->Data.MX.wPreference)
275 return FALSE;
276 if (strcmpX( r1->Data.MX.pNameExchange, r2->Data.MX.pNameExchange, wide ))
277 return FALSE;
278 break;
280 case DNS_TYPE_HINFO:
281 case DNS_TYPE_ISDN:
282 case DNS_TYPE_TEXT:
283 case DNS_TYPE_X25:
285 if (r1->Data.TXT.dwStringCount != r2->Data.TXT.dwStringCount)
286 return FALSE;
287 for (i = 0; i < r1->Data.TXT.dwStringCount; i++)
289 if (strcmpX( r1->Data.TXT.pStringArray[i], r2->Data.TXT.pStringArray[i], wide ))
290 return FALSE;
292 break;
294 case DNS_TYPE_NULL:
296 if (r1->Data.Null.dwByteCount != r2->Data.Null.dwByteCount)
297 return FALSE;
298 if (memcmp( r1->Data.Null.Data,
299 r2->Data.Null.Data, r1->Data.Null.dwByteCount ))
300 return FALSE;
301 break;
303 case DNS_TYPE_OPT:
305 if (r1->Data.Opt.wDataLength != r2->Data.Opt.wDataLength)
306 return FALSE;
307 /* ignore wPad */
308 if (memcmp( r1->Data.Opt.Data,
309 r2->Data.Opt.Data, r1->Data.Opt.wDataLength ))
310 return FALSE;
311 break;
313 case DNS_TYPE_AAAA:
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;
320 break;
322 case DNS_TYPE_KEY:
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)
328 return FALSE;
329 if (memcmp( r1->Data.KEY.Key, r2->Data.KEY.Key, r1->Data.KEY.wKeyLength ))
330 return FALSE;
331 break;
333 case DNS_TYPE_SIG:
335 if (strcmpX( r1->Data.SIG.pNameSigner, r2->Data.SIG.pNameSigner, wide ))
336 return FALSE;
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)
345 return FALSE;
346 if (memcmp( r1->Data.SIG.Signature, r2->Data.SIG.Signature, r1->Data.SIG.wSignatureLength ))
347 return FALSE;
348 break;
350 case DNS_TYPE_ATMA:
352 if (r1->Data.ATMA.AddressType != r2->Data.ATMA.AddressType)
353 return FALSE;
354 for (i = 0; i < DNS_ATMA_MAX_ADDR_LENGTH; i++)
356 if (r1->Data.ATMA.Address[i] != r2->Data.ATMA.Address[i])
357 return FALSE;
359 break;
361 case DNS_TYPE_NXT:
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) ))
367 return FALSE;
368 break;
370 case DNS_TYPE_SRV:
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)
376 return FALSE;
377 break;
379 case DNS_TYPE_TKEY:
381 if (strcmpX( r1->Data.TKEY.pNameAlgorithm, r2->Data.TKEY.pNameAlgorithm, wide ))
382 return FALSE;
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)
391 return FALSE;
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;
398 break;
400 case DNS_TYPE_TSIG:
402 if (strcmpX( r1->Data.TSIG.pNameAlgorithm, r2->Data.TSIG.pNameAlgorithm, wide ))
403 return FALSE;
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)
412 return FALSE;
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;
419 break;
421 case DNS_TYPE_WINS:
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)
427 return FALSE;
428 if (memcmp( r1->Data.WINS.WinsServers, r2->Data.WINS.WinsServers,
429 r1->wDataLength - sizeof(DNS_WINS_DATA) + sizeof(IP4_ADDRESS) ))
430 return FALSE;
431 break;
433 case DNS_TYPE_WINSR:
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)
438 return FALSE;
439 if (strcmpX( r1->Data.WINSR.pNameResultDomain, r2->Data.WINSR.pNameResultDomain, wide ))
440 return FALSE;
441 break;
443 default:
444 FIXME( "unknown type: %s\n", debugstr_type( r1->wType ) );
445 return FALSE;
447 return TRUE;
450 static LPVOID strdupX( LPCVOID src, DNS_CHARSET in, DNS_CHARSET out )
452 switch (in)
454 case DnsCharSetUnicode:
456 switch (out)
458 case DnsCharSetUnicode: return wcsdup( src );
459 case DnsCharSetUtf8: return strdup_wu( src );
460 case DnsCharSetAnsi: return strdup_wa( src );
461 default:
462 WARN( "unhandled target charset: %d\n", out );
463 break;
465 break;
467 case DnsCharSetUtf8:
468 switch (out)
470 case DnsCharSetUnicode: return strdup_uw( src );
471 case DnsCharSetUtf8: return strdup( src );
472 case DnsCharSetAnsi: return strdup_ua( src );
473 default:
474 WARN( "unhandled target charset: %d\n", out );
475 break;
477 break;
478 case DnsCharSetAnsi:
479 switch (out)
481 case DnsCharSetUnicode: return strdup_aw( src );
482 case DnsCharSetUtf8: return strdup_au( src );
483 case DnsCharSetAnsi: return strdup( src );
484 default:
485 WARN( "unhandled target charset: %d\n", out );
486 break;
488 break;
489 default:
490 WARN( "unhandled source charset: %d\n", in );
491 break;
493 return NULL;
496 /******************************************************************************
497 * DnsRecordCopyEx [DNSAPI.@]
500 PDNS_RECORD WINAPI DnsRecordCopyEx( PDNS_RECORD src, DNS_CHARSET in, DNS_CHARSET out )
502 DNS_RECORD *dst;
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;
521 switch (src->wType)
523 case DNS_TYPE_HINFO:
524 case DNS_TYPE_ISDN:
525 case DNS_TYPE_TEXT:
526 case DNS_TYPE_X25:
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] );
534 goto error;
537 break;
539 case DNS_TYPE_MINFO:
540 case DNS_TYPE_RP:
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 );
549 goto error;
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);
556 break;
558 case DNS_TYPE_AFSDB:
559 case DNS_TYPE_RT:
560 case DNS_TYPE_MX:
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);
568 break;
570 case DNS_TYPE_NXT:
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);
578 break;
580 case DNS_TYPE_CNAME:
581 case DNS_TYPE_MB:
582 case DNS_TYPE_MD:
583 case DNS_TYPE_MF:
584 case DNS_TYPE_MG:
585 case DNS_TYPE_MR:
586 case DNS_TYPE_NS:
587 case DNS_TYPE_PTR:
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);
595 break;
597 case DNS_TYPE_SIG:
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);
605 break;
607 case DNS_TYPE_SOA:
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 );
616 goto error;
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);
623 break;
625 case DNS_TYPE_SRV:
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);
633 break;
635 default:
636 break;
638 return dst;
640 error:
641 free( dst->pName );
642 free( dst );
643 return NULL;
646 /******************************************************************************
647 * DnsRecordListFree [DNSAPI.@]
650 VOID WINAPI DnsRecordListFree( PDNS_RECORD list, DNS_FREE_TYPE type )
652 DNS_RECORD *r, *next;
653 unsigned int i;
655 TRACE( "(%p,%d)\n", list, type );
657 if (!list) return;
659 switch (type)
661 case DnsFreeRecordList:
663 for (r = list; (list = r); r = next)
665 free( r->pName );
667 switch (r->wType)
669 case DNS_TYPE_HINFO:
670 case DNS_TYPE_ISDN:
671 case DNS_TYPE_TEXT:
672 case DNS_TYPE_X25:
673 for (i = 0; i < r->Data.TXT.dwStringCount; i++)
674 free( r->Data.TXT.pStringArray[i] );
676 break;
678 case DNS_TYPE_MINFO:
679 case DNS_TYPE_RP:
680 free( r->Data.MINFO.pNameMailbox );
681 free( r->Data.MINFO.pNameErrorsMailbox );
682 break;
684 case DNS_TYPE_AFSDB:
685 case DNS_TYPE_RT:
686 case DNS_TYPE_MX:
687 free( r->Data.MX.pNameExchange );
688 break;
690 case DNS_TYPE_NXT:
691 free( r->Data.NXT.pNameNext );
692 break;
694 case DNS_TYPE_CNAME:
695 case DNS_TYPE_MB:
696 case DNS_TYPE_MD:
697 case DNS_TYPE_MF:
698 case DNS_TYPE_MG:
699 case DNS_TYPE_MR:
700 case DNS_TYPE_NS:
701 case DNS_TYPE_PTR:
702 free( r->Data.PTR.pNameHost );
703 break;
705 case DNS_TYPE_SIG:
706 free( r->Data.SIG.pNameSigner );
707 break;
709 case DNS_TYPE_SOA:
710 free( r->Data.SOA.pNamePrimaryServer );
711 free( r->Data.SOA.pNameAdministrator );
712 break;
714 case DNS_TYPE_SRV:
715 free( r->Data.SRV.pNameTarget );
716 break;
719 next = r->pNext;
720 free( r );
722 break;
724 case DnsFreeFlat:
725 case DnsFreeParsedMessageFields:
727 FIXME( "unhandled free type: %d\n", type );
728 break;
730 default:
731 WARN( "unknown free type: %d\n", type );
732 break;
736 /******************************************************************************
737 * DnsFree [DNSAPI.@]
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 )
752 BOOL ret = TRUE;
753 DNS_RECORD *r, *t, *u;
754 DNS_RRSET rr1, rr2;
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;
763 if (set1 && !set2)
765 if (diff1) *diff1 = DnsRecordSetCopyEx( set1, 0, set1->Flags.S.CharSet );
766 return FALSE;
768 if (!set1 && set2)
770 if (diff2) *diff2 = DnsRecordSetCopyEx( set2, 0, set2->Flags.S.CharSet );
771 return FALSE;
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 );
782 if (!u) goto error;
784 if (!DnsRecordCompare( t, u ))
786 DNS_RRSET_ADD( rr1, u );
787 ret = FALSE;
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 );
798 if (!u) goto error;
800 if (!DnsRecordCompare( r, u ))
802 DNS_RRSET_ADD( rr2, u );
803 ret = FALSE;
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 );
818 return ret;
820 error:
821 DNS_RRSET_TERMINATE( rr1 );
822 DNS_RRSET_TERMINATE( rr2 );
824 DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
825 DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
827 return FALSE;
830 /******************************************************************************
831 * DnsRecordSetCopyEx [DNSAPI.@]
834 PDNS_RECORD WINAPI DnsRecordSetCopyEx( PDNS_RECORD src_set, DNS_CHARSET in, DNS_CHARSET out )
836 DNS_RRSET dst_set;
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 );
846 if (!dst)
848 DNS_RRSET_TERMINATE( dst_set );
849 DnsRecordListFree( dst_set.pFirstRR, DnsFreeRecordList );
850 return NULL;
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 )
865 DNS_RECORD *r, *s;
867 TRACE( "(%p)\n", set );
869 for (r = set; (set = r); r = set->pNext)
871 if (r->pNext && !r->pNext->pNext)
873 s = r->pNext;
874 r->pNext = NULL;
875 return s;
878 return NULL;
882 static unsigned int get_record_size( WORD type, const BYTE *data, WORD len )
884 switch (type)
886 case DNS_TYPE_KEY:
887 return offsetof( DNS_RECORDA, Data.Key.Key[len] );
889 case DNS_TYPE_SIG:
890 return offsetof( DNS_RECORDA, Data.Sig.Signature[len] );
892 case DNS_TYPE_HINFO:
893 case DNS_TYPE_ISDN:
894 case DNS_TYPE_TEXT:
895 case DNS_TYPE_X25:
897 int i;
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] );
903 case DNS_TYPE_NULL:
904 case DNS_TYPE_OPT:
905 return offsetof( DNS_RECORDA, Data.Null.Data[len] );
907 case DNS_TYPE_WKS:
908 return offsetof( DNS_RECORDA, Data.Wks.BitMask[len / 8] );
910 case DNS_TYPE_NXT:
911 return offsetof( DNS_RECORDA, Data.Nxt.wTypes[len * 8] );
913 case DNS_TYPE_WINS:
914 return offsetof( DNS_RECORDA, Data.Wins.WinsServers[len / 4] );
916 default:
917 return sizeof(DNS_RECORDA);
921 static DNS_STATUS extract_rdata( const BYTE *base, const BYTE *end, const BYTE *pos, WORD len, WORD type,
922 DNS_RECORDA *r )
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;
928 unsigned int i;
930 switch (type)
932 case DNS_TYPE_A:
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);
936 break;
938 case DNS_TYPE_AAAA:
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);
946 break;
948 case DNS_TYPE_KEY:
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] );
956 break;
958 case DNS_TYPE_RP:
959 case DNS_TYPE_MINFO:
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);
969 break;
971 case DNS_TYPE_AFSDB:
972 case DNS_TYPE_RT:
973 case DNS_TYPE_MX:
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);
979 break;
981 case DNS_TYPE_NULL:
982 r->Data.Null.dwByteCount = len;
983 memcpy( r->Data.Null.Data, pos, len );
984 r->wDataLength = offsetof( DNS_NULL_DATA, Data[len] );
985 break;
987 case DNS_TYPE_OPT:
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] );
992 break;
994 case DNS_TYPE_CNAME:
995 case DNS_TYPE_NS:
996 case DNS_TYPE_MB:
997 case DNS_TYPE_MD:
998 case DNS_TYPE_MF:
999 case DNS_TYPE_MG:
1000 case DNS_TYPE_MR:
1001 case DNS_TYPE_PTR:
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);
1005 break;
1007 case DNS_TYPE_SIG:
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] );
1021 break;
1023 case DNS_TYPE_SOA:
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);
1039 break;
1041 case DNS_TYPE_SRV:
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);
1049 break;
1051 case DNS_TYPE_HINFO:
1052 case DNS_TYPE_ISDN:
1053 case DNS_TYPE_X25:
1054 case DNS_TYPE_TEXT:
1055 for (i = 0; pos < rrend; i++)
1057 BYTE len = pos[0];
1058 if (pos + len + 1 > rrend) return DNS_ERROR_BAD_PACKET;
1059 memcpy( name, pos + 1, len );
1060 name[len] = 0;
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;
1066 pos += len + 1;
1068 r->Data.TXT.dwStringCount = i;
1069 r->wDataLength = offsetof( DNS_TXT_DATAA, pStringArray[r->Data.TXT.dwStringCount] );
1070 break;
1072 case DNS_TYPE_ATMA:
1073 case DNS_TYPE_LOC:
1074 case DNS_TYPE_NXT:
1075 case DNS_TYPE_TSIG:
1076 case DNS_TYPE_WKS:
1077 case DNS_TYPE_TKEY:
1078 case DNS_TYPE_WINS:
1079 case DNS_TYPE_WINSR:
1080 default:
1081 FIXME( "unhandled type: %s\n", debugstr_type( type ));
1082 return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
1085 return ret;
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 )
1091 DNS_STATUS ret;
1092 DNS_RECORDA *record;
1093 char name[DNS_MAX_NAME_BUFFER_LENGTH];
1094 WORD type, rdlen;
1095 DWORD ttl;
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;
1107 *pos = ptr + rdlen;
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 )))
1118 free( record );
1119 return ERROR_NOT_ENOUGH_MEMORY;
1121 if ((ret = extract_rdata( base, end, ptr, rdlen, type, record )))
1123 free( record->pName );
1124 free( record );
1125 return ret;
1127 *recp = record;
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,
1133 DNS_RRSET *rrset )
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;
1141 unsigned int num;
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 )))
1151 return ret;
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;
1165 return ret;
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;
1176 DNS_RRSET rrset;
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 );
1187 return ret;
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;
1198 DNS_RRSET rrset;
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 );
1209 return ret;