1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/other-licenses/android/getaddrinfo.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2356 @@ 1.4 +/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ 1.5 +/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ 1.6 + 1.7 +/* 1.8 + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 1.9 + * All rights reserved. 1.10 + * 1.11 + * Redistribution and use in source and binary forms, with or without 1.12 + * modification, are permitted provided that the following conditions 1.13 + * are met: 1.14 + * 1. Redistributions of source code must retain the above copyright 1.15 + * notice, this list of conditions and the following disclaimer. 1.16 + * 2. Redistributions in binary form must reproduce the above copyright 1.17 + * notice, this list of conditions and the following disclaimer in the 1.18 + * documentation and/or other materials provided with the distribution. 1.19 + * 3. Neither the name of the project nor the names of its contributors 1.20 + * may be used to endorse or promote products derived from this software 1.21 + * without specific prior written permission. 1.22 + * 1.23 + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1.24 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.25 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.26 + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 1.27 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1.28 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1.29 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1.30 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1.31 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1.32 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1.33 + * SUCH DAMAGE. 1.34 + */ 1.35 + 1.36 +/* 1.37 + * This version of getaddrinfo.c is derived from Android 2.3 "Gingerbread", 1.38 + * which contains uncredited changes by Android/Google developers. It has 1.39 + * been modified in 2011 for use in the Android build of Mozilla Firefox by 1.40 + * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>, 1.41 + * and Steve Workman <sjhworkman@gmail.com>). 1.42 + * These changes are offered under the same license as the original NetBSD 1.43 + * file, whose copyright and license are unchanged above. 1.44 + */ 1.45 +#define ANDROID_CHANGES 1 1.46 +#define INET6 1 1.47 + 1.48 +/* 1.49 + * Issues to be discussed: 1.50 + * - Return values. There are nonstandard return values defined and used 1.51 + * in the source code. This is because RFC2553 is silent about which error 1.52 + * code must be returned for which situation. 1.53 + * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 1.54 + * says to use inet_aton() to convert IPv4 numeric to binary (alows 1.55 + * classful form as a result). 1.56 + * current code - disallow classful form for IPv4 (due to use of inet_pton). 1.57 + * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 1.58 + * invalid. 1.59 + * current code - SEGV on freeaddrinfo(NULL) 1.60 + * Note: 1.61 + * - We use getipnodebyname() just for thread-safeness. There's no intent 1.62 + * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to 1.63 + * getipnodebyname(). 1.64 + * - MOZILLA: Thread safeness for pre-Honeycomb Android versions implemented by 1.65 + * way of open/gets/close and mmap rather than fopen/fgets/fclose. Affects 1.66 + * _files_getaddrinfo for hosts file. Note: Honeycomb and later versions use 1.67 + * a thread-safe stdio, so for those versions normal Bionic libc getaddrinfo 1.68 + * is used. 1.69 + * - The code filters out AFs that are not supported by the kernel, 1.70 + * when globbing NULL hostname (to loopback, or wildcard). Is it the right 1.71 + * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 1.72 + * in ai_flags? 1.73 + * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 1.74 + * (1) what should we do against numeric hostname (2) what should we do 1.75 + * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 1.76 + * non-loopback address configured? global address configured? 1.77 + * - To avoid search order issue, we have a big amount of code duplicate 1.78 + * from gethnamaddr.c and some other places. The issues that there's no 1.79 + * lower layer function to lookup "IPv4 or IPv6" record. Calling 1.80 + * gethostbyname2 from getaddrinfo will end up in wrong search order, as 1.81 + * follows: 1.82 + * - The code makes use of following calls when asked to resolver with 1.83 + * ai_family = PF_UNSPEC: 1.84 + * getipnodebyname(host, AF_INET6); 1.85 + * getipnodebyname(host, AF_INET); 1.86 + * This will result in the following queries if the node is configure to 1.87 + * prefer /etc/hosts than DNS: 1.88 + * lookup /etc/hosts for IPv6 address 1.89 + * lookup DNS for IPv6 address 1.90 + * lookup /etc/hosts for IPv4 address 1.91 + * lookup DNS for IPv4 address 1.92 + * which may not meet people's requirement. 1.93 + * The right thing to happen is to have underlying layer which does 1.94 + * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. 1.95 + * This would result in a bit of code duplicate with _dns_ghbyname() and 1.96 + * friends. 1.97 + */ 1.98 + 1.99 +#include <fcntl.h> 1.100 +#include <sys/cdefs.h> 1.101 +#include <sys/types.h> 1.102 +#include <sys/stat.h> 1.103 +#include <sys/param.h> 1.104 +#include <sys/socket.h> 1.105 +#include <sys/un.h> 1.106 +#include <sys/mman.h> 1.107 +#include <net/if.h> 1.108 +#include <netinet/in.h> 1.109 +#include <arpa/inet.h> 1.110 +#include "arpa_nameser.h" 1.111 +#include <assert.h> 1.112 +#include <ctype.h> 1.113 +#include <errno.h> 1.114 +#include <netdb.h> 1.115 +#include "resolv_private.h" 1.116 +#include <stddef.h> 1.117 +#include <stdlib.h> 1.118 +#include <string.h> 1.119 +#include <unistd.h> 1.120 + 1.121 +#include <syslog.h> 1.122 +#include <stdarg.h> 1.123 +#include "nsswitch.h" 1.124 + 1.125 +#ifdef MOZ_GETADDRINFO_LOG_VERBOSE 1.126 +#include <android/log.h> 1.127 +#endif 1.128 + 1.129 +#ifdef ANDROID_CHANGES 1.130 +#include <sys/system_properties.h> 1.131 +#endif /* ANDROID_CHANGES */ 1.132 + 1.133 +typedef struct _pseudo_FILE { 1.134 + int fd; 1.135 + off_t maplen; 1.136 + void* mapping; 1.137 + off_t offset; 1.138 +} _pseudo_FILE; 1.139 + 1.140 +#define _PSEUDO_FILE_INITIALIZER { -1, 0, MAP_FAILED, 0 } 1.141 + 1.142 +static void 1.143 +_pseudo_fclose(_pseudo_FILE * __restrict__ fp) 1.144 +{ 1.145 + assert(fp); 1.146 + fp->offset = 0; 1.147 + if (fp->mapping != MAP_FAILED) { 1.148 + (void) munmap(fp->mapping, fp->maplen); 1.149 + fp->mapping = MAP_FAILED; 1.150 + } 1.151 + fp->maplen = 0; 1.152 + if (fp->fd != -1) { 1.153 + (void) close(fp->fd); 1.154 + fp->fd = -1; 1.155 + } 1.156 +} 1.157 + 1.158 +static _pseudo_FILE * 1.159 +_pseudo_fopen_r(_pseudo_FILE * __restrict__ fp, const char* fname) 1.160 +{ 1.161 + struct stat statbuf; 1.162 + assert(fp); 1.163 + fp->fd = open(fname, O_RDONLY); 1.164 + if (fp->fd < 0) { 1.165 + fp->fd = -1; 1.166 + return NULL; 1.167 + } 1.168 + if ((0 != fstat(fp->fd, &statbuf)) || (statbuf.st_size <= 0)) { 1.169 + close(fp->fd); 1.170 + fp->fd = -1; 1.171 + return NULL; 1.172 + } 1.173 + fp->maplen = statbuf.st_size; 1.174 + fp->mapping = mmap(NULL, fp->maplen, PROT_READ, MAP_PRIVATE, fp->fd, 0); 1.175 + if (fp->mapping == MAP_FAILED) { 1.176 + close(fp->fd); 1.177 + fp->fd = -1; 1.178 + return NULL; 1.179 + } 1.180 + fp->offset = 0; 1.181 + return fp; 1.182 +} 1.183 + 1.184 +static void 1.185 +_pseudo_rewind(_pseudo_FILE * __restrict__ fp) 1.186 +{ 1.187 + assert(fp); 1.188 + fp->offset = 0; 1.189 +} 1.190 + 1.191 +static char* 1.192 +_pseudo_fgets(char* buf, int bufsize, _pseudo_FILE * __restrict__ fp) 1.193 +{ 1.194 + char* current; 1.195 + char* endp; 1.196 + int maxcopy; 1.197 + assert(fp); 1.198 + maxcopy = fp->maplen - fp->offset; 1.199 + if (fp->mapping == MAP_FAILED) 1.200 + return NULL; 1.201 + if (maxcopy > bufsize - 1) 1.202 + maxcopy = bufsize - 1; 1.203 + if (maxcopy <= 0) 1.204 + return NULL; 1.205 + current = ((char*) fp->mapping) + fp->offset; 1.206 + endp = memccpy(buf, current, '\n', maxcopy); 1.207 + if (endp) 1.208 + maxcopy = endp - buf; 1.209 + buf[maxcopy] = '\0'; 1.210 + fp->offset += maxcopy; 1.211 + return buf; 1.212 +} 1.213 + 1.214 +typedef union sockaddr_union { 1.215 + struct sockaddr generic; 1.216 + struct sockaddr_in in; 1.217 + struct sockaddr_in6 in6; 1.218 +} sockaddr_union; 1.219 + 1.220 +#define SUCCESS 0 1.221 +#define ANY 0 1.222 +#define YES 1 1.223 +#define NO 0 1.224 + 1.225 +static const char in_addrany[] = { 0, 0, 0, 0 }; 1.226 +static const char in_loopback[] = { 127, 0, 0, 1 }; 1.227 +#ifdef INET6 1.228 +static const char in6_addrany[] = { 1.229 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1.230 +}; 1.231 +static const char in6_loopback[] = { 1.232 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 1.233 +}; 1.234 +#endif 1.235 + 1.236 +static const struct afd { 1.237 + int a_af; 1.238 + int a_addrlen; 1.239 + int a_socklen; 1.240 + int a_off; 1.241 + const char *a_addrany; 1.242 + const char *a_loopback; 1.243 + int a_scoped; 1.244 +} afdl [] = { 1.245 +#ifdef INET6 1.246 + {PF_INET6, sizeof(struct in6_addr), 1.247 + sizeof(struct sockaddr_in6), 1.248 + offsetof(struct sockaddr_in6, sin6_addr), 1.249 + in6_addrany, in6_loopback, 1}, 1.250 +#endif 1.251 + {PF_INET, sizeof(struct in_addr), 1.252 + sizeof(struct sockaddr_in), 1.253 + offsetof(struct sockaddr_in, sin_addr), 1.254 + in_addrany, in_loopback, 0}, 1.255 + {0, 0, 0, 0, NULL, NULL, 0}, 1.256 +}; 1.257 + 1.258 +struct explore { 1.259 + int e_af; 1.260 + int e_socktype; 1.261 + int e_protocol; 1.262 + const char *e_protostr; 1.263 + int e_wild; 1.264 +#define WILD_AF(ex) ((ex)->e_wild & 0x01) 1.265 +#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 1.266 +#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 1.267 +}; 1.268 + 1.269 +static const struct explore explore[] = { 1.270 +#if 0 1.271 + { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 1.272 +#endif 1.273 +#ifdef INET6 1.274 + { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 1.275 + { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 1.276 + { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 1.277 +#endif 1.278 + { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 1.279 + { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 1.280 + { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 1.281 + { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 1.282 + { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 1.283 + { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, 1.284 + { -1, 0, 0, NULL, 0 }, 1.285 +}; 1.286 + 1.287 +#ifdef INET6 1.288 +#define PTON_MAX 16 1.289 +#else 1.290 +#define PTON_MAX 4 1.291 +#endif 1.292 + 1.293 +static const ns_src default_dns_files[] = { 1.294 + { NSSRC_FILES, NS_SUCCESS }, 1.295 + { NSSRC_DNS, NS_SUCCESS }, 1.296 + { 0, 0 } 1.297 +}; 1.298 + 1.299 +#define MAXPACKET (64*1024) 1.300 + 1.301 +typedef union { 1.302 + HEADER hdr; 1.303 + u_char buf[MAXPACKET]; 1.304 +} querybuf; 1.305 + 1.306 +struct res_target { 1.307 + struct res_target *next; 1.308 + const char *name; /* domain name */ 1.309 + int qclass, qtype; /* class and type of query */ 1.310 + u_char *answer; /* buffer to put answer */ 1.311 + int anslen; /* size of answer buffer */ 1.312 + int n; /* result length */ 1.313 +}; 1.314 + 1.315 +static int str2number(const char *); 1.316 +static int explore_fqdn(const struct addrinfo *, const char *, 1.317 + const char *, struct addrinfo **); 1.318 +static int explore_null(const struct addrinfo *, 1.319 + const char *, struct addrinfo **); 1.320 +static int explore_numeric(const struct addrinfo *, const char *, 1.321 + const char *, struct addrinfo **, const char *); 1.322 +static int explore_numeric_scope(const struct addrinfo *, const char *, 1.323 + const char *, struct addrinfo **); 1.324 +static int get_canonname(const struct addrinfo *, 1.325 + struct addrinfo *, const char *); 1.326 +static struct addrinfo *get_ai(const struct addrinfo *, 1.327 + const struct afd *, const char *); 1.328 +static int get_portmatch(const struct addrinfo *, const char *); 1.329 +static int get_port(const struct addrinfo *, const char *, int); 1.330 +static const struct afd *find_afd(int); 1.331 +#ifdef INET6 1.332 +static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); 1.333 +#endif 1.334 + 1.335 +static struct addrinfo *getanswer(const querybuf *, int, const char *, int, 1.336 + const struct addrinfo *); 1.337 +static int _dns_getaddrinfo(void *, void *, va_list); 1.338 +static void _sethtent(_pseudo_FILE * __restrict__); 1.339 +static void _endhtent(_pseudo_FILE * __restrict__); 1.340 +static struct addrinfo *_gethtent(_pseudo_FILE * __restrict__, const char *, 1.341 + const struct addrinfo *); 1.342 +static int _files_getaddrinfo(void *, void *, va_list); 1.343 + 1.344 +static int res_queryN(const char *, struct res_target *, res_state); 1.345 +static int res_searchN(const char *, struct res_target *, res_state); 1.346 +static int res_querydomainN(const char *, const char *, 1.347 + struct res_target *, res_state); 1.348 + 1.349 +static const char * const ai_errlist[] = { 1.350 + "Success", 1.351 + "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 1.352 + "Temporary failure in name resolution", /* EAI_AGAIN */ 1.353 + "Invalid value for ai_flags", /* EAI_BADFLAGS */ 1.354 + "Non-recoverable failure in name resolution", /* EAI_FAIL */ 1.355 + "ai_family not supported", /* EAI_FAMILY */ 1.356 + "Memory allocation failure", /* EAI_MEMORY */ 1.357 + "No address associated with hostname", /* EAI_NODATA */ 1.358 + "hostname nor servname provided, or not known", /* EAI_NONAME */ 1.359 + "servname not supported for ai_socktype", /* EAI_SERVICE */ 1.360 + "ai_socktype not supported", /* EAI_SOCKTYPE */ 1.361 + "System error returned in errno", /* EAI_SYSTEM */ 1.362 + "Invalid value for hints", /* EAI_BADHINTS */ 1.363 + "Resolved protocol is unknown", /* EAI_PROTOCOL */ 1.364 + "Argument buffer overflow", /* EAI_OVERFLOW */ 1.365 + "Unknown error", /* EAI_MAX */ 1.366 +}; 1.367 + 1.368 +/* XXX macros that make external reference is BAD. */ 1.369 + 1.370 +#define GET_AI(ai, afd, addr) \ 1.371 +do { \ 1.372 + /* external reference: pai, error, and label free */ \ 1.373 + (ai) = get_ai(pai, (afd), (addr)); \ 1.374 + if ((ai) == NULL) { \ 1.375 + error = EAI_MEMORY; \ 1.376 + goto free; \ 1.377 + } \ 1.378 +} while (/*CONSTCOND*/0) 1.379 + 1.380 +#define GET_PORT(ai, serv) \ 1.381 +do { \ 1.382 + /* external reference: error and label free */ \ 1.383 + error = get_port((ai), (serv), 0); \ 1.384 + if (error != 0) \ 1.385 + goto free; \ 1.386 +} while (/*CONSTCOND*/0) 1.387 + 1.388 +#define GET_CANONNAME(ai, str) \ 1.389 +do { \ 1.390 + /* external reference: pai, error and label free */ \ 1.391 + error = get_canonname(pai, (ai), (str)); \ 1.392 + if (error != 0) \ 1.393 + goto free; \ 1.394 +} while (/*CONSTCOND*/0) 1.395 + 1.396 +#define ERR(err) \ 1.397 +do { \ 1.398 + /* external reference: error, and label bad */ \ 1.399 + error = (err); \ 1.400 + goto bad; \ 1.401 + /*NOTREACHED*/ \ 1.402 +} while (/*CONSTCOND*/0) 1.403 + 1.404 +#define MATCH_FAMILY(x, y, w) \ 1.405 + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \ 1.406 + (y) == PF_UNSPEC))) 1.407 +#define MATCH(x, y, w) \ 1.408 + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 1.409 + 1.410 +#pragma GCC visibility push(default) 1.411 + 1.412 +extern const char * 1.413 +__wrap_gai_strerror(int ecode); 1.414 +extern void 1.415 +__wrap_freeaddrinfo(struct addrinfo *ai); 1.416 +extern int 1.417 +__wrap_getaddrinfo(const char *hostname, const char *servname, 1.418 + const struct addrinfo *hints, struct addrinfo **res); 1.419 + 1.420 +int android_sdk_version; 1.421 + 1.422 +#pragma GCC visibility pop 1.423 + 1.424 +int android_sdk_version = -1; 1.425 + 1.426 +static int honeycomb_or_later() 1.427 +{ 1.428 +#ifdef MOZ_GETADDRINFO_LOG_VERBOSE 1.429 + __android_log_print(ANDROID_LOG_INFO, "getaddrinfo", 1.430 + "I am%s Honeycomb\n", 1.431 + (android_sdk_version >= 11) ? "" : " not"); 1.432 +#endif 1.433 + return android_sdk_version >= 11; 1.434 +} 1.435 + 1.436 +const char * 1.437 +__wrap_gai_strerror(int ecode) 1.438 +{ 1.439 + if (honeycomb_or_later()) 1.440 + return gai_strerror(ecode); 1.441 + if (ecode < 0 || ecode > EAI_MAX) 1.442 + ecode = EAI_MAX; 1.443 + return ai_errlist[ecode]; 1.444 +} 1.445 + 1.446 +void 1.447 +__wrap_freeaddrinfo(struct addrinfo *ai) 1.448 +{ 1.449 + struct addrinfo *next; 1.450 + 1.451 + if (honeycomb_or_later()) { 1.452 + freeaddrinfo(ai); 1.453 + return; 1.454 + } 1.455 + 1.456 + assert(ai != NULL); 1.457 + 1.458 + do { 1.459 + next = ai->ai_next; 1.460 + if (ai->ai_canonname) 1.461 + free(ai->ai_canonname); 1.462 + /* no need to free(ai->ai_addr) */ 1.463 + free(ai); 1.464 + ai = next; 1.465 + } while (ai); 1.466 +} 1.467 + 1.468 +static int 1.469 +str2number(const char *p) 1.470 +{ 1.471 + char *ep; 1.472 + unsigned long v; 1.473 + 1.474 + assert(p != NULL); 1.475 + 1.476 + if (*p == '\0') 1.477 + return -1; 1.478 + ep = NULL; 1.479 + errno = 0; 1.480 + v = strtoul(p, &ep, 10); 1.481 + if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) 1.482 + return v; 1.483 + else 1.484 + return -1; 1.485 +} 1.486 + 1.487 +/* 1.488 + * Connect a UDP socket to a given unicast address. This will cause no network 1.489 + * traffic, but will fail fast if the system has no or limited reachability to 1.490 + * the destination (e.g., no IPv4 address, no IPv6 default route, ...). 1.491 + */ 1.492 +static int 1.493 +_test_connect(int pf, struct sockaddr *addr, size_t addrlen) { 1.494 + int s = socket(pf, SOCK_DGRAM, IPPROTO_UDP); 1.495 + if (s < 0) 1.496 + return 0; 1.497 + int ret; 1.498 + do { 1.499 + ret = connect(s, addr, addrlen); 1.500 + } while (ret < 0 && errno == EINTR); 1.501 + int success = (ret == 0); 1.502 + do { 1.503 + ret = close(s); 1.504 + } while (ret < 0 && errno == EINTR); 1.505 + return success; 1.506 +} 1.507 + 1.508 +/* 1.509 + * The following functions determine whether IPv4 or IPv6 connectivity is 1.510 + * available in order to implement AI_ADDRCONFIG. 1.511 + * 1.512 + * Strictly speaking, AI_ADDRCONFIG should not look at whether connectivity is 1.513 + * available, but whether addresses of the specified family are "configured 1.514 + * on the local system". However, bionic doesn't currently support getifaddrs, 1.515 + * so checking for connectivity is the next best thing. 1.516 + */ 1.517 +static int 1.518 +_have_ipv6() { 1.519 + static const struct sockaddr_in6 sin6_test = { 1.520 + .sin6_family = AF_INET6, 1.521 + .sin6_addr.s6_addr = { // 2000:: 1.522 + 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 1.523 + }; 1.524 + sockaddr_union addr = { .in6 = sin6_test }; 1.525 + return _test_connect(PF_INET6, &addr.generic, sizeof(addr.in6)); 1.526 +} 1.527 + 1.528 +static int 1.529 +_have_ipv4() { 1.530 + static const struct sockaddr_in sin_test = { 1.531 + .sin_family = AF_INET, 1.532 + .sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8 1.533 + }; 1.534 + sockaddr_union addr = { .in = sin_test }; 1.535 + return _test_connect(PF_INET, &addr.generic, sizeof(addr.in)); 1.536 +} 1.537 + 1.538 +int 1.539 +__wrap_getaddrinfo(const char *hostname, const char *servname, 1.540 + const struct addrinfo *hints, struct addrinfo **res) 1.541 +{ 1.542 + struct addrinfo sentinel; 1.543 + struct addrinfo *cur; 1.544 + int error = 0; 1.545 + struct addrinfo ai; 1.546 + struct addrinfo ai0; 1.547 + struct addrinfo *pai; 1.548 + const struct explore *ex; 1.549 + 1.550 + if (honeycomb_or_later()) 1.551 + return getaddrinfo(hostname, servname, hints, res); 1.552 + 1.553 + /* hostname is allowed to be NULL */ 1.554 + /* servname is allowed to be NULL */ 1.555 + /* hints is allowed to be NULL */ 1.556 + assert(res != NULL); 1.557 + 1.558 + memset(&sentinel, 0, sizeof(sentinel)); 1.559 + cur = &sentinel; 1.560 + pai = &ai; 1.561 + pai->ai_flags = 0; 1.562 + pai->ai_family = PF_UNSPEC; 1.563 + pai->ai_socktype = ANY; 1.564 + pai->ai_protocol = ANY; 1.565 + pai->ai_addrlen = 0; 1.566 + pai->ai_canonname = NULL; 1.567 + pai->ai_addr = NULL; 1.568 + pai->ai_next = NULL; 1.569 + 1.570 + if (hostname == NULL && servname == NULL) 1.571 + return EAI_NONAME; 1.572 + if (hints) { 1.573 + /* error check for hints */ 1.574 + if (hints->ai_addrlen || hints->ai_canonname || 1.575 + hints->ai_addr || hints->ai_next) 1.576 + ERR(EAI_BADHINTS); /* xxx */ 1.577 + if (hints->ai_flags & ~AI_MASK) 1.578 + ERR(EAI_BADFLAGS); 1.579 + switch (hints->ai_family) { 1.580 + case PF_UNSPEC: 1.581 + case PF_INET: 1.582 +#ifdef INET6 1.583 + case PF_INET6: 1.584 +#endif 1.585 + break; 1.586 + default: 1.587 + ERR(EAI_FAMILY); 1.588 + } 1.589 + memcpy(pai, hints, sizeof(*pai)); 1.590 + 1.591 + /* 1.592 + * if both socktype/protocol are specified, check if they 1.593 + * are meaningful combination. 1.594 + */ 1.595 + if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 1.596 + for (ex = explore; ex->e_af >= 0; ex++) { 1.597 + if (pai->ai_family != ex->e_af) 1.598 + continue; 1.599 + if (ex->e_socktype == ANY) 1.600 + continue; 1.601 + if (ex->e_protocol == ANY) 1.602 + continue; 1.603 + if (pai->ai_socktype == ex->e_socktype 1.604 + && pai->ai_protocol != ex->e_protocol) { 1.605 + ERR(EAI_BADHINTS); 1.606 + } 1.607 + } 1.608 + } 1.609 + } 1.610 + 1.611 + /* 1.612 + * check for special cases. (1) numeric servname is disallowed if 1.613 + * socktype/protocol are left unspecified. (2) servname is disallowed 1.614 + * for raw and other inet{,6} sockets. 1.615 + */ 1.616 + if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 1.617 +#ifdef PF_INET6 1.618 + || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 1.619 +#endif 1.620 + ) { 1.621 + ai0 = *pai; /* backup *pai */ 1.622 + 1.623 + if (pai->ai_family == PF_UNSPEC) { 1.624 +#ifdef PF_INET6 1.625 + pai->ai_family = PF_INET6; 1.626 +#else 1.627 + pai->ai_family = PF_INET; 1.628 +#endif 1.629 + } 1.630 + error = get_portmatch(pai, servname); 1.631 + if (error) 1.632 + ERR(error); 1.633 + 1.634 + *pai = ai0; 1.635 + } 1.636 + 1.637 + ai0 = *pai; 1.638 + 1.639 + /* NULL hostname, or numeric hostname */ 1.640 + for (ex = explore; ex->e_af >= 0; ex++) { 1.641 + *pai = ai0; 1.642 + 1.643 + /* PF_UNSPEC entries are prepared for DNS queries only */ 1.644 + if (ex->e_af == PF_UNSPEC) 1.645 + continue; 1.646 + 1.647 + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 1.648 + continue; 1.649 + if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 1.650 + continue; 1.651 + if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 1.652 + continue; 1.653 + 1.654 + if (pai->ai_family == PF_UNSPEC) 1.655 + pai->ai_family = ex->e_af; 1.656 + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 1.657 + pai->ai_socktype = ex->e_socktype; 1.658 + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 1.659 + pai->ai_protocol = ex->e_protocol; 1.660 + 1.661 + if (hostname == NULL) 1.662 + error = explore_null(pai, servname, &cur->ai_next); 1.663 + else 1.664 + error = explore_numeric_scope(pai, hostname, servname, 1.665 + &cur->ai_next); 1.666 + 1.667 + if (error) 1.668 + goto free; 1.669 + 1.670 + while (cur->ai_next) 1.671 + cur = cur->ai_next; 1.672 + } 1.673 + 1.674 + /* 1.675 + * XXX 1.676 + * If numeric representation of AF1 can be interpreted as FQDN 1.677 + * representation of AF2, we need to think again about the code below. 1.678 + */ 1.679 + if (sentinel.ai_next) 1.680 + goto good; 1.681 + 1.682 + if (hostname == NULL) 1.683 + ERR(EAI_NODATA); 1.684 + if (pai->ai_flags & AI_NUMERICHOST) 1.685 + ERR(EAI_NONAME); 1.686 + 1.687 + /* 1.688 + * hostname as alphabetical name. 1.689 + * we would like to prefer AF_INET6 than AF_INET, so we'll make a 1.690 + * outer loop by AFs. 1.691 + */ 1.692 + for (ex = explore; ex->e_af >= 0; ex++) { 1.693 + *pai = ai0; 1.694 + 1.695 + /* require exact match for family field */ 1.696 + if (pai->ai_family != ex->e_af) 1.697 + continue; 1.698 + 1.699 + if (!MATCH(pai->ai_socktype, ex->e_socktype, 1.700 + WILD_SOCKTYPE(ex))) { 1.701 + continue; 1.702 + } 1.703 + if (!MATCH(pai->ai_protocol, ex->e_protocol, 1.704 + WILD_PROTOCOL(ex))) { 1.705 + continue; 1.706 + } 1.707 + 1.708 + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 1.709 + pai->ai_socktype = ex->e_socktype; 1.710 + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 1.711 + pai->ai_protocol = ex->e_protocol; 1.712 + 1.713 + error = explore_fqdn(pai, hostname, servname, 1.714 + &cur->ai_next); 1.715 + 1.716 + while (cur && cur->ai_next) 1.717 + cur = cur->ai_next; 1.718 + } 1.719 + 1.720 + /* XXX */ 1.721 + if (sentinel.ai_next) 1.722 + error = 0; 1.723 + 1.724 + if (error) 1.725 + goto free; 1.726 + if (error == 0) { 1.727 + if (sentinel.ai_next) { 1.728 + good: 1.729 + *res = sentinel.ai_next; 1.730 + return SUCCESS; 1.731 + } else 1.732 + error = EAI_FAIL; 1.733 + } 1.734 + free: 1.735 + bad: 1.736 + if (sentinel.ai_next) 1.737 + __wrap_freeaddrinfo(sentinel.ai_next); 1.738 + *res = NULL; 1.739 + return error; 1.740 +} 1.741 + 1.742 +/* 1.743 + * FQDN hostname, DNS lookup 1.744 + */ 1.745 +static int 1.746 +explore_fqdn(const struct addrinfo *pai, const char *hostname, 1.747 + const char *servname, struct addrinfo **res) 1.748 +{ 1.749 + struct addrinfo *result; 1.750 + struct addrinfo *cur; 1.751 + int error = 0; 1.752 + static const ns_dtab dtab[] = { 1.753 + NS_FILES_CB(_files_getaddrinfo, NULL) 1.754 + { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 1.755 + NS_NIS_CB(_yp_getaddrinfo, NULL) 1.756 + { 0, 0, 0 } 1.757 + }; 1.758 + 1.759 + assert(pai != NULL); 1.760 + /* hostname may be NULL */ 1.761 + /* servname may be NULL */ 1.762 + assert(res != NULL); 1.763 + 1.764 + result = NULL; 1.765 + 1.766 + /* 1.767 + * if the servname does not match socktype/protocol, ignore it. 1.768 + */ 1.769 + if (get_portmatch(pai, servname) != 0) 1.770 + return 0; 1.771 + 1.772 + switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 1.773 + default_dns_files, hostname, pai)) { 1.774 + case NS_TRYAGAIN: 1.775 + error = EAI_AGAIN; 1.776 + goto free; 1.777 + case NS_UNAVAIL: 1.778 + error = EAI_FAIL; 1.779 + goto free; 1.780 + case NS_NOTFOUND: 1.781 + error = EAI_NODATA; 1.782 + goto free; 1.783 + case NS_SUCCESS: 1.784 + error = 0; 1.785 + for (cur = result; cur; cur = cur->ai_next) { 1.786 + GET_PORT(cur, servname); 1.787 + /* canonname should be filled already */ 1.788 + } 1.789 + break; 1.790 + } 1.791 + 1.792 + *res = result; 1.793 + 1.794 + return 0; 1.795 + 1.796 +free: 1.797 + if (result) 1.798 + __wrap_freeaddrinfo(result); 1.799 + return error; 1.800 +} 1.801 + 1.802 +/* 1.803 + * hostname == NULL. 1.804 + * passive socket -> anyaddr (0.0.0.0 or ::) 1.805 + * non-passive socket -> localhost (127.0.0.1 or ::1) 1.806 + */ 1.807 +static int 1.808 +explore_null(const struct addrinfo *pai, const char *servname, 1.809 + struct addrinfo **res) 1.810 +{ 1.811 + int s; 1.812 + const struct afd *afd; 1.813 + struct addrinfo *cur; 1.814 + struct addrinfo sentinel; 1.815 + int error; 1.816 + 1.817 + assert(pai != NULL); 1.818 + /* servname may be NULL */ 1.819 + assert(res != NULL); 1.820 + 1.821 + *res = NULL; 1.822 + sentinel.ai_next = NULL; 1.823 + cur = &sentinel; 1.824 + 1.825 + /* 1.826 + * filter out AFs that are not supported by the kernel 1.827 + * XXX errno? 1.828 + */ 1.829 + s = socket(pai->ai_family, SOCK_DGRAM, 0); 1.830 + if (s < 0) { 1.831 + if (errno != EMFILE) 1.832 + return 0; 1.833 + } else 1.834 + close(s); 1.835 + 1.836 + /* 1.837 + * if the servname does not match socktype/protocol, ignore it. 1.838 + */ 1.839 + if (get_portmatch(pai, servname) != 0) 1.840 + return 0; 1.841 + 1.842 + afd = find_afd(pai->ai_family); 1.843 + if (afd == NULL) 1.844 + return 0; 1.845 + 1.846 + if (pai->ai_flags & AI_PASSIVE) { 1.847 + GET_AI(cur->ai_next, afd, afd->a_addrany); 1.848 + /* xxx meaningless? 1.849 + * GET_CANONNAME(cur->ai_next, "anyaddr"); 1.850 + */ 1.851 + GET_PORT(cur->ai_next, servname); 1.852 + } else { 1.853 + GET_AI(cur->ai_next, afd, afd->a_loopback); 1.854 + /* xxx meaningless? 1.855 + * GET_CANONNAME(cur->ai_next, "localhost"); 1.856 + */ 1.857 + GET_PORT(cur->ai_next, servname); 1.858 + } 1.859 + cur = cur->ai_next; 1.860 + 1.861 + *res = sentinel.ai_next; 1.862 + return 0; 1.863 + 1.864 +free: 1.865 + if (sentinel.ai_next) 1.866 + __wrap_freeaddrinfo(sentinel.ai_next); 1.867 + return error; 1.868 +} 1.869 + 1.870 +/* 1.871 + * numeric hostname 1.872 + */ 1.873 +static int 1.874 +explore_numeric(const struct addrinfo *pai, const char *hostname, 1.875 + const char *servname, struct addrinfo **res, const char *canonname) 1.876 +{ 1.877 + const struct afd *afd; 1.878 + struct addrinfo *cur; 1.879 + struct addrinfo sentinel; 1.880 + int error; 1.881 + char pton[PTON_MAX]; 1.882 + 1.883 + assert(pai != NULL); 1.884 + /* hostname may be NULL */ 1.885 + /* servname may be NULL */ 1.886 + assert(res != NULL); 1.887 + 1.888 + *res = NULL; 1.889 + sentinel.ai_next = NULL; 1.890 + cur = &sentinel; 1.891 + 1.892 + /* 1.893 + * if the servname does not match socktype/protocol, ignore it. 1.894 + */ 1.895 + if (get_portmatch(pai, servname) != 0) 1.896 + return 0; 1.897 + 1.898 + afd = find_afd(pai->ai_family); 1.899 + if (afd == NULL) 1.900 + return 0; 1.901 + 1.902 + switch (afd->a_af) { 1.903 +#if 0 /*X/Open spec*/ 1.904 + case AF_INET: 1.905 + if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 1.906 + if (pai->ai_family == afd->a_af || 1.907 + pai->ai_family == PF_UNSPEC /*?*/) { 1.908 + GET_AI(cur->ai_next, afd, pton); 1.909 + GET_PORT(cur->ai_next, servname); 1.910 + if ((pai->ai_flags & AI_CANONNAME)) { 1.911 + /* 1.912 + * Set the numeric address itself as 1.913 + * the canonical name, based on a 1.914 + * clarification in rfc2553bis-03. 1.915 + */ 1.916 + GET_CANONNAME(cur->ai_next, canonname); 1.917 + } 1.918 + while (cur && cur->ai_next) 1.919 + cur = cur->ai_next; 1.920 + } else 1.921 + ERR(EAI_FAMILY); /*xxx*/ 1.922 + } 1.923 + break; 1.924 +#endif 1.925 + default: 1.926 + if (inet_pton(afd->a_af, hostname, pton) == 1) { 1.927 + if (pai->ai_family == afd->a_af || 1.928 + pai->ai_family == PF_UNSPEC /*?*/) { 1.929 + GET_AI(cur->ai_next, afd, pton); 1.930 + GET_PORT(cur->ai_next, servname); 1.931 + if ((pai->ai_flags & AI_CANONNAME)) { 1.932 + /* 1.933 + * Set the numeric address itself as 1.934 + * the canonical name, based on a 1.935 + * clarification in rfc2553bis-03. 1.936 + */ 1.937 + GET_CANONNAME(cur->ai_next, canonname); 1.938 + } 1.939 + while (cur->ai_next) 1.940 + cur = cur->ai_next; 1.941 + } else 1.942 + ERR(EAI_FAMILY); /*xxx*/ 1.943 + } 1.944 + break; 1.945 + } 1.946 + 1.947 + *res = sentinel.ai_next; 1.948 + return 0; 1.949 + 1.950 +free: 1.951 +bad: 1.952 + if (sentinel.ai_next) 1.953 + __wrap_freeaddrinfo(sentinel.ai_next); 1.954 + return error; 1.955 +} 1.956 + 1.957 +/* 1.958 + * numeric hostname with scope 1.959 + */ 1.960 +static int 1.961 +explore_numeric_scope(const struct addrinfo *pai, const char *hostname, 1.962 + const char *servname, struct addrinfo **res) 1.963 +{ 1.964 +#if !defined(SCOPE_DELIMITER) || !defined(INET6) 1.965 + return explore_numeric(pai, hostname, servname, res, hostname); 1.966 +#else 1.967 + const struct afd *afd; 1.968 + struct addrinfo *cur; 1.969 + int error; 1.970 + char *cp, *hostname2 = NULL, *scope, *addr; 1.971 + struct sockaddr_in6 *sin6; 1.972 + 1.973 + assert(pai != NULL); 1.974 + /* hostname may be NULL */ 1.975 + /* servname may be NULL */ 1.976 + assert(res != NULL); 1.977 + 1.978 + /* 1.979 + * if the servname does not match socktype/protocol, ignore it. 1.980 + */ 1.981 + if (get_portmatch(pai, servname) != 0) 1.982 + return 0; 1.983 + 1.984 + afd = find_afd(pai->ai_family); 1.985 + if (afd == NULL) 1.986 + return 0; 1.987 + 1.988 + if (!afd->a_scoped) 1.989 + return explore_numeric(pai, hostname, servname, res, hostname); 1.990 + 1.991 + cp = strchr(hostname, SCOPE_DELIMITER); 1.992 + if (cp == NULL) 1.993 + return explore_numeric(pai, hostname, servname, res, hostname); 1.994 + 1.995 + /* 1.996 + * Handle special case of <scoped_address><delimiter><scope id> 1.997 + */ 1.998 + hostname2 = strdup(hostname); 1.999 + if (hostname2 == NULL) 1.1000 + return EAI_MEMORY; 1.1001 + /* terminate at the delimiter */ 1.1002 + hostname2[cp - hostname] = '\0'; 1.1003 + addr = hostname2; 1.1004 + scope = cp + 1; 1.1005 + 1.1006 + error = explore_numeric(pai, addr, servname, res, hostname); 1.1007 + if (error == 0) { 1.1008 + u_int32_t scopeid; 1.1009 + 1.1010 + for (cur = *res; cur; cur = cur->ai_next) { 1.1011 + if (cur->ai_family != AF_INET6) 1.1012 + continue; 1.1013 + sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 1.1014 + if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { 1.1015 + free(hostname2); 1.1016 + return(EAI_NODATA); /* XXX: is return OK? */ 1.1017 + } 1.1018 + sin6->sin6_scope_id = scopeid; 1.1019 + } 1.1020 + } 1.1021 + 1.1022 + free(hostname2); 1.1023 + 1.1024 + return error; 1.1025 +#endif 1.1026 +} 1.1027 + 1.1028 +static int 1.1029 +get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) 1.1030 +{ 1.1031 + 1.1032 + assert(pai != NULL); 1.1033 + assert(ai != NULL); 1.1034 + assert(str != NULL); 1.1035 + 1.1036 + if ((pai->ai_flags & AI_CANONNAME) != 0) { 1.1037 + ai->ai_canonname = strdup(str); 1.1038 + if (ai->ai_canonname == NULL) 1.1039 + return EAI_MEMORY; 1.1040 + } 1.1041 + return 0; 1.1042 +} 1.1043 + 1.1044 +static struct addrinfo * 1.1045 +get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) 1.1046 +{ 1.1047 + char *p; 1.1048 + struct addrinfo *ai; 1.1049 + 1.1050 + assert(pai != NULL); 1.1051 + assert(afd != NULL); 1.1052 + assert(addr != NULL); 1.1053 + 1.1054 + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 1.1055 + + (afd->a_socklen)); 1.1056 + if (ai == NULL) 1.1057 + return NULL; 1.1058 + 1.1059 + memcpy(ai, pai, sizeof(struct addrinfo)); 1.1060 + ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 1.1061 + memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 1.1062 + 1.1063 +#ifdef HAVE_SA_LEN 1.1064 + ai->ai_addr->sa_len = afd->a_socklen; 1.1065 +#endif 1.1066 + 1.1067 + ai->ai_addrlen = afd->a_socklen; 1.1068 +#if defined (__alpha__) || (defined(__i386__) && defined(_LP64)) || defined(__sparc64__) 1.1069 + ai->__ai_pad0 = 0; 1.1070 +#endif 1.1071 + ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 1.1072 + p = (char *)(void *)(ai->ai_addr); 1.1073 + memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 1.1074 + return ai; 1.1075 +} 1.1076 + 1.1077 +static int 1.1078 +get_portmatch(const struct addrinfo *ai, const char *servname) 1.1079 +{ 1.1080 + 1.1081 + assert(ai != NULL); 1.1082 + /* servname may be NULL */ 1.1083 + 1.1084 + return get_port(ai, servname, 1); 1.1085 +} 1.1086 + 1.1087 +static int 1.1088 +get_port(const struct addrinfo *ai, const char *servname, int matchonly) 1.1089 +{ 1.1090 + const char *proto; 1.1091 + struct servent *sp; 1.1092 + int port; 1.1093 + int allownumeric; 1.1094 + 1.1095 + assert(ai != NULL); 1.1096 + /* servname may be NULL */ 1.1097 + 1.1098 + if (servname == NULL) 1.1099 + return 0; 1.1100 + switch (ai->ai_family) { 1.1101 + case AF_INET: 1.1102 +#ifdef AF_INET6 1.1103 + case AF_INET6: 1.1104 +#endif 1.1105 + break; 1.1106 + default: 1.1107 + return 0; 1.1108 + } 1.1109 + 1.1110 + switch (ai->ai_socktype) { 1.1111 + case SOCK_RAW: 1.1112 + return EAI_SERVICE; 1.1113 + case SOCK_DGRAM: 1.1114 + case SOCK_STREAM: 1.1115 + allownumeric = 1; 1.1116 + break; 1.1117 + case ANY: 1.1118 +#if 1 /* ANDROID-SPECIFIC CHANGE TO MATCH GLIBC */ 1.1119 + allownumeric = 1; 1.1120 +#else 1.1121 + allownumeric = 0; 1.1122 +#endif 1.1123 + break; 1.1124 + default: 1.1125 + return EAI_SOCKTYPE; 1.1126 + } 1.1127 + 1.1128 + port = str2number(servname); 1.1129 + if (port >= 0) { 1.1130 + if (!allownumeric) 1.1131 + return EAI_SERVICE; 1.1132 + if (port < 0 || port > 65535) 1.1133 + return EAI_SERVICE; 1.1134 + port = htons(port); 1.1135 + } else { 1.1136 + if (ai->ai_flags & AI_NUMERICSERV) 1.1137 + return EAI_NONAME; 1.1138 + 1.1139 + switch (ai->ai_socktype) { 1.1140 + case SOCK_DGRAM: 1.1141 + proto = "udp"; 1.1142 + break; 1.1143 + case SOCK_STREAM: 1.1144 + proto = "tcp"; 1.1145 + break; 1.1146 + default: 1.1147 + proto = NULL; 1.1148 + break; 1.1149 + } 1.1150 + 1.1151 + if ((sp = getservbyname(servname, proto)) == NULL) 1.1152 + return EAI_SERVICE; 1.1153 + port = sp->s_port; 1.1154 + } 1.1155 + 1.1156 + if (!matchonly) { 1.1157 + switch (ai->ai_family) { 1.1158 + case AF_INET: 1.1159 + ((struct sockaddr_in *)(void *) 1.1160 + ai->ai_addr)->sin_port = port; 1.1161 + break; 1.1162 +#ifdef INET6 1.1163 + case AF_INET6: 1.1164 + ((struct sockaddr_in6 *)(void *) 1.1165 + ai->ai_addr)->sin6_port = port; 1.1166 + break; 1.1167 +#endif 1.1168 + } 1.1169 + } 1.1170 + 1.1171 + return 0; 1.1172 +} 1.1173 + 1.1174 +static const struct afd * 1.1175 +find_afd(int af) 1.1176 +{ 1.1177 + const struct afd *afd; 1.1178 + 1.1179 + if (af == PF_UNSPEC) 1.1180 + return NULL; 1.1181 + for (afd = afdl; afd->a_af; afd++) { 1.1182 + if (afd->a_af == af) 1.1183 + return afd; 1.1184 + } 1.1185 + return NULL; 1.1186 +} 1.1187 + 1.1188 +#ifdef INET6 1.1189 +/* convert a string to a scope identifier. XXX: IPv6 specific */ 1.1190 +static int 1.1191 +ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) 1.1192 +{ 1.1193 + u_long lscopeid; 1.1194 + struct in6_addr *a6; 1.1195 + char *ep; 1.1196 + 1.1197 + assert(scope != NULL); 1.1198 + assert(sin6 != NULL); 1.1199 + assert(scopeid != NULL); 1.1200 + 1.1201 + a6 = &sin6->sin6_addr; 1.1202 + 1.1203 + /* empty scopeid portion is invalid */ 1.1204 + if (*scope == '\0') 1.1205 + return -1; 1.1206 + 1.1207 + if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 1.1208 + /* 1.1209 + * We currently assume a one-to-one mapping between links 1.1210 + * and interfaces, so we simply use interface indices for 1.1211 + * like-local scopes. 1.1212 + */ 1.1213 + *scopeid = if_nametoindex(scope); 1.1214 + if (*scopeid == 0) 1.1215 + goto trynumeric; 1.1216 + return 0; 1.1217 + } 1.1218 + 1.1219 + /* still unclear about literal, allow numeric only - placeholder */ 1.1220 + if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 1.1221 + goto trynumeric; 1.1222 + if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 1.1223 + goto trynumeric; 1.1224 + else 1.1225 + goto trynumeric; /* global */ 1.1226 + 1.1227 + /* try to convert to a numeric id as a last resort */ 1.1228 + trynumeric: 1.1229 + errno = 0; 1.1230 + lscopeid = strtoul(scope, &ep, 10); 1.1231 + *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); 1.1232 + if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) 1.1233 + return 0; 1.1234 + else 1.1235 + return -1; 1.1236 +} 1.1237 +#endif 1.1238 + 1.1239 +/* code duplicate with gethnamaddr.c */ 1.1240 + 1.1241 +static const char AskedForGot[] = 1.1242 + "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 1.1243 + 1.1244 +static struct addrinfo * 1.1245 +getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 1.1246 + const struct addrinfo *pai) 1.1247 +{ 1.1248 + struct addrinfo sentinel, *cur; 1.1249 + struct addrinfo ai; 1.1250 + const struct afd *afd; 1.1251 + char *canonname; 1.1252 + const HEADER *hp; 1.1253 + const u_char *cp; 1.1254 + int n; 1.1255 + const u_char *eom; 1.1256 + char *bp, *ep; 1.1257 + int type, class, ancount, qdcount; 1.1258 + int haveanswer, had_error; 1.1259 + char tbuf[MAXDNAME]; 1.1260 + int (*name_ok) (const char *); 1.1261 + char hostbuf[8*1024]; 1.1262 + 1.1263 + assert(answer != NULL); 1.1264 + assert(qname != NULL); 1.1265 + assert(pai != NULL); 1.1266 + 1.1267 + memset(&sentinel, 0, sizeof(sentinel)); 1.1268 + cur = &sentinel; 1.1269 + 1.1270 + canonname = NULL; 1.1271 + eom = answer->buf + anslen; 1.1272 + switch (qtype) { 1.1273 + case T_A: 1.1274 + case T_AAAA: 1.1275 + case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 1.1276 + name_ok = res_hnok; 1.1277 + break; 1.1278 + default: 1.1279 + return NULL; /* XXX should be abort(); */ 1.1280 + } 1.1281 + /* 1.1282 + * find first satisfactory answer 1.1283 + */ 1.1284 + hp = &answer->hdr; 1.1285 + ancount = ntohs(hp->ancount); 1.1286 + qdcount = ntohs(hp->qdcount); 1.1287 + bp = hostbuf; 1.1288 + ep = hostbuf + sizeof hostbuf; 1.1289 + cp = answer->buf + HFIXEDSZ; 1.1290 + if (qdcount != 1) { 1.1291 + h_errno = NO_RECOVERY; 1.1292 + return (NULL); 1.1293 + } 1.1294 + n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 1.1295 + if ((n < 0) || !(*name_ok)(bp)) { 1.1296 + h_errno = NO_RECOVERY; 1.1297 + return (NULL); 1.1298 + } 1.1299 + cp += n + QFIXEDSZ; 1.1300 + if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 1.1301 + /* res_send() has already verified that the query name is the 1.1302 + * same as the one we sent; this just gets the expanded name 1.1303 + * (i.e., with the succeeding search-domain tacked on). 1.1304 + */ 1.1305 + n = strlen(bp) + 1; /* for the \0 */ 1.1306 + if (n >= MAXHOSTNAMELEN) { 1.1307 + h_errno = NO_RECOVERY; 1.1308 + return (NULL); 1.1309 + } 1.1310 + canonname = bp; 1.1311 + bp += n; 1.1312 + /* The qname can be abbreviated, but h_name is now absolute. */ 1.1313 + qname = canonname; 1.1314 + } 1.1315 + haveanswer = 0; 1.1316 + had_error = 0; 1.1317 + while (ancount-- > 0 && cp < eom && !had_error) { 1.1318 + n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 1.1319 + if ((n < 0) || !(*name_ok)(bp)) { 1.1320 + had_error++; 1.1321 + continue; 1.1322 + } 1.1323 + cp += n; /* name */ 1.1324 + type = _getshort(cp); 1.1325 + cp += INT16SZ; /* type */ 1.1326 + class = _getshort(cp); 1.1327 + cp += INT16SZ + INT32SZ; /* class, TTL */ 1.1328 + n = _getshort(cp); 1.1329 + cp += INT16SZ; /* len */ 1.1330 + if (class != C_IN) { 1.1331 + /* XXX - debug? syslog? */ 1.1332 + cp += n; 1.1333 + continue; /* XXX - had_error++ ? */ 1.1334 + } 1.1335 + if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 1.1336 + type == T_CNAME) { 1.1337 + n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1.1338 + if ((n < 0) || !(*name_ok)(tbuf)) { 1.1339 + had_error++; 1.1340 + continue; 1.1341 + } 1.1342 + cp += n; 1.1343 + /* Get canonical name. */ 1.1344 + n = strlen(tbuf) + 1; /* for the \0 */ 1.1345 + if (n > ep - bp || n >= MAXHOSTNAMELEN) { 1.1346 + had_error++; 1.1347 + continue; 1.1348 + } 1.1349 + strlcpy(bp, tbuf, (size_t)(ep - bp)); 1.1350 + canonname = bp; 1.1351 + bp += n; 1.1352 + continue; 1.1353 + } 1.1354 + if (qtype == T_ANY) { 1.1355 + if (!(type == T_A || type == T_AAAA)) { 1.1356 + cp += n; 1.1357 + continue; 1.1358 + } 1.1359 + } else if (type != qtype) { 1.1360 + if (type != T_KEY && type != T_SIG) 1.1361 + syslog(LOG_NOTICE|LOG_AUTH, 1.1362 + "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 1.1363 + qname, p_class(C_IN), p_type(qtype), 1.1364 + p_type(type)); 1.1365 + cp += n; 1.1366 + continue; /* XXX - had_error++ ? */ 1.1367 + } 1.1368 + switch (type) { 1.1369 + case T_A: 1.1370 + case T_AAAA: 1.1371 + if (strcasecmp(canonname, bp) != 0) { 1.1372 + syslog(LOG_NOTICE|LOG_AUTH, 1.1373 + AskedForGot, canonname, bp); 1.1374 + cp += n; 1.1375 + continue; /* XXX - had_error++ ? */ 1.1376 + } 1.1377 + if (type == T_A && n != INADDRSZ) { 1.1378 + cp += n; 1.1379 + continue; 1.1380 + } 1.1381 + if (type == T_AAAA && n != IN6ADDRSZ) { 1.1382 + cp += n; 1.1383 + continue; 1.1384 + } 1.1385 + if (type == T_AAAA) { 1.1386 + struct in6_addr in6; 1.1387 + memcpy(&in6, cp, IN6ADDRSZ); 1.1388 + if (IN6_IS_ADDR_V4MAPPED(&in6)) { 1.1389 + cp += n; 1.1390 + continue; 1.1391 + } 1.1392 + } 1.1393 + if (!haveanswer) { 1.1394 + int nn; 1.1395 + 1.1396 + canonname = bp; 1.1397 + nn = strlen(bp) + 1; /* for the \0 */ 1.1398 + bp += nn; 1.1399 + } 1.1400 + 1.1401 + /* don't overwrite pai */ 1.1402 + ai = *pai; 1.1403 + ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 1.1404 + afd = find_afd(ai.ai_family); 1.1405 + if (afd == NULL) { 1.1406 + cp += n; 1.1407 + continue; 1.1408 + } 1.1409 + cur->ai_next = get_ai(&ai, afd, (const char *)cp); 1.1410 + if (cur->ai_next == NULL) 1.1411 + had_error++; 1.1412 + while (cur && cur->ai_next) 1.1413 + cur = cur->ai_next; 1.1414 + cp += n; 1.1415 + break; 1.1416 + default: 1.1417 + abort(); 1.1418 + } 1.1419 + if (!had_error) 1.1420 + haveanswer++; 1.1421 + } 1.1422 + if (haveanswer) { 1.1423 + if (!canonname) 1.1424 + (void)get_canonname(pai, sentinel.ai_next, qname); 1.1425 + else 1.1426 + (void)get_canonname(pai, sentinel.ai_next, canonname); 1.1427 + h_errno = NETDB_SUCCESS; 1.1428 + return sentinel.ai_next; 1.1429 + } 1.1430 + 1.1431 + h_errno = NO_RECOVERY; 1.1432 + return NULL; 1.1433 +} 1.1434 + 1.1435 +struct addrinfo_sort_elem { 1.1436 + struct addrinfo *ai; 1.1437 + int has_src_addr; 1.1438 + sockaddr_union src_addr; 1.1439 + int original_order; 1.1440 +}; 1.1441 + 1.1442 +/*ARGSUSED*/ 1.1443 +static int 1.1444 +_get_scope(const struct sockaddr *addr) 1.1445 +{ 1.1446 + if (addr->sa_family == AF_INET6) { 1.1447 + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; 1.1448 + if (IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr)) { 1.1449 + return IPV6_ADDR_MC_SCOPE(&addr6->sin6_addr); 1.1450 + } else if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) || 1.1451 + IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) { 1.1452 + /* 1.1453 + * RFC 4291 section 2.5.3 says loopback is to be treated as having 1.1454 + * link-local scope. 1.1455 + */ 1.1456 + return IPV6_ADDR_SCOPE_LINKLOCAL; 1.1457 + } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) { 1.1458 + return IPV6_ADDR_SCOPE_SITELOCAL; 1.1459 + } else { 1.1460 + return IPV6_ADDR_SCOPE_GLOBAL; 1.1461 + } 1.1462 + } else if (addr->sa_family == AF_INET) { 1.1463 + const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; 1.1464 + unsigned long int na = ntohl(addr4->sin_addr.s_addr); 1.1465 + 1.1466 + if (IN_LOOPBACK(na) || /* 127.0.0.0/8 */ 1.1467 + (na & 0xffff0000) == 0xa9fe0000) { /* 169.254.0.0/16 */ 1.1468 + return IPV6_ADDR_SCOPE_LINKLOCAL; 1.1469 + } else { 1.1470 + /* 1.1471 + * According to draft-ietf-6man-rfc3484-revise-01 section 2.3, 1.1472 + * it is best not to treat the private IPv4 ranges 1.1473 + * (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) as being 1.1474 + * in a special scope, so we don't. 1.1475 + */ 1.1476 + return IPV6_ADDR_SCOPE_GLOBAL; 1.1477 + } 1.1478 + } else { 1.1479 + /* 1.1480 + * This should never happen. 1.1481 + * Return a scope with low priority as a last resort. 1.1482 + */ 1.1483 + return IPV6_ADDR_SCOPE_NODELOCAL; 1.1484 + } 1.1485 +} 1.1486 + 1.1487 +/* These macros are modelled after the ones in <netinet/in6.h>. */ 1.1488 + 1.1489 +/* RFC 4380, section 2.6 */ 1.1490 +#define IN6_IS_ADDR_TEREDO(a) \ 1.1491 + ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == ntohl(0x20010000))) 1.1492 + 1.1493 +/* RFC 3056, section 2. */ 1.1494 +#define IN6_IS_ADDR_6TO4(a) \ 1.1495 + (((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02)) 1.1496 + 1.1497 +/* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */ 1.1498 +#define IN6_IS_ADDR_6BONE(a) \ 1.1499 + (((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe)) 1.1500 + 1.1501 +/* 1.1502 + * Get the label for a given IPv4/IPv6 address. 1.1503 + * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01. 1.1504 + */ 1.1505 + 1.1506 +/*ARGSUSED*/ 1.1507 +static int 1.1508 +_get_label(const struct sockaddr *addr) 1.1509 +{ 1.1510 + if (addr->sa_family == AF_INET) { 1.1511 + return 3; 1.1512 + } else if (addr->sa_family == AF_INET6) { 1.1513 + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; 1.1514 + if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) { 1.1515 + return 0; 1.1516 + } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) { 1.1517 + return 3; 1.1518 + } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) { 1.1519 + return 4; 1.1520 + } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) { 1.1521 + return 5; 1.1522 + } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) { 1.1523 + return 10; 1.1524 + } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) { 1.1525 + return 11; 1.1526 + } else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) { 1.1527 + return 12; 1.1528 + } else { 1.1529 + return 2; 1.1530 + } 1.1531 + } else { 1.1532 + /* 1.1533 + * This should never happen. 1.1534 + * Return a semi-random label as a last resort. 1.1535 + */ 1.1536 + return 1; 1.1537 + } 1.1538 +} 1.1539 + 1.1540 +/* 1.1541 + * Get the precedence for a given IPv4/IPv6 address. 1.1542 + * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01. 1.1543 + */ 1.1544 + 1.1545 +/*ARGSUSED*/ 1.1546 +static int 1.1547 +_get_precedence(const struct sockaddr *addr) 1.1548 +{ 1.1549 + if (addr->sa_family == AF_INET) { 1.1550 + return 30; 1.1551 + } else if (addr->sa_family == AF_INET6) { 1.1552 + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; 1.1553 + if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) { 1.1554 + return 60; 1.1555 + } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) { 1.1556 + return 30; 1.1557 + } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) { 1.1558 + return 20; 1.1559 + } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) { 1.1560 + return 10; 1.1561 + } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) || 1.1562 + IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) || 1.1563 + IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) { 1.1564 + return 1; 1.1565 + } else { 1.1566 + return 40; 1.1567 + } 1.1568 + } else { 1.1569 + return 1; 1.1570 + } 1.1571 +} 1.1572 + 1.1573 +/* 1.1574 + * Find number of matching initial bits between the two addresses a1 and a2. 1.1575 + */ 1.1576 + 1.1577 +/*ARGSUSED*/ 1.1578 +static int 1.1579 +_common_prefix_len(const struct in6_addr *a1, const struct in6_addr *a2) 1.1580 +{ 1.1581 + const char *p1 = (const char *)a1; 1.1582 + const char *p2 = (const char *)a2; 1.1583 + unsigned i; 1.1584 + 1.1585 + for (i = 0; i < sizeof(*a1); ++i) { 1.1586 + int x, j; 1.1587 + 1.1588 + if (p1[i] == p2[i]) { 1.1589 + continue; 1.1590 + } 1.1591 + x = p1[i] ^ p2[i]; 1.1592 + for (j = 0; j < CHAR_BIT; ++j) { 1.1593 + if (x & (1 << (CHAR_BIT - 1))) { 1.1594 + return i * CHAR_BIT + j; 1.1595 + } 1.1596 + x <<= 1; 1.1597 + } 1.1598 + } 1.1599 + return sizeof(*a1) * CHAR_BIT; 1.1600 +} 1.1601 + 1.1602 +/* 1.1603 + * Compare two source/destination address pairs. 1.1604 + * RFC 3484, section 6. 1.1605 + */ 1.1606 + 1.1607 +/*ARGSUSED*/ 1.1608 +static int 1.1609 +_rfc3484_compare(const void *ptr1, const void* ptr2) 1.1610 +{ 1.1611 + const struct addrinfo_sort_elem *a1 = (const struct addrinfo_sort_elem *)ptr1; 1.1612 + const struct addrinfo_sort_elem *a2 = (const struct addrinfo_sort_elem *)ptr2; 1.1613 + int scope_src1, scope_dst1, scope_match1; 1.1614 + int scope_src2, scope_dst2, scope_match2; 1.1615 + int label_src1, label_dst1, label_match1; 1.1616 + int label_src2, label_dst2, label_match2; 1.1617 + int precedence1, precedence2; 1.1618 + int prefixlen1, prefixlen2; 1.1619 + 1.1620 + /* Rule 1: Avoid unusable destinations. */ 1.1621 + if (a1->has_src_addr != a2->has_src_addr) { 1.1622 + return a2->has_src_addr - a1->has_src_addr; 1.1623 + } 1.1624 + 1.1625 + /* Rule 2: Prefer matching scope. */ 1.1626 + scope_src1 = _get_scope(&a1->src_addr.generic); 1.1627 + scope_dst1 = _get_scope(a1->ai->ai_addr); 1.1628 + scope_match1 = (scope_src1 == scope_dst1); 1.1629 + 1.1630 + scope_src2 = _get_scope(&a2->src_addr.generic); 1.1631 + scope_dst2 = _get_scope(a2->ai->ai_addr); 1.1632 + scope_match2 = (scope_src2 == scope_dst2); 1.1633 + 1.1634 + if (scope_match1 != scope_match2) { 1.1635 + return scope_match2 - scope_match1; 1.1636 + } 1.1637 + 1.1638 + /* 1.1639 + * Rule 3: Avoid deprecated addresses. 1.1640 + * TODO(sesse): We don't currently have a good way of finding this. 1.1641 + */ 1.1642 + 1.1643 + /* 1.1644 + * Rule 4: Prefer home addresses. 1.1645 + * TODO(sesse): We don't currently have a good way of finding this. 1.1646 + */ 1.1647 + 1.1648 + /* Rule 5: Prefer matching label. */ 1.1649 + label_src1 = _get_label(&a1->src_addr.generic); 1.1650 + label_dst1 = _get_label(a1->ai->ai_addr); 1.1651 + label_match1 = (label_src1 == label_dst1); 1.1652 + 1.1653 + label_src2 = _get_label(&a2->src_addr.generic); 1.1654 + label_dst2 = _get_label(a2->ai->ai_addr); 1.1655 + label_match2 = (label_src2 == label_dst2); 1.1656 + 1.1657 + if (label_match1 != label_match2) { 1.1658 + return label_match2 - label_match1; 1.1659 + } 1.1660 + 1.1661 + /* Rule 6: Prefer higher precedence. */ 1.1662 + precedence1 = _get_precedence(a1->ai->ai_addr); 1.1663 + precedence2 = _get_precedence(a2->ai->ai_addr); 1.1664 + if (precedence1 != precedence2) { 1.1665 + return precedence2 - precedence1; 1.1666 + } 1.1667 + 1.1668 + /* 1.1669 + * Rule 7: Prefer native transport. 1.1670 + * TODO(sesse): We don't currently have a good way of finding this. 1.1671 + */ 1.1672 + 1.1673 + /* Rule 8: Prefer smaller scope. */ 1.1674 + if (scope_dst1 != scope_dst2) { 1.1675 + return scope_dst1 - scope_dst2; 1.1676 + } 1.1677 + 1.1678 + /* 1.1679 + * Rule 9: Use longest matching prefix. 1.1680 + * We implement this for IPv6 only, as the rules in RFC 3484 don't seem 1.1681 + * to work very well directly applied to IPv4. (glibc uses information from 1.1682 + * the routing table for a custom IPv4 implementation here.) 1.1683 + */ 1.1684 + if (a1->has_src_addr && a1->ai->ai_addr->sa_family == AF_INET6 && 1.1685 + a2->has_src_addr && a2->ai->ai_addr->sa_family == AF_INET6) { 1.1686 + const struct sockaddr_in6 *a1_src = &a1->src_addr.in6; 1.1687 + const struct sockaddr_in6 *a1_dst = (const struct sockaddr_in6 *)a1->ai->ai_addr; 1.1688 + const struct sockaddr_in6 *a2_src = &a2->src_addr.in6; 1.1689 + const struct sockaddr_in6 *a2_dst = (const struct sockaddr_in6 *)a2->ai->ai_addr; 1.1690 + prefixlen1 = _common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr); 1.1691 + prefixlen2 = _common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr); 1.1692 + if (prefixlen1 != prefixlen2) { 1.1693 + return prefixlen2 - prefixlen1; 1.1694 + } 1.1695 + } 1.1696 + 1.1697 + /* 1.1698 + * Rule 10: Leave the order unchanged. 1.1699 + * We need this since qsort() is not necessarily stable. 1.1700 + */ 1.1701 + return a1->original_order - a2->original_order; 1.1702 +} 1.1703 + 1.1704 +/* 1.1705 + * Find the source address that will be used if trying to connect to the given 1.1706 + * address. src_addr must be large enough to hold a struct sockaddr_in6. 1.1707 + * 1.1708 + * Returns 1 if a source address was found, 0 if the address is unreachable, 1.1709 + * and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are 1.1710 + * undefined. 1.1711 + */ 1.1712 + 1.1713 +/*ARGSUSED*/ 1.1714 +static int 1.1715 +_find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr) 1.1716 +{ 1.1717 + int sock; 1.1718 + int ret; 1.1719 + socklen_t len; 1.1720 + 1.1721 + switch (addr->sa_family) { 1.1722 + case AF_INET: 1.1723 + len = sizeof(struct sockaddr_in); 1.1724 + break; 1.1725 + case AF_INET6: 1.1726 + len = sizeof(struct sockaddr_in6); 1.1727 + break; 1.1728 + default: 1.1729 + /* No known usable source address for non-INET families. */ 1.1730 + return 0; 1.1731 + } 1.1732 + 1.1733 + sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP); 1.1734 + if (sock == -1) { 1.1735 + if (errno == EAFNOSUPPORT) { 1.1736 + return 0; 1.1737 + } else { 1.1738 + return -1; 1.1739 + } 1.1740 + } 1.1741 + 1.1742 + do { 1.1743 + ret = connect(sock, addr, len); 1.1744 + } while (ret == -1 && errno == EINTR); 1.1745 + 1.1746 + if (ret == -1) { 1.1747 + close(sock); 1.1748 + return 0; 1.1749 + } 1.1750 + 1.1751 + if (getsockname(sock, src_addr, &len) == -1) { 1.1752 + close(sock); 1.1753 + return -1; 1.1754 + } 1.1755 + close(sock); 1.1756 + return 1; 1.1757 +} 1.1758 + 1.1759 +/* 1.1760 + * Sort the linked list starting at sentinel->ai_next in RFC3484 order. 1.1761 + * Will leave the list unchanged if an error occurs. 1.1762 + */ 1.1763 + 1.1764 +/*ARGSUSED*/ 1.1765 +static void 1.1766 +_rfc3484_sort(struct addrinfo *list_sentinel) 1.1767 +{ 1.1768 + struct addrinfo *cur; 1.1769 + int nelem = 0, i; 1.1770 + struct addrinfo_sort_elem *elems; 1.1771 + 1.1772 + cur = list_sentinel->ai_next; 1.1773 + while (cur) { 1.1774 + ++nelem; 1.1775 + cur = cur->ai_next; 1.1776 + } 1.1777 + 1.1778 + elems = (struct addrinfo_sort_elem *)malloc(nelem * sizeof(struct addrinfo_sort_elem)); 1.1779 + if (elems == NULL) { 1.1780 + goto error; 1.1781 + } 1.1782 + 1.1783 + /* 1.1784 + * Convert the linked list to an array that also contains the candidate 1.1785 + * source address for each destination address. 1.1786 + */ 1.1787 + for (i = 0, cur = list_sentinel->ai_next; i < nelem; ++i, cur = cur->ai_next) { 1.1788 + int has_src_addr; 1.1789 + assert(cur != NULL); 1.1790 + elems[i].ai = cur; 1.1791 + elems[i].original_order = i; 1.1792 + 1.1793 + has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic); 1.1794 + if (has_src_addr == -1) { 1.1795 + goto error; 1.1796 + } 1.1797 + elems[i].has_src_addr = has_src_addr; 1.1798 + } 1.1799 + 1.1800 + /* Sort the addresses, and rearrange the linked list so it matches the sorted order. */ 1.1801 + qsort((void *)elems, nelem, sizeof(struct addrinfo_sort_elem), _rfc3484_compare); 1.1802 + 1.1803 + list_sentinel->ai_next = elems[0].ai; 1.1804 + for (i = 0; i < nelem - 1; ++i) { 1.1805 + elems[i].ai->ai_next = elems[i + 1].ai; 1.1806 + } 1.1807 + elems[nelem - 1].ai->ai_next = NULL; 1.1808 + 1.1809 +error: 1.1810 + free(elems); 1.1811 +} 1.1812 + 1.1813 +/*ARGSUSED*/ 1.1814 +static int 1.1815 +_dns_getaddrinfo(void *rv, void *cb_data, va_list ap) 1.1816 +{ 1.1817 + struct addrinfo *ai; 1.1818 + querybuf *buf, *buf2; 1.1819 + const char *name; 1.1820 + const struct addrinfo *pai; 1.1821 + struct addrinfo sentinel, *cur; 1.1822 + struct res_target q, q2; 1.1823 + res_state res; 1.1824 + 1.1825 + name = va_arg(ap, char *); 1.1826 + pai = va_arg(ap, const struct addrinfo *); 1.1827 + //fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name); 1.1828 + 1.1829 + memset(&q, 0, sizeof(q)); 1.1830 + memset(&q2, 0, sizeof(q2)); 1.1831 + memset(&sentinel, 0, sizeof(sentinel)); 1.1832 + cur = &sentinel; 1.1833 + 1.1834 + buf = malloc(sizeof(*buf)); 1.1835 + if (buf == NULL) { 1.1836 + h_errno = NETDB_INTERNAL; 1.1837 + return NS_NOTFOUND; 1.1838 + } 1.1839 + buf2 = malloc(sizeof(*buf2)); 1.1840 + if (buf2 == NULL) { 1.1841 + free(buf); 1.1842 + h_errno = NETDB_INTERNAL; 1.1843 + return NS_NOTFOUND; 1.1844 + } 1.1845 + 1.1846 + switch (pai->ai_family) { 1.1847 + case AF_UNSPEC: 1.1848 + /* prefer IPv6 */ 1.1849 + q.name = name; 1.1850 + q.qclass = C_IN; 1.1851 + q.answer = buf->buf; 1.1852 + q.anslen = sizeof(buf->buf); 1.1853 + int query_ipv6 = 1, query_ipv4 = 1; 1.1854 + if (pai->ai_flags & AI_ADDRCONFIG) { 1.1855 + query_ipv6 = _have_ipv6(); 1.1856 + query_ipv4 = _have_ipv4(); 1.1857 + } 1.1858 + if (query_ipv6) { 1.1859 + q.qtype = T_AAAA; 1.1860 + if (query_ipv4) { 1.1861 + q.next = &q2; 1.1862 + q2.name = name; 1.1863 + q2.qclass = C_IN; 1.1864 + q2.qtype = T_A; 1.1865 + q2.answer = buf2->buf; 1.1866 + q2.anslen = sizeof(buf2->buf); 1.1867 + } 1.1868 + } else if (query_ipv4) { 1.1869 + q.qtype = T_A; 1.1870 + } else { 1.1871 + free(buf); 1.1872 + free(buf2); 1.1873 + return NS_NOTFOUND; 1.1874 + } 1.1875 + break; 1.1876 + case AF_INET: 1.1877 + q.name = name; 1.1878 + q.qclass = C_IN; 1.1879 + q.qtype = T_A; 1.1880 + q.answer = buf->buf; 1.1881 + q.anslen = sizeof(buf->buf); 1.1882 + break; 1.1883 + case AF_INET6: 1.1884 + q.name = name; 1.1885 + q.qclass = C_IN; 1.1886 + q.qtype = T_AAAA; 1.1887 + q.answer = buf->buf; 1.1888 + q.anslen = sizeof(buf->buf); 1.1889 + break; 1.1890 + default: 1.1891 + free(buf); 1.1892 + free(buf2); 1.1893 + return NS_UNAVAIL; 1.1894 + } 1.1895 + 1.1896 + res = __res_get_state(); 1.1897 + if (res == NULL) { 1.1898 + free(buf); 1.1899 + free(buf2); 1.1900 + return NS_NOTFOUND; 1.1901 + } 1.1902 + 1.1903 + if (res_searchN(name, &q, res) < 0) { 1.1904 + __res_put_state(res); 1.1905 + free(buf); 1.1906 + free(buf2); 1.1907 + return NS_NOTFOUND; 1.1908 + } 1.1909 + ai = getanswer(buf, q.n, q.name, q.qtype, pai); 1.1910 + if (ai) { 1.1911 + cur->ai_next = ai; 1.1912 + while (cur && cur->ai_next) 1.1913 + cur = cur->ai_next; 1.1914 + } 1.1915 + if (q.next) { 1.1916 + ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); 1.1917 + if (ai) 1.1918 + cur->ai_next = ai; 1.1919 + } 1.1920 + free(buf); 1.1921 + free(buf2); 1.1922 + if (sentinel.ai_next == NULL) { 1.1923 + __res_put_state(res); 1.1924 + switch (h_errno) { 1.1925 + case HOST_NOT_FOUND: 1.1926 + return NS_NOTFOUND; 1.1927 + case TRY_AGAIN: 1.1928 + return NS_TRYAGAIN; 1.1929 + default: 1.1930 + return NS_UNAVAIL; 1.1931 + } 1.1932 + } 1.1933 + 1.1934 + _rfc3484_sort(&sentinel); 1.1935 + 1.1936 + __res_put_state(res); 1.1937 + 1.1938 + *((struct addrinfo **)rv) = sentinel.ai_next; 1.1939 + return NS_SUCCESS; 1.1940 +} 1.1941 + 1.1942 +static void 1.1943 +_sethtent(_pseudo_FILE * __restrict__ hostf) 1.1944 +{ 1.1945 + assert(hostf); 1.1946 + if (hostf->mapping == MAP_FAILED) 1.1947 + (void) _pseudo_fopen_r(hostf, _PATH_HOSTS); 1.1948 + else 1.1949 + _pseudo_rewind(hostf); 1.1950 +} 1.1951 + 1.1952 +static void 1.1953 +_endhtent(_pseudo_FILE * __restrict__ hostf) 1.1954 +{ 1.1955 + assert(hostf); 1.1956 + (void) _pseudo_fclose(hostf); 1.1957 +} 1.1958 + 1.1959 +static struct addrinfo * 1.1960 +_gethtent(_pseudo_FILE * __restrict__ hostf, const char *name, const struct addrinfo *pai) 1.1961 +{ 1.1962 + char *p; 1.1963 + char *cp, *tname, *cname; 1.1964 + struct addrinfo hints, *res0, *res; 1.1965 + int error; 1.1966 + const char *addr; 1.1967 + char hostbuf[8*1024]; 1.1968 + 1.1969 + assert(hostf); 1.1970 +// fprintf(stderr, "_gethtent() name = '%s'\n", name); 1.1971 + assert(name != NULL); 1.1972 + assert(pai != NULL); 1.1973 + 1.1974 + if (hostf->mapping == MAP_FAILED) 1.1975 + (void) _pseudo_fopen_r(hostf, _PATH_HOSTS); 1.1976 + if (hostf->mapping == MAP_FAILED) 1.1977 + return (NULL); 1.1978 + again: 1.1979 + if (!(p = _pseudo_fgets(hostbuf, sizeof hostbuf, hostf))) 1.1980 + return (NULL); 1.1981 + if (*p == '#') 1.1982 + goto again; 1.1983 + if (!(cp = strpbrk(p, "#\n"))) 1.1984 + goto again; 1.1985 + *cp = '\0'; 1.1986 + if (!(cp = strpbrk(p, " \t"))) 1.1987 + goto again; 1.1988 + *cp++ = '\0'; 1.1989 + addr = p; 1.1990 + /* if this is not something we're looking for, skip it. */ 1.1991 + cname = NULL; 1.1992 + while (cp && *cp) { 1.1993 + if (*cp == ' ' || *cp == '\t') { 1.1994 + cp++; 1.1995 + continue; 1.1996 + } 1.1997 + if (!cname) 1.1998 + cname = cp; 1.1999 + tname = cp; 1.2000 + if ((cp = strpbrk(cp, " \t")) != NULL) 1.2001 + *cp++ = '\0'; 1.2002 +// fprintf(stderr, "\ttname = '%s'", tname); 1.2003 + if (strcasecmp(name, tname) == 0) 1.2004 + goto found; 1.2005 + } 1.2006 + goto again; 1.2007 + 1.2008 +found: 1.2009 + hints = *pai; 1.2010 + hints.ai_flags = AI_NUMERICHOST; 1.2011 + error = __wrap_getaddrinfo(addr, NULL, &hints, &res0); 1.2012 + if (error) 1.2013 + goto again; 1.2014 + for (res = res0; res; res = res->ai_next) { 1.2015 + /* cover it up */ 1.2016 + res->ai_flags = pai->ai_flags; 1.2017 + 1.2018 + if (pai->ai_flags & AI_CANONNAME) { 1.2019 + if (get_canonname(pai, res, cname) != 0) { 1.2020 + __wrap_freeaddrinfo(res0); 1.2021 + goto again; 1.2022 + } 1.2023 + } 1.2024 + } 1.2025 + return res0; 1.2026 +} 1.2027 + 1.2028 +/*ARGSUSED*/ 1.2029 +static int 1.2030 +_files_getaddrinfo(void *rv, void *cb_data, va_list ap) 1.2031 +{ 1.2032 + const char *name; 1.2033 + const struct addrinfo *pai; 1.2034 + struct addrinfo sentinel, *cur; 1.2035 + struct addrinfo *p; 1.2036 + _pseudo_FILE hostf = _PSEUDO_FILE_INITIALIZER; 1.2037 + 1.2038 + name = va_arg(ap, char *); 1.2039 + pai = va_arg(ap, struct addrinfo *); 1.2040 + 1.2041 +// fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name); 1.2042 + memset(&sentinel, 0, sizeof(sentinel)); 1.2043 + cur = &sentinel; 1.2044 + 1.2045 + _sethtent(&hostf); 1.2046 + while ((p = _gethtent(&hostf, name, pai)) != NULL) { 1.2047 + cur->ai_next = p; 1.2048 + while (cur && cur->ai_next) 1.2049 + cur = cur->ai_next; 1.2050 + } 1.2051 + _endhtent(&hostf); 1.2052 + 1.2053 + *((struct addrinfo **)rv) = sentinel.ai_next; 1.2054 + if (sentinel.ai_next == NULL) 1.2055 + return NS_NOTFOUND; 1.2056 + return NS_SUCCESS; 1.2057 +} 1.2058 + 1.2059 +/* resolver logic */ 1.2060 + 1.2061 +/* 1.2062 + * Formulate a normal query, send, and await answer. 1.2063 + * Returned answer is placed in supplied buffer "answer". 1.2064 + * Perform preliminary check of answer, returning success only 1.2065 + * if no error is indicated and the answer count is nonzero. 1.2066 + * Return the size of the response on success, -1 on error. 1.2067 + * Error number is left in h_errno. 1.2068 + * 1.2069 + * Caller must parse answer and determine whether it answers the question. 1.2070 + */ 1.2071 +static int 1.2072 +res_queryN(const char *name, /* domain name */ struct res_target *target, 1.2073 + res_state res) 1.2074 +{ 1.2075 + u_char buf[MAXPACKET]; 1.2076 + HEADER *hp; 1.2077 + int n; 1.2078 + struct res_target *t; 1.2079 + int rcode; 1.2080 + int ancount; 1.2081 + 1.2082 + assert(name != NULL); 1.2083 + /* XXX: target may be NULL??? */ 1.2084 + 1.2085 + rcode = NOERROR; 1.2086 + ancount = 0; 1.2087 + 1.2088 + for (t = target; t; t = t->next) { 1.2089 + int class, type; 1.2090 + u_char *answer; 1.2091 + int anslen; 1.2092 + 1.2093 + hp = (HEADER *)(void *)t->answer; 1.2094 + hp->rcode = NOERROR; /* default */ 1.2095 + 1.2096 + /* make it easier... */ 1.2097 + class = t->qclass; 1.2098 + type = t->qtype; 1.2099 + answer = t->answer; 1.2100 + anslen = t->anslen; 1.2101 +#ifdef DEBUG 1.2102 + if (res->options & RES_DEBUG) 1.2103 + printf(";; res_nquery(%s, %d, %d)\n", name, class, type); 1.2104 +#endif 1.2105 + 1.2106 + n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, 1.2107 + buf, sizeof(buf)); 1.2108 +#ifdef RES_USE_EDNS0 1.2109 + if (n > 0 && (res->options & RES_USE_EDNS0) != 0) 1.2110 + n = res_nopt(res, n, buf, sizeof(buf), anslen); 1.2111 +#endif 1.2112 + if (n <= 0) { 1.2113 +#ifdef DEBUG 1.2114 + if (res->options & RES_DEBUG) 1.2115 + printf(";; res_nquery: mkquery failed\n"); 1.2116 +#endif 1.2117 + h_errno = NO_RECOVERY; 1.2118 + return n; 1.2119 + } 1.2120 + n = res_nsend(res, buf, n, answer, anslen); 1.2121 +#if 0 1.2122 + if (n < 0) { 1.2123 +#ifdef DEBUG 1.2124 + if (res->options & RES_DEBUG) 1.2125 + printf(";; res_query: send error\n"); 1.2126 +#endif 1.2127 + h_errno = TRY_AGAIN; 1.2128 + return n; 1.2129 + } 1.2130 +#endif 1.2131 + 1.2132 + if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 1.2133 + rcode = hp->rcode; /* record most recent error */ 1.2134 +#ifdef DEBUG 1.2135 + if (res->options & RES_DEBUG) 1.2136 + printf(";; rcode = %u, ancount=%u\n", hp->rcode, 1.2137 + ntohs(hp->ancount)); 1.2138 +#endif 1.2139 + continue; 1.2140 + } 1.2141 + 1.2142 + ancount += ntohs(hp->ancount); 1.2143 + 1.2144 + t->n = n; 1.2145 + } 1.2146 + 1.2147 + if (ancount == 0) { 1.2148 + switch (rcode) { 1.2149 + case NXDOMAIN: 1.2150 + h_errno = HOST_NOT_FOUND; 1.2151 + break; 1.2152 + case SERVFAIL: 1.2153 + h_errno = TRY_AGAIN; 1.2154 + break; 1.2155 + case NOERROR: 1.2156 + h_errno = NO_DATA; 1.2157 + break; 1.2158 + case FORMERR: 1.2159 + case NOTIMP: 1.2160 + case REFUSED: 1.2161 + default: 1.2162 + h_errno = NO_RECOVERY; 1.2163 + break; 1.2164 + } 1.2165 + return -1; 1.2166 + } 1.2167 + return ancount; 1.2168 +} 1.2169 + 1.2170 +/* 1.2171 + * Formulate a normal query, send, and retrieve answer in supplied buffer. 1.2172 + * Return the size of the response on success, -1 on error. 1.2173 + * If enabled, implement search rules until answer or unrecoverable failure 1.2174 + * is detected. Error code, if any, is left in h_errno. 1.2175 + */ 1.2176 +static int 1.2177 +res_searchN(const char *name, struct res_target *target, res_state res) 1.2178 +{ 1.2179 + const char *cp, * const *domain; 1.2180 + HEADER *hp; 1.2181 + u_int dots; 1.2182 + int trailing_dot, ret, saved_herrno; 1.2183 + int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 1.2184 + 1.2185 + assert(name != NULL); 1.2186 + assert(target != NULL); 1.2187 + 1.2188 + hp = (HEADER *)(void *)target->answer; /*XXX*/ 1.2189 + 1.2190 + errno = 0; 1.2191 + h_errno = HOST_NOT_FOUND; /* default, if we never query */ 1.2192 + dots = 0; 1.2193 + for (cp = name; *cp; cp++) 1.2194 + dots += (*cp == '.'); 1.2195 + trailing_dot = 0; 1.2196 + if (cp > name && *--cp == '.') 1.2197 + trailing_dot++; 1.2198 + 1.2199 + 1.2200 + //fprintf(stderr, "res_searchN() name = '%s'\n", name); 1.2201 + 1.2202 + /* 1.2203 + * if there aren't any dots, it could be a user-level alias 1.2204 + */ 1.2205 + if (!dots && (cp = __hostalias(name)) != NULL) { 1.2206 + ret = res_queryN(cp, target, res); 1.2207 + return ret; 1.2208 + } 1.2209 + 1.2210 + /* 1.2211 + * If there are dots in the name already, let's just give it a try 1.2212 + * 'as is'. The threshold can be set with the "ndots" option. 1.2213 + */ 1.2214 + saved_herrno = -1; 1.2215 + if (dots >= res->ndots) { 1.2216 + ret = res_querydomainN(name, NULL, target, res); 1.2217 + if (ret > 0) 1.2218 + return (ret); 1.2219 + saved_herrno = h_errno; 1.2220 + tried_as_is++; 1.2221 + } 1.2222 + 1.2223 + /* 1.2224 + * We do at least one level of search if 1.2225 + * - there is no dot and RES_DEFNAME is set, or 1.2226 + * - there is at least one dot, there is no trailing dot, 1.2227 + * and RES_DNSRCH is set. 1.2228 + */ 1.2229 + if ((!dots && (res->options & RES_DEFNAMES)) || 1.2230 + (dots && !trailing_dot && (res->options & RES_DNSRCH))) { 1.2231 + int done = 0; 1.2232 + 1.2233 + for (domain = (const char * const *)res->dnsrch; 1.2234 + *domain && !done; 1.2235 + domain++) { 1.2236 + 1.2237 + ret = res_querydomainN(name, *domain, target, res); 1.2238 + if (ret > 0) 1.2239 + return ret; 1.2240 + 1.2241 + /* 1.2242 + * If no server present, give up. 1.2243 + * If name isn't found in this domain, 1.2244 + * keep trying higher domains in the search list 1.2245 + * (if that's enabled). 1.2246 + * On a NO_DATA error, keep trying, otherwise 1.2247 + * a wildcard entry of another type could keep us 1.2248 + * from finding this entry higher in the domain. 1.2249 + * If we get some other error (negative answer or 1.2250 + * server failure), then stop searching up, 1.2251 + * but try the input name below in case it's 1.2252 + * fully-qualified. 1.2253 + */ 1.2254 + if (errno == ECONNREFUSED) { 1.2255 + h_errno = TRY_AGAIN; 1.2256 + return -1; 1.2257 + } 1.2258 + 1.2259 + switch (h_errno) { 1.2260 + case NO_DATA: 1.2261 + got_nodata++; 1.2262 + /* FALLTHROUGH */ 1.2263 + case HOST_NOT_FOUND: 1.2264 + /* keep trying */ 1.2265 + break; 1.2266 + case TRY_AGAIN: 1.2267 + if (hp->rcode == SERVFAIL) { 1.2268 + /* try next search element, if any */ 1.2269 + got_servfail++; 1.2270 + break; 1.2271 + } 1.2272 + /* FALLTHROUGH */ 1.2273 + default: 1.2274 + /* anything else implies that we're done */ 1.2275 + done++; 1.2276 + } 1.2277 + /* 1.2278 + * if we got here for some reason other than DNSRCH, 1.2279 + * we only wanted one iteration of the loop, so stop. 1.2280 + */ 1.2281 + if (!(res->options & RES_DNSRCH)) 1.2282 + done++; 1.2283 + } 1.2284 + } 1.2285 + 1.2286 + /* 1.2287 + * if we have not already tried the name "as is", do that now. 1.2288 + * note that we do this regardless of how many dots were in the 1.2289 + * name or whether it ends with a dot. 1.2290 + */ 1.2291 + if (!tried_as_is) { 1.2292 + ret = res_querydomainN(name, NULL, target, res); 1.2293 + if (ret > 0) 1.2294 + return ret; 1.2295 + } 1.2296 + 1.2297 + /* 1.2298 + * if we got here, we didn't satisfy the search. 1.2299 + * if we did an initial full query, return that query's h_errno 1.2300 + * (note that we wouldn't be here if that query had succeeded). 1.2301 + * else if we ever got a nodata, send that back as the reason. 1.2302 + * else send back meaningless h_errno, that being the one from 1.2303 + * the last DNSRCH we did. 1.2304 + */ 1.2305 + if (saved_herrno != -1) 1.2306 + h_errno = saved_herrno; 1.2307 + else if (got_nodata) 1.2308 + h_errno = NO_DATA; 1.2309 + else if (got_servfail) 1.2310 + h_errno = TRY_AGAIN; 1.2311 + return -1; 1.2312 +} 1.2313 + 1.2314 +/* 1.2315 + * Perform a call on res_query on the concatenation of name and domain, 1.2316 + * removing a trailing dot from name if domain is NULL. 1.2317 + */ 1.2318 +static int 1.2319 +res_querydomainN(const char *name, const char *domain, 1.2320 + struct res_target *target, res_state res) 1.2321 +{ 1.2322 + char nbuf[MAXDNAME]; 1.2323 + const char *longname = nbuf; 1.2324 + size_t n, d; 1.2325 + 1.2326 + assert(name != NULL); 1.2327 + /* XXX: target may be NULL??? */ 1.2328 + 1.2329 +#ifdef DEBUG 1.2330 + if (res->options & RES_DEBUG) 1.2331 + printf(";; res_querydomain(%s, %s)\n", 1.2332 + name, domain?domain:"<Nil>"); 1.2333 +#endif 1.2334 + if (domain == NULL) { 1.2335 + /* 1.2336 + * Check for trailing '.'; 1.2337 + * copy without '.' if present. 1.2338 + */ 1.2339 + n = strlen(name); 1.2340 + if (n + 1 > sizeof(nbuf)) { 1.2341 + h_errno = NO_RECOVERY; 1.2342 + return -1; 1.2343 + } 1.2344 + if (n > 0 && name[--n] == '.') { 1.2345 + strncpy(nbuf, name, n); 1.2346 + nbuf[n] = '\0'; 1.2347 + } else 1.2348 + longname = name; 1.2349 + } else { 1.2350 + n = strlen(name); 1.2351 + d = strlen(domain); 1.2352 + if (n + 1 + d + 1 > sizeof(nbuf)) { 1.2353 + h_errno = NO_RECOVERY; 1.2354 + return -1; 1.2355 + } 1.2356 + snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); 1.2357 + } 1.2358 + return res_queryN(longname, target, res); 1.2359 +}