Use __transparent_union__ instead of transparent_union.
[kopensolaris-gnu/glibc.git] / resolv / gethnamaddr.c
1 /*
2  * ++Copyright++ 1985, 1988, 1993
3  * -
4  * Copyright (c) 1985, 1988, 1993
5  *    The Regents of the University of California.  All rights reserved.
6  *
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.
22  *
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.
36  *
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.
43  *
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--
54  */
55
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 */
60
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>
67
68 #include <stdio.h>
69 #include <netdb.h>
70 #include <resolv.h>
71 #include <ctype.h>
72 #include <errno.h>
73 #include <syslog.h>
74
75 #ifndef LOG_AUTH
76 # define LOG_AUTH 0
77 #endif
78
79 #define MULTI_PTRS_ARE_ALIASES 1        /* XXX - experimental */
80
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
87
88 #if defined(USE_OPTIONS_H)
89 # include <../conf/options.h>
90 #endif
91
92 #ifdef SPRINTF_CHAR
93 # define SPRINTF(x) strlen(sprintf/**/x)
94 #else
95 # define SPRINTF(x) ((size_t)sprintf x)
96 #endif
97
98 #define MAXALIASES      35
99 #define MAXADDRS        35
100
101 static const char AskedForGot[] =
102                           "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
103
104 static char *h_addr_ptrs[MAXADDRS + 1];
105
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;
112
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));
115
116 #ifdef RESOLVSORT
117 static void addrsort __P((char **, int));
118 #endif
119
120 #if PACKETSZ > 1024
121 #define MAXPACKET       PACKETSZ
122 #else
123 #define MAXPACKET       1024
124 #endif
125
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
131
132 typedef union {
133     HEADER hdr;
134     u_char buf[MAXPACKET];
135 } querybuf;
136
137 typedef union {
138     int32_t al;
139     char ac;
140 } align;
141
142 #ifndef h_errno
143 extern int h_errno;
144 #endif
145
146 #ifdef DEBUG
147 static void
148 dprintf(msg, num)
149         char *msg;
150         int num;
151 {
152         if (_res.options & RES_DEBUG) {
153                 int save = errno;
154
155                 printf(msg, num);
156                 __set_errno (save);
157         }
158 }
159 #else
160 # define dprintf(msg, num) /*nada*/
161 #endif
162
163 static struct hostent *
164 getanswer(answer, anslen, qname, qtype)
165         const querybuf *answer;
166         int anslen;
167         const char *qname;
168         int qtype;
169 {
170         register const HEADER *hp;
171         register const u_char *cp;
172         register int n;
173         const u_char *eom;
174         char *bp, **ap, **hap;
175         int type, class, buflen, ancount, qdcount;
176         int haveanswer, had_error;
177         int toobig = 0;
178         char tbuf[MAXDNAME];
179         const char *tname;
180         int (*name_ok) __P((const char *));
181
182         tname = qname;
183         host.h_name = NULL;
184         eom = answer->buf + anslen;
185         switch (qtype) {
186         case T_A:
187         case T_AAAA:
188                 name_ok = res_hnok;
189                 break;
190         case T_PTR:
191                 name_ok = res_dnok;
192                 break;
193         default:
194                 return (NULL);  /* XXX should be abort(); */
195         }
196         /*
197          * find first satisfactory answer
198          */
199         hp = &answer->hdr;
200         ancount = ntohs(hp->ancount);
201         qdcount = ntohs(hp->qdcount);
202         bp = hostbuf;
203         buflen = sizeof hostbuf;
204         cp = answer->buf + HFIXEDSZ;
205         if (qdcount != 1) {
206                 __set_h_errno (NO_RECOVERY);
207                 return (NULL);
208         }
209         n = dn_expand(answer->buf, eom, cp, bp, buflen);
210         if ((n < 0) || !(*name_ok)(bp)) {
211                 __set_h_errno (NO_RECOVERY);
212                 return (NULL);
213         }
214         cp += n + QFIXEDSZ;
215         if (qtype == T_A || qtype == T_AAAA) {
216                 /* res_send() has already verified that the query name is the
217                  * same as the one we sent; this just gets the expanded name
218                  * (i.e., with the succeeding search-domain tacked on).
219                  */
220                 n = strlen(bp) + 1;             /* for the \0 */
221                 if (n >= MAXHOSTNAMELEN) {
222                         __set_h_errno (NO_RECOVERY);
223                         return (NULL);
224                 }
225                 host.h_name = bp;
226                 bp += n;
227                 buflen -= n;
228                 /* The qname can be abbreviated, but h_name is now absolute. */
229                 qname = host.h_name;
230         }
231         ap = host_aliases;
232         *ap = NULL;
233         host.h_aliases = host_aliases;
234         hap = h_addr_ptrs;
235         *hap = NULL;
236         host.h_addr_list = h_addr_ptrs;
237         haveanswer = 0;
238         had_error = 0;
239         while (ancount-- > 0 && cp < eom && !had_error) {
240                 n = dn_expand(answer->buf, eom, cp, bp, buflen);
241                 if ((n < 0) || !(*name_ok)(bp)) {
242                         had_error++;
243                         continue;
244                 }
245                 cp += n;                        /* name */
246                 type = _getshort(cp);
247                 cp += INT16SZ;                  /* type */
248                 class = _getshort(cp);
249                 cp += INT16SZ + INT32SZ;        /* class, TTL */
250                 n = _getshort(cp);
251                 cp += INT16SZ;                  /* len */
252                 if (class != C_IN) {
253                         /* XXX - debug? syslog? */
254                         cp += n;
255                         continue;               /* XXX - had_error++ ? */
256                 }
257                 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
258                         if (ap >= &host_aliases[MAXALIASES-1])
259                                 continue;
260                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
261                         if ((n < 0) || !(*name_ok)(tbuf)) {
262                                 had_error++;
263                                 continue;
264                         }
265                         cp += n;
266                         /* Store alias. */
267                         *ap++ = bp;
268                         n = strlen(bp) + 1;     /* for the \0 */
269                         if (n >= MAXHOSTNAMELEN) {
270                                 had_error++;
271                                 continue;
272                         }
273                         bp += n;
274                         buflen -= n;
275                         /* Get canonical name. */
276                         n = strlen(tbuf) + 1;   /* for the \0 */
277                         if (n > buflen || n >= MAXHOSTNAMELEN) {
278                                 had_error++;
279                                 continue;
280                         }
281                         strcpy(bp, tbuf);
282                         host.h_name = bp;
283                         bp += n;
284                         buflen -= n;
285                         continue;
286                 }
287                 if (qtype == T_PTR && type == T_CNAME) {
288                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
289                         if (n < 0 || !res_hnok(tbuf)) {
290                                 had_error++;
291                                 continue;
292                         }
293                         cp += n;
294                         /* Get canonical name. */
295                         n = strlen(tbuf) + 1;   /* for the \0 */
296                         if (n > buflen || n >= MAXHOSTNAMELEN) {
297                                 had_error++;
298                                 continue;
299                         }
300                         strcpy(bp, tbuf);
301                         tname = bp;
302                         bp += n;
303                         buflen -= n;
304                         continue;
305                 }
306                 if (type != qtype) {
307                         syslog(LOG_NOTICE|LOG_AUTH,
308                "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
309                                qname, p_class(C_IN), p_type(qtype),
310                                p_type(type));
311                         cp += n;
312                         continue;               /* XXX - had_error++ ? */
313                 }
314                 switch (type) {
315                 case T_PTR:
316                         if (strcasecmp(tname, bp) != 0) {
317                                 syslog(LOG_NOTICE|LOG_AUTH,
318                                        AskedForGot, qname, bp);
319                                 cp += n;
320                                 continue;       /* XXX - had_error++ ? */
321                         }
322                         n = dn_expand(answer->buf, eom, cp, bp, buflen);
323                         if ((n < 0) || !res_hnok(bp)) {
324                                 had_error++;
325                                 break;
326                         }
327 #if MULTI_PTRS_ARE_ALIASES
328                         cp += n;
329                         if (!haveanswer)
330                                 host.h_name = bp;
331                         else if (ap < &host_aliases[MAXALIASES-1])
332                                 *ap++ = bp;
333                         else
334                                 n = -1;
335                         if (n != -1) {
336                                 n = strlen(bp) + 1;     /* for the \0 */
337                                 if (n >= MAXHOSTNAMELEN) {
338                                         had_error++;
339                                         break;
340                                 }
341                                 bp += n;
342                                 buflen -= n;
343                         }
344                         break;
345 #else
346                         host.h_name = bp;
347                         if (_res.options & RES_USE_INET6) {
348                                 n = strlen(bp) + 1;     /* for the \0 */
349                                 if (n >= MAXHOSTNAMELEN) {
350                                         had_error++;
351                                         break;
352                                 }
353                                 bp += n;
354                                 buflen -= n;
355                                 map_v4v6_hostent(&host, &bp, &buflen);
356                         }
357                         __set_h_errno (NETDB_SUCCESS);
358                         return (&host);
359 #endif
360                 case T_A:
361                 case T_AAAA:
362                         if (strcasecmp(host.h_name, bp) != 0) {
363                                 syslog(LOG_NOTICE|LOG_AUTH,
364                                        AskedForGot, host.h_name, bp);
365                                 cp += n;
366                                 continue;       /* XXX - had_error++ ? */
367                         }
368                         if (n != host.h_length) {
369                                 cp += n;
370                                 continue;
371                         }
372                         if (!haveanswer) {
373                                 register int nn;
374
375                                 host.h_name = bp;
376                                 nn = strlen(bp) + 1;    /* for the \0 */
377                                 bp += nn;
378                                 buflen -= nn;
379                         }
380
381                         bp += sizeof(align) - ((u_long)bp % sizeof(align));
382
383                         if (bp + n >= &hostbuf[sizeof hostbuf]) {
384                                 dprintf("size (%d) too big\n", n);
385                                 had_error++;
386                                 continue;
387                         }
388                         if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
389                                 if (!toobig++) {
390                                         dprintf("Too many addresses (%d)\n",
391                                                 MAXADDRS);
392                                 }
393                                 cp += n;
394                                 continue;
395                         }
396                         bcopy(cp, *hap++ = bp, n);
397                         bp += n;
398                         buflen -= n;
399                         cp += n;
400                         break;
401                 default:
402                         abort();
403                 }
404                 if (!had_error)
405                         haveanswer++;
406         }
407         if (haveanswer) {
408                 *ap = NULL;
409                 *hap = NULL;
410 # if defined(RESOLVSORT)
411                 /*
412                  * Note: we sort even if host can take only one address
413                  * in its return structures - should give it the "best"
414                  * address in that case, not some random one
415                  */
416                 if (_res.nsort && haveanswer > 1 && qtype == T_A)
417                         addrsort(h_addr_ptrs, haveanswer);
418 # endif /*RESOLVSORT*/
419                 if (!host.h_name) {
420                         n = strlen(qname) + 1;  /* for the \0 */
421                         if (n > buflen || n >= MAXHOSTNAMELEN)
422                                 goto no_recovery;
423                         strcpy(bp, qname);
424                         host.h_name = bp;
425                         bp += n;
426                         buflen -= n;
427                 }
428                 if (_res.options & RES_USE_INET6)
429                         map_v4v6_hostent(&host, &bp, &buflen);
430                 __set_h_errno (NETDB_SUCCESS);
431                 return (&host);
432         }
433  no_recovery:
434         __set_h_errno (NO_RECOVERY);
435         return (NULL);
436 }
437
438 struct hostent *
439 gethostbyname(name)
440         const char *name;
441 {
442         struct hostent *hp;
443
444         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
445                 __set_h_errno (NETDB_INTERNAL);
446                 return (NULL);
447        }
448         if (_res.options & RES_USE_INET6) {
449                 hp = gethostbyname2(name, AF_INET6);
450                 if (hp)
451                         return (hp);
452         }
453         return (gethostbyname2(name, AF_INET));
454 }
455
456 struct hostent *
457 gethostbyname2(name, af)
458         const char *name;
459         int af;
460 {
461         querybuf buf;
462         register const char *cp;
463         char *bp;
464         int n, size, type, len;
465         extern struct hostent *_gethtbyname2();
466
467         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
468                 __set_h_errno (NETDB_INTERNAL);
469                 return (NULL);
470         }
471
472         switch (af) {
473         case AF_INET:
474                 size = INADDRSZ;
475                 type = T_A;
476                 break;
477         case AF_INET6:
478                 size = IN6ADDRSZ;
479                 type = T_AAAA;
480                 break;
481         default:
482                 __set_h_errno (NETDB_INTERNAL);
483                 __set_errno (EAFNOSUPPORT);
484                 return (NULL);
485         }
486
487         host.h_addrtype = af;
488         host.h_length = size;
489
490         /*
491          * if there aren't any dots, it could be a user-level alias.
492          * this is also done in res_query() since we are not the only
493          * function that looks up host names.
494          */
495         if (!strchr(name, '.') && (cp = __hostalias(name)))
496                 name = cp;
497
498         /*
499          * disallow names consisting only of digits/dots, unless
500          * they end in a dot.
501          */
502         if (isdigit(name[0]))
503                 for (cp = name;; ++cp) {
504                         if (!*cp) {
505                                 if (*--cp == '.')
506                                         break;
507                                 /*
508                                  * All-numeric, no dot at the end.
509                                  * Fake up a hostent as if we'd actually
510                                  * done a lookup.
511                                  */
512                                 if (inet_pton(af, name, host_addr) <= 0) {
513                                         __set_h_errno (HOST_NOT_FOUND);
514                                         return (NULL);
515                                 }
516                                 strncpy(hostbuf, name, MAXDNAME);
517                                 hostbuf[MAXDNAME] = '\0';
518                                 bp = hostbuf + MAXDNAME;
519                                 len = sizeof hostbuf - MAXDNAME;
520                                 host.h_name = hostbuf;
521                                 host.h_aliases = host_aliases;
522                                 host_aliases[0] = NULL;
523                                 h_addr_ptrs[0] = (char *)host_addr;
524                                 h_addr_ptrs[1] = NULL;
525                                 host.h_addr_list = h_addr_ptrs;
526                                 if (_res.options & RES_USE_INET6)
527                                         map_v4v6_hostent(&host, &bp, &len);
528                                 __set_h_errno (NETDB_SUCCESS);
529                                 return (&host);
530                         }
531                         if (!isdigit(*cp) && *cp != '.')
532                                 break;
533                }
534         if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
535             name[0] == ':')
536                 for (cp = name;; ++cp) {
537                         if (!*cp) {
538                                 if (*--cp == '.')
539                                         break;
540                                 /*
541                                  * All-IPv6-legal, no dot at the end.
542                                  * Fake up a hostent as if we'd actually
543                                  * done a lookup.
544                                  */
545                                 if (inet_pton(af, name, host_addr) <= 0) {
546                                         __set_h_errno (HOST_NOT_FOUND);
547                                         return (NULL);
548                                 }
549                                 strncpy(hostbuf, name, MAXDNAME);
550                                 hostbuf[MAXDNAME] = '\0';
551                                 bp = hostbuf + MAXDNAME;
552                                 len = sizeof hostbuf - MAXDNAME;
553                                 host.h_name = hostbuf;
554                                 host.h_aliases = host_aliases;
555                                 host_aliases[0] = NULL;
556                                 h_addr_ptrs[0] = (char *)host_addr;
557                                 h_addr_ptrs[1] = NULL;
558                                 host.h_addr_list = h_addr_ptrs;
559                                 __set_h_errno (NETDB_SUCCESS);
560                                 return (&host);
561                         }
562                         if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
563                                 break;
564                 }
565
566         if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf.buf))) < 0) {
567                 dprintf("res_search failed (%d)\n", n);
568                 if (errno == ECONNREFUSED)
569                         return (_gethtbyname2(name, af));
570                 return (NULL);
571         }
572         return (getanswer(&buf, n, name, type));
573 }
574
575 struct hostent *
576 gethostbyaddr(addr, len, af)
577         const char *addr;       /* XXX should have been def'd as u_char! */
578         int len, af;
579 {
580         const u_char *uaddr = (const u_char *)addr;
581         static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
582         static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
583         int n, size;
584         querybuf buf;
585         register struct hostent *hp;
586         char qbuf[MAXDNAME+1], *qp;
587 #ifdef SUNSECURITY
588         register struct hostent *rhp;
589         char **haddr;
590         u_long old_options;
591         char hname2[MAXDNAME+1];
592 #endif /*SUNSECURITY*/
593         extern struct hostent *_gethtbyaddr();
594
595         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
596                 __set_h_errno (NETDB_INTERNAL);
597                 return (NULL);
598         }
599         if (af == AF_INET6 && len == IN6ADDRSZ &&
600             (!bcmp(uaddr, mapped, sizeof mapped) ||
601              !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
602                 /* Unmap. */
603                 addr += sizeof mapped;
604                 uaddr += sizeof mapped;
605                 af = AF_INET;
606                 len = INADDRSZ;
607         }
608         switch (af) {
609         case AF_INET:
610                 size = INADDRSZ;
611                 break;
612         case AF_INET6:
613                 size = IN6ADDRSZ;
614                 break;
615         default:
616                 __set_errno (EAFNOSUPPORT);
617                 __set_h_errno (NETDB_INTERNAL);
618                 return (NULL);
619         }
620         if (size != len) {
621                 __set_errno (EINVAL);
622                 __set_h_errno (NETDB_INTERNAL);
623                 return (NULL);
624         }
625         switch (af) {
626         case AF_INET:
627                 (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
628                                (uaddr[3] & 0xff),
629                                (uaddr[2] & 0xff),
630                                (uaddr[1] & 0xff),
631                                (uaddr[0] & 0xff));
632                 break;
633         case AF_INET6:
634                 qp = qbuf;
635                 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
636                         qp += SPRINTF((qp, "%x.%x.",
637                                        uaddr[n] & 0xf,
638                                        (uaddr[n] >> 4) & 0xf));
639                 }
640                 strcpy(qp, "ip6.int");
641                 break;
642         default:
643                 abort();
644         }
645         n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
646         if (n < 0) {
647                 dprintf("res_query failed (%d)\n", n);
648                 if (errno == ECONNREFUSED)
649                         return (_gethtbyaddr(addr, len, af));
650                 return (NULL);
651         }
652         if (!(hp = getanswer(&buf, n, qbuf, T_PTR)))
653                 return (NULL);  /* h_errno was set by getanswer() */
654 #ifdef SUNSECURITY
655         if (af == AF_INET) {
656             /*
657              * turn off search as the name should be absolute,
658              * 'localhost' should be matched by defnames
659              */
660             strncpy(hname2, hp->h_name, MAXDNAME);
661             hname2[MAXDNAME] = '\0';
662             old_options = _res.options;
663             _res.options &= ~RES_DNSRCH;
664             _res.options |= RES_DEFNAMES;
665             if (!(rhp = gethostbyname(hname2))) {
666                 syslog(LOG_NOTICE|LOG_AUTH,
667                        "gethostbyaddr: No A record for %s (verifying [%s])",
668                        hname2, inet_ntoa(*((struct in_addr *)addr)));
669                 _res.options = old_options;
670                 __set_h_errno (HOST_NOT_FOUND);
671                 return (NULL);
672             }
673             _res.options = old_options;
674             for (haddr = rhp->h_addr_list; *haddr; haddr++)
675                 if (!memcmp(*haddr, addr, INADDRSZ))
676                         break;
677             if (!*haddr) {
678                 syslog(LOG_NOTICE|LOG_AUTH,
679                        "gethostbyaddr: A record of %s != PTR record [%s]",
680                        hname2, inet_ntoa(*((struct in_addr *)addr)));
681                 __set_h_errno (HOST_NOT_FOUND);
682                 return (NULL);
683             }
684         }
685 #endif /*SUNSECURITY*/
686         hp->h_addrtype = af;
687         hp->h_length = len;
688         bcopy(addr, host_addr, len);
689         h_addr_ptrs[0] = (char *)host_addr;
690         h_addr_ptrs[1] = NULL;
691         if (af == AF_INET && (_res.options & RES_USE_INET6)) {
692                 map_v4v6_address((char*)host_addr, (char*)host_addr);
693                 hp->h_addrtype = AF_INET6;
694                 hp->h_length = IN6ADDRSZ;
695         }
696         __set_h_errno (NETDB_SUCCESS);
697         return (hp);
698 }
699
700 void
701 _sethtent(f)
702         int f;
703 {
704         if (!hostf)
705                 hostf = fopen(_PATH_HOSTS, "r" );
706         else
707                 rewind(hostf);
708         stayopen = f;
709 }
710
711 void
712 _endhtent()
713 {
714         if (hostf && !stayopen) {
715                 (void) fclose(hostf);
716                 hostf = NULL;
717         }
718 }
719
720 struct hostent *
721 _gethtent()
722 {
723         char *p;
724         register char *cp, **q;
725         int af, len;
726
727         if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
728                 __set_h_errno (NETDB_INTERNAL);
729                 return (NULL);
730         }
731  again:
732         if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
733                 __set_h_errno (HOST_NOT_FOUND);
734                 return (NULL);
735         }
736         if (*p == '#')
737                 goto again;
738         if (!(cp = strpbrk(p, "#\n")))
739                 goto again;
740         *cp = '\0';
741         if (!(cp = strpbrk(p, " \t")))
742                 goto again;
743         *cp++ = '\0';
744         if (inet_pton(AF_INET6, p, host_addr) > 0) {
745                 af = AF_INET6;
746                 len = IN6ADDRSZ;
747         } else if (inet_pton(AF_INET, p, host_addr) > 0) {
748                 if (_res.options & RES_USE_INET6) {
749                         map_v4v6_address((char*)host_addr, (char*)host_addr);
750                         af = AF_INET6;
751                         len = IN6ADDRSZ;
752                 } else {
753                         af = AF_INET;
754                         len = INADDRSZ;
755                 }
756         } else {
757                 goto again;
758         }
759         h_addr_ptrs[0] = (char *)host_addr;
760         h_addr_ptrs[1] = NULL;
761         host.h_addr_list = h_addr_ptrs;
762         host.h_length = len;
763         host.h_addrtype = af;
764         while (*cp == ' ' || *cp == '\t')
765                 cp++;
766         host.h_name = cp;
767         q = host.h_aliases = host_aliases;
768         if (cp = strpbrk(cp, " \t"))
769                 *cp++ = '\0';
770         while (cp && *cp) {
771                 if (*cp == ' ' || *cp == '\t') {
772                         cp++;
773                         continue;
774                 }
775                 if (q < &host_aliases[MAXALIASES - 1])
776                         *q++ = cp;
777                 if (cp = strpbrk(cp, " \t"))
778                         *cp++ = '\0';
779         }
780         *q = NULL;
781         __set_h_errno (NETDB_SUCCESS);
782         return (&host);
783 }
784
785 struct hostent *
786 _gethtbyname(name)
787         const char *name;
788 {
789         extern struct hostent *_gethtbyname2();
790         struct hostent *hp;
791
792         if (_res.options & RES_USE_INET6) {
793                 hp = _gethtbyname2(name, AF_INET6);
794                 if (hp)
795                         return (hp);
796         }
797         return (_gethtbyname2(name, AF_INET));
798 }
799
800 struct hostent *
801 _gethtbyname2(name, af)
802         const char *name;
803         int af;
804 {
805         register struct hostent *p;
806         register char **cp;
807
808         _sethtent(0);
809         while (p = _gethtent()) {
810                 if (p->h_addrtype != af)
811                         continue;
812                 if (strcasecmp(p->h_name, name) == 0)
813                         break;
814                 for (cp = p->h_aliases; *cp != 0; cp++)
815                         if (strcasecmp(*cp, name) == 0)
816                                 goto found;
817         }
818  found:
819         _endhtent();
820         return (p);
821 }
822
823 struct hostent *
824 _gethtbyaddr(addr, len, af)
825         const char *addr;
826         int len, af;
827 {
828         register struct hostent *p;
829
830         _sethtent(0);
831         while (p = _gethtent())
832                 if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
833                         break;
834         _endhtent();
835         return (p);
836 }
837
838 static void
839 map_v4v6_address(src, dst)
840         const char *src;
841         char *dst;
842 {
843         u_char *p = (u_char *)dst;
844         char tmp[INADDRSZ];
845         int i;
846
847         /* Stash a temporary copy so our caller can update in place. */
848         bcopy(src, tmp, INADDRSZ);
849         /* Mark this ipv6 addr as a mapped ipv4. */
850         for (i = 0; i < 10; i++)
851                 *p++ = 0x00;
852         *p++ = 0xff;
853         *p++ = 0xff;
854         /* Retrieve the saved copy and we're done. */
855         bcopy(tmp, (void*)p, INADDRSZ);
856 }
857
858 static void
859 map_v4v6_hostent(hp, bpp, lenp)
860         struct hostent *hp;
861         char **bpp;
862         int *lenp;
863 {
864         char **ap;
865
866         if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
867                 return;
868         hp->h_addrtype = AF_INET6;
869         hp->h_length = IN6ADDRSZ;
870         for (ap = hp->h_addr_list; *ap; ap++) {
871                 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
872
873                 if (*lenp < (i + IN6ADDRSZ)) {
874                         /* Out of memory.  Truncate address list here.  XXX */
875                         *ap = NULL;
876                         return;
877                 }
878                 *bpp += i;
879                 *lenp -= i;
880                 map_v4v6_address(*ap, *bpp);
881                 *ap = *bpp;
882                 *bpp += IN6ADDRSZ;
883                 *lenp -= IN6ADDRSZ;
884         }
885 }
886
887 #ifdef RESOLVSORT
888 static void
889 addrsort(ap, num)
890         char **ap;
891         int num;
892 {
893         int i, j;
894         char **p;
895         short aval[MAXADDRS];
896         int needsort = 0;
897
898         p = ap;
899         for (i = 0; i < num; i++, p++) {
900             for (j = 0 ; (unsigned)j < _res.nsort; j++)
901                 if (_res.sort_list[j].addr.s_addr ==
902                     (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
903                         break;
904             aval[i] = j;
905             if (needsort == 0 && i > 0 && j < aval[i-1])
906                 needsort = i;
907         }
908         if (!needsort)
909             return;
910
911         while (needsort < num) {
912             for (j = needsort - 1; j >= 0; j--) {
913                 if (aval[j] > aval[j+1]) {
914                     char *hp;
915
916                     i = aval[j];
917                     aval[j] = aval[j+1];
918                     aval[j+1] = i;
919
920                     hp = ap[j];
921                     ap[j] = ap[j+1];
922                     ap[j+1] = hp;
923
924                 } else
925                     break;
926             }
927             needsort++;
928         }
929 }
930 #endif
931
932 #if defined(BSD43_BSD43_NFS) || defined(sun)
933 /* some libc's out there are bound internally to these names (UMIPS) */
934 void
935 ht_sethostent(stayopen)
936         int stayopen;
937 {
938         _sethtent(stayopen);
939 }
940
941 void
942 ht_endhostent()
943 {
944         _endhtent();
945 }
946
947 struct hostent *
948 ht_gethostbyname(name)
949         char *name;
950 {
951         return (_gethtbyname(name));
952 }
953
954 struct hostent *
955 ht_gethostbyaddr(addr, len, af)
956         const char *addr;
957         int len, af;
958 {
959         return (_gethtbyaddr(addr, len, af));
960 }
961
962 struct hostent *
963 gethostent()
964 {
965         return (_gethtent());
966 }
967
968 void
969 dns_service()
970 {
971         return;
972 }
973
974 #undef dn_skipname
975 dn_skipname(comp_dn, eom)
976         const u_char *comp_dn, *eom;
977 {
978         return (__dn_skipname(comp_dn, eom));
979 }
980 #endif /*old-style libc with yp junk in it*/