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