tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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