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