host_resolver_proc.cc revision abe5b9b6785ffd62806ae6a9da4d3b6d10caea94
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 19namespace net { 20 21namespace { 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 57HostResolverProc* HostResolverProc::default_proc_ = NULL; 58 59HostResolverProc::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 67void HostResolverProc::SetPreviousProc(HostResolverProc* proc) { 68 HostResolverProc* current_previous = previous_proc_; 69 previous_proc_ = NULL; 70 // Now that we've guaranteed |this| is the last proc in a chain, we can 71 // detect potential cycles using GetLastProc(). 72 previous_proc_ = (GetLastProc(proc) == this) ? current_previous : proc; 73} 74 75void HostResolverProc::SetLastProc(HostResolverProc* proc) { 76 GetLastProc(this)->SetPreviousProc(proc); 77} 78 79// static 80HostResolverProc* HostResolverProc::GetLastProc(HostResolverProc* proc) { 81 if (proc == NULL) 82 return NULL; 83 HostResolverProc* last_proc = proc; 84 while (last_proc->previous_proc_ != NULL) 85 last_proc = last_proc->previous_proc_; 86 return last_proc; 87} 88 89// static 90HostResolverProc* HostResolverProc::SetDefault(HostResolverProc* proc) { 91 HostResolverProc* old = default_proc_; 92 default_proc_ = proc; 93 return old; 94} 95 96// static 97HostResolverProc* HostResolverProc::GetDefault() { 98 return default_proc_; 99} 100 101HostResolverProc::~HostResolverProc() { 102} 103 104int HostResolverProc::ResolveUsingPrevious( 105 const std::string& host, 106 AddressFamily address_family, 107 HostResolverFlags host_resolver_flags, 108 AddressList* addrlist, 109 int* os_error) { 110 if (previous_proc_) { 111 return previous_proc_->Resolve(host, address_family, host_resolver_flags, 112 addrlist, os_error); 113 } 114 115 // Final fallback is the system resolver. 116 return SystemHostResolverProc(host, address_family, host_resolver_flags, 117 addrlist, os_error); 118} 119 120int 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 if (err) { 238#if defined(OS_WIN) 239 err = WSAGetLastError(); 240#endif 241 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; 251#elif defined(OS_POSIX) 252 if (err != EAI_NONAME && err != EAI_NODATA) 253 return ERR_NAME_RESOLUTION_FAILED; 254#endif 255 256 return ERR_NAME_NOT_RESOLVED; 257 } 258 259 addrlist->Adopt(ai); 260 return OK; 261} 262 263} // namespace net 264