1 /* $NetBSD: getipnode.c,v 1.6 2014/12/10 04:38:02 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2005, 2007, 2009, 2012, 2014 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 146 LIBLWRES_EXTERNAL_DATA const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 147 #endif 148 149 #ifndef IN6_IS_ADDR_V4COMPAT 150 static 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 164 static 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 172 static int 173 scan_interfaces(int *, int *); 174 175 static struct hostent * 176 copyandmerge(struct hostent *, struct hostent *, int, int *); 177 178 static struct hostent * 179 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src); 180 181 static struct hostent * 182 hostfromname(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 200 struct hostent * 201 lwres_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. */ 335 struct hostent * 336 lwres_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 memmove(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 */ 465 void 466 lwres_freehostent(struct hostent *he) { 467 char **cpp; 468 int names = 1; 469 int addresses = 1; 470 471 if (he == NULL) 472 return; 473 474 free(he->h_name); 475 476 cpp = he->h_addr_list; 477 while (*cpp != NULL) { 478 free(*cpp); 479 *cpp = NULL; 480 cpp++; 481 addresses++; 482 } 483 484 cpp = he->h_aliases; 485 while (*cpp != NULL) { 486 free(*cpp); 487 cpp++; 488 names++; 489 } 490 491 free(he->h_aliases); 492 free(he->h_addr_list); 493 free(he); 494 } 495 496 /* 497 * Private 498 */ 499 500 /* 501 * Scan the interface table and set have_v4 and have_v6 depending 502 * upon whether there are IPv4 and IPv6 interface addresses. 503 * 504 * Returns: 505 * 0 on success 506 * -1 on failure. 507 */ 508 509 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ 510 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 511 512 #ifdef __hpux 513 #define lifc_len iflc_len 514 #define lifc_buf iflc_buf 515 #define lifc_req iflc_req 516 #define LIFCONF if_laddrconf 517 #else 518 #define ISC_HAVE_LIFC_FAMILY 1 519 #define ISC_HAVE_LIFC_FLAGS 1 520 #define LIFCONF lifconf 521 #endif 522 523 #ifdef __hpux 524 #define lifr_addr iflr_addr 525 #define lifr_name iflr_name 526 #define lifr_dstaddr iflr_dstaddr 527 #define lifr_flags iflr_flags 528 #define ss_family sa_family 529 #define LIFREQ if_laddrreq 530 #else 531 #define LIFREQ lifreq 532 #endif 533 534 static int 535 scan_interfaces6(int *have_v4, int *have_v6) { 536 struct LIFCONF lifc; 537 struct LIFREQ lifreq; 538 struct in_addr in4; 539 struct in6_addr in6; 540 char *buf = NULL, *cp, *cplim; 541 static unsigned int bufsiz = 4095; 542 int s, cpsize, n; 543 544 /* 545 * Set to zero. Used as loop terminators below. 546 */ 547 *have_v4 = *have_v6 = 0; 548 549 /* 550 * Get interface list from system. 551 */ 552 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) 553 goto err_ret; 554 555 /* 556 * Grow buffer until large enough to contain all interface 557 * descriptions. 558 */ 559 for (;;) { 560 buf = malloc(bufsiz); 561 if (buf == NULL) 562 goto err_ret; 563 #ifdef ISC_HAVE_LIFC_FAMILY 564 lifc.lifc_family = AF_UNSPEC; /* request all families */ 565 #endif 566 #ifdef ISC_HAVE_LIFC_FLAGS 567 lifc.lifc_flags = 0; 568 #endif 569 lifc.lifc_len = bufsiz; 570 lifc.lifc_buf = buf; 571 if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) { 572 /* 573 * Some OS's just return what will fit rather 574 * than set EINVAL if the buffer is too small 575 * to fit all the interfaces in. If 576 * lifc.lifc_len is too near to the end of the 577 * buffer we will grow it just in case and 578 * retry. 579 */ 580 if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz) 581 break; 582 } 583 if ((n == -1) && errno != EINVAL) 584 goto err_ret; 585 586 if (bufsiz > 1000000) 587 goto err_ret; 588 589 free(buf); 590 bufsiz += 4096; 591 } 592 593 /* 594 * Parse system's interface list. 595 */ 596 cplim = buf + lifc.lifc_len; /* skip over if's with big ifr_addr's */ 597 for (cp = buf; 598 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; 599 cp += cpsize) { 600 memmove(&lifreq, cp, sizeof(lifreq)); 601 #ifdef LWRES_PLATFORM_HAVESALEN 602 #ifdef FIX_ZERO_SA_LEN 603 if (lifreq.lifr_addr.sa_len == 0) 604 lifreq.lifr_addr.sa_len = 16; 605 #endif 606 #ifdef HAVE_MINIMUM_IFREQ 607 cpsize = sizeof(lifreq); 608 if (lifreq.lifr_addr.sa_len > sizeof(struct sockaddr)) 609 cpsize += (int)lifreq.lifr_addr.sa_len - 610 (int)(sizeof(struct sockaddr)); 611 #else 612 cpsize = sizeof(lifreq.lifr_name) + lifreq.lifr_addr.sa_len; 613 #endif /* HAVE_MINIMUM_IFREQ */ 614 #elif defined SIOCGIFCONF_ADDR 615 cpsize = sizeof(lifreq); 616 #else 617 cpsize = sizeof(lifreq.lifr_name); 618 /* XXX maybe this should be a hard error? */ 619 if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0) 620 continue; 621 #endif 622 switch (lifreq.lifr_addr.ss_family) { 623 case AF_INET: 624 if (*have_v4 == 0) { 625 memmove(&in4, 626 &((struct sockaddr_in *) 627 &lifreq.lifr_addr)->sin_addr, 628 sizeof(in4)); 629 if (in4.s_addr == INADDR_ANY) 630 break; 631 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); 632 if (n < 0) 633 break; 634 if ((lifreq.lifr_flags & IFF_UP) == 0) 635 break; 636 *have_v4 = 1; 637 } 638 break; 639 case AF_INET6: 640 if (*have_v6 == 0) { 641 memmove(&in6, 642 &((struct sockaddr_in6 *) 643 &lifreq.lifr_addr)->sin6_addr, 644 sizeof(in6)); 645 if (memcmp(&in6, &in6addr_any, 646 sizeof(in6)) == 0) 647 break; 648 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); 649 if (n < 0) 650 break; 651 if ((lifreq.lifr_flags & IFF_UP) == 0) 652 break; 653 *have_v6 = 1; 654 } 655 break; 656 } 657 } 658 if (buf != NULL) 659 free(buf); 660 close(s); 661 return (0); 662 err_ret: 663 if (buf != NULL) 664 free(buf); 665 if (s != -1) 666 close(s); 667 return (-1); 668 } 669 #endif 670 671 static int 672 scan_interfaces(int *have_v4, int *have_v6) { 673 #if !defined(SIOCGIFCONF) || !defined(SIOCGIFADDR) 674 *have_v4 = *have_v6 = 1; 675 return (0); 676 #else 677 struct ifconf ifc; 678 union { 679 char _pad[256]; /* leave space for IPv6 addresses */ 680 struct ifreq ifreq; 681 } u; 682 struct in_addr in4; 683 struct in6_addr in6; 684 char *buf = NULL, *cp, *cplim; 685 static unsigned int bufsiz = 4095; 686 int s, n; 687 size_t cpsize; 688 689 #ifdef WIN32 690 InitSockets(); 691 #endif 692 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ 693 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) 694 /* 695 * Try to scan the interfaces using IPv6 ioctls(). 696 */ 697 if (!scan_interfaces6(have_v4, have_v6)) { 698 #ifdef WIN32 699 DestroySockets(); 700 #endif 701 return (0); 702 } 703 #endif 704 705 /* 706 * Set to zero. Used as loop terminators below. 707 */ 708 *have_v4 = *have_v6 = 0; 709 710 /* 711 * Get interface list from system. 712 */ 713 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 714 goto err_ret; 715 716 /* 717 * Grow buffer until large enough to contain all interface 718 * descriptions. 719 */ 720 for (;;) { 721 buf = malloc(bufsiz); 722 if (buf == NULL) 723 goto err_ret; 724 ifc.ifc_len = bufsiz; 725 ifc.ifc_buf = buf; 726 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF 727 /* 728 * This is a fix for IRIX OS in which the call to ioctl with 729 * the flag SIOCGIFCONF may not return an entry for all the 730 * interfaces like most flavors of Unix. 731 */ 732 if (emul_ioctl(&ifc) >= 0) 733 break; 734 #else 735 if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) { 736 /* 737 * Some OS's just return what will fit rather 738 * than set EINVAL if the buffer is too small 739 * to fit all the interfaces in. If 740 * ifc.ifc_len is too near to the end of the 741 * buffer we will grow it just in case and 742 * retry. 743 */ 744 if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz) 745 break; 746 } 747 #endif 748 if ((n == -1) && errno != EINVAL) 749 goto err_ret; 750 751 if (bufsiz > 1000000) 752 goto err_ret; 753 754 free(buf); 755 bufsiz += 4096; 756 } 757 758 /* 759 * Parse system's interface list. 760 */ 761 cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */ 762 for (cp = buf; 763 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; 764 cp += cpsize) { 765 memmove(&u.ifreq, cp, sizeof(u.ifreq)); 766 #ifdef LWRES_PLATFORM_HAVESALEN 767 #ifdef FIX_ZERO_SA_LEN 768 if (u.ifreq.ifr_addr.sa_len == 0) 769 u.ifreq.ifr_addr.sa_len = 16; 770 #endif 771 #ifdef HAVE_MINIMUM_IFREQ 772 cpsize = sizeof(u.ifreq); 773 if (u.ifreq.ifr_addr.sa_len > sizeof(struct sockaddr)) 774 cpsize += (int)u.ifreq.ifr_addr.sa_len - 775 (int)(sizeof(struct sockaddr)); 776 #else 777 cpsize = sizeof(u.ifreq.ifr_name) + u.ifreq.ifr_addr.sa_len; 778 #endif /* HAVE_MINIMUM_IFREQ */ 779 if (cpsize > sizeof(u.ifreq) && cpsize <= sizeof(u)) 780 memmove(&u.ifreq, cp, cpsize); 781 #elif defined SIOCGIFCONF_ADDR 782 cpsize = sizeof(u.ifreq); 783 #else 784 cpsize = sizeof(u.ifreq.ifr_name); 785 /* XXX maybe this should be a hard error? */ 786 if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0) 787 continue; 788 #endif 789 switch (u.ifreq.ifr_addr.sa_family) { 790 case AF_INET: 791 if (*have_v4 == 0) { 792 memmove(&in4, 793 &((struct sockaddr_in *) 794 &u.ifreq.ifr_addr)->sin_addr, 795 sizeof(in4)); 796 if (in4.s_addr == INADDR_ANY) 797 break; 798 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); 799 if (n < 0) 800 break; 801 if ((u.ifreq.ifr_flags & IFF_UP) == 0) 802 break; 803 *have_v4 = 1; 804 } 805 break; 806 case AF_INET6: 807 if (*have_v6 == 0) { 808 memmove(&in6, 809 &((struct sockaddr_in6 *) 810 &u.ifreq.ifr_addr)->sin6_addr, 811 sizeof(in6)); 812 if (memcmp(&in6, &in6addr_any, 813 sizeof(in6)) == 0) 814 break; 815 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); 816 if (n < 0) 817 break; 818 if ((u.ifreq.ifr_flags & IFF_UP) == 0) 819 break; 820 *have_v6 = 1; 821 } 822 break; 823 } 824 } 825 if (buf != NULL) 826 free(buf); 827 #ifdef WIN32 828 DestroySockets(); 829 #endif 830 close(s); 831 return (0); 832 833 err_ret: 834 if (buf != NULL) 835 free(buf); 836 if (s != -1) 837 close(s); 838 #ifdef WIN32 839 DestroySockets(); 840 #endif 841 return (-1); 842 #endif 843 } 844 845 static struct hostent * 846 copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) 847 { 848 struct hostent *he = NULL; 849 int addresses = 1; /* NULL terminator */ 850 int names = 1; /* NULL terminator */ 851 int len = 0; 852 char **cpp, **npp; 853 854 /* 855 * Work out array sizes. 856 */ 857 if (he1 != NULL) { 858 cpp = he1->h_addr_list; 859 while (*cpp != NULL) { 860 addresses++; 861 cpp++; 862 } 863 cpp = he1->h_aliases; 864 while (*cpp != NULL) { 865 names++; 866 cpp++; 867 } 868 } 869 870 if (he2 != NULL) { 871 cpp = he2->h_addr_list; 872 while (*cpp != NULL) { 873 addresses++; 874 cpp++; 875 } 876 if (he1 == NULL) { 877 cpp = he2->h_aliases; 878 while (*cpp != NULL) { 879 names++; 880 cpp++; 881 } 882 } 883 } 884 885 if (addresses == 1) { 886 *error_num = NO_ADDRESS; 887 return (NULL); 888 } 889 890 he = malloc(sizeof(*he)); 891 if (he == NULL) 892 goto no_recovery; 893 894 he->h_addr_list = malloc(sizeof(char *) * (addresses)); 895 if (he->h_addr_list == NULL) 896 goto cleanup0; 897 memset(he->h_addr_list, 0, sizeof(char *) * (addresses)); 898 899 /* 900 * Copy addresses. 901 */ 902 npp = he->h_addr_list; 903 if (he1 != NULL) { 904 cpp = he1->h_addr_list; 905 while (*cpp != NULL) { 906 *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 907 if (*npp == NULL) 908 goto cleanup1; 909 /* 910 * Convert to mapped if required. 911 */ 912 if (af == AF_INET6 && he1->h_addrtype == AF_INET) { 913 memmove(*npp, in6addr_mapped, 914 sizeof(in6addr_mapped)); 915 memmove(*npp + sizeof(in6addr_mapped), *cpp, 916 INADDRSZ); 917 } else { 918 memmove(*npp, *cpp, 919 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 920 } 921 cpp++; 922 npp++; 923 } 924 } 925 926 if (he2 != NULL) { 927 cpp = he2->h_addr_list; 928 while (*cpp != NULL) { 929 *npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 930 if (*npp == NULL) 931 goto cleanup1; 932 /* 933 * Convert to mapped if required. 934 */ 935 if (af == AF_INET6 && he2->h_addrtype == AF_INET) { 936 memmove(*npp, in6addr_mapped, 937 sizeof(in6addr_mapped)); 938 memmove(*npp + sizeof(in6addr_mapped), *cpp, 939 INADDRSZ); 940 } else { 941 memmove(*npp, *cpp, 942 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); 943 } 944 cpp++; 945 npp++; 946 } 947 } 948 949 he->h_aliases = malloc(sizeof(char *) * (names)); 950 if (he->h_aliases == NULL) 951 goto cleanup1; 952 memset(he->h_aliases, 0, sizeof(char *) * (names)); 953 954 /* 955 * Copy aliases. 956 */ 957 npp = he->h_aliases; 958 cpp = (he1 != NULL) ? he1->h_aliases 959 : ((he2 != NULL) ? he2->h_aliases : NULL); 960 while (cpp != NULL && *cpp != NULL) { 961 len = strlen (*cpp) + 1; 962 *npp = malloc(len); 963 if (*npp == NULL) 964 goto cleanup2; 965 strcpy(*npp, *cpp); 966 npp++; 967 cpp++; 968 } 969 970 /* 971 * Copy hostname. 972 */ 973 he->h_name = malloc(strlen((he1 != NULL) ? 974 he1->h_name : he2->h_name) + 1); 975 if (he->h_name == NULL) 976 goto cleanup2; 977 strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name); 978 979 /* 980 * Set address type and length. 981 */ 982 he->h_addrtype = af; 983 he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ; 984 return (he); 985 986 cleanup2: 987 cpp = he->h_aliases; 988 while (*cpp != NULL) { 989 free(*cpp); 990 cpp++; 991 } 992 free(he->h_aliases); 993 994 cleanup1: 995 cpp = he->h_addr_list; 996 while (*cpp != NULL) { 997 free(*cpp); 998 *cpp = NULL; 999 cpp++; 1000 } 1001 free(he->h_addr_list); 1002 1003 cleanup0: 1004 free(he); 1005 1006 no_recovery: 1007 *error_num = NO_RECOVERY; 1008 return (NULL); 1009 } 1010 1011 static struct hostent * 1012 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) { 1013 struct hostent *he; 1014 int i; 1015 1016 he = malloc(sizeof(*he)); 1017 if (he == NULL) 1018 goto cleanup; 1019 memset(he, 0, sizeof(*he)); 1020 1021 /* 1022 * Set family and length. 1023 */ 1024 he->h_addrtype = af; 1025 switch (af) { 1026 case AF_INET: 1027 he->h_length = INADDRSZ; 1028 break; 1029 case AF_INET6: 1030 he->h_length = IN6ADDRSZ; 1031 break; 1032 default: 1033 INSIST(0); 1034 } 1035 1036 /* 1037 * Copy name. 1038 */ 1039 he->h_name = strdup(addr->realname); 1040 if (he->h_name == NULL) 1041 goto cleanup; 1042 1043 /* 1044 * Copy aliases. 1045 */ 1046 he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1)); 1047 if (he->h_aliases == NULL) 1048 goto cleanup; 1049 for (i = 0; i < addr->naliases; i++) { 1050 he->h_aliases[i] = strdup(addr->aliases[i]); 1051 if (he->h_aliases[i] == NULL) 1052 goto cleanup; 1053 } 1054 he->h_aliases[i] = NULL; 1055 1056 /* 1057 * Copy address. 1058 */ 1059 he->h_addr_list = malloc(sizeof(char *) * 2); 1060 if (he->h_addr_list == NULL) 1061 goto cleanup; 1062 he->h_addr_list[0] = malloc(he->h_length); 1063 if (he->h_addr_list[0] == NULL) 1064 goto cleanup; 1065 memmove(he->h_addr_list[0], src, he->h_length); 1066 he->h_addr_list[1] = NULL; 1067 return (he); 1068 1069 cleanup: 1070 if (he != NULL && he->h_addr_list != NULL) { 1071 for (i = 0; he->h_addr_list[i] != NULL; i++) 1072 free(he->h_addr_list[i]); 1073 free(he->h_addr_list); 1074 } 1075 if (he != NULL && he->h_aliases != NULL) { 1076 for (i = 0; he->h_aliases[i] != NULL; i++) 1077 free(he->h_aliases[i]); 1078 free(he->h_aliases); 1079 } 1080 if (he != NULL && he->h_name != NULL) 1081 free(he->h_name); 1082 if (he != NULL) 1083 free(he); 1084 return (NULL); 1085 } 1086 1087 static struct hostent * 1088 hostfromname(lwres_gabnresponse_t *name, int af) { 1089 struct hostent *he; 1090 int i; 1091 lwres_addr_t *addr; 1092 1093 he = malloc(sizeof(*he)); 1094 if (he == NULL) 1095 goto cleanup; 1096 memset(he, 0, sizeof(*he)); 1097 1098 /* 1099 * Set family and length. 1100 */ 1101 he->h_addrtype = af; 1102 switch (af) { 1103 case AF_INET: 1104 he->h_length = INADDRSZ; 1105 break; 1106 case AF_INET6: 1107 he->h_length = IN6ADDRSZ; 1108 break; 1109 default: 1110 INSIST(0); 1111 } 1112 1113 /* 1114 * Copy name. 1115 */ 1116 he->h_name = strdup(name->realname); 1117 if (he->h_name == NULL) 1118 goto cleanup; 1119 1120 /* 1121 * Copy aliases. 1122 */ 1123 he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1)); 1124 if (he->h_aliases == NULL) 1125 goto cleanup; 1126 for (i = 0; i < name->naliases; i++) { 1127 he->h_aliases[i] = strdup(name->aliases[i]); 1128 if (he->h_aliases[i] == NULL) 1129 goto cleanup; 1130 } 1131 he->h_aliases[i] = NULL; 1132 1133 /* 1134 * Copy addresses. 1135 */ 1136 he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1)); 1137 if (he->h_addr_list == NULL) 1138 goto cleanup; 1139 addr = LWRES_LIST_HEAD(name->addrs); 1140 i = 0; 1141 while (addr != NULL) { 1142 he->h_addr_list[i] = malloc(he->h_length); 1143 if (he->h_addr_list[i] == NULL) 1144 goto cleanup; 1145 memmove(he->h_addr_list[i], addr->address, he->h_length); 1146 addr = LWRES_LIST_NEXT(addr, link); 1147 i++; 1148 } 1149 he->h_addr_list[i] = NULL; 1150 return (he); 1151 1152 cleanup: 1153 if (he != NULL && he->h_addr_list != NULL) { 1154 for (i = 0; he->h_addr_list[i] != NULL; i++) 1155 free(he->h_addr_list[i]); 1156 free(he->h_addr_list); 1157 } 1158 if (he != NULL && he->h_aliases != NULL) { 1159 for (i = 0; he->h_aliases[i] != NULL; i++) 1160 free(he->h_aliases[i]); 1161 free(he->h_aliases); 1162 } 1163 if (he != NULL && he->h_name != NULL) 1164 free(he->h_name); 1165 if (he != NULL) 1166 free(he); 1167 return (NULL); 1168 } 1169