tor-browser

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

PlatformDNSAndroid.cpp (4651B)


      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/Atomics.h"
     13 #include "mozilla/StaticPrefs_network.h"
     14 
     15 #include <string.h>
     16 #include <netinet/in.h>
     17 #include <resolv.h>
     18 #include <poll.h>
     19 #include <android/multinetwork.h>
     20 
     21 namespace mozilla::net {
     22 
     23 // The first call to ResolveHTTPSRecordImpl will load the library
     24 // and function pointers.
     25 static Atomic<bool> sLibLoading{false};
     26 
     27 // https://developer.android.com/ndk/reference/group/networking#android_res_nquery
     28 // The function android_res_nquery is defined in <android/multinetwork.h>
     29 typedef int (*android_res_nquery_ptr)(net_handle_t network, const char* dname,
     30                                      int ns_class, int ns_type,
     31                                      uint32_t flags);
     32 static Atomic<android_res_nquery_ptr> sAndroidResNQuery;
     33 
     34 #define LOG(msg, ...) \
     35  MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
     36 
     37 nsresult ResolveHTTPSRecordImpl(const nsACString& aHost,
     38                                nsIDNSService::DNSFlags aFlags,
     39                                TypeRecordResultType& aResult, uint32_t& aTTL) {
     40  DNSPacket packet;
     41  nsAutoCString host(aHost);
     42  nsAutoCString cname;
     43  nsresult rv;
     44 
     45  if (xpc::IsInAutomation() &&
     46      !StaticPrefs::network_dns_native_https_query_in_automation()) {
     47    return NS_ERROR_UNKNOWN_HOST;
     48  }
     49 
     50  if (!sLibLoading.exchange(true)) {
     51    // We're the first call here, load the library and symbols.
     52    if (__builtin_available(android 29, *)) {
     53      sAndroidResNQuery = android_res_nquery;  // API 29
     54    } else {
     55      LOG("No android_res_nquery symbol");
     56    }
     57  }
     58 
     59  if (!sAndroidResNQuery) {
     60    LOG("nquery not loaded");
     61    // The library hasn't been loaded yet.
     62    return NS_ERROR_UNKNOWN_HOST;
     63  }
     64 
     65  LOG("resolving %s\n", host.get());
     66  TimeStamp startTime = TimeStamp::Now();
     67  // Perform the query
     68  rv = packet.FillBuffer(
     69      [&](unsigned char response[DNSPacket::MAX_SIZE]) -> int {
     70        int fd = 0;
     71        auto closeSocket = MakeScopeExit([&] {
     72          if (fd > 0) {
     73            close(fd);
     74          }
     75        });
     76        uint32_t flags = 0;
     77        if (aFlags & nsIDNSService::RESOLVE_BYPASS_CACHE) {
     78          flags = ANDROID_RESOLV_NO_CACHE_LOOKUP;
     79        }
     80        fd = sAndroidResNQuery(0, host.get(), ns_c_in,
     81                               nsIDNSService::RESOLVE_TYPE_HTTPSSVC, flags);
     82 
     83        if (fd < 0) {
     84          LOG("DNS query failed");
     85          return fd;
     86        }
     87 
     88        struct pollfd fds;
     89        fds.fd = fd;
     90        fds.events = POLLIN;  // Wait for read events
     91 
     92        // Wait for an event on the file descriptor
     93        int ret = poll(&fds, 1,
     94                       StaticPrefs::network_dns_native_https_timeout_android());
     95        if (ret <= 0) {
     96          LOG("poll failed %d", ret);
     97          return -1;
     98        }
     99 
    100        ssize_t len = recv(fd, response, DNSPacket::MAX_SIZE - 1, 0);
    101        if (len <= 8) {
    102          LOG("size too small %zd", len);
    103          return len < 0 ? len : -1;
    104        }
    105 
    106        // The first 8 bytes are UDP header.
    107        // XXX: we should consider avoiding this move somehow.
    108        for (int i = 0; i < len - 8; i++) {
    109          response[i] = response[i + 8];
    110        }
    111 
    112        return len - 8;
    113      });
    114  mozilla::glean::networking::dns_native_https_call_time.AccumulateRawDuration(
    115      TimeStamp::Now() - startTime);
    116  if (NS_FAILED(rv)) {
    117    LOG("failed rv");
    118    return rv;
    119  }
    120  packet.SetNativePacket(true);
    121 
    122  int32_t loopCount = 64;
    123  while (loopCount > 0 && aResult.is<Nothing>()) {
    124    loopCount--;
    125    DOHresp resp;
    126    nsClassHashtable<nsCStringHashKey, DOHresp> additionalRecords;
    127    rv = packet.Decode(host, TRRTYPE_HTTPSSVC, cname, true, resp, aResult,
    128                       additionalRecords, aTTL);
    129    if (NS_FAILED(rv)) {
    130      LOG("Decode failed %x", static_cast<uint32_t>(rv));
    131      return rv;
    132    }
    133    if (!cname.IsEmpty() && aResult.is<Nothing>()) {
    134      host = cname;
    135      cname.Truncate();
    136      continue;
    137    }
    138  }
    139 
    140  if (aResult.is<Nothing>()) {
    141    LOG("Result is nothing");
    142    // The call succeeded, but no HTTPS records were found.
    143    return NS_ERROR_UNKNOWN_HOST;
    144  }
    145 
    146  return NS_OK;
    147 }
    148 
    149 void DNSThreadShutdown() {}
    150 
    151 }  // namespace mozilla::net