Update.
[glibc.git] / resolv / gethnamaddr.c
blob7f1b742c4dec1817c56382a33b0c8e0c4eb25276
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 /* XXX: when incrementing bp, we have to decrement
424 * buflen by the same amount --okir */
425 buflen -= sizeof(align) - ((u_long)bp % sizeof(align));
427 bp += sizeof(align) - ((u_long)bp % sizeof(align));
429 if (bp + n >= &hostbuf[sizeof hostbuf]) {
430 dprintf("size (%d) too big\n", n);
431 had_error++;
432 continue;
434 if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
435 if (!toobig++) {
436 dprintf("Too many addresses (%d)\n",
437 MAXADDRS);
439 cp += n;
440 continue;
442 bcopy(cp, *hap++ = bp, n);
443 bp += n;
444 buflen -= n;
445 cp += n;
446 if (cp != erdata) {
447 __set_h_errno (NO_RECOVERY);
448 return (NULL);
450 break;
451 default:
452 abort();
454 if (!had_error)
455 haveanswer++;
457 if (haveanswer) {
458 *ap = NULL;
459 *hap = NULL;
460 # if defined(RESOLVSORT)
462 * Note: we sort even if host can take only one address
463 * in its return structures - should give it the "best"
464 * address in that case, not some random one
466 if (_res.nsort && haveanswer > 1 && qtype == T_A)
467 addrsort(h_addr_ptrs, haveanswer);
468 # endif /*RESOLVSORT*/
469 if (!host.h_name) {
470 n = strlen(qname) + 1; /* for the \0 */
471 if (n > buflen || n >= MAXHOSTNAMELEN)
472 goto no_recovery;
473 strcpy(bp, qname);
474 host.h_name = bp;
475 bp += n;
476 buflen -= n;
478 if (_res.options & RES_USE_INET6)
479 map_v4v6_hostent(&host, &bp, &buflen);
480 __set_h_errno (NETDB_SUCCESS);
481 return (&host);
483 no_recovery:
484 __set_h_errno (NO_RECOVERY);
485 return (NULL);
488 struct hostent *
489 gethostbyname(name)
490 const char *name;
492 struct hostent *hp;
494 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
495 __set_h_errno (NETDB_INTERNAL);
496 return (NULL);
498 if (_res.options & RES_USE_INET6) {
499 hp = gethostbyname2(name, AF_INET6);
500 if (hp)
501 return (hp);
503 return (gethostbyname2(name, AF_INET));
506 struct hostent *
507 gethostbyname2(name, af)
508 const char *name;
509 int af;
511 querybuf buf;
512 register const char *cp;
513 char *bp;
514 int n, size, type, len;
515 extern struct hostent *_gethtbyname2();
517 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
518 __set_h_errno (NETDB_INTERNAL);
519 return (NULL);
522 switch (af) {
523 case AF_INET:
524 size = INADDRSZ;
525 type = T_A;
526 break;
527 case AF_INET6:
528 size = IN6ADDRSZ;
529 type = T_AAAA;
530 break;
531 default:
532 __set_h_errno (NETDB_INTERNAL);
533 __set_errno (EAFNOSUPPORT);
534 return (NULL);
537 host.h_addrtype = af;
538 host.h_length = size;
541 * if there aren't any dots, it could be a user-level alias.
542 * this is also done in res_query() since we are not the only
543 * function that looks up host names.
545 if (!strchr(name, '.') && (cp = __hostalias(name)))
546 name = cp;
549 * disallow names consisting only of digits/dots, unless
550 * they end in a dot.
552 if (isdigit(name[0]))
553 for (cp = name;; ++cp) {
554 if (!*cp) {
555 if (*--cp == '.')
556 break;
558 * All-numeric, no dot at the end.
559 * Fake up a hostent as if we'd actually
560 * done a lookup.
562 if (inet_pton(af, name, host_addr) <= 0) {
563 __set_h_errno (HOST_NOT_FOUND);
564 return (NULL);
566 strncpy(hostbuf, name, MAXDNAME);
567 hostbuf[MAXDNAME] = '\0';
568 bp = hostbuf + MAXDNAME;
569 len = sizeof hostbuf - MAXDNAME;
570 host.h_name = hostbuf;
571 host.h_aliases = host_aliases;
572 host_aliases[0] = NULL;
573 h_addr_ptrs[0] = (char *)host_addr;
574 h_addr_ptrs[1] = NULL;
575 host.h_addr_list = h_addr_ptrs;
576 if (_res.options & RES_USE_INET6)
577 map_v4v6_hostent(&host, &bp, &len);
578 __set_h_errno (NETDB_SUCCESS);
579 return (&host);
581 if (!isdigit(*cp) && *cp != '.')
582 break;
584 if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
585 name[0] == ':')
586 for (cp = name;; ++cp) {
587 if (!*cp) {
588 if (*--cp == '.')
589 break;
591 * All-IPv6-legal, no dot at the end.
592 * Fake up a hostent as if we'd actually
593 * done a lookup.
595 if (inet_pton(af, name, host_addr) <= 0) {
596 __set_h_errno (HOST_NOT_FOUND);
597 return (NULL);
599 strncpy(hostbuf, name, MAXDNAME);
600 hostbuf[MAXDNAME] = '\0';
601 bp = hostbuf + MAXDNAME;
602 len = sizeof hostbuf - MAXDNAME;
603 host.h_name = hostbuf;
604 host.h_aliases = host_aliases;
605 host_aliases[0] = NULL;
606 h_addr_ptrs[0] = (char *)host_addr;
607 h_addr_ptrs[1] = NULL;
608 host.h_addr_list = h_addr_ptrs;
609 __set_h_errno (NETDB_SUCCESS);
610 return (&host);
612 if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
613 break;
616 if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf.buf))) < 0) {
617 dprintf("res_search failed (%d)\n", n);
618 if (errno == ECONNREFUSED)
619 return (_gethtbyname2(name, af));
620 return (NULL);
622 return (getanswer(&buf, n, name, type));
625 struct hostent *
626 gethostbyaddr(addr, len, af)
627 const char *addr; /* XXX should have been def'd as u_char! */
628 size_t len;
629 int af;
631 const u_char *uaddr = (const u_char *)addr;
632 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
633 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
634 int n, size;
635 querybuf buf;
636 register struct hostent *hp;
637 char qbuf[MAXDNAME+1], *qp;
638 #ifdef SUNSECURITY
639 register struct hostent *rhp;
640 char **haddr;
641 u_long old_options;
642 char hname2[MAXDNAME+1];
643 #endif /*SUNSECURITY*/
644 extern struct hostent *_gethtbyaddr();
646 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
647 __set_h_errno (NETDB_INTERNAL);
648 return (NULL);
650 if (af == AF_INET6 && len == IN6ADDRSZ &&
651 (!bcmp(uaddr, mapped, sizeof mapped) ||
652 !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
653 /* Unmap. */
654 addr += sizeof mapped;
655 uaddr += sizeof mapped;
656 af = AF_INET;
657 len = INADDRSZ;
659 switch (af) {
660 case AF_INET:
661 size = INADDRSZ;
662 break;
663 case AF_INET6:
664 size = IN6ADDRSZ;
665 break;
666 default:
667 __set_errno (EAFNOSUPPORT);
668 __set_h_errno (NETDB_INTERNAL);
669 return (NULL);
671 if (size != len) {
672 __set_errno (EINVAL);
673 __set_h_errno (NETDB_INTERNAL);
674 return (NULL);
676 switch (af) {
677 case AF_INET:
678 (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
679 (uaddr[3] & 0xff),
680 (uaddr[2] & 0xff),
681 (uaddr[1] & 0xff),
682 (uaddr[0] & 0xff));
683 break;
684 case AF_INET6:
685 qp = qbuf;
686 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
687 qp += SPRINTF((qp, "%x.%x.",
688 uaddr[n] & 0xf,
689 (uaddr[n] >> 4) & 0xf));
691 strcpy(qp, "ip6.int");
692 break;
693 default:
694 abort();
696 n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
697 if (n < 0) {
698 dprintf("res_query failed (%d)\n", n);
699 if (errno == ECONNREFUSED)
700 return (_gethtbyaddr(addr, len, af));
701 return (NULL);
703 if (!(hp = getanswer(&buf, n, qbuf, T_PTR)))
704 return (NULL); /* h_errno was set by getanswer() */
705 #ifdef SUNSECURITY
706 if (af == AF_INET) {
708 * turn off search as the name should be absolute,
709 * 'localhost' should be matched by defnames
711 strncpy(hname2, hp->h_name, MAXDNAME);
712 hname2[MAXDNAME] = '\0';
713 old_options = _res.options;
714 _res.options &= ~RES_DNSRCH;
715 _res.options |= RES_DEFNAMES;
716 if (!(rhp = gethostbyname(hname2))) {
717 syslog(LOG_NOTICE|LOG_AUTH,
718 "gethostbyaddr: No A record for %s (verifying [%s])",
719 hname2, inet_ntoa(*((struct in_addr *)addr)));
720 _res.options = old_options;
721 __set_h_errno (HOST_NOT_FOUND);
722 return (NULL);
724 _res.options = old_options;
725 for (haddr = rhp->h_addr_list; *haddr; haddr++)
726 if (!memcmp(*haddr, addr, INADDRSZ))
727 break;
728 if (!*haddr) {
729 syslog(LOG_NOTICE|LOG_AUTH,
730 "gethostbyaddr: A record of %s != PTR record [%s]",
731 hname2, inet_ntoa(*((struct in_addr *)addr)));
732 __set_h_errno (HOST_NOT_FOUND);
733 return (NULL);
736 #endif /*SUNSECURITY*/
737 hp->h_addrtype = af;
738 hp->h_length = len;
739 bcopy(addr, host_addr, len);
740 h_addr_ptrs[0] = (char *)host_addr;
741 h_addr_ptrs[1] = NULL;
742 if (af == AF_INET && (_res.options & RES_USE_INET6)) {
743 map_v4v6_address((char*)host_addr, (char*)host_addr);
744 hp->h_addrtype = AF_INET6;
745 hp->h_length = IN6ADDRSZ;
747 __set_h_errno (NETDB_SUCCESS);
748 return (hp);
751 void
752 _sethtent(f)
753 int f;
755 if (!hostf)
756 hostf = fopen(_PATH_HOSTS, "r" );
757 else
758 rewind(hostf);
759 stayopen = f;
762 void
763 _endhtent()
765 if (hostf && !stayopen) {
766 (void) fclose(hostf);
767 hostf = NULL;
771 struct hostent *
772 _gethtent()
774 char *p;
775 register char *cp, **q;
776 int af, len;
778 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
779 __set_h_errno (NETDB_INTERNAL);
780 return (NULL);
782 again:
783 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
784 __set_h_errno (HOST_NOT_FOUND);
785 return (NULL);
787 if (*p == '#')
788 goto again;
789 if (!(cp = strpbrk(p, "#\n")))
790 goto again;
791 *cp = '\0';
792 if (!(cp = strpbrk(p, " \t")))
793 goto again;
794 *cp++ = '\0';
795 if (inet_pton(AF_INET6, p, host_addr) > 0) {
796 af = AF_INET6;
797 len = IN6ADDRSZ;
798 } else if (inet_pton(AF_INET, p, host_addr) > 0) {
799 if (_res.options & RES_USE_INET6) {
800 map_v4v6_address((char*)host_addr, (char*)host_addr);
801 af = AF_INET6;
802 len = IN6ADDRSZ;
803 } else {
804 af = AF_INET;
805 len = INADDRSZ;
807 } else {
808 goto again;
810 h_addr_ptrs[0] = (char *)host_addr;
811 h_addr_ptrs[1] = NULL;
812 host.h_addr_list = h_addr_ptrs;
813 host.h_length = len;
814 host.h_addrtype = af;
815 while (*cp == ' ' || *cp == '\t')
816 cp++;
817 host.h_name = cp;
818 q = host.h_aliases = host_aliases;
819 if ((cp = strpbrk(cp, " \t")))
820 *cp++ = '\0';
821 while (cp && *cp) {
822 if (*cp == ' ' || *cp == '\t') {
823 cp++;
824 continue;
826 if (q < &host_aliases[MAXALIASES - 1])
827 *q++ = cp;
828 if ((cp = strpbrk(cp, " \t")))
829 *cp++ = '\0';
831 *q = NULL;
832 __set_h_errno (NETDB_SUCCESS);
833 return (&host);
836 struct hostent *
837 _gethtbyname(name)
838 const char *name;
840 extern struct hostent *_gethtbyname2();
841 struct hostent *hp;
843 if (_res.options & RES_USE_INET6) {
844 hp = _gethtbyname2(name, AF_INET6);
845 if (hp)
846 return (hp);
848 return (_gethtbyname2(name, AF_INET));
851 struct hostent *
852 _gethtbyname2(name, af)
853 const char *name;
854 int af;
856 register struct hostent *p;
857 register char **cp;
859 _sethtent(0);
860 while ((p = _gethtent())) {
861 if (p->h_addrtype != af)
862 continue;
863 if (strcasecmp(p->h_name, name) == 0)
864 break;
865 for (cp = p->h_aliases; *cp != 0; cp++)
866 if (strcasecmp(*cp, name) == 0)
867 goto found;
869 found:
870 _endhtent();
871 return (p);
874 struct hostent *
875 _gethtbyaddr(addr, len, af)
876 const char *addr;
877 size_t len;
878 int af;
880 register struct hostent *p;
882 _sethtent(0);
883 while ((p = _gethtent()))
884 if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
885 break;
886 _endhtent();
887 return (p);
890 static void
891 map_v4v6_address(src, dst)
892 const char *src;
893 char *dst;
895 u_char *p = (u_char *)dst;
896 char tmp[INADDRSZ];
897 int i;
899 /* Stash a temporary copy so our caller can update in place. */
900 bcopy(src, tmp, INADDRSZ);
901 /* Mark this ipv6 addr as a mapped ipv4. */
902 for (i = 0; i < 10; i++)
903 *p++ = 0x00;
904 *p++ = 0xff;
905 *p++ = 0xff;
906 /* Retrieve the saved copy and we're done. */
907 bcopy(tmp, (void*)p, INADDRSZ);
910 static void
911 map_v4v6_hostent(hp, bpp, lenp)
912 struct hostent *hp;
913 char **bpp;
914 int *lenp;
916 char **ap;
918 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
919 return;
920 hp->h_addrtype = AF_INET6;
921 hp->h_length = IN6ADDRSZ;
922 for (ap = hp->h_addr_list; *ap; ap++) {
923 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
925 if (*lenp < (i + IN6ADDRSZ)) {
926 /* Out of memory. Truncate address list here. XXX */
927 *ap = NULL;
928 return;
930 *bpp += i;
931 *lenp -= i;
932 map_v4v6_address(*ap, *bpp);
933 *ap = *bpp;
934 *bpp += IN6ADDRSZ;
935 *lenp -= IN6ADDRSZ;
939 #ifdef RESOLVSORT
940 extern void
941 addrsort(ap, num)
942 char **ap;
943 int num;
945 int i, j;
946 char **p;
947 short aval[MAXADDRS];
948 int needsort = 0;
950 p = ap;
951 for (i = 0; i < num; i++, p++) {
952 for (j = 0 ; (unsigned)j < _res.nsort; j++)
953 if (_res.sort_list[j].addr.s_addr ==
954 (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
955 break;
956 aval[i] = j;
957 if (needsort == 0 && i > 0 && j < aval[i-1])
958 needsort = i;
960 if (!needsort)
961 return;
963 while (needsort < num) {
964 for (j = needsort - 1; j >= 0; j--) {
965 if (aval[j] > aval[j+1]) {
966 char *hp;
968 i = aval[j];
969 aval[j] = aval[j+1];
970 aval[j+1] = i;
972 hp = ap[j];
973 ap[j] = ap[j+1];
974 ap[j+1] = hp;
976 } else
977 break;
979 needsort++;
982 #endif
984 #if defined(BSD43_BSD43_NFS) || defined(sun)
985 /* some libc's out there are bound internally to these names (UMIPS) */
986 void
987 ht_sethostent(stayopen)
988 int stayopen;
990 _sethtent(stayopen);
993 void
994 ht_endhostent()
996 _endhtent();
999 struct hostent *
1000 ht_gethostbyname(name)
1001 char *name;
1003 return (_gethtbyname(name));
1006 struct hostent *
1007 ht_gethostbyaddr(addr, len, af)
1008 const char *addr;
1009 size_t len;
1010 int af;
1012 return (_gethtbyaddr(addr, len, af));
1015 struct hostent *
1016 gethostent()
1018 return (_gethtent());
1021 void
1022 dns_service()
1024 return;
1027 #undef dn_skipname
1028 dn_skipname(comp_dn, eom)
1029 const u_char *comp_dn, *eom;
1031 return (__dn_skipname(comp_dn, eom));
1033 #endif /*old-style libc with yp junk in it*/