1 /*
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 "resolv"
18
19 #include "PrivateDnsConfiguration.h"
20
21 #include <algorithm>
22
23 #include <android-base/format.h>
24 #include <android-base/logging.h>
25 #include <android/binder_ibinder.h>
26 #include <netdutils/Slice.h>
27 #include <netdutils/ThreadUtil.h>
28 #include <sys/socket.h>
29
30 #include "DnsTlsTransport.h"
31 #include "ResolverEventReporter.h"
32 #include "doh.h"
33 #include "netd_resolv/resolv.h"
34 #include "resolv_cache.h"
35 #include "resolv_private.h"
36 #include "util.h"
37
38 using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
39 using aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
40 using android::netdutils::IPAddress;
41 using android::netdutils::IPSockAddr;
42 using android::netdutils::setThreadName;
43 using android::netdutils::Slice;
44 using std::chrono::milliseconds;
45
46 namespace android {
47 namespace net {
48
set(int32_t netId,uint32_t mark,const std::vector<std::string> & servers,const std::string & name,const std::string & caCert)49 int PrivateDnsConfiguration::set(int32_t netId, uint32_t mark,
50 const std::vector<std::string>& servers, const std::string& name,
51 const std::string& caCert) {
52 LOG(DEBUG) << "PrivateDnsConfiguration::set(" << netId << ", 0x" << std::hex << mark << std::dec
53 << ", " << servers.size() << ", " << name << ")";
54
55 // Parse the list of servers that has been passed in
56 PrivateDnsTracker tmp;
57 for (const auto& s : servers) {
58 IPAddress ip;
59 if (!IPAddress::forString(s, &ip)) {
60 LOG(WARNING) << "Failed to parse server address (" << s << ")";
61 return -EINVAL;
62 }
63
64 auto server = std::make_unique<DnsTlsServer>(ip);
65 server->name = name;
66 server->certificate = caCert;
67 server->mark = mark;
68 tmp[ServerIdentity(*server)] = std::move(server);
69 }
70
71 std::lock_guard guard(mPrivateDnsLock);
72 if (!name.empty()) {
73 mPrivateDnsModes[netId] = PrivateDnsMode::STRICT;
74 } else if (!tmp.empty()) {
75 mPrivateDnsModes[netId] = PrivateDnsMode::OPPORTUNISTIC;
76 } else {
77 mPrivateDnsModes[netId] = PrivateDnsMode::OFF;
78 mPrivateDnsTransports.erase(netId);
79 // TODO: signal validation threads to stop.
80 return 0;
81 }
82
83 // Create the tracker if it was not present
84 auto& tracker = mPrivateDnsTransports[netId];
85
86 // Add the servers if not contained in tracker.
87 for (auto& [identity, server] : tmp) {
88 if (tracker.find(identity) == tracker.end()) {
89 tracker[identity] = std::move(server);
90 }
91 }
92
93 for (auto& [identity, server] : tracker) {
94 const bool active = tmp.find(identity) != tmp.end();
95 server->setActive(active);
96
97 // For simplicity, deem the validation result of inactive servers as unreliable.
98 if (!server->active() && server->validationState() == Validation::success) {
99 updateServerState(identity, Validation::success_but_expired, netId);
100 }
101
102 if (needsValidation(*server)) {
103 updateServerState(identity, Validation::in_process, netId);
104 startValidation(identity, netId, false);
105 }
106 }
107
108 return 0;
109 }
110
getStatus(unsigned netId) const111 PrivateDnsStatus PrivateDnsConfiguration::getStatus(unsigned netId) const {
112 PrivateDnsStatus status{
113 .mode = PrivateDnsMode::OFF,
114 .dotServersMap = {},
115 .dohServersMap = {},
116 };
117 std::lock_guard guard(mPrivateDnsLock);
118
119 const auto mode = mPrivateDnsModes.find(netId);
120 if (mode == mPrivateDnsModes.end()) return status;
121 status.mode = mode->second;
122
123 const auto netPair = mPrivateDnsTransports.find(netId);
124 if (netPair != mPrivateDnsTransports.end()) {
125 for (const auto& [_, server] : netPair->second) {
126 if (server->isDot() && server->active()) {
127 DnsTlsServer& dotServer = *static_cast<DnsTlsServer*>(server.get());
128 status.dotServersMap.emplace(dotServer, server->validationState());
129 }
130 }
131 }
132
133 auto it = mDohTracker.find(netId);
134 if (it != mDohTracker.end()) {
135 status.dohServersMap.emplace(
136 netdutils::IPSockAddr::toIPSockAddr(it->second.ipAddr, kDohPort),
137 it->second.status);
138 }
139
140 return status;
141 }
142
clear(unsigned netId)143 void PrivateDnsConfiguration::clear(unsigned netId) {
144 LOG(DEBUG) << "PrivateDnsConfiguration::clear(" << netId << ")";
145 std::lock_guard guard(mPrivateDnsLock);
146 mPrivateDnsModes.erase(netId);
147 mPrivateDnsTransports.erase(netId);
148 }
149
requestValidation(unsigned netId,const ServerIdentity & identity,uint32_t mark)150 base::Result<void> PrivateDnsConfiguration::requestValidation(unsigned netId,
151 const ServerIdentity& identity,
152 uint32_t mark) {
153 std::lock_guard guard(mPrivateDnsLock);
154
155 // Running revalidation requires to mark the server as in_process, which means the server
156 // won't be used until the validation passes. It's necessary and safe to run revalidation
157 // when in private DNS opportunistic mode, because there's a fallback mechanics even if
158 // all of the private DNS servers are in in_process state.
159 if (auto it = mPrivateDnsModes.find(netId); it == mPrivateDnsModes.end()) {
160 return Errorf("NetId not found in mPrivateDnsModes");
161 } else if (it->second != PrivateDnsMode::OPPORTUNISTIC) {
162 return Errorf("Private DNS setting is not opportunistic mode");
163 }
164
165 auto result = getPrivateDnsLocked(identity, netId);
166 if (!result.ok()) {
167 return result.error();
168 }
169
170 const IPrivateDnsServer* server = result.value();
171
172 if (!server->active()) return Errorf("Server is not active");
173
174 if (server->validationState() != Validation::success) {
175 return Errorf("Server validation state mismatched");
176 }
177
178 // Don't run the validation if |mark| (from android_net_context.dns_mark) is different.
179 // This is to protect validation from running on unexpected marks.
180 // Validation should be associated with a mark gotten by system permission.
181 if (server->validationMark() != mark) return Errorf("Socket mark mismatched");
182
183 updateServerState(identity, Validation::in_process, netId);
184 startValidation(identity, netId, true);
185 return {};
186 }
187
startValidation(const ServerIdentity & identity,unsigned netId,bool isRevalidation)188 void PrivateDnsConfiguration::startValidation(const ServerIdentity& identity, unsigned netId,
189 bool isRevalidation) {
190 // This ensures that the thread sends probe at least once in case
191 // the server is removed before the thread starts running.
192 // TODO: consider moving these code to the thread.
193 const auto result = getPrivateDnsLocked(identity, netId);
194 if (!result.ok()) return;
195 DnsTlsServer server = *static_cast<const DnsTlsServer*>(result.value());
196
197 std::thread validate_thread([this, identity, server, netId, isRevalidation] {
198 setThreadName(fmt::format("TlsVerify_{}", netId));
199
200 // cat /proc/sys/net/ipv4/tcp_syn_retries yields "6".
201 //
202 // Start with a 1 minute delay and backoff to once per hour.
203 //
204 // Assumptions:
205 // [1] Each TLS validation is ~10KB of certs+handshake+payload.
206 // [2] Network typically provision clients with <=4 nameservers.
207 // [3] Average month has 30 days.
208 //
209 // Each validation pass in a given hour is ~1.2MB of data. And 24
210 // such validation passes per day is about ~30MB per month, in the
211 // worst case. Otherwise, this will cost ~600 SYNs per month
212 // (6 SYNs per ip, 4 ips per validation pass, 24 passes per day).
213 auto backoff = mBackoffBuilder.build();
214
215 while (true) {
216 // ::validate() is a blocking call that performs network operations.
217 // It can take milliseconds to minutes, up to the SYN retry limit.
218 LOG(WARNING) << "Validating DnsTlsServer " << server.toIpString() << " with mark 0x"
219 << std::hex << server.validationMark();
220 const bool success = DnsTlsTransport::validate(server, server.validationMark());
221 LOG(WARNING) << "validateDnsTlsServer returned " << success << " for "
222 << server.toIpString();
223
224 const bool needs_reeval =
225 this->recordPrivateDnsValidation(identity, netId, success, isRevalidation);
226
227 if (!needs_reeval) {
228 break;
229 }
230
231 if (backoff.hasNextTimeout()) {
232 // TODO: make the thread able to receive signals to shutdown early.
233 std::this_thread::sleep_for(backoff.getNextTimeout());
234 } else {
235 break;
236 }
237 }
238 });
239 validate_thread.detach();
240 }
241
sendPrivateDnsValidationEvent(const ServerIdentity & identity,unsigned netId,bool success) const242 void PrivateDnsConfiguration::sendPrivateDnsValidationEvent(const ServerIdentity& identity,
243 unsigned netId, bool success) const {
244 LOG(DEBUG) << "Sending validation " << (success ? "success" : "failure") << " event on netId "
245 << netId << " for " << identity.sockaddr.toString() << " with hostname {"
246 << identity.provider << "}";
247 // Send a validation event to NetdEventListenerService.
248 const auto& listeners = ResolverEventReporter::getInstance().getListeners();
249 if (listeners.empty()) {
250 LOG(ERROR)
251 << "Validation event not sent since no INetdEventListener receiver is available.";
252 }
253 for (const auto& it : listeners) {
254 it->onPrivateDnsValidationEvent(netId, identity.sockaddr.ip().toString(), identity.provider,
255 success);
256 }
257
258 // Send a validation event to unsolicited event listeners.
259 const auto& unsolEventListeners = ResolverEventReporter::getInstance().getUnsolEventListeners();
260 const PrivateDnsValidationEventParcel validationEvent = {
261 .netId = static_cast<int32_t>(netId),
262 .ipAddress = identity.sockaddr.ip().toString(),
263 .hostname = identity.provider,
264 .validation = success ? IDnsResolverUnsolicitedEventListener::VALIDATION_RESULT_SUCCESS
265 : IDnsResolverUnsolicitedEventListener::VALIDATION_RESULT_FAILURE,
266 .protocol = (identity.sockaddr.port() == kDotPort)
267 ? IDnsResolverUnsolicitedEventListener::PROTOCOL_DOT
268 : IDnsResolverUnsolicitedEventListener::PROTOCOL_DOH,
269 };
270 for (const auto& it : unsolEventListeners) {
271 it->onPrivateDnsValidationEvent(validationEvent);
272 }
273 }
274
recordPrivateDnsValidation(const ServerIdentity & identity,unsigned netId,bool success,bool isRevalidation)275 bool PrivateDnsConfiguration::recordPrivateDnsValidation(const ServerIdentity& identity,
276 unsigned netId, bool success,
277 bool isRevalidation) {
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 LOG(WARNING) << "netId " << netId << " was erased during private DNS validation";
286 notifyValidationStateUpdate(identity.sockaddr, Validation::fail, netId);
287 return DONT_REEVALUATE;
288 }
289
290 const auto mode = mPrivateDnsModes.find(netId);
291 if (mode == mPrivateDnsModes.end()) {
292 LOG(WARNING) << "netId " << netId << " has no private DNS validation mode";
293 notifyValidationStateUpdate(identity.sockaddr, Validation::fail, netId);
294 return DONT_REEVALUATE;
295 }
296
297 bool reevaluationStatus = NEEDS_REEVALUATION;
298 if (success) {
299 reevaluationStatus = DONT_REEVALUATE;
300 } else if (mode->second == PrivateDnsMode::OFF) {
301 reevaluationStatus = DONT_REEVALUATE;
302 } else if (mode->second == PrivateDnsMode::OPPORTUNISTIC && !isRevalidation) {
303 reevaluationStatus = DONT_REEVALUATE;
304 }
305
306 auto& tracker = netPair->second;
307 auto serverPair = tracker.find(identity);
308 if (serverPair == tracker.end()) {
309 LOG(WARNING) << "Server " << identity.sockaddr.ip().toString()
310 << " was removed during private DNS validation";
311 success = false;
312 reevaluationStatus = DONT_REEVALUATE;
313 } else if (!serverPair->second->active()) {
314 LOG(WARNING) << "Server " << identity.sockaddr.ip().toString()
315 << " was removed from the configuration";
316 success = false;
317 reevaluationStatus = DONT_REEVALUATE;
318 }
319
320 // Send private dns validation result to listeners.
321 if (needReportEvent(netId, identity, success)) {
322 sendPrivateDnsValidationEvent(identity, netId, success);
323 }
324
325 if (success) {
326 updateServerState(identity, Validation::success, netId);
327 } else {
328 // Validation failure is expected if a user is on a captive portal.
329 // TODO: Trigger a second validation attempt after captive portal login
330 // succeeds.
331 const auto result = (reevaluationStatus == NEEDS_REEVALUATION) ? Validation::in_process
332 : Validation::fail;
333 updateServerState(identity, result, netId);
334 }
335 LOG(WARNING) << "Validation " << (success ? "success" : "failed");
336
337 return reevaluationStatus;
338 }
339
updateServerState(const ServerIdentity & identity,Validation state,uint32_t netId)340 void PrivateDnsConfiguration::updateServerState(const ServerIdentity& identity, Validation state,
341 uint32_t netId) {
342 const auto result = getPrivateDnsLocked(identity, netId);
343 if (!result.ok()) {
344 notifyValidationStateUpdate(identity.sockaddr, Validation::fail, netId);
345 return;
346 }
347
348 auto* server = result.value();
349
350 server->setValidationState(state);
351 notifyValidationStateUpdate(identity.sockaddr, state, netId);
352
353 RecordEntry record(netId, identity, state);
354 mPrivateDnsLog.push(std::move(record));
355 }
356
needsValidation(const IPrivateDnsServer & server) const357 bool PrivateDnsConfiguration::needsValidation(const IPrivateDnsServer& server) const {
358 // The server is not expected to be used on the network.
359 if (!server.active()) return false;
360
361 // The server is newly added.
362 if (server.validationState() == Validation::unknown_server) return true;
363
364 // The server has failed at least one validation attempt. Give it another try.
365 if (server.validationState() == Validation::fail) return true;
366
367 // The previous validation result might be unreliable.
368 if (server.validationState() == Validation::success_but_expired) return true;
369
370 return false;
371 }
372
getPrivateDns(const ServerIdentity & identity,unsigned netId)373 base::Result<IPrivateDnsServer*> PrivateDnsConfiguration::getPrivateDns(
374 const ServerIdentity& identity, unsigned netId) {
375 std::lock_guard guard(mPrivateDnsLock);
376 return getPrivateDnsLocked(identity, netId);
377 }
378
getPrivateDnsLocked(const ServerIdentity & identity,unsigned netId)379 base::Result<IPrivateDnsServer*> PrivateDnsConfiguration::getPrivateDnsLocked(
380 const ServerIdentity& identity, unsigned netId) {
381 auto netPair = mPrivateDnsTransports.find(netId);
382 if (netPair == mPrivateDnsTransports.end()) {
383 return Errorf("Failed to get private DNS: netId {} not found", netId);
384 }
385
386 auto iter = netPair->second.find(identity);
387 if (iter == netPair->second.end()) {
388 return Errorf("Failed to get private DNS: server {{{}/{}}} not found", identity.sockaddr,
389 identity.provider);
390 }
391
392 return iter->second.get();
393 }
394
setObserver(PrivateDnsValidationObserver * observer)395 void PrivateDnsConfiguration::setObserver(PrivateDnsValidationObserver* observer) {
396 std::lock_guard guard(mPrivateDnsLock);
397 mObserver = observer;
398 }
399
getDohServer(unsigned netId) const400 base::Result<netdutils::IPSockAddr> PrivateDnsConfiguration::getDohServer(unsigned netId) const {
401 std::lock_guard guard(mPrivateDnsLock);
402 auto it = mDohTracker.find(netId);
403 if (it != mDohTracker.end()) {
404 return netdutils::IPSockAddr::toIPSockAddr(it->second.ipAddr, kDohPort);
405 }
406
407 return Errorf("Failed to get DoH Server: netId {} not found", netId);
408 }
409
notifyValidationStateUpdate(const netdutils::IPSockAddr & sockaddr,Validation validation,uint32_t netId) const410 void PrivateDnsConfiguration::notifyValidationStateUpdate(const netdutils::IPSockAddr& sockaddr,
411 Validation validation,
412 uint32_t netId) const {
413 if (mObserver) {
414 mObserver->onValidationStateUpdate(sockaddr.ip().toString(), validation, netId);
415 }
416 }
417
dump(netdutils::DumpWriter & dw) const418 void PrivateDnsConfiguration::dump(netdutils::DumpWriter& dw) const {
419 dw.println("PrivateDnsLog:");
420 netdutils::ScopedIndent indentStats(dw);
421
422 for (const auto& record : mPrivateDnsLog.copy()) {
423 dw.println(fmt::format(
424 "{} - netId={} PrivateDns={{{}/{}}} state={}", timestampToString(record.timestamp),
425 record.netId, record.serverIdentity.sockaddr.toString(),
426 record.serverIdentity.provider, validationStatusToString(record.state)));
427 }
428 dw.blankline();
429 }
430
initDoh()431 void PrivateDnsConfiguration::initDoh() {
432 std::lock_guard guard(mPrivateDnsLock);
433 initDohLocked();
434 }
435
initDohLocked()436 void PrivateDnsConfiguration::initDohLocked() {
437 if (mDohDispatcher != nullptr) return;
438 mDohDispatcher = doh_dispatcher_new(
439 [](uint32_t net_id, bool success, const char* ip_addr, const char* host) {
440 android::net::PrivateDnsConfiguration::getInstance().onDohStatusUpdate(
441 net_id, success, ip_addr, host);
442 },
443 [](int32_t sock) { resolv_tag_socket(sock, AID_DNS, NET_CONTEXT_INVALID_PID); });
444 }
445
setDoh(int32_t netId,uint32_t mark,const std::vector<std::string> & servers,const std::string & name,const std::string & caCert)446 int PrivateDnsConfiguration::setDoh(int32_t netId, uint32_t mark,
447 const std::vector<std::string>& servers,
448 const std::string& name, const std::string& caCert) {
449 LOG(DEBUG) << "PrivateDnsConfiguration::setDoh(" << netId << ", 0x" << std::hex << mark
450 << std::dec << ", " << servers.size() << ", " << name << ")";
451 std::lock_guard guard(mPrivateDnsLock);
452 if (servers.empty()) {
453 clearDohLocked(netId);
454 return 0;
455 }
456
457 const auto getTimeoutFromFlag = [&](const std::string_view key, int defaultValue) -> uint64_t {
458 static constexpr int kMinTimeoutMs = 1000;
459 uint64_t timeout = Experiments::getInstance()->getFlag(key, defaultValue);
460 if (timeout < kMinTimeoutMs) {
461 timeout = kMinTimeoutMs;
462 }
463 return timeout;
464 };
465
466 // Sort the input servers to ensure that we could get the server vector at the same order.
467 std::vector<std::string> sortedServers = servers;
468 // Prefer ipv6.
469 std::sort(sortedServers.begin(), sortedServers.end(), [](std::string a, std::string b) {
470 IPAddress ipa = IPAddress::forString(a);
471 IPAddress ipb = IPAddress::forString(b);
472 return ipa > ipb;
473 });
474
475 initDohLocked();
476
477 // TODO: 1. Improve how to choose the server
478 // TODO: 2. Support multiple servers
479 for (const auto& entry : mAvailableDoHProviders) {
480 const auto& doh = entry.getDohIdentity(sortedServers, name);
481 if (!doh.ok()) continue;
482
483 // Since the DnsResolver is expected to be configured by the system server, add the
484 // restriction to prevent ResolverTestProvider from being used other than testing.
485 if (entry.requireRootPermission && AIBinder_getCallingUid() != AID_ROOT) continue;
486
487 auto it = mDohTracker.find(netId);
488 // Skip if the same server already exists and its status == success.
489 if (it != mDohTracker.end() && it->second == doh.value() &&
490 it->second.status == Validation::success) {
491 return 0;
492 }
493 const auto& [dohIt, _] = mDohTracker.insert_or_assign(netId, doh.value());
494 const auto& dohId = dohIt->second;
495
496 RecordEntry record(netId,
497 {netdutils::IPSockAddr::toIPSockAddr(dohId.ipAddr, kDohPort), name},
498 dohId.status);
499 mPrivateDnsLog.push(std::move(record));
500 LOG(INFO) << __func__ << ": Upgrading server to DoH: " << name;
501 resolv_stats_set_addrs(netId, PROTO_DOH, {dohId.ipAddr}, kDohPort);
502
503 const FeatureFlags flags = {
504 .probe_timeout_ms =
505 getTimeoutFromFlag("doh_probe_timeout_ms", kDohProbeDefaultTimeoutMs),
506 .idle_timeout_ms =
507 getTimeoutFromFlag("doh_idle_timeout_ms", kDohIdleDefaultTimeoutMs),
508 .use_session_resumption =
509 Experiments::getInstance()->getFlag("doh_session_resumption", 0) == 1,
510 };
511 LOG(DEBUG) << __func__ << ": probe_timeout_ms=" << flags.probe_timeout_ms
512 << ", idle_timeout_ms=" << flags.idle_timeout_ms
513 << ", use_session_resumption=" << flags.use_session_resumption;
514
515 return doh_net_new(mDohDispatcher, netId, dohId.httpsTemplate.c_str(), dohId.host.c_str(),
516 dohId.ipAddr.c_str(), mark, caCert.c_str(), &flags);
517 }
518
519 LOG(INFO) << __func__ << ": No suitable DoH server found";
520 clearDohLocked(netId);
521 return 0;
522 }
523
clearDohLocked(unsigned netId)524 void PrivateDnsConfiguration::clearDohLocked(unsigned netId) {
525 LOG(DEBUG) << "PrivateDnsConfiguration::clearDohLocked (" << netId << ")";
526 if (mDohDispatcher != nullptr) doh_net_delete(mDohDispatcher, netId);
527 mDohTracker.erase(netId);
528 resolv_stats_set_addrs(netId, PROTO_DOH, {}, kDohPort);
529 }
530
clearDoh(unsigned netId)531 void PrivateDnsConfiguration::clearDoh(unsigned netId) {
532 std::lock_guard guard(mPrivateDnsLock);
533 clearDohLocked(netId);
534 }
535
dohQuery(unsigned netId,const Slice query,const Slice answer,uint64_t timeoutMs)536 ssize_t PrivateDnsConfiguration::dohQuery(unsigned netId, const Slice query, const Slice answer,
537 uint64_t timeoutMs) {
538 {
539 std::lock_guard guard(mPrivateDnsLock);
540 // It's safe because mDohDispatcher won't be deleted after initializing.
541 if (mDohDispatcher == nullptr) return DOH_RESULT_CAN_NOT_SEND;
542 }
543 return doh_query(mDohDispatcher, netId, query.base(), query.size(), answer.base(),
544 answer.size(), timeoutMs);
545 }
546
onDohStatusUpdate(uint32_t netId,bool success,const char * ipAddr,const char * host)547 void PrivateDnsConfiguration::onDohStatusUpdate(uint32_t netId, bool success, const char* ipAddr,
548 const char* host) {
549 LOG(INFO) << __func__ << ": " << netId << ", " << success << ", " << ipAddr << ", " << host;
550 std::lock_guard guard(mPrivateDnsLock);
551 // Update the server status.
552 auto it = mDohTracker.find(netId);
553 if (it == mDohTracker.end() || (it->second.ipAddr != ipAddr && it->second.host != host)) {
554 LOG(WARNING) << __func__ << ": Obsolete event";
555 return;
556 }
557 Validation status = success ? Validation::success : Validation::fail;
558 it->second.status = status;
559 // Send the events to registered listeners.
560 ServerIdentity identity = {netdutils::IPSockAddr::toIPSockAddr(ipAddr, kDohPort), host};
561 if (needReportEvent(netId, identity, success)) {
562 sendPrivateDnsValidationEvent(identity, netId, success);
563 }
564 // Add log.
565 RecordEntry record(netId, identity, status);
566 mPrivateDnsLog.push(std::move(record));
567 }
568
needReportEvent(uint32_t netId,ServerIdentity identity,bool success) const569 bool PrivateDnsConfiguration::needReportEvent(uint32_t netId, ServerIdentity identity,
570 bool success) const {
571 // If the result is success or DoH is not enable, no concern to report the events.
572 if (success || !isDoHEnabled()) return true;
573 // If the result is failure, check another transport's status to determine if we should report
574 // the event.
575 switch (identity.sockaddr.port()) {
576 // DoH
577 case kDohPort: {
578 auto netPair = mPrivateDnsTransports.find(netId);
579 if (netPair == mPrivateDnsTransports.end()) return true;
580 for (const auto& [id, server] : netPair->second) {
581 if ((identity.sockaddr.ip() == id.sockaddr.ip()) &&
582 (identity.sockaddr.port() != id.sockaddr.port()) &&
583 (server->validationState() == Validation::success)) {
584 LOG(DEBUG) << __func__
585 << ": Skip reporting DoH validation failure event, server addr: "
586 << identity.sockaddr.ip().toString();
587 return false;
588 }
589 }
590 break;
591 }
592 // DoT
593 case kDotPort: {
594 auto it = mDohTracker.find(netId);
595 if (it == mDohTracker.end()) return true;
596 if (it->second == identity && it->second.status == Validation::success) {
597 LOG(DEBUG) << __func__
598 << ": Skip reporting DoT validation failure event, server addr: "
599 << identity.sockaddr.ip().toString();
600 return false;
601 }
602 break;
603 }
604 }
605 return true;
606 }
607
608 } // namespace net
609 } // namespace android
610