// Copyright (c) 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/dns/address_info.h" #include #include "base/logging.h" #include "base/notreached.h" #include "base/sys_byteorder.h" #include "build/build_config.h" #include "net/base/address_list.h" #include "net/base/net_errors.h" #include "net/base/sys_addrinfo.h" #if BUILDFLAG(IS_ANDROID) #include "net/android/network_library.h" #endif // BUILDFLAG(IS_ANDROID) namespace net { namespace { const addrinfo* Next(const addrinfo* ai) { return ai->ai_next; } } // namespace //// iterator AddressInfo::const_iterator::const_iterator(const addrinfo* ai) : ai_(ai) {} bool AddressInfo::const_iterator::operator!=( const AddressInfo::const_iterator& o) const { return ai_ != o.ai_; } AddressInfo::const_iterator& AddressInfo::const_iterator::operator++() { ai_ = Next(ai_); return *this; } const addrinfo* AddressInfo::const_iterator::operator->() const { return ai_; } const addrinfo& AddressInfo::const_iterator::operator*() const { return *ai_; } //// constructors AddressInfo::AddressInfoAndResult AddressInfo::Get( const std::string& host, const addrinfo& hints, std::unique_ptr getter, handles::NetworkHandle network) { if (getter == nullptr) getter = std::make_unique(); int err = OK; int os_error = 0; std::unique_ptr ai = getter->getaddrinfo(host, &hints, &os_error, network); if (!ai) { err = ERR_NAME_NOT_RESOLVED; // If the call to getaddrinfo() failed because of a system error, report // it separately from ERR_NAME_NOT_RESOLVED. #if BUILDFLAG(IS_WIN) if (os_error != WSAHOST_NOT_FOUND && os_error != WSANO_DATA) err = ERR_NAME_RESOLUTION_FAILED; #elif BUILDFLAG(IS_ANDROID) // Workaround for Android's getaddrinfo leaving ai==nullptr without an // error. // http://crbug.com/134142 err = ERR_NAME_NOT_RESOLVED; #elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_FREEBSD) if (os_error != EAI_NONAME && os_error != EAI_NODATA) err = ERR_NAME_RESOLUTION_FAILED; #endif return AddressInfoAndResult(absl::optional(), err, os_error); } return AddressInfoAndResult(absl::optional(AddressInfo( std::move(ai), std::move(getter))), OK, 0); } AddressInfo::AddressInfo(AddressInfo&& other) = default; AddressInfo& AddressInfo::operator=(AddressInfo&& other) = default; AddressInfo::~AddressInfo() = default; //// public methods AddressInfo::const_iterator AddressInfo::begin() const { return const_iterator(ai_.get()); } AddressInfo::const_iterator AddressInfo::end() const { return const_iterator(nullptr); } absl::optional AddressInfo::GetCanonicalName() const { return (ai_->ai_canonname != nullptr) ? absl::optional(std::string(ai_->ai_canonname)) : absl::optional(); } bool AddressInfo::IsAllLocalhostOfOneFamily() const { bool saw_v4_localhost = false; bool saw_v6_localhost = false; const auto* ai = ai_.get(); for (; ai != nullptr; ai = Next(ai)) { switch (ai->ai_family) { case AF_INET: { const struct sockaddr_in* addr_in = reinterpret_cast(ai->ai_addr); if ((base::NetToHost32(addr_in->sin_addr.s_addr) & 0xff000000) == 0x7f000000) saw_v4_localhost = true; else return false; break; } case AF_INET6: { const struct sockaddr_in6* addr_in6 = reinterpret_cast(ai->ai_addr); if (IN6_IS_ADDR_LOOPBACK(&addr_in6->sin6_addr)) saw_v6_localhost = true; else return false; break; } default: NOTREACHED(); return false; } } return saw_v4_localhost != saw_v6_localhost; } AddressList AddressInfo::CreateAddressList() const { AddressList list; auto canonical_name = GetCanonicalName(); if (canonical_name) { std::vector aliases({*canonical_name}); list.SetDnsAliases(std::move(aliases)); } for (auto&& ai : *this) { IPEndPoint ipe; // NOTE: Ignoring non-INET* families. if (ipe.FromSockAddr(ai.ai_addr, ai.ai_addrlen)) list.push_back(ipe); else DLOG(WARNING) << "Unknown family found in addrinfo: " << ai.ai_family; } return list; } //// private methods AddressInfo::AddressInfo(std::unique_ptr ai, std::unique_ptr getter) : ai_(std::move(ai)), getter_(std::move(getter)) {} //// AddrInfoGetter AddrInfoGetter::AddrInfoGetter() = default; AddrInfoGetter::~AddrInfoGetter() = default; std::unique_ptr AddrInfoGetter::getaddrinfo( const std::string& host, const addrinfo* hints, int* out_os_error, handles::NetworkHandle network) { addrinfo* ai; // We wrap freeaddrinfo() in a lambda just in case some operating systems use // a different signature for it. FreeAddrInfoFunc deleter = [](addrinfo* ai) { ::freeaddrinfo(ai); }; std::unique_ptr rv = {nullptr, deleter}; if (network != handles::kInvalidNetworkHandle) { // Currently, only Android supports lookups for a specific network. #if BUILDFLAG(IS_ANDROID) *out_os_error = android::GetAddrInfoForNetwork(network, host.c_str(), nullptr, hints, &ai); #elif BUILDFLAG(IS_WIN) *out_os_error = WSAEOPNOTSUPP; return rv; #else errno = ENOSYS; *out_os_error = EAI_SYSTEM; return rv; #endif // BUILDFLAG(IS_ANDROID) } else { *out_os_error = ::getaddrinfo(host.c_str(), nullptr, hints, &ai); } if (*out_os_error) { #if BUILDFLAG(IS_WIN) *out_os_error = WSAGetLastError(); #endif return rv; } rv.reset(ai); return rv; } } // namespace net