Use thread safe resolver functions.
[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 = ns_get16(cp);
263                 cp += INT16SZ;                  /* type */
264                 class = ns_get16(cp);
265                 cp += INT16SZ + INT32SZ;        /* class, TTL */
266                 n = ns_get16(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                         /* XXX: when incrementing bp, we have to decrement
424                          * buflen by the same amount --okir */
425                         buflen -= sizeof(align) - ((u_long)bp % sizeof(align));
426
427                         bp += sizeof(align) - ((u_long)bp % sizeof(align));
428
429                         if (bp + n >= &hostbuf[sizeof hostbuf]) {
430                                 dprintf("size (%d) too big\n", n);
431                                 had_error++;
432                                 continue;
433                         }
434                         if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
435                                 if (!toobig++) {
436                                         dprintf("Too many addresses (%d)\n",
437                                                 MAXADDRS);
438                                 }
439                                 cp += n;
440                                 continue;
441                         }
442                         bcopy(cp, *hap++ = bp, n);
443                         bp += n;
444                         buflen -= n;
445                         cp += n;
446                         if (cp != erdata) {
447                                 __set_h_errno (NO_RECOVERY);
448                                 return (NULL);
449                         }
450                         break;
451                 default:
452                         abort();
453                 }
454                 if (!had_error)
455                         haveanswer++;
456         }
457         if (haveanswer) {
458                 *ap = NULL;
459                 *hap = NULL;
460 # if defined(RESOLVSORT)
461                 /*
462                  * Note: we sort even if host can take only one address
463                  * in its return structures - should give it the "best"
464                  * address in that case, not some random one
465                  */
466                 if (_res.nsort && haveanswer > 1 && qtype == T_A)
467                         addrsort(h_addr_ptrs, haveanswer);
468 # endif /*RESOLVSORT*/
469                 if (!host.h_name) {
470                         n = strlen(qname) + 1;  /* for the \0 */
471                         if (n > buflen || n >= MAXHOSTNAMELEN)
472                                 goto no_recovery;
473                         strcpy(bp, qname);
474                         host.h_name = bp;
475                         bp += n;
476                         buflen -= n;
477                 }
478                 if (_res.options & RES_USE_INET6)
479                         map_v4v6_hostent(&host, &bp, &buflen);
480                 __set_h_errno (NETDB_SUCCESS);
481                 return (&host);
482         }
483  no_recovery:
484         __set_h_errno (NO_RECOVERY);
485         return (NULL);
486 }
487
488 struct hostent *
489 gethostbyname(name)
490         const char *name;
491 {
492         struct hostent *hp;
493
494         if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) {
495                 __set_h_errno (NETDB_INTERNAL);
496                 return (NULL);
497        }
498         if (_res.options & RES_USE_INET6) {
499                 hp = gethostbyname2(name, AF_INET6);
500                 if (hp)
501                         return (hp);
502         }
503         return (gethostbyname2(name, AF_INET));
504 }
505
506 struct hostent *
507 gethostbyname2(name, af)
508         const char *name;
509         int af;
510 {
511         querybuf buf;
512         register const char *cp;
513         char *bp;
514         int n, size, type, len;
515         extern struct hostent *_gethtbyname2();
516
517         if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) {
518                 __set_h_errno (NETDB_INTERNAL);
519                 return (NULL);
520         }
521
522         switch (af) {
523         case AF_INET:
524                 size = INADDRSZ;
525                 type = T_A;
526                 break;
527         case AF_INET6:
528                 size = IN6ADDRSZ;
529                 type = T_AAAA;
530                 break;
531         default:
532                 __set_h_errno (NETDB_INTERNAL);
533                 __set_errno (EAFNOSUPPORT);
534                 return (NULL);
535         }
536
537         host.h_addrtype = af;
538         host.h_length = size;
539
540         /*
541          * if there aren't any dots, it could be a user-level alias.
542          * this is also done in res_query() since we are not the only
543          * function that looks up host names.
544          */
545         if (!strchr(name, '.') && (cp = __hostalias(name)))
546                 name = cp;
547
548         /*
549          * disallow names consisting only of digits/dots, unless
550          * they end in a dot.
551          */
552         if (isdigit(name[0]))
553                 for (cp = name;; ++cp) {
554                         if (!*cp) {
555                                 if (*--cp == '.')
556                                         break;
557                                 /*
558                                  * All-numeric, no dot at the end.
559                                  * Fake up a hostent as if we'd actually
560                                  * done a lookup.
561                                  */
562                                 if (inet_pton(af, name, host_addr) <= 0) {
563                                         __set_h_errno (HOST_NOT_FOUND);
564                                         return (NULL);
565                                 }
566                                 strncpy(hostbuf, name, MAXDNAME);
567                                 hostbuf[MAXDNAME] = '\0';
568                                 bp = hostbuf + MAXDNAME;
569                                 len = sizeof hostbuf - MAXDNAME;
570                                 host.h_name = hostbuf;
571                                 host.h_aliases = host_aliases;
572                                 host_aliases[0] = NULL;
573                                 h_addr_ptrs[0] = (char *)host_addr;
574                                 h_addr_ptrs[1] = NULL;
575                                 host.h_addr_list = h_addr_ptrs;
576                                 if (_res.options & RES_USE_INET6)
577                                         map_v4v6_hostent(&host, &bp, &len);
578                                 __set_h_errno (NETDB_SUCCESS);
579                                 return (&host);
580                         }
581                         if (!isdigit(*cp) && *cp != '.')
582                                 break;
583                }
584         if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
585             name[0] == ':')
586                 for (cp = name;; ++cp) {
587                         if (!*cp) {
588                                 if (*--cp == '.')
589                                         break;
590                                 /*
591                                  * All-IPv6-legal, no dot at the end.
592                                  * Fake up a hostent as if we'd actually
593                                  * done a lookup.
594                                  */
595                                 if (inet_pton(af, name, host_addr) <= 0) {
596                                         __set_h_errno (HOST_NOT_FOUND);
597                                         return (NULL);
598                                 }
599                                 strncpy(hostbuf, name, MAXDNAME);
600                                 hostbuf[MAXDNAME] = '\0';
601                                 bp = hostbuf + MAXDNAME;
602                                 len = sizeof hostbuf - MAXDNAME;
603                                 host.h_name = hostbuf;
604                                 host.h_aliases = host_aliases;
605                                 host_aliases[0] = NULL;
606                                 h_addr_ptrs[0] = (char *)host_addr;
607                                 h_addr_ptrs[1] = NULL;
608                                 host.h_addr_list = h_addr_ptrs;
609                                 __set_h_errno (NETDB_SUCCESS);
610                                 return (&host);
611                         }
612                         if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
613                                 break;
614                 }
615
616         if ((n = res_nsearch(&_res, name, C_IN, type, buf.buf, sizeof(buf.buf))) < 0) {
617                 dprintf("res_nsearch failed (%d)\n", n);
618                 if (errno == ECONNREFUSED)
619                         return (_gethtbyname2(name, af));
620                 return (NULL);
621         }
622         return (getanswer(&buf, n, name, type));
623 }
624
625 struct hostent *
626 gethostbyaddr(addr, len, af)
627         const char *addr;       /* XXX should have been def'd as u_char! */
628         size_t len;
629         int af;
630 {
631         const u_char *uaddr = (const u_char *)addr;
632         static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
633         static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
634         int n, size;
635         querybuf buf;
636         register struct hostent *hp;
637         char qbuf[MAXDNAME+1], *qp;
638 #ifdef SUNSECURITY
639         register struct hostent *rhp;
640         char **haddr;
641         u_long old_options;
642         char hname2[MAXDNAME+1];
643 #endif /*SUNSECURITY*/
644         extern struct hostent *_gethtbyaddr();
645
646         if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) {
647                 __set_h_errno (NETDB_INTERNAL);
648                 return (NULL);
649         }
650         if (af == AF_INET6 && len == IN6ADDRSZ &&
651             (!bcmp(uaddr, mapped, sizeof mapped) ||
652              !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
653                 /* Unmap. */
654                 addr += sizeof mapped;
655                 uaddr += sizeof mapped;
656                 af = AF_INET;
657                 len = INADDRSZ;
658         }
659         switch (af) {
660         case AF_INET:
661                 size = INADDRSZ;
662                 break;
663         case AF_INET6:
664                 size = IN6ADDRSZ;
665                 break;
666         default:
667                 __set_errno (EAFNOSUPPORT);
668                 __set_h_errno (NETDB_INTERNAL);
669                 return (NULL);
670         }
671         if (size != len) {
672                 __set_errno (EINVAL);
673                 __set_h_errno (NETDB_INTERNAL);
674                 return (NULL);
675         }
676         switch (af) {
677         case AF_INET:
678                 (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
679                                (uaddr[3] & 0xff),
680                                (uaddr[2] & 0xff),
681                                (uaddr[1] & 0xff),
682                                (uaddr[0] & 0xff));
683                 break;
684         case AF_INET6:
685                 qp = qbuf;
686                 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
687                         qp += SPRINTF((qp, "%x.%x.",
688                                        uaddr[n] & 0xf,
689                                        (uaddr[n] >> 4) & 0xf));
690                 }
691                 strcpy(qp, "ip6.int");
692                 break;
693         default:
694                 abort();
695         }
696         n = res_nquery(&_res, qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
697         if (n < 0) {
698                 dprintf("res_nquery failed (%d)\n", n);
699                 if (errno == ECONNREFUSED)
700                         return (_gethtbyaddr(addr, len, af));
701                 return (NULL);
702         }
703         if (!(hp = getanswer(&buf, n, qbuf, T_PTR)))
704                 return (NULL);  /* h_errno was set by getanswer() */
705 #ifdef SUNSECURITY
706         if (af == AF_INET) {
707             /*
708              * turn off search as the name should be absolute,
709              * 'localhost' should be matched by defnames
710              */
711             strncpy(hname2, hp->h_name, MAXDNAME);
712             hname2[MAXDNAME] = '\0';
713             old_options = _res.options;
714             _res.options &= ~RES_DNSRCH;
715             _res.options |= RES_DEFNAMES;
716             if (!(rhp = gethostbyname(hname2))) {
717                 syslog(LOG_NOTICE|LOG_AUTH,
718                        "gethostbyaddr: No A record for %s (verifying [%s])",
719                        hname2, inet_ntoa(*((struct in_addr *)addr)));
720                 _res.options = old_options;
721                 __set_h_errno (HOST_NOT_FOUND);
722                 return (NULL);
723             }
724             _res.options = old_options;
725             for (haddr = rhp->h_addr_list; *haddr; haddr++)
726                 if (!memcmp(*haddr, addr, INADDRSZ))
727                         break;
728             if (!*haddr) {
729                 syslog(LOG_NOTICE|LOG_AUTH,
730                        "gethostbyaddr: A record of %s != PTR record [%s]",
731                        hname2, inet_ntoa(*((struct in_addr *)addr)));
732                 __set_h_errno (HOST_NOT_FOUND);
733                 return (NULL);
734             }
735         }
736 #endif /*SUNSECURITY*/
737         hp->h_addrtype = af;
738         hp->h_length = len;
739         bcopy(addr, host_addr, len);
740         h_addr_ptrs[0] = (char *)host_addr;
741         h_addr_ptrs[1] = NULL;
742         if (af == AF_INET && (_res.options & RES_USE_INET6)) {
743                 map_v4v6_address((char*)host_addr, (char*)host_addr);
744                 hp->h_addrtype = AF_INET6;
745                 hp->h_length = IN6ADDRSZ;
746         }
747         __set_h_errno (NETDB_SUCCESS);
748         return (hp);
749 }
750
751 void
752 _sethtent(f)
753         int f;
754 {
755         if (!hostf)
756                 hostf = fopen(_PATH_HOSTS, "r" );
757         else
758                 rewind(hostf);
759         stayopen = f;
760 }
761
762 void
763 _endhtent()
764 {
765         if (hostf && !stayopen) {
766                 (void) fclose(hostf);
767                 hostf = NULL;
768         }
769 }
770
771 struct hostent *
772 _gethtent()
773 {
774         char *p;
775         register char *cp, **q;
776         int af, len;
777
778         if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
779                 __set_h_errno (NETDB_INTERNAL);
780                 return (NULL);
781         }
782  again:
783         if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
784                 __set_h_errno (HOST_NOT_FOUND);
785                 return (NULL);
786         }
787         if (*p == '#')
788                 goto again;
789         if (!(cp = strpbrk(p, "#\n")))
790                 goto again;
791         *cp = '\0';
792         if (!(cp = strpbrk(p, " \t")))
793                 goto again;
794         *cp++ = '\0';
795         if (inet_pton(AF_INET6, p, host_addr) > 0) {
796                 af = AF_INET6;
797                 len = IN6ADDRSZ;
798         } else if (inet_pton(AF_INET, p, host_addr) > 0) {
799                 if (_res.options & RES_USE_INET6) {
800                         map_v4v6_address((char*)host_addr, (char*)host_addr);
801                         af = AF_INET6;
802                         len = IN6ADDRSZ;
803                 } else {
804                         af = AF_INET;
805                         len = INADDRSZ;
806                 }
807         } else {
808                 goto again;
809         }
810         h_addr_ptrs[0] = (char *)host_addr;
811         h_addr_ptrs[1] = NULL;
812         host.h_addr_list = h_addr_ptrs;
813         host.h_length = len;
814         host.h_addrtype = af;
815         while (*cp == ' ' || *cp == '\t')
816                 cp++;
817         host.h_name = cp;
818         q = host.h_aliases = host_aliases;
819         if ((cp = strpbrk(cp, " \t")))
820                 *cp++ = '\0';
821         while (cp && *cp) {
822                 if (*cp == ' ' || *cp == '\t') {
823                         cp++;
824                         continue;
825                 }
826                 if (q < &host_aliases[MAXALIASES - 1])
827                         *q++ = cp;
828                 if ((cp = strpbrk(cp, " \t")))
829                         *cp++ = '\0';
830         }
831         *q = NULL;
832         __set_h_errno (NETDB_SUCCESS);
833         return (&host);
834 }
835
836 struct hostent *
837 _gethtbyname(name)
838         const char *name;
839 {
840         extern struct hostent *_gethtbyname2();
841         struct hostent *hp;
842
843         if (_res.options & RES_USE_INET6) {
844                 hp = _gethtbyname2(name, AF_INET6);
845                 if (hp)
846                         return (hp);
847         }
848         return (_gethtbyname2(name, AF_INET));
849 }
850
851 struct hostent *
852 _gethtbyname2(name, af)
853         const char *name;
854         int af;
855 {
856         register struct hostent *p;
857         register char **cp;
858
859         _sethtent(0);
860         while ((p = _gethtent())) {
861                 if (p->h_addrtype != af)
862                         continue;
863                 if (strcasecmp(p->h_name, name) == 0)
864                         break;
865                 for (cp = p->h_aliases; *cp != 0; cp++)
866                         if (strcasecmp(*cp, name) == 0)
867                                 goto found;
868         }
869  found:
870         _endhtent();
871         return (p);
872 }
873
874 struct hostent *
875 _gethtbyaddr(addr, len, af)
876         const char *addr;
877         size_t len;
878         int af;
879 {
880         register struct hostent *p;
881
882         _sethtent(0);
883         while ((p = _gethtent()))
884                 if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
885                         break;
886         _endhtent();
887         return (p);
888 }
889
890 static void
891 map_v4v6_address(src, dst)
892         const char *src;
893         char *dst;
894 {
895         u_char *p = (u_char *)dst;
896         char tmp[INADDRSZ];
897         int i;
898
899         /* Stash a temporary copy so our caller can update in place. */
900         bcopy(src, tmp, INADDRSZ);
901         /* Mark this ipv6 addr as a mapped ipv4. */
902         for (i = 0; i < 10; i++)
903                 *p++ = 0x00;
904         *p++ = 0xff;
905         *p++ = 0xff;
906         /* Retrieve the saved copy and we're done. */
907         bcopy(tmp, (void*)p, INADDRSZ);
908 }
909
910 static void
911 map_v4v6_hostent(hp, bpp, lenp)
912         struct hostent *hp;
913         char **bpp;
914         int *lenp;
915 {
916         char **ap;
917
918         if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
919                 return;
920         hp->h_addrtype = AF_INET6;
921         hp->h_length = IN6ADDRSZ;
922         for (ap = hp->h_addr_list; *ap; ap++) {
923                 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
924
925                 if (*lenp < (i + IN6ADDRSZ)) {
926                         /* Out of memory.  Truncate address list here.  XXX */
927                         *ap = NULL;
928                         return;
929                 }
930                 *bpp += i;
931                 *lenp -= i;
932                 map_v4v6_address(*ap, *bpp);
933                 *ap = *bpp;
934                 *bpp += IN6ADDRSZ;
935                 *lenp -= IN6ADDRSZ;
936         }
937 }
938
939 #ifdef RESOLVSORT
940 extern void
941 addrsort(ap, num)
942         char **ap;
943         int num;
944 {
945         int i, j;
946         char **p;
947         short aval[MAXADDRS];
948         int needsort = 0;
949
950         p = ap;
951         for (i = 0; i < num; i++, p++) {
952             for (j = 0 ; (unsigned)j < _res.nsort; j++)
953                 if (_res.sort_list[j].addr.s_addr ==
954                     (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
955                         break;
956             aval[i] = j;
957             if (needsort == 0 && i > 0 && j < aval[i-1])
958                 needsort = i;
959         }
960         if (!needsort)
961             return;
962
963         while (needsort < num) {
964             for (j = needsort - 1; j >= 0; j--) {
965                 if (aval[j] > aval[j+1]) {
966                     char *hp;
967
968                     i = aval[j];
969                     aval[j] = aval[j+1];
970                     aval[j+1] = i;
971
972                     hp = ap[j];
973                     ap[j] = ap[j+1];
974                     ap[j+1] = hp;
975
976                 } else
977                     break;
978             }
979             needsort++;
980         }
981 }
982 #endif
983
984 #if defined(BSD43_BSD43_NFS) || defined(sun)
985 /* some libc's out there are bound internally to these names (UMIPS) */
986 void
987 ht_sethostent(stayopen)
988         int stayopen;
989 {
990         _sethtent(stayopen);
991 }
992
993 void
994 ht_endhostent()
995 {
996         _endhtent();
997 }
998
999 struct hostent *
1000 ht_gethostbyname(name)
1001         char *name;
1002 {
1003         return (_gethtbyname(name));
1004 }
1005
1006 struct hostent *
1007 ht_gethostbyaddr(addr, len, af)
1008         const char *addr;
1009         size_t len;
1010         int af;
1011 {
1012         return (_gethtbyaddr(addr, len, af));
1013 }
1014
1015 struct hostent *
1016 gethostent()
1017 {
1018         return (_gethtent());
1019 }
1020
1021 void
1022 dns_service()
1023 {
1024         return;
1025 }
1026
1027 #undef dn_skipname
1028 dn_skipname(comp_dn, eom)
1029         const u_char *comp_dn, *eom;
1030 {
1031         return (__dn_skipname(comp_dn, eom));
1032 }
1033 #endif /*old-style libc with yp junk in it*/