Link Rust DoH into DnsResolver with default off
Expect no behavior changes since DoH is disabled.
Test: atest
Bug: 155855709
Change-Id: Ie99cc4c4035c9bfda4a125f5ebf57e2e2f9d2036
diff --git a/Android.bp b/Android.bp
index 2e264b5..5e2f35c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -192,6 +192,7 @@
"libbase",
"libcutils",
"libnetdutils",
+ "libdoh_ffi",
"libprotobuf-cpp-lite",
"libstatslog_resolv",
"libstatspush_compat",
diff --git a/DnsResolver.cpp b/DnsResolver.cpp
index fcd4293..82366e8 100644
--- a/DnsResolver.cpp
+++ b/DnsResolver.cpp
@@ -81,6 +81,7 @@
auto& dnsTlsDispatcher = DnsTlsDispatcher::getInstance();
auto& privateDnsConfiguration = PrivateDnsConfiguration::getInstance();
privateDnsConfiguration.setObserver(&dnsTlsDispatcher);
+ if (isDoHEnabled()) privateDnsConfiguration.initDoh();
}
bool DnsResolver::start() {
diff --git a/PrivateDnsConfiguration.cpp b/PrivateDnsConfiguration.cpp
index b09c7ce..802728f 100644
--- a/PrivateDnsConfiguration.cpp
+++ b/PrivateDnsConfiguration.cpp
@@ -21,18 +21,22 @@
#include <android-base/format.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <netdutils/Slice.h>
#include <netdutils/ThreadUtil.h>
#include <sys/socket.h>
#include "DnsTlsTransport.h"
#include "ResolverEventReporter.h"
+#include "doh.h"
#include "netd_resolv/resolv.h"
+#include "resolv_private.h"
#include "util.h"
using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
using aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
using android::base::StringPrintf;
using android::netdutils::setThreadName;
+using android::netdutils::Slice;
using std::chrono::milliseconds;
namespace android {
@@ -238,9 +242,9 @@
}
void PrivateDnsConfiguration::sendPrivateDnsValidationEvent(const ServerIdentity& identity,
- unsigned netId, bool success) {
+ unsigned netId, bool success) const {
LOG(DEBUG) << "Sending validation " << (success ? "success" : "failure") << " event on netId "
- << netId << " for " << identity.sockaddr.ip().toString() << " with hostname {"
+ << netId << " for " << identity.sockaddr.toString() << " with hostname {"
<< identity.provider << "}";
// Send a validation event to NetdEventListenerService.
const auto& listeners = ResolverEventReporter::getInstance().getListeners();
@@ -313,7 +317,9 @@
}
// Send private dns validation result to listeners.
- sendPrivateDnsValidationEvent(identity, netId, success);
+ if (needReportEvent(netId, identity, success)) {
+ sendPrivateDnsValidationEvent(identity, netId, success);
+ }
if (success) {
updateServerState(identity, Validation::success, netId);
@@ -411,5 +417,134 @@
dw.blankline();
}
+void PrivateDnsConfiguration::initDoh() {
+ std::lock_guard guard(mPrivateDnsLock);
+ initDohLocked();
+}
+
+void PrivateDnsConfiguration::initDohLocked() {
+ if (mDohDispatcher != nullptr) return;
+ mDohDispatcher = doh_dispatcher_new(
+ [](uint32_t net_id, bool success, const char* ip_addr, const char* host) {
+ android::net::PrivateDnsConfiguration::getInstance().onDohStatusUpdate(
+ net_id, success, ip_addr, host);
+ });
+}
+
+int PrivateDnsConfiguration::setDoh(int32_t netId, uint32_t mark,
+ const std::vector<std::string>& servers,
+ const std::string& name, const std::string& caCert) {
+ if (servers.empty()) return 0;
+ LOG(DEBUG) << "PrivateDnsConfiguration::setDoh(" << netId << ", 0x" << std::hex << mark
+ << std::dec << ", " << servers.size() << ", " << name << ")";
+ std::lock_guard guard(mPrivateDnsLock);
+
+ initDohLocked();
+
+ // TODO: 1. Improve how to choose the server
+ // TODO: 2. Support multiple servers
+ for (const auto& entry : mAvailableDoHProviders) {
+ const auto& doh = entry.getDohIdentity(servers, name);
+ if (!doh.ok()) continue;
+
+ auto it = mDohTracker.find(netId);
+ // Skip if the same server already exists and its status == success.
+ if (it != mDohTracker.end() && it->second == doh.value() &&
+ it->second.status == Validation::success) {
+ return 0;
+ }
+ const auto& [dohIt, _] = mDohTracker.insert_or_assign(netId, doh.value());
+ const auto& dohId = dohIt->second;
+
+ RecordEntry record(netId, {netdutils::IPSockAddr::toIPSockAddr(dohId.ipAddr, 443), name},
+ dohId.status);
+ mPrivateDnsLog.push(std::move(record));
+ return doh_net_new(mDohDispatcher, netId, dohId.httpsTemplate.c_str(), dohId.host.c_str(),
+ dohId.ipAddr.c_str(), mark, caCert.c_str(), 3000);
+ }
+
+ LOG(INFO) << __func__ << "No suitable DoH server found";
+ return 0;
+}
+
+void PrivateDnsConfiguration::clearDoh(unsigned netId) {
+ LOG(DEBUG) << "PrivateDnsConfiguration::clearDoh (" << netId << ")";
+ std::lock_guard guard(mPrivateDnsLock);
+ if (mDohDispatcher != nullptr) doh_net_delete(mDohDispatcher, netId);
+ mDohTracker.erase(netId);
+}
+
+ssize_t PrivateDnsConfiguration::dohQuery(unsigned netId, const Slice query, const Slice answer,
+ uint64_t timeoutMs) {
+ {
+ std::lock_guard guard(mPrivateDnsLock);
+ // It's safe because mDohDispatcher won't be deleted after initializing.
+ if (mDohDispatcher == nullptr) return RESULT_CAN_NOT_SEND;
+ }
+ return doh_query(mDohDispatcher, netId, query.base(), query.size(), answer.base(),
+ answer.size(), timeoutMs);
+}
+
+void PrivateDnsConfiguration::onDohStatusUpdate(uint32_t netId, bool success, const char* ipAddr,
+ const char* host) {
+ LOG(INFO) << __func__ << netId << ", " << success << ", " << ipAddr << ", " << host;
+ std::lock_guard guard(mPrivateDnsLock);
+ // Update the server status.
+ auto it = mDohTracker.find(netId);
+ if (it == mDohTracker.end() || (it->second.ipAddr != ipAddr && it->second.host != host)) {
+ LOG(WARNING) << __func__ << "obsolete event";
+ return;
+ }
+ Validation status = success ? Validation::success : Validation::fail;
+ it->second.status = status;
+ // Send the events to registered listeners.
+ ServerIdentity identity = {netdutils::IPSockAddr::toIPSockAddr(ipAddr, 443), host};
+ if (needReportEvent(netId, identity, success)) {
+ sendPrivateDnsValidationEvent(identity, netId, success);
+ }
+ // Add log.
+ RecordEntry record(netId, identity, status);
+ mPrivateDnsLog.push(std::move(record));
+}
+
+bool PrivateDnsConfiguration::needReportEvent(uint32_t netId, ServerIdentity identity,
+ bool success) const {
+ // If the result is success or DoH is not enable, no concern to report the events.
+ if (success || !isDoHEnabled()) return true;
+ // If the result is failure, check another transport's status to determine if we should report
+ // the event.
+ switch (identity.sockaddr.port()) {
+ // DoH
+ case 443: {
+ auto netPair = mPrivateDnsTransports.find(netId);
+ if (netPair == mPrivateDnsTransports.end()) return true;
+ for (const auto& [id, server] : netPair->second) {
+ if ((identity.sockaddr.ip() == id.sockaddr.ip()) &&
+ (identity.sockaddr.port() != id.sockaddr.port()) &&
+ (server->validationState() == Validation::success)) {
+ LOG(DEBUG) << __func__
+ << "skip reporting DoH validation failure event, server addr: " +
+ identity.sockaddr.ip().toString();
+ return false;
+ }
+ }
+ break;
+ }
+ // DoT
+ case 853: {
+ auto it = mDohTracker.find(netId);
+ if (it == mDohTracker.end()) return true;
+ if (it->second == identity && it->second.status == Validation::success) {
+ LOG(DEBUG) << __func__
+ << "skip reporting DoT validation failure event, server addr: " +
+ identity.sockaddr.ip().toString();
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
} // namespace net
} // namespace android
diff --git a/PrivateDnsConfiguration.h b/PrivateDnsConfiguration.h
index f7e6592..cd3205f 100644
--- a/PrivateDnsConfiguration.h
+++ b/PrivateDnsConfiguration.h
@@ -16,20 +16,25 @@
#pragma once
+#include <array>
#include <list>
#include <map>
#include <mutex>
#include <vector>
+#include <android-base/format.h>
+#include <android-base/logging.h>
#include <android-base/result.h>
#include <android-base/thread_annotations.h>
#include <netdutils/BackoffSequence.h>
#include <netdutils/DumpWriter.h>
#include <netdutils/InternetAddresses.h>
+#include <netdutils/Slice.h>
#include "DnsTlsServer.h"
#include "LockedQueue.h"
#include "PrivateDnsValidationObserver.h"
+#include "doh.h"
namespace android {
namespace net {
@@ -61,6 +66,8 @@
explicit ServerIdentity(const IPrivateDnsServer& server)
: sockaddr(server.addr()), provider(server.provider()) {}
+ ServerIdentity(const netdutils::IPSockAddr& addr, const std::string& host)
+ : sockaddr(addr), provider(host) {}
bool operator<(const ServerIdentity& other) const {
return std::tie(sockaddr, provider) < std::tie(other.sockaddr, other.provider);
@@ -79,10 +86,20 @@
int set(int32_t netId, uint32_t mark, const std::vector<std::string>& servers,
const std::string& name, const std::string& caCert) EXCLUDES(mPrivateDnsLock);
+ void initDoh() EXCLUDES(mPrivateDnsLock);
+
+ int setDoh(int32_t netId, uint32_t mark, const std::vector<std::string>& servers,
+ const std::string& name, const std::string& caCert) EXCLUDES(mPrivateDnsLock);
+
PrivateDnsStatus getStatus(unsigned netId) const EXCLUDES(mPrivateDnsLock);
void clear(unsigned netId) EXCLUDES(mPrivateDnsLock);
+ void clearDoh(unsigned netId) EXCLUDES(mPrivateDnsLock);
+
+ ssize_t dohQuery(unsigned netId, const netdutils::Slice query, const netdutils::Slice answer,
+ uint64_t timeoutMs) EXCLUDES(mPrivateDnsLock);
+
// Request the server to be revalidated on a connection tagged with |mark|.
// Returns a Result to indicate if the request is accepted.
base::Result<void> requestValidation(unsigned netId, const ServerIdentity& identity,
@@ -92,6 +109,9 @@
void dump(netdutils::DumpWriter& dw) const;
+ void onDohStatusUpdate(uint32_t netId, bool success, const char* ipAddr, const char* host)
+ EXCLUDES(mPrivateDnsLock);
+
private:
typedef std::map<ServerIdentity, std::unique_ptr<IPrivateDnsServer>> PrivateDnsTracker;
@@ -105,8 +125,8 @@
bool recordPrivateDnsValidation(const ServerIdentity& identity, unsigned netId, bool success,
bool isRevalidation) EXCLUDES(mPrivateDnsLock);
- void sendPrivateDnsValidationEvent(const ServerIdentity& identity, unsigned netId, bool success)
- REQUIRES(mPrivateDnsLock);
+ void sendPrivateDnsValidationEvent(const ServerIdentity& identity, unsigned netId,
+ bool success) const REQUIRES(mPrivateDnsLock);
// Decide if a validation for |server| is needed. Note that servers that have failed
// multiple validation attempts but for which there is still a validating
@@ -123,6 +143,8 @@
base::Result<IPrivateDnsServer*> getPrivateDnsLocked(const ServerIdentity& identity,
unsigned netId) REQUIRES(mPrivateDnsLock);
+ void initDohLocked() REQUIRES(mPrivateDnsLock);
+
mutable std::mutex mPrivateDnsLock;
std::map<unsigned, PrivateDnsMode> mPrivateDnsModes GUARDED_BY(mPrivateDnsLock);
@@ -135,9 +157,14 @@
void notifyValidationStateUpdate(const netdutils::IPSockAddr& sockaddr, Validation validation,
uint32_t netId) const REQUIRES(mPrivateDnsLock);
+ bool needReportEvent(uint32_t netId, ServerIdentity identity, bool success) const
+ REQUIRES(mPrivateDnsLock);
+
// TODO: fix the reentrancy problem.
PrivateDnsValidationObserver* mObserver GUARDED_BY(mPrivateDnsLock);
+ DohDispatcher* mDohDispatcher;
+
friend class PrivateDnsConfigurationTest;
// It's not const because PrivateDnsConfigurationTest needs to override it.
@@ -147,6 +174,58 @@
.withInitialRetransmissionTime(std::chrono::seconds(60))
.withMaximumRetransmissionTime(std::chrono::seconds(3600));
+ struct DohIdentity {
+ std::string httpsTemplate;
+ std::string ipAddr;
+ std::string host;
+ Validation status;
+ bool operator<(const DohIdentity& other) const {
+ return std::tie(ipAddr, host) < std::tie(other.ipAddr, other.host);
+ }
+ bool operator==(const DohIdentity& other) const {
+ return std::tie(ipAddr, host) == std::tie(other.ipAddr, other.host);
+ }
+ bool operator<(const ServerIdentity& other) const {
+ std::string otherIp = other.sockaddr.ip().toString();
+ return std::tie(ipAddr, host) < std::tie(otherIp, other.provider);
+ }
+ bool operator==(const ServerIdentity& other) const {
+ std::string otherIp = other.sockaddr.ip().toString();
+ return std::tie(ipAddr, host) == std::tie(otherIp, other.provider);
+ }
+ };
+
+ struct DohProviderEntry {
+ std::string provider;
+ std::set<std::string> ips;
+ std::string host;
+ std::string httpsTemplate;
+ base::Result<DohIdentity> getDohIdentity(const std::vector<std::string>& ips,
+ const std::string& host) const {
+ if (!host.empty() && this->host != host) return Errorf("host {} not matched", host);
+ for (const auto& ip : ips) {
+ if (this->ips.find(ip) == this->ips.end()) continue;
+ LOG(INFO) << fmt::format("getDohIdentity: {} {}", ip, host);
+ // Only pick the first one for now.
+ return DohIdentity{httpsTemplate, ip, host, Validation::in_process};
+ }
+ return Errorf("server not matched");
+ };
+ };
+
+ // TODO: Move below DoH relevant stuff into Rust implementation.
+ std::map<unsigned, DohIdentity> mDohTracker GUARDED_BY(mPrivateDnsLock);
+ std::array<DohProviderEntry, 2> mAvailableDoHProviders = {{
+ {"Google",
+ {"2001:4860:4860::8888", "2001:4860:4860::8844", "8.8.8.8", "8.8.4.4"},
+ "dns.google",
+ "https://dns.google/dns-query"},
+ {"Cloudflare",
+ {"2606:4700::6810:f8f9", "2606:4700::6810:f9f9", "104.16.248.249", "104.16.249.249"},
+ "cloudflare-dns.com",
+ "https://cloudflare-dns.com/dns-query"},
+ }};
+
struct RecordEntry {
RecordEntry(uint32_t netId, const ServerIdentity& identity, Validation state)
: netId(netId), serverIdentity(identity), state(state) {}
diff --git a/ResolverController.cpp b/ResolverController.cpp
index c983a15..9e693d3 100644
--- a/ResolverController.cpp
+++ b/ResolverController.cpp
@@ -34,6 +34,7 @@
#include "ResolverStats.h"
#include "resolv_cache.h"
#include "stats.h"
+#include "util.h"
using aidl::android::net::ResolverParamsParcel;
using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
@@ -169,6 +170,7 @@
resolv_delete_cache_for_net(netId);
mDns64Configuration.stopPrefixDiscovery(netId);
PrivateDnsConfiguration::getInstance().clear(netId);
+ if (isDoHEnabled()) PrivateDnsConfiguration::getInstance().clearDoh(netId);
// Don't get this instance in PrivateDnsConfiguration. It's probe to deadlock.
DnsTlsDispatcher::getInstance().forceCleanup(netId);
@@ -206,9 +208,9 @@
// through a different network. For example, on a VPN with no DNS servers (Do53), if the VPN
// applies to UID 0, dns_mark is assigned for default network rathan the VPN. (note that it's
// possible that a VPN doesn't have any DNS servers but DoT servers in DNS strict mode)
- const int err = PrivateDnsConfiguration::getInstance().set(
- resolverParams.netId, netcontext.app_mark, tlsServers, resolverParams.tlsName,
- resolverParams.caCertificate);
+ int err = PrivateDnsConfiguration::getInstance().set(resolverParams.netId, netcontext.app_mark,
+ tlsServers, resolverParams.tlsName,
+ resolverParams.caCertificate);
if (err != 0) {
return err;
@@ -225,6 +227,15 @@
return err;
}
+ if (isDoHEnabled())
+ err = PrivateDnsConfiguration::getInstance().setDoh(
+ resolverParams.netId, netcontext.app_mark, tlsServers, resolverParams.tlsName,
+ resolverParams.caCertificate);
+
+ if (err != 0) {
+ return err;
+ }
+
res_params res_params = {};
res_params.sample_validity = resolverParams.sampleValiditySeconds;
res_params.success_threshold = resolverParams.successThreshold;
diff --git a/res_send.cpp b/res_send.cpp
index 46cd31d..a0c3091 100644
--- a/res_send.cpp
+++ b/res_send.cpp
@@ -110,6 +110,7 @@
#include "netd_resolv/resolv.h"
#include "private/android_filesystem_config.h"
+#include "doh.h"
#include "res_comp.h"
#include "res_debug.h"
#include "resolv_cache.h"
@@ -125,6 +126,7 @@
using android::net::CacheStatus;
using android::net::DnsQueryEvent;
using android::net::DnsTlsDispatcher;
+using android::net::DnsTlsServer;
using android::net::DnsTlsTransport;
using android::net::IpVersion;
using android::net::IV_IPV4;
@@ -139,6 +141,7 @@
using android::net::PrivateDnsMode;
using android::net::PrivateDnsModes;
using android::net::PrivateDnsStatus;
+using android::net::PROTO_DOH;
using android::net::PROTO_MDNS;
using android::net::PROTO_TCP;
using android::net::PROTO_UDP;
@@ -164,8 +167,11 @@
static int connect_with_timeout(int sock, const struct sockaddr* nsap, socklen_t salen,
const struct timespec timeout);
static int retrying_poll(const int sock, short events, const struct timespec* finish);
-static int res_tls_send(ResState*, const Slice query, const Slice answer, int* rcode,
- bool* fallback);
+static int res_private_dns_send(ResState*, const Slice query, const Slice answer, int* rcode,
+ bool* fallback);
+static int res_tls_send(const std::list<DnsTlsServer>& tlsServers, ResState*, const Slice query,
+ const Slice answer, int* rcode, PrivateDnsMode mode);
+static ssize_t res_doh_send(ResState*, const Slice query, const Slice answer, int* rcode);
NsType getQueryType(const uint8_t* msg, size_t msgLen) {
ns_msg handle;
@@ -507,14 +513,14 @@
if (sleepTimeMs != 0ms) {
std::this_thread::sleep_for(sleepTimeMs);
}
- // DoT
+ // Private DNS
if (!(statp->netcontext_flags & NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS) &&
!isMdnsResolution(statp->flags)) {
bool fallback = false;
- int resplen = res_tls_send(statp, Slice(const_cast<uint8_t*>(buf), buflen),
- Slice(ans, anssiz), rcode, &fallback);
+ int resplen = res_private_dns_send(statp, Slice(const_cast<uint8_t*>(buf), buflen),
+ Slice(ans, anssiz), rcode, &fallback);
if (resplen > 0) {
- LOG(DEBUG) << __func__ << ": got answer from DoT";
+ LOG(DEBUG) << __func__ << ": got answer from Private DNS";
res_pquery(ans, resplen);
if (cache_status == RESOLV_CACHE_NOTFOUND) {
resolv_cache_add(statp->netid, buf, buflen, ans, resplen);
@@ -1314,60 +1320,108 @@
}
}
-static int res_tls_send(ResState* statp, const Slice query, const Slice answer, int* rcode,
- bool* fallback) {
- int resplen = 0;
+static int res_private_dns_send(ResState* statp, const Slice query, const Slice answer, int* rcode,
+ bool* fallback) {
const unsigned netId = statp->netid;
auto& privateDnsConfiguration = PrivateDnsConfiguration::getInstance();
PrivateDnsStatus privateDnsStatus = privateDnsConfiguration.getStatus(netId);
statp->event->set_private_dns_modes(convertEnumType(privateDnsStatus.mode));
- if (privateDnsStatus.mode == PrivateDnsMode::OFF) {
- *fallback = true;
- return -1;
- }
-
- if (privateDnsStatus.validatedServers().empty()) {
- if (privateDnsStatus.mode == PrivateDnsMode::OPPORTUNISTIC) {
+ const bool enableDoH = isDoHEnabled();
+ ssize_t result = -1;
+ switch (privateDnsStatus.mode) {
+ case PrivateDnsMode::OFF: {
*fallback = true;
return -1;
- } else {
- // Sleep and iterate some small number of times checking for the
- // arrival of resolved and validated server IP addresses, instead
- // of returning an immediate error.
- // This is needed because as soon as a network becomes the default network, apps will
- // send DNS queries on that network. If no servers have yet validated, and we do not
- // block those queries, they would immediately fail, causing application-visible errors.
- // Note that this can happen even before the network validates, since an unvalidated
- // network can become the default network if no validated networks are available.
- //
- // TODO: see if there is a better way to address this problem, such as buffering the
- // queries in a queue or only blocking queries for the first few seconds after a default
- // network change.
- for (int i = 0; i < 42; i++) {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- // Calling getStatus() to merely check if there's any validated server seems
- // wasteful. Consider adding a new method in PrivateDnsConfiguration for speed ups.
- if (!privateDnsConfiguration.getStatus(netId).validatedServers().empty()) {
- privateDnsStatus = privateDnsConfiguration.getStatus(netId);
- break;
- }
+ }
+ case PrivateDnsMode::OPPORTUNISTIC: {
+ *fallback = true;
+ if (enableDoH) {
+ result = res_doh_send(statp, query, answer, rcode);
+ if (result != RESULT_CAN_NOT_SEND) return result;
+ }
+ return res_tls_send(privateDnsStatus.validatedServers(), statp, query, answer, rcode,
+ privateDnsStatus.mode);
+ }
+ case PrivateDnsMode::STRICT: {
+ *fallback = false;
+ if (enableDoH) {
+ result = res_doh_send(statp, query, answer, rcode);
+ if (result != RESULT_CAN_NOT_SEND) return result;
}
if (privateDnsStatus.validatedServers().empty()) {
- return -1;
+ // Sleep and iterate some small number of times checking for the
+ // arrival of resolved and validated server IP addresses, instead
+ // of returning an immediate error.
+ // This is needed because as soon as a network becomes the default network, apps
+ // will send DNS queries on that network. If no servers have yet validated, and we
+ // do not block those queries, they would immediately fail, causing
+ // application-visible errors. Note that this can happen even before the network
+ // validates, since an unvalidated network can become the default network if no
+ // validated networks are available.
+ //
+ // TODO: see if there is a better way to address this problem, such as buffering the
+ // queries in a queue or only blocking queries for the first few seconds after a
+ // default network change.
+ for (int i = 0; i < 42; i++) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ if (enableDoH) {
+ result = res_doh_send(statp, query, answer, rcode);
+ if (result != RESULT_CAN_NOT_SEND) return result;
+ }
+ // Calling getStatus() to merely check if there's any validated server seems
+ // wasteful. Consider adding a new method in PrivateDnsConfiguration for speed
+ // ups.
+ if (!privateDnsConfiguration.getStatus(netId).validatedServers().empty()) {
+ privateDnsStatus = privateDnsConfiguration.getStatus(netId);
+ break;
+ }
+ }
}
+ return res_tls_send(privateDnsStatus.validatedServers(), statp, query, answer, rcode,
+ privateDnsStatus.mode);
}
}
+ LOG(ERROR) << __func__ << ": unknown private DNS mode";
+ return -1;
+}
+ssize_t res_doh_send(ResState* statp, const Slice query, const Slice answer, int* rcode) {
+ auto& privateDnsConfiguration = PrivateDnsConfiguration::getInstance();
+ const unsigned netId = statp->netid;
+ LOG(INFO) << __func__ << ": performing query over Https";
+ Stopwatch queryStopwatch;
+ ssize_t result = privateDnsConfiguration.dohQuery(netId, query, answer, /*timeoutMs*/ 2000);
+ LOG(INFO) << __func__ << ": Https query result: " << result;
+
+ if (result == RESULT_CAN_NOT_SEND) return RESULT_CAN_NOT_SEND;
+
+ DnsQueryEvent* dnsQueryEvent = statp->event->mutable_dns_query_events()->add_dns_query_event();
+ dnsQueryEvent->set_latency_micros(saturate_cast<int32_t>(queryStopwatch.timeTakenUs()));
+ // TODO: Make this information available.
+ // dnsQueryEvent->set_ip_version(ipFamilyToIPVersion(?));
+ if (result > 0) {
+ *rcode = reinterpret_cast<HEADER*>(answer.base())->rcode;
+ } else {
+ *rcode = -result;
+ }
+ dnsQueryEvent->set_rcode(static_cast<NsRcode>(*rcode));
+ dnsQueryEvent->set_protocol(PROTO_DOH);
+ dnsQueryEvent->set_type(getQueryType(query.base(), query.size()));
+ return result;
+}
+
+int res_tls_send(const std::list<DnsTlsServer>& tlsServers, ResState* statp, const Slice query,
+ const Slice answer, int* rcode, PrivateDnsMode mode) {
+ if (tlsServers.empty()) return -1;
LOG(INFO) << __func__ << ": performing query over TLS";
-
- const auto response = DnsTlsDispatcher::getInstance().query(privateDnsStatus.validatedServers(),
- statp, query, answer, &resplen);
+ int resplen = 0;
+ const auto response =
+ DnsTlsDispatcher::getInstance().query(tlsServers, statp, query, answer, &resplen);
LOG(INFO) << __func__ << ": TLS query result: " << static_cast<int>(response);
-
- if (privateDnsStatus.mode == PrivateDnsMode::OPPORTUNISTIC) {
+ if (mode == PrivateDnsMode::OPPORTUNISTIC) {
// In opportunistic mode, handle falling back to cleartext in some
// cases (DNS shouldn't fail if a validated opportunistic mode server
// becomes unreachable for some reason).
@@ -1375,12 +1429,11 @@
case DnsTlsTransport::Response::success:
*rcode = reinterpret_cast<HEADER*>(answer.base())->rcode;
return resplen;
+ // It's OPPORTUNISTIC mode,
+ // hence it's not required to do anything because it'll fallback to UDP.
case DnsTlsTransport::Response::network_error:
- // No need to set the error timeout here since it will fallback to UDP.
+ [[fallthrough]];
case DnsTlsTransport::Response::internal_error:
- // Note: this will cause cleartext queries to be emitted, with
- // all of the EDNS0 goodness enabled. Fingers crossed. :-/
- *fallback = true;
[[fallthrough]];
default:
return -1;
diff --git a/tests/Android.bp b/tests/Android.bp
index 351cea2..896f699 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -103,6 +103,7 @@
"dnsresolver_aidl_interface-lateststable-ndk_platform",
"golddata_proto",
"libcrypto_static",
+ "libdoh_ffi_for_test",
"libgmock",
"libnetd_resolv",
"libnetd_test_dnsresponder_ndk",
@@ -232,6 +233,7 @@
"netd_event_listener_interface-lateststable-ndk_platform",
"libcrypto_static",
"libcutils",
+ "libdoh_ffi_for_test",
"libgmock",
"libnetd_resolv",
"libnetd_test_dnsresponder_ndk",