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/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