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