Sat Jun 15 18:13:43 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[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/param.h>
62 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
65 #include <arpa/nameser.h>
66
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <unistd.h>
70 #include <netdb.h>
71 #include <resolv.h>
72 #include <ctype.h>
73 #include <errno.h>
74 #include <syslog.h>
75
76 #include "res_hconf.h"
77
78 #ifndef LOG_AUTH
79 # define LOG_AUTH 0
80 #endif
81
82 #define MULTI_PTRS_ARE_ALIASES 1        /* XXX - experimental */
83
84 #if defined(BSD) && (BSD >= 199103) && defined(AF_INET6)
85 # include <string.h>
86 #else
87 # include "../conf/portability.h"
88 #endif
89 #if defined(USE_OPTIONS_H)
90 # include <../conf/options.h>
91 #endif
92
93 #ifdef SPRINTF_CHAR
94 # define SPRINTF(x) strlen(sprintf/**/x)
95 #else
96 # define SPRINTF(x) sprintf x
97 #endif
98
99 #define MAXALIASES      35
100 #define MAXADDRS        35
101 #define MAXADDRBUFSIZE  8192
102
103 static const char AskedForGot[] =
104                           "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
105
106 static char *h_addr_ptrs[MAXADDRS + 1];
107 static struct hostent *gethostbyname_ipv4 __P((const char *));
108
109 static struct hostent host;
110 static char *host_aliases[MAXALIASES];
111 static char hostbuf[MAXADDRBUFSIZE];
112 static u_char host_addr[16];    /* IPv4 or IPv6 */
113 static FILE *hostf = NULL;
114 static int stayopen = 0;
115
116 static void map_v4v6_address __P((const char *src, char *dst));
117 static void map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len));
118
119 #ifdef RESOLVSORT
120 static void addrsort __P((char **, int));
121 #endif
122
123 #if PACKETSZ > 1024
124 #define MAXPACKET       PACKETSZ
125 #else
126 #define MAXPACKET       1024
127 #endif
128
129 typedef union {
130     HEADER hdr;
131     u_char buf[MAXPACKET];
132 } querybuf;
133
134 typedef union {
135     int32_t al;
136     char ac;
137 } align;
138
139 extern int h_errno;
140
141 #ifdef DEBUG
142 static void
143 dprintf(msg, num)
144         char *msg;
145         int num;
146 {
147         if (_res.options & RES_DEBUG) {
148                 int save = errno;
149
150                 printf(msg, num);
151                 errno = save;
152         }
153 }
154 #else
155 # define dprintf(msg, num) /*nada*/
156 #endif
157
158 static struct hostent *
159 getanswer(answer, anslen, qname, qtype)
160         const querybuf *answer;
161         int anslen;
162         const char *qname;
163         int qtype;
164 {
165         register const HEADER *hp;
166         register const u_char *cp;
167         register int n;
168         const u_char *eom;
169         char *bp, **ap, **hap;
170         int type, class, buflen, ancount, qdcount;
171         int haveanswer, had_error;
172         int toobig = 0;
173         char tbuf[MAXDNAME+1];
174         const char *tname;
175         int (*name_ok) __P((const char *));
176
177         tname = qname;
178         host.h_name = NULL;
179         eom = answer->buf + anslen;
180         switch (qtype) {
181         case T_A:
182         case T_AAAA:
183                 name_ok = res_hnok;
184                 break;
185         case T_PTR:
186                 name_ok = res_dnok;
187                 break;
188         default:
189                 return (NULL);  /* XXX should be abort(); */
190         }
191         /*
192          * find first satisfactory answer
193          */
194         hp = &answer->hdr;
195         ancount = ntohs(hp->ancount);
196         qdcount = ntohs(hp->qdcount);
197         bp = hostbuf;
198         buflen = sizeof hostbuf;
199         cp = answer->buf + HFIXEDSZ;
200         if (qdcount != 1) {
201                 h_errno = NO_RECOVERY;
202                 return (NULL);
203         }
204         n = dn_expand(answer->buf, eom, cp, bp, buflen);
205         if ((n < 0) || !(*name_ok)(bp)) {
206                 h_errno = NO_RECOVERY;
207                 return (NULL);
208         }
209         cp += n + QFIXEDSZ;
210         if (qtype == T_A || qtype == T_AAAA) {
211                 /* res_send() has already verified that the query name is the
212                  * same as the one we sent; this just gets the expanded name
213                  * (i.e., with the succeeding search-domain tacked on).
214                  */
215                 n = strlen(bp) + 1;             /* for the \0 */
216                 host.h_name = bp;
217                 bp += n;
218                 buflen -= n;
219                 /* The qname can be abbreviated, but h_name is now absolute. */
220                 qname = host.h_name;
221         }
222         ap = host_aliases;
223         *ap = NULL;
224         host.h_aliases = host_aliases;
225         hap = h_addr_ptrs;
226         *hap = NULL;
227         host.h_addr_list = h_addr_ptrs;
228         haveanswer = 0;
229         had_error = 0;
230         while (ancount-- > 0 && cp < eom && !had_error) {
231                 n = dn_expand(answer->buf, eom, cp, bp, buflen);
232                 if ((n < 0) || !(*name_ok)(bp)) {
233                         had_error++;
234                         continue;
235                 }
236                 cp += n;                        /* name */
237                 type = _getshort(cp);
238                 cp += INT16SZ;                  /* type */
239                 class = _getshort(cp);
240                 cp += INT16SZ + INT32SZ;        /* class, TTL */
241                 n = _getshort(cp);
242                 cp += INT16SZ;                  /* len */
243                 if (class != C_IN) {
244                         /* XXX - debug? syslog? */
245                         cp += n;
246                         continue;               /* XXX - had_error++ ? */
247                 }
248                 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
249                         if (ap >= &host_aliases[MAXALIASES-1])
250                                 continue;
251                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
252                         if ((n < 0) || !(*name_ok)(tbuf)) {
253                                 had_error++;
254                                 continue;
255                         }
256                         cp += n;
257                         /* Store alias. */
258                         *ap++ = bp;
259                         n = strlen(bp) + 1;     /* for the \0 */
260                         bp += n;
261                         buflen -= n;
262                         /* Get canonical name. */
263                         n = strlen(tbuf) + 1;   /* for the \0 */
264                         if (n > buflen) {
265                                 had_error++;
266                                 continue;
267                         }
268                         strcpy(bp, tbuf);
269                         host.h_name = bp;
270                         bp += n;
271                         buflen -= n;
272                         continue;
273                 }
274                 if (qtype == T_PTR && type == T_CNAME) {
275                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
276                         if ((n < 0) || !res_hnok(tbuf)) {
277                                 had_error++;
278                                 continue;
279                         }
280                         cp += n;
281                         /* Get canonical name. */
282                         n = strlen(tbuf) + 1;   /* for the \0 */
283                         if (n > buflen) {
284                                 had_error++;
285                                 continue;
286                         }
287                         strcpy(bp, tbuf);
288                         tname = bp;
289                         bp += n;
290                         buflen -= n;
291                         continue;
292                 }
293                 if (type != qtype) {
294                         syslog(LOG_NOTICE|LOG_AUTH,
295                "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
296                                qname, p_class(C_IN), p_type(qtype),
297                                p_type(type));
298                         cp += n;
299                         continue;               /* XXX - had_error++ ? */
300                 }
301                 switch (type) {
302                 case T_PTR:
303                         if (strcasecmp(tname, bp) != 0) {
304                                 syslog(LOG_NOTICE|LOG_AUTH,
305                                        AskedForGot, qname, bp);
306                                 cp += n;
307                                 continue;       /* XXX - had_error++ ? */
308                         }
309                         n = dn_expand(answer->buf, eom, cp, bp, buflen);
310                         if ((n < 0) || !res_hnok(bp)) {
311                                 had_error++;
312                                 break;
313                         }
314 #if MULTI_PTRS_ARE_ALIASES
315                         cp += n;
316                         if (!haveanswer)
317                                 host.h_name = bp;
318                         else if (ap < &host_aliases[MAXALIASES-1])
319                                 *ap++ = bp;
320                         else
321                                 n = -1;
322                         if (n != -1) {
323                                 n = strlen(bp) + 1;     /* for the \0 */
324                                 bp += n;
325                                 buflen -= n;
326                         }
327                         break;
328 #else
329                         host.h_name = bp;
330                         if (_res.options & RES_USE_INET6) {
331                                 n = strlen(bp) + 1;     /* for the \0 */
332                                 bp += n;
333                                 buflen -= n;
334                                 map_v4v6_hostent(&host, &bp, &buflen);
335                         }
336                         h_errno = NETDB_SUCCESS;
337                         return (&host);
338 #endif
339                 case T_A:
340                 case T_AAAA:
341                         if (strcasecmp(host.h_name, bp) != 0) {
342                                 syslog(LOG_NOTICE|LOG_AUTH,
343                                        AskedForGot, host.h_name, bp);
344                                 cp += n;
345                                 continue;       /* XXX - had_error++ ? */
346                         }
347                         if (haveanswer) {
348                                 if (n != host.h_length) {
349                                         cp += n;
350                                         continue;
351                                 }
352                         } else {
353                                 register int nn;
354
355                                 host.h_name = bp;
356                                 nn = strlen(bp) + 1;    /* for the \0 */
357                                 bp += nn;
358                                 buflen -= nn;
359                         }
360
361                         bp += sizeof(align) - ((u_long)bp % sizeof(align));
362
363                         if (bp + n >= &hostbuf[sizeof hostbuf]) {
364                                 dprintf("size (%d) too big\n", n);
365                                 had_error++;
366                                 continue;
367                         }
368                         if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
369                                 if (!toobig++)
370                                         dprintf("Too many addresses (%d)\n",
371                                                 MAXADDRS);
372                                 cp += n;
373                                 continue;
374                         }
375                         bcopy(cp, *hap++ = bp, n);
376                         bp += n;
377                         cp += n;
378                         break;
379                 default:
380                         abort();
381                 }
382                 if (!had_error)
383                         haveanswer++;
384         }
385         if (haveanswer) {
386                 *ap = NULL;
387                 *hap = NULL;
388 # if defined(RESOLVSORT)
389                 /*
390                  * Note: we sort even if host can take only one address
391                  * in its return structures - should give it the "best"
392                  * address in that case, not some random one
393                  */
394                 if (_res.nsort && haveanswer > 1 && qtype == T_A)
395                         addrsort(h_addr_ptrs, haveanswer);
396 # endif /*RESOLVSORT*/
397                 if (!host.h_name) {
398                         n = strlen(qname) + 1;  /* for the \0 */
399                         if (n > buflen)
400                                 goto try_again;
401                         strcpy(bp, qname);
402                         host.h_name = bp;
403                         bp += n;
404                         buflen -= n;
405                 }
406                 if (_res.options & RES_USE_INET6)
407                         map_v4v6_hostent(&host, &bp, &buflen);
408                 h_errno = NETDB_SUCCESS;
409                 return (&host);
410         }
411  try_again:
412         h_errno = TRY_AGAIN;
413         return (NULL);
414 }
415
416 struct hostent *
417 gethostbyname(name)
418         const char *name;
419 {
420         struct hostent *hp;
421
422         if (_res.options & RES_USE_INET6) {
423                 hp = gethostbyname2(name, AF_INET6);
424                 if (hp)
425                         return (hp);
426         }
427         return (gethostbyname2(name, AF_INET));
428 }
429
430 struct hostent *
431 gethostbyname2(name, af)
432         const char *name;
433         int af;
434 {
435         querybuf buf;
436         register const char *cp;
437         char *bp;
438         int i, n, size, type, len;
439         extern struct hostent *_gethtbyname2();
440
441         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
442                 h_errno = NETDB_INTERNAL;
443                 return (NULL);
444         }
445
446         switch (af) {
447         case AF_INET:
448                 size = INADDRSZ;
449                 type = T_A;
450                 break;
451         case AF_INET6:
452                 size = IN6ADDRSZ;
453                 type = T_AAAA;
454                 break;
455         default:
456                 h_errno = NETDB_INTERNAL;
457                 errno = EAFNOSUPPORT;
458                 return (NULL);
459         }
460
461         host.h_addrtype = af;
462         host.h_length = size;
463
464         /*
465          * if there aren't any dots, it could be a user-level alias.
466          * this is also done in res_query() since we are not the only
467          * function that looks up host names.
468          */
469         if (!strchr(name, '.') && (cp = __hostalias(name)))
470                 name = cp;
471
472         /*
473          * disallow names consisting only of digits/dots, unless
474          * they end in a dot.
475          */
476         if (isdigit(name[0]))
477                 for (cp = name;; ++cp) {
478                         if (!*cp) {
479                                 if (*--cp == '.')
480                                         break;
481                                 /*
482                                  * All-numeric, no dot at the end.
483                                  * Fake up a hostent as if we'd actually
484                                  * done a lookup.
485                                  */
486                                 if (inet_pton(af, name, host_addr) <= 0) {
487                                         h_errno = HOST_NOT_FOUND;
488                                         return (NULL);
489                                 }
490                                 strncpy(hostbuf, name, MAXDNAME);
491                                 hostbuf[MAXDNAME] = '\0';
492                                 bp = hostbuf + MAXDNAME;
493                                 len = sizeof hostbuf - MAXDNAME;
494                                 host.h_name = hostbuf;
495                                 host.h_aliases = host_aliases;
496                                 host_aliases[0] = NULL;
497                                 h_addr_ptrs[0] = (char *)host_addr;
498                                 h_addr_ptrs[1] = NULL;
499                                 host.h_addr_list = h_addr_ptrs;
500                                 if (_res.options & RES_USE_INET6)
501                                         map_v4v6_hostent(&host, &bp, &len);
502                                 h_errno = NETDB_SUCCESS;
503                                 return (&host);
504                         }
505                         if (!isdigit(*cp) && *cp != '.')
506                                 break;
507                 }
508
509         h_errno = HOST_NOT_FOUND;
510         for (i = 0; i < _res_hconf.num_services; ++i) {
511                 struct hostent * hp;
512                 char * cp = (char *) name;
513
514                 if (_res_hconf.num_trimdomains > 0) {
515                         size_t name_len = strlen(name);
516
517                         cp = malloc(name_len + 1);
518                         memcpy(cp, name, name_len + 1);
519                         _res_hconf_trim_domain(cp);
520                 }
521
522                 hp = NULL;
523                 switch (_res_hconf.service[i]) {
524                       case SERVICE_BIND:
525                         if ((n = res_search(cp, C_IN, type,
526                                             buf.buf, sizeof(buf))) < 0)
527                         {
528                                 dprintf("res_search failed (%d)\n", n);
529                                 break;
530                         }
531                         hp = getanswer(&buf, n, cp, type);
532                         break;
533
534                       case SERVICE_HOSTS:
535                         hp = _gethtbyname2(cp, af);
536                         break;
537 #ifdef HAVE_NYS
538                       case SERVICE_NIS:
539                         hp = _getnishost(cp, "hosts.byname");
540                         break;
541 #endif
542                       default:
543                         break;
544                 }
545                 if (cp != name)
546                         free(cp);
547                 if (hp) {
548                         if ((_res_hconf.flags & HCONF_FLAG_REORDER)
549                             && hp->h_addr_list[0] && hp->h_addr_list[1])
550                                 _res_hconf_reorder_addrs(hp);
551                         _res_hconf_trim_domains(hp);
552                         return hp;
553                 }
554         }
555         if (h_errno == NETDB_SUCCESS)
556                 h_errno = HOST_NOT_FOUND;
557         return NULL;
558 }
559
560 struct hostent *
561 gethostbyaddr(addr, len, af)
562         const char *addr;       /* XXX should have been def'd as u_char! */
563         int len, af;
564 {
565         const u_char *uaddr = (const u_char *)addr;
566         static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
567         static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
568         int n, size;
569         querybuf buf;
570         register struct hostent *hp;
571         char qbuf[MAXDNAME+1], *qp;
572         register struct hostent *rhp;
573         char **haddr;
574         u_long old_options;
575         char hname2[MAXDNAME+1];
576         int i, old_num_trimdomains;
577         extern struct hostent *_gethtbyaddr();
578
579         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
580                 h_errno = NETDB_INTERNAL;
581                 return (NULL);
582         }
583         if (af == AF_INET6 && len == IN6ADDRSZ &&
584             (!bcmp(uaddr, mapped, sizeof mapped) ||
585              !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
586                 /* Unmap. */
587                 addr += sizeof mapped;
588                 uaddr += sizeof mapped;
589                 af = AF_INET;
590                 len = INADDRSZ;
591         }
592         switch (af) {
593         case AF_INET:
594                 size = INADDRSZ;
595                 break;
596         case AF_INET6:
597                 size = IN6ADDRSZ;
598                 break;
599         default:
600                 errno = EAFNOSUPPORT;
601                 h_errno = NETDB_INTERNAL;
602                 return (NULL);
603         }
604         if (size != len) {
605                 errno = EINVAL;
606                 h_errno = NETDB_INTERNAL;
607                 return (NULL);
608         }
609
610         h_errno = NETDB_SUCCESS;
611         for (i = 0; i < _res_hconf.num_services; ++i) {
612                 hp = NULL;
613                 switch (_res_hconf.service[i]) {
614                 case SERVICE_BIND:
615                         switch (af) {
616                         case AF_INET:
617                                 (void) sprintf(qbuf,
618                                                "%u.%u.%u.%u.in-addr.arpa",
619                                                (uaddr[3] & 0xff),
620                                                (uaddr[2] & 0xff),
621                                                (uaddr[1] & 0xff),
622                                                (uaddr[0] & 0xff));
623                                 break;
624                         case AF_INET6:
625                                 qp = qbuf;
626                                 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
627                                         qp += SPRINTF((qp, "%x.%x.",
628                                                        uaddr[n] & 0xf,
629                                                        (uaddr[n] >> 4) & 0xf));
630                                 }
631                                 strcpy(qp, "ip6.int");
632                                 break;
633                         default:
634                                 abort();
635                         }
636                         n = res_query(qbuf, C_IN, T_PTR,
637                                       (u_char *)buf.buf, sizeof buf.buf);
638                         if (n < 0) {
639                                 dprintf("res_query failed (%d)\n", n);
640                                 break;
641                         }
642                         hp = getanswer(&buf, n, qbuf, T_PTR);
643                         if (!hp)
644                                 break;  /* h_errno was set by getanswer() */
645                         if (af == AF_INET
646                             && (_res_hconf.flags & HCONF_FLAG_SPOOF)) {
647                                 /*
648                                  * Turn off search as the name should
649                                  * be absolute, 'localhost' should be
650                                  * matched by defnames
651                                  */
652                                 strncpy(hname2, hp->h_name, MAXDNAME);
653                                 hname2[MAXDNAME] = '\0';
654                                 old_options = _res.options;
655                                 /*
656                                  * Also turn off domain trimming to prevent it
657                                  * from causing the name comparison to fail.
658                                  */
659                                 old_num_trimdomains =
660                                         _res_hconf.num_trimdomains;
661                                 _res.options &= ~RES_DNSRCH;
662                                 _res.options |= RES_DEFNAMES;
663                                 rhp = gethostbyname(hname2);
664                                 _res.options = old_options;
665                                 /* There must be an A record and
666                                    the names must match.  */
667                                 if (!rhp || strcmp(hname2, rhp->h_name)) {
668                                         syslog(LOG_NOTICE|LOG_AUTH,
669                                                "gethostbyaddr: No A record for"
670                                                " %s (verifying [%s])",
671                                                hname2,
672                                                inet_ntoa(*((struct in_addr *)
673                                                            addr)));
674                                         h_errno = HOST_NOT_FOUND;
675                                         break;
676                                 }
677                                 for (haddr = rhp->h_addr_list; *haddr; haddr++)
678                                         if (!memcmp(*haddr, addr, INADDRSZ))
679                                                 break;
680                                 if (!*haddr) {
681                                         syslog(LOG_NOTICE|LOG_AUTH,
682                                                "gethostbyaddr: A record of %s"
683                                                " != PTR record [%s]",
684                                                hname2,
685                                                inet_ntoa(*((struct in_addr *)
686                                                            addr)));
687                                         h_errno = HOST_NOT_FOUND;
688                                         break;
689                                 }
690                         }
691                         hp->h_addrtype = af;
692                         hp->h_length = len;
693                         bcopy(addr, host_addr, len);
694                         h_addr_ptrs[0] = (char *)host_addr;
695                         h_addr_ptrs[1] = NULL;
696                         if (af == AF_INET && (_res.options & RES_USE_INET6)) {
697                                 map_v4v6_address((char*)host_addr,
698                                                  (char*)host_addr);
699                                 hp->h_addrtype = AF_INET6;
700                                 hp->h_length = IN6ADDRSZ;
701                         }
702                         h_errno = NETDB_SUCCESS;
703                         break;
704
705                 case SERVICE_HOSTS:
706                         hp = _gethtbyaddr(addr, len, af);
707                         break;
708
709 #ifdef HAVE_NYS
710                 case SERVICE_NIS:
711                         if (af == AF_INET) {
712                                 sprintf(qbuf, "%u.%u.%u.%u",
713                                         (unsigned)addr[0] & 0xff,
714                                         (unsigned)addr[1] & 0xff,
715                                         (unsigned)addr[2] & 0xff,
716                                         (unsigned)addr[3] & 0xff);
717                                 hp = _getnishost(qbuf, "hosts.byaddr");
718                         }
719                         break;
720 #endif
721
722                 default:
723                         break;
724                 }
725                 if (hp) {
726                         _res_hconf_trim_domains(hp);
727                         return hp;
728                 }
729         }
730         if (h_errno == NETDB_SUCCESS)
731                 h_errno = HOST_NOT_FOUND;
732         return NULL;
733 }
734
735 void
736 _sethtent(f)
737         int f;
738 {
739         if (!hostf)
740                 hostf = fopen(_PATH_HOSTS, "r" );
741         else
742                 rewind(hostf);
743         stayopen = f;
744 }
745
746 void
747 _endhtent()
748 {
749         if (hostf && !stayopen) {
750                 (void) fclose(hostf);
751                 hostf = NULL;
752         }
753 }
754
755 struct hostent *
756 _gethtent()
757 {
758         char *p;
759         register char *cp, **q;
760         int af, len;
761
762         if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
763                 h_errno = NETDB_INTERNAL;
764                 return (NULL);
765         }
766  again:
767         if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
768                 h_errno = HOST_NOT_FOUND;
769                 return (NULL);
770         }
771         if (*p == '#')
772                 goto again;
773         if (!(cp = strpbrk(p, "#\n")))
774                 goto again;
775         *cp = '\0';
776         if (!(cp = strpbrk(p, " \t")))
777                 goto again;
778         *cp++ = '\0';
779         if ((_res.options & RES_USE_INET6) &&
780             inet_pton(AF_INET6, p, host_addr) > 0) {
781                 af = AF_INET6;
782                 len = IN6ADDRSZ;
783         } else if (inet_pton(AF_INET, p, host_addr) > 0) {
784                 if (_res.options & RES_USE_INET6) {
785                         map_v4v6_address((char*)host_addr, (char*)host_addr);
786                         af = AF_INET6;
787                         len = IN6ADDRSZ;
788                 } else {
789                         af = AF_INET;
790                         len = INADDRSZ;
791                 }
792         } else {
793                 goto again;
794         }
795         h_addr_ptrs[0] = (char *)host_addr;
796         h_addr_ptrs[1] = NULL;
797         host.h_addr_list = h_addr_ptrs;
798         host.h_length = len;
799         host.h_addrtype = af;
800         while (*cp == ' ' || *cp == '\t')
801                 cp++;
802         host.h_name = cp;
803         q = host.h_aliases = host_aliases;
804         if (cp = strpbrk(cp, " \t"))
805                 *cp++ = '\0';
806         while (cp && *cp) {
807                 if (*cp == ' ' || *cp == '\t') {
808                         cp++;
809                         continue;
810                 }
811                 if (q < &host_aliases[MAXALIASES - 1])
812                         *q++ = cp;
813                 if (cp = strpbrk(cp, " \t"))
814                         *cp++ = '\0';
815         }
816         *q = NULL;
817         if (_res.options & RES_USE_INET6) {
818                 char *bp = hostbuf;
819                 int buflen = sizeof hostbuf;
820
821                 map_v4v6_hostent(&host, &bp, &buflen);
822         }
823         h_errno = NETDB_SUCCESS;
824         return (&host);
825 }
826
827 struct hstorage {
828         char    *name;                          /* canonical name */
829         char ** alp;                            /* address list pointer */
830         char *  abp;                            /* address buffer pointer */
831         char *  addr_list[MAXADDRS + 1];        /* address list storage */
832         char    addr_buf[MAXADDRBUFSIZE];       /* addresses storage */
833 };
834
835 static void
836 append_addr (struct hstorage * hs, struct hostent *p)
837 {
838         if (hs->alp < hs->addr_list + MAXADDRS
839             && hs->abp + p->h_length < hs->addr_buf + MAXADDRBUFSIZE)
840         {
841                 hs->alp[0] = hs->abp;
842                 hs->alp[1] = 0;
843                 memcpy(hs->abp, p->h_addr_list[0], p->h_length);
844                 hs->abp += p->h_length;
845                 ++hs->alp;
846         }
847 }
848
849 /*
850  * Lookup IP address and aliases for host NAME.  If multiaddress mode
851  * is enabled, the entire /etc/hosts file is searched and the union of
852  * all addresses found for NAME is returned (this may be slow with
853  * large /etc/hosts files, but is convenient for smallish sites that
854  * don't want to go through the complexity of running named locally).
855  * If multiaddress mode is enabled, the address returned in
856  * h_addr_list[0] is one that is on the same net as one of the host's
857  * local addresses (if such an address exists).  For compatibility
858  * with the BIND version of gethostbyname(), the alias field is empty
859  * unless the name being looked up is an alias itself.  In the latter
860  * case, the name field contains the canonical name and the alias
861  * field the name that is being looked up.  A difference from the BIND
862  * version is that this is true even if the alias applies only to one
863  * of the interfaces on the target host.o
864  */
865 struct hostent *
866 _gethtbyname(name)
867         const char *name;
868 {
869         extern struct hostent *_gethtbyname2();
870         struct hostent *hp;
871
872         if (_res.options & RES_USE_INET6) {
873                 hp = _gethtbyname2(name, AF_INET6);
874                 if (hp)
875                         return (hp);
876         }
877         return (_gethtbyname2(name, AF_INET));
878 }
879
880 struct hostent *
881 _gethtbyname2(name, af)
882         const char *name;
883         int af;
884 {
885         register struct hostent *p;
886         register char **cp;
887
888         _sethtent(0);
889
890         if (_res_hconf.flags & HCONF_FLAG_MULTI) {
891                 /*
892                  * More statics; not pretty, but it would require
893                  * interface changes to make these functions
894                  * reentrant.
895                  */
896                 static char *aliases[2] = {0};
897                 static struct hstorage self = {0}, target = {0};
898                 static size_t self_name_size = 0; /* Allocated in self.name. */
899                 static struct hostent ht;
900                 int found;
901
902                 if (aliases[0])
903                         free (aliases[0]);      /* Malloced in a prev call.  */
904                 aliases[0] = aliases[1] = 0;
905
906                 /* Get current host name in a large enough buffer.  */
907                 do {
908                            errno = 0;
909
910                            if (self.name)
911                            {
912                                    self_name_size += self_name_size;
913                                    self.name =
914                                            realloc (self.name, self_name_size);
915                            } else {
916                                    self_name_size = 128; /* Initial guess */
917                                    self.name = malloc (self_name_size);
918                            }
919
920                            if (! self.name)
921                            {
922                                    errno = ENOMEM;
923                                    return 0;
924                            }
925                    } while ((gethostname(self.name, self_name_size) == 0
926                              && !memchr (self.name, '\0', self_name_size))
927                             || errno == ENAMETOOLONG);
928                 
929                 if (errno)
930                         /* gethostname failed, abort.  */
931                 {
932                         free (self.name);
933                         self.name = 0;
934                 }
935
936                 self.alp = self.addr_list;
937                 self.abp = self.addr_buf;
938
939                 if (target.name)
940                         free (target.name);
941                 target.name = strdup (name);
942
943                 target.alp = target.addr_list;
944                 target.abp = target.addr_buf;
945
946                 _sethtent(0);
947                 while ((p = _gethtent()) != 0) {
948                         found = 1;
949
950                         if (p->h_addrtype != af)
951                                 continue;
952                         if (strcasecmp(p->h_name, name) != 0) {
953                                 found = 0;
954                                 for (cp = p->h_aliases; *cp; ++cp)
955                                         if (strcasecmp(*cp, name) == 0) {
956                                                 found = 1;
957                                                 if (!aliases[0]) {
958                                                         aliases[0] =
959                                                           target.name;
960                                                         target.name =
961                                                           strdup (p->h_name);
962                                                 }
963                                                 break;
964                                         }
965                         }
966                         if (found) {
967                                 /* they better be all the same type and length! */
968                                 ht.h_addrtype = p->h_addrtype;
969                                 ht.h_length = p->h_length;
970                                 append_addr(&target, p);
971                                 /*
972                                  * If the current hostentry is for the target host, we don't
973                                  * check for the local host name.  This nicely optimizes the
974                                  * case where NAME is a local name since address ordering
975                                  * doesn't matter in that case.
976                                  */
977                                 continue;
978                         }
979                         found = 1;
980                         if (strcasecmp(p->h_name, self.name) != 0) {
981                                 found = 0;
982                                 for (cp = p->h_aliases; *cp; ++cp)
983                                         if (strcasecmp(*cp, self.name) == 0) {
984                                                 found = 1;
985                                                 break;
986                                         }
987                         }
988                         if (found) {
989                                 append_addr(&self, p);
990                         }
991                 }
992                 _endhtent();
993
994                 if (target.alp == target.addr_list)
995                         return NULL;            /* found nothing */
996
997                 ht.h_aliases   = aliases;
998                 ht.h_name      = target.name;
999                 ht.h_addr_list = target.addr_list;
1000                 /*
1001                  * XXX (davidm) Isn't this subsumed by REORDER???
1002                  *
1003                  * Finding the `best' address is necessarily address
1004                  * specific.  For now, we do IPv4 addresses only.
1005                  */
1006                 if (af == AF_INET) {
1007                         u_int32_t a1, a2, diff, mindiff = ~0;
1008                         int i, j, bestaddr = 0;
1009
1010                         for (i = 0; self.addr_list[i]; ++i) {
1011                                 for (j = 0; target.addr_list[j]; ++j) {
1012                                         memcpy(&a1, self.addr_list[i], 4);
1013                                         memcpy(&a2, target.addr_list[j], 4);
1014                                         a1 = ntohl(a1);
1015                                         a2 = ntohl(a2);
1016                                         diff = a1 ^ a2;
1017                                         if (diff < mindiff) {
1018                                                 bestaddr = j;
1019                                                 mindiff = diff;
1020                                         }
1021                                 }
1022                         }
1023                         if (bestaddr > 0) {
1024                                 char * tmp;
1025
1026                                 tmp = target.addr_list[0];
1027                                 target.addr_list[0] = target.addr_list[bestaddr];
1028                                 target.addr_list[bestaddr] = tmp;
1029                         }
1030                 } else if (af == AF_INET6) {
1031                         /* XXX To do!!! */
1032                 }
1033                 ht.h_addr_list = target.addr_list;
1034                 return &ht;
1035         } else {
1036                 _sethtent(0);
1037                 while (p = _gethtent()) {
1038                         if (p->h_addrtype != af)
1039                                 continue;
1040                         if (strcasecmp(p->h_name, name) == 0)
1041                                 break;
1042                         for (cp = p->h_aliases; *cp != 0; cp++)
1043                                 if (strcasecmp(*cp, name) == 0)
1044                                         goto found;
1045                 }
1046         }
1047  found:
1048         _endhtent();
1049         return (p);
1050 }
1051
1052 struct hostent *
1053 _gethtbyaddr(addr, len, af)
1054         const char *addr;
1055         int len, af;
1056 {
1057         register struct hostent *p;
1058
1059         _sethtent(0);
1060         while (p = _gethtent())
1061                 if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
1062                         break;
1063         _endhtent();
1064         return (p);
1065 }
1066
1067 static void
1068 map_v4v6_address(src, dst)
1069         const char *src;
1070         char *dst;
1071 {
1072         u_char *p = (u_char *)dst;
1073         char tmp[INADDRSZ];
1074         int i;
1075
1076         /* Stash a temporary copy so our caller can update in place. */
1077         bcopy(src, tmp, INADDRSZ);
1078         /* Mark this ipv6 addr as a mapped ipv4. */
1079         for (i = 0; i < 10; i++)
1080                 *p++ = 0x00;
1081         *p++ = 0xff;
1082         *p++ = 0xff;
1083         /* Retrieve the saved copy and we're done. */
1084         bcopy(tmp, (void*)p, INADDRSZ);
1085 }
1086
1087 static void
1088 map_v4v6_hostent(hp, bpp, lenp)
1089         struct hostent *hp;
1090         char **bpp;
1091         int *lenp;
1092 {
1093         char **ap;
1094
1095         if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1096                 return;
1097         hp->h_addrtype = AF_INET6;
1098         hp->h_length = IN6ADDRSZ;
1099         for (ap = hp->h_addr_list; *ap; ap++) {
1100                 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
1101
1102                 if (*lenp < (i + IN6ADDRSZ)) {
1103                         /* Out of memory.  Truncate address list here.  XXX */
1104                         *ap = NULL;
1105                         return;
1106                 }
1107                 *bpp += i;
1108                 *lenp -= i;
1109                 map_v4v6_address(*ap, *bpp);
1110                 *ap = *bpp;
1111                 *bpp += IN6ADDRSZ;
1112                 *lenp -= IN6ADDRSZ;
1113         }
1114 }
1115
1116 #ifdef RESOLVSORT
1117 static void
1118 addrsort(ap, num)
1119         char **ap;
1120         int num;
1121 {
1122         int i, j;
1123         char **p;
1124         short aval[MAXADDRS];
1125         int needsort = 0;
1126
1127         p = ap;
1128         for (i = 0; i < num; i++, p++) {
1129             for (j = 0 ; (unsigned)j < _res.nsort; j++)
1130                 if (_res.sort_list[j].addr.s_addr ==
1131                     (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
1132                         break;
1133             aval[i] = j;
1134             if (needsort == 0 && i > 0 && j < aval[i-1])
1135                 needsort = i;
1136         }
1137         if (!needsort)
1138             return;
1139
1140         while (needsort < num) {
1141             for (j = needsort - 1; j >= 0; j--) {
1142                 if (aval[j] > aval[j+1]) {
1143                     char *hp;
1144
1145                     i = aval[j];
1146                     aval[j] = aval[j+1];
1147                     aval[j+1] = i;
1148
1149                     hp = ap[j];
1150                     ap[j] = ap[j+1];
1151                     ap[j+1] = hp;
1152
1153                 } else
1154                     break;
1155             }
1156             needsort++;
1157         }
1158 }
1159 #endif
1160
1161 #if defined(BSD43_BSD43_NFS) || defined(sun)
1162 /* some libc's out there are bound internally to these names (UMIPS) */
1163 void
1164 ht_sethostent(stayopen)
1165         int stayopen;
1166 {
1167         _sethtent(stayopen);
1168 }
1169
1170 void
1171 ht_endhostent()
1172 {
1173         _endhtent();
1174 }
1175
1176 struct hostent *
1177 ht_gethostbyname(name)
1178         char *name;
1179 {
1180         return (_gethtbyname(name));
1181 }
1182
1183 struct hostent *
1184 ht_gethostbyaddr(addr, len, af)
1185         const char *addr;
1186         int len, af;
1187 {
1188         return (_gethtbyaddr(addr, len, af));
1189 }
1190
1191 struct hostent *
1192 gethostent()
1193 {
1194         struct hostent * hp;
1195         int i;
1196
1197         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1198                 h_errno = NETDB_INTERNAL;
1199                 return (NULL);
1200         }
1201
1202         /*
1203          * This doesn't look quite right.  Shouldn't we read one
1204          * service until it returns 0, then move on to the next
1205          * service?  If so, it requires adding some state and
1206          * initializing that state in sethostent().
1207          * (davidm@azstarnet.com)
1208          */
1209         for (i = 0; i < _res_hconf.num_services; ++i) {
1210                 hp = NULL;
1211                 switch (_res_hconf.service[i]) {
1212                       case SERVICE_HOSTS:
1213                         hp = _gethtent ();
1214                         break;
1215
1216 #ifdef HAVE_NYS
1217                       case SERVICE_NIS:
1218                         hp = _getnishost (NULL, "hosts.byname");
1219                         break;
1220 #endif
1221
1222                       case SERVICE_BIND:
1223                       default:
1224                         break;
1225                 }
1226                 if (hp) {
1227                         if ((_res_hconf.flags & HCONF_FLAG_REORDER)
1228                             && hp->h_addr_list[0] && hp->h_addr_list[1])
1229                                 _res_hconf_reorder_addrs (hp);
1230                         return hp;
1231                 }
1232         }
1233         h_errno = HOST_NOT_FOUND;
1234         return NULL;
1235 }
1236
1237 void
1238 dns_service()
1239 {
1240         return;
1241 }
1242
1243 #undef dn_skipname
1244 dn_skipname(comp_dn, eom)
1245         const u_char *comp_dn, *eom;
1246 {
1247         return (__dn_skipname(comp_dn, eom));
1248 }
1249 #endif /*old-style libc with yp junk in it*/