tor-browser

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

PlatformDNSWin.cpp (4705B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=4 sw=2 sts=2 et cin: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "GetAddrInfo.h"
      8 #include "mozilla/glean/NetwerkMetrics.h"
      9 #include "mozilla/net/DNSPacket.h"
     10 #include "nsIDNSService.h"
     11 #include "mozilla/Maybe.h"
     12 #include "mozilla/ScopeExit.h"
     13 #include "mozilla/StaticPrefs_network.h"
     14 
     15 #ifdef DNSQUERY_AVAILABLE
     16 // There is a bug in windns.h where the type of parameter ppQueryResultsSet for
     17 // DnsQuery_A is dependent on UNICODE being set. It should *always* be
     18 // PDNS_RECORDA, but if UNICODE is set it is PDNS_RECORDW. To get around this
     19 // we make sure that UNICODE is unset.
     20 #  undef UNICODE
     21 #  include <ws2tcpip.h>
     22 #  undef GetAddrInfo
     23 #  include <windns.h>
     24 #endif  // DNSQUERY_AVAILABLE
     25 
     26 namespace mozilla::net {
     27 
     28 #define LOG(msg, ...) \
     29  MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
     30 
     31 nsresult ResolveHTTPSRecordImpl(const nsACString& aHost,
     32                                nsIDNSService::DNSFlags aFlags,
     33                                TypeRecordResultType& aResult, uint32_t& aTTL) {
     34  nsAutoCString host(aHost);
     35  PDNS_RECORD result = nullptr;
     36  nsAutoCString cname;
     37  aTTL = UINT32_MAX;
     38 
     39  if (xpc::IsInAutomation() &&
     40      !StaticPrefs::network_dns_native_https_query_in_automation()) {
     41    return NS_ERROR_UNKNOWN_HOST;
     42  }
     43 
     44  TimeStamp startTime = TimeStamp::Now();
     45 
     46  DNS_STATUS status =
     47      DnsQuery_A(host.get(), nsIDNSService::RESOLVE_TYPE_HTTPSSVC,
     48                 DNS_QUERY_STANDARD, nullptr, &result, nullptr);
     49 
     50  mozilla::glean::networking::dns_native_https_call_time.AccumulateRawDuration(
     51      TimeStamp::Now() - startTime);
     52 
     53  if (status != ERROR_SUCCESS) {
     54    LOG("DnsQuery_A failed with error: %ld\n", status);
     55    return NS_ERROR_UNKNOWN_HOST;
     56  }
     57 
     58  // This will free the record if we exit early from this function.
     59  auto freeDnsRecord =
     60      MakeScopeExit([&]() { DnsRecordListFree(result, DnsFreeRecordList); });
     61 
     62  auto CheckRecords = [&aResult, &cname, &aTTL](
     63                          PDNS_RECORD result,
     64                          const nsCString& aHost) -> nsresult {
     65    PDNS_RECORD current = result;
     66 
     67    for (current = result; current; current = current->pNext) {
     68      if (strcmp(current->pName, aHost.get()) != 0) {
     69        continue;
     70      }
     71      if (current->wType == nsIDNSService::RESOLVE_TYPE_HTTPSSVC) {
     72        const unsigned char* ptr = (const unsigned char*)&(current->Data);
     73        struct SVCB parsed;
     74        nsresult rv = DNSPacket::ParseHTTPS(current->wDataLength, parsed, 0,
     75                                            ptr, current->wDataLength, aHost);
     76        if (NS_FAILED(rv)) {
     77          return rv;
     78        }
     79 
     80        if (parsed.mSvcDomainName.IsEmpty() && parsed.mSvcFieldPriority == 0) {
     81          // For AliasMode SVCB RRs, a TargetName of "." indicates that the
     82          // service is not available or does not exist.
     83          continue;
     84        }
     85 
     86        if (parsed.mSvcFieldPriority == 0) {
     87          // Alias form SvcDomainName must not have the "." value (empty)
     88          if (parsed.mSvcDomainName.IsEmpty()) {
     89            return NS_ERROR_UNEXPECTED;
     90          }
     91          cname = parsed.mSvcDomainName;
     92          ToLowerCase(cname);
     93          break;
     94        }
     95 
     96        if (!aResult.is<TypeRecordHTTPSSVC>()) {
     97          aResult = mozilla::AsVariant(CopyableTArray<SVCB>());
     98        }
     99        auto& results = aResult.as<TypeRecordHTTPSSVC>();
    100        results.AppendElement(parsed);
    101        aTTL = std::min<uint32_t>(aTTL, current->dwTtl);
    102      } else if (current->wType == DNS_TYPE_CNAME) {
    103        cname = current->Data.Cname.pNameHost;
    104        ToLowerCase(cname);
    105        aTTL = std::min<uint32_t>(aTTL, current->dwTtl);
    106        break;
    107      }
    108    }
    109    return NS_OK;
    110  };
    111 
    112  int32_t loopCount = 64;
    113  while (loopCount > 0 && aResult.is<Nothing>()) {
    114    loopCount--;
    115 
    116    nsresult rv = CheckRecords(result, host);
    117    if (NS_FAILED(rv)) {
    118      return rv;
    119    }
    120 
    121    if (aResult.is<Nothing>() && !cname.IsEmpty()) {
    122      host = cname;
    123      cname.Truncate();
    124      continue;
    125    }
    126 
    127    if (aResult.is<Nothing>()) {
    128      return NS_ERROR_UNKNOWN_HOST;
    129    }
    130  }
    131 
    132  // CNAME loop
    133  if (loopCount == 0) {
    134    return NS_ERROR_UNKNOWN_HOST;
    135  }
    136 
    137  if (aResult.is<Nothing>()) {
    138    // The call succeeded, but no HTTPS records were found.
    139    return NS_ERROR_UNKNOWN_HOST;
    140  }
    141 
    142  if (aTTL == UINT32_MAX) {
    143    aTTL = 60;  // Defaults to 60 seconds
    144  }
    145  return NS_OK;
    146 }
    147 
    148 void DNSThreadShutdown() {}
    149 
    150 }  // namespace mozilla::net