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
9 #include "base/logging.h"
10 #include "base/notreached.h"
11 #include "base/sys_byteorder.h"
12 #include "build/build_config.h"
13 #include "net/base/address_list.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/sys_addrinfo.h"
16
17 #if BUILDFLAG(IS_ANDROID)
18 #include "net/android/network_library.h"
19 #endif // BUILDFLAG(IS_ANDROID)
20
21 namespace net {
22
23 namespace {
24
Next(const addrinfo * ai)25 const addrinfo* Next(const addrinfo* ai) {
26 return ai->ai_next;
27 }
28
29 } // namespace
30
31 //// iterator
32
const_iterator(const addrinfo * ai)33 AddressInfo::const_iterator::const_iterator(const addrinfo* ai) : ai_(ai) {}
34
operator !=(const AddressInfo::const_iterator & o) const35 bool AddressInfo::const_iterator::operator!=(
36 const AddressInfo::const_iterator& o) const {
37 return ai_ != o.ai_;
38 }
39
operator ++()40 AddressInfo::const_iterator& AddressInfo::const_iterator::operator++() {
41 ai_ = Next(ai_);
42 return *this;
43 }
44
operator ->() const45 const addrinfo* AddressInfo::const_iterator::operator->() const {
46 return ai_;
47 }
48
operator *() const49 const addrinfo& AddressInfo::const_iterator::operator*() const {
50 return *ai_;
51 }
52
53 //// constructors
54
Get(const std::string & host,const addrinfo & hints,std::unique_ptr<AddrInfoGetter> getter,handles::NetworkHandle network)55 AddressInfo::AddressInfoAndResult AddressInfo::Get(
56 const std::string& host,
57 const addrinfo& hints,
58 std::unique_ptr<AddrInfoGetter> getter,
59 handles::NetworkHandle network) {
60 if (getter == nullptr)
61 getter = std::make_unique<AddrInfoGetter>();
62 int err = OK;
63 int os_error = 0;
64 std::unique_ptr<addrinfo, FreeAddrInfoFunc> ai =
65 getter->getaddrinfo(host, &hints, &os_error, network);
66
67 if (!ai) {
68 err = ERR_NAME_NOT_RESOLVED;
69
70 // If the call to getaddrinfo() failed because of a system error, report
71 // it separately from ERR_NAME_NOT_RESOLVED.
72 #if BUILDFLAG(IS_WIN)
73 if (os_error != WSAHOST_NOT_FOUND && os_error != WSANO_DATA)
74 err = ERR_NAME_RESOLUTION_FAILED;
75 #elif BUILDFLAG(IS_ANDROID)
76 // Workaround for Android's getaddrinfo leaving ai==nullptr without an
77 // error.
78 // http://crbug.com/134142
79 err = ERR_NAME_NOT_RESOLVED;
80 #elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_FREEBSD)
81 if (os_error != EAI_NONAME && os_error != EAI_NODATA)
82 err = ERR_NAME_RESOLUTION_FAILED;
83 #endif
84
85 return AddressInfoAndResult(absl::optional<AddressInfo>(), err, os_error);
86 }
87
88 return AddressInfoAndResult(absl::optional<AddressInfo>(AddressInfo(
89 std::move(ai), std::move(getter))),
90 OK, 0);
91 }
92
93 AddressInfo::AddressInfo(AddressInfo&& other) = default;
94
95 AddressInfo& AddressInfo::operator=(AddressInfo&& other) = default;
96
97 AddressInfo::~AddressInfo() = default;
98
99 //// public methods
100
begin() const101 AddressInfo::const_iterator AddressInfo::begin() const {
102 return const_iterator(ai_.get());
103 }
104
end() const105 AddressInfo::const_iterator AddressInfo::end() const {
106 return const_iterator(nullptr);
107 }
108
GetCanonicalName() const109 absl::optional<std::string> AddressInfo::GetCanonicalName() const {
110 return (ai_->ai_canonname != nullptr)
111 ? absl::optional<std::string>(std::string(ai_->ai_canonname))
112 : absl::optional<std::string>();
113 }
114
IsAllLocalhostOfOneFamily() const115 bool AddressInfo::IsAllLocalhostOfOneFamily() const {
116 bool saw_v4_localhost = false;
117 bool saw_v6_localhost = false;
118 const auto* ai = ai_.get();
119 for (; ai != nullptr; ai = Next(ai)) {
120 switch (ai->ai_family) {
121 case AF_INET: {
122 const struct sockaddr_in* addr_in =
123 reinterpret_cast<struct sockaddr_in*>(ai->ai_addr);
124 if ((base::NetToHost32(addr_in->sin_addr.s_addr) & 0xff000000) ==
125 0x7f000000)
126 saw_v4_localhost = true;
127 else
128 return false;
129 break;
130 }
131 case AF_INET6: {
132 const struct sockaddr_in6* addr_in6 =
133 reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr);
134 if (IN6_IS_ADDR_LOOPBACK(&addr_in6->sin6_addr))
135 saw_v6_localhost = true;
136 else
137 return false;
138 break;
139 }
140 default:
141 NOTREACHED();
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