getaddrinfo.c revision 1.98 1 /* $NetBSD: getaddrinfo.c,v 1.98 2012/03/17 21:56:40 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.98 2012/03/17 21:56:40 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 ERR(error);
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 /* ADDRCONFIG check */
507 if ((((uint64_t)1 << ex->e_af) & mask) == 0)
508 continue;
509
510 /* require exact match for family field */
511 if (pai->ai_family != ex->e_af)
512 continue;
513
514 if (!MATCH(pai->ai_socktype, ex->e_socktype,
515 WILD_SOCKTYPE(ex))) {
516 continue;
517 }
518 if (!MATCH(pai->ai_protocol, ex->e_protocol,
519 WILD_PROTOCOL(ex))) {
520 continue;
521 }
522
523 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
524 pai->ai_socktype = ex->e_socktype;
525 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
526 pai->ai_protocol = ex->e_protocol;
527
528 error = explore_fqdn(pai, hostname, servname, &cur->ai_next,
529 &svd);
530
531 while (cur && cur->ai_next)
532 cur = cur->ai_next;
533 }
534
535 /* XXX */
536 if (sentinel.ai_next)
537 error = 0;
538
539 if (error)
540 goto free;
541
542 if (sentinel.ai_next) {
543 good:
544 endservent_r(&svd);
545 *res = sentinel.ai_next;
546 return SUCCESS;
547 } else
548 error = EAI_FAIL;
549 free:
550 bad:
551 endservent_r(&svd);
552 if (sentinel.ai_next)
553 freeaddrinfo(sentinel.ai_next);
554 *res = NULL;
555 return error;
556 }
557
558 /*
559 * FQDN hostname, DNS lookup
560 */
561 static int
562 explore_fqdn(const struct addrinfo *pai, const char *hostname,
563 const char *servname, struct addrinfo **res, struct servent_data *svd)
564 {
565 struct addrinfo *result;
566 struct addrinfo *cur;
567 int error = 0;
568 static const ns_dtab dtab[] = {
569 NS_FILES_CB(_files_getaddrinfo, NULL)
570 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
571 NS_NIS_CB(_yp_getaddrinfo, NULL)
572 NS_NULL_CB
573 };
574
575 _DIAGASSERT(pai != NULL);
576 /* hostname may be NULL */
577 /* servname may be NULL */
578 _DIAGASSERT(res != NULL);
579
580 result = NULL;
581
582 /*
583 * if the servname does not match socktype/protocol, ignore it.
584 */
585 if (get_portmatch(pai, servname, svd) != 0)
586 return 0;
587
588 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
589 default_dns_files, hostname, pai)) {
590 case NS_TRYAGAIN:
591 error = EAI_AGAIN;
592 goto free;
593 case NS_UNAVAIL:
594 error = EAI_FAIL;
595 goto free;
596 case NS_NOTFOUND:
597 error = EAI_NODATA;
598 goto free;
599 case NS_SUCCESS:
600 error = 0;
601 for (cur = result; cur; cur = cur->ai_next) {
602 GET_PORT(cur, servname, svd);
603 /* canonname should be filled already */
604 }
605 break;
606 }
607
608 *res = result;
609
610 return 0;
611
612 free:
613 if (result)
614 freeaddrinfo(result);
615 return error;
616 }
617
618 /*
619 * hostname == NULL.
620 * passive socket -> anyaddr (0.0.0.0 or ::)
621 * non-passive socket -> localhost (127.0.0.1 or ::1)
622 */
623 static int
624 explore_null(const struct addrinfo *pai, const char *servname,
625 struct addrinfo **res, struct servent_data *svd)
626 {
627 int s;
628 const struct afd *afd;
629 struct addrinfo *cur;
630 struct addrinfo sentinel;
631 int error;
632
633 _DIAGASSERT(pai != NULL);
634 /* servname may be NULL */
635 _DIAGASSERT(res != NULL);
636
637 *res = NULL;
638 sentinel.ai_next = NULL;
639 cur = &sentinel;
640
641 /*
642 * filter out AFs that are not supported by the kernel
643 * XXX errno?
644 */
645 s = socket(pai->ai_family, SOCK_DGRAM, 0);
646 if (s < 0) {
647 if (errno != EMFILE)
648 return 0;
649 } else
650 close(s);
651
652 /*
653 * if the servname does not match socktype/protocol, ignore it.
654 */
655 if (get_portmatch(pai, servname, svd) != 0)
656 return 0;
657
658 afd = find_afd(pai->ai_family);
659 if (afd == NULL)
660 return 0;
661
662 if (pai->ai_flags & AI_PASSIVE) {
663 GET_AI(cur->ai_next, afd, afd->a_addrany);
664 /* xxx meaningless?
665 * GET_CANONNAME(cur->ai_next, "anyaddr");
666 */
667 GET_PORT(cur->ai_next, servname, svd);
668 } else {
669 GET_AI(cur->ai_next, afd, afd->a_loopback);
670 /* xxx meaningless?
671 * GET_CANONNAME(cur->ai_next, "localhost");
672 */
673 GET_PORT(cur->ai_next, servname, svd);
674 }
675 cur = cur->ai_next;
676
677 *res = sentinel.ai_next;
678 return 0;
679
680 free:
681 if (sentinel.ai_next)
682 freeaddrinfo(sentinel.ai_next);
683 return error;
684 }
685
686 /*
687 * numeric hostname
688 */
689 static int
690 explore_numeric(const struct addrinfo *pai, const char *hostname,
691 const char *servname, struct addrinfo **res, const char *canonname,
692 struct servent_data *svd)
693 {
694 const struct afd *afd;
695 struct addrinfo *cur;
696 struct addrinfo sentinel;
697 int error;
698 char pton[PTON_MAX];
699
700 _DIAGASSERT(pai != NULL);
701 /* hostname may be NULL */
702 /* servname may be NULL */
703 _DIAGASSERT(res != NULL);
704
705 *res = NULL;
706 sentinel.ai_next = NULL;
707 cur = &sentinel;
708
709 /*
710 * if the servname does not match socktype/protocol, ignore it.
711 */
712 if (get_portmatch(pai, servname, svd) != 0)
713 return 0;
714
715 afd = find_afd(pai->ai_family);
716 if (afd == NULL)
717 return 0;
718
719 switch (afd->a_af) {
720 #if 0 /*X/Open spec*/
721 case AF_INET:
722 if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
723 if (pai->ai_family == afd->a_af ||
724 pai->ai_family == PF_UNSPEC /*?*/) {
725 GET_AI(cur->ai_next, afd, pton);
726 GET_PORT(cur->ai_next, servname, svd);
727 if ((pai->ai_flags & AI_CANONNAME)) {
728 /*
729 * Set the numeric address itself as
730 * the canonical name, based on a
731 * clarification in rfc2553bis-03.
732 */
733 GET_CANONNAME(cur->ai_next, canonname);
734 }
735 while (cur && cur->ai_next)
736 cur = cur->ai_next;
737 } else
738 ERR(EAI_FAMILY); /*xxx*/
739 }
740 break;
741 #endif
742 default:
743 if (inet_pton(afd->a_af, hostname, pton) == 1) {
744 if (pai->ai_family == afd->a_af ||
745 pai->ai_family == PF_UNSPEC /*?*/) {
746 GET_AI(cur->ai_next, afd, pton);
747 GET_PORT(cur->ai_next, servname, svd);
748 if ((pai->ai_flags & AI_CANONNAME)) {
749 /*
750 * Set the numeric address itself as
751 * the canonical name, based on a
752 * clarification in rfc2553bis-03.
753 */
754 GET_CANONNAME(cur->ai_next, canonname);
755 }
756 while (cur->ai_next)
757 cur = cur->ai_next;
758 } else
759 ERR(EAI_FAMILY); /*xxx*/
760 }
761 break;
762 }
763
764 *res = sentinel.ai_next;
765 return 0;
766
767 free:
768 bad:
769 if (sentinel.ai_next)
770 freeaddrinfo(sentinel.ai_next);
771 return error;
772 }
773
774 /*
775 * numeric hostname with scope
776 */
777 static int
778 explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
779 const char *servname, struct addrinfo **res, struct servent_data *svd)
780 {
781 #if !defined(SCOPE_DELIMITER) || !defined(INET6)
782 return explore_numeric(pai, hostname, servname, res, hostname, svd);
783 #else
784 const struct afd *afd;
785 struct addrinfo *cur;
786 int error;
787 char *cp, *hostname2 = NULL, *scope, *addr;
788 struct sockaddr_in6 *sin6;
789
790 _DIAGASSERT(pai != NULL);
791 /* hostname may be NULL */
792 /* servname may be NULL */
793 _DIAGASSERT(res != NULL);
794
795 /*
796 * if the servname does not match socktype/protocol, ignore it.
797 */
798 if (get_portmatch(pai, servname, svd) != 0)
799 return 0;
800
801 afd = find_afd(pai->ai_family);
802 if (afd == NULL)
803 return 0;
804
805 if (!afd->a_scoped)
806 return explore_numeric(pai, hostname, servname, res, hostname,
807 svd);
808
809 cp = strchr(hostname, SCOPE_DELIMITER);
810 if (cp == NULL)
811 return explore_numeric(pai, hostname, servname, res, hostname,
812 svd);
813
814 /*
815 * Handle special case of <scoped_address><delimiter><scope id>
816 */
817 hostname2 = strdup(hostname);
818 if (hostname2 == NULL)
819 return EAI_MEMORY;
820 /* terminate at the delimiter */
821 hostname2[cp - hostname] = '\0';
822 addr = hostname2;
823 scope = cp + 1;
824
825 error = explore_numeric(pai, addr, servname, res, hostname, svd);
826 if (error == 0) {
827 u_int32_t scopeid;
828
829 for (cur = *res; cur; cur = cur->ai_next) {
830 if (cur->ai_family != AF_INET6)
831 continue;
832 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
833 if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
834 free(hostname2);
835 return(EAI_NODATA); /* XXX: is return OK? */
836 }
837 sin6->sin6_scope_id = scopeid;
838 }
839 }
840
841 free(hostname2);
842
843 return error;
844 #endif
845 }
846
847 static int
848 get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
849 {
850
851 _DIAGASSERT(pai != NULL);
852 _DIAGASSERT(ai != NULL);
853 _DIAGASSERT(str != NULL);
854
855 if ((pai->ai_flags & AI_CANONNAME) != 0) {
856 ai->ai_canonname = strdup(str);
857 if (ai->ai_canonname == NULL)
858 return EAI_MEMORY;
859 }
860 return 0;
861 }
862
863 struct addrinfo *
864 allocaddrinfo(socklen_t addrlen)
865 {
866 struct addrinfo *ai;
867
868 ai = calloc(sizeof(struct addrinfo) + addrlen, 1);
869 if (ai) {
870 ai->ai_addr = (void *)(ai+1);
871 ai->ai_addrlen = ai->ai_addr->sa_len = addrlen;
872 }
873
874 return ai;
875 }
876
877 static struct addrinfo *
878 get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
879 {
880 char *p;
881 struct addrinfo *ai;
882 struct sockaddr *save;
883
884 _DIAGASSERT(pai != NULL);
885 _DIAGASSERT(afd != NULL);
886 _DIAGASSERT(addr != NULL);
887
888 ai = allocaddrinfo((socklen_t)afd->a_socklen);
889 if (ai == NULL)
890 return NULL;
891
892 save = ai->ai_addr;
893 memcpy(ai, pai, sizeof(struct addrinfo));
894
895 /* since we just overwrote all of ai, we have
896 to restore ai_addr and ai_addrlen */
897 ai->ai_addr = save;
898 ai->ai_addrlen = (socklen_t)afd->a_socklen;
899
900 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
901 p = (char *)(void *)(ai->ai_addr);
902 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
903 return ai;
904 }
905
906 static int
907 get_portmatch(const struct addrinfo *ai, const char *servname,
908 struct servent_data *svd)
909 {
910
911 _DIAGASSERT(ai != NULL);
912 /* servname may be NULL */
913
914 return get_port(ai, servname, 1, svd);
915 }
916
917 static int
918 get_port(const struct addrinfo *ai, const char *servname, int matchonly,
919 struct servent_data *svd)
920 {
921 const char *proto;
922 struct servent *sp;
923 int port;
924 int allownumeric;
925
926 _DIAGASSERT(ai != NULL);
927 /* servname may be NULL */
928
929 if (servname == NULL)
930 return 0;
931 switch (ai->ai_family) {
932 case AF_INET:
933 #ifdef AF_INET6
934 case AF_INET6:
935 #endif
936 break;
937 default:
938 return 0;
939 }
940
941 switch (ai->ai_socktype) {
942 case SOCK_RAW:
943 return EAI_SERVICE;
944 case SOCK_DGRAM:
945 case SOCK_STREAM:
946 allownumeric = 1;
947 break;
948 case ANY:
949 /*
950 * This was 0. It is now 1 so that queries specifying
951 * a NULL hint, or hint without socktype (but, hopefully,
952 * with protocol) and numeric address actually work.
953 */
954 allownumeric = 1;
955 break;
956 default:
957 return EAI_SOCKTYPE;
958 }
959
960 port = str2number(servname);
961 if (port >= 0) {
962 if (!allownumeric)
963 return EAI_SERVICE;
964 if (port < 0 || port > 65535)
965 return EAI_SERVICE;
966 port = htons(port);
967 } else {
968 struct servent sv;
969 if (ai->ai_flags & AI_NUMERICSERV)
970 return EAI_NONAME;
971
972 switch (ai->ai_socktype) {
973 case SOCK_DGRAM:
974 proto = "udp";
975 break;
976 case SOCK_STREAM:
977 proto = "tcp";
978 break;
979 default:
980 proto = NULL;
981 break;
982 }
983
984 sp = getservbyname_r(servname, proto, &sv, svd);
985 if (sp == NULL)
986 return EAI_SERVICE;
987 port = sp->s_port;
988 }
989
990 if (!matchonly) {
991 switch (ai->ai_family) {
992 case AF_INET:
993 ((struct sockaddr_in *)(void *)
994 ai->ai_addr)->sin_port = port;
995 break;
996 #ifdef INET6
997 case AF_INET6:
998 ((struct sockaddr_in6 *)(void *)
999 ai->ai_addr)->sin6_port = port;
1000 break;
1001 #endif
1002 }
1003 }
1004
1005 return 0;
1006 }
1007
1008 static const struct afd *
1009 find_afd(int af)
1010 {
1011 const struct afd *afd;
1012
1013 if (af == PF_UNSPEC)
1014 return NULL;
1015 for (afd = afdl; afd->a_af; afd++) {
1016 if (afd->a_af == af)
1017 return afd;
1018 }
1019 return NULL;
1020 }
1021
1022 /*
1023 * AI_ADDRCONFIG check: Build a mask containing a bit set for each address
1024 * family configured in the system.
1025 *
1026 */
1027 static int
1028 addrconfig(uint64_t *mask)
1029 {
1030 struct ifaddrs *ifaddrs, *ifa;
1031
1032 if (getifaddrs(&ifaddrs) == -1)
1033 return -1;
1034
1035 mask = 0;
1036 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
1037 if (ifa->ifa_addr && (ifa->ifa_flags & IFF_UP)) {
1038 _DIAGASSERT(ifa->ifa_addr->sa_family < 64);
1039 *mask |= (uint64_t)1 << ifa->ifa_addr->sa_family;
1040 }
1041
1042 freeifaddrs(ifaddrs);
1043 return 0;
1044 }
1045
1046 #ifdef INET6
1047 /* convert a string to a scope identifier. XXX: IPv6 specific */
1048 static int
1049 ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
1050 {
1051 u_long lscopeid;
1052 struct in6_addr *a6;
1053 char *ep;
1054
1055 _DIAGASSERT(scope != NULL);
1056 _DIAGASSERT(sin6 != NULL);
1057 _DIAGASSERT(scopeid != NULL);
1058
1059 a6 = &sin6->sin6_addr;
1060
1061 /* empty scopeid portion is invalid */
1062 if (*scope == '\0')
1063 return -1;
1064
1065 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1066 /*
1067 * We currently assume a one-to-one mapping between links
1068 * and interfaces, so we simply use interface indices for
1069 * like-local scopes.
1070 */
1071 *scopeid = if_nametoindex(scope);
1072 if (*scopeid == 0)
1073 goto trynumeric;
1074 return 0;
1075 }
1076
1077 /* still unclear about literal, allow numeric only - placeholder */
1078 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1079 goto trynumeric;
1080 if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1081 goto trynumeric;
1082 else
1083 goto trynumeric; /* global */
1084
1085 /* try to convert to a numeric id as a last resort */
1086 trynumeric:
1087 errno = 0;
1088 lscopeid = strtoul(scope, &ep, 10);
1089 *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1090 if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
1091 return 0;
1092 else
1093 return -1;
1094 }
1095 #endif
1096
1097 /* code duplicate with gethnamaddr.c */
1098
1099 static const char AskedForGot[] =
1100 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1101
1102 static struct addrinfo *
1103 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
1104 const struct addrinfo *pai)
1105 {
1106 struct addrinfo sentinel, *cur;
1107 struct addrinfo ai;
1108 const struct afd *afd;
1109 char *canonname;
1110 const HEADER *hp;
1111 const u_char *cp;
1112 int n;
1113 const u_char *eom;
1114 char *bp, *ep;
1115 int type, class, ancount, qdcount;
1116 int haveanswer, had_error;
1117 char tbuf[MAXDNAME];
1118 int (*name_ok) (const char *);
1119 char hostbuf[8*1024];
1120
1121 _DIAGASSERT(answer != NULL);
1122 _DIAGASSERT(qname != NULL);
1123 _DIAGASSERT(pai != NULL);
1124
1125 memset(&sentinel, 0, sizeof(sentinel));
1126 cur = &sentinel;
1127
1128 canonname = NULL;
1129 eom = answer->buf + anslen;
1130 switch (qtype) {
1131 case T_A:
1132 case T_AAAA:
1133 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
1134 name_ok = res_hnok;
1135 break;
1136 default:
1137 return NULL; /* XXX should be abort(); */
1138 }
1139 /*
1140 * find first satisfactory answer
1141 */
1142 hp = &answer->hdr;
1143 ancount = ntohs(hp->ancount);
1144 qdcount = ntohs(hp->qdcount);
1145 bp = hostbuf;
1146 ep = hostbuf + sizeof hostbuf;
1147 cp = answer->buf + HFIXEDSZ;
1148 if (qdcount != 1) {
1149 h_errno = NO_RECOVERY;
1150 return (NULL);
1151 }
1152 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
1153 if ((n < 0) || !(*name_ok)(bp)) {
1154 h_errno = NO_RECOVERY;
1155 return (NULL);
1156 }
1157 cp += n + QFIXEDSZ;
1158 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1159 /* res_send() has already verified that the query name is the
1160 * same as the one we sent; this just gets the expanded name
1161 * (i.e., with the succeeding search-domain tacked on).
1162 */
1163 n = (int)strlen(bp) + 1; /* for the \0 */
1164 if (n >= MAXHOSTNAMELEN) {
1165 h_errno = NO_RECOVERY;
1166 return (NULL);
1167 }
1168 canonname = bp;
1169 bp += n;
1170 /* The qname can be abbreviated, but h_name is now absolute. */
1171 qname = canonname;
1172 }
1173 haveanswer = 0;
1174 had_error = 0;
1175 while (ancount-- > 0 && cp < eom && !had_error) {
1176 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
1177 if ((n < 0) || !(*name_ok)(bp)) {
1178 had_error++;
1179 continue;
1180 }
1181 cp += n; /* name */
1182 type = _getshort(cp);
1183 cp += INT16SZ; /* type */
1184 class = _getshort(cp);
1185 cp += INT16SZ + INT32SZ; /* class, TTL */
1186 n = _getshort(cp);
1187 cp += INT16SZ; /* len */
1188 if (class != C_IN) {
1189 /* XXX - debug? syslog? */
1190 cp += n;
1191 continue; /* XXX - had_error++ ? */
1192 }
1193 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1194 type == T_CNAME) {
1195 n = dn_expand(answer->buf, eom, cp, tbuf, (int)sizeof tbuf);
1196 if ((n < 0) || !(*name_ok)(tbuf)) {
1197 had_error++;
1198 continue;
1199 }
1200 cp += n;
1201 /* Get canonical name. */
1202 n = (int)strlen(tbuf) + 1; /* for the \0 */
1203 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1204 had_error++;
1205 continue;
1206 }
1207 strlcpy(bp, tbuf, (size_t)(ep - bp));
1208 canonname = bp;
1209 bp += n;
1210 continue;
1211 }
1212 if (qtype == T_ANY) {
1213 if (!(type == T_A || type == T_AAAA)) {
1214 cp += n;
1215 continue;
1216 }
1217 } else if (type != qtype) {
1218 if (type != T_KEY && type != T_SIG) {
1219 struct syslog_data sd = SYSLOG_DATA_INIT;
1220 syslog_r(LOG_NOTICE|LOG_AUTH, &sd,
1221 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1222 qname, p_class(C_IN), p_type(qtype),
1223 p_type(type));
1224 }
1225 cp += n;
1226 continue; /* XXX - had_error++ ? */
1227 }
1228 switch (type) {
1229 case T_A:
1230 case T_AAAA:
1231 if (strcasecmp(canonname, bp) != 0) {
1232 struct syslog_data sd = SYSLOG_DATA_INIT;
1233 syslog_r(LOG_NOTICE|LOG_AUTH, &sd,
1234 AskedForGot, canonname, bp);
1235 cp += n;
1236 continue; /* XXX - had_error++ ? */
1237 }
1238 if (type == T_A && n != INADDRSZ) {
1239 cp += n;
1240 continue;
1241 }
1242 if (type == T_AAAA && n != IN6ADDRSZ) {
1243 cp += n;
1244 continue;
1245 }
1246 if (type == T_AAAA) {
1247 struct in6_addr in6;
1248 memcpy(&in6, cp, IN6ADDRSZ);
1249 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1250 cp += n;
1251 continue;
1252 }
1253 }
1254 if (!haveanswer) {
1255 int nn;
1256
1257 canonname = bp;
1258 nn = (int)strlen(bp) + 1; /* for the \0 */
1259 bp += nn;
1260 }
1261
1262 /* don't overwrite pai */
1263 ai = *pai;
1264 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1265 afd = find_afd(ai.ai_family);
1266 if (afd == NULL) {
1267 cp += n;
1268 continue;
1269 }
1270 cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1271 if (cur->ai_next == NULL)
1272 had_error++;
1273 while (cur && cur->ai_next)
1274 cur = cur->ai_next;
1275 cp += n;
1276 break;
1277 default:
1278 abort();
1279 }
1280 if (!had_error)
1281 haveanswer++;
1282 }
1283 if (haveanswer) {
1284 if (!canonname)
1285 (void)get_canonname(pai, sentinel.ai_next, qname);
1286 else
1287 (void)get_canonname(pai, sentinel.ai_next, canonname);
1288 h_errno = NETDB_SUCCESS;
1289 return sentinel.ai_next;
1290 }
1291
1292 h_errno = NO_RECOVERY;
1293 return NULL;
1294 }
1295
1296 #define SORTEDADDR(p) (((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr)
1297 #define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr)
1298
1299 static void
1300 aisort(struct addrinfo *s, res_state res)
1301 {
1302 struct addrinfo head, *t, *p;
1303 int i;
1304
1305 head.ai_next = NULL;
1306 t = &head;
1307
1308 for (i = 0; i < res->nsort; i++) {
1309 p = s;
1310 while (p->ai_next) {
1311 if ((p->ai_next->ai_family != AF_INET)
1312 || SORTMATCH(p, res->sort_list[i])) {
1313 t->ai_next = p->ai_next;
1314 t = t->ai_next;
1315 p->ai_next = p->ai_next->ai_next;
1316 } else {
1317 p = p->ai_next;
1318 }
1319 }
1320 }
1321
1322 /* add rest of list and reset s to the new list*/
1323 t->ai_next = s->ai_next;
1324 s->ai_next = head.ai_next;
1325 }
1326
1327 /*ARGSUSED*/
1328 static int
1329 _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
1330 {
1331 struct addrinfo *ai;
1332 querybuf *buf, *buf2;
1333 const char *name;
1334 const struct addrinfo *pai;
1335 struct addrinfo sentinel, *cur;
1336 struct res_target q, q2;
1337 res_state res;
1338
1339 name = va_arg(ap, char *);
1340 pai = va_arg(ap, const struct addrinfo *);
1341
1342 memset(&q, 0, sizeof(q));
1343 memset(&q2, 0, sizeof(q2));
1344 memset(&sentinel, 0, sizeof(sentinel));
1345 cur = &sentinel;
1346
1347 buf = malloc(sizeof(*buf));
1348 if (buf == NULL) {
1349 h_errno = NETDB_INTERNAL;
1350 return NS_NOTFOUND;
1351 }
1352 buf2 = malloc(sizeof(*buf2));
1353 if (buf2 == NULL) {
1354 free(buf);
1355 h_errno = NETDB_INTERNAL;
1356 return NS_NOTFOUND;
1357 }
1358
1359 switch (pai->ai_family) {
1360 case AF_UNSPEC:
1361 /* prefer IPv6 */
1362 q.name = name;
1363 q.qclass = C_IN;
1364 q.qtype = T_AAAA;
1365 q.answer = buf->buf;
1366 q.anslen = sizeof(buf->buf);
1367 q.next = &q2;
1368 q2.name = name;
1369 q2.qclass = C_IN;
1370 q2.qtype = T_A;
1371 q2.answer = buf2->buf;
1372 q2.anslen = sizeof(buf2->buf);
1373 break;
1374 case AF_INET:
1375 q.name = name;
1376 q.qclass = C_IN;
1377 q.qtype = T_A;
1378 q.answer = buf->buf;
1379 q.anslen = sizeof(buf->buf);
1380 break;
1381 case AF_INET6:
1382 q.name = name;
1383 q.qclass = C_IN;
1384 q.qtype = T_AAAA;
1385 q.answer = buf->buf;
1386 q.anslen = sizeof(buf->buf);
1387 break;
1388 default:
1389 free(buf);
1390 free(buf2);
1391 return NS_UNAVAIL;
1392 }
1393
1394 res = __res_get_state();
1395 if (res == NULL) {
1396 free(buf);
1397 free(buf2);
1398 return NS_NOTFOUND;
1399 }
1400
1401 if (res_searchN(name, &q, res) < 0) {
1402 __res_put_state(res);
1403 free(buf);
1404 free(buf2);
1405 return NS_NOTFOUND;
1406 }
1407 ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1408 if (ai) {
1409 cur->ai_next = ai;
1410 while (cur && cur->ai_next)
1411 cur = cur->ai_next;
1412 }
1413 if (q.next) {
1414 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1415 if (ai)
1416 cur->ai_next = ai;
1417 }
1418 free(buf);
1419 free(buf2);
1420 if (sentinel.ai_next == NULL) {
1421 __res_put_state(res);
1422 switch (h_errno) {
1423 case HOST_NOT_FOUND:
1424 return NS_NOTFOUND;
1425 case TRY_AGAIN:
1426 return NS_TRYAGAIN;
1427 default:
1428 return NS_UNAVAIL;
1429 }
1430 }
1431
1432 if (res->nsort)
1433 aisort(&sentinel, res);
1434
1435 __res_put_state(res);
1436
1437 *((struct addrinfo **)rv) = sentinel.ai_next;
1438 return NS_SUCCESS;
1439 }
1440
1441 static void
1442 _sethtent(FILE **hostf)
1443 {
1444
1445 if (!*hostf)
1446 *hostf = fopen(_PATH_HOSTS, "re");
1447 else
1448 rewind(*hostf);
1449 }
1450
1451 static void
1452 _endhtent(FILE **hostf)
1453 {
1454
1455 if (*hostf) {
1456 (void) fclose(*hostf);
1457 *hostf = NULL;
1458 }
1459 }
1460
1461 static struct addrinfo *
1462 _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
1463 {
1464 char *p;
1465 char *cp, *tname, *cname;
1466 struct addrinfo hints, *res0, *res;
1467 int error;
1468 const char *addr;
1469 char hostbuf[8*1024];
1470
1471 _DIAGASSERT(name != NULL);
1472 _DIAGASSERT(pai != NULL);
1473
1474 if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re")))
1475 return (NULL);
1476 again:
1477 if (!(p = fgets(hostbuf, (int)sizeof hostbuf, *hostf)))
1478 return (NULL);
1479 if (*p == '#')
1480 goto again;
1481 if (!(cp = strpbrk(p, "#\n")))
1482 goto again;
1483 *cp = '\0';
1484 if (!(cp = strpbrk(p, " \t")))
1485 goto again;
1486 *cp++ = '\0';
1487 addr = p;
1488 /* if this is not something we're looking for, skip it. */
1489 cname = NULL;
1490 while (cp && *cp) {
1491 if (*cp == ' ' || *cp == '\t') {
1492 cp++;
1493 continue;
1494 }
1495 if (!cname)
1496 cname = cp;
1497 tname = cp;
1498 if ((cp = strpbrk(cp, " \t")) != NULL)
1499 *cp++ = '\0';
1500 if (strcasecmp(name, tname) == 0)
1501 goto found;
1502 }
1503 goto again;
1504
1505 found:
1506 hints = *pai;
1507 hints.ai_flags = AI_NUMERICHOST;
1508 error = getaddrinfo(addr, NULL, &hints, &res0);
1509 if (error)
1510 goto again;
1511 for (res = res0; res; res = res->ai_next) {
1512 /* cover it up */
1513 res->ai_flags = pai->ai_flags;
1514
1515 if (pai->ai_flags & AI_CANONNAME) {
1516 if (get_canonname(pai, res, cname) != 0) {
1517 freeaddrinfo(res0);
1518 goto again;
1519 }
1520 }
1521 }
1522 return res0;
1523 }
1524
1525 /*ARGSUSED*/
1526 static int
1527 _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
1528 {
1529 const char *name;
1530 const struct addrinfo *pai;
1531 struct addrinfo sentinel, *cur;
1532 struct addrinfo *p;
1533 #ifndef _REENTRANT
1534 static
1535 #endif
1536 FILE *hostf = NULL;
1537
1538 name = va_arg(ap, char *);
1539 pai = va_arg(ap, const struct addrinfo *);
1540
1541 memset(&sentinel, 0, sizeof(sentinel));
1542 cur = &sentinel;
1543
1544 _sethtent(&hostf);
1545 while ((p = _gethtent(&hostf, name, pai)) != NULL) {
1546 cur->ai_next = p;
1547 while (cur && cur->ai_next)
1548 cur = cur->ai_next;
1549 }
1550 _endhtent(&hostf);
1551
1552 *((struct addrinfo **)rv) = sentinel.ai_next;
1553 if (sentinel.ai_next == NULL)
1554 return NS_NOTFOUND;
1555 return NS_SUCCESS;
1556 }
1557
1558 #ifdef YP
1559 /*ARGSUSED*/
1560 static struct addrinfo *
1561 _yphostent(char *line, const struct addrinfo *pai)
1562 {
1563 struct addrinfo sentinel, *cur;
1564 struct addrinfo hints, *res, *res0;
1565 int error;
1566 char *p;
1567 const char *addr, *canonname;
1568 char *nextline;
1569 char *cp;
1570
1571 _DIAGASSERT(line != NULL);
1572 _DIAGASSERT(pai != NULL);
1573
1574 p = line;
1575 addr = canonname = NULL;
1576
1577 memset(&sentinel, 0, sizeof(sentinel));
1578 cur = &sentinel;
1579
1580 nextline:
1581 /* terminate line */
1582 cp = strchr(p, '\n');
1583 if (cp) {
1584 *cp++ = '\0';
1585 nextline = cp;
1586 } else
1587 nextline = NULL;
1588
1589 cp = strpbrk(p, " \t");
1590 if (cp == NULL) {
1591 if (canonname == NULL)
1592 return (NULL);
1593 else
1594 goto done;
1595 }
1596 *cp++ = '\0';
1597
1598 addr = p;
1599
1600 while (cp && *cp) {
1601 if (*cp == ' ' || *cp == '\t') {
1602 cp++;
1603 continue;
1604 }
1605 if (!canonname)
1606 canonname = cp;
1607 if ((cp = strpbrk(cp, " \t")) != NULL)
1608 *cp++ = '\0';
1609 }
1610
1611 hints = *pai;
1612 hints.ai_flags = AI_NUMERICHOST;
1613 error = getaddrinfo(addr, NULL, &hints, &res0);
1614 if (error == 0) {
1615 for (res = res0; res; res = res->ai_next) {
1616 /* cover it up */
1617 res->ai_flags = pai->ai_flags;
1618
1619 if (pai->ai_flags & AI_CANONNAME)
1620 (void)get_canonname(pai, res, canonname);
1621 }
1622 } else
1623 res0 = NULL;
1624 if (res0) {
1625 cur->ai_next = res0;
1626 while (cur->ai_next)
1627 cur = cur->ai_next;
1628 }
1629
1630 if (nextline) {
1631 p = nextline;
1632 goto nextline;
1633 }
1634
1635 done:
1636 return sentinel.ai_next;
1637 }
1638
1639 /*ARGSUSED*/
1640 static int
1641 _yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
1642 {
1643 struct addrinfo sentinel, *cur;
1644 struct addrinfo *ai = NULL;
1645 char *ypbuf;
1646 int ypbuflen, r;
1647 const char *name;
1648 const struct addrinfo *pai;
1649 char *ypdomain;
1650
1651 if (_yp_check(&ypdomain) == 0)
1652 return NS_UNAVAIL;
1653
1654 name = va_arg(ap, char *);
1655 pai = va_arg(ap, const struct addrinfo *);
1656
1657 memset(&sentinel, 0, sizeof(sentinel));
1658 cur = &sentinel;
1659
1660 /* hosts.byname is only for IPv4 (Solaris8) */
1661 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
1662 r = yp_match(ypdomain, "hosts.byname", name,
1663 (int)strlen(name), &ypbuf, &ypbuflen);
1664 if (r == 0) {
1665 struct addrinfo ai4;
1666
1667 ai4 = *pai;
1668 ai4.ai_family = AF_INET;
1669 ai = _yphostent(ypbuf, &ai4);
1670 if (ai) {
1671 cur->ai_next = ai;
1672 while (cur && cur->ai_next)
1673 cur = cur->ai_next;
1674 }
1675 }
1676 free(ypbuf);
1677 }
1678
1679 /* ipnodes.byname can hold both IPv4/v6 */
1680 r = yp_match(ypdomain, "ipnodes.byname", name,
1681 (int)strlen(name), &ypbuf, &ypbuflen);
1682 if (r == 0) {
1683 ai = _yphostent(ypbuf, pai);
1684 if (ai)
1685 cur->ai_next = ai;
1686 free(ypbuf);
1687 }
1688
1689 if (sentinel.ai_next == NULL) {
1690 h_errno = HOST_NOT_FOUND;
1691 return NS_NOTFOUND;
1692 }
1693 *((struct addrinfo **)rv) = sentinel.ai_next;
1694 return NS_SUCCESS;
1695 }
1696 #endif
1697
1698 /* resolver logic */
1699
1700 /*
1701 * Formulate a normal query, send, and await answer.
1702 * Returned answer is placed in supplied buffer "answer".
1703 * Perform preliminary check of answer, returning success only
1704 * if no error is indicated and the answer count is nonzero.
1705 * Return the size of the response on success, -1 on error.
1706 * Error number is left in h_errno.
1707 *
1708 * Caller must parse answer and determine whether it answers the question.
1709 */
1710 static int
1711 res_queryN(const char *name, /* domain name */ struct res_target *target,
1712 res_state res)
1713 {
1714 u_char buf[MAXPACKET];
1715 HEADER *hp;
1716 int n;
1717 struct res_target *t;
1718 int rcode;
1719 int ancount;
1720
1721 _DIAGASSERT(name != NULL);
1722 /* XXX: target may be NULL??? */
1723
1724 rcode = NOERROR;
1725 ancount = 0;
1726
1727 for (t = target; t; t = t->next) {
1728 int class, type;
1729 u_char *answer;
1730 int anslen;
1731
1732 hp = (HEADER *)(void *)t->answer;
1733 hp->rcode = NOERROR; /* default */
1734
1735 /* make it easier... */
1736 class = t->qclass;
1737 type = t->qtype;
1738 answer = t->answer;
1739 anslen = t->anslen;
1740 #ifdef DEBUG
1741 if (res->options & RES_DEBUG)
1742 printf(";; res_nquery(%s, %d, %d)\n", name, class, type);
1743 #endif
1744
1745 n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
1746 buf, (int)sizeof(buf));
1747 #ifdef RES_USE_EDNS0
1748 if (n > 0 && (res->options & RES_USE_EDNS0) != 0)
1749 n = res_nopt(res, n, buf, (int)sizeof(buf), anslen);
1750 #endif
1751 if (n <= 0) {
1752 #ifdef DEBUG
1753 if (res->options & RES_DEBUG)
1754 printf(";; res_nquery: mkquery failed\n");
1755 #endif
1756 h_errno = NO_RECOVERY;
1757 return n;
1758 }
1759 n = res_nsend(res, buf, n, answer, anslen);
1760 #if 0
1761 if (n < 0) {
1762 #ifdef DEBUG
1763 if (res->options & RES_DEBUG)
1764 printf(";; res_query: send error\n");
1765 #endif
1766 h_errno = TRY_AGAIN;
1767 return n;
1768 }
1769 #endif
1770
1771 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1772 rcode = hp->rcode; /* record most recent error */
1773 #ifdef DEBUG
1774 if (res->options & RES_DEBUG)
1775 printf(";; rcode = %u, ancount=%u\n", hp->rcode,
1776 ntohs(hp->ancount));
1777 #endif
1778 continue;
1779 }
1780
1781 ancount += ntohs(hp->ancount);
1782
1783 t->n = n;
1784 }
1785
1786 if (ancount == 0) {
1787 switch (rcode) {
1788 case NXDOMAIN:
1789 h_errno = HOST_NOT_FOUND;
1790 break;
1791 case SERVFAIL:
1792 h_errno = TRY_AGAIN;
1793 break;
1794 case NOERROR:
1795 h_errno = NO_DATA;
1796 break;
1797 case FORMERR:
1798 case NOTIMP:
1799 case REFUSED:
1800 default:
1801 h_errno = NO_RECOVERY;
1802 break;
1803 }
1804 return -1;
1805 }
1806 return ancount;
1807 }
1808
1809 /*
1810 * Formulate a normal query, send, and retrieve answer in supplied buffer.
1811 * Return the size of the response on success, -1 on error.
1812 * If enabled, implement search rules until answer or unrecoverable failure
1813 * is detected. Error code, if any, is left in h_errno.
1814 */
1815 static int
1816 res_searchN(const char *name, struct res_target *target, res_state res)
1817 {
1818 const char *cp, * const *domain;
1819 HEADER *hp;
1820 u_int dots;
1821 int trailing_dot, ret, saved_herrno;
1822 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1823
1824 _DIAGASSERT(name != NULL);
1825 _DIAGASSERT(target != NULL);
1826
1827 hp = (HEADER *)(void *)target->answer; /*XXX*/
1828
1829 errno = 0;
1830 h_errno = HOST_NOT_FOUND; /* default, if we never query */
1831 dots = 0;
1832 for (cp = name; *cp; cp++)
1833 dots += (*cp == '.');
1834 trailing_dot = 0;
1835 if (cp > name && *--cp == '.')
1836 trailing_dot++;
1837
1838 /*
1839 * if there aren't any dots, it could be a user-level alias
1840 */
1841 if (!dots && (cp = __hostalias(name)) != NULL) {
1842 ret = res_queryN(cp, target, res);
1843 return ret;
1844 }
1845
1846 /*
1847 * If there are dots in the name already, let's just give it a try
1848 * 'as is'. The threshold can be set with the "ndots" option.
1849 */
1850 saved_herrno = -1;
1851 if (dots >= res->ndots) {
1852 ret = res_querydomainN(name, NULL, target, res);
1853 if (ret > 0)
1854 return (ret);
1855 saved_herrno = h_errno;
1856 tried_as_is++;
1857 }
1858
1859 /*
1860 * We do at least one level of search if
1861 * - there is no dot and RES_DEFNAME is set, or
1862 * - there is at least one dot, there is no trailing dot,
1863 * and RES_DNSRCH is set.
1864 */
1865 if ((!dots && (res->options & RES_DEFNAMES)) ||
1866 (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
1867 int done = 0;
1868
1869 for (domain = (const char * const *)res->dnsrch;
1870 *domain && !done;
1871 domain++) {
1872
1873 ret = res_querydomainN(name, *domain, target, res);
1874 if (ret > 0)
1875 return ret;
1876
1877 /*
1878 * If no server present, give up.
1879 * If name isn't found in this domain,
1880 * keep trying higher domains in the search list
1881 * (if that's enabled).
1882 * On a NO_DATA error, keep trying, otherwise
1883 * a wildcard entry of another type could keep us
1884 * from finding this entry higher in the domain.
1885 * If we get some other error (negative answer or
1886 * server failure), then stop searching up,
1887 * but try the input name below in case it's
1888 * fully-qualified.
1889 */
1890 if (errno == ECONNREFUSED) {
1891 h_errno = TRY_AGAIN;
1892 return -1;
1893 }
1894
1895 switch (h_errno) {
1896 case NO_DATA:
1897 got_nodata++;
1898 /* FALLTHROUGH */
1899 case HOST_NOT_FOUND:
1900 /* keep trying */
1901 break;
1902 case TRY_AGAIN:
1903 if (hp->rcode == SERVFAIL) {
1904 /* try next search element, if any */
1905 got_servfail++;
1906 break;
1907 }
1908 /* FALLTHROUGH */
1909 default:
1910 /* anything else implies that we're done */
1911 done++;
1912 }
1913 /*
1914 * if we got here for some reason other than DNSRCH,
1915 * we only wanted one iteration of the loop, so stop.
1916 */
1917 if (!(res->options & RES_DNSRCH))
1918 done++;
1919 }
1920 }
1921
1922 /*
1923 * if we have not already tried the name "as is", do that now.
1924 * note that we do this regardless of how many dots were in the
1925 * name or whether it ends with a dot.
1926 */
1927 if (!tried_as_is) {
1928 ret = res_querydomainN(name, NULL, target, res);
1929 if (ret > 0)
1930 return ret;
1931 }
1932
1933 /*
1934 * if we got here, we didn't satisfy the search.
1935 * if we did an initial full query, return that query's h_errno
1936 * (note that we wouldn't be here if that query had succeeded).
1937 * else if we ever got a nodata, send that back as the reason.
1938 * else send back meaningless h_errno, that being the one from
1939 * the last DNSRCH we did.
1940 */
1941 if (saved_herrno != -1)
1942 h_errno = saved_herrno;
1943 else if (got_nodata)
1944 h_errno = NO_DATA;
1945 else if (got_servfail)
1946 h_errno = TRY_AGAIN;
1947 return -1;
1948 }
1949
1950 /*
1951 * Perform a call on res_query on the concatenation of name and domain,
1952 * removing a trailing dot from name if domain is NULL.
1953 */
1954 static int
1955 res_querydomainN(const char *name, const char *domain,
1956 struct res_target *target, res_state res)
1957 {
1958 char nbuf[MAXDNAME];
1959 const char *longname = nbuf;
1960 size_t n, d;
1961
1962 _DIAGASSERT(name != NULL);
1963 /* XXX: target may be NULL??? */
1964
1965 #ifdef DEBUG
1966 if (res->options & RES_DEBUG)
1967 printf(";; res_querydomain(%s, %s)\n",
1968 name, domain?domain:"<Nil>");
1969 #endif
1970 if (domain == NULL) {
1971 /*
1972 * Check for trailing '.';
1973 * copy without '.' if present.
1974 */
1975 n = strlen(name);
1976 if (n + 1 > sizeof(nbuf)) {
1977 h_errno = NO_RECOVERY;
1978 return -1;
1979 }
1980 if (n > 0 && name[--n] == '.') {
1981 strncpy(nbuf, name, n);
1982 nbuf[n] = '\0';
1983 } else
1984 longname = name;
1985 } else {
1986 n = strlen(name);
1987 d = strlen(domain);
1988 if (n + 1 + d + 1 > sizeof(nbuf)) {
1989 h_errno = NO_RECOVERY;
1990 return -1;
1991 }
1992 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
1993 }
1994 return res_queryN(longname, target, res);
1995 }
1996