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 uint_t i; 213 214 /* 215 * We currently accumulate three services in the 216 * SOCKTYPE_ANY/AI_NUMERICSERV case and one otherwise. If the logic in 217 * this function is extended to return all matches from the services 218 * database when AI_NUMERICSERV is not specified, this will need 219 * revisiting. 220 */ 221 #define SPINFO_SIZE 3 222 spinfo_t spinfo[SPINFO_SIZE]; 223 uint_t spidx = 0; 224 /* Note that these macros require spinfo and spidx to be in scope */ 225 #define SP_ADDX(type, proto, port) \ 226 do { \ 227 ASSERT3U(spidx, <, SPINFO_SIZE); \ 228 spinfo[spidx].si_socktype = (type); \ 229 spinfo[spidx].si_protocol = (proto); \ 230 spinfo[spidx].si_port = (port); \ 231 spidx++; \ 232 } while (0) 233 #define SP_ADD(sp) \ 234 do { \ 235 int _type, _proto; \ 236 servtype((sp)->s_proto, &_type, &_proto); \ 237 SP_ADDX(_type, _proto, (sp)->s_port); \ 238 } while (0) 239 240 *res = NULL; 241 242 if (hostname == NULL && servname == NULL) 243 return (EAI_NONAME); 244 245 cur = &ai; 246 aip = &ai; 247 248 if (hints == NULL) { 249 aip->ai_flags = 0; 250 aip->ai_family = PF_UNSPEC; 251 aip->ai_socktype = ANY; 252 aip->ai_protocol = ANY; 253 } else { 254 (void) memcpy(aip, hints, sizeof (*aip)); 255 256 /* check for bad flags in hints */ 257 if (hints->ai_flags != 0 && (hints->ai_flags & ~AI_MASK)) 258 return (EAI_BADFLAGS); 259 260 if ((hostname == NULL || *hostname == '\0') && 261 (hints->ai_flags & AI_CANONNAME)) { 262 return (EAI_BADFLAGS); 263 } 264 265 if (hints->ai_family != PF_UNSPEC && 266 hints->ai_family != PF_INET && 267 hints->ai_family != PF_INET6) { 268 return (EAI_FAMILY); 269 } 270 271 switch (aip->ai_socktype) { 272 case ANY: 273 switch (aip->ai_protocol) { 274 case ANY: 275 break; 276 case IPPROTO_UDP: 277 aip->ai_socktype = SOCK_DGRAM; 278 break; 279 case IPPROTO_TCP: 280 case IPPROTO_SCTP: 281 aip->ai_socktype = SOCK_STREAM; 282 break; 283 default: 284 aip->ai_socktype = SOCK_RAW; 285 break; 286 } 287 break; 288 case SOCK_RAW: 289 break; 290 case SOCK_SEQPACKET: 291 /* 292 * If the hint does not have a preference on the 293 * protocol, use SCTP as the default for 294 * SOCK_SEQPACKET. 295 */ 296 if (aip->ai_protocol == ANY) 297 aip->ai_protocol = IPPROTO_SCTP; 298 break; 299 case SOCK_DGRAM: 300 aip->ai_protocol = IPPROTO_UDP; 301 break; 302 case SOCK_STREAM: 303 /* 304 * If the hint does not have a preference on the 305 * protocol, use TCP as the default for SOCK_STREAM. 306 */ 307 if (aip->ai_protocol == ANY) 308 aip->ai_protocol = IPPROTO_TCP; 309 break; 310 default: 311 return (EAI_SOCKTYPE); 312 } 313 } 314 315 aip->ai_addrlen = 0; 316 aip->ai_canonname = NULL; 317 aip->ai_addr = NULL; 318 aip->ai_next = NULL; 319 #ifdef __sparcv9 320 /* 321 * We need to clear _ai_pad to preserve binary compatibility with 322 * previously compiled 64-bit applications by guaranteeing the upper 323 * 32-bits are empty. 324 */ 325 aip->_ai_pad = 0; 326 #endif /* __sparcv9 */ 327 328 /* 329 * Get the service. 330 */ 331 332 if (servname != NULL) { 333 struct servent result; 334 int bufsize = 128; 335 char *buf = NULL; 336 struct servent *sp; 337 const char *proto = NULL; 338 339 switch (aip->ai_socktype) { 340 case ANY: 341 case SOCK_RAW: 342 proto = NULL; 343 break; 344 case SOCK_DGRAM: 345 proto = "udp"; 346 break; 347 case SOCK_STREAM: 348 /* 349 * If there is no hint given, use TCP as the default 350 * protocol. 351 */ 352 switch (aip->ai_protocol) { 353 case ANY: 354 case IPPROTO_TCP: 355 default: 356 proto = "tcp"; 357 break; 358 case IPPROTO_SCTP: 359 proto = "sctp"; 360 break; 361 } 362 break; 363 case SOCK_SEQPACKET: 364 /* Default to SCTP if no hint given. */ 365 switch (aip->ai_protocol) { 366 case ANY: 367 default: 368 proto = "sctp"; 369 break; 370 } 371 break; 372 } 373 /* 374 * Servname string can be a decimal port number. 375 */ 376 if (str_isnumber(servname)) { 377 ushort_t port = htons(atoi(servname)); 378 379 if (aip->ai_socktype == ANY) { 380 /* 381 * The socket type is not known so we return 382 * one result for each of these types. 383 */ 384 SP_ADDX(SOCK_STREAM, IPPROTO_TCP, port); 385 SP_ADDX(SOCK_DGRAM, IPPROTO_UDP, port); 386 SP_ADDX(SOCK_STREAM, IPPROTO_SCTP, port); 387 } else { 388 /* 389 * If we know the socket type then we can 390 * return it. 391 */ 392 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 393 port); 394 } 395 } else if (aip->ai_flags & AI_NUMERICSERV) { 396 /* 397 * The AI_NUMERICSERV flag was specified, but the 398 * servname is not a decimal number so we fail. 399 */ 400 return (EAI_NONAME); 401 } else { 402 /* 403 * Look up the provided service name in the service 404 * database. 405 */ 406 do { 407 buf = reallocf(buf, bufsize); 408 if (buf == NULL) 409 return (EAI_MEMORY); 410 411 sp = getservbyname_r(servname, proto, &result, 412 buf, bufsize); 413 if (sp == NULL && errno != ERANGE) { 414 free(buf); 415 return (EAI_SERVICE); 416 } 417 /* 418 * errno == ERANGE so our scratch buffer space 419 * wasn't big enough. Double it and try again. 420 */ 421 bufsize *= 2; 422 } while (sp == NULL); 423 if (aip->ai_socktype != ANY) { 424 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 425 sp->s_port); 426 } else { 427 SP_ADD(sp); 428 } 429 } 430 free(buf); 431 432 if (spidx == 0) 433 return (EAI_SERVICE); 434 } else { 435 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 0); 436 } 437 438 error = get_addr(aip->ai_family, hostname, aip, cur, 439 spinfo, spidx, version); 440 441 if (error != 0) { 442 if (aip->ai_next != NULL) 443 freeaddrinfo(aip->ai_next); 444 return (error); 445 } 446 447 *res = aip->ai_next; 448 return (0); 449 } 450 #undef SP_ADD 451 #undef SP_ADDX 452 453 int 454 getaddrinfo(const char *hostname, const char *servname, 455 const struct addrinfo *hints, struct addrinfo **res) 456 { 457 return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT)); 458 } 459 460 int 461 __xnet_getaddrinfo(const char *hostname, const char *servname, 462 const struct addrinfo *hints, struct addrinfo **res) 463 { 464 return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6)); 465 } 466 467 static int 468 add_address4(struct addrinfo *aip, struct addrinfo **cur, 469 struct in_addr *addr, const char *canonname, spinfo_t *info) 470 { 471 struct addrinfo *nai; 472 int addrlen; 473 474 nai = malloc(sizeof (struct addrinfo)); 475 if (nai == NULL) 476 return (EAI_MEMORY); 477 478 *nai = *aip; 479 nai->ai_next = NULL; 480 addrlen = sizeof (struct sockaddr_in); 481 482 nai->ai_addr = malloc(addrlen); 483 if (nai->ai_addr == NULL) { 484 freeaddrinfo(nai); 485 return (EAI_MEMORY); 486 } 487 488 bzero(nai->ai_addr, addrlen); 489 nai->ai_addrlen = addrlen; 490 nai->ai_family = PF_INET; 491 492 (void) memcpy(&ai2sin(nai)->sin_addr, addr, sizeof (struct in_addr)); 493 nai->ai_canonname = NULL; 494 if ((nai->ai_flags & AI_CANONNAME) && canonname != NULL) { 495 canonname = strdup(canonname); 496 if (canonname == NULL) { 497 freeaddrinfo(nai); 498 return (EAI_MEMORY); 499 } 500 nai->ai_canonname = (char *)canonname; 501 } 502 ai2sin(nai)->sin_family = PF_INET; 503 ai2sin(nai)->sin_port = info->si_port; 504 nai->ai_socktype = info->si_socktype; 505 nai->ai_protocol = info->si_protocol; 506 507 (*cur)->ai_next = nai; 508 *cur = nai; 509 510 return (0); 511 } 512 513 static int 514 add_address6(struct addrinfo *aip, struct addrinfo **cur, 515 struct in6_addr *addr, const char *zonestr, const char *canonname, 516 spinfo_t *info) 517 { 518 struct addrinfo *nai; 519 int addrlen; 520 521 nai = malloc(sizeof (struct addrinfo)); 522 if (nai == NULL) 523 return (EAI_MEMORY); 524 525 *nai = *aip; 526 nai->ai_next = NULL; 527 addrlen = sizeof (struct sockaddr_in6); 528 529 nai->ai_addr = malloc(addrlen); 530 if (nai->ai_addr == NULL) { 531 freeaddrinfo(nai); 532 return (EAI_MEMORY); 533 } 534 535 bzero(nai->ai_addr, addrlen); 536 nai->ai_addrlen = addrlen; 537 nai->ai_family = PF_INET6; 538 539 (void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr, 540 &addr->s6_addr, sizeof (struct in6_addr)); 541 nai->ai_canonname = NULL; 542 if ((nai->ai_flags & AI_CANONNAME) && canonname != NULL) { 543 canonname = strdup(canonname); 544 if (canonname == NULL) { 545 freeaddrinfo(nai); 546 return (EAI_MEMORY); 547 } 548 nai->ai_canonname = (char *)canonname; 549 } 550 ai2sin6(nai)->sin6_family = PF_INET6; 551 ai2sin6(nai)->sin6_port = info->si_port; 552 nai->ai_socktype = info->si_socktype; 553 nai->ai_protocol = info->si_protocol; 554 555 /* set sin6_scope_id */ 556 if (zonestr != NULL) { 557 /* Translate 'zonestr' into a valid sin6_scope_id. */ 558 int err = getscopeidfromzone(ai2sin6(nai), zonestr, 559 &ai2sin6(nai)->sin6_scope_id); 560 if (err != 0) { 561 freeaddrinfo(nai); 562 return (err); 563 } 564 } else { 565 ai2sin6(nai)->sin6_scope_id = 0; 566 } 567 568 (*cur)->ai_next = nai; 569 *cur = nai; 570 571 return (0); 572 } 573 574 static int 575 get_addr(int family, const char *hostname, struct addrinfo *aip, 576 struct addrinfo *cur, spinfo_t *ports, uint_t nport, int version) 577 { 578 struct hostent *hp; 579 char _hostname[MAXHOSTNAMELEN]; 580 int errnum; 581 boolean_t firsttime = B_TRUE; 582 char *zonestr = NULL; 583 uint_t i; 584 585 if (hostname == NULL) { 586 /* 587 * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or :: 588 * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1 589 */ 590 const char *canon = "loopback"; 591 errnum = 0; 592 593 /* 594 * PF_INET gets IPv4 only, PF_INET6 gets IPv6 only. 595 * PF_UNSPEC gets both. 596 */ 597 if (family != PF_INET) { 598 struct in6_addr v6addr; 599 600 if (aip->ai_flags & AI_PASSIVE) { 601 (void) memcpy(&v6addr.s6_addr, 602 in6addr_any.s6_addr, 603 sizeof (struct in6_addr)); 604 canon = NULL; 605 } else { 606 (void) memcpy(&v6addr.s6_addr, 607 in6addr_loopback.s6_addr, 608 sizeof (struct in6_addr)); 609 } 610 611 for (i = 0; i < nport; i++) { 612 errnum = add_address6(aip, &cur, &v6addr, NULL, 613 canon, &ports[i]); 614 canon = NULL; 615 if (errnum != 0) 616 break; 617 } 618 } 619 620 if (errnum == 0 && family != PF_INET6) { 621 struct in_addr addr; 622 623 if (aip->ai_flags & AI_PASSIVE) { 624 addr.s_addr = INADDR_ANY; 625 canon = NULL; 626 } else { 627 addr.s_addr = htonl(INADDR_LOOPBACK); 628 } 629 630 for (i = 0; i < nport; i++) { 631 errnum = add_address4(aip, &cur, &addr, canon, 632 &ports[i]); 633 canon = NULL; 634 if (errnum != 0) 635 break; 636 } 637 } 638 639 return (errnum); 640 } 641 642 /* 643 * Check for existence of address-zoneid delimiter '%' 644 * If the delimiter exists, parse the zoneid portion of 645 * <addr>%<zone_id> 646 */ 647 if ((zonestr = strchr(hostname, '%')) != NULL) { 648 /* make sure we have room for <addr> portion of hostname */ 649 if ((zonestr - hostname) + 1 > sizeof (_hostname)) 650 return (EAI_MEMORY); 651 652 /* chop off and save <zone_id> portion */ 653 (void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1); 654 ++zonestr; /* make zonestr point at start of <zone-id> */ 655 /* ensure zone is valid */ 656 if (*zonestr == '\0' || strlen(zonestr) > LIFNAMSIZ) 657 return (EAI_NONAME); 658 } else { 659 size_t hlen = sizeof (_hostname); 660 661 if (strlcpy(_hostname, hostname, hlen) >= hlen) 662 return (EAI_MEMORY); 663 } 664 665 /* Check to see if AI_NUMERICHOST bit is set */ 666 if (aip->ai_flags & AI_NUMERICHOST) { 667 struct in6_addr v6addr; 668 669 /* check to see if _hostname points to a literal IP address */ 670 if (!(inet_addr(_hostname) != ((in_addr_t)-1) || 671 strcmp(_hostname, HOST_BROADCAST) == 0 || 672 inet_pton(AF_INET6, _hostname, &v6addr) > 0)) { 673 return (EAI_NONAME); 674 } 675 } 676 677 /* if hostname argument is literal, name service doesn't get called */ 678 if (family == PF_UNSPEC) { 679 hp = getipnodebyname(_hostname, AF_INET6, 680 AI_ALL | aip->ai_flags | AI_V4MAPPED | AI_ADDRINFO, 681 &errnum); 682 } else { 683 hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum); 684 } 685 686 if (hp == NULL) { 687 switch (errnum) { 688 case HOST_NOT_FOUND: 689 return (EAI_NONAME); 690 case TRY_AGAIN: 691 return (EAI_AGAIN); 692 case NO_RECOVERY: 693 return (EAI_FAIL); 694 case NO_ADDRESS: 695 if (version == GAIV_XPG6) 696 return (EAI_NONAME); 697 return (EAI_NODATA); 698 default: 699 return (EAI_SYSTEM); 700 } 701 } 702 703 for (i = 0; hp->h_addr_list[i]; i++) { 704 boolean_t create_v6_addrinfo = B_TRUE; 705 struct in_addr v4addr; 706 struct in6_addr v6addr; 707 uint_t j; 708 709 /* Determine if an IPv6 addrinfo structure should be created */ 710 if (hp->h_addrtype == AF_INET6) { 711 struct in6_addr *v6addrp; 712 713 v6addrp = (struct in6_addr *)hp->h_addr_list[i]; 714 if (!(aip->ai_flags & AI_V4MAPPED) && 715 IN6_IS_ADDR_V4MAPPED(v6addrp)) { 716 create_v6_addrinfo = B_FALSE; 717 IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr); 718 } else { 719 (void) memcpy(&v6addr.s6_addr, 720 hp->h_addr_list[i], 721 sizeof (struct in6_addr)); 722 } 723 } else if (hp->h_addrtype == AF_INET) { 724 create_v6_addrinfo = B_FALSE; 725 (void) memcpy(&v4addr.s_addr, hp->h_addr_list[i], 726 sizeof (struct in_addr)); 727 } else { 728 return (EAI_SYSTEM); 729 } 730 731 for (j = 0; j < nport; j++) { 732 if (create_v6_addrinfo) { 733 errnum = add_address6(aip, &cur, &v6addr, 734 zonestr, firsttime ? hp->h_name : NULL, 735 &ports[j]); 736 } else { 737 errnum = add_address4(aip, &cur, &v4addr, 738 firsttime ? hp->h_name : NULL, 739 &ports[j]); 740 } 741 firsttime = B_FALSE; 742 if (errnum != 0) { 743 freehostent(hp); 744 return (errnum); 745 } 746 } 747 } 748 freehostent(hp); 749 return (0); 750 } 751 752 /* 753 * getscopeidfromzone(sa, zone, sin6_scope_id) 754 * 755 * Converts the string pointed to by 'zone' into a sin6_scope_id. 756 * 'zone' will either be a pointer to an interface name or will 757 * be a literal sin6_scope_id. 758 * 759 * 0 is returned on success and the output parameter 'sin6_scope_id' will 760 * be set to a valid sin6_scope_id. 761 * EAI_NONAME is returned for either of two reasons: 762 * 1. The IPv6 address pointed to by sa->sin6_addr is not 763 * part of the 'link scope' (ie link local, nodelocal multicast or 764 * linklocal multicast address) 765 * 2. The string pointed to by 'zone' can not be translate to a valid 766 * sin6_scope_id. 767 */ 768 static uint_t 769 getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone, 770 uint32_t *sin6_scope_id) 771 { 772 const in6_addr_t *addr = &sa->sin6_addr; 773 ulong_t ul_scope_id; 774 char *endp; 775 776 if (IN6_IS_ADDR_LINKSCOPE(addr)) { 777 /* 778 * Look up interface index associated with interface name 779 * pointed to by 'zone'. Since the address is part of the link 780 * scope, there is a one-to-one relationship between interface 781 * index and sin6_scope_id. 782 * If an interface index can not be found for 'zone', then 783 * treat 'zone' as a literal sin6_scope_id value. 784 */ 785 if ((*sin6_scope_id = if_nametoindex(zone)) != 0) { 786 return (0); 787 } else { 788 if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) { 789 /* check that entire string was read */ 790 if (*endp != '\0') { 791 return (EAI_NONAME); 792 } 793 *sin6_scope_id = 794 (uint32_t)(ul_scope_id & 0xffffffffUL); 795 } else { 796 return (EAI_NONAME); 797 } 798 } 799 } else { 800 return (EAI_NONAME); 801 } 802 return (0); 803 } 804 805 void 806 freeaddrinfo(struct addrinfo *ai) 807 { 808 struct addrinfo *next; 809 810 do { 811 next = ai->ai_next; 812 free(ai->ai_canonname); 813 free(ai->ai_addr); 814 free(ai); 815 ai = next; 816 } while (ai != NULL); 817 } 818 819 static void 820 servtype(const char *tag, int *type, int *proto) 821 { 822 *type = *proto = 0; 823 if (strcmp(tag, "udp") == 0) { 824 *type = SOCK_DGRAM; 825 *proto = IPPROTO_UDP; 826 } else if (strcmp(tag, "tcp") == 0) { 827 *type = SOCK_STREAM; 828 *proto = IPPROTO_TCP; 829 } else if (strcmp(tag, "sctp") == 0) { 830 *type = SOCK_STREAM; 831 *proto = IPPROTO_SCTP; 832 } 833 } 834 835 static boolean_t 836 str_isnumber(const char *p) 837 { 838 char *q = (char *)p; 839 while (*q != '\0') { 840 if (!isdigit(*q)) 841 return (B_FALSE); 842 q++; 843 } 844 return (B_TRUE); 845 } 846 847 static const char *gai_errlist[] = { 848 "name translation error 0 (no error)", /* 0 */ 849 "specified address family not supported", /* 1 EAI_ADDRFAMILY */ 850 "temporary name resolution failure", /* 2 EAI_AGAIN */ 851 "invalid flags", /* 3 EAI_BADFLAGS */ 852 "non-recoverable name resolution failure", /* 4 EAI_FAIL */ 853 "specified address family not supported", /* 5 EAI_FAMILY */ 854 "memory allocation failure", /* 6 EAI_MEMORY */ 855 "no address for the specified node name", /* 7 EAI_NODATA */ 856 "node name or service name not known", /* 8 EAI_NONAME */ 857 "service name not available for the specified socket type", 858 /* 9 EAI_SERVICE */ 859 "specified socket type not supported", /* 10 EAI_SOCKTYPE */ 860 "system error", /* 11 EAI_SYSTEM */ 861 }; 862 static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) }; 863 864 const char * 865 gai_strerror(int ecode) 866 { 867 if (ecode < 0) 868 return (dgettext(TEXT_DOMAIN, 869 "name translation internal error")); 870 else if (ecode < gai_nerr) 871 return (dgettext(TEXT_DOMAIN, gai_errlist[ecode])); 872 return (dgettext(TEXT_DOMAIN, "unknown name translation error")); 873 } 874