Bug 1691408 - Record confirmation event telemetry r=nhnt11,dragana,necko-reviewers

- Adds new TRR* argument to CompleteLookup so we can extract the channel
  status from the TRR request.
- Record event whenever the confirmation context changes
- NetworkID is recorded whenever we start a new confirmation attempt
- Captive portal status is updated based on observer notifications
- We keep a buffer of the last 32 confirmation results.

Differential Revision: https://phabricator.services.mozilla.com/D105173
This commit is contained in:
Valentin Gosu 2021-02-17 10:26:41 +00:00
Родитель e5e0b8d7a7
Коммит efa654d3d5
8 изменённых файлов: 312 добавлений и 114 удалений

Просмотреть файл

@ -633,7 +633,8 @@ void TRR::SaveAdditionalRecords(
addrRec->mTrrStart = TimeStamp::Now();
LOG(("Completing lookup for additional: %s", nsCString(iter.Key()).get()));
(void)mHostResolver->CompleteLookup(hostRecord, NS_OK, ai, mPB,
mOriginSuffix, AddrHostRecord::TRR_OK);
mOriginSuffix, AddrHostRecord::TRR_OK,
this);
}
}
@ -672,7 +673,7 @@ void TRR::StoreIPHintAsDNSRecord(const struct SVCB& aSVCBRecord) {
addrRec->mTrrStart = TimeStamp::Now();
(void)mHostResolver->CompleteLookup(hostRecord, NS_OK, ai, mPB, mOriginSuffix,
AddrHostRecord::TRR_OK);
AddrHostRecord::TRR_OK, this);
}
nsresult TRR::ReturnData(nsIChannel* aChannel) {
@ -705,7 +706,7 @@ nsresult TRR::ReturnData(nsIChannel* aChannel) {
return NS_ERROR_FAILURE;
}
(void)mHostResolver->CompleteLookup(mRec, NS_OK, ai, mPB, mOriginSuffix,
mTRRSkippedReason);
mTRRSkippedReason, this);
mHostResolver = nullptr;
mRec = nullptr;
} else {
@ -732,7 +733,7 @@ nsresult TRR::FailData(nsresult error) {
RefPtr<AddrInfo> ai = new AddrInfo(mHost, mType, std::move(noAddresses));
(void)mHostResolver->CompleteLookup(mRec, error, ai, mPB, mOriginSuffix,
mTRRSkippedReason);
mTRRSkippedReason, this);
}
mHostResolver = nullptr;
@ -862,6 +863,8 @@ TRR::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
nsCOMPtr<nsIChannel> channel;
channel.swap(mChannel);
mChannelStatus = aStatusCode;
{
// Cancel the timer since we don't need it anymore.
nsCOMPtr<nsITimer> timer;

Просмотреть файл

@ -103,6 +103,8 @@ class TRR : public Runnable,
void SetTimeout(uint32_t aTimeoutMs) { mTimeoutMs = aTimeoutMs; }
nsresult ChannelStatus() { return mChannelStatus; }
protected:
virtual ~TRR() = default;
virtual DNSPacket* GetOrCreateDNSPacket();
@ -142,6 +144,7 @@ class TRR : public Runnable,
bool mFailed = false;
bool mPB;
DOHresp mDNS;
nsresult mChannelStatus = NS_OK;
// The request timeout in milliseconds. If 0 we will use the default timeout
// we get from the prefs.

Просмотреть файл

@ -162,10 +162,11 @@ nsresult TRRQuery::DispatchLookup(TRR* pushedTRR, bool aUseODoH) {
AHostResolver::LookupStatus TRRQuery::CompleteLookup(
nsHostRecord* rec, nsresult status, AddrInfo* aNewRRSet, bool pb,
const nsACString& aOriginsuffix, nsHostRecord::TRRSkippedReason aReason) {
const nsACString& aOriginsuffix, nsHostRecord::TRRSkippedReason aReason,
TRR* aTRRRequest) {
if (rec != mRecord) {
return mHostResolver->CompleteLookup(rec, status, aNewRRSet, pb,
aOriginsuffix, aReason);
aOriginsuffix, aReason, aTRRRequest);
}
RefPtr<AddrInfo> newRRSet(aNewRRSet);
@ -270,7 +271,7 @@ AHostResolver::LookupStatus TRRQuery::CompleteLookup(
}
return mHostResolver->CompleteLookup(rec, status, newRRSet, pb, aOriginsuffix,
aReason);
aReason, aTRRRequest);
}
AHostResolver::LookupStatus TRRQuery::CompleteLookupByType(

Просмотреть файл

@ -31,10 +31,11 @@ class TRRQuery : public AHostResolver {
AddrHostRecord::TRRSkippedReason mTRRAAAAFailReason =
AddrHostRecord::TRR_UNSET;
virtual LookupStatus CompleteLookup(
nsHostRecord*, nsresult, mozilla::net::AddrInfo*, bool pb,
const nsACString& aOriginsuffix,
nsHostRecord::TRRSkippedReason aReason) override;
virtual LookupStatus CompleteLookup(nsHostRecord*, nsresult,
mozilla::net::AddrInfo*, bool pb,
const nsACString& aOriginsuffix,
nsHostRecord::TRRSkippedReason aReason,
TRR* aTRRRequest) override;
virtual LookupStatus CompleteLookupByType(
nsHostRecord*, nsresult, mozilla::net::TypeRecordResultType& aResult,
uint32_t aTtl, bool pb) override;

Просмотреть файл

@ -56,10 +56,9 @@ TRRService::TRRService()
mConfirmationNS("example.com"_ns),
mCaptiveIsPassed(false),
mTRRBLStorage("DataMutex::TRRBlocklist"),
mConfirmationState(CONFIRM_INIT),
mRetryConfirmInterval(125),
mTRRFailures(0),
mParentalControlEnabled(false) {
mConfirmation.mState = CONFIRM_INIT;
mConfirmation.mTRRFailures = 0;
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
}
@ -171,11 +170,10 @@ nsresult TRRService::Init() {
mParentalControlEnabled = GetParentalControlEnabledInternal();
nsCOMPtr<nsINetworkLinkService> nls =
do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
if (nls) {
mLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
if (mLinkService) {
nsTArray<nsCString> suffixList;
nls->GetDnsSuffixList(suffixList);
mLinkService->GetDnsSuffixList(suffixList);
RebuildSuffixList(std::move(suffixList));
}
@ -203,6 +201,8 @@ nsresult TRRService::Init() {
return NS_ERROR_FAILURE;
}
Telemetry::SetEventRecordingEnabled("network.dns"_ns, true);
LOG(("Initialized TRRService\n"));
return NS_OK;
}
@ -236,27 +236,27 @@ bool TRRService::Enabled(nsIRequest::TRRMode aRequestMode) {
return false;
}
if (mConfirmationState == CONFIRM_INIT &&
if (mConfirmation.mState == CONFIRM_INIT &&
(!StaticPrefs::network_trr_wait_for_portal() || mCaptiveIsPassed ||
(mMode == nsIDNSService::MODE_TRRONLY ||
aRequestMode == nsIRequest::TRR_ONLY_MODE))) {
LOG(("TRRService::Enabled => CONFIRM_TRYING\n"));
mConfirmationState = CONFIRM_TRYING;
mConfirmation.mState = CONFIRM_TRYING;
}
if (mConfirmationState == CONFIRM_TRYING) {
if (mConfirmation.mState == CONFIRM_TRYING) {
LOG(("TRRService::Enabled MaybeConfirm()\n"));
MaybeConfirm();
MaybeConfirm("context-init");
if (mMode == nsIDNSService::MODE_TRRONLY) {
MOZ_ASSERT(mConfirmationState == CONFIRM_OK,
MOZ_ASSERT(mConfirmation.mState == CONFIRM_OK,
"Global mode is trr-only, but confirmation failed?");
}
}
LOG(("TRRService::Enabled mConfirmationState=%d mCaptiveIsPassed=%d\n",
(int)mConfirmationState, (int)mCaptiveIsPassed));
LOG(("TRRService::Enabled mConfirmation.mState=%d mCaptiveIsPassed=%d\n",
(int)mConfirmation.mState, (int)mCaptiveIsPassed));
if (mConfirmationState == CONFIRM_OK) {
if (mConfirmation.mState == CONFIRM_OK) {
return true;
}
@ -275,7 +275,7 @@ bool TRRService::Enabled(nsIRequest::TRRMode aRequestMode) {
if ((aRequestMode == nsIRequest::TRR_DEFAULT_MODE &&
mMode == nsIDNSService::MODE_TRRFIRST) ||
aRequestMode == nsIRequest::TRR_FIRST_MODE) {
return mConfirmationState != CONFIRM_FAILED;
return mConfirmation.mState != CONFIRM_FAILED;
}
return false;
@ -352,12 +352,12 @@ nsresult TRRService::ReadPrefs(const char* name) {
nsAutoCString old(mConfirmationNS);
Preferences::GetCString(TRR_PREF("confirmationNS"), mConfirmationNS);
if (name && !old.IsEmpty() && !mConfirmationNS.Equals(old) &&
(mConfirmationState > CONFIRM_TRYING) &&
(mConfirmation.mState > CONFIRM_TRYING) &&
(mMode == nsIDNSService::MODE_TRRFIRST ||
mMode == nsIDNSService::MODE_TRRONLY)) {
LOG(("TRR::ReadPrefs: restart confirmationNS state\n"));
mConfirmationState = CONFIRM_TRYING;
MaybeConfirm_locked();
mConfirmation.mState = CONFIRM_TRYING;
MaybeConfirm_locked("pref-change");
}
}
if (!name || !strcmp(name, TRR_PREF("bootstrapAddress"))) {
@ -572,18 +572,19 @@ TRRService::Observe(nsISupports* aSubject, const char* aTopic,
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
ReadPrefs(NS_ConvertUTF16toUTF8(aData).get());
mConfirmation.RecordEvent("pref-change");
MutexAutoLock lock(mLock);
if (((mConfirmationState == CONFIRM_INIT) && !mBootstrapAddr.IsEmpty() &&
if (((mConfirmation.mState == CONFIRM_INIT) && !mBootstrapAddr.IsEmpty() &&
(mMode == nsIDNSService::MODE_TRRONLY)) ||
(mConfirmationState == CONFIRM_FAILED)) {
mConfirmationState = CONFIRM_TRYING;
MaybeConfirm_locked();
(mConfirmation.mState == CONFIRM_FAILED)) {
mConfirmation.mState = CONFIRM_TRYING;
MaybeConfirm_locked("pref-change");
}
} else if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
// We are in a captive portal
LOG(("TRRservice in captive portal\n"));
mCaptiveIsPassed = false;
mConfirmation.mCaptivePortalStatus = nsICaptivePortalService::LOCKED_PORTAL;
} else if (!strcmp(aTopic, NS_CAPTIVE_PORTAL_CONNECTIVITY)) {
nsAutoCString data = NS_ConvertUTF16toUTF8(aData);
LOG(("TRRservice captive portal was %s\n", data.get()));
@ -592,19 +593,23 @@ TRRService::Observe(nsISupports* aSubject, const char* aTopic,
// unless the service is in a TRR=enabled mode.
if (mMode == nsIDNSService::MODE_TRRFIRST ||
mMode == nsIDNSService::MODE_TRRONLY) {
if (mRetryConfirmTimer) {
mRetryConfirmTimer->Cancel();
mRetryConfirmTimer = nullptr;
if (mConfirmation.mTimer) {
mConfirmation.mTimer->Cancel();
mConfirmation.mTimer = nullptr;
}
mRetryConfirmInterval = StaticPrefs::network_trr_retry_timeout_ms();
if (mConfirmationState != CONFIRM_OK) {
mConfirmationState = CONFIRM_TRYING;
MaybeConfirm();
mConfirmation.mRetryInterval =
StaticPrefs::network_trr_retry_timeout_ms();
if (mConfirmation.mState != CONFIRM_OK) {
mConfirmation.mState = CONFIRM_TRYING;
MaybeConfirm("cp-connectivity");
}
}
mCaptiveIsPassed = true;
nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
if (cps) {
cps->GetState(&mConfirmation.mCaptivePortalStatus);
}
} else if (!strcmp(aTopic, kClearPrivateData) || !strcmp(aTopic, kPurge)) {
// flush the TRR blocklist
auto bl = mTRRBLStorage.Lock();
@ -623,12 +628,23 @@ TRRService::Observe(nsISupports* aSubject, const char* aTopic,
}
}
if (!strcmp(aTopic, NS_NETWORK_LINK_TOPIC) && mURISetByDetection) {
// If the URI was set via SetDetectedTrrURI we need to restore it to the
// default pref when a network link change occurs.
CheckURIPrefs();
if (!strcmp(aTopic, NS_NETWORK_LINK_TOPIC)) {
if (NS_ConvertUTF16toUTF8(aData).EqualsLiteral(
NS_NETWORK_LINK_DATA_DOWN)) {
mConfirmation.RecordEvent("network-change");
}
if (mURISetByDetection) {
// If the URI was set via SetDetectedTrrURI we need to restore it to the
// default pref when a network link change occurs.
CheckURIPrefs();
}
}
} else if (!strcmp(aTopic, "xpcom-shutdown-threads")) {
// If a confirmation is still in progress we record the event.
// Since there should be no more confirmations after this, the shutdown
// reason would not really be recorded in telemetry.
mConfirmation.RecordEvent("shutdown");
if (sTRRBackgroundThread) {
nsCOMPtr<nsIThread> thread;
{
@ -656,32 +672,48 @@ void TRRService::RebuildSuffixList(nsTArray<nsCString>&& aSuffixList) {
}
}
void TRRService::MaybeConfirm() {
void TRRService::MaybeConfirm(const char* aReason) {
MutexAutoLock lock(mLock);
MaybeConfirm_locked();
MaybeConfirm_locked(aReason);
}
void TRRService::MaybeConfirm_locked() {
void TRRService::MaybeConfirm_locked(const char* aReason) {
mLock.AssertCurrentThreadOwns();
if (mMode == nsIDNSService::MODE_TRROFF || mConfirmer ||
mConfirmationState != CONFIRM_TRYING) {
if (mMode == nsIDNSService::MODE_TRROFF || mConfirmation.mTask ||
mConfirmation.mState != CONFIRM_TRYING) {
LOG(
("TRRService:MaybeConfirm mode=%d, mConfirmer=%p "
"mConfirmationState=%d\n",
(int)mMode, (void*)mConfirmer, (int)mConfirmationState));
("TRRService:MaybeConfirm mode=%d, mConfirmation.mTask=%p "
"mConfirmation.mState=%d\n",
(int)mMode, (void*)mConfirmation.mTask, (int)mConfirmation.mState));
return;
}
if (mConfirmationNS.Equals("skip") || mMode == nsIDNSService::MODE_TRRONLY) {
LOG(("TRRService starting confirmation test %s SKIPPED\n",
mPrivateURI.get()));
mConfirmationState = CONFIRM_OK;
mConfirmation.mState = CONFIRM_OK;
} else {
LOG(("TRRService starting confirmation test %s %s\n", mPrivateURI.get(),
mConfirmationNS.get()));
mConfirmer = new TRR(this, mConfirmationNS, TRRTYPE_NS, ""_ns, false);
mConfirmer->SetTimeout(StaticPrefs::network_trr_confirmation_timeout_ms());
DispatchTRRRequestInternal(mConfirmer, false);
mConfirmation.mTask =
new TRR(this, mConfirmationNS, TRRTYPE_NS, ""_ns, false);
mConfirmation.mTask->SetTimeout(
StaticPrefs::network_trr_confirmation_timeout_ms());
if (mLinkService) {
mLinkService->GetNetworkID(mConfirmation.mNetworkId);
}
if (mConfirmation.mFirstRequestTime.IsNull()) {
mConfirmation.mFirstRequestTime = TimeStamp::Now();
}
if (mConfirmation.mTrigger.IsEmpty()) {
mConfirmation.mTrigger.Assign(aReason);
}
DispatchTRRRequestInternal(mConfirmation.mTask, false);
}
}
@ -866,12 +898,12 @@ void TRRService::AddToBlocklist(const nsACString& aHost,
NS_IMETHODIMP
TRRService::Notify(nsITimer* aTimer) {
if (aTimer == mRetryConfirmTimer) {
mRetryConfirmTimer = nullptr;
if (mConfirmationState == CONFIRM_FAILED) {
if (aTimer == mConfirmation.mTimer) {
mConfirmation.mTimer = nullptr;
if (mConfirmation.mState == CONFIRM_FAILED) {
LOG(("TRRService retry NS of %s\n", mConfirmationNS.get()));
mConfirmationState = CONFIRM_TRYING;
MaybeConfirm();
mConfirmation.mState = CONFIRM_TRYING;
MaybeConfirm("retry");
}
} else {
MOZ_CRASH("Unknown timer");
@ -892,25 +924,129 @@ void TRRService::TRRIsOkay(enum TrrOkay aReason) {
? Telemetry::LABELS_DNS_TRR_SUCCESS2::Timeout
: Telemetry::LABELS_DNS_TRR_SUCCESS2::Bad));
if (aReason == OKAY_NORMAL) {
mTRRFailures = 0;
mConfirmation.mTRRFailures = 0;
} else if ((mMode == nsIDNSService::MODE_TRRFIRST) &&
(mConfirmationState == CONFIRM_OK)) {
(mConfirmation.mState == CONFIRM_OK)) {
// only count failures while in OK state
uint32_t fails = ++mTRRFailures;
uint32_t fails = ++mConfirmation.mTRRFailures;
if (fails >= StaticPrefs::network_trr_max_fails()) {
LOG(("TRRService goes FAILED after %u failures in a row\n", fails));
mConfirmationState = CONFIRM_FAILED;
mConfirmation.mState = CONFIRM_FAILED;
mConfirmation.mTrigger.Assign("failed-lookups");
// Fire off a timer and start re-trying the NS domain again
NS_NewTimerWithCallback(getter_AddRefs(mRetryConfirmTimer), this,
mRetryConfirmInterval, nsITimer::TYPE_ONE_SHOT);
mTRRFailures = 0; // clear it again
NS_NewTimerWithCallback(getter_AddRefs(mConfirmation.mTimer), this,
mConfirmation.mRetryInterval,
nsITimer::TYPE_ONE_SHOT);
mConfirmation.mTRRFailures = 0; // clear it again
}
}
}
void TRRService::ConfirmationContext::RecordEvent(const char* aReason) {
// Reset the confirmation context attributes
// Only resets the attributes that we keep for telemetry purposes.
auto reset = [&]() {
mAttemptCount = 0;
mNetworkId.Truncate();
mFirstRequestTime = TimeStamp();
mContextChangeReason.Assign(aReason);
mTrigger.Truncate();
mRetryInterval = StaticPrefs::network_trr_retry_timeout_ms();
};
if (mAttemptCount == 0) {
// XXX: resetting everything might not be the best thing here, even if the
// context changes, because there might still be a confirmation pending.
// But cancelling and retrying that confirmation might just make the whole
// confirmation longer for no reason.
reset();
return;
}
Telemetry::EventID eventType =
Telemetry::EventID::NetworkDns_Trrconfirmation_Context;
nsAutoCString results;
static_assert(RESULTS_SIZE < 64);
// mResults is a circular buffer ending at mAttemptCount
if (mAttemptCount <= RESULTS_SIZE) {
// We have fewer attempts than the size of the buffer, so all of the
// results are in the buffer.
results.Append(nsDependentCSubstring(mResults, mAttemptCount));
} else {
// More attempts than the buffer size.
// That means past RESULTS_SIZE attempts in order are
// [posInResults .. end-of-buffer) + [start-of-buffer .. posInResults)
uint32_t posInResults = mAttemptCount % RESULTS_SIZE;
results.Append(nsDependentCSubstring(mResults + posInResults,
RESULTS_SIZE - posInResults));
results.Append(nsDependentCSubstring(mResults, posInResults));
}
auto extra = Some<nsTArray<mozilla::Telemetry::EventExtraEntry>>({
Telemetry::EventExtraEntry{"trigger"_ns, mTrigger},
Telemetry::EventExtraEntry{"contextReason"_ns, mContextChangeReason},
Telemetry::EventExtraEntry{"attemptCount"_ns,
nsPrintfCString("%u", mAttemptCount)},
Telemetry::EventExtraEntry{"results"_ns, results},
Telemetry::EventExtraEntry{
"time"_ns,
nsPrintfCString(
"%f",
!mFirstRequestTime.IsNull()
? (TimeStamp::Now() - mFirstRequestTime).ToMilliseconds()
: 0.0)},
Telemetry::EventExtraEntry{"networkID"_ns, mNetworkId},
Telemetry::EventExtraEntry{"captivePortal"_ns,
nsPrintfCString("%i", mCaptivePortalStatus)},
});
ConfirmationState state = mState;
Telemetry::RecordEvent(eventType, mozilla::Some(nsPrintfCString("%u", state)),
extra);
reset();
}
void TRRService::ConfirmationContext::RequestCompleted(
nsresult aLookupStatus, nsresult aChannelStatus) {
auto statusToChar = [aLookupStatus, aChannelStatus]() -> char {
if (aChannelStatus == NS_OK) {
// Return + if confirmation was OK, or - if confirmation failed
return aLookupStatus == NS_OK ? '+' : '-';
}
switch (aChannelStatus) {
case NS_ERROR_NET_TIMEOUT_EXTERNAL:
// TRR timeout expired
return 't';
case NS_ERROR_UNKNOWN_HOST:
// TRRServiceChannel failed to due to unresolved host
return 'd';
default:
break;
}
// The error is a network error
if (NS_ERROR_GET_MODULE(aChannelStatus) == NS_ERROR_MODULE_NETWORK) {
return 'n';
}
// Some other kind of failure.
return '?';
};
mResults[mAttemptCount % RESULTS_SIZE] = statusToChar();
mAttemptCount++;
}
AHostResolver::LookupStatus TRRService::CompleteLookup(
nsHostRecord* rec, nsresult status, AddrInfo* aNewRRSet, bool pb,
const nsACString& aOriginSuffix, nsHostRecord::TRRSkippedReason aReason) {
const nsACString& aOriginSuffix, nsHostRecord::TRRSkippedReason aReason,
TRR* aTRRRequest) {
// this is an NS check for the TRR blocklist or confirmationNS check
MOZ_ASSERT_IF(XRE_IsParentProcess(), NS_IsMainThread() || IsOnTRRThread());
@ -923,35 +1059,44 @@ AHostResolver::LookupStatus TRRService::CompleteLookup(
#ifdef DEBUG
{
MutexAutoLock lock(mLock);
MOZ_ASSERT(!mConfirmer || (mConfirmationState == CONFIRM_TRYING));
MOZ_ASSERT(!mConfirmation.mTask ||
(mConfirmation.mState == CONFIRM_TRYING));
}
#endif
if (mConfirmationState == CONFIRM_TRYING) {
if (mConfirmation.mState == CONFIRM_TRYING) {
mConfirmation.RequestCompleted(status, aTRRRequest->ChannelStatus());
{
MutexAutoLock lock(mLock);
MOZ_ASSERT(mConfirmer);
mConfirmationState = NS_SUCCEEDED(status) ? CONFIRM_OK : CONFIRM_FAILED;
MOZ_ASSERT(mConfirmation.mTask);
mConfirmation.mState = NS_SUCCEEDED(status) ? CONFIRM_OK : CONFIRM_FAILED;
LOG(("TRRService finishing confirmation test %s %d %X\n",
mPrivateURI.get(), (int)mConfirmationState, (unsigned int)status));
mConfirmer = nullptr;
if (mConfirmationState == CONFIRM_OK) {
// A fresh confirmation means previous blocked entries might not
// be valid anymore.
auto bl = mTRRBLStorage.Lock();
bl->Clear();
}
mPrivateURI.get(), (int)mConfirmation.mState, (unsigned int)status));
mConfirmation.mTask = nullptr;
}
if (mConfirmationState == CONFIRM_FAILED) {
// retry failed NS confirmation
NS_NewTimerWithCallback(getter_AddRefs(mRetryConfirmTimer), this,
mRetryConfirmInterval, nsITimer::TYPE_ONE_SHOT);
if (mRetryConfirmInterval < 64000) {
// double the interval up to this point
mRetryConfirmInterval *= 2;
}
if (mConfirmation.mState == CONFIRM_OK) {
mConfirmation.mRetryInterval =
StaticPrefs::network_trr_retry_timeout_ms();
// Record event and start new confirmation context
mConfirmation.RecordEvent("success");
// A fresh confirmation means previous blocked entries might not
// be valid anymore.
auto bl = mTRRBLStorage.Lock();
bl->Clear();
} else {
mRetryConfirmInterval = StaticPrefs::network_trr_retry_timeout_ms();
MOZ_ASSERT(mConfirmation.mState == CONFIRM_FAILED);
// retry failed NS confirmation
NS_NewTimerWithCallback(getter_AddRefs(mConfirmation.mTimer), this,
mConfirmation.mRetryInterval,
nsITimer::TYPE_ONE_SHOT);
if (mConfirmation.mRetryInterval < 64000) {
// double the interval up to this point
mConfirmation.mRetryInterval *= 2;
}
}
if (mMode != nsIDNSService::MODE_TRRONLY) {
@ -959,7 +1104,7 @@ AHostResolver::LookupStatus TRRService::CompleteLookup(
// confirmation in trr-first mode
Telemetry::Accumulate(Telemetry::DNS_TRR_NS_VERFIFIED2,
TRRService::AutoDetectedKey(),
(mConfirmationState == CONFIRM_OK));
(mConfirmation.mState == CONFIRM_OK));
}
return LOOKUP_OK;

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsWeakReference.h"
#include "ODoHService.h"
#include "TRRServiceBase.h"
#include "nsICaptivePortalService.h"
class nsDNSService;
class nsIPrefBranch;
@ -39,7 +40,7 @@ class TRRService : public TRRServiceBase,
nsresult Init();
nsresult Start();
bool Enabled(nsIRequest::TRRMode aRequestMode = nsIRequest::TRR_DEFAULT_MODE);
bool IsConfirmed() { return mConfirmationState == CONFIRM_OK; }
bool IsConfirmed() { return mConfirmation.mState == CONFIRM_OK; }
bool DisableIPv6() { return mDisableIPv6; }
nsresult GetURI(nsACString& result);
@ -48,7 +49,8 @@ class TRRService : public TRRServiceBase,
LookupStatus CompleteLookup(nsHostRecord*, nsresult, mozilla::net::AddrInfo*,
bool pb, const nsACString& aOriginSuffix,
nsHostRecord::TRRSkippedReason aReason) override;
nsHostRecord::TRRSkippedReason aReason,
TRR* aTrrRequest) override;
LookupStatus CompleteLookupByType(nsHostRecord*, nsresult,
mozilla::net::TypeRecordResultType&,
uint32_t, bool pb) override;
@ -85,8 +87,8 @@ class TRRService : public TRRServiceBase,
nsresult ReadPrefs(const char* name);
void GetPrefBranch(nsIPrefBranch** result);
void MaybeConfirm();
void MaybeConfirm_locked();
void MaybeConfirm(const char* aReason);
void MaybeConfirm_locked(const char* aReason);
friend class ::nsDNSService;
void SetDetectedTrrURI(const nsACString& aURI);
@ -139,13 +141,53 @@ class TRRService : public TRRServiceBase,
CONFIRM_OK = 2,
CONFIRM_FAILED = 3
};
Atomic<ConfirmationState, Relaxed> mConfirmationState;
RefPtr<TRR> mConfirmer;
nsCOMPtr<nsITimer> mRetryConfirmTimer;
uint32_t mRetryConfirmInterval; // milliseconds until retry
Atomic<uint32_t, Relaxed> mTRRFailures;
class ConfirmationContext {
static const size_t RESULTS_SIZE = 32;
public:
Atomic<ConfirmationState, Relaxed> mState;
RefPtr<TRR> mTask;
nsCOMPtr<nsITimer> mTimer;
uint32_t mRetryInterval = 125; // milliseconds until retry
// The number of TRR requests that failed in a row.
Atomic<uint32_t, Relaxed> mTRRFailures;
// The number of confirmation retries.
uint32_t mAttemptCount = 0;
// The results of past confirmation attempts.
// This is circular buffer ending at mAttemptCount.
char mResults[RESULTS_SIZE] = {0};
// Time when first confirmation started. Needed so we can
// record the time from start to confirmed.
TimeStamp mFirstRequestTime;
// The network ID at the start of the last confirmation attempt
nsCString mNetworkId;
// Captive portal status at the time of recording.
int32_t mCaptivePortalStatus = nsICaptivePortalService::UNKNOWN;
// The reason the confirmation context changed.
nsCString mContextChangeReason;
// What triggered the confirmation
nsCString mTrigger;
// Called when a confirmation completes successfully or when the
// confirmation context changes.
void RecordEvent(const char* aReason);
// Called when a confirmation request is completed. The status is recorded
// in the results.
void RequestCompleted(nsresult aLookupStatus, nsresult aChannelStatus);
};
ConfirmationContext mConfirmation;
bool mParentalControlEnabled;
RefPtr<ODoHService> mODoHService;
nsCOMPtr<nsINetworkLinkService> mLinkService;
};
extern TRRService* gTRRService;

Просмотреть файл

@ -754,7 +754,7 @@ void nsHostResolver::ClearPendingQueue(
rec->Cancel();
if (rec->IsAddrRecord()) {
CompleteLookup(rec, NS_ERROR_ABORT, nullptr, rec->pb, rec->originSuffix,
rec->mTRRTRRSkippedReason);
rec->mTRRTRRSkippedReason, nullptr);
} else {
mozilla::net::TypeRecordResultType empty(Nothing{});
CompleteLookupByType(rec, NS_ERROR_ABORT, empty, 0, rec->pb);
@ -1865,7 +1865,8 @@ void nsHostResolver::AddToEvictionQ(nsHostRecord* rec) {
// returns LOOKUP_RESOLVEAGAIN, but only if 'status' is not NS_ERROR_ABORT.
nsHostResolver::LookupStatus nsHostResolver::CompleteLookup(
nsHostRecord* rec, nsresult status, AddrInfo* aNewRRSet, bool pb,
const nsACString& aOriginsuffix, nsHostRecord::TRRSkippedReason aReason) {
const nsACString& aOriginsuffix, nsHostRecord::TRRSkippedReason aReason,
mozilla::net::TRR* aTRRRequest) {
MutexAutoLock lock(mLock);
MOZ_ASSERT(rec);
MOZ_ASSERT(rec->pb == pb);
@ -2231,9 +2232,9 @@ void nsHostResolver::ThreadFunc() {
LOG1(("DNS lookup thread - lookup completed for host [%s]: %s.\n",
rec->host.get(), ai ? "success" : "failure: unknown host"));
if (LOOKUP_RESOLVEAGAIN == CompleteLookup(rec, status, ai, rec->pb,
rec->originSuffix,
rec->mTRRTRRSkippedReason)) {
if (LOOKUP_RESOLVEAGAIN ==
CompleteLookup(rec, status, ai, rec->pb, rec->originSuffix,
rec->mTRRTRRSkippedReason, nullptr)) {
// leave 'rec' assigned and loop to make a renewed host resolve
LOG(("DNS lookup thread - Re-resolving host [%s].\n", rec->host.get()));
} else {

Просмотреть файл

@ -421,10 +421,11 @@ class AHostResolver {
LOOKUP_RESOLVEAGAIN,
};
virtual LookupStatus CompleteLookup(
nsHostRecord*, nsresult, mozilla::net::AddrInfo*, bool pb,
const nsACString& aOriginsuffix,
nsHostRecord::TRRSkippedReason aReason) = 0;
virtual LookupStatus CompleteLookup(nsHostRecord*, nsresult,
mozilla::net::AddrInfo*, bool pb,
const nsACString& aOriginsuffix,
nsHostRecord::TRRSkippedReason aReason,
mozilla::net::TRR*) = 0;
virtual LookupStatus CompleteLookupByType(
nsHostRecord*, nsresult, mozilla::net::TypeRecordResultType& aResult,
uint32_t aTtl, bool pb) = 0;
@ -551,7 +552,8 @@ class nsHostResolver : public nsISupports, public AHostResolver {
LookupStatus CompleteLookup(nsHostRecord*, nsresult, mozilla::net::AddrInfo*,
bool pb, const nsACString& aOriginsuffix,
nsHostRecord::TRRSkippedReason aReason) override;
nsHostRecord::TRRSkippedReason aReason,
mozilla::net::TRR* aTRRRequest) override;
LookupStatus CompleteLookupByType(nsHostRecord*, nsresult,
mozilla::net::TypeRecordResultType& aResult,
uint32_t aTtl, bool pb) override;