summaryrefslogtreecommitdiffstats
path: root/netwerk/dns/nsHostRecord.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/dns/nsHostRecord.cpp')
-rw-r--r--netwerk/dns/nsHostRecord.cpp596
1 files changed, 596 insertions, 0 deletions
diff --git a/netwerk/dns/nsHostRecord.cpp b/netwerk/dns/nsHostRecord.cpp
new file mode 100644
index 0000000000..54aee3dde9
--- /dev/null
+++ b/netwerk/dns/nsHostRecord.cpp
@@ -0,0 +1,596 @@
+/* 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"
+#include "mozilla/StaticPrefs_network.h"
+#include "mozilla/Telemetry.h"
+#include "TRRService.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)
+
+//----------------------------------------------------------------------------
+
+using namespace mozilla;
+using namespace mozilla::net;
+
+nsHostKey::nsHostKey(const nsACString& aHost, const nsACString& aTrrServer,
+ uint16_t aType, nsIDNSService::DNSFlags 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<TRRQuery> 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;
+ mTtl = uint32_t(aFromHostRecord->mTtl);
+}
+
+bool nsHostRecord::HasUsableResult(const mozilla::TimeStamp& now,
+ nsIDNSService::DNSFlags queryFlags) const {
+ if (mDoomed) {
+ return false;
+ }
+
+ return HasUsableResultInternal(now, queryFlags);
+}
+
+//----------------------------------------------------------------------------
+// AddrHostRecord
+//----------------------------------------------------------------------------
+
+static size_t SizeOfResolveHostCallbackListExcludingHead(
+ const mozilla::LinkedList<RefPtr<nsResolveHostCallback>>& 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, nsIDNSService::DNSFlags 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::NotifyRetryingTrr() {
+ MOZ_ASSERT(mFirstTRRSkippedReason ==
+ mozilla::net::TRRSkippedReason::TRR_UNSET);
+
+ // Save the skip reason of our first attempt for recording telemetry later.
+ mFirstTRRSkippedReason = mTRRSkippedReason;
+ mTRRSkippedReason = mozilla::net::TRRSkippedReason::TRR_UNSET;
+}
+
+void AddrHostRecord::ResolveComplete() {
+ if (LoadNativeUsed()) {
+ if (mNativeSuccess) {
+ uint32_t millis = static_cast<uint32_t>(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<uint32_t>(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<uint32_t>(mTRRSkippedReason));
+ }
+
+ return;
+ }
+
+ if (mResolverType == DNSResolverType::TRR) {
+ if (mTRRSuccess) {
+ MOZ_DIAGNOSTIC_ASSERT(mTRRSkippedReason ==
+ mozilla::net::TRRSkippedReason::TRR_OK);
+ uint32_t millis = static_cast<uint32_t>(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) {
+ MOZ_ASSERT(mTRRSkippedReason != mozilla::net::TRRSkippedReason::TRR_UNSET);
+
+ Telemetry::Accumulate(Telemetry::TRR_SKIP_REASON_TRR_FIRST2,
+ TRRService::ProviderKey(),
+ static_cast<uint32_t>(mTRRSkippedReason));
+ if (!mTRRSuccess && LoadNativeUsed()) {
+ Telemetry::Accumulate(
+ mNativeSuccess ? Telemetry::TRR_SKIP_REASON_NATIVE_SUCCESS
+ : Telemetry::TRR_SKIP_REASON_NATIVE_FAILED,
+ TRRService::ProviderKey(), static_cast<uint32_t>(mTRRSkippedReason));
+ }
+
+ if (IsRelevantTRRSkipReason(mTRRSkippedReason)) {
+ Telemetry::Accumulate(Telemetry::TRR_RELEVANT_SKIP_REASON_TRR_FIRST,
+ TRRService::ProviderKey(),
+ static_cast<uint32_t>(mTRRSkippedReason));
+
+ if (!mTRRSuccess && LoadNativeUsed()) {
+ Telemetry::Accumulate(
+ mNativeSuccess ? Telemetry::TRR_RELEVANT_SKIP_REASON_NATIVE_SUCCESS
+ : Telemetry::TRR_RELEVANT_SKIP_REASON_NATIVE_FAILED,
+ TRRService::ProviderKey(),
+ static_cast<uint32_t>(mTRRSkippedReason));
+ }
+ }
+
+ if (StaticPrefs::network_trr_retry_on_recoverable_errors()) {
+ nsAutoCString telemetryKey(TRRService::ProviderKey());
+
+ if (mFirstTRRSkippedReason != mozilla::net::TRRSkippedReason::TRR_UNSET) {
+ telemetryKey.AppendLiteral("|");
+ telemetryKey.AppendInt(static_cast<uint32_t>(mFirstTRRSkippedReason));
+
+ Telemetry::Accumulate(mTRRSuccess
+ ? Telemetry::TRR_SKIP_REASON_RETRY_SUCCESS
+ : Telemetry::TRR_SKIP_REASON_RETRY_FAILED,
+ TRRService::ProviderKey(),
+ static_cast<uint32_t>(mFirstTRRSkippedReason));
+ }
+
+ Telemetry::Accumulate(Telemetry::TRR_SKIP_REASON_STRICT_MODE,
+ telemetryKey,
+ static_cast<uint32_t>(mTRRSkippedReason));
+
+ if (mTRRSuccess) {
+ Telemetry::Accumulate(Telemetry::TRR_ATTEMPT_COUNT,
+ TRRService::ProviderKey(), mTrrAttempts);
+ }
+ }
+ }
+
+ 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 &&
+ !LoadGetTtl() && TRRService::Get()) {
+ TRRService::Get()->AddToBlocklist(nsCString(host), originSuffix, pb, true);
+ }
+}
+
+AddrHostRecord::DnsPriority AddrHostRecord::GetPriority(
+ nsIDNSService::DNSFlags aFlags) {
+ if (IsHighPriority(aFlags)) {
+ return AddrHostRecord::DNS_PRIORITY_HIGH;
+ }
+ if (IsMediumPriority(aFlags)) {
+ return AddrHostRecord::DNS_PRIORITY_MEDIUM;
+ }
+
+ return AddrHostRecord::DNS_PRIORITY_LOW;
+}
+
+nsresult AddrHostRecord::GetTtl(uint32_t* aResult) {
+ NS_ENSURE_ARG(aResult);
+ *aResult = mTtl;
+ return NS_OK;
+}
+
+//----------------------------------------------------------------------------
+// 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, nsIDNSService::DNSFlags queryFlags) const {
+ if (CheckExpiration(now) == EXP_EXPIRED) {
+ return false;
+ }
+
+ if (negative) {
+ return true;
+ }
+
+ return !mResults.is<Nothing>();
+}
+
+bool TypeHostRecord::RefreshForNegativeResponse() const { return false; }
+
+NS_IMETHODIMP TypeHostRecord::GetRecords(CopyableTArray<nsCString>& aRecords) {
+ // deep copy
+ MutexAutoLock lock(mResultsLock);
+
+ if (!mResults.is<TypeRecordTxt>()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ aRecords = mResults.as<CopyableTArray<nsCString>>();
+ return NS_OK;
+}
+
+NS_IMETHODIMP TypeHostRecord::GetRecordsAsOneString(nsACString& aRecords) {
+ // deep copy
+ MutexAutoLock lock(mResultsLock);
+
+ if (!mResults.is<TypeRecordTxt>()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ auto& results = mResults.as<CopyableTArray<nsCString>>();
+ 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<RefPtr<nsISVCBRecord>>& aRecords) {
+ MutexAutoLock lock(mResultsLock);
+ if (!mResults.is<TypeRecordHTTPSSVC>()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ auto& results = mResults.as<TypeRecordHTTPSSVC>();
+
+ for (const SVCB& r : results) {
+ RefPtr<nsISVCBRecord> 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<TypeRecordHTTPSSVC>()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ auto& results = mResults.as<TypeRecordHTTPSSVC>();
+ nsCOMPtr<nsISVCBRecord> 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<RefPtr<nsISVCBRecord>>& aResult) {
+ MutexAutoLock lock(mResultsLock);
+ if (!mResults.is<TypeRecordHTTPSSVC>()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ auto& records = mResults.as<TypeRecordHTTPSSVC>();
+ 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<TypeRecordHTTPSSVC>()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ auto& results = mResults.as<TypeRecordHTTPSSVC>();
+ *aResult = HasIPAddressesInternal(results);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TypeHostRecord::GetAllRecordsExcluded(bool* aResult) {
+ NS_ENSURE_ARG(aResult);
+ MutexAutoLock lock(mResultsLock);
+
+ if (!mResults.is<TypeRecordHTTPSSVC>()) {
+ 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;
+}