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