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