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.9 2005/11/13 02:04:47 swildner 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(const querybuf *answer, int anslen, const char *qname, int qtype, 1031 struct hostent *template, int *errp) 1032 { 1033 const HEADER *hp; 1034 const u_char *cp; 1035 int n; 1036 const u_char *eom, *erdata; 1037 char *bp, **ap, **hap, *obp; 1038 int type, class, buflen, ancount, qdcount; 1039 int haveanswer, had_error; 1040 char tbuf[MAXDNAME]; 1041 const char *tname; 1042 int (*name_ok) (const char *); 1043 static char *h_addr_ptrs[MAXADDRS + 1]; 1044 static char *host_aliases[MAXALIASES]; 1045 static char hostbuf[8*1024]; 1046 1047 #define BOUNDED_INCR(x) \ 1048 do { \ 1049 cp += x; \ 1050 if (cp > eom) { \ 1051 *errp = NO_RECOVERY; \ 1052 return (NULL); \ 1053 } \ 1054 } while (0) 1055 1056 #define BOUNDS_CHECK(ptr, count) \ 1057 do { \ 1058 if ((ptr) + (count) > eom) { \ 1059 *errp = NO_RECOVERY; \ 1060 return (NULL); \ 1061 } \ 1062 } while (0) 1063 1064 /* XXX do {} while (0) cannot be put here */ 1065 #define DNS_ASSERT(x) \ 1066 { \ 1067 if (!(x)) { \ 1068 cp += n; \ 1069 continue; \ 1070 } \ 1071 } 1072 1073 /* XXX do {} while (0) cannot be put here */ 1074 #define DNS_FATAL(x) \ 1075 { \ 1076 if (!(x)) { \ 1077 had_error++; \ 1078 continue; \ 1079 } \ 1080 } 1081 1082 tname = qname; 1083 template->h_name = NULL; 1084 eom = answer->buf + anslen; 1085 switch (qtype) { 1086 case T_A: 1087 case T_AAAA: 1088 name_ok = res_hnok; 1089 break; 1090 case T_PTR: 1091 name_ok = res_dnok; 1092 break; 1093 default: 1094 return (NULL); /* XXX should be abort(); */ 1095 } 1096 /* 1097 * find first satisfactory answer 1098 */ 1099 hp = &answer->hdr; 1100 ancount = ntohs(hp->ancount); 1101 qdcount = ntohs(hp->qdcount); 1102 bp = hostbuf; 1103 buflen = sizeof hostbuf; 1104 cp = answer->buf; 1105 BOUNDED_INCR(HFIXEDSZ); 1106 if (qdcount != 1) { 1107 *errp = NO_RECOVERY; 1108 return (NULL); 1109 } 1110 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1111 if ((n < 0) || !(*name_ok)(bp)) { 1112 *errp = NO_RECOVERY; 1113 return (NULL); 1114 } 1115 BOUNDED_INCR(n + QFIXEDSZ); 1116 if (qtype == T_A || qtype == T_AAAA) { 1117 /* res_send() has already verified that the query name is the 1118 * same as the one we sent; this just gets the expanded name 1119 * (i.e., with the succeeding search-domain tacked on). 1120 */ 1121 n = strlen(bp) + 1; /* for the \0 */ 1122 if (n >= MAXHOSTNAMELEN) { 1123 *errp = NO_RECOVERY; 1124 return (NULL); 1125 } 1126 template->h_name = bp; 1127 bp += n; 1128 buflen -= n; 1129 /* The qname can be abbreviated, but h_name is now absolute. */ 1130 qname = template->h_name; 1131 } 1132 ap = host_aliases; 1133 *ap = NULL; 1134 template->h_aliases = host_aliases; 1135 hap = h_addr_ptrs; 1136 *hap = NULL; 1137 template->h_addr_list = h_addr_ptrs; 1138 haveanswer = 0; 1139 had_error = 0; 1140 while (ancount-- > 0 && cp < eom && !had_error) { 1141 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1142 DNS_FATAL(n >= 0); 1143 DNS_FATAL((*name_ok)(bp)); 1144 cp += n; /* name */ 1145 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); 1146 NS_GET16(type, cp); /* type */ 1147 NS_GET16(class, cp); /* class */ 1148 cp += INT32SZ; /* skip TTL */ 1149 NS_GET16(n, cp); /* len */ 1150 BOUNDS_CHECK(cp, n); 1151 erdata = cp + n; 1152 DNS_ASSERT(class == C_IN); 1153 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { 1154 if (ap >= &host_aliases[MAXALIASES-1]) 1155 continue; 1156 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1157 DNS_FATAL(n >= 0); 1158 DNS_FATAL((*name_ok)(tbuf)); 1159 cp += n; 1160 if (cp != erdata) { 1161 *errp = NO_RECOVERY; 1162 return (NULL); 1163 } 1164 /* Store alias. */ 1165 *ap++ = bp; 1166 n = strlen(bp) + 1; /* for the \0 */ 1167 DNS_FATAL(n < MAXHOSTNAMELEN); 1168 bp += n; 1169 buflen -= n; 1170 /* Get canonical name. */ 1171 n = strlen(tbuf) + 1; /* for the \0 */ 1172 DNS_FATAL(n <= buflen); 1173 DNS_FATAL(n < MAXHOSTNAMELEN); 1174 strcpy(bp, tbuf); 1175 template->h_name = bp; 1176 bp += n; 1177 buflen -= n; 1178 continue; 1179 } 1180 if (qtype == T_PTR && type == T_CNAME) { 1181 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1182 if (n < 0 || !res_dnok(tbuf)) { 1183 had_error++; 1184 continue; 1185 } 1186 cp += n; 1187 if (cp != erdata) { 1188 *errp = NO_RECOVERY; 1189 return (NULL); 1190 } 1191 /* Get canonical name. */ 1192 n = strlen(tbuf) + 1; /* for the \0 */ 1193 if (n > buflen || n >= MAXHOSTNAMELEN) { 1194 had_error++; 1195 continue; 1196 } 1197 strcpy(bp, tbuf); 1198 tname = bp; 1199 bp += n; 1200 buflen -= n; 1201 continue; 1202 } 1203 DNS_ASSERT(type == qtype); 1204 switch (type) { 1205 case T_PTR: 1206 DNS_ASSERT(strcasecmp(tname, bp) == 0); 1207 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1208 DNS_FATAL(n >= 0); 1209 DNS_FATAL(res_hnok(bp)); 1210 #if MULTI_PTRS_ARE_ALIASES 1211 cp += n; 1212 if (cp != erdata) { 1213 *errp = NO_RECOVERY; 1214 return (NULL); 1215 } 1216 if (!haveanswer) 1217 template->h_name = bp; 1218 else if (ap < &host_aliases[MAXALIASES-1]) 1219 *ap++ = bp; 1220 else 1221 n = -1; 1222 if (n != -1) { 1223 n = strlen(bp) + 1; /* for the \0 */ 1224 if (n >= MAXHOSTNAMELEN) { 1225 had_error++; 1226 break; 1227 } 1228 bp += n; 1229 buflen -= n; 1230 } 1231 break; 1232 #else 1233 template->h_name = bp; 1234 *errp = NETDB_SUCCESS; 1235 return (template); 1236 #endif 1237 case T_A: 1238 case T_AAAA: 1239 DNS_ASSERT(strcasecmp(template->h_name, bp) == 0); 1240 DNS_ASSERT(n == template->h_length); 1241 if (!haveanswer) { 1242 int nn; 1243 1244 template->h_name = bp; 1245 nn = strlen(bp) + 1; /* for the \0 */ 1246 bp += nn; 1247 buflen -= nn; 1248 } 1249 obp = bp; /* ALIGN rounds up */ 1250 bp = (char *)ALIGN(bp); 1251 buflen -= (bp - obp); 1252 1253 DNS_FATAL(bp + n < &hostbuf[sizeof hostbuf]); 1254 DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]); 1255 #ifdef FILTER_V4MAPPED 1256 if (type == T_AAAA) { 1257 struct in6_addr in6; 1258 memcpy(&in6, cp, sizeof(in6)); 1259 DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0); 1260 } 1261 #endif 1262 bcopy(cp, *hap++ = bp, n); 1263 bp += n; 1264 buflen -= n; 1265 cp += n; 1266 if (cp != erdata) { 1267 *errp = NO_RECOVERY; 1268 return (NULL); 1269 } 1270 break; 1271 default: 1272 abort(); 1273 } 1274 if (!had_error) 1275 haveanswer++; 1276 } 1277 if (haveanswer) { 1278 *ap = NULL; 1279 *hap = NULL; 1280 if (!template->h_name) { 1281 n = strlen(qname) + 1; /* for the \0 */ 1282 if (n > buflen || n >= MAXHOSTNAMELEN) 1283 goto no_recovery; 1284 strcpy(bp, qname); 1285 template->h_name = bp; 1286 bp += n; 1287 buflen -= n; 1288 } 1289 *errp = NETDB_SUCCESS; 1290 return (template); 1291 } 1292 no_recovery: 1293 *errp = NO_RECOVERY; 1294 return (NULL); 1295 1296 #undef BOUNDED_INCR 1297 #undef BOUNDS_CHECK 1298 #undef DNS_ASSERT 1299 #undef DNS_FATAL 1300 } 1301 1302 /* res_search() variant with multiple query support. */ 1303 static struct hostent * 1304 _res_search_multi(const char *name, struct __res_type_list *rtl, int *errp) 1305 { 1306 const char *cp, * const *domain; 1307 struct hostent *hp0 = NULL, *hp; 1308 struct hostent hpbuf; 1309 u_int dots; 1310 int trailing_dot, ret, saved_herrno; 1311 int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 1312 struct __res_type_list *rtl0 = rtl; 1313 querybuf *buf; 1314 1315 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1316 *errp = NETDB_INTERNAL; 1317 return (NULL); 1318 } 1319 dots = 0; 1320 for (cp = name; *cp; cp++) 1321 dots += (*cp == '.'); 1322 trailing_dot = 0; 1323 if (cp > name && *--cp == '.') 1324 trailing_dot++; 1325 1326 buf = malloc(sizeof(*buf)); 1327 if (buf == NULL) { 1328 *errp = NETDB_INTERNAL; 1329 return NULL; 1330 } 1331 1332 /* If there aren't any dots, it could be a user-level alias */ 1333 if (!dots && (cp = hostalias(name)) != NULL) { 1334 for(rtl = rtl0; rtl != NULL; 1335 rtl = SLIST_NEXT(rtl, rtl_entry)) { 1336 ret = res_query(cp, C_IN, rtl->rtl_type, buf->buf, 1337 sizeof(buf->buf)); 1338 if (ret > 0 && (size_t)ret < sizeof(buf->buf)) { 1339 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1340 ? AF_INET6 : AF_INET; 1341 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1342 hp = getanswer(buf, ret, name, rtl->rtl_type, 1343 &hpbuf, errp); 1344 if (!hp) 1345 continue; 1346 hp = _hpcopy(&hpbuf, errp); 1347 hp0 = _hpmerge(hp0, hp, errp); 1348 } 1349 } 1350 free(buf); 1351 return (hp0); 1352 } 1353 1354 /* 1355 * If there are dots in the name already, let's just give it a try 1356 * 'as is'. The threshold can be set with the "ndots" option. 1357 */ 1358 saved_herrno = -1; 1359 if (dots >= _res.ndots) { 1360 for(rtl = rtl0; rtl != NULL; 1361 rtl = SLIST_NEXT(rtl, rtl_entry)) { 1362 ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type, 1363 buf->buf, sizeof(buf->buf)); 1364 if (ret > 0 && (size_t)ret < sizeof(buf->buf)) { 1365 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1366 ? AF_INET6 : AF_INET; 1367 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1368 hp = getanswer(buf, ret, name, rtl->rtl_type, 1369 &hpbuf, errp); 1370 if (!hp) 1371 continue; 1372 hp = _hpcopy(&hpbuf, errp); 1373 hp0 = _hpmerge(hp0, hp, errp); 1374 } 1375 } 1376 if (hp0 != NULL) { 1377 free(buf); 1378 return (hp0); 1379 } 1380 saved_herrno = *errp; 1381 tried_as_is++; 1382 } 1383 1384 /* 1385 * We do at least one level of search if 1386 * - there is no dot and RES_DEFNAME is set, or 1387 * - there is at least one dot, there is no trailing dot, 1388 * and RES_DNSRCH is set. 1389 */ 1390 if ((!dots && (_res.options & RES_DEFNAMES)) || 1391 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 1392 int done = 0; 1393 1394 for (domain = (const char * const *)_res.dnsrch; 1395 *domain && !done; 1396 domain++) { 1397 1398 for(rtl = rtl0; rtl != NULL; 1399 rtl = SLIST_NEXT(rtl, rtl_entry)) { 1400 ret = res_querydomain(name, *domain, C_IN, 1401 rtl->rtl_type, 1402 buf->buf, sizeof(buf->buf)); 1403 if (ret > 0 && (size_t)ret < sizeof(buf->buf)) { 1404 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1405 ? AF_INET6 : AF_INET; 1406 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1407 hp = getanswer(buf, ret, name, 1408 rtl->rtl_type, &hpbuf, errp); 1409 if (!hp) 1410 continue; 1411 hp = _hpcopy(&hpbuf, errp); 1412 hp0 = _hpmerge(hp0, hp, errp); 1413 } 1414 } 1415 if (hp0 != NULL) { 1416 free(buf); 1417 return (hp0); 1418 } 1419 1420 /* 1421 * If no server present, give up. 1422 * If name isn't found in this domain, 1423 * keep trying higher domains in the search list 1424 * (if that's enabled). 1425 * On a NO_DATA error, keep trying, otherwise 1426 * a wildcard entry of another type could keep us 1427 * from finding this entry higher in the domain. 1428 * If we get some other error (negative answer or 1429 * server failure), then stop searching up, 1430 * but try the input name below in case it's 1431 * fully-qualified. 1432 */ 1433 if (errno == ECONNREFUSED) { 1434 free(buf); 1435 *errp = TRY_AGAIN; 1436 return (NULL); 1437 } 1438 1439 switch (*errp) { 1440 case NO_DATA: 1441 got_nodata++; 1442 /* FALLTHROUGH */ 1443 case HOST_NOT_FOUND: 1444 /* keep trying */ 1445 break; 1446 case TRY_AGAIN: 1447 if (buf->hdr.rcode == SERVFAIL) { 1448 /* try next search element, if any */ 1449 got_servfail++; 1450 break; 1451 } 1452 /* FALLTHROUGH */ 1453 default: 1454 /* anything else implies that we're done */ 1455 done++; 1456 } 1457 1458 /* if we got here for some reason other than DNSRCH, 1459 * we only wanted one iteration of the loop, so stop. 1460 */ 1461 if (!(_res.options & RES_DNSRCH)) 1462 done++; 1463 } 1464 } 1465 1466 /* 1467 * If we have not already tried the name "as is", do that now. 1468 * note that we do this regardless of how many dots were in the 1469 * name or whether it ends with a dot unless NOTLDQUERY is set. 1470 */ 1471 if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { 1472 for(rtl = rtl0; rtl != NULL; 1473 rtl = SLIST_NEXT(rtl, rtl_entry)) { 1474 ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type, 1475 buf->buf, sizeof(buf->buf)); 1476 if (ret > 0 && (size_t)ret < sizeof(buf->buf)) { 1477 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1478 ? AF_INET6 : AF_INET; 1479 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1480 hp = getanswer(buf, ret, name, rtl->rtl_type, 1481 &hpbuf, errp); 1482 if (!hp) 1483 continue; 1484 hp = _hpcopy(&hpbuf, errp); 1485 hp0 = _hpmerge(hp0, hp, errp); 1486 } 1487 } 1488 if (hp0 != NULL) { 1489 free(buf); 1490 return (hp0); 1491 } 1492 } 1493 1494 free(buf); 1495 1496 /* if we got here, we didn't satisfy the search. 1497 * if we did an initial full query, return that query's h_errno 1498 * (note that we wouldn't be here if that query had succeeded). 1499 * else if we ever got a nodata, send that back as the reason. 1500 * else send back meaningless h_errno, that being the one from 1501 * the last DNSRCH we did. 1502 */ 1503 if (saved_herrno != -1) 1504 *errp = saved_herrno; 1505 else if (got_nodata) 1506 *errp = NO_DATA; 1507 else if (got_servfail) 1508 *errp = TRY_AGAIN; 1509 return (NULL); 1510 } 1511 1512 static struct hostent * 1513 _dns_ghbyname(const char *name, int af, int *errp) 1514 { 1515 struct __res_type_list *rtl, rtl4; 1516 #ifdef INET6 1517 struct __res_type_list rtl6; 1518 #endif 1519 1520 #ifdef INET6 1521 switch (af) { 1522 case AF_UNSPEC: 1523 SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1524 SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA; 1525 rtl = &rtl6; 1526 break; 1527 case AF_INET6: 1528 SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA; 1529 rtl = &rtl6; 1530 break; 1531 case AF_INET: 1532 SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1533 rtl = &rtl4; 1534 break; 1535 default: 1536 return(NULL); 1537 } 1538 #else 1539 SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1540 rtl = &rtl4; 1541 #endif 1542 return(_res_search_multi(name, rtl, errp)); 1543 } 1544 1545 static struct hostent * 1546 _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 1547 { 1548 int n; 1549 struct hostent *hp; 1550 u_char c; 1551 const u_char *cp; 1552 char *bp; 1553 struct hostent hbuf; 1554 int na; 1555 #ifdef INET6 1556 static const char hex[] = "0123456789abcdef"; 1557 #endif 1558 querybuf *buf; 1559 char qbuf[MAXDNAME+1]; 1560 char *hlist[2]; 1561 const char *tld6[] = { "ip6.arpa", "ip6.int", NULL }; 1562 const char *tld4[] = { "in-addr.arpa", NULL }; 1563 const char **tld; 1564 1565 #ifdef INET6 1566 /* XXX */ 1567 if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr)) 1568 return NULL; 1569 #endif 1570 1571 switch (af) { 1572 #ifdef INET6 1573 case AF_INET6: 1574 tld = tld6; 1575 break; 1576 #endif 1577 case AF_INET: 1578 tld = tld4; 1579 break; 1580 default: 1581 return NULL; 1582 } 1583 1584 if ((_res.options & RES_INIT) == 0) { 1585 if (res_init() < 0) { 1586 *errp = h_errno; 1587 return NULL; 1588 } 1589 } 1590 memset(&hbuf, 0, sizeof(hbuf)); 1591 hbuf.h_name = NULL; 1592 hbuf.h_addrtype = af; 1593 hbuf.h_length = addrlen; 1594 na = 0; 1595 1596 buf = malloc(sizeof(*buf)); 1597 if (buf == NULL) { 1598 *errp = NETDB_INTERNAL; 1599 return NULL; 1600 } 1601 for (/* nothing */; *tld; tld++) { 1602 /* 1603 * XXX assumes that MAXDNAME is big enough - error checks 1604 * has been made by callers 1605 */ 1606 n = 0; 1607 bp = qbuf; 1608 cp = (const uint8_t *)addr+addrlen-1; 1609 switch (af) { 1610 #ifdef INET6 1611 case AF_INET6: 1612 for (; n < addrlen; n++, cp--) { 1613 c = *cp; 1614 *bp++ = hex[c & 0xf]; 1615 *bp++ = '.'; 1616 *bp++ = hex[c >> 4]; 1617 *bp++ = '.'; 1618 } 1619 strcpy(bp, *tld); 1620 break; 1621 #endif 1622 case AF_INET: 1623 for (; n < addrlen; n++, cp--) { 1624 c = *cp; 1625 if (c >= 100) 1626 *bp++ = '0' + c / 100; 1627 if (c >= 10) 1628 *bp++ = '0' + (c % 100) / 10; 1629 *bp++ = '0' + c % 10; 1630 *bp++ = '.'; 1631 } 1632 strcpy(bp, *tld); 1633 break; 1634 } 1635 1636 n = res_query(qbuf, C_IN, T_PTR, buf->buf, sizeof buf->buf); 1637 if (n < 0) { 1638 *errp = h_errno; 1639 continue; 1640 } else if ((size_t)n > sizeof(buf->buf)) { 1641 *errp = NETDB_INTERNAL; 1642 #if 0 1643 errno = ERANGE; /* XXX is it OK to set errno here? */ 1644 #endif 1645 continue; 1646 } 1647 hp = getanswer(buf, n, qbuf, T_PTR, &hbuf, errp); 1648 if (!hp) 1649 continue; 1650 free(buf); 1651 hbuf.h_addrtype = af; 1652 hbuf.h_length = addrlen; 1653 hbuf.h_addr_list = hlist; 1654 hlist[0] = addr; 1655 hlist[1] = NULL; 1656 return _hpcopy(&hbuf, errp); 1657 } 1658 free(buf); 1659 return NULL; 1660 } 1661 1662 #ifdef ICMPNL 1663 1664 /* 1665 * experimental: 1666 * draft-ietf-ipngwg-icmp-namelookups-02.txt 1667 * ifindex is assumed to be encoded in addr. 1668 */ 1669 #include <sys/uio.h> 1670 #include <netinet/ip6.h> 1671 #include <netinet/icmp6.h> 1672 1673 struct _icmp_host_cache { 1674 struct _icmp_host_cache *hc_next; 1675 int hc_ifindex; 1676 struct in6_addr hc_addr; 1677 char *hc_name; 1678 }; 1679 1680 static char * 1681 _icmp_fqdn_query(const struct in6_addr *addr, int ifindex) 1682 { 1683 int s; 1684 struct icmp6_filter filter; 1685 struct msghdr msg; 1686 struct cmsghdr *cmsg; 1687 struct in6_pktinfo *pkt; 1688 char cbuf[256]; 1689 char buf[1024]; 1690 int cc; 1691 struct icmp6_fqdn_query *fq; 1692 struct icmp6_fqdn_reply *fr; 1693 struct _icmp_host_cache *hc; 1694 struct sockaddr_in6 sin6; 1695 struct iovec iov; 1696 fd_set s_fds, fds; 1697 struct timeval tout; 1698 int len; 1699 char *name; 1700 static int pid; 1701 static struct _icmp_host_cache *hc_head; 1702 1703 for (hc = hc_head; hc; hc = hc->hc_next) { 1704 if (hc->hc_ifindex == ifindex 1705 && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) 1706 return hc->hc_name; 1707 } 1708 1709 if (pid == 0) 1710 pid = getpid(); 1711 1712 ICMP6_FILTER_SETBLOCKALL(&filter); 1713 ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter); 1714 1715 FD_ZERO(&s_fds); 1716 tout.tv_sec = 0; 1717 tout.tv_usec = 200000; /*XXX: 200ms*/ 1718 1719 fq = (struct icmp6_fqdn_query *)buf; 1720 fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY; 1721 fq->icmp6_fqdn_code = 0; 1722 fq->icmp6_fqdn_cksum = 0; 1723 fq->icmp6_fqdn_id = (u_short)pid; 1724 fq->icmp6_fqdn_unused = 0; 1725 fq->icmp6_fqdn_cookie[0] = 0; 1726 fq->icmp6_fqdn_cookie[1] = 0; 1727 1728 memset(&sin6, 0, sizeof(sin6)); 1729 sin6.sin6_family = AF_INET6; 1730 sin6.sin6_addr = *addr; 1731 1732 memset(&msg, 0, sizeof(msg)); 1733 msg.msg_name = (caddr_t)&sin6; 1734 msg.msg_namelen = sizeof(sin6); 1735 msg.msg_iov = &iov; 1736 msg.msg_iovlen = 1; 1737 msg.msg_control = NULL; 1738 msg.msg_controllen = 0; 1739 iov.iov_base = (caddr_t)buf; 1740 iov.iov_len = sizeof(struct icmp6_fqdn_query); 1741 1742 if (ifindex) { 1743 msg.msg_control = cbuf; 1744 msg.msg_controllen = sizeof(cbuf); 1745 cmsg = CMSG_FIRSTHDR(&msg); 1746 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1747 cmsg->cmsg_level = IPPROTO_IPV6; 1748 cmsg->cmsg_type = IPV6_PKTINFO; 1749 pkt = (struct in6_pktinfo *)&cmsg[1]; 1750 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr)); 1751 pkt->ipi6_ifindex = ifindex; 1752 cmsg = CMSG_NXTHDR(&msg, cmsg); 1753 msg.msg_controllen = (char *)cmsg - cbuf; 1754 } 1755 1756 if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) 1757 return NULL; 1758 _setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, 1759 (char *)&filter, sizeof(filter)); 1760 cc = _sendmsg(s, &msg, 0); 1761 if (cc < 0) { 1762 _close(s); 1763 return NULL; 1764 } 1765 FD_SET(s, &s_fds); 1766 for (;;) { 1767 fds = s_fds; 1768 if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) { 1769 _close(s); 1770 return NULL; 1771 } 1772 len = sizeof(sin6); 1773 cc = _recvfrom(s, buf, sizeof(buf), 0, 1774 (struct sockaddr *)&sin6, &len); 1775 if (cc <= 0) { 1776 _close(s); 1777 return NULL; 1778 } 1779 if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) 1780 continue; 1781 if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr)) 1782 continue; 1783 fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr)); 1784 if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY) 1785 break; 1786 } 1787 _close(s); 1788 if (fr->icmp6_fqdn_cookie[1] != 0) { 1789 /* rfc1788 type */ 1790 name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4; 1791 len = (buf + cc) - name; 1792 } else { 1793 len = fr->icmp6_fqdn_namelen; 1794 name = fr->icmp6_fqdn_name; 1795 } 1796 if (len <= 0) 1797 return NULL; 1798 name[len] = 0; 1799 1800 if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL) 1801 return NULL; 1802 /* XXX: limit number of cached entries */ 1803 hc->hc_ifindex = ifindex; 1804 hc->hc_addr = *addr; 1805 hc->hc_name = strdup(name); 1806 hc->hc_next = hc_head; 1807 hc_head = hc; 1808 return hc->hc_name; 1809 } 1810 1811 static struct hostent * 1812 _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 1813 { 1814 char *hname; 1815 int ifindex; 1816 struct in6_addr addr6; 1817 1818 if (af != AF_INET6) { 1819 /* 1820 * Note: rfc1788 defines Who Are You for IPv4, 1821 * but no one implements it. 1822 */ 1823 return NULL; 1824 } 1825 1826 memcpy(&addr6, addr, addrlen); 1827 ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3]; 1828 addr6.s6_addr[2] = addr6.s6_addr[3] = 0; 1829 1830 if (!IN6_IS_ADDR_LINKLOCAL(&addr6)) 1831 return NULL; /*XXX*/ 1832 1833 if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL) 1834 return NULL; 1835 return _hpaddr(af, hname, &addr6, errp); 1836 } 1837 #endif /* ICMPNL */ 1838