tor-browser

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

nsDNSService2.cpp (57153B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set sw=2 ts=8 et 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 "nsDNSService2.h"
      8 #include "nsIDNSRecord.h"
      9 #include "nsIDNSListener.h"
     10 #include "nsIDNSByTypeRecord.h"
     11 #include "nsICancelable.h"
     12 #include "nsIPrefBranch.h"
     13 #include "nsIOService.h"
     14 #include "nsIXPConnect.h"
     15 #include "nsProxyRelease.h"
     16 #include "nsReadableUtils.h"
     17 #include "nsString.h"
     18 #include "nsCRT.h"
     19 #include "nsNetCID.h"
     20 #include "nsError.h"
     21 #include "nsDNSPrefetch.h"
     22 #include "nsThreadUtils.h"
     23 #include "nsIProtocolProxyService.h"
     24 #include "nsIObliviousHttp.h"
     25 #include "prsystem.h"
     26 #include "prnetdb.h"
     27 #include "prmon.h"
     28 #include "prio.h"
     29 #include "nsCharSeparatedTokenizer.h"
     30 #include "nsNetAddr.h"
     31 #include "nsNetUtil.h"
     32 #include "nsProxyRelease.h"
     33 #include "nsQueryObject.h"
     34 #include "nsIObserverService.h"
     35 #include "nsINetworkLinkService.h"
     36 #include "DNSAdditionalInfo.h"
     37 #include "TRRService.h"
     38 
     39 #include "mozilla/ClearOnShutdown.h"
     40 #include "mozilla/net/NeckoCommon.h"
     41 #include "mozilla/net/ChildDNSService.h"
     42 #include "mozilla/net/DNSListenerProxy.h"
     43 #include "mozilla/Services.h"
     44 #include "mozilla/StaticPrefs_network.h"
     45 #include "mozilla/StaticPtr.h"
     46 #include "mozilla/SyncRunnable.h"
     47 // Put DNSLogging.h at the end to avoid LOG being overwritten by other headers.
     48 #include "DNSLogging.h"
     49 
     50 using namespace mozilla;
     51 using namespace mozilla::net;
     52 
     53 static const char kPrefDnsCacheEntries[] = "network.dnsCacheEntries";
     54 static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration";
     55 static const char kPrefDnsCacheGrace[] =
     56    "network.dnsCacheExpirationGracePeriod";
     57 static const char kPrefIPv4OnlyDomains[] = "network.dns.ipv4OnlyDomains";
     58 static const char kPrefDnsLocalDomains[] = "network.dns.localDomains";
     59 static const char kPrefDnsForceResolve[] = "network.dns.forceResolve";
     60 static const char kPrefDnsNotifyResolution[] = "network.dns.notifyResolution";
     61 static const char kPrefDnsMockHTTPSRRDomain[] =
     62    "network.dns.mock_HTTPS_RR_domain";
     63 
     64 //-----------------------------------------------------------------------------
     65 
     66 class nsDNSRecord : public nsIDNSAddrRecord {
     67 public:
     68  NS_DECL_THREADSAFE_ISUPPORTS
     69  NS_DECL_NSIDNSRECORD
     70  NS_DECL_NSIDNSADDRRECORD
     71 
     72  explicit nsDNSRecord(nsHostRecord* hostRecord) {
     73    mHostRecord = do_QueryObject(hostRecord);
     74  }
     75 
     76 private:
     77  virtual ~nsDNSRecord() = default;
     78 
     79  RefPtr<AddrHostRecord> mHostRecord;
     80  // Since mIter is holding a weak reference to the NetAddr array we must
     81  // make sure it is not released. So we also keep a RefPtr to the AddrInfo
     82  // which is immutable.
     83  RefPtr<AddrInfo> mAddrInfo;
     84  nsTArray<NetAddr>::const_iterator mIter;
     85  const NetAddr* iter() {
     86    if (!mIter.GetArray()) {
     87      return nullptr;
     88    }
     89    if (mIter.GetArray()->end() == mIter) {
     90      return nullptr;
     91    }
     92    return &*mIter;
     93  }
     94 
     95  int mIterGenCnt = -1;  // the generation count of
     96                         // mHostRecord->addr_info when we
     97                         // start iterating
     98  bool mDone = false;
     99 };
    100 
    101 NS_IMPL_ISUPPORTS(nsDNSRecord, nsIDNSRecord, nsIDNSAddrRecord)
    102 
    103 NS_IMETHODIMP
    104 nsDNSRecord::GetCanonicalName(nsACString& result) {
    105  // this method should only be called if we have a CNAME
    106  NS_ENSURE_TRUE(mHostRecord->flags & nsIDNSService::RESOLVE_CANONICAL_NAME,
    107                 NS_ERROR_NOT_AVAILABLE);
    108 
    109  MutexAutoLock lock(mHostRecord->addr_info_lock);
    110 
    111  // if the record is for an IP address literal, then the canonical
    112  // host name is the IP address literal.
    113  if (!mHostRecord->addr_info) {
    114    result = mHostRecord->host;
    115    return NS_OK;
    116  }
    117 
    118  if (mHostRecord->addr_info->CanonicalHostname().IsEmpty()) {
    119    result = mHostRecord->addr_info->Hostname();
    120  } else {
    121    result = mHostRecord->addr_info->CanonicalHostname();
    122  }
    123  return NS_OK;
    124 }
    125 
    126 NS_IMETHODIMP
    127 nsDNSRecord::IsTRR(bool* retval) {
    128  MutexAutoLock lock(mHostRecord->addr_info_lock);
    129  if (mHostRecord->addr_info) {
    130    *retval = mHostRecord->addr_info->IsTRR();
    131  } else {
    132    *retval = false;
    133  }
    134  return NS_OK;
    135 }
    136 
    137 NS_IMETHODIMP
    138 nsDNSRecord::ResolvedInSocketProcess(bool* retval) {
    139  *retval = false;
    140  return NS_OK;
    141 }
    142 
    143 NS_IMETHODIMP
    144 nsDNSRecord::GetTrrFetchDuration(double* aTime) {
    145  MutexAutoLock lock(mHostRecord->addr_info_lock);
    146  if (mHostRecord->addr_info && mHostRecord->addr_info->IsTRR()) {
    147    *aTime = mHostRecord->addr_info->GetTrrFetchDuration();
    148  } else {
    149    *aTime = 0;
    150  }
    151  return NS_OK;
    152 }
    153 
    154 NS_IMETHODIMP
    155 nsDNSRecord::GetTrrFetchDurationNetworkOnly(double* aTime) {
    156  MutexAutoLock lock(mHostRecord->addr_info_lock);
    157  if (mHostRecord->addr_info && mHostRecord->addr_info->IsTRR()) {
    158    *aTime = mHostRecord->addr_info->GetTrrFetchDurationNetworkOnly();
    159  } else {
    160    *aTime = 0;
    161  }
    162  return NS_OK;
    163 }
    164 
    165 NS_IMETHODIMP
    166 nsDNSRecord::GetNextAddr(uint16_t port, NetAddr* addr) {
    167  if (mDone) {
    168    return NS_ERROR_NOT_AVAILABLE;
    169  }
    170 
    171  mHostRecord->addr_info_lock.Lock();
    172  if (mHostRecord->addr_info) {
    173    if (mIterGenCnt != mHostRecord->addr_info_gencnt) {
    174      // mHostRecord->addr_info has changed, restart the iteration.
    175      mIter = nsTArray<NetAddr>::const_iterator();
    176      mIterGenCnt = mHostRecord->addr_info_gencnt;
    177      // Make sure to hold a RefPtr to the AddrInfo so we can iterate through
    178      // the NetAddr array.
    179      mAddrInfo = mHostRecord->addr_info;
    180    }
    181 
    182    bool startedFresh = !iter();
    183 
    184    do {
    185      if (!iter()) {
    186        mIter = mAddrInfo->Addresses().begin();
    187      } else {
    188        mIter++;
    189      }
    190    } while (iter() && mHostRecord->Blocklisted(iter()));
    191 
    192    if (!iter() && startedFresh) {
    193      // If everything was blocklisted we want to reset the blocklist (and
    194      // likely relearn it) and return the first address. That is better
    195      // than nothing.
    196      mHostRecord->ResetBlocklist();
    197      mIter = mAddrInfo->Addresses().begin();
    198    }
    199 
    200    if (iter()) {
    201      *addr = *mIter;
    202    }
    203 
    204    mHostRecord->addr_info_lock.Unlock();
    205 
    206    if (!iter()) {
    207      mDone = true;
    208      mIter = nsTArray<NetAddr>::const_iterator();
    209      mAddrInfo = nullptr;
    210      mIterGenCnt = -1;
    211      return NS_ERROR_NOT_AVAILABLE;
    212    }
    213  } else {
    214    mHostRecord->addr_info_lock.Unlock();
    215 
    216    if (!mHostRecord->addr) {
    217      // Both mHostRecord->addr_info and mHostRecord->addr are null.
    218      // This can happen if mHostRecord->addr_info expired and the
    219      // attempt to reresolve it failed.
    220      return NS_ERROR_NOT_AVAILABLE;
    221    }
    222    *addr = *mHostRecord->addr;
    223    mDone = true;
    224  }
    225 
    226  // set given port
    227  port = htons(port);
    228  if (addr->raw.family == AF_INET) {
    229    addr->inet.port = port;
    230  } else if (addr->raw.family == AF_INET6) {
    231    addr->inet6.port = port;
    232  }
    233 
    234  return NS_OK;
    235 }
    236 
    237 NS_IMETHODIMP
    238 nsDNSRecord::GetAddresses(nsTArray<NetAddr>& aAddressArray) {
    239  if (mDone) {
    240    return NS_ERROR_NOT_AVAILABLE;
    241  }
    242 
    243  mHostRecord->addr_info_lock.Lock();
    244  if (mHostRecord->addr_info) {
    245    for (const auto& address : mHostRecord->addr_info->Addresses()) {
    246      if (mHostRecord->Blocklisted(&address)) {
    247        continue;
    248      }
    249      NetAddr* addr = aAddressArray.AppendElement(address);
    250      if (addr->raw.family == AF_INET) {
    251        addr->inet.port = 0;
    252      } else if (addr->raw.family == AF_INET6) {
    253        addr->inet6.port = 0;
    254      }
    255    }
    256    mHostRecord->addr_info_lock.Unlock();
    257  } else {
    258    mHostRecord->addr_info_lock.Unlock();
    259 
    260    if (!mHostRecord->addr) {
    261      return NS_ERROR_NOT_AVAILABLE;
    262    }
    263    NetAddr* addr = aAddressArray.AppendElement(NetAddr());
    264    *addr = *mHostRecord->addr;
    265    if (addr->raw.family == AF_INET) {
    266      addr->inet.port = 0;
    267    } else if (addr->raw.family == AF_INET6) {
    268      addr->inet6.port = 0;
    269    }
    270  }
    271  return NS_OK;
    272 }
    273 
    274 NS_IMETHODIMP
    275 nsDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr** result) {
    276  NetAddr addr;
    277  nsresult rv = GetNextAddr(port, &addr);
    278  if (NS_FAILED(rv)) {
    279    return rv;
    280  }
    281 
    282  RefPtr<nsNetAddr> netaddr = new nsNetAddr(&addr);
    283  netaddr.forget(result);
    284 
    285  return NS_OK;
    286 }
    287 
    288 NS_IMETHODIMP
    289 nsDNSRecord::GetNextAddrAsString(nsACString& result) {
    290  NetAddr addr;
    291  nsresult rv = GetNextAddr(0, &addr);
    292  if (NS_FAILED(rv)) {
    293    return rv;
    294  }
    295 
    296  char buf[kIPv6CStrBufSize];
    297  if (addr.ToStringBuffer(buf, sizeof(buf))) {
    298    result.Assign(buf);
    299    return NS_OK;
    300  }
    301  NS_ERROR("NetAddrToString failed unexpectedly");
    302  return NS_ERROR_FAILURE;  // conversion failed for some reason
    303 }
    304 
    305 NS_IMETHODIMP
    306 nsDNSRecord::HasMore(bool* result) {
    307  if (mDone) {
    308    *result = false;
    309    return NS_OK;
    310  }
    311 
    312  nsTArray<NetAddr>::const_iterator iterCopy = mIter;
    313  int iterGenCntCopy = mIterGenCnt;
    314 
    315  NetAddr addr;
    316  *result = NS_SUCCEEDED(GetNextAddr(0, &addr));
    317 
    318  mIter = iterCopy;
    319  mIterGenCnt = iterGenCntCopy;
    320  mDone = false;
    321 
    322  return NS_OK;
    323 }
    324 
    325 NS_IMETHODIMP
    326 nsDNSRecord::Rewind() {
    327  mIter = nsTArray<NetAddr>::const_iterator();
    328  mIterGenCnt = -1;
    329  mDone = false;
    330  return NS_OK;
    331 }
    332 
    333 NS_IMETHODIMP
    334 nsDNSRecord::ReportUnusable(uint16_t aPort) {
    335  // right now we don't use the port in the blocklist
    336 
    337  MutexAutoLock lock(mHostRecord->addr_info_lock);
    338 
    339  // Check that we are using a real addr_info (as opposed to a single
    340  // constant address), and that the generation count is valid. Otherwise,
    341  // ignore the report.
    342 
    343  if (mHostRecord->addr_info && mIterGenCnt == mHostRecord->addr_info_gencnt &&
    344      iter()) {
    345    mHostRecord->ReportUnusable(iter());
    346  }
    347 
    348  return NS_OK;
    349 }
    350 
    351 NS_IMETHODIMP
    352 nsDNSRecord::GetEffectiveTRRMode(nsIRequest::TRRMode* aMode) {
    353  *aMode = mHostRecord->EffectiveTRRMode();
    354  return NS_OK;
    355 }
    356 
    357 NS_IMETHODIMP nsDNSRecord::GetTrrSkipReason(
    358    nsITRRSkipReason::value* aTrrSkipReason) {
    359  *aTrrSkipReason = mHostRecord->TrrSkipReason();
    360  return NS_OK;
    361 }
    362 
    363 NS_IMETHODIMP
    364 nsDNSRecord::GetTtl(uint32_t* aTtl) { return mHostRecord->GetTtl(aTtl); }
    365 
    366 NS_IMETHODIMP
    367 nsDNSRecord::GetLastUpdate(mozilla::TimeStamp* aLastUpdate) {
    368  MutexAutoLock lock(mHostRecord->addr_info_lock);
    369  return mHostRecord->GetLastUpdate(aLastUpdate);
    370 }
    371 
    372 class nsDNSByTypeRecord : public nsIDNSByTypeRecord,
    373                          public nsIDNSTXTRecord,
    374                          public nsIDNSHTTPSSVCRecord {
    375 public:
    376  NS_DECL_THREADSAFE_ISUPPORTS
    377  NS_DECL_NSIDNSRECORD
    378  NS_DECL_NSIDNSBYTYPERECORD
    379  NS_DECL_NSIDNSTXTRECORD
    380  NS_DECL_NSIDNSHTTPSSVCRECORD
    381 
    382  explicit nsDNSByTypeRecord(nsHostRecord* hostRecord) {
    383    mHostRecord = do_QueryObject(hostRecord);
    384  }
    385 
    386 private:
    387  virtual ~nsDNSByTypeRecord() = default;
    388  RefPtr<TypeHostRecord> mHostRecord;
    389 };
    390 
    391 NS_IMPL_ISUPPORTS(nsDNSByTypeRecord, nsIDNSRecord, nsIDNSByTypeRecord,
    392                  nsIDNSTXTRecord, nsIDNSHTTPSSVCRecord)
    393 
    394 NS_IMETHODIMP
    395 nsDNSByTypeRecord::GetType(uint32_t* aType) {
    396  *aType = mHostRecord->GetType();
    397  return NS_OK;
    398 }
    399 
    400 NS_IMETHODIMP
    401 nsDNSByTypeRecord::GetRecords(CopyableTArray<nsCString>& aRecords) {
    402  // deep copy
    403  return mHostRecord->GetRecords(aRecords);
    404 }
    405 
    406 NS_IMETHODIMP
    407 nsDNSByTypeRecord::GetRecordsAsOneString(nsACString& aRecords) {
    408  // deep copy
    409  return mHostRecord->GetRecordsAsOneString(aRecords);
    410 }
    411 
    412 NS_IMETHODIMP
    413 nsDNSByTypeRecord::GetRecords(nsTArray<RefPtr<nsISVCBRecord>>& aRecords) {
    414  return mHostRecord->GetRecords(aRecords);
    415 }
    416 
    417 NS_IMETHODIMP
    418 nsDNSByTypeRecord::GetServiceModeRecord(bool aNoHttp2, bool aNoHttp3,
    419                                        nsISVCBRecord** aRecord) {
    420  return mHostRecord->GetServiceModeRecord(aNoHttp2, aNoHttp3, aRecord);
    421 }
    422 
    423 NS_IMETHODIMP
    424 nsDNSByTypeRecord::GetServiceModeRecordWithCname(bool aNoHttp2, bool aNoHttp3,
    425                                                 const nsACString& aCname,
    426                                                 nsISVCBRecord** aRecord) {
    427  return mHostRecord->GetServiceModeRecordWithCname(aNoHttp2, aNoHttp3, aCname,
    428                                                    aRecord);
    429 }
    430 
    431 NS_IMETHODIMP
    432 nsDNSByTypeRecord::IsTRR(bool* aResult) { return mHostRecord->IsTRR(aResult); }
    433 
    434 NS_IMETHODIMP
    435 nsDNSByTypeRecord::GetAllRecords(bool aNoHttp2, bool aNoHttp3,
    436                                 const nsACString& aCname,
    437                                 nsTArray<RefPtr<nsISVCBRecord>>& aResult) {
    438  return mHostRecord->GetAllRecords(aNoHttp2, aNoHttp3, aCname, aResult);
    439 }
    440 
    441 NS_IMETHODIMP
    442 nsDNSByTypeRecord::GetAllRecordsWithEchConfig(
    443    bool aNoHttp2, bool aNoHttp3, const nsACString& aCname,
    444    bool* aAllRecordsHaveEchConfig, bool* aAllRecordsInH3ExcludedList,
    445    nsTArray<RefPtr<nsISVCBRecord>>& aResult) {
    446  return mHostRecord->GetAllRecordsWithEchConfig(
    447      aNoHttp2, aNoHttp3, aCname, aAllRecordsHaveEchConfig,
    448      aAllRecordsInH3ExcludedList, aResult);
    449 }
    450 
    451 NS_IMETHODIMP
    452 nsDNSByTypeRecord::GetHasIPAddresses(bool* aResult) {
    453  return mHostRecord->GetHasIPAddresses(aResult);
    454 }
    455 
    456 NS_IMETHODIMP
    457 nsDNSByTypeRecord::GetAllRecordsExcluded(bool* aResult) {
    458  return mHostRecord->GetAllRecordsExcluded(aResult);
    459 }
    460 
    461 NS_IMETHODIMP
    462 nsDNSByTypeRecord::GetResults(mozilla::net::TypeRecordResultType* aResults) {
    463  *aResults = mHostRecord->GetResults();
    464  return NS_OK;
    465 }
    466 
    467 NS_IMETHODIMP
    468 nsDNSByTypeRecord::GetTtl(uint32_t* aTtl) { return mHostRecord->GetTtl(aTtl); }
    469 
    470 //-----------------------------------------------------------------------------
    471 
    472 class nsDNSAsyncRequest final : public nsResolveHostCallback,
    473                                public nsICancelable {
    474 public:
    475  NS_DECL_THREADSAFE_ISUPPORTS
    476  NS_DECL_NSICANCELABLE
    477 
    478  nsDNSAsyncRequest(nsHostResolver* res, const nsACString& host,
    479                    const nsACString& trrServer, uint16_t type,
    480                    const OriginAttributes& attrs, nsIDNSListener* listener,
    481                    nsIDNSService::DNSFlags flags, uint16_t af)
    482      : mResolver(res),
    483        mHost(host),
    484        mTrrServer(trrServer),
    485        mType(type),
    486        mOriginAttributes(attrs),
    487        mListener(listener),
    488        mFlags(flags),
    489        mAF(af) {}
    490 
    491  void OnResolveHostComplete(nsHostResolver*, nsHostRecord*, nsresult) override;
    492  // Returns TRUE if the DNS listener arg is the same as the member listener
    493  // Used in Cancellations to remove DNS requests associated with a
    494  // particular hostname and nsIDNSListener
    495  bool EqualsAsyncListener(nsIDNSListener* aListener) override;
    496 
    497  size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const override;
    498 
    499  RefPtr<nsHostResolver> mResolver;
    500  nsCString mHost;       // hostname we're resolving
    501  nsCString mTrrServer;  // A trr server to be used.
    502  uint16_t mType = 0;
    503  const OriginAttributes
    504      mOriginAttributes;  // The originAttributes for this resolving
    505  nsCOMPtr<nsIDNSListener> mListener;
    506  nsIDNSService::DNSFlags mFlags = nsIDNSService::RESOLVE_DEFAULT_FLAGS;
    507  uint16_t mAF = 0;
    508 
    509 private:
    510  virtual ~nsDNSAsyncRequest() = default;
    511 };
    512 
    513 NS_IMPL_ISUPPORTS(nsDNSAsyncRequest, nsICancelable)
    514 
    515 void nsDNSAsyncRequest::OnResolveHostComplete(nsHostResolver* resolver,
    516                                              nsHostRecord* hostRecord,
    517                                              nsresult status) {
    518  // need to have an owning ref when we issue the callback to enable
    519  // the caller to be able to addref/release multiple times without
    520  // destroying the record prematurely.
    521  nsCOMPtr<nsIDNSRecord> rec;
    522  if (NS_SUCCEEDED(status) ||
    523      mFlags & nsIDNSService::RESOLVE_WANT_RECORD_ON_ERROR) {
    524    MOZ_ASSERT(hostRecord, "no host record");
    525    if (!hostRecord) {
    526      mListener->OnLookupComplete(this, nullptr, NS_ERROR_UNKNOWN_HOST);
    527      mListener = nullptr;
    528      return;
    529    }
    530    if (hostRecord->type != nsDNSService::RESOLVE_TYPE_DEFAULT) {
    531      rec = new nsDNSByTypeRecord(hostRecord);
    532    } else {
    533      rec = new nsDNSRecord(hostRecord);
    534    }
    535  }
    536 
    537  LOG(("OnResolveHostComplete: %s", mHost.get()));
    538  mListener->OnLookupComplete(this, rec, status);
    539  mListener = nullptr;
    540 }
    541 
    542 bool nsDNSAsyncRequest::EqualsAsyncListener(nsIDNSListener* aListener) {
    543  uintptr_t originalListenerAddr = reinterpret_cast<uintptr_t>(mListener.get());
    544  RefPtr<DNSListenerProxy> wrapper = do_QueryObject(mListener);
    545  if (wrapper) {
    546    originalListenerAddr = wrapper->GetOriginalListenerAddress();
    547  }
    548 
    549  uintptr_t listenerAddr = reinterpret_cast<uintptr_t>(aListener);
    550  return (listenerAddr == originalListenerAddr);
    551 }
    552 
    553 size_t nsDNSAsyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
    554  size_t n = mallocSizeOf(this);
    555 
    556  // The following fields aren't measured.
    557  // - mHost, because it's a non-owning pointer
    558  // - mResolver, because it's a non-owning pointer
    559  // - mListener, because it's a non-owning pointer
    560 
    561  return n;
    562 }
    563 
    564 NS_IMETHODIMP
    565 nsDNSAsyncRequest::Cancel(nsresult reason) {
    566  NS_ENSURE_ARG(NS_FAILED(reason));
    567  MOZ_DIAGNOSTIC_ASSERT(mResolver, "mResolver should not be null");
    568  mResolver->DetachCallback(mHost, mTrrServer, mType, mOriginAttributes, mFlags,
    569                            mAF, this, reason);
    570  return NS_OK;
    571 }
    572 
    573 //-----------------------------------------------------------------------------
    574 
    575 class DNSCacheRequest : public nsResolveHostCallback {
    576 public:
    577  NS_DECL_THREADSAFE_ISUPPORTS
    578 
    579  DNSCacheRequest() = default;
    580 
    581  void OnResolveHostComplete(nsHostResolver* resolver, nsHostRecord* hostRecord,
    582                             nsresult status) override {
    583    mStatus = status;
    584    mHostRecord = hostRecord;
    585  }
    586 
    587  bool EqualsAsyncListener(nsIDNSListener* aListener) override {
    588    // Sync request: no listener to compare
    589    return false;
    590  }
    591 
    592  size_t SizeOfIncludingThis(
    593      mozilla::MallocSizeOf mallocSizeOf) const override {
    594    size_t n = mallocSizeOf(this);
    595 
    596    // The following fields aren't measured.
    597    // - mHostRecord, because it's a non-owning pointer
    598 
    599    // Measurement of the following members may be added later if DMD finds it
    600    // is worthwhile:
    601    // - nsDNSSyncRequest::mMonitor
    602 
    603    return n;
    604  }
    605 
    606  nsresult mStatus = NS_OK;
    607  RefPtr<nsHostRecord> mHostRecord;
    608 
    609 protected:
    610  virtual ~DNSCacheRequest() = default;
    611 };
    612 
    613 NS_IMPL_ISUPPORTS0(DNSCacheRequest)
    614 
    615 class nsDNSSyncRequest : public DNSCacheRequest {
    616 public:
    617  explicit nsDNSSyncRequest(PRMonitor* mon) : mMonitor(mon) {}
    618 
    619  void OnResolveHostComplete(nsHostResolver*, nsHostRecord*, nsresult) override;
    620 
    621  bool mDone = false;
    622 
    623 private:
    624  virtual ~nsDNSSyncRequest() = default;
    625 
    626  PRMonitor* mMonitor = nullptr;
    627 };
    628 
    629 void nsDNSSyncRequest::OnResolveHostComplete(nsHostResolver* resolver,
    630                                             nsHostRecord* hostRecord,
    631                                             nsresult status) {
    632  // store results, and wake up nsDNSService::Resolve to process results.
    633  PR_EnterMonitor(mMonitor);
    634  mDone = true;
    635  DNSCacheRequest::OnResolveHostComplete(resolver, hostRecord, status);
    636  PR_Notify(mMonitor);
    637  PR_ExitMonitor(mMonitor);
    638 }
    639 
    640 class NotifyDNSResolution : public Runnable {
    641 public:
    642  explicit NotifyDNSResolution(const nsACString& aHostname)
    643      : mozilla::Runnable("NotifyDNSResolution"), mHostname(aHostname) {}
    644 
    645  NS_IMETHOD Run() override {
    646    MOZ_ASSERT(NS_IsMainThread());
    647    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
    648    if (obs) {
    649      obs->NotifyObservers(nullptr, "dns-resolution-request",
    650                           NS_ConvertUTF8toUTF16(mHostname).get());
    651    }
    652    return NS_OK;
    653  }
    654 
    655 private:
    656  nsCString mHostname;
    657 };
    658 
    659 //-----------------------------------------------------------------------------
    660 
    661 static StaticRefPtr<DNSServiceWrapper> gDNSServiceWrapper;
    662 
    663 NS_IMPL_ISUPPORTS(DNSServiceWrapper, nsIDNSService, nsPIDNSService)
    664 
    665 // static
    666 already_AddRefed<nsIDNSService> DNSServiceWrapper::GetSingleton() {
    667  if (!gDNSServiceWrapper) {
    668    gDNSServiceWrapper = new DNSServiceWrapper();
    669    // Not strictly needed, but simple and avoids bypassing lock-checking
    670    MutexAutoLock lock(gDNSServiceWrapper->mLock);
    671    gDNSServiceWrapper->mDNSServiceInUse = ChildDNSService::GetSingleton();
    672    if (gDNSServiceWrapper->mDNSServiceInUse) {
    673      ClearOnShutdown(&gDNSServiceWrapper);
    674      nsDNSPrefetch::Initialize(gDNSServiceWrapper);
    675    } else {
    676      MutexAutoUnlock unlock(
    677          gDNSServiceWrapper->mLock);  // don't destroy with held lock
    678      gDNSServiceWrapper = nullptr;
    679    }
    680  }
    681 
    682  return do_AddRef(gDNSServiceWrapper);
    683 }
    684 
    685 // static
    686 void DNSServiceWrapper::SwitchToBackupDNSService() {
    687  if (!gDNSServiceWrapper) {
    688    return;
    689  }
    690 
    691  gDNSServiceWrapper->mBackupDNSService = nsDNSService::GetSingleton();
    692 
    693  MutexAutoLock lock(gDNSServiceWrapper->mLock);
    694  gDNSServiceWrapper->mBackupDNSService.swap(
    695      gDNSServiceWrapper->mDNSServiceInUse);
    696 }
    697 
    698 nsIDNSService* DNSServiceWrapper::DNSService() {
    699  MOZ_ASSERT(XRE_IsParentProcess());
    700 
    701  MutexAutoLock lock(mLock);
    702  return mDNSServiceInUse.get();
    703 }
    704 
    705 nsPIDNSService* DNSServiceWrapper::PIDNSService() {
    706  MOZ_ASSERT(XRE_IsParentProcess());
    707 
    708  nsCOMPtr<nsPIDNSService> service = do_QueryInterface(DNSService());
    709  return service.get();
    710 }
    711 
    712 //-----------------------------------------------------------------------------
    713 NS_IMPL_ISUPPORTS_INHERITED(nsDNSService, DNSServiceBase, nsIDNSService,
    714                            nsPIDNSService, nsIMemoryReporter)
    715 
    716 /******************************************************************************
    717 * nsDNSService impl:
    718 * singleton instance ctor/dtor methods
    719 ******************************************************************************/
    720 static StaticRefPtr<nsDNSService> gDNSService;
    721 static Atomic<bool> gInited(false);
    722 
    723 // Note: be careful of races!  Called from multiple threads
    724 already_AddRefed<nsIDNSService> GetOrInitDNSService() {
    725  if (gInited) {
    726    return nsDNSService::GetXPCOMSingleton();
    727  }
    728 
    729  nsCOMPtr<nsIDNSService> dns = nullptr;
    730  auto initTask = [&dns]() {
    731    // In case someone inited it while we were waiting
    732    if (gInited) {
    733      dns = nsDNSService::GetXPCOMSingleton();
    734      return;
    735    }
    736    dns = do_GetService(NS_DNSSERVICE_CID);
    737  };
    738  if (!NS_IsMainThread()) {
    739    // Forward to the main thread synchronously.
    740    RefPtr<nsIThread> mainThread = do_GetMainThread();
    741    if (!mainThread) {
    742      return nullptr;
    743    }
    744 
    745    SyncRunnable::DispatchToThread(
    746        mainThread, NS_NewRunnableFunction("GetOrInitDNSService", initTask));
    747  } else {
    748    initTask();
    749  }
    750 
    751  return dns.forget();
    752 }
    753 
    754 already_AddRefed<nsIDNSService> nsDNSService::GetXPCOMSingleton() {
    755  auto getDNSHelper = []() -> already_AddRefed<nsIDNSService> {
    756    if (nsIOService::UseSocketProcess()) {
    757      if (XRE_IsSocketProcess()) {
    758        return GetSingleton();
    759      }
    760 
    761      if (XRE_IsParentProcess()) {
    762        return DNSServiceWrapper::GetSingleton();
    763      }
    764 
    765      if (XRE_IsContentProcess()) {
    766        return ChildDNSService::GetSingleton();
    767      }
    768 
    769      return nullptr;
    770    }
    771 
    772    if (XRE_IsParentProcess()) {
    773      return GetSingleton();
    774    }
    775 
    776    if (XRE_IsContentProcess() || XRE_IsSocketProcess()) {
    777      return ChildDNSService::GetSingleton();
    778    }
    779 
    780    return nullptr;
    781  };
    782 
    783  if (gInited) {
    784    return getDNSHelper();
    785  }
    786 
    787  nsCOMPtr<nsIDNSService> dns = getDNSHelper();
    788  if (dns) {
    789    gInited = true;
    790  }
    791  return dns.forget();
    792 }
    793 
    794 already_AddRefed<nsDNSService> nsDNSService::GetSingleton() {
    795  MOZ_ASSERT_IF(nsIOService::UseSocketProcess(), XRE_IsSocketProcess());
    796  MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(), XRE_IsParentProcess());
    797 
    798  if (!gDNSService) {
    799    if (!NS_IsMainThread()) {
    800      return nullptr;
    801    }
    802    gDNSService = new nsDNSService();
    803    if (NS_SUCCEEDED(gDNSService->Init())) {
    804      ClearOnShutdown(&gDNSService);
    805    } else {
    806      gDNSService = nullptr;
    807    }
    808  }
    809 
    810  return do_AddRef(gDNSService);
    811 }
    812 
    813 void nsDNSService::ReadPrefs(const char* name) {
    814  DNSServiceBase::ReadPrefs(name);
    815 
    816  bool tmpbool;
    817 
    818  // DNSservice prefs
    819  if (!name || !strcmp(name, kPrefDnsNotifyResolution)) {
    820    if (NS_SUCCEEDED(
    821            Preferences::GetBool(kPrefDnsNotifyResolution, &tmpbool))) {
    822      mNotifyResolution = tmpbool;
    823    }
    824  }
    825  if (!name || !strcmp(name, kPrefIPv4OnlyDomains)) {
    826    MutexAutoLock lock(mLock);
    827    Preferences::GetCString(kPrefIPv4OnlyDomains, mIPv4OnlyDomains);
    828  }
    829  if (!name || !strcmp(name, kPrefDnsLocalDomains)) {
    830    nsCString localDomains;
    831    Preferences::GetCString(kPrefDnsLocalDomains, localDomains);
    832    MutexAutoLock lock(mLock);
    833    mLocalDomains.Clear();
    834    for (const auto& token :
    835         nsCCharSeparatedTokenizerTemplate<NS_IsAsciiWhitespace,
    836                                           nsTokenizerFlags::SeparatorOptional>(
    837             localDomains, ',')
    838             .ToRange()) {
    839      mLocalDomains.Insert(token);
    840    }
    841  }
    842  if (!name || !strcmp(name, kPrefDnsForceResolve)) {
    843    Preferences::GetCString(kPrefDnsForceResolve, mForceResolve);
    844    mForceResolveOn = !mForceResolve.IsEmpty();
    845  }
    846  if (!name || !strcmp(name, kPrefDnsMockHTTPSRRDomain)) {
    847    nsCString mockHTTPSRRDomain;
    848    Preferences::GetCString(kPrefDnsMockHTTPSRRDomain, mockHTTPSRRDomain);
    849    if (mockHTTPSRRDomain.IsEmpty()) {
    850      mHasMockHTTPSRRDomainSet = false;
    851    } else {
    852      mHasMockHTTPSRRDomainSet = true;
    853      MutexAutoLock lock(mLock);
    854      mMockHTTPSRRDomain = mockHTTPSRRDomain;
    855    }
    856  }
    857 }
    858 
    859 NS_IMETHODIMP
    860 nsDNSService::Init() {
    861  MOZ_ASSERT(NS_IsMainThread());
    862 
    863  ReadPrefs(nullptr);
    864 
    865  nsCOMPtr<nsIObserverService> observerService =
    866      mozilla::services::GetObserverService();
    867  if (observerService) {
    868    observerService->AddObserver(this, "last-pb-context-exited", false);
    869    observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
    870    observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
    871  }
    872 
    873  RefPtr<nsHostResolver> res;
    874  nsresult rv = nsHostResolver::Create(getter_AddRefs(res));
    875  if (NS_SUCCEEDED(rv)) {
    876    // now, set all of our member variables while holding the lock
    877    MutexAutoLock lock(mLock);
    878    MOZ_ASSERT(!mResolver);
    879    mResolver = res;
    880  }
    881 
    882  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
    883  if (prefs) {
    884    // register as prefs observer
    885    prefs->AddObserver(kPrefDnsCacheEntries, this, false);
    886    prefs->AddObserver(kPrefDnsCacheExpiration, this, false);
    887    prefs->AddObserver(kPrefDnsCacheGrace, this, false);
    888    prefs->AddObserver(kPrefIPv4OnlyDomains, this, false);
    889    prefs->AddObserver(kPrefDnsLocalDomains, this, false);
    890    prefs->AddObserver(kPrefDnsForceResolve, this, false);
    891    prefs->AddObserver(kPrefDnsNotifyResolution, this, false);
    892    prefs->AddObserver(kPrefDnsMockHTTPSRRDomain, this, false);
    893    AddPrefObserver(prefs);
    894  }
    895 
    896  nsDNSPrefetch::Initialize(this);
    897 
    898  RegisterWeakMemoryReporter(this);
    899 
    900  nsCOMPtr<nsIObliviousHttpService> ohttpService(
    901      do_GetService("@mozilla.org/network/oblivious-http-service;1"));
    902 
    903  mTrrService = new TRRService();
    904  bool httpsEnabled;
    905  {
    906    MutexAutoLock lock(mLock);
    907    httpsEnabled = mResolver->IsNativeHTTPSEnabled();
    908  }
    909  if (NS_FAILED(mTrrService->Init(httpsEnabled))) {
    910    mTrrService = nullptr;
    911  }
    912 
    913  return NS_OK;
    914 }
    915 
    916 NS_IMETHODIMP
    917 nsDNSService::Shutdown() {
    918  UnregisterWeakMemoryReporter(this);
    919 
    920  RefPtr<nsHostResolver> res;
    921  {
    922    MutexAutoLock lock(mLock);
    923    res = std::move(mResolver);
    924  }
    925  if (res) {
    926    // Shutdown outside lock.
    927    res->Shutdown();
    928  }
    929 
    930  nsCOMPtr<nsIObserverService> observerService =
    931      mozilla::services::GetObserverService();
    932  if (observerService) {
    933    observerService->RemoveObserver(this, NS_NETWORK_LINK_TOPIC);
    934    observerService->RemoveObserver(this, "last-pb-context-exited");
    935    observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
    936  }
    937 
    938  return NS_OK;
    939 }
    940 
    941 bool nsDNSService::GetOffline() const {
    942  bool offline = false;
    943  nsCOMPtr<nsIIOService> io = do_GetService(NS_IOSERVICE_CONTRACTID);
    944  if (io) {
    945    io->GetOffline(&offline);
    946  }
    947  return offline;
    948 }
    949 
    950 NS_IMETHODIMP
    951 nsDNSService::GetPrefetchEnabled(bool* outVal) {
    952  MutexAutoLock lock(mLock);
    953  *outVal = !mDisablePrefetch;
    954  return NS_OK;
    955 }
    956 
    957 NS_IMETHODIMP
    958 nsDNSService::SetPrefetchEnabled(bool inVal) {
    959  MutexAutoLock lock(mLock);
    960  mDisablePrefetch = !inVal;
    961  return NS_OK;
    962 }
    963 
    964 already_AddRefed<nsHostResolver> nsDNSService::GetResolverLocked() {
    965  MutexAutoLock lock(mLock);
    966  return do_AddRef(mResolver);
    967 }
    968 
    969 nsresult nsDNSService::PreprocessHostname(bool aLocalDomain,
    970                                          const nsACString& aInput,
    971                                          nsACString& aACE) {
    972  // Enforce RFC 7686
    973  if (StaticPrefs::network_dns_blockDotOnion() &&
    974      StringEndsWith(aInput, ".onion"_ns)) {
    975    return NS_ERROR_UNKNOWN_HOST;
    976  }
    977 
    978  if (aLocalDomain) {
    979    aACE.AssignLiteral("localhost");
    980    return NS_OK;
    981  }
    982 
    983  if (mTrrService && mTrrService->MaybeBootstrap(aInput, aACE)) {
    984    return NS_OK;
    985  }
    986 
    987  if (mForceResolveOn) {
    988    MutexAutoLock lock(mLock);
    989    if (!aInput.LowerCaseEqualsASCII("localhost") &&
    990        !aInput.LowerCaseEqualsASCII("127.0.0.1")) {
    991      aACE.Assign(mForceResolve);
    992      return NS_OK;
    993    }
    994  }
    995 
    996  if (!NS_SUCCEEDED(NS_DomainToASCIIAllowAnyGlyphfulASCII(aInput, aACE))) {
    997    return NS_ERROR_FAILURE;
    998  }
    999  return NS_OK;
   1000 }
   1001 
   1002 bool nsDNSService::IsLocalDomain(const nsACString& aHostname) const {
   1003  bool localDomain = mLocalDomains.Contains(aHostname);
   1004  if (StringEndsWith(aHostname, "."_ns)) {
   1005    localDomain = localDomain || mLocalDomains.Contains(Substring(
   1006                                     aHostname, 0, aHostname.Length() - 1));
   1007  }
   1008  return localDomain;
   1009 }
   1010 
   1011 nsresult nsDNSService::AsyncResolveInternal(
   1012    const nsACString& aHostname, uint16_t type, nsIDNSService::DNSFlags flags,
   1013    nsIDNSAdditionalInfo* aInfo, nsIDNSListener* aListener,
   1014    nsIEventTarget* target_, const OriginAttributes& aOriginAttributes,
   1015    nsICancelable** result) {
   1016  // grab reference to global host resolver and IDN service.  beware
   1017  // simultaneous shutdown!!
   1018  RefPtr<nsHostResolver> res;
   1019  nsCOMPtr<nsIEventTarget> target = target_;
   1020  nsCOMPtr<nsIDNSListener> listener = aListener;
   1021  bool localDomain = false;
   1022  {
   1023    MutexAutoLock lock(mLock);
   1024 
   1025    if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) {
   1026      return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
   1027    }
   1028 
   1029    res = mResolver;
   1030 
   1031    localDomain = IsLocalDomain(aHostname);
   1032  }
   1033 
   1034  if (mNotifyResolution) {
   1035    NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
   1036  }
   1037 
   1038  if (!res) {
   1039    return NS_ERROR_OFFLINE;
   1040  }
   1041 
   1042  if ((type != RESOLVE_TYPE_DEFAULT) && (type != RESOLVE_TYPE_TXT) &&
   1043      (type != RESOLVE_TYPE_HTTPSSVC)) {
   1044    return NS_ERROR_INVALID_ARG;
   1045  }
   1046 
   1047  if (DNSForbiddenByActiveProxy(aHostname, flags)) {
   1048    // nsHostResolver returns NS_ERROR_UNKNOWN_HOST for lots of reasons.
   1049    // We use a different error code to differentiate this failure and to make
   1050    // it clear(er) where this error comes from.
   1051    return NS_ERROR_UNKNOWN_PROXY_HOST;
   1052  }
   1053 
   1054  nsCString hostname;
   1055  nsresult rv = PreprocessHostname(localDomain, aHostname, hostname);
   1056  if (NS_FAILED(rv)) {
   1057    return rv;
   1058  }
   1059 
   1060  if (GetOffline() && (!StaticPrefs::network_dns_offline_localhost() ||
   1061                       !hostname.LowerCaseEqualsASCII("localhost"))) {
   1062    flags |= RESOLVE_OFFLINE;
   1063  }
   1064 
   1065  // make sure JS callers get notification on the main thread
   1066  nsCOMPtr<nsIXPConnectWrappedJS> wrappedListener = do_QueryInterface(listener);
   1067  if (wrappedListener && !target) {
   1068    target = GetMainThreadSerialEventTarget();
   1069  }
   1070 
   1071  if (target) {
   1072    listener = new DNSListenerProxy(listener, target);
   1073  }
   1074 
   1075  uint16_t af =
   1076      (type != RESOLVE_TYPE_DEFAULT) ? 0 : GetAFForLookup(hostname, flags);
   1077 
   1078  MOZ_ASSERT(listener);
   1079  RefPtr<nsDNSAsyncRequest> req =
   1080      new nsDNSAsyncRequest(res, hostname, DNSAdditionalInfo::URL(aInfo), type,
   1081                            aOriginAttributes, listener, flags, af);
   1082  if (!req) {
   1083    return NS_ERROR_OUT_OF_MEMORY;
   1084  }
   1085 
   1086  if (type == RESOLVE_TYPE_HTTPSSVC && mHasMockHTTPSRRDomainSet) {
   1087    MutexAutoLock lock(mLock);
   1088    if (req->mHost == mMockHTTPSRRDomain) {
   1089      flags |= nsIDNSService::RESOLVE_CREATE_MOCK_HTTPS_RR;
   1090    }
   1091  }
   1092 
   1093  rv = res->ResolveHost(req->mHost, DNSAdditionalInfo::URL(aInfo),
   1094                        DNSAdditionalInfo::Port(aInfo), type,
   1095                        req->mOriginAttributes, flags, af, req);
   1096  req.forget(result);
   1097  return rv;
   1098 }
   1099 
   1100 nsresult nsDNSService::CancelAsyncResolveInternal(
   1101    const nsACString& aHostname, uint16_t aType, nsIDNSService::DNSFlags aFlags,
   1102    nsIDNSAdditionalInfo* aInfo, nsIDNSListener* aListener, nsresult aReason,
   1103    const OriginAttributes& aOriginAttributes) {
   1104  // grab reference to global host resolver and IDN service.  beware
   1105  // simultaneous shutdown!!
   1106  RefPtr<nsHostResolver> res;
   1107  bool localDomain = false;
   1108  {
   1109    MutexAutoLock lock(mLock);
   1110 
   1111    if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) {
   1112      return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
   1113    }
   1114 
   1115    res = mResolver;
   1116    localDomain = IsLocalDomain(aHostname);
   1117  }
   1118  if (!res) {
   1119    return NS_ERROR_OFFLINE;
   1120  }
   1121 
   1122  nsCString hostname;
   1123  nsresult rv = PreprocessHostname(localDomain, aHostname, hostname);
   1124  if (NS_FAILED(rv)) {
   1125    return rv;
   1126  }
   1127 
   1128  uint16_t af =
   1129      (aType != RESOLVE_TYPE_DEFAULT) ? 0 : GetAFForLookup(hostname, aFlags);
   1130 
   1131  res->CancelAsyncRequest(hostname, DNSAdditionalInfo::URL(aInfo), aType,
   1132                          aOriginAttributes, aFlags, af, aListener, aReason);
   1133  return NS_OK;
   1134 }
   1135 
   1136 NS_IMETHODIMP
   1137 nsDNSService::AsyncResolve(const nsACString& aHostname,
   1138                           nsIDNSService::ResolveType aType,
   1139                           nsIDNSService::DNSFlags flags,
   1140                           nsIDNSAdditionalInfo* aInfo,
   1141                           nsIDNSListener* listener, nsIEventTarget* target_,
   1142                           JS::Handle<JS::Value> aOriginAttributes,
   1143                           JSContext* aCx, uint8_t aArgc,
   1144                           nsICancelable** result) {
   1145  OriginAttributes attrs;
   1146 
   1147  LOG(("DNSService::AsyncResolve %s", PromiseFlatCString(aHostname).get()));
   1148  if (aArgc == 1) {
   1149    if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   1150      return NS_ERROR_INVALID_ARG;
   1151    }
   1152  }
   1153 
   1154  return AsyncResolveInternal(aHostname, aType, flags, aInfo, listener, target_,
   1155                              attrs, result);
   1156 }
   1157 
   1158 NS_IMETHODIMP
   1159 nsDNSService::AsyncResolveNative(
   1160    const nsACString& aHostname, nsIDNSService::ResolveType aType,
   1161    nsIDNSService::DNSFlags flags, nsIDNSAdditionalInfo* aInfo,
   1162    nsIDNSListener* aListener, nsIEventTarget* target_,
   1163    const OriginAttributes& aOriginAttributes, nsICancelable** result) {
   1164  return AsyncResolveInternal(aHostname, aType, flags, aInfo, aListener,
   1165                              target_, aOriginAttributes, result);
   1166 }
   1167 
   1168 NS_IMETHODIMP
   1169 nsDNSService::NewAdditionalInfo(const nsACString& aTrrURL, int32_t aPort,
   1170                                nsIDNSAdditionalInfo** aInfo) {
   1171  RefPtr<DNSAdditionalInfo> res = new DNSAdditionalInfo(aTrrURL, aPort);
   1172  res.forget(aInfo);
   1173  return NS_OK;
   1174 }
   1175 
   1176 NS_IMETHODIMP
   1177 nsDNSService::CancelAsyncResolve(const nsACString& aHostname,
   1178                                 nsIDNSService::ResolveType aType,
   1179                                 nsIDNSService::DNSFlags aFlags,
   1180                                 nsIDNSAdditionalInfo* aInfo,
   1181                                 nsIDNSListener* aListener, nsresult aReason,
   1182                                 JS::Handle<JS::Value> aOriginAttributes,
   1183                                 JSContext* aCx, uint8_t aArgc) {
   1184  OriginAttributes attrs;
   1185 
   1186  if (aArgc == 1) {
   1187    if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   1188      return NS_ERROR_INVALID_ARG;
   1189    }
   1190  }
   1191 
   1192  return CancelAsyncResolveInternal(aHostname, aType, aFlags, aInfo, aListener,
   1193                                    aReason, attrs);
   1194 }
   1195 
   1196 NS_IMETHODIMP
   1197 nsDNSService::CancelAsyncResolveNative(
   1198    const nsACString& aHostname, nsIDNSService::ResolveType aType,
   1199    nsIDNSService::DNSFlags aFlags, nsIDNSAdditionalInfo* aInfo,
   1200    nsIDNSListener* aListener, nsresult aReason,
   1201    const OriginAttributes& aOriginAttributes) {
   1202  return CancelAsyncResolveInternal(aHostname, aType, aFlags, aInfo, aListener,
   1203                                    aReason, aOriginAttributes);
   1204 }
   1205 
   1206 NS_IMETHODIMP
   1207 nsDNSService::Resolve(const nsACString& aHostname,
   1208                      nsIDNSService::DNSFlags flags,
   1209                      JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx,
   1210                      uint8_t aArgc, nsIDNSRecord** result) {
   1211  OriginAttributes attrs;
   1212 
   1213  if (aArgc == 1) {
   1214    if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   1215      return NS_ERROR_INVALID_ARG;
   1216    }
   1217  }
   1218 
   1219  return ResolveNative(aHostname, flags, attrs, result);
   1220 }
   1221 
   1222 NS_IMETHODIMP
   1223 nsDNSService::ResolveNative(const nsACString& aHostname,
   1224                            nsIDNSService::DNSFlags flags,
   1225                            const OriginAttributes& aOriginAttributes,
   1226                            nsIDNSRecord** result) {
   1227  // Synchronous resolution is not allowed on the main thread.
   1228  // However, if RESOLVE_OFFLINE is set, we're only reading from the DNS cache,
   1229  // so it's safe to allow this on the main thread.
   1230  if (NS_IsMainThread() && !(flags & nsIDNSService::RESOLVE_OFFLINE)) {
   1231    return NS_ERROR_NOT_AVAILABLE;
   1232  }
   1233 
   1234  return ResolveInternal(aHostname, flags, aOriginAttributes, result);
   1235 }
   1236 
   1237 nsresult nsDNSService::DeprecatedSyncResolve(
   1238    const nsACString& aHostname, nsIDNSService::DNSFlags flags,
   1239    const OriginAttributes& aOriginAttributes, nsIDNSRecord** result) {
   1240  return ResolveInternal(aHostname, flags, aOriginAttributes, result);
   1241 }
   1242 
   1243 nsresult nsDNSService::ResolveInternal(
   1244    const nsACString& aHostname, nsIDNSService::DNSFlags flags,
   1245    const OriginAttributes& aOriginAttributes, nsIDNSRecord** result) {
   1246  // grab reference to global host resolver and IDN service.  beware
   1247  // simultaneous shutdown!!
   1248  RefPtr<nsHostResolver> res;
   1249  bool localDomain = false;
   1250  {
   1251    MutexAutoLock lock(mLock);
   1252    res = mResolver;
   1253    localDomain = IsLocalDomain(aHostname);
   1254  }
   1255 
   1256  if (mNotifyResolution) {
   1257    NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
   1258  }
   1259 
   1260  NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE);
   1261 
   1262  nsCString hostname;
   1263  nsresult rv = PreprocessHostname(localDomain, aHostname, hostname);
   1264  if (NS_FAILED(rv)) {
   1265    return rv;
   1266  }
   1267 
   1268  if (GetOffline() && (!StaticPrefs::network_dns_offline_localhost() ||
   1269                       !hostname.LowerCaseEqualsASCII("localhost"))) {
   1270    flags |= RESOLVE_OFFLINE;
   1271  }
   1272 
   1273  if (DNSForbiddenByActiveProxy(aHostname, flags)) {
   1274    return NS_ERROR_UNKNOWN_PROXY_HOST;
   1275  }
   1276 
   1277  //  Since RESOLVE_OFFLINE is set, we can use DNSCacheRequest to retrieve the
   1278  //  cached result directly.
   1279  if (flags & RESOLVE_OFFLINE) {
   1280    RefPtr<DNSCacheRequest> req = new DNSCacheRequest();
   1281    uint16_t af = GetAFForLookup(hostname, flags);
   1282    rv = res->ResolveHost(hostname, ""_ns, -1, RESOLVE_TYPE_DEFAULT,
   1283                          aOriginAttributes, flags, af, req);
   1284    if (NS_SUCCEEDED(rv)) {
   1285      RefPtr<nsDNSRecord> rec = new nsDNSRecord(req->mHostRecord);
   1286      rec.forget(result);
   1287    }
   1288    return rv;
   1289  }
   1290 
   1291  //
   1292  // sync resolve: since the host resolver only works asynchronously, we need
   1293  // to use a mutex and a condvar to wait for the result.  however, since the
   1294  // result may be in the resolvers cache, we might get called back recursively
   1295  // on the same thread.  so, our mutex needs to be re-entrant.  in other words,
   1296  // we need to use a monitor! ;-)
   1297  //
   1298 
   1299  PRMonitor* mon = PR_NewMonitor();
   1300  if (!mon) {
   1301    return NS_ERROR_OUT_OF_MEMORY;
   1302  }
   1303 
   1304  PR_EnterMonitor(mon);
   1305  RefPtr<nsDNSSyncRequest> syncReq = new nsDNSSyncRequest(mon);
   1306 
   1307  uint16_t af = GetAFForLookup(hostname, flags);
   1308 
   1309  // TRR uses the main thread for the HTTPS channel to the DoH server.
   1310  // If this were to block the main thread while waiting for TRR it would
   1311  // likely cause a deadlock. Instead we intentionally choose to not use TRR
   1312  // for this.
   1313  if (NS_IsMainThread()) {
   1314    flags |= RESOLVE_DISABLE_TRR;
   1315  }
   1316 
   1317  rv = res->ResolveHost(hostname, ""_ns, -1, RESOLVE_TYPE_DEFAULT,
   1318                        aOriginAttributes, flags, af, syncReq);
   1319  if (NS_SUCCEEDED(rv)) {
   1320    // wait for result
   1321    while (!syncReq->mDone) {
   1322      PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
   1323    }
   1324 
   1325    if (NS_FAILED(syncReq->mStatus)) {
   1326      rv = syncReq->mStatus;
   1327    } else {
   1328      NS_ASSERTION(syncReq->mHostRecord, "no host record");
   1329      RefPtr<nsDNSRecord> rec = new nsDNSRecord(syncReq->mHostRecord);
   1330      rec.forget(result);
   1331    }
   1332  }
   1333 
   1334  PR_ExitMonitor(mon);
   1335  PR_DestroyMonitor(mon);
   1336  return rv;
   1337 }
   1338 
   1339 NS_IMETHODIMP
   1340 nsDNSService::GetMyHostName(nsACString& result) {
   1341  char name[100];
   1342  if (PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof(name)) == PR_SUCCESS) {
   1343    result = name;
   1344    return NS_OK;
   1345  }
   1346  return NS_ERROR_FAILURE;
   1347 }
   1348 
   1349 NS_IMETHODIMP
   1350 nsDNSService::Observe(nsISupports* subject, const char* topic,
   1351                      const char16_t* data) {
   1352  bool flushCache = false;
   1353  RefPtr<nsHostResolver> resolver = GetResolverLocked();
   1354 
   1355  if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
   1356    nsAutoCString converted = NS_ConvertUTF16toUTF8(data);
   1357    if (!strcmp(converted.get(), NS_NETWORK_LINK_DATA_CHANGED)) {
   1358      flushCache = true;
   1359    }
   1360  } else if (!strcmp(topic, "last-pb-context-exited")) {
   1361    flushCache = true;
   1362  } else if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
   1363    ReadPrefs(NS_ConvertUTF16toUTF8(data).get());
   1364    NS_ENSURE_TRUE(resolver, NS_ERROR_NOT_INITIALIZED);
   1365  } else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
   1366    Shutdown();
   1367  }
   1368 
   1369  if (flushCache && resolver) {
   1370    resolver->FlushCache(false);
   1371    return NS_OK;
   1372  }
   1373 
   1374  return NS_OK;
   1375 }
   1376 
   1377 uint16_t nsDNSService::GetAFForLookup(const nsACString& host,
   1378                                      nsIDNSService::DNSFlags flags) {
   1379  if (StaticPrefs::network_dns_disableIPv6() ||
   1380      (flags & RESOLVE_DISABLE_IPV6)) {
   1381    return PR_AF_INET;
   1382  }
   1383 
   1384  MutexAutoLock lock(mLock);
   1385 
   1386  uint16_t af = PR_AF_UNSPEC;
   1387 
   1388  if (!mIPv4OnlyDomains.IsEmpty()) {
   1389    const char *domain, *domainEnd, *end;
   1390    uint32_t hostLen, domainLen;
   1391 
   1392    // see if host is in one of the IPv4-only domains
   1393    domain = mIPv4OnlyDomains.BeginReading();
   1394    domainEnd = mIPv4OnlyDomains.EndReading();
   1395 
   1396    nsACString::const_iterator hostStart;
   1397    host.BeginReading(hostStart);
   1398    hostLen = host.Length();
   1399 
   1400    do {
   1401      // skip any whitespace
   1402      while (*domain == ' ' || *domain == '\t') {
   1403        ++domain;
   1404      }
   1405 
   1406      // find end of this domain in the string
   1407      end = strchr(domain, ',');
   1408      if (!end) {
   1409        end = domainEnd;
   1410      }
   1411 
   1412      // to see if the hostname is in the domain, check if the domain
   1413      // matches the end of the hostname.
   1414      domainLen = end - domain;
   1415      if (domainLen && hostLen >= domainLen) {
   1416        const char* hostTail = hostStart.get() + hostLen - domainLen;
   1417        if (nsCRT::strncasecmp(domain, hostTail, domainLen) == 0) {
   1418          // now, make sure either that the hostname is a direct match or
   1419          // that the hostname begins with a dot.
   1420          if (hostLen == domainLen || *hostTail == '.' ||
   1421              *(hostTail - 1) == '.') {
   1422            af = PR_AF_INET;
   1423            break;
   1424          }
   1425        }
   1426      }
   1427 
   1428      domain = end + 1;
   1429    } while (*end);
   1430  }
   1431 
   1432  if ((af != PR_AF_INET) && (flags & RESOLVE_DISABLE_IPV4)) {
   1433    af = PR_AF_INET6;
   1434  }
   1435 
   1436  return af;
   1437 }
   1438 
   1439 NS_IMETHODIMP
   1440 nsDNSService::GetDNSCacheEntries(
   1441    nsTArray<mozilla::net::DNSCacheEntries>* args) {
   1442  RefPtr<nsHostResolver> resolver = GetResolverLocked();
   1443  NS_ENSURE_TRUE(resolver, NS_ERROR_NOT_INITIALIZED);
   1444  resolver->GetDNSCacheEntries(args);
   1445  return NS_OK;
   1446 }
   1447 
   1448 NS_IMETHODIMP
   1449 nsDNSService::ClearCache(bool aTrrToo) {
   1450  RefPtr<nsHostResolver> resolver = GetResolverLocked();
   1451  NS_ENSURE_TRUE(resolver, NS_ERROR_NOT_INITIALIZED);
   1452  resolver->FlushCache(aTrrToo, true);
   1453  return NS_OK;
   1454 }
   1455 
   1456 // For testing purposes only
   1457 NS_IMETHODIMP
   1458 nsDNSService::ReloadParentalControlEnabled() {
   1459  if (mTrrService) {
   1460    mTrrService->mParentalControlEnabled =
   1461        TRRService::ReloadParentalControlsEnabled();
   1462  }
   1463  return NS_OK;
   1464 }
   1465 
   1466 NS_IMETHODIMP
   1467 nsDNSService::SetDetectedTrrURI(const nsACString& aURI) {
   1468  if (mTrrService) {
   1469    mTrrService->SetDetectedTrrURI(aURI);
   1470  }
   1471  return NS_OK;
   1472 }
   1473 
   1474 NS_IMETHODIMP
   1475 nsDNSService::SetHeuristicDetectionResult(nsITRRSkipReason::value aValue) {
   1476  if (mTrrService) {
   1477    mTrrService->SetHeuristicDetectionResult(aValue);
   1478  }
   1479  return NS_OK;
   1480 }
   1481 
   1482 NS_IMETHODIMP
   1483 nsDNSService::GetHeuristicDetectionResult(nsITRRSkipReason::value* aValue) {
   1484  if (!mTrrService) {
   1485    return NS_ERROR_NOT_AVAILABLE;
   1486  }
   1487 
   1488  *aValue = mTrrService->GetHeuristicDetectionResult();
   1489  return NS_OK;
   1490 }
   1491 
   1492 NS_IMETHODIMP
   1493 nsDNSService::GetTRRSkipReasonName(nsITRRSkipReason::value aValue,
   1494                                   nsACString& aName) {
   1495  return mozilla::net::GetTRRSkipReasonName(aValue, aName);
   1496 }
   1497 
   1498 NS_IMETHODIMP
   1499 nsDNSService::GetCurrentTrrURI(nsACString& aURI) {
   1500  if (mTrrService) {
   1501    mTrrService->GetURI(aURI);
   1502  }
   1503  return NS_OK;
   1504 }
   1505 
   1506 NS_IMETHODIMP
   1507 nsDNSService::GetCurrentTrrMode(nsIDNSService::ResolverMode* aMode) {
   1508  *aMode = nsIDNSService::MODE_NATIVEONLY;  // The default mode.
   1509  if (mTrrService) {
   1510    *aMode = mTrrService->Mode();
   1511  }
   1512  return NS_OK;
   1513 }
   1514 
   1515 NS_IMETHODIMP
   1516 nsDNSService::GetCurrentTrrConfirmationState(uint32_t* aConfirmationState) {
   1517  *aConfirmationState = uint32_t(TRRService::CONFIRM_OFF);
   1518  if (mTrrService) {
   1519    *aConfirmationState = mTrrService->ConfirmationState();
   1520  }
   1521  return NS_OK;
   1522 }
   1523 
   1524 NS_IMETHODIMP
   1525 nsDNSService::GetTrrDomain(nsACString& aTRRDomain) {
   1526  aTRRDomain.Truncate();
   1527  nsAutoCString url;
   1528  if (mTrrService) {
   1529    mTrrService->GetURI(url);
   1530  }
   1531  nsCOMPtr<nsIURI> uri;
   1532  nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
   1533  if (NS_FAILED(rv)) {
   1534    // An empty TRR domain in case of invalid URL.
   1535    return NS_OK;
   1536  }
   1537  return uri->GetHost(aTRRDomain);
   1538 }
   1539 
   1540 nsresult nsDNSService::GetTRRDomainKey(nsACString& aTRRDomain) {
   1541  aTRRDomain = TRRService::ProviderKey();
   1542  return NS_OK;
   1543 }
   1544 
   1545 size_t nsDNSService::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
   1546  // Measurement of the following members may be added later if DMD finds it
   1547  // is worthwhile:
   1548  // - mIDN
   1549  // - mLock
   1550 
   1551  size_t n = mallocSizeOf(this);
   1552  MutexAutoLock lock(mLock);
   1553  n += mResolver ? mResolver->SizeOfIncludingThis(mallocSizeOf) : 0;
   1554  n += mIPv4OnlyDomains.SizeOfExcludingThisIfUnshared(mallocSizeOf);
   1555  n += mLocalDomains.SizeOfExcludingThis(mallocSizeOf);
   1556  n += mFailedSVCDomainNames.ShallowSizeOfExcludingThis(mallocSizeOf);
   1557  for (const auto& data : mFailedSVCDomainNames.Values()) {
   1558    n += data->ShallowSizeOfExcludingThis(mallocSizeOf);
   1559    for (const auto& name : *data) {
   1560      n += name.SizeOfExcludingThisIfUnshared(mallocSizeOf);
   1561    }
   1562  }
   1563  return n;
   1564 }
   1565 
   1566 MOZ_DEFINE_MALLOC_SIZE_OF(DNSServiceMallocSizeOf)
   1567 
   1568 NS_IMETHODIMP
   1569 nsDNSService::CollectReports(nsIHandleReportCallback* aHandleReport,
   1570                             nsISupports* aData, bool aAnonymize) {
   1571  MOZ_COLLECT_REPORT("explicit/network/dns-service", KIND_HEAP, UNITS_BYTES,
   1572                     SizeOfIncludingThis(DNSServiceMallocSizeOf),
   1573                     "Memory used for the DNS service.");
   1574 
   1575  return NS_OK;
   1576 }
   1577 
   1578 NS_IMETHODIMP
   1579 nsDNSService::ReportFailedSVCDomainName(const nsACString& aOwnerName,
   1580                                        const nsACString& aSVCDomainName) {
   1581  MutexAutoLock lock(mLock);
   1582 
   1583  mFailedSVCDomainNames.GetOrInsertNew(aOwnerName, 1)
   1584      ->AppendElement(aSVCDomainName);
   1585  return NS_OK;
   1586 }
   1587 
   1588 NS_IMETHODIMP
   1589 nsDNSService::IsSVCDomainNameFailed(const nsACString& aOwnerName,
   1590                                    const nsACString& aSVCDomainName,
   1591                                    bool* aResult) {
   1592  NS_ENSURE_ARG(aResult);
   1593 
   1594  MutexAutoLock lock(mLock);
   1595  *aResult = false;
   1596  nsTArray<nsCString>* failedList = mFailedSVCDomainNames.Get(aOwnerName);
   1597  if (!failedList) {
   1598    return NS_OK;
   1599  }
   1600 
   1601  *aResult = failedList->Contains(aSVCDomainName);
   1602  return NS_OK;
   1603 }
   1604 
   1605 NS_IMETHODIMP
   1606 nsDNSService::ResetExcludedSVCDomainName(const nsACString& aOwnerName) {
   1607  MutexAutoLock lock(mLock);
   1608  mFailedSVCDomainNames.Remove(aOwnerName);
   1609  return NS_OK;
   1610 }
   1611 
   1612 NS_IMETHODIMP
   1613 nsDNSService::GetLastConfirmationStatus(nsresult* aConfirmationStatus) {
   1614  if (!mTrrService) {
   1615    return NS_ERROR_NOT_AVAILABLE;
   1616  }
   1617  *aConfirmationStatus = mTrrService->LastConfirmationStatus();
   1618  return NS_OK;
   1619 }
   1620 
   1621 NS_IMETHODIMP nsDNSService::GetLastConfirmationSkipReason(
   1622    TRRSkippedReason* aSkipReason) {
   1623  if (!mTrrService) {
   1624    return NS_ERROR_NOT_AVAILABLE;
   1625  }
   1626  *aSkipReason = mTrrService->LastConfirmationSkipReason();
   1627  return NS_OK;
   1628 }
   1629 
   1630 namespace mozilla::net {
   1631 nsresult GetTRRSkipReasonName(TRRSkippedReason aReason, nsACString& aName) {
   1632  static_assert(TRRSkippedReason::TRR_UNSET == 0);
   1633  static_assert(TRRSkippedReason::TRR_OK == 1);
   1634  static_assert(TRRSkippedReason::TRR_NO_GSERVICE == 2);
   1635  static_assert(TRRSkippedReason::TRR_PARENTAL_CONTROL == 3);
   1636  static_assert(TRRSkippedReason::TRR_OFF_EXPLICIT == 4);
   1637  static_assert(TRRSkippedReason::TRR_REQ_MODE_DISABLED == 5);
   1638  static_assert(TRRSkippedReason::TRR_MODE_NOT_ENABLED == 6);
   1639  static_assert(TRRSkippedReason::TRR_FAILED == 7);
   1640  static_assert(TRRSkippedReason::TRR_MODE_UNHANDLED_DEFAULT == 8);
   1641  static_assert(TRRSkippedReason::TRR_MODE_UNHANDLED_DISABLED == 9);
   1642  static_assert(TRRSkippedReason::TRR_DISABLED_FLAG == 10);
   1643  static_assert(TRRSkippedReason::TRR_TIMEOUT == 11);
   1644  static_assert(TRRSkippedReason::TRR_CHANNEL_DNS_FAIL == 12);
   1645  static_assert(TRRSkippedReason::TRR_BROWSER_IS_OFFLINE == 13);
   1646  static_assert(TRRSkippedReason::TRR_NOT_CONFIRMED == 14);
   1647  static_assert(TRRSkippedReason::TRR_DID_NOT_MAKE_QUERY == 15);
   1648  static_assert(TRRSkippedReason::TRR_UNKNOWN_CHANNEL_FAILURE == 16);
   1649  static_assert(TRRSkippedReason::TRR_HOST_BLOCKED_TEMPORARY == 17);
   1650  static_assert(TRRSkippedReason::TRR_SEND_FAILED == 18);
   1651  static_assert(TRRSkippedReason::TRR_NET_RESET == 19);
   1652  static_assert(TRRSkippedReason::TRR_NET_TIMEOUT == 20);
   1653  static_assert(TRRSkippedReason::TRR_NET_REFUSED == 21);
   1654  static_assert(TRRSkippedReason::TRR_NET_INTERRUPT == 22);
   1655  static_assert(TRRSkippedReason::TRR_NET_INADEQ_SEQURITY == 23);
   1656  static_assert(TRRSkippedReason::TRR_NO_ANSWERS == 24);
   1657  static_assert(TRRSkippedReason::TRR_DECODE_FAILED == 25);
   1658  static_assert(TRRSkippedReason::TRR_EXCLUDED == 26);
   1659  static_assert(TRRSkippedReason::TRR_SERVER_RESPONSE_ERR == 27);
   1660  static_assert(TRRSkippedReason::TRR_RCODE_FAIL == 28);
   1661  static_assert(TRRSkippedReason::TRR_NO_CONNECTIVITY == 29);
   1662  static_assert(TRRSkippedReason::TRR_NXDOMAIN == 30);
   1663  static_assert(TRRSkippedReason::TRR_REQ_CANCELLED == 31);
   1664  static_assert(TRRSkippedReason::ODOH_KEY_NOT_USABLE == 32);
   1665  static_assert(TRRSkippedReason::ODOH_UPDATE_KEY_FAILED == 33);
   1666  static_assert(TRRSkippedReason::ODOH_KEY_NOT_AVAILABLE == 34);
   1667  static_assert(TRRSkippedReason::ODOH_ENCRYPTION_FAILED == 35);
   1668  static_assert(TRRSkippedReason::ODOH_DECRYPTION_FAILED == 36);
   1669  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH ==
   1670                37);
   1671  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH ==
   1672                38);
   1673  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY == 39);
   1674  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_CANARY == 40);
   1675  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS == 41);
   1676  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS ==
   1677                42);
   1678  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS ==
   1679                43);
   1680  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY ==
   1681                44);
   1682  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_VPN == 45);
   1683  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_PROXY == 46);
   1684  static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_NRPT == 47);
   1685  static_assert(TRRSkippedReason::TRR_BAD_URL == 48);
   1686  static_assert(TRRSkippedReason::TRR_SYSTEM_SLEEP_MODE == 49);
   1687 
   1688  switch (aReason) {
   1689    case TRRSkippedReason::TRR_UNSET:
   1690      aName = "TRR_UNSET"_ns;
   1691      break;
   1692    case TRRSkippedReason::TRR_OK:
   1693      aName = "TRR_OK"_ns;
   1694      break;
   1695    case TRRSkippedReason::TRR_NO_GSERVICE:
   1696      aName = "TRR_NO_GSERVICE"_ns;
   1697      break;
   1698    case TRRSkippedReason::TRR_PARENTAL_CONTROL:
   1699      aName = "TRR_PARENTAL_CONTROL"_ns;
   1700      break;
   1701    case TRRSkippedReason::TRR_OFF_EXPLICIT:
   1702      aName = "TRR_OFF_EXPLICIT"_ns;
   1703      break;
   1704    case TRRSkippedReason::TRR_REQ_MODE_DISABLED:
   1705      aName = "TRR_REQ_MODE_DISABLED"_ns;
   1706      break;
   1707    case TRRSkippedReason::TRR_MODE_NOT_ENABLED:
   1708      aName = "TRR_MODE_NOT_ENABLED"_ns;
   1709      break;
   1710    case TRRSkippedReason::TRR_FAILED:
   1711      aName = "TRR_FAILED"_ns;
   1712      break;
   1713    case TRRSkippedReason::TRR_MODE_UNHANDLED_DEFAULT:
   1714      aName = "TRR_MODE_UNHANDLED_DEFAULT"_ns;
   1715      break;
   1716    case TRRSkippedReason::TRR_MODE_UNHANDLED_DISABLED:
   1717      aName = "TRR_MODE_UNHANDLED_DISABLED"_ns;
   1718      break;
   1719    case TRRSkippedReason::TRR_DISABLED_FLAG:
   1720      aName = "TRR_DISABLED_FLAG"_ns;
   1721      break;
   1722    case TRRSkippedReason::TRR_TIMEOUT:
   1723      aName = "TRR_TIMEOUT"_ns;
   1724      break;
   1725    case TRRSkippedReason::TRR_CHANNEL_DNS_FAIL:
   1726      aName = "TRR_CHANNEL_DNS_FAIL"_ns;
   1727      break;
   1728    case TRRSkippedReason::TRR_BROWSER_IS_OFFLINE:
   1729      aName = "TRR_BROWSER_IS_OFFLINE"_ns;
   1730      break;
   1731    case TRRSkippedReason::TRR_NOT_CONFIRMED:
   1732      aName = "TRR_NOT_CONFIRMED"_ns;
   1733      break;
   1734    case TRRSkippedReason::TRR_DID_NOT_MAKE_QUERY:
   1735      aName = "TRR_DID_NOT_MAKE_QUERY"_ns;
   1736      break;
   1737    case TRRSkippedReason::TRR_UNKNOWN_CHANNEL_FAILURE:
   1738      aName = "TRR_UNKNOWN_CHANNEL_FAILURE"_ns;
   1739      break;
   1740    case TRRSkippedReason::TRR_HOST_BLOCKED_TEMPORARY:
   1741      aName = "TRR_HOST_BLOCKED_TEMPORARY"_ns;
   1742      break;
   1743    case TRRSkippedReason::TRR_SEND_FAILED:
   1744      aName = "TRR_SEND_FAILED"_ns;
   1745      break;
   1746    case TRRSkippedReason::TRR_NET_RESET:
   1747      aName = "TRR_NET_RESET"_ns;
   1748      break;
   1749    case TRRSkippedReason::TRR_NET_TIMEOUT:
   1750      aName = "TRR_NET_TIMEOUT"_ns;
   1751      break;
   1752    case TRRSkippedReason::TRR_NET_REFUSED:
   1753      aName = "TRR_NET_REFUSED"_ns;
   1754      break;
   1755    case TRRSkippedReason::TRR_NET_INTERRUPT:
   1756      aName = "TRR_NET_INTERRUPT"_ns;
   1757      break;
   1758    case TRRSkippedReason::TRR_NET_INADEQ_SEQURITY:
   1759      aName = "TRR_NET_INADEQ_SEQURITY"_ns;
   1760      break;
   1761    case TRRSkippedReason::TRR_NO_ANSWERS:
   1762      aName = "TRR_NO_ANSWERS"_ns;
   1763      break;
   1764    case TRRSkippedReason::TRR_DECODE_FAILED:
   1765      aName = "TRR_DECODE_FAILED"_ns;
   1766      break;
   1767    case TRRSkippedReason::TRR_EXCLUDED:
   1768      aName = "TRR_EXCLUDED"_ns;
   1769      break;
   1770    case TRRSkippedReason::TRR_SERVER_RESPONSE_ERR:
   1771      aName = "TRR_SERVER_RESPONSE_ERR"_ns;
   1772      break;
   1773    case TRRSkippedReason::TRR_RCODE_FAIL:
   1774      aName = "TRR_RCODE_FAIL"_ns;
   1775      break;
   1776    case TRRSkippedReason::TRR_NO_CONNECTIVITY:
   1777      aName = "TRR_NO_CONNECTIVITY"_ns;
   1778      break;
   1779    case TRRSkippedReason::TRR_NXDOMAIN:
   1780      aName = "TRR_NXDOMAIN"_ns;
   1781      break;
   1782    case TRRSkippedReason::TRR_REQ_CANCELLED:
   1783      aName = "TRR_REQ_CANCELLED"_ns;
   1784      break;
   1785    case TRRSkippedReason::ODOH_KEY_NOT_USABLE:
   1786      aName = "ODOH_KEY_NOT_USABLE"_ns;
   1787      break;
   1788    case TRRSkippedReason::ODOH_UPDATE_KEY_FAILED:
   1789      aName = "ODOH_UPDATE_KEY_FAILED"_ns;
   1790      break;
   1791    case TRRSkippedReason::ODOH_KEY_NOT_AVAILABLE:
   1792      aName = "ODOH_KEY_NOT_AVAILABLE"_ns;
   1793      break;
   1794    case TRRSkippedReason::ODOH_ENCRYPTION_FAILED:
   1795      aName = "ODOH_ENCRYPTION_FAILED"_ns;
   1796      break;
   1797    case TRRSkippedReason::ODOH_DECRYPTION_FAILED:
   1798      aName = "ODOH_DECRYPTION_FAILED"_ns;
   1799      break;
   1800    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH:
   1801      aName = "TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH"_ns;
   1802      break;
   1803    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH:
   1804      aName = "TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH"_ns;
   1805      break;
   1806    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY:
   1807      aName = "TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY"_ns;
   1808      break;
   1809    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_CANARY:
   1810      aName = "TRR_HEURISTIC_TRIPPED_CANARY"_ns;
   1811      break;
   1812    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS:
   1813      aName = "TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS"_ns;
   1814      break;
   1815    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS:
   1816      aName = "TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS"_ns;
   1817      break;
   1818    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS:
   1819      aName = "TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS"_ns;
   1820      break;
   1821    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY:
   1822      aName = "TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY"_ns;
   1823      break;
   1824    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_VPN:
   1825      aName = "TRR_HEURISTIC_TRIPPED_VPN"_ns;
   1826      break;
   1827    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_PROXY:
   1828      aName = "TRR_HEURISTIC_TRIPPED_PROXY"_ns;
   1829      break;
   1830    case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_NRPT:
   1831      aName = "TRR_HEURISTIC_TRIPPED_NRPT"_ns;
   1832      break;
   1833    case TRRSkippedReason::TRR_BAD_URL:
   1834      aName = "TRR_BAD_URL"_ns;
   1835      break;
   1836    case TRRSkippedReason::TRR_SYSTEM_SLEEP_MODE:
   1837      aName = "TRR_SYSTEM_SLEEP_MODE"_ns;
   1838      break;
   1839    default:
   1840      MOZ_ASSERT(false, "Unknown value");
   1841  }
   1842 
   1843  return NS_OK;
   1844 }
   1845 }  // namespace mozilla::net