summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/gethostnamadr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/gethostnamadr.c')
-rw-r--r--src/lib/libc/net/gethostnamadr.c1126
1 files changed, 1126 insertions, 0 deletions
diff --git a/src/lib/libc/net/gethostnamadr.c b/src/lib/libc/net/gethostnamadr.c
new file mode 100644
index 0000000000..d1c7d80df6
--- /dev/null
+++ b/src/lib/libc/net/gethostnamadr.c
@@ -0,0 +1,1126 @@
1/* $OpenBSD: gethostnamadr.c,v 1.68 2005/08/06 20:30:03 espie Exp $ */
2/*-
3 * Copyright (c) 1985, 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 * -
30 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
31 *
32 * Permission to use, copy, modify, and distribute this software for any
33 * purpose with or without fee is hereby granted, provided that the above
34 * copyright notice and this permission notice appear in all copies, and that
35 * the name of Digital Equipment Corporation not be used in advertising or
36 * publicity pertaining to distribution of the document or software without
37 * specific, written prior permission.
38 *
39 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
40 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
41 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
42 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
43 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
44 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
45 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
46 * SOFTWARE.
47 * -
48 * --Copyright--
49 */
50
51#include <sys/param.h>
52#include <sys/socket.h>
53#include <netinet/in.h>
54#include <arpa/inet.h>
55#include <arpa/nameser.h>
56#include <netdb.h>
57#include <resolv.h>
58#include <stdio.h>
59#include <ctype.h>
60#include <errno.h>
61#include <string.h>
62#include <syslog.h>
63#include <stdlib.h>
64#ifdef YP
65#include <rpc/rpc.h>
66#include <rpcsvc/yp.h>
67#include <rpcsvc/ypclnt.h>
68#include "ypinternal.h"
69#endif
70#include "thread_private.h"
71
72#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
73
74#define MAXALIASES 35
75#define MAXADDRS 35
76
77static char *h_addr_ptrs[MAXADDRS + 1];
78
79#ifdef YP
80static char *__ypdomain;
81#endif
82
83static struct hostent host;
84static char *host_aliases[MAXALIASES];
85static char hostbuf[BUFSIZ+1];
86static union {
87 struct in_addr _host_in_addr;
88 u_char _host_addr[16]; /* IPv4 or IPv6 */
89} _host_addr_u;
90#define host_addr _host_addr_u._host_addr
91static FILE *hostf = NULL;
92static int stayopen = 0;
93
94static void map_v4v6_address(const char *src, char *dst);
95static void map_v4v6_hostent(struct hostent *hp, char **bp, char *);
96
97#ifdef RESOLVSORT
98static void addrsort(char **, int);
99#endif
100
101int _hokchar(const char *);
102
103static const char AskedForGot[] =
104 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
105
106#define MAXPACKET (64*1024)
107
108typedef union {
109 HEADER hdr;
110 u_char buf[MAXPACKET];
111} querybuf;
112
113typedef union {
114 int32_t al;
115 char ac;
116} align;
117
118static struct hostent *getanswer(const querybuf *, int, const char *, int);
119
120extern int h_errno;
121
122int
123_hokchar(const char *p)
124{
125 char c;
126
127 /*
128 * Many people do not obey RFC 822 and 1035. The valid
129 * characters are a-z, A-Z, 0-9, '-' and . But the others
130 * tested for below can happen, and we must be more permissive
131 * than the resolver until those idiots clean up their act.
132 * We let '/' through, but not '..'
133 */
134 while ((c = *p++)) {
135 if (('a' <= c && c <= 'z') ||
136 ('A' <= c && c <= 'Z') ||
137 ('0' <= c && c <= '9'))
138 continue;
139 if (strchr("-_/", c))
140 continue;
141 if (c == '.' && *p != '.')
142 continue;
143 return 0;
144 }
145 return 1;
146}
147
148static struct hostent *
149getanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
150{
151 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
152 const HEADER *hp;
153 const u_char *cp, *eom;
154 char tbuf[MAXDNAME];
155 char *bp, **ap, **hap, *ep;
156 int type, class, ancount, qdcount, n;
157 int haveanswer, had_error, toobig = 0;
158 const char *tname;
159 int (*name_ok)(const char *);
160
161 tname = qname;
162 host.h_name = NULL;
163 eom = answer->buf + anslen;
164 switch (qtype) {
165 case T_A:
166 case T_AAAA:
167#ifdef USE_RESOLV_NAME_OK
168 name_ok = res_hnok;
169 break;
170#endif
171 case T_PTR:
172#ifdef USE_RESOLV_NAME_OK
173 name_ok = res_dnok;
174#else
175 name_ok = _hokchar;
176#endif
177 break;
178 default:
179 return (NULL);
180 }
181 /*
182 * find first satisfactory answer
183 */
184 hp = &answer->hdr;
185 ancount = ntohs(hp->ancount);
186 qdcount = ntohs(hp->qdcount);
187 bp = hostbuf;
188 ep = hostbuf + sizeof hostbuf;
189 cp = answer->buf + HFIXEDSZ;
190 if (qdcount != 1) {
191 h_errno = NO_RECOVERY;
192 return (NULL);
193 }
194 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
195 if ((n < 0) || !(*name_ok)(bp)) {
196 h_errno = NO_RECOVERY;
197 return (NULL);
198 }
199 cp += n + QFIXEDSZ;
200 if (qtype == T_A || qtype == T_AAAA) {
201 /* res_send() has already verified that the query name is the
202 * same as the one we sent; this just gets the expanded name
203 * (i.e., with the succeeding search-domain tacked on).
204 */
205 n = strlen(bp) + 1; /* for the \0 */
206 host.h_name = bp;
207 bp += n;
208 /* The qname can be abbreviated, but h_name is now absolute. */
209 qname = host.h_name;
210 }
211 ap = host_aliases;
212 *ap = NULL;
213 host.h_aliases = host_aliases;
214 hap = h_addr_ptrs;
215 *hap = NULL;
216 host.h_addr_list = h_addr_ptrs;
217 haveanswer = 0;
218 had_error = 0;
219 while (ancount-- > 0 && cp < eom && !had_error) {
220 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
221 if ((n < 0) || !(*name_ok)(bp)) {
222 had_error++;
223 continue;
224 }
225 cp += n; /* name */
226 if (cp >= eom)
227 break;
228 type = _getshort(cp);
229 cp += INT16SZ; /* type */
230 if (cp >= eom)
231 break;
232 class = _getshort(cp);
233 cp += INT16SZ + INT32SZ; /* class, TTL */
234 if (cp >= eom)
235 break;
236 n = _getshort(cp);
237 cp += INT16SZ; /* len */
238 if (cp >= eom)
239 break;
240 if (type == T_SIG) {
241 /* XXX - ignore signatures as we don't use them yet */
242 cp += n;
243 continue;
244 }
245 if (class != C_IN) {
246 /* XXX - debug? syslog? */
247 cp += n;
248 continue; /* XXX - had_error++ ? */
249 }
250 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
251 if (ap >= &host_aliases[MAXALIASES-1])
252 continue;
253 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
254 if ((n < 0) || !(*name_ok)(tbuf)) {
255 had_error++;
256 continue;
257 }
258 cp += n;
259 /* Store alias. */
260 *ap++ = bp;
261 n = strlen(bp) + 1; /* for the \0 */
262 bp += n;
263 /* Get canonical name. */
264 n = strlen(tbuf) + 1; /* for the \0 */
265 if (n > ep - bp) {
266 had_error++;
267 continue;
268 }
269 strlcpy(bp, tbuf, ep - bp);
270 host.h_name = bp;
271 bp += n;
272 continue;
273 }
274 if (qtype == T_PTR && type == T_CNAME) {
275 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
276#ifdef USE_RESOLV_NAME_OK
277 if ((n < 0) || !res_hnok(tbuf)) {
278#else
279 if ((n < 0) || !_hokchar(tbuf)) {
280#endif
281 had_error++;
282 continue;
283 }
284 cp += n;
285 /* Get canonical name. */
286 n = strlen(tbuf) + 1; /* for the \0 */
287 if (n > ep - bp) {
288 had_error++;
289 continue;
290 }
291 strlcpy(bp, tbuf, ep - bp);
292 tname = bp;
293 bp += n;
294 continue;
295 }
296 if (type != qtype) {
297 syslog(LOG_NOTICE|LOG_AUTH,
298 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
299 qname, p_class(C_IN), p_type(qtype),
300 p_type(type));
301 cp += n;
302 continue; /* XXX - had_error++ ? */
303 }
304 switch (type) {
305 case T_PTR:
306 if (strcasecmp(tname, bp) != 0) {
307 syslog(LOG_NOTICE|LOG_AUTH,
308 AskedForGot, qname, bp);
309 cp += n;
310 continue; /* XXX - had_error++ ? */
311 }
312 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
313#ifdef USE_RESOLV_NAME_OK
314 if ((n < 0) || !res_hnok(bp)) {
315#else
316 if ((n < 0) || !_hokchar(bp)) {
317#endif
318 had_error++;
319 break;
320 }
321#if MULTI_PTRS_ARE_ALIASES
322 cp += n;
323 if (!haveanswer)
324 host.h_name = bp;
325 else if (ap < &host_aliases[MAXALIASES-1])
326 *ap++ = bp;
327 else
328 n = -1;
329 if (n != -1) {
330 n = strlen(bp) + 1; /* for the \0 */
331 bp += n;
332 }
333 break;
334#else
335 host.h_name = bp;
336 if (_resp->options & RES_USE_INET6) {
337 n = strlen(bp) + 1; /* for the \0 */
338 bp += n;
339 map_v4v6_hostent(&host, &bp, ep);
340 }
341 h_errno = NETDB_SUCCESS;
342 return (&host);
343#endif
344 case T_A:
345 case T_AAAA:
346 if (strcasecmp(host.h_name, bp) != 0) {
347 syslog(LOG_NOTICE|LOG_AUTH,
348 AskedForGot, host.h_name, bp);
349 cp += n;
350 continue; /* XXX - had_error++ ? */
351 }
352 if (n != host.h_length) {
353 cp += n;
354 continue;
355 }
356 if (type == T_AAAA) {
357 struct in6_addr in6;
358 memcpy(&in6, cp, IN6ADDRSZ);
359 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
360 cp += n;
361 continue;
362 }
363 }
364 if (!haveanswer) {
365 int nn;
366
367 host.h_name = bp;
368 nn = strlen(bp) + 1; /* for the \0 */
369 bp += nn;
370 }
371
372 bp += sizeof(align) - ((u_long)bp % sizeof(align));
373
374 if (bp + n >= &hostbuf[sizeof hostbuf]) {
375#ifdef DEBUG
376 if (_resp->options & RES_DEBUG)
377 printf("size (%d) too big\n", n);
378#endif
379 had_error++;
380 continue;
381 }
382 if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
383 if (!toobig++)
384#ifdef DEBUG
385 if (_resp->options & RES_DEBUG)
386 printf("Too many addresses (%d)\n", MAXADDRS);
387#endif
388 cp += n;
389 continue;
390 }
391 bcopy(cp, *hap++ = bp, n);
392 bp += n;
393 cp += n;
394 break;
395 }
396 if (!had_error)
397 haveanswer++;
398 }
399 if (haveanswer) {
400 *ap = NULL;
401 *hap = NULL;
402# if defined(RESOLVSORT)
403 /*
404 * Note: we sort even if host can take only one address
405 * in its return structures - should give it the "best"
406 * address in that case, not some random one
407 */
408 if (_resp->nsort && haveanswer > 1 && qtype == T_A)
409 addrsort(h_addr_ptrs, haveanswer);
410# endif /*RESOLVSORT*/
411 if (!host.h_name) {
412 n = strlen(qname) + 1; /* for the \0 */
413 if (n > ep - bp)
414 goto try_again;
415 strlcpy(bp, qname, ep - bp);
416 host.h_name = bp;
417 bp += n;
418 }
419 if (_resp->options & RES_USE_INET6)
420 map_v4v6_hostent(&host, &bp, ep);
421 h_errno = NETDB_SUCCESS;
422 return (&host);
423 }
424 try_again:
425 h_errno = TRY_AGAIN;
426 return (NULL);
427}
428
429#ifdef notyet
430/*
431 * XXX This is an extremely bogus implementation.
432 *
433 * FreeBSD has this interface:
434 * int gethostbyaddr_r(const char *addr, int len, int type,
435 * struct hostent *result, struct hostent_data *buffer)
436 */
437
438struct hostent *
439gethostbyname_r(const char *name, struct hostent *hp, char *buf, int buflen,
440 int *errorp)
441{
442 struct hostent *res;
443
444 res = gethostbyname(name);
445 *errorp = h_errno;
446 if (res == NULL)
447 return NULL;
448 memcpy(hp, res, sizeof *hp); /* XXX not sufficient */
449 return hp;
450}
451
452/*
453 * XXX This is an extremely bogus implementation.
454 */
455struct hostent *
456gethostbyaddr_r(const char *addr, int len, int af, struct hostent *he,
457 char *buf, int buflen, int *errorp)
458{
459 struct hostent * res;
460
461 res = gethostbyaddr(addr, len, af);
462 *errorp = h_errno;
463 if (res == NULL)
464 return NULL;
465 memcpy(he, res, sizeof *he); /* XXX not sufficient */
466 return he;
467}
468
469/* XXX RFC2133 expects a gethostbyname2_r() -- unimplemented */
470#endif
471
472struct hostent *
473gethostbyname(const char *name)
474{
475 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
476 struct hostent *hp;
477 extern struct hostent *_gethtbyname2(const char *, int);
478
479 if (_res_init(0) == -1)
480 hp = _gethtbyname2(name, AF_INET);
481
482 else if (_resp->options & RES_USE_INET6) {
483 hp = gethostbyname2(name, AF_INET6);
484 if (hp == NULL)
485 hp = gethostbyname2(name, AF_INET);
486 }
487 else
488 hp = gethostbyname2(name, AF_INET);
489 return hp;
490}
491
492struct hostent *
493gethostbyname2(const char *name, int af)
494{
495 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
496 querybuf *buf;
497 const char *cp;
498 char *bp, *ep;
499 int n, size, type, i;
500 struct hostent *hp;
501 char lookups[MAXDNSLUS];
502 extern struct hostent *_gethtbyname2(const char *, int);
503 extern struct hostent *_yp_gethtbyname(const char *);
504
505 if (_res_init(0) == -1)
506 return (_gethtbyname2(name, af));
507
508 switch (af) {
509 case AF_INET:
510 size = INADDRSZ;
511 type = T_A;
512 break;
513 case AF_INET6:
514 size = IN6ADDRSZ;
515 type = T_AAAA;
516 break;
517 default:
518 h_errno = NETDB_INTERNAL;
519 errno = EAFNOSUPPORT;
520 return (NULL);
521 }
522
523 host.h_addrtype = af;
524 host.h_length = size;
525
526 /*
527 * if there aren't any dots, it could be a user-level alias.
528 * this is also done in res_query() since we are not the only
529 * function that looks up host names.
530 */
531 if (!strchr(name, '.') && (cp = __hostalias(name)))
532 name = cp;
533
534 /*
535 * disallow names consisting only of digits/dots, unless
536 * they end in a dot.
537 */
538 if (isdigit(name[0]))
539 for (cp = name;; ++cp) {
540 if (!*cp) {
541 if (*--cp == '.')
542 break;
543 /*
544 * All-numeric, no dot at the end.
545 * Fake up a hostent as if we'd actually
546 * done a lookup.
547 */
548 if (inet_pton(af, name, host_addr) <= 0) {
549 h_errno = HOST_NOT_FOUND;
550 return (NULL);
551 }
552 strlcpy(hostbuf, name, MAXHOSTNAMELEN);
553 bp = hostbuf + MAXHOSTNAMELEN;
554 ep = hostbuf + sizeof(hostbuf);
555 host.h_name = hostbuf;
556 host.h_aliases = host_aliases;
557 host_aliases[0] = NULL;
558 h_addr_ptrs[0] = (char *)host_addr;
559 h_addr_ptrs[1] = NULL;
560 host.h_addr_list = h_addr_ptrs;
561 if (_resp->options & RES_USE_INET6)
562 map_v4v6_hostent(&host, &bp, ep);
563 h_errno = NETDB_SUCCESS;
564 return (&host);
565 }
566 if (!isdigit(*cp) && *cp != '.')
567 break;
568 }
569 if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
570 name[0] == ':')
571 for (cp = name;; ++cp) {
572 if (!*cp) {
573 if (*--cp == '.')
574 break;
575 /*
576 * All-IPv6-legal, no dot at the end.
577 * Fake up a hostent as if we'd actually
578 * done a lookup.
579 */
580 if (inet_pton(af, name, host_addr) <= 0) {
581 h_errno = HOST_NOT_FOUND;
582 return (NULL);
583 }
584 strlcpy(hostbuf, name, MAXHOSTNAMELEN);
585 bp = hostbuf + MAXHOSTNAMELEN;
586 ep = hostbuf + sizeof(hostbuf);
587 host.h_name = hostbuf;
588 host.h_aliases = host_aliases;
589 host_aliases[0] = NULL;
590 h_addr_ptrs[0] = (char *)host_addr;
591 h_addr_ptrs[1] = NULL;
592 host.h_addr_list = h_addr_ptrs;
593 h_errno = NETDB_SUCCESS;
594 return (&host);
595 }
596 if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
597 break;
598 }
599
600 bcopy(_resp->lookups, lookups, sizeof lookups);
601 if (lookups[0] == '\0')
602 strlcpy(lookups, "bf", sizeof lookups);
603
604 hp = (struct hostent *)NULL;
605 for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
606 switch (lookups[i]) {
607#ifdef YP
608 case 'y':
609 /* YP only supports AF_INET. */
610 if (af == AF_INET)
611 hp = _yp_gethtbyname(name);
612 break;
613#endif
614 case 'b':
615 buf = malloc(sizeof(*buf));
616 if (buf == NULL)
617 break;
618 if ((n = res_search(name, C_IN, type, buf->buf,
619 sizeof(buf->buf))) < 0) {
620 free(buf);
621#ifdef DEBUG
622 if (_resp->options & RES_DEBUG)
623 printf("res_search failed\n");
624#endif
625 break;
626 }
627 hp = getanswer(buf, n, name, type);
628 free(buf);
629 break;
630 case 'f':
631 hp = _gethtbyname2(name, af);
632 break;
633 }
634 }
635 /* XXX h_errno not correct in all cases... */
636 return (hp);
637}
638
639struct hostent *
640gethostbyaddr(const void *addr, socklen_t len, int af)
641{
642 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
643 const u_char *uaddr = (const u_char *)addr;
644 int n, size, i;
645 querybuf *buf;
646 struct hostent *hp;
647 char qbuf[MAXDNAME+1], *qp, *ep;
648 char lookups[MAXDNSLUS];
649 struct hostent *res;
650 extern struct hostent *_gethtbyaddr(const void *, socklen_t, int);
651 extern struct hostent *_yp_gethtbyaddr(const void *);
652
653 if (_res_init(0) == -1) {
654 res = _gethtbyaddr(addr, len, af);
655 return (res);
656 }
657
658 if (af == AF_INET6 && len == IN6ADDRSZ &&
659 (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)uaddr) ||
660 IN6_IS_ADDR_SITELOCAL((struct in6_addr *)uaddr))) {
661 h_errno = HOST_NOT_FOUND;
662 return (NULL);
663 }
664 if (af == AF_INET6 && len == IN6ADDRSZ &&
665 (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)uaddr) ||
666 IN6_IS_ADDR_V4COMPAT((struct in6_addr *)uaddr))) {
667 /* Unmap. */
668 uaddr += IN6ADDRSZ - INADDRSZ;
669 af = AF_INET;
670 len = INADDRSZ;
671 }
672 switch (af) {
673 case AF_INET:
674 size = INADDRSZ;
675 break;
676 case AF_INET6:
677 size = IN6ADDRSZ;
678 break;
679 default:
680 errno = EAFNOSUPPORT;
681 h_errno = NETDB_INTERNAL;
682 return (NULL);
683 }
684 if (size != len) {
685 errno = EINVAL;
686 h_errno = NETDB_INTERNAL;
687 return (NULL);
688 }
689 ep = qbuf + sizeof(qbuf);
690 switch (af) {
691 case AF_INET:
692 (void) snprintf(qbuf, sizeof qbuf, "%u.%u.%u.%u.in-addr.arpa",
693 (uaddr[3] & 0xff), (uaddr[2] & 0xff),
694 (uaddr[1] & 0xff), (uaddr[0] & 0xff));
695 break;
696 case AF_INET6:
697 qp = qbuf;
698 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
699 i = snprintf(qp, ep - qp, "%x.%x.",
700 uaddr[n] & 0xf, (uaddr[n] >> 4) & 0xf);
701 if (i <= 0 || i >= ep - qp) {
702 errno = EINVAL;
703 h_errno = NETDB_INTERNAL;
704 return (NULL);
705 }
706 qp += i;
707 }
708 strlcpy(qp, "ip6.arpa", ep - qp);
709 break;
710 }
711
712 bcopy(_resp->lookups, lookups, sizeof lookups);
713 if (lookups[0] == '\0')
714 strlcpy(lookups, "bf", sizeof lookups);
715
716 hp = (struct hostent *)NULL;
717 for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
718 switch (lookups[i]) {
719#ifdef YP
720 case 'y':
721 /* YP only supports AF_INET. */
722 if (af == AF_INET)
723 hp = _yp_gethtbyaddr(uaddr);
724 break;
725#endif
726 case 'b':
727 buf = malloc(sizeof(*buf));
728 if (!buf)
729 break;
730 n = res_query(qbuf, C_IN, T_PTR, buf->buf,
731 sizeof(buf->buf));
732 if (n < 0) {
733 free(buf);
734#ifdef DEBUG
735 if (_resp->options & RES_DEBUG)
736 printf("res_query failed\n");
737#endif
738 break;
739 }
740 if (!(hp = getanswer(buf, n, qbuf, T_PTR))) {
741 free(buf);
742 break;
743 }
744 free(buf);
745 hp->h_addrtype = af;
746 hp->h_length = len;
747 bcopy(uaddr, host_addr, len);
748 h_addr_ptrs[0] = (char *)host_addr;
749 h_addr_ptrs[1] = NULL;
750 if (af == AF_INET && (_resp->options & RES_USE_INET6)) {
751 map_v4v6_address((char*)host_addr,
752 (char*)host_addr);
753 hp->h_addrtype = AF_INET6;
754 hp->h_length = IN6ADDRSZ;
755 }
756 h_errno = NETDB_SUCCESS;
757 break;
758 case 'f':
759 hp = _gethtbyaddr(uaddr, len, af);
760 break;
761 }
762 }
763 /* XXX h_errno not correct in all cases... */
764 return (hp);
765}
766
767void
768_sethtent(int f)
769{
770 if (hostf == NULL)
771 hostf = fopen(_PATH_HOSTS, "r" );
772 else
773 rewind(hostf);
774 stayopen = f;
775}
776
777void
778_endhtent(void)
779{
780 if (hostf && !stayopen) {
781 (void) fclose(hostf);
782 hostf = NULL;
783 }
784}
785
786static struct hostent *
787_gethtent(void)
788{
789 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
790 char *p, *cp, **q;
791 int af;
792 size_t len;
793
794 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
795 h_errno = NETDB_INTERNAL;
796 return (NULL);
797 }
798 again:
799 if ((p = fgetln(hostf, &len)) == NULL) {
800 h_errno = HOST_NOT_FOUND;
801 return (NULL);
802 }
803 if (p[len-1] == '\n')
804 len--;
805 if (len >= sizeof(hostbuf) || len == 0)
806 goto again;
807 p = memcpy(hostbuf, p, len);
808 hostbuf[len] = '\0';
809 if (*p == '#')
810 goto again;
811 if ((cp = strchr(p, '#')))
812 *cp = '\0';
813 if (!(cp = strpbrk(p, " \t")))
814 goto again;
815 *cp++ = '\0';
816 if (inet_pton(AF_INET6, p, host_addr) > 0) {
817 af = AF_INET6;
818 len = IN6ADDRSZ;
819 } else if (inet_pton(AF_INET, p, host_addr) > 0) {
820 if (_resp->options & RES_USE_INET6) {
821 map_v4v6_address((char*)host_addr, (char*)host_addr);
822 af = AF_INET6;
823 len = IN6ADDRSZ;
824 } else {
825 af = AF_INET;
826 len = INADDRSZ;
827 }
828 } else {
829 goto again;
830 }
831 /* if this is not something we're looking for, skip it. */
832 if (host.h_addrtype != AF_UNSPEC && host.h_addrtype != af)
833 goto again;
834 if (host.h_length != 0 && host.h_length != len)
835 goto again;
836 h_addr_ptrs[0] = (char *)host_addr;
837 h_addr_ptrs[1] = NULL;
838 host.h_addr_list = h_addr_ptrs;
839 host.h_length = len;
840 host.h_addrtype = af;
841 while (*cp == ' ' || *cp == '\t')
842 cp++;
843 host.h_name = cp;
844 q = host.h_aliases = host_aliases;
845 if ((cp = strpbrk(cp, " \t")))
846 *cp++ = '\0';
847 while (cp && *cp) {
848 if (*cp == ' ' || *cp == '\t') {
849 cp++;
850 continue;
851 }
852 if (q < &host_aliases[MAXALIASES - 1])
853 *q++ = cp;
854 if ((cp = strpbrk(cp, " \t")))
855 *cp++ = '\0';
856 }
857 *q = NULL;
858 if (_resp->options & RES_USE_INET6) {
859 char *bp = hostbuf;
860 char *ep = hostbuf + sizeof hostbuf;
861
862 map_v4v6_hostent(&host, &bp, ep);
863 }
864 h_errno = NETDB_SUCCESS;
865 return (&host);
866}
867
868struct hostent *
869_gethtbyname2(const char *name, int af)
870{
871 struct hostent *p;
872 char **cp;
873
874 _sethtent(0);
875 while ((p = _gethtent())) {
876 if (p->h_addrtype != af)
877 continue;
878 if (strcasecmp(p->h_name, name) == 0)
879 break;
880 for (cp = p->h_aliases; *cp != 0; cp++)
881 if (strcasecmp(*cp, name) == 0)
882 goto found;
883 }
884 found:
885 _endhtent();
886 return (p);
887}
888
889struct hostent *
890_gethtbyaddr(const void *addr, socklen_t len, int af)
891{
892 struct hostent *p;
893
894 host.h_length = len;
895 host.h_addrtype = af;
896
897 _sethtent(0);
898 while ((p = _gethtent()))
899 if (p->h_addrtype == af && p->h_length == len &&
900 !bcmp(p->h_addr, addr, len))
901 break;
902 _endhtent();
903 return (p);
904}
905
906#ifdef YP
907struct hostent *
908_yphostent(char *line)
909{
910 static struct in_addr host_addrs[MAXADDRS];
911 char *p = line;
912 char *cp, **q;
913 char **hap;
914 struct in_addr *buf;
915 int more;
916
917 host.h_name = NULL;
918 host.h_addr_list = h_addr_ptrs;
919 host.h_length = INADDRSZ;
920 host.h_addrtype = AF_INET;
921 hap = h_addr_ptrs;
922 buf = host_addrs;
923 q = host.h_aliases = host_aliases;
924
925nextline:
926 /* check for host_addrs overflow */
927 if (buf >= &host_addrs[sizeof(host_addrs) / sizeof(host_addrs[0])])
928 goto done;
929
930 more = 0;
931 cp = strpbrk(p, " \t");
932 if (cp == NULL)
933 goto done;
934 *cp++ = '\0';
935
936 *hap++ = (char *)buf;
937 (void) inet_aton(p, buf++);
938
939 while (*cp == ' ' || *cp == '\t')
940 cp++;
941 p = cp;
942 cp = strpbrk(p, " \t\n");
943 if (cp != NULL) {
944 if (*cp == '\n')
945 more = 1;
946 *cp++ = '\0';
947 }
948 if (!host.h_name)
949 host.h_name = p;
950 else if (strcmp(host.h_name, p)==0)
951 ;
952 else if (q < &host_aliases[MAXALIASES - 1])
953 *q++ = p;
954 p = cp;
955 if (more)
956 goto nextline;
957
958 while (cp && *cp) {
959 if (*cp == ' ' || *cp == '\t') {
960 cp++;
961 continue;
962 }
963 if (*cp == '\n') {
964 cp++;
965 goto nextline;
966 }
967 if (q < &host_aliases[MAXALIASES - 1])
968 *q++ = cp;
969 cp = strpbrk(cp, " \t");
970 if (cp != NULL)
971 *cp++ = '\0';
972 }
973done:
974 if (host.h_name == NULL)
975 return (NULL);
976 *q = NULL;
977 *hap = NULL;
978 return (&host);
979}
980
981struct hostent *
982_yp_gethtbyaddr(const void *addr)
983{
984 struct hostent *hp = NULL;
985 const u_char *uaddr = (const u_char *)addr;
986 static char *__ypcurrent;
987 int __ypcurrentlen, r;
988 char name[sizeof("xxx.xxx.xxx.xxx")];
989
990 if (!__ypdomain) {
991 if (_yp_check(&__ypdomain) == 0)
992 return (hp);
993 }
994 snprintf(name, sizeof name, "%u.%u.%u.%u", (uaddr[0] & 0xff),
995 (uaddr[1] & 0xff), (uaddr[2] & 0xff), (uaddr[3] & 0xff));
996 if (__ypcurrent)
997 free(__ypcurrent);
998 __ypcurrent = NULL;
999 r = yp_match(__ypdomain, "hosts.byaddr", name,
1000 strlen(name), &__ypcurrent, &__ypcurrentlen);
1001 if (r==0)
1002 hp = _yphostent(__ypcurrent);
1003 if (hp==NULL)
1004 h_errno = HOST_NOT_FOUND;
1005 return (hp);
1006}
1007
1008struct hostent *
1009_yp_gethtbyname(const char *name)
1010{
1011 struct hostent *hp = (struct hostent *)NULL;
1012 static char *__ypcurrent;
1013 int __ypcurrentlen, r;
1014
1015 if (strlen(name) >= MAXHOSTNAMELEN)
1016 return (NULL);
1017 if (!__ypdomain) {
1018 if (_yp_check(&__ypdomain) == 0)
1019 return (hp);
1020 }
1021 if (__ypcurrent)
1022 free(__ypcurrent);
1023 __ypcurrent = NULL;
1024 r = yp_match(__ypdomain, "hosts.byname", name,
1025 strlen(name), &__ypcurrent, &__ypcurrentlen);
1026 if (r == 0)
1027 hp = _yphostent(__ypcurrent);
1028 if (hp == NULL)
1029 h_errno = HOST_NOT_FOUND;
1030 return (hp);
1031}
1032#endif
1033
1034static void
1035map_v4v6_address(const char *src, char *dst)
1036{
1037 u_char *p = (u_char *)dst;
1038 char tmp[INADDRSZ];
1039 int i;
1040
1041 /* Stash a temporary copy so our caller can update in place. */
1042 bcopy(src, tmp, INADDRSZ);
1043 /* Mark this ipv6 addr as a mapped ipv4. */
1044 for (i = 0; i < 10; i++)
1045 *p++ = 0x00;
1046 *p++ = 0xff;
1047 *p++ = 0xff;
1048 /* Retrieve the saved copy and we're done. */
1049 bcopy(tmp, (void*)p, INADDRSZ);
1050}
1051
1052static void
1053map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1054{
1055 char **ap;
1056
1057 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1058 return;
1059 hp->h_addrtype = AF_INET6;
1060 hp->h_length = IN6ADDRSZ;
1061 for (ap = hp->h_addr_list; *ap; ap++) {
1062 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
1063
1064 if (ep - *bpp < (i + IN6ADDRSZ)) {
1065 /* Out of memory. Truncate address list here. XXX */
1066 *ap = NULL;
1067 return;
1068 }
1069 *bpp += i;
1070 map_v4v6_address(*ap, *bpp);
1071 *ap = *bpp;
1072 *bpp += IN6ADDRSZ;
1073 }
1074}
1075
1076struct hostent *
1077gethostent(void)
1078{
1079 host.h_addrtype = AF_UNSPEC;
1080 host.h_length = 0;
1081 return (_gethtent());
1082}
1083
1084#ifdef RESOLVSORT
1085static void
1086addrsort(char **ap, int num)
1087{
1088 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
1089 int i, j;
1090 char **p;
1091 short aval[MAXADDRS];
1092 int needsort = 0;
1093
1094 p = ap;
1095 for (i = 0; i < num; i++, p++) {
1096 for (j = 0 ; (unsigned)j < _resp->nsort; j++)
1097 if (_resp->sort_list[j].addr.s_addr ==
1098 (((struct in_addr *)(*p))->s_addr &
1099 _resp->sort_list[j].mask))
1100 break;
1101 aval[i] = j;
1102 if (needsort == 0 && i > 0 && j < aval[i-1])
1103 needsort = i;
1104 }
1105 if (!needsort)
1106 return;
1107
1108 while (needsort < num) {
1109 for (j = needsort - 1; j >= 0; j--) {
1110 if (aval[j] > aval[j+1]) {
1111 char *hp;
1112
1113 i = aval[j];
1114 aval[j] = aval[j+1];
1115 aval[j+1] = i;
1116
1117 hp = ap[j];
1118 ap[j] = ap[j+1];
1119 ap[j+1] = hp;
1120 } else
1121 break;
1122 }
1123 needsort++;
1124 }
1125}
1126#endif