[DNSAPI] Set proper record flags for query results and converted records
[reactos.git] / dll / win32 / dnsapi / query.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/dnsapi/dnsapi/query.c
5 * PURPOSE: DNSAPI functions built on the ADNS library.
6 * PROGRAMER: Art Yerkes
7 * UPDATE HISTORY:
8 * 12/15/03 -- Created
9 */
10
11 #include "precomp.h"
12 #include <winreg.h>
13 #include <iphlpapi.h>
14 #include <strsafe.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19
20 /* DnsQuery ****************************
21 * Begin a DNS query, and allow the result to be placed in the application
22 * supplied result pointer. The result can be manipulated with the record
23 * functions.
24 *
25 * Name -- The DNS object to be queried.
26 * Type -- The type of records to be returned. These are
27 * listed in windns.h
28 * Options -- Query options. DNS_QUERY_STANDARD is the base
29 * state, and every other option takes precedence.
30 * multiple options can be combined. Listed in
31 * windns.h
32 * Servers -- List of alternate servers (optional)
33 * QueryResultSet -- Pointer to the result pointer that will be filled
34 * when the response is available.
35 * Reserved -- Response as it appears on the wire. Optional.
36 */
37
38 static PCHAR
39 DnsWToC(const WCHAR *WideString)
40 {
41 PCHAR AnsiString;
42 int AnsiLen = WideCharToMultiByte(CP_ACP,
43 0,
44 WideString,
45 -1,
46 NULL,
47 0,
48 NULL,
49 0);
50 if (AnsiLen == 0)
51 return NULL;
52 AnsiString = RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen);
53 if (AnsiString == NULL)
54 {
55 return NULL;
56 }
57 WideCharToMultiByte(CP_ACP,
58 0,
59 WideString,
60 -1,
61 AnsiString,
62 AnsiLen,
63 NULL,
64 0);
65
66 return AnsiString;
67 }
68
69 static PWCHAR
70 DnsCToW(const CHAR *NarrowString)
71 {
72 PWCHAR WideString;
73 int WideLen = MultiByteToWideChar(CP_ACP,
74 0,
75 NarrowString,
76 -1,
77 NULL,
78 0);
79 if (WideLen == 0)
80 return NULL;
81 WideString = RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen * sizeof(WCHAR));
82 if (WideString == NULL)
83 {
84 return NULL;
85 }
86 MultiByteToWideChar(CP_ACP,
87 0,
88 NarrowString,
89 -1,
90 WideString,
91 WideLen);
92
93 return WideString;
94 }
95
96 static PCHAR
97 DnsWToUTF8(const WCHAR *WideString)
98 {
99 PCHAR AnsiString;
100 int AnsiLen = WideCharToMultiByte(CP_UTF8,
101 0,
102 WideString,
103 -1,
104 NULL,
105 0,
106 NULL,
107 0);
108 if (AnsiLen == 0)
109 return NULL;
110 AnsiString = RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen);
111 if (AnsiString == NULL)
112 {
113 return NULL;
114 }
115 WideCharToMultiByte(CP_UTF8,
116 0,
117 WideString,
118 -1,
119 AnsiString,
120 AnsiLen,
121 NULL,
122 0);
123
124 return AnsiString;
125 }
126
127 static PWCHAR
128 DnsUTF8ToW(const CHAR *NarrowString)
129 {
130 PWCHAR WideString;
131 int WideLen = MultiByteToWideChar(CP_UTF8,
132 0,
133 NarrowString,
134 -1,
135 NULL,
136 0);
137 if (WideLen == 0)
138 return NULL;
139 WideString = RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen * sizeof(WCHAR));
140 if (WideString == NULL)
141 {
142 return NULL;
143 }
144 MultiByteToWideChar(CP_UTF8,
145 0,
146 NarrowString,
147 -1,
148 WideString,
149 WideLen);
150
151 return WideString;
152 }
153
154 DNS_STATUS WINAPI
155 DnsQuery_CodePage(UINT CodePage,
156 LPCSTR Name,
157 WORD Type,
158 DWORD Options,
159 PVOID Extra,
160 PDNS_RECORD *QueryResultSet,
161 PVOID *Reserved)
162 {
163 UINT i;
164 PWCHAR Buffer;
165 DNS_STATUS Status;
166 PDNS_RECORD QueryResultWide;
167 PDNS_RECORD ConvertedRecord = 0, LastRecord = 0;
168
169 if (Name == NULL)
170 return ERROR_INVALID_PARAMETER;
171 if (QueryResultSet == NULL)
172 return ERROR_INVALID_PARAMETER;
173
174 switch (CodePage)
175 {
176 case CP_ACP:
177 Buffer = DnsCToW(Name);
178 break;
179
180 case CP_UTF8:
181 Buffer = DnsUTF8ToW(Name);
182 break;
183
184 default:
185 return ERROR_INVALID_PARAMETER;
186 }
187
188 Status = DnsQuery_W(Buffer, Type, Options, Extra, &QueryResultWide, Reserved);
189
190 while (Status == ERROR_SUCCESS && QueryResultWide)
191 {
192 switch (QueryResultWide->wType)
193 {
194 case DNS_TYPE_A:
195 case DNS_TYPE_WKS:
196 case DNS_TYPE_CNAME:
197 case DNS_TYPE_PTR:
198 case DNS_TYPE_NS:
199 case DNS_TYPE_MB:
200 case DNS_TYPE_MD:
201 case DNS_TYPE_MF:
202 case DNS_TYPE_MG:
203 case DNS_TYPE_MR:
204 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
205 break;
206
207 case DNS_TYPE_MINFO:
208 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATA) + QueryResultWide->Data.TXT.dwStringCount);
209 break;
210
211 case DNS_TYPE_NULL:
212 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount);
213 break;
214 }
215 if (ConvertedRecord == NULL)
216 {
217 /* The name */
218 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
219 /* The result*/
220 DnsIntFreeRecordList(QueryResultWide);
221 QueryResultSet = NULL;
222 return ERROR_OUTOFMEMORY;
223 }
224
225 if (CodePage == CP_ACP)
226 {
227 ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName);
228 ConvertedRecord->Flags.S.CharSet = DnsCharSetAnsi;
229 }
230 else
231 {
232 ConvertedRecord->pName = DnsWToUTF8((PWCHAR)QueryResultWide->pName);
233 ConvertedRecord->Flags.S.CharSet = DnsCharSetUtf8;
234 }
235
236 ConvertedRecord->wType = QueryResultWide->wType;
237
238 switch (QueryResultWide->wType)
239 {
240 case DNS_TYPE_A:
241 case DNS_TYPE_WKS:
242 ConvertedRecord->wDataLength = QueryResultWide->wDataLength;
243 memcpy(&ConvertedRecord->Data, &QueryResultWide->Data, QueryResultWide->wDataLength);
244 break;
245
246 case DNS_TYPE_CNAME:
247 case DNS_TYPE_PTR:
248 case DNS_TYPE_NS:
249 case DNS_TYPE_MB:
250 case DNS_TYPE_MD:
251 case DNS_TYPE_MF:
252 case DNS_TYPE_MG:
253 case DNS_TYPE_MR:
254 ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATA);
255 if (CodePage == CP_ACP)
256 ConvertedRecord->Data.PTR.pNameHost = DnsWToC((PWCHAR)QueryResultWide->Data.PTR.pNameHost);
257 else
258 ConvertedRecord->Data.PTR.pNameHost = DnsWToUTF8((PWCHAR)QueryResultWide->Data.PTR.pNameHost);
259 break;
260
261 case DNS_TYPE_MINFO:
262 ConvertedRecord->wDataLength = sizeof(DNS_MINFO_DATA);
263 if (CodePage == CP_ACP)
264 {
265 ConvertedRecord->Data.MINFO.pNameMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameMailbox);
266 ConvertedRecord->Data.MINFO.pNameErrorsMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameErrorsMailbox);
267 }
268 else
269 {
270 ConvertedRecord->Data.MINFO.pNameMailbox = DnsWToUTF8((PWCHAR)QueryResultWide->Data.MINFO.pNameMailbox);
271 ConvertedRecord->Data.MINFO.pNameErrorsMailbox = DnsWToUTF8((PWCHAR)QueryResultWide->Data.MINFO.pNameErrorsMailbox);
272 }
273 break;
274
275 case DNS_TYPE_MX:
276 ConvertedRecord->wDataLength = sizeof(DNS_MX_DATA);
277 if (CodePage == CP_ACP)
278 ConvertedRecord->Data.MX.pNameExchange = DnsWToC((PWCHAR)QueryResultWide->Data.MX.pNameExchange);
279 else
280 ConvertedRecord->Data.MX.pNameExchange = DnsWToUTF8((PWCHAR)QueryResultWide->Data.MX.pNameExchange);
281 ConvertedRecord->Data.MX.wPreference = QueryResultWide->Data.MX.wPreference;
282 break;
283
284 case DNS_TYPE_HINFO:
285 ConvertedRecord->wDataLength = sizeof(DNS_TXT_DATA) + (sizeof(PCHAR) * QueryResultWide->Data.TXT.dwStringCount);
286 ConvertedRecord->Data.TXT.dwStringCount = QueryResultWide->Data.TXT.dwStringCount;
287
288 if (CodePage == CP_ACP)
289 for (i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++)
290 ConvertedRecord->Data.TXT.pStringArray[i] = DnsWToC((PWCHAR)QueryResultWide->Data.TXT.pStringArray[i]);
291 else
292 for (i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++)
293 ConvertedRecord->Data.TXT.pStringArray[i] = DnsWToUTF8((PWCHAR)QueryResultWide->Data.TXT.pStringArray[i]);
294
295 break;
296
297 case DNS_TYPE_NULL:
298 ConvertedRecord->wDataLength = sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount;
299 ConvertedRecord->Data.Null.dwByteCount = QueryResultWide->Data.Null.dwByteCount;
300 memcpy(&ConvertedRecord->Data.Null.Data, &QueryResultWide->Data.Null.Data, QueryResultWide->Data.Null.dwByteCount);
301 break;
302 }
303
304 if (LastRecord)
305 {
306 LastRecord->pNext = ConvertedRecord;
307 LastRecord = LastRecord->pNext;
308 }
309 else
310 {
311 LastRecord = *QueryResultSet = ConvertedRecord;
312 }
313
314 QueryResultWide = QueryResultWide->pNext;
315 }
316
317 if (LastRecord)
318 LastRecord->pNext = 0;
319
320 /* The name */
321 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
322 /* The result*/
323 if (QueryResultWide) DnsIntFreeRecordList(QueryResultWide);
324
325 return Status;
326 }
327
328 DNS_STATUS WINAPI
329 DnsQuery_A(LPCSTR Name,
330 WORD Type,
331 DWORD Options,
332 PVOID Extra,
333 PDNS_RECORD *QueryResultSet,
334 PVOID *Reserved)
335 {
336 return DnsQuery_CodePage(CP_ACP, Name, Type, Options, Extra, QueryResultSet, Reserved);
337 }
338
339 DNS_STATUS WINAPI
340 DnsQuery_UTF8(LPCSTR Name,
341 WORD Type,
342 DWORD Options,
343 PVOID Extra,
344 PDNS_RECORD *QueryResultSet,
345 PVOID *Reserved)
346 {
347 return DnsQuery_CodePage(CP_UTF8, Name, Type, Options, Extra, QueryResultSet, Reserved);
348 }
349
350 WCHAR
351 *xstrsave(const WCHAR *str)
352 {
353 WCHAR *p;
354 size_t len = 0;
355
356 /* FIXME: how much instead of MAX_PATH? */
357 StringCbLengthW(str, MAX_PATH, &len);
358 len+=sizeof(WCHAR);
359
360 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
361
362 if (p)
363 StringCbCopyW(p, len, str);
364
365 return p;
366 }
367
368 CHAR
369 *xstrsaveA(const CHAR *str)
370 {
371 CHAR *p;
372 size_t len = 0;
373
374 /* FIXME: how much instead of MAX_PATH? */
375 StringCbLengthA(str, MAX_PATH, &len);
376 len++;
377
378 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
379
380 if (p)
381 StringCbCopyA(p, len, str);
382
383 return p;
384 }
385
386
387 /* This function is far from perfect but it works enough */
388 IP4_ADDRESS
389 CheckForCurrentHostname(CONST CHAR * Name, PFIXED_INFO network_info)
390 {
391 PCHAR TempName;
392 DWORD AdapterAddressesSize, Status;
393 IP4_ADDRESS ret = 0, Address;
394 PIP_ADAPTER_ADDRESSES Addresses = NULL, pip;
395 BOOL Found = FALSE;
396
397 if (network_info->DomainName[0])
398 {
399 size_t StringLength;
400 size_t TempSize = 2;
401 StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength);
402 TempSize += StringLength;
403 StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength);
404 TempSize += StringLength;
405 TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, TempSize);
406 StringCchCopyA(TempName, TempSize, network_info->HostName);
407 StringCchCatA(TempName, TempSize, ".");
408 StringCchCatA(TempName, TempSize, network_info->DomainName);
409 }
410 else
411 {
412 TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, 1);
413 TempName[0] = 0;
414 }
415 Found = !stricmp(Name, network_info->HostName) || !stricmp(Name, TempName);
416 RtlFreeHeap(RtlGetProcessHeap(), 0, TempName);
417 if (!Found)
418 {
419 return 0;
420 }
421 /* get adapter info */
422 AdapterAddressesSize = 0;
423 GetAdaptersAddresses(AF_INET,
424 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
425 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
426 NULL,
427 Addresses,
428 &AdapterAddressesSize);
429 if (!AdapterAddressesSize)
430 {
431 return 0;
432 }
433 Addresses = RtlAllocateHeap(RtlGetProcessHeap(), 0, AdapterAddressesSize);
434 Status = GetAdaptersAddresses(AF_INET,
435 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
436 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
437 NULL,
438 Addresses,
439 &AdapterAddressesSize);
440 if (Status)
441 {
442 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
443 return 0;
444 }
445 for (pip = Addresses; pip != NULL; pip = pip->Next) {
446 Address = ((LPSOCKADDR_IN)pip->FirstUnicastAddress->Address.lpSockaddr)->sin_addr.S_un.S_addr;
447 if (Address != ntohl(INADDR_LOOPBACK))
448 break;
449 }
450 if (Address && Address != ntohl(INADDR_LOOPBACK))
451 {
452 ret = Address;
453 }
454 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
455 return ret;
456 }
457
458 BOOL
459 ParseV4Address(LPCSTR AddressString,
460 OUT PDWORD pAddress)
461 {
462 CHAR * cp = (CHAR *)AddressString;
463 DWORD val, base;
464 unsigned char c;
465 DWORD parts[4], *pp = parts;
466 if (!AddressString)
467 return FALSE;
468 if (!isdigit(*cp)) return FALSE;
469
470 again:
471 /*
472 * Collect number up to ``.''.
473 * Values are specified as for C:
474 * 0x=hex, 0=octal, other=decimal.
475 */
476 val = 0; base = 10;
477 if (*cp == '0') {
478 if (*++cp == 'x' || *cp == 'X')
479 base = 16, cp++;
480 else
481 base = 8;
482 }
483 while ((c = *cp)) {
484 if (isdigit(c)) {
485 val = (val * base) + (c - '0');
486 cp++;
487 continue;
488 }
489 if (base == 16 && isxdigit(c)) {
490 val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
491 cp++;
492 continue;
493 }
494 break;
495 }
496 if (*cp == '.') {
497 /*
498 * Internet format:
499 * a.b.c.d
500 */
501 if (pp >= parts + 4) return FALSE;
502 *pp++ = val;
503 cp++;
504 goto again;
505 }
506 /*
507 * Check for trailing characters.
508 */
509 if (*cp && *cp > ' ') return FALSE;
510
511 if (pp >= parts + 4) return FALSE;
512 *pp++ = val;
513 /*
514 * Concoct the address according to
515 * the number of parts specified.
516 */
517 if ((DWORD)(pp - parts) != 4) return FALSE;
518 if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff || parts[3] > 0xff) return FALSE;
519 val = (parts[3] << 24) | (parts[2] << 16) | (parts[1] << 8) | parts[0];
520
521 if (pAddress)
522 *pAddress = val;
523
524 return TRUE;
525 }
526
527
528 DNS_STATUS WINAPI
529 DnsQuery_W(LPCWSTR Name,
530 WORD Type,
531 DWORD Options,
532 PVOID Extra,
533 PDNS_RECORD *QueryResultSet,
534 PVOID *Reserved)
535 {
536 DWORD dwRecords = 0;
537 DNS_STATUS Status = ERROR_SUCCESS;
538
539 DPRINT("DnsQuery_W()\n");
540
541 *QueryResultSet = NULL;
542
543 RpcTryExcept
544 {
545 Status = R_ResolverQuery(NULL,
546 Name,
547 Type,
548 Options,
549 &dwRecords,
550 (DNS_RECORDW **)QueryResultSet);
551 DPRINT("R_ResolverQuery() returned %lu\n", Status);
552 }
553 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
554 {
555 Status = RpcExceptionCode();
556 DPRINT("Exception returned %lu\n", Status);
557 }
558 RpcEndExcept;
559
560 return Status;
561 }
562
563
564 DNS_STATUS
565 WINAPI
566 Query_Main(LPCWSTR Name,
567 WORD Type,
568 DWORD Options,
569 PDNS_RECORD *QueryResultSet)
570 {
571 adns_state astate;
572 int quflags = (Options & DNS_QUERY_NO_RECURSION) == 0 ? adns_qf_search : 0;
573 int adns_error;
574 adns_answer *answer;
575 LPSTR CurrentName;
576 unsigned i, CNameLoop;
577 PFIXED_INFO network_info;
578 ULONG network_info_blen = 0;
579 DWORD network_info_result;
580 PIP_ADDR_STRING pip;
581 IP4_ADDRESS Address;
582 struct in_addr addr;
583 PCHAR HostWithDomainName;
584 PCHAR AnsiName;
585 size_t NameLen = 0;
586
587 if (Name == NULL)
588 return ERROR_INVALID_PARAMETER;
589 if (QueryResultSet == NULL)
590 return ERROR_INVALID_PARAMETER;
591
592 *QueryResultSet = NULL;
593
594 switch (Type)
595 {
596 case DNS_TYPE_A:
597 /* FIXME: how much instead of MAX_PATH? */
598 NameLen = WideCharToMultiByte(CP_ACP,
599 0,
600 Name,
601 -1,
602 NULL,
603 0,
604 NULL,
605 0);
606 AnsiName = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen);
607 if (NULL == AnsiName)
608 {
609 return ERROR_OUTOFMEMORY;
610 }
611 WideCharToMultiByte(CP_ACP,
612 0,
613 Name,
614 -1,
615 AnsiName,
616 NameLen,
617 NULL,
618 0);
619 NameLen--;
620 /* Is it an IPv4 address? */
621 if (ParseV4Address(AnsiName, &Address))
622 {
623 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
624 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
625
626 if (NULL == *QueryResultSet)
627 {
628 return ERROR_OUTOFMEMORY;
629 }
630
631 (*QueryResultSet)->pNext = NULL;
632 (*QueryResultSet)->wType = Type;
633 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
634 (*QueryResultSet)->Flags.S.Section = DnsSectionAnswer;
635 (*QueryResultSet)->Flags.S.CharSet = DnsCharSetUnicode;
636 (*QueryResultSet)->Data.A.IpAddress = Address;
637
638 (*QueryResultSet)->pName = (LPSTR)xstrsave(Name);
639
640 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
641 }
642
643 /* Check allowed characters
644 * According to RFC a-z,A-Z,0-9,-,_, but can't start or end with - or _
645 */
646 if (AnsiName[0] == '-' || AnsiName[0] == '_' || AnsiName[NameLen - 1] == '-' ||
647 AnsiName[NameLen - 1] == '_' || strstr(AnsiName, "..") != NULL)
648 {
649 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
650 return ERROR_INVALID_NAME;
651 }
652 i = 0;
653 while (i < NameLen)
654 {
655 if (!((AnsiName[i] >= 'a' && AnsiName[i] <= 'z') ||
656 (AnsiName[i] >= 'A' && AnsiName[i] <= 'Z') ||
657 (AnsiName[i] >= '0' && AnsiName[i] <= '9') ||
658 AnsiName[i] == '-' || AnsiName[i] == '_' || AnsiName[i] == '.'))
659 {
660 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
661 return DNS_ERROR_INVALID_NAME_CHAR;
662 }
663 i++;
664 }
665
666 network_info_result = GetNetworkParams(NULL, &network_info_blen);
667 network_info = (PFIXED_INFO)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen);
668 if (NULL == network_info)
669 {
670 return ERROR_OUTOFMEMORY;
671 }
672
673 network_info_result = GetNetworkParams(network_info, &network_info_blen);
674 if (network_info_result != ERROR_SUCCESS)
675 {
676 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
677 return network_info_result;
678 }
679
680 if ((Address = CheckForCurrentHostname(NameLen != 0 ? AnsiName : network_info->HostName, network_info)) != 0)
681 {
682 size_t TempLen = 2, StringLength = 0;
683 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
684 StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength);
685 TempLen += StringLength;
686 StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength);
687 TempLen += StringLength;
688 HostWithDomainName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen);
689 StringCchCopyA(HostWithDomainName, TempLen, network_info->HostName);
690 if (network_info->DomainName[0])
691 {
692 StringCchCatA(HostWithDomainName, TempLen, ".");
693 StringCchCatA(HostWithDomainName, TempLen, network_info->DomainName);
694 }
695 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
696 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
697
698 if (NULL == *QueryResultSet)
699 {
700 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
701 return ERROR_OUTOFMEMORY;
702 }
703
704 (*QueryResultSet)->pNext = NULL;
705 (*QueryResultSet)->wType = Type;
706 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
707 (*QueryResultSet)->Flags.S.Section = DnsSectionAnswer;
708 (*QueryResultSet)->Flags.S.CharSet = DnsCharSetUnicode;
709 (*QueryResultSet)->Data.A.IpAddress = Address;
710
711 (*QueryResultSet)->pName = (LPSTR)DnsCToW(HostWithDomainName);
712
713 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
714 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
715 }
716
717 if ((Options & DNS_QUERY_NO_WIRE_QUERY) != 0)
718 {
719 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
720 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
721 return ERROR_FILE_NOT_FOUND;
722 }
723
724 adns_error = adns_init(&astate, adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn, 0);
725 if (adns_error != adns_s_ok)
726 {
727 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
728 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
729 return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
730 }
731 for (pip = &(network_info->DnsServerList); pip; pip = pip->Next)
732 {
733 addr.s_addr = inet_addr(pip->IpAddress.String);
734 if ((addr.s_addr != INADDR_ANY) && (addr.s_addr != INADDR_NONE))
735 adns_addserver(astate, addr);
736 }
737 if (network_info->DomainName[0])
738 {
739 adns_ccf_search(astate, "LOCALDOMAIN", -1, network_info->DomainName);
740 }
741 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
742
743 if (!adns_numservers(astate))
744 {
745 /* There are no servers to query so bail out */
746 adns_finish(astate);
747 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
748 return ERROR_FILE_NOT_FOUND;
749 }
750
751 /*
752 * adns doesn't resolve chained CNAME records (a CNAME which points to
753 * another CNAME pointing to another... pointing to an A record), according
754 * to a mailing list thread the authors believe that chained CNAME records
755 * are invalid and the DNS entries should be fixed. That's a nice academic
756 * standpoint, but there certainly are chained CNAME records out there,
757 * even some fairly major ones (at the time of this writing
758 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
759 * these fine, so we should too. So we loop here to try to resolve CNAME
760 * chains ourselves. Of course, there must be a limit to protect against
761 * CNAME loops.
762 */
763
764 #define CNAME_LOOP_MAX 16
765
766 CurrentName = AnsiName;
767
768 for (CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++)
769 {
770 adns_error = adns_synchronous(astate, CurrentName, adns_r_addr, quflags, &answer);
771
772 if (adns_error != adns_s_ok)
773 {
774 adns_finish(astate);
775
776 if (CurrentName != AnsiName)
777 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
778
779 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
780 return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
781 }
782
783 if (answer && answer->rrs.addr)
784 {
785 if (CurrentName != AnsiName)
786 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
787
788 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
789 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
790
791 if (NULL == *QueryResultSet)
792 {
793 adns_finish(astate);
794 return ERROR_OUTOFMEMORY;
795 }
796
797 (*QueryResultSet)->pNext = NULL;
798 (*QueryResultSet)->wType = Type;
799 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
800 (*QueryResultSet)->Flags.S.Section = DnsSectionAnswer;
801 (*QueryResultSet)->Flags.S.CharSet = DnsCharSetUnicode;
802 (*QueryResultSet)->Data.A.IpAddress = answer->rrs.addr->addr.inet.sin_addr.s_addr;
803
804 adns_finish(astate);
805
806 (*QueryResultSet)->pName = (LPSTR)xstrsave(Name);
807
808 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
809 }
810
811 if (NULL == answer || adns_s_prohibitedcname != answer->status || NULL == answer->cname)
812 {
813 adns_finish(astate);
814
815 if (CurrentName != AnsiName)
816 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
817
818 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
819 return ERROR_FILE_NOT_FOUND;
820 }
821
822 if (CurrentName != AnsiName)
823 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
824
825 CurrentName = (LPSTR)xstrsaveA(answer->cname);
826
827 if (!CurrentName)
828 {
829 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
830 adns_finish(astate);
831 return ERROR_OUTOFMEMORY;
832 }
833 }
834
835 adns_finish(astate);
836 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
837 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
838 return ERROR_FILE_NOT_FOUND;
839
840 default:
841 return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */
842 }
843 }
844
845 void
846 DnsIntFreeRecordList(PDNS_RECORD ToDelete)
847 {
848 UINT i;
849 PDNS_RECORD next = 0;
850
851 while(ToDelete)
852 {
853 if(ToDelete->pName)
854 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->pName);
855
856 switch(ToDelete->wType)
857 {
858 case DNS_TYPE_CNAME:
859 case DNS_TYPE_PTR:
860 case DNS_TYPE_NS:
861 case DNS_TYPE_MB:
862 case DNS_TYPE_MD:
863 case DNS_TYPE_MF:
864 case DNS_TYPE_MG:
865 case DNS_TYPE_MR:
866 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.PTR.pNameHost);
867 break;
868
869 case DNS_TYPE_MINFO:
870 case DNS_TYPE_MX:
871 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.MX.pNameExchange);
872 break;
873
874 case DNS_TYPE_HINFO:
875 for(i = 0; i < ToDelete->Data.TXT.dwStringCount; i++)
876 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray[i]);
877
878 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray);
879 break;
880 }
881
882 next = ToDelete->pNext;
883 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete);
884 ToDelete = next;
885 }
886 }
887
888 BOOL
889 WINAPI
890 DnsFlushResolverCache(VOID)
891 {
892 DNS_STATUS Status = ERROR_SUCCESS;
893
894 DPRINT("DnsFlushResolverCache()\n");
895
896 RpcTryExcept
897 {
898 Status = R_ResolverFlushCache(NULL);
899 DPRINT("R_ResolverFlushCache() returned %lu\n", Status);
900 }
901 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
902 {
903 Status = RpcExceptionCode();
904 DPRINT("Exception returned %lu\n", Status);
905 }
906 RpcEndExcept;
907
908 return (Status == ERROR_SUCCESS);
909 }
910
911 BOOL
912 WINAPI
913 DnsGetCacheDataTable(
914 _Out_ PDNS_CACHE_ENTRY *DnsCache)
915 {
916 DNS_STATUS Status = ERROR_SUCCESS;
917 PDNS_CACHE_ENTRY CacheEntries = NULL;
918
919 if (DnsCache == NULL)
920 return FALSE;
921
922 RpcTryExcept
923 {
924 Status = CRrReadCache(NULL,
925 &CacheEntries);
926 DPRINT("CRrReadCache() returned %lu\n", Status);
927 }
928 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
929 {
930 Status = RpcExceptionCode();
931 DPRINT1("Exception returned %lu\n", Status);
932 }
933 RpcEndExcept;
934
935 if (Status != ERROR_SUCCESS)
936 return FALSE;
937
938 if (CacheEntries == NULL)
939 return FALSE;
940
941 *DnsCache = CacheEntries;
942
943 return TRUE;
944 }
945
946 DWORD
947 WINAPI
948 GetCurrentTimeInSeconds(VOID)
949 {
950 FILETIME Time;
951 FILETIME Adjustment;
952 ULARGE_INTEGER lTime, lAdj;
953 SYSTEMTIME st = {1970, 1, 0, 1, 0, 0, 0};
954
955 SystemTimeToFileTime(&st, &Adjustment);
956 memcpy(&lAdj, &Adjustment, sizeof(lAdj));
957 GetSystemTimeAsFileTime(&Time);
958 memcpy(&lTime, &Time, sizeof(lTime));
959 lTime.QuadPart -= lAdj.QuadPart;
960 return (DWORD)(lTime.QuadPart/10000000ULL);
961 }