Program local and TLS servers, and allow TLS-bypass
This change comprises several parts:
[1] Define a wasExplicitlyConfigured() notion on a DnsTlsServer to
indicate whether the hostname or any fingerprints have been
explicitly set. A DnsTlsServer not wasExplicitlyConfigured()
implies opportunistic mode.
[2] The locally-assigned DNS servers get set in bionic, and the TLS
servers get set in ResolverController.
[3] ResolverController::getPrivateDnsMode returns the Private DNS mode
configured for a given netid.
[4] ResolverController::getValidatedTlsServers() returns a list of
validated DnsTlsServers for a given netid.
[5] The mode and a non-empty list together instruct the qhook in
DnsProxyListener to hand a query off to the DnsTlsDispatcher.
[6] The DnsTlsDispatcher iterates over the list of DnsTlsServers,
preferring servers for which connections already exist.
[7] Enable EDNS0 for DNS-over-TLS queries (set the appropriate flag
in the android_net_context.flags field).
[8] Introduce NETID_USE_LOCAL_NAMESERVERS flag for setting the high
bit of netids in order to pass this informatin across the
app<->netd boundary.
[9] Update setNetworkForResolv and getNetworkForResolv to handle the
NETID_USE_LOCAL_NAMESERVERS flag accordingly.
[10] DnsProxyListener translates the NETID_USE_LOCAL_NAMESERVERS bit
into the NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS flag.
Test: as follows
- built
- flashed
- booted
- ./system/netd/tests/runtests.sh passes
Bug: 34953048
Bug: 64133961
Bug: 72345192
Bug: 76103007
Change-Id: Ib564c6a23c44b36755418fd1557cd86ea54dae44
diff --git a/server/ResolverController.cpp b/server/ResolverController.cpp
index 081eb2a..86bfcb2 100644
--- a/server/ResolverController.cpp
+++ b/server/ResolverController.cpp
@@ -82,11 +82,20 @@
return true;
}
+const char* getPrivateDnsModeString(PrivateDnsMode mode) {
+ switch (mode) {
+ case PrivateDnsMode::OFF: return "OFF";
+ case PrivateDnsMode::OPPORTUNISTIC: return "OPPORTUNISTIC";
+ case PrivateDnsMode::STRICT: return "STRICT";
+ }
+}
+
+std::mutex privateDnsLock;
+std::map<unsigned, PrivateDnsMode> privateDnsModes GUARDED_BY(privateDnsLock);
// Structure for tracking the validation status of servers on a specific netId.
// Using the AddressComparator ensures at most one entry per IP address.
typedef std::map<DnsTlsServer, ResolverController::Validation,
AddressComparator> PrivateDnsTracker;
-std::mutex privateDnsLock;
std::map<unsigned, PrivateDnsTracker> privateDnsTransports GUARDED_BY(privateDnsLock);
EventReporter eventReporter;
android::sp<android::net::metrics::INetdEventListener> netdEventListener;
@@ -165,15 +174,18 @@
validate_thread.detach();
}
-int setPrivateDnsProviders(int32_t netId,
+int setPrivateDnsConfiguration(int32_t netId,
const std::vector<std::string>& servers, const std::string& name,
const std::set<std::vector<uint8_t>>& fingerprints) {
if (DBG) {
- ALOGD("setPrivateDnsProviders(%u, %zu, %s, %zu)",
+ ALOGD("setPrivateDnsConfiguration(%u, %zu, %s, %zu)",
netId, servers.size(), name.c_str(), fingerprints.size());
}
+
+ const bool explicitlyConfigured = !name.empty() || !fingerprints.empty();
+
// Parse the list of servers that has been passed in
- std::set<DnsTlsServer> set;
+ std::set<DnsTlsServer> tlsServers;
for (size_t i = 0; i < servers.size(); ++i) {
sockaddr_storage parsed;
if (!parseServer(servers[i].c_str(), &parsed)) {
@@ -182,10 +194,20 @@
DnsTlsServer server(parsed);
server.name = name;
server.fingerprints = fingerprints;
- set.insert(server);
+ tlsServers.insert(server);
}
std::lock_guard<std::mutex> guard(privateDnsLock);
+ if (explicitlyConfigured) {
+ privateDnsModes[netId] = PrivateDnsMode::STRICT;
+ } else if (!tlsServers.empty()) {
+ privateDnsModes[netId] = PrivateDnsMode::OPPORTUNISTIC;
+ } else {
+ privateDnsModes[netId] = PrivateDnsMode::OFF;
+ privateDnsTransports.erase(netId);
+ return 0;
+ }
+
// Create the tracker if it was not present
auto netPair = privateDnsTransports.find(netId);
if (netPair == privateDnsTransports.end()) {
@@ -201,7 +223,7 @@
// Remove any servers from the tracker that are not in |servers| exactly.
for (auto it = tracker.begin(); it != tracker.end();) {
- if (set.count(it->first) == 0) {
+ if (tlsServers.count(it->first) == 0) {
it = tracker.erase(it);
} else {
++it;
@@ -209,7 +231,7 @@
}
// Add any new or changed servers to the tracker, and initiate async checks for them.
- for (const auto& server : set) {
+ for (const auto& server : tlsServers) {
// Don't probe a server more than once. This means that the only way to
// re-check a failed server is to remove it and re-add it from the netId.
if (tracker.count(server) == 0) {
@@ -224,6 +246,7 @@
ALOGD("clearPrivateDnsProviders(%u)", netId);
}
std::lock_guard<std::mutex> guard(privateDnsLock);
+ privateDnsModes.erase(netId);
privateDnsTransports.erase(netId);
}
@@ -248,37 +271,30 @@
return -_resolv_set_nameservers_for_net(netId, servers, numservers, searchDomains, params);
}
-ResolverController::Validation ResolverController::getTlsStatus(unsigned netId,
- const sockaddr_storage& insecureServer,
- DnsTlsServer* secureServer) {
- // This mutex is on the critical path of every DNS lookup that doesn't hit a local cache.
- // If the overhead of mutex acquisition proves too high, we could reduce it by maintaining
- // an atomic_int32_t counter of validated connections, and returning early if it's zero.
- if (DBG) {
- ALOGD("getTlsStatus(%u, %s)?", netId, addrToString(&insecureServer).c_str());
- }
+ResolverController::PrivateDnsStatus
+ResolverController::getPrivateDnsStatus(unsigned netid) const {
+ PrivateDnsStatus status{PrivateDnsMode::OFF, {}};
+
+ // This mutex is on the critical path of every DNS lookup.
+ //
+ // If the overhead of mutex acquisition proves too high, we could reduce it
+ // by maintaining an atomic_int32_t counter of TLS-enabled netids, or by
+ // using an RWLock.
std::lock_guard<std::mutex> guard(privateDnsLock);
- const auto netPair = privateDnsTransports.find(netId);
- if (netPair == privateDnsTransports.end()) {
- if (DBG) {
- ALOGD("Not using TLS: no tracked servers for netId %u", netId);
+
+ const auto mode = privateDnsModes.find(netid);
+ if (mode == privateDnsModes.end()) return status;
+ status.mode = mode->second;
+
+ const auto netPair = privateDnsTransports.find(netid);
+ if (netPair != privateDnsTransports.end()) {
+ for (const auto& serverPair : netPair->second) {
+ if (serverPair.second == Validation::success) {
+ status.validatedServers.push_back(serverPair.first);
+ }
}
- return Validation::unknown_netid;
}
- const auto& tracker = netPair->second;
- const auto serverPair = tracker.find(insecureServer);
- if (serverPair == tracker.end()) {
- if (DBG) {
- ALOGD("Server is not in the tracker (size %zu) for netid %u", tracker.size(), netId);
- }
- return Validation::unknown_server;
- }
- const auto& validatedServer = serverPair->first;
- Validation status = serverPair->second;
- if (DBG) {
- ALOGD("Server %s has status %d", addrToString(&(validatedServer.ss)).c_str(), (int)status);
- }
- *secureServer = validatedServer;
+
return status;
}
@@ -383,30 +399,16 @@
return -EINVAL;
}
- if (!tlsServers.empty()) {
- const int err = setPrivateDnsProviders(netId, tlsServers, tlsName, tlsFingerprints);
- if (err != 0) {
- return err;
- }
- } else {
- clearPrivateDnsProviders(netId);
+ const int err = setPrivateDnsConfiguration(netId, tlsServers, tlsName, tlsFingerprints);
+ if (err != 0) {
+ return err;
}
- // TODO: separate out configuring TLS servers and locally-assigned servers.
- // We should always program bionic with locally-assigned servers, so we can
- // make TLS-bypass simple by not setting .qhook in the right circumstances.
- // Relatedly, shunting queries to DNS-over-TLS should not be based on
- // matching resolver IPs in the qhook but rather purely a function of the
- // current state of DNS-over-TLS as known only within the dispatcher.
- const std::vector<std::string>& nameservers = (!tlsServers.empty())
- ? tlsServers // Strict mode or Opportunistic
- : servers; // off
-
- // Convert server list to bionic's format.
- auto server_count = std::min<size_t>(MAXNS, nameservers.size());
+ // Convert network-assigned server list to bionic's format.
+ auto server_count = std::min<size_t>(MAXNS, servers.size());
std::vector<const char*> server_ptrs;
for (size_t i = 0 ; i < server_count ; ++i) {
- server_ptrs.push_back(nameservers[i].c_str());
+ server_ptrs.push_back(servers[i].c_str());
}
std::string domains_str;
@@ -502,9 +504,12 @@
}
{
std::lock_guard<std::mutex> guard(privateDnsLock);
+ const auto& mode = privateDnsModes.find(netId);
+ dw.println("Private DNS mode: %s", getPrivateDnsModeString(
+ mode != privateDnsModes.end() ? mode->second : PrivateDnsMode::OFF));
const auto& netPair = privateDnsTransports.find(netId);
if (netPair == privateDnsTransports.end()) {
- dw.println("No Private DNS configured");
+ dw.println("No Private DNS servers configured");
} else {
const auto& tracker = netPair->second;
dw.println("Private DNS configuration (%zu entries)", tracker.size());