1 /* 2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1996-1999 by Internet Software Consortium. 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 14 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 16 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 17 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 * SOFTWARE. 21 */ 22 23 #pragma ident "%Z%%M% %I% %E% SMI" 24 25 #if !defined(LINT) && !defined(CODECENTER) 26 static const char rcsid[] = "$Id: gethostent.c,v 1.34 2003/05/29 00:05:18 marka Exp $"; 27 #endif 28 29 /* Imports */ 30 31 #include "port_before.h" 32 33 #if !defined(__BIND_NOSTATIC) 34 35 #include <sys/types.h> 36 #include <sys/param.h> 37 #include <sys/socket.h> 38 #include <sys/ioctl.h> 39 #include <netinet/in.h> 40 #include <net/if.h> 41 #include <arpa/inet.h> 42 #include <arpa/nameser.h> 43 44 #include <ctype.h> 45 #include <errno.h> 46 #include <stdlib.h> 47 #include <netdb.h> 48 #include <resolv.h> 49 #include <stdio.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include <irs.h> 54 #include <isc/memcluster.h> 55 56 #include "port_after.h" 57 58 #include "irs_p.h" 59 #include "irs_data.h" 60 61 /* Definitions */ 62 63 struct pvt { 64 char * aliases[1]; 65 char * addrs[2]; 66 char addr[NS_IN6ADDRSZ]; 67 char name[NS_MAXDNAME + 1]; 68 struct hostent host; 69 }; 70 71 /* Forward */ 72 73 static struct net_data *init(void); 74 static void freepvt(struct net_data *); 75 static struct hostent *fakeaddr(const char *, int, struct net_data *); 76 77 #ifdef SUNW_OVERRIDE_RETRY 78 extern int __res_retry(int); 79 extern int __res_retry_reset(void); 80 #endif /* SUNW_OVERRIDE_RETRY */ 81 82 /* Public */ 83 84 struct hostent * 85 gethostbyname(const char *name) { 86 struct net_data *net_data = init(); 87 88 return (gethostbyname_p(name, net_data)); 89 } 90 91 struct hostent * 92 gethostbyname2(const char *name, int af) { 93 struct net_data *net_data = init(); 94 95 return (gethostbyname2_p(name, af, net_data)); 96 } 97 98 struct hostent * 99 #ifdef ORIGINAL_ISC_CODE 100 gethostbyaddr(const char *addr, int len, int af) { 101 #else 102 gethostbyaddr(const void *addr, socklen_t len, int af) { 103 #endif /* ORIGINAL_ISC_CODE */ 104 struct net_data *net_data = init(); 105 106 return (gethostbyaddr_p(addr, len, af, net_data)); 107 } 108 109 struct hostent * 110 gethostent() { 111 struct net_data *net_data = init(); 112 113 return (gethostent_p(net_data)); 114 } 115 116 #ifdef ORIGINAL_ISC_CODE 117 void 118 #else 119 int 120 #endif 121 sethostent(int stayopen) { 122 struct net_data *net_data = init(); 123 sethostent_p(stayopen, net_data); 124 #ifdef ORIGINAL_ISC_CODE 125 #else 126 return (0); 127 #endif 128 } 129 130 131 #ifdef ORIGINAL_ISC_CODE 132 void 133 #else 134 int 135 #endif 136 endhostent() { 137 struct net_data *net_data = init(); 138 endhostent_p(net_data); 139 #ifdef ORIGINAL_ISC_CODE 140 #else 141 return (0); 142 #endif 143 } 144 145 /* Shared private. */ 146 147 struct hostent * 148 gethostbyname_p(const char *name, struct net_data *net_data) { 149 struct hostent *hp; 150 151 if (!net_data) 152 #ifdef SUNW_SETHERRNO 153 { 154 /* 155 * Should set the context h_errno, but since net_data 156 * is NULL, we don't have a context. 157 */ 158 h_errno = NETDB_INTERNAL; 159 return (NULL); 160 } 161 #else 162 return (NULL); 163 #endif /* SUNW_SETHERRNO */ 164 165 if (net_data->res->options & RES_USE_INET6) { 166 hp = gethostbyname2_p(name, AF_INET6, net_data); 167 if (hp) 168 return (hp); 169 } 170 return (gethostbyname2_p(name, AF_INET, net_data)); 171 } 172 173 struct hostent * 174 gethostbyname2_p(const char *name, int af, struct net_data *net_data) { 175 struct irs_ho *ho; 176 char tmp[NS_MAXDNAME]; 177 struct hostent *hp; 178 const char *cp; 179 char **hap; 180 181 if (!net_data || !(ho = net_data->ho)) 182 #ifdef SUNW_SETHERRNO 183 { 184 h_errno = NETDB_INTERNAL; 185 return (NULL); 186 } 187 #else 188 return (NULL); 189 #endif /* SUNW_SETHERRNO */ 190 if (net_data->ho_stayopen && net_data->ho_last && 191 net_data->ho_last->h_addrtype == af) { 192 if (ns_samename(name, net_data->ho_last->h_name) == 1) 193 return (net_data->ho_last); 194 for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++) 195 if (ns_samename(name, *hap) == 1) 196 return (net_data->ho_last); 197 } 198 if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name, 199 tmp, sizeof tmp))) 200 name = cp; 201 if ((hp = fakeaddr(name, af, net_data)) != NULL) 202 return (hp); 203 #ifdef SUNW_OVERRIDE_RETRY 204 net_data->res->retry = __res_retry(net_data->res->retry); 205 #endif /* SUNW_OVERRIDE_RETRY */ 206 net_data->ho_last = (*ho->byname2)(ho, name, af); 207 #ifdef SUNW_OVERRIDE_RETRY 208 net_data->res->retry = __res_retry_reset(); 209 #endif /* SUNW_OVERRIDE_RETRY */ 210 if (!net_data->ho_stayopen) 211 endhostent(); 212 return (net_data->ho_last); 213 } 214 215 struct hostent * 216 gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) { 217 struct irs_ho *ho; 218 char **hap; 219 220 if (!net_data || !(ho = net_data->ho)) 221 #ifdef SUNW_SETHERRNO 222 { 223 h_errno = NETDB_INTERNAL; 224 return (NULL); 225 } 226 #else 227 return (NULL); 228 #endif /* SUNW_SETHERRNO */ 229 if (net_data->ho_stayopen && net_data->ho_last && 230 net_data->ho_last->h_length == len) 231 for (hap = net_data->ho_last->h_addr_list; 232 hap && *hap; 233 hap++) 234 if (!memcmp(addr, *hap, len)) 235 return (net_data->ho_last); 236 net_data->ho_last = (*ho->byaddr)(ho, addr, len, af); 237 if (!net_data->ho_stayopen) 238 endhostent(); 239 return (net_data->ho_last); 240 } 241 242 243 struct hostent * 244 gethostent_p(struct net_data *net_data) { 245 struct irs_ho *ho; 246 struct hostent *hp; 247 248 if (!net_data || !(ho = net_data->ho)) 249 #ifdef SUNW_SETHERRNO 250 { 251 h_errno = NETDB_INTERNAL; 252 return (NULL); 253 } 254 #else 255 return (NULL); 256 #endif /* SUNW_SETHERRNO */ 257 while ((hp = (*ho->next)(ho)) != NULL && 258 hp->h_addrtype == AF_INET6 && 259 (net_data->res->options & RES_USE_INET6) == 0) 260 continue; 261 net_data->ho_last = hp; 262 return (net_data->ho_last); 263 } 264 265 266 void 267 sethostent_p(int stayopen, struct net_data *net_data) { 268 struct irs_ho *ho; 269 270 if (!net_data || !(ho = net_data->ho)) 271 return; 272 freepvt(net_data); 273 (*ho->rewind)(ho); 274 net_data->ho_stayopen = (stayopen != 0); 275 if (stayopen == 0) 276 net_data_minimize(net_data); 277 } 278 279 void 280 endhostent_p(struct net_data *net_data) { 281 struct irs_ho *ho; 282 283 if ((net_data != NULL) && ((ho = net_data->ho) != NULL)) 284 (*ho->minimize)(ho); 285 } 286 287 #ifndef IN6_IS_ADDR_V4COMPAT 288 static const unsigned char in6addr_compat[12] = { 289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 290 #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \ 291 ((x)->s6_addr[12] != 0 || \ 292 (x)->s6_addr[13] != 0 || \ 293 (x)->s6_addr[14] != 0 || \ 294 ((x)->s6_addr[15] != 0 && \ 295 (x)->s6_addr[15] != 1))) 296 #endif 297 #ifndef IN6_IS_ADDR_V4MAPPED 298 #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12)) 299 #endif 300 301 static const unsigned char in6addr_mapped[12] = { 302 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; 303 304 static int scan_interfaces(int *, int *); 305 static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *); 306 307 /* 308 * Public functions 309 */ 310 311 /* 312 * AI_V4MAPPED + AF_INET6 313 * If no IPv6 address then a query for IPv4 and map returned values. 314 * 315 * AI_ALL + AI_V4MAPPED + AF_INET6 316 * Return IPv6 and IPv4 mapped. 317 * 318 * AI_ADDRCONFIG 319 * Only return IPv6 / IPv4 address if there is an interface of that 320 * type active. 321 */ 322 323 struct hostent * 324 getipnodebyname(const char *name, int af, int flags, int *error_num) { 325 int have_v4 = 1, have_v6 = 1; 326 struct in_addr in4; 327 struct in6_addr in6; 328 struct hostent he, *he1 = NULL, *he2 = NULL, *he3; 329 int v4 = 0, v6 = 0; 330 struct net_data *net_data = init(); 331 u_long options; 332 int tmp_err; 333 334 if (net_data == NULL) { 335 *error_num = NO_RECOVERY; 336 return (NULL); 337 } 338 339 /* If we care about active interfaces then check. */ 340 if ((flags & AI_ADDRCONFIG) != 0) 341 if (scan_interfaces(&have_v4, &have_v6) == -1) { 342 *error_num = NO_RECOVERY; 343 return (NULL); 344 } 345 346 /* Check for literal address. */ 347 if ((v4 = inet_pton(AF_INET, name, &in4)) != 1) 348 v6 = inet_pton(AF_INET6, name, &in6); 349 350 /* Impossible combination? */ 351 352 if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) || 353 (af == AF_INET && v6 == 1) || 354 (have_v4 == 0 && v4 == 1) || 355 (have_v6 == 0 && v6 == 1) || 356 (have_v4 == 0 && af == AF_INET) || 357 (have_v6 == 0 && af == AF_INET6)) { 358 *error_num = HOST_NOT_FOUND; 359 return (NULL); 360 } 361 362 /* Literal address? */ 363 if (v4 == 1 || v6 == 1) { 364 char *addr_list[2]; 365 char *aliases[1]; 366 367 DE_CONST(name, he.h_name); 368 he.h_addr_list = addr_list; 369 he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6; 370 he.h_addr_list[1] = NULL; 371 he.h_aliases = aliases; 372 he.h_aliases[0] = NULL; 373 he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ; 374 he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6; 375 return (copyandmerge(&he, NULL, af, error_num)); 376 } 377 378 options = net_data->res->options; 379 net_data->res->options &= ~RES_USE_INET6; 380 381 tmp_err = NO_RECOVERY; 382 if (have_v6 && af == AF_INET6) { 383 he2 = gethostbyname2_p(name, AF_INET6, net_data); 384 if (he2 != NULL) { 385 he1 = copyandmerge(he2, NULL, af, error_num); 386 if (he1 == NULL) 387 return (NULL); 388 he2 = NULL; 389 } else { 390 tmp_err = net_data->res->res_h_errno; 391 } 392 } 393 394 if (have_v4 && 395 ((af == AF_INET) || 396 (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 && 397 (he1 == NULL || (flags & AI_ALL) != 0)))) { 398 he2 = gethostbyname2_p(name, AF_INET, net_data); 399 if (he1 == NULL && he2 == NULL) { 400 *error_num = net_data->res->res_h_errno; 401 return (NULL); 402 } 403 } else 404 *error_num = tmp_err; 405 406 net_data->res->options = options; 407 408 he3 = copyandmerge(he1, he2, af, error_num); 409 410 if (he1 != NULL) 411 freehostent(he1); 412 return (he3); 413 } 414 415 struct hostent * 416 getipnodebyaddr(const void *src, size_t len, int af, int *error_num) { 417 struct hostent *he1, *he2; 418 struct net_data *net_data = init(); 419 420 /* Sanity Checks. */ 421 if (src == NULL) { 422 *error_num = NO_RECOVERY; 423 return (NULL); 424 } 425 426 switch (af) { 427 case AF_INET: 428 if (len != INADDRSZ) { 429 *error_num = NO_RECOVERY; 430 return (NULL); 431 } 432 break; 433 case AF_INET6: 434 if (len != IN6ADDRSZ) { 435 *error_num = NO_RECOVERY; 436 return (NULL); 437 } 438 break; 439 default: 440 *error_num = NO_RECOVERY; 441 return (NULL); 442 } 443 444 /* 445 * Lookup IPv4 and IPv4 mapped/compatible addresses 446 */ 447 if ((af == AF_INET6 && 448 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) || 449 (af == AF_INET6 && 450 IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) || 451 (af == AF_INET)) { 452 const char *cp = src; 453 454 if (af == AF_INET6) 455 cp += 12; 456 he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data); 457 if (he1 == NULL) { 458 *error_num = net_data->res->res_h_errno; 459 return (NULL); 460 } 461 he2 = copyandmerge(he1, NULL, af, error_num); 462 if (he2 == NULL) 463 return (NULL); 464 /* 465 * Restore original address if mapped/compatible. 466 */ 467 if (af == AF_INET6) 468 memcpy(he1->h_addr, src, len); 469 return (he2); 470 } 471 472 /* 473 * Lookup IPv6 address. 474 */ 475 if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) { 476 *error_num = HOST_NOT_FOUND; 477 return (NULL); 478 } 479 480 he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data); 481 if (he1 == NULL) { 482 *error_num = net_data->res->res_h_errno; 483 return (NULL); 484 } 485 return (copyandmerge(he1, NULL, af, error_num)); 486 } 487 488 void 489 freehostent(struct hostent *he) { 490 char **cpp; 491 int names = 1; 492 int addresses = 1; 493 494 memput(he->h_name, strlen(he->h_name) + 1); 495 496 cpp = he->h_addr_list; 497 while (*cpp != NULL) { 498 memput(*cpp, (he->h_addrtype == AF_INET) ? 499 INADDRSZ : IN6ADDRSZ); 500 *cpp = NULL; 501 cpp++; 502 addresses++; 503 } 504 505 cpp = he->h_aliases; 506 while (*cpp != NULL) { 507 memput(*cpp, strlen(*cpp) + 1); 508 cpp++; 509 names++; 510 } 511 512 memput(he->h_aliases, sizeof(char *) * (names)); 513 memput(he->h_addr_list, sizeof(char *) * (addresses)); 514 memput(he, sizeof *he); 515 } 516 517 /* 518 * Private 519 */ 520 521 /* 522 * Scan the interface table and set have_v4 and have_v6 depending 523 * upon whether there are IPv4 and IPv6 interface addresses. 524 * 525 * Returns: 526 * 0 on success 527 * -1 on failure. 528 */ 529 530 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ 531 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 532 533 #define SETFAMILYFLAGS 534 #define LIFCONF lifconf 535 #define LIFREQ lifreq 536 537 static void 538 scan_interfaces6(int *have_v4, int *have_v6) { 539 struct LIFCONF lifc; 540 struct LIFREQ lifreq; 541 struct in_addr in4; 542 struct in6_addr in6; 543 char *buf = NULL, *cp, *cplim; 544 static unsigned int bufsiz = 4095; 545 int s, cpsize, n; 546 547 /* Get interface list from system. */ 548 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) 549 goto cleanup; 550 551 /* 552 * Grow buffer until large enough to contain all interface 553 * descriptions. 554 */ 555 for (;;) { 556 buf = memget(bufsiz); 557 if (buf == NULL) 558 goto cleanup; 559 #ifdef SETFAMILYFLAGS 560 lifc.lifc_family = AF_UNSPEC; /* request all families */ 561 lifc.lifc_flags = 0; 562 #endif 563 lifc.lifc_len = bufsiz; 564 lifc.lifc_buf = buf; 565 if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) { 566 /* 567 * Some OS's just return what will fit rather 568 * than set EINVAL if the buffer is too small 569 * to fit all the interfaces in. If 570 * lifc.lifc_len is too near to the end of the 571 * buffer we will grow it just in case and 572 * retry. 573 */ 574 if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz) 575 break; 576 } 577 if ((n == -1) && errno != EINVAL) 578 goto cleanup; 579 580 if (bufsiz > 1000000) 581 goto cleanup; 582 583 memput(buf, bufsiz); 584 bufsiz += 4096; 585 } 586 587 /* Parse system's interface list. */ 588 cplim = buf + lifc.lifc_len; /* skip over if's with big ifr_addr's */ 589 for (cp = buf; 590 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; 591 cp += cpsize) { 592 memcpy(&lifreq, cp, sizeof lifreq); 593 #ifdef HAVE_SA_LEN 594 #ifdef FIX_ZERO_SA_LEN 595 if (lifreq.lifr_addr.sa_len == 0) 596 lifreq.lifr_addr.sa_len = 16; 597 #endif 598 #ifdef HAVE_MINIMUM_IFREQ 599 cpsize = sizeof lifreq; 600 if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr)) 601 cpsize += (int)lifreq.lifr_addr.sa_len - 602 (int)(sizeof (struct sockaddr)); 603 #else 604 cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len; 605 #endif /* HAVE_MINIMUM_IFREQ */ 606 #elif defined SIOCGIFCONF_ADDR 607 cpsize = sizeof lifreq; 608 #else 609 cpsize = sizeof lifreq.lifr_name; 610 /* XXX maybe this should be a hard error? */ 611 if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0) 612 continue; 613 #endif 614 switch (lifreq.lifr_addr.ss_family) { 615 case AF_INET: 616 if (*have_v4 == 0) { 617 memcpy(&in4, 618 &((struct sockaddr_in *) 619 &lifreq.lifr_addr)->sin_addr, 620 sizeof in4); 621 if (in4.s_addr == INADDR_ANY) 622 break; 623 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); 624 if (n < 0) 625 break; 626 if ((lifreq.lifr_flags & IFF_UP) == 0) 627 break; 628 *have_v4 = 1; 629 } 630 break; 631 case AF_INET6: 632 if (*have_v6 == 0) { 633 memcpy(&in6, 634 &((struct sockaddr_in6 *) 635 &lifreq.lifr_addr)->sin6_addr, sizeof in6); 636 if (memcmp(&in6, &in6addr_any, sizeof in6) == 0) 637 break; 638 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); 639 if (n < 0) 640 break; 641 if ((lifreq.lifr_flags & IFF_UP) == 0) 642 break; 643 *have_v6 = 1; 644 } 645 break; 646 } 647 } 648 if (buf != NULL) 649 memput(buf, bufsiz); 650 close(s); 651 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ 652 return; 653 cleanup: 654 if (buf != NULL) 655 memput(buf, bufsiz); 656 if (s != -1) 657 close(s); 658 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ 659 return; 660 } 661 #endif 662 663 static int 664 scan_interfaces(int *have_v4, int *have_v6) { 665 struct ifconf ifc; 666 union { 667 char _pad[256]; /* leave space for IPv6 addresses */ 668 struct ifreq ifreq; 669 } u; 670 struct in_addr in4; 671 struct in6_addr in6; 672 char *buf = NULL, *cp, *cplim; 673 static unsigned int bufsiz = 4095; 674 int s, n; 675 size_t cpsize; 676 677 /* Set to zero. Used as loop terminators below. */ 678 *have_v4 = *have_v6 = 0; 679 680 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ 681 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 682 /* 683 * Try to scan the interfaces using IPv6 ioctls(). 684 */ 685 scan_interfaces6(have_v4, have_v6); 686 if (*have_v4 != 0 && *have_v6 != 0) 687 return (0); 688 #endif 689 690 /* Get interface list from system. */ 691 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 692 goto err_ret; 693 694 /* 695 * Grow buffer until large enough to contain all interface 696 * descriptions. 697 */ 698 for (;;) { 699 buf = memget(bufsiz); 700 if (buf == NULL) 701 goto err_ret; 702 ifc.ifc_len = bufsiz; 703 ifc.ifc_buf = buf; 704 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF 705 /* 706 * This is a fix for IRIX OS in which the call to ioctl with 707 * the flag SIOCGIFCONF may not return an entry for all the 708 * interfaces like most flavors of Unix. 709 */ 710 if (emul_ioctl(&ifc) >= 0) 711 break; 712 #else 713 if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) { 714 /* 715 * Some OS's just return what will fit rather 716 * than set EINVAL if the buffer is too small 717 * to fit all the interfaces in. If 718 * ifc.ifc_len is too near to the end of the 719 * buffer we will grow it just in case and 720 * retry. 721 */ 722 if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz) 723 break; 724 } 725 #endif 726 if ((n == -1) && errno != EINVAL) 727 goto err_ret; 728 729 if (bufsiz > 1000000) 730 goto err_ret; 731 732 memput(buf, bufsiz); 733 bufsiz += 4096; 734 } 735 736 /* Parse system's interface list. */ 737 cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */ 738 for (cp = buf; 739 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; 740 cp += cpsize) { 741 memcpy(&u.ifreq, cp, sizeof u.ifreq); 742 #ifdef HAVE_SA_LEN 743 #ifdef FIX_ZERO_SA_LEN 744 if (u.ifreq.ifr_addr.sa_len == 0) 745 u.ifreq.ifr_addr.sa_len = 16; 746 #endif 747 #ifdef HAVE_MINIMUM_IFREQ 748 cpsize = sizeof u.ifreq; 749 if (u.ifreq.ifr_addr.sa_len > sizeof (struct sockaddr)) 750 cpsize += (int)u.ifreq.ifr_addr.sa_len - 751 (int)(sizeof (struct sockaddr)); 752 #else 753 cpsize = sizeof u.ifreq.ifr_name + u.ifreq.ifr_addr.sa_len; 754 #endif /* HAVE_MINIMUM_IFREQ */ 755 if (cpsize > sizeof u.ifreq && cpsize <= sizeof u) 756 memcpy(&u.ifreq, cp, cpsize); 757 #elif defined SIOCGIFCONF_ADDR 758 cpsize = sizeof u.ifreq; 759 #else 760 cpsize = sizeof u.ifreq.ifr_name; 761 /* XXX maybe this should be a hard error? */ 762 if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0) 763 continue; 764 #endif 765 switch (u.ifreq.ifr_addr.sa_family) { 766 case AF_INET: 767 if (*have_v4 == 0) { 768 memcpy(&in4, 769 &((struct sockaddr_in *) 770 &u.ifreq.ifr_addr)->sin_addr, 771 sizeof in4); 772 if (in4.s_addr == INADDR_ANY) 773 break; 774 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); 775 if (n < 0) 776 break; 777 if ((u.ifreq.ifr_flags & IFF_UP) == 0) 778 break; 779 *have_v4 = 1; 780 } 781 break; 782 case AF_INET6: 783 if (*have_v6 == 0) { 784 memcpy(&in6, 785 &((struct sockaddr_in6 *) 786 &u.ifreq.ifr_addr)->sin6_addr, 787 sizeof in6); 788 if (memcmp(&in6, &in6addr_any, sizeof in6) == 0) 789 break; 790 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); 791 if (n < 0) 792 break; 793 if ((u.ifreq.ifr_flags & IFF_UP) == 0) 794 break; 795 *have_v6 = 1; 796 } 797 break; 798 } 799 } 800 if (buf != NULL) 801 memput(buf, bufsiz); 802 close(s); 803 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ 804 return (0); 805 err_ret: 806 if (buf != NULL) 807 memput(buf, bufsiz); 808 if (s != -1) 809 close(s); 810 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ 811 return (-1); 812 } 813 814 static struct hostent * 815 copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) { 816 struct hostent *he = NULL; 817 int addresses = 1; /* NULL terminator */ 818 int names = 1; /* NULL terminator */ 819 int len = 0; 820 char **cpp, **npp; 821 822 /* 823 * Work out array sizes; 824 */ 825 if (he1 != NULL) { 826 cpp = he1->h_addr_list; 827 while (*cpp != NULL) { 828 addresses++; 829 cpp++; 830 } 831 cpp = he1->h_aliases; 832 while (*cpp != NULL) { 833 names++; 834 cpp++; 835 } 836 } 837 838 if (he2 != NULL) { 839 cpp = he2->h_addr_list; 840 while (*cpp != NULL) { 841 addresses++; 842 cpp++; 843 } 844 if (he1 == NULL) { 845 cpp = he2->h_aliases; 846 while (*cpp != NULL) { 847 names++; 848 cpp++; 849 } 850 } 851 } 852 853 if (addresses == 1) { 854 *error_num = NO_ADDRESS; 855 return (NULL); 856 } 857 858 he = memget(sizeof *he); 859 if (he == NULL) 860 goto no_recovery; 861 862 he->h_addr_list = memget(sizeof(char *) * (addresses)); 863 if (he->h_addr_list == NULL) 864 goto cleanup0; 865 memset(he->h_addr_list, 0, sizeof(char *) * (addresses)); 866 867 /* copy addresses */ 868 npp = he->h_addr_list; 869 if (he1 != NULL) { 870 cpp = he1->h_addr_list; 871 while (*cpp != NULL) { 872 *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 873 if (*npp == NULL) 874 goto cleanup1; 875 /* convert to mapped if required */ 876 if (af == AF_INET6 && he1->h_addrtype == AF_INET) { 877 memcpy(*npp, in6addr_mapped, 878 sizeof in6addr_mapped); 879 memcpy(*npp + sizeof in6addr_mapped, *cpp, 880 INADDRSZ); 881 } else { 882 memcpy(*npp, *cpp, 883 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 884 } 885 cpp++; 886 npp++; 887 } 888 } 889 890 if (he2 != NULL) { 891 cpp = he2->h_addr_list; 892 while (*cpp != NULL) { 893 *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 894 if (*npp == NULL) 895 goto cleanup1; 896 /* convert to mapped if required */ 897 if (af == AF_INET6 && he2->h_addrtype == AF_INET) { 898 memcpy(*npp, in6addr_mapped, 899 sizeof in6addr_mapped); 900 memcpy(*npp + sizeof in6addr_mapped, *cpp, 901 INADDRSZ); 902 } else { 903 memcpy(*npp, *cpp, 904 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 905 } 906 cpp++; 907 npp++; 908 } 909 } 910 911 he->h_aliases = memget(sizeof(char *) * (names)); 912 if (he->h_aliases == NULL) 913 goto cleanup1; 914 memset(he->h_aliases, 0, sizeof(char *) * (names)); 915 916 /* copy aliases */ 917 npp = he->h_aliases; 918 cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases; 919 while (*cpp != NULL) { 920 len = strlen (*cpp) + 1; 921 *npp = memget(len); 922 if (*npp == NULL) 923 goto cleanup2; 924 strcpy(*npp, *cpp); 925 npp++; 926 cpp++; 927 } 928 929 /* copy hostname */ 930 he->h_name = memget(strlen((he1 != NULL) ? 931 he1->h_name : he2->h_name) + 1); 932 if (he->h_name == NULL) 933 goto cleanup2; 934 strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name); 935 936 /* set address type and length */ 937 he->h_addrtype = af; 938 he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ; 939 return(he); 940 941 cleanup2: 942 cpp = he->h_aliases; 943 while (*cpp != NULL) { 944 memput(*cpp, strlen(*cpp) + 1); 945 cpp++; 946 } 947 memput(he->h_aliases, sizeof(char *) * (names)); 948 949 cleanup1: 950 cpp = he->h_addr_list; 951 while (*cpp != NULL) { 952 memput(*cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 953 *cpp = NULL; 954 cpp++; 955 } 956 memput(he->h_addr_list, sizeof(char *) * (addresses)); 957 958 cleanup0: 959 memput(he, sizeof *he); 960 961 no_recovery: 962 *error_num = NO_RECOVERY; 963 return (NULL); 964 } 965 966 static struct net_data * 967 init() { 968 struct net_data *net_data; 969 970 if (!(net_data = net_data_init(NULL))) 971 goto error; 972 if (!net_data->ho) { 973 net_data->ho = (*net_data->irs->ho_map)(net_data->irs); 974 if (!net_data->ho || !net_data->res) { 975 error: 976 errno = EIO; 977 if (net_data && net_data->res) 978 RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); 979 return (NULL); 980 } 981 982 (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL); 983 } 984 985 return (net_data); 986 } 987 988 static void 989 freepvt(struct net_data *net_data) { 990 if (net_data->ho_data) { 991 free(net_data->ho_data); 992 net_data->ho_data = NULL; 993 } 994 } 995 996 static struct hostent * 997 fakeaddr(const char *name, int af, struct net_data *net_data) { 998 struct pvt *pvt; 999 1000 freepvt(net_data); 1001 net_data->ho_data = malloc(sizeof (struct pvt)); 1002 if (!net_data->ho_data) { 1003 errno = ENOMEM; 1004 RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); 1005 return (NULL); 1006 } 1007 pvt = net_data->ho_data; 1008 #ifndef __bsdi__ 1009 /* 1010 * Unlike its forebear(inet_aton), our friendly inet_pton() is strict 1011 * in its interpretation of its input, and it will only return "1" if 1012 * the input string is a formally valid(and thus unambiguous with 1013 * respect to host names) internet address specification for this AF. 1014 * 1015 * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now. 1016 */ 1017 if (inet_pton(af, name, pvt->addr) != 1) { 1018 #else 1019 /* BSDI XXX 1020 * We put this back to inet_aton -- we really want the old behavior 1021 * Long live 127.1... 1022 */ 1023 if ((af != AF_INET || 1024 inet_aton(name, (struct in_addr *)pvt->addr) != 1) && 1025 inet_pton(af, name, pvt->addr) != 1) { 1026 #endif 1027 RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); 1028 return (NULL); 1029 } 1030 strncpy(pvt->name, name, NS_MAXDNAME); 1031 pvt->name[NS_MAXDNAME] = '\0'; 1032 if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0) { 1033 map_v4v6_address(pvt->addr, pvt->addr); 1034 af = AF_INET6; 1035 } 1036 pvt->host.h_addrtype = af; 1037 switch(af) { 1038 case AF_INET: 1039 pvt->host.h_length = NS_INADDRSZ; 1040 break; 1041 case AF_INET6: 1042 pvt->host.h_length = NS_IN6ADDRSZ; 1043 break; 1044 default: 1045 errno = EAFNOSUPPORT; 1046 RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); 1047 return (NULL); 1048 } 1049 pvt->host.h_name = pvt->name; 1050 pvt->host.h_aliases = pvt->aliases; 1051 pvt->aliases[0] = NULL; 1052 pvt->addrs[0] = (char *)pvt->addr; 1053 pvt->addrs[1] = NULL; 1054 pvt->host.h_addr_list = pvt->addrs; 1055 RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS); 1056 return (&pvt->host); 1057 } 1058 1059 #ifdef grot /* for future use in gethostbyaddr(), for "SUNSECURITY" */ 1060 struct hostent *rhp; 1061 char **haddr; 1062 u_long old_options; 1063 char hname2[MAXDNAME+1]; 1064 1065 if (af == AF_INET) { 1066 /* 1067 * turn off search as the name should be absolute, 1068 * 'localhost' should be matched by defnames 1069 */ 1070 strncpy(hname2, hp->h_name, MAXDNAME); 1071 hname2[MAXDNAME] = '\0'; 1072 old_options = net_data->res->options; 1073 net_data->res->options &= ~RES_DNSRCH; 1074 net_data->res->options |= RES_DEFNAMES; 1075 if (!(rhp = gethostbyname(hname2))) { 1076 net_data->res->options = old_options; 1077 RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); 1078 return (NULL); 1079 } 1080 net_data->res->options = old_options; 1081 for (haddr = rhp->h_addr_list; *haddr; haddr++) 1082 if (!memcmp(*haddr, addr, INADDRSZ)) 1083 break; 1084 if (!*haddr) { 1085 RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); 1086 return (NULL); 1087 } 1088 } 1089 #endif /* grot */ 1090 1091 #endif /*__BIND_NOSTATIC*/ 1092