(obstack_free): Explicitly convert __obj to
[kopensolaris-gnu/glibc.git] / resolv / gethnamaddr.c
1 /*
2  * ++Copyright++ 1985, 1988, 1993
3  * -
4  * Copyright (c) 1985, 1988, 1993
5  *    The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 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 rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
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 <netdb.h>
70 #include <resolv.h>
71 #include <ctype.h>
72 #include <errno.h>
73 #include <syslog.h>
74
75 #ifndef LOG_AUTH
76 # define LOG_AUTH 0
77 #endif
78
79 #define MULTI_PTRS_ARE_ALIASES 1        /* XXX - experimental */
80
81 #if defined(BSD) && (BSD >= 199103) && defined(AF_INET6)
82 # include <stdlib.h>
83 # include <string.h>
84 #else
85 # include "../conf/portability.h"
86 #endif
87
88 #if defined(USE_OPTIONS_H)
89 # include <../conf/options.h>
90 #endif
91
92 #ifdef SPRINTF_CHAR
93 # define SPRINTF(x) strlen(sprintf/**/x)
94 #else
95 # define SPRINTF(x) ((size_t)sprintf x)
96 #endif
97
98 #define MAXALIASES      35
99 #define MAXADDRS        35
100
101 static const char AskedForGot[] =
102                           "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
103
104 static char *h_addr_ptrs[MAXADDRS + 1];
105
106 static struct hostent host;
107 static char *host_aliases[MAXALIASES];
108 static char hostbuf[8*1024];
109 static u_char host_addr[16];    /* IPv4 or IPv6 */
110 static FILE *hostf = NULL;
111 static int stayopen = 0;
112
113 static void map_v4v6_address __P((const char *src, char *dst));
114 static void map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len));
115
116 #ifdef RESOLVSORT
117 extern void addrsort __P((char **, int));
118 #endif
119
120 #if PACKETSZ > 1024
121 #define MAXPACKET       PACKETSZ
122 #else
123 #define MAXPACKET       1024
124 #endif
125
126 /* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length.  */
127 #ifdef MAXHOSTNAMELEN
128 # undef MAXHOSTNAMELEN
129 #endif
130 #define MAXHOSTNAMELEN 256
131
132 typedef union {
133     HEADER hdr;
134     u_char buf[MAXPACKET];
135 } querybuf;
136
137 typedef union {
138     int32_t al;
139     char ac;
140 } align;
141
142 #ifndef h_errno
143 extern int h_errno;
144 #endif
145
146 #ifdef DEBUG
147 static void
148 dprintf(msg, num)
149         char *msg;
150         int num;
151 {
152         if (_res.options & RES_DEBUG) {
153                 int save = errno;
154
155                 printf(msg, num);
156                 __set_errno (save);
157         }
158 }
159 #else
160 # define dprintf(msg, num) /*nada*/
161 #endif
162
163 #define BOUNDED_INCR(x) \
164         do { \
165                 cp += x; \
166                 if (cp > eom) { \
167                         __set_h_errno (NO_RECOVERY); \
168                         return (NULL); \
169                 } \
170         } while (0)
171
172 #define BOUNDS_CHECK(ptr, count) \
173         do { \
174                 if ((ptr) + (count) > eom) { \
175                         __set_h_errno (NO_RECOVERY); \
176                         return (NULL); \
177                 } \
178         } while (0)
179
180
181 static struct hostent *
182 getanswer(answer, anslen, qname, qtype)
183         const querybuf *answer;
184         int anslen;
185         const char *qname;
186         int qtype;
187 {
188         register const HEADER *hp;
189         register const u_char *cp;
190         register int n;
191         const u_char *eom, *erdata;
192         char *bp, **ap, **hap;
193         int type, class, buflen, ancount, qdcount;
194         int haveanswer, had_error;
195         int toobig = 0;
196         char tbuf[MAXDNAME];
197         const char *tname;
198         int (*name_ok) __P((const char *));
199
200         tname = qname;
201         host.h_name = NULL;
202         eom = answer->buf + anslen;
203         switch (qtype) {
204         case T_A:
205         case T_AAAA:
206                 name_ok = res_hnok;
207                 break;
208         case T_PTR:
209                 name_ok = res_dnok;
210                 break;
211         default:
212                 return (NULL);  /* XXX should be abort(); */
213         }
214         /*
215          * find first satisfactory answer
216          */
217         hp = &answer->hdr;
218         ancount = ntohs(hp->ancount);
219         qdcount = ntohs(hp->qdcount);
220         bp = hostbuf;
221         buflen = sizeof hostbuf;
222         cp = answer->buf;
223         BOUNDED_INCR(HFIXEDSZ);
224         if (qdcount != 1) {
225                 __set_h_errno (NO_RECOVERY);
226                 return (NULL);
227         }
228         n = dn_expand(answer->buf, eom, cp, bp, buflen);
229         if ((n < 0) || !(*name_ok)(bp)) {
230                 __set_h_errno (NO_RECOVERY);
231                 return (NULL);
232         }
233         BOUNDED_INCR(n + QFIXEDSZ);
234         if (qtype == T_A || qtype == T_AAAA) {
235                 /* res_send() has already verified that the query name is the
236                  * same as the one we sent; this just gets the expanded name
237                  * (i.e., with the succeeding search-domain tacked on).
238                  */
239                 n = strlen(bp) + 1;             /* for the \0 */
240                 if (n >= MAXHOSTNAMELEN) {
241                         __set_h_errno (NO_RECOVERY);
242                         return (NULL);
243                 }
244                 host.h_name = bp;
245                 bp += n;
246                 buflen -= n;
247                 /* The qname can be abbreviated, but h_name is now absolute. */
248                 qname = host.h_name;
249         }
250         ap = host_aliases;
251         *ap = NULL;
252         host.h_aliases = host_aliases;
253         hap = h_addr_ptrs;
254         *hap = NULL;
255         host.h_addr_list = h_addr_ptrs;
256         haveanswer = 0;
257         had_error = 0;
258         while (ancount-- > 0 && cp < eom && !had_error) {
259                 n = dn_expand(answer->buf, eom, cp, bp, buflen);
260                 if ((n < 0) || !(*name_ok)(bp)) {
261                         had_error++;
262                         continue;
263                 }
264                 cp += n;                        /* name */
265                 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
266                 type = _getshort(cp);
267                 cp += INT16SZ;                  /* type */
268                 class = _getshort(cp);
269                 cp += INT16SZ + INT32SZ;        /* class, TTL */
270                 n = _getshort(cp);
271                 cp += INT16SZ;                  /* len */
272                 BOUNDS_CHECK(cp, n);
273                 erdata = cp + n;
274                 if (class != C_IN) {
275                         /* XXX - debug? syslog? */
276                         cp += n;
277                         continue;               /* XXX - had_error++ ? */
278                 }
279                 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
280                         if (ap >= &host_aliases[MAXALIASES-1])
281                                 continue;
282                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
283                         if ((n < 0) || !(*name_ok)(tbuf)) {
284                                 had_error++;
285                                 continue;
286                         }
287                         cp += n;
288                         if (cp != erdata) {
289                                 __set_h_errno (NO_RECOVERY);
290                                 return (NULL);
291                         }
292                         /* Store alias. */
293                         *ap++ = bp;
294                         n = strlen(bp) + 1;     /* for the \0 */
295                         if (n >= MAXHOSTNAMELEN) {
296                                 had_error++;
297                                 continue;
298                         }
299                         bp += n;
300                         buflen -= n;
301                         /* Get canonical name. */
302                         n = strlen(tbuf) + 1;   /* for the \0 */
303                         if (n > buflen || n >= MAXHOSTNAMELEN) {
304                                 had_error++;
305                                 continue;
306                         }
307                         strcpy(bp, tbuf);
308                         host.h_name = bp;
309                         bp += n;
310                         buflen -= n;
311                         continue;
312                 }
313                 if (qtype == T_PTR && type == T_CNAME) {
314                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
315                         if (n < 0 || !res_dnok(tbuf)) {
316                                 had_error++;
317                                 continue;
318                         }
319                         cp += n;
320                         if (cp != erdata) {
321                                 __set_h_errno (NO_RECOVERY);
322                                 return (NULL);
323                         }
324                         /* Get canonical name. */
325                         n = strlen(tbuf) + 1;   /* for the \0 */
326                         if (n > buflen || n >= MAXHOSTNAMELEN) {
327                                 had_error++;
328                                 continue;
329                         }
330                         strcpy(bp, tbuf);
331                         tname = bp;
332                         bp += n;
333                         buflen -= n;
334                         continue;
335                 }
336                 if ((type == T_SIG) || (type == T_KEY) || (type == T_NXT)) {
337                         /* We don't support DNSSEC yet.  For now, ignore
338                          * the record and send a low priority message
339                          * to syslog.
340                          */
341                         syslog(LOG_DEBUG|LOG_AUTH,
342                "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
343                                qname, p_class(C_IN), p_type(qtype),
344                                p_type(type));
345                         cp += n;
346                         continue;
347                 }
348                 if (type != qtype) {
349                         syslog(LOG_NOTICE|LOG_AUTH,
350                "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
351                                qname, p_class(C_IN), p_type(qtype),
352                                p_type(type));
353                         cp += n;
354                         continue;               /* XXX - had_error++ ? */
355                 }
356                 switch (type) {
357                 case T_PTR:
358                         if (strcasecmp(tname, bp) != 0) {
359                                 syslog(LOG_NOTICE|LOG_AUTH,
360                                        AskedForGot, qname, bp);
361                                 cp += n;
362                                 continue;       /* XXX - had_error++ ? */
363                         }
364                         n = dn_expand(answer->buf, eom, cp, bp, buflen);
365                         if ((n < 0) || !res_hnok(bp)) {
366                                 had_error++;
367                                 break;
368                         }
369 #if MULTI_PTRS_ARE_ALIASES
370                         cp += n;
371                         if (cp != erdata) {
372                                 __set_h_errno (NO_RECOVERY);
373                                 return (NULL);
374                         }
375                         if (!haveanswer)
376                                 host.h_name = bp;
377                         else if (ap < &host_aliases[MAXALIASES-1])
378                                 *ap++ = bp;
379                         else
380                                 n = -1;
381                         if (n != -1) {
382                                 n = strlen(bp) + 1;     /* for the \0 */
383                                 if (n >= MAXHOSTNAMELEN) {
384                                         had_error++;
385                                         break;
386                                 }
387                                 bp += n;
388                                 buflen -= n;
389                         }
390                         break;
391 #else
392                         host.h_name = bp;
393                         if (_res.options & RES_USE_INET6) {
394                                 n = strlen(bp) + 1;     /* for the \0 */
395                                 if (n >= MAXHOSTNAMELEN) {
396                                         had_error++;
397                                         break;
398                                 }
399                                 bp += n;
400                                 buflen -= n;
401                                 map_v4v6_hostent(&host, &bp, &buflen);
402                         }
403                         __set_h_errno (NETDB_SUCCESS);
404                         return (&host);
405 #endif
406                 case T_A:
407                 case T_AAAA:
408                         if (strcasecmp(host.h_name, bp) != 0) {
409                                 syslog(LOG_NOTICE|LOG_AUTH,
410                                        AskedForGot, host.h_name, bp);
411                                 cp += n;
412                                 continue;       /* XXX - had_error++ ? */
413                         }
414                         if (n != host.h_length) {
415                                 cp += n;
416                                 continue;
417                         }
418                         if (!haveanswer) {
419                                 register int nn;
420
421                                 host.h_name = bp;
422                                 nn = strlen(bp) + 1;    /* for the \0 */
423                                 bp += nn;
424                                 buflen -= nn;
425                         }
426
427                         bp += sizeof(align) - ((u_long)bp % sizeof(align));
428
429                         if (bp + n >= &hostbuf[sizeof hostbuf]) {
430                                 dprintf("size (%d) too big\n", n);
431                                 had_error++;
432                                 continue;
433                         }
434                         if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
435                                 if (!toobig++) {
436                                         dprintf("Too many addresses (%d)\n",
437                                                 MAXADDRS);
438                                 }
439                                 cp += n;
440                                 continue;
441                         }
442                         bcopy(cp, *hap++ = bp, n);
443                         bp += n;
444                         buflen -= n;
445                         cp += n;
446                         if (cp != erdata) {
447                                 __set_h_errno (NO_RECOVERY);
448                                 return (NULL);
449                         }
450                         break;
451                 default:
452                         abort();
453                 }
454                 if (!had_error)
455                         haveanswer++;
456         }
457         if (haveanswer) {
458                 *ap = NULL;
459                 *hap = NULL;
460 # if defined(RESOLVSORT)
461                 /*
462                  * Note: we sort even if host can take only one address
463                  * in its return structures - should give it the "best"
464                  * address in that case, not some random one
465                  */
466                 if (_res.nsort && haveanswer > 1 && qtype == T_A)
467                         addrsort(h_addr_ptrs, haveanswer);
468 # endif /*RESOLVSORT*/
469                 if (!host.h_name) {
470                         n = strlen(qname) + 1;  /* for the \0 */
471                         if (n > buflen || n >= MAXHOSTNAMELEN)
472                                 goto no_recovery;
473                         strcpy(bp, qname);
474                         host.h_name = bp;
475                         bp += n;
476                         buflen -= n;
477                 }
478                 if (_res.options & RES_USE_INET6)
479                         map_v4v6_hostent(&host, &bp, &buflen);
480                 __set_h_errno (NETDB_SUCCESS);
481                 return (&host);
482         }
483  no_recovery:
484         __set_h_errno (NO_RECOVERY);
485         return (NULL);
486 }
487
488 struct hostent *
489 gethostbyname(name)
490         const char *name;
491 {
492         struct hostent *hp;
493
494         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
495                 __set_h_errno (NETDB_INTERNAL);
496                 return (NULL);
497        }
498         if (_res.options & RES_USE_INET6) {
499                 hp = gethostbyname2(name, AF_INET6);
500                 if (hp)
501                         return (hp);
502         }
503         return (gethostbyname2(name, AF_INET));
504 }
505
506 struct hostent *
507 gethostbyname2(name, af)
508         const char *name;
509         int af;
510 {
511         querybuf buf;
512         register const char *cp;
513         char *bp;
514         int n, size, type, len;
515         extern struct hostent *_gethtbyname2();
516
517         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
518                 __set_h_errno (NETDB_INTERNAL);
519                 return (NULL);
520         }
521
522         switch (af) {
523         case AF_INET:
524                 size = INADDRSZ;
525                 type = T_A;
526                 break;
527         case AF_INET6:
528                 size = IN6ADDRSZ;
529                 type = T_AAAA;
530                 break;
531         default:
532                 __set_h_errno (NETDB_INTERNAL);
533                 __set_errno (EAFNOSUPPORT);
534                 return (NULL);
535         }
536
537         host.h_addrtype = af;
538         host.h_length = size;
539
540         /*
541          * if there aren't any dots, it could be a user-level alias.
542          * this is also done in res_query() since we are not the only
543          * function that looks up host names.
544          */
545         if (!strchr(name, '.') && (cp = __hostalias(name)))
546                 name = cp;
547
548         /*
549          * disallow names consisting only of digits/dots, unless
550          * they end in a dot.
551          */
552         if (isdigit(name[0]))
553                 for (cp = name;; ++cp) {
554                         if (!*cp) {
555                                 if (*--cp == '.')
556                                         break;
557                                 /*
558                                  * All-numeric, no dot at the end.
559                                  * Fake up a hostent as if we'd actually
560                                  * done a lookup.
561                                  */
562                                 if (inet_pton(af, name, host_addr) <= 0) {
563                                         __set_h_errno (HOST_NOT_FOUND);
564                                         return (NULL);
565                                 }
566                                 strncpy(hostbuf, name, MAXDNAME);
567                                 hostbuf[MAXDNAME] = '\0';
568                                 bp = hostbuf + MAXDNAME;
569                                 len = sizeof hostbuf - MAXDNAME;
570                                 host.h_name = hostbuf;
571                                 host.h_aliases = host_aliases;
572                                 host_aliases[0] = NULL;
573                                 h_addr_ptrs[0] = (char *)host_addr;
574                                 h_addr_ptrs[1] = NULL;
575                                 host.h_addr_list = h_addr_ptrs;
576                                 if (_res.options & RES_USE_INET6)
577                                         map_v4v6_hostent(&host, &bp, &len);
578                                 __set_h_errno (NETDB_SUCCESS);
579                                 return (&host);
580                         }
581                         if (!isdigit(*cp) && *cp != '.')
582                                 break;
583                }
584         if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
585             name[0] == ':')
586                 for (cp = name;; ++cp) {
587                         if (!*cp) {
588                                 if (*--cp == '.')
589                                         break;
590                                 /*
591                                  * All-IPv6-legal, no dot at the end.
592                                  * Fake up a hostent as if we'd actually
593                                  * done a lookup.
594                                  */
595                                 if (inet_pton(af, name, host_addr) <= 0) {
596                                         __set_h_errno (HOST_NOT_FOUND);
597                                         return (NULL);
598                                 }
599                                 strncpy(hostbuf, name, MAXDNAME);
600                                 hostbuf[MAXDNAME] = '\0';
601                                 bp = hostbuf + MAXDNAME;
602                                 len = sizeof hostbuf - MAXDNAME;
603                                 host.h_name = hostbuf;
604                                 host.h_aliases = host_aliases;
605                                 host_aliases[0] = NULL;
606                                 h_addr_ptrs[0] = (char *)host_addr;
607                                 h_addr_ptrs[1] = NULL;
608                                 host.h_addr_list = h_addr_ptrs;
609                                 __set_h_errno (NETDB_SUCCESS);
610                                 return (&host);
611                         }
612                         if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
613                                 break;
614                 }
615
616         if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf.buf))) < 0) {
617                 dprintf("res_search failed (%d)\n", n);
618                 if (errno == ECONNREFUSED)
619                         return (_gethtbyname2(name, af));
620                 return (NULL);
621         }
622         return (getanswer(&buf, n, name, type));
623 }
624
625 struct hostent *
626 gethostbyaddr(addr, len, af)
627         const char *addr;       /* XXX should have been def'd as u_char! */
628         int len, af;
629 {
630         const u_char *uaddr = (const u_char *)addr;
631         static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
632         static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
633         int n, size;
634         querybuf buf;
635         register struct hostent *hp;
636         char qbuf[MAXDNAME+1], *qp;
637 #ifdef SUNSECURITY
638         register struct hostent *rhp;
639         char **haddr;
640         u_long old_options;
641         char hname2[MAXDNAME+1];
642 #endif /*SUNSECURITY*/
643         extern struct hostent *_gethtbyaddr();
644
645         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
646                 __set_h_errno (NETDB_INTERNAL);
647                 return (NULL);
648         }
649         if (af == AF_INET6 && len == IN6ADDRSZ &&
650             (!bcmp(uaddr, mapped, sizeof mapped) ||
651              !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
652                 /* Unmap. */
653                 addr += sizeof mapped;
654                 uaddr += sizeof mapped;
655                 af = AF_INET;
656                 len = INADDRSZ;
657         }
658         switch (af) {
659         case AF_INET:
660                 size = INADDRSZ;
661                 break;
662         case AF_INET6:
663                 size = IN6ADDRSZ;
664                 break;
665         default:
666                 __set_errno (EAFNOSUPPORT);
667                 __set_h_errno (NETDB_INTERNAL);
668                 return (NULL);
669         }
670         if (size != len) {
671                 __set_errno (EINVAL);
672                 __set_h_errno (NETDB_INTERNAL);
673                 return (NULL);
674         }
675         switch (af) {
676         case AF_INET:
677                 (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
678                                (uaddr[3] & 0xff),
679                                (uaddr[2] & 0xff),
680                                (uaddr[1] & 0xff),
681                                (uaddr[0] & 0xff));
682                 break;
683         case AF_INET6:
684                 qp = qbuf;
685                 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
686                         qp += SPRINTF((qp, "%x.%x.",
687                                        uaddr[n] & 0xf,
688                                        (uaddr[n] >> 4) & 0xf));
689                 }
690                 strcpy(qp, "ip6.int");
691                 break;
692         default:
693                 abort();
694         }
695         n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
696         if (n < 0) {
697                 dprintf("res_query failed (%d)\n", n);
698                 if (errno == ECONNREFUSED)
699                         return (_gethtbyaddr(addr, len, af));
700                 return (NULL);
701         }
702         if (!(hp = getanswer(&buf, n, qbuf, T_PTR)))
703                 return (NULL);  /* h_errno was set by getanswer() */
704 #ifdef SUNSECURITY
705         if (af == AF_INET) {
706             /*
707              * turn off search as the name should be absolute,
708              * 'localhost' should be matched by defnames
709              */
710             strncpy(hname2, hp->h_name, MAXDNAME);
711             hname2[MAXDNAME] = '\0';
712             old_options = _res.options;
713             _res.options &= ~RES_DNSRCH;
714             _res.options |= RES_DEFNAMES;
715             if (!(rhp = gethostbyname(hname2))) {
716                 syslog(LOG_NOTICE|LOG_AUTH,
717                        "gethostbyaddr: No A record for %s (verifying [%s])",
718                        hname2, inet_ntoa(*((struct in_addr *)addr)));
719                 _res.options = old_options;
720                 __set_h_errno (HOST_NOT_FOUND);
721                 return (NULL);
722             }
723             _res.options = old_options;
724             for (haddr = rhp->h_addr_list; *haddr; haddr++)
725                 if (!memcmp(*haddr, addr, INADDRSZ))
726                         break;
727             if (!*haddr) {
728                 syslog(LOG_NOTICE|LOG_AUTH,
729                        "gethostbyaddr: A record of %s != PTR record [%s]",
730                        hname2, inet_ntoa(*((struct in_addr *)addr)));
731                 __set_h_errno (HOST_NOT_FOUND);
732                 return (NULL);
733             }
734         }
735 #endif /*SUNSECURITY*/
736         hp->h_addrtype = af;
737         hp->h_length = len;
738         bcopy(addr, host_addr, len);
739         h_addr_ptrs[0] = (char *)host_addr;
740         h_addr_ptrs[1] = NULL;
741         if (af == AF_INET && (_res.options & RES_USE_INET6)) {
742                 map_v4v6_address((char*)host_addr, (char*)host_addr);
743                 hp->h_addrtype = AF_INET6;
744                 hp->h_length = IN6ADDRSZ;
745         }
746         __set_h_errno (NETDB_SUCCESS);
747         return (hp);
748 }
749
750 void
751 _sethtent(f)
752         int f;
753 {
754         if (!hostf)
755                 hostf = fopen(_PATH_HOSTS, "r" );
756         else
757                 rewind(hostf);
758         stayopen = f;
759 }
760
761 void
762 _endhtent()
763 {
764         if (hostf && !stayopen) {
765                 (void) fclose(hostf);
766                 hostf = NULL;
767         }
768 }
769
770 struct hostent *
771 _gethtent()
772 {
773         char *p;
774         register char *cp, **q;
775         int af, len;
776
777         if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
778                 __set_h_errno (NETDB_INTERNAL);
779                 return (NULL);
780         }
781  again:
782         if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
783                 __set_h_errno (HOST_NOT_FOUND);
784                 return (NULL);
785         }
786         if (*p == '#')
787                 goto again;
788         if (!(cp = strpbrk(p, "#\n")))
789                 goto again;
790         *cp = '\0';
791         if (!(cp = strpbrk(p, " \t")))
792                 goto again;
793         *cp++ = '\0';
794         if (inet_pton(AF_INET6, p, host_addr) > 0) {
795                 af = AF_INET6;
796                 len = IN6ADDRSZ;
797         } else if (inet_pton(AF_INET, p, host_addr) > 0) {
798                 if (_res.options & RES_USE_INET6) {
799                         map_v4v6_address((char*)host_addr, (char*)host_addr);
800                         af = AF_INET6;
801                         len = IN6ADDRSZ;
802                 } else {
803                         af = AF_INET;
804                         len = INADDRSZ;
805                 }
806         } else {
807                 goto again;
808         }
809         h_addr_ptrs[0] = (char *)host_addr;
810         h_addr_ptrs[1] = NULL;
811         host.h_addr_list = h_addr_ptrs;
812         host.h_length = len;
813         host.h_addrtype = af;
814         while (*cp == ' ' || *cp == '\t')
815                 cp++;
816         host.h_name = cp;
817         q = host.h_aliases = host_aliases;
818         if ((cp = strpbrk(cp, " \t")))
819                 *cp++ = '\0';
820         while (cp && *cp) {
821                 if (*cp == ' ' || *cp == '\t') {
822                         cp++;
823                         continue;
824                 }
825                 if (q < &host_aliases[MAXALIASES - 1])
826                         *q++ = cp;
827                 if ((cp = strpbrk(cp, " \t")))
828                         *cp++ = '\0';
829         }
830         *q = NULL;
831         __set_h_errno (NETDB_SUCCESS);
832         return (&host);
833 }
834
835 struct hostent *
836 _gethtbyname(name)
837         const char *name;
838 {
839         extern struct hostent *_gethtbyname2();
840         struct hostent *hp;
841
842         if (_res.options & RES_USE_INET6) {
843                 hp = _gethtbyname2(name, AF_INET6);
844                 if (hp)
845                         return (hp);
846         }
847         return (_gethtbyname2(name, AF_INET));
848 }
849
850 struct hostent *
851 _gethtbyname2(name, af)
852         const char *name;
853         int af;
854 {
855         register struct hostent *p;
856         register char **cp;
857
858         _sethtent(0);
859         while ((p = _gethtent())) {
860                 if (p->h_addrtype != af)
861                         continue;
862                 if (strcasecmp(p->h_name, name) == 0)
863                         break;
864                 for (cp = p->h_aliases; *cp != 0; cp++)
865                         if (strcasecmp(*cp, name) == 0)
866                                 goto found;
867         }
868  found:
869         _endhtent();
870         return (p);
871 }
872
873 struct hostent *
874 _gethtbyaddr(addr, len, af)
875         const char *addr;
876         int len, af;
877 {
878         register struct hostent *p;
879
880         _sethtent(0);
881         while ((p = _gethtent()))
882                 if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
883                         break;
884         _endhtent();
885         return (p);
886 }
887
888 static void
889 map_v4v6_address(src, dst)
890         const char *src;
891         char *dst;
892 {
893         u_char *p = (u_char *)dst;
894         char tmp[INADDRSZ];
895         int i;
896
897         /* Stash a temporary copy so our caller can update in place. */
898         bcopy(src, tmp, INADDRSZ);
899         /* Mark this ipv6 addr as a mapped ipv4. */
900         for (i = 0; i < 10; i++)
901                 *p++ = 0x00;
902         *p++ = 0xff;
903         *p++ = 0xff;
904         /* Retrieve the saved copy and we're done. */
905         bcopy(tmp, (void*)p, INADDRSZ);
906 }
907
908 static void
909 map_v4v6_hostent(hp, bpp, lenp)
910         struct hostent *hp;
911         char **bpp;
912         int *lenp;
913 {
914         char **ap;
915
916         if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
917                 return;
918         hp->h_addrtype = AF_INET6;
919         hp->h_length = IN6ADDRSZ;
920         for (ap = hp->h_addr_list; *ap; ap++) {
921                 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
922
923                 if (*lenp < (i + IN6ADDRSZ)) {
924                         /* Out of memory.  Truncate address list here.  XXX */
925                         *ap = NULL;
926                         return;
927                 }
928                 *bpp += i;
929                 *lenp -= i;
930                 map_v4v6_address(*ap, *bpp);
931                 *ap = *bpp;
932                 *bpp += IN6ADDRSZ;
933                 *lenp -= IN6ADDRSZ;
934         }
935 }
936
937 #ifdef RESOLVSORT
938 extern void
939 addrsort(ap, num)
940         char **ap;
941         int num;
942 {
943         int i, j;
944         char **p;
945         short aval[MAXADDRS];
946         int needsort = 0;
947
948         p = ap;
949         for (i = 0; i < num; i++, p++) {
950             for (j = 0 ; (unsigned)j < _res.nsort; j++)
951                 if (_res.sort_list[j].addr.s_addr ==
952                     (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
953                         break;
954             aval[i] = j;
955             if (needsort == 0 && i > 0 && j < aval[i-1])
956                 needsort = i;
957         }
958         if (!needsort)
959             return;
960
961         while (needsort < num) {
962             for (j = needsort - 1; j >= 0; j--) {
963                 if (aval[j] > aval[j+1]) {
964                     char *hp;
965
966                     i = aval[j];
967                     aval[j] = aval[j+1];
968                     aval[j+1] = i;
969
970                     hp = ap[j];
971                     ap[j] = ap[j+1];
972                     ap[j+1] = hp;
973
974                 } else
975                     break;
976             }
977             needsort++;
978         }
979 }
980 #endif
981
982 #if defined(BSD43_BSD43_NFS) || defined(sun)
983 /* some libc's out there are bound internally to these names (UMIPS) */
984 void
985 ht_sethostent(stayopen)
986         int stayopen;
987 {
988         _sethtent(stayopen);
989 }
990
991 void
992 ht_endhostent()
993 {
994         _endhtent();
995 }
996
997 struct hostent *
998 ht_gethostbyname(name)
999         char *name;
1000 {
1001         return (_gethtbyname(name));
1002 }
1003
1004 struct hostent *
1005 ht_gethostbyaddr(addr, len, af)
1006         const char *addr;
1007         int len, af;
1008 {
1009         return (_gethtbyaddr(addr, len, af));
1010 }
1011
1012 struct hostent *
1013 gethostent()
1014 {
1015         return (_gethtent());
1016 }
1017
1018 void
1019 dns_service()
1020 {
1021         return;
1022 }
1023
1024 #undef dn_skipname
1025 dn_skipname(comp_dn, eom)
1026         const u_char *comp_dn, *eom;
1027 {
1028         return (__dn_skipname(comp_dn, eom));
1029 }
1030 #endif /*old-style libc with yp junk in it*/