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