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