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