xref: /aosp_15_r20/external/cronet/net/dns/address_info.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/dns/address_info.h"
6 
7 #include <memory>
8 #include <optional>
9 
10 #include "base/logging.h"
11 #include "base/notreached.h"
12 #include "base/sys_byteorder.h"
13 #include "build/build_config.h"
14 #include "net/base/address_list.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/sys_addrinfo.h"
17 
18 #if BUILDFLAG(IS_ANDROID)
19 #include "net/android/network_library.h"
20 #endif  // BUILDFLAG(IS_ANDROID)
21 
22 namespace net {
23 
24 namespace {
25 
Next(const addrinfo * ai)26 const addrinfo* Next(const addrinfo* ai) {
27   return ai->ai_next;
28 }
29 
30 }  // namespace
31 
32 //// iterator
33 
const_iterator(const addrinfo * ai)34 AddressInfo::const_iterator::const_iterator(const addrinfo* ai) : ai_(ai) {}
35 
operator !=(const AddressInfo::const_iterator & o) const36 bool AddressInfo::const_iterator::operator!=(
37     const AddressInfo::const_iterator& o) const {
38   return ai_ != o.ai_;
39 }
40 
operator ++()41 AddressInfo::const_iterator& AddressInfo::const_iterator::operator++() {
42   ai_ = Next(ai_);
43   return *this;
44 }
45 
operator ->() const46 const addrinfo* AddressInfo::const_iterator::operator->() const {
47   return ai_;
48 }
49 
operator *() const50 const addrinfo& AddressInfo::const_iterator::operator*() const {
51   return *ai_;
52 }
53 
54 //// constructors
55 
Get(const std::string & host,const addrinfo & hints,std::unique_ptr<AddrInfoGetter> getter,handles::NetworkHandle network)56 AddressInfo::AddressInfoAndResult AddressInfo::Get(
57     const std::string& host,
58     const addrinfo& hints,
59     std::unique_ptr<AddrInfoGetter> getter,
60     handles::NetworkHandle network) {
61   if (getter == nullptr)
62     getter = std::make_unique<AddrInfoGetter>();
63   int err = OK;
64   int os_error = 0;
65   std::unique_ptr<addrinfo, FreeAddrInfoFunc> ai =
66       getter->getaddrinfo(host, &hints, &os_error, network);
67 
68   if (!ai) {
69     err = ERR_NAME_NOT_RESOLVED;
70 
71     // If the call to getaddrinfo() failed because of a system error, report
72     // it separately from ERR_NAME_NOT_RESOLVED.
73 #if BUILDFLAG(IS_WIN)
74     if (os_error != WSAHOST_NOT_FOUND && os_error != WSANO_DATA)
75       err = ERR_NAME_RESOLUTION_FAILED;
76 #elif BUILDFLAG(IS_ANDROID)
77     // Workaround for Android's getaddrinfo leaving ai==nullptr without an
78     // error.
79     // http://crbug.com/134142
80     err = ERR_NAME_NOT_RESOLVED;
81 #elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_FREEBSD)
82     if (os_error != EAI_NONAME && os_error != EAI_NODATA)
83       err = ERR_NAME_RESOLUTION_FAILED;
84 #endif
85 
86     return AddressInfoAndResult(std::optional<AddressInfo>(), err, os_error);
87   }
88 
89   return AddressInfoAndResult(
90       std::optional<AddressInfo>(AddressInfo(std::move(ai), std::move(getter))),
91       OK, 0);
92 }
93 
94 AddressInfo::AddressInfo(AddressInfo&& other) = default;
95 
96 AddressInfo& AddressInfo::operator=(AddressInfo&& other) = default;
97 
98 AddressInfo::~AddressInfo() = default;
99 
100 //// public methods
101 
begin() const102 AddressInfo::const_iterator AddressInfo::begin() const {
103   return const_iterator(ai_.get());
104 }
105 
end() const106 AddressInfo::const_iterator AddressInfo::end() const {
107   return const_iterator(nullptr);
108 }
109 
GetCanonicalName() const110 std::optional<std::string> AddressInfo::GetCanonicalName() const {
111   return (ai_->ai_canonname != nullptr)
112              ? std::optional<std::string>(std::string(ai_->ai_canonname))
113              : std::optional<std::string>();
114 }
115 
IsAllLocalhostOfOneFamily() const116 bool AddressInfo::IsAllLocalhostOfOneFamily() const {
117   bool saw_v4_localhost = false;
118   bool saw_v6_localhost = false;
119   const auto* ai = ai_.get();
120   for (; ai != nullptr; ai = Next(ai)) {
121     switch (ai->ai_family) {
122       case AF_INET: {
123         const struct sockaddr_in* addr_in =
124             reinterpret_cast<struct sockaddr_in*>(ai->ai_addr);
125         if ((base::NetToHost32(addr_in->sin_addr.s_addr) & 0xff000000) ==
126             0x7f000000)
127           saw_v4_localhost = true;
128         else
129           return false;
130         break;
131       }
132       case AF_INET6: {
133         const struct sockaddr_in6* addr_in6 =
134             reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr);
135         if (IN6_IS_ADDR_LOOPBACK(&addr_in6->sin6_addr))
136           saw_v6_localhost = true;
137         else
138           return false;
139         break;
140       }
141       default:
142         return false;
143     }
144   }
145 
146   return saw_v4_localhost != saw_v6_localhost;
147 }
148 
CreateAddressList() const149 AddressList AddressInfo::CreateAddressList() const {
150   AddressList list;
151   auto canonical_name = GetCanonicalName();
152   if (canonical_name) {
153     std::vector<std::string> aliases({*canonical_name});
154     list.SetDnsAliases(std::move(aliases));
155   }
156   for (auto&& ai : *this) {
157     IPEndPoint ipe;
158     // NOTE: Ignoring non-INET* families.
159     if (ipe.FromSockAddr(ai.ai_addr, ai.ai_addrlen))
160       list.push_back(ipe);
161     else
162       DLOG(WARNING) << "Unknown family found in addrinfo: " << ai.ai_family;
163   }
164   return list;
165 }
166 
167 //// private methods
168 
AddressInfo(std::unique_ptr<addrinfo,FreeAddrInfoFunc> ai,std::unique_ptr<AddrInfoGetter> getter)169 AddressInfo::AddressInfo(std::unique_ptr<addrinfo, FreeAddrInfoFunc> ai,
170                          std::unique_ptr<AddrInfoGetter> getter)
171     : ai_(std::move(ai)), getter_(std::move(getter)) {}
172 
173 //// AddrInfoGetter
174 
175 AddrInfoGetter::AddrInfoGetter() = default;
176 AddrInfoGetter::~AddrInfoGetter() = default;
177 
getaddrinfo(const std::string & host,const addrinfo * hints,int * out_os_error,handles::NetworkHandle network)178 std::unique_ptr<addrinfo, FreeAddrInfoFunc> AddrInfoGetter::getaddrinfo(
179     const std::string& host,
180     const addrinfo* hints,
181     int* out_os_error,
182     handles::NetworkHandle network) {
183   addrinfo* ai;
184   // We wrap freeaddrinfo() in a lambda just in case some operating systems use
185   // a different signature for it.
186   FreeAddrInfoFunc deleter = [](addrinfo* ai) { ::freeaddrinfo(ai); };
187 
188   std::unique_ptr<addrinfo, FreeAddrInfoFunc> rv = {nullptr, deleter};
189 
190   if (network != handles::kInvalidNetworkHandle) {
191     // Currently, only Android supports lookups for a specific network.
192 #if BUILDFLAG(IS_ANDROID)
193     *out_os_error = android::GetAddrInfoForNetwork(network, host.c_str(),
194                                                    nullptr, hints, &ai);
195 #elif BUILDFLAG(IS_WIN)
196     *out_os_error = WSAEOPNOTSUPP;
197     return rv;
198 #else
199     errno = ENOSYS;
200     *out_os_error = EAI_SYSTEM;
201     return rv;
202 #endif  // BUILDFLAG(IS_ANDROID)
203   } else {
204     *out_os_error = ::getaddrinfo(host.c_str(), nullptr, hints, &ai);
205   }
206 
207   if (*out_os_error) {
208 #if BUILDFLAG(IS_WIN)
209     *out_os_error = WSAGetLastError();
210 #endif
211     return rv;
212   }
213 
214   rv.reset(ai);
215   return rv;
216 }
217 
218 }  // namespace net
219