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