other-licenses/android/getaddrinfo.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */
michael@0 2 /* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */
michael@0 3
michael@0 4 /*
michael@0 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
michael@0 6 * All rights reserved.
michael@0 7 *
michael@0 8 * Redistribution and use in source and binary forms, with or without
michael@0 9 * modification, are permitted provided that the following conditions
michael@0 10 * are met:
michael@0 11 * 1. Redistributions of source code must retain the above copyright
michael@0 12 * notice, this list of conditions and the following disclaimer.
michael@0 13 * 2. Redistributions in binary form must reproduce the above copyright
michael@0 14 * notice, this list of conditions and the following disclaimer in the
michael@0 15 * documentation and/or other materials provided with the distribution.
michael@0 16 * 3. Neither the name of the project nor the names of its contributors
michael@0 17 * may be used to endorse or promote products derived from this software
michael@0 18 * without specific prior written permission.
michael@0 19 *
michael@0 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
michael@0 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
michael@0 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
michael@0 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
michael@0 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
michael@0 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
michael@0 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
michael@0 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
michael@0 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
michael@0 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@0 30 * SUCH DAMAGE.
michael@0 31 */
michael@0 32
michael@0 33 /*
michael@0 34 * This version of getaddrinfo.c is derived from Android 2.3 "Gingerbread",
michael@0 35 * which contains uncredited changes by Android/Google developers. It has
michael@0 36 * been modified in 2011 for use in the Android build of Mozilla Firefox by
michael@0 37 * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>,
michael@0 38 * and Steve Workman <sjhworkman@gmail.com>).
michael@0 39 * These changes are offered under the same license as the original NetBSD
michael@0 40 * file, whose copyright and license are unchanged above.
michael@0 41 */
michael@0 42 #define ANDROID_CHANGES 1
michael@0 43 #define INET6 1
michael@0 44
michael@0 45 /*
michael@0 46 * Issues to be discussed:
michael@0 47 * - Return values. There are nonstandard return values defined and used
michael@0 48 * in the source code. This is because RFC2553 is silent about which error
michael@0 49 * code must be returned for which situation.
michael@0 50 * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
michael@0 51 * says to use inet_aton() to convert IPv4 numeric to binary (alows
michael@0 52 * classful form as a result).
michael@0 53 * current code - disallow classful form for IPv4 (due to use of inet_pton).
michael@0 54 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
michael@0 55 * invalid.
michael@0 56 * current code - SEGV on freeaddrinfo(NULL)
michael@0 57 * Note:
michael@0 58 * - We use getipnodebyname() just for thread-safeness. There's no intent
michael@0 59 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
michael@0 60 * getipnodebyname().
michael@0 61 * - MOZILLA: Thread safeness for pre-Honeycomb Android versions implemented by
michael@0 62 * way of open/gets/close and mmap rather than fopen/fgets/fclose. Affects
michael@0 63 * _files_getaddrinfo for hosts file. Note: Honeycomb and later versions use
michael@0 64 * a thread-safe stdio, so for those versions normal Bionic libc getaddrinfo
michael@0 65 * is used.
michael@0 66 * - The code filters out AFs that are not supported by the kernel,
michael@0 67 * when globbing NULL hostname (to loopback, or wildcard). Is it the right
michael@0 68 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
michael@0 69 * in ai_flags?
michael@0 70 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
michael@0 71 * (1) what should we do against numeric hostname (2) what should we do
michael@0 72 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
michael@0 73 * non-loopback address configured? global address configured?
michael@0 74 * - To avoid search order issue, we have a big amount of code duplicate
michael@0 75 * from gethnamaddr.c and some other places. The issues that there's no
michael@0 76 * lower layer function to lookup "IPv4 or IPv6" record. Calling
michael@0 77 * gethostbyname2 from getaddrinfo will end up in wrong search order, as
michael@0 78 * follows:
michael@0 79 * - The code makes use of following calls when asked to resolver with
michael@0 80 * ai_family = PF_UNSPEC:
michael@0 81 * getipnodebyname(host, AF_INET6);
michael@0 82 * getipnodebyname(host, AF_INET);
michael@0 83 * This will result in the following queries if the node is configure to
michael@0 84 * prefer /etc/hosts than DNS:
michael@0 85 * lookup /etc/hosts for IPv6 address
michael@0 86 * lookup DNS for IPv6 address
michael@0 87 * lookup /etc/hosts for IPv4 address
michael@0 88 * lookup DNS for IPv4 address
michael@0 89 * which may not meet people's requirement.
michael@0 90 * The right thing to happen is to have underlying layer which does
michael@0 91 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
michael@0 92 * This would result in a bit of code duplicate with _dns_ghbyname() and
michael@0 93 * friends.
michael@0 94 */
michael@0 95
michael@0 96 #include <fcntl.h>
michael@0 97 #include <sys/cdefs.h>
michael@0 98 #include <sys/types.h>
michael@0 99 #include <sys/stat.h>
michael@0 100 #include <sys/param.h>
michael@0 101 #include <sys/socket.h>
michael@0 102 #include <sys/un.h>
michael@0 103 #include <sys/mman.h>
michael@0 104 #include <net/if.h>
michael@0 105 #include <netinet/in.h>
michael@0 106 #include <arpa/inet.h>
michael@0 107 #include "arpa_nameser.h"
michael@0 108 #include <assert.h>
michael@0 109 #include <ctype.h>
michael@0 110 #include <errno.h>
michael@0 111 #include <netdb.h>
michael@0 112 #include "resolv_private.h"
michael@0 113 #include <stddef.h>
michael@0 114 #include <stdlib.h>
michael@0 115 #include <string.h>
michael@0 116 #include <unistd.h>
michael@0 117
michael@0 118 #include <syslog.h>
michael@0 119 #include <stdarg.h>
michael@0 120 #include "nsswitch.h"
michael@0 121
michael@0 122 #ifdef MOZ_GETADDRINFO_LOG_VERBOSE
michael@0 123 #include <android/log.h>
michael@0 124 #endif
michael@0 125
michael@0 126 #ifdef ANDROID_CHANGES
michael@0 127 #include <sys/system_properties.h>
michael@0 128 #endif /* ANDROID_CHANGES */
michael@0 129
michael@0 130 typedef struct _pseudo_FILE {
michael@0 131 int fd;
michael@0 132 off_t maplen;
michael@0 133 void* mapping;
michael@0 134 off_t offset;
michael@0 135 } _pseudo_FILE;
michael@0 136
michael@0 137 #define _PSEUDO_FILE_INITIALIZER { -1, 0, MAP_FAILED, 0 }
michael@0 138
michael@0 139 static void
michael@0 140 _pseudo_fclose(_pseudo_FILE * __restrict__ fp)
michael@0 141 {
michael@0 142 assert(fp);
michael@0 143 fp->offset = 0;
michael@0 144 if (fp->mapping != MAP_FAILED) {
michael@0 145 (void) munmap(fp->mapping, fp->maplen);
michael@0 146 fp->mapping = MAP_FAILED;
michael@0 147 }
michael@0 148 fp->maplen = 0;
michael@0 149 if (fp->fd != -1) {
michael@0 150 (void) close(fp->fd);
michael@0 151 fp->fd = -1;
michael@0 152 }
michael@0 153 }
michael@0 154
michael@0 155 static _pseudo_FILE *
michael@0 156 _pseudo_fopen_r(_pseudo_FILE * __restrict__ fp, const char* fname)
michael@0 157 {
michael@0 158 struct stat statbuf;
michael@0 159 assert(fp);
michael@0 160 fp->fd = open(fname, O_RDONLY);
michael@0 161 if (fp->fd < 0) {
michael@0 162 fp->fd = -1;
michael@0 163 return NULL;
michael@0 164 }
michael@0 165 if ((0 != fstat(fp->fd, &statbuf)) || (statbuf.st_size <= 0)) {
michael@0 166 close(fp->fd);
michael@0 167 fp->fd = -1;
michael@0 168 return NULL;
michael@0 169 }
michael@0 170 fp->maplen = statbuf.st_size;
michael@0 171 fp->mapping = mmap(NULL, fp->maplen, PROT_READ, MAP_PRIVATE, fp->fd, 0);
michael@0 172 if (fp->mapping == MAP_FAILED) {
michael@0 173 close(fp->fd);
michael@0 174 fp->fd = -1;
michael@0 175 return NULL;
michael@0 176 }
michael@0 177 fp->offset = 0;
michael@0 178 return fp;
michael@0 179 }
michael@0 180
michael@0 181 static void
michael@0 182 _pseudo_rewind(_pseudo_FILE * __restrict__ fp)
michael@0 183 {
michael@0 184 assert(fp);
michael@0 185 fp->offset = 0;
michael@0 186 }
michael@0 187
michael@0 188 static char*
michael@0 189 _pseudo_fgets(char* buf, int bufsize, _pseudo_FILE * __restrict__ fp)
michael@0 190 {
michael@0 191 char* current;
michael@0 192 char* endp;
michael@0 193 int maxcopy;
michael@0 194 assert(fp);
michael@0 195 maxcopy = fp->maplen - fp->offset;
michael@0 196 if (fp->mapping == MAP_FAILED)
michael@0 197 return NULL;
michael@0 198 if (maxcopy > bufsize - 1)
michael@0 199 maxcopy = bufsize - 1;
michael@0 200 if (maxcopy <= 0)
michael@0 201 return NULL;
michael@0 202 current = ((char*) fp->mapping) + fp->offset;
michael@0 203 endp = memccpy(buf, current, '\n', maxcopy);
michael@0 204 if (endp)
michael@0 205 maxcopy = endp - buf;
michael@0 206 buf[maxcopy] = '\0';
michael@0 207 fp->offset += maxcopy;
michael@0 208 return buf;
michael@0 209 }
michael@0 210
michael@0 211 typedef union sockaddr_union {
michael@0 212 struct sockaddr generic;
michael@0 213 struct sockaddr_in in;
michael@0 214 struct sockaddr_in6 in6;
michael@0 215 } sockaddr_union;
michael@0 216
michael@0 217 #define SUCCESS 0
michael@0 218 #define ANY 0
michael@0 219 #define YES 1
michael@0 220 #define NO 0
michael@0 221
michael@0 222 static const char in_addrany[] = { 0, 0, 0, 0 };
michael@0 223 static const char in_loopback[] = { 127, 0, 0, 1 };
michael@0 224 #ifdef INET6
michael@0 225 static const char in6_addrany[] = {
michael@0 226 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
michael@0 227 };
michael@0 228 static const char in6_loopback[] = {
michael@0 229 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
michael@0 230 };
michael@0 231 #endif
michael@0 232
michael@0 233 static const struct afd {
michael@0 234 int a_af;
michael@0 235 int a_addrlen;
michael@0 236 int a_socklen;
michael@0 237 int a_off;
michael@0 238 const char *a_addrany;
michael@0 239 const char *a_loopback;
michael@0 240 int a_scoped;
michael@0 241 } afdl [] = {
michael@0 242 #ifdef INET6
michael@0 243 {PF_INET6, sizeof(struct in6_addr),
michael@0 244 sizeof(struct sockaddr_in6),
michael@0 245 offsetof(struct sockaddr_in6, sin6_addr),
michael@0 246 in6_addrany, in6_loopback, 1},
michael@0 247 #endif
michael@0 248 {PF_INET, sizeof(struct in_addr),
michael@0 249 sizeof(struct sockaddr_in),
michael@0 250 offsetof(struct sockaddr_in, sin_addr),
michael@0 251 in_addrany, in_loopback, 0},
michael@0 252 {0, 0, 0, 0, NULL, NULL, 0},
michael@0 253 };
michael@0 254
michael@0 255 struct explore {
michael@0 256 int e_af;
michael@0 257 int e_socktype;
michael@0 258 int e_protocol;
michael@0 259 const char *e_protostr;
michael@0 260 int e_wild;
michael@0 261 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
michael@0 262 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
michael@0 263 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
michael@0 264 };
michael@0 265
michael@0 266 static const struct explore explore[] = {
michael@0 267 #if 0
michael@0 268 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
michael@0 269 #endif
michael@0 270 #ifdef INET6
michael@0 271 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
michael@0 272 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
michael@0 273 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
michael@0 274 #endif
michael@0 275 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
michael@0 276 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
michael@0 277 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
michael@0 278 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
michael@0 279 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
michael@0 280 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
michael@0 281 { -1, 0, 0, NULL, 0 },
michael@0 282 };
michael@0 283
michael@0 284 #ifdef INET6
michael@0 285 #define PTON_MAX 16
michael@0 286 #else
michael@0 287 #define PTON_MAX 4
michael@0 288 #endif
michael@0 289
michael@0 290 static const ns_src default_dns_files[] = {
michael@0 291 { NSSRC_FILES, NS_SUCCESS },
michael@0 292 { NSSRC_DNS, NS_SUCCESS },
michael@0 293 { 0, 0 }
michael@0 294 };
michael@0 295
michael@0 296 #define MAXPACKET (64*1024)
michael@0 297
michael@0 298 typedef union {
michael@0 299 HEADER hdr;
michael@0 300 u_char buf[MAXPACKET];
michael@0 301 } querybuf;
michael@0 302
michael@0 303 struct res_target {
michael@0 304 struct res_target *next;
michael@0 305 const char *name; /* domain name */
michael@0 306 int qclass, qtype; /* class and type of query */
michael@0 307 u_char *answer; /* buffer to put answer */
michael@0 308 int anslen; /* size of answer buffer */
michael@0 309 int n; /* result length */
michael@0 310 };
michael@0 311
michael@0 312 static int str2number(const char *);
michael@0 313 static int explore_fqdn(const struct addrinfo *, const char *,
michael@0 314 const char *, struct addrinfo **);
michael@0 315 static int explore_null(const struct addrinfo *,
michael@0 316 const char *, struct addrinfo **);
michael@0 317 static int explore_numeric(const struct addrinfo *, const char *,
michael@0 318 const char *, struct addrinfo **, const char *);
michael@0 319 static int explore_numeric_scope(const struct addrinfo *, const char *,
michael@0 320 const char *, struct addrinfo **);
michael@0 321 static int get_canonname(const struct addrinfo *,
michael@0 322 struct addrinfo *, const char *);
michael@0 323 static struct addrinfo *get_ai(const struct addrinfo *,
michael@0 324 const struct afd *, const char *);
michael@0 325 static int get_portmatch(const struct addrinfo *, const char *);
michael@0 326 static int get_port(const struct addrinfo *, const char *, int);
michael@0 327 static const struct afd *find_afd(int);
michael@0 328 #ifdef INET6
michael@0 329 static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
michael@0 330 #endif
michael@0 331
michael@0 332 static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
michael@0 333 const struct addrinfo *);
michael@0 334 static int _dns_getaddrinfo(void *, void *, va_list);
michael@0 335 static void _sethtent(_pseudo_FILE * __restrict__);
michael@0 336 static void _endhtent(_pseudo_FILE * __restrict__);
michael@0 337 static struct addrinfo *_gethtent(_pseudo_FILE * __restrict__, const char *,
michael@0 338 const struct addrinfo *);
michael@0 339 static int _files_getaddrinfo(void *, void *, va_list);
michael@0 340
michael@0 341 static int res_queryN(const char *, struct res_target *, res_state);
michael@0 342 static int res_searchN(const char *, struct res_target *, res_state);
michael@0 343 static int res_querydomainN(const char *, const char *,
michael@0 344 struct res_target *, res_state);
michael@0 345
michael@0 346 static const char * const ai_errlist[] = {
michael@0 347 "Success",
michael@0 348 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
michael@0 349 "Temporary failure in name resolution", /* EAI_AGAIN */
michael@0 350 "Invalid value for ai_flags", /* EAI_BADFLAGS */
michael@0 351 "Non-recoverable failure in name resolution", /* EAI_FAIL */
michael@0 352 "ai_family not supported", /* EAI_FAMILY */
michael@0 353 "Memory allocation failure", /* EAI_MEMORY */
michael@0 354 "No address associated with hostname", /* EAI_NODATA */
michael@0 355 "hostname nor servname provided, or not known", /* EAI_NONAME */
michael@0 356 "servname not supported for ai_socktype", /* EAI_SERVICE */
michael@0 357 "ai_socktype not supported", /* EAI_SOCKTYPE */
michael@0 358 "System error returned in errno", /* EAI_SYSTEM */
michael@0 359 "Invalid value for hints", /* EAI_BADHINTS */
michael@0 360 "Resolved protocol is unknown", /* EAI_PROTOCOL */
michael@0 361 "Argument buffer overflow", /* EAI_OVERFLOW */
michael@0 362 "Unknown error", /* EAI_MAX */
michael@0 363 };
michael@0 364
michael@0 365 /* XXX macros that make external reference is BAD. */
michael@0 366
michael@0 367 #define GET_AI(ai, afd, addr) \
michael@0 368 do { \
michael@0 369 /* external reference: pai, error, and label free */ \
michael@0 370 (ai) = get_ai(pai, (afd), (addr)); \
michael@0 371 if ((ai) == NULL) { \
michael@0 372 error = EAI_MEMORY; \
michael@0 373 goto free; \
michael@0 374 } \
michael@0 375 } while (/*CONSTCOND*/0)
michael@0 376
michael@0 377 #define GET_PORT(ai, serv) \
michael@0 378 do { \
michael@0 379 /* external reference: error and label free */ \
michael@0 380 error = get_port((ai), (serv), 0); \
michael@0 381 if (error != 0) \
michael@0 382 goto free; \
michael@0 383 } while (/*CONSTCOND*/0)
michael@0 384
michael@0 385 #define GET_CANONNAME(ai, str) \
michael@0 386 do { \
michael@0 387 /* external reference: pai, error and label free */ \
michael@0 388 error = get_canonname(pai, (ai), (str)); \
michael@0 389 if (error != 0) \
michael@0 390 goto free; \
michael@0 391 } while (/*CONSTCOND*/0)
michael@0 392
michael@0 393 #define ERR(err) \
michael@0 394 do { \
michael@0 395 /* external reference: error, and label bad */ \
michael@0 396 error = (err); \
michael@0 397 goto bad; \
michael@0 398 /*NOTREACHED*/ \
michael@0 399 } while (/*CONSTCOND*/0)
michael@0 400
michael@0 401 #define MATCH_FAMILY(x, y, w) \
michael@0 402 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \
michael@0 403 (y) == PF_UNSPEC)))
michael@0 404 #define MATCH(x, y, w) \
michael@0 405 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
michael@0 406
michael@0 407 #pragma GCC visibility push(default)
michael@0 408
michael@0 409 extern const char *
michael@0 410 __wrap_gai_strerror(int ecode);
michael@0 411 extern void
michael@0 412 __wrap_freeaddrinfo(struct addrinfo *ai);
michael@0 413 extern int
michael@0 414 __wrap_getaddrinfo(const char *hostname, const char *servname,
michael@0 415 const struct addrinfo *hints, struct addrinfo **res);
michael@0 416
michael@0 417 int android_sdk_version;
michael@0 418
michael@0 419 #pragma GCC visibility pop
michael@0 420
michael@0 421 int android_sdk_version = -1;
michael@0 422
michael@0 423 static int honeycomb_or_later()
michael@0 424 {
michael@0 425 #ifdef MOZ_GETADDRINFO_LOG_VERBOSE
michael@0 426 __android_log_print(ANDROID_LOG_INFO, "getaddrinfo",
michael@0 427 "I am%s Honeycomb\n",
michael@0 428 (android_sdk_version >= 11) ? "" : " not");
michael@0 429 #endif
michael@0 430 return android_sdk_version >= 11;
michael@0 431 }
michael@0 432
michael@0 433 const char *
michael@0 434 __wrap_gai_strerror(int ecode)
michael@0 435 {
michael@0 436 if (honeycomb_or_later())
michael@0 437 return gai_strerror(ecode);
michael@0 438 if (ecode < 0 || ecode > EAI_MAX)
michael@0 439 ecode = EAI_MAX;
michael@0 440 return ai_errlist[ecode];
michael@0 441 }
michael@0 442
michael@0 443 void
michael@0 444 __wrap_freeaddrinfo(struct addrinfo *ai)
michael@0 445 {
michael@0 446 struct addrinfo *next;
michael@0 447
michael@0 448 if (honeycomb_or_later()) {
michael@0 449 freeaddrinfo(ai);
michael@0 450 return;
michael@0 451 }
michael@0 452
michael@0 453 assert(ai != NULL);
michael@0 454
michael@0 455 do {
michael@0 456 next = ai->ai_next;
michael@0 457 if (ai->ai_canonname)
michael@0 458 free(ai->ai_canonname);
michael@0 459 /* no need to free(ai->ai_addr) */
michael@0 460 free(ai);
michael@0 461 ai = next;
michael@0 462 } while (ai);
michael@0 463 }
michael@0 464
michael@0 465 static int
michael@0 466 str2number(const char *p)
michael@0 467 {
michael@0 468 char *ep;
michael@0 469 unsigned long v;
michael@0 470
michael@0 471 assert(p != NULL);
michael@0 472
michael@0 473 if (*p == '\0')
michael@0 474 return -1;
michael@0 475 ep = NULL;
michael@0 476 errno = 0;
michael@0 477 v = strtoul(p, &ep, 10);
michael@0 478 if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX)
michael@0 479 return v;
michael@0 480 else
michael@0 481 return -1;
michael@0 482 }
michael@0 483
michael@0 484 /*
michael@0 485 * Connect a UDP socket to a given unicast address. This will cause no network
michael@0 486 * traffic, but will fail fast if the system has no or limited reachability to
michael@0 487 * the destination (e.g., no IPv4 address, no IPv6 default route, ...).
michael@0 488 */
michael@0 489 static int
michael@0 490 _test_connect(int pf, struct sockaddr *addr, size_t addrlen) {
michael@0 491 int s = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
michael@0 492 if (s < 0)
michael@0 493 return 0;
michael@0 494 int ret;
michael@0 495 do {
michael@0 496 ret = connect(s, addr, addrlen);
michael@0 497 } while (ret < 0 && errno == EINTR);
michael@0 498 int success = (ret == 0);
michael@0 499 do {
michael@0 500 ret = close(s);
michael@0 501 } while (ret < 0 && errno == EINTR);
michael@0 502 return success;
michael@0 503 }
michael@0 504
michael@0 505 /*
michael@0 506 * The following functions determine whether IPv4 or IPv6 connectivity is
michael@0 507 * available in order to implement AI_ADDRCONFIG.
michael@0 508 *
michael@0 509 * Strictly speaking, AI_ADDRCONFIG should not look at whether connectivity is
michael@0 510 * available, but whether addresses of the specified family are "configured
michael@0 511 * on the local system". However, bionic doesn't currently support getifaddrs,
michael@0 512 * so checking for connectivity is the next best thing.
michael@0 513 */
michael@0 514 static int
michael@0 515 _have_ipv6() {
michael@0 516 static const struct sockaddr_in6 sin6_test = {
michael@0 517 .sin6_family = AF_INET6,
michael@0 518 .sin6_addr.s6_addr = { // 2000::
michael@0 519 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
michael@0 520 };
michael@0 521 sockaddr_union addr = { .in6 = sin6_test };
michael@0 522 return _test_connect(PF_INET6, &addr.generic, sizeof(addr.in6));
michael@0 523 }
michael@0 524
michael@0 525 static int
michael@0 526 _have_ipv4() {
michael@0 527 static const struct sockaddr_in sin_test = {
michael@0 528 .sin_family = AF_INET,
michael@0 529 .sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8
michael@0 530 };
michael@0 531 sockaddr_union addr = { .in = sin_test };
michael@0 532 return _test_connect(PF_INET, &addr.generic, sizeof(addr.in));
michael@0 533 }
michael@0 534
michael@0 535 int
michael@0 536 __wrap_getaddrinfo(const char *hostname, const char *servname,
michael@0 537 const struct addrinfo *hints, struct addrinfo **res)
michael@0 538 {
michael@0 539 struct addrinfo sentinel;
michael@0 540 struct addrinfo *cur;
michael@0 541 int error = 0;
michael@0 542 struct addrinfo ai;
michael@0 543 struct addrinfo ai0;
michael@0 544 struct addrinfo *pai;
michael@0 545 const struct explore *ex;
michael@0 546
michael@0 547 if (honeycomb_or_later())
michael@0 548 return getaddrinfo(hostname, servname, hints, res);
michael@0 549
michael@0 550 /* hostname is allowed to be NULL */
michael@0 551 /* servname is allowed to be NULL */
michael@0 552 /* hints is allowed to be NULL */
michael@0 553 assert(res != NULL);
michael@0 554
michael@0 555 memset(&sentinel, 0, sizeof(sentinel));
michael@0 556 cur = &sentinel;
michael@0 557 pai = &ai;
michael@0 558 pai->ai_flags = 0;
michael@0 559 pai->ai_family = PF_UNSPEC;
michael@0 560 pai->ai_socktype = ANY;
michael@0 561 pai->ai_protocol = ANY;
michael@0 562 pai->ai_addrlen = 0;
michael@0 563 pai->ai_canonname = NULL;
michael@0 564 pai->ai_addr = NULL;
michael@0 565 pai->ai_next = NULL;
michael@0 566
michael@0 567 if (hostname == NULL && servname == NULL)
michael@0 568 return EAI_NONAME;
michael@0 569 if (hints) {
michael@0 570 /* error check for hints */
michael@0 571 if (hints->ai_addrlen || hints->ai_canonname ||
michael@0 572 hints->ai_addr || hints->ai_next)
michael@0 573 ERR(EAI_BADHINTS); /* xxx */
michael@0 574 if (hints->ai_flags & ~AI_MASK)
michael@0 575 ERR(EAI_BADFLAGS);
michael@0 576 switch (hints->ai_family) {
michael@0 577 case PF_UNSPEC:
michael@0 578 case PF_INET:
michael@0 579 #ifdef INET6
michael@0 580 case PF_INET6:
michael@0 581 #endif
michael@0 582 break;
michael@0 583 default:
michael@0 584 ERR(EAI_FAMILY);
michael@0 585 }
michael@0 586 memcpy(pai, hints, sizeof(*pai));
michael@0 587
michael@0 588 /*
michael@0 589 * if both socktype/protocol are specified, check if they
michael@0 590 * are meaningful combination.
michael@0 591 */
michael@0 592 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
michael@0 593 for (ex = explore; ex->e_af >= 0; ex++) {
michael@0 594 if (pai->ai_family != ex->e_af)
michael@0 595 continue;
michael@0 596 if (ex->e_socktype == ANY)
michael@0 597 continue;
michael@0 598 if (ex->e_protocol == ANY)
michael@0 599 continue;
michael@0 600 if (pai->ai_socktype == ex->e_socktype
michael@0 601 && pai->ai_protocol != ex->e_protocol) {
michael@0 602 ERR(EAI_BADHINTS);
michael@0 603 }
michael@0 604 }
michael@0 605 }
michael@0 606 }
michael@0 607
michael@0 608 /*
michael@0 609 * check for special cases. (1) numeric servname is disallowed if
michael@0 610 * socktype/protocol are left unspecified. (2) servname is disallowed
michael@0 611 * for raw and other inet{,6} sockets.
michael@0 612 */
michael@0 613 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
michael@0 614 #ifdef PF_INET6
michael@0 615 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
michael@0 616 #endif
michael@0 617 ) {
michael@0 618 ai0 = *pai; /* backup *pai */
michael@0 619
michael@0 620 if (pai->ai_family == PF_UNSPEC) {
michael@0 621 #ifdef PF_INET6
michael@0 622 pai->ai_family = PF_INET6;
michael@0 623 #else
michael@0 624 pai->ai_family = PF_INET;
michael@0 625 #endif
michael@0 626 }
michael@0 627 error = get_portmatch(pai, servname);
michael@0 628 if (error)
michael@0 629 ERR(error);
michael@0 630
michael@0 631 *pai = ai0;
michael@0 632 }
michael@0 633
michael@0 634 ai0 = *pai;
michael@0 635
michael@0 636 /* NULL hostname, or numeric hostname */
michael@0 637 for (ex = explore; ex->e_af >= 0; ex++) {
michael@0 638 *pai = ai0;
michael@0 639
michael@0 640 /* PF_UNSPEC entries are prepared for DNS queries only */
michael@0 641 if (ex->e_af == PF_UNSPEC)
michael@0 642 continue;
michael@0 643
michael@0 644 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
michael@0 645 continue;
michael@0 646 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
michael@0 647 continue;
michael@0 648 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
michael@0 649 continue;
michael@0 650
michael@0 651 if (pai->ai_family == PF_UNSPEC)
michael@0 652 pai->ai_family = ex->e_af;
michael@0 653 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
michael@0 654 pai->ai_socktype = ex->e_socktype;
michael@0 655 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
michael@0 656 pai->ai_protocol = ex->e_protocol;
michael@0 657
michael@0 658 if (hostname == NULL)
michael@0 659 error = explore_null(pai, servname, &cur->ai_next);
michael@0 660 else
michael@0 661 error = explore_numeric_scope(pai, hostname, servname,
michael@0 662 &cur->ai_next);
michael@0 663
michael@0 664 if (error)
michael@0 665 goto free;
michael@0 666
michael@0 667 while (cur->ai_next)
michael@0 668 cur = cur->ai_next;
michael@0 669 }
michael@0 670
michael@0 671 /*
michael@0 672 * XXX
michael@0 673 * If numeric representation of AF1 can be interpreted as FQDN
michael@0 674 * representation of AF2, we need to think again about the code below.
michael@0 675 */
michael@0 676 if (sentinel.ai_next)
michael@0 677 goto good;
michael@0 678
michael@0 679 if (hostname == NULL)
michael@0 680 ERR(EAI_NODATA);
michael@0 681 if (pai->ai_flags & AI_NUMERICHOST)
michael@0 682 ERR(EAI_NONAME);
michael@0 683
michael@0 684 /*
michael@0 685 * hostname as alphabetical name.
michael@0 686 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
michael@0 687 * outer loop by AFs.
michael@0 688 */
michael@0 689 for (ex = explore; ex->e_af >= 0; ex++) {
michael@0 690 *pai = ai0;
michael@0 691
michael@0 692 /* require exact match for family field */
michael@0 693 if (pai->ai_family != ex->e_af)
michael@0 694 continue;
michael@0 695
michael@0 696 if (!MATCH(pai->ai_socktype, ex->e_socktype,
michael@0 697 WILD_SOCKTYPE(ex))) {
michael@0 698 continue;
michael@0 699 }
michael@0 700 if (!MATCH(pai->ai_protocol, ex->e_protocol,
michael@0 701 WILD_PROTOCOL(ex))) {
michael@0 702 continue;
michael@0 703 }
michael@0 704
michael@0 705 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
michael@0 706 pai->ai_socktype = ex->e_socktype;
michael@0 707 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
michael@0 708 pai->ai_protocol = ex->e_protocol;
michael@0 709
michael@0 710 error = explore_fqdn(pai, hostname, servname,
michael@0 711 &cur->ai_next);
michael@0 712
michael@0 713 while (cur && cur->ai_next)
michael@0 714 cur = cur->ai_next;
michael@0 715 }
michael@0 716
michael@0 717 /* XXX */
michael@0 718 if (sentinel.ai_next)
michael@0 719 error = 0;
michael@0 720
michael@0 721 if (error)
michael@0 722 goto free;
michael@0 723 if (error == 0) {
michael@0 724 if (sentinel.ai_next) {
michael@0 725 good:
michael@0 726 *res = sentinel.ai_next;
michael@0 727 return SUCCESS;
michael@0 728 } else
michael@0 729 error = EAI_FAIL;
michael@0 730 }
michael@0 731 free:
michael@0 732 bad:
michael@0 733 if (sentinel.ai_next)
michael@0 734 __wrap_freeaddrinfo(sentinel.ai_next);
michael@0 735 *res = NULL;
michael@0 736 return error;
michael@0 737 }
michael@0 738
michael@0 739 /*
michael@0 740 * FQDN hostname, DNS lookup
michael@0 741 */
michael@0 742 static int
michael@0 743 explore_fqdn(const struct addrinfo *pai, const char *hostname,
michael@0 744 const char *servname, struct addrinfo **res)
michael@0 745 {
michael@0 746 struct addrinfo *result;
michael@0 747 struct addrinfo *cur;
michael@0 748 int error = 0;
michael@0 749 static const ns_dtab dtab[] = {
michael@0 750 NS_FILES_CB(_files_getaddrinfo, NULL)
michael@0 751 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
michael@0 752 NS_NIS_CB(_yp_getaddrinfo, NULL)
michael@0 753 { 0, 0, 0 }
michael@0 754 };
michael@0 755
michael@0 756 assert(pai != NULL);
michael@0 757 /* hostname may be NULL */
michael@0 758 /* servname may be NULL */
michael@0 759 assert(res != NULL);
michael@0 760
michael@0 761 result = NULL;
michael@0 762
michael@0 763 /*
michael@0 764 * if the servname does not match socktype/protocol, ignore it.
michael@0 765 */
michael@0 766 if (get_portmatch(pai, servname) != 0)
michael@0 767 return 0;
michael@0 768
michael@0 769 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
michael@0 770 default_dns_files, hostname, pai)) {
michael@0 771 case NS_TRYAGAIN:
michael@0 772 error = EAI_AGAIN;
michael@0 773 goto free;
michael@0 774 case NS_UNAVAIL:
michael@0 775 error = EAI_FAIL;
michael@0 776 goto free;
michael@0 777 case NS_NOTFOUND:
michael@0 778 error = EAI_NODATA;
michael@0 779 goto free;
michael@0 780 case NS_SUCCESS:
michael@0 781 error = 0;
michael@0 782 for (cur = result; cur; cur = cur->ai_next) {
michael@0 783 GET_PORT(cur, servname);
michael@0 784 /* canonname should be filled already */
michael@0 785 }
michael@0 786 break;
michael@0 787 }
michael@0 788
michael@0 789 *res = result;
michael@0 790
michael@0 791 return 0;
michael@0 792
michael@0 793 free:
michael@0 794 if (result)
michael@0 795 __wrap_freeaddrinfo(result);
michael@0 796 return error;
michael@0 797 }
michael@0 798
michael@0 799 /*
michael@0 800 * hostname == NULL.
michael@0 801 * passive socket -> anyaddr (0.0.0.0 or ::)
michael@0 802 * non-passive socket -> localhost (127.0.0.1 or ::1)
michael@0 803 */
michael@0 804 static int
michael@0 805 explore_null(const struct addrinfo *pai, const char *servname,
michael@0 806 struct addrinfo **res)
michael@0 807 {
michael@0 808 int s;
michael@0 809 const struct afd *afd;
michael@0 810 struct addrinfo *cur;
michael@0 811 struct addrinfo sentinel;
michael@0 812 int error;
michael@0 813
michael@0 814 assert(pai != NULL);
michael@0 815 /* servname may be NULL */
michael@0 816 assert(res != NULL);
michael@0 817
michael@0 818 *res = NULL;
michael@0 819 sentinel.ai_next = NULL;
michael@0 820 cur = &sentinel;
michael@0 821
michael@0 822 /*
michael@0 823 * filter out AFs that are not supported by the kernel
michael@0 824 * XXX errno?
michael@0 825 */
michael@0 826 s = socket(pai->ai_family, SOCK_DGRAM, 0);
michael@0 827 if (s < 0) {
michael@0 828 if (errno != EMFILE)
michael@0 829 return 0;
michael@0 830 } else
michael@0 831 close(s);
michael@0 832
michael@0 833 /*
michael@0 834 * if the servname does not match socktype/protocol, ignore it.
michael@0 835 */
michael@0 836 if (get_portmatch(pai, servname) != 0)
michael@0 837 return 0;
michael@0 838
michael@0 839 afd = find_afd(pai->ai_family);
michael@0 840 if (afd == NULL)
michael@0 841 return 0;
michael@0 842
michael@0 843 if (pai->ai_flags & AI_PASSIVE) {
michael@0 844 GET_AI(cur->ai_next, afd, afd->a_addrany);
michael@0 845 /* xxx meaningless?
michael@0 846 * GET_CANONNAME(cur->ai_next, "anyaddr");
michael@0 847 */
michael@0 848 GET_PORT(cur->ai_next, servname);
michael@0 849 } else {
michael@0 850 GET_AI(cur->ai_next, afd, afd->a_loopback);
michael@0 851 /* xxx meaningless?
michael@0 852 * GET_CANONNAME(cur->ai_next, "localhost");
michael@0 853 */
michael@0 854 GET_PORT(cur->ai_next, servname);
michael@0 855 }
michael@0 856 cur = cur->ai_next;
michael@0 857
michael@0 858 *res = sentinel.ai_next;
michael@0 859 return 0;
michael@0 860
michael@0 861 free:
michael@0 862 if (sentinel.ai_next)
michael@0 863 __wrap_freeaddrinfo(sentinel.ai_next);
michael@0 864 return error;
michael@0 865 }
michael@0 866
michael@0 867 /*
michael@0 868 * numeric hostname
michael@0 869 */
michael@0 870 static int
michael@0 871 explore_numeric(const struct addrinfo *pai, const char *hostname,
michael@0 872 const char *servname, struct addrinfo **res, const char *canonname)
michael@0 873 {
michael@0 874 const struct afd *afd;
michael@0 875 struct addrinfo *cur;
michael@0 876 struct addrinfo sentinel;
michael@0 877 int error;
michael@0 878 char pton[PTON_MAX];
michael@0 879
michael@0 880 assert(pai != NULL);
michael@0 881 /* hostname may be NULL */
michael@0 882 /* servname may be NULL */
michael@0 883 assert(res != NULL);
michael@0 884
michael@0 885 *res = NULL;
michael@0 886 sentinel.ai_next = NULL;
michael@0 887 cur = &sentinel;
michael@0 888
michael@0 889 /*
michael@0 890 * if the servname does not match socktype/protocol, ignore it.
michael@0 891 */
michael@0 892 if (get_portmatch(pai, servname) != 0)
michael@0 893 return 0;
michael@0 894
michael@0 895 afd = find_afd(pai->ai_family);
michael@0 896 if (afd == NULL)
michael@0 897 return 0;
michael@0 898
michael@0 899 switch (afd->a_af) {
michael@0 900 #if 0 /*X/Open spec*/
michael@0 901 case AF_INET:
michael@0 902 if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
michael@0 903 if (pai->ai_family == afd->a_af ||
michael@0 904 pai->ai_family == PF_UNSPEC /*?*/) {
michael@0 905 GET_AI(cur->ai_next, afd, pton);
michael@0 906 GET_PORT(cur->ai_next, servname);
michael@0 907 if ((pai->ai_flags & AI_CANONNAME)) {
michael@0 908 /*
michael@0 909 * Set the numeric address itself as
michael@0 910 * the canonical name, based on a
michael@0 911 * clarification in rfc2553bis-03.
michael@0 912 */
michael@0 913 GET_CANONNAME(cur->ai_next, canonname);
michael@0 914 }
michael@0 915 while (cur && cur->ai_next)
michael@0 916 cur = cur->ai_next;
michael@0 917 } else
michael@0 918 ERR(EAI_FAMILY); /*xxx*/
michael@0 919 }
michael@0 920 break;
michael@0 921 #endif
michael@0 922 default:
michael@0 923 if (inet_pton(afd->a_af, hostname, pton) == 1) {
michael@0 924 if (pai->ai_family == afd->a_af ||
michael@0 925 pai->ai_family == PF_UNSPEC /*?*/) {
michael@0 926 GET_AI(cur->ai_next, afd, pton);
michael@0 927 GET_PORT(cur->ai_next, servname);
michael@0 928 if ((pai->ai_flags & AI_CANONNAME)) {
michael@0 929 /*
michael@0 930 * Set the numeric address itself as
michael@0 931 * the canonical name, based on a
michael@0 932 * clarification in rfc2553bis-03.
michael@0 933 */
michael@0 934 GET_CANONNAME(cur->ai_next, canonname);
michael@0 935 }
michael@0 936 while (cur->ai_next)
michael@0 937 cur = cur->ai_next;
michael@0 938 } else
michael@0 939 ERR(EAI_FAMILY); /*xxx*/
michael@0 940 }
michael@0 941 break;
michael@0 942 }
michael@0 943
michael@0 944 *res = sentinel.ai_next;
michael@0 945 return 0;
michael@0 946
michael@0 947 free:
michael@0 948 bad:
michael@0 949 if (sentinel.ai_next)
michael@0 950 __wrap_freeaddrinfo(sentinel.ai_next);
michael@0 951 return error;
michael@0 952 }
michael@0 953
michael@0 954 /*
michael@0 955 * numeric hostname with scope
michael@0 956 */
michael@0 957 static int
michael@0 958 explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
michael@0 959 const char *servname, struct addrinfo **res)
michael@0 960 {
michael@0 961 #if !defined(SCOPE_DELIMITER) || !defined(INET6)
michael@0 962 return explore_numeric(pai, hostname, servname, res, hostname);
michael@0 963 #else
michael@0 964 const struct afd *afd;
michael@0 965 struct addrinfo *cur;
michael@0 966 int error;
michael@0 967 char *cp, *hostname2 = NULL, *scope, *addr;
michael@0 968 struct sockaddr_in6 *sin6;
michael@0 969
michael@0 970 assert(pai != NULL);
michael@0 971 /* hostname may be NULL */
michael@0 972 /* servname may be NULL */
michael@0 973 assert(res != NULL);
michael@0 974
michael@0 975 /*
michael@0 976 * if the servname does not match socktype/protocol, ignore it.
michael@0 977 */
michael@0 978 if (get_portmatch(pai, servname) != 0)
michael@0 979 return 0;
michael@0 980
michael@0 981 afd = find_afd(pai->ai_family);
michael@0 982 if (afd == NULL)
michael@0 983 return 0;
michael@0 984
michael@0 985 if (!afd->a_scoped)
michael@0 986 return explore_numeric(pai, hostname, servname, res, hostname);
michael@0 987
michael@0 988 cp = strchr(hostname, SCOPE_DELIMITER);
michael@0 989 if (cp == NULL)
michael@0 990 return explore_numeric(pai, hostname, servname, res, hostname);
michael@0 991
michael@0 992 /*
michael@0 993 * Handle special case of <scoped_address><delimiter><scope id>
michael@0 994 */
michael@0 995 hostname2 = strdup(hostname);
michael@0 996 if (hostname2 == NULL)
michael@0 997 return EAI_MEMORY;
michael@0 998 /* terminate at the delimiter */
michael@0 999 hostname2[cp - hostname] = '\0';
michael@0 1000 addr = hostname2;
michael@0 1001 scope = cp + 1;
michael@0 1002
michael@0 1003 error = explore_numeric(pai, addr, servname, res, hostname);
michael@0 1004 if (error == 0) {
michael@0 1005 u_int32_t scopeid;
michael@0 1006
michael@0 1007 for (cur = *res; cur; cur = cur->ai_next) {
michael@0 1008 if (cur->ai_family != AF_INET6)
michael@0 1009 continue;
michael@0 1010 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
michael@0 1011 if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
michael@0 1012 free(hostname2);
michael@0 1013 return(EAI_NODATA); /* XXX: is return OK? */
michael@0 1014 }
michael@0 1015 sin6->sin6_scope_id = scopeid;
michael@0 1016 }
michael@0 1017 }
michael@0 1018
michael@0 1019 free(hostname2);
michael@0 1020
michael@0 1021 return error;
michael@0 1022 #endif
michael@0 1023 }
michael@0 1024
michael@0 1025 static int
michael@0 1026 get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
michael@0 1027 {
michael@0 1028
michael@0 1029 assert(pai != NULL);
michael@0 1030 assert(ai != NULL);
michael@0 1031 assert(str != NULL);
michael@0 1032
michael@0 1033 if ((pai->ai_flags & AI_CANONNAME) != 0) {
michael@0 1034 ai->ai_canonname = strdup(str);
michael@0 1035 if (ai->ai_canonname == NULL)
michael@0 1036 return EAI_MEMORY;
michael@0 1037 }
michael@0 1038 return 0;
michael@0 1039 }
michael@0 1040
michael@0 1041 static struct addrinfo *
michael@0 1042 get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
michael@0 1043 {
michael@0 1044 char *p;
michael@0 1045 struct addrinfo *ai;
michael@0 1046
michael@0 1047 assert(pai != NULL);
michael@0 1048 assert(afd != NULL);
michael@0 1049 assert(addr != NULL);
michael@0 1050
michael@0 1051 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
michael@0 1052 + (afd->a_socklen));
michael@0 1053 if (ai == NULL)
michael@0 1054 return NULL;
michael@0 1055
michael@0 1056 memcpy(ai, pai, sizeof(struct addrinfo));
michael@0 1057 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
michael@0 1058 memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
michael@0 1059
michael@0 1060 #ifdef HAVE_SA_LEN
michael@0 1061 ai->ai_addr->sa_len = afd->a_socklen;
michael@0 1062 #endif
michael@0 1063
michael@0 1064 ai->ai_addrlen = afd->a_socklen;
michael@0 1065 #if defined (__alpha__) || (defined(__i386__) && defined(_LP64)) || defined(__sparc64__)
michael@0 1066 ai->__ai_pad0 = 0;
michael@0 1067 #endif
michael@0 1068 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
michael@0 1069 p = (char *)(void *)(ai->ai_addr);
michael@0 1070 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
michael@0 1071 return ai;
michael@0 1072 }
michael@0 1073
michael@0 1074 static int
michael@0 1075 get_portmatch(const struct addrinfo *ai, const char *servname)
michael@0 1076 {
michael@0 1077
michael@0 1078 assert(ai != NULL);
michael@0 1079 /* servname may be NULL */
michael@0 1080
michael@0 1081 return get_port(ai, servname, 1);
michael@0 1082 }
michael@0 1083
michael@0 1084 static int
michael@0 1085 get_port(const struct addrinfo *ai, const char *servname, int matchonly)
michael@0 1086 {
michael@0 1087 const char *proto;
michael@0 1088 struct servent *sp;
michael@0 1089 int port;
michael@0 1090 int allownumeric;
michael@0 1091
michael@0 1092 assert(ai != NULL);
michael@0 1093 /* servname may be NULL */
michael@0 1094
michael@0 1095 if (servname == NULL)
michael@0 1096 return 0;
michael@0 1097 switch (ai->ai_family) {
michael@0 1098 case AF_INET:
michael@0 1099 #ifdef AF_INET6
michael@0 1100 case AF_INET6:
michael@0 1101 #endif
michael@0 1102 break;
michael@0 1103 default:
michael@0 1104 return 0;
michael@0 1105 }
michael@0 1106
michael@0 1107 switch (ai->ai_socktype) {
michael@0 1108 case SOCK_RAW:
michael@0 1109 return EAI_SERVICE;
michael@0 1110 case SOCK_DGRAM:
michael@0 1111 case SOCK_STREAM:
michael@0 1112 allownumeric = 1;
michael@0 1113 break;
michael@0 1114 case ANY:
michael@0 1115 #if 1 /* ANDROID-SPECIFIC CHANGE TO MATCH GLIBC */
michael@0 1116 allownumeric = 1;
michael@0 1117 #else
michael@0 1118 allownumeric = 0;
michael@0 1119 #endif
michael@0 1120 break;
michael@0 1121 default:
michael@0 1122 return EAI_SOCKTYPE;
michael@0 1123 }
michael@0 1124
michael@0 1125 port = str2number(servname);
michael@0 1126 if (port >= 0) {
michael@0 1127 if (!allownumeric)
michael@0 1128 return EAI_SERVICE;
michael@0 1129 if (port < 0 || port > 65535)
michael@0 1130 return EAI_SERVICE;
michael@0 1131 port = htons(port);
michael@0 1132 } else {
michael@0 1133 if (ai->ai_flags & AI_NUMERICSERV)
michael@0 1134 return EAI_NONAME;
michael@0 1135
michael@0 1136 switch (ai->ai_socktype) {
michael@0 1137 case SOCK_DGRAM:
michael@0 1138 proto = "udp";
michael@0 1139 break;
michael@0 1140 case SOCK_STREAM:
michael@0 1141 proto = "tcp";
michael@0 1142 break;
michael@0 1143 default:
michael@0 1144 proto = NULL;
michael@0 1145 break;
michael@0 1146 }
michael@0 1147
michael@0 1148 if ((sp = getservbyname(servname, proto)) == NULL)
michael@0 1149 return EAI_SERVICE;
michael@0 1150 port = sp->s_port;
michael@0 1151 }
michael@0 1152
michael@0 1153 if (!matchonly) {
michael@0 1154 switch (ai->ai_family) {
michael@0 1155 case AF_INET:
michael@0 1156 ((struct sockaddr_in *)(void *)
michael@0 1157 ai->ai_addr)->sin_port = port;
michael@0 1158 break;
michael@0 1159 #ifdef INET6
michael@0 1160 case AF_INET6:
michael@0 1161 ((struct sockaddr_in6 *)(void *)
michael@0 1162 ai->ai_addr)->sin6_port = port;
michael@0 1163 break;
michael@0 1164 #endif
michael@0 1165 }
michael@0 1166 }
michael@0 1167
michael@0 1168 return 0;
michael@0 1169 }
michael@0 1170
michael@0 1171 static const struct afd *
michael@0 1172 find_afd(int af)
michael@0 1173 {
michael@0 1174 const struct afd *afd;
michael@0 1175
michael@0 1176 if (af == PF_UNSPEC)
michael@0 1177 return NULL;
michael@0 1178 for (afd = afdl; afd->a_af; afd++) {
michael@0 1179 if (afd->a_af == af)
michael@0 1180 return afd;
michael@0 1181 }
michael@0 1182 return NULL;
michael@0 1183 }
michael@0 1184
michael@0 1185 #ifdef INET6
michael@0 1186 /* convert a string to a scope identifier. XXX: IPv6 specific */
michael@0 1187 static int
michael@0 1188 ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
michael@0 1189 {
michael@0 1190 u_long lscopeid;
michael@0 1191 struct in6_addr *a6;
michael@0 1192 char *ep;
michael@0 1193
michael@0 1194 assert(scope != NULL);
michael@0 1195 assert(sin6 != NULL);
michael@0 1196 assert(scopeid != NULL);
michael@0 1197
michael@0 1198 a6 = &sin6->sin6_addr;
michael@0 1199
michael@0 1200 /* empty scopeid portion is invalid */
michael@0 1201 if (*scope == '\0')
michael@0 1202 return -1;
michael@0 1203
michael@0 1204 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
michael@0 1205 /*
michael@0 1206 * We currently assume a one-to-one mapping between links
michael@0 1207 * and interfaces, so we simply use interface indices for
michael@0 1208 * like-local scopes.
michael@0 1209 */
michael@0 1210 *scopeid = if_nametoindex(scope);
michael@0 1211 if (*scopeid == 0)
michael@0 1212 goto trynumeric;
michael@0 1213 return 0;
michael@0 1214 }
michael@0 1215
michael@0 1216 /* still unclear about literal, allow numeric only - placeholder */
michael@0 1217 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
michael@0 1218 goto trynumeric;
michael@0 1219 if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
michael@0 1220 goto trynumeric;
michael@0 1221 else
michael@0 1222 goto trynumeric; /* global */
michael@0 1223
michael@0 1224 /* try to convert to a numeric id as a last resort */
michael@0 1225 trynumeric:
michael@0 1226 errno = 0;
michael@0 1227 lscopeid = strtoul(scope, &ep, 10);
michael@0 1228 *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
michael@0 1229 if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
michael@0 1230 return 0;
michael@0 1231 else
michael@0 1232 return -1;
michael@0 1233 }
michael@0 1234 #endif
michael@0 1235
michael@0 1236 /* code duplicate with gethnamaddr.c */
michael@0 1237
michael@0 1238 static const char AskedForGot[] =
michael@0 1239 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
michael@0 1240
michael@0 1241 static struct addrinfo *
michael@0 1242 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
michael@0 1243 const struct addrinfo *pai)
michael@0 1244 {
michael@0 1245 struct addrinfo sentinel, *cur;
michael@0 1246 struct addrinfo ai;
michael@0 1247 const struct afd *afd;
michael@0 1248 char *canonname;
michael@0 1249 const HEADER *hp;
michael@0 1250 const u_char *cp;
michael@0 1251 int n;
michael@0 1252 const u_char *eom;
michael@0 1253 char *bp, *ep;
michael@0 1254 int type, class, ancount, qdcount;
michael@0 1255 int haveanswer, had_error;
michael@0 1256 char tbuf[MAXDNAME];
michael@0 1257 int (*name_ok) (const char *);
michael@0 1258 char hostbuf[8*1024];
michael@0 1259
michael@0 1260 assert(answer != NULL);
michael@0 1261 assert(qname != NULL);
michael@0 1262 assert(pai != NULL);
michael@0 1263
michael@0 1264 memset(&sentinel, 0, sizeof(sentinel));
michael@0 1265 cur = &sentinel;
michael@0 1266
michael@0 1267 canonname = NULL;
michael@0 1268 eom = answer->buf + anslen;
michael@0 1269 switch (qtype) {
michael@0 1270 case T_A:
michael@0 1271 case T_AAAA:
michael@0 1272 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
michael@0 1273 name_ok = res_hnok;
michael@0 1274 break;
michael@0 1275 default:
michael@0 1276 return NULL; /* XXX should be abort(); */
michael@0 1277 }
michael@0 1278 /*
michael@0 1279 * find first satisfactory answer
michael@0 1280 */
michael@0 1281 hp = &answer->hdr;
michael@0 1282 ancount = ntohs(hp->ancount);
michael@0 1283 qdcount = ntohs(hp->qdcount);
michael@0 1284 bp = hostbuf;
michael@0 1285 ep = hostbuf + sizeof hostbuf;
michael@0 1286 cp = answer->buf + HFIXEDSZ;
michael@0 1287 if (qdcount != 1) {
michael@0 1288 h_errno = NO_RECOVERY;
michael@0 1289 return (NULL);
michael@0 1290 }
michael@0 1291 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
michael@0 1292 if ((n < 0) || !(*name_ok)(bp)) {
michael@0 1293 h_errno = NO_RECOVERY;
michael@0 1294 return (NULL);
michael@0 1295 }
michael@0 1296 cp += n + QFIXEDSZ;
michael@0 1297 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
michael@0 1298 /* res_send() has already verified that the query name is the
michael@0 1299 * same as the one we sent; this just gets the expanded name
michael@0 1300 * (i.e., with the succeeding search-domain tacked on).
michael@0 1301 */
michael@0 1302 n = strlen(bp) + 1; /* for the \0 */
michael@0 1303 if (n >= MAXHOSTNAMELEN) {
michael@0 1304 h_errno = NO_RECOVERY;
michael@0 1305 return (NULL);
michael@0 1306 }
michael@0 1307 canonname = bp;
michael@0 1308 bp += n;
michael@0 1309 /* The qname can be abbreviated, but h_name is now absolute. */
michael@0 1310 qname = canonname;
michael@0 1311 }
michael@0 1312 haveanswer = 0;
michael@0 1313 had_error = 0;
michael@0 1314 while (ancount-- > 0 && cp < eom && !had_error) {
michael@0 1315 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
michael@0 1316 if ((n < 0) || !(*name_ok)(bp)) {
michael@0 1317 had_error++;
michael@0 1318 continue;
michael@0 1319 }
michael@0 1320 cp += n; /* name */
michael@0 1321 type = _getshort(cp);
michael@0 1322 cp += INT16SZ; /* type */
michael@0 1323 class = _getshort(cp);
michael@0 1324 cp += INT16SZ + INT32SZ; /* class, TTL */
michael@0 1325 n = _getshort(cp);
michael@0 1326 cp += INT16SZ; /* len */
michael@0 1327 if (class != C_IN) {
michael@0 1328 /* XXX - debug? syslog? */
michael@0 1329 cp += n;
michael@0 1330 continue; /* XXX - had_error++ ? */
michael@0 1331 }
michael@0 1332 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
michael@0 1333 type == T_CNAME) {
michael@0 1334 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
michael@0 1335 if ((n < 0) || !(*name_ok)(tbuf)) {
michael@0 1336 had_error++;
michael@0 1337 continue;
michael@0 1338 }
michael@0 1339 cp += n;
michael@0 1340 /* Get canonical name. */
michael@0 1341 n = strlen(tbuf) + 1; /* for the \0 */
michael@0 1342 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
michael@0 1343 had_error++;
michael@0 1344 continue;
michael@0 1345 }
michael@0 1346 strlcpy(bp, tbuf, (size_t)(ep - bp));
michael@0 1347 canonname = bp;
michael@0 1348 bp += n;
michael@0 1349 continue;
michael@0 1350 }
michael@0 1351 if (qtype == T_ANY) {
michael@0 1352 if (!(type == T_A || type == T_AAAA)) {
michael@0 1353 cp += n;
michael@0 1354 continue;
michael@0 1355 }
michael@0 1356 } else if (type != qtype) {
michael@0 1357 if (type != T_KEY && type != T_SIG)
michael@0 1358 syslog(LOG_NOTICE|LOG_AUTH,
michael@0 1359 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
michael@0 1360 qname, p_class(C_IN), p_type(qtype),
michael@0 1361 p_type(type));
michael@0 1362 cp += n;
michael@0 1363 continue; /* XXX - had_error++ ? */
michael@0 1364 }
michael@0 1365 switch (type) {
michael@0 1366 case T_A:
michael@0 1367 case T_AAAA:
michael@0 1368 if (strcasecmp(canonname, bp) != 0) {
michael@0 1369 syslog(LOG_NOTICE|LOG_AUTH,
michael@0 1370 AskedForGot, canonname, bp);
michael@0 1371 cp += n;
michael@0 1372 continue; /* XXX - had_error++ ? */
michael@0 1373 }
michael@0 1374 if (type == T_A && n != INADDRSZ) {
michael@0 1375 cp += n;
michael@0 1376 continue;
michael@0 1377 }
michael@0 1378 if (type == T_AAAA && n != IN6ADDRSZ) {
michael@0 1379 cp += n;
michael@0 1380 continue;
michael@0 1381 }
michael@0 1382 if (type == T_AAAA) {
michael@0 1383 struct in6_addr in6;
michael@0 1384 memcpy(&in6, cp, IN6ADDRSZ);
michael@0 1385 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
michael@0 1386 cp += n;
michael@0 1387 continue;
michael@0 1388 }
michael@0 1389 }
michael@0 1390 if (!haveanswer) {
michael@0 1391 int nn;
michael@0 1392
michael@0 1393 canonname = bp;
michael@0 1394 nn = strlen(bp) + 1; /* for the \0 */
michael@0 1395 bp += nn;
michael@0 1396 }
michael@0 1397
michael@0 1398 /* don't overwrite pai */
michael@0 1399 ai = *pai;
michael@0 1400 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
michael@0 1401 afd = find_afd(ai.ai_family);
michael@0 1402 if (afd == NULL) {
michael@0 1403 cp += n;
michael@0 1404 continue;
michael@0 1405 }
michael@0 1406 cur->ai_next = get_ai(&ai, afd, (const char *)cp);
michael@0 1407 if (cur->ai_next == NULL)
michael@0 1408 had_error++;
michael@0 1409 while (cur && cur->ai_next)
michael@0 1410 cur = cur->ai_next;
michael@0 1411 cp += n;
michael@0 1412 break;
michael@0 1413 default:
michael@0 1414 abort();
michael@0 1415 }
michael@0 1416 if (!had_error)
michael@0 1417 haveanswer++;
michael@0 1418 }
michael@0 1419 if (haveanswer) {
michael@0 1420 if (!canonname)
michael@0 1421 (void)get_canonname(pai, sentinel.ai_next, qname);
michael@0 1422 else
michael@0 1423 (void)get_canonname(pai, sentinel.ai_next, canonname);
michael@0 1424 h_errno = NETDB_SUCCESS;
michael@0 1425 return sentinel.ai_next;
michael@0 1426 }
michael@0 1427
michael@0 1428 h_errno = NO_RECOVERY;
michael@0 1429 return NULL;
michael@0 1430 }
michael@0 1431
michael@0 1432 struct addrinfo_sort_elem {
michael@0 1433 struct addrinfo *ai;
michael@0 1434 int has_src_addr;
michael@0 1435 sockaddr_union src_addr;
michael@0 1436 int original_order;
michael@0 1437 };
michael@0 1438
michael@0 1439 /*ARGSUSED*/
michael@0 1440 static int
michael@0 1441 _get_scope(const struct sockaddr *addr)
michael@0 1442 {
michael@0 1443 if (addr->sa_family == AF_INET6) {
michael@0 1444 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
michael@0 1445 if (IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr)) {
michael@0 1446 return IPV6_ADDR_MC_SCOPE(&addr6->sin6_addr);
michael@0 1447 } else if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) ||
michael@0 1448 IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) {
michael@0 1449 /*
michael@0 1450 * RFC 4291 section 2.5.3 says loopback is to be treated as having
michael@0 1451 * link-local scope.
michael@0 1452 */
michael@0 1453 return IPV6_ADDR_SCOPE_LINKLOCAL;
michael@0 1454 } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) {
michael@0 1455 return IPV6_ADDR_SCOPE_SITELOCAL;
michael@0 1456 } else {
michael@0 1457 return IPV6_ADDR_SCOPE_GLOBAL;
michael@0 1458 }
michael@0 1459 } else if (addr->sa_family == AF_INET) {
michael@0 1460 const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
michael@0 1461 unsigned long int na = ntohl(addr4->sin_addr.s_addr);
michael@0 1462
michael@0 1463 if (IN_LOOPBACK(na) || /* 127.0.0.0/8 */
michael@0 1464 (na & 0xffff0000) == 0xa9fe0000) { /* 169.254.0.0/16 */
michael@0 1465 return IPV6_ADDR_SCOPE_LINKLOCAL;
michael@0 1466 } else {
michael@0 1467 /*
michael@0 1468 * According to draft-ietf-6man-rfc3484-revise-01 section 2.3,
michael@0 1469 * it is best not to treat the private IPv4 ranges
michael@0 1470 * (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) as being
michael@0 1471 * in a special scope, so we don't.
michael@0 1472 */
michael@0 1473 return IPV6_ADDR_SCOPE_GLOBAL;
michael@0 1474 }
michael@0 1475 } else {
michael@0 1476 /*
michael@0 1477 * This should never happen.
michael@0 1478 * Return a scope with low priority as a last resort.
michael@0 1479 */
michael@0 1480 return IPV6_ADDR_SCOPE_NODELOCAL;
michael@0 1481 }
michael@0 1482 }
michael@0 1483
michael@0 1484 /* These macros are modelled after the ones in <netinet/in6.h>. */
michael@0 1485
michael@0 1486 /* RFC 4380, section 2.6 */
michael@0 1487 #define IN6_IS_ADDR_TEREDO(a) \
michael@0 1488 ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == ntohl(0x20010000)))
michael@0 1489
michael@0 1490 /* RFC 3056, section 2. */
michael@0 1491 #define IN6_IS_ADDR_6TO4(a) \
michael@0 1492 (((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02))
michael@0 1493
michael@0 1494 /* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */
michael@0 1495 #define IN6_IS_ADDR_6BONE(a) \
michael@0 1496 (((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe))
michael@0 1497
michael@0 1498 /*
michael@0 1499 * Get the label for a given IPv4/IPv6 address.
michael@0 1500 * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01.
michael@0 1501 */
michael@0 1502
michael@0 1503 /*ARGSUSED*/
michael@0 1504 static int
michael@0 1505 _get_label(const struct sockaddr *addr)
michael@0 1506 {
michael@0 1507 if (addr->sa_family == AF_INET) {
michael@0 1508 return 3;
michael@0 1509 } else if (addr->sa_family == AF_INET6) {
michael@0 1510 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
michael@0 1511 if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
michael@0 1512 return 0;
michael@0 1513 } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
michael@0 1514 return 3;
michael@0 1515 } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
michael@0 1516 return 4;
michael@0 1517 } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
michael@0 1518 return 5;
michael@0 1519 } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
michael@0 1520 return 10;
michael@0 1521 } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) {
michael@0 1522 return 11;
michael@0 1523 } else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
michael@0 1524 return 12;
michael@0 1525 } else {
michael@0 1526 return 2;
michael@0 1527 }
michael@0 1528 } else {
michael@0 1529 /*
michael@0 1530 * This should never happen.
michael@0 1531 * Return a semi-random label as a last resort.
michael@0 1532 */
michael@0 1533 return 1;
michael@0 1534 }
michael@0 1535 }
michael@0 1536
michael@0 1537 /*
michael@0 1538 * Get the precedence for a given IPv4/IPv6 address.
michael@0 1539 * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01.
michael@0 1540 */
michael@0 1541
michael@0 1542 /*ARGSUSED*/
michael@0 1543 static int
michael@0 1544 _get_precedence(const struct sockaddr *addr)
michael@0 1545 {
michael@0 1546 if (addr->sa_family == AF_INET) {
michael@0 1547 return 30;
michael@0 1548 } else if (addr->sa_family == AF_INET6) {
michael@0 1549 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
michael@0 1550 if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
michael@0 1551 return 60;
michael@0 1552 } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
michael@0 1553 return 30;
michael@0 1554 } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
michael@0 1555 return 20;
michael@0 1556 } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
michael@0 1557 return 10;
michael@0 1558 } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) ||
michael@0 1559 IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) ||
michael@0 1560 IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
michael@0 1561 return 1;
michael@0 1562 } else {
michael@0 1563 return 40;
michael@0 1564 }
michael@0 1565 } else {
michael@0 1566 return 1;
michael@0 1567 }
michael@0 1568 }
michael@0 1569
michael@0 1570 /*
michael@0 1571 * Find number of matching initial bits between the two addresses a1 and a2.
michael@0 1572 */
michael@0 1573
michael@0 1574 /*ARGSUSED*/
michael@0 1575 static int
michael@0 1576 _common_prefix_len(const struct in6_addr *a1, const struct in6_addr *a2)
michael@0 1577 {
michael@0 1578 const char *p1 = (const char *)a1;
michael@0 1579 const char *p2 = (const char *)a2;
michael@0 1580 unsigned i;
michael@0 1581
michael@0 1582 for (i = 0; i < sizeof(*a1); ++i) {
michael@0 1583 int x, j;
michael@0 1584
michael@0 1585 if (p1[i] == p2[i]) {
michael@0 1586 continue;
michael@0 1587 }
michael@0 1588 x = p1[i] ^ p2[i];
michael@0 1589 for (j = 0; j < CHAR_BIT; ++j) {
michael@0 1590 if (x & (1 << (CHAR_BIT - 1))) {
michael@0 1591 return i * CHAR_BIT + j;
michael@0 1592 }
michael@0 1593 x <<= 1;
michael@0 1594 }
michael@0 1595 }
michael@0 1596 return sizeof(*a1) * CHAR_BIT;
michael@0 1597 }
michael@0 1598
michael@0 1599 /*
michael@0 1600 * Compare two source/destination address pairs.
michael@0 1601 * RFC 3484, section 6.
michael@0 1602 */
michael@0 1603
michael@0 1604 /*ARGSUSED*/
michael@0 1605 static int
michael@0 1606 _rfc3484_compare(const void *ptr1, const void* ptr2)
michael@0 1607 {
michael@0 1608 const struct addrinfo_sort_elem *a1 = (const struct addrinfo_sort_elem *)ptr1;
michael@0 1609 const struct addrinfo_sort_elem *a2 = (const struct addrinfo_sort_elem *)ptr2;
michael@0 1610 int scope_src1, scope_dst1, scope_match1;
michael@0 1611 int scope_src2, scope_dst2, scope_match2;
michael@0 1612 int label_src1, label_dst1, label_match1;
michael@0 1613 int label_src2, label_dst2, label_match2;
michael@0 1614 int precedence1, precedence2;
michael@0 1615 int prefixlen1, prefixlen2;
michael@0 1616
michael@0 1617 /* Rule 1: Avoid unusable destinations. */
michael@0 1618 if (a1->has_src_addr != a2->has_src_addr) {
michael@0 1619 return a2->has_src_addr - a1->has_src_addr;
michael@0 1620 }
michael@0 1621
michael@0 1622 /* Rule 2: Prefer matching scope. */
michael@0 1623 scope_src1 = _get_scope(&a1->src_addr.generic);
michael@0 1624 scope_dst1 = _get_scope(a1->ai->ai_addr);
michael@0 1625 scope_match1 = (scope_src1 == scope_dst1);
michael@0 1626
michael@0 1627 scope_src2 = _get_scope(&a2->src_addr.generic);
michael@0 1628 scope_dst2 = _get_scope(a2->ai->ai_addr);
michael@0 1629 scope_match2 = (scope_src2 == scope_dst2);
michael@0 1630
michael@0 1631 if (scope_match1 != scope_match2) {
michael@0 1632 return scope_match2 - scope_match1;
michael@0 1633 }
michael@0 1634
michael@0 1635 /*
michael@0 1636 * Rule 3: Avoid deprecated addresses.
michael@0 1637 * TODO(sesse): We don't currently have a good way of finding this.
michael@0 1638 */
michael@0 1639
michael@0 1640 /*
michael@0 1641 * Rule 4: Prefer home addresses.
michael@0 1642 * TODO(sesse): We don't currently have a good way of finding this.
michael@0 1643 */
michael@0 1644
michael@0 1645 /* Rule 5: Prefer matching label. */
michael@0 1646 label_src1 = _get_label(&a1->src_addr.generic);
michael@0 1647 label_dst1 = _get_label(a1->ai->ai_addr);
michael@0 1648 label_match1 = (label_src1 == label_dst1);
michael@0 1649
michael@0 1650 label_src2 = _get_label(&a2->src_addr.generic);
michael@0 1651 label_dst2 = _get_label(a2->ai->ai_addr);
michael@0 1652 label_match2 = (label_src2 == label_dst2);
michael@0 1653
michael@0 1654 if (label_match1 != label_match2) {
michael@0 1655 return label_match2 - label_match1;
michael@0 1656 }
michael@0 1657
michael@0 1658 /* Rule 6: Prefer higher precedence. */
michael@0 1659 precedence1 = _get_precedence(a1->ai->ai_addr);
michael@0 1660 precedence2 = _get_precedence(a2->ai->ai_addr);
michael@0 1661 if (precedence1 != precedence2) {
michael@0 1662 return precedence2 - precedence1;
michael@0 1663 }
michael@0 1664
michael@0 1665 /*
michael@0 1666 * Rule 7: Prefer native transport.
michael@0 1667 * TODO(sesse): We don't currently have a good way of finding this.
michael@0 1668 */
michael@0 1669
michael@0 1670 /* Rule 8: Prefer smaller scope. */
michael@0 1671 if (scope_dst1 != scope_dst2) {
michael@0 1672 return scope_dst1 - scope_dst2;
michael@0 1673 }
michael@0 1674
michael@0 1675 /*
michael@0 1676 * Rule 9: Use longest matching prefix.
michael@0 1677 * We implement this for IPv6 only, as the rules in RFC 3484 don't seem
michael@0 1678 * to work very well directly applied to IPv4. (glibc uses information from
michael@0 1679 * the routing table for a custom IPv4 implementation here.)
michael@0 1680 */
michael@0 1681 if (a1->has_src_addr && a1->ai->ai_addr->sa_family == AF_INET6 &&
michael@0 1682 a2->has_src_addr && a2->ai->ai_addr->sa_family == AF_INET6) {
michael@0 1683 const struct sockaddr_in6 *a1_src = &a1->src_addr.in6;
michael@0 1684 const struct sockaddr_in6 *a1_dst = (const struct sockaddr_in6 *)a1->ai->ai_addr;
michael@0 1685 const struct sockaddr_in6 *a2_src = &a2->src_addr.in6;
michael@0 1686 const struct sockaddr_in6 *a2_dst = (const struct sockaddr_in6 *)a2->ai->ai_addr;
michael@0 1687 prefixlen1 = _common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr);
michael@0 1688 prefixlen2 = _common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr);
michael@0 1689 if (prefixlen1 != prefixlen2) {
michael@0 1690 return prefixlen2 - prefixlen1;
michael@0 1691 }
michael@0 1692 }
michael@0 1693
michael@0 1694 /*
michael@0 1695 * Rule 10: Leave the order unchanged.
michael@0 1696 * We need this since qsort() is not necessarily stable.
michael@0 1697 */
michael@0 1698 return a1->original_order - a2->original_order;
michael@0 1699 }
michael@0 1700
michael@0 1701 /*
michael@0 1702 * Find the source address that will be used if trying to connect to the given
michael@0 1703 * address. src_addr must be large enough to hold a struct sockaddr_in6.
michael@0 1704 *
michael@0 1705 * Returns 1 if a source address was found, 0 if the address is unreachable,
michael@0 1706 * and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are
michael@0 1707 * undefined.
michael@0 1708 */
michael@0 1709
michael@0 1710 /*ARGSUSED*/
michael@0 1711 static int
michael@0 1712 _find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr)
michael@0 1713 {
michael@0 1714 int sock;
michael@0 1715 int ret;
michael@0 1716 socklen_t len;
michael@0 1717
michael@0 1718 switch (addr->sa_family) {
michael@0 1719 case AF_INET:
michael@0 1720 len = sizeof(struct sockaddr_in);
michael@0 1721 break;
michael@0 1722 case AF_INET6:
michael@0 1723 len = sizeof(struct sockaddr_in6);
michael@0 1724 break;
michael@0 1725 default:
michael@0 1726 /* No known usable source address for non-INET families. */
michael@0 1727 return 0;
michael@0 1728 }
michael@0 1729
michael@0 1730 sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
michael@0 1731 if (sock == -1) {
michael@0 1732 if (errno == EAFNOSUPPORT) {
michael@0 1733 return 0;
michael@0 1734 } else {
michael@0 1735 return -1;
michael@0 1736 }
michael@0 1737 }
michael@0 1738
michael@0 1739 do {
michael@0 1740 ret = connect(sock, addr, len);
michael@0 1741 } while (ret == -1 && errno == EINTR);
michael@0 1742
michael@0 1743 if (ret == -1) {
michael@0 1744 close(sock);
michael@0 1745 return 0;
michael@0 1746 }
michael@0 1747
michael@0 1748 if (getsockname(sock, src_addr, &len) == -1) {
michael@0 1749 close(sock);
michael@0 1750 return -1;
michael@0 1751 }
michael@0 1752 close(sock);
michael@0 1753 return 1;
michael@0 1754 }
michael@0 1755
michael@0 1756 /*
michael@0 1757 * Sort the linked list starting at sentinel->ai_next in RFC3484 order.
michael@0 1758 * Will leave the list unchanged if an error occurs.
michael@0 1759 */
michael@0 1760
michael@0 1761 /*ARGSUSED*/
michael@0 1762 static void
michael@0 1763 _rfc3484_sort(struct addrinfo *list_sentinel)
michael@0 1764 {
michael@0 1765 struct addrinfo *cur;
michael@0 1766 int nelem = 0, i;
michael@0 1767 struct addrinfo_sort_elem *elems;
michael@0 1768
michael@0 1769 cur = list_sentinel->ai_next;
michael@0 1770 while (cur) {
michael@0 1771 ++nelem;
michael@0 1772 cur = cur->ai_next;
michael@0 1773 }
michael@0 1774
michael@0 1775 elems = (struct addrinfo_sort_elem *)malloc(nelem * sizeof(struct addrinfo_sort_elem));
michael@0 1776 if (elems == NULL) {
michael@0 1777 goto error;
michael@0 1778 }
michael@0 1779
michael@0 1780 /*
michael@0 1781 * Convert the linked list to an array that also contains the candidate
michael@0 1782 * source address for each destination address.
michael@0 1783 */
michael@0 1784 for (i = 0, cur = list_sentinel->ai_next; i < nelem; ++i, cur = cur->ai_next) {
michael@0 1785 int has_src_addr;
michael@0 1786 assert(cur != NULL);
michael@0 1787 elems[i].ai = cur;
michael@0 1788 elems[i].original_order = i;
michael@0 1789
michael@0 1790 has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic);
michael@0 1791 if (has_src_addr == -1) {
michael@0 1792 goto error;
michael@0 1793 }
michael@0 1794 elems[i].has_src_addr = has_src_addr;
michael@0 1795 }
michael@0 1796
michael@0 1797 /* Sort the addresses, and rearrange the linked list so it matches the sorted order. */
michael@0 1798 qsort((void *)elems, nelem, sizeof(struct addrinfo_sort_elem), _rfc3484_compare);
michael@0 1799
michael@0 1800 list_sentinel->ai_next = elems[0].ai;
michael@0 1801 for (i = 0; i < nelem - 1; ++i) {
michael@0 1802 elems[i].ai->ai_next = elems[i + 1].ai;
michael@0 1803 }
michael@0 1804 elems[nelem - 1].ai->ai_next = NULL;
michael@0 1805
michael@0 1806 error:
michael@0 1807 free(elems);
michael@0 1808 }
michael@0 1809
michael@0 1810 /*ARGSUSED*/
michael@0 1811 static int
michael@0 1812 _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
michael@0 1813 {
michael@0 1814 struct addrinfo *ai;
michael@0 1815 querybuf *buf, *buf2;
michael@0 1816 const char *name;
michael@0 1817 const struct addrinfo *pai;
michael@0 1818 struct addrinfo sentinel, *cur;
michael@0 1819 struct res_target q, q2;
michael@0 1820 res_state res;
michael@0 1821
michael@0 1822 name = va_arg(ap, char *);
michael@0 1823 pai = va_arg(ap, const struct addrinfo *);
michael@0 1824 //fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name);
michael@0 1825
michael@0 1826 memset(&q, 0, sizeof(q));
michael@0 1827 memset(&q2, 0, sizeof(q2));
michael@0 1828 memset(&sentinel, 0, sizeof(sentinel));
michael@0 1829 cur = &sentinel;
michael@0 1830
michael@0 1831 buf = malloc(sizeof(*buf));
michael@0 1832 if (buf == NULL) {
michael@0 1833 h_errno = NETDB_INTERNAL;
michael@0 1834 return NS_NOTFOUND;
michael@0 1835 }
michael@0 1836 buf2 = malloc(sizeof(*buf2));
michael@0 1837 if (buf2 == NULL) {
michael@0 1838 free(buf);
michael@0 1839 h_errno = NETDB_INTERNAL;
michael@0 1840 return NS_NOTFOUND;
michael@0 1841 }
michael@0 1842
michael@0 1843 switch (pai->ai_family) {
michael@0 1844 case AF_UNSPEC:
michael@0 1845 /* prefer IPv6 */
michael@0 1846 q.name = name;
michael@0 1847 q.qclass = C_IN;
michael@0 1848 q.answer = buf->buf;
michael@0 1849 q.anslen = sizeof(buf->buf);
michael@0 1850 int query_ipv6 = 1, query_ipv4 = 1;
michael@0 1851 if (pai->ai_flags & AI_ADDRCONFIG) {
michael@0 1852 query_ipv6 = _have_ipv6();
michael@0 1853 query_ipv4 = _have_ipv4();
michael@0 1854 }
michael@0 1855 if (query_ipv6) {
michael@0 1856 q.qtype = T_AAAA;
michael@0 1857 if (query_ipv4) {
michael@0 1858 q.next = &q2;
michael@0 1859 q2.name = name;
michael@0 1860 q2.qclass = C_IN;
michael@0 1861 q2.qtype = T_A;
michael@0 1862 q2.answer = buf2->buf;
michael@0 1863 q2.anslen = sizeof(buf2->buf);
michael@0 1864 }
michael@0 1865 } else if (query_ipv4) {
michael@0 1866 q.qtype = T_A;
michael@0 1867 } else {
michael@0 1868 free(buf);
michael@0 1869 free(buf2);
michael@0 1870 return NS_NOTFOUND;
michael@0 1871 }
michael@0 1872 break;
michael@0 1873 case AF_INET:
michael@0 1874 q.name = name;
michael@0 1875 q.qclass = C_IN;
michael@0 1876 q.qtype = T_A;
michael@0 1877 q.answer = buf->buf;
michael@0 1878 q.anslen = sizeof(buf->buf);
michael@0 1879 break;
michael@0 1880 case AF_INET6:
michael@0 1881 q.name = name;
michael@0 1882 q.qclass = C_IN;
michael@0 1883 q.qtype = T_AAAA;
michael@0 1884 q.answer = buf->buf;
michael@0 1885 q.anslen = sizeof(buf->buf);
michael@0 1886 break;
michael@0 1887 default:
michael@0 1888 free(buf);
michael@0 1889 free(buf2);
michael@0 1890 return NS_UNAVAIL;
michael@0 1891 }
michael@0 1892
michael@0 1893 res = __res_get_state();
michael@0 1894 if (res == NULL) {
michael@0 1895 free(buf);
michael@0 1896 free(buf2);
michael@0 1897 return NS_NOTFOUND;
michael@0 1898 }
michael@0 1899
michael@0 1900 if (res_searchN(name, &q, res) < 0) {
michael@0 1901 __res_put_state(res);
michael@0 1902 free(buf);
michael@0 1903 free(buf2);
michael@0 1904 return NS_NOTFOUND;
michael@0 1905 }
michael@0 1906 ai = getanswer(buf, q.n, q.name, q.qtype, pai);
michael@0 1907 if (ai) {
michael@0 1908 cur->ai_next = ai;
michael@0 1909 while (cur && cur->ai_next)
michael@0 1910 cur = cur->ai_next;
michael@0 1911 }
michael@0 1912 if (q.next) {
michael@0 1913 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
michael@0 1914 if (ai)
michael@0 1915 cur->ai_next = ai;
michael@0 1916 }
michael@0 1917 free(buf);
michael@0 1918 free(buf2);
michael@0 1919 if (sentinel.ai_next == NULL) {
michael@0 1920 __res_put_state(res);
michael@0 1921 switch (h_errno) {
michael@0 1922 case HOST_NOT_FOUND:
michael@0 1923 return NS_NOTFOUND;
michael@0 1924 case TRY_AGAIN:
michael@0 1925 return NS_TRYAGAIN;
michael@0 1926 default:
michael@0 1927 return NS_UNAVAIL;
michael@0 1928 }
michael@0 1929 }
michael@0 1930
michael@0 1931 _rfc3484_sort(&sentinel);
michael@0 1932
michael@0 1933 __res_put_state(res);
michael@0 1934
michael@0 1935 *((struct addrinfo **)rv) = sentinel.ai_next;
michael@0 1936 return NS_SUCCESS;
michael@0 1937 }
michael@0 1938
michael@0 1939 static void
michael@0 1940 _sethtent(_pseudo_FILE * __restrict__ hostf)
michael@0 1941 {
michael@0 1942 assert(hostf);
michael@0 1943 if (hostf->mapping == MAP_FAILED)
michael@0 1944 (void) _pseudo_fopen_r(hostf, _PATH_HOSTS);
michael@0 1945 else
michael@0 1946 _pseudo_rewind(hostf);
michael@0 1947 }
michael@0 1948
michael@0 1949 static void
michael@0 1950 _endhtent(_pseudo_FILE * __restrict__ hostf)
michael@0 1951 {
michael@0 1952 assert(hostf);
michael@0 1953 (void) _pseudo_fclose(hostf);
michael@0 1954 }
michael@0 1955
michael@0 1956 static struct addrinfo *
michael@0 1957 _gethtent(_pseudo_FILE * __restrict__ hostf, const char *name, const struct addrinfo *pai)
michael@0 1958 {
michael@0 1959 char *p;
michael@0 1960 char *cp, *tname, *cname;
michael@0 1961 struct addrinfo hints, *res0, *res;
michael@0 1962 int error;
michael@0 1963 const char *addr;
michael@0 1964 char hostbuf[8*1024];
michael@0 1965
michael@0 1966 assert(hostf);
michael@0 1967 // fprintf(stderr, "_gethtent() name = '%s'\n", name);
michael@0 1968 assert(name != NULL);
michael@0 1969 assert(pai != NULL);
michael@0 1970
michael@0 1971 if (hostf->mapping == MAP_FAILED)
michael@0 1972 (void) _pseudo_fopen_r(hostf, _PATH_HOSTS);
michael@0 1973 if (hostf->mapping == MAP_FAILED)
michael@0 1974 return (NULL);
michael@0 1975 again:
michael@0 1976 if (!(p = _pseudo_fgets(hostbuf, sizeof hostbuf, hostf)))
michael@0 1977 return (NULL);
michael@0 1978 if (*p == '#')
michael@0 1979 goto again;
michael@0 1980 if (!(cp = strpbrk(p, "#\n")))
michael@0 1981 goto again;
michael@0 1982 *cp = '\0';
michael@0 1983 if (!(cp = strpbrk(p, " \t")))
michael@0 1984 goto again;
michael@0 1985 *cp++ = '\0';
michael@0 1986 addr = p;
michael@0 1987 /* if this is not something we're looking for, skip it. */
michael@0 1988 cname = NULL;
michael@0 1989 while (cp && *cp) {
michael@0 1990 if (*cp == ' ' || *cp == '\t') {
michael@0 1991 cp++;
michael@0 1992 continue;
michael@0 1993 }
michael@0 1994 if (!cname)
michael@0 1995 cname = cp;
michael@0 1996 tname = cp;
michael@0 1997 if ((cp = strpbrk(cp, " \t")) != NULL)
michael@0 1998 *cp++ = '\0';
michael@0 1999 // fprintf(stderr, "\ttname = '%s'", tname);
michael@0 2000 if (strcasecmp(name, tname) == 0)
michael@0 2001 goto found;
michael@0 2002 }
michael@0 2003 goto again;
michael@0 2004
michael@0 2005 found:
michael@0 2006 hints = *pai;
michael@0 2007 hints.ai_flags = AI_NUMERICHOST;
michael@0 2008 error = __wrap_getaddrinfo(addr, NULL, &hints, &res0);
michael@0 2009 if (error)
michael@0 2010 goto again;
michael@0 2011 for (res = res0; res; res = res->ai_next) {
michael@0 2012 /* cover it up */
michael@0 2013 res->ai_flags = pai->ai_flags;
michael@0 2014
michael@0 2015 if (pai->ai_flags & AI_CANONNAME) {
michael@0 2016 if (get_canonname(pai, res, cname) != 0) {
michael@0 2017 __wrap_freeaddrinfo(res0);
michael@0 2018 goto again;
michael@0 2019 }
michael@0 2020 }
michael@0 2021 }
michael@0 2022 return res0;
michael@0 2023 }
michael@0 2024
michael@0 2025 /*ARGSUSED*/
michael@0 2026 static int
michael@0 2027 _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
michael@0 2028 {
michael@0 2029 const char *name;
michael@0 2030 const struct addrinfo *pai;
michael@0 2031 struct addrinfo sentinel, *cur;
michael@0 2032 struct addrinfo *p;
michael@0 2033 _pseudo_FILE hostf = _PSEUDO_FILE_INITIALIZER;
michael@0 2034
michael@0 2035 name = va_arg(ap, char *);
michael@0 2036 pai = va_arg(ap, struct addrinfo *);
michael@0 2037
michael@0 2038 // fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name);
michael@0 2039 memset(&sentinel, 0, sizeof(sentinel));
michael@0 2040 cur = &sentinel;
michael@0 2041
michael@0 2042 _sethtent(&hostf);
michael@0 2043 while ((p = _gethtent(&hostf, name, pai)) != NULL) {
michael@0 2044 cur->ai_next = p;
michael@0 2045 while (cur && cur->ai_next)
michael@0 2046 cur = cur->ai_next;
michael@0 2047 }
michael@0 2048 _endhtent(&hostf);
michael@0 2049
michael@0 2050 *((struct addrinfo **)rv) = sentinel.ai_next;
michael@0 2051 if (sentinel.ai_next == NULL)
michael@0 2052 return NS_NOTFOUND;
michael@0 2053 return NS_SUCCESS;
michael@0 2054 }
michael@0 2055
michael@0 2056 /* resolver logic */
michael@0 2057
michael@0 2058 /*
michael@0 2059 * Formulate a normal query, send, and await answer.
michael@0 2060 * Returned answer is placed in supplied buffer "answer".
michael@0 2061 * Perform preliminary check of answer, returning success only
michael@0 2062 * if no error is indicated and the answer count is nonzero.
michael@0 2063 * Return the size of the response on success, -1 on error.
michael@0 2064 * Error number is left in h_errno.
michael@0 2065 *
michael@0 2066 * Caller must parse answer and determine whether it answers the question.
michael@0 2067 */
michael@0 2068 static int
michael@0 2069 res_queryN(const char *name, /* domain name */ struct res_target *target,
michael@0 2070 res_state res)
michael@0 2071 {
michael@0 2072 u_char buf[MAXPACKET];
michael@0 2073 HEADER *hp;
michael@0 2074 int n;
michael@0 2075 struct res_target *t;
michael@0 2076 int rcode;
michael@0 2077 int ancount;
michael@0 2078
michael@0 2079 assert(name != NULL);
michael@0 2080 /* XXX: target may be NULL??? */
michael@0 2081
michael@0 2082 rcode = NOERROR;
michael@0 2083 ancount = 0;
michael@0 2084
michael@0 2085 for (t = target; t; t = t->next) {
michael@0 2086 int class, type;
michael@0 2087 u_char *answer;
michael@0 2088 int anslen;
michael@0 2089
michael@0 2090 hp = (HEADER *)(void *)t->answer;
michael@0 2091 hp->rcode = NOERROR; /* default */
michael@0 2092
michael@0 2093 /* make it easier... */
michael@0 2094 class = t->qclass;
michael@0 2095 type = t->qtype;
michael@0 2096 answer = t->answer;
michael@0 2097 anslen = t->anslen;
michael@0 2098 #ifdef DEBUG
michael@0 2099 if (res->options & RES_DEBUG)
michael@0 2100 printf(";; res_nquery(%s, %d, %d)\n", name, class, type);
michael@0 2101 #endif
michael@0 2102
michael@0 2103 n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
michael@0 2104 buf, sizeof(buf));
michael@0 2105 #ifdef RES_USE_EDNS0
michael@0 2106 if (n > 0 && (res->options & RES_USE_EDNS0) != 0)
michael@0 2107 n = res_nopt(res, n, buf, sizeof(buf), anslen);
michael@0 2108 #endif
michael@0 2109 if (n <= 0) {
michael@0 2110 #ifdef DEBUG
michael@0 2111 if (res->options & RES_DEBUG)
michael@0 2112 printf(";; res_nquery: mkquery failed\n");
michael@0 2113 #endif
michael@0 2114 h_errno = NO_RECOVERY;
michael@0 2115 return n;
michael@0 2116 }
michael@0 2117 n = res_nsend(res, buf, n, answer, anslen);
michael@0 2118 #if 0
michael@0 2119 if (n < 0) {
michael@0 2120 #ifdef DEBUG
michael@0 2121 if (res->options & RES_DEBUG)
michael@0 2122 printf(";; res_query: send error\n");
michael@0 2123 #endif
michael@0 2124 h_errno = TRY_AGAIN;
michael@0 2125 return n;
michael@0 2126 }
michael@0 2127 #endif
michael@0 2128
michael@0 2129 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
michael@0 2130 rcode = hp->rcode; /* record most recent error */
michael@0 2131 #ifdef DEBUG
michael@0 2132 if (res->options & RES_DEBUG)
michael@0 2133 printf(";; rcode = %u, ancount=%u\n", hp->rcode,
michael@0 2134 ntohs(hp->ancount));
michael@0 2135 #endif
michael@0 2136 continue;
michael@0 2137 }
michael@0 2138
michael@0 2139 ancount += ntohs(hp->ancount);
michael@0 2140
michael@0 2141 t->n = n;
michael@0 2142 }
michael@0 2143
michael@0 2144 if (ancount == 0) {
michael@0 2145 switch (rcode) {
michael@0 2146 case NXDOMAIN:
michael@0 2147 h_errno = HOST_NOT_FOUND;
michael@0 2148 break;
michael@0 2149 case SERVFAIL:
michael@0 2150 h_errno = TRY_AGAIN;
michael@0 2151 break;
michael@0 2152 case NOERROR:
michael@0 2153 h_errno = NO_DATA;
michael@0 2154 break;
michael@0 2155 case FORMERR:
michael@0 2156 case NOTIMP:
michael@0 2157 case REFUSED:
michael@0 2158 default:
michael@0 2159 h_errno = NO_RECOVERY;
michael@0 2160 break;
michael@0 2161 }
michael@0 2162 return -1;
michael@0 2163 }
michael@0 2164 return ancount;
michael@0 2165 }
michael@0 2166
michael@0 2167 /*
michael@0 2168 * Formulate a normal query, send, and retrieve answer in supplied buffer.
michael@0 2169 * Return the size of the response on success, -1 on error.
michael@0 2170 * If enabled, implement search rules until answer or unrecoverable failure
michael@0 2171 * is detected. Error code, if any, is left in h_errno.
michael@0 2172 */
michael@0 2173 static int
michael@0 2174 res_searchN(const char *name, struct res_target *target, res_state res)
michael@0 2175 {
michael@0 2176 const char *cp, * const *domain;
michael@0 2177 HEADER *hp;
michael@0 2178 u_int dots;
michael@0 2179 int trailing_dot, ret, saved_herrno;
michael@0 2180 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
michael@0 2181
michael@0 2182 assert(name != NULL);
michael@0 2183 assert(target != NULL);
michael@0 2184
michael@0 2185 hp = (HEADER *)(void *)target->answer; /*XXX*/
michael@0 2186
michael@0 2187 errno = 0;
michael@0 2188 h_errno = HOST_NOT_FOUND; /* default, if we never query */
michael@0 2189 dots = 0;
michael@0 2190 for (cp = name; *cp; cp++)
michael@0 2191 dots += (*cp == '.');
michael@0 2192 trailing_dot = 0;
michael@0 2193 if (cp > name && *--cp == '.')
michael@0 2194 trailing_dot++;
michael@0 2195
michael@0 2196
michael@0 2197 //fprintf(stderr, "res_searchN() name = '%s'\n", name);
michael@0 2198
michael@0 2199 /*
michael@0 2200 * if there aren't any dots, it could be a user-level alias
michael@0 2201 */
michael@0 2202 if (!dots && (cp = __hostalias(name)) != NULL) {
michael@0 2203 ret = res_queryN(cp, target, res);
michael@0 2204 return ret;
michael@0 2205 }
michael@0 2206
michael@0 2207 /*
michael@0 2208 * If there are dots in the name already, let's just give it a try
michael@0 2209 * 'as is'. The threshold can be set with the "ndots" option.
michael@0 2210 */
michael@0 2211 saved_herrno = -1;
michael@0 2212 if (dots >= res->ndots) {
michael@0 2213 ret = res_querydomainN(name, NULL, target, res);
michael@0 2214 if (ret > 0)
michael@0 2215 return (ret);
michael@0 2216 saved_herrno = h_errno;
michael@0 2217 tried_as_is++;
michael@0 2218 }
michael@0 2219
michael@0 2220 /*
michael@0 2221 * We do at least one level of search if
michael@0 2222 * - there is no dot and RES_DEFNAME is set, or
michael@0 2223 * - there is at least one dot, there is no trailing dot,
michael@0 2224 * and RES_DNSRCH is set.
michael@0 2225 */
michael@0 2226 if ((!dots && (res->options & RES_DEFNAMES)) ||
michael@0 2227 (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
michael@0 2228 int done = 0;
michael@0 2229
michael@0 2230 for (domain = (const char * const *)res->dnsrch;
michael@0 2231 *domain && !done;
michael@0 2232 domain++) {
michael@0 2233
michael@0 2234 ret = res_querydomainN(name, *domain, target, res);
michael@0 2235 if (ret > 0)
michael@0 2236 return ret;
michael@0 2237
michael@0 2238 /*
michael@0 2239 * If no server present, give up.
michael@0 2240 * If name isn't found in this domain,
michael@0 2241 * keep trying higher domains in the search list
michael@0 2242 * (if that's enabled).
michael@0 2243 * On a NO_DATA error, keep trying, otherwise
michael@0 2244 * a wildcard entry of another type could keep us
michael@0 2245 * from finding this entry higher in the domain.
michael@0 2246 * If we get some other error (negative answer or
michael@0 2247 * server failure), then stop searching up,
michael@0 2248 * but try the input name below in case it's
michael@0 2249 * fully-qualified.
michael@0 2250 */
michael@0 2251 if (errno == ECONNREFUSED) {
michael@0 2252 h_errno = TRY_AGAIN;
michael@0 2253 return -1;
michael@0 2254 }
michael@0 2255
michael@0 2256 switch (h_errno) {
michael@0 2257 case NO_DATA:
michael@0 2258 got_nodata++;
michael@0 2259 /* FALLTHROUGH */
michael@0 2260 case HOST_NOT_FOUND:
michael@0 2261 /* keep trying */
michael@0 2262 break;
michael@0 2263 case TRY_AGAIN:
michael@0 2264 if (hp->rcode == SERVFAIL) {
michael@0 2265 /* try next search element, if any */
michael@0 2266 got_servfail++;
michael@0 2267 break;
michael@0 2268 }
michael@0 2269 /* FALLTHROUGH */
michael@0 2270 default:
michael@0 2271 /* anything else implies that we're done */
michael@0 2272 done++;
michael@0 2273 }
michael@0 2274 /*
michael@0 2275 * if we got here for some reason other than DNSRCH,
michael@0 2276 * we only wanted one iteration of the loop, so stop.
michael@0 2277 */
michael@0 2278 if (!(res->options & RES_DNSRCH))
michael@0 2279 done++;
michael@0 2280 }
michael@0 2281 }
michael@0 2282
michael@0 2283 /*
michael@0 2284 * if we have not already tried the name "as is", do that now.
michael@0 2285 * note that we do this regardless of how many dots were in the
michael@0 2286 * name or whether it ends with a dot.
michael@0 2287 */
michael@0 2288 if (!tried_as_is) {
michael@0 2289 ret = res_querydomainN(name, NULL, target, res);
michael@0 2290 if (ret > 0)
michael@0 2291 return ret;
michael@0 2292 }
michael@0 2293
michael@0 2294 /*
michael@0 2295 * if we got here, we didn't satisfy the search.
michael@0 2296 * if we did an initial full query, return that query's h_errno
michael@0 2297 * (note that we wouldn't be here if that query had succeeded).
michael@0 2298 * else if we ever got a nodata, send that back as the reason.
michael@0 2299 * else send back meaningless h_errno, that being the one from
michael@0 2300 * the last DNSRCH we did.
michael@0 2301 */
michael@0 2302 if (saved_herrno != -1)
michael@0 2303 h_errno = saved_herrno;
michael@0 2304 else if (got_nodata)
michael@0 2305 h_errno = NO_DATA;
michael@0 2306 else if (got_servfail)
michael@0 2307 h_errno = TRY_AGAIN;
michael@0 2308 return -1;
michael@0 2309 }
michael@0 2310
michael@0 2311 /*
michael@0 2312 * Perform a call on res_query on the concatenation of name and domain,
michael@0 2313 * removing a trailing dot from name if domain is NULL.
michael@0 2314 */
michael@0 2315 static int
michael@0 2316 res_querydomainN(const char *name, const char *domain,
michael@0 2317 struct res_target *target, res_state res)
michael@0 2318 {
michael@0 2319 char nbuf[MAXDNAME];
michael@0 2320 const char *longname = nbuf;
michael@0 2321 size_t n, d;
michael@0 2322
michael@0 2323 assert(name != NULL);
michael@0 2324 /* XXX: target may be NULL??? */
michael@0 2325
michael@0 2326 #ifdef DEBUG
michael@0 2327 if (res->options & RES_DEBUG)
michael@0 2328 printf(";; res_querydomain(%s, %s)\n",
michael@0 2329 name, domain?domain:"<Nil>");
michael@0 2330 #endif
michael@0 2331 if (domain == NULL) {
michael@0 2332 /*
michael@0 2333 * Check for trailing '.';
michael@0 2334 * copy without '.' if present.
michael@0 2335 */
michael@0 2336 n = strlen(name);
michael@0 2337 if (n + 1 > sizeof(nbuf)) {
michael@0 2338 h_errno = NO_RECOVERY;
michael@0 2339 return -1;
michael@0 2340 }
michael@0 2341 if (n > 0 && name[--n] == '.') {
michael@0 2342 strncpy(nbuf, name, n);
michael@0 2343 nbuf[n] = '\0';
michael@0 2344 } else
michael@0 2345 longname = name;
michael@0 2346 } else {
michael@0 2347 n = strlen(name);
michael@0 2348 d = strlen(domain);
michael@0 2349 if (n + 1 + d + 1 > sizeof(nbuf)) {
michael@0 2350 h_errno = NO_RECOVERY;
michael@0 2351 return -1;
michael@0 2352 }
michael@0 2353 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
michael@0 2354 }
michael@0 2355 return res_queryN(longname, target, res);
michael@0 2356 }

mercurial