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