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