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 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 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 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 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 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 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 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 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 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 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 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 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