blob: a34b6faa6367b7f273ac400f505ea84c71671c88 [file] [log] [blame]
Mike Yub601ff72018-11-01 20:07:00 +08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "PrivateDnsConfiguration"
18#define DBG 0
19
Mike Yu303b0df2018-12-24 17:05:02 +080020#include "PrivateDnsConfiguration.h"
21
Mike Yub601ff72018-11-01 20:07:00 +080022#include <log/log.h>
23#include <netdb.h>
24#include <sys/socket.h>
25
Bernie Innocentiec4219b2019-01-30 11:16:36 +090026#include "DnsTlsTransport.h"
Mike Yu303b0df2018-12-24 17:05:02 +080027#include "ResolverEventReporter.h"
Bernie Innocentiec4219b2019-01-30 11:16:36 +090028#include "netd_resolv/resolv.h"
Mike Yub601ff72018-11-01 20:07:00 +080029#include "netdutils/BackoffSequence.h"
30
Mike Yu303b0df2018-12-24 17:05:02 +080031using aidl::android::net::metrics::INetdEventListener;
32
Mike Yub601ff72018-11-01 20:07:00 +080033int resolv_set_private_dns_for_net(unsigned netid, uint32_t mark, const char** servers,
Bernie Innocentib102dd22018-12-04 14:57:48 +090034 const int numServers, const char* tlsName,
35 const uint8_t** fingerprints, const int numFingerprint) {
Mike Yub601ff72018-11-01 20:07:00 +080036 std::vector<std::string> tlsServers;
Bernie Innocentib102dd22018-12-04 14:57:48 +090037 for (int i = 0; i < numServers; i++) {
Mike Yub601ff72018-11-01 20:07:00 +080038 tlsServers.push_back(std::string(servers[i]));
39 }
40
41 std::set<std::vector<uint8_t>> tlsFingerprints;
Bernie Innocentib102dd22018-12-04 14:57:48 +090042 for (int i = 0; i < numFingerprint; i++) {
Mike Yub601ff72018-11-01 20:07:00 +080043 // Each fingerprint stored are 32(SHA256_SIZE) bytes long.
44 tlsFingerprints.emplace(std::vector<uint8_t>(fingerprints[i], fingerprints[i] + 32));
45 }
46
47 return android::net::gPrivateDnsConfiguration.set(netid, mark, tlsServers, std::string(tlsName),
48 tlsFingerprints);
49}
50
51void resolv_delete_private_dns_for_net(unsigned netid) {
52 android::net::gPrivateDnsConfiguration.clear(netid);
53}
54
55void resolv_get_private_dns_status_for_net(unsigned netid, ExternalPrivateDnsStatus* status) {
56 android::net::gPrivateDnsConfiguration.getStatus(netid, status);
57}
58
Mike Yub601ff72018-11-01 20:07:00 +080059namespace android {
60
61using android::netdutils::BackoffSequence;
62
63namespace net {
64
65std::string addrToString(const sockaddr_storage* addr) {
66 char out[INET6_ADDRSTRLEN] = {0};
67 getnameinfo((const sockaddr*) addr, sizeof(sockaddr_storage), out, INET6_ADDRSTRLEN, nullptr, 0,
68 NI_NUMERICHOST);
69 return std::string(out);
70}
71
72bool parseServer(const char* server, sockaddr_storage* parsed) {
73 addrinfo hints = {.ai_family = AF_UNSPEC, .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV};
74 addrinfo* res;
75
76 int err = getaddrinfo(server, "853", &hints, &res);
77 if (err != 0) {
78 ALOGW("Failed to parse server address (%s): %s", server, gai_strerror(err));
79 return false;
80 }
81
82 memcpy(parsed, res->ai_addr, res->ai_addrlen);
83 freeaddrinfo(res);
84 return true;
85}
86
Mike Yub601ff72018-11-01 20:07:00 +080087int PrivateDnsConfiguration::set(int32_t netId, uint32_t mark,
88 const std::vector<std::string>& servers, const std::string& name,
89 const std::set<std::vector<uint8_t>>& fingerprints) {
90 if (DBG) {
91 ALOGD("PrivateDnsConfiguration::set(%u, %zu, %s, %zu)", netId, servers.size(), name.c_str(),
92 fingerprints.size());
93 }
94
95 const bool explicitlyConfigured = !name.empty() || !fingerprints.empty();
96
97 // Parse the list of servers that has been passed in
98 std::set<DnsTlsServer> tlsServers;
99 for (size_t i = 0; i < servers.size(); ++i) {
100 sockaddr_storage parsed;
101 if (!parseServer(servers[i].c_str(), &parsed)) {
102 return -EINVAL;
103 }
104 DnsTlsServer server(parsed);
105 server.name = name;
106 server.fingerprints = fingerprints;
107 tlsServers.insert(server);
108 }
109
110 std::lock_guard guard(mPrivateDnsLock);
111 if (explicitlyConfigured) {
112 mPrivateDnsModes[netId] = PrivateDnsMode::STRICT;
113 } else if (!tlsServers.empty()) {
114 mPrivateDnsModes[netId] = PrivateDnsMode::OPPORTUNISTIC;
115 } else {
116 mPrivateDnsModes[netId] = PrivateDnsMode::OFF;
117 mPrivateDnsTransports.erase(netId);
118 return 0;
119 }
120
121 // Create the tracker if it was not present
122 auto netPair = mPrivateDnsTransports.find(netId);
123 if (netPair == mPrivateDnsTransports.end()) {
124 // No TLS tracker yet for this netId.
125 bool added;
126 std::tie(netPair, added) = mPrivateDnsTransports.emplace(netId, PrivateDnsTracker());
127 if (!added) {
128 ALOGE("Memory error while recording private DNS for netId %d", netId);
129 return -ENOMEM;
130 }
131 }
132 auto& tracker = netPair->second;
133
134 // Remove any servers from the tracker that are not in |servers| exactly.
135 for (auto it = tracker.begin(); it != tracker.end();) {
136 if (tlsServers.count(it->first) == 0) {
137 it = tracker.erase(it);
138 } else {
139 ++it;
140 }
141 }
142
143 // Add any new or changed servers to the tracker, and initiate async checks for them.
144 for (const auto& server : tlsServers) {
145 if (needsValidation(tracker, server)) {
146 validatePrivateDnsProvider(server, tracker, netId, mark);
147 }
148 }
149 return 0;
150}
151
152PrivateDnsStatus PrivateDnsConfiguration::getStatus(unsigned netId) {
153 PrivateDnsStatus status{PrivateDnsMode::OFF, {}};
154
155 // This mutex is on the critical path of every DNS lookup.
156 //
157 // If the overhead of mutex acquisition proves too high, we could reduce
158 // it by maintaining an atomic_int32_t counter of TLS-enabled netids, or
159 // by using an RWLock.
160 std::lock_guard guard(mPrivateDnsLock);
161
162 const auto mode = mPrivateDnsModes.find(netId);
163 if (mode == mPrivateDnsModes.end()) return status;
164 status.mode = mode->second;
165
166 const auto netPair = mPrivateDnsTransports.find(netId);
167 if (netPair != mPrivateDnsTransports.end()) {
168 for (const auto& serverPair : netPair->second) {
169 if (serverPair.second == Validation::success) {
170 status.validatedServers.push_back(serverPair.first);
171 }
172 }
173 }
174
175 return status;
176}
177
178void PrivateDnsConfiguration::getStatus(unsigned netId, ExternalPrivateDnsStatus* status) {
179 // This mutex is on the critical path of every DNS lookup.
180 //
181 // If the overhead of mutex acquisition proves too high, we could reduce
182 // it by maintaining an atomic_int32_t counter of TLS-enabled netids, or
183 // by using an RWLock.
184 std::lock_guard guard(mPrivateDnsLock);
185
186 const auto mode = mPrivateDnsModes.find(netId);
187 if (mode == mPrivateDnsModes.end()) return;
188 status->mode = mode->second;
189
190 const auto netPair = mPrivateDnsTransports.find(netId);
191 if (netPair != mPrivateDnsTransports.end()) {
Mike Yub601ff72018-11-01 20:07:00 +0800192 int count = 0;
193 for (const auto& serverPair : netPair->second) {
194 status->serverStatus[count].ss = serverPair.first.ss;
195 status->serverStatus[count].hostname =
196 serverPair.first.name.empty() ? "" : serverPair.first.name.c_str();
197 status->serverStatus[count].validation = serverPair.second;
Mike Yub601ff72018-11-01 20:07:00 +0800198 count++;
Bernie Innocenti4c2a4612018-11-20 19:23:56 +0900199 if (count >= MAXNS) break; // Lose the rest
Mike Yub601ff72018-11-01 20:07:00 +0800200 }
Bernie Innocenti93390222019-01-10 18:33:45 +0900201 status->numServers = count;
Mike Yub601ff72018-11-01 20:07:00 +0800202 }
203}
204
205void PrivateDnsConfiguration::clear(unsigned netId) {
206 if (DBG) {
207 ALOGD("PrivateDnsConfiguration::clear(%u)", netId);
208 }
209 std::lock_guard guard(mPrivateDnsLock);
210 mPrivateDnsModes.erase(netId);
211 mPrivateDnsTransports.erase(netId);
212}
213
214void PrivateDnsConfiguration::validatePrivateDnsProvider(const DnsTlsServer& server,
215 PrivateDnsTracker& tracker, unsigned netId,
216 uint32_t mark) REQUIRES(mPrivateDnsLock) {
217 if (DBG) {
Mike Yu303b0df2018-12-24 17:05:02 +0800218 ALOGD("validatePrivateDnsProvider(%s, %u)", addrToString(&server.ss).c_str(), netId);
Mike Yub601ff72018-11-01 20:07:00 +0800219 }
220
221 tracker[server] = Validation::in_process;
222 if (DBG) {
223 ALOGD("Server %s marked as in_process. Tracker now has size %zu",
Mike Yu303b0df2018-12-24 17:05:02 +0800224 addrToString(&server.ss).c_str(), tracker.size());
Mike Yub601ff72018-11-01 20:07:00 +0800225 }
226 // Note that capturing |server| and |netId| in this lambda create copies.
227 std::thread validate_thread([this, server, netId, mark] {
228 // cat /proc/sys/net/ipv4/tcp_syn_retries yields "6".
229 //
230 // Start with a 1 minute delay and backoff to once per hour.
231 //
232 // Assumptions:
233 // [1] Each TLS validation is ~10KB of certs+handshake+payload.
234 // [2] Network typically provision clients with <=4 nameservers.
235 // [3] Average month has 30 days.
236 //
237 // Each validation pass in a given hour is ~1.2MB of data. And 24
238 // such validation passes per day is about ~30MB per month, in the
239 // worst case. Otherwise, this will cost ~600 SYNs per month
240 // (6 SYNs per ip, 4 ips per validation pass, 24 passes per day).
241 auto backoff = BackoffSequence<>::Builder()
242 .withInitialRetransmissionTime(std::chrono::seconds(60))
243 .withMaximumRetransmissionTime(std::chrono::seconds(3600))
244 .build();
245
246 while (true) {
247 // ::validate() is a blocking call that performs network operations.
248 // It can take milliseconds to minutes, up to the SYN retry limit.
249 const bool success = DnsTlsTransport::validate(server, netId, mark);
250 if (DBG) {
251 ALOGD("validateDnsTlsServer returned %d for %s", success,
Mike Yu303b0df2018-12-24 17:05:02 +0800252 addrToString(&server.ss).c_str());
Mike Yub601ff72018-11-01 20:07:00 +0800253 }
254
255 const bool needs_reeval = this->recordPrivateDnsValidation(server, netId, success);
256 if (!needs_reeval) {
257 break;
258 }
259
260 if (backoff.hasNextTimeout()) {
261 std::this_thread::sleep_for(backoff.getNextTimeout());
262 } else {
263 break;
264 }
265 }
266 });
267 validate_thread.detach();
268}
269
270bool PrivateDnsConfiguration::recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId,
271 bool success) {
272 constexpr bool NEEDS_REEVALUATION = true;
273 constexpr bool DONT_REEVALUATE = false;
274
275 std::lock_guard guard(mPrivateDnsLock);
276
277 auto netPair = mPrivateDnsTransports.find(netId);
278 if (netPair == mPrivateDnsTransports.end()) {
279 ALOGW("netId %u was erased during private DNS validation", netId);
280 return DONT_REEVALUATE;
281 }
282
283 const auto mode = mPrivateDnsModes.find(netId);
284 if (mode == mPrivateDnsModes.end()) {
285 ALOGW("netId %u has no private DNS validation mode", netId);
286 return DONT_REEVALUATE;
287 }
288 const bool modeDoesReevaluation = (mode->second == PrivateDnsMode::STRICT);
289
290 bool reevaluationStatus =
291 (success || !modeDoesReevaluation) ? DONT_REEVALUATE : NEEDS_REEVALUATION;
292
293 auto& tracker = netPair->second;
294 auto serverPair = tracker.find(server);
295 if (serverPair == tracker.end()) {
296 ALOGW("Server %s was removed during private DNS validation",
Mike Yu303b0df2018-12-24 17:05:02 +0800297 addrToString(&server.ss).c_str());
Mike Yub601ff72018-11-01 20:07:00 +0800298 success = false;
299 reevaluationStatus = DONT_REEVALUATE;
300 } else if (!(serverPair->first == server)) {
301 // TODO: It doesn't seem correct to overwrite the tracker entry for
302 // |server| down below in this circumstance... Fix this.
303 ALOGW("Server %s was changed during private DNS validation",
Mike Yu303b0df2018-12-24 17:05:02 +0800304 addrToString(&server.ss).c_str());
Mike Yub601ff72018-11-01 20:07:00 +0800305 success = false;
306 reevaluationStatus = DONT_REEVALUATE;
307 }
308
Mike Yu303b0df2018-12-24 17:05:02 +0800309 // Send a validation event to NetdEventListenerService.
310 const std::shared_ptr<INetdEventListener> listener = ResolverEventReporter::getListener();
311 if (listener != nullptr) {
312 listener->onPrivateDnsValidationEvent(netId, addrToString(&server.ss), server.name,
313 success);
314 if (DBG) {
315 ALOGD("Sent validation %s event on netId %u for %s with hostname %s",
316 success ? "success" : "failure", netId, addrToString(&server.ss).c_str(),
317 server.name.c_str());
318 }
319 } else {
320 ALOGE("Validation event not sent since NetdEventListenerService is unavailable.");
Mike Yub601ff72018-11-01 20:07:00 +0800321 }
322
323 if (success) {
324 tracker[server] = Validation::success;
325 if (DBG) {
326 ALOGD("Validation succeeded for %s! Tracker now has %zu entries.",
Mike Yu303b0df2018-12-24 17:05:02 +0800327 addrToString(&server.ss).c_str(), tracker.size());
Mike Yub601ff72018-11-01 20:07:00 +0800328 }
329 } else {
330 // Validation failure is expected if a user is on a captive portal.
331 // TODO: Trigger a second validation attempt after captive portal login
332 // succeeds.
333 tracker[server] = (reevaluationStatus == NEEDS_REEVALUATION) ? Validation::in_process
334 : Validation::fail;
335 if (DBG) {
Mike Yu303b0df2018-12-24 17:05:02 +0800336 ALOGD("Validation failed for %s!", addrToString(&server.ss).c_str());
Mike Yub601ff72018-11-01 20:07:00 +0800337 }
338 }
339
340 return reevaluationStatus;
341}
342
343// Start validation for newly added servers as well as any servers that have
344// landed in Validation::fail state. Note that servers that have failed
345// multiple validation attempts but for which there is still a validating
346// thread running are marked as being Validation::in_process.
347bool PrivateDnsConfiguration::needsValidation(const PrivateDnsTracker& tracker,
348 const DnsTlsServer& server) {
349 const auto& iter = tracker.find(server);
350 return (iter == tracker.end()) || (iter->second == Validation::fail);
351}
352
353PrivateDnsConfiguration gPrivateDnsConfiguration;
354
355} // namespace net
356} // namespace android