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