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