1/* 2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <netdb.h> 25#include <sys/types.h> 26#include <ctype.h> 27#include <stdio.h> 28#include <stdint.h> 29#include <sys/socket.h> 30#include <net/if.h> 31#include <netinet/in.h> 32#include <network/sa_compare.h> 33#include <arpa/inet.h> 34#include <ifaddrs.h> 35#include <net/if.h> 36#include <string.h> 37#include <sys/param.h> 38#include <notify.h> 39#include <notify_keys.h> 40#include <pthread.h> 41#include <TargetConditionals.h> 42#include "netdb_async.h" 43#include "si_module.h" 44 45#define SOCK_UNSPEC 0 46#define IPPROTO_UNSPEC 0 47 48#define IPV6_ADDR_LEN 16 49#define IPV4_ADDR_LEN 4 50 51#define WANT_NOTHING 0 52#define WANT_A4_ONLY 1 53#define WANT_A6_ONLY 2 54#define WANT_A6_PLUS_MAPPED_A4 3 55#define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4 56 57#define V6TO4_PREFIX_16 0x2002 58 59static int net_config_token = -1; 60static uint32_t net_v4_count = 0; 61static uint32_t net_v6_count = 0; // includes 6to4 addresses 62static pthread_mutex_t net_config_mutex = PTHREAD_MUTEX_INITIALIZER; 63 64// Libc SPI 65int _inet_aton_check(const char *cp, struct in_addr *addr, int strict); 66 67typedef struct { 68 struct hostent host; 69 int alias_count; 70 int addr_count; 71 uint64_t ttl; 72} build_hostent_t; 73 74__private_extern__ int 75si_inet_config(uint32_t *inet4, uint32_t *inet6) 76{ 77 int status, checkit; 78 struct ifaddrs *ifa, *ifap; 79 80 pthread_mutex_lock(&net_config_mutex); 81 82 checkit = 1; 83 84 if (net_config_token < 0) 85 { 86 status = notify_register_check(kNotifySCNetworkChange, &net_config_token); 87 if (status != 0) net_config_token = -1; 88 } 89 90 if (net_config_token >= 0) 91 { 92 status = notify_check(net_config_token, &checkit); 93 if (status != 0) checkit = 1; 94 } 95 96 status = 0; 97 98 if (checkit != 0) 99 { 100 if (getifaddrs(&ifa) < 0) 101 { 102 status = -1; 103 } 104 else 105 { 106 net_v4_count = 0; 107 net_v6_count = 0; 108 109 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) 110 { 111 if (ifap->ifa_addr == NULL) continue; 112 if ((ifap->ifa_flags & IFF_UP) == 0) continue; 113 114 if (ifap->ifa_addr->sa_family == AF_INET) 115 { 116 net_v4_count++; 117 } 118 else if (ifap->ifa_addr->sa_family == AF_INET6) 119 { 120 net_v6_count++; 121 } 122 } 123 freeifaddrs(ifa); 124 } 125 126 } 127 128 if (inet4 != NULL) *inet4 = net_v4_count; 129 if (inet6 != NULL) *inet6 = net_v6_count; 130 131 pthread_mutex_unlock(&net_config_mutex); 132 133 return status; 134} 135 136void 137freeaddrinfo(struct addrinfo *a) 138{ 139 struct addrinfo *next; 140 141 while (a != NULL) 142 { 143 next = a->ai_next; 144 if (a->ai_addr != NULL) free(a->ai_addr); 145 if (a->ai_canonname != NULL) free(a->ai_canonname); 146 free(a); 147 a = next; 148 } 149} 150 151const char * 152gai_strerror(int32_t err) 153{ 154 switch (err) 155 { 156 case EAI_ADDRFAMILY: return "Address family for nodename not supported"; 157 case EAI_AGAIN: return "Temporary failure in name resolution"; 158 case EAI_BADFLAGS: return "Invalid value for ai_flags"; 159 case EAI_FAIL: return "Non-recoverable failure in name resolution"; 160 case EAI_FAMILY: return "ai_family not supported"; 161 case EAI_MEMORY: return "Memory allocation failure"; 162 case EAI_NODATA: return "No address associated with nodename"; 163 case EAI_NONAME: return "nodename nor servname provided, or not known"; 164 case EAI_SERVICE: return "servname not supported for ai_socktype"; 165 case EAI_SOCKTYPE: return "ai_socktype not supported"; 166 case EAI_SYSTEM: return "System error"; 167 case EAI_BADHINTS: return "Bad hints"; 168 case EAI_PROTOCOL: return "ai_protocol not supported"; 169 case EAI_OVERFLOW: return "argument buffer overflow"; 170 } 171 172 return "Unknown error"; 173} 174 175/* 176 * getnameinfo 177 * 178 * We handle some "trival" cases locally. If the caller passes 179 * NI_NUMERICHOST (only), then this call turns into a getservbyport 180 * to get the service name + inet_pton() to create a host string. 181 * If the caller passes NI_NUMERICSERV (only), then we zero out the port 182 * number, complete the getnameinfo, and use printf() to create a service 183 * string. If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV, 184 * we inet_ntop() and printf() and return the results. 185 */ 186si_item_t * 187si_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *interface, uint32_t *err) 188{ 189 si_item_t *out = NULL; 190 const struct sockaddr *lookup_sa; 191 struct sockaddr_in s4; 192 struct in_addr a4; 193 struct in6_addr a6; 194 const uint64_t unused = 0; 195 void *addr = NULL; 196 char *host = NULL; 197 char *serv = NULL; 198 uint32_t ifnum = 0; 199 uint16_t port = 0; 200 201 int do_host_lookup = ((flags & NI_NUMERICHOST) == 0); 202 int do_serv_lookup = ((flags & NI_NUMERICSERV) == 0); 203 204 /* check input */ 205 if ((si == NULL) || (sa == NULL)) 206 { 207 if (err != NULL) *err = SI_STATUS_EAI_FAIL; 208 return NULL; 209 } 210 211 if (err != NULL) *err = SI_STATUS_NO_ERROR; 212 213 lookup_sa = sa; 214 215 if (sa->sa_family == AF_INET) 216 { 217 struct sockaddr_in *s4 = (struct sockaddr_in *)sa; 218 memcpy(&a4, &s4->sin_addr, sizeof(a4)); 219 port = s4->sin_port; 220 addr = &a4; 221 } 222 else if (sa->sa_family == AF_INET6) 223 { 224 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa; 225 memcpy(&a6, &s6->sin6_addr, sizeof(a6)); 226 port = s6->sin6_port; 227 228 /* Look for scope id in IPv6 Link Local, Multicast Node Local, and Multicast Link Local */ 229 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr)) 230 { 231 ifnum = ntohs(a6.__u6_addr.__u6_addr16[1]); 232 if (ifnum == 0) 233 { 234 ifnum = s6->sin6_scope_id; 235 a6.__u6_addr.__u6_addr16[1] = htons(ifnum); 236 } 237 238 if ((ifnum != s6->sin6_scope_id) && (s6->sin6_scope_id != 0)) 239 { 240 if (err != NULL) *err = SI_STATUS_EAI_FAIL; 241 return NULL; 242 } 243 } 244 245 /* v4 mapped and compat addresses are converted to plain v4 */ 246 if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr)) 247 { 248 memcpy(&a4, &s6->sin6_addr.s6_addr[12], sizeof(a4)); 249 addr = &a4; 250 memset(&s4, 0, sizeof(s4)); 251 s4.sin_len = sizeof(s4); 252 s4.sin_family = AF_INET; 253 s4.sin_port = port; 254 memcpy(&s4.sin_addr, &a4, sizeof(s4.sin_addr)); 255 lookup_sa = (const struct sockaddr *)&s4; 256 } 257 else 258 { 259 addr = &a6; 260 } 261 } 262 else 263 { 264 if (err != NULL) *err = SI_STATUS_EAI_FAMILY; 265 return NULL; 266 } 267 268 if (do_host_lookup == 1) 269 { 270 si_item_t *item = si_host_byaddr(si, addr, lookup_sa->sa_family, interface, NULL); 271 if (item != NULL) 272 { 273 struct hostent *h; 274 h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t)); 275 host = strdup(h->h_name); 276 si_item_release(item); 277 if (host == NULL) 278 { 279 if (err != NULL) *err = SI_STATUS_EAI_MEMORY; 280 return NULL; 281 } 282 } 283 } 284 285 if ((do_serv_lookup == 1) && (port != 0)) 286 { 287 si_item_t *item = si_service_byport(si, port, NULL); 288 if (item != NULL) 289 { 290 struct servent *s; 291 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t)); 292 serv = strdup(s->s_name); 293 si_item_release(item); 294 if (serv == NULL) 295 { 296 free(host); 297 if (err != NULL) *err = SI_STATUS_EAI_MEMORY; 298 return NULL; 299 } 300 } 301 } 302 303 /* 304 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not 305 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME). 306 */ 307 if ((host == NULL) && ((flags & NI_NAMEREQD) == 0)) 308 { 309 char tmp[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1]; 310 tmp[0] = '\0'; 311 if (sa->sa_family == AF_INET) 312 { 313 char buf[INET_ADDRSTRLEN]; 314 if (inet_ntop(AF_INET, &a4, buf, sizeof(buf)) != 0) 315 { 316 host = strdup(buf); 317 } 318 } 319 else if (sa->sa_family == AF_INET6) 320 { 321 char buf[INET6_ADDRSTRLEN]; 322 323 /* zero the embedded scope ID */ 324 if (ifnum != 0) 325 { 326 a6.__u6_addr.__u6_addr16[1] = 0; 327 } 328 329 if (inet_ntop(AF_INET6, &a6, buf, sizeof(buf)) != 0) 330 { 331 if (ifnum != 0) 332 { 333 char ifname[IF_NAMESIZE]; 334 if (if_indextoname(ifnum, ifname) != NULL) 335 { 336 asprintf(&host, "%s%%%s", buf, ifname); 337 } 338 else 339 { 340 /* ENXIO */ 341 if (err != NULL) *err = SI_STATUS_EAI_FAIL; 342 return NULL; 343 } 344 } 345 else 346 { 347 host = strdup(buf); 348 } 349 } 350 } 351 } 352 353 /* Return numeric service name for NI_NUMERICSERV or if lookup failed. */ 354 if (serv == NULL) 355 { 356 asprintf(&serv, "%hu", ntohs(port)); 357 } 358 359 if ((host == NULL) || (serv == NULL)) 360 { 361 if (err != NULL) 362 { 363 if ((flags & NI_NAMEREQD) != 0) 364 { 365 *err = SI_STATUS_EAI_NONAME; 366 } 367 else 368 { 369 *err = SI_STATUS_EAI_MEMORY; 370 } 371 } 372 } 373 else 374 { 375 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_NAMEINFO, 1, unused, unused, host, serv); 376 } 377 378 free(host); 379 free(serv); 380 return out; 381} 382 383static int 384_gai_numericserv(const char *serv, uint16_t *port) 385{ 386 int numeric; 387 char *endptr; 388 long num; 389 390 numeric = 0; 391 392 if (serv == NULL) 393 { 394 if (port) *port = 0; 395 numeric = 1; 396 } 397 else 398 { 399 num = strtol(serv, &endptr, 10); 400 if ((serv[0] != '\0') && (*endptr == '\0') && (num >= 0) && (num <= UINT16_MAX)) 401 { 402 numeric = 1; 403 if (port != NULL) *port = (uint16_t)num; 404 } 405 } 406 407 return numeric; 408} 409 410int 411_gai_serv_to_port(const char *serv, uint32_t proto, uint16_t *port) 412{ 413 si_item_t *item; 414 struct servent *s; 415 const char *protoname = NULL; 416 417 if (_gai_numericserv(serv, port)) return 0; 418 419 if (proto == IPPROTO_UDP) protoname = "udp"; 420 if (proto == IPPROTO_TCP) protoname = "tcp"; 421 422 item = si_service_byname(si_search(), serv, protoname); 423 if (item == NULL) return -1; 424 425 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t)); 426 if (port) *port = ntohs(s->s_port); 427 si_item_release(item); 428 429 return 0; 430} 431 432si_item_t * 433si_addrinfo_v4(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr *addr, uint16_t iface, const char *cname) 434{ 435 socket_data_t sockdata; 436 struct sockaddr_in *sa; 437 int32_t len, v32; 438 uint64_t unused; 439 440 unused = 0; 441 len = sizeof(struct sockaddr_in); 442 memset(&sockdata, 0, sizeof(socket_data_t)); 443 sa = (struct sockaddr_in *)&sockdata; 444 445 sa->sin_len = len; 446 sa->sin_family = AF_INET; 447 sa->sin_port = htons(port); 448 memcpy(&sa->sin_addr, addr, sizeof(sa->sin_addr)); 449 450 /* Kludge: Jam the interface number into sin_zero (4 bytes). */ 451 v32 = iface; 452 memmove(sa->sin_zero, &v32, sizeof(uint32_t)); 453 454 return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET, sock, proto, len, sockdata, cname); 455} 456 457si_item_t * 458si_addrinfo_v4_mapped(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr *addr, uint16_t iface, const char *cname) 459{ 460 socket_data_t sockdata; 461 struct sockaddr_in6 *sa; 462 int32_t len; 463 uint64_t unused; 464 465 unused = 0; 466 len = sizeof(struct sockaddr_in6); 467 memset(&sockdata, 0, sizeof(socket_data_t)); 468 sa = (struct sockaddr_in6 *)&sockdata; 469 470 sa->sin6_len = len; 471 sa->sin6_family = AF_INET6; 472 sa->sin6_port = htons(port); 473 memset(&(sa->sin6_addr.__u6_addr.__u6_addr8[10]), 0xff, 2); 474 memcpy(&(sa->sin6_addr.__u6_addr.__u6_addr8[12]), addr, sizeof(struct in_addr)); 475 476 /* sin6_scope_id is in host byte order */ 477 sa->sin6_scope_id = iface; 478 479 return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname); 480} 481 482 483si_item_t * 484si_addrinfo_v6(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in6_addr *addr, uint16_t iface, const char *cname) 485{ 486 socket_data_t sockdata; 487 struct sockaddr_in6 *sa; 488 int32_t len; 489 uint64_t unused; 490 491 unused = 0; 492 len = sizeof(struct sockaddr_in6); 493 memset(&sockdata, 0, sizeof(socket_data_t)); 494 sa = (struct sockaddr_in6 *)&sockdata; 495 496 sa->sin6_len = len; 497 sa->sin6_family = AF_INET6; 498 sa->sin6_port = htons(port); 499 memcpy(&sa->sin6_addr, addr, sizeof(sa->sin6_addr)); 500 501 /* sin6_scope_id is in host byte order */ 502 sa->sin6_scope_id = iface; 503 504 if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) 505 { 506 /* check for embedded scopeid */ 507 uint16_t esid = ntohs(sa->sin6_addr.__u6_addr.__u6_addr16[1]); 508 if (esid != 0) 509 { 510 sa->sin6_addr.__u6_addr.__u6_addr16[1] = 0; 511 if (iface == 0) sa->sin6_scope_id = esid; 512 } 513 } 514 515 return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname); 516} 517 518si_list_t * 519si_addrinfo_list(si_mod_t *si, uint32_t flags, int socktype, int proto, struct in_addr *a4, struct in6_addr *a6, int port, int scopeid, const char *cname4, const char *cname6) 520{ 521 int do_map = 0; 522 si_item_t *item = NULL; 523 si_list_t *out4 = NULL, *out6 = NULL; 524 525 if ((flags & AI_V4MAPPED) && ((flags & AI_ALL) || (a6 == NULL))) do_map = 1; 526 527 if (a6 != NULL) 528 { 529 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP)) 530 { 531 item = si_addrinfo_v6(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a6, scopeid, cname6); 532 out6 = si_list_add(out6, item); 533 si_item_release(item); 534 } 535 536 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP)) 537 { 538 item = si_addrinfo_v6(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a6, scopeid, cname6); 539 out6 = si_list_add(out6, item); 540 si_item_release(item); 541 } 542 543 if (proto == IPPROTO_ICMPV6) 544 { 545 item = si_addrinfo_v6(si, 0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, scopeid, cname6); 546 out6 = si_list_add(out6, item); 547 si_item_release(item); 548 } 549 } 550 551 if (a4 != NULL) 552 { 553 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP)) 554 { 555 if (do_map == 0) 556 { 557 item = si_addrinfo_v4(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4); 558 out4 = si_list_add(out4, item); 559 } 560 else 561 { 562 item = si_addrinfo_v4_mapped(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4); 563 out6 = si_list_add(out6, item); 564 } 565 566 si_item_release(item); 567 } 568 569 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP)) 570 { 571 if (do_map == 0) 572 { 573 item = si_addrinfo_v4(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4); 574 out4 = si_list_add(out4, item); 575 } 576 else 577 { 578 item = si_addrinfo_v4_mapped(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4); 579 out6 = si_list_add(out6, item); 580 } 581 582 si_item_release(item); 583 } 584 585 if (proto == IPPROTO_ICMP) 586 { 587 if (do_map == 0) 588 { 589 item = si_addrinfo_v4(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4); 590 out4 = si_list_add(out4, item); 591 } 592 else 593 { 594 item = si_addrinfo_v4_mapped(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4); 595 out6 = si_list_add(out6, item); 596 } 597 598 si_item_release(item); 599 } 600 } 601 602 out6 = si_list_concat(out6, out4); 603 si_list_release(out4); 604 605 return out6; 606} 607 608/* 609 * _gai_numerichost 610 * Determines whether the given host name is a numeric IPv4 or IPv6 address, 611 * based on the address family input value. If the input addres family is 612 * unspecified, a more specific value will be provided on output if possible. 613 * Returns 1 if host name is numeric or 0 if not, or -1 on error. 614 */ 615static int 616_gai_numerichost(const char* nodename, uint32_t *family, int flags, struct in_addr *a4, struct in6_addr *a6, int *scope) 617{ 618 int numerichost, passive; 619 620 numerichost = 0; 621 622 if (nodename == NULL) 623 { 624 /* return loopback or passive addresses */ 625 passive = (flags & AI_PASSIVE); 626 627 if (((*family == AF_UNSPEC) || (*family == AF_INET)) || ((*family == AF_INET6) && (flags & AI_V4MAPPED) && (flags & AI_ALL))) 628 { 629 if (passive) a4->s_addr = 0; 630 else a4->s_addr = htonl(INADDR_LOOPBACK); 631 } 632 633 if ((*family == AF_UNSPEC) || (*family == AF_INET6)) 634 { 635 memset(a6, 0, sizeof(*a6)); 636 if (!passive) a6->__u6_addr.__u6_addr32[3] = htonl(1); 637 } 638 639 numerichost = 1; 640 } 641 else 642 { 643 /* 644 * numeric IPv4 host valid for AF_UNSPEC and AF_INET 645 * also valid for AF_INET6 with AI_V4MAPPED 646 */ 647 numerichost = inet_pton(AF_INET, nodename, a4); 648 if (numerichost == 0) 649 { 650 /* inet_pton doesn't allow "a", "a.b", or "a.b.c" forms, so we re-check */ 651 numerichost = _inet_aton_check(nodename, a4, 1); 652 } 653 654 if (numerichost == 1) 655 { 656 if (*family == AF_UNSPEC) 657 { 658 *family = AF_INET; 659 } 660 else if (*family == AF_INET6) 661 { 662 if (flags & AI_V4MAPPED) 663 { 664 memset(a6, 0, sizeof(struct in6_addr)); 665 memset(&(a6->__u6_addr.__u6_addr8[10]), 0xff, 2); 666 memcpy(&(a6->__u6_addr.__u6_addr8[12]), a4, sizeof(struct in_addr)); 667 } 668 else 669 { 670 numerichost = -1; 671 } 672 } 673 674 return numerichost; 675 } 676 677 /* numeric IPv6 host valid for AF_UNSPEC and AF_INET6 */ 678 numerichost = inet_pton(AF_INET6, nodename, a6); 679 if (numerichost == 1) 680 { 681 /* check for scope/zone id */ 682 char *p = strrchr(nodename, SCOPE_DELIMITER); 683 if (p != NULL) 684 { 685 int i, d; 686 char *x; 687 688 p++; 689 d = 1; 690 for (x = p; (*x != '\0') && (d == 1); x++) 691 { 692 i = *x; 693 d = isdigit(i); 694 } 695 696 if (d == 1) *scope = atoi(p); 697 else *scope = if_nametoindex(p); 698 } 699 700 if (*family == AF_UNSPEC) *family = AF_INET6; 701 else if (*family == AF_INET) numerichost = -1; 702 703 return numerichost; 704 } 705 } 706 707 return numerichost; 708} 709 710/* si_addrinfo_list_from_hostent 711 * Returns an addrinfo list from IPv4 and IPv6 hostent entries 712 */ 713si_list_t * 714si_addrinfo_list_from_hostent(si_mod_t *si, uint32_t flags, uint32_t socktype, uint32_t proto, uint16_t port, uint16_t scope, const struct hostent *h4, const struct hostent *h6) 715{ 716 int i; 717 si_list_t *out = NULL; 718 si_list_t *list; 719 720 if ((h6 != NULL) && (h6->h_addr_list != NULL)) 721 { 722 for (i = 0; h6->h_addr_list[i] != NULL; i++) 723 { 724 struct in6_addr a6; 725 memcpy(&a6, h6->h_addr_list[i], h6->h_length); 726 list = si_addrinfo_list(si, flags, socktype, proto, NULL, &a6, port, scope, NULL, h6->h_name); 727 out = si_list_concat(out, list); 728 si_list_release(list); 729 } 730 } 731 732 if ((h4 != NULL) && (h4->h_addr_list != NULL)) 733 { 734 for (i = 0; h4->h_addr_list[i] != NULL; i++) 735 { 736 struct in_addr a4; 737 memcpy(&a4, h4->h_addr_list[i], h4->h_length); 738 list = si_addrinfo_list(si, flags, socktype, proto, &a4, NULL, port, 0, h4->h_name, NULL); 739 out = si_list_concat(out, list); 740 si_list_release(list); 741 } 742 } 743 744 return out; 745} 746 747int 748_gai_addr_sort(const void *a, const void *b) 749{ 750 si_item_t **item_a, **item_b; 751 si_addrinfo_t *p, *q; 752 struct sockaddr *sp, *sq; 753 754 item_a = (si_item_t **)a; 755 item_b = (si_item_t **)b; 756 757 p = (si_addrinfo_t *)((uintptr_t)*item_a + sizeof(si_item_t)); 758 q = (si_addrinfo_t *)((uintptr_t)*item_b + sizeof(si_item_t)); 759 760 sp = (struct sockaddr *)p->ai_addr.x; 761 sq = (struct sockaddr *)q->ai_addr.x; 762 763 /* 764 * sa_dst_compare(A,B) returns -1 if A is less desirable than B, 765 * 0 if they are equally desirable, and 1 if A is more desirable. 766 * qsort() expects the inverse, so we swap sp and sq. 767 */ 768 return sa_dst_compare(sq, sp, 0); 769} 770 771static si_list_t * 772_gai_sort_list(si_list_t *in, uint32_t flags) 773{ 774 si_list_t *out; 775 int filter_mapped; 776 uint32_t i; 777 uint32_t v4mapped_count = 0; 778 uint32_t v6_count = 0; 779 si_addrinfo_t *a; 780 781 if (in == NULL) return NULL; 782 783 for (i = 0; i < in->count; i++) 784 { 785 a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t)); 786 if (a->ai_family == AF_INET6) 787 { 788 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)a->ai_addr.x; 789 if (IN6_IS_ADDR_V4MAPPED(&(s6->sin6_addr))) v4mapped_count++; 790 else v6_count++; 791 } 792 } 793 794 filter_mapped = 1; 795 if ((flags & AI_V4MAPPED) && ((v6_count == 0) || (flags & AI_ALL))) filter_mapped = 0; 796 797 out = in; 798 799 if ((filter_mapped == 1) && (v4mapped_count > 0)) 800 { 801 i = in->count - v4mapped_count; 802 if (i == 0) return NULL; 803 804 out = (si_list_t *)calloc(1, sizeof(si_list_t)); 805 if (out == NULL) return in; 806 807 out->count = i; 808 out->refcount = in->refcount; 809 810 out->entry = (si_item_t **)calloc(out->count, sizeof(si_item_t *)); 811 if (out->entry == NULL) 812 { 813 free(out); 814 return in; 815 } 816 817 out->curr = 0; 818 819 for (i = 0; i < in->count; i++) 820 { 821 a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t)); 822 if (a->ai_family == AF_INET6) 823 { 824 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)a->ai_addr.x; 825 if (IN6_IS_ADDR_V4MAPPED(&(s6->sin6_addr))) 826 { 827 si_item_release(in->entry[i]); 828 continue; 829 } 830 } 831 832 out->entry[out->curr++] = in->entry[i]; 833 } 834 835 out->curr = 0; 836 837 free(in->entry); 838 free(in); 839 } 840 841 qsort(&out->entry[0], out->count, sizeof(si_item_t *), _gai_addr_sort); 842 return out; 843} 844 845/* _gai_simple 846 * Simple lookup via gethostbyname2(3) mechanism. 847 */ 848si_list_t * 849_gai_simple(si_mod_t *si, const void *nodeptr, const void *servptr, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err) 850{ 851 si_item_t *h4_item = NULL, *h6_item = NULL; 852 struct hostent *h4 = NULL, *h6 = NULL; 853 si_list_t *out = NULL; 854 uint16_t port; 855 856 if ((flags & AI_NUMERICSERV) != 0) 857 { 858 port = *(uint16_t*)servptr; 859 } 860 else 861 { 862 if (_gai_serv_to_port(servptr, proto, &port) != 0) 863 { 864 if (err) *err = SI_STATUS_EAI_NONAME; 865 return NULL; 866 } 867 } 868 869 if ((flags & AI_NUMERICHOST) != 0) 870 { 871 if (family == AF_INET) 872 { 873 h4_item = si_host_byaddr(si, nodeptr, AF_INET, interface, NULL); 874 } 875 else if (family == AF_INET6) 876 { 877 h6_item = si_host_byaddr(si, nodeptr, AF_INET6, interface, NULL); 878 } 879 } 880 else 881 { 882 if ((family == AF_INET) || (family == AF_UNSPEC)) 883 { 884 h4_item = si_host_byname(si, nodeptr, AF_INET, interface, NULL); 885 } 886 887 if ((family == AF_INET6) || (family == AF_UNSPEC)) 888 { 889 h6_item = si_host_byname(si, nodeptr, AF_INET6, interface, NULL); 890 } 891 } 892 893 if (h4_item != NULL) 894 { 895 h4 = (struct hostent *)((uintptr_t)h4_item + sizeof(si_item_t)); 896 } 897 898 if (h6_item != NULL) 899 { 900 h6 = (struct hostent *)((uintptr_t)h6_item + sizeof(si_item_t)); 901 } 902 903 out = si_addrinfo_list_from_hostent(si, flags, socktype, proto, port, 0, h4, h6); 904 si_item_release(h4_item); 905 si_item_release(h6_item); 906 907 return _gai_sort_list(out, flags); 908} 909 910si_list_t * 911si_srv_byname(si_mod_t *si, const char *qname, const char *interface, uint32_t *err) 912{ 913 if (si == NULL) return 0; 914 if (si->vtable->sim_srv_byname == NULL) return 0; 915 916 return si->vtable->sim_srv_byname(si, qname, interface, err); 917} 918 919int 920si_wants_addrinfo(si_mod_t *si) 921{ 922 if (si == NULL) return 0; 923 if (si->vtable->sim_addrinfo == NULL) return 0; 924 if (si->vtable->sim_wants_addrinfo == NULL) return 0; 925 926 return si->vtable->sim_wants_addrinfo(si); 927} 928 929static si_list_t * 930_gai_srv(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err) 931{ 932 int i; 933 char *qname; 934 si_srv_t *srv; 935 si_item_t *item; 936 937 si_list_t *list = NULL; 938 si_list_t *result = NULL; 939 940 /* Minimum SRV priority is zero. Start below that. */ 941 int lastprio = -1; 942 int currprio; 943 944 if (node == NULL || serv == NULL) return NULL; 945 946 asprintf(&qname, "%s.%s", serv, node); 947 list = si_srv_byname(si, qname, interface, err); 948 free(qname); 949 950 /* Iterate the SRV records starting at lowest priority and attempt to 951 * lookup the target host name. Returns the first successful lookup. 952 * It's an O(n^2) algorithm but data sets are small (less than 100) and 953 * sorting overhead is dwarfed by network I/O for each element. 954 */ 955 while (list != NULL && result == NULL) 956 { 957 /* Find the next lowest priority level. */ 958 /* Maximum SRV priority is UINT16_MAX. Start above that. */ 959 currprio = INT_MAX; 960 961 for (i = 0; i < list->count; ++i) 962 { 963 item = list->entry[i]; 964 srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t)); 965 966 if (srv->priority > lastprio && srv->priority < currprio) 967 { 968 currprio = srv->priority; 969 } 970 } 971 972 if (currprio == INT_MAX) 973 { 974 /* All priorities have been evaluated. Done. */ 975 break; 976 } 977 else 978 { 979 lastprio = currprio; 980 } 981 982 /* Lookup hosts at the current priority level. Return first match. */ 983 for (i = 0; i < list->count; ++i) 984 { 985 item = list->entry[i]; 986 srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t)); 987 988 if (srv->priority == currprio) 989 { 990 /* So that _gai_simple expects an integer service. */ 991 flags |= AI_NUMERICSERV; 992 993 result = _gai_simple(si, srv->target, &srv->port, family, socktype, proto, flags, interface, err); 994 if (result) 995 { 996 break; 997 } 998 } 999 } 1000 } 1001 1002 if (list != NULL) 1003 { 1004 si_list_release(list); 1005 } 1006 1007 return result; 1008} 1009 1010si_list_t * 1011si_addrinfo(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err) 1012{ 1013 int numerichost, numericserv = 0; 1014 int scope = 0; 1015 const void *nodeptr = NULL, *servptr = NULL; 1016 uint16_t port; 1017 struct in_addr a4, *p4; 1018 struct in6_addr a6, *p6; 1019 const char *cname; 1020 si_list_t *out; 1021 1022 if (err != NULL) *err = SI_STATUS_NO_ERROR; 1023 1024 if (si == NULL) 1025 { 1026 if (err != NULL) *err = SI_STATUS_EAI_FAIL; 1027 return NULL; 1028 } 1029 1030 /* treat empty strings as NULL */ 1031 if ((node != NULL) && (node[0] == '\0')) node = NULL; 1032 if ((serv != NULL) && (serv[0] == '\0')) serv = NULL; 1033 1034 /* make sure we have a query */ 1035 if ((node == NULL) && (serv == NULL)) 1036 { 1037 if (err != NULL) *err = SI_STATUS_EAI_NONAME; 1038 return NULL; 1039 } 1040 1041 /* verify family is supported */ 1042 switch (family) 1043 { 1044 case AF_UNSPEC: 1045 case AF_INET: 1046 case AF_INET6: 1047 break; 1048 default: 1049 if (err != NULL) *err = SI_STATUS_EAI_FAMILY; 1050 return NULL; 1051 } 1052 1053 /* verify socket type is supported */ 1054 switch (socktype) 1055 { 1056 case SOCK_UNSPEC: 1057 case SOCK_RAW: 1058 case SOCK_DGRAM: 1059 case SOCK_STREAM: 1060 break; 1061 default: 1062 if (err != NULL) *err = SI_STATUS_EAI_BADHINTS; 1063 return NULL; 1064 } 1065 1066 /* verify protocol is supported */ 1067 switch (proto) 1068 { 1069 case IPPROTO_UNSPEC: 1070 case IPPROTO_UDP: 1071 case IPPROTO_TCP: 1072 case IPPROTO_ICMP: 1073 case IPPROTO_ICMPV6: 1074 break; 1075 default: 1076 if (err != NULL) *err = SI_STATUS_EAI_BADHINTS; 1077 return NULL; 1078 } 1079 1080 /* verify socket type compatible with protocol */ 1081 if (((socktype == SOCK_DGRAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_UDP)) || ((socktype == SOCK_STREAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_TCP))) 1082 { 1083 if (err != NULL) *err = SI_STATUS_EAI_BADHINTS; 1084 return NULL; 1085 } 1086 1087 /* check AI_V4MAPPED and AI_ALL */ 1088 if (family != AF_INET6) 1089 { 1090 /* unset AI_V4MAPPED and AI_ALL unless family is AF_INET6 */ 1091 flags &= ~(AI_V4MAPPED | AI_ALL); 1092 } 1093 else if ((flags & AI_V4MAPPED) == 0) 1094 { 1095 /* unset AI_ALL unless family is AF_INET6 and AI_V4MAPPED is set */ 1096 flags &= ~AI_ALL; 1097 } 1098 1099 memset(&a4, 0, sizeof(struct in_addr)); 1100 memset(&a6, 0, sizeof(struct in6_addr)); 1101 1102 /* determine the protocol if possible */ 1103 if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_DGRAM)) proto = IPPROTO_UDP; 1104 if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_STREAM)) proto = IPPROTO_TCP; 1105 1106 port = 0; 1107 1108 if ((flags & AI_SRV) != 0) 1109 { 1110 /* AI_SRV SPI */ 1111 out = _gai_srv(si, node, serv, family, socktype, proto, flags, interface, err); 1112 return _gai_sort_list(out, flags); 1113 } 1114 else 1115 { 1116 /* Usual service lookup */ 1117 numericserv = _gai_numericserv(serv, &port); 1118 } 1119 1120 if ((flags & AI_NUMERICSERV) && (numericserv == 0)) 1121 { 1122 /* FreeBSD returns SI_STATUS_EAI_SERVICE */ 1123 if (err != NULL) *err = SI_STATUS_EAI_NONAME; 1124 return NULL; 1125 } 1126 1127 if ((serv != NULL) && (strcmp(serv, "0") != 0)) 1128 { 1129 if (numericserv == 1) 1130 { 1131 flags |= AI_NUMERICSERV; 1132 servptr = &port; 1133 } 1134 else 1135 { 1136 servptr = serv; 1137 } 1138 } 1139 1140 numerichost = _gai_numerichost(node, &family, flags, &a4, &a6, &scope); 1141 if ((numerichost == -1) || ((flags & AI_NUMERICHOST) && (numerichost == 0))) 1142 { 1143 if (err != NULL) *err = SI_STATUS_EAI_NONAME; 1144 return NULL; 1145 } 1146 1147 if (numerichost == 1) 1148 { 1149 flags |= AI_NUMERICHOST; 1150 if (family == AF_INET) 1151 { 1152 nodeptr = &a4; 1153 } 1154 else if (family == AF_INET6) 1155 { 1156 nodeptr = &a6; 1157 } 1158 } 1159 else 1160 { 1161 nodeptr = node; 1162 } 1163 1164 if ((numerichost == 1) && (numericserv == 0)) 1165 { 1166 /* only service lookup needed. convert to port and perform a trivial getaddrinfo */ 1167 if (_gai_serv_to_port(serv, proto, &port) != 0) 1168 { 1169 if (err != NULL) *err = SI_STATUS_EAI_NONAME; 1170 return NULL; 1171 } 1172 else 1173 { 1174 flags |= AI_NUMERICSERV; 1175 servptr = &port; 1176 numericserv = 1; 1177 } 1178 } 1179 1180 if ((numerichost == 1) && (numericserv == 1)) 1181 { 1182 p4 = &a4; 1183 p6 = &a6; 1184 cname = NULL; 1185 1186 if (family == AF_INET) p6 = NULL; 1187 if (family == AF_INET6) p4 = NULL; 1188 if (node == NULL) cname = "localhost"; 1189 1190 /* allow nodename to be a mapped IPv4 address, e.g. "::ffff:10.0.0.1" */ 1191 if (p6 != NULL) flags |= AI_V4MAPPED; 1192 1193 /* handle trivial questions */ 1194 out = si_addrinfo_list(si, flags, socktype, proto, p4, p6, port, scope, cname, cname); 1195 return _gai_sort_list(out, flags); 1196 } 1197 else if (si_wants_addrinfo(si)) 1198 { 1199 /* or let the current module handle the host lookups intelligently */ 1200 out = si->vtable->sim_addrinfo(si, nodeptr, servptr, family, socktype, proto, flags, interface, err); 1201 return _gai_sort_list(out, flags); 1202 } 1203 1204 /* fall back to a default path */ 1205 out = _gai_simple(si, nodeptr, servptr, family, socktype, proto, flags, interface, err); 1206 return _gai_sort_list(out, flags); 1207} 1208 1209static struct addrinfo * 1210si_item_to_addrinfo(si_item_t *item) 1211{ 1212 si_addrinfo_t *a; 1213 struct addrinfo *out; 1214 1215 if (item == NULL) return NULL; 1216 1217 a = (si_addrinfo_t *)((uintptr_t)item + sizeof(si_item_t)); 1218 1219 out = (struct addrinfo *)calloc(1, sizeof(struct addrinfo)); 1220 if (out == NULL) return NULL; 1221 1222 out->ai_flags = a->ai_flags; 1223 out->ai_family = a->ai_family; 1224 out->ai_socktype = a->ai_socktype; 1225 out->ai_protocol = a->ai_protocol; 1226 out->ai_addrlen = a->ai_addrlen; 1227 1228 out->ai_addr = (struct sockaddr *)calloc(1, out->ai_addrlen); 1229 if (out->ai_addr == NULL) 1230 { 1231 free(out); 1232 return NULL; 1233 } 1234 1235 memcpy(out->ai_addr, a->ai_addr.x, out->ai_addrlen); 1236 1237 if (a->ai_canonname != NULL) 1238 { 1239 out->ai_canonname = strdup(a->ai_canonname); 1240 if (out->ai_canonname == NULL) 1241 { 1242 free(out); 1243 return NULL; 1244 } 1245 } 1246 1247 return out; 1248} 1249 1250struct addrinfo * 1251si_list_to_addrinfo(si_list_t *list) 1252{ 1253 struct addrinfo *tail, *out; 1254 int i; 1255 1256 if (list == NULL) return NULL; 1257 if (list->count == 0) return NULL; 1258 1259 i = list->count - 1; 1260 1261 out = si_item_to_addrinfo(list->entry[i]); 1262 tail = out; 1263 1264 for (i--; i >= 0; i--) 1265 { 1266 out = si_item_to_addrinfo(list->entry[i]); 1267 if (out == NULL) 1268 { 1269 freeaddrinfo(tail); 1270 return NULL; 1271 } 1272 1273 out->ai_next = tail; 1274 tail = out; 1275 } 1276 1277 return out; 1278} 1279 1280/* getipnodebyname */ 1281 1282static si_item_t * 1283make_hostent(si_mod_t *si, const char *name, struct in_addr addr) 1284{ 1285 char *addrs[2]; 1286 char *aliases[1]; 1287 uint64_t unused; 1288 1289 if (name == NULL) return NULL; 1290 1291 unused = 0; 1292 1293 addrs[0] = (char *)&(addr.s_addr); 1294 addrs[1] = NULL; 1295 aliases[0] = NULL; 1296 1297 return (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, unused, unused, name, aliases, AF_INET, IPV4_ADDR_LEN, addrs); 1298} 1299 1300static si_item_t * 1301make_hostent6(si_mod_t *si, const char *name, struct in6_addr addr) 1302{ 1303 char *addrs[2]; 1304 char *aliases[1]; 1305 uint64_t unused; 1306 1307 if (name == NULL) return NULL; 1308 1309 unused = 0; 1310 1311 addrs[0] = (char *)&(addr.__u6_addr.__u6_addr32[0]); 1312 addrs[1] = NULL; 1313 aliases[0] = NULL; 1314 1315 return (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, name, aliases, AF_INET6, IPV6_ADDR_LEN, addrs); 1316} 1317 1318static char * 1319lower_case(const char *s) 1320{ 1321 int i; 1322 char *t; 1323 1324 if (s == NULL) return NULL; 1325 1326 t = malloc(strlen(s) + 1); 1327 1328 for (i = 0; s[i] != '\0'; i++) 1329 { 1330 if ((s[i] >= 'A') && (s[i] <= 'Z')) t[i] = s[i] + 32; 1331 else t[i] = s[i]; 1332 } 1333 1334 t[i] = '\0'; 1335 1336 return t; 1337} 1338 1339static int 1340merge_alias(const char *name, build_hostent_t *h) 1341{ 1342 int i; 1343 1344 if (name == NULL) return 0; 1345 if (h == NULL) return 0; 1346 1347 if ((h->host.h_name != NULL) && (string_equal(name, h->host.h_name))) return 0; 1348 1349 for (i = 0; i < h->alias_count; i++) 1350 { 1351 if (string_equal(name, h->host.h_aliases[i])) return 0; 1352 } 1353 1354 if (h->alias_count == 0) h->host.h_aliases = (char **)calloc(2, sizeof(char *)); 1355 else h->host.h_aliases = (char **)reallocf(h->host.h_aliases, (h->alias_count + 2) * sizeof(char *)); 1356 1357 if (h->host.h_aliases == NULL) 1358 { 1359 h->alias_count = 0; 1360 return -1; 1361 } 1362 1363 h->host.h_aliases[h->alias_count] = lower_case(name); 1364 h->alias_count++; 1365 h->host.h_aliases[h->alias_count] = NULL; 1366 1367 return 0; 1368} 1369 1370static int 1371append_addr(const char *addr, uint32_t len, build_hostent_t *h) 1372{ 1373 if (addr == NULL) return 0; 1374 if (h == NULL) return 0; 1375 1376 if (h->addr_count == 0) h->host.h_addr_list = (char **)calloc(2, sizeof(char *)); 1377 else h->host.h_addr_list = (char **)reallocf(h->host.h_addr_list, (h->addr_count + 2) * sizeof(char *)); 1378 1379 if (h->host.h_addr_list == NULL) 1380 { 1381 h->addr_count = 0; 1382 return -1; 1383 } 1384 1385 h->host.h_addr_list[h->addr_count] = malloc(len); 1386 if (h->host.h_addr_list[h->addr_count] == NULL) return -1; 1387 1388 memcpy(h->host.h_addr_list[h->addr_count], addr, len); 1389 h->addr_count++; 1390 h->host.h_addr_list[h->addr_count] = NULL; 1391 1392 return 0; 1393} 1394 1395static void 1396free_build_hostent(build_hostent_t *h) 1397{ 1398 uint32_t i; 1399 char **aliases; 1400 1401 if (h == NULL) return; 1402 1403 if (h->host.h_name != NULL) free(h->host.h_name); 1404 h->host.h_name = NULL; 1405 1406 aliases = h->host.h_aliases; 1407 if (aliases != NULL) 1408 { 1409 while (*aliases != NULL) free(*aliases++); 1410 free(h->host.h_aliases); 1411 } 1412 1413 h->host.h_aliases = NULL; 1414 1415 if (h->host.h_addr_list != NULL) 1416 { 1417 for (i = 0; h->host.h_addr_list[i] != NULL; i++) free(h->host.h_addr_list[i]); 1418 free(h->host.h_addr_list); 1419 } 1420 1421 h->host.h_addr_list = NULL; 1422 free(h); 1423} 1424 1425si_item_t * 1426si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const char *interface, uint32_t *err) 1427{ 1428 int i, status, want; 1429 uint32_t if4, if6; 1430 struct in_addr addr4; 1431 struct in6_addr addr6; 1432 si_item_t *item4, *item6; 1433 build_hostent_t *out; 1434 struct hostent *h; 1435 uint64_t unused; 1436 1437 memset(&addr4, 0, sizeof(struct in_addr)); 1438 memset(&addr6, 0, sizeof(struct in6_addr)); 1439 1440 if (err != NULL) *err = 0; 1441 1442 if (family == AF_INET) 1443 { 1444 status = inet_aton(name, &addr4); 1445 if (status == 1) 1446 { 1447 /* create a host entry */ 1448 item4 = make_hostent(si, name, addr4); 1449 if (item4 == NULL) 1450 { 1451 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1452 return NULL; 1453 } 1454 1455 return item4; 1456 } 1457 } 1458 else if (family == AF_INET6) 1459 { 1460 status = inet_pton(family, name, &addr6); 1461 if (status == 1) 1462 { 1463 /* create a host entry */ 1464 item6 = make_hostent6(si, name, addr6); 1465 if (item6 == NULL) 1466 { 1467 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1468 return NULL; 1469 } 1470 1471 return item6; 1472 } 1473 1474 status = inet_aton(name, &addr4); 1475 if (status == 1) 1476 { 1477 if (!(flags & (AI_V4MAPPED | AI_V4MAPPED_CFG))) 1478 { 1479 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; 1480 return NULL; 1481 } 1482 1483 addr6.__u6_addr.__u6_addr32[0] = 0x00000000; 1484 addr6.__u6_addr.__u6_addr32[1] = 0x00000000; 1485 addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff); 1486 memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr4.s_addr), IPV4_ADDR_LEN); 1487 1488 /* create a host entry */ 1489 item6 = make_hostent6(si, name, addr6); 1490 if (item6 == NULL) 1491 { 1492 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1493 return NULL; 1494 } 1495 1496 return item6; 1497 } 1498 } 1499 else 1500 { 1501 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1502 return NULL; 1503 } 1504 1505 /* 1506 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have. 1507 */ 1508 1509 if4 = 0; 1510 if6 = 0; 1511 1512 if (flags & AI_ADDRCONFIG) 1513 { 1514 if (si_inet_config(&if4, &if6) < 0) 1515 { 1516 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1517 return NULL; 1518 } 1519 1520 /* Bail out if there are no interfaces */ 1521 if ((if4 == 0) && (if6 == 0)) 1522 { 1523 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1524 return NULL; 1525 } 1526 } 1527 1528 /* 1529 * Figure out what we want. 1530 * If user asked for AF_INET, we only want V4 addresses. 1531 */ 1532 want = WANT_A4_ONLY; 1533 1534 if (family == AF_INET) 1535 { 1536 if ((flags & AI_ADDRCONFIG) && (if4 == 0)) 1537 { 1538 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1539 return NULL; 1540 } 1541 } 1542 else if (family == AF_INET6) 1543 { 1544 /* family == AF_INET6 */ 1545 want = WANT_A6_ONLY; 1546 1547 if (flags & (AI_V4MAPPED | AI_V4MAPPED_CFG)) 1548 { 1549 if (flags & AI_ALL) 1550 { 1551 want = WANT_A6_PLUS_MAPPED_A4; 1552 } 1553 else 1554 { 1555 want = WANT_A6_OR_MAPPED_A4_IF_NO_A6; 1556 } 1557 } 1558 else 1559 { 1560 if ((flags & AI_ADDRCONFIG) && (if6 == 0)) 1561 { 1562 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1563 return NULL; 1564 } 1565 } 1566 } 1567 else 1568 { 1569 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1570 return NULL; 1571 } 1572 1573 item6 = NULL; 1574 item4 = NULL; 1575 1576 /* fetch IPv6 data if required */ 1577 if ((want == WANT_A6_ONLY) || (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) || (want == WANT_A6_PLUS_MAPPED_A4)) 1578 { 1579 item6 = si_host_byname(si, name, AF_INET6, interface, (uint32_t *)err); 1580 } 1581 1582 /* fetch IPv4 data if required */ 1583 if ((want == WANT_A4_ONLY) || (want == WANT_A6_PLUS_MAPPED_A4) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (item6 == NULL))) 1584 { 1585 item4 = si_host_byname(si, name, AF_INET, interface, (uint32_t *)err); 1586 } 1587 1588 if (want == WANT_A4_ONLY) 1589 { 1590 si_item_release(item6); 1591 if ((item4 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; 1592 return item4; 1593 } 1594 1595 if (want == WANT_A6_ONLY) 1596 { 1597 si_item_release(item4); 1598 if ((item6 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; 1599 return item6; 1600 } 1601 1602 if ((item6 == NULL) && (item4 == NULL)) 1603 { 1604 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; 1605 return NULL; 1606 } 1607 1608 /* output item will have IPv6 + mapped IPv4 addresses */ 1609 1610 out = (build_hostent_t *)calloc(1, sizeof(build_hostent_t)); 1611 if (out == NULL) 1612 { 1613 si_item_release(item4); 1614 si_item_release(item6); 1615 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 1616 return NULL; 1617 } 1618 1619 if (item4 != NULL) 1620 { 1621 h = (struct hostent *)((uintptr_t)item4 + sizeof(si_item_t)); 1622 1623 out->host.h_name = lower_case(h->h_name); 1624 1625 if (h->h_aliases != NULL) 1626 { 1627 for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out); 1628 } 1629 1630 for (i = 0; h->h_addr_list[i] != 0; i++) 1631 { 1632 addr6.__u6_addr.__u6_addr32[0] = 0x00000000; 1633 addr6.__u6_addr.__u6_addr32[1] = 0x00000000; 1634 addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff); 1635 memmove(&(addr6.__u6_addr.__u6_addr32[3]), h->h_addr_list[i], IPV4_ADDR_LEN); 1636 append_addr((const char *)&addr6, IPV6_ADDR_LEN, out); 1637 } 1638 } 1639 1640 if (item6 != NULL) 1641 { 1642 h = (struct hostent *)((uintptr_t)item6 + sizeof(si_item_t)); 1643 1644 if (out->host.h_name == NULL) out->host.h_name = lower_case(h->h_name); 1645 1646 if (h->h_aliases != NULL) 1647 { 1648 for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out); 1649 } 1650 1651 for (i = 0; h->h_addr_list[i] != 0; i++) append_addr(h->h_addr_list[i], IPV6_ADDR_LEN, out); 1652 } 1653 1654 si_item_release(item4); 1655 si_item_release(item6); 1656 1657 unused = 0; 1658 1659 item6 = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, out->host.h_name, out->host.h_aliases, AF_INET6, IPV6_ADDR_LEN, out->host.h_addr_list); 1660 1661 free_build_hostent(out); 1662 1663 return item6; 1664} 1665