Merge from vendor branch LESS:
[dragonfly.git] / lib / libc / net / gethostbydns.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. 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  * @(#)gethostnamadr.c  8.1 (Berkeley) 6/4/93
52  * $From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $
53  * $FreeBSD: src/lib/libc/net/gethostbydns.c,v 1.27.2.5 2002/11/02 18:54:57 ume Exp $
54  * $DragonFly: src/lib/libc/net/gethostbydns.c,v 1.6 2005/11/13 02:04:47 swildner Exp $
55  */
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 <stdlib.h>
66 #include <unistd.h>
67 #include <string.h>
68 #include <netdb.h>
69 #include <resolv.h>
70 #include <ctype.h>
71 #include <errno.h>
72 #include <syslog.h>
73
74 #include "res_config.h"
75
76 #define SPRINTF(x) ((size_t)sprintf x)
77
78 #define MAXALIASES      35
79 #define MAXADDRS        35
80
81 static const char AskedForGot[] =
82                 "gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
83
84 static char *h_addr_ptrs[MAXADDRS + 1];
85
86 static struct hostent host;
87 static char *host_aliases[MAXALIASES];
88 static char hostbuf[8*1024];
89 static u_char host_addr[16];    /* IPv4 or IPv6 */
90
91 #ifdef RESOLVSORT
92 static void addrsort (char **, int);
93 #endif
94
95 #define MAXPACKET       (64*1024)
96
97 typedef union {
98     HEADER hdr;
99     u_char buf[MAXPACKET];
100 } querybuf;
101
102 typedef union {
103     int32_t al;
104     char ac;
105 } align;
106
107 extern int h_errno;
108 int _dns_ttl_;
109
110 #ifdef DEBUG
111 static void
112 dprintf(char *msg, int num)
113 {
114         if (_res.options & RES_DEBUG) {
115                 int save = errno;
116
117                 printf(msg, num);
118                 errno = save;
119         }
120 }
121 #else
122 # define dprintf(msg, num) /*nada*/
123 #endif
124
125 #define BOUNDED_INCR(x) \
126         do { \
127                 cp += x; \
128                 if (cp > eom) { \
129                         h_errno = NO_RECOVERY; \
130                         return (NULL); \
131                 } \
132         } while (0)
133
134 #define BOUNDS_CHECK(ptr, count) \
135         do { \
136                 if ((ptr) + (count) > eom) { \
137                         h_errno = NO_RECOVERY; \
138                         return (NULL); \
139                 } \
140         } while (0)
141
142 static struct hostent *
143 gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
144 {
145         const HEADER *hp;
146         const u_char *cp;
147         int n;
148         const u_char *eom, *erdata;
149         char *bp, **ap, **hap;
150         int type, class, buflen, ancount, qdcount;
151         int haveanswer, had_error;
152         int toobig = 0;
153         char tbuf[MAXDNAME];
154         const char *tname;
155         int (*name_ok) (const char *);
156
157         tname = qname;
158         host.h_name = NULL;
159         eom = answer->buf + anslen;
160         switch (qtype) {
161         case T_A:
162         case T_AAAA:
163                 name_ok = res_hnok;
164                 break;
165         case T_PTR:
166                 name_ok = res_dnok;
167                 break;
168         default:
169                 h_errno = NO_RECOVERY;
170                 return (NULL);  /* XXX should be abort(); */
171         }
172         /*
173          * find first satisfactory answer
174          */
175         hp = &answer->hdr;
176         ancount = ntohs(hp->ancount);
177         qdcount = ntohs(hp->qdcount);
178         bp = hostbuf;
179         buflen = sizeof hostbuf;
180         cp = answer->buf;
181         BOUNDED_INCR(HFIXEDSZ);
182         if (qdcount != 1) {
183                 h_errno = NO_RECOVERY;
184                 return (NULL);
185         }
186         n = dn_expand(answer->buf, eom, cp, bp, buflen);
187         if ((n < 0) || !(*name_ok)(bp)) {
188                 h_errno = NO_RECOVERY;
189                 return (NULL);
190         }
191         BOUNDED_INCR(n + QFIXEDSZ);
192         if (qtype == T_A || qtype == T_AAAA) {
193                 /* res_send() has already verified that the query name is the
194                  * same as the one we sent; this just gets the expanded name
195                  * (i.e., with the succeeding search-domain tacked on).
196                  */
197                 n = strlen(bp) + 1;             /* for the \0 */
198                 if (n >= MAXHOSTNAMELEN) {
199                         h_errno = NO_RECOVERY;
200                         return (NULL);
201                 }
202                 host.h_name = bp;
203                 bp += n;
204                 buflen -= n;
205                 /* The qname can be abbreviated, but h_name is now absolute. */
206                 qname = host.h_name;
207         }
208         ap = host_aliases;
209         *ap = NULL;
210         host.h_aliases = host_aliases;
211         hap = h_addr_ptrs;
212         *hap = NULL;
213         host.h_addr_list = h_addr_ptrs;
214         haveanswer = 0;
215         had_error = 0;
216         _dns_ttl_ = -1;
217         while (ancount-- > 0 && cp < eom && !had_error) {
218                 n = dn_expand(answer->buf, eom, cp, bp, buflen);
219                 if ((n < 0) || !(*name_ok)(bp)) {
220                         had_error++;
221                         continue;
222                 }
223                 cp += n;                        /* name */
224                 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
225                 type = _getshort(cp);
226                 cp += INT16SZ;                  /* type */
227                 class = _getshort(cp);
228                 cp += INT16SZ;                  /* class */
229                 if (qtype == T_A  && type == T_A)
230                         _dns_ttl_ = _getlong(cp);
231                 cp += INT32SZ;                  /* TTL */
232                 n = _getshort(cp);
233                 cp += INT16SZ;                  /* len */
234                 BOUNDS_CHECK(cp, n);
235                 erdata = cp + n;
236                 if (class != C_IN) {
237                         /* XXX - debug? syslog? */
238                         cp += n;
239                         continue;               /* XXX - had_error++ ? */
240                 }
241                 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
242                         if (ap >= &host_aliases[MAXALIASES-1])
243                                 continue;
244                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
245                         if ((n < 0) || !(*name_ok)(tbuf)) {
246                                 had_error++;
247                                 continue;
248                         }
249                         cp += n;
250                         if (cp != erdata) {
251                                 h_errno = NO_RECOVERY;
252                                 return (NULL);
253                         }
254                         /* Store alias. */
255                         *ap++ = bp;
256                         n = strlen(bp) + 1;     /* for the \0 */
257                         if (n >= MAXHOSTNAMELEN) {
258                                 had_error++;
259                                 continue;
260                         }
261                         bp += n;
262                         buflen -= n;
263                         /* Get canonical name. */
264                         n = strlen(tbuf) + 1;   /* for the \0 */
265                         if (n > buflen || n >= MAXHOSTNAMELEN) {
266                                 had_error++;
267                                 continue;
268                         }
269                         strcpy(bp, tbuf);
270                         host.h_name = bp;
271                         bp += n;
272                         buflen -= n;
273                         continue;
274                 }
275                 if (qtype == T_PTR && type == T_CNAME) {
276                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
277                         if (n < 0 || !res_dnok(tbuf)) {
278                                 had_error++;
279                                 continue;
280                         }
281                         cp += n;
282                         if (cp != erdata) {
283                                 h_errno = NO_RECOVERY;
284                                 return (NULL);
285                         }
286                         /* Get canonical name. */
287                         n = strlen(tbuf) + 1;   /* for the \0 */
288                         if (n > buflen || n >= MAXHOSTNAMELEN) {
289                                 had_error++;
290                                 continue;
291                         }
292                         strcpy(bp, tbuf);
293                         tname = bp;
294                         bp += n;
295                         buflen -= n;
296                         continue;
297                 }
298                 if (type != qtype) {
299                         if (type != T_SIG)
300                                 syslog(LOG_NOTICE|LOG_AUTH,
301         "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"",
302                                        qname, p_class(C_IN), p_type(qtype),
303                                        p_type(type));
304                         cp += n;
305                         continue;               /* XXX - had_error++ ? */
306                 }
307                 switch (type) {
308                 case T_PTR:
309                         if (strcasecmp(tname, bp) != 0) {
310                                 syslog(LOG_NOTICE|LOG_AUTH,
311                                        AskedForGot, qname, bp);
312                                 cp += n;
313                                 continue;       /* XXX - had_error++ ? */
314                         }
315                         n = dn_expand(answer->buf, eom, cp, bp, buflen);
316                         if ((n < 0) || !res_hnok(bp)) {
317                                 had_error++;
318                                 break;
319                         }
320 #if MULTI_PTRS_ARE_ALIASES
321                         cp += n;
322                         if (cp != erdata) {
323                                 h_errno = NO_RECOVERY;
324                                 return (NULL);
325                         }
326                         if (!haveanswer)
327                                 host.h_name = bp;
328                         else if (ap < &host_aliases[MAXALIASES-1])
329                                 *ap++ = bp;
330                         else
331                                 n = -1;
332                         if (n != -1) {
333                                 n = strlen(bp) + 1;     /* for the \0 */
334                                 if (n >= MAXHOSTNAMELEN) {
335                                         had_error++;
336                                         break;
337                                 }
338                                 bp += n;
339                                 buflen -= n;
340                         }
341                         break;
342 #else
343                         host.h_name = bp;
344                         if (_res.options & RES_USE_INET6) {
345                                 n = strlen(bp) + 1;     /* for the \0 */
346                                 if (n >= MAXHOSTNAMELEN) {
347                                         had_error++;
348                                         break;
349                                 }
350                                 bp += n;
351                                 buflen -= n;
352                                 _map_v4v6_hostent(&host, &bp, &buflen);
353                         }
354                         h_errno = NETDB_SUCCESS;
355                         return (&host);
356 #endif
357                 case T_A:
358                 case T_AAAA:
359                         if (strcasecmp(host.h_name, bp) != 0) {
360                                 syslog(LOG_NOTICE|LOG_AUTH,
361                                        AskedForGot, host.h_name, bp);
362                                 cp += n;
363                                 continue;       /* XXX - had_error++ ? */
364                         }
365                         if (n != host.h_length) {
366                                 cp += n;
367                                 continue;
368                         }
369                         if (!haveanswer) {
370                                 int nn;
371
372                                 host.h_name = bp;
373                                 nn = strlen(bp) + 1;    /* for the \0 */
374                                 bp += nn;
375                                 buflen -= nn;
376                         }
377
378                         buflen -= sizeof(align) - ((u_long)bp % sizeof(align));
379                         bp += sizeof(align) - ((u_long)bp % sizeof(align));
380
381                         if (bp + n >= &hostbuf[sizeof hostbuf]) {
382                                 dprintf("size (%d) too big\n", n);
383                                 had_error++;
384                                 continue;
385                         }
386                         if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
387                                 if (!toobig++)
388                                         dprintf("Too many addresses (%d)\n",
389                                                 MAXADDRS);
390                                 cp += n;
391                                 continue;
392                         }
393                         bcopy(cp, *hap++ = bp, n);
394                         bp += n;
395                         buflen -= n;
396                         cp += n;
397                         if (cp != erdata) {
398                                 h_errno = NO_RECOVERY;
399                                 return (NULL);
400                         }
401                         break;
402                 default:
403                         dprintf("Impossible condition (type=%d)\n", type);
404                         h_errno = NO_RECOVERY;
405                         return (NULL);
406                         /* BIND has abort() here, too risky on bad data */
407                 }
408                 if (!had_error)
409                         haveanswer++;
410         }
411         if (haveanswer) {
412                 *ap = NULL;
413                 *hap = NULL;
414 # if defined(RESOLVSORT)
415                 /*
416                  * Note: we sort even if host can take only one address
417                  * in its return structures - should give it the "best"
418                  * address in that case, not some random one
419                  */
420                 if (_res.nsort && haveanswer > 1 && qtype == T_A)
421                         addrsort(h_addr_ptrs, haveanswer);
422 # endif /*RESOLVSORT*/
423                 if (!host.h_name) {
424                         n = strlen(qname) + 1;  /* for the \0 */
425                         if (n > buflen || n >= MAXHOSTNAMELEN)
426                                 goto no_recovery;
427                         strcpy(bp, qname);
428                         host.h_name = bp;
429                         bp += n;
430                         buflen -= n;
431                 }
432                 if (_res.options & RES_USE_INET6)
433                         _map_v4v6_hostent(&host, &bp, &buflen);
434                 h_errno = NETDB_SUCCESS;
435                 return (&host);
436         }
437  no_recovery:
438         h_errno = NO_RECOVERY;
439         return (NULL);
440 }
441
442 struct hostent *
443 __dns_getanswer(const char *answer, int anslen, const char *qname, int qtype)
444 {
445         switch(qtype) {
446         case T_AAAA:
447                 host.h_addrtype = AF_INET6;
448                 host.h_length = IN6ADDRSZ;
449                 break;
450         case T_A:
451         default:
452                 host.h_addrtype = AF_INET;
453                 host.h_length = INADDRSZ;
454                 break;
455         }
456
457         return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
458 }
459
460 struct hostent *
461 _gethostbydnsname(const char *name, int af)
462 {
463         querybuf *buf;
464         const char *cp;
465         char *bp;
466         int n, size, type, len;
467         struct hostent *hp;
468
469         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
470                 h_errno = NETDB_INTERNAL;
471                 return (NULL);
472         }
473
474         switch (af) {
475         case AF_INET:
476                 size = INADDRSZ;
477                 type = T_A;
478                 break;
479         case AF_INET6:
480                 size = IN6ADDRSZ;
481                 type = T_AAAA;
482                 break;
483         default:
484                 h_errno = NETDB_INTERNAL;
485                 errno = EAFNOSUPPORT;
486                 return (NULL);
487         }
488
489         host.h_addrtype = af;
490         host.h_length = size;
491
492         /*
493          * if there aren't any dots, it could be a user-level alias.
494          * this is also done in res_query() since we are not the only
495          * function that looks up host names.
496          */
497         if (!strchr(name, '.') && (cp = __hostalias(name)))
498                 name = cp;
499
500         /*
501          * disallow names consisting only of digits/dots, unless
502          * they end in a dot.
503          */
504         if (isdigit((unsigned char)name[0]))
505                 for (cp = name;; ++cp) {
506                         if (!*cp) {
507                                 if (*--cp == '.')
508                                         break;
509                                 /*
510                                  * All-numeric, no dot at the end.
511                                  * Fake up a hostent as if we'd actually
512                                  * done a lookup.
513                                  */
514                                 if (inet_pton(af, name, host_addr) <= 0) {
515                                         h_errno = HOST_NOT_FOUND;
516                                         return (NULL);
517                                 }
518                                 strncpy(hostbuf, name, MAXDNAME);
519                                 hostbuf[MAXDNAME] = '\0';
520                                 bp = hostbuf + MAXDNAME;
521                                 len = sizeof hostbuf - MAXDNAME;
522                                 host.h_name = hostbuf;
523                                 host.h_aliases = host_aliases;
524                                 host_aliases[0] = NULL;
525                                 h_addr_ptrs[0] = (char *)host_addr;
526                                 h_addr_ptrs[1] = NULL;
527                                 host.h_addr_list = h_addr_ptrs;
528                                 if (_res.options & RES_USE_INET6)
529                                         _map_v4v6_hostent(&host, &bp, &len);
530                                 h_errno = NETDB_SUCCESS;
531                                 return (&host);
532                         }
533                         if (!isdigit((unsigned char)*cp) && *cp != '.')
534                                 break;
535                 }
536         if ((isxdigit((unsigned char)name[0]) && strchr(name, ':') != NULL) ||
537             name[0] == ':')
538                 for (cp = name;; ++cp) {
539                         if (!*cp) {
540                                 if (*--cp == '.')
541                                         break;
542                                 /*
543                                  * All-IPv6-legal, no dot at the end.
544                                  * Fake up a hostent as if we'd actually
545                                  * done a lookup.
546                                  */
547                                 if (inet_pton(af, name, host_addr) <= 0) {
548                                         h_errno = HOST_NOT_FOUND;
549                                         return (NULL);
550                                 }
551                                 strncpy(hostbuf, name, MAXDNAME);
552                                 hostbuf[MAXDNAME] = '\0';
553                                 bp = hostbuf + MAXDNAME;
554                                 len = sizeof hostbuf - MAXDNAME;
555                                 host.h_name = hostbuf;
556                                 host.h_aliases = host_aliases;
557                                 host_aliases[0] = NULL;
558                                 h_addr_ptrs[0] = (char *)host_addr;
559                                 h_addr_ptrs[1] = NULL;
560                                 host.h_addr_list = h_addr_ptrs;
561                                 h_errno = NETDB_SUCCESS;
562                                 return (&host);
563                         }
564                         if (!isxdigit((unsigned char)*cp) && *cp != ':' && *cp != '.')
565                                 break;
566                 }
567
568         if ((buf = malloc(sizeof(*buf))) == NULL) {
569                 h_errno = NETDB_INTERNAL;
570                 return (NULL);
571         }
572         n = res_search(name, C_IN, type, buf->buf, sizeof(buf->buf));
573         if (n < 0) {
574                 free(buf);
575                 dprintf("res_search failed (%d)\n", n);
576                 return (NULL);
577         } else if (n > sizeof(buf->buf)) {
578                 free(buf);
579                 dprintf("static buffer is too small (%d)\n", n);
580                 return (NULL);
581         }
582         hp = gethostanswer(buf, n, name, type);
583         free(buf);
584         return (hp);
585 }
586
587 struct hostent *
588 _gethostbydnsaddr(const char *addr,     /* XXX should have been def'd as u_char! */
589                   int len,
590                   int af)
591 {
592         const u_char *uaddr = (const u_char *)addr;
593         static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
594         static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
595         int n, size;
596         querybuf *buf;
597         struct hostent *hp;
598         char qbuf[MAXDNAME+1], *qp;
599 #ifdef SUNSECURITY
600         struct hostent *rhp;
601         char **haddr;
602         u_long old_options;
603         char hname2[MAXDNAME+1];
604 #endif /*SUNSECURITY*/
605         
606         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
607                 h_errno = NETDB_INTERNAL;
608                 return (NULL);
609         }
610         if (af == AF_INET6 && len == IN6ADDRSZ &&
611             (!bcmp(uaddr, mapped, sizeof mapped) ||
612              !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
613                 /* Unmap. */
614                 addr += sizeof mapped;
615                 uaddr += sizeof mapped;
616                 af = AF_INET;
617                 len = INADDRSZ;
618         }
619         switch (af) {
620         case AF_INET:
621                 size = INADDRSZ;
622                 break;
623         case AF_INET6:
624                 size = IN6ADDRSZ;
625                 break;
626         default:
627                 errno = EAFNOSUPPORT;
628                 h_errno = NETDB_INTERNAL;
629                 return (NULL);
630         }
631         if (size != len) {
632                 errno = EINVAL;
633                 h_errno = NETDB_INTERNAL;
634                 return (NULL);
635         }
636         switch (af) {
637         case AF_INET:
638                 sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
639                                (uaddr[3] & 0xff),
640                                (uaddr[2] & 0xff),
641                                (uaddr[1] & 0xff),
642                                (uaddr[0] & 0xff));
643                 break;
644         case AF_INET6:
645                 qp = qbuf;
646                 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
647                         qp += SPRINTF((qp, "%x.%x.",
648                                        uaddr[n] & 0xf,
649                                        (uaddr[n] >> 4) & 0xf));
650                 }
651                 strlcat(qbuf, "ip6.arpa", sizeof(qbuf));
652                 break;
653         default:
654                 abort();
655         }
656         if ((buf = malloc(sizeof(*buf))) == NULL) {
657                 h_errno = NETDB_INTERNAL;
658                 return (NULL);
659         }
660         n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf->buf, sizeof buf->buf);
661         if (n < 0 && af == AF_INET6) {
662                 *qp = '\0';
663                 strlcat(qbuf, "ip6.int", sizeof(qbuf));
664                 n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf->buf,
665                               sizeof buf->buf);
666         }
667         if (n < 0) {
668                 free(buf);
669                 dprintf("res_query failed (%d)\n", n);
670                 return (NULL);
671         }
672         if (n > sizeof buf->buf) {
673                 free(buf);
674                 dprintf("static buffer is too small (%d)\n", n);
675                 return (NULL);
676         }
677         if (!(hp = gethostanswer(buf, n, qbuf, T_PTR))) {
678                 free(buf);
679                 return (NULL);  /* h_errno was set by gethostanswer() */
680         }
681         free(buf);
682 #ifdef SUNSECURITY
683         if (af == AF_INET) {
684             /*
685              * turn off search as the name should be absolute,
686              * 'localhost' should be matched by defnames
687              */
688             strncpy(hname2, hp->h_name, MAXDNAME);
689             hname2[MAXDNAME] = '\0';
690             old_options = _res.options;
691             _res.options &= ~RES_DNSRCH;
692             _res.options |= RES_DEFNAMES;
693             if (!(rhp = gethostbyname(hname2))) {
694                 syslog(LOG_NOTICE|LOG_AUTH,
695                        "gethostbyaddr: No A record for %s (verifying [%s])",
696                        hname2, inet_ntoa(*((struct in_addr *)addr)));
697                 _res.options = old_options;
698                 h_errno = HOST_NOT_FOUND;
699                 return (NULL);
700             }
701             _res.options = old_options;
702             for (haddr = rhp->h_addr_list; *haddr; haddr++)
703                 if (!memcmp(*haddr, addr, INADDRSZ))
704                         break;
705             if (!*haddr) {
706                 syslog(LOG_NOTICE|LOG_AUTH,
707                        "gethostbyaddr: A record of %s != PTR record [%s]",
708                        hname2, inet_ntoa(*((struct in_addr *)addr)));
709                 h_errno = HOST_NOT_FOUND;
710                 return (NULL);
711             }
712         }
713 #endif /*SUNSECURITY*/
714         hp->h_addrtype = af;
715         hp->h_length = len;
716         bcopy(addr, host_addr, len);
717         h_addr_ptrs[0] = (char *)host_addr;
718         h_addr_ptrs[1] = NULL;
719         if (af == AF_INET && (_res.options & RES_USE_INET6)) {
720                 _map_v4v6_address((char*)host_addr, (char*)host_addr);
721                 hp->h_addrtype = AF_INET6;
722                 hp->h_length = IN6ADDRSZ;
723         }
724         h_errno = NETDB_SUCCESS;
725         return (hp);
726 }
727
728 #ifdef RESOLVSORT
729 static void
730 addrsort(char **ap, int num)
731 {
732         int i, j;
733         char **p;
734         short aval[MAXADDRS];
735         int needsort = 0;
736
737         p = ap;
738         for (i = 0; i < num; i++, p++) {
739             for (j = 0 ; (unsigned)j < _res.nsort; j++)
740                 if (_res.sort_list[j].addr.s_addr == 
741                     (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
742                         break;
743             aval[i] = j;
744             if (needsort == 0 && i > 0 && j < aval[i-1])
745                 needsort = i;
746         }
747         if (!needsort)
748             return;
749
750         while (needsort < num) {
751             for (j = needsort - 1; j >= 0; j--) {
752                 if (aval[j] > aval[j+1]) {
753                     char *hp;
754
755                     i = aval[j];
756                     aval[j] = aval[j+1];
757                     aval[j+1] = i;
758
759                     hp = ap[j];
760                     ap[j] = ap[j+1];
761                     ap[j+1] = hp;
762
763                 } else
764                     break;
765             }
766             needsort++;
767         }
768 }
769 #endif
770 void
771 _sethostdnsent(int stayopen)
772 {
773         if ((_res.options & RES_INIT) == 0 && res_init() == -1)
774                 return;
775         if (stayopen)
776                 _res.options |= RES_STAYOPEN | RES_USEVC;
777 }
778
779 void
780 _endhostdnsent(void)
781 {
782         _res.options &= ~(RES_STAYOPEN | RES_USEVC);
783         res_close();
784 }