1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/net/ChildDNSService.h"
6 #include "nsDNSPrefetch.h"
7 #include "nsIDNSListener.h"
8 #include "nsIOService.h"
9 #include "nsThreadUtils.h"
10 #include "nsIXPConnect.h"
11 #include "nsIProtocolProxyService.h"
13 #include "nsQueryObject.h"
14 #include "mozilla/ClearOnShutdown.h"
15 #include "mozilla/StaticPrefs_network.h"
16 #include "mozilla/StaticPtr.h"
17 #include "mozilla/SyncRunnable.h"
18 #include "mozilla/net/NeckoChild.h"
19 #include "mozilla/net/DNSListenerProxy.h"
20 #include "mozilla/net/TRRServiceParent.h"
21 #include "nsHostResolver.h"
22 #include "nsServiceManagerUtils.h"
24 #include "DNSAdditionalInfo.h"
25 #include "TRRService.h"
30 //-----------------------------------------------------------------------------
32 //-----------------------------------------------------------------------------
34 static StaticRefPtr
<ChildDNSService
> gChildDNSService
;
36 already_AddRefed
<ChildDNSService
> ChildDNSService::GetSingleton() {
37 MOZ_ASSERT_IF(nsIOService::UseSocketProcess(),
38 XRE_IsContentProcess() || XRE_IsParentProcess());
39 MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(),
40 XRE_IsContentProcess() || XRE_IsSocketProcess());
42 if (!gChildDNSService
) {
43 if (NS_WARN_IF(!NS_IsMainThread())) {
46 gChildDNSService
= new ChildDNSService();
47 gChildDNSService
->Init();
48 ClearOnShutdown(&gChildDNSService
);
51 return do_AddRef(gChildDNSService
);
54 NS_IMPL_ISUPPORTS_INHERITED(ChildDNSService
, DNSServiceBase
, nsIDNSService
,
57 ChildDNSService::ChildDNSService() {
58 MOZ_ASSERT_IF(nsIOService::UseSocketProcess(),
59 XRE_IsContentProcess() || XRE_IsParentProcess());
60 MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(),
61 XRE_IsContentProcess() || XRE_IsSocketProcess());
62 if (XRE_IsParentProcess() && nsIOService::UseSocketProcess()) {
63 nsDNSPrefetch::Initialize(this);
64 mTRRServiceParent
= new TRRServiceParent();
65 mTRRServiceParent
->Init();
69 void ChildDNSService::GetDNSRecordHashKey(
70 const nsACString
& aHost
, const nsACString
& aTrrServer
, int32_t aPort
,
71 uint16_t aType
, const OriginAttributes
& aOriginAttributes
,
72 nsIDNSService::DNSFlags aFlags
, uintptr_t aListenerAddr
,
73 nsACString
& aHashKey
) {
74 aHashKey
.Assign(aHost
);
75 aHashKey
.Assign(aTrrServer
);
76 aHashKey
.AppendInt(aPort
);
77 aHashKey
.AppendInt(aType
);
79 nsAutoCString originSuffix
;
80 aOriginAttributes
.CreateSuffix(originSuffix
);
81 aHashKey
.Append(originSuffix
);
83 aHashKey
.AppendInt(aFlags
);
84 aHashKey
.AppendPrintf("0x%" PRIxPTR
, aListenerAddr
);
87 nsresult
ChildDNSService::AsyncResolveInternal(
88 const nsACString
& hostname
, uint16_t type
, nsIDNSService::DNSFlags flags
,
89 nsIDNSAdditionalInfo
* aInfo
, nsIDNSListener
* listener
,
90 nsIEventTarget
* target_
, const OriginAttributes
& aOriginAttributes
,
91 nsICancelable
** result
) {
92 if (XRE_IsContentProcess()) {
93 NS_ENSURE_TRUE(gNeckoChild
!= nullptr, NS_ERROR_FAILURE
);
96 if (DNSForbiddenByActiveProxy(hostname
, flags
)) {
97 // nsHostResolver returns NS_ERROR_UNKNOWN_HOST for lots of reasons.
98 // We use a different error code to differentiate this failure and to make
99 // it clear(er) where this error comes from.
100 return NS_ERROR_UNKNOWN_PROXY_HOST
;
103 bool resolveDNSInSocketProcess
= false;
104 if (XRE_IsParentProcess() && nsIOService::UseSocketProcess()) {
105 resolveDNSInSocketProcess
= true;
106 if (type
!= nsIDNSService::RESOLVE_TYPE_DEFAULT
&&
107 (mTRRServiceParent
->Mode() != nsIDNSService::MODE_TRRFIRST
&&
108 mTRRServiceParent
->Mode() != nsIDNSService::MODE_TRRONLY
) &&
109 !StaticPrefs::network_dns_native_https_query()) {
110 return NS_ERROR_UNKNOWN_HOST
;
114 if (mDisablePrefetch
&& (flags
& RESOLVE_SPECULATE
)) {
115 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL
;
118 // We need original listener for the pending requests hash.
119 uintptr_t originalListenerAddr
= reinterpret_cast<uintptr_t>(listener
);
121 // make sure JS callers get notification on the main thread
122 nsCOMPtr
<nsIEventTarget
> target
= target_
;
123 nsCOMPtr
<nsIXPConnectWrappedJS
> wrappedListener
= do_QueryInterface(listener
);
124 if (wrappedListener
&& !target
) {
125 target
= GetMainThreadSerialEventTarget();
128 // Guarantee listener freed on main thread. Not sure we need this in child
129 // (or in parent in nsDNSService.cpp) but doesn't hurt.
130 listener
= new DNSListenerProxy(listener
, target
);
133 RefPtr
<DNSRequestSender
> sender
= new DNSRequestSender(
134 hostname
, DNSAdditionalInfo::URL(aInfo
), DNSAdditionalInfo::Port(aInfo
),
135 type
, aOriginAttributes
, flags
, listener
, target
);
136 RefPtr
<DNSRequestActor
> dnsReq
;
137 if (resolveDNSInSocketProcess
) {
138 dnsReq
= new DNSRequestParent(sender
);
139 if (!mTRRServiceParent
->TRRConnectionInfoInited()) {
140 mTRRServiceParent
->InitTRRConnectionInfo();
143 dnsReq
= new DNSRequestChild(sender
);
147 MutexAutoLock
lock(mPendingRequestsLock
);
149 GetDNSRecordHashKey(hostname
, DNSAdditionalInfo::URL(aInfo
),
150 DNSAdditionalInfo::Port(aInfo
), type
, aOriginAttributes
,
151 flags
, originalListenerAddr
, key
);
152 mPendingRequests
.GetOrInsertNew(key
)->AppendElement(sender
);
155 sender
->StartRequest();
157 sender
.forget(result
);
161 nsresult
ChildDNSService::CancelAsyncResolveInternal(
162 const nsACString
& aHostname
, uint16_t aType
, nsIDNSService::DNSFlags aFlags
,
163 nsIDNSAdditionalInfo
* aInfo
, nsIDNSListener
* aListener
, nsresult aReason
,
164 const OriginAttributes
& aOriginAttributes
) {
165 if (mDisablePrefetch
&& (aFlags
& RESOLVE_SPECULATE
)) {
166 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL
;
169 MutexAutoLock
lock(mPendingRequestsLock
);
170 nsTArray
<RefPtr
<DNSRequestSender
>>* hashEntry
;
172 uintptr_t listenerAddr
= reinterpret_cast<uintptr_t>(aListener
);
173 GetDNSRecordHashKey(aHostname
, DNSAdditionalInfo::URL(aInfo
),
174 DNSAdditionalInfo::Port(aInfo
), aType
, aOriginAttributes
,
175 aFlags
, listenerAddr
, key
);
176 if (mPendingRequests
.Get(key
, &hashEntry
)) {
177 // We cancel just one.
178 hashEntry
->ElementAt(0)->Cancel(aReason
);
184 //-----------------------------------------------------------------------------
185 // ChildDNSService::nsIDNSService
186 //-----------------------------------------------------------------------------
189 ChildDNSService::AsyncResolve(const nsACString
& hostname
,
190 nsIDNSService::ResolveType aType
,
191 nsIDNSService::DNSFlags flags
,
192 nsIDNSAdditionalInfo
* aInfo
,
193 nsIDNSListener
* listener
, nsIEventTarget
* target_
,
194 JS::Handle
<JS::Value
> aOriginAttributes
,
195 JSContext
* aCx
, uint8_t aArgc
,
196 nsICancelable
** result
) {
197 OriginAttributes attrs
;
200 if (!aOriginAttributes
.isObject() || !attrs
.Init(aCx
, aOriginAttributes
)) {
201 return NS_ERROR_INVALID_ARG
;
205 return AsyncResolveInternal(hostname
, aType
, flags
, aInfo
, listener
, target_
,
210 ChildDNSService::AsyncResolveNative(
211 const nsACString
& hostname
, nsIDNSService::ResolveType aType
,
212 nsIDNSService::DNSFlags flags
, nsIDNSAdditionalInfo
* aInfo
,
213 nsIDNSListener
* listener
, nsIEventTarget
* target_
,
214 const OriginAttributes
& aOriginAttributes
, nsICancelable
** result
) {
215 return AsyncResolveInternal(hostname
, aType
, flags
, aInfo
, listener
, target_
,
216 aOriginAttributes
, result
);
220 ChildDNSService::NewAdditionalInfo(const nsACString
& aTrrURL
, int32_t aPort
,
221 nsIDNSAdditionalInfo
** aInfo
) {
222 RefPtr
<DNSAdditionalInfo
> res
= new DNSAdditionalInfo(aTrrURL
, aPort
);
228 ChildDNSService::CancelAsyncResolve(const nsACString
& aHostname
,
229 nsIDNSService::ResolveType aType
,
230 nsIDNSService::DNSFlags aFlags
,
231 nsIDNSAdditionalInfo
* aInfo
,
232 nsIDNSListener
* aListener
, nsresult aReason
,
233 JS::Handle
<JS::Value
> aOriginAttributes
,
234 JSContext
* aCx
, uint8_t aArgc
) {
235 OriginAttributes attrs
;
238 if (!aOriginAttributes
.isObject() || !attrs
.Init(aCx
, aOriginAttributes
)) {
239 return NS_ERROR_INVALID_ARG
;
243 return CancelAsyncResolveInternal(aHostname
, aType
, aFlags
, aInfo
, aListener
,
248 ChildDNSService::CancelAsyncResolveNative(
249 const nsACString
& aHostname
, nsIDNSService::ResolveType aType
,
250 nsIDNSService::DNSFlags aFlags
, nsIDNSAdditionalInfo
* aInfo
,
251 nsIDNSListener
* aListener
, nsresult aReason
,
252 const OriginAttributes
& aOriginAttributes
) {
253 return CancelAsyncResolveInternal(aHostname
, aType
, aFlags
, aInfo
, aListener
,
254 aReason
, aOriginAttributes
);
258 ChildDNSService::Resolve(const nsACString
& hostname
,
259 nsIDNSService::DNSFlags flags
,
260 JS::Handle
<JS::Value
> aOriginAttributes
,
261 JSContext
* aCx
, uint8_t aArgc
, nsIDNSRecord
** result
) {
262 // not planning to ever support this, since sync IPDL is evil.
263 return NS_ERROR_NOT_AVAILABLE
;
267 ChildDNSService::ResolveNative(const nsACString
& hostname
,
268 nsIDNSService::DNSFlags flags
,
269 const OriginAttributes
& aOriginAttributes
,
270 nsIDNSRecord
** result
) {
271 // not planning to ever support this, since sync IPDL is evil.
272 return NS_ERROR_NOT_AVAILABLE
;
276 ChildDNSService::GetDNSCacheEntries(
277 nsTArray
<mozilla::net::DNSCacheEntries
>* args
) {
278 // Only used by networking dashboard, so may not ever need this in child.
279 // (and would provide a way to spy on what hosts other apps are connecting to,
280 // unless we start keeping per-app DNS caches).
281 return NS_ERROR_NOT_AVAILABLE
;
285 ChildDNSService::ClearCache(bool aTrrToo
) {
286 if (!mTRRServiceParent
|| !mTRRServiceParent
->CanSend()) {
287 return NS_ERROR_NOT_AVAILABLE
;
290 Unused
<< mTRRServiceParent
->SendClearDNSCache(aTrrToo
);
295 ChildDNSService::ReloadParentalControlEnabled() {
296 if (!mTRRServiceParent
) {
297 return NS_ERROR_NOT_AVAILABLE
;
300 mTRRServiceParent
->UpdateParentalControlEnabled();
305 ChildDNSService::SetDetectedTrrURI(const nsACString
& aURI
) {
306 if (!mTRRServiceParent
) {
307 return NS_ERROR_NOT_AVAILABLE
;
310 mTRRServiceParent
->SetDetectedTrrURI(aURI
);
315 ChildDNSService::SetHeuristicDetectionResult(nsITRRSkipReason::value aValue
) {
316 return NS_ERROR_NOT_IMPLEMENTED
;
320 ChildDNSService::GetHeuristicDetectionResult(nsITRRSkipReason::value
* aValue
) {
321 return NS_ERROR_NOT_IMPLEMENTED
;
325 ChildDNSService::GetTRRSkipReasonName(nsITRRSkipReason::value aValue
,
327 return mozilla::net::GetTRRSkipReasonName(aValue
, aName
);
331 ChildDNSService::GetCurrentTrrURI(nsACString
& aURI
) {
332 if (!mTRRServiceParent
) {
333 return NS_ERROR_NOT_AVAILABLE
;
336 mTRRServiceParent
->GetURI(aURI
);
341 ChildDNSService::GetCurrentTrrMode(nsIDNSService::ResolverMode
* aMode
) {
342 if (XRE_IsContentProcess()) {
346 if (!mTRRServiceParent
) {
347 return NS_ERROR_NOT_AVAILABLE
;
350 *aMode
= mTRRServiceParent
->Mode();
354 void ChildDNSService::SetTRRModeInChild(
355 nsIDNSService::ResolverMode mode
,
356 nsIDNSService::ResolverMode modeFromPref
) {
357 if (!XRE_IsContentProcess()) {
358 MOZ_ASSERT(false, "Why are we calling this?");
362 TRRService::SetCurrentTRRMode(modeFromPref
);
366 ChildDNSService::GetCurrentTrrConfirmationState(uint32_t* aConfirmationState
) {
367 if (!mTRRServiceParent
) {
368 return NS_ERROR_NOT_AVAILABLE
;
371 *aConfirmationState
= mTRRServiceParent
->GetConfirmationState();
376 ChildDNSService::GetMyHostName(nsACString
& result
) {
377 if (XRE_IsParentProcess()) {
379 if (PR_GetSystemInfo(PR_SI_HOSTNAME
, name
, sizeof(name
)) == PR_SUCCESS
) {
384 return NS_ERROR_FAILURE
;
386 // TODO: get value from parent during PNecko construction?
387 return NS_ERROR_NOT_AVAILABLE
;
390 void ChildDNSService::NotifyRequestDone(DNSRequestSender
* aDnsRequest
) {
391 // We need the original flags and listener for the pending requests hash.
392 nsIDNSService::DNSFlags originalFlags
=
393 aDnsRequest
->mFlags
& ~RESOLVE_OFFLINE
;
394 uintptr_t originalListenerAddr
=
395 reinterpret_cast<uintptr_t>(aDnsRequest
->mListener
.get());
396 RefPtr
<DNSListenerProxy
> wrapper
= do_QueryObject(aDnsRequest
->mListener
);
398 originalListenerAddr
= wrapper
->GetOriginalListenerAddress();
401 MutexAutoLock
lock(mPendingRequestsLock
);
404 GetDNSRecordHashKey(aDnsRequest
->mHost
, aDnsRequest
->mTrrServer
,
405 aDnsRequest
->mPort
, aDnsRequest
->mType
,
406 aDnsRequest
->mOriginAttributes
, originalFlags
,
407 originalListenerAddr
, key
);
409 nsTArray
<RefPtr
<DNSRequestSender
>>* hashEntry
;
411 if (mPendingRequests
.Get(key
, &hashEntry
)) {
412 auto idx
= hashEntry
->IndexOf(aDnsRequest
);
413 if (idx
!= nsTArray
<RefPtr
<DNSRequestSender
>>::NoIndex
) {
414 hashEntry
->RemoveElementAt(idx
);
415 if (hashEntry
->IsEmpty()) {
416 mPendingRequests
.Remove(key
);
422 //-----------------------------------------------------------------------------
423 // ChildDNSService::nsPIDNSService
424 //-----------------------------------------------------------------------------
426 nsresult
ChildDNSService::Init() {
429 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
431 AddPrefObserver(prefs
);
437 nsresult
ChildDNSService::Shutdown() { return NS_OK
; }
440 ChildDNSService::GetPrefetchEnabled(bool* outVal
) {
441 *outVal
= !mDisablePrefetch
;
446 ChildDNSService::SetPrefetchEnabled(bool inVal
) {
447 mDisablePrefetch
= !inVal
;
452 ChildDNSService::ReportFailedSVCDomainName(const nsACString
& aOwnerName
,
453 const nsACString
& aSVCDomainName
) {
454 return NS_ERROR_NOT_IMPLEMENTED
;
458 ChildDNSService::IsSVCDomainNameFailed(const nsACString
& aOwnerName
,
459 const nsACString
& aSVCDomainName
,
461 return NS_ERROR_NOT_IMPLEMENTED
;
465 ChildDNSService::ResetExcludedSVCDomainName(const nsACString
& aOwnerName
) {
466 return NS_ERROR_NOT_IMPLEMENTED
;
469 //-----------------------------------------------------------------------------
470 // ChildDNSService::nsIObserver
471 //-----------------------------------------------------------------------------
474 ChildDNSService::Observe(nsISupports
* subject
, const char* topic
,
475 const char16_t
* data
) {
476 if (!strcmp(topic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
)) {
478 ReadPrefs(NS_ConvertUTF16toUTF8(data
).get());
483 void ChildDNSService::SetTRRDomain(const nsACString
& aTRRDomain
) {
484 mTRRDomain
= aTRRDomain
;
485 TRRService::SetProviderDomain(aTRRDomain
);
488 nsresult
ChildDNSService::GetTRRDomainKey(nsACString
& aTRRDomain
) {
489 aTRRDomain
= TRRService::ProviderKey();
494 ChildDNSService::GetTrrDomain(nsACString
& aTRRDomain
) {
495 aTRRDomain
= mTRRDomain
;
500 ChildDNSService::GetLastConfirmationStatus(nsresult
* aConfirmationStatus
) {
501 // XXX(valentin): Fix for socket process
502 *aConfirmationStatus
= NS_OK
;
506 NS_IMETHODIMP
ChildDNSService::GetLastConfirmationSkipReason(
507 TRRSkippedReason
* aSkipReason
) {
508 // XXX(valentin): Fix for socket process
509 *aSkipReason
= nsITRRSkipReason::TRR_UNSET
;
514 } // namespace mozilla