blob: 29b827ee7d5b50c887fb7f7dc4df24796e25066f [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
Ken Chen5471dca2019-04-15 15:25:35 +080017#define LOG_TAG "resolv"
Mike Yub601ff72018-11-01 20:07:00 +080018#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
31int resolv_set_private_dns_for_net(unsigned netid, uint32_t mark, const char** servers,
Bernie Innocentib102dd22018-12-04 14:57:48 +090032 const int numServers, const char* tlsName,
33 const uint8_t** fingerprints, const int numFingerprint) {
Mike Yub601ff72018-11-01 20:07:00 +080034 std::vector<std::string> tlsServers;
Bernie Innocentib102dd22018-12-04 14:57:48 +090035 for (int i = 0; i < numServers; i++) {
Mike Yub601ff72018-11-01 20:07:00 +080036 tlsServers.push_back(std::string(servers[i]));
37 }
38
39 std::set<std::vector<uint8_t>> tlsFingerprints;
Bernie Innocentib102dd22018-12-04 14:57:48 +090040 for (int i = 0; i < numFingerprint; i++) {
Mike Yub601ff72018-11-01 20:07:00 +080041 // Each fingerprint stored are 32(SHA256_SIZE) bytes long.
42 tlsFingerprints.emplace(std::vector<uint8_t>(fingerprints[i], fingerprints[i] + 32));
43 }
44
45 return android::net::gPrivateDnsConfiguration.set(netid, mark, tlsServers, std::string(tlsName),
46 tlsFingerprints);
47}
48
49void resolv_delete_private_dns_for_net(unsigned netid) {
50 android::net::gPrivateDnsConfiguration.clear(netid);
51}
52
Mike Yub601ff72018-11-01 20:07:00 +080053namespace android {
Mike Yub601ff72018-11-01 20:07:00 +080054namespace net {
55
56std::string addrToString(const sockaddr_storage* addr) {
57 char out[INET6_ADDRSTRLEN] = {0};
58 getnameinfo((const sockaddr*) addr, sizeof(sockaddr_storage), out, INET6_ADDRSTRLEN, nullptr, 0,
59 NI_NUMERICHOST);
60 return std::string(out);
61}
62
63bool parseServer(const char* server, sockaddr_storage* parsed) {
64 addrinfo hints = {.ai_family = AF_UNSPEC, .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV};
65 addrinfo* res;
66
67 int err = getaddrinfo(server, "853", &hints, &res);
68 if (err != 0) {
69 ALOGW("Failed to parse server address (%s): %s", server, gai_strerror(err));
70 return false;
71 }
72
73 memcpy(parsed, res->ai_addr, res->ai_addrlen);
74 freeaddrinfo(res);
75 return true;
76}
77
Mike Yub601ff72018-11-01 20:07:00 +080078int PrivateDnsConfiguration::set(int32_t netId, uint32_t mark,
79 const std::vector<std::string>& servers, const std::string& name,
80 const std::set<std::vector<uint8_t>>& fingerprints) {
81 if (DBG) {
82 ALOGD("PrivateDnsConfiguration::set(%u, %zu, %s, %zu)", netId, servers.size(), name.c_str(),
83 fingerprints.size());
84 }
85
86 const bool explicitlyConfigured = !name.empty() || !fingerprints.empty();
87
88 // Parse the list of servers that has been passed in
89 std::set<DnsTlsServer> tlsServers;
90 for (size_t i = 0; i < servers.size(); ++i) {
91 sockaddr_storage parsed;
92 if (!parseServer(servers[i].c_str(), &parsed)) {
93 return -EINVAL;
94 }
95 DnsTlsServer server(parsed);
96 server.name = name;
97 server.fingerprints = fingerprints;
98 tlsServers.insert(server);
99 }
100
101 std::lock_guard guard(mPrivateDnsLock);
102 if (explicitlyConfigured) {
103 mPrivateDnsModes[netId] = PrivateDnsMode::STRICT;
104 } else if (!tlsServers.empty()) {
105 mPrivateDnsModes[netId] = PrivateDnsMode::OPPORTUNISTIC;
106 } else {
107 mPrivateDnsModes[netId] = PrivateDnsMode::OFF;
108 mPrivateDnsTransports.erase(netId);
109 return 0;
110 }
111
112 // Create the tracker if it was not present
113 auto netPair = mPrivateDnsTransports.find(netId);
114 if (netPair == mPrivateDnsTransports.end()) {
115 // No TLS tracker yet for this netId.
116 bool added;
117 std::tie(netPair, added) = mPrivateDnsTransports.emplace(netId, PrivateDnsTracker());
118 if (!added) {
119 ALOGE("Memory error while recording private DNS for netId %d", netId);
120 return -ENOMEM;
121 }
122 }
123 auto& tracker = netPair->second;
124
125 // Remove any servers from the tracker that are not in |servers| exactly.
126 for (auto it = tracker.begin(); it != tracker.end();) {
127 if (tlsServers.count(it->first) == 0) {
128 it = tracker.erase(it);
129 } else {
130 ++it;
131 }
132 }
133
134 // Add any new or changed servers to the tracker, and initiate async checks for them.
135 for (const auto& server : tlsServers) {
136 if (needsValidation(tracker, server)) {
137 validatePrivateDnsProvider(server, tracker, netId, mark);
138 }
139 }
140 return 0;
141}
142
143PrivateDnsStatus PrivateDnsConfiguration::getStatus(unsigned netId) {
144 PrivateDnsStatus status{PrivateDnsMode::OFF, {}};
Mike Yub601ff72018-11-01 20:07:00 +0800145 std::lock_guard guard(mPrivateDnsLock);
146
147 const auto mode = mPrivateDnsModes.find(netId);
148 if (mode == mPrivateDnsModes.end()) return status;
149 status.mode = mode->second;
150
151 const auto netPair = mPrivateDnsTransports.find(netId);
152 if (netPair != mPrivateDnsTransports.end()) {
153 for (const auto& serverPair : netPair->second) {
154 if (serverPair.second == Validation::success) {
155 status.validatedServers.push_back(serverPair.first);
156 }
157 }
158 }
159
160 return status;
161}
162
163void PrivateDnsConfiguration::getStatus(unsigned netId, ExternalPrivateDnsStatus* status) {
Mike Yub601ff72018-11-01 20:07:00 +0800164 std::lock_guard guard(mPrivateDnsLock);
165
166 const auto mode = mPrivateDnsModes.find(netId);
167 if (mode == mPrivateDnsModes.end()) return;
168 status->mode = mode->second;
169
170 const auto netPair = mPrivateDnsTransports.find(netId);
171 if (netPair != mPrivateDnsTransports.end()) {
Mike Yub601ff72018-11-01 20:07:00 +0800172 int count = 0;
173 for (const auto& serverPair : netPair->second) {
174 status->serverStatus[count].ss = serverPair.first.ss;
175 status->serverStatus[count].hostname =
176 serverPair.first.name.empty() ? "" : serverPair.first.name.c_str();
177 status->serverStatus[count].validation = serverPair.second;
Mike Yub601ff72018-11-01 20:07:00 +0800178 count++;
Bernie Innocenti4c2a4612018-11-20 19:23:56 +0900179 if (count >= MAXNS) break; // Lose the rest
Mike Yub601ff72018-11-01 20:07:00 +0800180 }
Bernie Innocenti93390222019-01-10 18:33:45 +0900181 status->numServers = count;
Mike Yub601ff72018-11-01 20:07:00 +0800182 }
183}
184
185void PrivateDnsConfiguration::clear(unsigned netId) {
186 if (DBG) {
187 ALOGD("PrivateDnsConfiguration::clear(%u)", netId);
188 }
189 std::lock_guard guard(mPrivateDnsLock);
190 mPrivateDnsModes.erase(netId);
191 mPrivateDnsTransports.erase(netId);
192}
193
194void PrivateDnsConfiguration::validatePrivateDnsProvider(const DnsTlsServer& server,
195 PrivateDnsTracker& tracker, unsigned netId,
196 uint32_t mark) REQUIRES(mPrivateDnsLock) {
197 if (DBG) {
Mike Yu303b0df2018-12-24 17:05:02 +0800198 ALOGD("validatePrivateDnsProvider(%s, %u)", addrToString(&server.ss).c_str(), netId);
Mike Yub601ff72018-11-01 20:07:00 +0800199 }
200
201 tracker[server] = Validation::in_process;
202 if (DBG) {
203 ALOGD("Server %s marked as in_process. Tracker now has size %zu",
Mike Yu303b0df2018-12-24 17:05:02 +0800204 addrToString(&server.ss).c_str(), tracker.size());
Mike Yub601ff72018-11-01 20:07:00 +0800205 }
206 // Note that capturing |server| and |netId| in this lambda create copies.
207 std::thread validate_thread([this, server, netId, mark] {
208 // cat /proc/sys/net/ipv4/tcp_syn_retries yields "6".
209 //
210 // Start with a 1 minute delay and backoff to once per hour.
211 //
212 // Assumptions:
213 // [1] Each TLS validation is ~10KB of certs+handshake+payload.
214 // [2] Network typically provision clients with <=4 nameservers.
215 // [3] Average month has 30 days.
216 //
217 // Each validation pass in a given hour is ~1.2MB of data. And 24
218 // such validation passes per day is about ~30MB per month, in the
219 // worst case. Otherwise, this will cost ~600 SYNs per month
220 // (6 SYNs per ip, 4 ips per validation pass, 24 passes per day).
Bernie Innocenti23c6e2a2019-05-16 15:18:35 +0900221 auto backoff = netdutils::BackoffSequence<>::Builder()
Mike Yub601ff72018-11-01 20:07:00 +0800222 .withInitialRetransmissionTime(std::chrono::seconds(60))
223 .withMaximumRetransmissionTime(std::chrono::seconds(3600))
224 .build();
225
226 while (true) {
227 // ::validate() is a blocking call that performs network operations.
228 // It can take milliseconds to minutes, up to the SYN retry limit.
229 const bool success = DnsTlsTransport::validate(server, netId, mark);
230 if (DBG) {
231 ALOGD("validateDnsTlsServer returned %d for %s", success,
Mike Yu303b0df2018-12-24 17:05:02 +0800232 addrToString(&server.ss).c_str());
Mike Yub601ff72018-11-01 20:07:00 +0800233 }
234
235 const bool needs_reeval = this->recordPrivateDnsValidation(server, netId, success);
236 if (!needs_reeval) {
237 break;
238 }
239
240 if (backoff.hasNextTimeout()) {
241 std::this_thread::sleep_for(backoff.getNextTimeout());
242 } else {
243 break;
244 }
245 }
246 });
247 validate_thread.detach();
248}
249
250bool PrivateDnsConfiguration::recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId,
251 bool success) {
252 constexpr bool NEEDS_REEVALUATION = true;
253 constexpr bool DONT_REEVALUATE = false;
254
255 std::lock_guard guard(mPrivateDnsLock);
256
257 auto netPair = mPrivateDnsTransports.find(netId);
258 if (netPair == mPrivateDnsTransports.end()) {
259 ALOGW("netId %u was erased during private DNS validation", netId);
260 return DONT_REEVALUATE;
261 }
262
263 const auto mode = mPrivateDnsModes.find(netId);
264 if (mode == mPrivateDnsModes.end()) {
265 ALOGW("netId %u has no private DNS validation mode", netId);
266 return DONT_REEVALUATE;
267 }
268 const bool modeDoesReevaluation = (mode->second == PrivateDnsMode::STRICT);
269
270 bool reevaluationStatus =
271 (success || !modeDoesReevaluation) ? DONT_REEVALUATE : NEEDS_REEVALUATION;
272
273 auto& tracker = netPair->second;
274 auto serverPair = tracker.find(server);
275 if (serverPair == tracker.end()) {
276 ALOGW("Server %s was removed during private DNS validation",
Mike Yu303b0df2018-12-24 17:05:02 +0800277 addrToString(&server.ss).c_str());
Mike Yub601ff72018-11-01 20:07:00 +0800278 success = false;
279 reevaluationStatus = DONT_REEVALUATE;
280 } else if (!(serverPair->first == server)) {
281 // TODO: It doesn't seem correct to overwrite the tracker entry for
282 // |server| down below in this circumstance... Fix this.
283 ALOGW("Server %s was changed during private DNS validation",
Mike Yu303b0df2018-12-24 17:05:02 +0800284 addrToString(&server.ss).c_str());
Mike Yub601ff72018-11-01 20:07:00 +0800285 success = false;
286 reevaluationStatus = DONT_REEVALUATE;
287 }
288
Mike Yu303b0df2018-12-24 17:05:02 +0800289 // Send a validation event to NetdEventListenerService.
Hungming Chena32c8c12019-01-25 10:47:40 +0800290 const auto& listeners = ResolverEventReporter::getInstance().getListeners();
291 if (listeners.size() != 0) {
292 for (const auto& it : listeners) {
293 it->onPrivateDnsValidationEvent(netId, addrToString(&server.ss), server.name, success);
294 }
Mike Yu303b0df2018-12-24 17:05:02 +0800295 if (DBG) {
296 ALOGD("Sent validation %s event on netId %u for %s with hostname %s",
297 success ? "success" : "failure", netId, addrToString(&server.ss).c_str(),
298 server.name.c_str());
299 }
300 } else {
Hungming Chena32c8c12019-01-25 10:47:40 +0800301 ALOGE("Validation event not sent since no INetdEventListener receiver is available.");
Mike Yub601ff72018-11-01 20:07:00 +0800302 }
303
304 if (success) {
305 tracker[server] = Validation::success;
306 if (DBG) {
307 ALOGD("Validation succeeded for %s! Tracker now has %zu entries.",
Mike Yu303b0df2018-12-24 17:05:02 +0800308 addrToString(&server.ss).c_str(), tracker.size());
Mike Yub601ff72018-11-01 20:07:00 +0800309 }
310 } else {
311 // Validation failure is expected if a user is on a captive portal.
312 // TODO: Trigger a second validation attempt after captive portal login
313 // succeeds.
314 tracker[server] = (reevaluationStatus == NEEDS_REEVALUATION) ? Validation::in_process
315 : Validation::fail;
316 if (DBG) {
Mike Yu303b0df2018-12-24 17:05:02 +0800317 ALOGD("Validation failed for %s!", addrToString(&server.ss).c_str());
Mike Yub601ff72018-11-01 20:07:00 +0800318 }
319 }
320
321 return reevaluationStatus;
322}
323
324// Start validation for newly added servers as well as any servers that have
325// landed in Validation::fail state. Note that servers that have failed
326// multiple validation attempts but for which there is still a validating
327// thread running are marked as being Validation::in_process.
328bool PrivateDnsConfiguration::needsValidation(const PrivateDnsTracker& tracker,
329 const DnsTlsServer& server) {
330 const auto& iter = tracker.find(server);
331 return (iter == tracker.end()) || (iter->second == Validation::fail);
332}
333
334PrivateDnsConfiguration gPrivateDnsConfiguration;
335
336} // namespace net
337} // namespace android