1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2023 Oxide Computer Company 29 */ 30 31 #include <netdb.h> 32 #include <arpa/inet.h> 33 #include <nss_dbdefs.h> 34 #include <netinet/in.h> 35 #include <sys/debug.h> 36 #include <sys/socket.h> 37 #include <string.h> 38 #include <strings.h> 39 #include <stdio.h> 40 #include <ctype.h> 41 #include <sys/types.h> 42 #include <stdlib.h> 43 #include <libintl.h> 44 #include <net/if.h> 45 46 #define ai2sin(x) ((struct sockaddr_in *)((x)->ai_addr)) 47 #define ai2sin6(x) ((struct sockaddr_in6 *)((x)->ai_addr)) 48 49 #define HOST_BROADCAST "255.255.255.255" 50 51 /* 52 * getaddrinfo() returns EAI_NONAME in some cases, however since EAI_NONAME is 53 * not part of SUSv3 it needed to be masked in the standards compliant 54 * environment. GAIV_DEFAULT and GAIV_XPG6 accomplish this. 55 */ 56 #define GAIV_DEFAULT 0 57 #define GAIV_XPG6 1 58 59 /* 60 * Storage allocation for global variables in6addr_any and in6addr_loopback. 61 * The extern declarations for these variables are defined in <netinet/in.h>. 62 * These two variables could have been defined in any of the "C" files in 63 * libsocket. They are defined here with other IPv6 related interfaces. 64 */ 65 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 66 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 67 68 /* AI_MASK: all valid flags for addrinfo */ 69 #define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST \ 70 | AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL) 71 #define ANY 0 72 73 /* 74 * This is a private, undocumented, flag that getaddrinfo() uses for 75 * getipnodebyname(). In the case of AI_ADDRCONFIG && AI_V4MAPPED, if there are 76 * no IPv6 addresses, getaddrinfo() should return non-IPv4 mapped addresses. On 77 * the flip side, getipnodebyname() is defined by RFC 2553 to explicitly do so. 78 * Therefore this private flag indicates to getaddrinfo that we shouldn't do 79 * this. 80 */ 81 #define AI_ADDRINFO 0x8000 82 83 typedef struct { 84 int si_socktype; 85 int si_protocol; 86 ushort_t si_port; 87 } spinfo_t; 88 89 /* function prototypes for used by getaddrinfo() routine */ 90 static int get_addr(int, const char *, struct addrinfo *, 91 struct addrinfo *, spinfo_t *, uint_t, int); 92 static uint_t getscopeidfromzone(const struct sockaddr_in6 *, 93 const char *, uint32_t *); 94 static void servtype(const char *, int *, int *); 95 static boolean_t str_isnumber(const char *); 96 97 /* 98 * getaddrinfo: 99 * 100 * Purpose: 101 * Routine for performing Address-to-nodename in a protocol-independent 102 * fashion. 103 * Description and history of the routine: 104 * Nodename-to-address translation is done in a protocol- independent fashion 105 * using the getaddrinfo() function that is taken from IEEE POSIX 1003.1g. 106 * 107 * The official specification for this function will be the final POSIX 108 * standard, with the following additional requirements: 109 * 110 * - getaddrinfo() must be thread safe 111 * - The AI_NUMERICHOST is new. 112 * - All fields in socket address structures returned by getaddrinfo() that 113 * are not filled in through an explicit argument (e.g., sin6_flowinfo and 114 * sin_zero) must be set to 0. (This makes it easier to compare socket 115 * address structures). 116 * 117 * Input Parameters: 118 * 119 * nodename - pointer to a null-terminated string that represents 120 * a hostname or literal ip address (IPv4/IPv6), or this 121 * pointer can be NULL. 122 * servname - pointer to a null-terminated string that represents 123 * a servicename or literal port number, or this 124 * pointer can be NULL. 125 * hints - optional argument that points to an addrinfo structure 126 * to provide hints on the type of socket that the caller 127 * supports. 128 * 129 * Possible setting of the ai_flags member of the hints structure: 130 * 131 * AI_PASSIVE - If set, the caller plans to use the returned socket 132 * address in a call to bind(). In this case, it the 133 * nodename argument is NULL, then the IP address portion 134 * of the socket address structure will be set to 135 * INADDR_ANY for IPv4 or IN6ADDR_ANY_INIT for IPv6. 136 * If not set, then the returned socket address will be 137 * ready for a call to connect() (for conn-oriented) or 138 * connect(), sendto(), or sendmsg() (for connectionless). 139 * In this case, if nodename is NULL, then the IP address 140 * portion of the socket address structure will be set to 141 * the loopback address. 142 * AI_CANONNAME - If set, then upon successful return the ai_canonname 143 * field of the first addrinfo structure in the linked 144 * list will point to a NULL-terminated string 145 * containing the canonical name of the specified nodename. 146 * AI_NUMERICHOST - If set, then a non-NULL nodename string must be a numeric 147 * host address string. Otherwise an error of EAI_NONAME 148 * is returned. This flag prevents any type of name 149 * resolution service from being called. 150 * AI_NUMERICSERV - If set, then a non-null servname string supplied shall 151 * be a numeric port string. Otherwise, an [EAI_NONAME] 152 * error shall be returned. This flag shall prevent any 153 * type of name resolution service from being invoked. 154 * AI_ADDRCONFIG - If set, IPv4 addresses are returned only if an IPv4 155 * address is configured on the local system, and IPv6 156 * addresses are returned only if an IPv6 address is 157 * configured on the local system. 158 * AI_V4MAPPED - If set, along with an ai_family of AF_INET6, then 159 * getaddrinfo() shall return IPv4-mapped IPv6 addresses 160 * on finding no matching IPv6 addresses (ai_addrlen shall 161 * be 16). The AI_V4MAPPED flag shall be ignored unless 162 * ai_family equals AF_INET6. 163 * AI_ALL - If the AI_ALL flag is used with the AI_V4MAPPED flag, 164 * then getaddrinfo() shall return all matching IPv6 and 165 * IPv4 addresses. The AI_ALL flag without the AI_V4MAPPED 166 * flag is ignored. 167 * 168 * Output Parameters: 169 * 170 * res - upon successful return a pointer to a linked list of one 171 * or more addrinfo structures is returned through this 172 * argument. The caller can process each addrinfo structures 173 * in this list by following the ai_next pointer, until a 174 * NULL pointer is encountered. In each returned addrinfo 175 * structure the three members ai_family, ai_socktype, and 176 * ai_protocol are corresponding arguments for a call to the 177 * socket() function. In each addrinfo structure the ai_addr 178 * field points to filled-in socket address structure whose 179 * length is specified by the ai_addrlen member. 180 * 181 * Return Value: 182 * This function returns 0 upon success or a nonzero error code. The 183 * following names are nonzero error codes from getaddrinfo(), and are 184 * defined in <netdb.h>. 185 * EAI_ADDRFAMILY - address family not supported 186 * EAI_AGAIN - DNS temporary failure 187 * EAI_BADFLAGS - invalid ai_flags 188 * EAI_FAIL - DNS non-recoverable failure 189 * EAI_FAMILY - ai_family not supported 190 * EAI_MEMORY - memory allocation failure 191 * EAI_NODATA - no address associated with nodename 192 * EAI_NONAME - host/servname not known 193 * EAI_SERVICE - servname not supported for ai_socktype 194 * EAI_SOCKTYPE - ai_socktype not supported 195 * EAI_SYSTEM - system error in errno 196 * 197 * Memory Allocation: 198 * All of the information returned by getaddrinfo() is dynamically 199 * allocated: the addrinfo structures, and the socket address 200 * structures and canonical node name strings pointed to by the 201 * addrinfo structures. 202 */ 203 204 static int 205 _getaddrinfo(const char *hostname, const char *servname, 206 const struct addrinfo *hints, struct addrinfo **res, int version) 207 { 208 struct addrinfo *cur; 209 struct addrinfo *aip; 210 struct addrinfo ai; 211 int error; 212 213 /* 214 * We currently accumulate three services in the 215 * SOCKTYPE_ANY/AI_NUMERICSERV case and one otherwise. If the logic in 216 * this function is extended to return all matches from the services 217 * database when AI_NUMERICSERV is not specified, this will need 218 * revisiting. 219 */ 220 #define SPINFO_SIZE 3 221 spinfo_t spinfo[SPINFO_SIZE]; 222 uint_t spidx = 0; 223 /* Note that these macros require spinfo and spidx to be in scope */ 224 #define SP_ADDX(type, proto, port) \ 225 do { \ 226 ASSERT3U(spidx, <, SPINFO_SIZE); \ 227 spinfo[spidx].si_socktype = (type); \ 228 spinfo[spidx].si_protocol = (proto); \ 229 spinfo[spidx].si_port = (port); \ 230 spidx++; \ 231 } while (0) 232 #define SP_ADD(sp) \ 233 do { \ 234 int _type, _proto; \ 235 servtype((sp)->s_proto, &_type, &_proto); \ 236 SP_ADDX(_type, _proto, (sp)->s_port); \ 237 } while (0) 238 239 *res = NULL; 240 241 if (hostname == NULL && servname == NULL) 242 return (EAI_NONAME); 243 244 cur = &ai; 245 aip = &ai; 246 247 if (hints == NULL) { 248 aip->ai_flags = 0; 249 aip->ai_family = PF_UNSPEC; 250 aip->ai_socktype = ANY; 251 aip->ai_protocol = ANY; 252 } else { 253 (void) memcpy(aip, hints, sizeof (*aip)); 254 255 /* check for bad flags in hints */ 256 if (hints->ai_flags != 0 && (hints->ai_flags & ~AI_MASK)) 257 return (EAI_BADFLAGS); 258 259 if ((hostname == NULL || *hostname == '\0') && 260 (hints->ai_flags & AI_CANONNAME)) { 261 return (EAI_BADFLAGS); 262 } 263 264 if (hints->ai_family != PF_UNSPEC && 265 hints->ai_family != PF_INET && 266 hints->ai_family != PF_INET6) { 267 return (EAI_FAMILY); 268 } 269 270 switch (aip->ai_socktype) { 271 case ANY: 272 switch (aip->ai_protocol) { 273 case ANY: 274 break; 275 case IPPROTO_UDP: 276 aip->ai_socktype = SOCK_DGRAM; 277 break; 278 case IPPROTO_TCP: 279 case IPPROTO_SCTP: 280 aip->ai_socktype = SOCK_STREAM; 281 break; 282 default: 283 aip->ai_socktype = SOCK_RAW; 284 break; 285 } 286 break; 287 case SOCK_RAW: 288 break; 289 case SOCK_SEQPACKET: 290 /* 291 * If the hint does not have a preference on the 292 * protocol, use SCTP as the default for 293 * SOCK_SEQPACKET. 294 */ 295 if (aip->ai_protocol == ANY) 296 aip->ai_protocol = IPPROTO_SCTP; 297 break; 298 case SOCK_DGRAM: 299 aip->ai_protocol = IPPROTO_UDP; 300 break; 301 case SOCK_STREAM: 302 /* 303 * If the hint does not have a preference on the 304 * protocol, use TCP as the default for SOCK_STREAM. 305 */ 306 if (aip->ai_protocol == ANY) 307 aip->ai_protocol = IPPROTO_TCP; 308 break; 309 default: 310 return (EAI_SOCKTYPE); 311 } 312 } 313 314 aip->ai_addrlen = 0; 315 aip->ai_canonname = NULL; 316 aip->ai_addr = NULL; 317 aip->ai_next = NULL; 318 #ifdef __sparcv9 319 /* 320 * We need to clear _ai_pad to preserve binary compatibility with 321 * previously compiled 64-bit applications by guaranteeing the upper 322 * 32-bits are empty. 323 */ 324 aip->_ai_pad = 0; 325 #endif /* __sparcv9 */ 326 327 /* 328 * Get the service. 329 */ 330 331 if (servname != NULL) { 332 struct servent result; 333 int bufsize = 128; 334 char *buf = NULL; 335 struct servent *sp; 336 const char *proto = NULL; 337 338 switch (aip->ai_socktype) { 339 case ANY: 340 case SOCK_RAW: 341 proto = NULL; 342 break; 343 case SOCK_DGRAM: 344 proto = "udp"; 345 break; 346 case SOCK_STREAM: 347 /* 348 * If there is no hint given, use TCP as the default 349 * protocol. 350 */ 351 switch (aip->ai_protocol) { 352 case ANY: 353 case IPPROTO_TCP: 354 default: 355 proto = "tcp"; 356 break; 357 case IPPROTO_SCTP: 358 proto = "sctp"; 359 break; 360 } 361 break; 362 case SOCK_SEQPACKET: 363 /* Default to SCTP if no hint given. */ 364 switch (aip->ai_protocol) { 365 case ANY: 366 default: 367 proto = "sctp"; 368 break; 369 } 370 break; 371 } 372 /* 373 * Servname string can be a decimal port number. 374 */ 375 if (str_isnumber(servname)) { 376 ushort_t port = htons(atoi(servname)); 377 378 if (aip->ai_socktype == ANY) { 379 /* 380 * The socket type is not known so we return 381 * one result for each of these types. 382 */ 383 SP_ADDX(SOCK_STREAM, IPPROTO_TCP, port); 384 SP_ADDX(SOCK_DGRAM, IPPROTO_UDP, port); 385 SP_ADDX(SOCK_STREAM, IPPROTO_SCTP, port); 386 } else { 387 /* 388 * If we know the socket type then we can 389 * return it. 390 */ 391 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 392 port); 393 } 394 } else if (aip->ai_flags & AI_NUMERICSERV) { 395 /* 396 * The AI_NUMERICSERV flag was specified, but the 397 * servname is not a decimal number so we fail. 398 */ 399 return (EAI_NONAME); 400 } else { 401 /* 402 * Look up the provided service name in the service 403 * database. 404 */ 405 do { 406 buf = reallocf(buf, bufsize); 407 if (buf == NULL) 408 return (EAI_MEMORY); 409 410 sp = getservbyname_r(servname, proto, &result, 411 buf, bufsize); 412 if (sp == NULL && errno != ERANGE) { 413 free(buf); 414 return (EAI_SERVICE); 415 } 416 /* 417 * errno == ERANGE so our scratch buffer space 418 * wasn't big enough. Double it and try again. 419 */ 420 bufsize *= 2; 421 } while (sp == NULL); 422 if (aip->ai_socktype != ANY) { 423 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 424 sp->s_port); 425 } else { 426 SP_ADD(sp); 427 } 428 } 429 free(buf); 430 431 if (spidx == 0) 432 return (EAI_SERVICE); 433 } else { 434 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 0); 435 } 436 437 error = get_addr(aip->ai_family, hostname, aip, cur, 438 spinfo, spidx, version); 439 440 if (error != 0) { 441 if (aip->ai_next != NULL) 442 freeaddrinfo(aip->ai_next); 443 return (error); 444 } 445 446 *res = aip->ai_next; 447 return (0); 448 } 449 #undef SP_ADD 450 #undef SP_ADDX 451 452 int 453 getaddrinfo(const char *hostname, const char *servname, 454 const struct addrinfo *hints, struct addrinfo **res) 455 { 456 return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT)); 457 } 458 459 int 460 __xnet_getaddrinfo(const char *hostname, const char *servname, 461 const struct addrinfo *hints, struct addrinfo **res) 462 { 463 return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6)); 464 } 465 466 static int 467 add_address4(struct addrinfo *aip, struct addrinfo **cur, 468 struct in_addr *addr, const char *canonname, spinfo_t *info) 469 { 470 struct addrinfo *nai; 471 int addrlen; 472 473 nai = malloc(sizeof (struct addrinfo)); 474 if (nai == NULL) 475 return (EAI_MEMORY); 476 477 *nai = *aip; 478 nai->ai_next = NULL; 479 addrlen = sizeof (struct sockaddr_in); 480 481 nai->ai_addr = malloc(addrlen); 482 if (nai->ai_addr == NULL) { 483 freeaddrinfo(nai); 484 return (EAI_MEMORY); 485 } 486 487 bzero(nai->ai_addr, addrlen); 488 nai->ai_addrlen = addrlen; 489 nai->ai_family = PF_INET; 490 491 (void) memcpy(&ai2sin(nai)->sin_addr, addr, sizeof (struct in_addr)); 492 nai->ai_canonname = NULL; 493 if ((nai->ai_flags & AI_CANONNAME) && canonname != NULL) { 494 canonname = strdup(canonname); 495 if (canonname == NULL) { 496 freeaddrinfo(nai); 497 return (EAI_MEMORY); 498 } 499 nai->ai_canonname = (char *)canonname; 500 } 501 ai2sin(nai)->sin_family = PF_INET; 502 ai2sin(nai)->sin_port = info->si_port; 503 nai->ai_socktype = info->si_socktype; 504 nai->ai_protocol = info->si_protocol; 505 506 (*cur)->ai_next = nai; 507 *cur = nai; 508 509 return (0); 510 } 511 512 static int 513 add_address6(struct addrinfo *aip, struct addrinfo **cur, 514 struct in6_addr *addr, const char *zonestr, const char *canonname, 515 spinfo_t *info) 516 { 517 struct addrinfo *nai; 518 int addrlen; 519 520 nai = malloc(sizeof (struct addrinfo)); 521 if (nai == NULL) 522 return (EAI_MEMORY); 523 524 *nai = *aip; 525 nai->ai_next = NULL; 526 addrlen = sizeof (struct sockaddr_in6); 527 528 nai->ai_addr = malloc(addrlen); 529 if (nai->ai_addr == NULL) { 530 freeaddrinfo(nai); 531 return (EAI_MEMORY); 532 } 533 534 bzero(nai->ai_addr, addrlen); 535 nai->ai_addrlen = addrlen; 536 nai->ai_family = PF_INET6; 537 538 (void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr, 539 &addr->s6_addr, sizeof (struct in6_addr)); 540 nai->ai_canonname = NULL; 541 if ((nai->ai_flags & AI_CANONNAME) && canonname != NULL) { 542 canonname = strdup(canonname); 543 if (canonname == NULL) { 544 freeaddrinfo(nai); 545 return (EAI_MEMORY); 546 } 547 nai->ai_canonname = (char *)canonname; 548 } 549 ai2sin6(nai)->sin6_family = PF_INET6; 550 ai2sin6(nai)->sin6_port = info->si_port; 551 nai->ai_socktype = info->si_socktype; 552 nai->ai_protocol = info->si_protocol; 553 554 /* set sin6_scope_id */ 555 if (zonestr != NULL) { 556 /* Translate 'zonestr' into a valid sin6_scope_id. */ 557 int err = getscopeidfromzone(ai2sin6(nai), zonestr, 558 &ai2sin6(nai)->sin6_scope_id); 559 if (err != 0) { 560 freeaddrinfo(nai); 561 return (err); 562 } 563 } else { 564 ai2sin6(nai)->sin6_scope_id = 0; 565 } 566 567 (*cur)->ai_next = nai; 568 *cur = nai; 569 570 return (0); 571 } 572 573 static int 574 get_addr(int family, const char *hostname, struct addrinfo *aip, 575 struct addrinfo *cur, spinfo_t *ports, uint_t nport, int version) 576 { 577 struct hostent *hp; 578 char _hostname[MAXHOSTNAMELEN]; 579 int errnum; 580 boolean_t firsttime = B_TRUE; 581 char *zonestr = NULL; 582 uint_t i; 583 584 if (hostname == NULL) { 585 /* 586 * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or :: 587 * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1 588 */ 589 const char *canon = "loopback"; 590 errnum = 0; 591 592 /* 593 * PF_INET gets IPv4 only, PF_INET6 gets IPv6 only. 594 * PF_UNSPEC gets both. 595 */ 596 if (family != PF_INET) { 597 struct in6_addr v6addr; 598 599 if (aip->ai_flags & AI_PASSIVE) { 600 (void) memcpy(&v6addr.s6_addr, 601 in6addr_any.s6_addr, 602 sizeof (struct in6_addr)); 603 canon = NULL; 604 } else { 605 (void) memcpy(&v6addr.s6_addr, 606 in6addr_loopback.s6_addr, 607 sizeof (struct in6_addr)); 608 } 609 610 for (i = 0; i < nport; i++) { 611 errnum = add_address6(aip, &cur, &v6addr, NULL, 612 canon, &ports[i]); 613 canon = NULL; 614 if (errnum != 0) 615 break; 616 } 617 } 618 619 if (errnum == 0 && family != PF_INET6) { 620 struct in_addr addr; 621 622 if (aip->ai_flags & AI_PASSIVE) { 623 addr.s_addr = INADDR_ANY; 624 canon = NULL; 625 } else { 626 addr.s_addr = htonl(INADDR_LOOPBACK); 627 } 628 629 for (i = 0; i < nport; i++) { 630 errnum = add_address4(aip, &cur, &addr, canon, 631 &ports[i]); 632 canon = NULL; 633 if (errnum != 0) 634 break; 635 } 636 } 637 638 return (errnum); 639 } 640 641 /* 642 * Check for existence of address-zoneid delimiter '%' 643 * If the delimiter exists, parse the zoneid portion of 644 * <addr>%<zone_id> 645 */ 646 if ((zonestr = strchr(hostname, '%')) != NULL) { 647 /* make sure we have room for <addr> portion of hostname */ 648 if ((zonestr - hostname) + 1 > sizeof (_hostname)) 649 return (EAI_MEMORY); 650 651 /* chop off and save <zone_id> portion */ 652 (void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1); 653 ++zonestr; /* make zonestr point at start of <zone-id> */ 654 /* ensure zone is valid */ 655 if (*zonestr == '\0' || strlen(zonestr) > LIFNAMSIZ) 656 return (EAI_NONAME); 657 } else { 658 size_t hlen = sizeof (_hostname); 659 660 if (strlcpy(_hostname, hostname, hlen) >= hlen) 661 return (EAI_MEMORY); 662 } 663 664 /* Check to see if AI_NUMERICHOST bit is set */ 665 if (aip->ai_flags & AI_NUMERICHOST) { 666 struct in6_addr v6addr; 667 668 /* check to see if _hostname points to a literal IP address */ 669 if (!(inet_addr(_hostname) != ((in_addr_t)-1) || 670 strcmp(_hostname, HOST_BROADCAST) == 0 || 671 inet_pton(AF_INET6, _hostname, &v6addr) > 0)) { 672 return (EAI_NONAME); 673 } 674 } 675 676 /* if hostname argument is literal, name service doesn't get called */ 677 if (family == PF_UNSPEC) { 678 hp = getipnodebyname(_hostname, AF_INET6, 679 AI_ALL | aip->ai_flags | AI_V4MAPPED | AI_ADDRINFO, 680 &errnum); 681 } else { 682 hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum); 683 } 684 685 if (hp == NULL) { 686 switch (errnum) { 687 case HOST_NOT_FOUND: 688 return (EAI_NONAME); 689 case TRY_AGAIN: 690 return (EAI_AGAIN); 691 case NO_RECOVERY: 692 return (EAI_FAIL); 693 case NO_ADDRESS: 694 if (version == GAIV_XPG6) 695 return (EAI_NONAME); 696 return (EAI_NODATA); 697 default: 698 return (EAI_SYSTEM); 699 } 700 } 701 702 for (i = 0; hp->h_addr_list[i]; i++) { 703 boolean_t create_v6_addrinfo = B_TRUE; 704 struct in_addr v4addr; 705 struct in6_addr v6addr; 706 uint_t j; 707 708 /* Determine if an IPv6 addrinfo structure should be created */ 709 if (hp->h_addrtype == AF_INET6) { 710 struct in6_addr *v6addrp; 711 712 v6addrp = (struct in6_addr *)hp->h_addr_list[i]; 713 if (!(aip->ai_flags & AI_V4MAPPED) && 714 IN6_IS_ADDR_V4MAPPED(v6addrp)) { 715 create_v6_addrinfo = B_FALSE; 716 IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr); 717 } else { 718 (void) memcpy(&v6addr.s6_addr, 719 hp->h_addr_list[i], 720 sizeof (struct in6_addr)); 721 } 722 } else if (hp->h_addrtype == AF_INET) { 723 create_v6_addrinfo = B_FALSE; 724 (void) memcpy(&v4addr.s_addr, hp->h_addr_list[i], 725 sizeof (struct in_addr)); 726 } else { 727 return (EAI_SYSTEM); 728 } 729 730 for (j = 0; j < nport; j++) { 731 if (create_v6_addrinfo) { 732 errnum = add_address6(aip, &cur, &v6addr, 733 zonestr, firsttime ? hp->h_name : NULL, 734 &ports[j]); 735 } else { 736 errnum = add_address4(aip, &cur, &v4addr, 737 firsttime ? hp->h_name : NULL, 738 &ports[j]); 739 } 740 firsttime = B_FALSE; 741 if (errnum != 0) { 742 freehostent(hp); 743 return (errnum); 744 } 745 } 746 } 747 freehostent(hp); 748 return (0); 749 } 750 751 /* 752 * getscopeidfromzone(sa, zone, sin6_scope_id) 753 * 754 * Converts the string pointed to by 'zone' into a sin6_scope_id. 755 * 'zone' will either be a pointer to an interface name or will 756 * be a literal sin6_scope_id. 757 * 758 * 0 is returned on success and the output parameter 'sin6_scope_id' will 759 * be set to a valid sin6_scope_id. 760 * EAI_NONAME is returned for either of two reasons: 761 * 1. The IPv6 address pointed to by sa->sin6_addr is not 762 * part of the 'link scope' (ie link local, nodelocal multicast or 763 * linklocal multicast address) 764 * 2. The string pointed to by 'zone' can not be translate to a valid 765 * sin6_scope_id. 766 */ 767 static uint_t 768 getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone, 769 uint32_t *sin6_scope_id) 770 { 771 const in6_addr_t *addr = &sa->sin6_addr; 772 ulong_t ul_scope_id; 773 char *endp; 774 775 if (IN6_IS_ADDR_LINKSCOPE(addr)) { 776 /* 777 * Look up interface index associated with interface name 778 * pointed to by 'zone'. Since the address is part of the link 779 * scope, there is a one-to-one relationship between interface 780 * index and sin6_scope_id. 781 * If an interface index can not be found for 'zone', then 782 * treat 'zone' as a literal sin6_scope_id value. 783 */ 784 if ((*sin6_scope_id = if_nametoindex(zone)) != 0) { 785 return (0); 786 } else { 787 if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) { 788 /* check that entire string was read */ 789 if (*endp != '\0') { 790 return (EAI_NONAME); 791 } 792 *sin6_scope_id = 793 (uint32_t)(ul_scope_id & 0xffffffffUL); 794 } else { 795 return (EAI_NONAME); 796 } 797 } 798 } else { 799 return (EAI_NONAME); 800 } 801 return (0); 802 } 803 804 void 805 freeaddrinfo(struct addrinfo *ai) 806 { 807 struct addrinfo *next; 808 809 do { 810 next = ai->ai_next; 811 free(ai->ai_canonname); 812 free(ai->ai_addr); 813 free(ai); 814 ai = next; 815 } while (ai != NULL); 816 } 817 818 static void 819 servtype(const char *tag, int *type, int *proto) 820 { 821 *type = *proto = 0; 822 if (strcmp(tag, "udp") == 0) { 823 *type = SOCK_DGRAM; 824 *proto = IPPROTO_UDP; 825 } else if (strcmp(tag, "tcp") == 0) { 826 *type = SOCK_STREAM; 827 *proto = IPPROTO_TCP; 828 } else if (strcmp(tag, "sctp") == 0) { 829 *type = SOCK_STREAM; 830 *proto = IPPROTO_SCTP; 831 } 832 } 833 834 static boolean_t 835 str_isnumber(const char *p) 836 { 837 char *q = (char *)p; 838 while (*q != '\0') { 839 if (!isdigit(*q)) 840 return (B_FALSE); 841 q++; 842 } 843 return (B_TRUE); 844 } 845 846 static const char *gai_errlist[] = { 847 "name translation error 0 (no error)", /* 0 */ 848 "specified address family not supported", /* 1 EAI_ADDRFAMILY */ 849 "temporary name resolution failure", /* 2 EAI_AGAIN */ 850 "invalid flags", /* 3 EAI_BADFLAGS */ 851 "non-recoverable name resolution failure", /* 4 EAI_FAIL */ 852 "specified address family not supported", /* 5 EAI_FAMILY */ 853 "memory allocation failure", /* 6 EAI_MEMORY */ 854 "no address for the specified node name", /* 7 EAI_NODATA */ 855 "node name or service name not known", /* 8 EAI_NONAME */ 856 "service name not available for the specified socket type", 857 /* 9 EAI_SERVICE */ 858 "specified socket type not supported", /* 10 EAI_SOCKTYPE */ 859 "system error", /* 11 EAI_SYSTEM */ 860 }; 861 static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) }; 862 863 const char * 864 gai_strerror(int ecode) 865 { 866 if (ecode < 0) 867 return (dgettext(TEXT_DOMAIN, 868 "name translation internal error")); 869 else if (ecode < gai_nerr) 870 return (dgettext(TEXT_DOMAIN, gai_errlist[ecode])); 871 return (dgettext(TEXT_DOMAIN, "unknown name translation error")); 872 } 873