tor-browser

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

nsHostRecord.cpp (23235B)


      1 /* vim:set ts=4 sw=2 sts=2 et cin: */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "nsHostRecord.h"
      7 #include "TRRQuery.h"
      8 // Put DNSLogging.h at the end to avoid LOG being overwritten by other headers.
      9 #include "DNSLogging.h"
     10 #include "mozilla/StaticPrefs_network.h"
     11 #include "mozilla/glean/NetwerkDnsMetrics.h"
     12 #include "mozilla/ThreadSafety.h"
     13 #include "TRRService.h"
     14 #include "mozilla/ProfilerMarkers.h"
     15 
     16 //----------------------------------------------------------------------------
     17 // this macro filters out any flags that are not used when constructing the
     18 // host key.  the significant flags are those that would affect the resulting
     19 // host record (i.e., the flags that are passed down to PR_GetAddrInfoByName).
     20 #define RES_KEY_FLAGS(_f)                           \
     21  ((_f) &                                           \
     22   ((StaticPrefs::network_dns_always_ai_canonname() \
     23         ? 0                                        \
     24         : nsIDNSService::RESOLVE_CANONICAL_NAME) | \
     25    nsIDNSService::RESOLVE_DISABLE_TRR |            \
     26    nsIDNSService::RESOLVE_TRR_MODE_MASK | nsIDNSService::RESOLVE_IP_HINT))
     27 
     28 #define IS_ADDR_TYPE(_type) ((_type) == nsIDNSService::RESOLVE_TYPE_DEFAULT)
     29 #define IS_OTHER_TYPE(_type) ((_type) != nsIDNSService::RESOLVE_TYPE_DEFAULT)
     30 
     31 //----------------------------------------------------------------------------
     32 
     33 using namespace mozilla;
     34 using namespace mozilla::net;
     35 
     36 struct HostResolverMarker {
     37  static constexpr mozilla::Span<const char> MarkerTypeName() {
     38    return mozilla::MakeStringSpan("HostResolver");
     39  }
     40  static void StreamJSONMarkerData(
     41      mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
     42      const mozilla::ProfilerString8View& aHost,
     43      const mozilla::ProfilerString8View& aOriginSuffix, uint16_t aType,
     44      uint32_t aFlags) {
     45    aWriter.StringProperty("host", aHost);
     46    aWriter.StringProperty("originSuffix", aOriginSuffix);
     47    aWriter.IntProperty("qtype", aType);
     48    aWriter.StringProperty("flags", nsPrintfCString("0x%x", aFlags));
     49  }
     50  static MarkerSchema MarkerTypeDisplay() {
     51    using MS = MarkerSchema;
     52    MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
     53    schema.SetTableLabel("{marker.data.host}");
     54    schema.AddKeyFormat("host", MS::Format::SanitizedString,
     55                        MS::PayloadFlags::Searchable);
     56    schema.AddKeyFormat("originSuffix", MS::Format::SanitizedString,
     57                        MS::PayloadFlags::Searchable);
     58    schema.AddKeyFormat("qtype", MS::Format::Integer);
     59    schema.AddKeyFormat("flags", MS::Format::String);
     60    return schema;
     61  }
     62 };
     63 
     64 nsHostKey::nsHostKey(const nsACString& aHost, const nsACString& aTrrServer,
     65                     uint16_t aType, nsIDNSService::DNSFlags aFlags,
     66                     uint16_t aAf, bool aPb, const nsACString& aOriginsuffix)
     67    : host(aHost),
     68      mTrrServer(aTrrServer),
     69      type(aType),
     70      flags(aFlags),
     71      af(aAf),
     72      pb(aPb),
     73      originSuffix(aOriginsuffix) {}
     74 
     75 nsHostKey::nsHostKey(const nsHostKey& other)
     76    : host(other.host),
     77      mTrrServer(other.mTrrServer),
     78      type(other.type),
     79      flags(other.flags),
     80      af(other.af),
     81      pb(other.pb),
     82      originSuffix(other.originSuffix) {}
     83 
     84 bool nsHostKey::operator==(const nsHostKey& other) const {
     85  return host == other.host && mTrrServer == other.mTrrServer &&
     86         type == other.type &&
     87         RES_KEY_FLAGS(flags) == RES_KEY_FLAGS(other.flags) && af == other.af &&
     88         originSuffix == other.originSuffix;
     89 }
     90 
     91 PLDHashNumber nsHostKey::Hash() const {
     92  return AddToHash(HashString(host.get()), HashString(mTrrServer.get()), type,
     93                   RES_KEY_FLAGS(flags), af, HashString(originSuffix.get()));
     94 }
     95 
     96 size_t nsHostKey::SizeOfExcludingThis(
     97    mozilla::MallocSizeOf mallocSizeOf) const {
     98  size_t n = 0;
     99  n += host.SizeOfExcludingThisIfUnshared(mallocSizeOf);
    100  n += mTrrServer.SizeOfExcludingThisIfUnshared(mallocSizeOf);
    101  n += originSuffix.SizeOfExcludingThisIfUnshared(mallocSizeOf);
    102  return n;
    103 }
    104 
    105 //----------------------------------------------------------------------------
    106 // nsHostRecord
    107 //----------------------------------------------------------------------------
    108 
    109 NS_IMPL_ISUPPORTS0(nsHostRecord)
    110 
    111 nsHostRecord::nsHostRecord(const nsHostKey& key)
    112    : nsHostKey(key), mTRRQuery("nsHostRecord.mTRRQuery") {}
    113 
    114 void nsHostRecord::Invalidate() { mDoomed = true; }
    115 
    116 void nsHostRecord::Cancel() {
    117  RefPtr<TRRQuery> query;
    118  {
    119    auto lock = mTRRQuery.Lock();
    120    query.swap(lock.ref());
    121  }
    122 
    123  if (query) {
    124    query->Cancel(NS_ERROR_ABORT);
    125  }
    126 }
    127 
    128 nsHostRecord::ExpirationStatus nsHostRecord::CheckExpiration(
    129    const mozilla::TimeStamp& now) const {
    130  if (!mGraceStart.IsNull() && now >= mGraceStart && !mValidEnd.IsNull() &&
    131      now < mValidEnd) {
    132    return nsHostRecord::EXP_GRACE;
    133  }
    134  if (!mValidEnd.IsNull() && now < mValidEnd) {
    135    return nsHostRecord::EXP_VALID;
    136  }
    137 
    138  return nsHostRecord::EXP_EXPIRED;
    139 }
    140 
    141 void nsHostRecord::SetExpiration(const mozilla::TimeStamp& now,
    142                                 unsigned int valid, unsigned int grace) {
    143  mValidStart = now;
    144  if ((valid + grace) < 60) {
    145    grace = 60 - valid;
    146    LOG(("SetExpiration: artificially bumped grace to %d\n", grace));
    147  }
    148  mGraceStart = now + TimeDuration::FromSeconds(valid);
    149  mValidEnd = now + TimeDuration::FromSeconds(valid + grace);
    150  mTtl = valid;
    151 }
    152 
    153 void nsHostRecord::CopyExpirationTimesAndFlagsFrom(
    154    const nsHostRecord* aFromHostRecord) {
    155  // This is used to copy information from a cache entry to a record. All
    156  // information necessary for HasUsableRecord needs to be copied.
    157  mValidStart = aFromHostRecord->mValidStart;
    158  mValidEnd = aFromHostRecord->mValidEnd;
    159  mGraceStart = aFromHostRecord->mGraceStart;
    160  mDoomed = aFromHostRecord->mDoomed;
    161  mTtl = uint32_t(aFromHostRecord->mTtl);
    162 }
    163 
    164 bool nsHostRecord::HasUsableResult(const mozilla::TimeStamp& now,
    165                                   nsIDNSService::DNSFlags queryFlags) const {
    166  if (mDoomed) {
    167    return false;
    168  }
    169 
    170  return HasUsableResultInternal(now, queryFlags);
    171 }
    172 
    173 //----------------------------------------------------------------------------
    174 // AddrHostRecord
    175 //----------------------------------------------------------------------------
    176 
    177 static size_t SizeOfResolveHostCallbackListExcludingHead(
    178    const mozilla::LinkedList<RefPtr<nsResolveHostCallback>>& aCallbacks,
    179    MallocSizeOf mallocSizeOf) {
    180  size_t n = aCallbacks.sizeOfExcludingThis(mallocSizeOf);
    181 
    182  for (const nsResolveHostCallback* t = aCallbacks.getFirst(); t;
    183       t = t->getNext()) {
    184    n += t->SizeOfIncludingThis(mallocSizeOf);
    185  }
    186 
    187  return n;
    188 }
    189 
    190 NS_IMPL_ISUPPORTS_INHERITED(AddrHostRecord, nsHostRecord, AddrHostRecord)
    191 
    192 AddrHostRecord::AddrHostRecord(const nsHostKey& key) : nsHostRecord(key) {}
    193 
    194 AddrHostRecord::~AddrHostRecord() {
    195  mCallbacks.clear();
    196  glean::dns::blocklist_count.AccumulateSingleSample(mUnusableCount);
    197 }
    198 
    199 bool AddrHostRecord::Blocklisted(const NetAddr* aQuery) {
    200  addr_info_lock.AssertCurrentThreadOwns();
    201  LOG(("Checking unusable list for host [%s], host record [%p].\n", host.get(),
    202       this));
    203 
    204  // skip the string conversion for the common case of no blocklist
    205  if (!mUnusableItems.Length()) {
    206    return false;
    207  }
    208 
    209  char buf[kIPv6CStrBufSize];
    210  if (!aQuery->ToStringBuffer(buf, sizeof(buf))) {
    211    return false;
    212  }
    213  nsDependentCString strQuery(buf);
    214 
    215  for (uint32_t i = 0; i < mUnusableItems.Length(); i++) {
    216    if (mUnusableItems.ElementAt(i).Equals(strQuery)) {
    217      LOG(("Address [%s] is blocklisted for host [%s].\n", buf, host.get()));
    218      return true;
    219    }
    220  }
    221 
    222  return false;
    223 }
    224 
    225 void AddrHostRecord::ReportUnusable(const NetAddr* aAddress) {
    226  addr_info_lock.AssertCurrentThreadOwns();
    227  LOG(
    228      ("Adding address to blocklist for host [%s], host record [%p]."
    229       "used trr=%d\n",
    230       host.get(), this, mTRRSuccess));
    231 
    232  ++mUnusableCount;
    233 
    234  char buf[kIPv6CStrBufSize];
    235  if (aAddress->ToStringBuffer(buf, sizeof(buf))) {
    236    LOG(
    237        ("Successfully adding address [%s] to blocklist for host "
    238         "[%s].\n",
    239         buf, host.get()));
    240    mUnusableItems.AppendElement(nsCString(buf));
    241  }
    242 }
    243 
    244 void AddrHostRecord::ResetBlocklist() {
    245  addr_info_lock.AssertCurrentThreadOwns();
    246  LOG(("Resetting blocklist for host [%s], host record [%p].\n", host.get(),
    247       this));
    248  mUnusableItems.Clear();
    249 }
    250 
    251 size_t AddrHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
    252  size_t n = mallocSizeOf(this);
    253 
    254  n += nsHostKey::SizeOfExcludingThis(mallocSizeOf);
    255  n += SizeOfResolveHostCallbackListExcludingHead(mCallbacks, mallocSizeOf);
    256 
    257  n += addr_info ? addr_info->SizeOfIncludingThis(mallocSizeOf) : 0;
    258  n += mallocSizeOf(addr.get());
    259 
    260  n += mUnusableItems.ShallowSizeOfExcludingThis(mallocSizeOf);
    261  for (size_t i = 0; i < mUnusableItems.Length(); i++) {
    262    n += mUnusableItems[i].SizeOfExcludingThisIfUnshared(mallocSizeOf);
    263  }
    264  return n;
    265 }
    266 
    267 bool AddrHostRecord::HasUsableResultInternal(
    268    const mozilla::TimeStamp& now, nsIDNSService::DNSFlags queryFlags) const {
    269  // don't use cached negative results for high priority queries.
    270  if (negative && IsHighPriority(queryFlags)) {
    271    return false;
    272  }
    273 
    274  if (CheckExpiration(now) == EXP_EXPIRED) {
    275    return false;
    276  }
    277 
    278  if (negative) {
    279    return true;
    280  }
    281 
    282  return addr_info || addr;
    283 }
    284 
    285 // Returns true if the entry can be removed, or false if it should be left.
    286 // Sets ResolveAgain true for entries being resolved right now.
    287 bool AddrHostRecord::RemoveOrRefresh(bool aTrrToo) {
    288  // no need to flush TRRed names, they're not resolved "locally"
    289  MutexAutoLock lock(addr_info_lock);
    290  if (addr_info && !aTrrToo && addr_info->IsTRR()) {
    291    return false;
    292  }
    293  if (LoadNative()) {
    294    if (!onQueue()) {
    295      // The request has been passed to the OS resolver. The resultant DNS
    296      // record should be considered stale and not trusted; set a flag to
    297      // ensure it is called again.
    298      StoreResolveAgain(true);
    299    }
    300    // if onQueue is true, the host entry is already added to the cache
    301    // but is still pending to get resolved: just leave it in hash.
    302    return false;
    303  }
    304  // Already resolved; not in a pending state; remove from cache
    305  return true;
    306 }
    307 
    308 void AddrHostRecord::NotifyRetryingTrr() {
    309  MOZ_ASSERT(mFirstTRRSkippedReason ==
    310             mozilla::net::TRRSkippedReason::TRR_UNSET);
    311 
    312  // Save the skip reason of our first attempt for recording telemetry later.
    313  mFirstTRRSkippedReason = mTRRSkippedReason;
    314  mTRRSkippedReason = mozilla::net::TRRSkippedReason::TRR_UNSET;
    315 }
    316 
    317 void AddrHostRecord::ResolveComplete() {
    318  TimeStamp now = TimeStamp::Now();
    319 
    320  if (LoadNativeUsed()) {
    321    if (mNativeSuccess) {
    322      glean::dns::native_lookup_time.AccumulateRawDuration(mNativeDuration);
    323      profiler_add_marker(
    324          "Native DNS Lookup", geckoprofiler::category::NETWORK,
    325          MarkerOptions(MarkerTiming::Interval(mNativeStart, now),
    326                        MarkerThreadId::MainThread()),
    327          HostResolverMarker{}, host, originSuffix, type, flags);
    328    }
    329    glean::dns::lookup_disposition
    330        .Get(TRRService::ProviderKey(),
    331             mNativeSuccess ? "osOK"_ns : "osFail"_ns)
    332        .Add();
    333  }
    334 
    335  if (mResolverType == DNSResolverType::TRR) {
    336    if (mTRRSuccess) {
    337      MOZ_DIAGNOSTIC_ASSERT(mTRRSkippedReason ==
    338                            mozilla::net::TRRSkippedReason::TRR_OK);
    339      glean::dns::trr_lookup_time.Get(TRRService::ProviderKey())
    340          .AccumulateRawDuration(mTrrDuration);
    341      profiler_add_marker(
    342          "TRR DNS Lookup", geckoprofiler::category::NETWORK,
    343          MarkerOptions(MarkerTiming::Interval(now - mTrrDuration, now),
    344                        MarkerThreadId::MainThread()),
    345          HostResolverMarker{}, host, originSuffix, type, flags);
    346    }
    347    glean::dns::lookup_disposition
    348        .Get(TRRService::ProviderKey(), mTRRSuccess ? "trrOK"_ns : "trrFail"_ns)
    349        .Add();
    350  }
    351 
    352  if (nsHostResolver::Mode() == nsIDNSService::MODE_TRRFIRST ||
    353      nsHostResolver::Mode() == nsIDNSService::MODE_TRRONLY) {
    354    MOZ_ASSERT(mTRRSkippedReason != mozilla::net::TRRSkippedReason::TRR_UNSET);
    355 
    356    glean::dns::trr_skip_reason_trr_first.Get(TRRService::ProviderKey())
    357        .AccumulateSingleSample(static_cast<uint32_t>(mTRRSkippedReason));
    358    if (!mTRRSuccess && LoadNativeUsed()) {
    359      if (mNativeSuccess) {
    360        glean::dns::trr_skip_reason_native_success
    361            .Get(TRRService::ProviderKey())
    362            .AccumulateSingleSample(static_cast<uint32_t>(mTRRSkippedReason));
    363      } else {
    364        glean::dns::trr_skip_reason_native_failed.Get(TRRService::ProviderKey())
    365            .AccumulateSingleSample(static_cast<uint32_t>(mTRRSkippedReason));
    366      }
    367    }
    368 
    369    if (IsRelevantTRRSkipReason(mTRRSkippedReason)) {
    370      glean::dns::trr_relevant_skip_reason_trr_first
    371          .Get(TRRService::ProviderKey())
    372          .AccumulateSingleSample(static_cast<uint32_t>(mTRRSkippedReason));
    373 
    374      if (!mTRRSuccess && LoadNativeUsed()) {
    375        if (mNativeSuccess) {
    376          glean::dns::trr_relevant_skip_reason_native_success
    377              .Get(TRRService::ProviderKey())
    378              .AccumulateSingleSample(static_cast<uint32_t>(mTRRSkippedReason));
    379        } else {
    380          glean::dns::trr_relevant_skip_reason_native_failed
    381              .Get(TRRService::ProviderKey())
    382              .AccumulateSingleSample(static_cast<uint32_t>(mTRRSkippedReason));
    383        }
    384      }
    385    }
    386 
    387    if (StaticPrefs::network_trr_retry_on_recoverable_errors() &&
    388        nsHostResolver::Mode() == nsIDNSService::MODE_TRRFIRST) {
    389      nsAutoCString telemetryKey(TRRService::ProviderKey());
    390 
    391      if (mFirstTRRSkippedReason != mozilla::net::TRRSkippedReason::TRR_UNSET) {
    392        telemetryKey.AppendLiteral("|");
    393        telemetryKey.AppendInt(static_cast<uint32_t>(mFirstTRRSkippedReason));
    394 
    395        if (mTRRSuccess) {
    396          glean::dns::trr_skip_reason_retry_success
    397              .Get(TRRService::ProviderKey())
    398              .AccumulateSingleSample(
    399                  static_cast<uint32_t>(mFirstTRRSkippedReason));
    400        } else {
    401          glean::dns::trr_skip_reason_retry_failed
    402              .Get(TRRService::ProviderKey())
    403              .AccumulateSingleSample(
    404                  static_cast<uint32_t>(mFirstTRRSkippedReason));
    405        }
    406      }
    407 
    408      glean::dns::trr_skip_reason_strict_mode.Get(telemetryKey)
    409          .AccumulateSingleSample(static_cast<uint32_t>(mTRRSkippedReason));
    410 
    411      if (mTRRSuccess) {
    412        glean::dns::trr_attempt_count.Get(TRRService::ProviderKey())
    413            .AccumulateSingleSample(mTrrAttempts);
    414      }
    415    }
    416  }
    417 
    418  if (mEffectiveTRRMode == nsIRequest::TRR_FIRST_MODE) {
    419    if (flags & nsIDNSService::RESOLVE_DISABLE_TRR) {
    420      // TRR is disabled on request, which is a next-level back-off method.
    421      glean::dns::trr_disabled
    422          .Get(TRRService::ProviderKey(),
    423               mNativeSuccess ? "true"_ns : "false"_ns)
    424          .Add();
    425    } else {
    426      if (mTRRSuccess) {
    427        glean::dns::trr_first.Get(TRRService::ProviderKey(), "TRR"_ns).Add();
    428      } else if (mNativeSuccess) {
    429        if (mResolverType == DNSResolverType::TRR) {
    430          glean::dns::trr_first
    431              .Get(TRRService::ProviderKey(), "NativeAfterTRR"_ns)
    432              .Add();
    433        } else {
    434          glean::dns::trr_first.Get(TRRService::ProviderKey(), "Native"_ns)
    435              .Add();
    436        }
    437      } else {
    438        glean::dns::trr_first.Get(TRRService::ProviderKey(), "BothFailed"_ns)
    439            .Add();
    440      }
    441    }
    442  }
    443 
    444  switch (mEffectiveTRRMode) {
    445    case nsIRequest::TRR_DISABLED_MODE:
    446      glean::dns::lookup_algorithm
    447          .EnumGet(glean::dns::LookupAlgorithmLabel::eNativeonly)
    448          .Add();
    449      break;
    450    case nsIRequest::TRR_FIRST_MODE:
    451      glean::dns::lookup_algorithm
    452          .EnumGet(glean::dns::LookupAlgorithmLabel::eTrrfirst)
    453          .Add();
    454      break;
    455    case nsIRequest::TRR_ONLY_MODE:
    456      glean::dns::lookup_algorithm
    457          .EnumGet(glean::dns::LookupAlgorithmLabel::eTrronly)
    458          .Add();
    459      break;
    460    case nsIRequest::TRR_DEFAULT_MODE:
    461      MOZ_ASSERT_UNREACHABLE("We should not have a default value here");
    462      break;
    463  }
    464 
    465  if (mResolverType == DNSResolverType::TRR && !mTRRSuccess && mNativeSuccess &&
    466      !LoadGetTtl() && TRRService::Get()) {
    467    TRRService::Get()->AddToBlocklist(nsCString(host), originSuffix, pb, true);
    468  }
    469 }
    470 
    471 AddrHostRecord::DnsPriority AddrHostRecord::GetPriority(
    472    nsIDNSService::DNSFlags aFlags) {
    473  if (IsHighPriority(aFlags)) {
    474    return AddrHostRecord::DNS_PRIORITY_HIGH;
    475  }
    476  if (IsMediumPriority(aFlags)) {
    477    return AddrHostRecord::DNS_PRIORITY_MEDIUM;
    478  }
    479 
    480  return AddrHostRecord::DNS_PRIORITY_LOW;
    481 }
    482 
    483 nsresult AddrHostRecord::GetTtl(uint32_t* aResult) {
    484  NS_ENSURE_ARG(aResult);
    485  *aResult = mTtl;
    486  return NS_OK;
    487 }
    488 
    489 nsresult AddrHostRecord::GetLastUpdate(mozilla::TimeStamp* aLastUpdate) {
    490  addr_info_lock.AssertCurrentThreadOwns();
    491  *aLastUpdate = mLastUpdate;
    492  return NS_OK;
    493 }
    494 
    495 //----------------------------------------------------------------------------
    496 // TypeHostRecord
    497 //----------------------------------------------------------------------------
    498 
    499 NS_IMPL_ISUPPORTS_INHERITED(TypeHostRecord, nsHostRecord, TypeHostRecord,
    500                            nsIDNSTXTRecord, nsIDNSHTTPSSVCRecord)
    501 
    502 TypeHostRecord::TypeHostRecord(const nsHostKey& key)
    503    : nsHostRecord(key), DNSHTTPSSVCRecordBase(key.host) {}
    504 
    505 TypeHostRecord::~TypeHostRecord() { mCallbacks.clear(); }
    506 
    507 bool TypeHostRecord::HasUsableResultInternal(
    508    const mozilla::TimeStamp& now, nsIDNSService::DNSFlags queryFlags) const {
    509  if (CheckExpiration(now) == EXP_EXPIRED) {
    510    return false;
    511  }
    512 
    513  if (negative) {
    514    return true;
    515  }
    516 
    517  MOZ_PUSH_IGNORE_THREAD_SAFETY
    518  // To avoid locking in a const method
    519  return !mResults.is<Nothing>();
    520  MOZ_POP_THREAD_SAFETY
    521 }
    522 
    523 bool TypeHostRecord::RefreshForNegativeResponse() const { return false; }
    524 
    525 NS_IMETHODIMP TypeHostRecord::GetRecords(CopyableTArray<nsCString>& aRecords) {
    526  // deep copy
    527  MutexAutoLock lock(mResultsLock);
    528 
    529  if (!mResults.is<TypeRecordTxt>()) {
    530    return NS_ERROR_NOT_AVAILABLE;
    531  }
    532  aRecords = mResults.as<CopyableTArray<nsCString>>();
    533  return NS_OK;
    534 }
    535 
    536 NS_IMETHODIMP TypeHostRecord::GetRecordsAsOneString(nsACString& aRecords) {
    537  // deep copy
    538  MutexAutoLock lock(mResultsLock);
    539 
    540  if (!mResults.is<TypeRecordTxt>()) {
    541    return NS_ERROR_NOT_AVAILABLE;
    542  }
    543  auto& results = mResults.as<CopyableTArray<nsCString>>();
    544  for (uint32_t i = 0; i < results.Length(); i++) {
    545    aRecords.Append(results[i]);
    546  }
    547  return NS_OK;
    548 }
    549 
    550 size_t TypeHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
    551  size_t n = mallocSizeOf(this);
    552 
    553  n += nsHostKey::SizeOfExcludingThis(mallocSizeOf);
    554  n += SizeOfResolveHostCallbackListExcludingHead(mCallbacks, mallocSizeOf);
    555 
    556  return n;
    557 }
    558 
    559 uint32_t TypeHostRecord::GetType() {
    560  MutexAutoLock lock(mResultsLock);
    561 
    562  return mResults.match(
    563      [](TypeRecordEmpty&) {
    564        MOZ_ASSERT(false, "This should never be the case");
    565        return nsIDNSService::RESOLVE_TYPE_DEFAULT;
    566      },
    567      [](TypeRecordTxt&) { return nsIDNSService::RESOLVE_TYPE_TXT; },
    568      [](TypeRecordHTTPSSVC&) { return nsIDNSService::RESOLVE_TYPE_HTTPSSVC; });
    569 }
    570 
    571 TypeRecordResultType TypeHostRecord::GetResults() {
    572  MutexAutoLock lock(mResultsLock);
    573  return mResults;
    574 }
    575 
    576 NS_IMETHODIMP
    577 TypeHostRecord::GetRecords(nsTArray<RefPtr<nsISVCBRecord>>& aRecords) {
    578  MutexAutoLock lock(mResultsLock);
    579  if (!mResults.is<TypeRecordHTTPSSVC>()) {
    580    return NS_ERROR_NOT_AVAILABLE;
    581  }
    582 
    583  auto& results = mResults.as<TypeRecordHTTPSSVC>();
    584 
    585  for (const SVCB& r : results) {
    586    RefPtr<nsISVCBRecord> rec = new mozilla::net::SVCBRecord(r);
    587    aRecords.AppendElement(rec);
    588  }
    589 
    590  return NS_OK;
    591 }
    592 
    593 NS_IMETHODIMP
    594 TypeHostRecord::GetServiceModeRecord(bool aNoHttp2, bool aNoHttp3,
    595                                     nsISVCBRecord** aRecord) {
    596  return GetServiceModeRecordWithCname(aNoHttp2, aNoHttp3, ""_ns, aRecord);
    597 }
    598 
    599 NS_IMETHODIMP
    600 TypeHostRecord::GetServiceModeRecordWithCname(bool aNoHttp2, bool aNoHttp3,
    601                                              const nsACString& aCname,
    602                                              nsISVCBRecord** aRecord) {
    603  MutexAutoLock lock(mResultsLock);
    604  if (!mResults.is<TypeRecordHTTPSSVC>()) {
    605    return NS_ERROR_NOT_AVAILABLE;
    606  }
    607 
    608  auto& results = mResults.as<TypeRecordHTTPSSVC>();
    609  nsCOMPtr<nsISVCBRecord> result = GetServiceModeRecordInternal(
    610      aNoHttp2, aNoHttp3, results, mAllRecordsExcluded, true, aCname);
    611  if (!result) {
    612    return NS_ERROR_NOT_AVAILABLE;
    613  }
    614 
    615  result.forget(aRecord);
    616  return NS_OK;
    617 }
    618 
    619 NS_IMETHODIMP
    620 TypeHostRecord::IsTRR(bool* aResult) {
    621  *aResult = (mResolverType == DNSResolverType::TRR);
    622  return NS_OK;
    623 }
    624 
    625 NS_IMETHODIMP
    626 TypeHostRecord::GetAllRecords(bool aNoHttp2, bool aNoHttp3,
    627                              const nsACString& aCname,
    628                              nsTArray<RefPtr<nsISVCBRecord>>& aResult) {
    629  MutexAutoLock lock(mResultsLock);
    630  if (!mResults.is<TypeRecordHTTPSSVC>()) {
    631    return NS_ERROR_NOT_AVAILABLE;
    632  }
    633 
    634  auto& records = mResults.as<TypeRecordHTTPSSVC>();
    635  bool notused;
    636  GetAllRecordsInternal(aNoHttp2, aNoHttp3, aCname, records, false, &notused,
    637                        &notused, aResult);
    638  return NS_OK;
    639 }
    640 
    641 NS_IMETHODIMP
    642 TypeHostRecord::GetAllRecordsWithEchConfig(
    643    bool aNoHttp2, bool aNoHttp3, const nsACString& aCname,
    644    bool* aAllRecordsHaveEchConfig, bool* aAllRecordsInH3ExcludedList,
    645    nsTArray<RefPtr<nsISVCBRecord>>& aResult) {
    646  MutexAutoLock lock(mResultsLock);
    647  if (!mResults.is<TypeRecordHTTPSSVC>()) {
    648    return NS_ERROR_NOT_AVAILABLE;
    649  }
    650 
    651  auto& records = mResults.as<TypeRecordHTTPSSVC>();
    652  GetAllRecordsInternal(aNoHttp2, aNoHttp3, aCname, records, true,
    653                        aAllRecordsHaveEchConfig, aAllRecordsInH3ExcludedList,
    654                        aResult);
    655  return NS_OK;
    656 }
    657 
    658 NS_IMETHODIMP
    659 TypeHostRecord::GetHasIPAddresses(bool* aResult) {
    660  NS_ENSURE_ARG(aResult);
    661  MutexAutoLock lock(mResultsLock);
    662 
    663  if (!mResults.is<TypeRecordHTTPSSVC>()) {
    664    return NS_ERROR_NOT_AVAILABLE;
    665  }
    666 
    667  auto& results = mResults.as<TypeRecordHTTPSSVC>();
    668  *aResult = HasIPAddressesInternal(results);
    669  return NS_OK;
    670 }
    671 
    672 NS_IMETHODIMP
    673 TypeHostRecord::GetAllRecordsExcluded(bool* aResult) {
    674  NS_ENSURE_ARG(aResult);
    675  MutexAutoLock lock(mResultsLock);
    676 
    677  if (!mResults.is<TypeRecordHTTPSSVC>()) {
    678    return NS_ERROR_NOT_AVAILABLE;
    679  }
    680 
    681  *aResult = mAllRecordsExcluded;
    682  return NS_OK;
    683 }
    684 
    685 NS_IMETHODIMP
    686 TypeHostRecord::GetTtl(uint32_t* aResult) {
    687  NS_ENSURE_ARG(aResult);
    688  *aResult = mTtl;
    689  return NS_OK;
    690 }
    691 
    692 void TypeHostRecord::ResolveComplete() {
    693  if (IsRelevantTRRSkipReason(mTRRSkippedReason)) {
    694    glean::dns::trr_relevant_skip_reason_trr_first_type_rec
    695        .Get(TRRService::ProviderKey())
    696        .AccumulateSingleSample(static_cast<uint32_t>(mTRRSkippedReason));
    697  }
    698 
    699  if (mTRRSuccess) {
    700    glean::dns::by_type_succeeded_lookup_time.AccumulateRawDuration(
    701        mTrrDuration);
    702  } else {
    703    glean::dns::by_type_failed_lookup_time.AccumulateRawDuration(mTrrDuration);
    704  }
    705 }