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