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, ¬used, 637 ¬used, 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 }