blob: 10523a34942c830327053f4c26e4158293b2406d [file] [log] [blame]
[email protected]fe89ea72011-05-12 02:02:401// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]b59ff372009-07-15 22:04:322// 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
[email protected]b59ff372009-07-15 22:04:329#include "base/logging.h"
[email protected]b59ff372009-07-15 22:04:3210#include "net/base/address_list.h"
[email protected]37e658b2010-07-28 17:23:0411#include "net/base/dns_reload_timer.h"
[email protected]b59ff372009-07-15 22:04:3212#include "net/base/net_errors.h"
[email protected]a540c2d2009-12-12 00:47:3713#include "net/base/sys_addrinfo.h"
[email protected]b59ff372009-07-15 22:04:3214
[email protected]23f771162011-06-02 18:37:5115#if defined(OS_POSIX) && !defined(OS_MACOSX)
16#include <resolv.h>
17#endif
18
[email protected]b59ff372009-07-15 22:04:3219namespace net {
20
[email protected]eaf3a3b2010-09-03 20:34:2721namespace {
22
23bool 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
[email protected]b59ff372009-07-15 22:04:3257HostResolverProc* HostResolverProc::default_proc_ = NULL;
58
59HostResolverProc::HostResolverProc(HostResolverProc* previous) {
[email protected]c4ff4952010-01-08 19:12:4760 SetPreviousProc(previous);
[email protected]b59ff372009-07-15 22:04:3261
62 // Implicitly fall-back to the global default procedure.
63 if (!previous)
[email protected]c4ff4952010-01-08 19:12:4764 SetPreviousProc(default_proc_);
65}
66
[email protected]be1a48b2011-01-20 00:12:1367HostResolverProc::~HostResolverProc() {
68}
69
70int 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
[email protected]c4ff4952010-01-08 19:12:4786void 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
94void HostResolverProc::SetLastProc(HostResolverProc* proc) {
95 GetLastProc(this)->SetPreviousProc(proc);
96}
97
98// static
99HostResolverProc* 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;
[email protected]b59ff372009-07-15 22:04:32106}
107
108// static
109HostResolverProc* HostResolverProc::SetDefault(HostResolverProc* proc) {
110 HostResolverProc* old = default_proc_;
111 default_proc_ = proc;
112 return old;
113}
114
115// static
116HostResolverProc* HostResolverProc::GetDefault() {
117 return default_proc_;
118}
119
[email protected]123ab1e32009-10-21 19:12:57120int SystemHostResolverProc(const std::string& host,
121 AddressFamily address_family,
[email protected]5ea28dea2010-04-08 15:35:13122 HostResolverFlags host_resolver_flags,
[email protected]21526002010-05-16 19:42:46123 AddressList* addrlist,
124 int* os_error) {
[email protected]3eac24a22010-08-07 01:13:28125 static const size_t kMaxHostLength = 4096;
126
[email protected]21526002010-05-16 19:42:46127 if (os_error)
128 *os_error = 0;
129
[email protected]41547862009-08-17 20:47:02130 // 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
[email protected]3eac24a22010-08-07 01:13:28136 // 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
[email protected]b59ff372009-07-15 22:04:32141 struct addrinfo* ai = NULL;
142 struct addrinfo hints = {0};
[email protected]123ab1e32009-10-21 19:12:57143
144 switch (address_family) {
[email protected]dd030332009-10-23 04:35:31145 case ADDRESS_FAMILY_IPV4:
[email protected]123ab1e32009-10-21 19:12:57146 hints.ai_family = AF_INET;
147 break;
[email protected]dd030332009-10-23 04:35:31148 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;
[email protected]123ab1e32009-10-21 19:12:57154 default:
[email protected]dd030332009-10-23 04:35:31155 NOTREACHED();
[email protected]123ab1e32009-10-21 19:12:57156 hints.ai_family = AF_UNSPEC;
157 }
[email protected]b59ff372009-07-15 22:04:32158
[email protected]1a157302010-01-29 03:36:45159#if defined(OS_WIN) || defined(OS_OPENBSD)
[email protected]b59ff372009-07-15 22:04:32160 // 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.
[email protected]1a157302010-01-29 03:36:45180 //
181 // OpenBSD does not support it, either.
[email protected]b59ff372009-07-15 22:04:32182 hints.ai_flags = 0;
[email protected]b59ff372009-07-15 22:04:32183#else
184 hints.ai_flags = AI_ADDRCONFIG;
185#endif
186
[email protected]2f3bc65c2010-07-23 17:47:10187 // 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
[email protected]5ea28dea2010-04-08 15:35:13193 if (host_resolver_flags & HOST_RESOLVER_CANONNAME)
194 hints.ai_flags |= AI_CANONNAME;
195
[email protected]b59ff372009-07-15 22:04:32196 // Restrict result set to only this socket type to avoid duplicates.
197 hints.ai_socktype = SOCK_STREAM;
198
[email protected]f820596a2009-11-25 00:15:38199 int err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
[email protected]eaf3a3b2010-09-03 20:34:27200 bool should_retry = false;
[email protected]1a157302010-01-29 03:36:45201#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
[email protected]b59ff372009-07-15 22:04:32202 // 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.
[email protected]37e658b2010-07-28 17:23:04204 if (err && DnsReloadTimerHasExpired()) {
[email protected]8ec8c2992010-10-12 16:55:31205 // 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);
[email protected]b59ff372009-07-15 22:04:32210 if (!res_ninit(&_res))
[email protected]eaf3a3b2010-09-03 20:34:27211 should_retry = true;
[email protected]b59ff372009-07-15 22:04:32212 }
213#endif
[email protected]eaf3a3b2010-09-03 20:34:27214 // 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) {
[email protected]ab6d12232010-09-07 19:39:37230 if (ai != NULL) {
231 freeaddrinfo(ai);
232 ai = NULL;
233 }
[email protected]eaf3a3b2010-09-03 20:34:27234 err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
235 }
[email protected]b59ff372009-07-15 22:04:32236
[email protected]21526002010-05-16 19:42:46237 if (err) {
[email protected]21526002010-05-16 19:42:46238#if defined(OS_WIN)
[email protected]8ed0cab62010-10-15 04:12:45239 err = WSAGetLastError();
[email protected]21526002010-05-16 19:42:46240#endif
[email protected]8ed0cab62010-10-15 04:12:45241
242 // Return the OS error to the caller.
243 if (os_error)
244 *os_error = err;
245
246 // If the call to getaddrinfo() failed because of a system error, report
247 // it separately from ERR_NAME_NOT_RESOLVED.
248#if defined(OS_WIN)
249 if (err != WSAHOST_NOT_FOUND && err != WSANO_DATA)
250 return ERR_NAME_RESOLUTION_FAILED;
[email protected]23f771162011-06-02 18:37:51251#elif defined(OS_POSIX) && !defined(OS_FREEBSD)
[email protected]8ed0cab62010-10-15 04:12:45252 if (err != EAI_NONAME && err != EAI_NODATA)
253 return ERR_NAME_RESOLUTION_FAILED;
254#endif
255
[email protected]b59ff372009-07-15 22:04:32256 return ERR_NAME_NOT_RESOLVED;
[email protected]21526002010-05-16 19:42:46257 }
[email protected]b59ff372009-07-15 22:04:32258
[email protected]fe89ea72011-05-12 02:02:40259 *addrlist = AddressList::CreateByAdoptingFromSystem(ai);
[email protected]b59ff372009-07-15 22:04:32260 return OK;
261}
262
[email protected]b59ff372009-07-15 22:04:32263} // namespace net