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 (aip->ai_flags & AI_NUMERICSERV) { 377 ushort_t port; 378 379 if (!str_isnumber(servname)) 380 return (EAI_NONAME); 381 382 port = htons(atoi(servname)); 383 if (aip->ai_socktype == ANY) { 384 /* 385 * We cannot perform any name service lookups 386 * here, per RFC3493, and so we return one 387 * result for each of these types. 388 */ 389 SP_ADDX(SOCK_STREAM, IPPROTO_TCP, port); 390 SP_ADDX(SOCK_DGRAM, IPPROTO_UDP, port); 391 SP_ADDX(SOCK_STREAM, IPPROTO_SCTP, port); 392 } else { 393 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 394 port); 395 } 396 } else if (str_isnumber(servname)) { 397 ushort_t port = htons(atoi(servname)); 398 399 if (aip->ai_socktype != ANY) { 400 /* 401 * If we already know the socket type there is 402 * no need to call getservbyport. 403 */ 404 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 405 port); 406 } else { 407 do { 408 buf = reallocf(buf, bufsize); 409 if (buf == NULL) 410 return (EAI_MEMORY); 411 412 sp = getservbyport_r(port, proto, 413 &result, buf, bufsize); 414 if (sp == NULL && errno != ERANGE) { 415 free(buf); 416 return (EAI_SERVICE); 417 } 418 /* 419 * errno == ERANGE so our scratch 420 * buffer space wasn't big enough. 421 * Double it and try again. 422 */ 423 bufsize *= 2; 424 } while (sp == NULL); 425 SP_ADD(sp); 426 } 427 } else { 428 /* 429 * Look up the provided service name in the service 430 * database. 431 */ 432 do { 433 buf = reallocf(buf, bufsize); 434 if (buf == NULL) 435 return (EAI_MEMORY); 436 437 sp = getservbyname_r(servname, proto, &result, 438 buf, bufsize); 439 if (sp == NULL && errno != ERANGE) { 440 free(buf); 441 return (EAI_SERVICE); 442 } 443 /* 444 * errno == ERANGE so our scratch buffer space 445 * wasn't big enough. Double it and try again. 446 */ 447 bufsize *= 2; 448 } while (sp == NULL); 449 if (aip->ai_socktype != ANY) { 450 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 451 sp->s_port); 452 } else { 453 SP_ADD(sp); 454 } 455 } 456 free(buf); 457 458 if (spidx == 0) 459 return (EAI_SERVICE); 460 } else { 461 SP_ADDX(aip->ai_socktype, aip->ai_protocol, 0); 462 } 463 464 error = get_addr(aip->ai_family, hostname, aip, cur, 465 spinfo, spidx, version); 466 467 if (error != 0) { 468 if (aip->ai_next != NULL) 469 freeaddrinfo(aip->ai_next); 470 return (error); 471 } 472 473 *res = aip->ai_next; 474 return (0); 475 } 476 #undef SP_ADD 477 #undef SP_ADDX 478 479 int 480 getaddrinfo(const char *hostname, const char *servname, 481 const struct addrinfo *hints, struct addrinfo **res) 482 { 483 return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT)); 484 } 485 486 int 487 __xnet_getaddrinfo(const char *hostname, const char *servname, 488 const struct addrinfo *hints, struct addrinfo **res) 489 { 490 return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6)); 491 } 492 493 static int 494 add_address4(struct addrinfo *aip, struct addrinfo **cur, 495 struct in_addr *addr, const char *canonname, spinfo_t *info) 496 { 497 struct addrinfo *nai; 498 int addrlen; 499 500 nai = malloc(sizeof (struct addrinfo)); 501 if (nai == NULL) 502 return (EAI_MEMORY); 503 504 *nai = *aip; 505 nai->ai_next = NULL; 506 addrlen = sizeof (struct sockaddr_in); 507 508 nai->ai_addr = malloc(addrlen); 509 if (nai->ai_addr == NULL) { 510 freeaddrinfo(nai); 511 return (EAI_MEMORY); 512 } 513 514 bzero(nai->ai_addr, addrlen); 515 nai->ai_addrlen = addrlen; 516 nai->ai_family = PF_INET; 517 518 (void) memcpy(&ai2sin(nai)->sin_addr, addr, sizeof (struct in_addr)); 519 nai->ai_canonname = NULL; 520 if ((nai->ai_flags & AI_CANONNAME) && canonname != NULL) { 521 canonname = strdup(canonname); 522 if (canonname == NULL) { 523 freeaddrinfo(nai); 524 return (EAI_MEMORY); 525 } 526 nai->ai_canonname = (char *)canonname; 527 } 528 ai2sin(nai)->sin_family = PF_INET; 529 ai2sin(nai)->sin_port = info->si_port; 530 nai->ai_socktype = info->si_socktype; 531 nai->ai_protocol = info->si_protocol; 532 533 (*cur)->ai_next = nai; 534 *cur = nai; 535 536 return (0); 537 } 538 539 static int 540 add_address6(struct addrinfo *aip, struct addrinfo **cur, 541 struct in6_addr *addr, const char *zonestr, const char *canonname, 542 spinfo_t *info) 543 { 544 struct addrinfo *nai; 545 int addrlen; 546 547 nai = malloc(sizeof (struct addrinfo)); 548 if (nai == NULL) 549 return (EAI_MEMORY); 550 551 *nai = *aip; 552 nai->ai_next = NULL; 553 addrlen = sizeof (struct sockaddr_in6); 554 555 nai->ai_addr = malloc(addrlen); 556 if (nai->ai_addr == NULL) { 557 freeaddrinfo(nai); 558 return (EAI_MEMORY); 559 } 560 561 bzero(nai->ai_addr, addrlen); 562 nai->ai_addrlen = addrlen; 563 nai->ai_family = PF_INET6; 564 565 (void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr, 566 &addr->s6_addr, sizeof (struct in6_addr)); 567 nai->ai_canonname = NULL; 568 if ((nai->ai_flags & AI_CANONNAME) && canonname != NULL) { 569 canonname = strdup(canonname); 570 if (canonname == NULL) { 571 freeaddrinfo(nai); 572 return (EAI_MEMORY); 573 } 574 nai->ai_canonname = (char *)canonname; 575 } 576 ai2sin6(nai)->sin6_family = PF_INET6; 577 ai2sin6(nai)->sin6_port = info->si_port; 578 nai->ai_socktype = info->si_socktype; 579 nai->ai_protocol = info->si_protocol; 580 581 /* set sin6_scope_id */ 582 if (zonestr != NULL) { 583 /* Translate 'zonestr' into a valid sin6_scope_id. */ 584 int err = getscopeidfromzone(ai2sin6(nai), zonestr, 585 &ai2sin6(nai)->sin6_scope_id); 586 if (err != 0) { 587 freeaddrinfo(nai); 588 return (err); 589 } 590 } else { 591 ai2sin6(nai)->sin6_scope_id = 0; 592 } 593 594 (*cur)->ai_next = nai; 595 *cur = nai; 596 597 return (0); 598 } 599 600 static int 601 get_addr(int family, const char *hostname, struct addrinfo *aip, 602 struct addrinfo *cur, spinfo_t *ports, uint_t nport, int version) 603 { 604 struct hostent *hp; 605 char _hostname[MAXHOSTNAMELEN]; 606 int errnum; 607 boolean_t firsttime = B_TRUE; 608 char *zonestr = NULL; 609 uint_t i; 610 611 if (hostname == NULL) { 612 /* 613 * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or :: 614 * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1 615 */ 616 const char *canon = "loopback"; 617 errnum = 0; 618 619 /* 620 * PF_INET gets IPv4 only, PF_INET6 gets IPv6 only. 621 * PF_UNSPEC gets both. 622 */ 623 if (family != PF_INET) { 624 struct in6_addr v6addr; 625 626 if (aip->ai_flags & AI_PASSIVE) { 627 (void) memcpy(&v6addr.s6_addr, 628 in6addr_any.s6_addr, 629 sizeof (struct in6_addr)); 630 canon = NULL; 631 } else { 632 (void) memcpy(&v6addr.s6_addr, 633 in6addr_loopback.s6_addr, 634 sizeof (struct in6_addr)); 635 } 636 637 for (i = 0; i < nport; i++) { 638 errnum = add_address6(aip, &cur, &v6addr, NULL, 639 canon, &ports[i]); 640 canon = NULL; 641 if (errnum != 0) 642 break; 643 } 644 } 645 646 if (errnum == 0 && family != PF_INET6) { 647 struct in_addr addr; 648 649 if (aip->ai_flags & AI_PASSIVE) { 650 addr.s_addr = INADDR_ANY; 651 canon = NULL; 652 } else { 653 addr.s_addr = htonl(INADDR_LOOPBACK); 654 } 655 656 for (i = 0; i < nport; i++) { 657 errnum = add_address4(aip, &cur, &addr, canon, 658 &ports[i]); 659 canon = NULL; 660 if (errnum != 0) 661 break; 662 } 663 } 664 665 return (errnum); 666 } 667 668 /* 669 * Check for existence of address-zoneid delimiter '%' 670 * If the delimiter exists, parse the zoneid portion of 671 * <addr>%<zone_id> 672 */ 673 if ((zonestr = strchr(hostname, '%')) != NULL) { 674 /* make sure we have room for <addr> portion of hostname */ 675 if ((zonestr - hostname) + 1 > sizeof (_hostname)) 676 return (EAI_MEMORY); 677 678 /* chop off and save <zone_id> portion */ 679 (void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1); 680 ++zonestr; /* make zonestr point at start of <zone-id> */ 681 /* ensure zone is valid */ 682 if (*zonestr == '\0' || strlen(zonestr) > LIFNAMSIZ) 683 return (EAI_NONAME); 684 } else { 685 size_t hlen = sizeof (_hostname); 686 687 if (strlcpy(_hostname, hostname, hlen) >= hlen) 688 return (EAI_MEMORY); 689 } 690 691 /* Check to see if AI_NUMERICHOST bit is set */ 692 if (aip->ai_flags & AI_NUMERICHOST) { 693 struct in6_addr v6addr; 694 695 /* check to see if _hostname points to a literal IP address */ 696 if (!(inet_addr(_hostname) != ((in_addr_t)-1) || 697 strcmp(_hostname, HOST_BROADCAST) == 0 || 698 inet_pton(AF_INET6, _hostname, &v6addr) > 0)) { 699 return (EAI_NONAME); 700 } 701 } 702 703 /* if hostname argument is literal, name service doesn't get called */ 704 if (family == PF_UNSPEC) { 705 hp = getipnodebyname(_hostname, AF_INET6, 706 AI_ALL | aip->ai_flags | AI_V4MAPPED | AI_ADDRINFO, 707 &errnum); 708 } else { 709 hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum); 710 } 711 712 if (hp == NULL) { 713 switch (errnum) { 714 case HOST_NOT_FOUND: 715 return (EAI_NONAME); 716 case TRY_AGAIN: 717 return (EAI_AGAIN); 718 case NO_RECOVERY: 719 return (EAI_FAIL); 720 case NO_ADDRESS: 721 if (version == GAIV_XPG6) 722 return (EAI_NONAME); 723 return (EAI_NODATA); 724 default: 725 return (EAI_SYSTEM); 726 } 727 } 728 729 for (i = 0; hp->h_addr_list[i]; i++) { 730 boolean_t create_v6_addrinfo = B_TRUE; 731 struct in_addr v4addr; 732 struct in6_addr v6addr; 733 uint_t j; 734 735 /* Determine if an IPv6 addrinfo structure should be created */ 736 if (hp->h_addrtype == AF_INET6) { 737 struct in6_addr *v6addrp; 738 739 v6addrp = (struct in6_addr *)hp->h_addr_list[i]; 740 if (!(aip->ai_flags & AI_V4MAPPED) && 741 IN6_IS_ADDR_V4MAPPED(v6addrp)) { 742 create_v6_addrinfo = B_FALSE; 743 IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr); 744 } else { 745 (void) memcpy(&v6addr.s6_addr, 746 hp->h_addr_list[i], 747 sizeof (struct in6_addr)); 748 } 749 } else if (hp->h_addrtype == AF_INET) { 750 create_v6_addrinfo = B_FALSE; 751 (void) memcpy(&v4addr.s_addr, hp->h_addr_list[i], 752 sizeof (struct in_addr)); 753 } else { 754 return (EAI_SYSTEM); 755 } 756 757 for (j = 0; j < nport; j++) { 758 if (create_v6_addrinfo) { 759 errnum = add_address6(aip, &cur, &v6addr, 760 zonestr, firsttime ? hp->h_name : NULL, 761 &ports[j]); 762 } else { 763 errnum = add_address4(aip, &cur, &v4addr, 764 firsttime ? hp->h_name : NULL, 765 &ports[j]); 766 } 767 firsttime = B_FALSE; 768 if (errnum != 0) { 769 freehostent(hp); 770 return (errnum); 771 } 772 } 773 } 774 freehostent(hp); 775 return (0); 776 } 777 778 /* 779 * getscopeidfromzone(sa, zone, sin6_scope_id) 780 * 781 * Converts the string pointed to by 'zone' into a sin6_scope_id. 782 * 'zone' will either be a pointer to an interface name or will 783 * be a literal sin6_scope_id. 784 * 785 * 0 is returned on success and the output parameter 'sin6_scope_id' will 786 * be set to a valid sin6_scope_id. 787 * EAI_NONAME is returned for either of two reasons: 788 * 1. The IPv6 address pointed to by sa->sin6_addr is not 789 * part of the 'link scope' (ie link local, nodelocal multicast or 790 * linklocal multicast address) 791 * 2. The string pointed to by 'zone' can not be translate to a valid 792 * sin6_scope_id. 793 */ 794 static uint_t 795 getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone, 796 uint32_t *sin6_scope_id) 797 { 798 const in6_addr_t *addr = &sa->sin6_addr; 799 ulong_t ul_scope_id; 800 char *endp; 801 802 if (IN6_IS_ADDR_LINKSCOPE(addr)) { 803 /* 804 * Look up interface index associated with interface name 805 * pointed to by 'zone'. Since the address is part of the link 806 * scope, there is a one-to-one relationship between interface 807 * index and sin6_scope_id. 808 * If an interface index can not be found for 'zone', then 809 * treat 'zone' as a literal sin6_scope_id value. 810 */ 811 if ((*sin6_scope_id = if_nametoindex(zone)) != 0) { 812 return (0); 813 } else { 814 if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) { 815 /* check that entire string was read */ 816 if (*endp != '\0') { 817 return (EAI_NONAME); 818 } 819 *sin6_scope_id = 820 (uint32_t)(ul_scope_id & 0xffffffffUL); 821 } else { 822 return (EAI_NONAME); 823 } 824 } 825 } else { 826 return (EAI_NONAME); 827 } 828 return (0); 829 } 830 831 void 832 freeaddrinfo(struct addrinfo *ai) 833 { 834 struct addrinfo *next; 835 836 do { 837 next = ai->ai_next; 838 free(ai->ai_canonname); 839 free(ai->ai_addr); 840 free(ai); 841 ai = next; 842 } while (ai != NULL); 843 } 844 845 static void 846 servtype(const char *tag, int *type, int *proto) 847 { 848 *type = *proto = 0; 849 if (strcmp(tag, "udp") == 0) { 850 *type = SOCK_DGRAM; 851 *proto = IPPROTO_UDP; 852 } else if (strcmp(tag, "tcp") == 0) { 853 *type = SOCK_STREAM; 854 *proto = IPPROTO_TCP; 855 } else if (strcmp(tag, "sctp") == 0) { 856 *type = SOCK_STREAM; 857 *proto = IPPROTO_SCTP; 858 } 859 } 860 861 static boolean_t 862 str_isnumber(const char *p) 863 { 864 char *q = (char *)p; 865 while (*q != '\0') { 866 if (!isdigit(*q)) 867 return (B_FALSE); 868 q++; 869 } 870 return (B_TRUE); 871 } 872 873 static const char *gai_errlist[] = { 874 "name translation error 0 (no error)", /* 0 */ 875 "specified address family not supported", /* 1 EAI_ADDRFAMILY */ 876 "temporary name resolution failure", /* 2 EAI_AGAIN */ 877 "invalid flags", /* 3 EAI_BADFLAGS */ 878 "non-recoverable name resolution failure", /* 4 EAI_FAIL */ 879 "specified address family not supported", /* 5 EAI_FAMILY */ 880 "memory allocation failure", /* 6 EAI_MEMORY */ 881 "no address for the specified node name", /* 7 EAI_NODATA */ 882 "node name or service name not known", /* 8 EAI_NONAME */ 883 "service name not available for the specified socket type", 884 /* 9 EAI_SERVICE */ 885 "specified socket type not supported", /* 10 EAI_SOCKTYPE */ 886 "system error", /* 11 EAI_SYSTEM */ 887 }; 888 static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) }; 889 890 const char * 891 gai_strerror(int ecode) 892 { 893 if (ecode < 0) 894 return (dgettext(TEXT_DOMAIN, 895 "name translation internal error")); 896 else if (ecode < gai_nerr) 897 return (dgettext(TEXT_DOMAIN, gai_errlist[ecode])); 898 return (dgettext(TEXT_DOMAIN, "unknown name translation error")); 899 } 900