1/* 2 * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or 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 WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: getipnode.c,v 1.47 2009/09/01 23:47:45 tbox Exp $ */ 19 20/*! \file */ 21 22/** 23 * These functions perform thread safe, protocol independent 24 * nodename-to-address and address-to-nodename translation as defined in 25 * RFC2553. This use a struct hostent which is defined in namedb.h: 26 * 27 * \code 28 * struct hostent { 29 * char *h_name; // official name of host 30 * char **h_aliases; // alias list 31 * int h_addrtype; // host address type 32 * int h_length; // length of address 33 * char **h_addr_list; // list of addresses from name server 34 * }; 35 * #define h_addr h_addr_list[0] // address, for backward compatibility 36 * \endcode 37 * 38 * The members of this structure are: 39 * 40 * \li h_name: 41 * The official (canonical) name of the host. 42 * 43 * \li h_aliases: 44 * A NULL-terminated array of alternate names (nicknames) for the 45 * host. 46 * 47 * \li h_addrtype: 48 * The type of address being returned - usually PF_INET or 49 * PF_INET6. 50 * 51 * \li h_length: 52 * The length of the address in bytes. 53 * 54 * \li h_addr_list: 55 * A NULL terminated array of network addresses for the host. Host 56 * addresses are returned in network byte order. 57 * 58 * lwres_getipnodebyname() looks up addresses of protocol family af for 59 * the hostname name. The flags parameter contains ORed flag bits to 60 * specify the types of addresses that are searched for, and the types of 61 * addresses that are returned. The flag bits are: 62 * 63 * \li #AI_V4MAPPED: 64 * This is used with an af of #AF_INET6, and causes IPv4 addresses 65 * to be returned as IPv4-mapped IPv6 addresses. 66 * 67 * \li #AI_ALL: 68 * This is used with an af of #AF_INET6, and causes all known 69 * addresses (IPv6 and IPv4) to be returned. If #AI_V4MAPPED is 70 * also set, the IPv4 addresses are return as mapped IPv6 71 * addresses. 72 * 73 * \li #AI_ADDRCONFIG: 74 * Only return an IPv6 or IPv4 address if here is an active 75 * network interface of that type. This is not currently 76 * implemented in the BIND 9 lightweight resolver, and the flag is 77 * ignored. 78 * 79 * \li #AI_DEFAULT: 80 * This default sets the #AI_V4MAPPED and #AI_ADDRCONFIG flag bits. 81 * 82 * lwres_getipnodebyaddr() performs a reverse lookup of address src which 83 * is len bytes long. af denotes the protocol family, typically PF_INET 84 * or PF_INET6. 85 * 86 * lwres_freehostent() releases all the memory associated with the struct 87 * hostent pointer. Any memory allocated for the h_name, h_addr_list 88 * and h_aliases is freed, as is the memory for the hostent structure 89 * itself. 90 * 91 * \section getipnode_return Return Values 92 * 93 * If an error occurs, lwres_getipnodebyname() and 94 * lwres_getipnodebyaddr() set *error_num to an appropriate error code 95 * and the function returns a NULL pointer. The error codes and their 96 * meanings are defined in \link netdb.h <lwres/netdb.h>\endlink: 97 * 98 * \li #HOST_NOT_FOUND: 99 * No such host is known. 100 * 101 * \li #NO_ADDRESS: 102 * The server recognised the request and the name but no address 103 * is available. Another type of request to the name server for 104 * the domain might return an answer. 105 * 106 * \li #TRY_AGAIN: 107 * A temporary and possibly transient error occurred, such as a 108 * failure of a server to respond. The request may succeed if 109 * retried. 110 * 111 * \li #NO_RECOVERY: 112 * An unexpected failure occurred, and retrying the request is 113 * pointless. 114 * 115 * lwres_hstrerror() translates these error codes to suitable error 116 * messages. 117 * 118 * \section getipnode_see See Also 119 * 120 * getaddrinfo.c, gethost.c, getnameinfo.c, herror.c, RFC2553 121 */ 122 123#include <config.h> 124 125#include <stdio.h> 126#include <stdlib.h> 127#include <string.h> 128#include <errno.h> 129 130#include <lwres/lwres.h> 131#include <lwres/net.h> 132#include <lwres/netdb.h> /* XXX #include <netdb.h> */ 133 134#include "assert_p.h" 135 136#ifndef INADDRSZ 137#define INADDRSZ 4 138#endif 139#ifndef IN6ADDRSZ 140#define IN6ADDRSZ 16 141#endif 142 143#ifdef LWRES_PLATFORM_NEEDIN6ADDRANY 144LIBLWRES_EXTERNAL_DATA const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 145#endif 146 147#ifndef IN6_IS_ADDR_V4COMPAT 148static const unsigned char in6addr_compat[12] = { 149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 150}; 151#define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \ 152 ((x)->s6_addr[12] != 0 || \ 153 (x)->s6_addr[13] != 0 || \ 154 (x)->s6_addr[14] != 0 || \ 155 ((x)->s6_addr[15] != 0 && \ 156 (x)->s6_addr[15] != 1))) 157#endif 158#ifndef IN6_IS_ADDR_V4MAPPED 159#define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12)) 160#endif 161 162static const unsigned char in6addr_mapped[12] = { 163 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff 164}; 165 166/*** 167 *** Forward declarations. 168 ***/ 169 170static int 171scan_interfaces(int *, int *); 172 173static struct hostent * 174copyandmerge(struct hostent *, struct hostent *, int, int *); 175 176static struct hostent * 177hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src); 178 179static struct hostent * 180hostfromname(lwres_gabnresponse_t *name, int af); 181 182/*** 183 *** Public functions. 184 ***/ 185 186/*! 187 * AI_V4MAPPED + AF_INET6 188 * If no IPv6 address then a query for IPv4 and map returned values. 189 * 190 * AI_ALL + AI_V4MAPPED + AF_INET6 191 * Return IPv6 and IPv4 mapped. 192 * 193 * AI_ADDRCONFIG 194 * Only return IPv6 / IPv4 address if there is an interface of that 195 * type active. 196 */ 197 198struct hostent * 199lwres_getipnodebyname(const char *name, int af, int flags, int *error_num) { 200 int have_v4 = 1, have_v6 = 1; 201 struct in_addr in4; 202 struct in6_addr in6; 203 struct hostent he, *he1 = NULL, *he2 = NULL, *he3 = NULL; 204 int v4 = 0, v6 = 0; 205 int tmp_err = 0; 206 lwres_context_t *lwrctx = NULL; 207 lwres_gabnresponse_t *by = NULL; 208 int n; 209 210 /* 211 * If we care about active interfaces then check. 212 */ 213 if ((flags & AI_ADDRCONFIG) != 0) 214 if (scan_interfaces(&have_v4, &have_v6) == -1) { 215 *error_num = NO_RECOVERY; 216 return (NULL); 217 } 218 219 /* Check for literal address. */ 220 if ((v4 = lwres_net_pton(AF_INET, name, &in4)) != 1) 221 v6 = lwres_net_pton(AF_INET6, name, &in6); 222 223 /* 224 * Impossible combination? 225 */ 226 if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) || 227 (af == AF_INET && v6 == 1) || 228 (have_v4 == 0 && v4 == 1) || 229 (have_v6 == 0 && v6 == 1) || 230 (have_v4 == 0 && af == AF_INET) || 231 (have_v6 == 0 && af == AF_INET6 && 232 (((flags & AI_V4MAPPED) != 0 && have_v4) || 233 (flags & AI_V4MAPPED) == 0))) { 234 *error_num = HOST_NOT_FOUND; 235 return (NULL); 236 } 237 238 /* 239 * Literal address? 240 */ 241 if (v4 == 1 || v6 == 1) { 242 char *addr_list[2]; 243 char *aliases[1]; 244 char mappedname[sizeof("::ffff:123.123.123.123")]; 245 union { 246 const char *const_name; 247 char *deconst_name; 248 } u; 249 250 u.const_name = name; 251 if (v4 == 1 && af == AF_INET6) { 252 strcpy(mappedname, "::ffff:"); 253 lwres_net_ntop(AF_INET, (char *)&in4, 254 mappedname + sizeof("::ffff:") - 1, 255 sizeof(mappedname) - sizeof("::ffff:") 256 + 1); 257 he.h_name = mappedname; 258 } else 259 he.h_name = u.deconst_name; 260 he.h_addr_list = addr_list; 261 he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6; 262 he.h_addr_list[1] = NULL; 263 he.h_aliases = aliases; 264 he.h_aliases[0] = NULL; 265 he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ; 266 he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6; 267 return (copyandmerge(&he, NULL, af, error_num)); 268 } 269 270 n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0); 271 if (n != 0) { 272 *error_num = NO_RECOVERY; 273 goto cleanup; 274 } 275 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf); 276 tmp_err = NO_RECOVERY; 277 if (have_v6 && af == AF_INET6) { 278 n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V6, &by); 279 if (n == 0) { 280 he1 = hostfromname(by, AF_INET6); 281 lwres_gabnresponse_free(lwrctx, &by); 282 if (he1 == NULL) { 283 *error_num = NO_RECOVERY; 284 goto cleanup; 285 } 286 } else { 287 if (n == LWRES_R_NOTFOUND) 288 tmp_err = HOST_NOT_FOUND; 289 else { 290 *error_num = NO_RECOVERY; 291 goto cleanup; 292 } 293 } 294 } 295 296 if (have_v4 && 297 ((af == AF_INET) || 298 (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 && 299 (he1 == NULL || (flags & AI_ALL) != 0)))) { 300 n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V4, &by); 301 if (n == 0) { 302 he2 = hostfromname(by, AF_INET); 303 lwres_gabnresponse_free(lwrctx, &by); 304 if (he2 == NULL) { 305 *error_num = NO_RECOVERY; 306 goto cleanup; 307 } 308 } else if (he1 == NULL) { 309 if (n == LWRES_R_NOTFOUND) 310 *error_num = HOST_NOT_FOUND; 311 else 312 *error_num = NO_RECOVERY; 313 goto cleanup; 314 } 315 } else 316 *error_num = tmp_err; 317 318 he3 = copyandmerge(he1, he2, af, error_num); 319 320 cleanup: 321 if (he1 != NULL) 322 lwres_freehostent(he1); 323 if (he2 != NULL) 324 lwres_freehostent(he2); 325 if (lwrctx != NULL) { 326 lwres_conf_clear(lwrctx); 327 lwres_context_destroy(&lwrctx); 328 } 329 return (he3); 330} 331 332/*% performs a reverse lookup of address src which is len bytes long. af denotes the protocol family, typically #PF_INET or PF_INET6. */ 333struct hostent * 334lwres_getipnodebyaddr(const void *src, size_t len, int af, int *error_num) { 335 struct hostent *he1, *he2; 336 lwres_context_t *lwrctx = NULL; 337 lwres_gnbaresponse_t *by = NULL; 338 lwres_result_t n; 339 union { 340 const void *konst; 341 struct in6_addr *in6; 342 } u; 343 344 /* 345 * Sanity checks. 346 */ 347 if (src == NULL) { 348 *error_num = NO_RECOVERY; 349 return (NULL); 350 } 351 352 switch (af) { 353 case AF_INET: 354 if (len != (unsigned int)INADDRSZ) { 355 *error_num = NO_RECOVERY; 356 return (NULL); 357 } 358 break; 359 case AF_INET6: 360 if (len != (unsigned int)IN6ADDRSZ) { 361 *error_num = NO_RECOVERY; 362 return (NULL); 363 } 364 break; 365 default: 366 *error_num = NO_RECOVERY; 367 return (NULL); 368 } 369 370 /* 371 * The de-"const"-ing game is done because at least one 372 * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_* 373 * macros in such a way that they discard the const with 374 * internal casting, and gcc ends up complaining. Rather 375 * than replacing their own (possibly optimized) definitions 376 * with our own, cleanly discarding the const is the easiest 377 * thing to do. 378 */ 379 u.konst = src; 380 381 /* 382 * Look up IPv4 and IPv4 mapped/compatible addresses. 383 */ 384 if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(u.in6)) || 385 (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(u.in6)) || 386 (af == AF_INET)) { 387 const unsigned char *cp = src; 388 389 if (af == AF_INET6) 390 cp += 12; 391 n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0); 392 if (n == LWRES_R_SUCCESS) 393 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf); 394 if (n == LWRES_R_SUCCESS) 395 n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V4, 396 INADDRSZ, cp, &by); 397 if (n != LWRES_R_SUCCESS) { 398 lwres_conf_clear(lwrctx); 399 lwres_context_destroy(&lwrctx); 400 if (n == LWRES_R_NOTFOUND) 401 *error_num = HOST_NOT_FOUND; 402 else 403 *error_num = NO_RECOVERY; 404 return (NULL); 405 } 406 he1 = hostfromaddr(by, AF_INET, cp); 407 lwres_gnbaresponse_free(lwrctx, &by); 408 lwres_conf_clear(lwrctx); 409 lwres_context_destroy(&lwrctx); 410 if (af != AF_INET6) 411 return (he1); 412 413 /* 414 * Convert from AF_INET to AF_INET6. 415 */ 416 he2 = copyandmerge(he1, NULL, af, error_num); 417 lwres_freehostent(he1); 418 if (he2 == NULL) 419 return (NULL); 420 /* 421 * Restore original address. 422 */ 423 memcpy(he2->h_addr, src, len); 424 return (he2); 425 } 426 427 /* 428 * Lookup IPv6 address. 429 */ 430 if (memcmp(src, &in6addr_any, IN6ADDRSZ) == 0) { 431 *error_num = HOST_NOT_FOUND; 432 return (NULL); 433 } 434 435 n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0); 436 if (n == LWRES_R_SUCCESS) 437 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf); 438 if (n == LWRES_R_SUCCESS) 439 n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V6, IN6ADDRSZ, 440 src, &by); 441 if (n != 0) { 442 lwres_conf_clear(lwrctx); 443 lwres_context_destroy(&lwrctx); 444 445 if (n == LWRES_R_NOTFOUND) 446 *error_num = HOST_NOT_FOUND; 447 else 448 *error_num = NO_RECOVERY; 449 450 return (NULL); 451 } 452 453 he1 = hostfromaddr(by, AF_INET6, src); 454 lwres_gnbaresponse_free(lwrctx, &by); 455 if (he1 == NULL) 456 *error_num = NO_RECOVERY; 457 lwres_conf_clear(lwrctx); 458 lwres_context_destroy(&lwrctx); 459 return (he1); 460} 461 462/*% releases all the memory associated with the struct hostent pointer */ 463void 464lwres_freehostent(struct hostent *he) { 465 char **cpp; 466 int names = 1; 467 int addresses = 1; 468 469 free(he->h_name); 470 471 cpp = he->h_addr_list; 472 while (*cpp != NULL) { 473 free(*cpp); 474 *cpp = NULL; 475 cpp++; 476 addresses++; 477 } 478 479 cpp = he->h_aliases; 480 while (*cpp != NULL) { 481 free(*cpp); 482 cpp++; 483 names++; 484 } 485 486 free(he->h_aliases); 487 free(he->h_addr_list); 488 free(he); 489} 490 491/* 492 * Private 493 */ 494 495/* 496 * Scan the interface table and set have_v4 and have_v6 depending 497 * upon whether there are IPv4 and IPv6 interface addresses. 498 * 499 * Returns: 500 * 0 on success 501 * -1 on failure. 502 */ 503 504#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ 505 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 506 507#ifdef __hpux 508#define lifc_len iflc_len 509#define lifc_buf iflc_buf 510#define lifc_req iflc_req 511#define LIFCONF if_laddrconf 512#else 513#define ISC_HAVE_LIFC_FAMILY 1 514#define ISC_HAVE_LIFC_FLAGS 1 515#define LIFCONF lifconf 516#endif 517 518#ifdef __hpux 519#define lifr_addr iflr_addr 520#define lifr_name iflr_name 521#define lifr_dstaddr iflr_dstaddr 522#define lifr_flags iflr_flags 523#define ss_family sa_family 524#define LIFREQ if_laddrreq 525#else 526#define LIFREQ lifreq 527#endif 528 529static int 530scan_interfaces6(int *have_v4, int *have_v6) { 531 struct LIFCONF lifc; 532 struct LIFREQ lifreq; 533 struct in_addr in4; 534 struct in6_addr in6; 535 char *buf = NULL, *cp, *cplim; 536 static unsigned int bufsiz = 4095; 537 int s, cpsize, n; 538 539 /* 540 * Set to zero. Used as loop terminators below. 541 */ 542 *have_v4 = *have_v6 = 0; 543 544 /* 545 * Get interface list from system. 546 */ 547 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) 548 goto err_ret; 549 550 /* 551 * Grow buffer until large enough to contain all interface 552 * descriptions. 553 */ 554 for (;;) { 555 buf = malloc(bufsiz); 556 if (buf == NULL) 557 goto err_ret; 558#ifdef ISC_HAVE_LIFC_FAMILY 559 lifc.lifc_family = AF_UNSPEC; /* request all families */ 560#endif 561#ifdef ISC_HAVE_LIFC_FLAGS 562 lifc.lifc_flags = 0; 563#endif 564 lifc.lifc_len = bufsiz; 565 lifc.lifc_buf = buf; 566 if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) { 567 /* 568 * Some OS's just return what will fit rather 569 * than set EINVAL if the buffer is too small 570 * to fit all the interfaces in. If 571 * lifc.lifc_len is too near to the end of the 572 * buffer we will grow it just in case and 573 * retry. 574 */ 575 if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz) 576 break; 577 } 578 if ((n == -1) && errno != EINVAL) 579 goto err_ret; 580 581 if (bufsiz > 1000000) 582 goto err_ret; 583 584 free(buf); 585 bufsiz += 4096; 586 } 587 588 /* 589 * Parse system's interface list. 590 */ 591 cplim = buf + lifc.lifc_len; /* skip over if's with big ifr_addr's */ 592 for (cp = buf; 593 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; 594 cp += cpsize) { 595 memcpy(&lifreq, cp, sizeof(lifreq)); 596#ifdef LWRES_PLATFORM_HAVESALEN 597#ifdef FIX_ZERO_SA_LEN 598 if (lifreq.lifr_addr.sa_len == 0) 599 lifreq.lifr_addr.sa_len = 16; 600#endif 601#ifdef HAVE_MINIMUM_IFREQ 602 cpsize = sizeof(lifreq); 603 if (lifreq.lifr_addr.sa_len > sizeof(struct sockaddr)) 604 cpsize += (int)lifreq.lifr_addr.sa_len - 605 (int)(sizeof(struct sockaddr)); 606#else 607 cpsize = sizeof(lifreq.lifr_name) + lifreq.lifr_addr.sa_len; 608#endif /* HAVE_MINIMUM_IFREQ */ 609#elif defined SIOCGIFCONF_ADDR 610 cpsize = sizeof(lifreq); 611#else 612 cpsize = sizeof(lifreq.lifr_name); 613 /* XXX maybe this should be a hard error? */ 614 if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0) 615 continue; 616#endif 617 switch (lifreq.lifr_addr.ss_family) { 618 case AF_INET: 619 if (*have_v4 == 0) { 620 memcpy(&in4, 621 &((struct sockaddr_in *) 622 &lifreq.lifr_addr)->sin_addr, 623 sizeof(in4)); 624 if (in4.s_addr == INADDR_ANY) 625 break; 626 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); 627 if (n < 0) 628 break; 629 if ((lifreq.lifr_flags & IFF_UP) == 0) 630 break; 631 *have_v4 = 1; 632 } 633 break; 634 case AF_INET6: 635 if (*have_v6 == 0) { 636 memcpy(&in6, 637 &((struct sockaddr_in6 *) 638 &lifreq.lifr_addr)->sin6_addr, 639 sizeof(in6)); 640 if (memcmp(&in6, &in6addr_any, 641 sizeof(in6)) == 0) 642 break; 643 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); 644 if (n < 0) 645 break; 646 if ((lifreq.lifr_flags & IFF_UP) == 0) 647 break; 648 *have_v6 = 1; 649 } 650 break; 651 } 652 } 653 if (buf != NULL) 654 free(buf); 655 close(s); 656 return (0); 657 err_ret: 658 if (buf != NULL) 659 free(buf); 660 if (s != -1) 661 close(s); 662 return (-1); 663} 664#endif 665 666static int 667scan_interfaces(int *have_v4, int *have_v6) { 668#if !defined(SIOCGIFCONF) || !defined(SIOCGIFADDR) 669 *have_v4 = *have_v6 = 1; 670 return (0); 671#else 672 struct ifconf ifc; 673 union { 674 char _pad[256]; /* leave space for IPv6 addresses */ 675 struct ifreq ifreq; 676 } u; 677 struct in_addr in4; 678 struct in6_addr in6; 679 char *buf = NULL, *cp, *cplim; 680 static unsigned int bufsiz = 4095; 681 int s, n; 682 size_t cpsize; 683 684#ifdef WIN32 685 InitSockets(); 686#endif 687#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ 688 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 689 /* 690 * Try to scan the interfaces using IPv6 ioctls(). 691 */ 692 if (!scan_interfaces6(have_v4, have_v6)) { 693#ifdef WIN32 694 DestroySockets(); 695#endif 696 return (0); 697 } 698#endif 699 700 /* 701 * Set to zero. Used as loop terminators below. 702 */ 703 *have_v4 = *have_v6 = 0; 704 705 /* 706 * Get interface list from system. 707 */ 708 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 709 goto err_ret; 710 711 /* 712 * Grow buffer until large enough to contain all interface 713 * descriptions. 714 */ 715 for (;;) { 716 buf = malloc(bufsiz); 717 if (buf == NULL) 718 goto err_ret; 719 ifc.ifc_len = bufsiz; 720 ifc.ifc_buf = buf; 721#ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF 722 /* 723 * This is a fix for IRIX OS in which the call to ioctl with 724 * the flag SIOCGIFCONF may not return an entry for all the 725 * interfaces like most flavors of Unix. 726 */ 727 if (emul_ioctl(&ifc) >= 0) 728 break; 729#else 730 if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) { 731 /* 732 * Some OS's just return what will fit rather 733 * than set EINVAL if the buffer is too small 734 * to fit all the interfaces in. If 735 * ifc.ifc_len is too near to the end of the 736 * buffer we will grow it just in case and 737 * retry. 738 */ 739 if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz) 740 break; 741 } 742#endif 743 if ((n == -1) && errno != EINVAL) 744 goto err_ret; 745 746 if (bufsiz > 1000000) 747 goto err_ret; 748 749 free(buf); 750 bufsiz += 4096; 751 } 752 753 /* 754 * Parse system's interface list. 755 */ 756 cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */ 757 for (cp = buf; 758 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; 759 cp += cpsize) { 760 memcpy(&u.ifreq, cp, sizeof(u.ifreq)); 761#ifdef LWRES_PLATFORM_HAVESALEN 762#ifdef FIX_ZERO_SA_LEN 763 if (u.ifreq.ifr_addr.sa_len == 0) 764 u.ifreq.ifr_addr.sa_len = 16; 765#endif 766#ifdef HAVE_MINIMUM_IFREQ 767 cpsize = sizeof(u.ifreq); 768 if (u.ifreq.ifr_addr.sa_len > sizeof(struct sockaddr)) 769 cpsize += (int)u.ifreq.ifr_addr.sa_len - 770 (int)(sizeof(struct sockaddr)); 771#else 772 cpsize = sizeof(u.ifreq.ifr_name) + u.ifreq.ifr_addr.sa_len; 773#endif /* HAVE_MINIMUM_IFREQ */ 774 if (cpsize > sizeof(u.ifreq) && cpsize <= sizeof(u)) 775 memcpy(&u.ifreq, cp, cpsize); 776#elif defined SIOCGIFCONF_ADDR 777 cpsize = sizeof(u.ifreq); 778#else 779 cpsize = sizeof(u.ifreq.ifr_name); 780 /* XXX maybe this should be a hard error? */ 781 if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0) 782 continue; 783#endif 784 switch (u.ifreq.ifr_addr.sa_family) { 785 case AF_INET: 786 if (*have_v4 == 0) { 787 memcpy(&in4, 788 &((struct sockaddr_in *) 789 &u.ifreq.ifr_addr)->sin_addr, 790 sizeof(in4)); 791 if (in4.s_addr == INADDR_ANY) 792 break; 793 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); 794 if (n < 0) 795 break; 796 if ((u.ifreq.ifr_flags & IFF_UP) == 0) 797 break; 798 *have_v4 = 1; 799 } 800 break; 801 case AF_INET6: 802 if (*have_v6 == 0) { 803 memcpy(&in6, 804 &((struct sockaddr_in6 *) 805 &u.ifreq.ifr_addr)->sin6_addr, 806 sizeof(in6)); 807 if (memcmp(&in6, &in6addr_any, 808 sizeof(in6)) == 0) 809 break; 810 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); 811 if (n < 0) 812 break; 813 if ((u.ifreq.ifr_flags & IFF_UP) == 0) 814 break; 815 *have_v6 = 1; 816 } 817 break; 818 } 819 } 820 if (buf != NULL) 821 free(buf); 822#ifdef WIN32 823 DestroySockets(); 824#endif 825 close(s); 826 return (0); 827 828 err_ret: 829 if (buf != NULL) 830 free(buf); 831 if (s != -1) 832 close(s); 833#ifdef WIN32 834 DestroySockets(); 835#endif 836 return (-1); 837#endif 838} 839 840static struct hostent * 841copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) 842{ 843 struct hostent *he = NULL; 844 int addresses = 1; /* NULL terminator */ 845 int names = 1; /* NULL terminator */ 846 int len = 0; 847 char **cpp, **npp; 848 849 /* 850 * Work out array sizes. 851 */ 852 if (he1 != NULL) { 853 cpp = he1->h_addr_list; 854 while (*cpp != NULL) { 855 addresses++; 856 cpp++; 857 } 858 cpp = he1->h_aliases; 859 while (*cpp != NULL) { 860 names++; 861 cpp++; 862 } 863 } 864 865 if (he2 != NULL) { 866 cpp = he2->h_addr_list; 867 while (*cpp != NULL) { 868 addresses++; 869 cpp++; 870 } 871 if (he1 == NULL) { 872 cpp = he2->h_aliases; 873 while (*cpp != NULL) { 874 names++; 875 cpp++; 876 } 877 } 878 } 879 880 if (addresses == 1) { 881 *error_num = NO_ADDRESS; 882 return (NULL); 883 } 884 885 he = malloc(sizeof(*he)); 886 if (he == NULL) 887 goto no_recovery; 888 889 he->h_addr_list = malloc(sizeof(char *) * (addresses)); 890 if (he->h_addr_list == NULL) 891 goto cleanup0; 892 memset(he->h_addr_list, 0, sizeof(char *) * (addresses)); 893 894 /* 895 * Copy addresses. 896 */ 897 npp = he->h_addr_list; 898 if (he1 != NULL) { 899 cpp = he1->h_addr_list; 900 while (*cpp != NULL) { 901 *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 902 if (*npp == NULL) 903 goto cleanup1; 904 /* 905 * Convert to mapped if required. 906 */ 907 if (af == AF_INET6 && he1->h_addrtype == AF_INET) { 908 memcpy(*npp, in6addr_mapped, 909 sizeof(in6addr_mapped)); 910 memcpy(*npp + sizeof(in6addr_mapped), *cpp, 911 INADDRSZ); 912 } else { 913 memcpy(*npp, *cpp, 914 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 915 } 916 cpp++; 917 npp++; 918 } 919 } 920 921 if (he2 != NULL) { 922 cpp = he2->h_addr_list; 923 while (*cpp != NULL) { 924 *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 925 if (*npp == NULL) 926 goto cleanup1; 927 /* 928 * Convert to mapped if required. 929 */ 930 if (af == AF_INET6 && he2->h_addrtype == AF_INET) { 931 memcpy(*npp, in6addr_mapped, 932 sizeof(in6addr_mapped)); 933 memcpy(*npp + sizeof(in6addr_mapped), *cpp, 934 INADDRSZ); 935 } else { 936 memcpy(*npp, *cpp, 937 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 938 } 939 cpp++; 940 npp++; 941 } 942 } 943 944 he->h_aliases = malloc(sizeof(char *) * (names)); 945 if (he->h_aliases == NULL) 946 goto cleanup1; 947 memset(he->h_aliases, 0, sizeof(char *) * (names)); 948 949 /* 950 * Copy aliases. 951 */ 952 npp = he->h_aliases; 953 cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases; 954 while (*cpp != NULL) { 955 len = strlen (*cpp) + 1; 956 *npp = malloc(len); 957 if (*npp == NULL) 958 goto cleanup2; 959 strcpy(*npp, *cpp); 960 npp++; 961 cpp++; 962 } 963 964 /* 965 * Copy hostname. 966 */ 967 he->h_name = malloc(strlen((he1 != NULL) ? 968 he1->h_name : he2->h_name) + 1); 969 if (he->h_name == NULL) 970 goto cleanup2; 971 strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name); 972 973 /* 974 * Set address type and length. 975 */ 976 he->h_addrtype = af; 977 he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ; 978 return (he); 979 980 cleanup2: 981 cpp = he->h_aliases; 982 while (*cpp != NULL) { 983 free(*cpp); 984 cpp++; 985 } 986 free(he->h_aliases); 987 988 cleanup1: 989 cpp = he->h_addr_list; 990 while (*cpp != NULL) { 991 free(*cpp); 992 *cpp = NULL; 993 cpp++; 994 } 995 free(he->h_addr_list); 996 997 cleanup0: 998 free(he); 999 1000 no_recovery: 1001 *error_num = NO_RECOVERY; 1002 return (NULL); 1003} 1004 1005static struct hostent * 1006hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) { 1007 struct hostent *he; 1008 int i; 1009 1010 he = malloc(sizeof(*he)); 1011 if (he == NULL) 1012 goto cleanup; 1013 memset(he, 0, sizeof(*he)); 1014 1015 /* 1016 * Set family and length. 1017 */ 1018 he->h_addrtype = af; 1019 switch (af) { 1020 case AF_INET: 1021 he->h_length = INADDRSZ; 1022 break; 1023 case AF_INET6: 1024 he->h_length = IN6ADDRSZ; 1025 break; 1026 default: 1027 INSIST(0); 1028 } 1029 1030 /* 1031 * Copy name. 1032 */ 1033 he->h_name = strdup(addr->realname); 1034 if (he->h_name == NULL) 1035 goto cleanup; 1036 1037 /* 1038 * Copy aliases. 1039 */ 1040 he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1)); 1041 if (he->h_aliases == NULL) 1042 goto cleanup; 1043 for (i = 0; i < addr->naliases; i++) { 1044 he->h_aliases[i] = strdup(addr->aliases[i]); 1045 if (he->h_aliases[i] == NULL) 1046 goto cleanup; 1047 } 1048 he->h_aliases[i] = NULL; 1049 1050 /* 1051 * Copy address. 1052 */ 1053 he->h_addr_list = malloc(sizeof(char *) * 2); 1054 if (he->h_addr_list == NULL) 1055 goto cleanup; 1056 he->h_addr_list[0] = malloc(he->h_length); 1057 if (he->h_addr_list[0] == NULL) 1058 goto cleanup; 1059 memcpy(he->h_addr_list[0], src, he->h_length); 1060 he->h_addr_list[1] = NULL; 1061 return (he); 1062 1063 cleanup: 1064 if (he != NULL && he->h_addr_list != NULL) { 1065 for (i = 0; he->h_addr_list[i] != NULL; i++) 1066 free(he->h_addr_list[i]); 1067 free(he->h_addr_list); 1068 } 1069 if (he != NULL && he->h_aliases != NULL) { 1070 for (i = 0; he->h_aliases[i] != NULL; i++) 1071 free(he->h_aliases[i]); 1072 free(he->h_aliases); 1073 } 1074 if (he != NULL && he->h_name != NULL) 1075 free(he->h_name); 1076 if (he != NULL) 1077 free(he); 1078 return (NULL); 1079} 1080 1081static struct hostent * 1082hostfromname(lwres_gabnresponse_t *name, int af) { 1083 struct hostent *he; 1084 int i; 1085 lwres_addr_t *addr; 1086 1087 he = malloc(sizeof(*he)); 1088 if (he == NULL) 1089 goto cleanup; 1090 memset(he, 0, sizeof(*he)); 1091 1092 /* 1093 * Set family and length. 1094 */ 1095 he->h_addrtype = af; 1096 switch (af) { 1097 case AF_INET: 1098 he->h_length = INADDRSZ; 1099 break; 1100 case AF_INET6: 1101 he->h_length = IN6ADDRSZ; 1102 break; 1103 default: 1104 INSIST(0); 1105 } 1106 1107 /* 1108 * Copy name. 1109 */ 1110 he->h_name = strdup(name->realname); 1111 if (he->h_name == NULL) 1112 goto cleanup; 1113 1114 /* 1115 * Copy aliases. 1116 */ 1117 he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1)); 1118 for (i = 0; i < name->naliases; i++) { 1119 he->h_aliases[i] = strdup(name->aliases[i]); 1120 if (he->h_aliases[i] == NULL) 1121 goto cleanup; 1122 } 1123 he->h_aliases[i] = NULL; 1124 1125 /* 1126 * Copy addresses. 1127 */ 1128 he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1)); 1129 addr = LWRES_LIST_HEAD(name->addrs); 1130 i = 0; 1131 while (addr != NULL) { 1132 he->h_addr_list[i] = malloc(he->h_length); 1133 if (he->h_addr_list[i] == NULL) 1134 goto cleanup; 1135 memcpy(he->h_addr_list[i], addr->address, he->h_length); 1136 addr = LWRES_LIST_NEXT(addr, link); 1137 i++; 1138 } 1139 he->h_addr_list[i] = NULL; 1140 return (he); 1141 1142 cleanup: 1143 if (he != NULL && he->h_addr_list != NULL) { 1144 for (i = 0; he->h_addr_list[i] != NULL; i++) 1145 free(he->h_addr_list[i]); 1146 free(he->h_addr_list); 1147 } 1148 if (he != NULL && he->h_aliases != NULL) { 1149 for (i = 0; he->h_aliases[i] != NULL; i++) 1150 free(he->h_aliases[i]); 1151 free(he->h_aliases); 1152 } 1153 if (he != NULL && he->h_name != NULL) 1154 free(he->h_name); 1155 if (he != NULL) 1156 free(he); 1157 return (NULL); 1158} 1159