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/dns/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_.get()) { 79 return previous_proc_->Resolve( 80 host, address_family, host_resolver_flags, addrlist, os_error); 81 } 82 83 // Final fallback is the system resolver. 84 return SystemHostResolverCall(host, address_family, host_resolver_flags, 85 addrlist, os_error); 86 } 87 88 void HostResolverProc::SetPreviousProc(HostResolverProc* proc) { 89 HostResolverProc* current_previous = previous_proc_.get(); 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_.get() != NULL) 106 last_proc = last_proc->previous_proc_.get(); 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 SystemHostResolverCall(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 SystemHostResolverProc::SystemHostResolverProc() : HostResolverProc(NULL) {} 252 253 int SystemHostResolverProc::Resolve(const std::string& hostname, 254 AddressFamily address_family, 255 HostResolverFlags host_resolver_flags, 256 AddressList* addr_list, 257 int* os_error) { 258 return SystemHostResolverCall(hostname, 259 address_family, 260 host_resolver_flags, 261 addr_list, 262 os_error); 263 } 264 265 SystemHostResolverProc::~SystemHostResolverProc() {} 266 267 } // namespace net 268