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