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