| // Copyright 2019 The Chromium Authors |
| // 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 <memory> |
| |
| #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<AddrInfoGetter> getter, |
| handles::NetworkHandle network) { |
| if (getter == nullptr) |
| getter = std::make_unique<AddrInfoGetter>(); |
| int err = OK; |
| int os_error = 0; |
| std::unique_ptr<addrinfo, FreeAddrInfoFunc> 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<AddressInfo>(), err, os_error); |
| } |
| |
| return AddressInfoAndResult(absl::optional<AddressInfo>(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<std::string> AddressInfo::GetCanonicalName() const { |
| return (ai_->ai_canonname != nullptr) |
| ? absl::optional<std::string>(std::string(ai_->ai_canonname)) |
| : absl::optional<std::string>(); |
| } |
| |
| 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<struct sockaddr_in*>(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<struct sockaddr_in6*>(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<std::string> 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<addrinfo, FreeAddrInfoFunc> ai, |
| std::unique_ptr<AddrInfoGetter> getter) |
| : ai_(std::move(ai)), getter_(std::move(getter)) {} |
| |
| //// AddrInfoGetter |
| |
| AddrInfoGetter::AddrInfoGetter() = default; |
| AddrInfoGetter::~AddrInfoGetter() = default; |
| |
| std::unique_ptr<addrinfo, FreeAddrInfoFunc> 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<addrinfo, FreeAddrInfoFunc> 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 |