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