1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
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/base/host_resolver_proc.h"
6
7 #include "build/build_config.h"
8
9 #if defined(OS_POSIX) && !defined(OS_MACOSX)
10 #include <resolv.h>
11 #endif
12
13 #include "base/logging.h"
14 #include "net/base/address_list.h"
15 #include "net/base/dns_reload_timer.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/sys_addrinfo.h"
18
19 namespace net {
20
21 namespace {
22
IsAllLocalhostOfOneFamily(const struct addrinfo * ai)23 bool IsAllLocalhostOfOneFamily(const struct addrinfo* ai) {
24 bool saw_v4_localhost = false;
25 bool saw_v6_localhost = false;
26 for (; ai != NULL; ai = ai->ai_next) {
27 switch (ai->ai_family) {
28 case AF_INET: {
29 const struct sockaddr_in* addr_in =
30 reinterpret_cast<struct sockaddr_in*>(ai->ai_addr);
31 if ((ntohl(addr_in->sin_addr.s_addr) & 0xff000000) == 0x7f000000)
32 saw_v4_localhost = true;
33 else
34 return false;
35 break;
36 }
37 case AF_INET6: {
38 const struct sockaddr_in6* addr_in6 =
39 reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr);
40 if (IN6_IS_ADDR_LOOPBACK(&addr_in6->sin6_addr))
41 saw_v6_localhost = true;
42 else
43 return false;
44 break;
45 }
46 default:
47 NOTREACHED();
48 return false;
49 }
50 }
51
52 return saw_v4_localhost != saw_v6_localhost;
53 }
54
55 } // namespace
56
57 HostResolverProc* HostResolverProc::default_proc_ = NULL;
58
HostResolverProc(HostResolverProc * previous)59 HostResolverProc::HostResolverProc(HostResolverProc* previous) {
60 SetPreviousProc(previous);
61
62 // Implicitly fall-back to the global default procedure.
63 if (!previous)
64 SetPreviousProc(default_proc_);
65 }
66
~HostResolverProc()67 HostResolverProc::~HostResolverProc() {
68 }
69
ResolveUsingPrevious(const std::string & host,AddressFamily address_family,HostResolverFlags host_resolver_flags,AddressList * addrlist,int * os_error)70 int HostResolverProc::ResolveUsingPrevious(
71 const std::string& host,
72 AddressFamily address_family,
73 HostResolverFlags host_resolver_flags,
74 AddressList* addrlist,
75 int* os_error) {
76 if (previous_proc_) {
77 return previous_proc_->Resolve(host, address_family, host_resolver_flags,
78 addrlist, os_error);
79 }
80
81 // Final fallback is the system resolver.
82 return SystemHostResolverProc(host, address_family, host_resolver_flags,
83 addrlist, os_error);
84 }
85
SetPreviousProc(HostResolverProc * proc)86 void HostResolverProc::SetPreviousProc(HostResolverProc* proc) {
87 HostResolverProc* current_previous = previous_proc_;
88 previous_proc_ = NULL;
89 // Now that we've guaranteed |this| is the last proc in a chain, we can
90 // detect potential cycles using GetLastProc().
91 previous_proc_ = (GetLastProc(proc) == this) ? current_previous : proc;
92 }
93
SetLastProc(HostResolverProc * proc)94 void HostResolverProc::SetLastProc(HostResolverProc* proc) {
95 GetLastProc(this)->SetPreviousProc(proc);
96 }
97
98 // static
GetLastProc(HostResolverProc * proc)99 HostResolverProc* HostResolverProc::GetLastProc(HostResolverProc* proc) {
100 if (proc == NULL)
101 return NULL;
102 HostResolverProc* last_proc = proc;
103 while (last_proc->previous_proc_ != NULL)
104 last_proc = last_proc->previous_proc_;
105 return last_proc;
106 }
107
108 // static
SetDefault(HostResolverProc * proc)109 HostResolverProc* HostResolverProc::SetDefault(HostResolverProc* proc) {
110 HostResolverProc* old = default_proc_;
111 default_proc_ = proc;
112 return old;
113 }
114
115 // static
GetDefault()116 HostResolverProc* HostResolverProc::GetDefault() {
117 return default_proc_;
118 }
119
SystemHostResolverProc(const std::string & host,AddressFamily address_family,HostResolverFlags host_resolver_flags,AddressList * addrlist,int * os_error)120 int SystemHostResolverProc(const std::string& host,
121 AddressFamily address_family,
122 HostResolverFlags host_resolver_flags,
123 AddressList* addrlist,
124 int* os_error) {
125 static const size_t kMaxHostLength = 4096;
126
127 if (os_error)
128 *os_error = 0;
129
130 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
131 // On Windows it gives the default interface's address, whereas on Linux it
132 // gives an error. We will make it fail on all platforms for consistency.
133 if (host.empty())
134 return ERR_NAME_NOT_RESOLVED;
135
136 // Limit the size of hostnames that will be resolved to combat issues in some
137 // platform's resolvers.
138 if (host.size() > kMaxHostLength)
139 return ERR_NAME_NOT_RESOLVED;
140
141 struct addrinfo* ai = NULL;
142 struct addrinfo hints = {0};
143
144 switch (address_family) {
145 case ADDRESS_FAMILY_IPV4:
146 hints.ai_family = AF_INET;
147 break;
148 case ADDRESS_FAMILY_IPV6:
149 hints.ai_family = AF_INET6;
150 break;
151 case ADDRESS_FAMILY_UNSPECIFIED:
152 hints.ai_family = AF_UNSPEC;
153 break;
154 default:
155 NOTREACHED();
156 hints.ai_family = AF_UNSPEC;
157 }
158
159 #if defined(OS_WIN) || defined(OS_OPENBSD)
160 // DO NOT USE AI_ADDRCONFIG ON WINDOWS.
161 //
162 // The following comment in <winsock2.h> is the best documentation I found
163 // on AI_ADDRCONFIG for Windows:
164 // Flags used in "hints" argument to getaddrinfo()
165 // - AI_ADDRCONFIG is supported starting with Vista
166 // - default is AI_ADDRCONFIG ON whether the flag is set or not
167 // because the performance penalty in not having ADDRCONFIG in
168 // the multi-protocol stack environment is severe;
169 // this defaulting may be disabled by specifying the AI_ALL flag,
170 // in that case AI_ADDRCONFIG must be EXPLICITLY specified to
171 // enable ADDRCONFIG behavior
172 //
173 // Not only is AI_ADDRCONFIG unnecessary, but it can be harmful. If the
174 // computer is not connected to a network, AI_ADDRCONFIG causes getaddrinfo
175 // to fail with WSANO_DATA (11004) for "localhost", probably because of the
176 // following note on AI_ADDRCONFIG in the MSDN getaddrinfo page:
177 // The IPv4 or IPv6 loopback address is not considered a valid global
178 // address.
179 // See http://crbug.com/5234.
180 //
181 // OpenBSD does not support it, either.
182 hints.ai_flags = 0;
183 #else
184 hints.ai_flags = AI_ADDRCONFIG;
185 #endif
186
187 // On Linux AI_ADDRCONFIG doesn't consider loopback addreses, even if only
188 // loopback addresses are configured. So don't use it when there are only
189 // loopback addresses.
190 if (host_resolver_flags & HOST_RESOLVER_LOOPBACK_ONLY)
191 hints.ai_flags &= ~AI_ADDRCONFIG;
192
193 if (host_resolver_flags & HOST_RESOLVER_CANONNAME)
194 hints.ai_flags |= AI_CANONNAME;
195
196 // Restrict result set to only this socket type to avoid duplicates.
197 hints.ai_socktype = SOCK_STREAM;
198
199 int err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
200 bool should_retry = false;
201 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && !defined(ANDROID)
202 // If we fail, re-initialise the resolver just in case there have been any
203 // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info.
204 if (err && DnsReloadTimerHasExpired()) {
205 // When there's no network connection, _res may not be initialized by
206 // getaddrinfo. Therefore, we call res_nclose only when there are ns
207 // entries.
208 if (_res.nscount > 0)
209 res_nclose(&_res);
210 if (!res_ninit(&_res))
211 should_retry = true;
212 }
213 #endif
214 // If the lookup was restricted (either by address family, or address
215 // detection), and the results where all localhost of a single family,
216 // maybe we should retry. There were several bugs related to these
217 // issues, for example http://crbug.com/42058 and http://crbug.com/49024
218 if ((hints.ai_family != AF_UNSPEC || hints.ai_flags & AI_ADDRCONFIG) &&
219 err == 0 && IsAllLocalhostOfOneFamily(ai)) {
220 if (host_resolver_flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6) {
221 hints.ai_family = AF_UNSPEC;
222 should_retry = true;
223 }
224 if (hints.ai_flags & AI_ADDRCONFIG) {
225 hints.ai_flags &= ~AI_ADDRCONFIG;
226 should_retry = true;
227 }
228 }
229 if (should_retry) {
230 if (ai != NULL) {
231 freeaddrinfo(ai);
232 ai = NULL;
233 }
234 err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
235 }
236
237 #ifdef ANDROID
238 if (err || ai == NULL) {
239 #else
240 if (err) {
241 #endif
242 #if defined(OS_WIN)
243 err = WSAGetLastError();
244 #endif
245
246 // Return the OS error to the caller.
247 if (os_error)
248 *os_error = err;
249
250 // If the call to getaddrinfo() failed because of a system error, report
251 // it separately from ERR_NAME_NOT_RESOLVED.
252 #if defined(OS_WIN)
253 if (err != WSAHOST_NOT_FOUND && err != WSANO_DATA)
254 return ERR_NAME_RESOLUTION_FAILED;
255 #elif defined(OS_POSIX)
256 if (err != EAI_NONAME && err != EAI_NODATA)
257 return ERR_NAME_RESOLUTION_FAILED;
258 #endif
259
260 return ERR_NAME_NOT_RESOLVED;
261 }
262
263 addrlist->Adopt(ai);
264 return OK;
265 }
266
267 } // namespace net
268