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