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