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 "Dns64Configuration.h" 20 21 #include <android-base/logging.h> 22 #include <netdb.h> 23 #include <netdutils/BackoffSequence.h> 24 #include <netdutils/DumpWriter.h> 25 #include <netdutils/InternetAddresses.h> 26 #include <netdutils/ThreadUtil.h> 27 #include <thread> 28 #include <utility> 29 30 #include <arpa/inet.h> 31 32 #include "DnsResolver.h" 33 #include "getaddrinfo.h" 34 #include "netd_resolv/resolv.h" 35 #include "stats.pb.h" 36 37 namespace android { 38 39 using android::base::StringPrintf; 40 using android::net::NetworkDnsEventReported; 41 using netdutils::DumpWriter; 42 using netdutils::IPAddress; 43 using netdutils::IPPrefix; 44 using netdutils::ScopedAddrinfo; 45 using netdutils::setThreadName; 46 47 namespace net { 48 49 const char Dns64Configuration::kIPv4OnlyHost[] = "ipv4only.arpa."; 50 const char Dns64Configuration::kIPv4Literal1[] = "192.0.0.170"; 51 const char Dns64Configuration::kIPv4Literal2[] = "192.0.0.171"; 52 53 void Dns64Configuration::startPrefixDiscovery(unsigned netId) { 54 std::lock_guard guard(mMutex); 55 56 // TODO: Keep previous prefix for a while 57 // Currently, we remove current prefix, if any, before starting a prefix discovery. 58 // This causes that Netd and framework temporarily forgets DNS64 prefix even the prefix may be 59 // discovered in a short time. 60 removeDns64Config(netId); 61 62 Dns64Config cfg(getNextId(), netId); 63 // Emplace a copy of |cfg| in the map. 64 mDns64Configs.emplace(std::make_pair(netId, cfg)); 65 66 // Note that capturing |cfg| in this lambda creates a copy. 67 std::thread discovery_thread([this, cfg, netId] { 68 setThreadName(StringPrintf("Nat64Pfx_%u", netId).c_str()); 69 70 // Make a mutable copy rather than mark the whole lambda mutable. 71 // No particular reason. 72 Dns64Config evalCfg(cfg); 73 74 auto backoff = netdutils::BackoffSequence<>::Builder() 75 .withInitialRetransmissionTime(std::chrono::seconds(1)) 76 .withMaximumRetransmissionTime(std::chrono::seconds(3600)) 77 .build(); 78 79 while (true) { 80 if (!this->shouldContinueDiscovery(evalCfg)) break; 81 82 android_net_context netcontext{}; 83 mGetNetworkContextCallback(evalCfg.netId, 0, &netcontext); 84 85 // Prefix discovery must bypass private DNS because in strict mode 86 // the server generally won't know the NAT64 prefix. 87 netcontext.flags |= NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS; 88 if (doRfc7050PrefixDiscovery(netcontext, &evalCfg)) { 89 this->recordDns64Config(evalCfg); 90 break; 91 } 92 93 if (!this->shouldContinueDiscovery(evalCfg)) break; 94 95 if (!backoff.hasNextTimeout()) break; 96 { 97 std::unique_lock<std::mutex> cvGuard(mMutex); 98 // TODO: Consider some chrono math, combined with wait_until() 99 // perhaps, to prevent early re-resolves from the removal of 100 // other netids with IPv6-only nameservers. 101 mCv.wait_for(cvGuard, backoff.getNextTimeout()); 102 } 103 } 104 }); 105 discovery_thread.detach(); 106 } 107 108 void Dns64Configuration::stopPrefixDiscovery(unsigned netId) { 109 std::lock_guard guard(mMutex); 110 removeDns64Config(netId); 111 mCv.notify_all(); 112 } 113 114 IPPrefix Dns64Configuration::getPrefix64Locked(unsigned netId) const REQUIRES(mMutex) { 115 const auto& iter = mDns64Configs.find(netId); 116 if (iter != mDns64Configs.end()) return iter->second.prefix64; 117 118 return IPPrefix{}; 119 } 120 121 IPPrefix Dns64Configuration::getPrefix64(unsigned netId) const { 122 std::lock_guard guard(mMutex); 123 return getPrefix64Locked(netId); 124 } 125 126 void Dns64Configuration::dump(DumpWriter& dw, unsigned netId) { 127 static const char kLabel[] = "DNS64 config"; 128 129 std::lock_guard guard(mMutex); 130 131 const auto& iter = mDns64Configs.find(netId); 132 if (iter == mDns64Configs.end()) { 133 dw.println("%s: none", kLabel); 134 return; 135 } 136 137 const Dns64Config& cfg = iter->second; 138 if (cfg.prefix64.length() == 0) { 139 dw.println("%s: no prefix yet discovered", kLabel); 140 } else { 141 dw.println("%s: %s prefix %s", kLabel, cfg.isFromPrefixDiscovery() ? "discovered" : "set", 142 cfg.prefix64.toString().c_str()); 143 } 144 } 145 146 // NOTE: The full RFC 7050 DNS64 discovery process is not implemented here. 147 // Instead, and more simplistic version of the same thing is done, and it 148 // currently assumes the DNS64 prefix is a /96. 149 bool Dns64Configuration::doRfc7050PrefixDiscovery(const android_net_context& netcontext, 150 Dns64Config* cfg) { 151 LOG(WARNING) << "(" << cfg->netId << ", " << cfg->discoveryId 152 << ") Detecting NAT64 prefix from DNS..."; 153 154 const struct addrinfo hints = { 155 .ai_family = AF_INET6, 156 }; 157 158 // TODO: Refactor so that netd can get all the regular getaddrinfo handling 159 // that regular apps get. We bypass the UNIX socket connection back to 160 // ourselves, which means we also bypass all the special netcontext flag 161 // handling and the resolver event logging. 162 struct addrinfo* res = nullptr; 163 NetworkDnsEventReported event; 164 const int status = 165 resolv_getaddrinfo(kIPv4OnlyHost, nullptr, &hints, &netcontext, &res, &event); 166 ScopedAddrinfo result(res); 167 if (status != 0) { 168 LOG(WARNING) << "(" << cfg->netId << ", " << cfg->discoveryId << ") plat_prefix/dns(" 169 << kIPv4OnlyHost << ") status = " << status << "/" << gai_strerror(status); 170 return false; 171 } 172 173 // Use only the first result. If other records are present, possibly 174 // with differing DNS64 prefixes they are ignored. Note that this is a 175 // violation of https://tools.ietf.org/html/rfc7050#section-3 176 // 177 // "A node MUST look through all of the received AAAA resource records 178 // to collect one or more Pref64::/n." 179 // 180 // TODO: Consider remedying this. 181 if (result->ai_family != AF_INET6) { 182 LOG(WARNING) << "(" << cfg->netId << ", " << cfg->discoveryId 183 << ") plat_prefix/unexpected address family: " << result->ai_family; 184 return false; 185 } 186 const IPAddress ipv6(reinterpret_cast<sockaddr_in6*>(result->ai_addr)->sin6_addr); 187 // Only /96 DNS64 prefixes are supported at this time. 188 cfg->prefix64 = IPPrefix(ipv6, 96); 189 LOG(WARNING) << "(" << cfg->netId << ", " << cfg->discoveryId << ") Detected NAT64 prefix " 190 << cfg->prefix64.toString(); 191 return true; 192 } 193 194 bool Dns64Configuration::isDiscoveryInProgress(const Dns64Config& cfg) const REQUIRES(mMutex) { 195 const auto& iter = mDns64Configs.find(cfg.netId); 196 if (iter == mDns64Configs.end()) return false; 197 198 const Dns64Config& currentCfg = iter->second; 199 return (currentCfg.discoveryId == cfg.discoveryId); 200 } 201 202 bool Dns64Configuration::reportNat64PrefixStatus(unsigned netId, bool added, const IPPrefix& pfx) { 203 if (pfx.ip().family() != AF_INET6 || pfx.ip().scope_id() != 0) { 204 LOG(WARNING) << "Abort to send NAT64 prefix notification. Unexpected NAT64 prefix (" 205 << netId << ", " << added << ", " << pfx.toString() << ")."; 206 return false; 207 } 208 Nat64PrefixInfo args = {netId, added, pfx.ip().toString(), (uint8_t)pfx.length()}; 209 mPrefixCallback(args); 210 return true; 211 } 212 213 bool Dns64Configuration::shouldContinueDiscovery(const Dns64Config& cfg) { 214 std::lock_guard guard(mMutex); 215 return isDiscoveryInProgress(cfg); 216 } 217 218 void Dns64Configuration::removeDns64Config(unsigned netId) REQUIRES(mMutex) { 219 const auto& iter = mDns64Configs.find(netId); 220 if (iter == mDns64Configs.end()) return; 221 222 Dns64Config cfg = iter->second; 223 mDns64Configs.erase(iter); 224 225 // Only report a prefix removed event if the prefix was discovered, not if it was set. 226 if (cfg.isFromPrefixDiscovery() && !cfg.prefix64.isUninitialized()) { 227 reportNat64PrefixStatus(netId, PREFIX_REMOVED, cfg.prefix64); 228 } 229 } 230 231 void Dns64Configuration::recordDns64Config(const Dns64Config& cfg) { 232 std::lock_guard guard(mMutex); 233 if (!isDiscoveryInProgress(cfg)) return; 234 235 removeDns64Config(cfg.netId); 236 mDns64Configs.emplace(std::make_pair(cfg.netId, cfg)); 237 238 reportNat64PrefixStatus(cfg.netId, PREFIX_ADDED, cfg.prefix64); 239 } 240 241 int Dns64Configuration::setPrefix64(unsigned netId, const IPPrefix& pfx) { 242 if (pfx.isUninitialized() || pfx.family() != AF_INET6 || pfx.length() != 96) { 243 return -EINVAL; 244 } 245 246 std::lock_guard guard(mMutex); 247 248 // This method may only be called if prefix discovery has been stopped or was never started. 249 auto iter = mDns64Configs.find(netId); 250 if (iter != mDns64Configs.end()) { 251 if (iter->second.isFromPrefixDiscovery()) { 252 return -EEXIST; 253 } else { 254 mDns64Configs.erase(iter); 255 } 256 } 257 258 Dns64Config cfg(kNoDiscoveryId, netId); 259 cfg.prefix64 = pfx; 260 mDns64Configs.emplace(std::make_pair(netId, cfg)); 261 262 return 0; 263 } 264 265 int Dns64Configuration::clearPrefix64(unsigned netId) { 266 std::lock_guard guard(mMutex); 267 268 const auto& iter = mDns64Configs.find(netId); 269 if (iter == mDns64Configs.end() || iter->second.isFromPrefixDiscovery()) { 270 return -ENOENT; 271 } 272 273 mDns64Configs.erase(iter); 274 275 return 0; 276 } 277 278 } // namespace net 279 } // namespace android 280