ChildDNSService.cpp (16806B)
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/. */ 4 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" 26 27 namespace mozilla { 28 namespace net { 29 30 //----------------------------------------------------------------------------- 31 // ChildDNSService 32 //----------------------------------------------------------------------------- 33 34 static StaticRefPtr<ChildDNSService> gChildDNSService; 35 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()); 41 42 if (!gChildDNSService) { 43 if (NS_WARN_IF(!NS_IsMainThread())) { 44 return nullptr; 45 } 46 gChildDNSService = new ChildDNSService(); 47 gChildDNSService->Init(); 48 ClearOnShutdown(&gChildDNSService); 49 } 50 51 return do_AddRef(gChildDNSService); 52 } 53 54 NS_IMPL_ISUPPORTS_INHERITED(ChildDNSService, DNSServiceBase, nsIDNSService, 55 nsPIDNSService) 56 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(); 66 } 67 } 68 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); 78 79 nsAutoCString originSuffix; 80 aOriginAttributes.CreateSuffix(originSuffix); 81 aHashKey.Append(originSuffix); 82 83 aHashKey.AppendInt(aFlags); 84 aHashKey.AppendPrintf("0x%" PRIxPTR, aListenerAddr); 85 } 86 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); 94 } 95 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; 101 } 102 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; 111 } 112 } 113 114 if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) { 115 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; 116 } 117 118 // We need original listener for the pending requests hash. 119 uintptr_t originalListenerAddr = reinterpret_cast<uintptr_t>(listener); 120 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(); 126 } 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); 131 } 132 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(); 141 } 142 } else { 143 dnsReq = new DNSRequestChild(sender); 144 } 145 146 { 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); 153 } 154 155 sender->StartRequest(); 156 157 sender.forget(result); 158 return NS_OK; 159 } 160 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; 167 } 168 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); 179 } 180 181 return NS_OK; 182 } 183 184 //----------------------------------------------------------------------------- 185 // ChildDNSService::nsIDNSService 186 //----------------------------------------------------------------------------- 187 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; 198 199 if (aArgc == 1) { 200 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 201 return NS_ERROR_INVALID_ARG; 202 } 203 } 204 205 return AsyncResolveInternal(hostname, aType, flags, aInfo, listener, target_, 206 attrs, result); 207 } 208 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); 217 } 218 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; 225 } 226 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; 236 237 if (aArgc == 1) { 238 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { 239 return NS_ERROR_INVALID_ARG; 240 } 241 } 242 243 return CancelAsyncResolveInternal(aHostname, aType, aFlags, aInfo, aListener, 244 aReason, attrs); 245 } 246 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); 255 } 256 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; 264 } 265 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; 273 } 274 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; 282 } 283 284 NS_IMETHODIMP 285 ChildDNSService::ClearCache(bool aTrrToo) { 286 if (!mTRRServiceParent || !mTRRServiceParent->CanSend()) { 287 return NS_ERROR_NOT_AVAILABLE; 288 } 289 290 (void)mTRRServiceParent->SendClearDNSCache(aTrrToo); 291 return NS_OK; 292 } 293 294 NS_IMETHODIMP 295 ChildDNSService::ReloadParentalControlEnabled() { 296 if (!mTRRServiceParent) { 297 return NS_ERROR_NOT_AVAILABLE; 298 } 299 300 mTRRServiceParent->ReloadParentalControlsEnabled(); 301 return NS_OK; 302 } 303 304 NS_IMETHODIMP 305 ChildDNSService::SetDetectedTrrURI(const nsACString& aURI) { 306 if (!mTRRServiceParent) { 307 return NS_ERROR_NOT_AVAILABLE; 308 } 309 310 mTRRServiceParent->SetDetectedTrrURI(aURI); 311 return NS_OK; 312 } 313 314 NS_IMETHODIMP 315 ChildDNSService::SetHeuristicDetectionResult(nsITRRSkipReason::value aValue) { 316 return NS_ERROR_NOT_IMPLEMENTED; 317 } 318 319 NS_IMETHODIMP 320 ChildDNSService::GetHeuristicDetectionResult(nsITRRSkipReason::value* aValue) { 321 return NS_ERROR_NOT_IMPLEMENTED; 322 } 323 324 NS_IMETHODIMP 325 ChildDNSService::GetTRRSkipReasonName(nsITRRSkipReason::value aValue, 326 nsACString& aName) { 327 return mozilla::net::GetTRRSkipReasonName(aValue, aName); 328 } 329 330 NS_IMETHODIMP 331 ChildDNSService::GetCurrentTrrURI(nsACString& aURI) { 332 if (!mTRRServiceParent) { 333 return NS_ERROR_NOT_AVAILABLE; 334 } 335 336 mTRRServiceParent->GetURI(aURI); 337 return NS_OK; 338 } 339 340 NS_IMETHODIMP 341 ChildDNSService::GetCurrentTrrMode(nsIDNSService::ResolverMode* aMode) { 342 if (XRE_IsContentProcess()) { 343 *aMode = mTRRMode; 344 return NS_OK; 345 } 346 if (!mTRRServiceParent) { 347 return NS_ERROR_NOT_AVAILABLE; 348 } 349 350 *aMode = mTRRServiceParent->Mode(); 351 return NS_OK; 352 } 353 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; 360 } 361 mTRRMode = mode; 362 TRRService::SetCurrentTRRMode(modeFromPref); 363 } 364 365 NS_IMETHODIMP 366 ChildDNSService::GetCurrentTrrConfirmationState(uint32_t* aConfirmationState) { 367 if (!mTRRServiceParent) { 368 return NS_ERROR_NOT_AVAILABLE; 369 } 370 371 *aConfirmationState = mTRRServiceParent->GetConfirmationState(); 372 return NS_OK; 373 } 374 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; 382 } 383 384 return NS_ERROR_FAILURE; 385 } 386 // TODO: get value from parent during PNecko construction? 387 return NS_ERROR_NOT_AVAILABLE; 388 } 389 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(); 399 } 400 401 MutexAutoLock lock(mPendingRequestsLock); 402 403 nsCString key; 404 GetDNSRecordHashKey(aDnsRequest->mHost, aDnsRequest->mTrrServer, 405 aDnsRequest->mPort, aDnsRequest->mType, 406 aDnsRequest->mOriginAttributes, originalFlags, 407 originalListenerAddr, key); 408 409 nsTArray<RefPtr<DNSRequestSender>>* hashEntry; 410 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); 417 } 418 } 419 } 420 } 421 422 //----------------------------------------------------------------------------- 423 // ChildDNSService::nsPIDNSService 424 //----------------------------------------------------------------------------- 425 426 nsresult ChildDNSService::Init() { 427 ReadPrefs(nullptr); 428 429 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); 430 if (prefs) { 431 AddPrefObserver(prefs); 432 } 433 434 return NS_OK; 435 } 436 437 nsresult ChildDNSService::Shutdown() { return NS_OK; } 438 439 NS_IMETHODIMP 440 ChildDNSService::GetPrefetchEnabled(bool* outVal) { 441 *outVal = !mDisablePrefetch; 442 return NS_OK; 443 } 444 445 NS_IMETHODIMP 446 ChildDNSService::SetPrefetchEnabled(bool inVal) { 447 mDisablePrefetch = !inVal; 448 return NS_OK; 449 } 450 451 NS_IMETHODIMP 452 ChildDNSService::ReportFailedSVCDomainName(const nsACString& aOwnerName, 453 const nsACString& aSVCDomainName) { 454 return NS_ERROR_NOT_IMPLEMENTED; 455 } 456 457 NS_IMETHODIMP 458 ChildDNSService::IsSVCDomainNameFailed(const nsACString& aOwnerName, 459 const nsACString& aSVCDomainName, 460 bool* aResult) { 461 return NS_ERROR_NOT_IMPLEMENTED; 462 } 463 464 NS_IMETHODIMP 465 ChildDNSService::ResetExcludedSVCDomainName(const nsACString& aOwnerName) { 466 return NS_ERROR_NOT_IMPLEMENTED; 467 } 468 469 //----------------------------------------------------------------------------- 470 // ChildDNSService::nsIObserver 471 //----------------------------------------------------------------------------- 472 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()); 479 } 480 return NS_OK; 481 } 482 483 void ChildDNSService::SetTRRDomain(const nsACString& aTRRDomain) { 484 mTRRDomain = aTRRDomain; 485 TRRService::SetProviderDomain(aTRRDomain); 486 } 487 488 nsresult ChildDNSService::GetTRRDomainKey(nsACString& aTRRDomain) { 489 aTRRDomain = TRRService::ProviderKey(); 490 return NS_OK; 491 } 492 493 NS_IMETHODIMP 494 ChildDNSService::GetTrrDomain(nsACString& aTRRDomain) { 495 aTRRDomain = mTRRDomain; 496 return NS_OK; 497 } 498 499 NS_IMETHODIMP 500 ChildDNSService::GetLastConfirmationStatus(nsresult* aConfirmationStatus) { 501 // XXX(valentin): Fix for socket process 502 *aConfirmationStatus = NS_OK; 503 return NS_OK; 504 } 505 506 NS_IMETHODIMP ChildDNSService::GetLastConfirmationSkipReason( 507 TRRSkippedReason* aSkipReason) { 508 // XXX(valentin): Fix for socket process 509 *aSkipReason = nsITRRSkipReason::TRR_UNSET; 510 return NS_OK; 511 } 512 513 } // namespace net 514 } // namespace mozilla