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