blob: a1dfdca02887336021cc10112105296b4e03d332 [file] [log] [blame]
Erik Klined26a2c22018-05-11 19:33:19 +09001/*
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 "Dns64Configuration"
18#define DBG 0
19
20#include "Dns64Configuration.h"
21
22#include <log/log.h>
23#include <netdb.h>
24#include <thread>
25#include <utility>
26
27#include <arpa/inet.h>
Bernie Innocenti189eb502018-10-01 23:10:18 +090028
Luke Huang43754b42019-03-28 14:09:24 +080029#include "DnsResolver.h"
30#include "NetdConstants.h" // ScopedAddrinfo
Bernie Innocenti9fa30802019-05-29 10:51:38 -070031#include "getaddrinfo.h"
Luke Huang43754b42019-03-28 14:09:24 +080032#include "netd_resolv/resolv.h"
Erik Klined26a2c22018-05-11 19:33:19 +090033#include "netdutils/BackoffSequence.h"
Luke Huangb257d612019-03-14 21:19:13 +080034#include "netdutils/DumpWriter.h"
Bernie Innocenti189eb502018-10-01 23:10:18 +090035#include "netid_client.h"
Frank Li08ce7b82019-06-27 10:11:52 -070036#include "stats.pb.h"
Erik Klined26a2c22018-05-11 19:33:19 +090037
38namespace android {
39
Frank Li08ce7b82019-06-27 10:11:52 -070040using android::net::NetworkDnsEventReported;
Luke Huangb257d612019-03-14 21:19:13 +080041using netdutils::DumpWriter;
Erik Klined26a2c22018-05-11 19:33:19 +090042using netdutils::IPAddress;
43using netdutils::IPPrefix;
44
45namespace net {
46
47const char Dns64Configuration::kIPv4OnlyHost[] = "ipv4only.arpa.";
48const char Dns64Configuration::kIPv4Literal1[] = "192.0.0.170";
49const char Dns64Configuration::kIPv4Literal2[] = "192.0.0.171";
50
51void Dns64Configuration::startPrefixDiscovery(unsigned netId) {
52 std::lock_guard guard(mMutex);
53
nuccachenf52f7a52018-07-17 18:07:23 +080054 // TODO: Keep previous prefix for a while
55 // Currently, we remove current prefix, if any, before starting a prefix discovery.
56 // This causes that Netd and framework temporarily forgets DNS64 prefix even the prefix may be
57 // discovered in a short time.
58 removeDns64Config(netId);
Erik Klined26a2c22018-05-11 19:33:19 +090059
60 Dns64Config cfg(getNextId(), netId);
61 // Emplace a copy of |cfg| in the map.
62 mDns64Configs.emplace(std::make_pair(netId, cfg));
63
64 // Note that capturing |cfg| in this lambda creates a copy.
65 std::thread discovery_thread([this, cfg] {
66 // Make a mutable copy rather than mark the whole lambda mutable.
67 // No particular reason.
68 Dns64Config evalCfg(cfg);
69
70 auto backoff = netdutils::BackoffSequence<>::Builder()
Luke Huang43754b42019-03-28 14:09:24 +080071 .withInitialRetransmissionTime(std::chrono::seconds(1))
72 .withMaximumRetransmissionTime(std::chrono::seconds(3600))
73 .build();
Erik Klined26a2c22018-05-11 19:33:19 +090074
75 while (true) {
76 if (!this->shouldContinueDiscovery(evalCfg)) break;
77
78 android_net_context netcontext{};
Luke Huang43754b42019-03-28 14:09:24 +080079 mGetNetworkContextCallback(evalCfg.netId, 0, &netcontext);
80
Mike Yu924726d2018-11-27 13:19:31 +090081 // Prefix discovery must bypass private DNS because in strict mode
82 // the server generally won't know the NAT64 prefix.
83 netcontext.flags |= NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS;
Erik Klined26a2c22018-05-11 19:33:19 +090084 if (doRfc7050PrefixDiscovery(netcontext, &evalCfg)) {
85 this->recordDns64Config(evalCfg);
86 break;
87 }
88
89 if (!this->shouldContinueDiscovery(evalCfg)) break;
90
91 if (!backoff.hasNextTimeout()) break;
92 {
93 std::unique_lock<std::mutex> cvGuard(mMutex);
94 // TODO: Consider some chrono math, combined with wait_until()
95 // perhaps, to prevent early re-resolves from the removal of
96 // other netids with IPv6-only nameservers.
97 mCv.wait_for(cvGuard, backoff.getNextTimeout());
98 }
99 }
100 });
101 discovery_thread.detach();
102}
103
104void Dns64Configuration::stopPrefixDiscovery(unsigned netId) {
105 std::lock_guard guard(mMutex);
nuccachenf52f7a52018-07-17 18:07:23 +0800106 removeDns64Config(netId);
Erik Klined26a2c22018-05-11 19:33:19 +0900107 mCv.notify_all();
108}
109
nuccachenf52f7a52018-07-17 18:07:23 +0800110IPPrefix Dns64Configuration::getPrefix64Locked(unsigned netId) const REQUIRES(mMutex) {
Erik Klined26a2c22018-05-11 19:33:19 +0900111 const auto& iter = mDns64Configs.find(netId);
112 if (iter != mDns64Configs.end()) return iter->second.prefix64;
113
114 return IPPrefix{};
115}
116
nuccachenf52f7a52018-07-17 18:07:23 +0800117IPPrefix Dns64Configuration::getPrefix64(unsigned netId) const {
118 std::lock_guard guard(mMutex);
119 return getPrefix64Locked(netId);
120}
121
Erik Klined26a2c22018-05-11 19:33:19 +0900122void Dns64Configuration::dump(DumpWriter& dw, unsigned netId) {
123 static const char kLabel[] = "DNS64 config";
124
125 std::lock_guard guard(mMutex);
126
127 const auto& iter = mDns64Configs.find(netId);
128 if (iter == mDns64Configs.end()) {
129 dw.println("%s: none", kLabel);
130 return;
131 }
132
133 const Dns64Config& cfg = iter->second;
134 if (cfg.prefix64.length() == 0) {
135 dw.println("%s: no prefix yet discovered", kLabel);
136 } else {
137 dw.println("%s: discovered prefix %s", kLabel, cfg.prefix64.toString().c_str());
138 }
139}
140
141// NOTE: The full RFC 7050 DNS64 discovery process is not implemented here.
142// Instead, and more simplistic version of the same thing is done, and it
143// currently assumes the DNS64 prefix is a /96.
144bool Dns64Configuration::doRfc7050PrefixDiscovery(const android_net_context& netcontext,
145 Dns64Config* cfg) {
146 ALOGW("(%u, %u) Detecting NAT64 prefix from DNS...", cfg->netId, cfg->discoveryId);
147
148 const struct addrinfo hints = {
149 .ai_family = AF_INET6,
150 };
151
152 // TODO: Refactor so that netd can get all the regular getaddrinfo handling
153 // that regular apps get. We bypass the UNIX socket connection back to
154 // ourselves, which means we also bypass all the special netcontext flag
Mike Yu924726d2018-11-27 13:19:31 +0900155 // handling and the resolver event logging.
Erik Klined26a2c22018-05-11 19:33:19 +0900156 struct addrinfo* res = nullptr;
Frank Li08ce7b82019-06-27 10:11:52 -0700157 NetworkDnsEventReported event;
158 const int status = android_getaddrinfofornetcontext(kIPv4OnlyHost, nullptr, &hints, &netcontext,
159 &res, &event);
Erik Klined26a2c22018-05-11 19:33:19 +0900160 ScopedAddrinfo result(res);
161 if (status != 0) {
Luke Huang43754b42019-03-28 14:09:24 +0800162 ALOGW("(%u, %u) plat_prefix/dns(%s) status = %d/%s", cfg->netId, cfg->discoveryId,
163 kIPv4OnlyHost, status, gai_strerror(status));
Erik Klined26a2c22018-05-11 19:33:19 +0900164 return false;
165 }
166
167 // Use only the first result. If other records are present, possibly
168 // with differing DNS64 prefixes they are ignored. Note that this is a
169 // violation of https://tools.ietf.org/html/rfc7050#section-3
170 //
171 // "A node MUST look through all of the received AAAA resource records
172 // to collect one or more Pref64::/n."
173 //
174 // TODO: Consider remedying this.
175 if (result->ai_family != AF_INET6) {
Luke Huang43754b42019-03-28 14:09:24 +0800176 ALOGW("(%u, %u) plat_prefix/unexpected address family: %d", cfg->netId, cfg->discoveryId,
177 result->ai_family);
Erik Klined26a2c22018-05-11 19:33:19 +0900178 return false;
179 }
180 const IPAddress ipv6(reinterpret_cast<sockaddr_in6*>(result->ai_addr)->sin6_addr);
181 // Only /96 DNS64 prefixes are supported at this time.
182 cfg->prefix64 = IPPrefix(ipv6, 96);
183
Luke Huang43754b42019-03-28 14:09:24 +0800184 ALOGW("(%u, %u) Detected NAT64 prefix %s", cfg->netId, cfg->discoveryId,
185 cfg->prefix64.toString().c_str());
Erik Klined26a2c22018-05-11 19:33:19 +0900186
187 return true;
188}
189
Erik Kline603df202018-09-10 18:16:26 +0900190bool Dns64Configuration::isDiscoveryInProgress(const Dns64Config& cfg) const REQUIRES(mMutex) {
Erik Klined26a2c22018-05-11 19:33:19 +0900191 const auto& iter = mDns64Configs.find(cfg.netId);
192 if (iter == mDns64Configs.end()) return false;
193
194 const Dns64Config& currentCfg = iter->second;
195 return (currentCfg.discoveryId == cfg.discoveryId);
196}
197
nuccachenf52f7a52018-07-17 18:07:23 +0800198bool Dns64Configuration::reportNat64PrefixStatus(unsigned netId, bool added, const IPPrefix& pfx) {
199 if (pfx.ip().family() != AF_INET6 || pfx.ip().scope_id() != 0) {
200 ALOGW("Abort to send NAT64 prefix notification. Unexpected NAT64 prefix (%u, %d, %s).",
201 netId, added, pfx.toString().c_str());
202 return false;
203 }
Luke Huang43754b42019-03-28 14:09:24 +0800204 Nat64PrefixInfo args = {netId, added, pfx.ip().toString(), (uint8_t)pfx.length()};
nuccachenf52f7a52018-07-17 18:07:23 +0800205 mPrefixCallback(args);
206 return true;
207}
208
Erik Klined26a2c22018-05-11 19:33:19 +0900209bool Dns64Configuration::shouldContinueDiscovery(const Dns64Config& cfg) {
210 std::lock_guard guard(mMutex);
Erik Kline603df202018-09-10 18:16:26 +0900211 return isDiscoveryInProgress(cfg);
Erik Klined26a2c22018-05-11 19:33:19 +0900212}
213
nuccachenf52f7a52018-07-17 18:07:23 +0800214void Dns64Configuration::removeDns64Config(unsigned netId) REQUIRES(mMutex) {
215 IPPrefix prefix = getPrefix64Locked(netId);
216 mDns64Configs.erase(netId);
217 if (!prefix.isUninitialized()) {
218 reportNat64PrefixStatus(netId, PREFIX_REMOVED, prefix);
219 }
220}
221
Erik Klined26a2c22018-05-11 19:33:19 +0900222void Dns64Configuration::recordDns64Config(const Dns64Config& cfg) {
223 std::lock_guard guard(mMutex);
Erik Kline603df202018-09-10 18:16:26 +0900224 if (!isDiscoveryInProgress(cfg)) return;
Erik Klined26a2c22018-05-11 19:33:19 +0900225
nuccachenf52f7a52018-07-17 18:07:23 +0800226 removeDns64Config(cfg.netId);
Erik Klined26a2c22018-05-11 19:33:19 +0900227 mDns64Configs.emplace(std::make_pair(cfg.netId, cfg));
228
nuccachenf52f7a52018-07-17 18:07:23 +0800229 reportNat64PrefixStatus(cfg.netId, PREFIX_ADDED, cfg.prefix64);
230
Erik Klined26a2c22018-05-11 19:33:19 +0900231 // TODO: consider extending INetdEventListener to report the DNS64 prefix
232 // up to ConnectivityService to potentially include this in LinkProperties.
233}
234
235} // namespace net
236} // namespace android