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