GetAddrInfo.cpp (20681B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "GetAddrInfo.h" 8 9 #ifdef DNSQUERY_AVAILABLE 10 // There is a bug in windns.h where the type of parameter ppQueryResultsSet for 11 // DnsQuery_A is dependent on UNICODE being set. It should *always* be 12 // PDNS_RECORDA, but if UNICODE is set it is PDNS_RECORDW. To get around this 13 // we make sure that UNICODE is unset. 14 # undef UNICODE 15 # include <ws2tcpip.h> 16 # undef GetAddrInfo 17 # include <windns.h> 18 #endif // DNSQUERY_AVAILABLE 19 20 #include "mozilla/ClearOnShutdown.h" 21 #include "mozilla/net/DNS.h" 22 #include "NativeDNSResolverOverrideParent.h" 23 #include "prnetdb.h" 24 #include "nsIOService.h" 25 #include "nsHostResolver.h" 26 #include "nsError.h" 27 #include "mozilla/net/DNS.h" 28 #include <algorithm> 29 #include "prerror.h" 30 31 #include "mozilla/Logging.h" 32 #include "mozilla/StaticPrefs_network.h" 33 #include "mozilla/net/DNSPacket.h" 34 #include "nsIDNSService.h" 35 #include "nsINetworkLinkService.h" 36 37 namespace mozilla::net { 38 39 static StaticRefPtr<NativeDNSResolverOverride> gOverrideService; 40 41 LazyLogModule gGetAddrInfoLog("GetAddrInfo"); 42 #define LOG(msg, ...) \ 43 MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__)) 44 #define LOG_WARNING(msg, ...) \ 45 MOZ_LOG(gGetAddrInfoLog, LogLevel::Warning, ("[DNS]: " msg, ##__VA_ARGS__)) 46 47 #ifdef DNSQUERY_AVAILABLE 48 49 # define COMPUTER_NAME_BUFFER_SIZE 100 50 static char sDNSComputerName[COMPUTER_NAME_BUFFER_SIZE]; 51 static char sNETBIOSComputerName[MAX_COMPUTERNAME_LENGTH + 1]; 52 53 //////////////////////////// 54 // WINDOWS IMPLEMENTATION // 55 //////////////////////////// 56 57 // Ensure consistency of PR_* and AF_* constants to allow for legacy usage of 58 // PR_* constants with this API. 59 static_assert(PR_AF_INET == AF_INET && PR_AF_INET6 == AF_INET6 && 60 PR_AF_UNSPEC == AF_UNSPEC, 61 "PR_AF_* must match AF_*"); 62 63 // If successful, returns in aResult a TTL value that is smaller or 64 // equal with the one already there. Gets the TTL value by calling 65 // to DnsQuery_A and iterating through the returned 66 // records to find the one with the smallest TTL value. 67 static MOZ_ALWAYS_INLINE nsresult _CallDnsQuery_A_Windows( 68 const nsACString& aHost, uint16_t aAddressFamily, DWORD aFlags, 69 std::function<void(PDNS_RECORDA)> aCallback) { 70 NS_ConvertASCIItoUTF16 name(aHost); 71 72 auto callDnsQuery_A = [&](uint16_t reqFamily) { 73 PDNS_RECORDA dnsData = nullptr; 74 DNS_STATUS status = DnsQuery_A(aHost.BeginReading(), reqFamily, aFlags, 75 nullptr, &dnsData, nullptr); 76 if (status == DNS_INFO_NO_RECORDS || status == DNS_ERROR_RCODE_NAME_ERROR || 77 !dnsData) { 78 LOG("No DNS records found for %s. status=%lX. reqFamily = %X\n", 79 aHost.BeginReading(), status, reqFamily); 80 return NS_ERROR_FAILURE; 81 } else if (status != NOERROR) { 82 LOG_WARNING("DnsQuery_A failed with status %lX.\n", status); 83 return NS_ERROR_UNEXPECTED; 84 } 85 86 for (PDNS_RECORDA curRecord = dnsData; curRecord; 87 curRecord = curRecord->pNext) { 88 // Only records in the answer section are important 89 if (curRecord->Flags.S.Section != DnsSectionAnswer) { 90 continue; 91 } 92 if (curRecord->wType != reqFamily) { 93 continue; 94 } 95 96 aCallback(curRecord); 97 } 98 99 DnsFree(dnsData, DNS_FREE_TYPE::DnsFreeRecordList); 100 return NS_OK; 101 }; 102 103 if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET) { 104 callDnsQuery_A(DNS_TYPE_A); 105 } 106 107 if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET6) { 108 callDnsQuery_A(DNS_TYPE_AAAA); 109 } 110 return NS_OK; 111 } 112 113 bool recordTypeMatchesRequest(uint16_t wType, uint16_t aAddressFamily) { 114 if (aAddressFamily == PR_AF_UNSPEC) { 115 return wType == DNS_TYPE_A || wType == DNS_TYPE_AAAA; 116 } 117 if (aAddressFamily == PR_AF_INET) { 118 return wType == DNS_TYPE_A; 119 } 120 if (aAddressFamily == PR_AF_INET6) { 121 return wType == DNS_TYPE_AAAA; 122 } 123 return false; 124 } 125 126 static MOZ_ALWAYS_INLINE nsresult _GetTTLData_Windows(const nsACString& aHost, 127 uint32_t* aResult, 128 uint16_t aAddressFamily) { 129 MOZ_ASSERT(!aHost.IsEmpty()); 130 MOZ_ASSERT(aResult); 131 if (aAddressFamily != PR_AF_UNSPEC && aAddressFamily != PR_AF_INET && 132 aAddressFamily != PR_AF_INET6) { 133 return NS_ERROR_UNEXPECTED; 134 } 135 136 // In order to avoid using ANY records which are not always implemented as a 137 // "Gimme what you have" request in hostname resolvers, we should send A 138 // and/or AAAA requests, based on the address family requested. 139 const DWORD ttlFlags = 140 (DNS_QUERY_STANDARD | DNS_QUERY_NO_NETBT | DNS_QUERY_NO_HOSTS_FILE | 141 DNS_QUERY_NO_MULTICAST | DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE | 142 DNS_QUERY_DONT_RESET_TTL_VALUES); 143 unsigned int ttl = (unsigned int)-1; 144 _CallDnsQuery_A_Windows( 145 aHost, aAddressFamily, ttlFlags, 146 [&ttl, &aHost, aAddressFamily](PDNS_RECORDA curRecord) { 147 if (recordTypeMatchesRequest(curRecord->wType, aAddressFamily)) { 148 ttl = std::min<unsigned int>(ttl, curRecord->dwTtl); 149 } else { 150 LOG("Received unexpected record type %u in response for %s.\n", 151 curRecord->wType, aHost.BeginReading()); 152 } 153 }); 154 155 if (ttl == (unsigned int)-1) { 156 LOG("No useable TTL found."); 157 return NS_ERROR_FAILURE; 158 } 159 160 *aResult = ttl; 161 return NS_OK; 162 } 163 164 static MOZ_ALWAYS_INLINE nsresult 165 _DNSQuery_A_SingleLabel(const nsACString& aCanonHost, uint16_t aAddressFamily, 166 uint16_t aFlags, AddrInfo** aAddrInfo) { 167 bool setCanonName = aFlags & nsIDNSService::RESOLVE_CANONICAL_NAME; 168 nsAutoCString canonName; 169 const DWORD flags = (DNS_QUERY_STANDARD | DNS_QUERY_NO_MULTICAST | 170 DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE); 171 nsTArray<NetAddr> addresses; 172 173 _CallDnsQuery_A_Windows( 174 aCanonHost, aAddressFamily, flags, [&](PDNS_RECORDA curRecord) { 175 MOZ_DIAGNOSTIC_ASSERT(curRecord->wType == DNS_TYPE_A || 176 curRecord->wType == DNS_TYPE_AAAA); 177 if (setCanonName) { 178 canonName.Assign(curRecord->pName); 179 } 180 NetAddr addr{}; 181 addr.inet.family = AF_INET; 182 addr.inet.ip = curRecord->Data.A.IpAddress; 183 addresses.AppendElement(addr); 184 }); 185 186 LOG("Query for: %s has %zu results", aCanonHost.BeginReading(), 187 addresses.Length()); 188 if (addresses.IsEmpty()) { 189 return NS_ERROR_UNKNOWN_HOST; 190 } 191 RefPtr<AddrInfo> ai(new AddrInfo( 192 aCanonHost, canonName, DNSResolverType::Native, 0, std::move(addresses))); 193 ai.forget(aAddrInfo); 194 195 return NS_OK; 196 } 197 198 #endif 199 200 //////////////////////////////////// 201 // PORTABLE RUNTIME IMPLEMENTATION// 202 //////////////////////////////////// 203 204 static bool SkipIPv6DNSLookup() { 205 #if defined(XP_WIN) || defined(XP_LINUX) || defined(XP_MACOSX) 206 return StaticPrefs::network_dns_skip_ipv6_when_no_addresses() && 207 !nsINetworkLinkService::HasNonLocalIPv6Address(); 208 #else 209 return false; 210 #endif 211 } 212 213 static MOZ_ALWAYS_INLINE nsresult 214 _GetAddrInfo_Portable(const nsACString& aCanonHost, uint16_t aAddressFamily, 215 nsIDNSService::DNSFlags aFlags, AddrInfo** aAddrInfo) { 216 MOZ_ASSERT(!aCanonHost.IsEmpty()); 217 MOZ_ASSERT(aAddrInfo); 218 219 // We accept the same aFlags that nsHostResolver::ResolveHost accepts, but we 220 // need to translate the aFlags into a form that PR_GetAddrInfoByName 221 // accepts. 222 int prFlags = PR_AI_ADDRCONFIG; 223 if (!(aFlags & nsIDNSService::RESOLVE_CANONICAL_NAME)) { 224 prFlags |= PR_AI_NOCANONNAME; 225 } 226 227 // We need to remove IPv4 records manually because PR_GetAddrInfoByName 228 // doesn't support PR_AF_INET6. 229 bool disableIPv4 = aAddressFamily == PR_AF_INET6; 230 if (disableIPv4) { 231 aAddressFamily = PR_AF_UNSPEC; 232 } 233 234 if (SkipIPv6DNSLookup()) { 235 // If the family was AF_UNSPEC initially, make it AF_INET 236 // when there are no IPv6 addresses. 237 // If the DNS request specified IPv6 specifically, let it 238 // go through. 239 if (aAddressFamily == PR_AF_UNSPEC && !disableIPv4) { 240 aAddressFamily = PR_AF_INET; 241 } 242 } 243 244 #if defined(DNSQUERY_AVAILABLE) 245 if (StaticPrefs::network_dns_dns_query_single_label() && 246 !aCanonHost.Contains('.') && aCanonHost != "localhost"_ns) { 247 // For some reason we can't use DnsQuery_A to get the computer's IP. 248 if (!aCanonHost.Equals(nsDependentCString(sDNSComputerName), 249 nsCaseInsensitiveCStringComparator) && 250 !aCanonHost.Equals(nsDependentCString(sNETBIOSComputerName), 251 nsCaseInsensitiveCStringComparator)) { 252 // This is a single label name resolve without a dot. 253 // We use DNSQuery_A for these. 254 LOG("Resolving %s using DnsQuery_A (computername: %s)\n", 255 aCanonHost.BeginReading(), sDNSComputerName); 256 return _DNSQuery_A_SingleLabel(aCanonHost, aAddressFamily, aFlags, 257 aAddrInfo); 258 } 259 } 260 #endif 261 262 LOG("Resolving %s using PR_GetAddrInfoByName", aCanonHost.BeginReading()); 263 PRAddrInfo* prai = 264 PR_GetAddrInfoByName(aCanonHost.BeginReading(), aAddressFamily, prFlags); 265 266 if (!prai) { 267 LOG("PR_GetAddrInfoByName returned null PR_GetError:%d PR_GetOSErrpr:%d", 268 PR_GetError(), PR_GetOSError()); 269 return NS_ERROR_UNKNOWN_HOST; 270 } 271 272 nsAutoCString canonName; 273 if (aFlags & nsIDNSService::RESOLVE_CANONICAL_NAME) { 274 canonName.Assign(PR_GetCanonNameFromAddrInfo(prai)); 275 } 276 277 bool filterNameCollision = 278 !(aFlags & nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION); 279 RefPtr<AddrInfo> ai(new AddrInfo(aCanonHost, prai, disableIPv4, 280 filterNameCollision, canonName)); 281 PR_FreeAddrInfo(prai); 282 if (ai->Addresses().IsEmpty()) { 283 LOG("PR_GetAddrInfoByName returned empty address list"); 284 return NS_ERROR_UNKNOWN_HOST; 285 } 286 287 ai.forget(aAddrInfo); 288 289 LOG("PR_GetAddrInfoByName resolved successfully"); 290 return NS_OK; 291 } 292 293 ////////////////////////////////////// 294 // COMMON/PLATFORM INDEPENDENT CODE // 295 ////////////////////////////////////// 296 nsresult GetAddrInfoInit() { 297 LOG("Initializing GetAddrInfo.\n"); 298 299 #ifdef DNSQUERY_AVAILABLE 300 DWORD namesize = COMPUTER_NAME_BUFFER_SIZE; 301 if (!GetComputerNameExA(ComputerNameDnsHostname, sDNSComputerName, 302 &namesize)) { 303 sDNSComputerName[0] = 0; 304 } 305 namesize = MAX_COMPUTERNAME_LENGTH + 1; 306 if (!GetComputerNameExA(ComputerNameNetBIOS, sNETBIOSComputerName, 307 &namesize)) { 308 sNETBIOSComputerName[0] = 0; 309 } 310 #endif 311 return NS_OK; 312 } 313 314 nsresult GetAddrInfoShutdown() { 315 LOG("Shutting down GetAddrInfo.\n"); 316 return NS_OK; 317 } 318 319 bool FindAddrOverride(const nsACString& aHost, uint16_t aAddressFamily, 320 nsIDNSService::DNSFlags aFlags, AddrInfo** aAddrInfo) { 321 RefPtr<NativeDNSResolverOverride> overrideService = gOverrideService; 322 if (!overrideService) { 323 return false; 324 } 325 AutoReadLock lock(overrideService->mLock); 326 auto overrides = overrideService->mOverrides.Lookup(aHost); 327 if (!overrides) { 328 return false; 329 } 330 nsCString* cname = nullptr; 331 if (aFlags & nsIDNSService::RESOLVE_CANONICAL_NAME) { 332 cname = overrideService->mCnames.Lookup(aHost).DataPtrOrNull(); 333 } 334 335 RefPtr<AddrInfo> ai; 336 337 nsTArray<NetAddr> addresses; 338 for (const auto& ip : *overrides) { 339 if (aAddressFamily != AF_UNSPEC && ip.raw.family != aAddressFamily) { 340 continue; 341 } 342 addresses.AppendElement(ip); 343 } 344 345 if (!cname) { 346 ai = new AddrInfo(aHost, DNSResolverType::Native, 0, std::move(addresses)); 347 } else { 348 ai = new AddrInfo(aHost, *cname, DNSResolverType::Native, 0, 349 std::move(addresses)); 350 } 351 352 ai.forget(aAddrInfo); 353 return true; 354 } 355 356 nsresult GetAddrInfo(const nsACString& aHost, uint16_t aAddressFamily, 357 nsIDNSService::DNSFlags aFlags, AddrInfo** aAddrInfo, 358 bool aGetTtl) { 359 if (NS_WARN_IF(aHost.IsEmpty()) || NS_WARN_IF(!aAddrInfo)) { 360 return NS_ERROR_NULL_POINTER; 361 } 362 *aAddrInfo = nullptr; 363 364 if (StaticPrefs::network_dns_disabled()) { 365 return NS_ERROR_UNKNOWN_HOST; 366 } 367 368 #ifdef DNSQUERY_AVAILABLE 369 // The GetTTLData needs the canonical name to function properly 370 if (aGetTtl) { 371 aFlags |= nsIDNSService::RESOLVE_CANONICAL_NAME; 372 } 373 #endif 374 375 // If there is an override for this host, then we synthetize a result. 376 if (gOverrideService && 377 FindAddrOverride(aHost, aAddressFamily, aFlags, aAddrInfo)) { 378 LOG("Returning IP address from NativeDNSResolverOverride"); 379 return (*aAddrInfo)->Addresses().Length() ? NS_OK : NS_ERROR_UNKNOWN_HOST; 380 } 381 382 nsAutoCString host; 383 if (StaticPrefs::network_dns_copy_string_before_call()) { 384 host = Substring(aHost.BeginReading(), aHost.Length()); 385 MOZ_ASSERT(aHost.BeginReading() != host.BeginReading()); 386 } else { 387 host = aHost; 388 } 389 390 if (StaticPrefs::network_dns_native_is_localhost()) { 391 // pretend we use the given host but use IPv4 localhost instead! 392 host = "localhost"_ns; 393 aAddressFamily = PR_AF_INET; 394 } 395 396 RefPtr<AddrInfo> info; 397 nsresult rv = 398 _GetAddrInfo_Portable(host, aAddressFamily, aFlags, getter_AddRefs(info)); 399 400 #ifdef DNSQUERY_AVAILABLE 401 if (aGetTtl && NS_SUCCEEDED(rv)) { 402 // Figure out the canonical name, or if that fails, just use the host name 403 // we have. 404 nsAutoCString name; 405 if (info && !info->CanonicalHostname().IsEmpty()) { 406 name = info->CanonicalHostname(); 407 } else { 408 name = host; 409 } 410 411 LOG("Getting TTL for %s (cname = %s).", host.get(), name.get()); 412 uint32_t ttl = 0; 413 nsresult ttlRv = _GetTTLData_Windows(name, &ttl, aAddressFamily); 414 if (NS_SUCCEEDED(ttlRv)) { 415 auto builder = info->Build(); 416 builder.SetTTL(ttl); 417 info = builder.Finish(); 418 LOG("Got TTL %u for %s (name = %s).", ttl, host.get(), name.get()); 419 } else { 420 LOG_WARNING("Could not get TTL for %s (cname = %s).", host.get(), 421 name.get()); 422 } 423 } 424 #endif 425 426 info.forget(aAddrInfo); 427 return rv; 428 } 429 430 bool FindHTTPSRecordOverride(const nsACString& aHost, 431 TypeRecordResultType& aResult) { 432 LOG("FindHTTPSRecordOverride aHost=%s", nsCString(aHost).get()); 433 RefPtr<NativeDNSResolverOverride> overrideService = gOverrideService; 434 if (!overrideService) { 435 return false; 436 } 437 438 AutoReadLock lock(overrideService->mLock); 439 auto overrides = overrideService->mHTTPSRecordOverrides.Lookup(aHost); 440 if (!overrides) { 441 return false; 442 } 443 444 DNSPacket packet; 445 nsAutoCString host(aHost); 446 447 LOG("resolving %s\n", host.get()); 448 // Perform the query 449 nsresult rv = packet.FillBuffer( 450 [&](unsigned char response[DNSPacket::MAX_SIZE]) -> int { 451 if (overrides->Length() > DNSPacket::MAX_SIZE) { 452 return -1; 453 } 454 memcpy(response, overrides->Elements(), overrides->Length()); 455 return overrides->Length(); 456 }); 457 if (NS_FAILED(rv)) { 458 return false; 459 } 460 461 uint32_t ttl = 0; 462 rv = ParseHTTPSRecord(host, packet, aResult, ttl); 463 464 return NS_SUCCEEDED(rv); 465 } 466 467 nsresult ParseHTTPSRecord(nsCString& aHost, DNSPacket& aDNSPacket, 468 TypeRecordResultType& aResult, uint32_t& aTTL) { 469 nsAutoCString cname; 470 nsresult rv; 471 472 aDNSPacket.SetNativePacket(true); 473 474 int32_t loopCount = 64; 475 while (loopCount > 0 && aResult.is<Nothing>()) { 476 loopCount--; 477 DOHresp resp; 478 nsClassHashtable<nsCStringHashKey, DOHresp> additionalRecords; 479 rv = aDNSPacket.Decode(aHost, TRRTYPE_HTTPSSVC, cname, true, resp, aResult, 480 additionalRecords, aTTL); 481 if (NS_FAILED(rv)) { 482 LOG("Decode failed %x", static_cast<uint32_t>(rv)); 483 return rv; 484 } 485 if (!cname.IsEmpty() && aResult.is<Nothing>()) { 486 aHost = cname; 487 cname.Truncate(); 488 continue; 489 } 490 } 491 492 if (aResult.is<Nothing>()) { 493 LOG("Result is nothing"); 494 // The call succeeded, but no HTTPS records were found. 495 return NS_ERROR_UNKNOWN_HOST; 496 } 497 498 return NS_OK; 499 } 500 501 nsresult ResolveHTTPSRecord(const nsACString& aHost, 502 nsIDNSService::DNSFlags aFlags, 503 TypeRecordResultType& aResult, uint32_t& aTTL) { 504 if (gOverrideService) { 505 return FindHTTPSRecordOverride(aHost, aResult) ? NS_OK 506 : NS_ERROR_UNKNOWN_HOST; 507 } 508 509 return ResolveHTTPSRecordImpl(aHost, aFlags, aResult, aTTL); 510 } 511 512 nsresult CreateAndResolveMockHTTPSRecord(const nsACString& aHost, 513 nsIDNSService::DNSFlags aFlags, 514 TypeRecordResultType& aResult, 515 uint32_t& aTTL) { 516 nsCString buffer; 517 buffer += '\0'; 518 buffer += '\0'; // 16 bit id 519 buffer += 0x80; 520 buffer += '\0'; // Flags 521 buffer += '\0'; 522 buffer += '\0'; // Question count 523 buffer += '\0'; 524 buffer += 0x1; // Answer count 525 buffer += '\0'; 526 buffer += '\0'; 527 buffer += '\0'; 528 buffer += '\0'; 529 530 nsresult rv = DNSPacket::EncodeHost(buffer, aHost); 531 if (NS_FAILED(rv)) { 532 return rv; 533 } 534 535 buffer += '\0'; 536 buffer += 0x41; // TYPE 65 537 538 buffer += '\0'; 539 buffer += 0x1; // Class 540 541 buffer += '\0'; 542 buffer += '\0'; 543 buffer += '\0'; 544 buffer += 0xFF; // TTL 545 buffer += '\0'; 546 buffer += 0x03; // RDLENGTH 547 buffer += '\0'; 548 buffer += 0x01; // SvcPriority 549 buffer += '\0'; 550 551 DNSPacket packet; 552 nsAutoCString host(aHost); 553 554 LOG("resolving %s\n", host.get()); 555 // Perform the query 556 rv = packet.FillBuffer( 557 [&](unsigned char response[DNSPacket::MAX_SIZE]) -> int { 558 if (buffer.Length() > DNSPacket::MAX_SIZE) { 559 return -1; 560 } 561 memcpy(response, buffer.BeginReading(), buffer.Length()); 562 return buffer.Length(); 563 }); 564 if (NS_FAILED(rv)) { 565 return rv; 566 } 567 568 return ParseHTTPSRecord(host, packet, aResult, aTTL); 569 } 570 571 // static 572 already_AddRefed<nsINativeDNSResolverOverride> 573 NativeDNSResolverOverride::GetSingleton() { 574 if (nsIOService::UseSocketProcess() && XRE_IsParentProcess()) { 575 return NativeDNSResolverOverrideParent::GetSingleton(); 576 } 577 578 if (gOverrideService) { 579 return do_AddRef(gOverrideService); 580 } 581 582 gOverrideService = new NativeDNSResolverOverride(); 583 ClearOnShutdown(&gOverrideService); 584 return do_AddRef(gOverrideService); 585 } 586 587 NS_IMPL_ISUPPORTS(NativeDNSResolverOverride, nsINativeDNSResolverOverride) 588 589 NS_IMETHODIMP NativeDNSResolverOverride::AddIPOverride( 590 const nsACString& aHost, const nsACString& aIPLiteral) { 591 NetAddr tempAddr; 592 593 if (aIPLiteral.Equals("N/A"_ns)) { 594 AutoWriteLock lock(mLock); 595 auto& overrides = mOverrides.LookupOrInsert(aHost); 596 overrides.Clear(); 597 return NS_OK; 598 } 599 600 if (NS_FAILED(tempAddr.InitFromString(aIPLiteral))) { 601 return NS_ERROR_UNEXPECTED; 602 } 603 604 AutoWriteLock lock(mLock); 605 auto& overrides = mOverrides.LookupOrInsert(aHost); 606 overrides.AppendElement(tempAddr); 607 608 return NS_OK; 609 } 610 611 NS_IMETHODIMP NativeDNSResolverOverride::AddHTTPSRecordOverride( 612 const nsACString& aHost, const uint8_t* aData, uint32_t aLength) { 613 AutoWriteLock lock(mLock); 614 nsTArray<uint8_t> data(aData, aLength); 615 mHTTPSRecordOverrides.InsertOrUpdate(aHost, std::move(data)); 616 617 return NS_OK; 618 } 619 620 NS_IMETHODIMP NativeDNSResolverOverride::SetCnameOverride( 621 const nsACString& aHost, const nsACString& aCNAME) { 622 if (aCNAME.IsEmpty()) { 623 return NS_ERROR_UNEXPECTED; 624 } 625 626 AutoWriteLock lock(mLock); 627 mCnames.InsertOrUpdate(aHost, nsCString(aCNAME)); 628 629 return NS_OK; 630 } 631 632 NS_IMETHODIMP NativeDNSResolverOverride::ClearHostOverride( 633 const nsACString& aHost) { 634 AutoWriteLock lock(mLock); 635 mCnames.Remove(aHost); 636 auto overrides = mOverrides.Extract(aHost); 637 if (!overrides) { 638 return NS_OK; 639 } 640 641 overrides->Clear(); 642 return NS_OK; 643 } 644 645 NS_IMETHODIMP NativeDNSResolverOverride::ClearOverrides() { 646 AutoWriteLock lock(mLock); 647 mOverrides.Clear(); 648 mCnames.Clear(); 649 return NS_OK; 650 } 651 652 #ifdef MOZ_NO_HTTPS_IMPL 653 654 // If there is no platform specific implementation of ResolveHTTPSRecordImpl 655 // we link a dummy implementation here. 656 // Otherwise this is implemented in PlatformDNSWin/Linux/etc 657 nsresult ResolveHTTPSRecordImpl(const nsACString& aHost, 658 nsIDNSService::DNSFlags aFlags, 659 TypeRecordResultType& aResult, uint32_t& aTTL) { 660 return NS_ERROR_NOT_IMPLEMENTED; 661 } 662 663 void DNSThreadShutdown() {} 664 665 #endif // MOZ_NO_HTTPS_IMPL 666 667 } // namespace mozilla::net