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