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