getaddrinfo.c revision 1.102 1 /* $NetBSD: getaddrinfo.c,v 1.102 2013/05/03 19:24:52 christos 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 * - Return values. There are nonstandard return values defined and used
36 * in the source code. This is because RFC2553 is silent about which error
37 * code must be returned for which situation.
38 * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
39 * says to use inet_aton() to convert IPv4 numeric to binary (alows
40 * classful form as a result).
41 * current code - disallow classful form for IPv4 (due to use of inet_pton).
42 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
43 * invalid.
44 * current code - SEGV on freeaddrinfo(NULL)
45 * Note:
46 * - The code filters out AFs that are not supported by the kernel,
47 * when globbing NULL hostname (to loopback, or wildcard). Is it the right
48 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
49 * in ai_flags?
50 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
51 * (1) what should we do against numeric hostname (2) what should we do
52 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
53 * non-loopback address configured? global address configured?
54 */
55
56 #include <sys/cdefs.h>
57 #if defined(LIBC_SCCS) && !defined(lint)
58 __RCSID("$NetBSD: getaddrinfo.c,v 1.102 2013/05/03 19:24:52 christos Exp $");
59 #endif /* LIBC_SCCS and not lint */
60
61 #include "namespace.h"
62 #include <sys/types.h>
63 #include <sys/param.h>
64 #include <sys/socket.h>
65 #include <net/if.h>
66 #include <netinet/in.h>
67 #include <arpa/inet.h>
68 #include <arpa/nameser.h>
69 #include <assert.h>
70 #include <ctype.h>
71 #include <errno.h>
72 #include <netdb.h>
73 #include <resolv.h>
74 #include <stddef.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <string.h>
78 #include <unistd.h>
79 #include <ifaddrs.h>
80
81 #include <syslog.h>
82 #include <stdarg.h>
83 #include <nsswitch.h>
84
85 #ifdef YP
86 #include <rpc/rpc.h>
87 #include <rpcsvc/yp_prot.h>
88 #include <rpcsvc/ypclnt.h>
89 #endif
90
91 #include "servent.h"
92
93 #ifdef __weak_alias
94 __weak_alias(getaddrinfo,_getaddrinfo)
95 __weak_alias(freeaddrinfo,_freeaddrinfo)
96 __weak_alias(gai_strerror,_gai_strerror)
97 #endif
98
99 #define SUCCESS 0
100 #define ANY 0
101 #define YES 1
102 #define NO 0
103
104 static const char in_addrany[] = { 0, 0, 0, 0 };
105 static const char in_loopback[] = { 127, 0, 0, 1 };
106 #ifdef INET6
107 static const char in6_addrany[] = {
108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
109 };
110 static const char in6_loopback[] = {
111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
112 };
113 #endif
114
115 static const struct afd {
116 int a_af;
117 int a_addrlen;
118 int a_socklen;
119 int a_off;
120 const char *a_addrany;
121 const char *a_loopback;
122 int a_scoped;
123 } afdl [] = {
124 #ifdef INET6
125 {PF_INET6, sizeof(struct in6_addr),
126 sizeof(struct sockaddr_in6),
127 offsetof(struct sockaddr_in6, sin6_addr),
128 in6_addrany, in6_loopback, 1},
129 #endif
130 {PF_INET, sizeof(struct in_addr),
131 sizeof(struct sockaddr_in),
132 offsetof(struct sockaddr_in, sin_addr),
133 in_addrany, in_loopback, 0},
134 {0, 0, 0, 0, NULL, NULL, 0},
135 };
136
137 struct explore {
138 int e_af;
139 int e_socktype;
140 int e_protocol;
141 const char *e_protostr;
142 int e_wild;
143 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
144 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
145 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
146 };
147
148 static const struct explore explore[] = {
149 #if 0
150 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
151 #endif
152 #ifdef INET6
153 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
154 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
155 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
156 #endif
157 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
158 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
159 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
160 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
161 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
162 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
163 { -1, 0, 0, NULL, 0 },
164 };
165
166 #ifdef INET6
167 #define PTON_MAX 16
168 #else
169 #define PTON_MAX 4
170 #endif
171
172 static const ns_src default_dns_files[] = {
173 { NSSRC_FILES, NS_SUCCESS },
174 { NSSRC_DNS, NS_SUCCESS },
175 { 0, 0 }
176 };
177
178 #define MAXPACKET (64*1024)
179
180 typedef union {
181 HEADER hdr;
182 u_char buf[MAXPACKET];
183 } querybuf;
184
185 struct res_target {
186 struct res_target *next;
187 const char *name; /* domain name */
188 int qclass, qtype; /* class and type of query */
189 u_char *answer; /* buffer to put answer */
190 int anslen; /* size of answer buffer */
191 int n; /* result length */
192 };
193
194 static int str2number(const char *);
195 static int explore_fqdn(const struct addrinfo *, const char *,
196 const char *, struct addrinfo **, struct servent_data *);
197 static int explore_null(const struct addrinfo *,
198 const char *, struct addrinfo **, struct servent_data *);
199 static int explore_numeric(const struct addrinfo *, const char *,
200 const char *, struct addrinfo **, const char *, struct servent_data *);
201 static int explore_numeric_scope(const struct addrinfo *, const char *,
202 const char *, struct addrinfo **, struct servent_data *);
203 static int get_canonname(const struct addrinfo *,
204 struct addrinfo *, const char *);
205 static struct addrinfo *get_ai(const struct addrinfo *,
206 const struct afd *, const char *);
207 static int get_portmatch(const struct addrinfo *, const char *,
208 struct servent_data *);
209 static int get_port(const struct addrinfo *, const char *, int,
210 struct servent_data *);
211 static const struct afd *find_afd(int);
212 static int addrconfig(uint64_t *);
213 #ifdef INET6
214 static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
215 #endif
216
217 static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
218 const struct addrinfo *);
219 static void aisort(struct addrinfo *s, res_state res);
220 static int _dns_getaddrinfo(void *, void *, va_list);
221 static void _sethtent(FILE **);
222 static void _endhtent(FILE **);
223 static struct addrinfo *_gethtent(FILE **, const char *,
224 const struct addrinfo *);
225 static int _files_getaddrinfo(void *, void *, va_list);
226 #ifdef YP
227 static struct addrinfo *_yphostent(char *, const struct addrinfo *);
228 static int _yp_getaddrinfo(void *, void *, va_list);
229 #endif
230
231 static int res_queryN(const char *, struct res_target *, res_state);
232 static int res_searchN(const char *, struct res_target *, res_state);
233 static int res_querydomainN(const char *, const char *,
234 struct res_target *, res_state);
235
236 static const char * const ai_errlist[] = {
237 "Success",
238 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
239 "Temporary failure in name resolution", /* EAI_AGAIN */
240 "Invalid value for ai_flags", /* EAI_BADFLAGS */
241 "Non-recoverable failure in name resolution", /* EAI_FAIL */
242 "ai_family not supported", /* EAI_FAMILY */
243 "Memory allocation failure", /* EAI_MEMORY */
244 "No address associated with hostname", /* EAI_NODATA */
245 "hostname nor servname provided, or not known", /* EAI_NONAME */
246 "servname not supported for ai_socktype", /* EAI_SERVICE */
247 "ai_socktype not supported", /* EAI_SOCKTYPE */
248 "System error returned in errno", /* EAI_SYSTEM */
249 "Invalid value for hints", /* EAI_BADHINTS */
250 "Resolved protocol is unknown", /* EAI_PROTOCOL */
251 "Argument buffer overflow", /* EAI_OVERFLOW */
252 "Unknown error", /* EAI_MAX */
253 };
254
255 /* XXX macros that make external reference is BAD. */
256
257 #define GET_AI(ai, afd, addr) \
258 do { \
259 /* external reference: pai, error, and label free */ \
260 (ai) = get_ai(pai, (afd), (addr)); \
261 if ((ai) == NULL) { \
262 error = EAI_MEMORY; \
263 goto free; \
264 } \
265 } while (/*CONSTCOND*/0)
266
267 #define GET_PORT(ai, serv, svd) \
268 do { \
269 /* external reference: error and label free */ \
270 error = get_port((ai), (serv), 0, (svd)); \
271 if (error != 0) \
272 goto free; \
273 } while (/*CONSTCOND*/0)
274
275 #define GET_CANONNAME(ai, str) \
276 do { \
277 /* external reference: pai, error and label free */ \
278 error = get_canonname(pai, (ai), (str)); \
279 if (error != 0) \
280 goto free; \
281 } while (/*CONSTCOND*/0)
282
283 #define ERR(err) \
284 do { \
285 /* external reference: error, and label bad */ \
286 error = (err); \
287 goto bad; \
288 /*NOTREACHED*/ \
289 } while (/*CONSTCOND*/0)
290
291 #define MATCH_FAMILY(x, y, w) \
292 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \
293 (y) == PF_UNSPEC)))
294 #define MATCH(x, y, w) \
295 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
296
297 const char *
298 gai_strerror(int ecode)
299 {
300 if (ecode < 0 || ecode > EAI_MAX)
301 ecode = EAI_MAX;
302 return ai_errlist[ecode];
303 }
304
305 void
306 freeaddrinfo(struct addrinfo *ai)
307 {
308 struct addrinfo *next;
309
310 _DIAGASSERT(ai != NULL);
311
312 do {
313 next = ai->ai_next;
314 if (ai->ai_canonname)
315 free(ai->ai_canonname);
316 /* no need to free(ai->ai_addr) */
317 free(ai);
318 ai = next;
319 } while (ai);
320 }
321
322 static int
323 str2number(const char *p)
324 {
325 char *ep;
326 unsigned long v;
327
328 _DIAGASSERT(p != NULL);
329
330 if (*p == '\0')
331 return -1;
332 ep = NULL;
333 errno = 0;
334 v = strtoul(p, &ep, 10);
335 if (errno == 0 && ep && *ep == '\0' && v <= INT_MAX)
336 return (int)v;
337 else
338 return -1;
339 }
340
341 int
342 getaddrinfo(const char *hostname, const char *servname,
343 const struct addrinfo *hints, struct addrinfo **res)
344 {
345 struct addrinfo sentinel;
346 struct addrinfo *cur;
347 int error = 0;
348 struct addrinfo ai;
349 struct addrinfo ai0;
350 struct addrinfo *pai;
351 const struct explore *ex;
352 struct servent_data svd;
353 uint64_t mask = (uint64_t)~0ULL;
354
355 /* hostname is allowed to be NULL */
356 /* servname is allowed to be NULL */
357 /* hints is allowed to be NULL */
358 _DIAGASSERT(res != NULL);
359
360 (void)memset(&svd, 0, sizeof(svd));
361 memset(&sentinel, 0, sizeof(sentinel));
362 cur = &sentinel;
363 memset(&ai, 0, sizeof(ai));
364 pai = &ai;
365 pai->ai_flags = 0;
366 pai->ai_family = PF_UNSPEC;
367 pai->ai_socktype = ANY;
368 pai->ai_protocol = ANY;
369 pai->ai_addrlen = 0;
370 pai->ai_canonname = NULL;
371 pai->ai_addr = NULL;
372 pai->ai_next = NULL;
373
374 if (hostname == NULL && servname == NULL)
375 return EAI_NONAME;
376 if (hints) {
377 /* error check for hints */
378 if (hints->ai_addrlen || hints->ai_canonname ||
379 hints->ai_addr || hints->ai_next)
380 ERR(EAI_BADHINTS); /* xxx */
381 if (hints->ai_flags & ~AI_MASK)
382 ERR(EAI_BADFLAGS);
383 switch (hints->ai_family) {
384 case PF_UNSPEC:
385 case PF_INET:
386 #ifdef INET6
387 case PF_INET6:
388 #endif
389 break;
390 default:
391 ERR(EAI_FAMILY);
392 }
393 memcpy(pai, hints, sizeof(*pai));
394
395 /*
396 * if both socktype/protocol are specified, check if they
397 * are meaningful combination.
398 */
399 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
400 for (ex = explore; ex->e_af >= 0; ex++) {
401 if (pai->ai_family != ex->e_af)
402 continue;
403 if (ex->e_socktype == ANY)
404 continue;
405 if (ex->e_protocol == ANY)
406 continue;
407 if (pai->ai_socktype == ex->e_socktype
408 && pai->ai_protocol != ex->e_protocol) {
409 ERR(EAI_BADHINTS);
410 }
411 }
412 }
413 }
414
415 if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && addrconfig(&mask) == -1)
416 ERR(EAI_FAIL);
417
418 /*
419 * check for special cases. (1) numeric servname is disallowed if
420 * socktype/protocol are left unspecified. (2) servname is disallowed
421 * for raw and other inet{,6} sockets.
422 */
423 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
424 #ifdef PF_INET6
425 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
426 #endif
427 ) {
428 ai0 = *pai; /* backup *pai */
429
430 if (pai->ai_family == PF_UNSPEC) {
431 #ifdef PF_INET6
432 pai->ai_family = PF_INET6;
433 #else
434 pai->ai_family = PF_INET;
435 #endif
436 }
437 error = get_portmatch(pai, servname, &svd);
438 if (error)
439 goto bad;
440
441 *pai = ai0;
442 }
443
444 ai0 = *pai;
445
446 /* NULL hostname, or numeric hostname */
447 for (ex = explore; ex->e_af >= 0; ex++) {
448 *pai = ai0;
449
450 /* ADDRCONFIG check */
451 if ((((uint64_t)1 << ex->e_af) & mask) == 0)
452 continue;
453
454 /* PF_UNSPEC entries are prepared for DNS queries only */
455 if (ex->e_af == PF_UNSPEC)
456 continue;
457
458 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
459 continue;
460 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
461 continue;
462 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
463 continue;
464 if (pai->ai_family == PF_UNSPEC)
465 pai->ai_family = ex->e_af;
466 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
467 pai->ai_socktype = ex->e_socktype;
468 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
469 pai->ai_protocol = ex->e_protocol;
470
471 if (hostname == NULL)
472 error = explore_null(pai, servname, &cur->ai_next,
473 &svd);
474 else
475 error = explore_numeric_scope(pai, hostname, servname,
476 &cur->ai_next, &svd);
477
478 if (error)
479 goto free;
480
481 while (cur->ai_next)
482 cur = cur->ai_next;
483 }
484
485 /*
486 * XXX
487 * If numeric representation of AF1 can be interpreted as FQDN
488 * representation of AF2, we need to think again about the code below.
489 */
490 if (sentinel.ai_next)
491 goto good;
492
493 if (hostname == NULL)
494 ERR(EAI_NODATA);
495 if (pai->ai_flags & AI_NUMERICHOST)
496 ERR(EAI_NONAME);
497
498 /*
499 * hostname as alphabetical name.
500 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
501 * outer loop by AFs.
502 */
503 for (ex = explore; ex->e_af >= 0; ex++) {
504 *pai = ai0;
505
506
507 /* ADDRCONFIG check */
508 /* PF_UNSPEC entries are prepared for DNS queries only */
509 if (ex->e_af != PF_UNSPEC &&
510 (((uint64_t)1 << ex->e_af) & mask) == 0)
511 continue;
512
513 /* require exact match for family field */
514 if (pai->ai_family != ex->e_af)
515 continue;
516
517 if (!MATCH(pai->ai_socktype, ex->e_socktype,
518 WILD_SOCKTYPE(ex))) {
519 continue;
520 }
521 if (!MATCH(pai->ai_protocol, ex->e_protocol,
522 WILD_PROTOCOL(ex))) {
523 continue;
524 }
525
526 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
527 pai->ai_socktype = ex->e_socktype;
528 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
529 pai->ai_protocol = ex->e_protocol;
530
531 error = explore_fqdn(pai, hostname, servname, &cur->ai_next,
532 &svd);
533
534 while (cur && cur->ai_next)
535 cur = cur->ai_next;
536 }
537
538 /* XXX */
539 if (sentinel.ai_next)
540 error = 0;
541
542 if (error)
543 goto free;
544
545 if (sentinel.ai_next) {
546 good:
547 endservent_r(&svd);
548 *res = sentinel.ai_next;
549 return SUCCESS;
550 } else
551 error = EAI_FAIL;
552 free:
553 bad:
554 endservent_r(&svd);
555 if (sentinel.ai_next)
556 freeaddrinfo(sentinel.ai_next);
557 *res = NULL;
558 return error;
559 }
560
561 /*
562 * FQDN hostname, DNS lookup
563 */
564 static int
565 explore_fqdn(const struct addrinfo *pai, const char *hostname,
566 const char *servname, struct addrinfo **res, struct servent_data *svd)
567 {
568 struct addrinfo *result;
569 struct addrinfo *cur;
570 int error = 0;
571 static const ns_dtab dtab[] = {
572 NS_FILES_CB(_files_getaddrinfo, NULL)
573 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
574 NS_NIS_CB(_yp_getaddrinfo, NULL)
575 NS_NULL_CB
576 };
577
578 _DIAGASSERT(pai != NULL);
579 /* hostname may be NULL */
580 /* servname may be NULL */
581 _DIAGASSERT(res != NULL);
582
583 result = NULL;
584
585 /*
586 * if the servname does not match socktype/protocol, ignore it.
587 */
588 if (get_portmatch(pai, servname, svd) != 0)
589 return 0;
590
591 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
592 default_dns_files, hostname, pai)) {
593 case NS_TRYAGAIN:
594 error = EAI_AGAIN;
595 goto free;
596 case NS_UNAVAIL:
597 error = EAI_FAIL;
598 goto free;
599 case NS_NOTFOUND:
600 error = EAI_NODATA;
601 goto free;
602 case NS_SUCCESS:
603 error = 0;
604 for (cur = result; cur; cur = cur->ai_next) {
605 GET_PORT(cur, servname, svd);
606 /* canonname should be filled already */
607 }
608 break;
609 }
610
611 *res = result;
612
613 return 0;
614
615 free:
616 if (result)
617 freeaddrinfo(result);
618 return error;
619 }
620
621 /*
622 * hostname == NULL.
623 * passive socket -> anyaddr (0.0.0.0 or ::)
624 * non-passive socket -> localhost (127.0.0.1 or ::1)
625 */
626 static int
627 explore_null(const struct addrinfo *pai, const char *servname,
628 struct addrinfo **res, struct servent_data *svd)
629 {
630 int s;
631 const struct afd *afd;
632 struct addrinfo *cur;
633 struct addrinfo sentinel;
634 int error;
635
636 _DIAGASSERT(pai != NULL);
637 /* servname may be NULL */
638 _DIAGASSERT(res != NULL);
639
640 *res = NULL;
641 sentinel.ai_next = NULL;
642 cur = &sentinel;
643
644 /*
645 * filter out AFs that are not supported by the kernel
646 * XXX errno?
647 */
648 s = socket(pai->ai_family, SOCK_DGRAM, 0);
649 if (s < 0) {
650 if (errno != EMFILE)
651 return 0;
652 } else
653 close(s);
654
655 /*
656 * if the servname does not match socktype/protocol, ignore it.
657 */
658 if (get_portmatch(pai, servname, svd) != 0)
659 return 0;
660
661 afd = find_afd(pai->ai_family);
662 if (afd == NULL)
663 return 0;
664
665 if (pai->ai_flags & AI_PASSIVE) {
666 GET_AI(cur->ai_next, afd, afd->a_addrany);
667 /* xxx meaningless?
668 * GET_CANONNAME(cur->ai_next, "anyaddr");
669 */
670 GET_PORT(cur->ai_next, servname, svd);
671 } else {
672 GET_AI(cur->ai_next, afd, afd->a_loopback);
673 /* xxx meaningless?
674 * GET_CANONNAME(cur->ai_next, "localhost");
675 */
676 GET_PORT(cur->ai_next, servname, svd);
677 }
678 cur = cur->ai_next;
679
680 *res = sentinel.ai_next;
681 return 0;
682
683 free:
684 if (sentinel.ai_next)
685 freeaddrinfo(sentinel.ai_next);
686 return error;
687 }
688
689 /*
690 * numeric hostname
691 */
692 static int
693 explore_numeric(const struct addrinfo *pai, const char *hostname,
694 const char *servname, struct addrinfo **res, const char *canonname,
695 struct servent_data *svd)
696 {
697 const struct afd *afd;
698 struct addrinfo *cur;
699 struct addrinfo sentinel;
700 int error;
701 char pton[PTON_MAX];
702
703 _DIAGASSERT(pai != NULL);
704 /* hostname may be NULL */
705 /* servname may be NULL */
706 _DIAGASSERT(res != NULL);
707
708 *res = NULL;
709 sentinel.ai_next = NULL;
710 cur = &sentinel;
711
712 /*
713 * if the servname does not match socktype/protocol, ignore it.
714 */
715 if (get_portmatch(pai, servname, svd) != 0)
716 return 0;
717
718 afd = find_afd(pai->ai_family);
719 if (afd == NULL)
720 return 0;
721
722 switch (afd->a_af) {
723 #if 0 /*X/Open spec*/
724 case AF_INET:
725 if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
726 if (pai->ai_family == afd->a_af ||
727 pai->ai_family == PF_UNSPEC /*?*/) {
728 GET_AI(cur->ai_next, afd, pton);
729 GET_PORT(cur->ai_next, servname, svd);
730 if ((pai->ai_flags & AI_CANONNAME)) {
731 /*
732 * Set the numeric address itself as
733 * the canonical name, based on a
734 * clarification in rfc2553bis-03.
735 */
736 GET_CANONNAME(cur->ai_next, canonname);
737 }
738 while (cur && cur->ai_next)
739 cur = cur->ai_next;
740 } else
741 ERR(EAI_FAMILY); /*xxx*/
742 }
743 break;
744 #endif
745 default:
746 if (inet_pton(afd->a_af, hostname, pton) == 1) {
747 if (pai->ai_family == afd->a_af ||
748 pai->ai_family == PF_UNSPEC /*?*/) {
749 GET_AI(cur->ai_next, afd, pton);
750 GET_PORT(cur->ai_next, servname, svd);
751 if ((pai->ai_flags & AI_CANONNAME)) {
752 /*
753 * Set the numeric address itself as
754 * the canonical name, based on a
755 * clarification in rfc2553bis-03.
756 */
757 GET_CANONNAME(cur->ai_next, canonname);
758 }
759 while (cur->ai_next)
760 cur = cur->ai_next;
761 } else
762 ERR(EAI_FAMILY); /*xxx*/
763 }
764 break;
765 }
766
767 *res = sentinel.ai_next;
768 return 0;
769
770 free:
771 bad:
772 if (sentinel.ai_next)
773 freeaddrinfo(sentinel.ai_next);
774 return error;
775 }
776
777 /*
778 * numeric hostname with scope
779 */
780 static int
781 explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
782 const char *servname, struct addrinfo **res, struct servent_data *svd)
783 {
784 #if !defined(SCOPE_DELIMITER) || !defined(INET6)
785 return explore_numeric(pai, hostname, servname, res, hostname, svd);
786 #else
787 const struct afd *afd;
788 struct addrinfo *cur;
789 int error;
790 char *cp, *hostname2 = NULL, *scope, *addr;
791 struct sockaddr_in6 *sin6;
792
793 _DIAGASSERT(pai != NULL);
794 /* hostname may be NULL */
795 /* servname may be NULL */
796 _DIAGASSERT(res != NULL);
797
798 /*
799 * if the servname does not match socktype/protocol, ignore it.
800 */
801 if (get_portmatch(pai, servname, svd) != 0)
802 return 0;
803
804 afd = find_afd(pai->ai_family);
805 if (afd == NULL)
806 return 0;
807
808 if (!afd->a_scoped)
809 return explore_numeric(pai, hostname, servname, res, hostname,
810 svd);
811
812 cp = strchr(hostname, SCOPE_DELIMITER);
813 if (cp == NULL)
814 return explore_numeric(pai, hostname, servname, res, hostname,
815 svd);
816
817 /*
818 * Handle special case of <scoped_address><delimiter><scope id>
819 */
820 hostname2 = strdup(hostname);
821 if (hostname2 == NULL)
822 return EAI_MEMORY;
823 /* terminate at the delimiter */
824 hostname2[cp - hostname] = '\0';
825 addr = hostname2;
826 scope = cp + 1;
827
828 error = explore_numeric(pai, addr, servname, res, hostname, svd);
829 if (error == 0) {
830 u_int32_t scopeid;
831
832 for (cur = *res; cur; cur = cur->ai_next) {
833 if (cur->ai_family != AF_INET6)
834 continue;
835 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
836 if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
837 free(hostname2);
838 return(EAI_NODATA); /* XXX: is return OK? */
839 }
840 sin6->sin6_scope_id = scopeid;
841 }
842 }
843
844 free(hostname2);
845
846 return error;
847 #endif
848 }
849
850 static int
851 get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
852 {
853
854 _DIAGASSERT(pai != NULL);
855 _DIAGASSERT(ai != NULL);
856 _DIAGASSERT(str != NULL);
857
858 if ((pai->ai_flags & AI_CANONNAME) != 0) {
859 ai->ai_canonname = strdup(str);
860 if (ai->ai_canonname == NULL)
861 return EAI_MEMORY;
862 }
863 return 0;
864 }
865
866 struct addrinfo *
867 allocaddrinfo(socklen_t addrlen)
868 {
869 struct addrinfo *ai;
870
871 ai = calloc(sizeof(struct addrinfo) + addrlen, 1);
872 if (ai) {
873 ai->ai_addr = (void *)(ai+1);
874 ai->ai_addrlen = ai->ai_addr->sa_len = addrlen;
875 }
876
877 return ai;
878 }
879
880 static struct addrinfo *
881 get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
882 {
883 char *p;
884 struct addrinfo *ai;
885 struct sockaddr *save;
886
887 _DIAGASSERT(pai != NULL);
888 _DIAGASSERT(afd != NULL);
889 _DIAGASSERT(addr != NULL);
890
891 ai = allocaddrinfo((socklen_t)afd->a_socklen);
892 if (ai == NULL)
893 return NULL;
894
895 save = ai->ai_addr;
896 memcpy(ai, pai, sizeof(struct addrinfo));
897
898 /* since we just overwrote all of ai, we have
899 to restore ai_addr and ai_addrlen */
900 ai->ai_addr = save;
901 ai->ai_addrlen = (socklen_t)afd->a_socklen;
902
903 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
904 p = (char *)(void *)(ai->ai_addr);
905 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
906 return ai;
907 }
908
909 static int
910 get_portmatch(const struct addrinfo *ai, const char *servname,
911 struct servent_data *svd)
912 {
913
914 _DIAGASSERT(ai != NULL);
915 /* servname may be NULL */
916
917 return get_port(ai, servname, 1, svd);
918 }
919
920 static int
921 get_port(const struct addrinfo *ai, const char *servname, int matchonly,
922 struct servent_data *svd)
923 {
924 const char *proto;
925 struct servent *sp;
926 int port;
927 int allownumeric;
928
929 _DIAGASSERT(ai != NULL);
930 /* servname may be NULL */
931
932 if (servname == NULL)
933 return 0;
934 switch (ai->ai_family) {
935 case AF_INET:
936 #ifdef AF_INET6
937 case AF_INET6:
938 #endif
939 break;
940 default:
941 return 0;
942 }
943
944 switch (ai->ai_socktype) {
945 case SOCK_RAW:
946 return EAI_SERVICE;
947 case SOCK_DGRAM:
948 case SOCK_STREAM:
949 allownumeric = 1;
950 break;
951 case ANY:
952 /*
953 * This was 0. It is now 1 so that queries specifying
954 * a NULL hint, or hint without socktype (but, hopefully,
955 * with protocol) and numeric address actually work.
956 */
957 allownumeric = 1;
958 break;
959 default:
960 return EAI_SOCKTYPE;
961 }
962
963 port = str2number(servname);
964 if (port >= 0) {
965 if (!allownumeric)
966 return EAI_SERVICE;
967 if (port < 0 || port > 65535)
968 return EAI_SERVICE;
969 port = htons(port);
970 } else {
971 struct servent sv;
972 if (ai->ai_flags & AI_NUMERICSERV)
973 return EAI_NONAME;
974
975 switch (ai->ai_socktype) {
976 case SOCK_DGRAM:
977 proto = "udp";
978 break;
979 case SOCK_STREAM:
980 proto = "tcp";
981 break;
982 default:
983 proto = NULL;
984 break;
985 }
986
987 sp = getservbyname_r(servname, proto, &sv, svd);
988 if (sp == NULL)
989 return EAI_SERVICE;
990 port = sp->s_port;
991 }
992
993 if (!matchonly) {
994 switch (ai->ai_family) {
995 case AF_INET:
996 ((struct sockaddr_in *)(void *)
997 ai->ai_addr)->sin_port = port;
998 break;
999 #ifdef INET6
1000 case AF_INET6:
1001 ((struct sockaddr_in6 *)(void *)
1002 ai->ai_addr)->sin6_port = port;
1003 break;
1004 #endif
1005 }
1006 }
1007
1008 return 0;
1009 }
1010
1011 static const struct afd *
1012 find_afd(int af)
1013 {
1014 const struct afd *afd;
1015
1016 if (af == PF_UNSPEC)
1017 return NULL;
1018 for (afd = afdl; afd->a_af; afd++) {
1019 if (afd->a_af == af)
1020 return afd;
1021 }
1022 return NULL;
1023 }
1024
1025 /*
1026 * AI_ADDRCONFIG check: Build a mask containing a bit set for each address
1027 * family configured in the system.
1028 *
1029 */
1030 static int
1031 addrconfig(uint64_t *mask)
1032 {
1033 struct ifaddrs *ifaddrs, *ifa;
1034
1035 if (getifaddrs(&ifaddrs) == -1)
1036 return -1;
1037
1038 *mask = 0;
1039 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
1040 if (ifa->ifa_addr && (ifa->ifa_flags & IFF_UP)) {
1041 _DIAGASSERT(ifa->ifa_addr->sa_family < 64);
1042 *mask |= (uint64_t)1 << ifa->ifa_addr->sa_family;
1043 }
1044
1045 freeifaddrs(ifaddrs);
1046 return 0;
1047 }
1048
1049 #ifdef INET6
1050 /* convert a string to a scope identifier. XXX: IPv6 specific */
1051 static int
1052 ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
1053 {
1054 u_long lscopeid;
1055 struct in6_addr *a6;
1056 char *ep;
1057
1058 _DIAGASSERT(scope != NULL);
1059 _DIAGASSERT(sin6 != NULL);
1060 _DIAGASSERT(scopeid != NULL);
1061
1062 a6 = &sin6->sin6_addr;
1063
1064 /* empty scopeid portion is invalid */
1065 if (*scope == '\0')
1066 return -1;
1067
1068 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1069 /*
1070 * We currently assume a one-to-one mapping between links
1071 * and interfaces, so we simply use interface indices for
1072 * like-local scopes.
1073 */
1074 *scopeid = if_nametoindex(scope);
1075 if (*scopeid == 0)
1076 goto trynumeric;
1077 return 0;
1078 }
1079
1080 /* still unclear about literal, allow numeric only - placeholder */
1081 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1082 goto trynumeric;
1083 if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1084 goto trynumeric;
1085 else
1086 goto trynumeric; /* global */
1087
1088 /* try to convert to a numeric id as a last resort */
1089 trynumeric:
1090 errno = 0;
1091 lscopeid = strtoul(scope, &ep, 10);
1092 *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1093 if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
1094 return 0;
1095 else
1096 return -1;
1097 }
1098 #endif
1099
1100 /* code duplicate with gethnamaddr.c */
1101
1102 static const char AskedForGot[] =
1103 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1104
1105 static struct addrinfo *
1106 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
1107 const struct addrinfo *pai)
1108 {
1109 struct addrinfo sentinel, *cur;
1110 struct addrinfo ai;
1111 const struct afd *afd;
1112 char *canonname;
1113 const HEADER *hp;
1114 const u_char *cp;
1115 int n;
1116 const u_char *eom;
1117 char *bp, *ep;
1118 int type, class, ancount, qdcount;
1119 int haveanswer, had_error;
1120 char tbuf[MAXDNAME];
1121 int (*name_ok) (const char *);
1122 char hostbuf[8*1024];
1123
1124 _DIAGASSERT(answer != NULL);
1125 _DIAGASSERT(qname != NULL);
1126 _DIAGASSERT(pai != NULL);
1127
1128 memset(&sentinel, 0, sizeof(sentinel));
1129 cur = &sentinel;
1130
1131 canonname = NULL;
1132 eom = answer->buf + anslen;
1133 switch (qtype) {
1134 case T_A:
1135 case T_AAAA:
1136 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
1137 name_ok = res_hnok;
1138 break;
1139 default:
1140 return NULL; /* XXX should be abort(); */
1141 }
1142 /*
1143 * find first satisfactory answer
1144 */
1145 hp = &answer->hdr;
1146 ancount = ntohs(hp->ancount);
1147 qdcount = ntohs(hp->qdcount);
1148 bp = hostbuf;
1149 ep = hostbuf + sizeof hostbuf;
1150 cp = answer->buf + HFIXEDSZ;
1151 if (qdcount != 1) {
1152 h_errno = NO_RECOVERY;
1153 return (NULL);
1154 }
1155 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
1156 if ((n < 0) || !(*name_ok)(bp)) {
1157 h_errno = NO_RECOVERY;
1158 return (NULL);
1159 }
1160 cp += n + QFIXEDSZ;
1161 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1162 /* res_send() has already verified that the query name is the
1163 * same as the one we sent; this just gets the expanded name
1164 * (i.e., with the succeeding search-domain tacked on).
1165 */
1166 n = (int)strlen(bp) + 1; /* for the \0 */
1167 if (n >= MAXHOSTNAMELEN) {
1168 h_errno = NO_RECOVERY;
1169 return (NULL);
1170 }
1171 canonname = bp;
1172 bp += n;
1173 /* The qname can be abbreviated, but h_name is now absolute. */
1174 qname = canonname;
1175 }
1176 haveanswer = 0;
1177 had_error = 0;
1178 while (ancount-- > 0 && cp < eom && !had_error) {
1179 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
1180 if ((n < 0) || !(*name_ok)(bp)) {
1181 had_error++;
1182 continue;
1183 }
1184 cp += n; /* name */
1185 type = _getshort(cp);
1186 cp += INT16SZ; /* type */
1187 class = _getshort(cp);
1188 cp += INT16SZ + INT32SZ; /* class, TTL */
1189 n = _getshort(cp);
1190 cp += INT16SZ; /* len */
1191 if (class != C_IN) {
1192 /* XXX - debug? syslog? */
1193 cp += n;
1194 continue; /* XXX - had_error++ ? */
1195 }
1196 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1197 type == T_CNAME) {
1198 n = dn_expand(answer->buf, eom, cp, tbuf, (int)sizeof tbuf);
1199 if ((n < 0) || !(*name_ok)(tbuf)) {
1200 had_error++;
1201 continue;
1202 }
1203 cp += n;
1204 /* Get canonical name. */
1205 n = (int)strlen(tbuf) + 1; /* for the \0 */
1206 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1207 had_error++;
1208 continue;
1209 }
1210 strlcpy(bp, tbuf, (size_t)(ep - bp));
1211 canonname = bp;
1212 bp += n;
1213 continue;
1214 }
1215 if (qtype == T_ANY) {
1216 if (!(type == T_A || type == T_AAAA)) {
1217 cp += n;
1218 continue;
1219 }
1220 } else if (type != qtype) {
1221 if (type != T_KEY && type != T_SIG) {
1222 struct syslog_data sd = SYSLOG_DATA_INIT;
1223 syslog_r(LOG_NOTICE|LOG_AUTH, &sd,
1224 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1225 qname, p_class(C_IN), p_type(qtype),
1226 p_type(type));
1227 }
1228 cp += n;
1229 continue; /* XXX - had_error++ ? */
1230 }
1231 switch (type) {
1232 case T_A:
1233 case T_AAAA:
1234 if (strcasecmp(canonname, bp) != 0) {
1235 struct syslog_data sd = SYSLOG_DATA_INIT;
1236 syslog_r(LOG_NOTICE|LOG_AUTH, &sd,
1237 AskedForGot, canonname, bp);
1238 cp += n;
1239 continue; /* XXX - had_error++ ? */
1240 }
1241 if (type == T_A && n != INADDRSZ) {
1242 cp += n;
1243 continue;
1244 }
1245 if (type == T_AAAA && n != IN6ADDRSZ) {
1246 cp += n;
1247 continue;
1248 }
1249 if (type == T_AAAA) {
1250 struct in6_addr in6;
1251 memcpy(&in6, cp, IN6ADDRSZ);
1252 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1253 cp += n;
1254 continue;
1255 }
1256 }
1257 if (!haveanswer) {
1258 int nn;
1259
1260 canonname = bp;
1261 nn = (int)strlen(bp) + 1; /* for the \0 */
1262 bp += nn;
1263 }
1264
1265 /* don't overwrite pai */
1266 ai = *pai;
1267 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1268 afd = find_afd(ai.ai_family);
1269 if (afd == NULL) {
1270 cp += n;
1271 continue;
1272 }
1273 cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1274 if (cur->ai_next == NULL)
1275 had_error++;
1276 while (cur && cur->ai_next)
1277 cur = cur->ai_next;
1278 cp += n;
1279 break;
1280 default:
1281 abort();
1282 }
1283 if (!had_error)
1284 haveanswer++;
1285 }
1286 if (haveanswer) {
1287 if (!canonname)
1288 (void)get_canonname(pai, sentinel.ai_next, qname);
1289 else
1290 (void)get_canonname(pai, sentinel.ai_next, canonname);
1291 h_errno = NETDB_SUCCESS;
1292 return sentinel.ai_next;
1293 }
1294
1295 h_errno = NO_RECOVERY;
1296 return NULL;
1297 }
1298
1299 #define SORTEDADDR(p) (((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr)
1300 #define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr)
1301
1302 static void
1303 aisort(struct addrinfo *s, res_state res)
1304 {
1305 struct addrinfo head, *t, *p;
1306 int i;
1307
1308 head.ai_next = NULL;
1309 t = &head;
1310
1311 for (i = 0; i < res->nsort; i++) {
1312 p = s;
1313 while (p->ai_next) {
1314 if ((p->ai_next->ai_family != AF_INET)
1315 || SORTMATCH(p, res->sort_list[i])) {
1316 t->ai_next = p->ai_next;
1317 t = t->ai_next;
1318 p->ai_next = p->ai_next->ai_next;
1319 } else {
1320 p = p->ai_next;
1321 }
1322 }
1323 }
1324
1325 /* add rest of list and reset s to the new list*/
1326 t->ai_next = s->ai_next;
1327 s->ai_next = head.ai_next;
1328 }
1329
1330 /*ARGSUSED*/
1331 static int
1332 _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
1333 {
1334 struct addrinfo *ai;
1335 querybuf *buf, *buf2;
1336 const char *name;
1337 const struct addrinfo *pai;
1338 struct addrinfo sentinel, *cur;
1339 struct res_target q, q2;
1340 res_state res;
1341
1342 name = va_arg(ap, char *);
1343 pai = va_arg(ap, const struct addrinfo *);
1344
1345 memset(&q, 0, sizeof(q));
1346 memset(&q2, 0, sizeof(q2));
1347 memset(&sentinel, 0, sizeof(sentinel));
1348 cur = &sentinel;
1349
1350 buf = malloc(sizeof(*buf));
1351 if (buf == NULL) {
1352 h_errno = NETDB_INTERNAL;
1353 return NS_NOTFOUND;
1354 }
1355 buf2 = malloc(sizeof(*buf2));
1356 if (buf2 == NULL) {
1357 free(buf);
1358 h_errno = NETDB_INTERNAL;
1359 return NS_NOTFOUND;
1360 }
1361
1362 switch (pai->ai_family) {
1363 case AF_UNSPEC:
1364 /* prefer IPv6 */
1365 q.name = name;
1366 q.qclass = C_IN;
1367 q.qtype = T_AAAA;
1368 q.answer = buf->buf;
1369 q.anslen = sizeof(buf->buf);
1370 q.next = &q2;
1371 q2.name = name;
1372 q2.qclass = C_IN;
1373 q2.qtype = T_A;
1374 q2.answer = buf2->buf;
1375 q2.anslen = sizeof(buf2->buf);
1376 break;
1377 case AF_INET:
1378 q.name = name;
1379 q.qclass = C_IN;
1380 q.qtype = T_A;
1381 q.answer = buf->buf;
1382 q.anslen = sizeof(buf->buf);
1383 break;
1384 case AF_INET6:
1385 q.name = name;
1386 q.qclass = C_IN;
1387 q.qtype = T_AAAA;
1388 q.answer = buf->buf;
1389 q.anslen = sizeof(buf->buf);
1390 break;
1391 default:
1392 free(buf);
1393 free(buf2);
1394 return NS_UNAVAIL;
1395 }
1396
1397 res = __res_get_state();
1398 if (res == NULL) {
1399 free(buf);
1400 free(buf2);
1401 return NS_NOTFOUND;
1402 }
1403
1404 if (res_searchN(name, &q, res) < 0) {
1405 __res_put_state(res);
1406 free(buf);
1407 free(buf2);
1408 return NS_NOTFOUND;
1409 }
1410 ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1411 if (ai) {
1412 cur->ai_next = ai;
1413 while (cur && cur->ai_next)
1414 cur = cur->ai_next;
1415 }
1416 if (q.next) {
1417 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1418 if (ai)
1419 cur->ai_next = ai;
1420 }
1421 free(buf);
1422 free(buf2);
1423 if (sentinel.ai_next == NULL) {
1424 __res_put_state(res);
1425 switch (h_errno) {
1426 case HOST_NOT_FOUND:
1427 return NS_NOTFOUND;
1428 case TRY_AGAIN:
1429 return NS_TRYAGAIN;
1430 default:
1431 return NS_UNAVAIL;
1432 }
1433 }
1434
1435 if (res->nsort)
1436 aisort(&sentinel, res);
1437
1438 __res_put_state(res);
1439
1440 *((struct addrinfo **)rv) = sentinel.ai_next;
1441 return NS_SUCCESS;
1442 }
1443
1444 static void
1445 _sethtent(FILE **hostf)
1446 {
1447
1448 if (!*hostf)
1449 *hostf = fopen(_PATH_HOSTS, "re");
1450 else
1451 rewind(*hostf);
1452 }
1453
1454 static void
1455 _endhtent(FILE **hostf)
1456 {
1457
1458 if (*hostf) {
1459 (void) fclose(*hostf);
1460 *hostf = NULL;
1461 }
1462 }
1463
1464 static struct addrinfo *
1465 _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
1466 {
1467 char *p;
1468 char *cp, *tname, *cname;
1469 struct addrinfo hints, *res0, *res;
1470 int error;
1471 const char *addr;
1472 char hostbuf[8*1024];
1473
1474 _DIAGASSERT(name != NULL);
1475 _DIAGASSERT(pai != NULL);
1476
1477 if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re")))
1478 return (NULL);
1479 again:
1480 if (!(p = fgets(hostbuf, (int)sizeof hostbuf, *hostf)))
1481 return (NULL);
1482 if (*p == '#')
1483 goto again;
1484 if (!(cp = strpbrk(p, "#\n")))
1485 goto again;
1486 *cp = '\0';
1487 if (!(cp = strpbrk(p, " \t")))
1488 goto again;
1489 *cp++ = '\0';
1490 addr = p;
1491 /* if this is not something we're looking for, skip it. */
1492 cname = NULL;
1493 while (cp && *cp) {
1494 if (*cp == ' ' || *cp == '\t') {
1495 cp++;
1496 continue;
1497 }
1498 if (!cname)
1499 cname = cp;
1500 tname = cp;
1501 if ((cp = strpbrk(cp, " \t")) != NULL)
1502 *cp++ = '\0';
1503 if (strcasecmp(name, tname) == 0)
1504 goto found;
1505 }
1506 goto again;
1507
1508 found:
1509 hints = *pai;
1510 hints.ai_flags = AI_NUMERICHOST;
1511 error = getaddrinfo(addr, NULL, &hints, &res0);
1512 if (error)
1513 goto again;
1514 for (res = res0; res; res = res->ai_next) {
1515 /* cover it up */
1516 res->ai_flags = pai->ai_flags;
1517
1518 if (pai->ai_flags & AI_CANONNAME) {
1519 if (get_canonname(pai, res, cname) != 0) {
1520 freeaddrinfo(res0);
1521 goto again;
1522 }
1523 }
1524 }
1525 return res0;
1526 }
1527
1528 /*ARGSUSED*/
1529 static int
1530 _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
1531 {
1532 const char *name;
1533 const struct addrinfo *pai;
1534 struct addrinfo sentinel, *cur;
1535 struct addrinfo *p;
1536 #ifndef _REENTRANT
1537 static
1538 #endif
1539 FILE *hostf = NULL;
1540
1541 name = va_arg(ap, char *);
1542 pai = va_arg(ap, const struct addrinfo *);
1543
1544 memset(&sentinel, 0, sizeof(sentinel));
1545 cur = &sentinel;
1546
1547 _sethtent(&hostf);
1548 while ((p = _gethtent(&hostf, name, pai)) != NULL) {
1549 cur->ai_next = p;
1550 while (cur && cur->ai_next)
1551 cur = cur->ai_next;
1552 }
1553 _endhtent(&hostf);
1554
1555 *((struct addrinfo **)rv) = sentinel.ai_next;
1556 if (sentinel.ai_next == NULL)
1557 return NS_NOTFOUND;
1558 return NS_SUCCESS;
1559 }
1560
1561 #ifdef YP
1562 /*ARGSUSED*/
1563 static struct addrinfo *
1564 _yphostent(char *line, const struct addrinfo *pai)
1565 {
1566 struct addrinfo sentinel, *cur;
1567 struct addrinfo hints, *res, *res0;
1568 int error;
1569 char *p;
1570 const char *addr, *canonname;
1571 char *nextline;
1572 char *cp;
1573
1574 _DIAGASSERT(line != NULL);
1575 _DIAGASSERT(pai != NULL);
1576
1577 p = line;
1578 addr = canonname = NULL;
1579
1580 memset(&sentinel, 0, sizeof(sentinel));
1581 cur = &sentinel;
1582
1583 nextline:
1584 /* terminate line */
1585 cp = strchr(p, '\n');
1586 if (cp) {
1587 *cp++ = '\0';
1588 nextline = cp;
1589 } else
1590 nextline = NULL;
1591
1592 cp = strpbrk(p, " \t");
1593 if (cp == NULL) {
1594 if (canonname == NULL)
1595 return (NULL);
1596 else
1597 goto done;
1598 }
1599 *cp++ = '\0';
1600
1601 addr = p;
1602
1603 while (cp && *cp) {
1604 if (*cp == ' ' || *cp == '\t') {
1605 cp++;
1606 continue;
1607 }
1608 if (!canonname)
1609 canonname = cp;
1610 if ((cp = strpbrk(cp, " \t")) != NULL)
1611 *cp++ = '\0';
1612 }
1613
1614 hints = *pai;
1615 hints.ai_flags = AI_NUMERICHOST;
1616 error = getaddrinfo(addr, NULL, &hints, &res0);
1617 if (error == 0) {
1618 for (res = res0; res; res = res->ai_next) {
1619 /* cover it up */
1620 res->ai_flags = pai->ai_flags;
1621
1622 if (pai->ai_flags & AI_CANONNAME)
1623 (void)get_canonname(pai, res, canonname);
1624 }
1625 } else
1626 res0 = NULL;
1627 if (res0) {
1628 cur->ai_next = res0;
1629 while (cur->ai_next)
1630 cur = cur->ai_next;
1631 }
1632
1633 if (nextline) {
1634 p = nextline;
1635 goto nextline;
1636 }
1637
1638 done:
1639 return sentinel.ai_next;
1640 }
1641
1642 /*ARGSUSED*/
1643 static int
1644 _yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
1645 {
1646 struct addrinfo sentinel, *cur;
1647 struct addrinfo *ai = NULL;
1648 char *ypbuf;
1649 int ypbuflen, r;
1650 const char *name;
1651 const struct addrinfo *pai;
1652 char *ypdomain;
1653
1654 if (_yp_check(&ypdomain) == 0)
1655 return NS_UNAVAIL;
1656
1657 name = va_arg(ap, char *);
1658 pai = va_arg(ap, const struct addrinfo *);
1659
1660 memset(&sentinel, 0, sizeof(sentinel));
1661 cur = &sentinel;
1662
1663 /* hosts.byname is only for IPv4 (Solaris8) */
1664 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
1665 r = yp_match(ypdomain, "hosts.byname", name,
1666 (int)strlen(name), &ypbuf, &ypbuflen);
1667 if (r == 0) {
1668 struct addrinfo ai4;
1669
1670 ai4 = *pai;
1671 ai4.ai_family = AF_INET;
1672 ai = _yphostent(ypbuf, &ai4);
1673 if (ai) {
1674 cur->ai_next = ai;
1675 while (cur && cur->ai_next)
1676 cur = cur->ai_next;
1677 }
1678 }
1679 free(ypbuf);
1680 }
1681
1682 /* ipnodes.byname can hold both IPv4/v6 */
1683 r = yp_match(ypdomain, "ipnodes.byname", name,
1684 (int)strlen(name), &ypbuf, &ypbuflen);
1685 if (r == 0) {
1686 ai = _yphostent(ypbuf, pai);
1687 if (ai)
1688 cur->ai_next = ai;
1689 free(ypbuf);
1690 }
1691
1692 if (sentinel.ai_next == NULL) {
1693 h_errno = HOST_NOT_FOUND;
1694 return NS_NOTFOUND;
1695 }
1696 *((struct addrinfo **)rv) = sentinel.ai_next;
1697 return NS_SUCCESS;
1698 }
1699 #endif
1700
1701 /* resolver logic */
1702
1703 /*
1704 * Formulate a normal query, send, and await answer.
1705 * Returned answer is placed in supplied buffer "answer".
1706 * Perform preliminary check of answer, returning success only
1707 * if no error is indicated and the answer count is nonzero.
1708 * Return the size of the response on success, -1 on error.
1709 * Error number is left in h_errno.
1710 *
1711 * Caller must parse answer and determine whether it answers the question.
1712 */
1713 static int
1714 res_queryN(const char *name, /* domain name */ struct res_target *target,
1715 res_state res)
1716 {
1717 u_char buf[MAXPACKET];
1718 HEADER *hp;
1719 int n;
1720 struct res_target *t;
1721 int rcode;
1722 int ancount;
1723
1724 _DIAGASSERT(name != NULL);
1725 /* XXX: target may be NULL??? */
1726
1727 rcode = NOERROR;
1728 ancount = 0;
1729
1730 for (t = target; t; t = t->next) {
1731 int class, type;
1732 u_char *answer;
1733 int anslen;
1734
1735 hp = (HEADER *)(void *)t->answer;
1736 hp->rcode = NOERROR; /* default */
1737
1738 /* make it easier... */
1739 class = t->qclass;
1740 type = t->qtype;
1741 answer = t->answer;
1742 anslen = t->anslen;
1743 #ifdef DEBUG
1744 if (res->options & RES_DEBUG)
1745 printf(";; res_nquery(%s, %d, %d)\n", name, class, type);
1746 #endif
1747
1748 n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
1749 buf, (int)sizeof(buf));
1750 #ifdef RES_USE_EDNS0
1751 if (n > 0 && (res->options & RES_USE_EDNS0) != 0)
1752 n = res_nopt(res, n, buf, (int)sizeof(buf), anslen);
1753 #endif
1754 if (n <= 0) {
1755 #ifdef DEBUG
1756 if (res->options & RES_DEBUG)
1757 printf(";; res_nquery: mkquery failed\n");
1758 #endif
1759 h_errno = NO_RECOVERY;
1760 return n;
1761 }
1762 n = res_nsend(res, buf, n, answer, anslen);
1763 #if 0
1764 if (n < 0) {
1765 #ifdef DEBUG
1766 if (res->options & RES_DEBUG)
1767 printf(";; res_query: send error\n");
1768 #endif
1769 h_errno = TRY_AGAIN;
1770 return n;
1771 }
1772 #endif
1773
1774 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1775 rcode = hp->rcode; /* record most recent error */
1776 #ifdef DEBUG
1777 if (res->options & RES_DEBUG)
1778 printf(";; rcode = %u, ancount=%u\n", hp->rcode,
1779 ntohs(hp->ancount));
1780 #endif
1781 continue;
1782 }
1783
1784 ancount += ntohs(hp->ancount);
1785
1786 t->n = n;
1787 }
1788
1789 if (ancount == 0) {
1790 switch (rcode) {
1791 case NXDOMAIN:
1792 h_errno = HOST_NOT_FOUND;
1793 break;
1794 case SERVFAIL:
1795 h_errno = TRY_AGAIN;
1796 break;
1797 case NOERROR:
1798 h_errno = NO_DATA;
1799 break;
1800 case FORMERR:
1801 case NOTIMP:
1802 case REFUSED:
1803 default:
1804 h_errno = NO_RECOVERY;
1805 break;
1806 }
1807 return -1;
1808 }
1809 return ancount;
1810 }
1811
1812 /*
1813 * Formulate a normal query, send, and retrieve answer in supplied buffer.
1814 * Return the size of the response on success, -1 on error.
1815 * If enabled, implement search rules until answer or unrecoverable failure
1816 * is detected. Error code, if any, is left in h_errno.
1817 */
1818 static int
1819 res_searchN(const char *name, struct res_target *target, res_state res)
1820 {
1821 const char *cp, * const *domain;
1822 HEADER *hp;
1823 u_int dots;
1824 int trailing_dot, ret, saved_herrno;
1825 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1826
1827 _DIAGASSERT(name != NULL);
1828 _DIAGASSERT(target != NULL);
1829
1830 hp = (HEADER *)(void *)target->answer; /*XXX*/
1831
1832 errno = 0;
1833 h_errno = HOST_NOT_FOUND; /* default, if we never query */
1834 dots = 0;
1835 for (cp = name; *cp; cp++)
1836 dots += (*cp == '.');
1837 trailing_dot = 0;
1838 if (cp > name && *--cp == '.')
1839 trailing_dot++;
1840
1841 /*
1842 * if there aren't any dots, it could be a user-level alias
1843 */
1844 if (!dots && (cp = __hostalias(name)) != NULL) {
1845 ret = res_queryN(cp, target, res);
1846 return ret;
1847 }
1848
1849 /*
1850 * If there are dots in the name already, let's just give it a try
1851 * 'as is'. The threshold can be set with the "ndots" option.
1852 */
1853 saved_herrno = -1;
1854 if (dots >= res->ndots) {
1855 ret = res_querydomainN(name, NULL, target, res);
1856 if (ret > 0)
1857 return (ret);
1858 saved_herrno = h_errno;
1859 tried_as_is++;
1860 }
1861
1862 /*
1863 * We do at least one level of search if
1864 * - there is no dot and RES_DEFNAME is set, or
1865 * - there is at least one dot, there is no trailing dot,
1866 * and RES_DNSRCH is set.
1867 */
1868 if ((!dots && (res->options & RES_DEFNAMES)) ||
1869 (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
1870 int done = 0;
1871
1872 for (domain = (const char * const *)res->dnsrch;
1873 *domain && !done;
1874 domain++) {
1875
1876 ret = res_querydomainN(name, *domain, target, res);
1877 if (ret > 0)
1878 return ret;
1879
1880 /*
1881 * If no server present, give up.
1882 * If name isn't found in this domain,
1883 * keep trying higher domains in the search list
1884 * (if that's enabled).
1885 * On a NO_DATA error, keep trying, otherwise
1886 * a wildcard entry of another type could keep us
1887 * from finding this entry higher in the domain.
1888 * If we get some other error (negative answer or
1889 * server failure), then stop searching up,
1890 * but try the input name below in case it's
1891 * fully-qualified.
1892 */
1893 if (errno == ECONNREFUSED) {
1894 h_errno = TRY_AGAIN;
1895 return -1;
1896 }
1897
1898 switch (h_errno) {
1899 case NO_DATA:
1900 got_nodata++;
1901 /* FALLTHROUGH */
1902 case HOST_NOT_FOUND:
1903 /* keep trying */
1904 break;
1905 case TRY_AGAIN:
1906 if (hp->rcode == SERVFAIL) {
1907 /* try next search element, if any */
1908 got_servfail++;
1909 break;
1910 }
1911 /* FALLTHROUGH */
1912 default:
1913 /* anything else implies that we're done */
1914 done++;
1915 }
1916 /*
1917 * if we got here for some reason other than DNSRCH,
1918 * we only wanted one iteration of the loop, so stop.
1919 */
1920 if (!(res->options & RES_DNSRCH))
1921 done++;
1922 }
1923 }
1924
1925 /*
1926 * if we have not already tried the name "as is", do that now.
1927 * note that we do this regardless of how many dots were in the
1928 * name or whether it ends with a dot.
1929 */
1930 if (!tried_as_is) {
1931 ret = res_querydomainN(name, NULL, target, res);
1932 if (ret > 0)
1933 return ret;
1934 }
1935
1936 /*
1937 * if we got here, we didn't satisfy the search.
1938 * if we did an initial full query, return that query's h_errno
1939 * (note that we wouldn't be here if that query had succeeded).
1940 * else if we ever got a nodata, send that back as the reason.
1941 * else send back meaningless h_errno, that being the one from
1942 * the last DNSRCH we did.
1943 */
1944 if (saved_herrno != -1)
1945 h_errno = saved_herrno;
1946 else if (got_nodata)
1947 h_errno = NO_DATA;
1948 else if (got_servfail)
1949 h_errno = TRY_AGAIN;
1950 return -1;
1951 }
1952
1953 /*
1954 * Perform a call on res_query on the concatenation of name and domain,
1955 * removing a trailing dot from name if domain is NULL.
1956 */
1957 static int
1958 res_querydomainN(const char *name, const char *domain,
1959 struct res_target *target, res_state res)
1960 {
1961 char nbuf[MAXDNAME];
1962 const char *longname = nbuf;
1963 size_t n, d;
1964
1965 _DIAGASSERT(name != NULL);
1966 /* XXX: target may be NULL??? */
1967
1968 #ifdef DEBUG
1969 if (res->options & RES_DEBUG)
1970 printf(";; res_querydomain(%s, %s)\n",
1971 name, domain?domain:"<Nil>");
1972 #endif
1973 if (domain == NULL) {
1974 /*
1975 * Check for trailing '.';
1976 * copy without '.' if present.
1977 */
1978 n = strlen(name);
1979 if (n + 1 > sizeof(nbuf)) {
1980 h_errno = NO_RECOVERY;
1981 return -1;
1982 }
1983 if (n > 0 && name[--n] == '.') {
1984 strncpy(nbuf, name, n);
1985 nbuf[n] = '\0';
1986 } else
1987 longname = name;
1988 } else {
1989 n = strlen(name);
1990 d = strlen(domain);
1991 if (n + 1 + d + 1 > sizeof(nbuf)) {
1992 h_errno = NO_RECOVERY;
1993 return -1;
1994 }
1995 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
1996 }
1997 return res_queryN(longname, target, res);
1998 }
1999