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 * 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 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 * 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 * 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 * 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 * 507 ho_next(struct irs_ho *this) { 508 509 UNUSED(this); 510 511 return (NULL); 512 } 513 514 static void 515 ho_rewind(struct irs_ho *this) { 516 517 UNUSED(this); 518 519 /* NOOP */ 520 } 521 522 static void 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 * 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 * 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 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 * 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 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 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 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 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