Regenerated: autoconf configure.in
[glibc/pb-stable.git] / resolv / gethnamaddr.c
blob4484b81ce70a4fe8fe23f2d101a9bc7395ac243d
1 /*
2 * ++Copyright++ 1985, 1988, 1993
3 * -
4 * Copyright (c) 1985, 1988, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 * -
31 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
33 * Permission to use, copy, modify, and distribute this software for any
34 * purpose with or without fee is hereby granted, provided that the above
35 * copyright notice and this permission notice appear in all copies, and that
36 * the name of Digital Equipment Corporation not be used in advertising or
37 * publicity pertaining to distribution of the document or software without
38 * specific, written prior permission.
40 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
43 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 * SOFTWARE.
48 * -
49 * --Copyright--
52 #if defined(LIBC_SCCS) && !defined(lint)
53 static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
54 static char rcsid[] = "$Id$";
55 #endif /* LIBC_SCCS and not lint */
57 #include <sys/types.h>
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>
64 #include <stdio.h>
65 #include <netdb.h>
66 #include <resolv.h>
67 #include <ctype.h>
68 #include <errno.h>
69 #include <syslog.h>
71 #ifndef LOG_AUTH
72 # define LOG_AUTH 0
73 #endif
75 #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
77 #if defined(BSD) && (BSD >= 199103) && defined(AF_INET6)
78 # include <stdlib.h>
79 # include <string.h>
80 #else
81 # include "../conf/portability.h"
82 #endif
84 #if defined(USE_OPTIONS_H)
85 # include <../conf/options.h>
86 #endif
88 #ifdef SPRINTF_CHAR
89 # define SPRINTF(x) strlen(sprintf/**/x)
90 #else
91 # define SPRINTF(x) ((size_t)sprintf x)
92 #endif
94 #define MAXALIASES 35
95 #define MAXADDRS 35
97 static const char AskedForGot[] =
98 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
100 static char *h_addr_ptrs[MAXADDRS + 1];
102 static struct hostent host;
103 static char *host_aliases[MAXALIASES];
104 static char hostbuf[8*1024];
105 static u_char host_addr[16]; /* IPv4 or IPv6 */
106 static FILE *hostf = NULL;
107 static int stayopen = 0;
109 static void map_v4v6_address __P((const char *src, char *dst));
110 static void map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len));
112 #ifdef RESOLVSORT
113 extern void addrsort __P((char **, int));
114 #endif
116 #if PACKETSZ > 1024
117 #define MAXPACKET PACKETSZ
118 #else
119 #define MAXPACKET 1024
120 #endif
122 /* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */
123 #ifdef MAXHOSTNAMELEN
124 # undef MAXHOSTNAMELEN
125 #endif
126 #define MAXHOSTNAMELEN 256
128 typedef union {
129 HEADER hdr;
130 u_char buf[MAXPACKET];
131 } querybuf;
133 typedef union {
134 int32_t al;
135 char ac;
136 } align;
138 #ifndef h_errno
139 extern int h_errno;
140 #endif
142 #ifdef DEBUG
143 static void
144 dprintf(msg, num)
145 char *msg;
146 int num;
148 if (_res.options & RES_DEBUG) {
149 int save = errno;
151 printf(msg, num);
152 __set_errno (save);
155 #else
156 # define dprintf(msg, num) /*nada*/
157 #endif
159 #define BOUNDED_INCR(x) \
160 do { \
161 cp += x; \
162 if (cp > eom) { \
163 __set_h_errno (NO_RECOVERY); \
164 return (NULL); \
166 } while (0)
168 #define BOUNDS_CHECK(ptr, count) \
169 do { \
170 if ((ptr) + (count) > eom) { \
171 __set_h_errno (NO_RECOVERY); \
172 return (NULL); \
174 } while (0)
177 static struct hostent *
178 getanswer(answer, anslen, qname, qtype)
179 const querybuf *answer;
180 int anslen;
181 const char *qname;
182 int qtype;
184 register const HEADER *hp;
185 register const u_char *cp;
186 register int n;
187 const u_char *eom, *erdata;
188 char *bp, **ap, **hap;
189 int type, class, buflen, ancount, qdcount;
190 int haveanswer, had_error;
191 int toobig = 0;
192 char tbuf[MAXDNAME];
193 const char *tname;
194 int (*name_ok) __P((const char *));
196 tname = qname;
197 host.h_name = NULL;
198 eom = answer->buf + anslen;
199 switch (qtype) {
200 case T_A:
201 case T_AAAA:
202 name_ok = res_hnok;
203 break;
204 case T_PTR:
205 name_ok = res_dnok;
206 break;
207 default:
208 return (NULL); /* XXX should be abort(); */
211 * find first satisfactory answer
213 hp = &answer->hdr;
214 ancount = ntohs(hp->ancount);
215 qdcount = ntohs(hp->qdcount);
216 bp = hostbuf;
217 buflen = sizeof hostbuf;
218 cp = answer->buf;
219 BOUNDED_INCR(HFIXEDSZ);
220 if (qdcount != 1) {
221 __set_h_errno (NO_RECOVERY);
222 return (NULL);
224 n = dn_expand(answer->buf, eom, cp, bp, buflen);
225 if ((n < 0) || !(*name_ok)(bp)) {
226 __set_h_errno (NO_RECOVERY);
227 return (NULL);
229 BOUNDED_INCR(n + QFIXEDSZ);
230 if (qtype == T_A || qtype == T_AAAA) {
231 /* res_send() has already verified that the query name is the
232 * same as the one we sent; this just gets the expanded name
233 * (i.e., with the succeeding search-domain tacked on).
235 n = strlen(bp) + 1; /* for the \0 */
236 if (n >= MAXHOSTNAMELEN) {
237 __set_h_errno (NO_RECOVERY);
238 return (NULL);
240 host.h_name = bp;
241 bp += n;
242 buflen -= n;
243 /* The qname can be abbreviated, but h_name is now absolute. */
244 qname = host.h_name;
246 ap = host_aliases;
247 *ap = NULL;
248 host.h_aliases = host_aliases;
249 hap = h_addr_ptrs;
250 *hap = NULL;
251 host.h_addr_list = h_addr_ptrs;
252 haveanswer = 0;
253 had_error = 0;
254 while (ancount-- > 0 && cp < eom && !had_error) {
255 n = dn_expand(answer->buf, eom, cp, bp, buflen);
256 if ((n < 0) || !(*name_ok)(bp)) {
257 had_error++;
258 continue;
260 cp += n; /* name */
261 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
262 type = _getshort(cp);
263 cp += INT16SZ; /* type */
264 class = _getshort(cp);
265 cp += INT16SZ + INT32SZ; /* class, TTL */
266 n = _getshort(cp);
267 cp += INT16SZ; /* len */
268 BOUNDS_CHECK(cp, n);
269 erdata = cp + n;
270 if (class != C_IN) {
271 /* XXX - debug? syslog? */
272 cp += n;
273 continue; /* XXX - had_error++ ? */
275 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
276 if (ap >= &host_aliases[MAXALIASES-1])
277 continue;
278 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
279 if ((n < 0) || !(*name_ok)(tbuf)) {
280 had_error++;
281 continue;
283 cp += n;
284 if (cp != erdata) {
285 __set_h_errno (NO_RECOVERY);
286 return (NULL);
288 /* Store alias. */
289 *ap++ = bp;
290 n = strlen(bp) + 1; /* for the \0 */
291 if (n >= MAXHOSTNAMELEN) {
292 had_error++;
293 continue;
295 bp += n;
296 buflen -= n;
297 /* Get canonical name. */
298 n = strlen(tbuf) + 1; /* for the \0 */
299 if (n > buflen || n >= MAXHOSTNAMELEN) {
300 had_error++;
301 continue;
303 strcpy(bp, tbuf);
304 host.h_name = bp;
305 bp += n;
306 buflen -= n;
307 continue;
309 if (qtype == T_PTR && type == T_CNAME) {
310 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
311 if (n < 0 || !res_dnok(tbuf)) {
312 had_error++;
313 continue;
315 cp += n;
316 if (cp != erdata) {
317 __set_h_errno (NO_RECOVERY);
318 return (NULL);
320 /* Get canonical name. */
321 n = strlen(tbuf) + 1; /* for the \0 */
322 if (n > buflen || n >= MAXHOSTNAMELEN) {
323 had_error++;
324 continue;
326 strcpy(bp, tbuf);
327 tname = bp;
328 bp += n;
329 buflen -= n;
330 continue;
332 if ((type == T_SIG) || (type == T_KEY) || (type == T_NXT)) {
333 /* We don't support DNSSEC yet. For now, ignore
334 * the record and send a low priority message
335 * to syslog.
337 syslog(LOG_DEBUG|LOG_AUTH,
338 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
339 qname, p_class(C_IN), p_type(qtype),
340 p_type(type));
341 cp += n;
342 continue;
344 if (type != qtype) {
345 syslog(LOG_NOTICE|LOG_AUTH,
346 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
347 qname, p_class(C_IN), p_type(qtype),
348 p_type(type));
349 cp += n;
350 continue; /* XXX - had_error++ ? */
352 switch (type) {
353 case T_PTR:
354 if (strcasecmp(tname, bp) != 0) {
355 syslog(LOG_NOTICE|LOG_AUTH,
356 AskedForGot, qname, bp);
357 cp += n;
358 continue; /* XXX - had_error++ ? */
360 n = dn_expand(answer->buf, eom, cp, bp, buflen);
361 if ((n < 0) || !res_hnok(bp)) {
362 had_error++;
363 break;
365 #if MULTI_PTRS_ARE_ALIASES
366 cp += n;
367 if (cp != erdata) {
368 __set_h_errno (NO_RECOVERY);
369 return (NULL);
371 if (!haveanswer)
372 host.h_name = bp;
373 else if (ap < &host_aliases[MAXALIASES-1])
374 *ap++ = bp;
375 else
376 n = -1;
377 if (n != -1) {
378 n = strlen(bp) + 1; /* for the \0 */
379 if (n >= MAXHOSTNAMELEN) {
380 had_error++;
381 break;
383 bp += n;
384 buflen -= n;
386 break;
387 #else
388 host.h_name = bp;
389 if (_res.options & RES_USE_INET6) {
390 n = strlen(bp) + 1; /* for the \0 */
391 if (n >= MAXHOSTNAMELEN) {
392 had_error++;
393 break;
395 bp += n;
396 buflen -= n;
397 map_v4v6_hostent(&host, &bp, &buflen);
399 __set_h_errno (NETDB_SUCCESS);
400 return (&host);
401 #endif
402 case T_A:
403 case T_AAAA:
404 if (strcasecmp(host.h_name, bp) != 0) {
405 syslog(LOG_NOTICE|LOG_AUTH,
406 AskedForGot, host.h_name, bp);
407 cp += n;
408 continue; /* XXX - had_error++ ? */
410 if (n != host.h_length) {
411 cp += n;
412 continue;
414 if (!haveanswer) {
415 register int nn;
417 host.h_name = bp;
418 nn = strlen(bp) + 1; /* for the \0 */
419 bp += nn;
420 buflen -= nn;
423 bp += sizeof(align) - ((u_long)bp % sizeof(align));
425 if (bp + n >= &hostbuf[sizeof hostbuf]) {
426 dprintf("size (%d) too big\n", n);
427 had_error++;
428 continue;
430 if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
431 if (!toobig++) {
432 dprintf("Too many addresses (%d)\n",
433 MAXADDRS);
435 cp += n;
436 continue;
438 bcopy(cp, *hap++ = bp, n);
439 bp += n;
440 buflen -= n;
441 cp += n;
442 if (cp != erdata) {
443 __set_h_errno (NO_RECOVERY);
444 return (NULL);
446 break;
447 default:
448 abort();
450 if (!had_error)
451 haveanswer++;
453 if (haveanswer) {
454 *ap = NULL;
455 *hap = NULL;
456 # if defined(RESOLVSORT)
458 * Note: we sort even if host can take only one address
459 * in its return structures - should give it the "best"
460 * address in that case, not some random one
462 if (_res.nsort && haveanswer > 1 && qtype == T_A)
463 addrsort(h_addr_ptrs, haveanswer);
464 # endif /*RESOLVSORT*/
465 if (!host.h_name) {
466 n = strlen(qname) + 1; /* for the \0 */
467 if (n > buflen || n >= MAXHOSTNAMELEN)
468 goto no_recovery;
469 strcpy(bp, qname);
470 host.h_name = bp;
471 bp += n;
472 buflen -= n;
474 if (_res.options & RES_USE_INET6)
475 map_v4v6_hostent(&host, &bp, &buflen);
476 __set_h_errno (NETDB_SUCCESS);
477 return (&host);
479 no_recovery:
480 __set_h_errno (NO_RECOVERY);
481 return (NULL);
484 struct hostent *
485 gethostbyname(name)
486 const char *name;
488 struct hostent *hp;
490 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
491 __set_h_errno (NETDB_INTERNAL);
492 return (NULL);
494 if (_res.options & RES_USE_INET6) {
495 hp = gethostbyname2(name, AF_INET6);
496 if (hp)
497 return (hp);
499 return (gethostbyname2(name, AF_INET));
502 struct hostent *
503 gethostbyname2(name, af)
504 const char *name;
505 int af;
507 querybuf buf;
508 register const char *cp;
509 char *bp;
510 int n, size, type, len;
511 extern struct hostent *_gethtbyname2();
513 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
514 __set_h_errno (NETDB_INTERNAL);
515 return (NULL);
518 switch (af) {
519 case AF_INET:
520 size = INADDRSZ;
521 type = T_A;
522 break;
523 case AF_INET6:
524 size = IN6ADDRSZ;
525 type = T_AAAA;
526 break;
527 default:
528 __set_h_errno (NETDB_INTERNAL);
529 __set_errno (EAFNOSUPPORT);
530 return (NULL);
533 host.h_addrtype = af;
534 host.h_length = size;
537 * if there aren't any dots, it could be a user-level alias.
538 * this is also done in res_query() since we are not the only
539 * function that looks up host names.
541 if (!strchr(name, '.') && (cp = __hostalias(name)))
542 name = cp;
545 * disallow names consisting only of digits/dots, unless
546 * they end in a dot.
548 if (isdigit(name[0]))
549 for (cp = name;; ++cp) {
550 if (!*cp) {
551 if (*--cp == '.')
552 break;
554 * All-numeric, no dot at the end.
555 * Fake up a hostent as if we'd actually
556 * done a lookup.
558 if (inet_pton(af, name, host_addr) <= 0) {
559 __set_h_errno (HOST_NOT_FOUND);
560 return (NULL);
562 strncpy(hostbuf, name, MAXDNAME);
563 hostbuf[MAXDNAME] = '\0';
564 bp = hostbuf + MAXDNAME;
565 len = sizeof hostbuf - MAXDNAME;
566 host.h_name = hostbuf;
567 host.h_aliases = host_aliases;
568 host_aliases[0] = NULL;
569 h_addr_ptrs[0] = (char *)host_addr;
570 h_addr_ptrs[1] = NULL;
571 host.h_addr_list = h_addr_ptrs;
572 if (_res.options & RES_USE_INET6)
573 map_v4v6_hostent(&host, &bp, &len);
574 __set_h_errno (NETDB_SUCCESS);
575 return (&host);
577 if (!isdigit(*cp) && *cp != '.')
578 break;
580 if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
581 name[0] == ':')
582 for (cp = name;; ++cp) {
583 if (!*cp) {
584 if (*--cp == '.')
585 break;
587 * All-IPv6-legal, no dot at the end.
588 * Fake up a hostent as if we'd actually
589 * done a lookup.
591 if (inet_pton(af, name, host_addr) <= 0) {
592 __set_h_errno (HOST_NOT_FOUND);
593 return (NULL);
595 strncpy(hostbuf, name, MAXDNAME);
596 hostbuf[MAXDNAME] = '\0';
597 bp = hostbuf + MAXDNAME;
598 len = sizeof hostbuf - MAXDNAME;
599 host.h_name = hostbuf;
600 host.h_aliases = host_aliases;
601 host_aliases[0] = NULL;
602 h_addr_ptrs[0] = (char *)host_addr;
603 h_addr_ptrs[1] = NULL;
604 host.h_addr_list = h_addr_ptrs;
605 __set_h_errno (NETDB_SUCCESS);
606 return (&host);
608 if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
609 break;
612 if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf.buf))) < 0) {
613 dprintf("res_search failed (%d)\n", n);
614 if (errno == ECONNREFUSED)
615 return (_gethtbyname2(name, af));
616 return (NULL);
618 return (getanswer(&buf, n, name, type));
621 struct hostent *
622 gethostbyaddr(addr, len, af)
623 const char *addr; /* XXX should have been def'd as u_char! */
624 size_t len;
625 int af;
627 const u_char *uaddr = (const u_char *)addr;
628 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
629 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
630 int n, size;
631 querybuf buf;
632 register struct hostent *hp;
633 char qbuf[MAXDNAME+1], *qp;
634 #ifdef SUNSECURITY
635 register struct hostent *rhp;
636 char **haddr;
637 u_long old_options;
638 char hname2[MAXDNAME+1];
639 #endif /*SUNSECURITY*/
640 extern struct hostent *_gethtbyaddr();
642 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
643 __set_h_errno (NETDB_INTERNAL);
644 return (NULL);
646 if (af == AF_INET6 && len == IN6ADDRSZ &&
647 (!bcmp(uaddr, mapped, sizeof mapped) ||
648 !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
649 /* Unmap. */
650 addr += sizeof mapped;
651 uaddr += sizeof mapped;
652 af = AF_INET;
653 len = INADDRSZ;
655 switch (af) {
656 case AF_INET:
657 size = INADDRSZ;
658 break;
659 case AF_INET6:
660 size = IN6ADDRSZ;
661 break;
662 default:
663 __set_errno (EAFNOSUPPORT);
664 __set_h_errno (NETDB_INTERNAL);
665 return (NULL);
667 if (size != len) {
668 __set_errno (EINVAL);
669 __set_h_errno (NETDB_INTERNAL);
670 return (NULL);
672 switch (af) {
673 case AF_INET:
674 (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
675 (uaddr[3] & 0xff),
676 (uaddr[2] & 0xff),
677 (uaddr[1] & 0xff),
678 (uaddr[0] & 0xff));
679 break;
680 case AF_INET6:
681 qp = qbuf;
682 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
683 qp += SPRINTF((qp, "%x.%x.",
684 uaddr[n] & 0xf,
685 (uaddr[n] >> 4) & 0xf));
687 strcpy(qp, "ip6.int");
688 break;
689 default:
690 abort();
692 n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
693 if (n < 0) {
694 dprintf("res_query failed (%d)\n", n);
695 if (errno == ECONNREFUSED)
696 return (_gethtbyaddr(addr, len, af));
697 return (NULL);
699 if (!(hp = getanswer(&buf, n, qbuf, T_PTR)))
700 return (NULL); /* h_errno was set by getanswer() */
701 #ifdef SUNSECURITY
702 if (af == AF_INET) {
704 * turn off search as the name should be absolute,
705 * 'localhost' should be matched by defnames
707 strncpy(hname2, hp->h_name, MAXDNAME);
708 hname2[MAXDNAME] = '\0';
709 old_options = _res.options;
710 _res.options &= ~RES_DNSRCH;
711 _res.options |= RES_DEFNAMES;
712 if (!(rhp = gethostbyname(hname2))) {
713 syslog(LOG_NOTICE|LOG_AUTH,
714 "gethostbyaddr: No A record for %s (verifying [%s])",
715 hname2, inet_ntoa(*((struct in_addr *)addr)));
716 _res.options = old_options;
717 __set_h_errno (HOST_NOT_FOUND);
718 return (NULL);
720 _res.options = old_options;
721 for (haddr = rhp->h_addr_list; *haddr; haddr++)
722 if (!memcmp(*haddr, addr, INADDRSZ))
723 break;
724 if (!*haddr) {
725 syslog(LOG_NOTICE|LOG_AUTH,
726 "gethostbyaddr: A record of %s != PTR record [%s]",
727 hname2, inet_ntoa(*((struct in_addr *)addr)));
728 __set_h_errno (HOST_NOT_FOUND);
729 return (NULL);
732 #endif /*SUNSECURITY*/
733 hp->h_addrtype = af;
734 hp->h_length = len;
735 bcopy(addr, host_addr, len);
736 h_addr_ptrs[0] = (char *)host_addr;
737 h_addr_ptrs[1] = NULL;
738 if (af == AF_INET && (_res.options & RES_USE_INET6)) {
739 map_v4v6_address((char*)host_addr, (char*)host_addr);
740 hp->h_addrtype = AF_INET6;
741 hp->h_length = IN6ADDRSZ;
743 __set_h_errno (NETDB_SUCCESS);
744 return (hp);
747 void
748 _sethtent(f)
749 int f;
751 if (!hostf)
752 hostf = fopen(_PATH_HOSTS, "r" );
753 else
754 rewind(hostf);
755 stayopen = f;
758 void
759 _endhtent()
761 if (hostf && !stayopen) {
762 (void) fclose(hostf);
763 hostf = NULL;
767 struct hostent *
768 _gethtent()
770 char *p;
771 register char *cp, **q;
772 int af, len;
774 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
775 __set_h_errno (NETDB_INTERNAL);
776 return (NULL);
778 again:
779 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
780 __set_h_errno (HOST_NOT_FOUND);
781 return (NULL);
783 if (*p == '#')
784 goto again;
785 if (!(cp = strpbrk(p, "#\n")))
786 goto again;
787 *cp = '\0';
788 if (!(cp = strpbrk(p, " \t")))
789 goto again;
790 *cp++ = '\0';
791 if (inet_pton(AF_INET6, p, host_addr) > 0) {
792 af = AF_INET6;
793 len = IN6ADDRSZ;
794 } else if (inet_pton(AF_INET, p, host_addr) > 0) {
795 if (_res.options & RES_USE_INET6) {
796 map_v4v6_address((char*)host_addr, (char*)host_addr);
797 af = AF_INET6;
798 len = IN6ADDRSZ;
799 } else {
800 af = AF_INET;
801 len = INADDRSZ;
803 } else {
804 goto again;
806 h_addr_ptrs[0] = (char *)host_addr;
807 h_addr_ptrs[1] = NULL;
808 host.h_addr_list = h_addr_ptrs;
809 host.h_length = len;
810 host.h_addrtype = af;
811 while (*cp == ' ' || *cp == '\t')
812 cp++;
813 host.h_name = cp;
814 q = host.h_aliases = host_aliases;
815 if ((cp = strpbrk(cp, " \t")))
816 *cp++ = '\0';
817 while (cp && *cp) {
818 if (*cp == ' ' || *cp == '\t') {
819 cp++;
820 continue;
822 if (q < &host_aliases[MAXALIASES - 1])
823 *q++ = cp;
824 if ((cp = strpbrk(cp, " \t")))
825 *cp++ = '\0';
827 *q = NULL;
828 __set_h_errno (NETDB_SUCCESS);
829 return (&host);
832 struct hostent *
833 _gethtbyname(name)
834 const char *name;
836 extern struct hostent *_gethtbyname2();
837 struct hostent *hp;
839 if (_res.options & RES_USE_INET6) {
840 hp = _gethtbyname2(name, AF_INET6);
841 if (hp)
842 return (hp);
844 return (_gethtbyname2(name, AF_INET));
847 struct hostent *
848 _gethtbyname2(name, af)
849 const char *name;
850 int af;
852 register struct hostent *p;
853 register char **cp;
855 _sethtent(0);
856 while ((p = _gethtent())) {
857 if (p->h_addrtype != af)
858 continue;
859 if (strcasecmp(p->h_name, name) == 0)
860 break;
861 for (cp = p->h_aliases; *cp != 0; cp++)
862 if (strcasecmp(*cp, name) == 0)
863 goto found;
865 found:
866 _endhtent();
867 return (p);
870 struct hostent *
871 _gethtbyaddr(addr, len, af)
872 const char *addr;
873 size_t len;
874 int af;
876 register struct hostent *p;
878 _sethtent(0);
879 while ((p = _gethtent()))
880 if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
881 break;
882 _endhtent();
883 return (p);
886 static void
887 map_v4v6_address(src, dst)
888 const char *src;
889 char *dst;
891 u_char *p = (u_char *)dst;
892 char tmp[INADDRSZ];
893 int i;
895 /* Stash a temporary copy so our caller can update in place. */
896 bcopy(src, tmp, INADDRSZ);
897 /* Mark this ipv6 addr as a mapped ipv4. */
898 for (i = 0; i < 10; i++)
899 *p++ = 0x00;
900 *p++ = 0xff;
901 *p++ = 0xff;
902 /* Retrieve the saved copy and we're done. */
903 bcopy(tmp, (void*)p, INADDRSZ);
906 static void
907 map_v4v6_hostent(hp, bpp, lenp)
908 struct hostent *hp;
909 char **bpp;
910 int *lenp;
912 char **ap;
914 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
915 return;
916 hp->h_addrtype = AF_INET6;
917 hp->h_length = IN6ADDRSZ;
918 for (ap = hp->h_addr_list; *ap; ap++) {
919 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
921 if (*lenp < (i + IN6ADDRSZ)) {
922 /* Out of memory. Truncate address list here. XXX */
923 *ap = NULL;
924 return;
926 *bpp += i;
927 *lenp -= i;
928 map_v4v6_address(*ap, *bpp);
929 *ap = *bpp;
930 *bpp += IN6ADDRSZ;
931 *lenp -= IN6ADDRSZ;
935 #ifdef RESOLVSORT
936 extern void
937 addrsort(ap, num)
938 char **ap;
939 int num;
941 int i, j;
942 char **p;
943 short aval[MAXADDRS];
944 int needsort = 0;
946 p = ap;
947 for (i = 0; i < num; i++, p++) {
948 for (j = 0 ; (unsigned)j < _res.nsort; j++)
949 if (_res.sort_list[j].addr.s_addr ==
950 (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
951 break;
952 aval[i] = j;
953 if (needsort == 0 && i > 0 && j < aval[i-1])
954 needsort = i;
956 if (!needsort)
957 return;
959 while (needsort < num) {
960 for (j = needsort - 1; j >= 0; j--) {
961 if (aval[j] > aval[j+1]) {
962 char *hp;
964 i = aval[j];
965 aval[j] = aval[j+1];
966 aval[j+1] = i;
968 hp = ap[j];
969 ap[j] = ap[j+1];
970 ap[j+1] = hp;
972 } else
973 break;
975 needsort++;
978 #endif
980 #if defined(BSD43_BSD43_NFS) || defined(sun)
981 /* some libc's out there are bound internally to these names (UMIPS) */
982 void
983 ht_sethostent(stayopen)
984 int stayopen;
986 _sethtent(stayopen);
989 void
990 ht_endhostent()
992 _endhtent();
995 struct hostent *
996 ht_gethostbyname(name)
997 char *name;
999 return (_gethtbyname(name));
1002 struct hostent *
1003 ht_gethostbyaddr(addr, len, af)
1004 const char *addr;
1005 size_t len;
1006 int af;
1008 return (_gethtbyaddr(addr, len, af));
1011 struct hostent *
1012 gethostent()
1014 return (_gethtent());
1017 void
1018 dns_service()
1020 return;
1023 #undef dn_skipname
1024 dn_skipname(comp_dn, eom)
1025 const u_char *comp_dn, *eom;
1027 return (__dn_skipname(comp_dn, eom));
1029 #endif /*old-style libc with yp junk in it*/