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