tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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