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