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