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