tor-browser

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

HTTPSRecordResolver.cpp (6125B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 // HttpLog.h should generally be included first
      7 #include "HttpLog.h"
      8 
      9 #include "HTTPSRecordResolver.h"
     10 #include "mozilla/Components.h"
     11 #include "mozilla/StaticPrefs_network.h"
     12 #include "nsIDNSByTypeRecord.h"
     13 #include "nsIDNSAdditionalInfo.h"
     14 #include "nsIDNSService.h"
     15 #include "nsHttpConnectionInfo.h"
     16 #include "nsNetCID.h"
     17 #include "nsAHttpTransaction.h"
     18 #include "nsServiceManagerUtils.h"
     19 
     20 namespace mozilla {
     21 namespace net {
     22 
     23 NS_IMPL_ISUPPORTS(HTTPSRecordResolver, nsIDNSListener)
     24 
     25 HTTPSRecordResolver::HTTPSRecordResolver(nsAHttpTransaction* aTransaction)
     26    : mTransaction(aTransaction), mConnInfo(aTransaction->ConnectionInfo()) {}
     27 
     28 HTTPSRecordResolver::~HTTPSRecordResolver() = default;
     29 
     30 nsresult HTTPSRecordResolver::FetchHTTPSRRInternal(
     31    nsIEventTarget* aTarget, nsICancelable** aDNSRequest) {
     32  NS_ENSURE_ARG_POINTER(aTarget);
     33 
     34  // Only fetch HTTPS RR for https.
     35  if (!mConnInfo->FirstHopSSL()) {
     36    return NS_ERROR_FAILURE;
     37  }
     38 
     39  nsCOMPtr<nsIDNSService> dns = mozilla::components::DNS::Service();
     40  if (!dns) {
     41    return NS_ERROR_NOT_AVAILABLE;
     42  }
     43 
     44  nsIDNSService::DNSFlags flags =
     45      nsIDNSService::GetFlagsFromTRRMode(mConnInfo->GetTRRMode());
     46  if (mTransaction->Caps() & NS_HTTP_REFRESH_DNS) {
     47    flags |= nsIDNSService::RESOLVE_BYPASS_CACHE;
     48  }
     49 
     50  nsCOMPtr<nsIDNSAdditionalInfo> info;
     51  if (mConnInfo->OriginPort() != NS_HTTPS_DEFAULT_PORT) {
     52    dns->NewAdditionalInfo(""_ns, mConnInfo->OriginPort(),
     53                           getter_AddRefs(info));
     54  }
     55 
     56  MutexAutoLock lock(mMutex);
     57 
     58  nsresult rv = dns->AsyncResolveNative(
     59      mConnInfo->GetOrigin(), nsIDNSService::RESOLVE_TYPE_HTTPSSVC, flags, info,
     60      this, aTarget, mConnInfo->GetOriginAttributes(),
     61      getter_AddRefs(mHTTPSRecordRequest));
     62 
     63  if (NS_FAILED(rv)) {
     64    return rv;
     65  }
     66 
     67  nsCOMPtr<nsICancelable> request = mHTTPSRecordRequest;
     68  request.forget(aDNSRequest);
     69 
     70  if (!StaticPrefs::network_dns_https_rr_check_record_with_cname()) {
     71    return rv;
     72  }
     73 
     74  rv = dns->AsyncResolveNative(
     75      mConnInfo->GetOrigin(), nsIDNSService::RESOLVE_TYPE_DEFAULT,
     76      flags | nsIDNSService::RESOLVE_CANONICAL_NAME, nullptr, this, aTarget,
     77      mConnInfo->GetOriginAttributes(), getter_AddRefs(mCnameRequest));
     78  return rv;
     79 }
     80 
     81 NS_IMETHODIMP HTTPSRecordResolver::OnLookupComplete(nsICancelable* aRequest,
     82                                                    nsIDNSRecord* aRecord,
     83                                                    nsresult aStatus) {
     84  MutexAutoLock lock(mMutex);
     85  if (!mTransaction || mDone) {
     86    // The transaction is not interesed in a response anymore.
     87    mCnameRequest = nullptr;
     88    mHTTPSRecordRequest = nullptr;
     89    return NS_OK;
     90  }
     91 
     92  if (aRequest == mHTTPSRecordRequest) {
     93    nsCOMPtr<nsIDNSHTTPSSVCRecord> record = do_QueryInterface(aRecord);
     94    mHTTPSRecordRequest = nullptr;
     95    if (!record || NS_FAILED(aStatus)) {
     96      // When failed, we don't want to wait for the CNAME.
     97      mCnameRequest = nullptr;
     98      MutexAutoUnlock unlock(mMutex);
     99      return InvokeCallback();
    100    }
    101 
    102    mHTTPSRecord = record;
    103 
    104    // Waiting for the address record.
    105    if (mCnameRequest) {
    106      return NS_OK;
    107    }
    108 
    109    MutexAutoUnlock unlock(mMutex);
    110    return InvokeCallback();
    111  }
    112 
    113  // Having mCnameRequest indicates that we are interested in the address
    114  // record.
    115  if (mCnameRequest && aRequest == mCnameRequest) {
    116    nsCOMPtr<nsIDNSAddrRecord> addrRecord = do_QueryInterface(aRecord);
    117    mCnameRequest = nullptr;
    118    if (!addrRecord || NS_FAILED(aStatus)) {
    119      // If we are still waiting for HTTPS RR, don't invoke the callback.
    120      if (mHTTPSRecordRequest) {
    121        return NS_OK;
    122      }
    123 
    124      MutexAutoUnlock unlock(mMutex);
    125      return InvokeCallback();
    126    }
    127 
    128    mAddrRecord = addrRecord;
    129    // Waiting for the HTTPS record.
    130    if (mHTTPSRecordRequest) {
    131      return NS_OK;
    132    }
    133 
    134    MutexAutoUnlock unlock(mMutex);
    135    return InvokeCallback();
    136  }
    137 
    138  return NS_OK;
    139 }
    140 
    141 nsresult HTTPSRecordResolver::InvokeCallback() {
    142  MOZ_ASSERT(!mDone);
    143 
    144  mDone = true;
    145  if (!mHTTPSRecord) {
    146    return mTransaction->OnHTTPSRRAvailable(nullptr, nullptr, ""_ns);
    147  }
    148 
    149  nsCString cname;
    150  if (mAddrRecord) {
    151    (void)mAddrRecord->GetCanonicalName(cname);
    152  }
    153 
    154  // Make sure we use the updated caps from the transaction.
    155  uint32_t caps = mTransaction->Caps();
    156  nsCOMPtr<nsISVCBRecord> svcbRecord;
    157  if (NS_FAILED(mHTTPSRecord->GetServiceModeRecordWithCname(
    158          caps & NS_HTTP_DISALLOW_SPDY, caps & NS_HTTP_DISALLOW_HTTP3, cname,
    159          getter_AddRefs(svcbRecord)))) {
    160    return mTransaction->OnHTTPSRRAvailable(mHTTPSRecord, nullptr, cname);
    161  }
    162 
    163  return mTransaction->OnHTTPSRRAvailable(mHTTPSRecord, svcbRecord, cname);
    164 }
    165 
    166 void HTTPSRecordResolver::PrefetchAddrRecord(const nsACString& aTargetName,
    167                                             bool aRefreshDNS) {
    168  MOZ_ASSERT(mTransaction);
    169  nsCOMPtr<nsIDNSService> dns = mozilla::components::DNS::Service();
    170  if (!dns) {
    171    return;
    172  }
    173 
    174  nsIDNSService::DNSFlags flags = nsIDNSService::GetFlagsFromTRRMode(
    175      mTransaction->ConnectionInfo()->GetTRRMode());
    176  if (aRefreshDNS) {
    177    flags |= nsIDNSService::RESOLVE_BYPASS_CACHE;
    178  }
    179 
    180  nsCOMPtr<nsICancelable> tmpOutstanding;
    181 
    182  (void)dns->AsyncResolveNative(
    183      aTargetName, nsIDNSService::RESOLVE_TYPE_DEFAULT,
    184      flags | nsIDNSService::RESOLVE_SPECULATE, nullptr, this,
    185      GetCurrentSerialEventTarget(),
    186      mTransaction->ConnectionInfo()->GetOriginAttributes(),
    187      getter_AddRefs(tmpOutstanding));
    188 }
    189 
    190 void HTTPSRecordResolver::Close() {
    191  mTransaction = nullptr;
    192  MutexAutoLock lock(mMutex);
    193  if (mCnameRequest) {
    194    mCnameRequest->Cancel(NS_ERROR_ABORT);
    195    mCnameRequest = nullptr;
    196  }
    197  if (mHTTPSRecordRequest) {
    198    mHTTPSRecordRequest->Cancel(NS_ERROR_ABORT);
    199    mHTTPSRecordRequest = nullptr;
    200  }
    201 }
    202 
    203 }  // namespace net
    204 }  // namespace mozilla