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