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 #if !defined(LINT) && !defined(CODECENTER) 25 static const char rcsid[] = "$Id: gethostent.c,v 1.8 2006/01/10 05:06:00 marka Exp $"; 26 #endif 27 28 /* Imports */ 29 30 #include "port_before.h" 31 32 #if !defined(__BIND_NOSTATIC) 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/socket.h> 37 #include <sys/ioctl.h> 38 #include <netinet/in.h> 39 #include <net/if.h> 40 #include <arpa/inet.h> 41 #include <arpa/nameser.h> 42 43 #include <ctype.h> 44 #include <errno.h> 45 #include <stdlib.h> 46 #include <netdb.h> 47 #include <resolv.h> 48 #include <stdio.h> 49 #include <string.h> 50 #include <unistd.h> 51 52 #include <irs.h> 53 #include <isc/memcluster.h> 54 55 #include "port_after.h" 56 57 #include "irs_p.h" 58 #include "irs_data.h" 59 60 /* Definitions */ 61 62 struct pvt { 63 char * aliases[1]; 64 char * addrs[2]; 65 char addr[NS_IN6ADDRSZ]; 66 char name[NS_MAXDNAME + 1]; 67 struct hostent host; 68 }; 69 70 /* Forward */ 71 72 static struct net_data *init(void); 73 static void freepvt(struct net_data *); 74 static struct hostent *fakeaddr(const char *, int, struct net_data *); 75 76 #ifdef SUNW_OVERRIDE_RETRY 77 extern int __res_retry(int); 78 extern int __res_retry_reset(void); 79 #endif /* SUNW_OVERRIDE_RETRY */ 80 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 gethostbyaddr(const char *addr, int len, int af) { 100 struct net_data *net_data = init(); 101 102 return (gethostbyaddr_p(addr, len, af, net_data)); 103 } 104 105 struct hostent * 106 gethostent() { 107 struct net_data *net_data = init(); 108 109 return (gethostent_p(net_data)); 110 } 111 112 void 113 sethostent(int stayopen) { 114 struct net_data *net_data = init(); 115 sethostent_p(stayopen, net_data); 116 } 117 118 119 void 120 endhostent() { 121 struct net_data *net_data = init(); 122 endhostent_p(net_data); 123 } 124 125 /* Shared private. */ 126 127 struct hostent * 128 gethostbyname_p(const char *name, struct net_data *net_data) { 129 struct hostent *hp; 130 131 if (!net_data) 132 return (NULL); 133 134 if (net_data->res->options & RES_USE_INET6) { 135 hp = gethostbyname2_p(name, AF_INET6, net_data); 136 if (hp) 137 return (hp); 138 } 139 return (gethostbyname2_p(name, AF_INET, net_data)); 140 } 141 142 struct hostent * 143 gethostbyname2_p(const char *name, int af, struct net_data *net_data) { 144 struct irs_ho *ho; 145 char tmp[NS_MAXDNAME]; 146 struct hostent *hp; 147 const char *cp; 148 char **hap; 149 150 if (!net_data || !(ho = net_data->ho)) 151 return (NULL); 152 if (net_data->ho_stayopen && net_data->ho_last && 153 net_data->ho_last->h_addrtype == af) { 154 if (ns_samename(name, net_data->ho_last->h_name) == 1) 155 return (net_data->ho_last); 156 for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++) 157 if (ns_samename(name, *hap) == 1) 158 return (net_data->ho_last); 159 } 160 if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name, 161 tmp, sizeof tmp))) 162 name = cp; 163 if ((hp = fakeaddr(name, af, net_data)) != NULL) 164 return (hp); 165 #ifdef SUNW_OVERRIDE_RETRY 166 net_data->res->retry = __res_retry(net_data->res->retry); 167 #endif /* SUNW_OVERRIDE_RETRY */ 168 net_data->ho_last = (*ho->byname2)(ho, name, af); 169 #ifdef SUNW_OVERRIDE_RETRY 170 net_data->res->retry = __res_retry_reset(); 171 #endif /* SUNW_OVERRIDE_RETRY */ 172 if (!net_data->ho_stayopen) 173 endhostent(); 174 return (net_data->ho_last); 175 } 176 177 struct hostent * 178 gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) { 179 struct irs_ho *ho; 180 char **hap; 181 182 if (!net_data || !(ho = net_data->ho)) 183 return (NULL); 184 if (net_data->ho_stayopen && net_data->ho_last && 185 net_data->ho_last->h_length == len) 186 for (hap = net_data->ho_last->h_addr_list; 187 hap && *hap; 188 hap++) 189 if (!memcmp(addr, *hap, len)) 190 return (net_data->ho_last); 191 net_data->ho_last = (*ho->byaddr)(ho, addr, len, af); 192 if (!net_data->ho_stayopen) 193 endhostent(); 194 return (net_data->ho_last); 195 } 196 197 198 struct hostent * 199 gethostent_p(struct net_data *net_data) { 200 struct irs_ho *ho; 201 struct hostent *hp; 202 203 if (!net_data || !(ho = net_data->ho)) 204 return (NULL); 205 while ((hp = (*ho->next)(ho)) != NULL && 206 hp->h_addrtype == AF_INET6 && 207 (net_data->res->options & RES_USE_INET6) == 0U) 208 continue; 209 net_data->ho_last = hp; 210 return (net_data->ho_last); 211 } 212 213 214 void 215 sethostent_p(int stayopen, struct net_data *net_data) { 216 struct irs_ho *ho; 217 218 if (!net_data || !(ho = net_data->ho)) 219 return; 220 freepvt(net_data); 221 (*ho->rewind)(ho); 222 net_data->ho_stayopen = (stayopen != 0); 223 if (stayopen == 0) 224 net_data_minimize(net_data); 225 } 226 227 void 228 endhostent_p(struct net_data *net_data) { 229 struct irs_ho *ho; 230 231 if ((net_data != NULL) && ((ho = net_data->ho) != NULL)) 232 (*ho->minimize)(ho); 233 } 234 235 #ifndef IN6_IS_ADDR_V4COMPAT 236 static const unsigned char in6addr_compat[12] = { 237 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 238 #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \ 239 ((x)->s6_addr[12] != 0 || \ 240 (x)->s6_addr[13] != 0 || \ 241 (x)->s6_addr[14] != 0 || \ 242 ((x)->s6_addr[15] != 0 && \ 243 (x)->s6_addr[15] != 1))) 244 #endif 245 #ifndef IN6_IS_ADDR_V4MAPPED 246 #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12)) 247 #endif 248 249 static const unsigned char in6addr_mapped[12] = { 250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; 251 252 static int scan_interfaces(int *, int *); 253 static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *); 254 255 /*% 256 * Public functions 257 */ 258 259 /*% 260 * AI_V4MAPPED + AF_INET6 261 * If no IPv6 address then a query for IPv4 and map returned values. 262 * 263 * AI_ALL + AI_V4MAPPED + AF_INET6 264 * Return IPv6 and IPv4 mapped. 265 * 266 * AI_ADDRCONFIG 267 * Only return IPv6 / IPv4 address if there is an interface of that 268 * type active. 269 */ 270 271 struct hostent * 272 getipnodebyname(const char *name, int af, int flags, int *error_num) { 273 int have_v4 = 1, have_v6 = 1; 274 struct in_addr in4; 275 struct in6_addr in6; 276 struct hostent he, *he1 = NULL, *he2 = NULL, *he3; 277 int v4 = 0, v6 = 0; 278 struct net_data *net_data = init(); 279 u_long options; 280 int tmp_err; 281 282 if (net_data == NULL) { 283 *error_num = NO_RECOVERY; 284 return (NULL); 285 } 286 287 /* If we care about active interfaces then check. */ 288 if ((flags & AI_ADDRCONFIG) != 0) 289 if (scan_interfaces(&have_v4, &have_v6) == -1) { 290 *error_num = NO_RECOVERY; 291 return (NULL); 292 } 293 294 /* Check for literal address. */ 295 if ((v4 = inet_pton(AF_INET, name, &in4)) != 1) 296 v6 = inet_pton(AF_INET6, name, &in6); 297 298 /* Impossible combination? */ 299 300 if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) || 301 (af == AF_INET && v6 == 1) || 302 (have_v4 == 0 && v4 == 1) || 303 (have_v6 == 0 && v6 == 1) || 304 (have_v4 == 0 && af == AF_INET) || 305 (have_v6 == 0 && af == AF_INET6)) { 306 *error_num = HOST_NOT_FOUND; 307 return (NULL); 308 } 309 310 /* Literal address? */ 311 if (v4 == 1 || v6 == 1) { 312 char *addr_list[2]; 313 char *aliases[1]; 314 315 DE_CONST(name, he.h_name); 316 he.h_addr_list = addr_list; 317 he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6; 318 he.h_addr_list[1] = NULL; 319 he.h_aliases = aliases; 320 he.h_aliases[0] = NULL; 321 he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ; 322 he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6; 323 return (copyandmerge(&he, NULL, af, error_num)); 324 } 325 326 options = net_data->res->options; 327 net_data->res->options &= ~RES_USE_INET6; 328 329 tmp_err = NO_RECOVERY; 330 if (have_v6 && af == AF_INET6) { 331 he2 = gethostbyname2_p(name, AF_INET6, net_data); 332 if (he2 != NULL) { 333 he1 = copyandmerge(he2, NULL, af, error_num); 334 if (he1 == NULL) 335 return (NULL); 336 he2 = NULL; 337 } else { 338 tmp_err = net_data->res->res_h_errno; 339 } 340 } 341 342 if (have_v4 && 343 ((af == AF_INET) || 344 (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 && 345 (he1 == NULL || (flags & AI_ALL) != 0)))) { 346 he2 = gethostbyname2_p(name, AF_INET, net_data); 347 if (he1 == NULL && he2 == NULL) { 348 *error_num = net_data->res->res_h_errno; 349 return (NULL); 350 } 351 } else 352 *error_num = tmp_err; 353 354 net_data->res->options = options; 355 356 he3 = copyandmerge(he1, he2, af, error_num); 357 358 if (he1 != NULL) 359 freehostent(he1); 360 return (he3); 361 } 362 363 struct hostent * 364 getipnodebyaddr(const void *src, size_t len, int af, int *error_num) { 365 struct hostent *he1, *he2; 366 struct net_data *net_data = init(); 367 368 /* Sanity Checks. */ 369 #ifdef ORIGINAL_ISC_CODE 370 if (src == NULL) { 371 #else 372 /* this change was added circa May 2009, but not in ISC libbind 6.0 */ 373 if (src == NULL|| net_data == NULL) { 374 #endif /* ORIGINAL_ISC_CODE */ 375 *error_num = NO_RECOVERY; 376 return (NULL); 377 } 378 379 switch (af) { 380 case AF_INET: 381 if (len != (size_t)INADDRSZ) { 382 *error_num = NO_RECOVERY; 383 return (NULL); 384 } 385 break; 386 case AF_INET6: 387 if (len != (size_t)IN6ADDRSZ) { 388 *error_num = NO_RECOVERY; 389 return (NULL); 390 } 391 break; 392 default: 393 *error_num = NO_RECOVERY; 394 return (NULL); 395 } 396 397 /* 398 * Lookup IPv4 and IPv4 mapped/compatible addresses 399 */ 400 if ((af == AF_INET6 && 401 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) || 402 (af == AF_INET6 && 403 IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) || 404 (af == AF_INET)) { 405 const char *cp = src; 406 407 if (af == AF_INET6) 408 cp += 12; 409 he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data); 410 if (he1 == NULL) { 411 *error_num = net_data->res->res_h_errno; 412 return (NULL); 413 } 414 he2 = copyandmerge(he1, NULL, af, error_num); 415 if (he2 == NULL) 416 return (NULL); 417 /* 418 * Restore original address if mapped/compatible. 419 */ 420 if (af == AF_INET6) 421 memcpy(he1->h_addr, src, len); 422 return (he2); 423 } 424 425 /* 426 * Lookup IPv6 address. 427 */ 428 if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) { 429 *error_num = HOST_NOT_FOUND; 430 return (NULL); 431 } 432 433 he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data); 434 if (he1 == NULL) { 435 *error_num = net_data->res->res_h_errno; 436 return (NULL); 437 } 438 return (copyandmerge(he1, NULL, af, error_num)); 439 } 440 441 void 442 freehostent(struct hostent *he) { 443 char **cpp; 444 int names = 1; 445 int addresses = 1; 446 447 memput(he->h_name, strlen(he->h_name) + 1); 448 449 cpp = he->h_addr_list; 450 while (*cpp != NULL) { 451 memput(*cpp, (he->h_addrtype == AF_INET) ? 452 INADDRSZ : IN6ADDRSZ); 453 *cpp = NULL; 454 cpp++; 455 addresses++; 456 } 457 458 cpp = he->h_aliases; 459 while (*cpp != NULL) { 460 memput(*cpp, strlen(*cpp) + 1); 461 cpp++; 462 names++; 463 } 464 465 memput(he->h_aliases, sizeof(char *) * (names)); 466 memput(he->h_addr_list, sizeof(char *) * (addresses)); 467 memput(he, sizeof *he); 468 } 469 470 /*% 471 * Private 472 */ 473 474 /*% 475 * Scan the interface table and set have_v4 and have_v6 depending 476 * upon whether there are IPv4 and IPv6 interface addresses. 477 * 478 * Returns: 479 * 0 on success 480 * -1 on failure. 481 */ 482 483 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ 484 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 485 486 #ifdef __hpux 487 #define lifc_len iflc_len 488 #define lifc_buf iflc_buf 489 #define lifc_req iflc_req 490 #define LIFCONF if_laddrconf 491 #else 492 #define SETFAMILYFLAGS 493 #define LIFCONF lifconf 494 #endif 495 496 #ifdef __hpux 497 #define lifr_addr iflr_addr 498 #define lifr_name iflr_name 499 #define lifr_dstaddr iflr_dstaddr 500 #define lifr_flags iflr_flags 501 #define ss_family sa_family 502 #define LIFREQ if_laddrreq 503 #else 504 #define LIFREQ lifreq 505 #endif 506 507 static void 508 scan_interfaces6(int *have_v4, int *have_v6) { 509 struct LIFCONF lifc; 510 struct LIFREQ lifreq; 511 struct in_addr in4; 512 struct in6_addr in6; 513 char *buf = NULL, *cp, *cplim; 514 static unsigned int bufsiz = 4095; 515 int s, cpsize, n; 516 517 /* Get interface list from system. */ 518 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) 519 goto cleanup; 520 521 /* 522 * Grow buffer until large enough to contain all interface 523 * descriptions. 524 */ 525 for (;;) { 526 buf = memget(bufsiz); 527 if (buf == NULL) 528 goto cleanup; 529 #ifdef SETFAMILYFLAGS 530 lifc.lifc_family = AF_UNSPEC; /*%< request all families */ 531 lifc.lifc_flags = 0; 532 #endif 533 lifc.lifc_len = bufsiz; 534 lifc.lifc_buf = buf; 535 if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) { 536 /* 537 * Some OS's just return what will fit rather 538 * than set EINVAL if the buffer is too small 539 * to fit all the interfaces in. If 540 * lifc.lifc_len is too near to the end of the 541 * buffer we will grow it just in case and 542 * retry. 543 */ 544 if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz) 545 break; 546 } 547 if ((n == -1) && errno != EINVAL) 548 goto cleanup; 549 550 if (bufsiz > 1000000) 551 goto cleanup; 552 553 memput(buf, bufsiz); 554 bufsiz += 4096; 555 } 556 557 /* Parse system's interface list. */ 558 cplim = buf + lifc.lifc_len; /*%< skip over if's with big ifr_addr's */ 559 for (cp = buf; 560 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; 561 cp += cpsize) { 562 memcpy(&lifreq, cp, sizeof lifreq); 563 #ifdef HAVE_SA_LEN 564 #ifdef FIX_ZERO_SA_LEN 565 if (lifreq.lifr_addr.sa_len == 0) 566 lifreq.lifr_addr.sa_len = 16; 567 #endif 568 #ifdef HAVE_MINIMUM_IFREQ 569 cpsize = sizeof lifreq; 570 if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr)) 571 cpsize += (int)lifreq.lifr_addr.sa_len - 572 (int)(sizeof (struct sockaddr)); 573 #else 574 cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len; 575 #endif /* HAVE_MINIMUM_IFREQ */ 576 #elif defined SIOCGIFCONF_ADDR 577 cpsize = sizeof lifreq; 578 #else 579 cpsize = sizeof lifreq.lifr_name; 580 /* XXX maybe this should be a hard error? */ 581 if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0) 582 continue; 583 #endif 584 switch (lifreq.lifr_addr.ss_family) { 585 case AF_INET: 586 if (*have_v4 == 0) { 587 memcpy(&in4, 588 &((struct sockaddr_in *) 589 &lifreq.lifr_addr)->sin_addr, 590 sizeof in4); 591 if (in4.s_addr == INADDR_ANY) 592 break; 593 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); 594 if (n < 0) 595 break; 596 if ((lifreq.lifr_flags & IFF_UP) == 0) 597 break; 598 *have_v4 = 1; 599 } 600 break; 601 case AF_INET6: 602 if (*have_v6 == 0) { 603 memcpy(&in6, 604 &((struct sockaddr_in6 *) 605 &lifreq.lifr_addr)->sin6_addr, sizeof in6); 606 if (memcmp(&in6, &in6addr_any, sizeof in6) == 0) 607 break; 608 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); 609 if (n < 0) 610 break; 611 if ((lifreq.lifr_flags & IFF_UP) == 0) 612 break; 613 *have_v6 = 1; 614 } 615 break; 616 } 617 } 618 if (buf != NULL) 619 memput(buf, bufsiz); 620 close(s); 621 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ 622 return; 623 cleanup: 624 if (buf != NULL) 625 memput(buf, bufsiz); 626 if (s != -1) 627 close(s); 628 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ 629 return; 630 } 631 #endif 632 633 #if ( defined(__linux__) || defined(__linux) || defined(LINUX) ) 634 #ifndef IF_NAMESIZE 635 # ifdef IFNAMSIZ 636 # define IF_NAMESIZE IFNAMSIZ 637 # else 638 # define IF_NAMESIZE 16 639 # endif 640 #endif 641 static void 642 scan_linux6(int *have_v6) { 643 FILE *proc = NULL; 644 char address[33]; 645 char name[IF_NAMESIZE+1]; 646 int ifindex, prefix, flag3, flag4; 647 648 proc = fopen("/proc/net/if_inet6", "r"); 649 if (proc == NULL) 650 return; 651 652 if (fscanf(proc, "%32[a-f0-9] %x %x %x %x %16s\n", 653 address, &ifindex, &prefix, &flag3, &flag4, name) == 6) 654 *have_v6 = 1; 655 fclose(proc); 656 return; 657 } 658 #endif 659 660 static int 661 scan_interfaces(int *have_v4, int *have_v6) { 662 struct ifconf ifc; 663 union { 664 char _pad[256]; /*%< leave space for IPv6 addresses */ 665 struct ifreq ifreq; 666 } u; 667 struct in_addr in4; 668 struct in6_addr in6; 669 char *buf = NULL, *cp, *cplim; 670 static unsigned int bufsiz = 4095; 671 int s, n; 672 size_t cpsize; 673 674 /* Set to zero. Used as loop terminators below. */ 675 *have_v4 = *have_v6 = 0; 676 677 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ 678 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 679 /* 680 * Try to scan the interfaces using IPv6 ioctls(). 681 */ 682 scan_interfaces6(have_v4, have_v6); 683 if (*have_v4 != 0 && *have_v6 != 0) 684 return (0); 685 #endif 686 #ifdef __linux 687 scan_linux6(have_v6); 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 978 #ifdef SUNW_SETHERRNO 979 h_errno = NETDB_INTERNAL; 980 #endif /* SUNW_SETHERRNO */ 981 if (net_data && net_data->res) 982 RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); 983 return (NULL); 984 } 985 986 (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL); 987 } 988 989 return (net_data); 990 } 991 992 static void 993 freepvt(struct net_data *net_data) { 994 if (net_data->ho_data) { 995 free(net_data->ho_data); 996 net_data->ho_data = NULL; 997 } 998 } 999 1000 static struct hostent * 1001 fakeaddr(const char *name, int af, struct net_data *net_data) { 1002 struct pvt *pvt; 1003 1004 freepvt(net_data); 1005 net_data->ho_data = malloc(sizeof (struct pvt)); 1006 if (!net_data->ho_data) { 1007 errno = ENOMEM; 1008 RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); 1009 return (NULL); 1010 } 1011 pvt = net_data->ho_data; 1012 #ifndef __bsdi__ 1013 /* 1014 * Unlike its forebear(inet_aton), our friendly inet_pton() is strict 1015 * in its interpretation of its input, and it will only return "1" if 1016 * the input string is a formally valid(and thus unambiguous with 1017 * respect to host names) internet address specification for this AF. 1018 * 1019 * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now. 1020 */ 1021 if (inet_pton(af, name, pvt->addr) != 1) { 1022 #else 1023 /* BSDI XXX 1024 * We put this back to inet_aton -- we really want the old behavior 1025 * Long live 127.1... 1026 */ 1027 if ((af != AF_INET || 1028 inet_aton(name, (struct in_addr *)pvt->addr) != 1) && 1029 inet_pton(af, name, pvt->addr) != 1) { 1030 #endif 1031 RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); 1032 return (NULL); 1033 } 1034 strncpy(pvt->name, name, NS_MAXDNAME); 1035 pvt->name[NS_MAXDNAME] = '\0'; 1036 if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0U) { 1037 map_v4v6_address(pvt->addr, pvt->addr); 1038 af = AF_INET6; 1039 } 1040 pvt->host.h_addrtype = af; 1041 switch(af) { 1042 case AF_INET: 1043 pvt->host.h_length = NS_INADDRSZ; 1044 break; 1045 case AF_INET6: 1046 pvt->host.h_length = NS_IN6ADDRSZ; 1047 break; 1048 default: 1049 errno = EAFNOSUPPORT; 1050 RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); 1051 return (NULL); 1052 } 1053 pvt->host.h_name = pvt->name; 1054 pvt->host.h_aliases = pvt->aliases; 1055 pvt->aliases[0] = NULL; 1056 pvt->addrs[0] = (char *)pvt->addr; 1057 pvt->addrs[1] = NULL; 1058 pvt->host.h_addr_list = pvt->addrs; 1059 RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS); 1060 return (&pvt->host); 1061 } 1062 1063 #ifdef grot /*%< for future use in gethostbyaddr(), for "SUNSECURITY" */ 1064 struct hostent *rhp; 1065 char **haddr; 1066 u_long old_options; 1067 char hname2[MAXDNAME+1]; 1068 1069 if (af == AF_INET) { 1070 /* 1071 * turn off search as the name should be absolute, 1072 * 'localhost' should be matched by defnames 1073 */ 1074 strncpy(hname2, hp->h_name, MAXDNAME); 1075 hname2[MAXDNAME] = '\0'; 1076 old_options = net_data->res->options; 1077 net_data->res->options &= ~RES_DNSRCH; 1078 net_data->res->options |= RES_DEFNAMES; 1079 if (!(rhp = gethostbyname(hname2))) { 1080 net_data->res->options = old_options; 1081 RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); 1082 return (NULL); 1083 } 1084 net_data->res->options = old_options; 1085 for (haddr = rhp->h_addr_list; *haddr; haddr++) 1086 if (!memcmp(*haddr, addr, INADDRSZ)) 1087 break; 1088 if (!*haddr) { 1089 RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); 1090 return (NULL); 1091 } 1092 } 1093 #endif /* grot */ 1094 #endif /*__BIND_NOSTATIC*/ 1095 1096 /*! \file */ 1097