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