Merge from vendor branch OPENSSH:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / bind / irs / dns_ho.c
1 /*
2  * Copyright (c) 1985, 1988, 1993
3  *    The Regents of the University of California.  All rights reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /*
35  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
36  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
37  *
38  * Permission to use, copy, modify, and distribute this software for any
39  * purpose with or without fee is hereby granted, provided that the above
40  * copyright notice and this permission notice appear in all copies.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
43  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
45  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
48  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49  */
50
51 /* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 */
52 /* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */
53
54 #if defined(LIBC_SCCS) && !defined(lint)
55 static const char rcsid[] = "$Id: dns_ho.c,v 1.5.2.11 2004/05/17 07:46:42 marka Exp $";
56 #endif /* LIBC_SCCS and not lint */
57
58 /* Imports. */
59
60 #include "port_before.h"
61
62 #include <sys/types.h>
63 #include <sys/param.h>
64 #include <sys/socket.h>
65
66 #include <netinet/in.h>
67 #include <arpa/inet.h>
68 #include <arpa/nameser.h>
69
70 #include <ctype.h>
71 #include <errno.h>
72 #include <stdlib.h>
73 #include <netdb.h>
74 #include <resolv.h>
75 #include <stdio.h>
76 #include <string.h>
77 #include <syslog.h>
78
79 #include <isc/memcluster.h>
80 #include <irs.h>
81
82 #include "port_after.h"
83
84 #include "irs_p.h"
85 #include "dns_p.h"
86
87 #ifdef SPRINTF_CHAR
88 # define SPRINTF(x) strlen(sprintf/**/x)
89 #else
90 # define SPRINTF(x) sprintf x
91 #endif
92
93 /* Definitions. */
94
95 #define MAXALIASES      35
96 #define MAXADDRS        35
97
98 #define MAXPACKET (65535)       /* Maximum TCP message size */
99
100 #define BOUNDS_CHECK(ptr, count) \
101         if ((ptr) + (count) > eom) { \
102                 had_error++; \
103                 continue; \
104         } else (void)0
105
106 typedef union {
107         HEADER hdr;
108         u_char buf[MAXPACKET];
109 } querybuf;
110
111 struct dns_res_target {
112         struct dns_res_target *next;
113         querybuf qbuf;          /* query buffer */
114         u_char *answer;         /* buffer to put answer */
115         int anslen;             /* size of answer buffer */
116         int qclass, qtype;      /* class and type of query */
117         int action;             /* condition whether query is really issued */
118         char qname[MAXDNAME +1]; /* domain name */
119 #if 0
120         int n;                  /* result length */
121 #endif
122 };
123 enum {RESTGT_DOALWAYS, RESTGT_AFTERFAILURE, RESTGT_IGNORE};
124 enum {RESQRY_SUCCESS, RESQRY_FAIL};
125
126 struct pvt {
127         struct hostent  host;
128         char *          h_addr_ptrs[MAXADDRS + 1];
129         char *          host_aliases[MAXALIASES];
130         char            hostbuf[8*1024];
131         u_char          host_addr[16];  /* IPv4 or IPv6 */
132         struct __res_state  *res;
133         void            (*free_res)(void *);
134 };
135
136 typedef union {
137         int32_t al;
138         char ac;
139 } align;
140
141 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
142 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
143 /* Note: the IPv6 loopback address is in the "tunnel" space */
144 static const u_char v6local[] = { 0,0, 0,1 }; /* last 4 bytes of IPv6 addr */
145
146 /* Forwards. */
147
148 static void             ho_close(struct irs_ho *this);
149 static struct hostent * ho_byname(struct irs_ho *this, const char *name);
150 static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
151                                    int af);
152 static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
153                                   int len, int af);
154 static struct hostent * ho_next(struct irs_ho *this);
155 static void             ho_rewind(struct irs_ho *this);
156 static void             ho_minimize(struct irs_ho *this);
157 static struct __res_state * ho_res_get(struct irs_ho *this);
158 static void             ho_res_set(struct irs_ho *this,
159                                    struct __res_state *res,
160                                    void (*free_res)(void *));
161 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
162                                      const struct addrinfo *pai);
163
164 static void             map_v4v6_hostent(struct hostent *hp, char **bp,
165                                          char *ep);
166 static void             addrsort(res_state, char **, int);
167 static struct hostent * gethostans(struct irs_ho *this,
168                                    const u_char *ansbuf, int anslen,
169                                    const char *qname, int qtype,
170                                    int af, int size,
171                                    struct addrinfo **ret_aip,
172                                    const struct addrinfo *pai);
173 static int add_hostent(struct pvt *pvt, char *bp, char **hap,
174                        struct addrinfo *ai);
175 static int              init(struct irs_ho *this);
176
177 /* Exports. */
178
179 struct irs_ho *
180 irs_dns_ho(struct irs_acc *this) {
181         struct irs_ho *ho;
182         struct pvt *pvt;
183
184         UNUSED(this);
185
186         if (!(pvt = memget(sizeof *pvt))) {
187                 errno = ENOMEM;
188                 return (NULL);
189         }
190         memset(pvt, 0, sizeof *pvt);
191
192         if (!(ho = memget(sizeof *ho))) {
193                 memput(pvt, sizeof *pvt);
194                 errno = ENOMEM;
195                 return (NULL);
196         }
197         memset(ho, 0x5e, sizeof *ho);
198         ho->private = pvt;
199         ho->close = ho_close;
200         ho->byname = ho_byname;
201         ho->byname2 = ho_byname2;
202         ho->byaddr = ho_byaddr;
203         ho->next = ho_next;
204         ho->rewind = ho_rewind;
205         ho->minimize = ho_minimize;
206         ho->res_get = ho_res_get;
207         ho->res_set = ho_res_set;
208         ho->addrinfo = ho_addrinfo;
209         return (ho);
210 }
211
212 /* Methods. */
213
214 static void
215 ho_close(struct irs_ho *this) {
216         struct pvt *pvt = (struct pvt *)this->private;
217
218         ho_minimize(this);
219         if (pvt->res && pvt->free_res)
220                 (*pvt->free_res)(pvt->res);
221         if (pvt)
222                 memput(pvt, sizeof *pvt);
223         memput(this, sizeof *this);
224 }
225
226 static struct hostent *
227 ho_byname(struct irs_ho *this, const char *name) {
228         struct pvt *pvt = (struct pvt *)this->private;
229         struct hostent *hp;
230
231         if (init(this) == -1)
232                 return (NULL);
233
234         if (pvt->res->options & RES_USE_INET6) {
235                 hp = ho_byname2(this, name, AF_INET6);
236                 if (hp)
237                         return (hp);
238         }
239         return (ho_byname2(this, name, AF_INET));
240 }
241
242 static struct hostent *
243 ho_byname2(struct irs_ho *this, const char *name, int af)
244 {
245         struct pvt *pvt = (struct pvt *)this->private;
246         struct hostent *hp = NULL;
247         int n, size;
248         char tmp[NS_MAXDNAME];
249         const char *cp;
250         struct addrinfo ai;
251         struct dns_res_target *q, *p;
252         int querystate = RESQRY_FAIL;
253
254         if (init(this) == -1)
255                 return (NULL);
256
257         q = memget(sizeof(*q));
258         if (q == NULL) {
259                 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
260                 errno = ENOMEM;
261                 goto cleanup;
262         }
263         memset(q, 0, sizeof(q));
264
265         switch (af) {
266         case AF_INET:
267                 size = INADDRSZ;
268                 q->qclass = C_IN;
269                 q->qtype = T_A;
270                 q->answer = q->qbuf.buf;
271                 q->anslen = sizeof(q->qbuf);
272                 q->action = RESTGT_DOALWAYS;
273                 break;
274         case AF_INET6:
275                 size = IN6ADDRSZ;
276                 q->qclass = C_IN;
277                 q->qtype = T_AAAA;
278                 q->answer = q->qbuf.buf;
279                 q->anslen = sizeof(q->qbuf);
280                 q->action = RESTGT_DOALWAYS;
281                 break;
282         default:
283                 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
284                 errno = EAFNOSUPPORT;
285                 hp = NULL;
286                 goto cleanup;
287         }
288
289         /*
290          * if there aren't any dots, it could be a user-level alias.
291          * this is also done in res_nquery() since we are not the only
292          * function that looks up host names.
293          */
294         if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
295                                                       tmp, sizeof tmp)))
296                 name = cp;
297
298         for (p = q; p; p = p->next) {
299                 switch(p->action) {
300                 case RESTGT_DOALWAYS:
301                         break;
302                 case RESTGT_AFTERFAILURE:
303                         if (querystate == RESQRY_SUCCESS)
304                                 continue;
305                         break;
306                 case RESTGT_IGNORE:
307                         continue;
308                 }
309
310                 if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
311                                      p->answer, p->anslen)) < 0) {
312                         querystate = RESQRY_FAIL;
313                         continue;
314                 }
315
316                 memset(&ai, 0, sizeof(ai));
317                 ai.ai_family = af;
318                 if ((hp = gethostans(this, p->answer, n, name, p->qtype,
319                                      af, size, NULL,
320                                      (const struct addrinfo *)&ai)) != NULL)
321                         goto cleanup;   /* no more loop is necessary */
322
323                 querystate = RESQRY_FAIL;
324                 continue;
325         }
326
327  cleanup:
328         if (q != NULL)
329                 memput(q, sizeof(*q));
330         return(hp);
331 }
332
333 static struct hostent *
334 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af)
335 {
336         struct pvt *pvt = (struct pvt *)this->private;
337         const u_char *uaddr = addr;
338         char *qp;
339         struct hostent *hp = NULL;
340         struct addrinfo ai;
341         struct dns_res_target *q, *q2, *p;
342         int n, size, i;
343         int querystate = RESQRY_FAIL;
344         
345         if (init(this) == -1)
346                 return (NULL);
347
348         q = memget(sizeof(*q));
349         q2 = memget(sizeof(*q2));
350         if (q == NULL || q2 == NULL) {
351                 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
352                 errno = ENOMEM;
353                 goto cleanup;
354         }
355         memset(q, 0, sizeof(q));
356         memset(q2, 0, sizeof(q2));
357
358         if (af == AF_INET6 && len == IN6ADDRSZ &&
359             (!memcmp(uaddr, mapped, sizeof mapped) ||
360            (!memcmp(uaddr, tunnelled, sizeof tunnelled) &&
361             memcmp(&uaddr[sizeof tunnelled], v6local, sizeof(v6local))))) {
362                 /* Unmap. */
363                 addr = (const char *)addr + sizeof mapped;
364                 uaddr += sizeof mapped;
365                 af = AF_INET;
366                 len = INADDRSZ;
367         }
368         switch (af) {
369         case AF_INET:
370                 size = INADDRSZ;
371                 q->qclass = C_IN;
372                 q->qtype = T_PTR;
373                 q->answer = q->qbuf.buf;
374                 q->anslen = sizeof(q->qbuf);
375                 q->action = RESTGT_DOALWAYS;
376                 break;
377         case AF_INET6:
378                 size = IN6ADDRSZ;
379                 q->qclass = C_IN;
380                 q->qtype = T_PTR;
381                 q->answer = q->qbuf.buf;
382                 q->anslen = sizeof(q->qbuf);
383                 q->next = q2;
384                 q->action = RESTGT_DOALWAYS;
385                 q2->qclass = C_IN;
386                 q2->qtype = T_PTR;
387                 q2->answer = q2->qbuf.buf;
388                 q2->anslen = sizeof(q2->qbuf);
389                 if ((pvt->res->options & RES_NO_NIBBLE2) != 0U)
390                         q2->action = RESTGT_IGNORE;
391                 else
392                         q2->action = RESTGT_AFTERFAILURE;
393                 break;
394         default:
395                 errno = EAFNOSUPPORT;
396                 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
397                 hp = NULL;
398                 goto cleanup;
399         }
400         if (size > len) {
401                 errno = EINVAL;
402                 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
403                 hp = NULL;
404                 goto cleanup;
405         }
406         switch (af) {
407         case AF_INET:
408                 qp = q->qname;
409                 (void) sprintf(qp, "%u.%u.%u.%u.in-addr.arpa",
410                                (uaddr[3] & 0xff),
411                                (uaddr[2] & 0xff),
412                                (uaddr[1] & 0xff),
413                                (uaddr[0] & 0xff));
414                 break;
415         case AF_INET6:
416                 if (q->action != RESTGT_IGNORE) {
417                         const char *nibsuff = res_get_nibblesuffix(pvt->res);
418                         qp = q->qname;
419                         for (n = IN6ADDRSZ - 1; n >= 0; n--) {
420                                 i = SPRINTF((qp, "%x.%x.",
421                                                uaddr[n] & 0xf,
422                                                (uaddr[n] >> 4) & 0xf));
423                                 if (i != 4)
424                                         abort();
425                                 qp += i;
426                         }
427                         if (strlen(q->qname) + strlen(nibsuff) + 1 >
428                             sizeof q->qname) {
429                                 errno = ENAMETOOLONG;
430                                 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
431                                 hp = NULL;
432                                 goto cleanup;
433                         }
434                         strcpy(qp, nibsuff);    /* (checked) */
435                 }
436                 if (q2->action != RESTGT_IGNORE) {
437                         const char *nibsuff2 = res_get_nibblesuffix2(pvt->res);
438                         qp = q2->qname;
439                         for (n = IN6ADDRSZ - 1; n >= 0; n--) {
440                                 i = SPRINTF((qp, "%x.%x.",
441                                                uaddr[n] & 0xf,
442                                                (uaddr[n] >> 4) & 0xf));
443                                 if (i != 4)
444                                         abort();
445                                 qp += i;
446                         }
447                         if ((qp - q->qname) + strlen(nibsuff2) + 1 >
448                             sizeof q->qname){
449                                 errno = ENAMETOOLONG;
450                                 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
451                                 hp = NULL;
452                                 goto cleanup;
453                         }
454                         strcpy(qp, nibsuff2);   /* (checked) */
455                 }
456                 break;
457         default:
458                 abort();
459         }
460
461         for (p = q; p; p = p->next) {
462                 switch(p->action) {
463                 case RESTGT_DOALWAYS:
464                         break;
465                 case RESTGT_AFTERFAILURE:
466                         if (querystate == RESQRY_SUCCESS)
467                                 continue;
468                         break;
469                 case RESTGT_IGNORE:
470                         continue;
471                 }
472
473                 if ((n = res_nquery(pvt->res, p->qname, p->qclass, p->qtype,
474                                     p->answer, p->anslen)) < 0) {
475                         querystate = RESQRY_FAIL;
476                         continue;
477                 }
478
479                 memset(&ai, 0, sizeof(ai));
480                 ai.ai_family = af;
481                 hp = gethostans(this, p->answer, n, p->qname, T_PTR, af, size,
482                                 NULL, (const struct addrinfo *)&ai);
483                 if (!hp) {
484                         querystate = RESQRY_FAIL;
485                         continue;
486                 }
487                         
488                 memcpy(pvt->host_addr, addr, len);
489                 pvt->h_addr_ptrs[0] = (char *)pvt->host_addr;
490                 pvt->h_addr_ptrs[1] = NULL;
491                 if (af == AF_INET && (pvt->res->options & RES_USE_INET6)) {
492                         map_v4v6_address((char*)pvt->host_addr,
493                                          (char*)pvt->host_addr);
494                         pvt->host.h_addrtype = AF_INET6;
495                         pvt->host.h_length = IN6ADDRSZ;
496                 }
497
498                 RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
499                 goto cleanup;   /* no more loop is necessary. */
500         }
501         hp = NULL; /* H_ERRNO was set by subroutines */
502
503  cleanup:
504         if (q != NULL)
505                 memput(q, sizeof(*q));
506         if (q2 != NULL)
507                 memput(q2, sizeof(*q2));
508         return(hp);
509 }
510
511 static struct hostent *
512 ho_next(struct irs_ho *this) {
513
514         UNUSED(this);
515
516         return (NULL);
517 }
518
519 static void
520 ho_rewind(struct irs_ho *this) {
521
522         UNUSED(this);
523
524         /* NOOP */
525 }
526
527 static void
528 ho_minimize(struct irs_ho *this) {
529         struct pvt *pvt = (struct pvt *)this->private;
530
531         if (pvt->res)
532                 res_nclose(pvt->res);
533 }
534
535 static struct __res_state *
536 ho_res_get(struct irs_ho *this) {
537         struct pvt *pvt = (struct pvt *)this->private;
538
539         if (!pvt->res) {
540                 struct __res_state *res;
541                 res = (struct __res_state *)malloc(sizeof *res);
542                 if (!res) {
543                         errno = ENOMEM;
544                         return (NULL);
545                 }
546                 memset(res, 0, sizeof *res);
547                 ho_res_set(this, res, free);
548         }
549
550         return (pvt->res);
551 }
552
553 /* XXX */
554 extern struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
555                                            const char *));
556
557 static struct addrinfo *
558 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
559 {
560         struct pvt *pvt = (struct pvt *)this->private;
561         int n;
562         char tmp[NS_MAXDNAME];
563         const char *cp;
564         struct dns_res_target *q, *q2, *p;
565         struct addrinfo sentinel, *cur;
566         int querystate = RESQRY_FAIL;
567
568         if (init(this) == -1)
569                 return (NULL);
570
571         memset(&sentinel, 0, sizeof(sentinel));
572         cur = &sentinel;
573
574         q = memget(sizeof(*q));
575         q2 = memget(sizeof(*q2));
576         if (q == NULL || q2 == NULL) {
577                 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
578                 errno = ENOMEM;
579                 goto cleanup;
580         }
581         memset(q, 0, sizeof(q2));
582         memset(q2, 0, sizeof(q2));
583
584         switch (pai->ai_family) {
585         case AF_UNSPEC:
586                 /* prefer IPv6 */
587                 q->qclass = C_IN;
588                 q->qtype = T_AAAA;
589                 q->answer = q->qbuf.buf;
590                 q->anslen = sizeof(q->qbuf);
591                 q->next = q2;
592                 q->action = RESTGT_DOALWAYS;
593                 q2->qclass = C_IN;
594                 q2->qtype = T_A;
595                 q2->answer = q2->qbuf.buf;
596                 q2->anslen = sizeof(q2->qbuf);
597                 q2->action = RESTGT_DOALWAYS;
598                 break;
599         case AF_INET:
600                 q->qclass = C_IN;
601                 q->qtype = T_A;
602                 q->answer = q->qbuf.buf;
603                 q->anslen = sizeof(q->qbuf);
604                 q->action = RESTGT_DOALWAYS;
605                 break;
606         case AF_INET6:
607                 q->qclass = C_IN;
608                 q->qtype = T_AAAA;
609                 q->answer = q->qbuf.buf;
610                 q->anslen = sizeof(q->qbuf);
611                 q->action = RESTGT_DOALWAYS;
612                 break;
613         default:
614                 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /* better error? */
615                 goto cleanup;
616         }
617
618         /*
619          * if there aren't any dots, it could be a user-level alias.
620          * this is also done in res_nquery() since we are not the only
621          * function that looks up host names.
622          */
623         if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
624                                                       tmp, sizeof tmp)))
625                 name = cp;
626
627         for (p = q; p; p = p->next) {
628                 struct addrinfo *ai;
629
630                 switch(p->action) {
631                 case RESTGT_DOALWAYS:
632                         break;
633                 case RESTGT_AFTERFAILURE:
634                         if (querystate == RESQRY_SUCCESS)
635                                 continue;
636                         break;
637                 case RESTGT_IGNORE:
638                         continue;
639                 }
640
641                 if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
642                                      p->answer, p->anslen)) < 0) {
643                         querystate = RESQRY_FAIL;
644                         continue;
645                 }
646                 (void)gethostans(this, p->answer, n, name, p->qtype,
647                                  pai->ai_family, /* XXX: meaningless */
648                                  0, &ai, pai);
649                 if (ai) {
650                         querystate = RESQRY_SUCCESS;
651                         cur->ai_next = ai;
652                         while (cur && cur->ai_next)
653                                 cur = cur->ai_next;
654                 }
655                 else
656                         querystate = RESQRY_FAIL;
657         }
658
659  cleanup:
660         if (q != NULL)
661                 memput(q, sizeof(*q));
662         if (q2 != NULL)
663                 memput(q2, sizeof(*q2));
664         return(sentinel.ai_next);
665 }
666
667 static void
668 ho_res_set(struct irs_ho *this, struct __res_state *res,
669                 void (*free_res)(void *)) {
670         struct pvt *pvt = (struct pvt *)this->private;
671
672         if (pvt->res && pvt->free_res) {
673                 res_nclose(pvt->res);
674                 (*pvt->free_res)(pvt->res);
675         }
676
677         pvt->res = res;
678         pvt->free_res = free_res;
679 }
680
681 /* Private. */
682
683 static struct hostent *
684 gethostans(struct irs_ho *this,
685            const u_char *ansbuf, int anslen, const char *qname, int qtype,
686            int af, int size,    /* meaningless for addrinfo cases */
687            struct addrinfo **ret_aip, const struct addrinfo *pai)
688 {
689         struct pvt *pvt = (struct pvt *)this->private;
690         int type, class, ancount, qdcount, n, haveanswer, had_error;
691         int error = NETDB_SUCCESS, arcount;
692         int (*name_ok)(const char *);
693         const HEADER *hp;
694         const u_char *eom;
695         const u_char *eor;
696         const u_char *cp;
697         const char *tname;
698         const char *hname;
699         char *bp, *ep, **ap, **hap;
700         char tbuf[MAXDNAME+1];
701         struct addrinfo sentinel, *cur, ai;
702
703         if (pai == NULL) abort();
704         if (ret_aip != NULL)
705                 *ret_aip = NULL;
706         memset(&sentinel, 0, sizeof(sentinel));
707         cur = &sentinel;
708
709         tname = qname;
710         eom = ansbuf + anslen;
711         switch (qtype) {
712         case T_A:
713         case T_AAAA:
714         case T_ANY:     /* use T_ANY only for T_A/T_AAAA lookup */
715                 name_ok = res_hnok;
716                 break;
717         case T_PTR:
718                 name_ok = res_dnok;
719                 break;
720         default:
721                 abort();
722         }
723
724         pvt->host.h_addrtype = af;
725         pvt->host.h_length = size;
726         hname = pvt->host.h_name = NULL;
727
728         /*
729          * Find first satisfactory answer.
730          */
731         if (ansbuf + HFIXEDSZ > eom) {
732                 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
733                 return (NULL);
734         }
735         hp = (const HEADER *)ansbuf;
736         ancount = ntohs(hp->ancount);
737         qdcount = ntohs(hp->qdcount);
738         arcount = ntohs(hp->arcount);
739         bp = pvt->hostbuf;
740         ep = pvt->hostbuf + sizeof(pvt->hostbuf);
741         cp = ansbuf + HFIXEDSZ;
742         if (qdcount != 1) {
743                 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
744                 return (NULL);
745         }
746         n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
747         if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
748                 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
749                 return (NULL);
750         }
751         cp += n + QFIXEDSZ;
752         if (cp > eom) {
753                 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
754                 return (NULL);
755         }
756         if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
757                 /* res_nsend() has already verified that the query name is the
758                  * same as the one we sent; this just gets the expanded name
759                  * (i.e., with the succeeding search-domain tacked on).
760                  */
761                 n = strlen(bp) + 1;             /* for the \0 */
762                 if (n > MAXHOSTNAMELEN) {
763                         RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
764                         return (NULL);
765                 }
766                 pvt->host.h_name = bp;
767                 hname = bp;
768                 bp += n;
769                 /* The qname can be abbreviated, but hname is now absolute. */
770                 qname = pvt->host.h_name;
771         }
772         ap = pvt->host_aliases;
773         *ap = NULL;
774         pvt->host.h_aliases = pvt->host_aliases;
775         hap = pvt->h_addr_ptrs;
776         *hap = NULL;
777         pvt->host.h_addr_list = pvt->h_addr_ptrs;
778         haveanswer = 0;
779         had_error = 0;
780         while (ancount-- > 0 && cp < eom && !had_error) {
781                 n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
782                 if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
783                         had_error++;
784                         continue;
785                 }
786                 cp += n;                        /* name */
787                 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
788                 type = ns_get16(cp);
789                 cp += INT16SZ;                  /* type */
790                 class = ns_get16(cp);
791                 cp += INT16SZ + INT32SZ;        /* class, TTL */
792                 n = ns_get16(cp);
793                 cp += INT16SZ;                  /* len */
794                 BOUNDS_CHECK(cp, n);
795                 if (class != C_IN) {
796                         cp += n;
797                         continue;
798                 }
799                 eor = cp + n;
800                 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
801                     type == T_CNAME) {
802                         if (haveanswer) {
803                                 int level = LOG_CRIT;
804 #ifdef LOG_SECURITY
805                                 level |= LOG_SECURITY;
806 #endif
807                                 syslog(level,
808  "gethostans: possible attempt to exploit buffer overflow while looking up %s",
809                                         *qname ? qname : ".");
810                         }
811                         n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf);
812                         if (n < 0 || !maybe_ok(pvt->res, tbuf, name_ok)) {
813                                 had_error++;
814                                 continue;
815                         }
816                         cp += n;
817                         /* Store alias. */
818                         if (ap >= &pvt->host_aliases[MAXALIASES-1])
819                                 continue;
820                         *ap++ = bp;
821                         n = strlen(bp) + 1;     /* for the \0 */
822                         bp += n;
823                         /* Get canonical name. */
824                         n = strlen(tbuf) + 1;   /* for the \0 */
825                         if (n > (ep - bp) || n > MAXHOSTNAMELEN) {
826                                 had_error++;
827                                 continue;
828                         }
829                         strcpy(bp, tbuf);       /* (checked) */
830                         pvt->host.h_name = bp;
831                         hname = bp;
832                         bp += n;
833                         continue;
834                 }
835                 if (qtype == T_PTR && type == T_CNAME) {
836                         n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf);
837                         if (n < 0 || !maybe_dnok(pvt->res, tbuf)) {
838                                 had_error++;
839                                 continue;
840                         }
841                         cp += n;
842 #ifdef RES_USE_DNAME
843                         if ((pvt->res->options & RES_USE_DNAME) != 0U)
844 #endif
845                         {
846                                 /*
847                                  * We may be able to check this regardless
848                                  * of the USE_DNAME bit, but we add the check
849                                  * for now since the DNAME support is
850                                  * experimental.
851                                  */
852                                 if (ns_samename(tname, bp) != 1)
853                                         continue;
854                         }
855                         /* Get canonical name. */
856                         n = strlen(tbuf) + 1;   /* for the \0 */
857                         if (n > (ep - bp)) {
858                                 had_error++;
859                                 continue;
860                         }
861                         strcpy(bp, tbuf);       /* (checked) */
862                         tname = bp;
863                         bp += n;
864                         continue;
865                 }
866                 if (qtype == T_ANY) {
867                         if (!(type == T_A || type == T_AAAA)) {
868                                 cp += n;
869                                 continue;
870                         }
871                 } else if (type != qtype) {
872                         cp += n;
873                         continue;
874                 }
875                 switch (type) {
876                 case T_PTR:
877                         if (ret_aip != NULL) {
878                                 /* addrinfo never needs T_PTR */
879                                 cp += n;
880                                 continue;
881                         }
882                         if (ns_samename(tname, bp) != 1) {
883                                 cp += n;
884                                 continue;
885                         }
886                         n = dn_expand(ansbuf, eor, cp, bp, ep - bp);
887                         if (n < 0 || !maybe_hnok(pvt->res, bp) ||
888                             n >= MAXHOSTNAMELEN) {
889                                 had_error++;
890                                 break;
891                         }
892                         cp += n;
893                         if (!haveanswer) {
894                                 pvt->host.h_name = bp;
895                                 hname = bp;
896                         }
897                         else if (ap < &pvt->host_aliases[MAXALIASES-1])
898                                 *ap++ = bp;
899                         else
900                                 n = -1;
901                         if (n != -1) {
902                                 n = strlen(bp) + 1;     /* for the \0 */
903                                 bp += n;
904                         }
905                         break;
906                 case T_A:
907                 case T_AAAA:
908                         if (ns_samename(hname, bp) != 1) {
909                                 cp += n;
910                                 continue;
911                         }
912                         if (type == T_A && n != INADDRSZ) {
913                                 cp += n;
914                                 continue;
915                         }
916                         if (type == T_AAAA && n != IN6ADDRSZ) {
917                                 cp += n;
918                                 continue;
919                         }
920
921                         /* make addrinfo. don't overwrite constant PAI */
922                         ai = *pai;
923                         ai.ai_family = (type == T_AAAA) ? AF_INET6 : AF_INET;
924                         cur->ai_next = addr2addrinfo(
925                                         (const struct addrinfo *)&ai,
926                                         (const char *)cp);
927                         if (cur->ai_next == NULL)
928                                 had_error++;
929
930                         if (!haveanswer) {
931                                 int nn;
932
933                                 nn = strlen(bp) + 1;    /* for the \0 */
934                                 if (nn >= MAXHOSTNAMELEN) {
935                                         cp += n;
936                                         had_error++;
937                                         continue;
938                                 }
939                                 pvt->host.h_name = bp;
940                                 hname = bp;
941                                 bp += nn;
942                         }
943                         /* Ensure alignment. */
944                         bp = (char *)(((u_long)bp + (sizeof(align) - 1)) &
945                                       ~(sizeof(align) - 1));
946                         /* Avoid overflows. */
947                         if (bp + n >= &pvt->hostbuf[sizeof pvt->hostbuf]) {
948                                 had_error++;
949                                 continue;
950                         }
951                         if (ret_aip) { /* need addrinfo. keep it. */
952                                 while (cur && cur->ai_next)
953                                         cur = cur->ai_next;
954                         } else if (cur->ai_next) { /* need hostent */
955                                 struct addrinfo *aip = cur->ai_next;
956
957                                 for (aip = cur->ai_next; aip;
958                                      aip = aip->ai_next) {
959                                         int m;
960
961                                         m = add_hostent(pvt, bp, hap, aip);
962                                         if (m < 0) {
963                                                 had_error++;
964                                                 break;
965                                         }
966                                         if (m == 0)
967                                                 continue;
968                                         if (hap < &pvt->h_addr_ptrs[MAXADDRS-1])
969                                                 hap++;
970                                         *hap = NULL;
971                                         bp += m;
972                                 }
973
974                                 freeaddrinfo(cur->ai_next);
975                                 cur->ai_next = NULL;
976                         }
977                         cp += n;
978                         break;
979                 default:
980                         abort();
981                 }
982                 if (!had_error)
983                         haveanswer++;
984         }
985         if (haveanswer) {
986                 if (ret_aip == NULL) {
987                         *ap = NULL;
988                         *hap = NULL;
989
990                         if (pvt->res->nsort && haveanswer > 1 && qtype == T_A)
991                                 addrsort(pvt->res, pvt->h_addr_ptrs,
992                                          haveanswer);
993                         if (pvt->host.h_name == NULL) {
994                                 n = strlen(qname) + 1;  /* for the \0 */
995                                 if (n > (ep - bp) || n >= MAXHOSTNAMELEN)
996                                         goto no_recovery;
997                                 strcpy(bp, qname);      /* (checked) */
998                                 pvt->host.h_name = bp;
999                                 bp += n;
1000                         }
1001                         if (pvt->res->options & RES_USE_INET6)
1002                                 map_v4v6_hostent(&pvt->host, &bp, ep);
1003                         RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
1004                         return (&pvt->host);
1005                 } else {
1006                         if ((pai->ai_flags & AI_CANONNAME) != 0) {
1007                                 if (pvt->host.h_name == NULL) {
1008                                         sentinel.ai_next->ai_canonname =
1009                                                 strdup(qname);
1010                                 }
1011                                 else {
1012                                         sentinel.ai_next->ai_canonname =
1013                                                 strdup(pvt->host.h_name);
1014                                 }
1015                         }
1016                         *ret_aip = sentinel.ai_next;
1017                         return(NULL);
1018                 }
1019         }
1020  no_recovery:
1021         if (sentinel.ai_next) {
1022                 /* this should be impossible, but check it for safety */
1023                 freeaddrinfo(sentinel.ai_next);
1024         }
1025         if (error == NETDB_SUCCESS)
1026                 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
1027         else
1028                 RES_SET_H_ERRNO(pvt->res, error);
1029         return(NULL);
1030 }
1031
1032 static int
1033 add_hostent(struct pvt *pvt, char *bp, char **hap, struct addrinfo *ai)
1034 {
1035         int addrlen;
1036         char *addrp;
1037         const char **tap;
1038         char *obp = bp;
1039
1040         switch(ai->ai_addr->sa_family) {
1041         case AF_INET6:
1042                 addrlen = IN6ADDRSZ;
1043                 addrp = (char *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
1044                 break;
1045         case AF_INET:
1046                 addrlen = INADDRSZ;
1047                 addrp = (char *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
1048                 break;
1049         default:
1050                 return(-1);     /* abort? */
1051         }
1052
1053         /* Ensure alignment. */
1054         bp = (char *)(((u_long)bp + (sizeof(align) - 1)) &
1055                       ~(sizeof(align) - 1));
1056         /* Avoid overflows. */
1057         if (bp + addrlen >= &pvt->hostbuf[sizeof pvt->hostbuf])
1058                 return(-1);
1059         if (hap >= &pvt->h_addr_ptrs[MAXADDRS-1])
1060                 return(0); /* fail, but not treat it as an error. */
1061
1062         /* Suppress duplicates. */
1063         for (tap = (const char **)pvt->h_addr_ptrs;
1064              *tap != NULL;
1065              tap++)
1066                 if (memcmp(*tap, addrp, addrlen) == 0)
1067                         break;
1068         if (*tap != NULL)
1069                 return (0);
1070
1071         memcpy(*hap = bp, addrp, addrlen);
1072         return((bp + addrlen) - obp);
1073 }
1074
1075 static void
1076 map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) {
1077         char **ap;
1078
1079         if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1080                 return;
1081         hp->h_addrtype = AF_INET6;
1082         hp->h_length = IN6ADDRSZ;
1083         for (ap = hp->h_addr_list; *ap; ap++) {
1084                 int i = (u_long)*bpp % sizeof(align);
1085
1086                 if (i != 0)
1087                         i = sizeof(align) - i;
1088
1089                 if ((ep - *bpp) < (i + IN6ADDRSZ)) {
1090                         /* Out of memory.  Truncate address list here. */
1091                         *ap = NULL;
1092                         return;
1093                 }
1094                 *bpp += i;
1095                 map_v4v6_address(*ap, *bpp);
1096                 *ap = *bpp;
1097                 *bpp += IN6ADDRSZ;
1098         }
1099 }
1100
1101 static void
1102 addrsort(res_state statp, char **ap, int num) {
1103         int i, j, needsort = 0, aval[MAXADDRS];
1104         char **p;
1105
1106         p = ap;
1107         for (i = 0; i < num; i++, p++) {
1108                 for (j = 0 ; (unsigned)j < statp->nsort; j++)
1109                         if (statp->sort_list[j].addr.s_addr == 
1110                             (((struct in_addr *)(*p))->s_addr &
1111                              statp->sort_list[j].mask))
1112                                 break;
1113                 aval[i] = j;
1114                 if (needsort == 0 && i > 0 && j < aval[i-1])
1115                         needsort = i;
1116         }
1117         if (!needsort)
1118                 return;
1119
1120         while (needsort < num) {
1121                 for (j = needsort - 1; j >= 0; j--) {
1122                         if (aval[j] > aval[j+1]) {
1123                                 char *hp;
1124
1125                                 i = aval[j];
1126                                 aval[j] = aval[j+1];
1127                                 aval[j+1] = i;
1128
1129                                 hp = ap[j];
1130                                 ap[j] = ap[j+1];
1131                                 ap[j+1] = hp;
1132
1133                         } else
1134                                 break;
1135                 }
1136                 needsort++;
1137         }
1138 }
1139
1140 static int
1141 init(struct irs_ho *this) {
1142         struct pvt *pvt = (struct pvt *)this->private;
1143         
1144         if (!pvt->res && !ho_res_get(this))
1145                 return (-1);
1146         if (((pvt->res->options & RES_INIT) == 0U) &&
1147             res_ninit(pvt->res) == -1)
1148                 return (-1);
1149         return (0);
1150 }