blob: aa3b81abbcfa645d478257a333f565bc4d30e926 [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;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001302 } else {
Steinar H. Gundersona798b9f2010-12-20 11:15:33 +01001303 /*
1304 * According to draft-ietf-6man-rfc3484-revise-01 section 2.3,
1305 * it is best not to treat the private IPv4 ranges
1306 * (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) as being
1307 * in a special scope, so we don't.
1308 */
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001309 return IPV6_ADDR_SCOPE_GLOBAL;
1310 }
1311 } else {
1312 /*
1313 * This should never happen.
1314 * Return a scope with low priority as a last resort.
1315 */
1316 return IPV6_ADDR_SCOPE_NODELOCAL;
1317 }
1318}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001319
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001320/* These macros are modelled after the ones in <netinet/in6.h>. */
1321
1322/* RFC 4380, section 2.6 */
1323#define IN6_IS_ADDR_TEREDO(a) \
1324 ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == ntohl(0x20010000)))
1325
1326/* RFC 3056, section 2. */
1327#define IN6_IS_ADDR_6TO4(a) \
1328 (((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02))
1329
1330/*
1331 * Get the label for a given IPv4/IPv6 address.
1332 * RFC 3484, section 2.1, plus Teredo added in with label 5.
1333 */
1334
1335/*ARGSUSED*/
1336static int
1337_get_label(const struct sockaddr *addr)
1338{
1339 if (addr->sa_family == AF_INET) {
1340 return 4;
1341 } else if (addr->sa_family == AF_INET6) {
1342 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
1343 if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
1344 return 0;
1345 } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
1346 return 3;
1347 } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
1348 return 5;
1349 } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
1350 return 2;
1351 } else {
1352 return 1;
1353 }
1354 } else {
1355 /*
1356 * This should never happen.
1357 * Return a semi-random label as a last resort.
1358 */
1359 return 1;
1360 }
1361}
1362
1363/*
1364 * Get the precedence for a given IPv4/IPv6 address.
1365 * RFC 3484, section 2.1, plus Teredo added in with precedence 25.
1366 */
1367
1368/*ARGSUSED*/
1369static int
1370_get_precedence(const struct sockaddr *addr)
1371{
1372 if (addr->sa_family == AF_INET) {
1373 return 10;
1374 } else if (addr->sa_family == AF_INET6) {
1375 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
1376 if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
1377 return 50;
1378 } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
1379 return 20;
1380 } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
1381 return 25;
1382 } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
1383 return 30;
1384 } else {
1385 return 40;
1386 }
1387 } else {
1388 return 5;
1389 }
1390}
1391
1392/*
1393 * Find number of matching initial bits between the two addresses a1 and a2.
1394 */
1395
1396/*ARGSUSED*/
1397static int
1398_common_prefix_len(const struct in6_addr *a1, const struct in6_addr *a2)
1399{
1400 const char *p1 = (const char *)a1;
1401 const char *p2 = (const char *)a2;
1402 unsigned i;
1403
1404 for (i = 0; i < sizeof(*a1); ++i) {
1405 int x, j;
1406
1407 if (p1[i] == p2[i]) {
1408 continue;
1409 }
1410 x = p1[i] ^ p2[i];
1411 for (j = 0; j < CHAR_BIT; ++j) {
1412 if (x & (1 << (CHAR_BIT - 1))) {
1413 return i * CHAR_BIT + j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001414 }
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001415 x <<= 1;
1416 }
1417 }
1418 return sizeof(*a1) * CHAR_BIT;
1419}
1420
1421/*
1422 * Compare two source/destination address pairs.
1423 * RFC 3484, section 6.
1424 */
1425
1426/*ARGSUSED*/
1427static int
1428_rfc3484_compare(const void *ptr1, const void* ptr2)
1429{
1430 const struct addrinfo_sort_elem *a1 = (const struct addrinfo_sort_elem *)ptr1;
1431 const struct addrinfo_sort_elem *a2 = (const struct addrinfo_sort_elem *)ptr2;
1432 int scope_src1, scope_dst1, scope_match1;
1433 int scope_src2, scope_dst2, scope_match2;
1434 int label_src1, label_dst1, label_match1;
1435 int label_src2, label_dst2, label_match2;
1436 int precedence1, precedence2;
1437 int prefixlen1, prefixlen2;
1438
1439 /* Rule 1: Avoid unusable destinations. */
1440 if (a1->has_src_addr != a2->has_src_addr) {
1441 return a2->has_src_addr - a1->has_src_addr;
1442 }
1443
1444 /* Rule 2: Prefer matching scope. */
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001445 scope_src1 = _get_scope(&a1->src_addr.generic);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001446 scope_dst1 = _get_scope(a1->ai->ai_addr);
1447 scope_match1 = (scope_src1 == scope_dst1);
1448
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001449 scope_src2 = _get_scope(&a2->src_addr.generic);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001450 scope_dst2 = _get_scope(a2->ai->ai_addr);
1451 scope_match2 = (scope_src2 == scope_dst2);
1452
1453 if (scope_match1 != scope_match2) {
1454 return scope_match2 - scope_match1;
1455 }
1456
1457 /*
1458 * Rule 3: Avoid deprecated addresses.
1459 * TODO(sesse): We don't currently have a good way of finding this.
1460 */
1461
1462 /*
1463 * Rule 4: Prefer home addresses.
1464 * TODO(sesse): We don't currently have a good way of finding this.
1465 */
1466
1467 /* Rule 5: Prefer matching label. */
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001468 label_src1 = _get_label(&a1->src_addr.generic);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001469 label_dst1 = _get_label(a1->ai->ai_addr);
1470 label_match1 = (label_src1 == label_dst1);
1471
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001472 label_src2 = _get_label(&a2->src_addr.generic);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001473 label_dst2 = _get_label(a2->ai->ai_addr);
1474 label_match2 = (label_src2 == label_dst2);
1475
1476 if (label_match1 != label_match2) {
1477 return label_match2 - label_match1;
1478 }
1479
1480 /* Rule 6: Prefer higher precedence. */
1481 precedence1 = _get_precedence(a1->ai->ai_addr);
1482 precedence2 = _get_precedence(a2->ai->ai_addr);
1483 if (precedence1 != precedence2) {
1484 return precedence2 - precedence1;
1485 }
1486
1487 /*
1488 * Rule 7: Prefer native transport.
1489 * TODO(sesse): We don't currently have a good way of finding this.
1490 */
1491
1492 /* Rule 8: Prefer smaller scope. */
1493 if (scope_dst1 != scope_dst2) {
1494 return scope_dst1 - scope_dst2;
1495 }
1496
1497 /*
1498 * Rule 9: Use longest matching prefix.
1499 * We implement this for IPv6 only, as the rules in RFC 3484 don't seem
1500 * to work very well directly applied to IPv4. (glibc uses information from
1501 * the routing table for a custom IPv4 implementation here.)
1502 */
1503 if (a1->has_src_addr && a1->ai->ai_addr->sa_family == AF_INET6 &&
1504 a2->has_src_addr && a2->ai->ai_addr->sa_family == AF_INET6) {
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001505 const struct sockaddr_in6 *a1_src = &a1->src_addr.in6;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001506 const struct sockaddr_in6 *a1_dst = (const struct sockaddr_in6 *)a1->ai->ai_addr;
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001507 const struct sockaddr_in6 *a2_src = &a2->src_addr.in6;
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001508 const struct sockaddr_in6 *a2_dst = (const struct sockaddr_in6 *)a2->ai->ai_addr;
1509 prefixlen1 = _common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr);
Kenny Root7e0bfb52010-03-24 18:06:20 -07001510 prefixlen2 = _common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001511 if (prefixlen1 != prefixlen2) {
1512 return prefixlen2 - prefixlen1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001513 }
1514 }
1515
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001516 /*
1517 * Rule 10: Leave the order unchanged.
1518 * We need this since qsort() is not necessarily stable.
1519 */
1520 return a1->original_order - a2->original_order;
1521}
1522
1523/*
1524 * Find the source address that will be used if trying to connect to the given
1525 * address. src_addr must be large enough to hold a struct sockaddr_in6.
1526 *
1527 * Returns 1 if a source address was found, 0 if the address is unreachable,
1528 * and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are
1529 * undefined.
1530 */
1531
1532/*ARGSUSED*/
1533static int
1534_find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr)
1535{
1536 int sock;
1537 int ret;
1538 socklen_t len;
1539
1540 switch (addr->sa_family) {
1541 case AF_INET:
1542 len = sizeof(struct sockaddr_in);
1543 break;
1544 case AF_INET6:
1545 len = sizeof(struct sockaddr_in6);
1546 break;
1547 default:
1548 /* No known usable source address for non-INET families. */
1549 return 0;
1550 }
1551
1552 sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
1553 if (sock == -1) {
1554 if (errno == EAFNOSUPPORT) {
1555 return 0;
1556 } else {
1557 return -1;
1558 }
1559 }
1560
1561 do {
1562 ret = connect(sock, addr, len);
1563 } while (ret == -1 && errno == EINTR);
1564
1565 if (ret == -1) {
1566 close(sock);
1567 return 0;
1568 }
1569
1570 if (getsockname(sock, src_addr, &len) == -1) {
1571 close(sock);
1572 return -1;
1573 }
1574 close(sock);
1575 return 1;
1576}
1577
1578/*
1579 * Sort the linked list starting at sentinel->ai_next in RFC3484 order.
1580 * Will leave the list unchanged if an error occurs.
1581 */
1582
1583/*ARGSUSED*/
1584static void
1585_rfc3484_sort(struct addrinfo *list_sentinel)
1586{
1587 struct addrinfo *cur;
1588 int nelem = 0, i;
1589 struct addrinfo_sort_elem *elems;
1590
1591 cur = list_sentinel->ai_next;
1592 while (cur) {
1593 ++nelem;
1594 cur = cur->ai_next;
1595 }
1596
1597 elems = (struct addrinfo_sort_elem *)malloc(nelem * sizeof(struct addrinfo_sort_elem));
1598 if (elems == NULL) {
1599 goto error;
1600 }
1601
1602 /*
1603 * Convert the linked list to an array that also contains the candidate
1604 * source address for each destination address.
1605 */
1606 for (i = 0, cur = list_sentinel->ai_next; i < nelem; ++i, cur = cur->ai_next) {
1607 int has_src_addr;
1608 assert(cur != NULL);
1609 elems[i].ai = cur;
1610 elems[i].original_order = i;
1611
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -07001612 has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic);
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001613 if (has_src_addr == -1) {
1614 goto error;
1615 }
1616 elems[i].has_src_addr = has_src_addr;
1617 }
1618
1619 /* Sort the addresses, and rearrange the linked list so it matches the sorted order. */
1620 qsort((void *)elems, nelem, sizeof(struct addrinfo_sort_elem), _rfc3484_compare);
1621
1622 list_sentinel->ai_next = elems[0].ai;
1623 for (i = 0; i < nelem - 1; ++i) {
1624 elems[i].ai->ai_next = elems[i + 1].ai;
1625 }
1626 elems[nelem - 1].ai->ai_next = NULL;
1627
1628error:
1629 free(elems);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001630}
1631
1632/*ARGSUSED*/
1633static int
1634_dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
1635{
1636 struct addrinfo *ai;
1637 querybuf *buf, *buf2;
1638 const char *name;
1639 const struct addrinfo *pai;
1640 struct addrinfo sentinel, *cur;
1641 struct res_target q, q2;
1642 res_state res;
1643
1644 name = va_arg(ap, char *);
1645 pai = va_arg(ap, const struct addrinfo *);
David 'Digit' Turner5e563702009-05-05 15:50:24 +02001646 //fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001647
1648 memset(&q, 0, sizeof(q));
1649 memset(&q2, 0, sizeof(q2));
1650 memset(&sentinel, 0, sizeof(sentinel));
1651 cur = &sentinel;
1652
1653 buf = malloc(sizeof(*buf));
1654 if (buf == NULL) {
1655 h_errno = NETDB_INTERNAL;
1656 return NS_NOTFOUND;
1657 }
1658 buf2 = malloc(sizeof(*buf2));
1659 if (buf2 == NULL) {
1660 free(buf);
1661 h_errno = NETDB_INTERNAL;
1662 return NS_NOTFOUND;
1663 }
1664
1665 switch (pai->ai_family) {
1666 case AF_UNSPEC:
1667 /* prefer IPv6 */
1668 q.name = name;
1669 q.qclass = C_IN;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001670 q.answer = buf->buf;
1671 q.anslen = sizeof(buf->buf);
Lorenzo Colitti3d8f4ad2009-08-03 22:36:31 -07001672 /* If AI_ADDRCONFIG, lookup IPv6 only if we have connectivity */
1673 if (!(pai->ai_flags & AI_ADDRCONFIG) || _have_ipv6()) {
1674 q.qtype = T_AAAA;
1675 q.next = &q2;
1676 q2.name = name;
1677 q2.qclass = C_IN;
1678 q2.qtype = T_A;
1679 q2.answer = buf2->buf;
1680 q2.anslen = sizeof(buf2->buf);
1681 } else {
1682 q.qtype = T_A;
1683 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001684 break;
1685 case AF_INET:
1686 q.name = name;
1687 q.qclass = C_IN;
1688 q.qtype = T_A;
1689 q.answer = buf->buf;
1690 q.anslen = sizeof(buf->buf);
1691 break;
1692 case AF_INET6:
1693 q.name = name;
1694 q.qclass = C_IN;
1695 q.qtype = T_AAAA;
1696 q.answer = buf->buf;
1697 q.anslen = sizeof(buf->buf);
1698 break;
1699 default:
1700 free(buf);
1701 free(buf2);
1702 return NS_UNAVAIL;
1703 }
1704
1705 res = __res_get_state();
1706 if (res == NULL) {
1707 free(buf);
1708 free(buf2);
1709 return NS_NOTFOUND;
1710 }
1711
1712 if (res_searchN(name, &q, res) < 0) {
1713 __res_put_state(res);
1714 free(buf);
1715 free(buf2);
1716 return NS_NOTFOUND;
1717 }
1718 ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1719 if (ai) {
1720 cur->ai_next = ai;
1721 while (cur && cur->ai_next)
1722 cur = cur->ai_next;
1723 }
1724 if (q.next) {
1725 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1726 if (ai)
1727 cur->ai_next = ai;
1728 }
1729 free(buf);
1730 free(buf2);
1731 if (sentinel.ai_next == NULL) {
1732 __res_put_state(res);
1733 switch (h_errno) {
1734 case HOST_NOT_FOUND:
1735 return NS_NOTFOUND;
1736 case TRY_AGAIN:
1737 return NS_TRYAGAIN;
1738 default:
1739 return NS_UNAVAIL;
1740 }
1741 }
1742
Steinar H. Gunderson9ab75d42010-02-11 15:44:55 +01001743 _rfc3484_sort(&sentinel);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001744
1745 __res_put_state(res);
1746
1747 *((struct addrinfo **)rv) = sentinel.ai_next;
1748 return NS_SUCCESS;
1749}
1750
1751static void
1752_sethtent(FILE **hostf)
1753{
1754
1755 if (!*hostf)
1756 *hostf = fopen(_PATH_HOSTS, "r" );
1757 else
1758 rewind(*hostf);
1759}
1760
1761static void
1762_endhtent(FILE **hostf)
1763{
1764
1765 if (*hostf) {
1766 (void) fclose(*hostf);
1767 *hostf = NULL;
1768 }
1769}
1770
1771static struct addrinfo *
1772_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
1773{
1774 char *p;
1775 char *cp, *tname, *cname;
1776 struct addrinfo hints, *res0, *res;
1777 int error;
1778 const char *addr;
1779 char hostbuf[8*1024];
1780
1781// fprintf(stderr, "_gethtent() name = '%s'\n", name);
1782 assert(name != NULL);
1783 assert(pai != NULL);
1784
1785 if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" )))
1786 return (NULL);
1787 again:
1788 if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf)))
1789 return (NULL);
1790 if (*p == '#')
1791 goto again;
1792 if (!(cp = strpbrk(p, "#\n")))
1793 goto again;
1794 *cp = '\0';
1795 if (!(cp = strpbrk(p, " \t")))
1796 goto again;
1797 *cp++ = '\0';
1798 addr = p;
1799 /* if this is not something we're looking for, skip it. */
1800 cname = NULL;
1801 while (cp && *cp) {
1802 if (*cp == ' ' || *cp == '\t') {
1803 cp++;
1804 continue;
1805 }
1806 if (!cname)
1807 cname = cp;
1808 tname = cp;
1809 if ((cp = strpbrk(cp, " \t")) != NULL)
1810 *cp++ = '\0';
1811// fprintf(stderr, "\ttname = '%s'", tname);
1812 if (strcasecmp(name, tname) == 0)
1813 goto found;
1814 }
1815 goto again;
1816
1817found:
1818 hints = *pai;
1819 hints.ai_flags = AI_NUMERICHOST;
1820 error = getaddrinfo(addr, NULL, &hints, &res0);
1821 if (error)
1822 goto again;
1823 for (res = res0; res; res = res->ai_next) {
1824 /* cover it up */
1825 res->ai_flags = pai->ai_flags;
1826
1827 if (pai->ai_flags & AI_CANONNAME) {
1828 if (get_canonname(pai, res, cname) != 0) {
1829 freeaddrinfo(res0);
1830 goto again;
1831 }
1832 }
1833 }
1834 return res0;
1835}
1836
1837/*ARGSUSED*/
1838static int
1839_files_getaddrinfo(void *rv, void *cb_data, va_list ap)
1840{
1841 const char *name;
1842 const struct addrinfo *pai;
1843 struct addrinfo sentinel, *cur;
1844 struct addrinfo *p;
1845 FILE *hostf = NULL;
1846
1847 name = va_arg(ap, char *);
1848 pai = va_arg(ap, struct addrinfo *);
1849
1850// fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name);
1851 memset(&sentinel, 0, sizeof(sentinel));
1852 cur = &sentinel;
1853
1854 _sethtent(&hostf);
1855 while ((p = _gethtent(&hostf, name, pai)) != NULL) {
1856 cur->ai_next = p;
1857 while (cur && cur->ai_next)
1858 cur = cur->ai_next;
1859 }
1860 _endhtent(&hostf);
1861
1862 *((struct addrinfo **)rv) = sentinel.ai_next;
1863 if (sentinel.ai_next == NULL)
1864 return NS_NOTFOUND;
1865 return NS_SUCCESS;
1866}
1867
1868/* resolver logic */
1869
1870/*
1871 * Formulate a normal query, send, and await answer.
1872 * Returned answer is placed in supplied buffer "answer".
1873 * Perform preliminary check of answer, returning success only
1874 * if no error is indicated and the answer count is nonzero.
1875 * Return the size of the response on success, -1 on error.
1876 * Error number is left in h_errno.
1877 *
1878 * Caller must parse answer and determine whether it answers the question.
1879 */
1880static int
1881res_queryN(const char *name, /* domain name */ struct res_target *target,
1882 res_state res)
1883{
1884 u_char buf[MAXPACKET];
1885 HEADER *hp;
1886 int n;
1887 struct res_target *t;
1888 int rcode;
1889 int ancount;
1890
1891 assert(name != NULL);
1892 /* XXX: target may be NULL??? */
1893
1894 rcode = NOERROR;
1895 ancount = 0;
1896
1897 for (t = target; t; t = t->next) {
1898 int class, type;
1899 u_char *answer;
1900 int anslen;
1901
1902 hp = (HEADER *)(void *)t->answer;
1903 hp->rcode = NOERROR; /* default */
1904
1905 /* make it easier... */
1906 class = t->qclass;
1907 type = t->qtype;
1908 answer = t->answer;
1909 anslen = t->anslen;
1910#ifdef DEBUG
1911 if (res->options & RES_DEBUG)
1912 printf(";; res_nquery(%s, %d, %d)\n", name, class, type);
1913#endif
1914
1915 n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
1916 buf, sizeof(buf));
1917#ifdef RES_USE_EDNS0
1918 if (n > 0 && (res->options & RES_USE_EDNS0) != 0)
1919 n = res_nopt(res, n, buf, sizeof(buf), anslen);
1920#endif
1921 if (n <= 0) {
1922#ifdef DEBUG
1923 if (res->options & RES_DEBUG)
1924 printf(";; res_nquery: mkquery failed\n");
1925#endif
1926 h_errno = NO_RECOVERY;
1927 return n;
1928 }
1929 n = res_nsend(res, buf, n, answer, anslen);
1930#if 0
1931 if (n < 0) {
1932#ifdef DEBUG
1933 if (res->options & RES_DEBUG)
1934 printf(";; res_query: send error\n");
1935#endif
1936 h_errno = TRY_AGAIN;
1937 return n;
1938 }
1939#endif
1940
1941 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1942 rcode = hp->rcode; /* record most recent error */
1943#ifdef DEBUG
1944 if (res->options & RES_DEBUG)
1945 printf(";; rcode = %u, ancount=%u\n", hp->rcode,
1946 ntohs(hp->ancount));
1947#endif
1948 continue;
1949 }
1950
1951 ancount += ntohs(hp->ancount);
1952
1953 t->n = n;
1954 }
1955
1956 if (ancount == 0) {
1957 switch (rcode) {
1958 case NXDOMAIN:
1959 h_errno = HOST_NOT_FOUND;
1960 break;
1961 case SERVFAIL:
1962 h_errno = TRY_AGAIN;
1963 break;
1964 case NOERROR:
1965 h_errno = NO_DATA;
1966 break;
1967 case FORMERR:
1968 case NOTIMP:
1969 case REFUSED:
1970 default:
1971 h_errno = NO_RECOVERY;
1972 break;
1973 }
1974 return -1;
1975 }
1976 return ancount;
1977}
1978
1979/*
1980 * Formulate a normal query, send, and retrieve answer in supplied buffer.
1981 * Return the size of the response on success, -1 on error.
1982 * If enabled, implement search rules until answer or unrecoverable failure
1983 * is detected. Error code, if any, is left in h_errno.
1984 */
1985static int
1986res_searchN(const char *name, struct res_target *target, res_state res)
1987{
1988 const char *cp, * const *domain;
1989 HEADER *hp;
1990 u_int dots;
1991 int trailing_dot, ret, saved_herrno;
1992 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1993
1994 assert(name != NULL);
1995 assert(target != NULL);
1996
1997 hp = (HEADER *)(void *)target->answer; /*XXX*/
1998
1999 errno = 0;
2000 h_errno = HOST_NOT_FOUND; /* default, if we never query */
2001 dots = 0;
2002 for (cp = name; *cp; cp++)
2003 dots += (*cp == '.');
2004 trailing_dot = 0;
2005 if (cp > name && *--cp == '.')
2006 trailing_dot++;
2007
2008
David 'Digit' Turner5e563702009-05-05 15:50:24 +02002009 //fprintf(stderr, "res_searchN() name = '%s'\n", name);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002010
2011 /*
2012 * if there aren't any dots, it could be a user-level alias
2013 */
2014 if (!dots && (cp = __hostalias(name)) != NULL) {
2015 ret = res_queryN(cp, target, res);
2016 return ret;
2017 }
2018
2019 /*
2020 * If there are dots in the name already, let's just give it a try
2021 * 'as is'. The threshold can be set with the "ndots" option.
2022 */
2023 saved_herrno = -1;
2024 if (dots >= res->ndots) {
2025 ret = res_querydomainN(name, NULL, target, res);
2026 if (ret > 0)
2027 return (ret);
2028 saved_herrno = h_errno;
2029 tried_as_is++;
2030 }
2031
2032 /*
2033 * We do at least one level of search if
2034 * - there is no dot and RES_DEFNAME is set, or
2035 * - there is at least one dot, there is no trailing dot,
2036 * and RES_DNSRCH is set.
2037 */
2038 if ((!dots && (res->options & RES_DEFNAMES)) ||
2039 (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
2040 int done = 0;
2041
2042 for (domain = (const char * const *)res->dnsrch;
2043 *domain && !done;
2044 domain++) {
2045
2046 ret = res_querydomainN(name, *domain, target, res);
2047 if (ret > 0)
2048 return ret;
2049
2050 /*
2051 * If no server present, give up.
2052 * If name isn't found in this domain,
2053 * keep trying higher domains in the search list
2054 * (if that's enabled).
2055 * On a NO_DATA error, keep trying, otherwise
2056 * a wildcard entry of another type could keep us
2057 * from finding this entry higher in the domain.
2058 * If we get some other error (negative answer or
2059 * server failure), then stop searching up,
2060 * but try the input name below in case it's
2061 * fully-qualified.
2062 */
2063 if (errno == ECONNREFUSED) {
2064 h_errno = TRY_AGAIN;
2065 return -1;
2066 }
2067
2068 switch (h_errno) {
2069 case NO_DATA:
2070 got_nodata++;
2071 /* FALLTHROUGH */
2072 case HOST_NOT_FOUND:
2073 /* keep trying */
2074 break;
2075 case TRY_AGAIN:
2076 if (hp->rcode == SERVFAIL) {
2077 /* try next search element, if any */
2078 got_servfail++;
2079 break;
2080 }
2081 /* FALLTHROUGH */
2082 default:
2083 /* anything else implies that we're done */
2084 done++;
2085 }
2086 /*
2087 * if we got here for some reason other than DNSRCH,
2088 * we only wanted one iteration of the loop, so stop.
2089 */
2090 if (!(res->options & RES_DNSRCH))
2091 done++;
2092 }
2093 }
2094
2095 /*
2096 * if we have not already tried the name "as is", do that now.
2097 * note that we do this regardless of how many dots were in the
2098 * name or whether it ends with a dot.
2099 */
2100 if (!tried_as_is) {
2101 ret = res_querydomainN(name, NULL, target, res);
2102 if (ret > 0)
2103 return ret;
2104 }
2105
2106 /*
2107 * if we got here, we didn't satisfy the search.
2108 * if we did an initial full query, return that query's h_errno
2109 * (note that we wouldn't be here if that query had succeeded).
2110 * else if we ever got a nodata, send that back as the reason.
2111 * else send back meaningless h_errno, that being the one from
2112 * the last DNSRCH we did.
2113 */
2114 if (saved_herrno != -1)
2115 h_errno = saved_herrno;
2116 else if (got_nodata)
2117 h_errno = NO_DATA;
2118 else if (got_servfail)
2119 h_errno = TRY_AGAIN;
2120 return -1;
2121}
2122
2123/*
2124 * Perform a call on res_query on the concatenation of name and domain,
2125 * removing a trailing dot from name if domain is NULL.
2126 */
2127static int
2128res_querydomainN(const char *name, const char *domain,
2129 struct res_target *target, res_state res)
2130{
2131 char nbuf[MAXDNAME];
2132 const char *longname = nbuf;
2133 size_t n, d;
2134
2135 assert(name != NULL);
2136 /* XXX: target may be NULL??? */
2137
2138#ifdef DEBUG
2139 if (res->options & RES_DEBUG)
2140 printf(";; res_querydomain(%s, %s)\n",
2141 name, domain?domain:"<Nil>");
2142#endif
2143 if (domain == NULL) {
2144 /*
2145 * Check for trailing '.';
2146 * copy without '.' if present.
2147 */
2148 n = strlen(name);
2149 if (n + 1 > sizeof(nbuf)) {
2150 h_errno = NO_RECOVERY;
2151 return -1;
2152 }
2153 if (n > 0 && name[--n] == '.') {
2154 strncpy(nbuf, name, n);
2155 nbuf[n] = '\0';
2156 } else
2157 longname = name;
2158 } else {
2159 n = strlen(name);
2160 d = strlen(domain);
2161 if (n + 1 + d + 1 > sizeof(nbuf)) {
2162 h_errno = NO_RECOVERY;
2163 return -1;
2164 }
2165 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
2166 }
2167 return res_queryN(longname, target, res);
2168}