Bug 1887677: Correctly compute inClass predicate when validating unbound private...
[gecko.git] / netwerk / dns / ChildDNSService.cpp
blob653608ab01764f22b13897f41df4b5dbb87b6d47
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"
12 #include "nsNetCID.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"
23 #include "prsystem.h"
24 #include "DNSAdditionalInfo.h"
25 #include "TRRService.h"
27 namespace mozilla {
28 namespace net {
30 //-----------------------------------------------------------------------------
31 // ChildDNSService
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())) {
44 return nullptr;
46 gChildDNSService = new ChildDNSService();
47 gChildDNSService->Init();
48 ClearOnShutdown(&gChildDNSService);
51 return do_AddRef(gChildDNSService);
54 NS_IMPL_ISUPPORTS_INHERITED(ChildDNSService, DNSServiceBase, nsIDNSService,
55 nsPIDNSService)
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();
127 if (target) {
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();
142 } else {
143 dnsReq = new DNSRequestChild(sender);
147 MutexAutoLock lock(mPendingRequestsLock);
148 nsCString key;
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);
158 return NS_OK;
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;
171 nsCString key;
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);
181 return NS_OK;
184 //-----------------------------------------------------------------------------
185 // ChildDNSService::nsIDNSService
186 //-----------------------------------------------------------------------------
188 NS_IMETHODIMP
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;
199 if (aArgc == 1) {
200 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
201 return NS_ERROR_INVALID_ARG;
205 return AsyncResolveInternal(hostname, aType, flags, aInfo, listener, target_,
206 attrs, result);
209 NS_IMETHODIMP
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);
219 NS_IMETHODIMP
220 ChildDNSService::NewAdditionalInfo(const nsACString& aTrrURL, int32_t aPort,
221 nsIDNSAdditionalInfo** aInfo) {
222 RefPtr<DNSAdditionalInfo> res = new DNSAdditionalInfo(aTrrURL, aPort);
223 res.forget(aInfo);
224 return NS_OK;
227 NS_IMETHODIMP
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;
237 if (aArgc == 1) {
238 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
239 return NS_ERROR_INVALID_ARG;
243 return CancelAsyncResolveInternal(aHostname, aType, aFlags, aInfo, aListener,
244 aReason, attrs);
247 NS_IMETHODIMP
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);
257 NS_IMETHODIMP
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;
266 NS_IMETHODIMP
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;
275 NS_IMETHODIMP
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;
284 NS_IMETHODIMP
285 ChildDNSService::ClearCache(bool aTrrToo) {
286 if (!mTRRServiceParent || !mTRRServiceParent->CanSend()) {
287 return NS_ERROR_NOT_AVAILABLE;
290 Unused << mTRRServiceParent->SendClearDNSCache(aTrrToo);
291 return NS_OK;
294 NS_IMETHODIMP
295 ChildDNSService::ReloadParentalControlEnabled() {
296 if (!mTRRServiceParent) {
297 return NS_ERROR_NOT_AVAILABLE;
300 mTRRServiceParent->UpdateParentalControlEnabled();
301 return NS_OK;
304 NS_IMETHODIMP
305 ChildDNSService::SetDetectedTrrURI(const nsACString& aURI) {
306 if (!mTRRServiceParent) {
307 return NS_ERROR_NOT_AVAILABLE;
310 mTRRServiceParent->SetDetectedTrrURI(aURI);
311 return NS_OK;
314 NS_IMETHODIMP
315 ChildDNSService::SetHeuristicDetectionResult(nsITRRSkipReason::value aValue) {
316 return NS_ERROR_NOT_IMPLEMENTED;
319 NS_IMETHODIMP
320 ChildDNSService::GetHeuristicDetectionResult(nsITRRSkipReason::value* aValue) {
321 return NS_ERROR_NOT_IMPLEMENTED;
324 NS_IMETHODIMP
325 ChildDNSService::GetTRRSkipReasonName(nsITRRSkipReason::value aValue,
326 nsACString& aName) {
327 return mozilla::net::GetTRRSkipReasonName(aValue, aName);
330 NS_IMETHODIMP
331 ChildDNSService::GetCurrentTrrURI(nsACString& aURI) {
332 if (!mTRRServiceParent) {
333 return NS_ERROR_NOT_AVAILABLE;
336 mTRRServiceParent->GetURI(aURI);
337 return NS_OK;
340 NS_IMETHODIMP
341 ChildDNSService::GetCurrentTrrMode(nsIDNSService::ResolverMode* aMode) {
342 if (XRE_IsContentProcess()) {
343 *aMode = mTRRMode;
344 return NS_OK;
346 if (!mTRRServiceParent) {
347 return NS_ERROR_NOT_AVAILABLE;
350 *aMode = mTRRServiceParent->Mode();
351 return NS_OK;
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?");
359 return;
361 mTRRMode = mode;
362 TRRService::SetCurrentTRRMode(modeFromPref);
365 NS_IMETHODIMP
366 ChildDNSService::GetCurrentTrrConfirmationState(uint32_t* aConfirmationState) {
367 if (!mTRRServiceParent) {
368 return NS_ERROR_NOT_AVAILABLE;
371 *aConfirmationState = mTRRServiceParent->GetConfirmationState();
372 return NS_OK;
375 NS_IMETHODIMP
376 ChildDNSService::GetMyHostName(nsACString& result) {
377 if (XRE_IsParentProcess()) {
378 char name[100];
379 if (PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof(name)) == PR_SUCCESS) {
380 result = name;
381 return NS_OK;
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);
397 if (wrapper) {
398 originalListenerAddr = wrapper->GetOriginalListenerAddress();
401 MutexAutoLock lock(mPendingRequestsLock);
403 nsCString key;
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() {
427 ReadPrefs(nullptr);
429 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
430 if (prefs) {
431 AddPrefObserver(prefs);
434 return NS_OK;
437 nsresult ChildDNSService::Shutdown() { return NS_OK; }
439 NS_IMETHODIMP
440 ChildDNSService::GetPrefetchEnabled(bool* outVal) {
441 *outVal = !mDisablePrefetch;
442 return NS_OK;
445 NS_IMETHODIMP
446 ChildDNSService::SetPrefetchEnabled(bool inVal) {
447 mDisablePrefetch = !inVal;
448 return NS_OK;
451 NS_IMETHODIMP
452 ChildDNSService::ReportFailedSVCDomainName(const nsACString& aOwnerName,
453 const nsACString& aSVCDomainName) {
454 return NS_ERROR_NOT_IMPLEMENTED;
457 NS_IMETHODIMP
458 ChildDNSService::IsSVCDomainNameFailed(const nsACString& aOwnerName,
459 const nsACString& aSVCDomainName,
460 bool* aResult) {
461 return NS_ERROR_NOT_IMPLEMENTED;
464 NS_IMETHODIMP
465 ChildDNSService::ResetExcludedSVCDomainName(const nsACString& aOwnerName) {
466 return NS_ERROR_NOT_IMPLEMENTED;
469 //-----------------------------------------------------------------------------
470 // ChildDNSService::nsIObserver
471 //-----------------------------------------------------------------------------
473 NS_IMETHODIMP
474 ChildDNSService::Observe(nsISupports* subject, const char* topic,
475 const char16_t* data) {
476 if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
477 // Reread prefs
478 ReadPrefs(NS_ConvertUTF16toUTF8(data).get());
480 return NS_OK;
483 void ChildDNSService::SetTRRDomain(const nsACString& aTRRDomain) {
484 mTRRDomain = aTRRDomain;
485 TRRService::SetProviderDomain(aTRRDomain);
488 nsresult ChildDNSService::GetTRRDomainKey(nsACString& aTRRDomain) {
489 aTRRDomain = TRRService::ProviderKey();
490 return NS_OK;
493 NS_IMETHODIMP
494 ChildDNSService::GetTrrDomain(nsACString& aTRRDomain) {
495 aTRRDomain = mTRRDomain;
496 return NS_OK;
499 NS_IMETHODIMP
500 ChildDNSService::GetLastConfirmationStatus(nsresult* aConfirmationStatus) {
501 // XXX(valentin): Fix for socket process
502 *aConfirmationStatus = NS_OK;
503 return NS_OK;
506 NS_IMETHODIMP ChildDNSService::GetLastConfirmationSkipReason(
507 TRRSkippedReason* aSkipReason) {
508 // XXX(valentin): Fix for socket process
509 *aSkipReason = nsITRRSkipReason::TRR_UNSET;
510 return NS_OK;
513 } // namespace net
514 } // namespace mozilla