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