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