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