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