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