blob: 4eafcec55313aa9526a925442b9d2c2fee73a5cc [file] [log] [blame]
Mattias Falk89c1e972011-04-29 14:48:51 +02001/*
2 * Copyright (C) 2011 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 "ResolverController"
18#define DBG 0
19
Pierre Imaibeedec32016-04-13 06:44:51 +090020#include <algorithm>
21#include <cstdlib>
Ben Schwartze7601812017-04-28 16:38:29 -040022#include <map>
23#include <mutex>
24#include <set>
Pierre Imaibeedec32016-04-13 06:44:51 +090025#include <string>
Ben Schwartze7601812017-04-28 16:38:29 -040026#include <thread>
27#include <utility>
Pierre Imaibeedec32016-04-13 06:44:51 +090028#include <vector>
Logan Chien3f461482018-04-23 14:31:32 +080029#include <log/log.h>
Elliott Hughes970274a2012-09-11 18:56:36 -070030#include <net/if.h>
Pierre Imaibeedec32016-04-13 06:44:51 +090031#include <sys/socket.h>
32#include <netdb.h>
David 'Digit' Turner4da10dd2012-01-13 13:43:43 +010033
Ben Schwartze7601812017-04-28 16:38:29 -040034#include <arpa/inet.h>
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050035// NOTE: <resolv_netid.h> is a private C library header that provides
36// declarations for _resolv_set_nameservers_for_net and
37// _resolv_flush_cache_for_net
38#include <resolv_netid.h>
Pierre Imai95f5f942016-03-09 18:09:25 +090039#include <resolv_params.h>
Pierre Imaibeedec32016-04-13 06:44:51 +090040#include <resolv_stats.h>
41
Pierre Imai3a272072016-04-19 16:17:07 +090042#include <android-base/strings.h>
Ben Schwartzcbdd64a2017-08-23 18:21:46 -040043#include <android-base/thread_annotations.h>
Pierre Imaibeedec32016-04-13 06:44:51 +090044#include <android/net/INetd.h>
dalyk6250dbd2017-12-28 16:20:04 -050045#include <android/net/metrics/INetdEventListener.h>
Mattias Falk89c1e972011-04-29 14:48:51 +020046
Pierre Imai3a272072016-04-19 16:17:07 +090047#include "DumpWriter.h"
dalyk6250dbd2017-12-28 16:20:04 -050048#include "EventReporter.h"
Ben Schwartze7601812017-04-28 16:38:29 -040049#include "NetdConstants.h"
Mattias Falk89c1e972011-04-29 14:48:51 +020050#include "ResolverController.h"
Pierre Imaibeedec32016-04-13 06:44:51 +090051#include "ResolverStats.h"
Ben Schwartze7601812017-04-28 16:38:29 -040052#include "dns/DnsTlsTransport.h"
Ben Schwartz66810f62017-10-16 19:27:46 -040053#include "dns/DnsTlsServer.h"
Erik Klined739c212018-04-24 23:09:39 +090054#include "netdutils/BackoffSequence.h"
Mattias Falk89c1e972011-04-29 14:48:51 +020055
Lorenzo Colitti7035f222017-02-13 18:29:00 +090056namespace android {
Lorenzo Colitti7035f222017-02-13 18:29:00 +090057
Erik Klined739c212018-04-24 23:09:39 +090058using netdutils::BackoffSequence;
59
60namespace net {
Ben Schwartze7601812017-04-28 16:38:29 -040061namespace {
62
Ben Schwartz4204ecf2017-10-02 12:35:48 -040063std::string addrToString(const sockaddr_storage* addr) {
64 char out[INET6_ADDRSTRLEN] = {0};
65 getnameinfo((const sockaddr*)addr, sizeof(sockaddr_storage), out,
Yi Kongbdfd57e2018-07-25 13:26:10 -070066 INET6_ADDRSTRLEN, nullptr, 0, NI_NUMERICHOST);
Ben Schwartz4204ecf2017-10-02 12:35:48 -040067 return std::string(out);
68}
Ben Schwartze7601812017-04-28 16:38:29 -040069
Ben Schwartz008f74c2017-12-07 17:27:20 -050070bool parseServer(const char* server, sockaddr_storage* parsed) {
71 addrinfo hints = {
72 .ai_family = AF_UNSPEC,
73 .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV
74 };
75 addrinfo* res;
76
77 int err = getaddrinfo(server, "853", &hints, &res);
78 if (err != 0) {
79 ALOGW("Failed to parse server address (%s): %s", server, gai_strerror(err));
80 return false;
Ben Schwartze7601812017-04-28 16:38:29 -040081 }
Ben Schwartz008f74c2017-12-07 17:27:20 -050082
83 memcpy(parsed, res->ai_addr, res->ai_addrlen);
84 freeaddrinfo(res);
85 return true;
Ben Schwartze7601812017-04-28 16:38:29 -040086}
87
Erik Kline1564d482018-03-07 17:09:35 +090088const char* getPrivateDnsModeString(PrivateDnsMode mode) {
89 switch (mode) {
90 case PrivateDnsMode::OFF: return "OFF";
91 case PrivateDnsMode::OPPORTUNISTIC: return "OPPORTUNISTIC";
92 case PrivateDnsMode::STRICT: return "STRICT";
93 }
94}
95
Erik Klinefb757532018-01-18 20:12:06 +090096constexpr const char* validationStatusToString(ResolverController::Validation value) {
97 switch (value) {
98 case ResolverController::Validation::in_process: return "in_process";
99 case ResolverController::Validation::success: return "success";
100 case ResolverController::Validation::fail: return "fail";
101 case ResolverController::Validation::unknown_server: return "unknown_server";
102 case ResolverController::Validation::unknown_netid: return "unknown_netid";
103 default: return "unknown_status";
104 }
105}
106
Erik Klined739c212018-04-24 23:09:39 +0900107
108class PrivateDnsConfiguration {
109 public:
110 typedef ResolverController::PrivateDnsStatus PrivateDnsStatus;
111 typedef ResolverController::Validation Validation;
112 typedef std::map<DnsTlsServer, Validation, AddressComparator> PrivateDnsTracker;
113
114 int set(int32_t netId, const std::vector<std::string>& servers, const std::string& name,
115 const std::set<std::vector<uint8_t>>& fingerprints) {
116 if (DBG) {
117 ALOGD("PrivateDnsConfiguration::set(%u, %zu, %s, %zu)",
118 netId, servers.size(), name.c_str(), fingerprints.size());
119 }
120
121 const bool explicitlyConfigured = !name.empty() || !fingerprints.empty();
122
123 // Parse the list of servers that has been passed in
124 std::set<DnsTlsServer> tlsServers;
125 for (size_t i = 0; i < servers.size(); ++i) {
126 sockaddr_storage parsed;
127 if (!parseServer(servers[i].c_str(), &parsed)) {
128 return -EINVAL;
129 }
130 DnsTlsServer server(parsed);
131 server.name = name;
132 server.fingerprints = fingerprints;
133 tlsServers.insert(server);
134 }
135
136 std::lock_guard<std::mutex> guard(mPrivateDnsLock);
137 if (explicitlyConfigured) {
138 mPrivateDnsModes[netId] = PrivateDnsMode::STRICT;
139 } else if (!tlsServers.empty()) {
140 mPrivateDnsModes[netId] = PrivateDnsMode::OPPORTUNISTIC;
141 } else {
142 mPrivateDnsModes[netId] = PrivateDnsMode::OFF;
143 mPrivateDnsTransports.erase(netId);
144 return 0;
145 }
146
147 // Create the tracker if it was not present
148 auto netPair = mPrivateDnsTransports.find(netId);
149 if (netPair == mPrivateDnsTransports.end()) {
150 // No TLS tracker yet for this netId.
151 bool added;
152 std::tie(netPair, added) = mPrivateDnsTransports.emplace(netId, PrivateDnsTracker());
153 if (!added) {
154 ALOGE("Memory error while recording private DNS for netId %d", netId);
155 return -ENOMEM;
156 }
157 }
158 auto& tracker = netPair->second;
159
160 // Remove any servers from the tracker that are not in |servers| exactly.
161 for (auto it = tracker.begin(); it != tracker.end();) {
162 if (tlsServers.count(it->first) == 0) {
163 it = tracker.erase(it);
164 } else {
165 ++it;
166 }
167 }
168
169 // Add any new or changed servers to the tracker, and initiate async checks for them.
170 for (const auto& server : tlsServers) {
Erik Kline533a8422018-06-14 15:16:27 +0900171 if (needsValidation(tracker, server)) {
Erik Klined739c212018-04-24 23:09:39 +0900172 validatePrivateDnsProvider(server, tracker, netId);
173 }
174 }
175 return 0;
176 }
177
178 PrivateDnsStatus getStatus(unsigned netId) {
179 PrivateDnsStatus status{PrivateDnsMode::OFF, {}};
180
181 // This mutex is on the critical path of every DNS lookup.
182 //
183 // If the overhead of mutex acquisition proves too high, we could reduce
184 // it by maintaining an atomic_int32_t counter of TLS-enabled netids, or
185 // by using an RWLock.
186 std::lock_guard<std::mutex> guard(mPrivateDnsLock);
187
188 const auto mode = mPrivateDnsModes.find(netId);
189 if (mode == mPrivateDnsModes.end()) return status;
190 status.mode = mode->second;
191
192 const auto netPair = mPrivateDnsTransports.find(netId);
193 if (netPair != mPrivateDnsTransports.end()) {
194 for (const auto& serverPair : netPair->second) {
195 if (serverPair.second == Validation::success) {
196 status.validatedServers.push_back(serverPair.first);
197 }
198 }
199 }
200
201 return status;
202 }
203
204 void clear(unsigned netId) {
205 if (DBG) {
206 ALOGD("PrivateDnsConfiguration::clear(%u)", netId);
207 }
208 std::lock_guard<std::mutex> guard(mPrivateDnsLock);
209 mPrivateDnsModes.erase(netId);
210 mPrivateDnsTransports.erase(netId);
211 }
212
213 void dump(DumpWriter& dw, unsigned netId) {
214 std::lock_guard<std::mutex> guard(mPrivateDnsLock);
215
216 const auto& mode = mPrivateDnsModes.find(netId);
217 dw.println("Private DNS mode: %s", getPrivateDnsModeString(
218 (mode != mPrivateDnsModes.end()) ? mode->second : PrivateDnsMode::OFF));
219 const auto& netPair = mPrivateDnsTransports.find(netId);
220 if (netPair == mPrivateDnsTransports.end()) {
221 dw.println("No Private DNS servers configured");
222 } else {
223 const auto& tracker = netPair->second;
224 dw.println("Private DNS configuration (%zu entries)", tracker.size());
225 dw.incIndent();
226 for (const auto& kv : tracker) {
227 const auto& server = kv.first;
228 const auto status = kv.second;
229 dw.println("%s name{%s} status{%s}",
230 addrToString(&(server.ss)).c_str(),
231 server.name.c_str(),
232 validationStatusToString(status));
233 }
234 dw.decIndent();
235 }
236 }
237
238 private:
239 void validatePrivateDnsProvider(const DnsTlsServer& server, PrivateDnsTracker& tracker,
240 unsigned netId) REQUIRES(mPrivateDnsLock) {
241 if (DBG) {
242 ALOGD("validatePrivateDnsProvider(%s, %u)", addrToString(&(server.ss)).c_str(), netId);
243 }
244
245 tracker[server] = Validation::in_process;
246 if (DBG) {
247 ALOGD("Server %s marked as in_process. Tracker now has size %zu",
248 addrToString(&(server.ss)).c_str(), tracker.size());
249 }
250 // Note that capturing |server| and |netId| in this lambda create copies.
251 std::thread validate_thread([this, server, netId] {
252 // cat /proc/sys/net/ipv4/tcp_syn_retries yields "6".
253 //
254 // Start with a 1 minute delay and backoff to once per hour.
255 //
256 // Assumptions:
257 // [1] Each TLS validation is ~10KB of certs+handshake+payload.
258 // [2] Network typically provision clients with <=4 nameservers.
259 // [3] Average month has 30 days.
260 //
261 // Each validation pass in a given hour is ~1.2MB of data. And 24
262 // such validation passes per day is about ~30MB per month, in the
263 // worst case. Otherwise, this will cost ~600 SYNs per month
264 // (6 SYNs per ip, 4 ips per validation pass, 24 passes per day).
265 auto backoff = BackoffSequence<>::Builder()
266 .withInitialRetransmissionTime(std::chrono::seconds(60))
267 .withMaximumRetransmissionTime(std::chrono::seconds(3600))
268 .build();
269
270 while (true) {
271 // ::validate() is a blocking call that performs network operations.
272 // It can take milliseconds to minutes, up to the SYN retry limit.
273 const bool success = DnsTlsTransport::validate(server, netId);
274 if (DBG) {
275 ALOGD("validateDnsTlsServer returned %d for %s", success,
276 addrToString(&(server.ss)).c_str());
277 }
278
279 const bool needs_reeval = this->recordPrivateDnsValidation(server, netId, success);
280 if (!needs_reeval) {
281 break;
282 }
283
284 if (backoff.hasNextTimeout()) {
285 std::this_thread::sleep_for(backoff.getNextTimeout());
286 } else {
287 break;
288 }
289 }
290 });
291 validate_thread.detach();
292 }
293
294 bool recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId, bool success) {
295 constexpr bool NEEDS_REEVALUATION = true;
296 constexpr bool DONT_REEVALUATE = false;
297
298 std::lock_guard<std::mutex> guard(mPrivateDnsLock);
299
300 auto netPair = mPrivateDnsTransports.find(netId);
301 if (netPair == mPrivateDnsTransports.end()) {
302 ALOGW("netId %u was erased during private DNS validation", netId);
303 return DONT_REEVALUATE;
304 }
305
Erik Kline533a8422018-06-14 15:16:27 +0900306 const auto mode = mPrivateDnsModes.find(netId);
307 if (mode == mPrivateDnsModes.end()) {
308 ALOGW("netId %u has no private DNS validation mode", netId);
309 return DONT_REEVALUATE;
310 }
311 const bool modeDoesReevaluation = (mode->second == PrivateDnsMode::STRICT);
312
313 bool reevaluationStatus =
314 (success || !modeDoesReevaluation) ? DONT_REEVALUATE : NEEDS_REEVALUATION;
Erik Klined739c212018-04-24 23:09:39 +0900315
316 auto& tracker = netPair->second;
317 auto serverPair = tracker.find(server);
318 if (serverPair == tracker.end()) {
319 ALOGW("Server %s was removed during private DNS validation",
320 addrToString(&(server.ss)).c_str());
321 success = false;
322 reevaluationStatus = DONT_REEVALUATE;
323 } else if (!(serverPair->first == server)) {
324 // TODO: It doesn't seem correct to overwrite the tracker entry for
325 // |server| down below in this circumstance... Fix this.
326 ALOGW("Server %s was changed during private DNS validation",
327 addrToString(&(server.ss)).c_str());
328 success = false;
329 reevaluationStatus = DONT_REEVALUATE;
330 }
331
332 // Send a validation event to NetdEventListenerService.
333 if (mNetdEventListener == nullptr) {
334 mNetdEventListener = mEventReporter.getNetdEventListener();
335 }
336 if (mNetdEventListener != nullptr) {
337 const String16 ipLiteral(addrToString(&(server.ss)).c_str());
338 const String16 hostname(server.name.empty() ? "" : server.name.c_str());
339 mNetdEventListener->onPrivateDnsValidationEvent(netId, ipLiteral, hostname, success);
340 if (DBG) {
341 ALOGD("Sending validation %s event on netId %u for %s with hostname %s",
342 success ? "success" : "failure", netId,
343 addrToString(&(server.ss)).c_str(), server.name.c_str());
344 }
345 } else {
346 ALOGE("Validation event not sent since NetdEventListenerService is unavailable.");
347 }
348
349 if (success) {
350 tracker[server] = Validation::success;
351 if (DBG) {
352 ALOGD("Validation succeeded for %s! Tracker now has %zu entries.",
353 addrToString(&(server.ss)).c_str(), tracker.size());
354 }
355 } else {
356 // Validation failure is expected if a user is on a captive portal.
357 // TODO: Trigger a second validation attempt after captive portal login
358 // succeeds.
Erik Kline533a8422018-06-14 15:16:27 +0900359 tracker[server] = (reevaluationStatus == NEEDS_REEVALUATION) ? Validation::in_process
360 : Validation::fail;
Erik Klined739c212018-04-24 23:09:39 +0900361 if (DBG) {
362 ALOGD("Validation failed for %s!", addrToString(&(server.ss)).c_str());
363 }
364 }
365
366 return reevaluationStatus;
367 }
368
Erik Kline533a8422018-06-14 15:16:27 +0900369 // Start validation for newly added servers as well as any servers that have
370 // landed in Validation::fail state. Note that servers that have failed
371 // multiple validation attempts but for which there is still a validating
372 // thread running are marked as being Validation::in_process.
373 static bool needsValidation(const PrivateDnsTracker& tracker, const DnsTlsServer& server) {
374 const auto& iter = tracker.find(server);
375 return (iter == tracker.end()) || (iter->second == Validation::fail);
376 }
377
Erik Klined739c212018-04-24 23:09:39 +0900378 EventReporter mEventReporter;
379
380 std::mutex mPrivateDnsLock;
381 std::map<unsigned, PrivateDnsMode> mPrivateDnsModes GUARDED_BY(mPrivateDnsLock);
382 // Structure for tracking the validation status of servers on a specific netId.
383 // Using the AddressComparator ensures at most one entry per IP address.
384 std::map<unsigned, PrivateDnsTracker> mPrivateDnsTransports GUARDED_BY(mPrivateDnsLock);
385 android::sp<android::net::metrics::INetdEventListener>
386 mNetdEventListener GUARDED_BY(mPrivateDnsLock);
Erik Kline533a8422018-06-14 15:16:27 +0900387} sPrivateDnsConfiguration;
Erik Klined739c212018-04-24 23:09:39 +0900388
Ben Schwartze7601812017-04-28 16:38:29 -0400389} // namespace
390
Pierre Imai95f5f942016-03-09 18:09:25 +0900391int ResolverController::setDnsServers(unsigned netId, const char* searchDomains,
392 const char** servers, int numservers, const __res_params* params) {
Mattias Falk89c1e972011-04-29 14:48:51 +0200393 if (DBG) {
Ben Schwartz4204ecf2017-10-02 12:35:48 -0400394 ALOGD("setDnsServers netId = %u, numservers = %d", netId, numservers);
Mattias Falk89c1e972011-04-29 14:48:51 +0200395 }
Pierre Imaibeedec32016-04-13 06:44:51 +0900396 return -_resolv_set_nameservers_for_net(netId, servers, numservers, searchDomains, params);
Mattias Falk89c1e972011-04-29 14:48:51 +0200397}
Paul Jensen6a46f332014-08-06 18:42:27 +0000398
Erik Kline1564d482018-03-07 17:09:35 +0900399ResolverController::PrivateDnsStatus
Erik Klined739c212018-04-24 23:09:39 +0900400ResolverController::getPrivateDnsStatus(unsigned netId) const {
Erik Kline533a8422018-06-14 15:16:27 +0900401 return sPrivateDnsConfiguration.getStatus(netId);
Ben Schwartze7601812017-04-28 16:38:29 -0400402}
403
Lorenzo Colittidadc5f82014-11-29 13:54:25 +0900404int ResolverController::clearDnsServers(unsigned netId) {
Yi Kongbdfd57e2018-07-25 13:26:10 -0700405 _resolv_set_nameservers_for_net(netId, nullptr, 0, "", nullptr);
Lorenzo Colittidadc5f82014-11-29 13:54:25 +0900406 if (DBG) {
407 ALOGD("clearDnsServers netId = %u\n", netId);
408 }
Erik Kline533a8422018-06-14 15:16:27 +0900409 sPrivateDnsConfiguration.clear(netId);
Lorenzo Colittidadc5f82014-11-29 13:54:25 +0900410 return 0;
411}
412
Paul Jensen6a46f332014-08-06 18:42:27 +0000413int ResolverController::flushDnsCache(unsigned netId) {
414 if (DBG) {
415 ALOGD("flushDnsCache netId = %u\n", netId);
416 }
417
418 _resolv_flush_cache_for_net(netId);
419
420 return 0;
421}
Pierre Imaibeedec32016-04-13 06:44:51 +0900422
423int ResolverController::getDnsInfo(unsigned netId, std::vector<std::string>* servers,
424 std::vector<std::string>* domains, __res_params* params,
425 std::vector<android::net::ResolverStats>* stats) {
426 using android::net::ResolverStats;
427 using android::net::INetd;
428 static_assert(ResolverStats::STATS_SUCCESSES == INetd::RESOLVER_STATS_SUCCESSES &&
429 ResolverStats::STATS_ERRORS == INetd::RESOLVER_STATS_ERRORS &&
430 ResolverStats::STATS_TIMEOUTS == INetd::RESOLVER_STATS_TIMEOUTS &&
431 ResolverStats::STATS_INTERNAL_ERRORS == INetd::RESOLVER_STATS_INTERNAL_ERRORS &&
432 ResolverStats::STATS_RTT_AVG == INetd::RESOLVER_STATS_RTT_AVG &&
433 ResolverStats::STATS_LAST_SAMPLE_TIME == INetd::RESOLVER_STATS_LAST_SAMPLE_TIME &&
434 ResolverStats::STATS_USABLE == INetd::RESOLVER_STATS_USABLE &&
435 ResolverStats::STATS_COUNT == INetd::RESOLVER_STATS_COUNT,
436 "AIDL and ResolverStats.h out of sync");
437 int nscount = -1;
438 sockaddr_storage res_servers[MAXNS];
439 int dcount = -1;
440 char res_domains[MAXDNSRCH][MAXDNSRCHPATH];
441 __res_stats res_stats[MAXNS];
442 servers->clear();
443 domains->clear();
444 *params = __res_params{};
445 stats->clear();
446 int revision_id = android_net_res_stats_get_info_for_net(netId, &nscount, res_servers, &dcount,
447 res_domains, params, res_stats);
448
449 // If the netId is unknown (which can happen for valid net IDs for which no DNS servers have
450 // yet been configured), there is no revision ID. In this case there is no data to return.
451 if (revision_id < 0) {
452 return 0;
453 }
454
455 // Verify that the returned data is sane.
456 if (nscount < 0 || nscount > MAXNS || dcount < 0 || dcount > MAXDNSRCH) {
457 ALOGE("%s: nscount=%d, dcount=%d", __FUNCTION__, nscount, dcount);
458 return -ENOTRECOVERABLE;
459 }
460
461 // Determine which servers are considered usable by the resolver.
462 bool valid_servers[MAXNS];
463 std::fill_n(valid_servers, MAXNS, false);
464 android_net_res_stats_get_usable_servers(params, res_stats, nscount, valid_servers);
465
466 // Convert the server sockaddr structures to std::string.
467 stats->resize(nscount);
468 for (int i = 0 ; i < nscount ; ++i) {
469 char hbuf[NI_MAXHOST];
470 int rv = getnameinfo(reinterpret_cast<const sockaddr*>(&res_servers[i]),
471 sizeof(res_servers[i]), hbuf, sizeof(hbuf), nullptr, 0, NI_NUMERICHOST);
472 std::string server_str;
473 if (rv == 0) {
474 server_str.assign(hbuf);
475 } else {
476 ALOGE("getnameinfo() failed for server #%d: %s", i, gai_strerror(rv));
477 server_str.assign("<invalid>");
478 }
479 servers->push_back(std::move(server_str));
480 android::net::ResolverStats& cur_stats = (*stats)[i];
481 android_net_res_stats_aggregate(&res_stats[i], &cur_stats.successes, &cur_stats.errors,
482 &cur_stats.timeouts, &cur_stats.internal_errors, &cur_stats.rtt_avg,
483 &cur_stats.last_sample_time);
484 cur_stats.usable = valid_servers[i];
485 }
486
487 // Convert the stack-allocated search domain strings to std::string.
488 for (int i = 0 ; i < dcount ; ++i) {
489 domains->push_back(res_domains[i]);
490 }
491 return 0;
492}
493
494int ResolverController::setResolverConfiguration(int32_t netId,
495 const std::vector<std::string>& servers, const std::vector<std::string>& domains,
Erik Klinea1476fb2018-03-04 21:01:56 +0900496 const std::vector<int32_t>& params, const std::string& tlsName,
497 const std::vector<std::string>& tlsServers,
Ben Schwartz4204ecf2017-10-02 12:35:48 -0400498 const std::set<std::vector<uint8_t>>& tlsFingerprints) {
Pierre Imaibeedec32016-04-13 06:44:51 +0900499 using android::net::INetd;
Bernie Innocenticc93c372018-08-06 15:18:59 +0900500 // TODO: make RESOLVER_PARAMS_BASE_TIMEOUT_MSEC a mandatory parameter once all callers
501 // have been updated to specify it.
502 if (params.size() < INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC ||
503 params.size() > INetd::RESOLVER_PARAMS_COUNT) {
Pierre Imaibeedec32016-04-13 06:44:51 +0900504 ALOGE("%s: params.size()=%zu", __FUNCTION__, params.size());
505 return -EINVAL;
506 }
507
Erik Kline533a8422018-06-14 15:16:27 +0900508 const int err = sPrivateDnsConfiguration.set(netId, tlsServers, tlsName, tlsFingerprints);
Erik Kline1564d482018-03-07 17:09:35 +0900509 if (err != 0) {
510 return err;
Ben Schwartz4204ecf2017-10-02 12:35:48 -0400511 }
512
Erik Kline1564d482018-03-07 17:09:35 +0900513 // Convert network-assigned server list to bionic's format.
514 auto server_count = std::min<size_t>(MAXNS, servers.size());
Pierre Imaibeedec32016-04-13 06:44:51 +0900515 std::vector<const char*> server_ptrs;
Pierre Imai0452cb52016-05-30 16:42:34 +0900516 for (size_t i = 0 ; i < server_count ; ++i) {
Erik Kline1564d482018-03-07 17:09:35 +0900517 server_ptrs.push_back(servers[i].c_str());
Pierre Imaibeedec32016-04-13 06:44:51 +0900518 }
519
520 std::string domains_str;
521 if (!domains.empty()) {
522 domains_str = domains[0];
523 for (size_t i = 1 ; i < domains.size() ; ++i) {
524 domains_str += " " + domains[i];
525 }
526 }
527
Bernie Innocenticc93c372018-08-06 15:18:59 +0900528 __res_params res_params = {};
Pierre Imaibeedec32016-04-13 06:44:51 +0900529 res_params.sample_validity = params[INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY];
530 res_params.success_threshold = params[INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD];
531 res_params.min_samples = params[INetd::RESOLVER_PARAMS_MIN_SAMPLES];
532 res_params.max_samples = params[INetd::RESOLVER_PARAMS_MAX_SAMPLES];
Bernie Innocenticc93c372018-08-06 15:18:59 +0900533 if (params.size() > INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC) {
534 res_params.base_timeout_msec = params[INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC];
535 }
Pierre Imaibeedec32016-04-13 06:44:51 +0900536 return setDnsServers(netId, domains_str.c_str(), server_ptrs.data(), server_ptrs.size(),
537 &res_params);
538}
539
540int ResolverController::getResolverInfo(int32_t netId, std::vector<std::string>* servers,
541 std::vector<std::string>* domains, std::vector<int32_t>* params,
542 std::vector<int32_t>* stats) {
543 using android::net::ResolverStats;
544 using android::net::INetd;
545 __res_params res_params;
546 std::vector<ResolverStats> res_stats;
547 int ret = getDnsInfo(netId, servers, domains, &res_params, &res_stats);
548 if (ret != 0) {
549 return ret;
550 }
551
552 // Serialize the information for binder.
553 ResolverStats::encodeAll(res_stats, stats);
554
555 params->resize(INetd::RESOLVER_PARAMS_COUNT);
556 (*params)[INetd::RESOLVER_PARAMS_SAMPLE_VALIDITY] = res_params.sample_validity;
557 (*params)[INetd::RESOLVER_PARAMS_SUCCESS_THRESHOLD] = res_params.success_threshold;
558 (*params)[INetd::RESOLVER_PARAMS_MIN_SAMPLES] = res_params.min_samples;
559 (*params)[INetd::RESOLVER_PARAMS_MAX_SAMPLES] = res_params.max_samples;
Bernie Innocenticc93c372018-08-06 15:18:59 +0900560 (*params)[INetd::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC] = res_params.base_timeout_msec;
Pierre Imaibeedec32016-04-13 06:44:51 +0900561 return 0;
562}
Pierre Imai3a272072016-04-19 16:17:07 +0900563
564void ResolverController::dump(DumpWriter& dw, unsigned netId) {
565 // No lock needed since Bionic's resolver locks all accessed data structures internally.
566 using android::net::ResolverStats;
567 std::vector<std::string> servers;
568 std::vector<std::string> domains;
Bernie Innocenticc93c372018-08-06 15:18:59 +0900569 __res_params params = {};
Pierre Imai3a272072016-04-19 16:17:07 +0900570 std::vector<ResolverStats> stats;
571 time_t now = time(nullptr);
572 int rv = getDnsInfo(netId, &servers, &domains, &params, &stats);
573 dw.incIndent();
574 if (rv != 0) {
575 dw.println("getDnsInfo() failed for netid %u", netId);
576 } else {
577 if (servers.empty()) {
578 dw.println("No DNS servers defined");
579 } else {
580 dw.println("DNS servers: # IP (total, successes, errors, timeouts, internal errors, "
581 "RTT avg, last sample)");
582 dw.incIndent();
583 for (size_t i = 0 ; i < servers.size() ; ++i) {
584 if (i < stats.size()) {
585 const ResolverStats& s = stats[i];
586 int total = s.successes + s.errors + s.timeouts + s.internal_errors;
587 if (total > 0) {
588 int time_delta = (s.last_sample_time > 0) ? now - s.last_sample_time : -1;
589 dw.println("%s (%d, %d, %d, %d, %d, %dms, %ds)%s", servers[i].c_str(),
590 total, s.successes, s.errors, s.timeouts, s.internal_errors,
591 s.rtt_avg, time_delta, s.usable ? "" : " BROKEN");
592 } else {
593 dw.println("%s <no data>", servers[i].c_str());
594 }
595 } else {
596 dw.println("%s <no stats>", servers[i].c_str());
597 }
598 }
599 dw.decIndent();
600 }
601 if (domains.empty()) {
602 dw.println("No search domains defined");
603 } else {
604 std::string domains_str = android::base::Join(domains, ", ");
605 dw.println("search domains: %s", domains_str.c_str());
606 }
607 if (params.sample_validity != 0) {
Bernie Innocenticc93c372018-08-06 15:18:59 +0900608 dw.println(
609 "DNS parameters: sample validity = %us, success threshold = %u%%, "
610 "samples (min, max) = (%u, %u), base_timeout = %dmsec",
611 params.sample_validity, static_cast<unsigned>(params.success_threshold),
Pierre Imai3a272072016-04-19 16:17:07 +0900612 static_cast<unsigned>(params.min_samples),
Bernie Innocenticc93c372018-08-06 15:18:59 +0900613 static_cast<unsigned>(params.max_samples), params.base_timeout_msec);
Pierre Imai3a272072016-04-19 16:17:07 +0900614 }
Erik Klined739c212018-04-24 23:09:39 +0900615
Erik Kline533a8422018-06-14 15:16:27 +0900616 sPrivateDnsConfiguration.dump(dw, netId);
Pierre Imai3a272072016-04-19 16:17:07 +0900617 }
618 dw.decIndent();
619}
Lorenzo Colitti7035f222017-02-13 18:29:00 +0900620
621} // namespace net
622} // namespace android