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 return NS_ERROR_UNKNOWN_HOST
;
113 if (mDisablePrefetch
&& (flags
& RESOLVE_SPECULATE
)) {
114 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL
;
117 // We need original listener for the pending requests hash.
118 uintptr_t originalListenerAddr
= reinterpret_cast<uintptr_t>(listener
);
120 // make sure JS callers get notification on the main thread
121 nsCOMPtr
<nsIEventTarget
> target
= target_
;
122 nsCOMPtr
<nsIXPConnectWrappedJS
> wrappedListener
= do_QueryInterface(listener
);
123 if (wrappedListener
&& !target
) {
124 target
= GetMainThreadSerialEventTarget();
127 // Guarantee listener freed on main thread. Not sure we need this in child
128 // (or in parent in nsDNSService.cpp) but doesn't hurt.
129 listener
= new DNSListenerProxy(listener
, target
);
132 RefPtr
<DNSRequestSender
> sender
= new DNSRequestSender(
133 hostname
, DNSAdditionalInfo::URL(aInfo
), DNSAdditionalInfo::Port(aInfo
),
134 type
, aOriginAttributes
, flags
, listener
, target
);
135 RefPtr
<DNSRequestActor
> dnsReq
;
136 if (resolveDNSInSocketProcess
) {
137 dnsReq
= new DNSRequestParent(sender
);
138 if (!mTRRServiceParent
->TRRConnectionInfoInited()) {
139 mTRRServiceParent
->InitTRRConnectionInfo();
142 dnsReq
= new DNSRequestChild(sender
);
146 MutexAutoLock
lock(mPendingRequestsLock
);
148 GetDNSRecordHashKey(hostname
, DNSAdditionalInfo::URL(aInfo
),
149 DNSAdditionalInfo::Port(aInfo
), type
, aOriginAttributes
,
150 flags
, originalListenerAddr
, key
);
151 mPendingRequests
.GetOrInsertNew(key
)->AppendElement(sender
);
154 sender
->StartRequest();
156 sender
.forget(result
);
160 nsresult
ChildDNSService::CancelAsyncResolveInternal(
161 const nsACString
& aHostname
, uint16_t aType
, nsIDNSService::DNSFlags aFlags
,
162 nsIDNSAdditionalInfo
* aInfo
, nsIDNSListener
* aListener
, nsresult aReason
,
163 const OriginAttributes
& aOriginAttributes
) {
164 if (mDisablePrefetch
&& (aFlags
& RESOLVE_SPECULATE
)) {
165 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL
;
168 MutexAutoLock
lock(mPendingRequestsLock
);
169 nsTArray
<RefPtr
<DNSRequestSender
>>* hashEntry
;
171 uintptr_t listenerAddr
= reinterpret_cast<uintptr_t>(aListener
);
172 GetDNSRecordHashKey(aHostname
, DNSAdditionalInfo::URL(aInfo
),
173 DNSAdditionalInfo::Port(aInfo
), aType
, aOriginAttributes
,
174 aFlags
, listenerAddr
, key
);
175 if (mPendingRequests
.Get(key
, &hashEntry
)) {
176 // We cancel just one.
177 hashEntry
->ElementAt(0)->Cancel(aReason
);
183 //-----------------------------------------------------------------------------
184 // ChildDNSService::nsIDNSService
185 //-----------------------------------------------------------------------------
188 ChildDNSService::AsyncResolve(const nsACString
& hostname
,
189 nsIDNSService::ResolveType aType
,
190 nsIDNSService::DNSFlags flags
,
191 nsIDNSAdditionalInfo
* aInfo
,
192 nsIDNSListener
* listener
, nsIEventTarget
* target_
,
193 JS::Handle
<JS::Value
> aOriginAttributes
,
194 JSContext
* aCx
, uint8_t aArgc
,
195 nsICancelable
** result
) {
196 OriginAttributes attrs
;
199 if (!aOriginAttributes
.isObject() || !attrs
.Init(aCx
, aOriginAttributes
)) {
200 return NS_ERROR_INVALID_ARG
;
204 return AsyncResolveInternal(hostname
, aType
, flags
, aInfo
, listener
, target_
,
209 ChildDNSService::AsyncResolveNative(
210 const nsACString
& hostname
, nsIDNSService::ResolveType aType
,
211 nsIDNSService::DNSFlags flags
, nsIDNSAdditionalInfo
* aInfo
,
212 nsIDNSListener
* listener
, nsIEventTarget
* target_
,
213 const OriginAttributes
& aOriginAttributes
, nsICancelable
** result
) {
214 return AsyncResolveInternal(hostname
, aType
, flags
, aInfo
, listener
, target_
,
215 aOriginAttributes
, result
);
219 ChildDNSService::NewAdditionalInfo(const nsACString
& aTrrURL
, int32_t aPort
,
220 nsIDNSAdditionalInfo
** aInfo
) {
221 RefPtr
<DNSAdditionalInfo
> res
= new DNSAdditionalInfo(aTrrURL
, aPort
);
227 ChildDNSService::CancelAsyncResolve(const nsACString
& aHostname
,
228 nsIDNSService::ResolveType aType
,
229 nsIDNSService::DNSFlags aFlags
,
230 nsIDNSAdditionalInfo
* aInfo
,
231 nsIDNSListener
* aListener
, nsresult aReason
,
232 JS::Handle
<JS::Value
> aOriginAttributes
,
233 JSContext
* aCx
, uint8_t aArgc
) {
234 OriginAttributes attrs
;
237 if (!aOriginAttributes
.isObject() || !attrs
.Init(aCx
, aOriginAttributes
)) {
238 return NS_ERROR_INVALID_ARG
;
242 return CancelAsyncResolveInternal(aHostname
, aType
, aFlags
, aInfo
, aListener
,
247 ChildDNSService::CancelAsyncResolveNative(
248 const nsACString
& aHostname
, nsIDNSService::ResolveType aType
,
249 nsIDNSService::DNSFlags aFlags
, nsIDNSAdditionalInfo
* aInfo
,
250 nsIDNSListener
* aListener
, nsresult aReason
,
251 const OriginAttributes
& aOriginAttributes
) {
252 return CancelAsyncResolveInternal(aHostname
, aType
, aFlags
, aInfo
, aListener
,
253 aReason
, aOriginAttributes
);
257 ChildDNSService::Resolve(const nsACString
& hostname
,
258 nsIDNSService::DNSFlags flags
,
259 JS::Handle
<JS::Value
> aOriginAttributes
,
260 JSContext
* aCx
, uint8_t aArgc
, nsIDNSRecord
** result
) {
261 // not planning to ever support this, since sync IPDL is evil.
262 return NS_ERROR_NOT_AVAILABLE
;
266 ChildDNSService::ResolveNative(const nsACString
& hostname
,
267 nsIDNSService::DNSFlags flags
,
268 const OriginAttributes
& aOriginAttributes
,
269 nsIDNSRecord
** result
) {
270 // not planning to ever support this, since sync IPDL is evil.
271 return NS_ERROR_NOT_AVAILABLE
;
275 ChildDNSService::GetDNSCacheEntries(
276 nsTArray
<mozilla::net::DNSCacheEntries
>* args
) {
277 // Only used by networking dashboard, so may not ever need this in child.
278 // (and would provide a way to spy on what hosts other apps are connecting to,
279 // unless we start keeping per-app DNS caches).
280 return NS_ERROR_NOT_AVAILABLE
;
284 ChildDNSService::ClearCache(bool aTrrToo
) {
285 if (!mTRRServiceParent
|| !mTRRServiceParent
->CanSend()) {
286 return NS_ERROR_NOT_AVAILABLE
;
289 Unused
<< mTRRServiceParent
->SendClearDNSCache(aTrrToo
);
294 ChildDNSService::ReloadParentalControlEnabled() {
295 if (!mTRRServiceParent
) {
296 return NS_ERROR_NOT_AVAILABLE
;
299 mTRRServiceParent
->UpdateParentalControlEnabled();
304 ChildDNSService::SetDetectedTrrURI(const nsACString
& aURI
) {
305 if (!mTRRServiceParent
) {
306 return NS_ERROR_NOT_AVAILABLE
;
309 mTRRServiceParent
->SetDetectedTrrURI(aURI
);
314 ChildDNSService::SetHeuristicDetectionResult(nsITRRSkipReason::value aValue
) {
315 return NS_ERROR_NOT_IMPLEMENTED
;
319 ChildDNSService::GetHeuristicDetectionResult(nsITRRSkipReason::value
* aValue
) {
320 return NS_ERROR_NOT_IMPLEMENTED
;
324 ChildDNSService::GetTRRSkipReasonName(nsITRRSkipReason::value aValue
,
326 return mozilla::net::GetTRRSkipReasonName(aValue
, aName
);
330 ChildDNSService::GetCurrentTrrURI(nsACString
& aURI
) {
331 if (!mTRRServiceParent
) {
332 return NS_ERROR_NOT_AVAILABLE
;
335 mTRRServiceParent
->GetURI(aURI
);
340 ChildDNSService::GetCurrentTrrMode(nsIDNSService::ResolverMode
* aMode
) {
341 if (XRE_IsContentProcess()) {
345 if (!mTRRServiceParent
) {
346 return NS_ERROR_NOT_AVAILABLE
;
349 *aMode
= mTRRServiceParent
->Mode();
353 void ChildDNSService::SetTRRModeInChild(
354 nsIDNSService::ResolverMode mode
,
355 nsIDNSService::ResolverMode modeFromPref
) {
356 if (!XRE_IsContentProcess()) {
357 MOZ_ASSERT(false, "Why are we calling this?");
361 TRRService::SetCurrentTRRMode(modeFromPref
);
365 ChildDNSService::GetCurrentTrrConfirmationState(uint32_t* aConfirmationState
) {
366 if (!mTRRServiceParent
) {
367 return NS_ERROR_NOT_AVAILABLE
;
370 *aConfirmationState
= mTRRServiceParent
->GetConfirmationState();
375 ChildDNSService::GetMyHostName(nsACString
& result
) {
376 if (XRE_IsParentProcess()) {
378 if (PR_GetSystemInfo(PR_SI_HOSTNAME
, name
, sizeof(name
)) == PR_SUCCESS
) {
383 return NS_ERROR_FAILURE
;
385 // TODO: get value from parent during PNecko construction?
386 return NS_ERROR_NOT_AVAILABLE
;
389 void ChildDNSService::NotifyRequestDone(DNSRequestSender
* aDnsRequest
) {
390 // We need the original flags and listener for the pending requests hash.
391 nsIDNSService::DNSFlags originalFlags
=
392 aDnsRequest
->mFlags
& ~RESOLVE_OFFLINE
;
393 uintptr_t originalListenerAddr
=
394 reinterpret_cast<uintptr_t>(aDnsRequest
->mListener
.get());
395 RefPtr
<DNSListenerProxy
> wrapper
= do_QueryObject(aDnsRequest
->mListener
);
397 originalListenerAddr
= wrapper
->GetOriginalListenerAddress();
400 MutexAutoLock
lock(mPendingRequestsLock
);
403 GetDNSRecordHashKey(aDnsRequest
->mHost
, aDnsRequest
->mTrrServer
,
404 aDnsRequest
->mPort
, aDnsRequest
->mType
,
405 aDnsRequest
->mOriginAttributes
, originalFlags
,
406 originalListenerAddr
, key
);
408 nsTArray
<RefPtr
<DNSRequestSender
>>* hashEntry
;
410 if (mPendingRequests
.Get(key
, &hashEntry
)) {
411 auto idx
= hashEntry
->IndexOf(aDnsRequest
);
412 if (idx
!= nsTArray
<RefPtr
<DNSRequestSender
>>::NoIndex
) {
413 hashEntry
->RemoveElementAt(idx
);
414 if (hashEntry
->IsEmpty()) {
415 mPendingRequests
.Remove(key
);
421 //-----------------------------------------------------------------------------
422 // ChildDNSService::nsPIDNSService
423 //-----------------------------------------------------------------------------
425 nsresult
ChildDNSService::Init() {
428 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
430 AddPrefObserver(prefs
);
436 nsresult
ChildDNSService::Shutdown() { return NS_OK
; }
439 ChildDNSService::GetPrefetchEnabled(bool* outVal
) {
440 *outVal
= !mDisablePrefetch
;
445 ChildDNSService::SetPrefetchEnabled(bool inVal
) {
446 mDisablePrefetch
= !inVal
;
451 ChildDNSService::ReportFailedSVCDomainName(const nsACString
& aOwnerName
,
452 const nsACString
& aSVCDomainName
) {
453 return NS_ERROR_NOT_IMPLEMENTED
;
457 ChildDNSService::IsSVCDomainNameFailed(const nsACString
& aOwnerName
,
458 const nsACString
& aSVCDomainName
,
460 return NS_ERROR_NOT_IMPLEMENTED
;
464 ChildDNSService::ResetExcludedSVCDomainName(const nsACString
& aOwnerName
) {
465 return NS_ERROR_NOT_IMPLEMENTED
;
468 //-----------------------------------------------------------------------------
469 // ChildDNSService::nsIObserver
470 //-----------------------------------------------------------------------------
473 ChildDNSService::Observe(nsISupports
* subject
, const char* topic
,
474 const char16_t
* data
) {
475 if (!strcmp(topic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
)) {
477 ReadPrefs(NS_ConvertUTF16toUTF8(data
).get());
482 void ChildDNSService::SetTRRDomain(const nsACString
& aTRRDomain
) {
483 mTRRDomain
= aTRRDomain
;
484 TRRService::SetProviderDomain(aTRRDomain
);
487 nsresult
ChildDNSService::GetTRRDomainKey(nsACString
& aTRRDomain
) {
488 aTRRDomain
= TRRService::ProviderKey();
493 ChildDNSService::GetTrrDomain(nsACString
& aTRRDomain
) {
494 aTRRDomain
= mTRRDomain
;
499 ChildDNSService::GetLastConfirmationStatus(nsresult
* aConfirmationStatus
) {
500 // XXX(valentin): Fix for socket process
501 *aConfirmationStatus
= NS_OK
;
505 NS_IMETHODIMP
ChildDNSService::GetLastConfirmationSkipReason(
506 TRRSkippedReason
* aSkipReason
) {
507 // XXX(valentin): Fix for socket process
508 *aSkipReason
= nsITRRSkipReason::TRR_UNSET
;
513 } // namespace mozilla