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