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