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