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