From 0c9e5842a286e0ec3a011f18a6cf3003879dd4c1 Mon Sep 17 00:00:00 2001 From: Kershaw Chang Date: Wed, 16 Jun 2021 08:14:10 +0000 Subject: [PATCH] Bug 1713796 - P1: Move nsHostRecord to another file, r=necko-reviewers,valentin Differential Revision: https://phabricator.services.mozilla.com/D117322 --- netwerk/dns/DNSLogging.h | 26 ++ netwerk/dns/DNSPacket.cpp | 9 +- netwerk/dns/ODoH.cpp | 9 +- netwerk/dns/ODoHService.cpp | 5 +- netwerk/dns/TRR.cpp | 12 +- netwerk/dns/TRRQuery.cpp | 6 +- netwerk/dns/TRRService.cpp | 8 +- netwerk/dns/TRRServiceBase.cpp | 7 +- netwerk/dns/moz.build | 3 +- netwerk/dns/nsHostRecord.cpp | 532 +++++++++++++++++++++++++++++++++ netwerk/dns/nsHostRecord.h | 365 ++++++++++++++++++++++ netwerk/dns/nsHostResolver.cpp | 532 +-------------------------------- netwerk/dns/nsHostResolver.h | 341 +-------------------- tools/lint/rejected-words.yml | 1 + 14 files changed, 945 insertions(+), 911 deletions(-) create mode 100644 netwerk/dns/DNSLogging.h create mode 100644 netwerk/dns/nsHostRecord.cpp create mode 100644 netwerk/dns/nsHostRecord.h diff --git a/netwerk/dns/DNSLogging.h b/netwerk/dns/DNSLogging.h new file mode 100644 index 000000000000..4fd63730caca --- /dev/null +++ b/netwerk/dns/DNSLogging.h @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_DNSLogging_h +#define mozilla_DNSLogging_h + +#include "mozilla/Logging.h" + +#undef LOG + +namespace mozilla { +namespace net { +extern LazyLogModule gHostResolverLog; +} // namespace net +} // namespace mozilla + +#define LOG(msg) \ + MOZ_LOG(mozilla::net::gHostResolverLog, mozilla::LogLevel::Debug, msg) +#define LOG1(msg) \ + MOZ_LOG(mozilla::net::gHostResolverLog, mozilla::LogLevel::Error, msg) +#define LOG_ENABLED() \ + MOZ_LOG_TEST(mozilla::net::gHostResolverLog, mozilla::LogLevel::Debug) + +#endif // mozilla_DNSLogging_h diff --git a/netwerk/dns/DNSPacket.cpp b/netwerk/dns/DNSPacket.cpp index 6a4e1d1f8e41..46581225520a 100644 --- a/netwerk/dns/DNSPacket.cpp +++ b/netwerk/dns/DNSPacket.cpp @@ -8,17 +8,12 @@ #include "mozilla/EndianUtils.h" #include "mozilla/ScopeExit.h" #include "ODoHService.h" +// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. +#include "DNSLogging.h" namespace mozilla { namespace net { -extern mozilla::LazyLogModule gHostResolverLog; -#undef LOG -#undef LOG_ENABLED -#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args) -#define LOG_ENABLED() \ - MOZ_LOG_TEST(mozilla::net::gHostResolverLog, mozilla::LogLevel::Debug) - static uint16_t get16bit(const unsigned char* aData, unsigned int index) { return ((aData[index] << 8) | aData[index + 1]); } diff --git a/netwerk/dns/ODoH.cpp b/netwerk/dns/ODoH.cpp index 461e49b5e621..a7268e13194c 100644 --- a/netwerk/dns/ODoH.cpp +++ b/netwerk/dns/ODoH.cpp @@ -10,17 +10,12 @@ #include "nsIURIMutator.h" #include "ODoHService.h" #include "TRRService.h" +// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. +#include "DNSLogging.h" namespace mozilla { namespace net { -#undef LOG -#undef LOG_ENABLED -extern mozilla::LazyLogModule gHostResolverLog; -#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args) -#define LOG_ENABLED() \ - MOZ_LOG_TEST(mozilla::net::gHostResolverLog, mozilla::LogLevel::Debug) - NS_IMETHODIMP ODoH::Run() { if (!gODoHService) { diff --git a/netwerk/dns/ODoHService.cpp b/netwerk/dns/ODoHService.cpp index ed8b803a1a84..f03c3c30c288 100644 --- a/netwerk/dns/ODoHService.cpp +++ b/netwerk/dns/ODoHService.cpp @@ -18,6 +18,8 @@ #include "ODoH.h" #include "TRRService.h" #include "nsURLHelper.h" +// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. +#include "DNSLogging.h" static const char kODoHProxyURIPref[] = "network.trr.odoh.proxy_uri"; static const char kODoHTargetHostPref[] = "network.trr.odoh.target_host"; @@ -29,9 +31,6 @@ namespace net { ODoHService* gODoHService = nullptr; -extern mozilla::LazyLogModule gHostResolverLog; -#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args) - NS_IMPL_ISUPPORTS(ODoHService, nsIDNSListener, nsIObserver, nsISupportsWeakReference, nsITimerCallback, nsIStreamLoaderObserver) diff --git a/netwerk/dns/TRR.cpp b/netwerk/dns/TRR.cpp index 62dacb4eed3f..2ee7110f9e2b 100644 --- a/netwerk/dns/TRR.cpp +++ b/netwerk/dns/TRR.cpp @@ -37,17 +37,12 @@ #include "mozilla/TimeStamp.h" #include "mozilla/Tokenizer.h" #include "mozilla/UniquePtr.h" +// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. +#include "DNSLogging.h" namespace mozilla { namespace net { -#undef LOG -#undef LOG_ENABLED -extern mozilla::LazyLogModule gHostResolverLog; -#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args) -#define LOG_ENABLED() \ - MOZ_LOG_TEST(mozilla::net::gHostResolverLog, mozilla::LogLevel::Debug) - NS_IMPL_ISUPPORTS(TRR, nsIHttpPushListener, nsIInterfaceRequestor, nsIStreamListener, nsIRunnable, nsITimerCallback) @@ -1026,8 +1021,5 @@ void TRR::Cancel(nsresult aStatus) { bool TRR::UseDefaultServer() { return !mRec || mRec->mTrrServer.IsEmpty(); } -#undef LOG - -// namespace } // namespace net } // namespace mozilla diff --git a/netwerk/dns/TRRQuery.cpp b/netwerk/dns/TRRQuery.cpp index ff57fd66203f..08481636d8a3 100644 --- a/netwerk/dns/TRRQuery.cpp +++ b/netwerk/dns/TRRQuery.cpp @@ -5,14 +5,12 @@ #include "TRRQuery.h" #include "TRR.h" #include "ODoH.h" +// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. +#include "DNSLogging.h" namespace mozilla { namespace net { -#undef LOG -extern mozilla::LazyLogModule gHostResolverLog; -#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args) - static already_AddRefed merge_rrset(AddrInfo* rrto, AddrInfo* rrfrom) { MOZ_ASSERT(rrto && rrfrom); diff --git a/netwerk/dns/TRRService.cpp b/netwerk/dns/TRRService.cpp index 0e5e11e69d50..6e85f8d5cad7 100644 --- a/netwerk/dns/TRRService.cpp +++ b/netwerk/dns/TRRService.cpp @@ -24,6 +24,8 @@ #include "mozilla/TelemetryComms.h" #include "mozilla/Tokenizer.h" #include "mozilla/net/rust_helper.h" +// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. +#include "DNSLogging.h" #if defined(XP_WIN) && !defined(__MINGW32__) # include // for SHGetSpecialFolderPathA @@ -40,10 +42,6 @@ static const char kDisableIpv6Pref[] = "network.dns.disableIPv6"; namespace mozilla { namespace net { -#undef LOG -extern mozilla::LazyLogModule gHostResolverLog; -#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args) - TRRService* gTRRService = nullptr; StaticRefPtr sTRRBackgroundThread; static Atomic sTRRServicePtr; @@ -1302,7 +1300,5 @@ AHostResolver::LookupStatus TRRService::CompleteLookupByType( return LOOKUP_OK; } -#undef LOG - } // namespace net } // namespace mozilla diff --git a/netwerk/dns/TRRServiceBase.cpp b/netwerk/dns/TRRServiceBase.cpp index d330cfb32207..cbe7f7b1f905 100644 --- a/netwerk/dns/TRRServiceBase.cpp +++ b/netwerk/dns/TRRServiceBase.cpp @@ -6,20 +6,17 @@ #include "TRRServiceBase.h" -#include "mozilla/Logging.h" #include "mozilla/Preferences.h" #include "nsHostResolver.h" #include "nsNetUtil.h" #include "nsIOService.h" #include "nsIDNSService.h" +// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. +#include "DNSLogging.h" namespace mozilla { namespace net { -#undef LOG -extern mozilla::LazyLogModule gHostResolverLog; -#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args) - TRRServiceBase::TRRServiceBase() : mMode(nsIDNSService::MODE_NATIVEONLY), mURISetByDetection(false) {} diff --git a/netwerk/dns/moz.build b/netwerk/dns/moz.build index 31dd7c81b8d9..1e577f301fa1 100644 --- a/netwerk/dns/moz.build +++ b/netwerk/dns/moz.build @@ -54,7 +54,6 @@ EXPORTS.mozilla.net += [ SOURCES += [ "GetAddrInfo.cpp", # Undefines UNICODE "nsEffectiveTLDService.cpp", # Excluded from UNIFIED_SOURCES due to special build flags. - "nsHostResolver.cpp", # Redefines LOG ] UNIFIED_SOURCES += [ @@ -71,6 +70,8 @@ UNIFIED_SOURCES += [ "NativeDNSResolverOverrideChild.cpp", "NativeDNSResolverOverrideParent.cpp", "nsDNSService2.cpp", + "nsHostRecord.cpp", + "nsHostResolver.cpp", "nsIDNService.cpp", "ODoH.cpp", "ODoHService.cpp", diff --git a/netwerk/dns/nsHostRecord.cpp b/netwerk/dns/nsHostRecord.cpp new file mode 100644 index 000000000000..6f0ca13994db --- /dev/null +++ b/netwerk/dns/nsHostRecord.cpp @@ -0,0 +1,532 @@ +/* vim:set ts=4 sw=2 sts=2 et cin: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsHostRecord.h" +#include "TRRQuery.h" +// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. +#include "DNSLogging.h" + +//---------------------------------------------------------------------------- +// this macro filters out any flags that are not used when constructing the +// host key. the significant flags are those that would affect the resulting +// host record (i.e., the flags that are passed down to PR_GetAddrInfoByName). +#define RES_KEY_FLAGS(_f) \ + ((_f) & \ + (nsHostResolver::RES_CANON_NAME | nsHostResolver::RES_DISABLE_TRR | \ + nsIDNSService::RESOLVE_TRR_MODE_MASK | nsHostResolver::RES_IP_HINT)) + +#define IS_ADDR_TYPE(_type) ((_type) == nsIDNSService::RESOLVE_TYPE_DEFAULT) +#define IS_OTHER_TYPE(_type) ((_type) != nsIDNSService::RESOLVE_TYPE_DEFAULT) + +//---------------------------------------------------------------------------- + +nsHostKey::nsHostKey(const nsACString& aHost, const nsACString& aTrrServer, + uint16_t aType, uint16_t aFlags, uint16_t aAf, bool aPb, + const nsACString& aOriginsuffix) + : host(aHost), + mTrrServer(aTrrServer), + type(aType), + flags(aFlags), + af(aAf), + pb(aPb), + originSuffix(aOriginsuffix) {} + +bool nsHostKey::operator==(const nsHostKey& other) const { + return host == other.host && mTrrServer == other.mTrrServer && + type == other.type && + RES_KEY_FLAGS(flags) == RES_KEY_FLAGS(other.flags) && af == other.af && + originSuffix == other.originSuffix; +} + +PLDHashNumber nsHostKey::Hash() const { + return AddToHash(HashString(host.get()), HashString(mTrrServer.get()), type, + RES_KEY_FLAGS(flags), af, HashString(originSuffix.get())); +} + +size_t nsHostKey::SizeOfExcludingThis( + mozilla::MallocSizeOf mallocSizeOf) const { + size_t n = 0; + n += host.SizeOfExcludingThisIfUnshared(mallocSizeOf); + n += mTrrServer.SizeOfExcludingThisIfUnshared(mallocSizeOf); + n += originSuffix.SizeOfExcludingThisIfUnshared(mallocSizeOf); + return n; +} + +//---------------------------------------------------------------------------- +// nsHostRecord +//---------------------------------------------------------------------------- + +NS_IMPL_ISUPPORTS0(nsHostRecord) + +nsHostRecord::nsHostRecord(const nsHostKey& key) + : nsHostKey(key), mTRRQuery("nsHostRecord.mTRRQuery") {} + +void nsHostRecord::Invalidate() { mDoomed = true; } + +void nsHostRecord::Cancel() { + RefPtr query; + { + auto lock = mTRRQuery.Lock(); + query.swap(lock.ref()); + } + + if (query) { + query->Cancel(NS_ERROR_ABORT); + } +} + +nsHostRecord::ExpirationStatus nsHostRecord::CheckExpiration( + const mozilla::TimeStamp& now) const { + if (!mGraceStart.IsNull() && now >= mGraceStart && !mValidEnd.IsNull() && + now < mValidEnd) { + return nsHostRecord::EXP_GRACE; + } + if (!mValidEnd.IsNull() && now < mValidEnd) { + return nsHostRecord::EXP_VALID; + } + + return nsHostRecord::EXP_EXPIRED; +} + +void nsHostRecord::SetExpiration(const mozilla::TimeStamp& now, + unsigned int valid, unsigned int grace) { + mValidStart = now; + if ((valid + grace) < 60) { + grace = 60 - valid; + LOG(("SetExpiration: artificially bumped grace to %d\n", grace)); + } + mGraceStart = now + TimeDuration::FromSeconds(valid); + mValidEnd = now + TimeDuration::FromSeconds(valid + grace); + mTtl = valid; +} + +void nsHostRecord::CopyExpirationTimesAndFlagsFrom( + const nsHostRecord* aFromHostRecord) { + // This is used to copy information from a cache entry to a record. All + // information necessary for HasUsableRecord needs to be copied. + mValidStart = aFromHostRecord->mValidStart; + mValidEnd = aFromHostRecord->mValidEnd; + mGraceStart = aFromHostRecord->mGraceStart; + mDoomed = aFromHostRecord->mDoomed; +} + +bool nsHostRecord::HasUsableResult(const mozilla::TimeStamp& now, + uint16_t queryFlags) const { + if (mDoomed) { + return false; + } + + return HasUsableResultInternal(now, queryFlags); +} + +//---------------------------------------------------------------------------- +// AddrHostRecord +//---------------------------------------------------------------------------- + +static size_t SizeOfResolveHostCallbackListExcludingHead( + const mozilla::LinkedList>& aCallbacks, + MallocSizeOf mallocSizeOf) { + size_t n = aCallbacks.sizeOfExcludingThis(mallocSizeOf); + + for (const nsResolveHostCallback* t = aCallbacks.getFirst(); t; + t = t->getNext()) { + n += t->SizeOfIncludingThis(mallocSizeOf); + } + + return n; +} + +NS_IMPL_ISUPPORTS_INHERITED(AddrHostRecord, nsHostRecord, AddrHostRecord) + +AddrHostRecord::AddrHostRecord(const nsHostKey& key) : nsHostRecord(key) {} + +AddrHostRecord::~AddrHostRecord() { + mCallbacks.clear(); + Telemetry::Accumulate(Telemetry::DNS_BLACKLIST_COUNT, mUnusableCount); +} + +bool AddrHostRecord::Blocklisted(const NetAddr* aQuery) { + addr_info_lock.AssertCurrentThreadOwns(); + LOG(("Checking unusable list for host [%s], host record [%p].\n", host.get(), + this)); + + // skip the string conversion for the common case of no blocklist + if (!mUnusableItems.Length()) { + return false; + } + + char buf[kIPv6CStrBufSize]; + if (!aQuery->ToStringBuffer(buf, sizeof(buf))) { + return false; + } + nsDependentCString strQuery(buf); + + for (uint32_t i = 0; i < mUnusableItems.Length(); i++) { + if (mUnusableItems.ElementAt(i).Equals(strQuery)) { + LOG(("Address [%s] is blocklisted for host [%s].\n", buf, host.get())); + return true; + } + } + + return false; +} + +void AddrHostRecord::ReportUnusable(const NetAddr* aAddress) { + addr_info_lock.AssertCurrentThreadOwns(); + LOG( + ("Adding address to blocklist for host [%s], host record [%p]." + "used trr=%d\n", + host.get(), this, mTRRSuccess)); + + ++mUnusableCount; + + char buf[kIPv6CStrBufSize]; + if (aAddress->ToStringBuffer(buf, sizeof(buf))) { + LOG( + ("Successfully adding address [%s] to blocklist for host " + "[%s].\n", + buf, host.get())); + mUnusableItems.AppendElement(nsCString(buf)); + } +} + +void AddrHostRecord::ResetBlocklist() { + addr_info_lock.AssertCurrentThreadOwns(); + LOG(("Resetting blocklist for host [%s], host record [%p].\n", host.get(), + this)); + mUnusableItems.Clear(); +} + +size_t AddrHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const { + size_t n = mallocSizeOf(this); + + n += nsHostKey::SizeOfExcludingThis(mallocSizeOf); + n += SizeOfResolveHostCallbackListExcludingHead(mCallbacks, mallocSizeOf); + + n += addr_info ? addr_info->SizeOfIncludingThis(mallocSizeOf) : 0; + n += mallocSizeOf(addr.get()); + + n += mUnusableItems.ShallowSizeOfExcludingThis(mallocSizeOf); + for (size_t i = 0; i < mUnusableItems.Length(); i++) { + n += mUnusableItems[i].SizeOfExcludingThisIfUnshared(mallocSizeOf); + } + return n; +} + +bool AddrHostRecord::HasUsableResultInternal(const mozilla::TimeStamp& now, + uint16_t queryFlags) const { + // don't use cached negative results for high priority queries. + if (negative && IsHighPriority(queryFlags)) { + return false; + } + + if (CheckExpiration(now) == EXP_EXPIRED) { + return false; + } + + if (negative) { + return true; + } + + return addr_info || addr; +} + +// Returns true if the entry can be removed, or false if it should be left. +// Sets ResolveAgain true for entries being resolved right now. +bool AddrHostRecord::RemoveOrRefresh(bool aTrrToo) { + // no need to flush TRRed names, they're not resolved "locally" + MutexAutoLock lock(addr_info_lock); + if (addr_info && !aTrrToo && addr_info->IsTRROrODoH()) { + return false; + } + if (LoadNative()) { + if (!onQueue()) { + // The request has been passed to the OS resolver. The resultant DNS + // record should be considered stale and not trusted; set a flag to + // ensure it is called again. + StoreResolveAgain(true); + } + // if onQueue is true, the host entry is already added to the cache + // but is still pending to get resolved: just leave it in hash. + return false; + } + // Already resolved; not in a pending state; remove from cache + return true; +} + +void AddrHostRecord::ResolveComplete() { + if (LoadNativeUsed()) { + if (mNativeSuccess) { + uint32_t millis = static_cast(mNativeDuration.ToMilliseconds()); + Telemetry::Accumulate(Telemetry::DNS_NATIVE_LOOKUP_TIME, millis); + } + AccumulateCategoricalKeyed( + TRRService::ProviderKey(), + mNativeSuccess ? Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::osOK + : Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::osFail); + } + + if (mResolverType == DNSResolverType::ODoH) { + // XXX(kershaw): Consider adding the failed host name into a blocklist. + if (mTRRSuccess) { + uint32_t millis = static_cast(mTrrDuration.ToMilliseconds()); + Telemetry::Accumulate(Telemetry::DNS_ODOH_LOOKUP_TIME, millis); + } + + if (nsHostResolver::Mode() == nsIDNSService::MODE_TRRFIRST) { + Telemetry::Accumulate(Telemetry::ODOH_SKIP_REASON_ODOH_FIRST, + static_cast(mTRRSkippedReason)); + } + + return; + } + + if (mResolverType == DNSResolverType::TRR) { + if (mTRRSuccess) { + uint32_t millis = static_cast(mTrrDuration.ToMilliseconds()); + Telemetry::Accumulate(Telemetry::DNS_TRR_LOOKUP_TIME3, + TRRService::ProviderKey(), millis); + } + AccumulateCategoricalKeyed( + TRRService::ProviderKey(), + mTRRSuccess ? Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrOK + : Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrFail); + } + + if (nsHostResolver::Mode() == nsIDNSService::MODE_TRRFIRST) { + Telemetry::Accumulate(Telemetry::TRR_SKIP_REASON_TRR_FIRST2, + TRRService::ProviderKey(), + static_cast(mTRRSkippedReason)); + + if (!mTRRSuccess) { + Telemetry::Accumulate( + mNativeSuccess ? Telemetry::TRR_SKIP_REASON_NATIVE_SUCCESS + : Telemetry::TRR_SKIP_REASON_NATIVE_FAILED, + TRRService::ProviderKey(), static_cast(mTRRSkippedReason)); + } + } + + if (mEffectiveTRRMode == nsIRequest::TRR_FIRST_MODE) { + if (flags & nsIDNSService::RESOLVE_DISABLE_TRR) { + // TRR is disabled on request, which is a next-level back-off method. + Telemetry::Accumulate(Telemetry::DNS_TRR_DISABLED3, + TRRService::ProviderKey(), mNativeSuccess); + } else { + if (mTRRSuccess) { + AccumulateCategoricalKeyed(TRRService::ProviderKey(), + Telemetry::LABELS_DNS_TRR_FIRST4::TRR); + } else if (mNativeSuccess) { + if (mResolverType == DNSResolverType::TRR) { + AccumulateCategoricalKeyed( + TRRService::ProviderKey(), + Telemetry::LABELS_DNS_TRR_FIRST4::NativeAfterTRR); + } else { + AccumulateCategoricalKeyed(TRRService::ProviderKey(), + Telemetry::LABELS_DNS_TRR_FIRST4::Native); + } + } else { + AccumulateCategoricalKeyed( + TRRService::ProviderKey(), + Telemetry::LABELS_DNS_TRR_FIRST4::BothFailed); + } + } + } + + switch (mEffectiveTRRMode) { + case nsIRequest::TRR_DISABLED_MODE: + AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::nativeOnly); + break; + case nsIRequest::TRR_FIRST_MODE: + AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrFirst); + break; + case nsIRequest::TRR_ONLY_MODE: + AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrOnly); + break; + case nsIRequest::TRR_DEFAULT_MODE: + MOZ_ASSERT_UNREACHABLE("We should not have a default value here"); + break; + } + + if (mResolverType == DNSResolverType::TRR && !mTRRSuccess && mNativeSuccess && + gTRRService) { + gTRRService->AddToBlocklist(nsCString(host), originSuffix, pb, true); + } +} + +AddrHostRecord::DnsPriority AddrHostRecord::GetPriority(uint16_t aFlags) { + if (IsHighPriority(aFlags)) { + return AddrHostRecord::DNS_PRIORITY_HIGH; + } + if (IsMediumPriority(aFlags)) { + return AddrHostRecord::DNS_PRIORITY_MEDIUM; + } + + return AddrHostRecord::DNS_PRIORITY_LOW; +} + +//---------------------------------------------------------------------------- +// TypeHostRecord +//---------------------------------------------------------------------------- + +NS_IMPL_ISUPPORTS_INHERITED(TypeHostRecord, nsHostRecord, TypeHostRecord, + nsIDNSTXTRecord, nsIDNSHTTPSSVCRecord) + +TypeHostRecord::TypeHostRecord(const nsHostKey& key) + : nsHostRecord(key), DNSHTTPSSVCRecordBase(key.host) {} + +TypeHostRecord::~TypeHostRecord() { mCallbacks.clear(); } + +bool TypeHostRecord::HasUsableResultInternal(const mozilla::TimeStamp& now, + uint16_t queryFlags) const { + if (CheckExpiration(now) == EXP_EXPIRED) { + return false; + } + + if (negative) { + return true; + } + + return !mResults.is(); +} + +bool TypeHostRecord::RefreshForNegativeResponse() const { return false; } + +NS_IMETHODIMP TypeHostRecord::GetRecords(CopyableTArray& aRecords) { + // deep copy + MutexAutoLock lock(mResultsLock); + + if (!mResults.is()) { + return NS_ERROR_NOT_AVAILABLE; + } + aRecords = mResults.as>(); + return NS_OK; +} + +NS_IMETHODIMP TypeHostRecord::GetRecordsAsOneString(nsACString& aRecords) { + // deep copy + MutexAutoLock lock(mResultsLock); + + if (!mResults.is()) { + return NS_ERROR_NOT_AVAILABLE; + } + auto& results = mResults.as>(); + for (uint32_t i = 0; i < results.Length(); i++) { + aRecords.Append(results[i]); + } + return NS_OK; +} + +size_t TypeHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const { + size_t n = mallocSizeOf(this); + + n += nsHostKey::SizeOfExcludingThis(mallocSizeOf); + n += SizeOfResolveHostCallbackListExcludingHead(mCallbacks, mallocSizeOf); + + return n; +} + +uint32_t TypeHostRecord::GetType() { + MutexAutoLock lock(mResultsLock); + + return mResults.match( + [](TypeRecordEmpty&) { + MOZ_ASSERT(false, "This should never be the case"); + return nsIDNSService::RESOLVE_TYPE_DEFAULT; + }, + [](TypeRecordTxt&) { return nsIDNSService::RESOLVE_TYPE_TXT; }, + [](TypeRecordHTTPSSVC&) { return nsIDNSService::RESOLVE_TYPE_HTTPSSVC; }); +} + +TypeRecordResultType TypeHostRecord::GetResults() { + MutexAutoLock lock(mResultsLock); + return mResults; +} + +NS_IMETHODIMP +TypeHostRecord::GetRecords(nsTArray>& aRecords) { + MutexAutoLock lock(mResultsLock); + if (!mResults.is()) { + return NS_ERROR_NOT_AVAILABLE; + } + + auto& results = mResults.as(); + + for (const SVCB& r : results) { + RefPtr rec = new mozilla::net::SVCBRecord(r); + aRecords.AppendElement(rec); + } + + return NS_OK; +} + +NS_IMETHODIMP +TypeHostRecord::GetServiceModeRecord(bool aNoHttp2, bool aNoHttp3, + nsISVCBRecord** aRecord) { + MutexAutoLock lock(mResultsLock); + if (!mResults.is()) { + return NS_ERROR_NOT_AVAILABLE; + } + + auto& results = mResults.as(); + nsCOMPtr result = GetServiceModeRecordInternal( + aNoHttp2, aNoHttp3, results, mAllRecordsExcluded); + if (!result) { + return NS_ERROR_NOT_AVAILABLE; + } + + result.forget(aRecord); + return NS_OK; +} + +NS_IMETHODIMP +TypeHostRecord::GetAllRecordsWithEchConfig( + bool aNoHttp2, bool aNoHttp3, bool* aAllRecordsHaveEchConfig, + bool* aAllRecordsInH3ExcludedList, + nsTArray>& aResult) { + MutexAutoLock lock(mResultsLock); + if (!mResults.is()) { + return NS_ERROR_NOT_AVAILABLE; + } + + auto& records = mResults.as(); + GetAllRecordsWithEchConfigInternal(aNoHttp2, aNoHttp3, records, + aAllRecordsHaveEchConfig, + aAllRecordsInH3ExcludedList, aResult); + return NS_OK; +} + +NS_IMETHODIMP +TypeHostRecord::GetHasIPAddresses(bool* aResult) { + NS_ENSURE_ARG(aResult); + MutexAutoLock lock(mResultsLock); + + if (!mResults.is()) { + return NS_ERROR_NOT_AVAILABLE; + } + + auto& results = mResults.as(); + *aResult = HasIPAddressesInternal(results); + return NS_OK; +} + +NS_IMETHODIMP +TypeHostRecord::GetAllRecordsExcluded(bool* aResult) { + NS_ENSURE_ARG(aResult); + MutexAutoLock lock(mResultsLock); + + if (!mResults.is()) { + return NS_ERROR_NOT_AVAILABLE; + } + + *aResult = mAllRecordsExcluded; + return NS_OK; +} + +NS_IMETHODIMP +TypeHostRecord::GetTtl(uint32_t* aResult) { + NS_ENSURE_ARG(aResult); + *aResult = mTtl; + return NS_OK; +} diff --git a/netwerk/dns/nsHostRecord.h b/netwerk/dns/nsHostRecord.h new file mode 100644 index 000000000000..bcc88901b22d --- /dev/null +++ b/netwerk/dns/nsHostRecord.h @@ -0,0 +1,365 @@ +/* vim:set ts=4 sw=2 sts=2 et cin: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsHostRecord_h__ +#define nsHostRecord_h__ + +#include "mozilla/LinkedList.h" +#include "mozilla/net/HTTPSSVC.h" +#include "nsIDNSService.h" +#include "nsIDNSByTypeRecord.h" +#include "PLDHashTable.h" +#include "TRRSkippedReason.h" + +class nsHostRecord; +class nsHostResolver; + +namespace mozilla { +namespace net { +class TRR; +class TRRQuery; +} // namespace net +} // namespace mozilla + +/** + * This class is used to notify listeners when a ResolveHost operation is + * complete. Classes that derive it must implement threadsafe nsISupports + * to be able to use RefPtr with this class. + */ +class nsResolveHostCallback + : public mozilla::LinkedListElement>, + public nsISupports { + public: + /** + * OnResolveHostComplete + * + * this function is called to complete a host lookup initiated by + * nsHostResolver::ResolveHost. it may be invoked recursively from + * ResolveHost or on an unspecified background thread. + * + * NOTE: it is the responsibility of the implementor of this method + * to handle the callback in a thread safe manner. + * + * @param resolver + * nsHostResolver object associated with this result + * @param record + * the host record containing the results of the lookup + * @param status + * if successful, |record| contains non-null results + */ + virtual void OnResolveHostComplete(nsHostResolver* resolver, + nsHostRecord* record, nsresult status) = 0; + /** + * EqualsAsyncListener + * + * Determines if the listener argument matches the listener member var. + * For subclasses not implementing a member listener, should return false. + * For subclasses having a member listener, the function should check if + * they are the same. Used for cases where a pointer to an object + * implementing nsResolveHostCallback is unknown, but a pointer to + * the original listener is known. + * + * @param aListener + * nsIDNSListener object associated with the original request + */ + virtual bool EqualsAsyncListener(nsIDNSListener* aListener) = 0; + + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const = 0; + + protected: + virtual ~nsResolveHostCallback() = default; +}; + +struct nsHostKey { + const nsCString host; + const nsCString mTrrServer; + uint16_t type = 0; + uint16_t flags = 0; + uint16_t af = 0; + bool pb = false; + const nsCString originSuffix; + explicit nsHostKey(const nsACString& host, const nsACString& aTrrServer, + uint16_t type, uint16_t flags, uint16_t af, bool pb, + const nsACString& originSuffix); + bool operator==(const nsHostKey& other) const; + size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + PLDHashNumber Hash() const; +}; + +/** + * nsHostRecord - ref counted object type stored in host resolver cache. + */ +class nsHostRecord : public mozilla::LinkedListElement>, + public nsHostKey, + public nsISupports { + using TRRSkippedReason = mozilla::net::TRRSkippedReason; + + public: + NS_DECL_THREADSAFE_ISUPPORTS + + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return 0; + } + + // Returns the TRR mode encoded by the flags + nsIRequest::TRRMode TRRMode(); + + // Records the first reason that caused TRR to be skipped or to fail. + void RecordReason(TRRSkippedReason reason) { + if (mTRRSkippedReason == TRRSkippedReason::TRR_UNSET) { + mTRRSkippedReason = reason; + } + } + + enum DnsPriority { + DNS_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW, + DNS_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM, + DNS_PRIORITY_HIGH, + }; + + protected: + friend class nsHostResolver; + friend class mozilla::net::TRR; + friend class mozilla::net::TRRQuery; + + explicit nsHostRecord(const nsHostKey& key); + virtual ~nsHostRecord() = default; + + // Mark hostrecord as not usable + void Invalidate(); + + enum ExpirationStatus { + EXP_VALID, + EXP_GRACE, + EXP_EXPIRED, + }; + + ExpirationStatus CheckExpiration(const mozilla::TimeStamp& now) const; + + // Convenience function for setting the timestamps above (mValidStart, + // mValidEnd, and mGraceStart). valid and grace are durations in seconds. + void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid, + unsigned int grace); + void CopyExpirationTimesAndFlagsFrom(const nsHostRecord* aFromHostRecord); + + // Checks if the record is usable (not expired and has a value) + bool HasUsableResult(const mozilla::TimeStamp& now, + uint16_t queryFlags = 0) const; + + static DnsPriority GetPriority(uint16_t aFlags); + + virtual void Cancel(); + virtual bool HasUsableResultInternal(const mozilla::TimeStamp& now, + uint16_t queryFlags) const = 0; + virtual bool RefreshForNegativeResponse() const { return true; } + + mozilla::LinkedList> mCallbacks; + + bool IsAddrRecord() const { + return type == nsIDNSService::RESOLVE_TYPE_DEFAULT; + } + + // When the record began being valid. Used mainly for bookkeeping. + mozilla::TimeStamp mValidStart; + + // When the record is no longer valid (it's time of expiration) + mozilla::TimeStamp mValidEnd; + + // When the record enters its grace period. This must be before mValidEnd. + // If a record is in its grace period (and not expired), it will be used + // but a request to refresh it will be made. + mozilla::TimeStamp mGraceStart; + + uint32_t mTtl = 0; + + // The computed TRR mode that is actually used by the request. + // It is set in nsHostResolver::NameLookup and is based on the mode of the + // default resolver and the TRRMode encoded in the flags. + // The mode into account if the TRR service is disabled, + // parental controls are on, domain matches exclusion list, etc. + nsIRequest::TRRMode mEffectiveTRRMode = nsIRequest::TRR_DEFAULT_MODE; + + TRRSkippedReason mTRRSkippedReason = TRRSkippedReason::TRR_UNSET; + TRRSkippedReason mTRRAFailReason = TRRSkippedReason::TRR_UNSET; + TRRSkippedReason mTRRAAAAFailReason = TRRSkippedReason::TRR_UNSET; + + mozilla::DataMutex> mTRRQuery; + + // counter of outstanding resolving calls + mozilla::Atomic mResolving{0}; + + // True if this record is a cache of a failed lookup. Negative cache + // entries are valid just like any other (though never for more than 60 + // seconds), but a use of that negative entry forces an asynchronous refresh. + bool negative = false; + + // Explicitly expired + bool mDoomed = false; +}; + +// b020e996-f6ab-45e5-9bf5-1da71dd0053a +#define ADDRHOSTRECORD_IID \ + { \ + 0xb020e996, 0xf6ab, 0x45e5, { \ + 0x9b, 0xf5, 0x1d, 0xa7, 0x1d, 0xd0, 0x05, 0x3a \ + } \ + } + +class AddrHostRecord final : public nsHostRecord { + using Mutex = mozilla::Mutex; + using DNSResolverType = mozilla::net::DNSResolverType; + + public: + NS_DECLARE_STATIC_IID_ACCESSOR(ADDRHOSTRECORD_IID) + NS_DECL_ISUPPORTS_INHERITED + + /* a fully resolved host record has either a non-null |addr_info| or |addr| + * field. if |addr_info| is null, it implies that the |host| is an IP + * address literal. in which case, |addr| contains the parsed address. + * otherwise, if |addr_info| is non-null, then it contains one or many + * IP addresses corresponding to the given host name. if both |addr_info| + * and |addr| are null, then the given host has not yet been fully resolved. + * |af| is the address family of the record we are querying for. + */ + + /* the lock protects |addr_info| and |addr_info_gencnt| because they + * are mutable and accessed by the resolver worker thread and the + * nsDNSService2 class. |addr| doesn't change after it has been + * assigned a value. only the resolver worker thread modifies + * nsHostRecord (and only in nsHostResolver::CompleteLookup); + * the other threads just read it. therefore the resolver worker + * thread doesn't need to lock when reading |addr_info|. + */ + Mutex addr_info_lock{"AddrHostRecord.addr_info_lock"}; + // generation count of |addr_info| + int addr_info_gencnt = 0; + RefPtr addr_info; + mozilla::UniquePtr addr; + + // hold addr_info_lock when calling the blocklist functions + bool Blocklisted(const mozilla::net::NetAddr* query); + void ResetBlocklist(); + void ReportUnusable(const mozilla::net::NetAddr* aAddress); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const override; + + nsIRequest::TRRMode EffectiveTRRMode() const { return mEffectiveTRRMode; } + + private: + friend class nsHostResolver; + friend class mozilla::net::TRR; + friend class mozilla::net::TRRQuery; + + explicit AddrHostRecord(const nsHostKey& key); + ~AddrHostRecord(); + + // Checks if the record is usable (not expired and has a value) + bool HasUsableResultInternal(const mozilla::TimeStamp& now, + uint16_t queryFlags) const override; + + bool RemoveOrRefresh(bool aTrrToo); // Mark records currently being resolved + // as needed to resolve again. + + void ResolveComplete(); + + static DnsPriority GetPriority(uint16_t aFlags); + + // true if pending and on the queue (not yet given to getaddrinfo()) + bool onQueue() { return LoadNative() && isInList(); } + + // When the lookups of this record started and their durations + mozilla::TimeStamp mTrrStart; + mozilla::TimeStamp mNativeStart; + mozilla::TimeDuration mTrrDuration; + mozilla::TimeDuration mNativeDuration; + + // TRR or ODoH was used on this record + mozilla::Atomic mResolverType{DNSResolverType::Native}; + uint8_t mTRRSuccess = 0; // number of successful TRR responses + uint8_t mNativeSuccess = 0; // number of native lookup responses + + // clang-format off + MOZ_ATOMIC_BITFIELDS(mAtomicBitfields, 8, ( + // true if this record is being resolved "natively", which means that + // it is either on the pending queue or owned by one of the worker threads. + (uint16_t, Native, 1), + (uint16_t, NativeUsed, 1), + // true if off queue and contributing to mActiveAnyThreadCount + (uint16_t, UsingAnyThread, 1), + (uint16_t, GetTtl, 1), + (uint16_t, ResolveAgain, 1) + )) + // clang-format on + + // The number of times ReportUnusable() has been called in the record's + // lifetime. + uint32_t mUnusableCount = 0; + + // a list of addresses associated with this record that have been reported + // as unusable. the list is kept as a set of strings to make it independent + // of gencnt. + nsTArray mUnusableItems; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(AddrHostRecord, ADDRHOSTRECORD_IID) + +// 77b786a7-04be-44f2-987c-ab8aa96676e0 +#define TYPEHOSTRECORD_IID \ + { \ + 0x77b786a7, 0x04be, 0x44f2, { \ + 0x98, 0x7c, 0xab, 0x8a, 0xa9, 0x66, 0x76, 0xe0 \ + } \ + } + +class TypeHostRecord final : public nsHostRecord, + public nsIDNSTXTRecord, + public nsIDNSHTTPSSVCRecord, + public mozilla::net::DNSHTTPSSVCRecordBase { + public: + NS_DECLARE_STATIC_IID_ACCESSOR(TYPEHOSTRECORD_IID) + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIDNSTXTRECORD + NS_DECL_NSIDNSHTTPSSVCRECORD + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const override; + uint32_t GetType(); + mozilla::net::TypeRecordResultType GetResults(); + + private: + friend class nsHostResolver; + friend class mozilla::net::TRRQuery; + + explicit TypeHostRecord(const nsHostKey& key); + ~TypeHostRecord(); + + // Checks if the record is usable (not expired and has a value) + bool HasUsableResultInternal(const mozilla::TimeStamp& now, + uint16_t queryFlags) const override; + bool RefreshForNegativeResponse() const override; + + mozilla::net::TypeRecordResultType mResults = AsVariant(mozilla::Nothing()); + mozilla::Mutex mResultsLock{"TypeHostRecord.mResultsLock"}; + + // When the lookups of this record started (for telemetry). + mozilla::TimeStamp mStart; + bool mAllRecordsExcluded = false; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(TypeHostRecord, TYPEHOSTRECORD_IID) + +static inline bool IsHighPriority(uint16_t flags) { + return !(flags & (nsHostRecord::DNS_PRIORITY_LOW | + nsHostRecord::DNS_PRIORITY_MEDIUM)); +} + +static inline bool IsMediumPriority(uint16_t flags) { + return flags & nsHostRecord::DNS_PRIORITY_MEDIUM; +} + +static inline bool IsLowPriority(uint16_t flags) { + return flags & nsHostRecord::DNS_PRIORITY_LOW; +} + +#endif // nsHostRecord_h__ diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp index 07e9f9186750..5f94e2fe9bfe 100644 --- a/netwerk/dns/nsHostResolver.cpp +++ b/netwerk/dns/nsHostResolver.cpp @@ -47,6 +47,8 @@ #include "mozilla/DebugOnly.h" #include "mozilla/Preferences.h" #include "mozilla/StaticPrefs_network.h" +// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. +#include "DNSLogging.h" using namespace mozilla; using namespace mozilla::net; @@ -86,12 +88,6 @@ static_assert( namespace mozilla::net { LazyLogModule gHostResolverLog("nsHostResolver"); -#define LOG(args) \ - MOZ_LOG(mozilla::net::gHostResolverLog, mozilla::LogLevel::Debug, args) -#define LOG1(args) \ - MOZ_LOG(mozilla::net::gHostResolverLog, mozilla::LogLevel::Error, args) -#define LOG_ENABLED() \ - MOZ_LOG_TEST(mozilla::net::gHostResolverLog, mozilla::LogLevel::Debug) } // namespace mozilla::net //---------------------------------------------------------------------------- @@ -137,530 +133,6 @@ class nsResState { //---------------------------------------------------------------------------- -static inline bool IsHighPriority(uint16_t flags) { - return !(flags & (nsHostResolver::RES_PRIORITY_LOW | - nsHostResolver::RES_PRIORITY_MEDIUM)); -} - -static inline bool IsMediumPriority(uint16_t flags) { - return flags & nsHostResolver::RES_PRIORITY_MEDIUM; -} - -static inline bool IsLowPriority(uint16_t flags) { - return flags & nsHostResolver::RES_PRIORITY_LOW; -} - -//---------------------------------------------------------------------------- -// this macro filters out any flags that are not used when constructing the -// host key. the significant flags are those that would affect the resulting -// host record (i.e., the flags that are passed down to PR_GetAddrInfoByName). -#define RES_KEY_FLAGS(_f) \ - ((_f) & \ - (nsHostResolver::RES_CANON_NAME | nsHostResolver::RES_DISABLE_TRR | \ - nsIDNSService::RESOLVE_TRR_MODE_MASK | nsHostResolver::RES_IP_HINT)) - -#define IS_ADDR_TYPE(_type) ((_type) == nsIDNSService::RESOLVE_TYPE_DEFAULT) -#define IS_OTHER_TYPE(_type) ((_type) != nsIDNSService::RESOLVE_TYPE_DEFAULT) - -nsHostKey::nsHostKey(const nsACString& aHost, const nsACString& aTrrServer, - uint16_t aType, uint16_t aFlags, uint16_t aAf, bool aPb, - const nsACString& aOriginsuffix) - : host(aHost), - mTrrServer(aTrrServer), - type(aType), - flags(aFlags), - af(aAf), - pb(aPb), - originSuffix(aOriginsuffix) {} - -bool nsHostKey::operator==(const nsHostKey& other) const { - return host == other.host && mTrrServer == other.mTrrServer && - type == other.type && - RES_KEY_FLAGS(flags) == RES_KEY_FLAGS(other.flags) && af == other.af && - originSuffix == other.originSuffix; -} - -PLDHashNumber nsHostKey::Hash() const { - return AddToHash(HashString(host.get()), HashString(mTrrServer.get()), type, - RES_KEY_FLAGS(flags), af, HashString(originSuffix.get())); -} - -size_t nsHostKey::SizeOfExcludingThis( - mozilla::MallocSizeOf mallocSizeOf) const { - size_t n = 0; - n += host.SizeOfExcludingThisIfUnshared(mallocSizeOf); - n += mTrrServer.SizeOfExcludingThisIfUnshared(mallocSizeOf); - n += originSuffix.SizeOfExcludingThisIfUnshared(mallocSizeOf); - return n; -} - -NS_IMPL_ISUPPORTS0(nsHostRecord) - -nsHostRecord::nsHostRecord(const nsHostKey& key) - : nsHostKey(key), mTRRQuery("nsHostRecord.mTRRQuery") {} - -void nsHostRecord::Invalidate() { mDoomed = true; } - -void nsHostRecord::Cancel() { - RefPtr query; - { - auto lock = mTRRQuery.Lock(); - query.swap(lock.ref()); - } - - if (query) { - query->Cancel(NS_ERROR_ABORT); - } -} - -nsHostRecord::ExpirationStatus nsHostRecord::CheckExpiration( - const mozilla::TimeStamp& now) const { - if (!mGraceStart.IsNull() && now >= mGraceStart && !mValidEnd.IsNull() && - now < mValidEnd) { - return nsHostRecord::EXP_GRACE; - } - if (!mValidEnd.IsNull() && now < mValidEnd) { - return nsHostRecord::EXP_VALID; - } - - return nsHostRecord::EXP_EXPIRED; -} - -void nsHostRecord::SetExpiration(const mozilla::TimeStamp& now, - unsigned int valid, unsigned int grace) { - mValidStart = now; - if ((valid + grace) < 60) { - grace = 60 - valid; - LOG(("SetExpiration: artificially bumped grace to %d\n", grace)); - } - mGraceStart = now + TimeDuration::FromSeconds(valid); - mValidEnd = now + TimeDuration::FromSeconds(valid + grace); - mTtl = valid; -} - -void nsHostRecord::CopyExpirationTimesAndFlagsFrom( - const nsHostRecord* aFromHostRecord) { - // This is used to copy information from a cache entry to a record. All - // information necessary for HasUsableRecord needs to be copied. - mValidStart = aFromHostRecord->mValidStart; - mValidEnd = aFromHostRecord->mValidEnd; - mGraceStart = aFromHostRecord->mGraceStart; - mDoomed = aFromHostRecord->mDoomed; -} - -bool nsHostRecord::HasUsableResult(const mozilla::TimeStamp& now, - uint16_t queryFlags) const { - if (mDoomed) { - return false; - } - - return HasUsableResultInternal(now, queryFlags); -} - -static size_t SizeOfResolveHostCallbackListExcludingHead( - const mozilla::LinkedList>& aCallbacks, - MallocSizeOf mallocSizeOf) { - size_t n = aCallbacks.sizeOfExcludingThis(mallocSizeOf); - - for (const nsResolveHostCallback* t = aCallbacks.getFirst(); t; - t = t->getNext()) { - n += t->SizeOfIncludingThis(mallocSizeOf); - } - - return n; -} - -NS_IMPL_ISUPPORTS_INHERITED(AddrHostRecord, nsHostRecord, AddrHostRecord) - -AddrHostRecord::AddrHostRecord(const nsHostKey& key) : nsHostRecord(key) {} - -AddrHostRecord::~AddrHostRecord() { - mCallbacks.clear(); - Telemetry::Accumulate(Telemetry::DNS_BLACKLIST_COUNT, mUnusableCount); -} - -bool AddrHostRecord::Blocklisted(const NetAddr* aQuery) { - addr_info_lock.AssertCurrentThreadOwns(); - LOG(("Checking unusable list for host [%s], host record [%p].\n", host.get(), - this)); - - // skip the string conversion for the common case of no blocklist - if (!mUnusableItems.Length()) { - return false; - } - - char buf[kIPv6CStrBufSize]; - if (!aQuery->ToStringBuffer(buf, sizeof(buf))) { - return false; - } - nsDependentCString strQuery(buf); - - for (uint32_t i = 0; i < mUnusableItems.Length(); i++) { - if (mUnusableItems.ElementAt(i).Equals(strQuery)) { - LOG(("Address [%s] is blocklisted for host [%s].\n", buf, host.get())); - return true; - } - } - - return false; -} - -void AddrHostRecord::ReportUnusable(const NetAddr* aAddress) { - addr_info_lock.AssertCurrentThreadOwns(); - LOG( - ("Adding address to blocklist for host [%s], host record [%p]." - "used trr=%d\n", - host.get(), this, mTRRSuccess)); - - ++mUnusableCount; - - char buf[kIPv6CStrBufSize]; - if (aAddress->ToStringBuffer(buf, sizeof(buf))) { - LOG( - ("Successfully adding address [%s] to blocklist for host " - "[%s].\n", - buf, host.get())); - mUnusableItems.AppendElement(nsCString(buf)); - } -} - -void AddrHostRecord::ResetBlocklist() { - addr_info_lock.AssertCurrentThreadOwns(); - LOG(("Resetting blocklist for host [%s], host record [%p].\n", host.get(), - this)); - mUnusableItems.Clear(); -} - -size_t AddrHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const { - size_t n = mallocSizeOf(this); - - n += nsHostKey::SizeOfExcludingThis(mallocSizeOf); - n += SizeOfResolveHostCallbackListExcludingHead(mCallbacks, mallocSizeOf); - - n += addr_info ? addr_info->SizeOfIncludingThis(mallocSizeOf) : 0; - n += mallocSizeOf(addr.get()); - - n += mUnusableItems.ShallowSizeOfExcludingThis(mallocSizeOf); - for (size_t i = 0; i < mUnusableItems.Length(); i++) { - n += mUnusableItems[i].SizeOfExcludingThisIfUnshared(mallocSizeOf); - } - return n; -} - -bool AddrHostRecord::HasUsableResultInternal(const mozilla::TimeStamp& now, - uint16_t queryFlags) const { - // don't use cached negative results for high priority queries. - if (negative && IsHighPriority(queryFlags)) { - return false; - } - - if (CheckExpiration(now) == EXP_EXPIRED) { - return false; - } - - if (negative) { - return true; - } - - return addr_info || addr; -} - -// Returns true if the entry can be removed, or false if it should be left. -// Sets ResolveAgain true for entries being resolved right now. -bool AddrHostRecord::RemoveOrRefresh(bool aTrrToo) { - // no need to flush TRRed names, they're not resolved "locally" - MutexAutoLock lock(addr_info_lock); - if (addr_info && !aTrrToo && addr_info->IsTRROrODoH()) { - return false; - } - if (LoadNative()) { - if (!onQueue()) { - // The request has been passed to the OS resolver. The resultant DNS - // record should be considered stale and not trusted; set a flag to - // ensure it is called again. - StoreResolveAgain(true); - } - // if onQueue is true, the host entry is already added to the cache - // but is still pending to get resolved: just leave it in hash. - return false; - } - // Already resolved; not in a pending state; remove from cache - return true; -} - -void AddrHostRecord::ResolveComplete() { - if (LoadNativeUsed()) { - if (mNativeSuccess) { - uint32_t millis = static_cast(mNativeDuration.ToMilliseconds()); - Telemetry::Accumulate(Telemetry::DNS_NATIVE_LOOKUP_TIME, millis); - } - AccumulateCategoricalKeyed( - TRRService::ProviderKey(), - mNativeSuccess ? Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::osOK - : Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::osFail); - } - - if (mResolverType == DNSResolverType::ODoH) { - // XXX(kershaw): Consider adding the failed host name into a blocklist. - if (mTRRSuccess) { - uint32_t millis = static_cast(mTrrDuration.ToMilliseconds()); - Telemetry::Accumulate(Telemetry::DNS_ODOH_LOOKUP_TIME, millis); - } - - if (nsHostResolver::Mode() == nsIDNSService::MODE_TRRFIRST) { - Telemetry::Accumulate(Telemetry::ODOH_SKIP_REASON_ODOH_FIRST, - static_cast(mTRRSkippedReason)); - } - - return; - } - - if (mResolverType == DNSResolverType::TRR) { - if (mTRRSuccess) { - uint32_t millis = static_cast(mTrrDuration.ToMilliseconds()); - Telemetry::Accumulate(Telemetry::DNS_TRR_LOOKUP_TIME3, - TRRService::ProviderKey(), millis); - } - AccumulateCategoricalKeyed( - TRRService::ProviderKey(), - mTRRSuccess ? Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrOK - : Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrFail); - } - - if (nsHostResolver::Mode() == nsIDNSService::MODE_TRRFIRST) { - Telemetry::Accumulate(Telemetry::TRR_SKIP_REASON_TRR_FIRST2, - TRRService::ProviderKey(), - static_cast(mTRRSkippedReason)); - - if (!mTRRSuccess) { - Telemetry::Accumulate( - mNativeSuccess ? Telemetry::TRR_SKIP_REASON_NATIVE_SUCCESS - : Telemetry::TRR_SKIP_REASON_NATIVE_FAILED, - TRRService::ProviderKey(), static_cast(mTRRSkippedReason)); - } - } - - if (mEffectiveTRRMode == nsIRequest::TRR_FIRST_MODE) { - if (flags & nsIDNSService::RESOLVE_DISABLE_TRR) { - // TRR is disabled on request, which is a next-level back-off method. - Telemetry::Accumulate(Telemetry::DNS_TRR_DISABLED3, - TRRService::ProviderKey(), mNativeSuccess); - } else { - if (mTRRSuccess) { - AccumulateCategoricalKeyed(TRRService::ProviderKey(), - Telemetry::LABELS_DNS_TRR_FIRST4::TRR); - } else if (mNativeSuccess) { - if (mResolverType == DNSResolverType::TRR) { - AccumulateCategoricalKeyed( - TRRService::ProviderKey(), - Telemetry::LABELS_DNS_TRR_FIRST4::NativeAfterTRR); - } else { - AccumulateCategoricalKeyed(TRRService::ProviderKey(), - Telemetry::LABELS_DNS_TRR_FIRST4::Native); - } - } else { - AccumulateCategoricalKeyed( - TRRService::ProviderKey(), - Telemetry::LABELS_DNS_TRR_FIRST4::BothFailed); - } - } - } - - switch (mEffectiveTRRMode) { - case nsIRequest::TRR_DISABLED_MODE: - AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::nativeOnly); - break; - case nsIRequest::TRR_FIRST_MODE: - AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrFirst); - break; - case nsIRequest::TRR_ONLY_MODE: - AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrOnly); - break; - case nsIRequest::TRR_DEFAULT_MODE: - MOZ_ASSERT_UNREACHABLE("We should not have a default value here"); - break; - } - - if (mResolverType == DNSResolverType::TRR && !mTRRSuccess && mNativeSuccess && - gTRRService) { - gTRRService->AddToBlocklist(nsCString(host), originSuffix, pb, true); - } -} - -AddrHostRecord::DnsPriority AddrHostRecord::GetPriority(uint16_t aFlags) { - if (IsHighPriority(aFlags)) { - return AddrHostRecord::DNS_PRIORITY_HIGH; - } - if (IsMediumPriority(aFlags)) { - return AddrHostRecord::DNS_PRIORITY_MEDIUM; - } - - return AddrHostRecord::DNS_PRIORITY_LOW; -} - -NS_IMPL_ISUPPORTS_INHERITED(TypeHostRecord, nsHostRecord, TypeHostRecord, - nsIDNSTXTRecord, nsIDNSHTTPSSVCRecord) - -TypeHostRecord::TypeHostRecord(const nsHostKey& key) - : nsHostRecord(key), DNSHTTPSSVCRecordBase(key.host) {} - -TypeHostRecord::~TypeHostRecord() { mCallbacks.clear(); } - -bool TypeHostRecord::HasUsableResultInternal(const mozilla::TimeStamp& now, - uint16_t queryFlags) const { - if (CheckExpiration(now) == EXP_EXPIRED) { - return false; - } - - if (negative) { - return true; - } - - return !mResults.is(); -} - -bool TypeHostRecord::RefreshForNegativeResponse() const { return false; } - -NS_IMETHODIMP TypeHostRecord::GetRecords(CopyableTArray& aRecords) { - // deep copy - MutexAutoLock lock(mResultsLock); - - if (!mResults.is()) { - return NS_ERROR_NOT_AVAILABLE; - } - aRecords = mResults.as>(); - return NS_OK; -} - -NS_IMETHODIMP TypeHostRecord::GetRecordsAsOneString(nsACString& aRecords) { - // deep copy - MutexAutoLock lock(mResultsLock); - - if (!mResults.is()) { - return NS_ERROR_NOT_AVAILABLE; - } - auto& results = mResults.as>(); - for (uint32_t i = 0; i < results.Length(); i++) { - aRecords.Append(results[i]); - } - return NS_OK; -} - -size_t TypeHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const { - size_t n = mallocSizeOf(this); - - n += nsHostKey::SizeOfExcludingThis(mallocSizeOf); - n += SizeOfResolveHostCallbackListExcludingHead(mCallbacks, mallocSizeOf); - - return n; -} - -uint32_t TypeHostRecord::GetType() { - MutexAutoLock lock(mResultsLock); - - return mResults.match( - [](TypeRecordEmpty&) { - MOZ_ASSERT(false, "This should never be the case"); - return nsIDNSService::RESOLVE_TYPE_DEFAULT; - }, - [](TypeRecordTxt&) { return nsIDNSService::RESOLVE_TYPE_TXT; }, - [](TypeRecordHTTPSSVC&) { return nsIDNSService::RESOLVE_TYPE_HTTPSSVC; }); -} - -TypeRecordResultType TypeHostRecord::GetResults() { - MutexAutoLock lock(mResultsLock); - return mResults; -} - -NS_IMETHODIMP -TypeHostRecord::GetRecords(nsTArray>& aRecords) { - MutexAutoLock lock(mResultsLock); - if (!mResults.is()) { - return NS_ERROR_NOT_AVAILABLE; - } - - auto& results = mResults.as(); - - for (const SVCB& r : results) { - RefPtr rec = new mozilla::net::SVCBRecord(r); - aRecords.AppendElement(rec); - } - - return NS_OK; -} - -NS_IMETHODIMP -TypeHostRecord::GetServiceModeRecord(bool aNoHttp2, bool aNoHttp3, - nsISVCBRecord** aRecord) { - MutexAutoLock lock(mResultsLock); - if (!mResults.is()) { - return NS_ERROR_NOT_AVAILABLE; - } - - auto& results = mResults.as(); - nsCOMPtr result = GetServiceModeRecordInternal( - aNoHttp2, aNoHttp3, results, mAllRecordsExcluded); - if (!result) { - return NS_ERROR_NOT_AVAILABLE; - } - - result.forget(aRecord); - return NS_OK; -} - -NS_IMETHODIMP -TypeHostRecord::GetAllRecordsWithEchConfig( - bool aNoHttp2, bool aNoHttp3, bool* aAllRecordsHaveEchConfig, - bool* aAllRecordsInH3ExcludedList, - nsTArray>& aResult) { - MutexAutoLock lock(mResultsLock); - if (!mResults.is()) { - return NS_ERROR_NOT_AVAILABLE; - } - - auto& records = mResults.as(); - GetAllRecordsWithEchConfigInternal(aNoHttp2, aNoHttp3, records, - aAllRecordsHaveEchConfig, - aAllRecordsInH3ExcludedList, aResult); - return NS_OK; -} - -NS_IMETHODIMP -TypeHostRecord::GetHasIPAddresses(bool* aResult) { - NS_ENSURE_ARG(aResult); - MutexAutoLock lock(mResultsLock); - - if (!mResults.is()) { - return NS_ERROR_NOT_AVAILABLE; - } - - auto& results = mResults.as(); - *aResult = HasIPAddressesInternal(results); - return NS_OK; -} - -NS_IMETHODIMP -TypeHostRecord::GetAllRecordsExcluded(bool* aResult) { - NS_ENSURE_ARG(aResult); - MutexAutoLock lock(mResultsLock); - - if (!mResults.is()) { - return NS_ERROR_NOT_AVAILABLE; - } - - *aResult = mAllRecordsExcluded; - return NS_OK; -} - -NS_IMETHODIMP -TypeHostRecord::GetTtl(uint32_t* aResult) { - NS_ENSURE_ARG(aResult); - *aResult = mTtl; - return NS_OK; -} - -//---------------------------------------------------------------------------- - static const char kPrefGetTtl[] = "network.dns.get-ttl"; static const char kPrefNativeIsLocalhost[] = "network.dns.native-is-localhost"; static const char kPrefThreadIdleTime[] = diff --git a/netwerk/dns/nsHostResolver.h b/netwerk/dns/nsHostResolver.h index 6ac350eba3f6..3e2b26ab835d 100644 --- a/netwerk/dns/nsHostResolver.h +++ b/netwerk/dns/nsHostResolver.h @@ -14,26 +14,21 @@ #include "mozilla/Mutex.h" #include "nsISupportsImpl.h" #include "nsIDNSListener.h" -#include "nsIDNSService.h" #include "nsTArray.h" #include "GetAddrInfo.h" #include "mozilla/net/DNS.h" #include "mozilla/net/DashboardTypes.h" #include "mozilla/AtomicBitfields.h" #include "mozilla/Atomics.h" -#include "mozilla/LinkedList.h" #include "mozilla/TimeStamp.h" #include "mozilla/UniquePtr.h" +#include "nsHostRecord.h" #include "nsRefPtrHashtable.h" #include "nsIThreadPool.h" #include "mozilla/net/NetworkConnectivityService.h" -#include "nsIDNSByTypeRecord.h" #include "mozilla/net/DNSByTypeRecord.h" #include "mozilla/Maybe.h" -#include "TRRSkippedReason.h" -class nsHostResolver; -class nsResolveHostCallback; namespace mozilla { namespace net { class TRR; @@ -55,336 +50,6 @@ extern mozilla::Atomic gNativeIsLocalhost; (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \ MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY) -struct nsHostKey { - const nsCString host; - const nsCString mTrrServer; - uint16_t type = 0; - uint16_t flags = 0; - uint16_t af = 0; - bool pb = false; - const nsCString originSuffix; - explicit nsHostKey(const nsACString& host, const nsACString& aTrrServer, - uint16_t type, uint16_t flags, uint16_t af, bool pb, - const nsACString& originSuffix); - bool operator==(const nsHostKey& other) const; - size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; - PLDHashNumber Hash() const; -}; - -/** - * nsHostRecord - ref counted object type stored in host resolver cache. - */ -class nsHostRecord : public mozilla::LinkedListElement>, - public nsHostKey, - public nsISupports { - using TRRSkippedReason = mozilla::net::TRRSkippedReason; - - public: - NS_DECL_THREADSAFE_ISUPPORTS - - virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return 0; - } - - // Returns the TRR mode encoded by the flags - nsIRequest::TRRMode TRRMode(); - - // Records the first reason that caused TRR to be skipped or to fail. - void RecordReason(TRRSkippedReason reason) { - if (mTRRSkippedReason == TRRSkippedReason::TRR_UNSET) { - mTRRSkippedReason = reason; - } - } - - protected: - friend class nsHostResolver; - friend class mozilla::net::TRR; - friend class mozilla::net::TRRQuery; - - explicit nsHostRecord(const nsHostKey& key); - virtual ~nsHostRecord() = default; - - // Mark hostrecord as not usable - void Invalidate(); - - enum ExpirationStatus { - EXP_VALID, - EXP_GRACE, - EXP_EXPIRED, - }; - - ExpirationStatus CheckExpiration(const mozilla::TimeStamp& now) const; - - // Convenience function for setting the timestamps above (mValidStart, - // mValidEnd, and mGraceStart). valid and grace are durations in seconds. - void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid, - unsigned int grace); - void CopyExpirationTimesAndFlagsFrom(const nsHostRecord* aFromHostRecord); - - // Checks if the record is usable (not expired and has a value) - bool HasUsableResult(const mozilla::TimeStamp& now, - uint16_t queryFlags = 0) const; - - enum DnsPriority { - DNS_PRIORITY_LOW, - DNS_PRIORITY_MEDIUM, - DNS_PRIORITY_HIGH, - }; - static DnsPriority GetPriority(uint16_t aFlags); - - virtual void Cancel(); - virtual bool HasUsableResultInternal(const mozilla::TimeStamp& now, - uint16_t queryFlags) const = 0; - virtual bool RefreshForNegativeResponse() const { return true; } - - mozilla::LinkedList> mCallbacks; - - bool IsAddrRecord() const { - return type == nsIDNSService::RESOLVE_TYPE_DEFAULT; - } - - // When the record began being valid. Used mainly for bookkeeping. - mozilla::TimeStamp mValidStart; - - // When the record is no longer valid (it's time of expiration) - mozilla::TimeStamp mValidEnd; - - // When the record enters its grace period. This must be before mValidEnd. - // If a record is in its grace period (and not expired), it will be used - // but a request to refresh it will be made. - mozilla::TimeStamp mGraceStart; - - uint32_t mTtl = 0; - - // The computed TRR mode that is actually used by the request. - // It is set in nsHostResolver::NameLookup and is based on the mode of the - // default resolver and the TRRMode encoded in the flags. - // The mode into account if the TRR service is disabled, - // parental controls are on, domain matches exclusion list, etc. - nsIRequest::TRRMode mEffectiveTRRMode = nsIRequest::TRR_DEFAULT_MODE; - - TRRSkippedReason mTRRSkippedReason = TRRSkippedReason::TRR_UNSET; - TRRSkippedReason mTRRAFailReason = TRRSkippedReason::TRR_UNSET; - TRRSkippedReason mTRRAAAAFailReason = TRRSkippedReason::TRR_UNSET; - - mozilla::DataMutex> mTRRQuery; - - // counter of outstanding resolving calls - mozilla::Atomic mResolving{0}; - - // True if this record is a cache of a failed lookup. Negative cache - // entries are valid just like any other (though never for more than 60 - // seconds), but a use of that negative entry forces an asynchronous refresh. - bool negative = false; - - // Explicitly expired - bool mDoomed = false; -}; - -// b020e996-f6ab-45e5-9bf5-1da71dd0053a -#define ADDRHOSTRECORD_IID \ - { \ - 0xb020e996, 0xf6ab, 0x45e5, { \ - 0x9b, 0xf5, 0x1d, 0xa7, 0x1d, 0xd0, 0x05, 0x3a \ - } \ - } - -class AddrHostRecord final : public nsHostRecord { - using Mutex = mozilla::Mutex; - using DNSResolverType = mozilla::net::DNSResolverType; - - public: - NS_DECLARE_STATIC_IID_ACCESSOR(ADDRHOSTRECORD_IID) - NS_DECL_ISUPPORTS_INHERITED - - /* a fully resolved host record has either a non-null |addr_info| or |addr| - * field. if |addr_info| is null, it implies that the |host| is an IP - * address literal. in which case, |addr| contains the parsed address. - * otherwise, if |addr_info| is non-null, then it contains one or many - * IP addresses corresponding to the given host name. if both |addr_info| - * and |addr| are null, then the given host has not yet been fully resolved. - * |af| is the address family of the record we are querying for. - */ - - /* the lock protects |addr_info| and |addr_info_gencnt| because they - * are mutable and accessed by the resolver worker thread and the - * nsDNSService2 class. |addr| doesn't change after it has been - * assigned a value. only the resolver worker thread modifies - * nsHostRecord (and only in nsHostResolver::CompleteLookup); - * the other threads just read it. therefore the resolver worker - * thread doesn't need to lock when reading |addr_info|. - */ - Mutex addr_info_lock{"AddrHostRecord.addr_info_lock"}; - // generation count of |addr_info| - int addr_info_gencnt = 0; - RefPtr addr_info; - mozilla::UniquePtr addr; - - // hold addr_info_lock when calling the blocklist functions - bool Blocklisted(const mozilla::net::NetAddr* query); - void ResetBlocklist(); - void ReportUnusable(const mozilla::net::NetAddr* aAddress); - - size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const override; - - nsIRequest::TRRMode EffectiveTRRMode() const { return mEffectiveTRRMode; } - - private: - friend class nsHostResolver; - friend class mozilla::net::TRR; - friend class mozilla::net::TRRQuery; - - explicit AddrHostRecord(const nsHostKey& key); - ~AddrHostRecord(); - - // Checks if the record is usable (not expired and has a value) - bool HasUsableResultInternal(const mozilla::TimeStamp& now, - uint16_t queryFlags) const override; - - bool RemoveOrRefresh(bool aTrrToo); // Mark records currently being resolved - // as needed to resolve again. - - void ResolveComplete(); - - enum DnsPriority { - DNS_PRIORITY_LOW, - DNS_PRIORITY_MEDIUM, - DNS_PRIORITY_HIGH, - }; - static DnsPriority GetPriority(uint16_t aFlags); - - // true if pending and on the queue (not yet given to getaddrinfo()) - bool onQueue() { return LoadNative() && isInList(); } - - // When the lookups of this record started and their durations - mozilla::TimeStamp mTrrStart; - mozilla::TimeStamp mNativeStart; - mozilla::TimeDuration mTrrDuration; - mozilla::TimeDuration mNativeDuration; - - // TRR or ODoH was used on this record - mozilla::Atomic mResolverType{DNSResolverType::Native}; - uint8_t mTRRSuccess = 0; // number of successful TRR responses - uint8_t mNativeSuccess = 0; // number of native lookup responses - - // clang-format off - MOZ_ATOMIC_BITFIELDS(mAtomicBitfields, 8, ( - // true if this record is being resolved "natively", which means that - // it is either on the pending queue or owned by one of the worker threads. - (uint16_t, Native, 1), - (uint16_t, NativeUsed, 1), - // true if off queue and contributing to mActiveAnyThreadCount - (uint16_t, UsingAnyThread, 1), - (uint16_t, GetTtl, 1), - (uint16_t, ResolveAgain, 1) - )) - // clang-format on - - // The number of times ReportUnusable() has been called in the record's - // lifetime. - uint32_t mUnusableCount = 0; - - // a list of addresses associated with this record that have been reported - // as unusable. the list is kept as a set of strings to make it independent - // of gencnt. - nsTArray mUnusableItems; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(AddrHostRecord, ADDRHOSTRECORD_IID) - -// 77b786a7-04be-44f2-987c-ab8aa96676e0 -#define TYPEHOSTRECORD_IID \ - { \ - 0x77b786a7, 0x04be, 0x44f2, { \ - 0x98, 0x7c, 0xab, 0x8a, 0xa9, 0x66, 0x76, 0xe0 \ - } \ - } - -class TypeHostRecord final : public nsHostRecord, - public nsIDNSTXTRecord, - public nsIDNSHTTPSSVCRecord, - public mozilla::net::DNSHTTPSSVCRecordBase { - public: - NS_DECLARE_STATIC_IID_ACCESSOR(TYPEHOSTRECORD_IID) - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIDNSTXTRECORD - NS_DECL_NSIDNSHTTPSSVCRECORD - - size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const override; - uint32_t GetType(); - mozilla::net::TypeRecordResultType GetResults(); - - private: - friend class nsHostResolver; - friend class mozilla::net::TRRQuery; - - explicit TypeHostRecord(const nsHostKey& key); - ~TypeHostRecord(); - - // Checks if the record is usable (not expired and has a value) - bool HasUsableResultInternal(const mozilla::TimeStamp& now, - uint16_t queryFlags) const override; - bool RefreshForNegativeResponse() const override; - - mozilla::net::TypeRecordResultType mResults = AsVariant(mozilla::Nothing()); - mozilla::Mutex mResultsLock{"TypeHostRecord.mResultsLock"}; - - // When the lookups of this record started (for telemetry). - mozilla::TimeStamp mStart; - bool mAllRecordsExcluded = false; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(TypeHostRecord, TYPEHOSTRECORD_IID) - -/** - * This class is used to notify listeners when a ResolveHost operation is - * complete. Classes that derive it must implement threadsafe nsISupports - * to be able to use RefPtr with this class. - */ -class nsResolveHostCallback - : public mozilla::LinkedListElement>, - public nsISupports { - public: - /** - * OnResolveHostComplete - * - * this function is called to complete a host lookup initiated by - * nsHostResolver::ResolveHost. it may be invoked recursively from - * ResolveHost or on an unspecified background thread. - * - * NOTE: it is the responsibility of the implementor of this method - * to handle the callback in a thread safe manner. - * - * @param resolver - * nsHostResolver object associated with this result - * @param record - * the host record containing the results of the lookup - * @param status - * if successful, |record| contains non-null results - */ - virtual void OnResolveHostComplete(nsHostResolver* resolver, - nsHostRecord* record, nsresult status) = 0; - /** - * EqualsAsyncListener - * - * Determines if the listener argument matches the listener member var. - * For subclasses not implementing a member listener, should return false. - * For subclasses having a member listener, the function should check if - * they are the same. Used for cases where a pointer to an object - * implementing nsResolveHostCallback is unknown, but a pointer to - * the original listener is known. - * - * @param aListener - * nsIDNSListener object associated with the original request - */ - virtual bool EqualsAsyncListener(nsIDNSListener* aListener) = 0; - - virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const = 0; - - protected: - virtual ~nsResolveHostCallback() = default; -}; - class AHostResolver { public: AHostResolver() = default; @@ -506,8 +171,8 @@ class nsHostResolver : public nsISupports, public AHostResolver { enum { RES_BYPASS_CACHE = nsIDNSService::RESOLVE_BYPASS_CACHE, RES_CANON_NAME = nsIDNSService::RESOLVE_CANONICAL_NAME, - RES_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM, - RES_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW, + RES_PRIORITY_MEDIUM = nsHostRecord::DNS_PRIORITY_MEDIUM, + RES_PRIORITY_LOW = nsHostRecord::DNS_PRIORITY_LOW, RES_SPECULATE = nsIDNSService::RESOLVE_SPECULATE, // RES_DISABLE_IPV6 = nsIDNSService::RESOLVE_DISABLE_IPV6, // Not used RES_OFFLINE = nsIDNSService::RESOLVE_OFFLINE, diff --git a/tools/lint/rejected-words.yml b/tools/lint/rejected-words.yml index c1b229cd7fe5..aea4a6c97949 100644 --- a/tools/lint/rejected-words.yml +++ b/tools/lint/rejected-words.yml @@ -214,6 +214,7 @@ avoid-blacklist-and-whitelist: - netwerk/base/nsIOService.h - netwerk/base/nsURLHelper.cpp - netwerk/cookie/CookieCommons.h + - netwerk/dns/nsHostRecord.cpp - netwerk/dns/nsHostResolver.cpp - netwerk/dns/nsIDNService.cpp - netwerk/dns/nsIDNService.h