1 /* $FreeBSD: src/lib/libc/net/name6.c,v 1.6.2.9 2002/11/02 18:54:57 ume Exp $ */ 2 /* $DragonFly: src/lib/libc/net/name6.c,v 1.8 2005/09/19 09:34:53 asmodai Exp $ */ 3 /* $KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $ */ 4 5 /* 6 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 /* 34 * ++Copyright++ 1985, 1988, 1993 35 * - 36 * Copyright (c) 1985, 1988, 1993 37 * The Regents of the University of California. All rights reserved. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 * - 63 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 64 * 65 * Permission to use, copy, modify, and distribute this software for any 66 * purpose with or without fee is hereby granted, provided that the above 67 * copyright notice and this permission notice appear in all copies, and that 68 * the name of Digital Equipment Corporation not be used in advertising or 69 * publicity pertaining to distribution of the document or software without 70 * specific, written prior permission. 71 * 72 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 73 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 74 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 75 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 76 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 77 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 78 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 79 * SOFTWARE. 80 * - 81 * --Copyright-- 82 */ 83 84 /* 85 * Atsushi Onoe <onoe@sm.sony.co.jp> 86 */ 87 88 /* 89 * TODO for thread safe 90 * use mutex for _hostconf, _hostconf_init. 91 * rewrite resolvers to be thread safe 92 */ 93 94 #include "namespace.h" 95 #include <sys/param.h> 96 #include <sys/socket.h> 97 #include <sys/time.h> 98 #include <sys/queue.h> 99 #include <netinet/in.h> 100 101 #include <arpa/inet.h> 102 #include <arpa/nameser.h> 103 104 #include <errno.h> 105 #include <netdb.h> 106 #include <resolv.h> 107 #include <stdio.h> 108 #include <stdlib.h> 109 #include <string.h> 110 #include <unistd.h> 111 #include "un-namespace.h" 112 113 #ifndef _PATH_HOSTS 114 #define _PATH_HOSTS "/etc/hosts" 115 #endif 116 117 #ifndef MAXALIASES 118 #define MAXALIASES 10 119 #endif 120 #ifndef MAXADDRS 121 #define MAXADDRS 20 122 #endif 123 #ifndef MAXDNAME 124 #define MAXDNAME 1025 125 #endif 126 127 #ifdef INET6 128 #define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \ 129 sizeof(struct in_addr)) 130 #else 131 #define ADDRLEN(af) sizeof(struct in_addr) 132 #endif 133 134 #define MAPADDR(ab, ina) \ 135 do { \ 136 memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \ 137 memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \ 138 memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \ 139 } while (0) 140 #define MAPADDRENABLED(flags) \ 141 (((flags) & AI_V4MAPPED) || \ 142 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled())) 143 144 union inx_addr { 145 struct in_addr in_addr; 146 #ifdef INET6 147 struct in6_addr in6_addr; 148 #endif 149 struct { 150 u_char mau_zero[10]; 151 u_char mau_one[2]; 152 struct in_addr mau_inaddr; 153 } map_addr_un; 154 #define map_zero map_addr_un.mau_zero 155 #define map_one map_addr_un.mau_one 156 #define map_inaddr map_addr_un.mau_inaddr 157 }; 158 159 static struct hostent *_hpcopy(struct hostent *hp, int *errp); 160 static struct hostent *_hpaddr(int af, const char *name, void *addr, int *errp); 161 static struct hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp); 162 #ifdef INET6 163 static struct hostent *_hpmapv6(struct hostent *hp, int *errp); 164 #endif 165 static struct hostent *_hpsort(struct hostent *hp); 166 static struct hostent *_ghbyname(const char *name, int af, int flags, int *errp); 167 static char *_hgetword(char **pp); 168 static int _mapped_addr_enabled(void); 169 170 static FILE *_files_open(int *errp); 171 static struct hostent *_files_ghbyname(const char *name, int af, int *errp); 172 static struct hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp); 173 #ifdef YP 174 static struct hostent *_nis_ghbyname(const char *name, int af, int *errp); 175 static struct hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp); 176 #endif 177 static struct hostent *_dns_ghbyname(const char *name, int af, int *errp); 178 static struct hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp); 179 #ifdef ICMPNL 180 static struct hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp); 181 #endif /* ICMPNL */ 182 183 /* Make getipnodeby*() thread-safe in libc for use with kernel threads. */ 184 #include "libc_private.h" 185 #include "spinlock.h" 186 /* 187 * XXX: Our res_*() is not thread-safe. So, we share lock between 188 * getaddrinfo() and getipnodeby*(). Still, we cannot use 189 * getaddrinfo() and getipnodeby*() in conjunction with other 190 * functions which call res_*(). 191 */ 192 extern spinlock_t __getaddrinfo_thread_lock; 193 #define THREAD_LOCK() \ 194 if (__isthreaded) _SPINLOCK(&__getaddrinfo_thread_lock); 195 #define THREAD_UNLOCK() \ 196 if (__isthreaded) _SPINUNLOCK(&__getaddrinfo_thread_lock); 197 198 /* 199 * Select order host function. 200 */ 201 #define MAXHOSTCONF 4 202 203 #ifndef HOSTCONF 204 # define HOSTCONF "/etc/host.conf" 205 #endif /* !HOSTCONF */ 206 207 struct _hostconf { 208 struct hostent *(*byname)(const char *name, int af, int *errp); 209 struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp); 210 }; 211 212 /* default order */ 213 static struct _hostconf _hostconf[MAXHOSTCONF] = { 214 { _dns_ghbyname, _dns_ghbyaddr }, 215 { _files_ghbyname, _files_ghbyaddr }, 216 #ifdef ICMPNL 217 { NULL, _icmp_ghbyaddr }, 218 #endif /* ICMPNL */ 219 }; 220 221 static int _hostconf_init_done; 222 static void _hostconf_init(void); 223 224 /* 225 * Initialize hostconf structure. 226 */ 227 228 static void 229 _hostconf_init(void) 230 { 231 FILE *fp; 232 int n; 233 const char *p; 234 char *line; 235 char buf[BUFSIZ]; 236 237 _hostconf_init_done = 1; 238 n = 0; 239 p = HOSTCONF; 240 if ((fp = fopen(p, "r")) == NULL) 241 return; 242 while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) { 243 line = buf; 244 if ((p = _hgetword(&line)) == NULL) 245 continue; 246 do { 247 if (strcmp(p, "hosts") == 0 248 || strcmp(p, "local") == 0 249 || strcmp(p, "file") == 0 250 || strcmp(p, "files") == 0) { 251 _hostconf[n].byname = _files_ghbyname; 252 _hostconf[n].byaddr = _files_ghbyaddr; 253 n++; 254 } 255 else if (strcmp(p, "dns") == 0 256 || strcmp(p, "bind") == 0) { 257 _hostconf[n].byname = _dns_ghbyname; 258 _hostconf[n].byaddr = _dns_ghbyaddr; 259 n++; 260 } 261 #ifdef YP 262 else if (strcmp(p, "nis") == 0) { 263 _hostconf[n].byname = _nis_ghbyname; 264 _hostconf[n].byaddr = _nis_ghbyaddr; 265 n++; 266 } 267 #endif 268 #ifdef ICMPNL 269 else if (strcmp(p, "icmp") == 0) { 270 _hostconf[n].byname = NULL; 271 _hostconf[n].byaddr = _icmp_ghbyaddr; 272 n++; 273 } 274 #endif /* ICMPNL */ 275 } while ((p = _hgetword(&line)) != NULL); 276 } 277 fclose(fp); 278 if (n < 0) { 279 /* no keyword found. do not change default configuration */ 280 return; 281 } 282 for (; n < MAXHOSTCONF; n++) { 283 _hostconf[n].byname = NULL; 284 _hostconf[n].byaddr = NULL; 285 } 286 } 287 288 /* 289 * Check if kernel supports mapped address. 290 * implementation dependent 291 */ 292 #ifdef __KAME__ 293 #include <sys/sysctl.h> 294 #endif /* __KAME__ */ 295 296 static int 297 _mapped_addr_enabled(void) 298 { 299 /* implementation dependent check */ 300 #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR) 301 int mib[4]; 302 size_t len; 303 int val; 304 305 mib[0] = CTL_NET; 306 mib[1] = PF_INET6; 307 mib[2] = IPPROTO_IPV6; 308 mib[3] = IPV6CTL_MAPPED_ADDR; 309 len = sizeof(val); 310 if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0) 311 return 1; 312 #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */ 313 return 0; 314 } 315 316 /* 317 * Functions defined in RFC2553 318 * getipnodebyname, getipnodebyaddr, freehostent 319 */ 320 321 static struct hostent * 322 _ghbyname(const char *name, int af, int flags, int *errp) 323 { 324 struct hostent *hp; 325 int i; 326 327 if (flags & AI_ADDRCONFIG) { 328 int s; 329 330 /* 331 * TODO: 332 * Note that implementation dependent test for address 333 * configuration should be done everytime called 334 * (or apropriate interval), 335 * because addresses will be dynamically assigned or deleted. 336 */ 337 if (af == AF_UNSPEC) { 338 if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 339 af = AF_INET; 340 else { 341 _close(s); 342 if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) 343 af = AF_INET6; 344 else 345 _close(s); 346 } 347 348 } 349 if (af != AF_UNSPEC) { 350 if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 351 return NULL; 352 _close(s); 353 } 354 } 355 356 THREAD_LOCK(); 357 for (i = 0; i < MAXHOSTCONF; i++) { 358 if (_hostconf[i].byname 359 && (hp = (*_hostconf[i].byname)(name, af, errp)) != NULL) { 360 THREAD_UNLOCK(); 361 return hp; 362 } 363 } 364 THREAD_UNLOCK(); 365 366 return NULL; 367 } 368 369 /* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */ 370 static struct hostent * 371 _getipnodebyname_multi(const char *name, int af, int flags, int *errp) 372 { 373 struct hostent *hp; 374 union inx_addr addrbuf; 375 376 /* XXX: PF_UNSPEC is only supposed to be passed from getaddrinfo() */ 377 if (af != AF_INET 378 #ifdef INET6 379 && af != AF_INET6 380 #endif 381 && af != PF_UNSPEC 382 ) 383 { 384 *errp = NO_RECOVERY; 385 return NULL; 386 } 387 388 #ifdef INET6 389 /* special case for literal address */ 390 if (inet_pton(AF_INET6, name, &addrbuf) == 1) { 391 if (af != AF_INET6) { 392 *errp = HOST_NOT_FOUND; 393 return NULL; 394 } 395 return _hpaddr(af, name, &addrbuf, errp); 396 } 397 #endif 398 if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) { 399 if (af != AF_INET) { 400 if (MAPADDRENABLED(flags)) { 401 MAPADDR(&addrbuf, &addrbuf.in_addr); 402 } else { 403 *errp = HOST_NOT_FOUND; 404 return NULL; 405 } 406 } 407 return _hpaddr(af, name, &addrbuf, errp); 408 } 409 410 if (!_hostconf_init_done) 411 _hostconf_init(); 412 413 *errp = HOST_NOT_FOUND; 414 hp = _ghbyname(name, af, flags, errp); 415 416 #ifdef INET6 417 if (af == AF_INET6 418 && ((flags & AI_ALL) || hp == NULL) 419 && (MAPADDRENABLED(flags))) { 420 struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp); 421 if (hp == NULL) 422 hp = _hpmapv6(hp2, errp); 423 else { 424 if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) { 425 freehostent(hp2); 426 hp2 = NULL; 427 } 428 hp = _hpmerge(hp, hp2, errp); 429 } 430 } 431 #endif 432 return _hpsort(hp); 433 } 434 435 struct hostent * 436 getipnodebyname(const char *name, int af, int flags, int *errp) 437 { 438 if (af != AF_INET 439 #ifdef INET6 440 && af != AF_INET6 441 #endif 442 ) 443 { 444 *errp = NO_RECOVERY; 445 return NULL; 446 } 447 return(_getipnodebyname_multi(name, af ,flags, errp)); 448 } 449 450 struct hostent * 451 getipnodebyaddr(const void *src, size_t len, int af, int *errp) 452 { 453 struct hostent *hp; 454 int i; 455 #ifdef INET6 456 struct in6_addr addrbuf; 457 #else 458 struct in_addr addrbuf; 459 #endif 460 461 *errp = HOST_NOT_FOUND; 462 463 switch (af) { 464 case AF_INET: 465 if (len != sizeof(struct in_addr)) { 466 *errp = NO_RECOVERY; 467 return NULL; 468 } 469 if ((long)src & ~(sizeof(struct in_addr) - 1)) { 470 memcpy(&addrbuf, src, len); 471 src = &addrbuf; 472 } 473 if (((const struct in_addr *)src)->s_addr == 0) 474 return NULL; 475 break; 476 #ifdef INET6 477 case AF_INET6: 478 if (len != sizeof(struct in6_addr)) { 479 *errp = NO_RECOVERY; 480 return NULL; 481 } 482 if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/ 483 memcpy(&addrbuf, src, len); 484 src = &addrbuf; 485 } 486 if (IN6_IS_ADDR_UNSPECIFIED((const struct in6_addr *)src)) 487 return NULL; 488 if (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src) 489 || IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) { 490 src = (const char *)src + 491 (sizeof(struct in6_addr) - sizeof(struct in_addr)); 492 af = AF_INET; 493 len = sizeof(struct in_addr); 494 } 495 break; 496 #endif 497 default: 498 *errp = NO_RECOVERY; 499 return NULL; 500 } 501 502 if (!_hostconf_init_done) 503 _hostconf_init(); 504 THREAD_LOCK(); 505 for (i = 0; i < MAXHOSTCONF; i++) { 506 if (_hostconf[i].byaddr 507 && (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL) { 508 THREAD_UNLOCK(); 509 return hp; 510 } 511 } 512 THREAD_UNLOCK(); 513 514 return NULL; 515 } 516 517 void 518 freehostent(struct hostent *ptr) 519 { 520 free(ptr); 521 } 522 523 #if 0 524 525 /* XXX: should be deprecated */ 526 struct hostent * 527 getnodebyname(const char *name, int af, int flags) 528 { 529 return getipnodebyname(name, af, flags, &h_errno); 530 } 531 532 #ifdef __warn_references 533 __warn_references(getnodebyname, 534 "warning: getnodebyname() deprecated, " 535 "should use getaddrinfo() or getipnodebyname()"); 536 #endif 537 538 struct hostent * 539 getnodebyaddr(const void *src, size_t len, int af) 540 { 541 return getipnodebyaddr(src, len, af, &h_errno); 542 } 543 544 #ifdef __warn_references 545 __warn_references(getnodebyaddr, 546 "warning: getnodebyaddr() deprecated, " 547 "should use getnameinfo() or getipnodebyaddr()"); 548 #endif 549 550 #endif 551 552 /* 553 * Private utility functions 554 */ 555 556 /* 557 * _hpcopy: allocate and copy hostent structure 558 */ 559 static struct hostent * 560 _hpcopy(struct hostent *hp, int *errp) 561 { 562 struct hostent *nhp; 563 char *cp, **pp; 564 int size, addrsize; 565 int nalias = 0, naddr = 0; 566 int al_off; 567 int i; 568 569 if (hp == NULL) 570 return hp; 571 572 /* count size to be allocated */ 573 size = sizeof(struct hostent); 574 if (hp->h_name != NULL) 575 size += strlen(hp->h_name) + 1; 576 if ((pp = hp->h_aliases) != NULL) { 577 for (i = 0; *pp != NULL; i++, pp++) { 578 if (**pp != '\0') { 579 size += strlen(*pp) + 1; 580 nalias++; 581 } 582 } 583 } 584 /* adjust alignment */ 585 size = ALIGN(size); 586 al_off = size; 587 size += sizeof(char *) * (nalias + 1); 588 addrsize = ALIGN(hp->h_length); 589 if ((pp = hp->h_addr_list) != NULL) { 590 while (*pp++ != NULL) 591 naddr++; 592 } 593 size += addrsize * naddr; 594 size += sizeof(char *) * (naddr + 1); 595 596 /* copy */ 597 if ((nhp = (struct hostent *)malloc(size)) == NULL) { 598 *errp = TRY_AGAIN; 599 return NULL; 600 } 601 cp = (char *)&nhp[1]; 602 if (hp->h_name != NULL) { 603 nhp->h_name = cp; 604 strcpy(cp, hp->h_name); 605 cp += strlen(cp) + 1; 606 } else 607 nhp->h_name = NULL; 608 nhp->h_aliases = (char **)((char *)nhp + al_off); 609 if ((pp = hp->h_aliases) != NULL) { 610 for (i = 0; *pp != NULL; pp++) { 611 if (**pp != '\0') { 612 nhp->h_aliases[i++] = cp; 613 strcpy(cp, *pp); 614 cp += strlen(cp) + 1; 615 } 616 } 617 } 618 nhp->h_aliases[nalias] = NULL; 619 cp = (char *)&nhp->h_aliases[nalias + 1]; 620 nhp->h_addrtype = hp->h_addrtype; 621 nhp->h_length = hp->h_length; 622 nhp->h_addr_list = (char **)cp; 623 if ((pp = hp->h_addr_list) != NULL) { 624 cp = (char *)&nhp->h_addr_list[naddr + 1]; 625 for (i = 0; *pp != NULL; pp++) { 626 nhp->h_addr_list[i++] = cp; 627 memcpy(cp, *pp, hp->h_length); 628 cp += addrsize; 629 } 630 } 631 nhp->h_addr_list[naddr] = NULL; 632 return nhp; 633 } 634 635 /* 636 * _hpaddr: construct hostent structure with one address 637 */ 638 static struct hostent * 639 _hpaddr(int af, const char *name, void *addr, int *errp) 640 { 641 struct hostent *hp, hpbuf; 642 char *addrs[2]; 643 644 hp = &hpbuf; 645 hp->h_name = name; 646 hp->h_aliases = NULL; 647 hp->h_addrtype = af; 648 hp->h_length = ADDRLEN(af); 649 hp->h_addr_list = addrs; 650 addrs[0] = addr; 651 addrs[1] = NULL; 652 return _hpcopy(hp, errp); 653 } 654 655 /* 656 * _hpmerge: merge 2 hostent structure, arguments will be freed 657 */ 658 static struct hostent * 659 _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp) 660 { 661 int i, j; 662 int naddr, nalias; 663 char **pp; 664 struct hostent *hp, hpbuf; 665 char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1]; 666 union inx_addr addrbuf[MAXADDRS]; 667 668 if (hp1 == NULL) 669 return hp2; 670 if (hp2 == NULL) 671 return hp1; 672 673 #define HP(i) (i == 1 ? hp1 : hp2) 674 hp = &hpbuf; 675 hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name); 676 hp->h_aliases = aliases; 677 nalias = 0; 678 for (i = 1; i <= 2; i++) { 679 if ((pp = HP(i)->h_aliases) == NULL) 680 continue; 681 for (; nalias < MAXALIASES && *pp != NULL; pp++) { 682 /* check duplicates */ 683 for (j = 0; j < nalias; j++) 684 if (strcasecmp(*pp, aliases[j]) == 0) 685 break; 686 if (j == nalias) 687 aliases[nalias++] = *pp; 688 } 689 } 690 aliases[nalias] = NULL; 691 #ifdef INET6 692 if (hp1->h_length != hp2->h_length) { 693 hp->h_addrtype = AF_INET6; 694 hp->h_length = sizeof(struct in6_addr); 695 } else { 696 #endif 697 hp->h_addrtype = hp1->h_addrtype; 698 hp->h_length = hp1->h_length; 699 #ifdef INET6 700 } 701 #endif 702 hp->h_addr_list = addrs; 703 naddr = 0; 704 for (i = 1; i <= 2; i++) { 705 if ((pp = HP(i)->h_addr_list) == NULL) 706 continue; 707 if (HP(i)->h_length == hp->h_length) { 708 while (naddr < MAXADDRS && *pp != NULL) 709 addrs[naddr++] = *pp++; 710 } else { 711 /* copy IPv4 addr as mapped IPv6 addr */ 712 while (naddr < MAXADDRS && *pp != NULL) { 713 MAPADDR(&addrbuf[naddr], *pp++); 714 addrs[naddr] = (char *)&addrbuf[naddr]; 715 naddr++; 716 } 717 } 718 } 719 addrs[naddr] = NULL; 720 hp = _hpcopy(hp, errp); 721 freehostent(hp1); 722 freehostent(hp2); 723 return hp; 724 } 725 726 /* 727 * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses 728 */ 729 #ifdef INET6 730 static struct hostent * 731 _hpmapv6(struct hostent *hp, int *errp) 732 { 733 struct hostent *hp6; 734 735 if (hp == NULL) 736 return NULL; 737 if (hp->h_addrtype == AF_INET6) 738 return hp; 739 740 /* make dummy hostent to convert IPv6 address */ 741 if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) { 742 *errp = TRY_AGAIN; 743 return NULL; 744 } 745 hp6->h_name = NULL; 746 hp6->h_aliases = NULL; 747 hp6->h_addrtype = AF_INET6; 748 hp6->h_length = sizeof(struct in6_addr); 749 hp6->h_addr_list = NULL; 750 return _hpmerge(hp6, hp, errp); 751 } 752 #endif 753 754 /* 755 * _hpsort: sort address by sortlist 756 */ 757 static struct hostent * 758 _hpsort(struct hostent *hp) 759 { 760 int i, j, n; 761 u_char *ap, *sp, *mp, **pp; 762 char t; 763 char order[MAXADDRS]; 764 int nsort = _res.nsort; 765 766 if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0) 767 return hp; 768 for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) { 769 for (j = 0; j < nsort; j++) { 770 #ifdef INET6 771 if (_res_ext.sort_list[j].af != hp->h_addrtype) 772 continue; 773 sp = (u_char *)&_res_ext.sort_list[j].addr; 774 mp = (u_char *)&_res_ext.sort_list[j].mask; 775 #else 776 sp = (u_char *)&_res.sort_list[j].addr; 777 mp = (u_char *)&_res.sort_list[j].mask; 778 #endif 779 for (n = 0; n < hp->h_length; n++) { 780 if ((ap[n] & mp[n]) != sp[n]) 781 break; 782 } 783 if (n == hp->h_length) 784 break; 785 } 786 order[i] = j; 787 } 788 n = i; 789 pp = (u_char **)hp->h_addr_list; 790 for (i = 0; i < n - 1; i++) { 791 for (j = i + 1; j < n; j++) { 792 if (order[i] > order[j]) { 793 ap = pp[i]; 794 pp[i] = pp[j]; 795 pp[j] = ap; 796 t = order[i]; 797 order[i] = order[j]; 798 order[j] = t; 799 } 800 } 801 } 802 return hp; 803 } 804 805 static char * 806 _hgetword(char **pp) 807 { 808 char c, *p, *ret; 809 const char *sp; 810 static const char sep[] = "# \t\n"; 811 812 ret = NULL; 813 for (p = *pp; (c = *p) != '\0'; p++) { 814 for (sp = sep; *sp != '\0'; sp++) { 815 if (c == *sp) 816 break; 817 } 818 if (c == '#') 819 p[1] = '\0'; /* ignore rest of line */ 820 if (ret == NULL) { 821 if (*sp == '\0') 822 ret = p; 823 } else { 824 if (*sp != '\0') { 825 *p++ = '\0'; 826 break; 827 } 828 } 829 } 830 *pp = p; 831 if (ret == NULL || *ret == '\0') 832 return NULL; 833 return ret; 834 } 835 836 /* 837 * FILES (/etc/hosts) 838 */ 839 840 static FILE * 841 _files_open(int *errp) 842 { 843 FILE *fp; 844 fp = fopen(_PATH_HOSTS, "r"); 845 if (fp == NULL) 846 *errp = NO_RECOVERY; 847 return fp; 848 } 849 850 static struct hostent * 851 _files_ghbyname(const char *name, int af, int *errp) 852 { 853 int match, nalias; 854 char *p, *line, *addrstr, *cname; 855 FILE *fp; 856 struct hostent *rethp, *hp, hpbuf; 857 char *aliases[MAXALIASES + 1], *addrs[2]; 858 union inx_addr addrbuf; 859 char buf[BUFSIZ]; 860 int af0 = af; 861 862 if ((fp = _files_open(errp)) == NULL) 863 return NULL; 864 rethp = hp = NULL; 865 866 while (fgets(buf, sizeof(buf), fp)) { 867 line = buf; 868 if ((addrstr = _hgetword(&line)) == NULL 869 || (cname = _hgetword(&line)) == NULL) 870 continue; 871 match = (strcasecmp(cname, name) == 0); 872 nalias = 0; 873 while ((p = _hgetword(&line)) != NULL) { 874 if (!match) 875 match = (strcasecmp(p, name) == 0); 876 if (nalias < MAXALIASES) 877 aliases[nalias++] = p; 878 } 879 if (!match) 880 continue; 881 switch (af0) { 882 case AF_INET: 883 if (inet_aton(addrstr, (struct in_addr *)&addrbuf) 884 != 1) { 885 *errp = NO_DATA; /* name found */ 886 continue; 887 } 888 af = af0; 889 break; 890 #ifdef INET6 891 case AF_INET6: 892 if (inet_pton(af, addrstr, &addrbuf) != 1) { 893 *errp = NO_DATA; /* name found */ 894 continue; 895 } 896 af = af0; 897 break; 898 #endif 899 case AF_UNSPEC: 900 if (inet_aton(addrstr, (struct in_addr *)&addrbuf) 901 == 1) { 902 af = AF_INET; 903 break; 904 } 905 #ifdef INET6 906 if (inet_pton(AF_INET6, addrstr, &addrbuf) == 1) { 907 af = AF_INET6; 908 break; 909 } 910 #endif 911 *errp = NO_DATA; /* name found */ 912 continue; 913 /* NOTREACHED */ 914 } 915 hp = &hpbuf; 916 hp->h_name = cname; 917 hp->h_aliases = aliases; 918 aliases[nalias] = NULL; 919 hp->h_addrtype = af; 920 hp->h_length = ADDRLEN(af); 921 hp->h_addr_list = addrs; 922 addrs[0] = (char *)&addrbuf; 923 addrs[1] = NULL; 924 hp = _hpcopy(hp, errp); 925 rethp = _hpmerge(rethp, hp, errp); 926 } 927 fclose(fp); 928 return rethp; 929 } 930 931 static struct hostent * 932 _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 933 { 934 int nalias; 935 char *p, *line; 936 FILE *fp; 937 struct hostent *hp, hpbuf; 938 char *aliases[MAXALIASES + 1], *addrs[2]; 939 union inx_addr addrbuf; 940 char buf[BUFSIZ]; 941 942 if ((fp = _files_open(errp)) == NULL) 943 return NULL; 944 hp = NULL; 945 while (fgets(buf, sizeof(buf), fp)) { 946 line = buf; 947 if ((p = _hgetword(&line)) == NULL 948 || (af == AF_INET 949 ? inet_aton(p, (struct in_addr *)&addrbuf) 950 : inet_pton(af, p, &addrbuf)) != 1 951 || memcmp(addr, &addrbuf, addrlen) != 0 952 || (p = _hgetword(&line)) == NULL) 953 continue; 954 hp = &hpbuf; 955 hp->h_name = p; 956 hp->h_aliases = aliases; 957 nalias = 0; 958 while ((p = _hgetword(&line)) != NULL) { 959 if (nalias < MAXALIASES) 960 aliases[nalias++] = p; 961 } 962 aliases[nalias] = NULL; 963 hp->h_addrtype = af; 964 hp->h_length = addrlen; 965 hp->h_addr_list = addrs; 966 addrs[0] = (char *)&addrbuf; 967 addrs[1] = NULL; 968 hp = _hpcopy(hp, errp); 969 break; 970 } 971 fclose(fp); 972 return hp; 973 } 974 975 #ifdef YP 976 /* 977 * NIS 978 * 979 * XXX actually a hack, these are INET4 specific. 980 */ 981 static struct hostent * 982 _nis_ghbyname(const char *name, int af, int *errp) 983 { 984 struct hostent *hp = NULL; 985 986 if (af == AF_UNSPEC) 987 af = AF_INET; 988 if (af == AF_INET) { 989 hp = _gethostbynisname(name, af); 990 if (hp != NULL) 991 hp = _hpcopy(hp, errp); 992 } 993 return (hp); 994 995 } 996 997 static struct hostent * 998 _nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 999 { 1000 struct hostent *hp = NULL; 1001 1002 if (af == AF_INET) { 1003 hp = _gethostbynisaddr(addr, addrlen, af); 1004 if (hp != NULL) 1005 hp = _hpcopy(hp, errp); 1006 } 1007 return (hp); 1008 } 1009 #endif 1010 1011 struct __res_type_list { 1012 SLIST_ENTRY(__res_type_list) rtl_entry; 1013 int rtl_type; 1014 }; 1015 1016 #define MAXPACKET (64*1024) 1017 1018 typedef union { 1019 HEADER hdr; 1020 u_char buf[MAXPACKET]; 1021 } querybuf; 1022 1023 static struct hostent *getanswer (const querybuf *, int, const char *, 1024 int, struct hostent *, int *); 1025 1026 /* 1027 * we don't need to take care about sorting, nor IPv4 mapped address here. 1028 */ 1029 static struct hostent * 1030 getanswer(answer, anslen, qname, qtype, template, errp) 1031 const querybuf *answer; 1032 int anslen; 1033 const char *qname; 1034 int qtype; 1035 struct hostent *template; 1036 int *errp; 1037 { 1038 const HEADER *hp; 1039 const u_char *cp; 1040 int n; 1041 const u_char *eom, *erdata; 1042 char *bp, **ap, **hap, *obp; 1043 int type, class, buflen, ancount, qdcount; 1044 int haveanswer, had_error; 1045 char tbuf[MAXDNAME]; 1046 const char *tname; 1047 int (*name_ok) (const char *); 1048 static char *h_addr_ptrs[MAXADDRS + 1]; 1049 static char *host_aliases[MAXALIASES]; 1050 static char hostbuf[8*1024]; 1051 1052 #define BOUNDED_INCR(x) \ 1053 do { \ 1054 cp += x; \ 1055 if (cp > eom) { \ 1056 *errp = NO_RECOVERY; \ 1057 return (NULL); \ 1058 } \ 1059 } while (0) 1060 1061 #define BOUNDS_CHECK(ptr, count) \ 1062 do { \ 1063 if ((ptr) + (count) > eom) { \ 1064 *errp = NO_RECOVERY; \ 1065 return (NULL); \ 1066 } \ 1067 } while (0) 1068 1069 /* XXX do {} while (0) cannot be put here */ 1070 #define DNS_ASSERT(x) \ 1071 { \ 1072 if (!(x)) { \ 1073 cp += n; \ 1074 continue; \ 1075 } \ 1076 } 1077 1078 /* XXX do {} while (0) cannot be put here */ 1079 #define DNS_FATAL(x) \ 1080 { \ 1081 if (!(x)) { \ 1082 had_error++; \ 1083 continue; \ 1084 } \ 1085 } 1086 1087 tname = qname; 1088 template->h_name = NULL; 1089 eom = answer->buf + anslen; 1090 switch (qtype) { 1091 case T_A: 1092 case T_AAAA: 1093 name_ok = res_hnok; 1094 break; 1095 case T_PTR: 1096 name_ok = res_dnok; 1097 break; 1098 default: 1099 return (NULL); /* XXX should be abort(); */ 1100 } 1101 /* 1102 * find first satisfactory answer 1103 */ 1104 hp = &answer->hdr; 1105 ancount = ntohs(hp->ancount); 1106 qdcount = ntohs(hp->qdcount); 1107 bp = hostbuf; 1108 buflen = sizeof hostbuf; 1109 cp = answer->buf; 1110 BOUNDED_INCR(HFIXEDSZ); 1111 if (qdcount != 1) { 1112 *errp = NO_RECOVERY; 1113 return (NULL); 1114 } 1115 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1116 if ((n < 0) || !(*name_ok)(bp)) { 1117 *errp = NO_RECOVERY; 1118 return (NULL); 1119 } 1120 BOUNDED_INCR(n + QFIXEDSZ); 1121 if (qtype == T_A || qtype == T_AAAA) { 1122 /* res_send() has already verified that the query name is the 1123 * same as the one we sent; this just gets the expanded name 1124 * (i.e., with the succeeding search-domain tacked on). 1125 */ 1126 n = strlen(bp) + 1; /* for the \0 */ 1127 if (n >= MAXHOSTNAMELEN) { 1128 *errp = NO_RECOVERY; 1129 return (NULL); 1130 } 1131 template->h_name = bp; 1132 bp += n; 1133 buflen -= n; 1134 /* The qname can be abbreviated, but h_name is now absolute. */ 1135 qname = template->h_name; 1136 } 1137 ap = host_aliases; 1138 *ap = NULL; 1139 template->h_aliases = host_aliases; 1140 hap = h_addr_ptrs; 1141 *hap = NULL; 1142 template->h_addr_list = h_addr_ptrs; 1143 haveanswer = 0; 1144 had_error = 0; 1145 while (ancount-- > 0 && cp < eom && !had_error) { 1146 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1147 DNS_FATAL(n >= 0); 1148 DNS_FATAL((*name_ok)(bp)); 1149 cp += n; /* name */ 1150 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); 1151 NS_GET16(type, cp); /* type */ 1152 NS_GET16(class, cp); /* class */ 1153 cp += INT32SZ; /* skip TTL */ 1154 NS_GET16(n, cp); /* len */ 1155 BOUNDS_CHECK(cp, n); 1156 erdata = cp + n; 1157 DNS_ASSERT(class == C_IN); 1158 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { 1159 if (ap >= &host_aliases[MAXALIASES-1]) 1160 continue; 1161 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1162 DNS_FATAL(n >= 0); 1163 DNS_FATAL((*name_ok)(tbuf)); 1164 cp += n; 1165 if (cp != erdata) { 1166 *errp = NO_RECOVERY; 1167 return (NULL); 1168 } 1169 /* Store alias. */ 1170 *ap++ = bp; 1171 n = strlen(bp) + 1; /* for the \0 */ 1172 DNS_FATAL(n < MAXHOSTNAMELEN); 1173 bp += n; 1174 buflen -= n; 1175 /* Get canonical name. */ 1176 n = strlen(tbuf) + 1; /* for the \0 */ 1177 DNS_FATAL(n <= buflen); 1178 DNS_FATAL(n < MAXHOSTNAMELEN); 1179 strcpy(bp, tbuf); 1180 template->h_name = bp; 1181 bp += n; 1182 buflen -= n; 1183 continue; 1184 } 1185 if (qtype == T_PTR && type == T_CNAME) { 1186 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1187 if (n < 0 || !res_dnok(tbuf)) { 1188 had_error++; 1189 continue; 1190 } 1191 cp += n; 1192 if (cp != erdata) { 1193 *errp = NO_RECOVERY; 1194 return (NULL); 1195 } 1196 /* Get canonical name. */ 1197 n = strlen(tbuf) + 1; /* for the \0 */ 1198 if (n > buflen || n >= MAXHOSTNAMELEN) { 1199 had_error++; 1200 continue; 1201 } 1202 strcpy(bp, tbuf); 1203 tname = bp; 1204 bp += n; 1205 buflen -= n; 1206 continue; 1207 } 1208 DNS_ASSERT(type == qtype); 1209 switch (type) { 1210 case T_PTR: 1211 DNS_ASSERT(strcasecmp(tname, bp) == 0); 1212 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1213 DNS_FATAL(n >= 0); 1214 DNS_FATAL(res_hnok(bp)); 1215 #if MULTI_PTRS_ARE_ALIASES 1216 cp += n; 1217 if (cp != erdata) { 1218 *errp = NO_RECOVERY; 1219 return (NULL); 1220 } 1221 if (!haveanswer) 1222 template->h_name = bp; 1223 else if (ap < &host_aliases[MAXALIASES-1]) 1224 *ap++ = bp; 1225 else 1226 n = -1; 1227 if (n != -1) { 1228 n = strlen(bp) + 1; /* for the \0 */ 1229 if (n >= MAXHOSTNAMELEN) { 1230 had_error++; 1231 break; 1232 } 1233 bp += n; 1234 buflen -= n; 1235 } 1236 break; 1237 #else 1238 template->h_name = bp; 1239 *errp = NETDB_SUCCESS; 1240 return (template); 1241 #endif 1242 case T_A: 1243 case T_AAAA: 1244 DNS_ASSERT(strcasecmp(template->h_name, bp) == 0); 1245 DNS_ASSERT(n == template->h_length); 1246 if (!haveanswer) { 1247 int nn; 1248 1249 template->h_name = bp; 1250 nn = strlen(bp) + 1; /* for the \0 */ 1251 bp += nn; 1252 buflen -= nn; 1253 } 1254 obp = bp; /* ALIGN rounds up */ 1255 bp = (char *)ALIGN(bp); 1256 buflen -= (bp - obp); 1257 1258 DNS_FATAL(bp + n < &hostbuf[sizeof hostbuf]); 1259 DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]); 1260 #ifdef FILTER_V4MAPPED 1261 if (type == T_AAAA) { 1262 struct in6_addr in6; 1263 memcpy(&in6, cp, sizeof(in6)); 1264 DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0); 1265 } 1266 #endif 1267 bcopy(cp, *hap++ = bp, n); 1268 bp += n; 1269 buflen -= n; 1270 cp += n; 1271 if (cp != erdata) { 1272 *errp = NO_RECOVERY; 1273 return (NULL); 1274 } 1275 break; 1276 default: 1277 abort(); 1278 } 1279 if (!had_error) 1280 haveanswer++; 1281 } 1282 if (haveanswer) { 1283 *ap = NULL; 1284 *hap = NULL; 1285 if (!template->h_name) { 1286 n = strlen(qname) + 1; /* for the \0 */ 1287 if (n > buflen || n >= MAXHOSTNAMELEN) 1288 goto no_recovery; 1289 strcpy(bp, qname); 1290 template->h_name = bp; 1291 bp += n; 1292 buflen -= n; 1293 } 1294 *errp = NETDB_SUCCESS; 1295 return (template); 1296 } 1297 no_recovery: 1298 *errp = NO_RECOVERY; 1299 return (NULL); 1300 1301 #undef BOUNDED_INCR 1302 #undef BOUNDS_CHECK 1303 #undef DNS_ASSERT 1304 #undef DNS_FATAL 1305 } 1306 1307 /* res_search() variant with multiple query support. */ 1308 static struct hostent * 1309 _res_search_multi(const char *name, struct __res_type_list *rtl, int *errp) 1310 { 1311 const char *cp, * const *domain; 1312 struct hostent *hp0 = NULL, *hp; 1313 struct hostent hpbuf; 1314 u_int dots; 1315 int trailing_dot, ret, saved_herrno; 1316 int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 1317 struct __res_type_list *rtl0 = rtl; 1318 querybuf *buf; 1319 1320 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1321 *errp = NETDB_INTERNAL; 1322 return (NULL); 1323 } 1324 dots = 0; 1325 for (cp = name; *cp; cp++) 1326 dots += (*cp == '.'); 1327 trailing_dot = 0; 1328 if (cp > name && *--cp == '.') 1329 trailing_dot++; 1330 1331 buf = malloc(sizeof(*buf)); 1332 if (buf == NULL) { 1333 *errp = NETDB_INTERNAL; 1334 return NULL; 1335 } 1336 1337 /* If there aren't any dots, it could be a user-level alias */ 1338 if (!dots && (cp = hostalias(name)) != NULL) { 1339 for(rtl = rtl0; rtl != NULL; 1340 rtl = SLIST_NEXT(rtl, rtl_entry)) { 1341 ret = res_query(cp, C_IN, rtl->rtl_type, buf->buf, 1342 sizeof(buf->buf)); 1343 if (ret > 0 && (size_t)ret < sizeof(buf->buf)) { 1344 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1345 ? AF_INET6 : AF_INET; 1346 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1347 hp = getanswer(buf, ret, name, rtl->rtl_type, 1348 &hpbuf, errp); 1349 if (!hp) 1350 continue; 1351 hp = _hpcopy(&hpbuf, errp); 1352 hp0 = _hpmerge(hp0, hp, errp); 1353 } 1354 } 1355 free(buf); 1356 return (hp0); 1357 } 1358 1359 /* 1360 * If there are dots in the name already, let's just give it a try 1361 * 'as is'. The threshold can be set with the "ndots" option. 1362 */ 1363 saved_herrno = -1; 1364 if (dots >= _res.ndots) { 1365 for(rtl = rtl0; rtl != NULL; 1366 rtl = SLIST_NEXT(rtl, rtl_entry)) { 1367 ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type, 1368 buf->buf, sizeof(buf->buf)); 1369 if (ret > 0 && (size_t)ret < sizeof(buf->buf)) { 1370 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1371 ? AF_INET6 : AF_INET; 1372 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1373 hp = getanswer(buf, ret, name, rtl->rtl_type, 1374 &hpbuf, errp); 1375 if (!hp) 1376 continue; 1377 hp = _hpcopy(&hpbuf, errp); 1378 hp0 = _hpmerge(hp0, hp, errp); 1379 } 1380 } 1381 if (hp0 != NULL) { 1382 free(buf); 1383 return (hp0); 1384 } 1385 saved_herrno = *errp; 1386 tried_as_is++; 1387 } 1388 1389 /* 1390 * We do at least one level of search if 1391 * - there is no dot and RES_DEFNAME is set, or 1392 * - there is at least one dot, there is no trailing dot, 1393 * and RES_DNSRCH is set. 1394 */ 1395 if ((!dots && (_res.options & RES_DEFNAMES)) || 1396 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 1397 int done = 0; 1398 1399 for (domain = (const char * const *)_res.dnsrch; 1400 *domain && !done; 1401 domain++) { 1402 1403 for(rtl = rtl0; rtl != NULL; 1404 rtl = SLIST_NEXT(rtl, rtl_entry)) { 1405 ret = res_querydomain(name, *domain, C_IN, 1406 rtl->rtl_type, 1407 buf->buf, sizeof(buf->buf)); 1408 if (ret > 0 && (size_t)ret < sizeof(buf->buf)) { 1409 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1410 ? AF_INET6 : AF_INET; 1411 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1412 hp = getanswer(buf, ret, name, 1413 rtl->rtl_type, &hpbuf, errp); 1414 if (!hp) 1415 continue; 1416 hp = _hpcopy(&hpbuf, errp); 1417 hp0 = _hpmerge(hp0, hp, errp); 1418 } 1419 } 1420 if (hp0 != NULL) { 1421 free(buf); 1422 return (hp0); 1423 } 1424 1425 /* 1426 * If no server present, give up. 1427 * If name isn't found in this domain, 1428 * keep trying higher domains in the search list 1429 * (if that's enabled). 1430 * On a NO_DATA error, keep trying, otherwise 1431 * a wildcard entry of another type could keep us 1432 * from finding this entry higher in the domain. 1433 * If we get some other error (negative answer or 1434 * server failure), then stop searching up, 1435 * but try the input name below in case it's 1436 * fully-qualified. 1437 */ 1438 if (errno == ECONNREFUSED) { 1439 free(buf); 1440 *errp = TRY_AGAIN; 1441 return (NULL); 1442 } 1443 1444 switch (*errp) { 1445 case NO_DATA: 1446 got_nodata++; 1447 /* FALLTHROUGH */ 1448 case HOST_NOT_FOUND: 1449 /* keep trying */ 1450 break; 1451 case TRY_AGAIN: 1452 if (buf->hdr.rcode == SERVFAIL) { 1453 /* try next search element, if any */ 1454 got_servfail++; 1455 break; 1456 } 1457 /* FALLTHROUGH */ 1458 default: 1459 /* anything else implies that we're done */ 1460 done++; 1461 } 1462 1463 /* if we got here for some reason other than DNSRCH, 1464 * we only wanted one iteration of the loop, so stop. 1465 */ 1466 if (!(_res.options & RES_DNSRCH)) 1467 done++; 1468 } 1469 } 1470 1471 /* 1472 * If we have not already tried the name "as is", do that now. 1473 * note that we do this regardless of how many dots were in the 1474 * name or whether it ends with a dot unless NOTLDQUERY is set. 1475 */ 1476 if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { 1477 for(rtl = rtl0; rtl != NULL; 1478 rtl = SLIST_NEXT(rtl, rtl_entry)) { 1479 ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type, 1480 buf->buf, sizeof(buf->buf)); 1481 if (ret > 0 && (size_t)ret < sizeof(buf->buf)) { 1482 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1483 ? AF_INET6 : AF_INET; 1484 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1485 hp = getanswer(buf, ret, name, rtl->rtl_type, 1486 &hpbuf, errp); 1487 if (!hp) 1488 continue; 1489 hp = _hpcopy(&hpbuf, errp); 1490 hp0 = _hpmerge(hp0, hp, errp); 1491 } 1492 } 1493 if (hp0 != NULL) { 1494 free(buf); 1495 return (hp0); 1496 } 1497 } 1498 1499 free(buf); 1500 1501 /* if we got here, we didn't satisfy the search. 1502 * if we did an initial full query, return that query's h_errno 1503 * (note that we wouldn't be here if that query had succeeded). 1504 * else if we ever got a nodata, send that back as the reason. 1505 * else send back meaningless h_errno, that being the one from 1506 * the last DNSRCH we did. 1507 */ 1508 if (saved_herrno != -1) 1509 *errp = saved_herrno; 1510 else if (got_nodata) 1511 *errp = NO_DATA; 1512 else if (got_servfail) 1513 *errp = TRY_AGAIN; 1514 return (NULL); 1515 } 1516 1517 static struct hostent * 1518 _dns_ghbyname(const char *name, int af, int *errp) 1519 { 1520 struct __res_type_list *rtl, rtl4; 1521 #ifdef INET6 1522 struct __res_type_list rtl6; 1523 #endif 1524 1525 #ifdef INET6 1526 switch (af) { 1527 case AF_UNSPEC: 1528 SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1529 SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA; 1530 rtl = &rtl6; 1531 break; 1532 case AF_INET6: 1533 SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA; 1534 rtl = &rtl6; 1535 break; 1536 case AF_INET: 1537 SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1538 rtl = &rtl4; 1539 break; 1540 default: 1541 return(NULL); 1542 } 1543 #else 1544 SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1545 rtl = &rtl4; 1546 #endif 1547 return(_res_search_multi(name, rtl, errp)); 1548 } 1549 1550 static struct hostent * 1551 _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 1552 { 1553 int n; 1554 struct hostent *hp; 1555 u_char c; 1556 const u_char *cp; 1557 char *bp; 1558 struct hostent hbuf; 1559 int na; 1560 #ifdef INET6 1561 static const char hex[] = "0123456789abcdef"; 1562 #endif 1563 querybuf *buf; 1564 char qbuf[MAXDNAME+1]; 1565 char *hlist[2]; 1566 const char *tld6[] = { "ip6.arpa", "ip6.int", NULL }; 1567 const char *tld4[] = { "in-addr.arpa", NULL }; 1568 const char **tld; 1569 1570 #ifdef INET6 1571 /* XXX */ 1572 if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr)) 1573 return NULL; 1574 #endif 1575 1576 switch (af) { 1577 #ifdef INET6 1578 case AF_INET6: 1579 tld = tld6; 1580 break; 1581 #endif 1582 case AF_INET: 1583 tld = tld4; 1584 break; 1585 default: 1586 return NULL; 1587 } 1588 1589 if ((_res.options & RES_INIT) == 0) { 1590 if (res_init() < 0) { 1591 *errp = h_errno; 1592 return NULL; 1593 } 1594 } 1595 memset(&hbuf, 0, sizeof(hbuf)); 1596 hbuf.h_name = NULL; 1597 hbuf.h_addrtype = af; 1598 hbuf.h_length = addrlen; 1599 na = 0; 1600 1601 buf = malloc(sizeof(*buf)); 1602 if (buf == NULL) { 1603 *errp = NETDB_INTERNAL; 1604 return NULL; 1605 } 1606 for (/* nothing */; *tld; tld++) { 1607 /* 1608 * XXX assumes that MAXDNAME is big enough - error checks 1609 * has been made by callers 1610 */ 1611 n = 0; 1612 bp = qbuf; 1613 cp = (const uint8_t *)addr+addrlen-1; 1614 switch (af) { 1615 #ifdef INET6 1616 case AF_INET6: 1617 for (; n < addrlen; n++, cp--) { 1618 c = *cp; 1619 *bp++ = hex[c & 0xf]; 1620 *bp++ = '.'; 1621 *bp++ = hex[c >> 4]; 1622 *bp++ = '.'; 1623 } 1624 strcpy(bp, *tld); 1625 break; 1626 #endif 1627 case AF_INET: 1628 for (; n < addrlen; n++, cp--) { 1629 c = *cp; 1630 if (c >= 100) 1631 *bp++ = '0' + c / 100; 1632 if (c >= 10) 1633 *bp++ = '0' + (c % 100) / 10; 1634 *bp++ = '0' + c % 10; 1635 *bp++ = '.'; 1636 } 1637 strcpy(bp, *tld); 1638 break; 1639 } 1640 1641 n = res_query(qbuf, C_IN, T_PTR, buf->buf, sizeof buf->buf); 1642 if (n < 0) { 1643 *errp = h_errno; 1644 continue; 1645 } else if ((size_t)n > sizeof(buf->buf)) { 1646 *errp = NETDB_INTERNAL; 1647 #if 0 1648 errno = ERANGE; /* XXX is it OK to set errno here? */ 1649 #endif 1650 continue; 1651 } 1652 hp = getanswer(buf, n, qbuf, T_PTR, &hbuf, errp); 1653 if (!hp) 1654 continue; 1655 free(buf); 1656 hbuf.h_addrtype = af; 1657 hbuf.h_length = addrlen; 1658 hbuf.h_addr_list = hlist; 1659 hlist[0] = addr; 1660 hlist[1] = NULL; 1661 return _hpcopy(&hbuf, errp); 1662 } 1663 free(buf); 1664 return NULL; 1665 } 1666 1667 #ifdef ICMPNL 1668 1669 /* 1670 * experimental: 1671 * draft-ietf-ipngwg-icmp-namelookups-02.txt 1672 * ifindex is assumed to be encoded in addr. 1673 */ 1674 #include <sys/uio.h> 1675 #include <netinet/ip6.h> 1676 #include <netinet/icmp6.h> 1677 1678 struct _icmp_host_cache { 1679 struct _icmp_host_cache *hc_next; 1680 int hc_ifindex; 1681 struct in6_addr hc_addr; 1682 char *hc_name; 1683 }; 1684 1685 static char * 1686 _icmp_fqdn_query(const struct in6_addr *addr, int ifindex) 1687 { 1688 int s; 1689 struct icmp6_filter filter; 1690 struct msghdr msg; 1691 struct cmsghdr *cmsg; 1692 struct in6_pktinfo *pkt; 1693 char cbuf[256]; 1694 char buf[1024]; 1695 int cc; 1696 struct icmp6_fqdn_query *fq; 1697 struct icmp6_fqdn_reply *fr; 1698 struct _icmp_host_cache *hc; 1699 struct sockaddr_in6 sin6; 1700 struct iovec iov; 1701 fd_set s_fds, fds; 1702 struct timeval tout; 1703 int len; 1704 char *name; 1705 static int pid; 1706 static struct _icmp_host_cache *hc_head; 1707 1708 for (hc = hc_head; hc; hc = hc->hc_next) { 1709 if (hc->hc_ifindex == ifindex 1710 && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) 1711 return hc->hc_name; 1712 } 1713 1714 if (pid == 0) 1715 pid = getpid(); 1716 1717 ICMP6_FILTER_SETBLOCKALL(&filter); 1718 ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter); 1719 1720 FD_ZERO(&s_fds); 1721 tout.tv_sec = 0; 1722 tout.tv_usec = 200000; /*XXX: 200ms*/ 1723 1724 fq = (struct icmp6_fqdn_query *)buf; 1725 fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY; 1726 fq->icmp6_fqdn_code = 0; 1727 fq->icmp6_fqdn_cksum = 0; 1728 fq->icmp6_fqdn_id = (u_short)pid; 1729 fq->icmp6_fqdn_unused = 0; 1730 fq->icmp6_fqdn_cookie[0] = 0; 1731 fq->icmp6_fqdn_cookie[1] = 0; 1732 1733 memset(&sin6, 0, sizeof(sin6)); 1734 sin6.sin6_family = AF_INET6; 1735 sin6.sin6_addr = *addr; 1736 1737 memset(&msg, 0, sizeof(msg)); 1738 msg.msg_name = (caddr_t)&sin6; 1739 msg.msg_namelen = sizeof(sin6); 1740 msg.msg_iov = &iov; 1741 msg.msg_iovlen = 1; 1742 msg.msg_control = NULL; 1743 msg.msg_controllen = 0; 1744 iov.iov_base = (caddr_t)buf; 1745 iov.iov_len = sizeof(struct icmp6_fqdn_query); 1746 1747 if (ifindex) { 1748 msg.msg_control = cbuf; 1749 msg.msg_controllen = sizeof(cbuf); 1750 cmsg = CMSG_FIRSTHDR(&msg); 1751 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1752 cmsg->cmsg_level = IPPROTO_IPV6; 1753 cmsg->cmsg_type = IPV6_PKTINFO; 1754 pkt = (struct in6_pktinfo *)&cmsg[1]; 1755 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr)); 1756 pkt->ipi6_ifindex = ifindex; 1757 cmsg = CMSG_NXTHDR(&msg, cmsg); 1758 msg.msg_controllen = (char *)cmsg - cbuf; 1759 } 1760 1761 if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) 1762 return NULL; 1763 (void)_setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, 1764 (char *)&filter, sizeof(filter)); 1765 cc = _sendmsg(s, &msg, 0); 1766 if (cc < 0) { 1767 _close(s); 1768 return NULL; 1769 } 1770 FD_SET(s, &s_fds); 1771 for (;;) { 1772 fds = s_fds; 1773 if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) { 1774 _close(s); 1775 return NULL; 1776 } 1777 len = sizeof(sin6); 1778 cc = _recvfrom(s, buf, sizeof(buf), 0, 1779 (struct sockaddr *)&sin6, &len); 1780 if (cc <= 0) { 1781 _close(s); 1782 return NULL; 1783 } 1784 if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) 1785 continue; 1786 if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr)) 1787 continue; 1788 fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr)); 1789 if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY) 1790 break; 1791 } 1792 _close(s); 1793 if (fr->icmp6_fqdn_cookie[1] != 0) { 1794 /* rfc1788 type */ 1795 name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4; 1796 len = (buf + cc) - name; 1797 } else { 1798 len = fr->icmp6_fqdn_namelen; 1799 name = fr->icmp6_fqdn_name; 1800 } 1801 if (len <= 0) 1802 return NULL; 1803 name[len] = 0; 1804 1805 if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL) 1806 return NULL; 1807 /* XXX: limit number of cached entries */ 1808 hc->hc_ifindex = ifindex; 1809 hc->hc_addr = *addr; 1810 hc->hc_name = strdup(name); 1811 hc->hc_next = hc_head; 1812 hc_head = hc; 1813 return hc->hc_name; 1814 } 1815 1816 static struct hostent * 1817 _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 1818 { 1819 char *hname; 1820 int ifindex; 1821 struct in6_addr addr6; 1822 1823 if (af != AF_INET6) { 1824 /* 1825 * Note: rfc1788 defines Who Are You for IPv4, 1826 * but no one implements it. 1827 */ 1828 return NULL; 1829 } 1830 1831 memcpy(&addr6, addr, addrlen); 1832 ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3]; 1833 addr6.s6_addr[2] = addr6.s6_addr[3] = 0; 1834 1835 if (!IN6_IS_ADDR_LINKLOCAL(&addr6)) 1836 return NULL; /*XXX*/ 1837 1838 if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL) 1839 return NULL; 1840 return _hpaddr(af, hname, &addr6, errp); 1841 } 1842 #endif /* ICMPNL */ 1843