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.c1129
1 files changed, 1129 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..d49b9cdd7d
--- /dev/null
+++ b/src/lib/libc/net/gethostnamadr.c
@@ -0,0 +1,1129 @@
1/* $OpenBSD: gethostnamadr.c,v 1.72 2007/10/11 18:36:41 jakob 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 host.h_name = bp;
206 bp += strlen(bp) + 1; /* for the \0 */
207 /* The qname can be abbreviated, but h_name is now absolute. */
208 qname = host.h_name;
209 }
210 ap = host_aliases;
211 *ap = NULL;
212 host.h_aliases = host_aliases;
213 hap = h_addr_ptrs;
214 *hap = NULL;
215 host.h_addr_list = h_addr_ptrs;
216 haveanswer = 0;
217 had_error = 0;
218 while (ancount-- > 0 && cp < eom && !had_error) {
219 size_t len;
220
221 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
222 if ((n < 0) || !(*name_ok)(bp)) {
223 had_error++;
224 continue;
225 }
226 cp += n; /* name */
227 if (cp >= eom)
228 break;
229 type = _getshort(cp);
230 cp += INT16SZ; /* type */
231 if (cp >= eom)
232 break;
233 class = _getshort(cp);
234 cp += INT16SZ + INT32SZ; /* class, TTL */
235 if (cp >= eom)
236 break;
237 n = _getshort(cp);
238 cp += INT16SZ; /* len */
239 if (cp >= eom)
240 break;
241 if (type == T_SIG || type == T_RRSIG) {
242 /* XXX - ignore signatures as we don't use them yet */
243 cp += n;
244 continue;
245 }
246 if (class != C_IN) {
247 /* XXX - debug? syslog? */
248 cp += n;
249 continue; /* XXX - had_error++ ? */
250 }
251 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
252 if (ap >= &host_aliases[MAXALIASES-1])
253 continue;
254 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
255 if ((n < 0) || !(*name_ok)(tbuf)) {
256 had_error++;
257 continue;
258 }
259 cp += n;
260 /* Store alias. */
261 *ap++ = bp;
262 bp += strlen(bp) + 1; /* for the \0 */
263 /* Get canonical name. */
264 len = strlen(tbuf) + 1; /* for the \0 */
265 if (len > ep - bp) {
266 had_error++;
267 continue;
268 }
269 strlcpy(bp, tbuf, ep - bp);
270 host.h_name = bp;
271 bp += len;
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 len = strlen(tbuf) + 1; /* for the \0 */
287 if (len > ep - bp) {
288 had_error++;
289 continue;
290 }
291 strlcpy(bp, tbuf, ep - bp);
292 tname = bp;
293 bp += len;
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 host.h_name = bp;
366 bp += strlen(bp) + 1; /* for the \0 */
367 }
368
369 bp += sizeof(align) - ((u_long)bp % sizeof(align));
370
371 if (bp + n >= &hostbuf[sizeof hostbuf]) {
372#ifdef DEBUG
373 if (_resp->options & RES_DEBUG)
374 printf("size (%d) too big\n", n);
375#endif
376 had_error++;
377 continue;
378 }
379 if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
380 if (!toobig++)
381#ifdef DEBUG
382 if (_resp->options & RES_DEBUG)
383 printf("Too many addresses (%d)\n", MAXADDRS);
384#endif
385 cp += n;
386 continue;
387 }
388 bcopy(cp, *hap++ = bp, n);
389 bp += n;
390 cp += n;
391 break;
392 }
393 if (!had_error)
394 haveanswer++;
395 }
396 if (haveanswer) {
397 *ap = NULL;
398 *hap = NULL;
399# if defined(RESOLVSORT)
400 /*
401 * Note: we sort even if host can take only one address
402 * in its return structures - should give it the "best"
403 * address in that case, not some random one
404 */
405 if (_resp->nsort && haveanswer > 1 && qtype == T_A)
406 addrsort(h_addr_ptrs, haveanswer);
407# endif /*RESOLVSORT*/
408 if (!host.h_name) {
409 size_t len;
410
411 len = strlen(qname) + 1;
412 if (len > ep - bp) /* for the \0 */
413 goto try_again;
414 strlcpy(bp, qname, ep - bp);
415 host.h_name = bp;
416 bp += len;
417 }
418 if (_resp->options & RES_USE_INET6)
419 map_v4v6_hostent(&host, &bp, ep);
420 h_errno = NETDB_SUCCESS;
421 return (&host);
422 }
423 try_again:
424 h_errno = TRY_AGAIN;
425 return (NULL);
426}
427
428#ifdef notyet
429/*
430 * XXX This is an extremely bogus implementation.
431 *
432 * FreeBSD has this interface:
433 * int gethostbyaddr_r(const char *addr, int len, int type,
434 * struct hostent *result, struct hostent_data *buffer)
435 */
436
437struct hostent *
438gethostbyname_r(const char *name, struct hostent *hp, char *buf, int buflen,
439 int *errorp)
440{
441 struct hostent *res;
442
443 res = gethostbyname(name);
444 *errorp = h_errno;
445 if (res == NULL)
446 return NULL;
447 memcpy(hp, res, sizeof *hp); /* XXX not sufficient */
448 return hp;
449}
450
451/*
452 * XXX This is an extremely bogus implementation.
453 */
454struct hostent *
455gethostbyaddr_r(const char *addr, int len, int af, struct hostent *he,
456 char *buf, int buflen, int *errorp)
457{
458 struct hostent * res;
459
460 res = gethostbyaddr(addr, len, af);
461 *errorp = h_errno;
462 if (res == NULL)
463 return NULL;
464 memcpy(he, res, sizeof *he); /* XXX not sufficient */
465 return he;
466}
467
468/* XXX RFC2133 expects a gethostbyname2_r() -- unimplemented */
469#endif
470
471struct hostent *
472gethostbyname(const char *name)
473{
474 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
475 struct hostent *hp;
476 extern struct hostent *_gethtbyname2(const char *, int);
477
478 if (_res_init(0) == -1)
479 hp = _gethtbyname2(name, AF_INET);
480
481 else if (_resp->options & RES_USE_INET6) {
482 hp = gethostbyname2(name, AF_INET6);
483 if (hp == NULL)
484 hp = gethostbyname2(name, AF_INET);
485 }
486 else
487 hp = gethostbyname2(name, AF_INET);
488 return hp;
489}
490
491struct hostent *
492gethostbyname2(const char *name, int af)
493{
494 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
495 querybuf *buf;
496 const char *cp;
497 char *bp, *ep;
498 int n, size, type, i;
499 struct hostent *hp;
500 char lookups[MAXDNSLUS];
501 extern struct hostent *_gethtbyname2(const char *, int);
502#ifdef YP
503 extern struct hostent *_yp_gethtbyname(const char *);
504#endif
505
506 if (_res_init(0) == -1)
507 return (_gethtbyname2(name, af));
508
509 switch (af) {
510 case AF_INET:
511 size = INADDRSZ;
512 type = T_A;
513 break;
514 case AF_INET6:
515 size = IN6ADDRSZ;
516 type = T_AAAA;
517 break;
518 default:
519 h_errno = NETDB_INTERNAL;
520 errno = EAFNOSUPPORT;
521 return (NULL);
522 }
523
524 host.h_addrtype = af;
525 host.h_length = size;
526
527 /*
528 * if there aren't any dots, it could be a user-level alias.
529 * this is also done in res_query() since we are not the only
530 * function that looks up host names.
531 */
532 if (!strchr(name, '.') && (cp = __hostalias(name)))
533 name = cp;
534
535 /*
536 * disallow names consisting only of digits/dots, unless
537 * they end in a dot.
538 */
539 if (isdigit(name[0]))
540 for (cp = name;; ++cp) {
541 if (!*cp) {
542 if (*--cp == '.')
543 break;
544 /*
545 * All-numeric, no dot at the end.
546 * Fake up a hostent as if we'd actually
547 * done a lookup.
548 */
549 if (inet_pton(af, name, host_addr) <= 0) {
550 h_errno = HOST_NOT_FOUND;
551 return (NULL);
552 }
553 strlcpy(hostbuf, name, MAXHOSTNAMELEN);
554 bp = hostbuf + MAXHOSTNAMELEN;
555 ep = hostbuf + sizeof(hostbuf);
556 host.h_name = hostbuf;
557 host.h_aliases = host_aliases;
558 host_aliases[0] = NULL;
559 h_addr_ptrs[0] = (char *)host_addr;
560 h_addr_ptrs[1] = NULL;
561 host.h_addr_list = h_addr_ptrs;
562 if (_resp->options & RES_USE_INET6)
563 map_v4v6_hostent(&host, &bp, ep);
564 h_errno = NETDB_SUCCESS;
565 return (&host);
566 }
567 if (!isdigit(*cp) && *cp != '.')
568 break;
569 }
570 if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
571 name[0] == ':')
572 for (cp = name;; ++cp) {
573 if (!*cp) {
574 if (*--cp == '.')
575 break;
576 /*
577 * All-IPv6-legal, no dot at the end.
578 * Fake up a hostent as if we'd actually
579 * done a lookup.
580 */
581 if (inet_pton(af, name, host_addr) <= 0) {
582 h_errno = HOST_NOT_FOUND;
583 return (NULL);
584 }
585 strlcpy(hostbuf, name, MAXHOSTNAMELEN);
586 bp = hostbuf + MAXHOSTNAMELEN;
587 ep = hostbuf + sizeof(hostbuf);
588 host.h_name = hostbuf;
589 host.h_aliases = host_aliases;
590 host_aliases[0] = NULL;
591 h_addr_ptrs[0] = (char *)host_addr;
592 h_addr_ptrs[1] = NULL;
593 host.h_addr_list = h_addr_ptrs;
594 h_errno = NETDB_SUCCESS;
595 return (&host);
596 }
597 if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
598 break;
599 }
600
601 bcopy(_resp->lookups, lookups, sizeof lookups);
602 if (lookups[0] == '\0')
603 strlcpy(lookups, "bf", sizeof lookups);
604
605 hp = (struct hostent *)NULL;
606 for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
607 switch (lookups[i]) {
608#ifdef YP
609 case 'y':
610 /* YP only supports AF_INET. */
611 if (af == AF_INET)
612 hp = _yp_gethtbyname(name);
613 break;
614#endif
615 case 'b':
616 buf = malloc(sizeof(*buf));
617 if (buf == NULL)
618 break;
619 if ((n = res_search(name, C_IN, type, buf->buf,
620 sizeof(buf->buf))) < 0) {
621 free(buf);
622#ifdef DEBUG
623 if (_resp->options & RES_DEBUG)
624 printf("res_search failed\n");
625#endif
626 break;
627 }
628 hp = getanswer(buf, n, name, type);
629 free(buf);
630 break;
631 case 'f':
632 hp = _gethtbyname2(name, af);
633 break;
634 }
635 }
636 /* XXX h_errno not correct in all cases... */
637 return (hp);
638}
639
640struct hostent *
641gethostbyaddr(const void *addr, socklen_t len, int af)
642{
643 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
644 const u_char *uaddr = (const u_char *)addr;
645 int n, size, i;
646 querybuf *buf;
647 struct hostent *hp;
648 char qbuf[MAXDNAME+1], *qp, *ep;
649 char lookups[MAXDNSLUS];
650 struct hostent *res;
651 extern struct hostent *_gethtbyaddr(const void *, socklen_t, int);
652#ifdef YP
653 extern struct hostent *_yp_gethtbyaddr(const void *);
654#endif
655
656 if (_res_init(0) == -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 uaddr += IN6ADDRSZ - INADDRSZ;
672 af = AF_INET;
673 len = INADDRSZ;
674 }
675 switch (af) {
676 case AF_INET:
677 size = INADDRSZ;
678 break;
679 case AF_INET6:
680 size = IN6ADDRSZ;
681 break;
682 default:
683 errno = EAFNOSUPPORT;
684 h_errno = NETDB_INTERNAL;
685 return (NULL);
686 }
687 if (size != len) {
688 errno = EINVAL;
689 h_errno = NETDB_INTERNAL;
690 return (NULL);
691 }
692 ep = qbuf + sizeof(qbuf);
693 switch (af) {
694 case AF_INET:
695 (void) snprintf(qbuf, sizeof qbuf, "%u.%u.%u.%u.in-addr.arpa",
696 (uaddr[3] & 0xff), (uaddr[2] & 0xff),
697 (uaddr[1] & 0xff), (uaddr[0] & 0xff));
698 break;
699 case AF_INET6:
700 qp = qbuf;
701 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
702 i = snprintf(qp, ep - qp, "%x.%x.",
703 uaddr[n] & 0xf, (uaddr[n] >> 4) & 0xf);
704 if (i <= 0 || i >= ep - qp) {
705 errno = EINVAL;
706 h_errno = NETDB_INTERNAL;
707 return (NULL);
708 }
709 qp += i;
710 }
711 strlcpy(qp, "ip6.arpa", ep - qp);
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(uaddr);
727 break;
728#endif
729 case 'b':
730 buf = malloc(sizeof(*buf));
731 if (!buf)
732 break;
733 n = res_query(qbuf, C_IN, T_PTR, buf->buf,
734 sizeof(buf->buf));
735 if (n < 0) {
736 free(buf);
737#ifdef DEBUG
738 if (_resp->options & RES_DEBUG)
739 printf("res_query failed\n");
740#endif
741 break;
742 }
743 if (!(hp = getanswer(buf, n, qbuf, T_PTR))) {
744 free(buf);
745 break;
746 }
747 free(buf);
748 hp->h_addrtype = af;
749 hp->h_length = len;
750 bcopy(uaddr, host_addr, len);
751 h_addr_ptrs[0] = (char *)host_addr;
752 h_addr_ptrs[1] = NULL;
753 if (af == AF_INET && (_resp->options & RES_USE_INET6)) {
754 map_v4v6_address((char*)host_addr,
755 (char*)host_addr);
756 hp->h_addrtype = AF_INET6;
757 hp->h_length = IN6ADDRSZ;
758 }
759 h_errno = NETDB_SUCCESS;
760 break;
761 case 'f':
762 hp = _gethtbyaddr(uaddr, len, af);
763 break;
764 }
765 }
766 /* XXX h_errno not correct in all cases... */
767 return (hp);
768}
769
770void
771_sethtent(int f)
772{
773 if (hostf == NULL)
774 hostf = fopen(_PATH_HOSTS, "r" );
775 else
776 rewind(hostf);
777 stayopen = f;
778}
779
780void
781_endhtent(void)
782{
783 if (hostf && !stayopen) {
784 (void) fclose(hostf);
785 hostf = NULL;
786 }
787}
788
789static struct hostent *
790_gethtent(void)
791{
792 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
793 char *p, *cp, **q;
794 int af;
795 size_t len;
796
797 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
798 h_errno = NETDB_INTERNAL;
799 return (NULL);
800 }
801 again:
802 if ((p = fgetln(hostf, &len)) == NULL) {
803 h_errno = HOST_NOT_FOUND;
804 return (NULL);
805 }
806 if (p[len-1] == '\n')
807 len--;
808 if (len >= sizeof(hostbuf) || len == 0)
809 goto again;
810 p = memcpy(hostbuf, p, len);
811 hostbuf[len] = '\0';
812 if (*p == '#')
813 goto again;
814 if ((cp = strchr(p, '#')))
815 *cp = '\0';
816 if (!(cp = strpbrk(p, " \t")))
817 goto again;
818 *cp++ = '\0';
819 if (inet_pton(AF_INET6, p, host_addr) > 0) {
820 af = AF_INET6;
821 len = IN6ADDRSZ;
822 } else if (inet_pton(AF_INET, p, host_addr) > 0) {
823 if (_resp->options & RES_USE_INET6) {
824 map_v4v6_address((char*)host_addr, (char*)host_addr);
825 af = AF_INET6;
826 len = IN6ADDRSZ;
827 } else {
828 af = AF_INET;
829 len = INADDRSZ;
830 }
831 } else {
832 goto again;
833 }
834 /* if this is not something we're looking for, skip it. */
835 if (host.h_addrtype != AF_UNSPEC && host.h_addrtype != af)
836 goto again;
837 if (host.h_length != 0 && host.h_length != len)
838 goto again;
839 h_addr_ptrs[0] = (char *)host_addr;
840 h_addr_ptrs[1] = NULL;
841 host.h_addr_list = h_addr_ptrs;
842 host.h_length = len;
843 host.h_addrtype = af;
844 while (*cp == ' ' || *cp == '\t')
845 cp++;
846 host.h_name = cp;
847 q = host.h_aliases = host_aliases;
848 if ((cp = strpbrk(cp, " \t")))
849 *cp++ = '\0';
850 while (cp && *cp) {
851 if (*cp == ' ' || *cp == '\t') {
852 cp++;
853 continue;
854 }
855 if (q < &host_aliases[MAXALIASES - 1])
856 *q++ = cp;
857 if ((cp = strpbrk(cp, " \t")))
858 *cp++ = '\0';
859 }
860 *q = NULL;
861 if (_resp->options & RES_USE_INET6) {
862 char *bp = hostbuf;
863 char *ep = hostbuf + sizeof hostbuf;
864
865 map_v4v6_hostent(&host, &bp, ep);
866 }
867 h_errno = NETDB_SUCCESS;
868 return (&host);
869}
870
871struct hostent *
872_gethtbyname2(const char *name, int af)
873{
874 struct hostent *p;
875 char **cp;
876
877 _sethtent(0);
878 while ((p = _gethtent())) {
879 if (p->h_addrtype != af)
880 continue;
881 if (strcasecmp(p->h_name, name) == 0)
882 break;
883 for (cp = p->h_aliases; *cp != 0; cp++)
884 if (strcasecmp(*cp, name) == 0)
885 goto found;
886 }
887 found:
888 _endhtent();
889 return (p);
890}
891
892struct hostent *
893_gethtbyaddr(const void *addr, socklen_t len, int af)
894{
895 struct hostent *p;
896
897 host.h_length = len;
898 host.h_addrtype = af;
899
900 _sethtent(0);
901 while ((p = _gethtent()))
902 if (p->h_addrtype == af && p->h_length == len &&
903 !bcmp(p->h_addr, addr, len))
904 break;
905 _endhtent();
906 return (p);
907}
908
909#ifdef YP
910struct hostent *
911_yphostent(char *line)
912{
913 static struct in_addr host_addrs[MAXADDRS];
914 char *p = line;
915 char *cp, **q;
916 char **hap;
917 struct in_addr *buf;
918 int more;
919
920 host.h_name = NULL;
921 host.h_addr_list = h_addr_ptrs;
922 host.h_length = INADDRSZ;
923 host.h_addrtype = AF_INET;
924 hap = h_addr_ptrs;
925 buf = host_addrs;
926 q = host.h_aliases = host_aliases;
927
928nextline:
929 /* check for host_addrs overflow */
930 if (buf >= &host_addrs[sizeof(host_addrs) / sizeof(host_addrs[0])])
931 goto done;
932
933 more = 0;
934 cp = strpbrk(p, " \t");
935 if (cp == NULL)
936 goto done;
937 *cp++ = '\0';
938
939 *hap++ = (char *)buf;
940 (void) inet_aton(p, buf++);
941
942 while (*cp == ' ' || *cp == '\t')
943 cp++;
944 p = cp;
945 cp = strpbrk(p, " \t\n");
946 if (cp != NULL) {
947 if (*cp == '\n')
948 more = 1;
949 *cp++ = '\0';
950 }
951 if (!host.h_name)
952 host.h_name = p;
953 else if (strcmp(host.h_name, p)==0)
954 ;
955 else if (q < &host_aliases[MAXALIASES - 1])
956 *q++ = p;
957 p = cp;
958 if (more)
959 goto nextline;
960
961 while (cp && *cp) {
962 if (*cp == ' ' || *cp == '\t') {
963 cp++;
964 continue;
965 }
966 if (*cp == '\n') {
967 cp++;
968 goto nextline;
969 }
970 if (q < &host_aliases[MAXALIASES - 1])
971 *q++ = cp;
972 cp = strpbrk(cp, " \t");
973 if (cp != NULL)
974 *cp++ = '\0';
975 }
976done:
977 if (host.h_name == NULL)
978 return (NULL);
979 *q = NULL;
980 *hap = NULL;
981 return (&host);
982}
983
984struct hostent *
985_yp_gethtbyaddr(const void *addr)
986{
987 struct hostent *hp = NULL;
988 const u_char *uaddr = (const u_char *)addr;
989 static char *__ypcurrent;
990 int __ypcurrentlen, r;
991 char name[sizeof("xxx.xxx.xxx.xxx")];
992
993 if (!__ypdomain) {
994 if (_yp_check(&__ypdomain) == 0)
995 return (hp);
996 }
997 snprintf(name, sizeof name, "%u.%u.%u.%u", (uaddr[0] & 0xff),
998 (uaddr[1] & 0xff), (uaddr[2] & 0xff), (uaddr[3] & 0xff));
999 if (__ypcurrent)
1000 free(__ypcurrent);
1001 __ypcurrent = NULL;
1002 r = yp_match(__ypdomain, "hosts.byaddr", name,
1003 strlen(name), &__ypcurrent, &__ypcurrentlen);
1004 if (r==0)
1005 hp = _yphostent(__ypcurrent);
1006 if (hp==NULL)
1007 h_errno = HOST_NOT_FOUND;
1008 return (hp);
1009}
1010
1011struct hostent *
1012_yp_gethtbyname(const char *name)
1013{
1014 struct hostent *hp = (struct hostent *)NULL;
1015 static char *__ypcurrent;
1016 int __ypcurrentlen, r;
1017
1018 if (strlen(name) >= MAXHOSTNAMELEN)
1019 return (NULL);
1020 if (!__ypdomain) {
1021 if (_yp_check(&__ypdomain) == 0)
1022 return (hp);
1023 }
1024 if (__ypcurrent)
1025 free(__ypcurrent);
1026 __ypcurrent = NULL;
1027 r = yp_match(__ypdomain, "hosts.byname", name,
1028 strlen(name), &__ypcurrent, &__ypcurrentlen);
1029 if (r == 0)
1030 hp = _yphostent(__ypcurrent);
1031 if (hp == NULL)
1032 h_errno = HOST_NOT_FOUND;
1033 return (hp);
1034}
1035#endif
1036
1037static void
1038map_v4v6_address(const char *src, char *dst)
1039{
1040 u_char *p = (u_char *)dst;
1041 char tmp[INADDRSZ];
1042 int i;
1043
1044 /* Stash a temporary copy so our caller can update in place. */
1045 bcopy(src, tmp, INADDRSZ);
1046 /* Mark this ipv6 addr as a mapped ipv4. */
1047 for (i = 0; i < 10; i++)
1048 *p++ = 0x00;
1049 *p++ = 0xff;
1050 *p++ = 0xff;
1051 /* Retrieve the saved copy and we're done. */
1052 bcopy(tmp, (void*)p, INADDRSZ);
1053}
1054
1055static void
1056map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1057{
1058 char **ap;
1059
1060 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1061 return;
1062 hp->h_addrtype = AF_INET6;
1063 hp->h_length = IN6ADDRSZ;
1064 for (ap = hp->h_addr_list; *ap; ap++) {
1065 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
1066
1067 if (ep - *bpp < (i + IN6ADDRSZ)) {
1068 /* Out of memory. Truncate address list here. XXX */
1069 *ap = NULL;
1070 return;
1071 }
1072 *bpp += i;
1073 map_v4v6_address(*ap, *bpp);
1074 *ap = *bpp;
1075 *bpp += IN6ADDRSZ;
1076 }
1077}
1078
1079struct hostent *
1080gethostent(void)
1081{
1082 host.h_addrtype = AF_UNSPEC;
1083 host.h_length = 0;
1084 return (_gethtent());
1085}
1086
1087#ifdef RESOLVSORT
1088static void
1089addrsort(char **ap, int num)
1090{
1091 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
1092 int i, j;
1093 char **p;
1094 short aval[MAXADDRS];
1095 int needsort = 0;
1096
1097 p = ap;
1098 for (i = 0; i < num; i++, p++) {
1099 for (j = 0 ; (unsigned)j < _resp->nsort; j++)
1100 if (_resp->sort_list[j].addr.s_addr ==
1101 (((struct in_addr *)(*p))->s_addr &
1102 _resp->sort_list[j].mask))
1103 break;
1104 aval[i] = j;
1105 if (needsort == 0 && i > 0 && j < aval[i-1])
1106 needsort = i;
1107 }
1108 if (!needsort)
1109 return;
1110
1111 while (needsort < num) {
1112 for (j = needsort - 1; j >= 0; j--) {
1113 if (aval[j] > aval[j+1]) {
1114 char *hp;
1115
1116 i = aval[j];
1117 aval[j] = aval[j+1];
1118 aval[j+1] = i;
1119
1120 hp = ap[j];
1121 ap[j] = ap[j+1];
1122 ap[j+1] = hp;
1123 } else
1124 break;
1125 }
1126 needsort++;
1127 }
1128}
1129#endif