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
ParseIpv4Address(_In_ PCWSTR AddressString,_Out_ PIN_ADDR pAddress)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
ParseIpv6Address(_In_ PCWSTR AddressString,_Out_ PIN6_ADDR pAddress)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
CreateRecordForIpAddress(_In_ PCWSTR Name,_In_ WORD Type)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
DnsWToC(const WCHAR * WideString)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
DnsCToW(const CHAR * NarrowString)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
DnsWToUTF8(const WCHAR * WideString)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
DnsUTF8ToW(const CHAR * NarrowString)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
DnsQuery_CodePage(UINT CodePage,LPCSTR Name,WORD Type,DWORD Options,PVOID Extra,PDNS_RECORD * QueryResultSet,PVOID * Reserved)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
DnsQuery_A(LPCSTR Name,WORD Type,DWORD Options,PVOID Extra,PDNS_RECORD * QueryResultSet,PVOID * Reserved)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
DnsQuery_UTF8(LPCSTR Name,WORD Type,DWORD Options,PVOID Extra,PDNS_RECORD * QueryResultSet,PVOID * Reserved)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
DnsQuery_W(LPCWSTR Name,WORD Type,DWORD Options,PVOID Extra,PDNS_RECORD * QueryResultSet,PVOID * Reserved)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 size_t NameLen, i;
479 DNS_STATUS Status = ERROR_SUCCESS;
480
481 DPRINT("DnsQuery_W()\n");
482
483 if ((Name == NULL) ||
484 (QueryResultSet == NULL))
485 return ERROR_INVALID_PARAMETER;
486
487 *QueryResultSet = NULL;
488
489 /* Create an A or AAAA record for an IP4 or IP6 address */
490 pRecord = CreateRecordForIpAddress(Name,
491 Type);
492 if (pRecord != NULL)
493 {
494 *QueryResultSet = (PDNS_RECORD)pRecord;
495 return ERROR_SUCCESS;
496 }
497
498 /*
499 * Check allowed characters
500 * According to RFC a-z,A-Z,0-9,-,_, but can't start or end with - or _
501 */
502 NameLen = wcslen(Name);
503 if (Name[0] == L'-' || Name[0] == L'_' || Name[NameLen - 1] == L'-' ||
504 Name[NameLen - 1] == L'_' || wcsstr(Name, L"..") != NULL)
505 {
506 return ERROR_INVALID_NAME;
507 }
508
509 i = 0;
510 while (i < NameLen)
511 {
512 if (!((Name[i] >= L'a' && Name[i] <= L'z') ||
513 (Name[i] >= L'A' && Name[i] <= L'Z') ||
514 (Name[i] >= L'0' && Name[i] <= L'9') ||
515 Name[i] == L'-' || Name[i] == L'_' || Name[i] == L'.'))
516 {
517 return DNS_ERROR_INVALID_NAME_CHAR;
518 }
519
520 i++;
521 }
522
523 RpcTryExcept
524 {
525 Status = R_ResolverQuery(NULL,
526 Name,
527 Type,
528 Options,
529 &dwRecords,
530 (DNS_RECORDW **)QueryResultSet);
531 DPRINT("R_ResolverQuery() returned %lu\n", Status);
532 }
533 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
534 {
535 Status = RpcExceptionCode();
536 DPRINT("Exception returned %lu\n", Status);
537 }
538 RpcEndExcept;
539
540 return Status;
541 }
542
543 WCHAR
xstrsave(const WCHAR * str)544 *xstrsave(const WCHAR *str)
545 {
546 WCHAR *p;
547 size_t len = 0;
548
549 /* FIXME: how much instead of MAX_PATH? */
550 StringCbLengthW(str, MAX_PATH, &len);
551 len+=sizeof(WCHAR);
552
553 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
554
555 if (p)
556 StringCbCopyW(p, len, str);
557
558 return p;
559 }
560
561 CHAR
xstrsaveA(const CHAR * str)562 *xstrsaveA(const CHAR *str)
563 {
564 CHAR *p;
565 size_t len = 0;
566
567 /* FIXME: how much instead of MAX_PATH? */
568 StringCbLengthA(str, MAX_PATH, &len);
569 len++;
570
571 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
572
573 if (p)
574 StringCbCopyA(p, len, str);
575
576 return p;
577 }
578
579
580 /* This function is far from perfect but it works enough */
581 IP4_ADDRESS
CheckForCurrentHostname(CONST CHAR * Name,PFIXED_INFO network_info)582 CheckForCurrentHostname(CONST CHAR * Name, PFIXED_INFO network_info)
583 {
584 PCHAR TempName;
585 DWORD AdapterAddressesSize, Status;
586 IP4_ADDRESS ret = 0, Address;
587 PIP_ADAPTER_ADDRESSES Addresses = NULL, pip;
588 BOOL Found = FALSE;
589
590 if (network_info->DomainName[0])
591 {
592 size_t StringLength;
593 size_t TempSize = 2;
594 StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength);
595 TempSize += StringLength;
596 StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength);
597 TempSize += StringLength;
598 TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, TempSize);
599 StringCchCopyA(TempName, TempSize, network_info->HostName);
600 StringCchCatA(TempName, TempSize, ".");
601 StringCchCatA(TempName, TempSize, network_info->DomainName);
602 }
603 else
604 {
605 TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, 1);
606 TempName[0] = 0;
607 }
608 Found = !_stricmp(Name, network_info->HostName) || !_stricmp(Name, TempName);
609 RtlFreeHeap(RtlGetProcessHeap(), 0, TempName);
610 if (!Found)
611 {
612 return 0;
613 }
614 /* get adapter info */
615 AdapterAddressesSize = 0;
616 GetAdaptersAddresses(AF_INET,
617 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
618 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
619 NULL,
620 Addresses,
621 &AdapterAddressesSize);
622 if (!AdapterAddressesSize)
623 {
624 return 0;
625 }
626 Addresses = RtlAllocateHeap(RtlGetProcessHeap(), 0, AdapterAddressesSize);
627 Status = GetAdaptersAddresses(AF_INET,
628 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
629 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
630 NULL,
631 Addresses,
632 &AdapterAddressesSize);
633 if (Status)
634 {
635 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
636 return 0;
637 }
638 for (pip = Addresses; pip != NULL; pip = pip->Next) {
639 Address = ((LPSOCKADDR_IN)pip->FirstUnicastAddress->Address.lpSockaddr)->sin_addr.S_un.S_addr;
640 if (Address != ntohl(INADDR_LOOPBACK))
641 break;
642 }
643 if (Address && Address != ntohl(INADDR_LOOPBACK))
644 {
645 ret = Address;
646 }
647 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
648 return ret;
649 }
650
651
652 DNS_STATUS
653 WINAPI
Query_Main(LPCWSTR Name,WORD Type,DWORD Options,PDNS_RECORD * QueryResultSet)654 Query_Main(LPCWSTR Name,
655 WORD Type,
656 DWORD Options,
657 PDNS_RECORD *QueryResultSet)
658 {
659 adns_state astate;
660 int quflags = (Options & DNS_QUERY_NO_RECURSION) == 0 ? adns_qf_search : 0;
661 int adns_error;
662 adns_answer *answer;
663 LPSTR CurrentName;
664 unsigned CNameLoop;
665 PFIXED_INFO network_info;
666 ULONG network_info_blen = 0;
667 DWORD network_info_result;
668 PIP_ADDR_STRING pip;
669 IP4_ADDRESS Address;
670 struct in_addr addr;
671 PCHAR HostWithDomainName;
672 PCHAR AnsiName;
673 size_t NameLen = 0;
674
675 if (Name == NULL)
676 return ERROR_INVALID_PARAMETER;
677 if (QueryResultSet == NULL)
678 return ERROR_INVALID_PARAMETER;
679
680 *QueryResultSet = NULL;
681
682 switch (Type)
683 {
684 case DNS_TYPE_A:
685 /* FIXME: how much instead of MAX_PATH? */
686 NameLen = WideCharToMultiByte(CP_ACP,
687 0,
688 Name,
689 -1,
690 NULL,
691 0,
692 NULL,
693 0);
694 AnsiName = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen);
695 if (NULL == AnsiName)
696 {
697 return ERROR_OUTOFMEMORY;
698 }
699 WideCharToMultiByte(CP_ACP,
700 0,
701 Name,
702 -1,
703 AnsiName,
704 NameLen,
705 NULL,
706 0);
707 NameLen--;
708
709 network_info_result = GetNetworkParams(NULL, &network_info_blen);
710 network_info = (PFIXED_INFO)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen);
711 if (NULL == network_info)
712 {
713 return ERROR_OUTOFMEMORY;
714 }
715
716 network_info_result = GetNetworkParams(network_info, &network_info_blen);
717 if (network_info_result != ERROR_SUCCESS)
718 {
719 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
720 return network_info_result;
721 }
722
723 if ((Address = CheckForCurrentHostname(NameLen != 0 ? AnsiName : network_info->HostName, network_info)) != 0)
724 {
725 size_t TempLen = 2, StringLength = 0;
726 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
727 StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength);
728 TempLen += StringLength;
729 StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength);
730 TempLen += StringLength;
731 HostWithDomainName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen);
732 StringCchCopyA(HostWithDomainName, TempLen, network_info->HostName);
733 if (network_info->DomainName[0])
734 {
735 StringCchCatA(HostWithDomainName, TempLen, ".");
736 StringCchCatA(HostWithDomainName, TempLen, network_info->DomainName);
737 }
738 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
739 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
740
741 if (NULL == *QueryResultSet)
742 {
743 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
744 return ERROR_OUTOFMEMORY;
745 }
746
747 (*QueryResultSet)->pNext = NULL;
748 (*QueryResultSet)->wType = Type;
749 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
750 (*QueryResultSet)->Flags.S.Section = DnsSectionAnswer;
751 (*QueryResultSet)->Flags.S.CharSet = DnsCharSetUnicode;
752 (*QueryResultSet)->Data.A.IpAddress = Address;
753
754 (*QueryResultSet)->pName = (LPSTR)DnsCToW(HostWithDomainName);
755
756 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
757 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
758 }
759
760 if ((Options & DNS_QUERY_NO_WIRE_QUERY) != 0)
761 {
762 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
763 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
764 return ERROR_FILE_NOT_FOUND;
765 }
766
767 adns_error = adns_init(&astate, adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn, 0);
768 if (adns_error != adns_s_ok)
769 {
770 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
771 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
772 return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
773 }
774 for (pip = &(network_info->DnsServerList); pip; pip = pip->Next)
775 {
776 addr.s_addr = inet_addr(pip->IpAddress.String);
777 if ((addr.s_addr != INADDR_ANY) && (addr.s_addr != INADDR_NONE))
778 adns_addserver(astate, addr);
779 }
780 if (network_info->DomainName[0])
781 {
782 adns_ccf_search(astate, "LOCALDOMAIN", -1, network_info->DomainName);
783 }
784 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
785
786 if (!adns_numservers(astate))
787 {
788 /* There are no servers to query so bail out */
789 adns_finish(astate);
790 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
791 return ERROR_FILE_NOT_FOUND;
792 }
793
794 /*
795 * adns doesn't resolve chained CNAME records (a CNAME which points to
796 * another CNAME pointing to another... pointing to an A record), according
797 * to a mailing list thread the authors believe that chained CNAME records
798 * are invalid and the DNS entries should be fixed. That's a nice academic
799 * standpoint, but there certainly are chained CNAME records out there,
800 * even some fairly major ones (at the time of this writing
801 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
802 * these fine, so we should too. So we loop here to try to resolve CNAME
803 * chains ourselves. Of course, there must be a limit to protect against
804 * CNAME loops.
805 */
806
807 #define CNAME_LOOP_MAX 16
808
809 CurrentName = AnsiName;
810
811 for (CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++)
812 {
813 adns_error = adns_synchronous(astate, CurrentName, adns_r_addr, quflags, &answer);
814
815 if (adns_error != adns_s_ok)
816 {
817 adns_finish(astate);
818
819 if (CurrentName != AnsiName)
820 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
821
822 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
823 return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
824 }
825
826 if (answer && answer->rrs.addr)
827 {
828 if (CurrentName != AnsiName)
829 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
830
831 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
832 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
833
834 if (NULL == *QueryResultSet)
835 {
836 adns_finish(astate);
837 return ERROR_OUTOFMEMORY;
838 }
839
840 (*QueryResultSet)->pNext = NULL;
841 (*QueryResultSet)->wType = Type;
842 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
843 (*QueryResultSet)->Flags.S.Section = DnsSectionAnswer;
844 (*QueryResultSet)->Flags.S.CharSet = DnsCharSetUnicode;
845 (*QueryResultSet)->Data.A.IpAddress = answer->rrs.addr->addr.inet.sin_addr.s_addr;
846
847 adns_finish(astate);
848
849 (*QueryResultSet)->pName = (LPSTR)xstrsave(Name);
850
851 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
852 }
853
854 if (NULL == answer || adns_s_prohibitedcname != answer->status || NULL == answer->cname)
855 {
856 adns_finish(astate);
857
858 if (CurrentName != AnsiName)
859 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
860
861 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
862 return ERROR_FILE_NOT_FOUND;
863 }
864
865 if (CurrentName != AnsiName)
866 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
867
868 CurrentName = (LPSTR)xstrsaveA(answer->cname);
869
870 if (!CurrentName)
871 {
872 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
873 adns_finish(astate);
874 return ERROR_OUTOFMEMORY;
875 }
876 }
877
878 adns_finish(astate);
879 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
880 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
881 return ERROR_FILE_NOT_FOUND;
882
883 default:
884 return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */
885 }
886 }
887
888 void
DnsIntFreeRecordList(PDNS_RECORD ToDelete)889 DnsIntFreeRecordList(PDNS_RECORD ToDelete)
890 {
891 UINT i;
892 PDNS_RECORD next = 0;
893
894 while(ToDelete)
895 {
896 if(ToDelete->pName)
897 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->pName);
898
899 switch(ToDelete->wType)
900 {
901 case DNS_TYPE_CNAME:
902 case DNS_TYPE_PTR:
903 case DNS_TYPE_NS:
904 case DNS_TYPE_MB:
905 case DNS_TYPE_MD:
906 case DNS_TYPE_MF:
907 case DNS_TYPE_MG:
908 case DNS_TYPE_MR:
909 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.PTR.pNameHost);
910 break;
911
912 case DNS_TYPE_MINFO:
913 case DNS_TYPE_MX:
914 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.MX.pNameExchange);
915 break;
916
917 case DNS_TYPE_HINFO:
918 for(i = 0; i < ToDelete->Data.TXT.dwStringCount; i++)
919 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray[i]);
920
921 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray);
922 break;
923 }
924
925 next = ToDelete->pNext;
926 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete);
927 ToDelete = next;
928 }
929 }
930
931 BOOL
932 WINAPI
DnsFlushResolverCache(VOID)933 DnsFlushResolverCache(VOID)
934 {
935 DNS_STATUS Status = ERROR_SUCCESS;
936
937 DPRINT("DnsFlushResolverCache()\n");
938
939 RpcTryExcept
940 {
941 Status = R_ResolverFlushCache(NULL);
942 DPRINT("R_ResolverFlushCache() returned %lu\n", Status);
943 }
944 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
945 {
946 Status = RpcExceptionCode();
947 DPRINT("Exception returned %lu\n", Status);
948 }
949 RpcEndExcept;
950
951 return (Status == ERROR_SUCCESS);
952 }
953
954
955 BOOL
956 WINAPI
DnsFlushResolverCacheEntry_A(_In_ LPCSTR pszEntry)957 DnsFlushResolverCacheEntry_A(
958 _In_ LPCSTR pszEntry)
959 {
960 DNS_STATUS Status = ERROR_SUCCESS;
961 LPWSTR pszUnicodeEntry;
962
963 DPRINT1("DnsFlushResolverCacheEntry_A(%s)\n", pszEntry);
964
965 if (pszEntry == NULL)
966 return FALSE;
967
968 pszUnicodeEntry = DnsCToW(pszEntry);
969 if (pszUnicodeEntry == NULL)
970 return FALSE;
971
972 RpcTryExcept
973 {
974 Status = R_ResolverFlushCacheEntry(NULL, pszUnicodeEntry, DNS_TYPE_ANY);
975 DPRINT("R_ResolverFlushCacheEntry() returned %lu\n", Status);
976 }
977 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
978 {
979 Status = RpcExceptionCode();
980 DPRINT("Exception returned %lu\n", Status);
981 }
982 RpcEndExcept;
983
984 RtlFreeHeap(RtlGetProcessHeap(), 0, pszUnicodeEntry);
985
986 return (Status == ERROR_SUCCESS);
987 }
988
989
990 BOOL
991 WINAPI
DnsFlushResolverCacheEntry_UTF8(_In_ LPCSTR pszEntry)992 DnsFlushResolverCacheEntry_UTF8(
993 _In_ LPCSTR pszEntry)
994 {
995 DNS_STATUS Status = ERROR_SUCCESS;
996 LPWSTR pszUnicodeEntry;
997
998 DPRINT1("DnsFlushResolverCacheEntry_UTF8(%s)\n", pszEntry);
999
1000 if (pszEntry == NULL)
1001 return FALSE;
1002
1003 pszUnicodeEntry = DnsCToW(pszEntry);
1004 if (pszUnicodeEntry == NULL)
1005 return FALSE;
1006
1007 RpcTryExcept
1008 {
1009 Status = R_ResolverFlushCacheEntry(NULL, pszUnicodeEntry, DNS_TYPE_ANY);
1010 DPRINT("R_ResolverFlushCacheEntry() returned %lu\n", Status);
1011 }
1012 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1013 {
1014 Status = RpcExceptionCode();
1015 DPRINT("Exception returned %lu\n", Status);
1016 }
1017 RpcEndExcept;
1018
1019 RtlFreeHeap(RtlGetProcessHeap(), 0, pszUnicodeEntry);
1020
1021 return (Status == ERROR_SUCCESS);
1022 }
1023
1024
1025 BOOL
1026 WINAPI
DnsFlushResolverCacheEntry_W(_In_ LPCWSTR pszEntry)1027 DnsFlushResolverCacheEntry_W(
1028 _In_ LPCWSTR pszEntry)
1029 {
1030 DNS_STATUS Status = ERROR_SUCCESS;
1031
1032 DPRINT1("DnsFlushResolverCacheEntry_W(%S)\n", pszEntry);
1033
1034 if (pszEntry == NULL)
1035 return FALSE;
1036
1037 RpcTryExcept
1038 {
1039 Status = R_ResolverFlushCacheEntry(NULL, pszEntry, DNS_TYPE_ANY);
1040 DPRINT("R_ResolverFlushCacheEntry() returned %lu\n", Status);
1041 }
1042 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1043 {
1044 Status = RpcExceptionCode();
1045 DPRINT("Exception returned %lu\n", Status);
1046 }
1047 RpcEndExcept;
1048
1049 return (Status == ERROR_SUCCESS);
1050 }
1051
1052
1053 BOOL
1054 WINAPI
DnsGetCacheDataTable(_Out_ PDNS_CACHE_ENTRY * DnsCache)1055 DnsGetCacheDataTable(
1056 _Out_ PDNS_CACHE_ENTRY *DnsCache)
1057 {
1058 DNS_STATUS Status = ERROR_SUCCESS;
1059 PDNS_CACHE_ENTRY CacheEntries = NULL;
1060
1061 if (DnsCache == NULL)
1062 return FALSE;
1063
1064 RpcTryExcept
1065 {
1066 Status = CRrReadCache(NULL,
1067 &CacheEntries);
1068 DPRINT("CRrReadCache() returned %lu\n", Status);
1069 }
1070 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1071 {
1072 Status = RpcExceptionCode();
1073 DPRINT1("Exception returned %lu\n", Status);
1074 }
1075 RpcEndExcept;
1076
1077 if (Status != ERROR_SUCCESS)
1078 return FALSE;
1079
1080 if (CacheEntries == NULL)
1081 return FALSE;
1082
1083 *DnsCache = CacheEntries;
1084
1085 return TRUE;
1086 }
1087
1088 DWORD
1089 WINAPI
GetCurrentTimeInSeconds(VOID)1090 GetCurrentTimeInSeconds(VOID)
1091 {
1092 FILETIME Time;
1093 FILETIME Adjustment;
1094 ULARGE_INTEGER lTime, lAdj;
1095 SYSTEMTIME st = {1970, 1, 0, 1, 0, 0, 0};
1096
1097 SystemTimeToFileTime(&st, &Adjustment);
1098 memcpy(&lAdj, &Adjustment, sizeof(lAdj));
1099 GetSystemTimeAsFileTime(&Time);
1100 memcpy(&lTime, &Time, sizeof(lTime));
1101 lTime.QuadPart -= lAdj.QuadPart;
1102 return (DWORD)(lTime.QuadPart/10000000ULL);
1103 }
1104