blob: 5309e36c8441f7ff12b4adc72b746375c077c486 [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
20#include <log/log.h>
21#include <netdb.h>
22#include <sys/socket.h>
23
Bernie Innocentiec4219b2019-01-30 11:16:36 +090024#include "DnsTlsTransport.h"
25#include "PrivateDnsConfiguration.h"
26#include "netd_resolv/resolv.h"
Mike Yub601ff72018-11-01 20:07:00 +080027#include "netdutils/BackoffSequence.h"
28
29int resolv_set_private_dns_for_net(unsigned netid, uint32_t mark, const char** servers,
Bernie Innocentib102dd22018-12-04 14:57:48 +090030 const int numServers, const char* tlsName,
31 const uint8_t** fingerprints, const int numFingerprint) {
Mike Yub601ff72018-11-01 20:07:00 +080032 std::vector<std::string> tlsServers;
Bernie Innocentib102dd22018-12-04 14:57:48 +090033 for (int i = 0; i < numServers; i++) {
Mike Yub601ff72018-11-01 20:07:00 +080034 tlsServers.push_back(std::string(servers[i]));
35 }
36
37 std::set<std::vector<uint8_t>> tlsFingerprints;
Bernie Innocentib102dd22018-12-04 14:57:48 +090038 for (int i = 0; i < numFingerprint; i++) {
Mike Yub601ff72018-11-01 20:07:00 +080039 // Each fingerprint stored are 32(SHA256_SIZE) bytes long.
40 tlsFingerprints.emplace(std::vector<uint8_t>(fingerprints[i], fingerprints[i] + 32));
41 }
42
43 return android::net::gPrivateDnsConfiguration.set(netid, mark, tlsServers, std::string(tlsName),
44 tlsFingerprints);
45}
46
47void resolv_delete_private_dns_for_net(unsigned netid) {
48 android::net::gPrivateDnsConfiguration.clear(netid);
49}
50
51void resolv_get_private_dns_status_for_net(unsigned netid, ExternalPrivateDnsStatus* status) {
52 android::net::gPrivateDnsConfiguration.getStatus(netid, status);
53}
54
55void resolv_register_private_dns_callback(private_dns_validated_callback callback) {
56 android::net::gPrivateDnsConfiguration.setCallback(callback);
57}
58
59namespace 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
87void PrivateDnsConfiguration::setCallback(private_dns_validated_callback callback) {
88 if (mCallback == nullptr) {
89 mCallback = callback;
90 }
91}
92
93int PrivateDnsConfiguration::set(int32_t netId, uint32_t mark,
94 const std::vector<std::string>& servers, const std::string& name,
95 const std::set<std::vector<uint8_t>>& fingerprints) {
96 if (DBG) {
97 ALOGD("PrivateDnsConfiguration::set(%u, %zu, %s, %zu)", netId, servers.size(), name.c_str(),
98 fingerprints.size());
99 }
100
101 const bool explicitlyConfigured = !name.empty() || !fingerprints.empty();
102
103 // Parse the list of servers that has been passed in
104 std::set<DnsTlsServer> tlsServers;
105 for (size_t i = 0; i < servers.size(); ++i) {
106 sockaddr_storage parsed;
107 if (!parseServer(servers[i].c_str(), &parsed)) {
108 return -EINVAL;
109 }
110 DnsTlsServer server(parsed);
111 server.name = name;
112 server.fingerprints = fingerprints;
113 tlsServers.insert(server);
114 }
115
116 std::lock_guard guard(mPrivateDnsLock);
117 if (explicitlyConfigured) {
118 mPrivateDnsModes[netId] = PrivateDnsMode::STRICT;
119 } else if (!tlsServers.empty()) {
120 mPrivateDnsModes[netId] = PrivateDnsMode::OPPORTUNISTIC;
121 } else {
122 mPrivateDnsModes[netId] = PrivateDnsMode::OFF;
123 mPrivateDnsTransports.erase(netId);
124 return 0;
125 }
126
127 // Create the tracker if it was not present
128 auto netPair = mPrivateDnsTransports.find(netId);
129 if (netPair == mPrivateDnsTransports.end()) {
130 // No TLS tracker yet for this netId.
131 bool added;
132 std::tie(netPair, added) = mPrivateDnsTransports.emplace(netId, PrivateDnsTracker());
133 if (!added) {
134 ALOGE("Memory error while recording private DNS for netId %d", netId);
135 return -ENOMEM;
136 }
137 }
138 auto& tracker = netPair->second;
139
140 // Remove any servers from the tracker that are not in |servers| exactly.
141 for (auto it = tracker.begin(); it != tracker.end();) {
142 if (tlsServers.count(it->first) == 0) {
143 it = tracker.erase(it);
144 } else {
145 ++it;
146 }
147 }
148
149 // Add any new or changed servers to the tracker, and initiate async checks for them.
150 for (const auto& server : tlsServers) {
151 if (needsValidation(tracker, server)) {
152 validatePrivateDnsProvider(server, tracker, netId, mark);
153 }
154 }
155 return 0;
156}
157
158PrivateDnsStatus PrivateDnsConfiguration::getStatus(unsigned netId) {
159 PrivateDnsStatus status{PrivateDnsMode::OFF, {}};
160
161 // This mutex is on the critical path of every DNS lookup.
162 //
163 // If the overhead of mutex acquisition proves too high, we could reduce
164 // it by maintaining an atomic_int32_t counter of TLS-enabled netids, or
165 // by using an RWLock.
166 std::lock_guard guard(mPrivateDnsLock);
167
168 const auto mode = mPrivateDnsModes.find(netId);
169 if (mode == mPrivateDnsModes.end()) return status;
170 status.mode = mode->second;
171
172 const auto netPair = mPrivateDnsTransports.find(netId);
173 if (netPair != mPrivateDnsTransports.end()) {
174 for (const auto& serverPair : netPair->second) {
175 if (serverPair.second == Validation::success) {
176 status.validatedServers.push_back(serverPair.first);
177 }
178 }
179 }
180
181 return status;
182}
183
184void PrivateDnsConfiguration::getStatus(unsigned netId, ExternalPrivateDnsStatus* status) {
185 // This mutex is on the critical path of every DNS lookup.
186 //
187 // If the overhead of mutex acquisition proves too high, we could reduce
188 // it by maintaining an atomic_int32_t counter of TLS-enabled netids, or
189 // by using an RWLock.
190 std::lock_guard guard(mPrivateDnsLock);
191
192 const auto mode = mPrivateDnsModes.find(netId);
193 if (mode == mPrivateDnsModes.end()) return;
194 status->mode = mode->second;
195
196 const auto netPair = mPrivateDnsTransports.find(netId);
197 if (netPair != mPrivateDnsTransports.end()) {
Mike Yub601ff72018-11-01 20:07:00 +0800198 int count = 0;
199 for (const auto& serverPair : netPair->second) {
200 status->serverStatus[count].ss = serverPair.first.ss;
201 status->serverStatus[count].hostname =
202 serverPair.first.name.empty() ? "" : serverPair.first.name.c_str();
203 status->serverStatus[count].validation = serverPair.second;
Mike Yub601ff72018-11-01 20:07:00 +0800204 count++;
Bernie Innocenti4c2a4612018-11-20 19:23:56 +0900205 if (count >= MAXNS) break; // Lose the rest
Mike Yub601ff72018-11-01 20:07:00 +0800206 }
Bernie Innocenti93390222019-01-10 18:33:45 +0900207 status->numServers = count;
Mike Yub601ff72018-11-01 20:07:00 +0800208 }
209}
210
211void PrivateDnsConfiguration::clear(unsigned netId) {
212 if (DBG) {
213 ALOGD("PrivateDnsConfiguration::clear(%u)", netId);
214 }
215 std::lock_guard guard(mPrivateDnsLock);
216 mPrivateDnsModes.erase(netId);
217 mPrivateDnsTransports.erase(netId);
218}
219
220void PrivateDnsConfiguration::validatePrivateDnsProvider(const DnsTlsServer& server,
221 PrivateDnsTracker& tracker, unsigned netId,
222 uint32_t mark) REQUIRES(mPrivateDnsLock) {
223 if (DBG) {
224 ALOGD("validatePrivateDnsProvider(%s, %u)", addrToString(&(server.ss)).c_str(), netId);
225 }
226
227 tracker[server] = Validation::in_process;
228 if (DBG) {
229 ALOGD("Server %s marked as in_process. Tracker now has size %zu",
230 addrToString(&(server.ss)).c_str(), tracker.size());
231 }
232 // Note that capturing |server| and |netId| in this lambda create copies.
233 std::thread validate_thread([this, server, netId, mark] {
234 // cat /proc/sys/net/ipv4/tcp_syn_retries yields "6".
235 //
236 // Start with a 1 minute delay and backoff to once per hour.
237 //
238 // Assumptions:
239 // [1] Each TLS validation is ~10KB of certs+handshake+payload.
240 // [2] Network typically provision clients with <=4 nameservers.
241 // [3] Average month has 30 days.
242 //
243 // Each validation pass in a given hour is ~1.2MB of data. And 24
244 // such validation passes per day is about ~30MB per month, in the
245 // worst case. Otherwise, this will cost ~600 SYNs per month
246 // (6 SYNs per ip, 4 ips per validation pass, 24 passes per day).
247 auto backoff = BackoffSequence<>::Builder()
248 .withInitialRetransmissionTime(std::chrono::seconds(60))
249 .withMaximumRetransmissionTime(std::chrono::seconds(3600))
250 .build();
251
252 while (true) {
253 // ::validate() is a blocking call that performs network operations.
254 // It can take milliseconds to minutes, up to the SYN retry limit.
255 const bool success = DnsTlsTransport::validate(server, netId, mark);
256 if (DBG) {
257 ALOGD("validateDnsTlsServer returned %d for %s", success,
258 addrToString(&(server.ss)).c_str());
259 }
260
261 const bool needs_reeval = this->recordPrivateDnsValidation(server, netId, success);
262 if (!needs_reeval) {
263 break;
264 }
265
266 if (backoff.hasNextTimeout()) {
267 std::this_thread::sleep_for(backoff.getNextTimeout());
268 } else {
269 break;
270 }
271 }
272 });
273 validate_thread.detach();
274}
275
276bool PrivateDnsConfiguration::recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId,
277 bool success) {
278 constexpr bool NEEDS_REEVALUATION = true;
279 constexpr bool DONT_REEVALUATE = false;
280
281 std::lock_guard guard(mPrivateDnsLock);
282
283 auto netPair = mPrivateDnsTransports.find(netId);
284 if (netPair == mPrivateDnsTransports.end()) {
285 ALOGW("netId %u was erased during private DNS validation", netId);
286 return DONT_REEVALUATE;
287 }
288
289 const auto mode = mPrivateDnsModes.find(netId);
290 if (mode == mPrivateDnsModes.end()) {
291 ALOGW("netId %u has no private DNS validation mode", netId);
292 return DONT_REEVALUATE;
293 }
294 const bool modeDoesReevaluation = (mode->second == PrivateDnsMode::STRICT);
295
296 bool reevaluationStatus =
297 (success || !modeDoesReevaluation) ? DONT_REEVALUATE : NEEDS_REEVALUATION;
298
299 auto& tracker = netPair->second;
300 auto serverPair = tracker.find(server);
301 if (serverPair == tracker.end()) {
302 ALOGW("Server %s was removed during private DNS validation",
303 addrToString(&(server.ss)).c_str());
304 success = false;
305 reevaluationStatus = DONT_REEVALUATE;
306 } else if (!(serverPair->first == server)) {
307 // TODO: It doesn't seem correct to overwrite the tracker entry for
308 // |server| down below in this circumstance... Fix this.
309 ALOGW("Server %s was changed during private DNS validation",
310 addrToString(&(server.ss)).c_str());
311 success = false;
312 reevaluationStatus = DONT_REEVALUATE;
313 }
314
315 // Invoke the callback to send a validation event to NetdEventListenerService.
316 if (mCallback != nullptr) {
Ken Chence0a9d42018-11-14 15:59:41 +0800317 const std::string ipLiteral = addrToString(&(server.ss));
Mike Yub601ff72018-11-01 20:07:00 +0800318 const char* hostname = server.name.empty() ? "" : server.name.c_str();
Ken Chence0a9d42018-11-14 15:59:41 +0800319 mCallback(netId, ipLiteral.c_str(), hostname, success);
Mike Yub601ff72018-11-01 20:07:00 +0800320 }
321
322 if (success) {
323 tracker[server] = Validation::success;
324 if (DBG) {
325 ALOGD("Validation succeeded for %s! Tracker now has %zu entries.",
326 addrToString(&(server.ss)).c_str(), tracker.size());
327 }
328 } else {
329 // Validation failure is expected if a user is on a captive portal.
330 // TODO: Trigger a second validation attempt after captive portal login
331 // succeeds.
332 tracker[server] = (reevaluationStatus == NEEDS_REEVALUATION) ? Validation::in_process
333 : Validation::fail;
334 if (DBG) {
335 ALOGD("Validation failed for %s!", addrToString(&(server.ss)).c_str());
336 }
337 }
338
339 return reevaluationStatus;
340}
341
342// Start validation for newly added servers as well as any servers that have
343// landed in Validation::fail state. Note that servers that have failed
344// multiple validation attempts but for which there is still a validating
345// thread running are marked as being Validation::in_process.
346bool PrivateDnsConfiguration::needsValidation(const PrivateDnsTracker& tracker,
347 const DnsTlsServer& server) {
348 const auto& iter = tracker.find(server);
349 return (iter == tracker.end()) || (iter->second == Validation::fail);
350}
351
352PrivateDnsConfiguration gPrivateDnsConfiguration;
353
354} // namespace net
355} // namespace android