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.c1848
1 files changed, 1848 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..915286a404
--- /dev/null
+++ b/src/lib/libc/net/getaddrinfo.c
@@ -0,0 +1,1848 @@
1/* $OpenBSD: getaddrinfo.c,v 1.43 2002/08/27 08:53:13 itojun 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 (pai->ai_flags & AI_NUMERICHOST)
439 ERR(EAI_NODATA);
440 if (hostname == NULL)
441 ERR(EAI_NODATA);
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
502_THREAD_PRIVATE_MUTEX(getaddrinfo_explore_fqdn);
503
504static int
505explore_fqdn(pai, hostname, servname, res)
506 const struct addrinfo *pai;
507 const char *hostname;
508 const char *servname;
509 struct addrinfo **res;
510{
511 struct addrinfo *result;
512 struct addrinfo *cur;
513 int error = 0;
514 char lookups[MAXDNSLUS];
515 int i;
516
517 _THREAD_PRIVATE_MUTEX_LOCK(getaddrinfo_explore_fqdn);
518
519 result = NULL;
520
521#if 0
522 /*
523 * If AI_ADDRCONFIG is specified, check if we are expected to
524 * return the address family or not.
525 * XXX does not handle PF_UNSPEC case, should filter final result
526 */
527 if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(pai)) {
528 _THREAD_PRIVATE_MUTEX_UNLOCK(getaddrinfo_explore_fqdn);
529 return 0;
530 }
531#endif
532
533 /*
534 * if the servname does not match socktype/protocol, ignore it.
535 */
536 if (get_portmatch(pai, servname) != 0) {
537 _THREAD_PRIVATE_MUTEX_UNLOCK(getaddrinfo_explore_fqdn);
538 return 0;
539 }
540
541 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
542 strlcpy(lookups, "f", sizeof lookups);
543 else {
544 bcopy(_res.lookups, lookups, sizeof lookups);
545 if (lookups[0] == '\0')
546 strlcpy(lookups, "bf", sizeof lookups);
547 }
548
549 for (i = 0; i < MAXDNSLUS && result == NULL && lookups[i]; i++) {
550 switch (lookups[i]) {
551#ifdef YP
552 case 'y':
553 result = _yp_getaddrinfo(hostname, pai);
554 break;
555#endif
556 case 'b':
557 result = _dns_getaddrinfo(hostname, pai);
558 break;
559 case 'f':
560 result = _files_getaddrinfo(hostname, pai);
561 break;
562 }
563 }
564 if (result) {
565 for (cur = result; cur; cur = cur->ai_next) {
566 GET_PORT(cur, servname);
567 /* canonname should be filled already */
568 }
569 *res = result;
570 _THREAD_PRIVATE_MUTEX_UNLOCK(getaddrinfo_explore_fqdn);
571 return 0;
572 } else {
573 /* translate error code */
574 switch (h_errno) {
575 case NETDB_SUCCESS:
576 error = EAI_FAIL; /*XXX strange */
577 break;
578 case HOST_NOT_FOUND:
579 error = EAI_NODATA;
580 break;
581 case TRY_AGAIN:
582 error = EAI_AGAIN;
583 break;
584 case NO_RECOVERY:
585 error = EAI_FAIL;
586 break;
587 case NO_DATA:
588#if NO_ADDRESS != NO_DATA
589 case NO_ADDRESS:
590#endif
591 error = EAI_NODATA;
592 break;
593 default: /* unknown ones */
594 error = EAI_FAIL;
595 break;
596 }
597 }
598
599free:
600 if (result)
601 freeaddrinfo(result);
602 _THREAD_PRIVATE_MUTEX_UNLOCK(getaddrinfo_explore_fqdn);
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
871 if (servname == NULL)
872 return 0;
873 switch (ai->ai_family) {
874 case AF_INET:
875#ifdef AF_INET6
876 case AF_INET6:
877#endif
878 break;
879 default:
880 return 0;
881 }
882
883 switch (ai->ai_socktype) {
884 case SOCK_RAW:
885 return EAI_SERVICE;
886 case SOCK_DGRAM:
887 case SOCK_STREAM:
888 allownumeric = 1;
889 break;
890 case ANY:
891 allownumeric = 0;
892 break;
893 default:
894 return EAI_SOCKTYPE;
895 }
896
897 if (str_isnumber(servname)) {
898 if (!allownumeric)
899 return EAI_SERVICE;
900 port = atoi(servname);
901 if (port < 0 || port > 65535)
902 return EAI_SERVICE;
903 port = htons(port);
904 } else {
905 switch (ai->ai_socktype) {
906 case SOCK_DGRAM:
907 proto = "udp";
908 break;
909 case SOCK_STREAM:
910 proto = "tcp";
911 break;
912 default:
913 proto = NULL;
914 break;
915 }
916
917 if ((sp = getservbyname(servname, proto)) == NULL)
918 return EAI_SERVICE;
919 port = sp->s_port;
920 }
921
922 if (!matchonly) {
923 switch (ai->ai_family) {
924 case AF_INET:
925 ((struct sockaddr_in *)(void *)
926 ai->ai_addr)->sin_port = port;
927 break;
928#ifdef INET6
929 case AF_INET6:
930 ((struct sockaddr_in6 *)(void *)
931 ai->ai_addr)->sin6_port = port;
932 break;
933#endif
934 }
935 }
936
937 return 0;
938}
939
940static const struct afd *
941find_afd(af)
942 int af;
943{
944 const struct afd *afd;
945
946 if (af == PF_UNSPEC)
947 return NULL;
948 for (afd = afdl; afd->a_af; afd++) {
949 if (afd->a_af == af)
950 return afd;
951 }
952 return NULL;
953}
954
955#if 0
956/*
957 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend
958 * will take care of it.
959 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure
960 * if the code is right or not.
961 */
962static int
963addrconfig(pai)
964 const struct addrinfo *pai;
965{
966 int s;
967
968 /* XXX errno */
969 s = socket(pai->ai_family, SOCK_DGRAM, 0);
970 if (s < 0)
971 return 0;
972 close(s);
973 return 1;
974}
975#endif
976
977#ifdef INET6
978/* convert a string to a scope identifier. XXX: IPv6 specific */
979static int
980ip6_str2scopeid(scope, sin6, scopeid)
981 char *scope;
982 struct sockaddr_in6 *sin6;
983 u_int32_t *scopeid;
984{
985 u_long lscopeid;
986 struct in6_addr *a6 = &sin6->sin6_addr;
987 char *ep;
988
989 /* empty scopeid portion is invalid */
990 if (*scope == '\0')
991 return -1;
992
993 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
994 /*
995 * We currently assume a one-to-one mapping between links
996 * and interfaces, so we simply use interface indices for
997 * like-local scopes.
998 */
999 *scopeid = if_nametoindex(scope);
1000 if (*scopeid == 0)
1001 goto trynumeric;
1002 return 0;
1003 }
1004
1005 /* still unclear about literal, allow numeric only - placeholder */
1006 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1007 goto trynumeric;
1008 if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1009 goto trynumeric;
1010 else
1011 goto trynumeric; /* global */
1012
1013 /* try to convert to a numeric id as a last resort */
1014 trynumeric:
1015 errno = 0;
1016 lscopeid = strtoul(scope, &ep, 10);
1017 *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1018 if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
1019 return 0;
1020 else
1021 return -1;
1022}
1023#endif
1024
1025/* code duplicate with gethnamaddr.c */
1026
1027static const char AskedForGot[] =
1028 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1029static FILE *hostf = NULL;
1030
1031static struct addrinfo *
1032getanswer(answer, anslen, qname, qtype, pai)
1033 const querybuf *answer;
1034 int anslen;
1035 const char *qname;
1036 int qtype;
1037 const struct addrinfo *pai;
1038{
1039 struct addrinfo sentinel, *cur;
1040 struct addrinfo ai;
1041 const struct afd *afd;
1042 char *canonname;
1043 const HEADER *hp;
1044 const u_char *cp;
1045 int n;
1046 const u_char *eom;
1047 char *bp, *ep;
1048 int type, class, ancount, qdcount;
1049 int haveanswer, had_error;
1050 char tbuf[MAXDNAME];
1051 int (*name_ok)(const char *);
1052 char hostbuf[8*1024];
1053
1054 memset(&sentinel, 0, sizeof(sentinel));
1055 cur = &sentinel;
1056
1057 canonname = NULL;
1058 eom = answer->buf + anslen;
1059 switch (qtype) {
1060 case T_A:
1061 case T_AAAA:
1062 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
1063 name_ok = res_hnok;
1064 break;
1065 default:
1066 return (NULL); /* XXX should be abort() -- but that is illegal */
1067 }
1068 /*
1069 * find first satisfactory answer
1070 */
1071 hp = &answer->hdr;
1072 ancount = ntohs(hp->ancount);
1073 qdcount = ntohs(hp->qdcount);
1074 bp = hostbuf;
1075 ep = hostbuf + sizeof hostbuf;
1076 cp = answer->buf + HFIXEDSZ;
1077 if (qdcount != 1) {
1078 h_errno = NO_RECOVERY;
1079 return (NULL);
1080 }
1081 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1082 if ((n < 0) || !(*name_ok)(bp)) {
1083 h_errno = NO_RECOVERY;
1084 return (NULL);
1085 }
1086 cp += n + QFIXEDSZ;
1087 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1088 /* res_send() has already verified that the query name is the
1089 * same as the one we sent; this just gets the expanded name
1090 * (i.e., with the succeeding search-domain tacked on).
1091 */
1092 n = strlen(bp) + 1; /* for the \0 */
1093 if (n >= MAXHOSTNAMELEN) {
1094 h_errno = NO_RECOVERY;
1095 return (NULL);
1096 }
1097 canonname = bp;
1098 bp += n;
1099 /* The qname can be abbreviated, but h_name is now absolute. */
1100 qname = canonname;
1101 }
1102 haveanswer = 0;
1103 had_error = 0;
1104 while (ancount-- > 0 && cp < eom && !had_error) {
1105 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1106 if ((n < 0) || !(*name_ok)(bp)) {
1107 had_error++;
1108 continue;
1109 }
1110 cp += n; /* name */
1111 type = _getshort(cp);
1112 cp += INT16SZ; /* type */
1113 class = _getshort(cp);
1114 cp += INT16SZ + INT32SZ; /* class, TTL */
1115 n = _getshort(cp);
1116 cp += INT16SZ; /* len */
1117 if (class != C_IN) {
1118 /* XXX - debug? syslog? */
1119 cp += n;
1120 continue; /* XXX - had_error++ ? */
1121 }
1122 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1123 type == T_CNAME) {
1124 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1125 if ((n < 0) || !(*name_ok)(tbuf)) {
1126 had_error++;
1127 continue;
1128 }
1129 cp += n;
1130 /* Get canonical name. */
1131 n = strlen(tbuf) + 1; /* for the \0 */
1132 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1133 had_error++;
1134 continue;
1135 }
1136 strcpy(bp, tbuf);
1137 canonname = bp;
1138 bp += n;
1139 continue;
1140 }
1141 if (qtype == T_ANY) {
1142 if (!(type == T_A || type == T_AAAA)) {
1143 cp += n;
1144 continue;
1145 }
1146 } else if (type != qtype) {
1147 if (type != T_KEY && type != T_SIG)
1148 syslog(LOG_NOTICE|LOG_AUTH,
1149 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1150 qname, p_class(C_IN), p_type(qtype),
1151 p_type(type));
1152 cp += n;
1153 continue; /* XXX - had_error++ ? */
1154 }
1155 switch (type) {
1156 case T_A:
1157 case T_AAAA:
1158 if (strcasecmp(canonname, bp) != 0) {
1159 syslog(LOG_NOTICE|LOG_AUTH,
1160 AskedForGot, canonname, bp);
1161 cp += n;
1162 continue; /* XXX - had_error++ ? */
1163 }
1164 if (type == T_A && n != INADDRSZ) {
1165 cp += n;
1166 continue;
1167 }
1168 if (type == T_AAAA && n != IN6ADDRSZ) {
1169 cp += n;
1170 continue;
1171 }
1172 if (type == T_AAAA) {
1173 struct in6_addr in6;
1174 memcpy(&in6, cp, IN6ADDRSZ);
1175 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1176 cp += n;
1177 continue;
1178 }
1179 }
1180 if (!haveanswer) {
1181 int nn;
1182
1183 canonname = bp;
1184 nn = strlen(bp) + 1; /* for the \0 */
1185 bp += 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(); /* XXX abort illegal in library */
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*/
1223static struct addrinfo *
1224_dns_getaddrinfo(name, pai)
1225 const char *name;
1226 const struct addrinfo *pai;
1227{
1228 struct addrinfo *ai;
1229 querybuf *buf, *buf2;
1230 struct addrinfo sentinel, *cur;
1231 struct res_target q, q2;
1232
1233 memset(&q, 0, sizeof(q2));
1234 memset(&q2, 0, sizeof(q2));
1235 memset(&sentinel, 0, sizeof(sentinel));
1236 cur = &sentinel;
1237
1238 buf = malloc(sizeof(*buf));
1239 if (buf == NULL) {
1240 h_errno = NETDB_INTERNAL;
1241 return NULL;
1242 }
1243 buf2 = malloc(sizeof(*buf2));
1244 if (buf2 == NULL) {
1245 free(buf);
1246 h_errno = NETDB_INTERNAL;
1247 return NULL;
1248 }
1249
1250 switch (pai->ai_family) {
1251 case AF_UNSPEC:
1252 /* prefer IPv6 */
1253 q.qclass = C_IN;
1254 q.qtype = T_AAAA;
1255 q.answer = buf->buf;
1256 q.anslen = sizeof(buf->buf);
1257 q.next = &q2;
1258 q2.qclass = C_IN;
1259 q2.qtype = T_A;
1260 q2.answer = buf2->buf;
1261 q2.anslen = sizeof(buf2->buf);
1262 break;
1263 case AF_INET:
1264 q.qclass = C_IN;
1265 q.qtype = T_A;
1266 q.answer = buf->buf;
1267 q.anslen = sizeof(buf->buf);
1268 break;
1269 case AF_INET6:
1270 q.qclass = C_IN;
1271 q.qtype = T_AAAA;
1272 q.answer = buf->buf;
1273 q.anslen = sizeof(buf->buf);
1274 break;
1275 default:
1276 free(buf);
1277 free(buf2);
1278 return NULL;
1279 }
1280 if (res_searchN(name, &q) < 0) {
1281 free(buf);
1282 free(buf2);
1283 return NULL;
1284 }
1285 ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1286 if (ai) {
1287 cur->ai_next = ai;
1288 while (cur && cur->ai_next)
1289 cur = cur->ai_next;
1290 }
1291 if (q.next) {
1292 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1293 if (ai)
1294 cur->ai_next = ai;
1295 }
1296 free(buf);
1297 free(buf2);
1298 return sentinel.ai_next;
1299}
1300
1301static FILE *hostf;
1302
1303static void
1304_sethtent()
1305{
1306 if (!hostf)
1307 hostf = fopen(_PATH_HOSTS, "r" );
1308 else
1309 rewind(hostf);
1310}
1311
1312static void
1313_endhtent()
1314{
1315 if (hostf) {
1316 (void) fclose(hostf);
1317 hostf = NULL;
1318 }
1319}
1320
1321static struct addrinfo *
1322_gethtent(name, pai)
1323 const char *name;
1324 const struct addrinfo *pai;
1325{
1326 char *p;
1327 char *cp, *tname, *cname;
1328 struct addrinfo hints, *res0, *res;
1329 int error;
1330 const char *addr;
1331 char hostbuf[8*1024];
1332
1333 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
1334 return (NULL);
1335 again:
1336 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
1337 return (NULL);
1338 if (*p == '#')
1339 goto again;
1340 if (!(cp = strpbrk(p, "#\n")))
1341 goto again;
1342 *cp = '\0';
1343 if (!(cp = strpbrk(p, " \t")))
1344 goto again;
1345 *cp++ = '\0';
1346 addr = p;
1347 /* if this is not something we're looking for, skip it. */
1348 cname = NULL;
1349 while (cp && *cp) {
1350 if (*cp == ' ' || *cp == '\t') {
1351 cp++;
1352 continue;
1353 }
1354 if (!cname)
1355 cname = cp;
1356 tname = cp;
1357 if ((cp = strpbrk(cp, " \t")) != NULL)
1358 *cp++ = '\0';
1359 if (strcasecmp(name, tname) == 0)
1360 goto found;
1361 }
1362 goto again;
1363
1364found:
1365 hints = *pai;
1366 hints.ai_flags = AI_NUMERICHOST;
1367 error = getaddrinfo(addr, NULL, &hints, &res0);
1368 if (error)
1369 goto again;
1370 for (res = res0; res; res = res->ai_next) {
1371 /* cover it up */
1372 res->ai_flags = pai->ai_flags;
1373
1374 if (pai->ai_flags & AI_CANONNAME) {
1375 if (get_canonname(pai, res, cname) != 0) {
1376 freeaddrinfo(res0);
1377 goto again;
1378 }
1379 }
1380 }
1381 return res0;
1382}
1383
1384/*ARGSUSED*/
1385static struct addrinfo *
1386_files_getaddrinfo(name, pai)
1387 const char *name;
1388 const struct addrinfo *pai;
1389{
1390 struct addrinfo sentinel, *cur;
1391 struct addrinfo *p;
1392
1393 memset(&sentinel, 0, sizeof(sentinel));
1394 cur = &sentinel;
1395
1396 _sethtent();
1397 while ((p = _gethtent(name, pai)) != NULL) {
1398 cur->ai_next = p;
1399 while (cur && cur->ai_next)
1400 cur = cur->ai_next;
1401 }
1402 _endhtent();
1403
1404 return sentinel.ai_next;
1405}
1406
1407#ifdef YP
1408static char *__ypdomain;
1409
1410/*ARGSUSED*/
1411static struct addrinfo *
1412_yphostent(line, pai)
1413 char *line;
1414 const struct addrinfo *pai;
1415{
1416 struct addrinfo sentinel, *cur;
1417 struct addrinfo hints, *res, *res0;
1418 int error;
1419 char *p = line;
1420 const char *addr, *canonname;
1421 char *nextline;
1422 char *cp;
1423
1424 addr = canonname = NULL;
1425
1426 memset(&sentinel, 0, sizeof(sentinel));
1427 cur = &sentinel;
1428
1429nextline:
1430 /* terminate line */
1431 cp = strchr(p, '\n');
1432 if (cp) {
1433 *cp++ = '\0';
1434 nextline = cp;
1435 } else
1436 nextline = NULL;
1437
1438 cp = strpbrk(p, " \t");
1439 if (cp == NULL) {
1440 if (canonname == NULL)
1441 return (NULL);
1442 else
1443 goto done;
1444 }
1445 *cp++ = '\0';
1446
1447 addr = p;
1448
1449 while (cp && *cp) {
1450 if (*cp == ' ' || *cp == '\t') {
1451 cp++;
1452 continue;
1453 }
1454 if (!canonname)
1455 canonname = cp;
1456 if ((cp = strpbrk(cp, " \t")) != NULL)
1457 *cp++ = '\0';
1458 }
1459
1460 hints = *pai;
1461 hints.ai_flags = AI_NUMERICHOST;
1462 error = getaddrinfo(addr, NULL, &hints, &res0);
1463 if (error == 0) {
1464 for (res = res0; res; res = res->ai_next) {
1465 /* cover it up */
1466 res->ai_flags = pai->ai_flags;
1467
1468 if (pai->ai_flags & AI_CANONNAME)
1469 (void)get_canonname(pai, res, canonname);
1470 }
1471 } else
1472 res0 = NULL;
1473 if (res0) {
1474 cur->ai_next = res0;
1475 while (cur && cur->ai_next)
1476 cur = cur->ai_next;
1477 }
1478
1479 if (nextline) {
1480 p = nextline;
1481 goto nextline;
1482 }
1483
1484done:
1485 return sentinel.ai_next;
1486}
1487
1488/*ARGSUSED*/
1489static struct addrinfo *
1490_yp_getaddrinfo(name, pai)
1491 const char *name;
1492 const struct addrinfo *pai;
1493{
1494 struct addrinfo sentinel, *cur;
1495 struct addrinfo *ai = NULL;
1496 static char *__ypcurrent;
1497 int __ypcurrentlen, r;
1498
1499 memset(&sentinel, 0, sizeof(sentinel));
1500 cur = &sentinel;
1501
1502 if (!__ypdomain) {
1503 if (_yp_check(&__ypdomain) == 0)
1504 return NULL;
1505 }
1506 if (__ypcurrent)
1507 free(__ypcurrent);
1508 __ypcurrent = NULL;
1509
1510 /* hosts.byname is only for IPv4 (Solaris8) */
1511 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
1512 r = yp_match(__ypdomain, "hosts.byname", name,
1513 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1514 if (r == 0) {
1515 struct addrinfo ai4;
1516
1517 ai4 = *pai;
1518 ai4.ai_family = AF_INET;
1519 ai = _yphostent(__ypcurrent, &ai4);
1520 if (ai) {
1521 cur->ai_next = ai;
1522 while (cur && cur->ai_next)
1523 cur = cur->ai_next;
1524 }
1525 }
1526 }
1527
1528 /* ipnodes.byname can hold both IPv4/v6 */
1529 r = yp_match(__ypdomain, "ipnodes.byname", name,
1530 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1531 if (r == 0) {
1532 ai = _yphostent(__ypcurrent, pai);
1533 if (ai) {
1534 cur->ai_next = ai;
1535 while (cur && cur->ai_next)
1536 cur = cur->ai_next;
1537 }
1538 }
1539
1540 return sentinel.ai_next;
1541}
1542#endif
1543
1544
1545/* resolver logic */
1546
1547extern const char *__hostalias(const char *);
1548extern int h_errno;
1549extern int res_opt(int, u_char *, int, int);
1550
1551/*
1552 * Formulate a normal query, send, and await answer.
1553 * Returned answer is placed in supplied buffer "answer".
1554 * Perform preliminary check of answer, returning success only
1555 * if no error is indicated and the answer count is nonzero.
1556 * Return the size of the response on success, -1 on error.
1557 * Error number is left in h_errno.
1558 *
1559 * Caller must parse answer and determine whether it answers the question.
1560 */
1561static int
1562res_queryN(name, target)
1563 const char *name; /* domain name */
1564 struct res_target *target;
1565{
1566 u_char buf[MAXPACKET];
1567 HEADER *hp;
1568 int n;
1569 struct res_target *t;
1570 int rcode;
1571 int ancount;
1572
1573 rcode = NOERROR;
1574 ancount = 0;
1575
1576 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1577 h_errno = NETDB_INTERNAL;
1578 return (-1);
1579 }
1580
1581 for (t = target; t; t = t->next) {
1582 int class, type;
1583 u_char *answer;
1584 int anslen;
1585
1586 hp = (HEADER *)(void *)t->answer;
1587 hp->rcode = NOERROR; /* default */
1588
1589 /* make it easier... */
1590 class = t->qclass;
1591 type = t->qtype;
1592 answer = t->answer;
1593 anslen = t->anslen;
1594#ifdef DEBUG
1595 if (_res.options & RES_DEBUG)
1596 printf(";; res_query(%s, %d, %d)\n", name, class, type);
1597#endif
1598
1599 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
1600 buf, sizeof(buf));
1601 if (n > 0 && (_res.options & RES_USE_EDNS0) != 0)
1602 n = res_opt(n, buf, sizeof(buf), anslen);
1603 if (n <= 0) {
1604#ifdef DEBUG
1605 if (_res.options & RES_DEBUG)
1606 printf(";; res_query: mkquery failed\n");
1607#endif
1608 h_errno = NO_RECOVERY;
1609 return (n);
1610 }
1611 n = res_send(buf, n, answer, anslen);
1612#if 0
1613 if (n < 0) {
1614#ifdef DEBUG
1615 if (_res.options & RES_DEBUG)
1616 printf(";; res_query: send error\n");
1617#endif
1618 h_errno = TRY_AGAIN;
1619 return (n);
1620 }
1621#endif
1622
1623 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1624 rcode = hp->rcode; /* record most recent error */
1625#ifdef DEBUG
1626 if (_res.options & RES_DEBUG)
1627 printf(";; rcode = %u, ancount=%u\n", hp->rcode,
1628 ntohs(hp->ancount));
1629#endif
1630 continue;
1631 }
1632
1633 ancount += ntohs(hp->ancount);
1634
1635 t->n = n;
1636 }
1637
1638 if (ancount == 0) {
1639 switch (rcode) {
1640 case NXDOMAIN:
1641 h_errno = HOST_NOT_FOUND;
1642 break;
1643 case SERVFAIL:
1644 h_errno = TRY_AGAIN;
1645 break;
1646 case NOERROR:
1647 h_errno = NO_DATA;
1648 break;
1649 case FORMERR:
1650 case NOTIMP:
1651 case REFUSED:
1652 default:
1653 h_errno = NO_RECOVERY;
1654 break;
1655 }
1656 return (-1);
1657 }
1658 return (ancount);
1659}
1660
1661/*
1662 * Formulate a normal query, send, and retrieve answer in supplied buffer.
1663 * Return the size of the response on success, -1 on error.
1664 * If enabled, implement search rules until answer or unrecoverable failure
1665 * is detected. Error code, if any, is left in h_errno.
1666 */
1667static int
1668res_searchN(name, target)
1669 const char *name; /* domain name */
1670 struct res_target *target;
1671{
1672 const char *cp, * const *domain;
1673 HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/
1674 u_int dots;
1675 int trailing_dot, ret, saved_herrno;
1676 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1677
1678 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1679 h_errno = NETDB_INTERNAL;
1680 return (-1);
1681 }
1682
1683 errno = 0;
1684 h_errno = HOST_NOT_FOUND; /* default, if we never query */
1685 dots = 0;
1686 for (cp = name; *cp; cp++)
1687 dots += (*cp == '.');
1688 trailing_dot = 0;
1689 if (cp > name && *--cp == '.')
1690 trailing_dot++;
1691
1692 /*
1693 * if there aren't any dots, it could be a user-level alias
1694 */
1695 if (!dots && (cp = __hostalias(name)) != NULL)
1696 return (res_queryN(cp, target));
1697
1698 /*
1699 * If there are dots in the name already, let's just give it a try
1700 * 'as is'. The threshold can be set with the "ndots" option.
1701 */
1702 saved_herrno = -1;
1703 if (dots >= _res.ndots) {
1704 ret = res_querydomainN(name, NULL, target);
1705 if (ret > 0)
1706 return (ret);
1707 saved_herrno = h_errno;
1708 tried_as_is++;
1709 }
1710
1711 /*
1712 * We do at least one level of search if
1713 * - there is no dot and RES_DEFNAME is set, or
1714 * - there is at least one dot, there is no trailing dot,
1715 * and RES_DNSRCH is set.
1716 */
1717 if ((!dots && (_res.options & RES_DEFNAMES)) ||
1718 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1719 int done = 0;
1720
1721 for (domain = (const char * const *)_res.dnsrch;
1722 *domain && !done;
1723 domain++) {
1724
1725 ret = res_querydomainN(name, *domain, target);
1726 if (ret > 0)
1727 return (ret);
1728
1729 /*
1730 * If no server present, give up.
1731 * If name isn't found in this domain,
1732 * keep trying higher domains in the search list
1733 * (if that's enabled).
1734 * On a NO_DATA error, keep trying, otherwise
1735 * a wildcard entry of another type could keep us
1736 * from finding this entry higher in the domain.
1737 * If we get some other error (negative answer or
1738 * server failure), then stop searching up,
1739 * but try the input name below in case it's
1740 * fully-qualified.
1741 */
1742 if (errno == ECONNREFUSED) {
1743 h_errno = TRY_AGAIN;
1744 return (-1);
1745 }
1746
1747 switch (h_errno) {
1748 case NO_DATA:
1749 got_nodata++;
1750 /* FALLTHROUGH */
1751 case HOST_NOT_FOUND:
1752 /* keep trying */
1753 break;
1754 case TRY_AGAIN:
1755 if (hp->rcode == SERVFAIL) {
1756 /* try next search element, if any */
1757 got_servfail++;
1758 break;
1759 }
1760 /* FALLTHROUGH */
1761 default:
1762 /* anything else implies that we're done */
1763 done++;
1764 }
1765 /*
1766 * if we got here for some reason other than DNSRCH,
1767 * we only wanted one iteration of the loop, so stop.
1768 */
1769 if (!(_res.options & RES_DNSRCH))
1770 done++;
1771 }
1772 }
1773
1774 /*
1775 * if we have not already tried the name "as is", do that now.
1776 * note that we do this regardless of how many dots were in the
1777 * name or whether it ends with a dot.
1778 */
1779 if (!tried_as_is) {
1780 ret = res_querydomainN(name, NULL, target);
1781 if (ret > 0)
1782 return (ret);
1783 }
1784
1785 /*
1786 * if we got here, we didn't satisfy the search.
1787 * if we did an initial full query, return that query's h_errno
1788 * (note that we wouldn't be here if that query had succeeded).
1789 * else if we ever got a nodata, send that back as the reason.
1790 * else send back meaningless h_errno, that being the one from
1791 * the last DNSRCH we did.
1792 */
1793 if (saved_herrno != -1)
1794 h_errno = saved_herrno;
1795 else if (got_nodata)
1796 h_errno = NO_DATA;
1797 else if (got_servfail)
1798 h_errno = TRY_AGAIN;
1799 return (-1);
1800}
1801
1802/*
1803 * Perform a call on res_query on the concatenation of name and domain,
1804 * removing a trailing dot from name if domain is NULL.
1805 */
1806static int
1807res_querydomainN(name, domain, target)
1808 const char *name, *domain;
1809 struct res_target *target;
1810{
1811 char nbuf[MAXDNAME];
1812 const char *longname = nbuf;
1813 size_t n, d;
1814
1815 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1816 h_errno = NETDB_INTERNAL;
1817 return (-1);
1818 }
1819#ifdef DEBUG
1820 if (_res.options & RES_DEBUG)
1821 printf(";; res_querydomain(%s, %s)\n",
1822 name, domain?domain:"<Nil>");
1823#endif
1824 if (domain == NULL) {
1825 /*
1826 * Check for trailing '.';
1827 * copy without '.' if present.
1828 */
1829 n = strlen(name);
1830 if (n >= MAXDNAME) {
1831 h_errno = NO_RECOVERY;
1832 return (-1);
1833 }
1834 if (n > 0 && name[--n] == '.') {
1835 strlcpy(nbuf, name, n + 1);
1836 } else
1837 longname = name;
1838 } else {
1839 n = strlen(name);
1840 d = strlen(domain);
1841 if (n + d + 1 >= MAXDNAME) {
1842 h_errno = NO_RECOVERY;
1843 return (-1);
1844 }
1845 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
1846 }
1847 return (res_queryN(longname, target));
1848}