Bug 1807268 - Re-enable verifyShowClipboardSuggestionsToggleTest UI test r=jajohnson
[gecko.git] / netwerk / dns / nsDNSService2.cpp
blob0f89f3710247c25dadd6c5ab70363056ec5d1b3c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsDNSService2.h"
8 #include "nsIDNSRecord.h"
9 #include "nsIDNSListener.h"
10 #include "nsIDNSByTypeRecord.h"
11 #include "nsICancelable.h"
12 #include "nsIPrefBranch.h"
13 #include "nsIOService.h"
14 #include "nsIXPConnect.h"
15 #include "nsProxyRelease.h"
16 #include "nsReadableUtils.h"
17 #include "nsString.h"
18 #include "nsCRT.h"
19 #include "nsNetCID.h"
20 #include "nsError.h"
21 #include "nsDNSPrefetch.h"
22 #include "nsThreadUtils.h"
23 #include "nsIProtocolProxyService.h"
24 #include "nsIObliviousHttp.h"
25 #include "prsystem.h"
26 #include "prnetdb.h"
27 #include "prmon.h"
28 #include "prio.h"
29 #include "nsCharSeparatedTokenizer.h"
30 #include "nsNetAddr.h"
31 #include "nsProxyRelease.h"
32 #include "nsQueryObject.h"
33 #include "nsIObserverService.h"
34 #include "nsINetworkLinkService.h"
35 #include "DNSAdditionalInfo.h"
36 #include "TRRService.h"
38 #include "mozilla/Attributes.h"
39 #include "mozilla/ClearOnShutdown.h"
40 #include "mozilla/net/NeckoCommon.h"
41 #include "mozilla/net/ChildDNSService.h"
42 #include "mozilla/net/DNSListenerProxy.h"
43 #include "mozilla/Services.h"
44 #include "mozilla/StaticPrefs_network.h"
45 #include "mozilla/StaticPtr.h"
46 #include "mozilla/SyncRunnable.h"
47 #include "mozilla/TextUtils.h"
48 #include "mozilla/Utf8.h"
50 using namespace mozilla;
51 using namespace mozilla::net;
53 static const char kPrefDnsCacheEntries[] = "network.dnsCacheEntries";
54 static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration";
55 static const char kPrefDnsCacheGrace[] =
56 "network.dnsCacheExpirationGracePeriod";
57 static const char kPrefIPv4OnlyDomains[] = "network.dns.ipv4OnlyDomains";
58 static const char kPrefBlockDotOnion[] = "network.dns.blockDotOnion";
59 static const char kPrefDnsLocalDomains[] = "network.dns.localDomains";
60 static const char kPrefDnsForceResolve[] = "network.dns.forceResolve";
61 static const char kPrefDnsOfflineLocalhost[] = "network.dns.offline-localhost";
62 static const char kPrefDnsNotifyResolution[] = "network.dns.notifyResolution";
64 //-----------------------------------------------------------------------------
66 class nsDNSRecord : public nsIDNSAddrRecord {
67 public:
68 NS_DECL_THREADSAFE_ISUPPORTS
69 NS_DECL_NSIDNSRECORD
70 NS_DECL_NSIDNSADDRRECORD
72 explicit nsDNSRecord(nsHostRecord* hostRecord) {
73 mHostRecord = do_QueryObject(hostRecord);
76 private:
77 virtual ~nsDNSRecord() = default;
79 RefPtr<AddrHostRecord> mHostRecord;
80 // Since mIter is holding a weak reference to the NetAddr array we must
81 // make sure it is not released. So we also keep a RefPtr to the AddrInfo
82 // which is immutable.
83 RefPtr<AddrInfo> mAddrInfo;
84 nsTArray<NetAddr>::const_iterator mIter;
85 const NetAddr* iter() {
86 if (!mIter.GetArray()) {
87 return nullptr;
89 if (mIter.GetArray()->end() == mIter) {
90 return nullptr;
92 return &*mIter;
95 int mIterGenCnt = -1; // the generation count of
96 // mHostRecord->addr_info when we
97 // start iterating
98 bool mDone = false;
101 NS_IMPL_ISUPPORTS(nsDNSRecord, nsIDNSRecord, nsIDNSAddrRecord)
103 NS_IMETHODIMP
104 nsDNSRecord::GetCanonicalName(nsACString& result) {
105 // this method should only be called if we have a CNAME
106 NS_ENSURE_TRUE(mHostRecord->flags & nsHostResolver::RES_CANON_NAME,
107 NS_ERROR_NOT_AVAILABLE);
109 MutexAutoLock lock(mHostRecord->addr_info_lock);
111 // if the record is for an IP address literal, then the canonical
112 // host name is the IP address literal.
113 if (!mHostRecord->addr_info) {
114 result = mHostRecord->host;
115 return NS_OK;
118 if (mHostRecord->addr_info->CanonicalHostname().IsEmpty()) {
119 result = mHostRecord->addr_info->Hostname();
120 } else {
121 result = mHostRecord->addr_info->CanonicalHostname();
123 return NS_OK;
126 NS_IMETHODIMP
127 nsDNSRecord::IsTRR(bool* retval) {
128 MutexAutoLock lock(mHostRecord->addr_info_lock);
129 if (mHostRecord->addr_info) {
130 *retval = mHostRecord->addr_info->IsTRR();
131 } else {
132 *retval = false;
134 return NS_OK;
137 NS_IMETHODIMP
138 nsDNSRecord::ResolvedInSocketProcess(bool* retval) {
139 *retval = false;
140 return NS_OK;
143 NS_IMETHODIMP
144 nsDNSRecord::GetTrrFetchDuration(double* aTime) {
145 MutexAutoLock lock(mHostRecord->addr_info_lock);
146 if (mHostRecord->addr_info && mHostRecord->addr_info->IsTRR()) {
147 *aTime = mHostRecord->addr_info->GetTrrFetchDuration();
148 } else {
149 *aTime = 0;
151 return NS_OK;
154 NS_IMETHODIMP
155 nsDNSRecord::GetTrrFetchDurationNetworkOnly(double* aTime) {
156 MutexAutoLock lock(mHostRecord->addr_info_lock);
157 if (mHostRecord->addr_info && mHostRecord->addr_info->IsTRR()) {
158 *aTime = mHostRecord->addr_info->GetTrrFetchDurationNetworkOnly();
159 } else {
160 *aTime = 0;
162 return NS_OK;
165 NS_IMETHODIMP
166 nsDNSRecord::GetNextAddr(uint16_t port, NetAddr* addr) {
167 if (mDone) {
168 return NS_ERROR_NOT_AVAILABLE;
171 mHostRecord->addr_info_lock.Lock();
172 if (mHostRecord->addr_info) {
173 if (mIterGenCnt != mHostRecord->addr_info_gencnt) {
174 // mHostRecord->addr_info has changed, restart the iteration.
175 mIter = nsTArray<NetAddr>::const_iterator();
176 mIterGenCnt = mHostRecord->addr_info_gencnt;
177 // Make sure to hold a RefPtr to the AddrInfo so we can iterate through
178 // the NetAddr array.
179 mAddrInfo = mHostRecord->addr_info;
182 bool startedFresh = !iter();
184 do {
185 if (!iter()) {
186 mIter = mAddrInfo->Addresses().begin();
187 } else {
188 mIter++;
190 } while (iter() && mHostRecord->Blocklisted(iter()));
192 if (!iter() && startedFresh) {
193 // If everything was blocklisted we want to reset the blocklist (and
194 // likely relearn it) and return the first address. That is better
195 // than nothing.
196 mHostRecord->ResetBlocklist();
197 mIter = mAddrInfo->Addresses().begin();
200 if (iter()) {
201 *addr = *mIter;
204 mHostRecord->addr_info_lock.Unlock();
206 if (!iter()) {
207 mDone = true;
208 mIter = nsTArray<NetAddr>::const_iterator();
209 mAddrInfo = nullptr;
210 mIterGenCnt = -1;
211 return NS_ERROR_NOT_AVAILABLE;
213 } else {
214 mHostRecord->addr_info_lock.Unlock();
216 if (!mHostRecord->addr) {
217 // Both mHostRecord->addr_info and mHostRecord->addr are null.
218 // This can happen if mHostRecord->addr_info expired and the
219 // attempt to reresolve it failed.
220 return NS_ERROR_NOT_AVAILABLE;
222 memcpy(addr, mHostRecord->addr.get(), sizeof(NetAddr));
223 mDone = true;
226 // set given port
227 port = htons(port);
228 if (addr->raw.family == AF_INET) {
229 addr->inet.port = port;
230 } else if (addr->raw.family == AF_INET6) {
231 addr->inet6.port = port;
234 return NS_OK;
237 NS_IMETHODIMP
238 nsDNSRecord::GetAddresses(nsTArray<NetAddr>& aAddressArray) {
239 if (mDone) {
240 return NS_ERROR_NOT_AVAILABLE;
243 mHostRecord->addr_info_lock.Lock();
244 if (mHostRecord->addr_info) {
245 for (const auto& address : mHostRecord->addr_info->Addresses()) {
246 if (mHostRecord->Blocklisted(&address)) {
247 continue;
249 NetAddr* addr = aAddressArray.AppendElement(address);
250 if (addr->raw.family == AF_INET) {
251 addr->inet.port = 0;
252 } else if (addr->raw.family == AF_INET6) {
253 addr->inet6.port = 0;
256 mHostRecord->addr_info_lock.Unlock();
257 } else {
258 mHostRecord->addr_info_lock.Unlock();
260 if (!mHostRecord->addr) {
261 return NS_ERROR_NOT_AVAILABLE;
263 NetAddr* addr = aAddressArray.AppendElement(NetAddr());
264 memcpy(addr, mHostRecord->addr.get(), sizeof(NetAddr));
265 if (addr->raw.family == AF_INET) {
266 addr->inet.port = 0;
267 } else if (addr->raw.family == AF_INET6) {
268 addr->inet6.port = 0;
271 return NS_OK;
274 NS_IMETHODIMP
275 nsDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr** result) {
276 NetAddr addr;
277 nsresult rv = GetNextAddr(port, &addr);
278 if (NS_FAILED(rv)) {
279 return rv;
282 RefPtr<nsNetAddr> netaddr = new nsNetAddr(&addr);
283 netaddr.forget(result);
285 return NS_OK;
288 NS_IMETHODIMP
289 nsDNSRecord::GetNextAddrAsString(nsACString& result) {
290 NetAddr addr;
291 nsresult rv = GetNextAddr(0, &addr);
292 if (NS_FAILED(rv)) {
293 return rv;
296 char buf[kIPv6CStrBufSize];
297 if (addr.ToStringBuffer(buf, sizeof(buf))) {
298 result.Assign(buf);
299 return NS_OK;
301 NS_ERROR("NetAddrToString failed unexpectedly");
302 return NS_ERROR_FAILURE; // conversion failed for some reason
305 NS_IMETHODIMP
306 nsDNSRecord::HasMore(bool* result) {
307 if (mDone) {
308 *result = false;
309 return NS_OK;
312 nsTArray<NetAddr>::const_iterator iterCopy = mIter;
313 int iterGenCntCopy = mIterGenCnt;
315 NetAddr addr;
316 *result = NS_SUCCEEDED(GetNextAddr(0, &addr));
318 mIter = iterCopy;
319 mIterGenCnt = iterGenCntCopy;
320 mDone = false;
322 return NS_OK;
325 NS_IMETHODIMP
326 nsDNSRecord::Rewind() {
327 mIter = nsTArray<NetAddr>::const_iterator();
328 mIterGenCnt = -1;
329 mDone = false;
330 return NS_OK;
333 NS_IMETHODIMP
334 nsDNSRecord::ReportUnusable(uint16_t aPort) {
335 // right now we don't use the port in the blocklist
337 MutexAutoLock lock(mHostRecord->addr_info_lock);
339 // Check that we are using a real addr_info (as opposed to a single
340 // constant address), and that the generation count is valid. Otherwise,
341 // ignore the report.
343 if (mHostRecord->addr_info && mIterGenCnt == mHostRecord->addr_info_gencnt &&
344 iter()) {
345 mHostRecord->ReportUnusable(iter());
348 return NS_OK;
351 NS_IMETHODIMP
352 nsDNSRecord::GetEffectiveTRRMode(nsIRequest::TRRMode* aMode) {
353 *aMode = mHostRecord->EffectiveTRRMode();
354 return NS_OK;
357 NS_IMETHODIMP nsDNSRecord::GetTrrSkipReason(
358 nsITRRSkipReason::value* aTrrSkipReason) {
359 *aTrrSkipReason = mHostRecord->TrrSkipReason();
360 return NS_OK;
363 NS_IMETHODIMP
364 nsDNSRecord::GetTtl(uint32_t* aTtl) { return mHostRecord->GetTtl(aTtl); }
366 class nsDNSByTypeRecord : public nsIDNSByTypeRecord,
367 public nsIDNSTXTRecord,
368 public nsIDNSHTTPSSVCRecord {
369 public:
370 NS_DECL_THREADSAFE_ISUPPORTS
371 NS_DECL_NSIDNSRECORD
372 NS_DECL_NSIDNSBYTYPERECORD
373 NS_DECL_NSIDNSTXTRECORD
374 NS_DECL_NSIDNSHTTPSSVCRECORD
376 explicit nsDNSByTypeRecord(nsHostRecord* hostRecord) {
377 mHostRecord = do_QueryObject(hostRecord);
380 private:
381 virtual ~nsDNSByTypeRecord() = default;
382 RefPtr<TypeHostRecord> mHostRecord;
385 NS_IMPL_ISUPPORTS(nsDNSByTypeRecord, nsIDNSRecord, nsIDNSByTypeRecord,
386 nsIDNSTXTRecord, nsIDNSHTTPSSVCRecord)
388 NS_IMETHODIMP
389 nsDNSByTypeRecord::GetType(uint32_t* aType) {
390 *aType = mHostRecord->GetType();
391 return NS_OK;
394 NS_IMETHODIMP
395 nsDNSByTypeRecord::GetRecords(CopyableTArray<nsCString>& aRecords) {
396 // deep copy
397 return mHostRecord->GetRecords(aRecords);
400 NS_IMETHODIMP
401 nsDNSByTypeRecord::GetRecordsAsOneString(nsACString& aRecords) {
402 // deep copy
403 return mHostRecord->GetRecordsAsOneString(aRecords);
406 NS_IMETHODIMP
407 nsDNSByTypeRecord::GetRecords(nsTArray<RefPtr<nsISVCBRecord>>& aRecords) {
408 return mHostRecord->GetRecords(aRecords);
411 NS_IMETHODIMP
412 nsDNSByTypeRecord::GetServiceModeRecord(bool aNoHttp2, bool aNoHttp3,
413 nsISVCBRecord** aRecord) {
414 return mHostRecord->GetServiceModeRecord(aNoHttp2, aNoHttp3, aRecord);
417 NS_IMETHODIMP
418 nsDNSByTypeRecord::GetAllRecordsWithEchConfig(
419 bool aNoHttp2, bool aNoHttp3, bool* aAllRecordsHaveEchConfig,
420 bool* aAllRecordsInH3ExcludedList,
421 nsTArray<RefPtr<nsISVCBRecord>>& aResult) {
422 return mHostRecord->GetAllRecordsWithEchConfig(
423 aNoHttp2, aNoHttp3, aAllRecordsHaveEchConfig, aAllRecordsInH3ExcludedList,
424 aResult);
427 NS_IMETHODIMP
428 nsDNSByTypeRecord::GetHasIPAddresses(bool* aResult) {
429 return mHostRecord->GetHasIPAddresses(aResult);
432 NS_IMETHODIMP
433 nsDNSByTypeRecord::GetAllRecordsExcluded(bool* aResult) {
434 return mHostRecord->GetAllRecordsExcluded(aResult);
437 NS_IMETHODIMP
438 nsDNSByTypeRecord::GetResults(mozilla::net::TypeRecordResultType* aResults) {
439 *aResults = mHostRecord->GetResults();
440 return NS_OK;
443 NS_IMETHODIMP
444 nsDNSByTypeRecord::GetTtl(uint32_t* aTtl) { return mHostRecord->GetTtl(aTtl); }
446 //-----------------------------------------------------------------------------
448 class nsDNSAsyncRequest final : public nsResolveHostCallback,
449 public nsICancelable {
450 public:
451 NS_DECL_THREADSAFE_ISUPPORTS
452 NS_DECL_NSICANCELABLE
454 nsDNSAsyncRequest(nsHostResolver* res, const nsACString& host,
455 const nsACString& trrServer, uint16_t type,
456 const OriginAttributes& attrs, nsIDNSListener* listener,
457 nsIDNSService::DNSFlags flags, uint16_t af)
458 : mResolver(res),
459 mHost(host),
460 mTrrServer(trrServer),
461 mType(type),
462 mOriginAttributes(attrs),
463 mListener(listener),
464 mFlags(flags),
465 mAF(af) {}
467 void OnResolveHostComplete(nsHostResolver*, nsHostRecord*, nsresult) override;
468 // Returns TRUE if the DNS listener arg is the same as the member listener
469 // Used in Cancellations to remove DNS requests associated with a
470 // particular hostname and nsIDNSListener
471 bool EqualsAsyncListener(nsIDNSListener* aListener) override;
473 size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const override;
475 RefPtr<nsHostResolver> mResolver;
476 nsCString mHost; // hostname we're resolving
477 nsCString mTrrServer; // A trr server to be used.
478 uint16_t mType = 0;
479 const OriginAttributes
480 mOriginAttributes; // The originAttributes for this resolving
481 nsCOMPtr<nsIDNSListener> mListener;
482 nsIDNSService::DNSFlags mFlags = nsIDNSService::RESOLVE_DEFAULT_FLAGS;
483 uint16_t mAF = 0;
485 private:
486 virtual ~nsDNSAsyncRequest() = default;
489 NS_IMPL_ISUPPORTS(nsDNSAsyncRequest, nsICancelable)
491 void nsDNSAsyncRequest::OnResolveHostComplete(nsHostResolver* resolver,
492 nsHostRecord* hostRecord,
493 nsresult status) {
494 // need to have an owning ref when we issue the callback to enable
495 // the caller to be able to addref/release multiple times without
496 // destroying the record prematurely.
497 nsCOMPtr<nsIDNSRecord> rec;
498 if (NS_SUCCEEDED(status) ||
499 mFlags & nsIDNSService::RESOLVE_WANT_RECORD_ON_ERROR) {
500 MOZ_ASSERT(hostRecord, "no host record");
501 if (hostRecord->type != nsDNSService::RESOLVE_TYPE_DEFAULT) {
502 rec = new nsDNSByTypeRecord(hostRecord);
503 } else {
504 rec = new nsDNSRecord(hostRecord);
508 mListener->OnLookupComplete(this, rec, status);
509 mListener = nullptr;
512 bool nsDNSAsyncRequest::EqualsAsyncListener(nsIDNSListener* aListener) {
513 uintptr_t originalListenerAddr = reinterpret_cast<uintptr_t>(mListener.get());
514 RefPtr<DNSListenerProxy> wrapper = do_QueryObject(mListener);
515 if (wrapper) {
516 originalListenerAddr = wrapper->GetOriginalListenerAddress();
519 uintptr_t listenerAddr = reinterpret_cast<uintptr_t>(aListener);
520 return (listenerAddr == originalListenerAddr);
523 size_t nsDNSAsyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
524 size_t n = mallocSizeOf(this);
526 // The following fields aren't measured.
527 // - mHost, because it's a non-owning pointer
528 // - mResolver, because it's a non-owning pointer
529 // - mListener, because it's a non-owning pointer
531 return n;
534 NS_IMETHODIMP
535 nsDNSAsyncRequest::Cancel(nsresult reason) {
536 NS_ENSURE_ARG(NS_FAILED(reason));
537 MOZ_DIAGNOSTIC_ASSERT(mResolver, "mResolver should not be null");
538 mResolver->DetachCallback(mHost, mTrrServer, mType, mOriginAttributes, mFlags,
539 mAF, this, reason);
540 return NS_OK;
543 //-----------------------------------------------------------------------------
545 class nsDNSSyncRequest : public nsResolveHostCallback {
546 NS_DECL_THREADSAFE_ISUPPORTS
547 public:
548 explicit nsDNSSyncRequest(PRMonitor* mon) : mMonitor(mon) {}
550 void OnResolveHostComplete(nsHostResolver*, nsHostRecord*, nsresult) override;
551 bool EqualsAsyncListener(nsIDNSListener* aListener) override;
552 size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const override;
554 bool mDone = false;
555 nsresult mStatus = NS_OK;
556 RefPtr<nsHostRecord> mHostRecord;
558 private:
559 virtual ~nsDNSSyncRequest() = default;
561 PRMonitor* mMonitor = nullptr;
564 NS_IMPL_ISUPPORTS0(nsDNSSyncRequest)
566 void nsDNSSyncRequest::OnResolveHostComplete(nsHostResolver* resolver,
567 nsHostRecord* hostRecord,
568 nsresult status) {
569 // store results, and wake up nsDNSService::Resolve to process results.
570 PR_EnterMonitor(mMonitor);
571 mDone = true;
572 mStatus = status;
573 mHostRecord = hostRecord;
574 PR_Notify(mMonitor);
575 PR_ExitMonitor(mMonitor);
578 bool nsDNSSyncRequest::EqualsAsyncListener(nsIDNSListener* aListener) {
579 // Sync request: no listener to compare
580 return false;
583 size_t nsDNSSyncRequest::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
584 size_t n = mallocSizeOf(this);
586 // The following fields aren't measured.
587 // - mHostRecord, because it's a non-owning pointer
589 // Measurement of the following members may be added later if DMD finds it
590 // is worthwhile:
591 // - mMonitor
593 return n;
596 class NotifyDNSResolution : public Runnable {
597 public:
598 explicit NotifyDNSResolution(const nsACString& aHostname)
599 : mozilla::Runnable("NotifyDNSResolution"), mHostname(aHostname) {}
601 NS_IMETHOD Run() override {
602 MOZ_ASSERT(NS_IsMainThread());
603 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
604 if (obs) {
605 obs->NotifyObservers(nullptr, "dns-resolution-request",
606 NS_ConvertUTF8toUTF16(mHostname).get());
608 return NS_OK;
611 private:
612 nsCString mHostname;
615 //-----------------------------------------------------------------------------
617 static StaticRefPtr<DNSServiceWrapper> gDNSServiceWrapper;
619 NS_IMPL_ISUPPORTS(DNSServiceWrapper, nsIDNSService, nsPIDNSService)
621 // static
622 already_AddRefed<nsIDNSService> DNSServiceWrapper::GetSingleton() {
623 if (!gDNSServiceWrapper) {
624 gDNSServiceWrapper = new DNSServiceWrapper();
625 gDNSServiceWrapper->mDNSServiceInUse = ChildDNSService::GetSingleton();
626 if (gDNSServiceWrapper->mDNSServiceInUse) {
627 ClearOnShutdown(&gDNSServiceWrapper);
628 nsDNSPrefetch::Initialize(gDNSServiceWrapper);
629 } else {
630 gDNSServiceWrapper = nullptr;
634 return do_AddRef(gDNSServiceWrapper);
637 // static
638 void DNSServiceWrapper::SwitchToBackupDNSService() {
639 if (!gDNSServiceWrapper) {
640 return;
643 gDNSServiceWrapper->mBackupDNSService = nsDNSService::GetSingleton();
645 MutexAutoLock lock(gDNSServiceWrapper->mLock);
646 gDNSServiceWrapper->mBackupDNSService.swap(
647 gDNSServiceWrapper->mDNSServiceInUse);
650 nsIDNSService* DNSServiceWrapper::DNSService() {
651 MOZ_ASSERT(XRE_IsParentProcess());
653 MutexAutoLock lock(mLock);
654 return mDNSServiceInUse.get();
657 nsPIDNSService* DNSServiceWrapper::PIDNSService() {
658 MOZ_ASSERT(XRE_IsParentProcess());
660 nsCOMPtr<nsPIDNSService> service = do_QueryInterface(DNSService());
661 return service.get();
664 //-----------------------------------------------------------------------------
665 NS_IMPL_ISUPPORTS_INHERITED(nsDNSService, DNSServiceBase, nsIDNSService,
666 nsPIDNSService, nsIMemoryReporter)
668 /******************************************************************************
669 * nsDNSService impl:
670 * singleton instance ctor/dtor methods
671 ******************************************************************************/
672 static StaticRefPtr<nsDNSService> gDNSService;
673 static Atomic<bool> gInited(false);
675 already_AddRefed<nsIDNSService> GetOrInitDNSService() {
676 if (gInited) {
677 return nsDNSService::GetXPCOMSingleton();
680 nsCOMPtr<nsIDNSService> dns = nullptr;
681 auto initTask = [&dns]() { dns = do_GetService(NS_DNSSERVICE_CID); };
682 if (!NS_IsMainThread()) {
683 // Forward to the main thread synchronously.
684 RefPtr<nsIThread> mainThread = do_GetMainThread();
685 if (!mainThread) {
686 return nullptr;
689 SyncRunnable::DispatchToThread(
690 mainThread, NS_NewRunnableFunction("GetOrInitDNSService", initTask));
691 } else {
692 initTask();
695 return dns.forget();
698 already_AddRefed<nsIDNSService> nsDNSService::GetXPCOMSingleton() {
699 auto getDNSHelper = []() -> already_AddRefed<nsIDNSService> {
700 if (nsIOService::UseSocketProcess()) {
701 if (XRE_IsSocketProcess()) {
702 return GetSingleton();
705 if (XRE_IsParentProcess()) {
706 return DNSServiceWrapper::GetSingleton();
709 if (XRE_IsContentProcess()) {
710 return ChildDNSService::GetSingleton();
713 return nullptr;
716 if (XRE_IsParentProcess()) {
717 return GetSingleton();
720 if (XRE_IsContentProcess() || XRE_IsSocketProcess()) {
721 return ChildDNSService::GetSingleton();
724 return nullptr;
727 if (gInited) {
728 return getDNSHelper();
731 nsCOMPtr<nsIDNSService> dns = getDNSHelper();
732 if (dns) {
733 gInited = true;
735 return dns.forget();
738 already_AddRefed<nsDNSService> nsDNSService::GetSingleton() {
739 MOZ_ASSERT_IF(nsIOService::UseSocketProcess(), XRE_IsSocketProcess());
740 MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(), XRE_IsParentProcess());
742 if (!gDNSService) {
743 if (!NS_IsMainThread()) {
744 return nullptr;
746 gDNSService = new nsDNSService();
747 if (NS_SUCCEEDED(gDNSService->Init())) {
748 ClearOnShutdown(&gDNSService);
749 } else {
750 gDNSService = nullptr;
754 return do_AddRef(gDNSService);
757 void nsDNSService::ReadPrefs(const char* name) {
758 DNSServiceBase::ReadPrefs(name);
760 bool tmpbool;
761 uint32_t tmpint;
762 mResolverPrefsUpdated = false;
764 // resolver-specific prefs first
765 if (!name || !strcmp(name, kPrefDnsCacheEntries)) {
766 if (NS_SUCCEEDED(Preferences::GetUint(kPrefDnsCacheEntries, &tmpint))) {
767 if (!name || (tmpint != mResCacheEntries)) {
768 mResCacheEntries = tmpint;
769 mResolverPrefsUpdated = true;
773 if (!name || !strcmp(name, kPrefDnsCacheExpiration)) {
774 if (NS_SUCCEEDED(Preferences::GetUint(kPrefDnsCacheExpiration, &tmpint))) {
775 if (!name || (tmpint != mResCacheExpiration)) {
776 mResCacheExpiration = tmpint;
777 mResolverPrefsUpdated = true;
781 if (!name || !strcmp(name, kPrefDnsCacheGrace)) {
782 if (NS_SUCCEEDED(Preferences::GetUint(kPrefDnsCacheGrace, &tmpint))) {
783 if (!name || (tmpint != mResCacheGrace)) {
784 mResCacheGrace = tmpint;
785 mResolverPrefsUpdated = true;
790 // DNSservice prefs
791 if (!name || !strcmp(name, kPrefDnsOfflineLocalhost)) {
792 if (NS_SUCCEEDED(
793 Preferences::GetBool(kPrefDnsOfflineLocalhost, &tmpbool))) {
794 mOfflineLocalhost = tmpbool;
797 if (!name || !strcmp(name, kPrefBlockDotOnion)) {
798 if (NS_SUCCEEDED(Preferences::GetBool(kPrefBlockDotOnion, &tmpbool))) {
799 mBlockDotOnion = tmpbool;
802 if (!name || !strcmp(name, kPrefDnsNotifyResolution)) {
803 if (NS_SUCCEEDED(
804 Preferences::GetBool(kPrefDnsNotifyResolution, &tmpbool))) {
805 mNotifyResolution = tmpbool;
808 if (!name || !strcmp(name, kPrefIPv4OnlyDomains)) {
809 Preferences::GetCString(kPrefIPv4OnlyDomains, mIPv4OnlyDomains);
811 if (!name || !strcmp(name, kPrefDnsLocalDomains)) {
812 nsCString localDomains;
813 Preferences::GetCString(kPrefDnsLocalDomains, localDomains);
814 MutexAutoLock lock(mLock);
815 mLocalDomains.Clear();
816 for (const auto& token :
817 nsCCharSeparatedTokenizerTemplate<NS_IsAsciiWhitespace,
818 nsTokenizerFlags::SeparatorOptional>(
819 localDomains, ',')
820 .ToRange()) {
821 mLocalDomains.Insert(token);
824 if (!name || !strcmp(name, kPrefDnsForceResolve)) {
825 Preferences::GetCString(kPrefDnsForceResolve, mForceResolve);
826 mForceResolveOn = !mForceResolve.IsEmpty();
830 NS_IMETHODIMP
831 nsDNSService::Init() {
832 MOZ_ASSERT(!mResolver);
833 MOZ_ASSERT(NS_IsMainThread());
835 ReadPrefs(nullptr);
837 nsCOMPtr<nsIObserverService> observerService =
838 mozilla::services::GetObserverService();
839 if (observerService) {
840 observerService->AddObserver(this, "last-pb-context-exited", false);
841 observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
842 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
845 RefPtr<nsHostResolver> res;
846 nsresult rv = nsHostResolver::Create(mResCacheEntries, mResCacheExpiration,
847 mResCacheGrace, getter_AddRefs(res));
848 if (NS_SUCCEEDED(rv)) {
849 // now, set all of our member variables while holding the lock
850 MutexAutoLock lock(mLock);
851 mResolver = res;
854 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
855 if (prefs) {
856 // register as prefs observer
857 prefs->AddObserver(kPrefDnsCacheEntries, this, false);
858 prefs->AddObserver(kPrefDnsCacheExpiration, this, false);
859 prefs->AddObserver(kPrefDnsCacheGrace, this, false);
860 prefs->AddObserver(kPrefIPv4OnlyDomains, this, false);
861 prefs->AddObserver(kPrefDnsLocalDomains, this, false);
862 prefs->AddObserver(kPrefDnsForceResolve, this, false);
863 prefs->AddObserver(kPrefDnsOfflineLocalhost, this, false);
864 prefs->AddObserver(kPrefBlockDotOnion, this, false);
865 prefs->AddObserver(kPrefDnsNotifyResolution, this, false);
866 AddPrefObserver(prefs);
869 nsDNSPrefetch::Initialize(this);
871 RegisterWeakMemoryReporter(this);
873 nsCOMPtr<nsIObliviousHttpService> ohttpService(
874 do_GetService("@mozilla.org/network/oblivious-http-service;1"));
876 mTrrService = new TRRService();
877 if (NS_FAILED(mTrrService->Init())) {
878 mTrrService = nullptr;
881 nsCOMPtr<nsIIDNService> idn = do_GetService(NS_IDNSERVICE_CONTRACTID);
882 mIDN = idn;
884 return NS_OK;
887 NS_IMETHODIMP
888 nsDNSService::Shutdown() {
889 UnregisterWeakMemoryReporter(this);
891 RefPtr<nsHostResolver> res;
893 MutexAutoLock lock(mLock);
894 res = std::move(mResolver);
896 if (res) {
897 // Shutdown outside lock.
898 res->Shutdown();
901 nsCOMPtr<nsIObserverService> observerService =
902 mozilla::services::GetObserverService();
903 if (observerService) {
904 observerService->RemoveObserver(this, NS_NETWORK_LINK_TOPIC);
905 observerService->RemoveObserver(this, "last-pb-context-exited");
906 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
909 return NS_OK;
912 bool nsDNSService::GetOffline() const {
913 bool offline = false;
914 nsCOMPtr<nsIIOService> io = do_GetService(NS_IOSERVICE_CONTRACTID);
915 if (io) {
916 io->GetOffline(&offline);
918 return offline;
921 NS_IMETHODIMP
922 nsDNSService::GetPrefetchEnabled(bool* outVal) {
923 MutexAutoLock lock(mLock);
924 *outVal = !mDisablePrefetch;
925 return NS_OK;
928 NS_IMETHODIMP
929 nsDNSService::SetPrefetchEnabled(bool inVal) {
930 MutexAutoLock lock(mLock);
931 mDisablePrefetch = !inVal;
932 return NS_OK;
935 already_AddRefed<nsHostResolver> nsDNSService::GetResolverLocked() {
936 MutexAutoLock lock(mLock);
937 return do_AddRef(mResolver);
940 nsresult nsDNSService::PreprocessHostname(bool aLocalDomain,
941 const nsACString& aInput,
942 nsIIDNService* aIDN,
943 nsACString& aACE) {
944 // Enforce RFC 7686
945 if (mBlockDotOnion && StringEndsWith(aInput, ".onion"_ns)) {
946 return NS_ERROR_UNKNOWN_HOST;
949 if (aLocalDomain) {
950 aACE.AssignLiteral("localhost");
951 return NS_OK;
954 if (mTrrService && mTrrService->MaybeBootstrap(aInput, aACE)) {
955 return NS_OK;
958 if (mForceResolveOn) {
959 MutexAutoLock lock(mLock);
960 if (!aInput.LowerCaseEqualsASCII("localhost") &&
961 !aInput.LowerCaseEqualsASCII("127.0.0.1")) {
962 aACE.Assign(mForceResolve);
963 return NS_OK;
967 if (!aIDN || IsAscii(aInput)) {
968 aACE = aInput;
969 return NS_OK;
972 if (!(IsUtf8(aInput) && NS_SUCCEEDED(aIDN->ConvertUTF8toACE(aInput, aACE)))) {
973 return NS_ERROR_FAILURE;
975 return NS_OK;
978 bool nsDNSService::IsLocalDomain(const nsACString& aHostname) const {
979 bool localDomain = mLocalDomains.Contains(aHostname);
980 if (StringEndsWith(aHostname, "."_ns)) {
981 localDomain = localDomain || mLocalDomains.Contains(Substring(
982 aHostname, 0, aHostname.Length() - 1));
984 return localDomain;
987 nsresult nsDNSService::AsyncResolveInternal(
988 const nsACString& aHostname, uint16_t type, nsIDNSService::DNSFlags flags,
989 nsIDNSAdditionalInfo* aInfo, nsIDNSListener* aListener,
990 nsIEventTarget* target_, const OriginAttributes& aOriginAttributes,
991 nsICancelable** result) {
992 // grab reference to global host resolver and IDN service. beware
993 // simultaneous shutdown!!
994 RefPtr<nsHostResolver> res;
995 nsCOMPtr<nsIIDNService> idn;
996 nsCOMPtr<nsIEventTarget> target = target_;
997 nsCOMPtr<nsIDNSListener> listener = aListener;
998 bool localDomain = false;
1000 MutexAutoLock lock(mLock);
1002 if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) {
1003 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
1006 res = mResolver;
1007 idn = mIDN;
1009 localDomain = IsLocalDomain(aHostname);
1012 if (mNotifyResolution) {
1013 NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
1016 if (!res) {
1017 return NS_ERROR_OFFLINE;
1020 if ((type != RESOLVE_TYPE_DEFAULT) && (type != RESOLVE_TYPE_TXT) &&
1021 (type != RESOLVE_TYPE_HTTPSSVC)) {
1022 return NS_ERROR_INVALID_ARG;
1025 if (DNSForbiddenByActiveProxy(aHostname, flags)) {
1026 // nsHostResolver returns NS_ERROR_UNKNOWN_HOST for lots of reasons.
1027 // We use a different error code to differentiate this failure and to make
1028 // it clear(er) where this error comes from.
1029 return NS_ERROR_UNKNOWN_PROXY_HOST;
1032 nsCString hostname;
1033 nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname);
1034 if (NS_FAILED(rv)) {
1035 return rv;
1038 if (GetOffline() &&
1039 (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) {
1040 flags |= RESOLVE_OFFLINE;
1043 // make sure JS callers get notification on the main thread
1044 nsCOMPtr<nsIXPConnectWrappedJS> wrappedListener = do_QueryInterface(listener);
1045 if (wrappedListener && !target) {
1046 target = GetMainThreadSerialEventTarget();
1049 if (target) {
1050 listener = new DNSListenerProxy(listener, target);
1053 uint16_t af =
1054 (type != RESOLVE_TYPE_DEFAULT) ? 0 : GetAFForLookup(hostname, flags);
1056 MOZ_ASSERT(listener);
1057 RefPtr<nsDNSAsyncRequest> req =
1058 new nsDNSAsyncRequest(res, hostname, DNSAdditionalInfo::URL(aInfo), type,
1059 aOriginAttributes, listener, flags, af);
1060 if (!req) {
1061 return NS_ERROR_OUT_OF_MEMORY;
1064 rv = res->ResolveHost(req->mHost, DNSAdditionalInfo::URL(aInfo),
1065 DNSAdditionalInfo::Port(aInfo), type,
1066 req->mOriginAttributes, flags, af, req);
1067 req.forget(result);
1068 return rv;
1071 nsresult nsDNSService::CancelAsyncResolveInternal(
1072 const nsACString& aHostname, uint16_t aType, nsIDNSService::DNSFlags aFlags,
1073 nsIDNSAdditionalInfo* aInfo, nsIDNSListener* aListener, nsresult aReason,
1074 const OriginAttributes& aOriginAttributes) {
1075 // grab reference to global host resolver and IDN service. beware
1076 // simultaneous shutdown!!
1077 RefPtr<nsHostResolver> res;
1078 nsCOMPtr<nsIIDNService> idn;
1079 bool localDomain = false;
1081 MutexAutoLock lock(mLock);
1083 if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) {
1084 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
1087 res = mResolver;
1088 idn = mIDN;
1089 localDomain = IsLocalDomain(aHostname);
1091 if (!res) {
1092 return NS_ERROR_OFFLINE;
1095 nsCString hostname;
1096 nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname);
1097 if (NS_FAILED(rv)) {
1098 return rv;
1101 uint16_t af =
1102 (aType != RESOLVE_TYPE_DEFAULT) ? 0 : GetAFForLookup(hostname, aFlags);
1104 res->CancelAsyncRequest(hostname, DNSAdditionalInfo::URL(aInfo), aType,
1105 aOriginAttributes, aFlags, af, aListener, aReason);
1106 return NS_OK;
1109 NS_IMETHODIMP
1110 nsDNSService::AsyncResolve(const nsACString& aHostname,
1111 nsIDNSService::ResolveType aType,
1112 nsIDNSService::DNSFlags flags,
1113 nsIDNSAdditionalInfo* aInfo,
1114 nsIDNSListener* listener, nsIEventTarget* target_,
1115 JS::Handle<JS::Value> aOriginAttributes,
1116 JSContext* aCx, uint8_t aArgc,
1117 nsICancelable** result) {
1118 OriginAttributes attrs;
1120 if (aArgc == 1) {
1121 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
1122 return NS_ERROR_INVALID_ARG;
1126 return AsyncResolveInternal(aHostname, aType, flags, aInfo, listener, target_,
1127 attrs, result);
1130 NS_IMETHODIMP
1131 nsDNSService::AsyncResolveNative(
1132 const nsACString& aHostname, nsIDNSService::ResolveType aType,
1133 nsIDNSService::DNSFlags flags, nsIDNSAdditionalInfo* aInfo,
1134 nsIDNSListener* aListener, nsIEventTarget* target_,
1135 const OriginAttributes& aOriginAttributes, nsICancelable** result) {
1136 return AsyncResolveInternal(aHostname, aType, flags, aInfo, aListener,
1137 target_, aOriginAttributes, result);
1140 NS_IMETHODIMP
1141 nsDNSService::NewAdditionalInfo(const nsACString& aTrrURL, int32_t aPort,
1142 nsIDNSAdditionalInfo** aInfo) {
1143 RefPtr<DNSAdditionalInfo> res = new DNSAdditionalInfo(aTrrURL, aPort);
1144 res.forget(aInfo);
1145 return NS_OK;
1148 NS_IMETHODIMP
1149 nsDNSService::CancelAsyncResolve(const nsACString& aHostname,
1150 nsIDNSService::ResolveType aType,
1151 nsIDNSService::DNSFlags aFlags,
1152 nsIDNSAdditionalInfo* aInfo,
1153 nsIDNSListener* aListener, nsresult aReason,
1154 JS::Handle<JS::Value> aOriginAttributes,
1155 JSContext* aCx, uint8_t aArgc) {
1156 OriginAttributes attrs;
1158 if (aArgc == 1) {
1159 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
1160 return NS_ERROR_INVALID_ARG;
1164 return CancelAsyncResolveInternal(aHostname, aType, aFlags, aInfo, aListener,
1165 aReason, attrs);
1168 NS_IMETHODIMP
1169 nsDNSService::CancelAsyncResolveNative(
1170 const nsACString& aHostname, nsIDNSService::ResolveType aType,
1171 nsIDNSService::DNSFlags aFlags, nsIDNSAdditionalInfo* aInfo,
1172 nsIDNSListener* aListener, nsresult aReason,
1173 const OriginAttributes& aOriginAttributes) {
1174 return CancelAsyncResolveInternal(aHostname, aType, aFlags, aInfo, aListener,
1175 aReason, aOriginAttributes);
1178 NS_IMETHODIMP
1179 nsDNSService::Resolve(const nsACString& aHostname,
1180 nsIDNSService::DNSFlags flags,
1181 JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx,
1182 uint8_t aArgc, nsIDNSRecord** result) {
1183 OriginAttributes attrs;
1185 if (aArgc == 1) {
1186 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
1187 return NS_ERROR_INVALID_ARG;
1191 return ResolveNative(aHostname, flags, attrs, result);
1194 NS_IMETHODIMP
1195 nsDNSService::ResolveNative(const nsACString& aHostname,
1196 nsIDNSService::DNSFlags flags,
1197 const OriginAttributes& aOriginAttributes,
1198 nsIDNSRecord** result) {
1199 // Synchronous resolution is not available on the main thread.
1200 if (NS_IsMainThread()) {
1201 return NS_ERROR_NOT_AVAILABLE;
1204 return ResolveInternal(aHostname, flags, aOriginAttributes, result);
1207 nsresult nsDNSService::DeprecatedSyncResolve(
1208 const nsACString& aHostname, nsIDNSService::DNSFlags flags,
1209 const OriginAttributes& aOriginAttributes, nsIDNSRecord** result) {
1210 return ResolveInternal(aHostname, flags, aOriginAttributes, result);
1213 nsresult nsDNSService::ResolveInternal(
1214 const nsACString& aHostname, nsIDNSService::DNSFlags flags,
1215 const OriginAttributes& aOriginAttributes, nsIDNSRecord** result) {
1216 // grab reference to global host resolver and IDN service. beware
1217 // simultaneous shutdown!!
1218 RefPtr<nsHostResolver> res;
1219 nsCOMPtr<nsIIDNService> idn;
1220 bool localDomain = false;
1222 MutexAutoLock lock(mLock);
1223 res = mResolver;
1224 idn = mIDN;
1225 localDomain = IsLocalDomain(aHostname);
1228 if (mNotifyResolution) {
1229 NS_DispatchToMainThread(new NotifyDNSResolution(aHostname));
1232 NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE);
1234 nsCString hostname;
1235 nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname);
1236 if (NS_FAILED(rv)) {
1237 return rv;
1240 if (GetOffline() &&
1241 (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) {
1242 flags |= RESOLVE_OFFLINE;
1245 if (DNSForbiddenByActiveProxy(aHostname, flags)) {
1246 return NS_ERROR_UNKNOWN_PROXY_HOST;
1250 // sync resolve: since the host resolver only works asynchronously, we need
1251 // to use a mutex and a condvar to wait for the result. however, since the
1252 // result may be in the resolvers cache, we might get called back recursively
1253 // on the same thread. so, our mutex needs to be re-entrant. in other words,
1254 // we need to use a monitor! ;-)
1257 PRMonitor* mon = PR_NewMonitor();
1258 if (!mon) {
1259 return NS_ERROR_OUT_OF_MEMORY;
1262 PR_EnterMonitor(mon);
1263 RefPtr<nsDNSSyncRequest> syncReq = new nsDNSSyncRequest(mon);
1265 uint16_t af = GetAFForLookup(hostname, flags);
1267 // TRR uses the main thread for the HTTPS channel to the DoH server.
1268 // If this were to block the main thread while waiting for TRR it would
1269 // likely cause a deadlock. Instead we intentionally choose to not use TRR
1270 // for this.
1271 if (NS_IsMainThread()) {
1272 flags |= RESOLVE_DISABLE_TRR;
1275 rv = res->ResolveHost(hostname, ""_ns, -1, RESOLVE_TYPE_DEFAULT,
1276 aOriginAttributes, flags, af, syncReq);
1277 if (NS_SUCCEEDED(rv)) {
1278 // wait for result
1279 while (!syncReq->mDone) {
1280 PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
1283 if (NS_FAILED(syncReq->mStatus)) {
1284 rv = syncReq->mStatus;
1285 } else {
1286 NS_ASSERTION(syncReq->mHostRecord, "no host record");
1287 RefPtr<nsDNSRecord> rec = new nsDNSRecord(syncReq->mHostRecord);
1288 rec.forget(result);
1292 PR_ExitMonitor(mon);
1293 PR_DestroyMonitor(mon);
1294 return rv;
1297 NS_IMETHODIMP
1298 nsDNSService::GetMyHostName(nsACString& result) {
1299 char name[100];
1300 if (PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof(name)) == PR_SUCCESS) {
1301 result = name;
1302 return NS_OK;
1304 return NS_ERROR_FAILURE;
1307 NS_IMETHODIMP
1308 nsDNSService::Observe(nsISupports* subject, const char* topic,
1309 const char16_t* data) {
1310 bool flushCache = false;
1311 RefPtr<nsHostResolver> resolver = GetResolverLocked();
1313 if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
1314 nsAutoCString converted = NS_ConvertUTF16toUTF8(data);
1315 if (!strcmp(converted.get(), NS_NETWORK_LINK_DATA_CHANGED)) {
1316 flushCache = true;
1318 } else if (!strcmp(topic, "last-pb-context-exited")) {
1319 flushCache = true;
1320 } else if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
1321 ReadPrefs(NS_ConvertUTF16toUTF8(data).get());
1322 NS_ENSURE_TRUE(resolver, NS_ERROR_NOT_INITIALIZED);
1323 if (mResolverPrefsUpdated && resolver) {
1324 resolver->SetCacheLimits(mResCacheEntries, mResCacheExpiration,
1325 mResCacheGrace);
1327 } else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
1328 Shutdown();
1331 if (flushCache && resolver) {
1332 resolver->FlushCache(false);
1333 return NS_OK;
1336 return NS_OK;
1339 uint16_t nsDNSService::GetAFForLookup(const nsACString& host,
1340 nsIDNSService::DNSFlags flags) {
1341 if (StaticPrefs::network_dns_disableIPv6() ||
1342 (flags & RESOLVE_DISABLE_IPV6)) {
1343 return PR_AF_INET;
1346 MutexAutoLock lock(mLock);
1348 uint16_t af = PR_AF_UNSPEC;
1350 if (!mIPv4OnlyDomains.IsEmpty()) {
1351 const char *domain, *domainEnd, *end;
1352 uint32_t hostLen, domainLen;
1354 // see if host is in one of the IPv4-only domains
1355 domain = mIPv4OnlyDomains.BeginReading();
1356 domainEnd = mIPv4OnlyDomains.EndReading();
1358 nsACString::const_iterator hostStart;
1359 host.BeginReading(hostStart);
1360 hostLen = host.Length();
1362 do {
1363 // skip any whitespace
1364 while (*domain == ' ' || *domain == '\t') {
1365 ++domain;
1368 // find end of this domain in the string
1369 end = strchr(domain, ',');
1370 if (!end) {
1371 end = domainEnd;
1374 // to see if the hostname is in the domain, check if the domain
1375 // matches the end of the hostname.
1376 domainLen = end - domain;
1377 if (domainLen && hostLen >= domainLen) {
1378 const char* hostTail = hostStart.get() + hostLen - domainLen;
1379 if (nsCRT::strncasecmp(domain, hostTail, domainLen) == 0) {
1380 // now, make sure either that the hostname is a direct match or
1381 // that the hostname begins with a dot.
1382 if (hostLen == domainLen || *hostTail == '.' ||
1383 *(hostTail - 1) == '.') {
1384 af = PR_AF_INET;
1385 break;
1390 domain = end + 1;
1391 } while (*end);
1394 if ((af != PR_AF_INET) && (flags & RESOLVE_DISABLE_IPV4)) {
1395 af = PR_AF_INET6;
1398 return af;
1401 NS_IMETHODIMP
1402 nsDNSService::GetDNSCacheEntries(
1403 nsTArray<mozilla::net::DNSCacheEntries>* args) {
1404 RefPtr<nsHostResolver> resolver = GetResolverLocked();
1405 NS_ENSURE_TRUE(resolver, NS_ERROR_NOT_INITIALIZED);
1406 resolver->GetDNSCacheEntries(args);
1407 return NS_OK;
1410 NS_IMETHODIMP
1411 nsDNSService::ClearCache(bool aTrrToo) {
1412 RefPtr<nsHostResolver> resolver = GetResolverLocked();
1413 NS_ENSURE_TRUE(resolver, NS_ERROR_NOT_INITIALIZED);
1414 resolver->FlushCache(aTrrToo);
1415 return NS_OK;
1418 NS_IMETHODIMP
1419 nsDNSService::ReloadParentalControlEnabled() {
1420 if (mTrrService) {
1421 mTrrService->mParentalControlEnabled =
1422 TRRService::GetParentalControlEnabledInternal();
1424 return NS_OK;
1427 NS_IMETHODIMP
1428 nsDNSService::SetDetectedTrrURI(const nsACString& aURI) {
1429 if (mTrrService) {
1430 mTrrService->SetDetectedTrrURI(aURI);
1432 return NS_OK;
1435 NS_IMETHODIMP
1436 nsDNSService::SetHeuristicDetectionResult(nsITRRSkipReason::value aValue) {
1437 if (mTrrService) {
1438 mTrrService->SetHeuristicDetectionResult(aValue);
1440 return NS_OK;
1443 NS_IMETHODIMP
1444 nsDNSService::GetHeuristicDetectionResult(nsITRRSkipReason::value* aValue) {
1445 if (!mTrrService) {
1446 return NS_ERROR_NOT_AVAILABLE;
1449 *aValue = mTrrService->GetHeuristicDetectionResult();
1450 return NS_OK;
1453 NS_IMETHODIMP
1454 nsDNSService::GetTRRSkipReasonName(nsITRRSkipReason::value aValue,
1455 nsACString& aName) {
1456 return mozilla::net::GetTRRSkipReasonName(aValue, aName);
1459 NS_IMETHODIMP
1460 nsDNSService::GetCurrentTrrURI(nsACString& aURI) {
1461 if (mTrrService) {
1462 mTrrService->GetURI(aURI);
1464 return NS_OK;
1467 NS_IMETHODIMP
1468 nsDNSService::GetCurrentTrrMode(nsIDNSService::ResolverMode* aMode) {
1469 *aMode = nsIDNSService::MODE_NATIVEONLY; // The default mode.
1470 if (mTrrService) {
1471 *aMode = mTrrService->Mode();
1473 return NS_OK;
1476 NS_IMETHODIMP
1477 nsDNSService::GetCurrentTrrConfirmationState(uint32_t* aConfirmationState) {
1478 *aConfirmationState = uint32_t(TRRService::CONFIRM_OFF);
1479 if (mTrrService) {
1480 *aConfirmationState = mTrrService->ConfirmationState();
1482 return NS_OK;
1485 NS_IMETHODIMP
1486 nsDNSService::GetTrrDomain(nsACString& aTRRDomain) {
1487 aTRRDomain.Truncate();
1488 nsAutoCString url;
1489 if (mTrrService) {
1490 mTrrService->GetURI(url);
1492 nsCOMPtr<nsIURI> uri;
1493 nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
1494 if (NS_FAILED(rv)) {
1495 // An empty TRR domain in case of invalid URL.
1496 return NS_OK;
1498 return uri->GetHost(aTRRDomain);
1501 nsresult nsDNSService::GetTRRDomainKey(nsACString& aTRRDomain) {
1502 aTRRDomain = TRRService::ProviderKey();
1503 return NS_OK;
1506 size_t nsDNSService::SizeOfIncludingThis(
1507 mozilla::MallocSizeOf mallocSizeOf) const {
1508 // Measurement of the following members may be added later if DMD finds it
1509 // is worthwhile:
1510 // - mIDN
1511 // - mLock
1513 size_t n = mallocSizeOf(this);
1514 n += mResolver ? mResolver->SizeOfIncludingThis(mallocSizeOf) : 0;
1515 n += mIPv4OnlyDomains.SizeOfExcludingThisIfUnshared(mallocSizeOf);
1516 n += mLocalDomains.SizeOfExcludingThis(mallocSizeOf);
1517 n += mFailedSVCDomainNames.ShallowSizeOfExcludingThis(mallocSizeOf);
1518 for (const auto& data : mFailedSVCDomainNames.Values()) {
1519 n += data->ShallowSizeOfExcludingThis(mallocSizeOf);
1520 for (const auto& name : *data) {
1521 n += name.SizeOfExcludingThisIfUnshared(mallocSizeOf);
1524 return n;
1527 MOZ_DEFINE_MALLOC_SIZE_OF(DNSServiceMallocSizeOf)
1529 NS_IMETHODIMP
1530 nsDNSService::CollectReports(nsIHandleReportCallback* aHandleReport,
1531 nsISupports* aData, bool aAnonymize) {
1532 MOZ_COLLECT_REPORT("explicit/network/dns-service", KIND_HEAP, UNITS_BYTES,
1533 SizeOfIncludingThis(DNSServiceMallocSizeOf),
1534 "Memory used for the DNS service.");
1536 return NS_OK;
1539 NS_IMETHODIMP
1540 nsDNSService::ReportFailedSVCDomainName(const nsACString& aOwnerName,
1541 const nsACString& aSVCDomainName) {
1542 MutexAutoLock lock(mLock);
1544 mFailedSVCDomainNames.GetOrInsertNew(aOwnerName, 1)
1545 ->AppendElement(aSVCDomainName);
1546 return NS_OK;
1549 NS_IMETHODIMP
1550 nsDNSService::IsSVCDomainNameFailed(const nsACString& aOwnerName,
1551 const nsACString& aSVCDomainName,
1552 bool* aResult) {
1553 NS_ENSURE_ARG(aResult);
1555 MutexAutoLock lock(mLock);
1556 *aResult = false;
1557 nsTArray<nsCString>* failedList = mFailedSVCDomainNames.Get(aOwnerName);
1558 if (!failedList) {
1559 return NS_OK;
1562 *aResult = failedList->Contains(aSVCDomainName);
1563 return NS_OK;
1566 NS_IMETHODIMP
1567 nsDNSService::ResetExcludedSVCDomainName(const nsACString& aOwnerName) {
1568 MutexAutoLock lock(mLock);
1569 mFailedSVCDomainNames.Remove(aOwnerName);
1570 return NS_OK;
1573 NS_IMETHODIMP
1574 nsDNSService::GetLastConfirmationStatus(nsresult* aConfirmationStatus) {
1575 if (!mTrrService) {
1576 return NS_ERROR_NOT_AVAILABLE;
1578 *aConfirmationStatus = mTrrService->LastConfirmationStatus();
1579 return NS_OK;
1582 NS_IMETHODIMP nsDNSService::GetLastConfirmationSkipReason(
1583 TRRSkippedReason* aSkipReason) {
1584 if (!mTrrService) {
1585 return NS_ERROR_NOT_AVAILABLE;
1587 *aSkipReason = mTrrService->LastConfirmationSkipReason();
1588 return NS_OK;
1591 namespace mozilla::net {
1592 nsresult GetTRRSkipReasonName(TRRSkippedReason aReason, nsACString& aName) {
1593 static_assert(TRRSkippedReason::TRR_UNSET == 0);
1594 static_assert(TRRSkippedReason::TRR_OK == 1);
1595 static_assert(TRRSkippedReason::TRR_NO_GSERVICE == 2);
1596 static_assert(TRRSkippedReason::TRR_PARENTAL_CONTROL == 3);
1597 static_assert(TRRSkippedReason::TRR_OFF_EXPLICIT == 4);
1598 static_assert(TRRSkippedReason::TRR_REQ_MODE_DISABLED == 5);
1599 static_assert(TRRSkippedReason::TRR_MODE_NOT_ENABLED == 6);
1600 static_assert(TRRSkippedReason::TRR_FAILED == 7);
1601 static_assert(TRRSkippedReason::TRR_MODE_UNHANDLED_DEFAULT == 8);
1602 static_assert(TRRSkippedReason::TRR_MODE_UNHANDLED_DISABLED == 9);
1603 static_assert(TRRSkippedReason::TRR_DISABLED_FLAG == 10);
1604 static_assert(TRRSkippedReason::TRR_TIMEOUT == 11);
1605 static_assert(TRRSkippedReason::TRR_CHANNEL_DNS_FAIL == 12);
1606 static_assert(TRRSkippedReason::TRR_IS_OFFLINE == 13);
1607 static_assert(TRRSkippedReason::TRR_NOT_CONFIRMED == 14);
1608 static_assert(TRRSkippedReason::TRR_DID_NOT_MAKE_QUERY == 15);
1609 static_assert(TRRSkippedReason::TRR_UNKNOWN_CHANNEL_FAILURE == 16);
1610 static_assert(TRRSkippedReason::TRR_HOST_BLOCKED_TEMPORARY == 17);
1611 static_assert(TRRSkippedReason::TRR_SEND_FAILED == 18);
1612 static_assert(TRRSkippedReason::TRR_NET_RESET == 19);
1613 static_assert(TRRSkippedReason::TRR_NET_TIMEOUT == 20);
1614 static_assert(TRRSkippedReason::TRR_NET_REFUSED == 21);
1615 static_assert(TRRSkippedReason::TRR_NET_INTERRUPT == 22);
1616 static_assert(TRRSkippedReason::TRR_NET_INADEQ_SEQURITY == 23);
1617 static_assert(TRRSkippedReason::TRR_NO_ANSWERS == 24);
1618 static_assert(TRRSkippedReason::TRR_DECODE_FAILED == 25);
1619 static_assert(TRRSkippedReason::TRR_EXCLUDED == 26);
1620 static_assert(TRRSkippedReason::TRR_SERVER_RESPONSE_ERR == 27);
1621 static_assert(TRRSkippedReason::TRR_RCODE_FAIL == 28);
1622 static_assert(TRRSkippedReason::TRR_NO_CONNECTIVITY == 29);
1623 static_assert(TRRSkippedReason::TRR_NXDOMAIN == 30);
1624 static_assert(TRRSkippedReason::TRR_REQ_CANCELLED == 31);
1625 static_assert(TRRSkippedReason::ODOH_KEY_NOT_USABLE == 32);
1626 static_assert(TRRSkippedReason::ODOH_UPDATE_KEY_FAILED == 33);
1627 static_assert(TRRSkippedReason::ODOH_KEY_NOT_AVAILABLE == 34);
1628 static_assert(TRRSkippedReason::ODOH_ENCRYPTION_FAILED == 35);
1629 static_assert(TRRSkippedReason::ODOH_DECRYPTION_FAILED == 36);
1630 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH ==
1631 37);
1632 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH ==
1633 38);
1634 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY == 39);
1635 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_CANARY == 40);
1636 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS == 41);
1637 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS ==
1638 42);
1639 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS ==
1640 43);
1641 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY ==
1642 44);
1643 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_VPN == 45);
1644 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_PROXY == 46);
1645 static_assert(TRRSkippedReason::TRR_HEURISTIC_TRIPPED_NRPT == 47);
1646 static_assert(TRRSkippedReason::TRR_BAD_URL == 48);
1648 switch (aReason) {
1649 case TRRSkippedReason::TRR_UNSET:
1650 aName = "TRR_UNSET"_ns;
1651 break;
1652 case TRRSkippedReason::TRR_OK:
1653 aName = "TRR_OK"_ns;
1654 break;
1655 case TRRSkippedReason::TRR_NO_GSERVICE:
1656 aName = "TRR_NO_GSERVICE"_ns;
1657 break;
1658 case TRRSkippedReason::TRR_PARENTAL_CONTROL:
1659 aName = "TRR_PARENTAL_CONTROL"_ns;
1660 break;
1661 case TRRSkippedReason::TRR_OFF_EXPLICIT:
1662 aName = "TRR_OFF_EXPLICIT"_ns;
1663 break;
1664 case TRRSkippedReason::TRR_REQ_MODE_DISABLED:
1665 aName = "TRR_REQ_MODE_DISABLED"_ns;
1666 break;
1667 case TRRSkippedReason::TRR_MODE_NOT_ENABLED:
1668 aName = "TRR_MODE_NOT_ENABLED"_ns;
1669 break;
1670 case TRRSkippedReason::TRR_FAILED:
1671 aName = "TRR_FAILED"_ns;
1672 break;
1673 case TRRSkippedReason::TRR_MODE_UNHANDLED_DEFAULT:
1674 aName = "TRR_MODE_UNHANDLED_DEFAULT"_ns;
1675 break;
1676 case TRRSkippedReason::TRR_MODE_UNHANDLED_DISABLED:
1677 aName = "TRR_MODE_UNHANDLED_DISABLED"_ns;
1678 break;
1679 case TRRSkippedReason::TRR_DISABLED_FLAG:
1680 aName = "TRR_DISABLED_FLAG"_ns;
1681 break;
1682 case TRRSkippedReason::TRR_TIMEOUT:
1683 aName = "TRR_TIMEOUT"_ns;
1684 break;
1685 case TRRSkippedReason::TRR_CHANNEL_DNS_FAIL:
1686 aName = "TRR_CHANNEL_DNS_FAIL"_ns;
1687 break;
1688 case TRRSkippedReason::TRR_IS_OFFLINE:
1689 aName = "TRR_IS_OFFLINE"_ns;
1690 break;
1691 case TRRSkippedReason::TRR_NOT_CONFIRMED:
1692 aName = "TRR_NOT_CONFIRMED"_ns;
1693 break;
1694 case TRRSkippedReason::TRR_DID_NOT_MAKE_QUERY:
1695 aName = "TRR_DID_NOT_MAKE_QUERY"_ns;
1696 break;
1697 case TRRSkippedReason::TRR_UNKNOWN_CHANNEL_FAILURE:
1698 aName = "TRR_UNKNOWN_CHANNEL_FAILURE"_ns;
1699 break;
1700 case TRRSkippedReason::TRR_HOST_BLOCKED_TEMPORARY:
1701 aName = "TRR_HOST_BLOCKED_TEMPORARY"_ns;
1702 break;
1703 case TRRSkippedReason::TRR_SEND_FAILED:
1704 aName = "TRR_SEND_FAILED"_ns;
1705 break;
1706 case TRRSkippedReason::TRR_NET_RESET:
1707 aName = "TRR_NET_RESET"_ns;
1708 break;
1709 case TRRSkippedReason::TRR_NET_TIMEOUT:
1710 aName = "TRR_NET_TIMEOUT"_ns;
1711 break;
1712 case TRRSkippedReason::TRR_NET_REFUSED:
1713 aName = "TRR_NET_REFUSED"_ns;
1714 break;
1715 case TRRSkippedReason::TRR_NET_INTERRUPT:
1716 aName = "TRR_NET_INTERRUPT"_ns;
1717 break;
1718 case TRRSkippedReason::TRR_NET_INADEQ_SEQURITY:
1719 aName = "TRR_NET_INADEQ_SEQURITY"_ns;
1720 break;
1721 case TRRSkippedReason::TRR_NO_ANSWERS:
1722 aName = "TRR_NO_ANSWERS"_ns;
1723 break;
1724 case TRRSkippedReason::TRR_DECODE_FAILED:
1725 aName = "TRR_DECODE_FAILED"_ns;
1726 break;
1727 case TRRSkippedReason::TRR_EXCLUDED:
1728 aName = "TRR_EXCLUDED"_ns;
1729 break;
1730 case TRRSkippedReason::TRR_SERVER_RESPONSE_ERR:
1731 aName = "TRR_SERVER_RESPONSE_ERR"_ns;
1732 break;
1733 case TRRSkippedReason::TRR_RCODE_FAIL:
1734 aName = "TRR_RCODE_FAIL"_ns;
1735 break;
1736 case TRRSkippedReason::TRR_NO_CONNECTIVITY:
1737 aName = "TRR_NO_CONNECTIVITY"_ns;
1738 break;
1739 case TRRSkippedReason::TRR_NXDOMAIN:
1740 aName = "TRR_NXDOMAIN"_ns;
1741 break;
1742 case TRRSkippedReason::TRR_REQ_CANCELLED:
1743 aName = "TRR_REQ_CANCELLED"_ns;
1744 break;
1745 case TRRSkippedReason::ODOH_KEY_NOT_USABLE:
1746 aName = "ODOH_KEY_NOT_USABLE"_ns;
1747 break;
1748 case TRRSkippedReason::ODOH_UPDATE_KEY_FAILED:
1749 aName = "ODOH_UPDATE_KEY_FAILED"_ns;
1750 break;
1751 case TRRSkippedReason::ODOH_KEY_NOT_AVAILABLE:
1752 aName = "ODOH_KEY_NOT_AVAILABLE"_ns;
1753 break;
1754 case TRRSkippedReason::ODOH_ENCRYPTION_FAILED:
1755 aName = "ODOH_ENCRYPTION_FAILED"_ns;
1756 break;
1757 case TRRSkippedReason::ODOH_DECRYPTION_FAILED:
1758 aName = "ODOH_DECRYPTION_FAILED"_ns;
1759 break;
1760 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH:
1761 aName = "TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH"_ns;
1762 break;
1763 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH:
1764 aName = "TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH"_ns;
1765 break;
1766 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY:
1767 aName = "TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY"_ns;
1768 break;
1769 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_CANARY:
1770 aName = "TRR_HEURISTIC_TRIPPED_CANARY"_ns;
1771 break;
1772 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS:
1773 aName = "TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS"_ns;
1774 break;
1775 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS:
1776 aName = "TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS"_ns;
1777 break;
1778 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS:
1779 aName = "TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS"_ns;
1780 break;
1781 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY:
1782 aName = "TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY"_ns;
1783 break;
1784 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_VPN:
1785 aName = "TRR_HEURISTIC_TRIPPED_VPN"_ns;
1786 break;
1787 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_PROXY:
1788 aName = "TRR_HEURISTIC_TRIPPED_PROXY"_ns;
1789 break;
1790 case TRRSkippedReason::TRR_HEURISTIC_TRIPPED_NRPT:
1791 aName = "TRR_HEURISTIC_TRIPPED_NRPT"_ns;
1792 break;
1793 case TRRSkippedReason::TRR_BAD_URL:
1794 aName = "TRR_BAD_URL"_ns;
1795 break;
1796 default:
1797 MOZ_ASSERT(false, "Unknown value");
1800 return NS_OK;
1802 } // namespace mozilla::net