1 /* vim:set ts=4 sw=2 sts=2 et cin: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsHostRecord.h"
8 // Put DNSLogging.h at the end to avoid LOG being overwritten by other headers.
9 #include "DNSLogging.h"
10 #include "mozilla/StaticPrefs_network.h"
11 #include "mozilla/Telemetry.h"
12 #include "mozilla/ThreadSafety.h"
13 #include "TRRService.h"
15 //----------------------------------------------------------------------------
16 // this macro filters out any flags that are not used when constructing the
17 // host key. the significant flags are those that would affect the resulting
18 // host record (i.e., the flags that are passed down to PR_GetAddrInfoByName).
19 #define RES_KEY_FLAGS(_f) \
21 (nsIDNSService::RESOLVE_CANONICAL_NAME | \
22 nsIDNSService::RESOLVE_DISABLE_TRR | \
23 nsIDNSService::RESOLVE_TRR_MODE_MASK | nsIDNSService::RESOLVE_IP_HINT))
25 #define IS_ADDR_TYPE(_type) ((_type) == nsIDNSService::RESOLVE_TYPE_DEFAULT)
26 #define IS_OTHER_TYPE(_type) ((_type) != nsIDNSService::RESOLVE_TYPE_DEFAULT)
28 //----------------------------------------------------------------------------
30 using namespace mozilla
;
31 using namespace mozilla::net
;
33 nsHostKey::nsHostKey(const nsACString
& aHost
, const nsACString
& aTrrServer
,
34 uint16_t aType
, nsIDNSService::DNSFlags aFlags
,
35 uint16_t aAf
, bool aPb
, const nsACString
& aOriginsuffix
)
37 mTrrServer(aTrrServer
),
42 originSuffix(aOriginsuffix
) {}
44 nsHostKey::nsHostKey(const nsHostKey
& other
)
46 mTrrServer(other
.mTrrServer
),
51 originSuffix(other
.originSuffix
) {}
53 bool nsHostKey::operator==(const nsHostKey
& other
) const {
54 return host
== other
.host
&& mTrrServer
== other
.mTrrServer
&&
56 RES_KEY_FLAGS(flags
) == RES_KEY_FLAGS(other
.flags
) && af
== other
.af
&&
57 originSuffix
== other
.originSuffix
;
60 PLDHashNumber
nsHostKey::Hash() const {
61 return AddToHash(HashString(host
.get()), HashString(mTrrServer
.get()), type
,
62 RES_KEY_FLAGS(flags
), af
, HashString(originSuffix
.get()));
65 size_t nsHostKey::SizeOfExcludingThis(
66 mozilla::MallocSizeOf mallocSizeOf
) const {
68 n
+= host
.SizeOfExcludingThisIfUnshared(mallocSizeOf
);
69 n
+= mTrrServer
.SizeOfExcludingThisIfUnshared(mallocSizeOf
);
70 n
+= originSuffix
.SizeOfExcludingThisIfUnshared(mallocSizeOf
);
74 //----------------------------------------------------------------------------
76 //----------------------------------------------------------------------------
78 NS_IMPL_ISUPPORTS0(nsHostRecord
)
80 nsHostRecord::nsHostRecord(const nsHostKey
& key
)
81 : nsHostKey(key
), mTRRQuery("nsHostRecord.mTRRQuery") {}
83 void nsHostRecord::Invalidate() { mDoomed
= true; }
85 void nsHostRecord::Cancel() {
86 RefPtr
<TRRQuery
> query
;
88 auto lock
= mTRRQuery
.Lock();
89 query
.swap(lock
.ref());
93 query
->Cancel(NS_ERROR_ABORT
);
97 nsHostRecord::ExpirationStatus
nsHostRecord::CheckExpiration(
98 const mozilla::TimeStamp
& now
) const {
99 if (!mGraceStart
.IsNull() && now
>= mGraceStart
&& !mValidEnd
.IsNull() &&
101 return nsHostRecord::EXP_GRACE
;
103 if (!mValidEnd
.IsNull() && now
< mValidEnd
) {
104 return nsHostRecord::EXP_VALID
;
107 return nsHostRecord::EXP_EXPIRED
;
110 void nsHostRecord::SetExpiration(const mozilla::TimeStamp
& now
,
111 unsigned int valid
, unsigned int grace
) {
113 if ((valid
+ grace
) < 60) {
115 LOG(("SetExpiration: artificially bumped grace to %d\n", grace
));
117 mGraceStart
= now
+ TimeDuration::FromSeconds(valid
);
118 mValidEnd
= now
+ TimeDuration::FromSeconds(valid
+ grace
);
122 void nsHostRecord::CopyExpirationTimesAndFlagsFrom(
123 const nsHostRecord
* aFromHostRecord
) {
124 // This is used to copy information from a cache entry to a record. All
125 // information necessary for HasUsableRecord needs to be copied.
126 mValidStart
= aFromHostRecord
->mValidStart
;
127 mValidEnd
= aFromHostRecord
->mValidEnd
;
128 mGraceStart
= aFromHostRecord
->mGraceStart
;
129 mDoomed
= aFromHostRecord
->mDoomed
;
130 mTtl
= uint32_t(aFromHostRecord
->mTtl
);
133 bool nsHostRecord::HasUsableResult(const mozilla::TimeStamp
& now
,
134 nsIDNSService::DNSFlags queryFlags
) const {
139 return HasUsableResultInternal(now
, queryFlags
);
142 //----------------------------------------------------------------------------
144 //----------------------------------------------------------------------------
146 static size_t SizeOfResolveHostCallbackListExcludingHead(
147 const mozilla::LinkedList
<RefPtr
<nsResolveHostCallback
>>& aCallbacks
,
148 MallocSizeOf mallocSizeOf
) {
149 size_t n
= aCallbacks
.sizeOfExcludingThis(mallocSizeOf
);
151 for (const nsResolveHostCallback
* t
= aCallbacks
.getFirst(); t
;
153 n
+= t
->SizeOfIncludingThis(mallocSizeOf
);
159 NS_IMPL_ISUPPORTS_INHERITED(AddrHostRecord
, nsHostRecord
, AddrHostRecord
)
161 AddrHostRecord::AddrHostRecord(const nsHostKey
& key
) : nsHostRecord(key
) {}
163 AddrHostRecord::~AddrHostRecord() {
165 Telemetry::Accumulate(Telemetry::DNS_BLACKLIST_COUNT
, mUnusableCount
);
168 bool AddrHostRecord::Blocklisted(const NetAddr
* aQuery
) {
169 addr_info_lock
.AssertCurrentThreadOwns();
170 LOG(("Checking unusable list for host [%s], host record [%p].\n", host
.get(),
173 // skip the string conversion for the common case of no blocklist
174 if (!mUnusableItems
.Length()) {
178 char buf
[kIPv6CStrBufSize
];
179 if (!aQuery
->ToStringBuffer(buf
, sizeof(buf
))) {
182 nsDependentCString
strQuery(buf
);
184 for (uint32_t i
= 0; i
< mUnusableItems
.Length(); i
++) {
185 if (mUnusableItems
.ElementAt(i
).Equals(strQuery
)) {
186 LOG(("Address [%s] is blocklisted for host [%s].\n", buf
, host
.get()));
194 void AddrHostRecord::ReportUnusable(const NetAddr
* aAddress
) {
195 addr_info_lock
.AssertCurrentThreadOwns();
197 ("Adding address to blocklist for host [%s], host record [%p]."
199 host
.get(), this, mTRRSuccess
));
203 char buf
[kIPv6CStrBufSize
];
204 if (aAddress
->ToStringBuffer(buf
, sizeof(buf
))) {
206 ("Successfully adding address [%s] to blocklist for host "
209 mUnusableItems
.AppendElement(nsCString(buf
));
213 void AddrHostRecord::ResetBlocklist() {
214 addr_info_lock
.AssertCurrentThreadOwns();
215 LOG(("Resetting blocklist for host [%s], host record [%p].\n", host
.get(),
217 mUnusableItems
.Clear();
220 size_t AddrHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const {
221 size_t n
= mallocSizeOf(this);
223 n
+= nsHostKey::SizeOfExcludingThis(mallocSizeOf
);
224 n
+= SizeOfResolveHostCallbackListExcludingHead(mCallbacks
, mallocSizeOf
);
226 n
+= addr_info
? addr_info
->SizeOfIncludingThis(mallocSizeOf
) : 0;
227 n
+= mallocSizeOf(addr
.get());
229 n
+= mUnusableItems
.ShallowSizeOfExcludingThis(mallocSizeOf
);
230 for (size_t i
= 0; i
< mUnusableItems
.Length(); i
++) {
231 n
+= mUnusableItems
[i
].SizeOfExcludingThisIfUnshared(mallocSizeOf
);
236 bool AddrHostRecord::HasUsableResultInternal(
237 const mozilla::TimeStamp
& now
, nsIDNSService::DNSFlags queryFlags
) const {
238 // don't use cached negative results for high priority queries.
239 if (negative
&& IsHighPriority(queryFlags
)) {
243 if (CheckExpiration(now
) == EXP_EXPIRED
) {
251 return addr_info
|| addr
;
254 // Returns true if the entry can be removed, or false if it should be left.
255 // Sets ResolveAgain true for entries being resolved right now.
256 bool AddrHostRecord::RemoveOrRefresh(bool aTrrToo
) {
257 // no need to flush TRRed names, they're not resolved "locally"
258 MutexAutoLock
lock(addr_info_lock
);
259 if (addr_info
&& !aTrrToo
&& addr_info
->IsTRR()) {
264 // The request has been passed to the OS resolver. The resultant DNS
265 // record should be considered stale and not trusted; set a flag to
266 // ensure it is called again.
267 StoreResolveAgain(true);
269 // if onQueue is true, the host entry is already added to the cache
270 // but is still pending to get resolved: just leave it in hash.
273 // Already resolved; not in a pending state; remove from cache
277 void AddrHostRecord::NotifyRetryingTrr() {
278 MOZ_ASSERT(mFirstTRRSkippedReason
==
279 mozilla::net::TRRSkippedReason::TRR_UNSET
);
281 // Save the skip reason of our first attempt for recording telemetry later.
282 mFirstTRRSkippedReason
= mTRRSkippedReason
;
283 mTRRSkippedReason
= mozilla::net::TRRSkippedReason::TRR_UNSET
;
286 void AddrHostRecord::ResolveComplete() {
287 if (LoadNativeUsed()) {
288 if (mNativeSuccess
) {
289 uint32_t millis
= static_cast<uint32_t>(mNativeDuration
.ToMilliseconds());
290 Telemetry::Accumulate(Telemetry::DNS_NATIVE_LOOKUP_TIME
, millis
);
292 AccumulateCategoricalKeyed(
293 TRRService::ProviderKey(),
294 mNativeSuccess
? Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::osOK
295 : Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::osFail
);
298 if (mResolverType
== DNSResolverType::TRR
) {
300 MOZ_DIAGNOSTIC_ASSERT(mTRRSkippedReason
==
301 mozilla::net::TRRSkippedReason::TRR_OK
);
302 uint32_t millis
= static_cast<uint32_t>(mTrrDuration
.ToMilliseconds());
303 Telemetry::Accumulate(Telemetry::DNS_TRR_LOOKUP_TIME3
,
304 TRRService::ProviderKey(), millis
);
306 AccumulateCategoricalKeyed(
307 TRRService::ProviderKey(),
308 mTRRSuccess
? Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrOK
309 : Telemetry::LABELS_DNS_LOOKUP_DISPOSITION3::trrFail
);
312 if (nsHostResolver::Mode() == nsIDNSService::MODE_TRRFIRST
||
313 nsHostResolver::Mode() == nsIDNSService::MODE_TRRONLY
) {
314 MOZ_ASSERT(mTRRSkippedReason
!= mozilla::net::TRRSkippedReason::TRR_UNSET
);
316 Telemetry::Accumulate(Telemetry::TRR_SKIP_REASON_TRR_FIRST2
,
317 TRRService::ProviderKey(),
318 static_cast<uint32_t>(mTRRSkippedReason
));
319 if (!mTRRSuccess
&& LoadNativeUsed()) {
320 Telemetry::Accumulate(
321 mNativeSuccess
? Telemetry::TRR_SKIP_REASON_NATIVE_SUCCESS
322 : Telemetry::TRR_SKIP_REASON_NATIVE_FAILED
,
323 TRRService::ProviderKey(), static_cast<uint32_t>(mTRRSkippedReason
));
326 if (IsRelevantTRRSkipReason(mTRRSkippedReason
)) {
327 Telemetry::Accumulate(Telemetry::TRR_RELEVANT_SKIP_REASON_TRR_FIRST
,
328 TRRService::ProviderKey(),
329 static_cast<uint32_t>(mTRRSkippedReason
));
331 if (!mTRRSuccess
&& LoadNativeUsed()) {
332 Telemetry::Accumulate(
333 mNativeSuccess
? Telemetry::TRR_RELEVANT_SKIP_REASON_NATIVE_SUCCESS
334 : Telemetry::TRR_RELEVANT_SKIP_REASON_NATIVE_FAILED
,
335 TRRService::ProviderKey(),
336 static_cast<uint32_t>(mTRRSkippedReason
));
340 if (StaticPrefs::network_trr_retry_on_recoverable_errors() &&
341 nsHostResolver::Mode() == nsIDNSService::MODE_TRRFIRST
) {
342 nsAutoCString
telemetryKey(TRRService::ProviderKey());
344 if (mFirstTRRSkippedReason
!= mozilla::net::TRRSkippedReason::TRR_UNSET
) {
345 telemetryKey
.AppendLiteral("|");
346 telemetryKey
.AppendInt(static_cast<uint32_t>(mFirstTRRSkippedReason
));
348 Telemetry::Accumulate(mTRRSuccess
349 ? Telemetry::TRR_SKIP_REASON_RETRY_SUCCESS
350 : Telemetry::TRR_SKIP_REASON_RETRY_FAILED
,
351 TRRService::ProviderKey(),
352 static_cast<uint32_t>(mFirstTRRSkippedReason
));
355 Telemetry::Accumulate(Telemetry::TRR_SKIP_REASON_STRICT_MODE
,
357 static_cast<uint32_t>(mTRRSkippedReason
));
360 Telemetry::Accumulate(Telemetry::TRR_ATTEMPT_COUNT
,
361 TRRService::ProviderKey(), mTrrAttempts
);
366 if (mEffectiveTRRMode
== nsIRequest::TRR_FIRST_MODE
) {
367 if (flags
& nsIDNSService::RESOLVE_DISABLE_TRR
) {
368 // TRR is disabled on request, which is a next-level back-off method.
369 Telemetry::Accumulate(Telemetry::DNS_TRR_DISABLED3
,
370 TRRService::ProviderKey(), mNativeSuccess
);
373 AccumulateCategoricalKeyed(TRRService::ProviderKey(),
374 Telemetry::LABELS_DNS_TRR_FIRST4::TRR
);
375 } else if (mNativeSuccess
) {
376 if (mResolverType
== DNSResolverType::TRR
) {
377 AccumulateCategoricalKeyed(
378 TRRService::ProviderKey(),
379 Telemetry::LABELS_DNS_TRR_FIRST4::NativeAfterTRR
);
381 AccumulateCategoricalKeyed(TRRService::ProviderKey(),
382 Telemetry::LABELS_DNS_TRR_FIRST4::Native
);
385 AccumulateCategoricalKeyed(
386 TRRService::ProviderKey(),
387 Telemetry::LABELS_DNS_TRR_FIRST4::BothFailed
);
392 switch (mEffectiveTRRMode
) {
393 case nsIRequest::TRR_DISABLED_MODE
:
394 AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::nativeOnly
);
396 case nsIRequest::TRR_FIRST_MODE
:
397 AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrFirst
);
399 case nsIRequest::TRR_ONLY_MODE
:
400 AccumulateCategorical(Telemetry::LABELS_DNS_LOOKUP_ALGORITHM::trrOnly
);
402 case nsIRequest::TRR_DEFAULT_MODE
:
403 MOZ_ASSERT_UNREACHABLE("We should not have a default value here");
407 if (mResolverType
== DNSResolverType::TRR
&& !mTRRSuccess
&& mNativeSuccess
&&
408 !LoadGetTtl() && TRRService::Get()) {
409 TRRService::Get()->AddToBlocklist(nsCString(host
), originSuffix
, pb
, true);
413 AddrHostRecord::DnsPriority
AddrHostRecord::GetPriority(
414 nsIDNSService::DNSFlags aFlags
) {
415 if (IsHighPriority(aFlags
)) {
416 return AddrHostRecord::DNS_PRIORITY_HIGH
;
418 if (IsMediumPriority(aFlags
)) {
419 return AddrHostRecord::DNS_PRIORITY_MEDIUM
;
422 return AddrHostRecord::DNS_PRIORITY_LOW
;
425 nsresult
AddrHostRecord::GetTtl(uint32_t* aResult
) {
426 NS_ENSURE_ARG(aResult
);
431 //----------------------------------------------------------------------------
433 //----------------------------------------------------------------------------
435 NS_IMPL_ISUPPORTS_INHERITED(TypeHostRecord
, nsHostRecord
, TypeHostRecord
,
436 nsIDNSTXTRecord
, nsIDNSHTTPSSVCRecord
)
438 TypeHostRecord::TypeHostRecord(const nsHostKey
& key
)
439 : nsHostRecord(key
), DNSHTTPSSVCRecordBase(key
.host
) {}
441 TypeHostRecord::~TypeHostRecord() { mCallbacks
.clear(); }
443 bool TypeHostRecord::HasUsableResultInternal(
444 const mozilla::TimeStamp
& now
, nsIDNSService::DNSFlags queryFlags
) const {
445 if (CheckExpiration(now
) == EXP_EXPIRED
) {
453 MOZ_PUSH_IGNORE_THREAD_SAFETY
454 // To avoid locking in a const method
455 return !mResults
.is
<Nothing
>();
456 MOZ_POP_THREAD_SAFETY
459 bool TypeHostRecord::RefreshForNegativeResponse() const { return false; }
461 NS_IMETHODIMP
TypeHostRecord::GetRecords(CopyableTArray
<nsCString
>& aRecords
) {
463 MutexAutoLock
lock(mResultsLock
);
465 if (!mResults
.is
<TypeRecordTxt
>()) {
466 return NS_ERROR_NOT_AVAILABLE
;
468 aRecords
= mResults
.as
<CopyableTArray
<nsCString
>>();
472 NS_IMETHODIMP
TypeHostRecord::GetRecordsAsOneString(nsACString
& aRecords
) {
474 MutexAutoLock
lock(mResultsLock
);
476 if (!mResults
.is
<TypeRecordTxt
>()) {
477 return NS_ERROR_NOT_AVAILABLE
;
479 auto& results
= mResults
.as
<CopyableTArray
<nsCString
>>();
480 for (uint32_t i
= 0; i
< results
.Length(); i
++) {
481 aRecords
.Append(results
[i
]);
486 size_t TypeHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const {
487 size_t n
= mallocSizeOf(this);
489 n
+= nsHostKey::SizeOfExcludingThis(mallocSizeOf
);
490 n
+= SizeOfResolveHostCallbackListExcludingHead(mCallbacks
, mallocSizeOf
);
495 uint32_t TypeHostRecord::GetType() {
496 MutexAutoLock
lock(mResultsLock
);
498 return mResults
.match(
499 [](TypeRecordEmpty
&) {
500 MOZ_ASSERT(false, "This should never be the case");
501 return nsIDNSService::RESOLVE_TYPE_DEFAULT
;
503 [](TypeRecordTxt
&) { return nsIDNSService::RESOLVE_TYPE_TXT
; },
504 [](TypeRecordHTTPSSVC
&) { return nsIDNSService::RESOLVE_TYPE_HTTPSSVC
; });
507 TypeRecordResultType
TypeHostRecord::GetResults() {
508 MutexAutoLock
lock(mResultsLock
);
513 TypeHostRecord::GetRecords(nsTArray
<RefPtr
<nsISVCBRecord
>>& aRecords
) {
514 MutexAutoLock
lock(mResultsLock
);
515 if (!mResults
.is
<TypeRecordHTTPSSVC
>()) {
516 return NS_ERROR_NOT_AVAILABLE
;
519 auto& results
= mResults
.as
<TypeRecordHTTPSSVC
>();
521 for (const SVCB
& r
: results
) {
522 RefPtr
<nsISVCBRecord
> rec
= new mozilla::net::SVCBRecord(r
);
523 aRecords
.AppendElement(rec
);
530 TypeHostRecord::GetServiceModeRecord(bool aNoHttp2
, bool aNoHttp3
,
531 nsISVCBRecord
** aRecord
) {
532 return GetServiceModeRecordWithCname(aNoHttp2
, aNoHttp3
, ""_ns
, aRecord
);
536 TypeHostRecord::GetServiceModeRecordWithCname(bool aNoHttp2
, bool aNoHttp3
,
537 const nsACString
& aCname
,
538 nsISVCBRecord
** aRecord
) {
539 MutexAutoLock
lock(mResultsLock
);
540 if (!mResults
.is
<TypeRecordHTTPSSVC
>()) {
541 return NS_ERROR_NOT_AVAILABLE
;
544 auto& results
= mResults
.as
<TypeRecordHTTPSSVC
>();
545 nsCOMPtr
<nsISVCBRecord
> result
= GetServiceModeRecordInternal(
546 aNoHttp2
, aNoHttp3
, results
, mAllRecordsExcluded
, true, aCname
);
548 return NS_ERROR_NOT_AVAILABLE
;
551 result
.forget(aRecord
);
556 TypeHostRecord::IsTRR(bool* aResult
) {
557 *aResult
= (mResolverType
== DNSResolverType::TRR
);
562 TypeHostRecord::GetAllRecordsWithEchConfig(
563 bool aNoHttp2
, bool aNoHttp3
, const nsACString
& aCname
,
564 bool* aAllRecordsHaveEchConfig
, bool* aAllRecordsInH3ExcludedList
,
565 nsTArray
<RefPtr
<nsISVCBRecord
>>& aResult
) {
566 MutexAutoLock
lock(mResultsLock
);
567 if (!mResults
.is
<TypeRecordHTTPSSVC
>()) {
568 return NS_ERROR_NOT_AVAILABLE
;
571 auto& records
= mResults
.as
<TypeRecordHTTPSSVC
>();
572 GetAllRecordsWithEchConfigInternal(aNoHttp2
, aNoHttp3
, aCname
, records
,
573 aAllRecordsHaveEchConfig
,
574 aAllRecordsInH3ExcludedList
, aResult
);
579 TypeHostRecord::GetHasIPAddresses(bool* aResult
) {
580 NS_ENSURE_ARG(aResult
);
581 MutexAutoLock
lock(mResultsLock
);
583 if (!mResults
.is
<TypeRecordHTTPSSVC
>()) {
584 return NS_ERROR_NOT_AVAILABLE
;
587 auto& results
= mResults
.as
<TypeRecordHTTPSSVC
>();
588 *aResult
= HasIPAddressesInternal(results
);
593 TypeHostRecord::GetAllRecordsExcluded(bool* aResult
) {
594 NS_ENSURE_ARG(aResult
);
595 MutexAutoLock
lock(mResultsLock
);
597 if (!mResults
.is
<TypeRecordHTTPSSVC
>()) {
598 return NS_ERROR_NOT_AVAILABLE
;
601 *aResult
= mAllRecordsExcluded
;
606 TypeHostRecord::GetTtl(uint32_t* aResult
) {
607 NS_ENSURE_ARG(aResult
);
612 void TypeHostRecord::ResolveComplete() {
613 if (IsRelevantTRRSkipReason(mTRRSkippedReason
)) {
614 Telemetry::Accumulate(
615 Telemetry::TRR_RELEVANT_SKIP_REASON_TRR_FIRST_TYPE_REC
,
616 TRRService::ProviderKey(), static_cast<uint32_t>(mTRRSkippedReason
));
619 uint32_t millis
= static_cast<uint32_t>(mTrrDuration
.ToMilliseconds());
621 Telemetry::Accumulate(Telemetry::DNS_BY_TYPE_SUCCEEDED_LOOKUP_TIME
, millis
);
623 Telemetry::Accumulate(Telemetry::DNS_BY_TYPE_FAILED_LOOKUP_TIME
, millis
);