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