Update.
[glibc.git] / resolv / gethnamaddr.c
blob16d7509f235af0747cacbdfeef124972ec599e46
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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 * -
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * SOFTWARE.
52 * -
53 * --Copyright--
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
58 static char rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
61 #include <sys/types.h>
62 #include <sys/param.h>
63 #include <sys/socket.h>
64 #include <netinet/in.h>
65 #include <arpa/inet.h>
66 #include <arpa/nameser.h>
68 #include <stdio.h>
69 #include <netdb.h>
70 #include <resolv.h>
71 #include <ctype.h>
72 #include <errno.h>
73 #include <syslog.h>
75 #ifndef LOG_AUTH
76 # define LOG_AUTH 0
77 #endif
79 #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
81 #if defined(BSD) && (BSD >= 199103) && defined(AF_INET6)
82 # include <stdlib.h>
83 # include <string.h>
84 #else
85 # include "../conf/portability.h"
86 #endif
88 #if defined(USE_OPTIONS_H)
89 # include <../conf/options.h>
90 #endif
92 #ifdef SPRINTF_CHAR
93 # define SPRINTF(x) strlen(sprintf/**/x)
94 #else
95 # define SPRINTF(x) ((size_t)sprintf x)
96 #endif
98 #define MAXALIASES 35
99 #define MAXADDRS 35
101 static const char AskedForGot[] =
102 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
104 static char *h_addr_ptrs[MAXADDRS + 1];
106 static struct hostent host;
107 static char *host_aliases[MAXALIASES];
108 static char hostbuf[8*1024];
109 static u_char host_addr[16]; /* IPv4 or IPv6 */
110 static FILE *hostf = NULL;
111 static int stayopen = 0;
113 static void map_v4v6_address __P((const char *src, char *dst));
114 static void map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len));
116 #ifdef RESOLVSORT
117 extern void addrsort __P((char **, int));
118 #endif
120 #if PACKETSZ > 1024
121 #define MAXPACKET PACKETSZ
122 #else
123 #define MAXPACKET 1024
124 #endif
126 /* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */
127 #ifdef MAXHOSTNAMELEN
128 # undef MAXHOSTNAMELEN
129 #endif
130 #define MAXHOSTNAMELEN 256
132 typedef union {
133 HEADER hdr;
134 u_char buf[MAXPACKET];
135 } querybuf;
137 typedef union {
138 int32_t al;
139 char ac;
140 } align;
142 #ifndef h_errno
143 extern int h_errno;
144 #endif
146 #ifdef DEBUG
147 static void
148 dprintf(msg, num)
149 char *msg;
150 int num;
152 if (_res.options & RES_DEBUG) {
153 int save = errno;
155 printf(msg, num);
156 __set_errno (save);
159 #else
160 # define dprintf(msg, num) /*nada*/
161 #endif
163 #define BOUNDED_INCR(x) \
164 do { \
165 cp += x; \
166 if (cp > eom) { \
167 __set_h_errno (NO_RECOVERY); \
168 return (NULL); \
170 } while (0)
172 #define BOUNDS_CHECK(ptr, count) \
173 do { \
174 if ((ptr) + (count) > eom) { \
175 __set_h_errno (NO_RECOVERY); \
176 return (NULL); \
178 } while (0)
181 static struct hostent *
182 getanswer(answer, anslen, qname, qtype)
183 const querybuf *answer;
184 int anslen;
185 const char *qname;
186 int qtype;
188 register const HEADER *hp;
189 register const u_char *cp;
190 register int n;
191 const u_char *eom, *erdata;
192 char *bp, **ap, **hap;
193 int type, class, buflen, ancount, qdcount;
194 int haveanswer, had_error;
195 int toobig = 0;
196 char tbuf[MAXDNAME];
197 const char *tname;
198 int (*name_ok) __P((const char *));
200 tname = qname;
201 host.h_name = NULL;
202 eom = answer->buf + anslen;
203 switch (qtype) {
204 case T_A:
205 case T_AAAA:
206 name_ok = res_hnok;
207 break;
208 case T_PTR:
209 name_ok = res_dnok;
210 break;
211 default:
212 return (NULL); /* XXX should be abort(); */
215 * find first satisfactory answer
217 hp = &answer->hdr;
218 ancount = ntohs(hp->ancount);
219 qdcount = ntohs(hp->qdcount);
220 bp = hostbuf;
221 buflen = sizeof hostbuf;
222 cp = answer->buf;
223 BOUNDED_INCR(HFIXEDSZ);
224 if (qdcount != 1) {
225 __set_h_errno (NO_RECOVERY);
226 return (NULL);
228 n = dn_expand(answer->buf, eom, cp, bp, buflen);
229 if ((n < 0) || !(*name_ok)(bp)) {
230 __set_h_errno (NO_RECOVERY);
231 return (NULL);
233 BOUNDED_INCR(n + QFIXEDSZ);
234 if (qtype == T_A || qtype == T_AAAA) {
235 /* res_send() has already verified that the query name is the
236 * same as the one we sent; this just gets the expanded name
237 * (i.e., with the succeeding search-domain tacked on).
239 n = strlen(bp) + 1; /* for the \0 */
240 if (n >= MAXHOSTNAMELEN) {
241 __set_h_errno (NO_RECOVERY);
242 return (NULL);
244 host.h_name = bp;
245 bp += n;
246 buflen -= n;
247 /* The qname can be abbreviated, but h_name is now absolute. */
248 qname = host.h_name;
250 ap = host_aliases;
251 *ap = NULL;
252 host.h_aliases = host_aliases;
253 hap = h_addr_ptrs;
254 *hap = NULL;
255 host.h_addr_list = h_addr_ptrs;
256 haveanswer = 0;
257 had_error = 0;
258 while (ancount-- > 0 && cp < eom && !had_error) {
259 n = dn_expand(answer->buf, eom, cp, bp, buflen);
260 if ((n < 0) || !(*name_ok)(bp)) {
261 had_error++;
262 continue;
264 cp += n; /* name */
265 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
266 type = _getshort(cp);
267 cp += INT16SZ; /* type */
268 class = _getshort(cp);
269 cp += INT16SZ + INT32SZ; /* class, TTL */
270 n = _getshort(cp);
271 cp += INT16SZ; /* len */
272 BOUNDS_CHECK(cp, n);
273 erdata = cp + n;
274 if (class != C_IN) {
275 /* XXX - debug? syslog? */
276 cp += n;
277 continue; /* XXX - had_error++ ? */
279 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
280 if (ap >= &host_aliases[MAXALIASES-1])
281 continue;
282 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
283 if ((n < 0) || !(*name_ok)(tbuf)) {
284 had_error++;
285 continue;
287 cp += n;
288 if (cp != erdata) {
289 __set_h_errno (NO_RECOVERY);
290 return (NULL);
292 /* Store alias. */
293 *ap++ = bp;
294 n = strlen(bp) + 1; /* for the \0 */
295 if (n >= MAXHOSTNAMELEN) {
296 had_error++;
297 continue;
299 bp += n;
300 buflen -= n;
301 /* Get canonical name. */
302 n = strlen(tbuf) + 1; /* for the \0 */
303 if (n > buflen || n >= MAXHOSTNAMELEN) {
304 had_error++;
305 continue;
307 strcpy(bp, tbuf);
308 host.h_name = bp;
309 bp += n;
310 buflen -= n;
311 continue;
313 if (qtype == T_PTR && type == T_CNAME) {
314 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
315 if (n < 0 || !res_dnok(tbuf)) {
316 had_error++;
317 continue;
319 cp += n;
320 if (cp != erdata) {
321 __set_h_errno (NO_RECOVERY);
322 return (NULL);
324 /* Get canonical name. */
325 n = strlen(tbuf) + 1; /* for the \0 */
326 if (n > buflen || n >= MAXHOSTNAMELEN) {
327 had_error++;
328 continue;
330 strcpy(bp, tbuf);
331 tname = bp;
332 bp += n;
333 buflen -= n;
334 continue;
336 if ((type == T_SIG) || (type == T_KEY) || (type == T_NXT)) {
337 /* We don't support DNSSEC yet. For now, ignore
338 * the record and send a low priority message
339 * to syslog.
341 syslog(LOG_DEBUG|LOG_AUTH,
342 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
343 qname, p_class(C_IN), p_type(qtype),
344 p_type(type));
345 cp += n;
346 continue;
348 if (type != qtype) {
349 syslog(LOG_NOTICE|LOG_AUTH,
350 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
351 qname, p_class(C_IN), p_type(qtype),
352 p_type(type));
353 cp += n;
354 continue; /* XXX - had_error++ ? */
356 switch (type) {
357 case T_PTR:
358 if (strcasecmp(tname, bp) != 0) {
359 syslog(LOG_NOTICE|LOG_AUTH,
360 AskedForGot, qname, bp);
361 cp += n;
362 continue; /* XXX - had_error++ ? */
364 n = dn_expand(answer->buf, eom, cp, bp, buflen);
365 if ((n < 0) || !res_hnok(bp)) {
366 had_error++;
367 break;
369 #if MULTI_PTRS_ARE_ALIASES
370 cp += n;
371 if (cp != erdata) {
372 __set_h_errno (NO_RECOVERY);
373 return (NULL);
375 if (!haveanswer)
376 host.h_name = bp;
377 else if (ap < &host_aliases[MAXALIASES-1])
378 *ap++ = bp;
379 else
380 n = -1;
381 if (n != -1) {
382 n = strlen(bp) + 1; /* for the \0 */
383 if (n >= MAXHOSTNAMELEN) {
384 had_error++;
385 break;
387 bp += n;
388 buflen -= n;
390 break;
391 #else
392 host.h_name = bp;
393 if (_res.options & RES_USE_INET6) {
394 n = strlen(bp) + 1; /* for the \0 */
395 if (n >= MAXHOSTNAMELEN) {
396 had_error++;
397 break;
399 bp += n;
400 buflen -= n;
401 map_v4v6_hostent(&host, &bp, &buflen);
403 __set_h_errno (NETDB_SUCCESS);
404 return (&host);
405 #endif
406 case T_A:
407 case T_AAAA:
408 if (strcasecmp(host.h_name, bp) != 0) {
409 syslog(LOG_NOTICE|LOG_AUTH,
410 AskedForGot, host.h_name, bp);
411 cp += n;
412 continue; /* XXX - had_error++ ? */
414 if (n != host.h_length) {
415 cp += n;
416 continue;
418 if (!haveanswer) {
419 register int nn;
421 host.h_name = bp;
422 nn = strlen(bp) + 1; /* for the \0 */
423 bp += nn;
424 buflen -= nn;
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 int len, af;
630 const u_char *uaddr = (const u_char *)addr;
631 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
632 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
633 int n, size;
634 querybuf buf;
635 register struct hostent *hp;
636 char qbuf[MAXDNAME+1], *qp;
637 #ifdef SUNSECURITY
638 register struct hostent *rhp;
639 char **haddr;
640 u_long old_options;
641 char hname2[MAXDNAME+1];
642 #endif /*SUNSECURITY*/
643 extern struct hostent *_gethtbyaddr();
645 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
646 __set_h_errno (NETDB_INTERNAL);
647 return (NULL);
649 if (af == AF_INET6 && len == IN6ADDRSZ &&
650 (!bcmp(uaddr, mapped, sizeof mapped) ||
651 !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
652 /* Unmap. */
653 addr += sizeof mapped;
654 uaddr += sizeof mapped;
655 af = AF_INET;
656 len = INADDRSZ;
658 switch (af) {
659 case AF_INET:
660 size = INADDRSZ;
661 break;
662 case AF_INET6:
663 size = IN6ADDRSZ;
664 break;
665 default:
666 __set_errno (EAFNOSUPPORT);
667 __set_h_errno (NETDB_INTERNAL);
668 return (NULL);
670 if (size != len) {
671 __set_errno (EINVAL);
672 __set_h_errno (NETDB_INTERNAL);
673 return (NULL);
675 switch (af) {
676 case AF_INET:
677 (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
678 (uaddr[3] & 0xff),
679 (uaddr[2] & 0xff),
680 (uaddr[1] & 0xff),
681 (uaddr[0] & 0xff));
682 break;
683 case AF_INET6:
684 qp = qbuf;
685 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
686 qp += SPRINTF((qp, "%x.%x.",
687 uaddr[n] & 0xf,
688 (uaddr[n] >> 4) & 0xf));
690 strcpy(qp, "ip6.int");
691 break;
692 default:
693 abort();
695 n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
696 if (n < 0) {
697 dprintf("res_query failed (%d)\n", n);
698 if (errno == ECONNREFUSED)
699 return (_gethtbyaddr(addr, len, af));
700 return (NULL);
702 if (!(hp = getanswer(&buf, n, qbuf, T_PTR)))
703 return (NULL); /* h_errno was set by getanswer() */
704 #ifdef SUNSECURITY
705 if (af == AF_INET) {
707 * turn off search as the name should be absolute,
708 * 'localhost' should be matched by defnames
710 strncpy(hname2, hp->h_name, MAXDNAME);
711 hname2[MAXDNAME] = '\0';
712 old_options = _res.options;
713 _res.options &= ~RES_DNSRCH;
714 _res.options |= RES_DEFNAMES;
715 if (!(rhp = gethostbyname(hname2))) {
716 syslog(LOG_NOTICE|LOG_AUTH,
717 "gethostbyaddr: No A record for %s (verifying [%s])",
718 hname2, inet_ntoa(*((struct in_addr *)addr)));
719 _res.options = old_options;
720 __set_h_errno (HOST_NOT_FOUND);
721 return (NULL);
723 _res.options = old_options;
724 for (haddr = rhp->h_addr_list; *haddr; haddr++)
725 if (!memcmp(*haddr, addr, INADDRSZ))
726 break;
727 if (!*haddr) {
728 syslog(LOG_NOTICE|LOG_AUTH,
729 "gethostbyaddr: A record of %s != PTR record [%s]",
730 hname2, inet_ntoa(*((struct in_addr *)addr)));
731 __set_h_errno (HOST_NOT_FOUND);
732 return (NULL);
735 #endif /*SUNSECURITY*/
736 hp->h_addrtype = af;
737 hp->h_length = len;
738 bcopy(addr, host_addr, len);
739 h_addr_ptrs[0] = (char *)host_addr;
740 h_addr_ptrs[1] = NULL;
741 if (af == AF_INET && (_res.options & RES_USE_INET6)) {
742 map_v4v6_address((char*)host_addr, (char*)host_addr);
743 hp->h_addrtype = AF_INET6;
744 hp->h_length = IN6ADDRSZ;
746 __set_h_errno (NETDB_SUCCESS);
747 return (hp);
750 void
751 _sethtent(f)
752 int f;
754 if (!hostf)
755 hostf = fopen(_PATH_HOSTS, "r" );
756 else
757 rewind(hostf);
758 stayopen = f;
761 void
762 _endhtent()
764 if (hostf && !stayopen) {
765 (void) fclose(hostf);
766 hostf = NULL;
770 struct hostent *
771 _gethtent()
773 char *p;
774 register char *cp, **q;
775 int af, len;
777 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
778 __set_h_errno (NETDB_INTERNAL);
779 return (NULL);
781 again:
782 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
783 __set_h_errno (HOST_NOT_FOUND);
784 return (NULL);
786 if (*p == '#')
787 goto again;
788 if (!(cp = strpbrk(p, "#\n")))
789 goto again;
790 *cp = '\0';
791 if (!(cp = strpbrk(p, " \t")))
792 goto again;
793 *cp++ = '\0';
794 if (inet_pton(AF_INET6, p, host_addr) > 0) {
795 af = AF_INET6;
796 len = IN6ADDRSZ;
797 } else if (inet_pton(AF_INET, p, host_addr) > 0) {
798 if (_res.options & RES_USE_INET6) {
799 map_v4v6_address((char*)host_addr, (char*)host_addr);
800 af = AF_INET6;
801 len = IN6ADDRSZ;
802 } else {
803 af = AF_INET;
804 len = INADDRSZ;
806 } else {
807 goto again;
809 h_addr_ptrs[0] = (char *)host_addr;
810 h_addr_ptrs[1] = NULL;
811 host.h_addr_list = h_addr_ptrs;
812 host.h_length = len;
813 host.h_addrtype = af;
814 while (*cp == ' ' || *cp == '\t')
815 cp++;
816 host.h_name = cp;
817 q = host.h_aliases = host_aliases;
818 if (cp = strpbrk(cp, " \t"))
819 *cp++ = '\0';
820 while (cp && *cp) {
821 if (*cp == ' ' || *cp == '\t') {
822 cp++;
823 continue;
825 if (q < &host_aliases[MAXALIASES - 1])
826 *q++ = cp;
827 if (cp = strpbrk(cp, " \t"))
828 *cp++ = '\0';
830 *q = NULL;
831 __set_h_errno (NETDB_SUCCESS);
832 return (&host);
835 struct hostent *
836 _gethtbyname(name)
837 const char *name;
839 extern struct hostent *_gethtbyname2();
840 struct hostent *hp;
842 if (_res.options & RES_USE_INET6) {
843 hp = _gethtbyname2(name, AF_INET6);
844 if (hp)
845 return (hp);
847 return (_gethtbyname2(name, AF_INET));
850 struct hostent *
851 _gethtbyname2(name, af)
852 const char *name;
853 int af;
855 register struct hostent *p;
856 register char **cp;
858 _sethtent(0);
859 while (p = _gethtent()) {
860 if (p->h_addrtype != af)
861 continue;
862 if (strcasecmp(p->h_name, name) == 0)
863 break;
864 for (cp = p->h_aliases; *cp != 0; cp++)
865 if (strcasecmp(*cp, name) == 0)
866 goto found;
868 found:
869 _endhtent();
870 return (p);
873 struct hostent *
874 _gethtbyaddr(addr, len, af)
875 const char *addr;
876 int len, af;
878 register struct hostent *p;
880 _sethtent(0);
881 while (p = _gethtent())
882 if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
883 break;
884 _endhtent();
885 return (p);
888 static void
889 map_v4v6_address(src, dst)
890 const char *src;
891 char *dst;
893 u_char *p = (u_char *)dst;
894 char tmp[INADDRSZ];
895 int i;
897 /* Stash a temporary copy so our caller can update in place. */
898 bcopy(src, tmp, INADDRSZ);
899 /* Mark this ipv6 addr as a mapped ipv4. */
900 for (i = 0; i < 10; i++)
901 *p++ = 0x00;
902 *p++ = 0xff;
903 *p++ = 0xff;
904 /* Retrieve the saved copy and we're done. */
905 bcopy(tmp, (void*)p, INADDRSZ);
908 static void
909 map_v4v6_hostent(hp, bpp, lenp)
910 struct hostent *hp;
911 char **bpp;
912 int *lenp;
914 char **ap;
916 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
917 return;
918 hp->h_addrtype = AF_INET6;
919 hp->h_length = IN6ADDRSZ;
920 for (ap = hp->h_addr_list; *ap; ap++) {
921 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
923 if (*lenp < (i + IN6ADDRSZ)) {
924 /* Out of memory. Truncate address list here. XXX */
925 *ap = NULL;
926 return;
928 *bpp += i;
929 *lenp -= i;
930 map_v4v6_address(*ap, *bpp);
931 *ap = *bpp;
932 *bpp += IN6ADDRSZ;
933 *lenp -= IN6ADDRSZ;
937 #ifdef RESOLVSORT
938 extern void
939 addrsort(ap, num)
940 char **ap;
941 int num;
943 int i, j;
944 char **p;
945 short aval[MAXADDRS];
946 int needsort = 0;
948 p = ap;
949 for (i = 0; i < num; i++, p++) {
950 for (j = 0 ; (unsigned)j < _res.nsort; j++)
951 if (_res.sort_list[j].addr.s_addr ==
952 (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
953 break;
954 aval[i] = j;
955 if (needsort == 0 && i > 0 && j < aval[i-1])
956 needsort = i;
958 if (!needsort)
959 return;
961 while (needsort < num) {
962 for (j = needsort - 1; j >= 0; j--) {
963 if (aval[j] > aval[j+1]) {
964 char *hp;
966 i = aval[j];
967 aval[j] = aval[j+1];
968 aval[j+1] = i;
970 hp = ap[j];
971 ap[j] = ap[j+1];
972 ap[j+1] = hp;
974 } else
975 break;
977 needsort++;
980 #endif
982 #if defined(BSD43_BSD43_NFS) || defined(sun)
983 /* some libc's out there are bound internally to these names (UMIPS) */
984 void
985 ht_sethostent(stayopen)
986 int stayopen;
988 _sethtent(stayopen);
991 void
992 ht_endhostent()
994 _endhtent();
997 struct hostent *
998 ht_gethostbyname(name)
999 char *name;
1001 return (_gethtbyname(name));
1004 struct hostent *
1005 ht_gethostbyaddr(addr, len, af)
1006 const char *addr;
1007 int len, af;
1009 return (_gethtbyaddr(addr, len, af));
1012 struct hostent *
1013 gethostent()
1015 return (_gethtent());
1018 void
1019 dns_service()
1021 return;
1024 #undef dn_skipname
1025 dn_skipname(comp_dn, eom)
1026 const u_char *comp_dn, *eom;
1028 return (__dn_skipname(comp_dn, eom));
1030 #endif /*old-style libc with yp junk in it*/