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