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 67HostResolverProc::~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 86void 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; 106} 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 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#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