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
_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res,int version)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
getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)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
__xnet_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)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
get_addr(int family,const char * hostname,struct addrinfo * aip,struct addrinfo * cur,ushort_t port,int version)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
getscopeidfromzone(const struct sockaddr_in6 * sa,const char * zone,uint32_t * sin6_scope_id)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
freeaddrinfo(struct addrinfo * ai)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
str_isnumber(const char * p)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 *
gai_strerror(int ecode)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