2 * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
29 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
36 #include <sys/param.h>
37 #include <TargetConditionals.h>
38 #include "netdb_async.h"
39 #include "si_module.h"
42 #define IPPROTO_UNSPEC 0
44 #define IPV6_ADDR_LEN 16
45 #define IPV4_ADDR_LEN 4
47 #define WANT_NOTHING 0
48 #define WANT_A4_ONLY 1
49 #define WANT_A6_ONLY 2
50 #define WANT_A6_PLUS_MAPPED_A4 3
51 #define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4
61 freeaddrinfo(struct addrinfo
*a
)
63 struct addrinfo
*next
;
68 if (a
->ai_addr
!= NULL
) free(a
->ai_addr
);
69 if (a
->ai_canonname
!= NULL
) free(a
->ai_canonname
);
76 gai_strerror(int32_t err
)
80 case EAI_ADDRFAMILY
: return "Address family for nodename not supported";
81 case EAI_AGAIN
: return "Temporary failure in name resolution";
82 case EAI_BADFLAGS
: return "Invalid value for ai_flags";
83 case EAI_FAIL
: return "Non-recoverable failure in name resolution";
84 case EAI_FAMILY
: return "ai_family not supported";
85 case EAI_MEMORY
: return "Memory allocation failure";
86 case EAI_NODATA
: return "No address associated with nodename";
87 case EAI_NONAME
: return "nodename nor servname provided, or not known";
88 case EAI_SERVICE
: return "servname not supported for ai_socktype";
89 case EAI_SOCKTYPE
: return "ai_socktype not supported";
90 case EAI_SYSTEM
: return "System error";
91 case EAI_BADHINTS
: return "Bad hints";
92 case EAI_PROTOCOL
: return "ai_protocol not supported";
93 case EAI_OVERFLOW
: return "argument buffer overflow";
96 return "Unknown error";
102 * We handle some "trival" cases locally. If the caller passes
103 * NI_NUMERICHOST (only), then this call turns into a getservbyport
104 * to get the service name + inet_pton() to create a host string.
105 * If the caller passes NI_NUMERICSERV (only), then we zero out the port
106 * number, complete the getnameinfo, and use printf() to create a service
107 * string. If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV,
108 * we inet_ntop() and printf() and return the results.
110 __private_extern__ si_item_t
*
111 si_nameinfo(si_mod_t
*si
, const struct sockaddr
*sa
, int flags
, uint32_t *err
)
113 si_item_t
*out
= NULL
;
114 const struct sockaddr
*lookup_sa
;
115 struct sockaddr_in s4
;
118 const uint64_t unused
= 0;
125 int do_host_lookup
= ((flags
& NI_NUMERICHOST
) == 0);
126 int do_serv_lookup
= ((flags
& NI_NUMERICSERV
) == 0);
129 if ((si
== NULL
) || (sa
== NULL
))
131 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
135 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
139 if (sa
->sa_family
== AF_INET
)
141 struct sockaddr_in
*s4
= (struct sockaddr_in
*)sa
;
142 memcpy(&a4
, &s4
->sin_addr
, sizeof(a4
));
146 else if (sa
->sa_family
== AF_INET6
)
148 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)sa
;
149 memcpy(&a6
, &s6
->sin6_addr
, sizeof(a6
));
150 port
= s6
->sin6_port
;
152 /* Look for link-local IPv6 scope id */
153 if (IN6_IS_ADDR_LINKLOCAL(&s6
->sin6_addr
))
155 ifnum
= ntohs(a6
.__u6_addr
.__u6_addr16
[1]);
158 ifnum
= s6
->sin6_scope_id
;
159 a6
.__u6_addr
.__u6_addr16
[1] = htons(ifnum
);
162 if (ifnum
!= s6
->sin6_scope_id
)
164 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
169 /* v4 mapped and compat addresses are converted to plain v4 */
170 if (IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
) || IN6_IS_ADDR_V4COMPAT(&s6
->sin6_addr
))
172 memcpy(&a4
, &s6
->sin6_addr
.s6_addr
[12], sizeof(a4
));
174 memset(&s4
, 0, sizeof(s4
));
175 s4
.sin_len
= sizeof(s4
);
176 s4
.sin_family
= AF_INET
;
178 memcpy(&s4
.sin_addr
, &a4
, sizeof(s4
.sin_addr
));
179 lookup_sa
= (const struct sockaddr
*)&s4
;
188 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAMILY
;
192 if (do_host_lookup
== 1)
195 if ((do_serv_lookup
== 1) && (si
->sim_nameinfo
!= NULL
))
197 return si
->sim_nameinfo(si
, lookup_sa
, flags
, err
);
200 si_item_t
*item
= si_host_byaddr(si
, addr
, lookup_sa
->sa_family
, NULL
);
204 h
= (struct hostent
*)((uintptr_t)item
+ sizeof(si_item_t
));
205 host
= strdup(h
->h_name
);
206 si_item_release(item
);
209 if (err
!= NULL
) *err
= SI_STATUS_EAI_MEMORY
;
215 if ((do_serv_lookup
== 1) && (port
!= 0))
217 si_item_t
*item
= si_service_byport(si
, port
, NULL
);
221 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
222 serv
= strdup(s
->s_name
);
223 si_item_release(item
);
227 if (err
!= NULL
) *err
= SI_STATUS_EAI_MEMORY
;
234 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not
235 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME).
237 if (host
== NULL
&& (flags
& NI_NAMEREQD
) == 0)
239 char tmp
[INET6_ADDRSTRLEN
+ 1 + IF_NAMESIZE
+ 1];
241 if (sa
->sa_family
== AF_INET
)
243 char buf
[INET_ADDRSTRLEN
];
244 if (inet_ntop(AF_INET
, &a4
, buf
, sizeof(buf
)) != 0)
249 else if (sa
->sa_family
== AF_INET6
)
251 char buf
[INET6_ADDRSTRLEN
];
253 /* zero the embedded scope ID */
256 a6
.__u6_addr
.__u6_addr16
[1] = 0;
259 if (inet_ntop(AF_INET6
, &a6
, buf
, sizeof(buf
)) != 0)
263 char ifname
[IF_NAMESIZE
];
264 if (if_indextoname(ifnum
, ifname
) != NULL
)
266 asprintf(&host
, "%s%%%s", buf
, ifname
);
271 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
283 /* Return numeric service name for NI_NUMERICSERV or if lookup failed. */
286 asprintf(&serv
, "%hu", ntohs(port
));
289 if ((host
== NULL
) || (serv
== NULL
))
293 if ((flags
& NI_NAMEREQD
) != 0)
295 *err
= SI_STATUS_EAI_NONAME
;
299 *err
= SI_STATUS_EAI_MEMORY
;
305 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_NAMEINFO
, 1, unused
, unused
, host
, serv
);
314 _gai_numericserv(const char *serv
, uint16_t *port
)
329 num
= strtol(serv
, &endptr
, 10);
330 if ((serv
[0] != '\0') && (*endptr
== '\0') && (num
>= 0) && (num
<= UINT16_MAX
))
333 if (port
!= NULL
) *port
= (uint16_t)num
;
340 __private_extern__
int
341 _gai_serv_to_port(const char *serv
, uint32_t proto
, uint16_t *port
)
345 const char *protoname
= NULL
;
347 if (_gai_numericserv(serv
, port
)) return 0;
349 if (proto
== IPPROTO_UDP
) protoname
= "udp";
350 if (proto
== IPPROTO_TCP
) protoname
= "tcp";
352 item
= si_service_byname(si_search(), serv
, protoname
);
353 if (item
== NULL
) return -1;
355 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
356 if (port
) *port
= ntohs(s
->s_port
);
357 si_item_release(item
);
362 __private_extern__ si_item_t
*
363 si_addrinfo_v4(si_mod_t
*si
, int32_t flags
, int32_t sock
, int32_t proto
, uint16_t port
, struct in_addr
*addr
, uint16_t iface
, const char *cname
)
365 socket_data_t sockdata
;
366 struct sockaddr_in
*sa
;
371 len
= sizeof(struct sockaddr_in
);
372 memset(&sockdata
, 0, sizeof(socket_data_t
));
373 sa
= (struct sockaddr_in
*)&sockdata
;
376 sa
->sin_family
= AF_INET
;
377 sa
->sin_port
= htons(port
);
378 memcpy(&sa
->sin_addr
, addr
, sizeof(sa
->sin_addr
));
380 /* Kludge: Jam the interface number into sin_zero (4 bytes). */
382 memmove(sa
->sin_zero
, &v32
, sizeof(uint32_t));
384 return (si_item_t
*)LI_ils_create("L448844444Ss", (unsigned long)si
, CATEGORY_ADDRINFO
, 1, unused
, unused
, flags
, AF_INET
, sock
, proto
, len
, sockdata
, cname
);
387 __private_extern__ si_item_t
*
388 si_addrinfo_v6(si_mod_t
*si
, int32_t flags
, int32_t sock
, int32_t proto
, uint16_t port
, struct in6_addr
*addr
, uint16_t iface
, const char *cname
)
390 socket_data_t sockdata
;
391 struct sockaddr_in6
*sa
;
396 len
= sizeof(struct sockaddr_in6
);
397 memset(&sockdata
, 0, sizeof(socket_data_t
));
398 sa
= (struct sockaddr_in6
*)&sockdata
;
401 sa
->sin6_family
= AF_INET6
;
402 sa
->sin6_port
= htons(port
);
403 memcpy(&sa
->sin6_addr
, addr
, sizeof(sa
->sin6_addr
));
405 /* sin6_scope_id is in host byte order */
406 sa
->sin6_scope_id
= iface
;
408 if (IN6_IS_ADDR_LINKLOCAL(&sa
->sin6_addr
))
410 /* check for embedded scopeid */
411 uint16_t esid
= ntohs(sa
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
414 sa
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
415 if (iface
== 0) sa
->sin6_scope_id
= esid
;
419 return (si_item_t
*)LI_ils_create("L448844444Ss", (unsigned long)si
, CATEGORY_ADDRINFO
, 1, unused
, unused
, flags
, AF_INET6
, sock
, proto
, len
, sockdata
, cname
);
422 __private_extern__ si_list_t
*
423 si_addrinfo_list(si_mod_t
*si
, int socktype
, int proto
, struct in_addr
*a4
, struct in6_addr
*a6
, int port
, int scopeid
, const char *cname4
, const char *cname6
)
425 si_item_t
*item
= NULL
;
426 si_list_t
*out4
= NULL
, *out6
= NULL
;
429 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
431 item
= si_addrinfo_v4(si
, 0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, cname4
);
432 out4
= si_list_add(out4
, item
);
433 si_item_release(item
);
436 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
438 item
= si_addrinfo_v4(si
, 0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, cname4
);
439 out4
= si_list_add(out4
, item
);
440 si_item_release(item
);
443 if (proto
== IPPROTO_ICMP
)
445 item
= si_addrinfo_v4(si
, 0, SOCK_RAW
, IPPROTO_ICMP
, port
, a4
, 0, cname4
);
446 out4
= si_list_add(out4
, item
);
447 si_item_release(item
);
453 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
455 item
= si_addrinfo_v6(si
, 0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a6
, scopeid
, cname6
);
456 out6
= si_list_add(out6
, item
);
457 si_item_release(item
);
460 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
462 item
= si_addrinfo_v6(si
, 0, SOCK_STREAM
, IPPROTO_TCP
, port
, a6
, scopeid
, cname6
);
463 out6
= si_list_add(out6
, item
);
464 si_item_release(item
);
467 if (proto
== IPPROTO_ICMPV6
)
469 item
= si_addrinfo_v6(si
, 0, SOCK_RAW
, IPPROTO_ICMPV6
, port
, a6
, scopeid
, cname6
);
470 out6
= si_list_add(out6
, item
);
471 si_item_release(item
);
475 out6
= si_list_concat(out6
, out4
);
476 si_list_release(out4
);
483 * Determines whether the given host name is a numeric IPv4 or IPv6 address,
484 * based on the address family input value. If the input addres family is
485 * unspecified, a more specific value will be provided on output if possible.
486 * Returns 1 if host name is numeric or 0 if not, or -1 on error.
489 _gai_numerichost(const char* nodename
, uint32_t *family
, int flags
, struct in_addr
*a4
, struct in6_addr
*a6
)
491 int numerichost
, passive
;
495 if (nodename
== NULL
)
497 /* return loopback or passive addresses */
498 passive
= (flags
& AI_PASSIVE
);
500 if ((*family
== AF_UNSPEC
) || (*family
== AF_INET
))
502 if (passive
) a4
->s_addr
= 0;
503 else a4
->s_addr
= htonl(INADDR_LOOPBACK
);
506 if ((*family
== AF_UNSPEC
) || (*family
== AF_INET6
))
508 memset(a6
, 0, sizeof(*a6
));
509 if (!passive
) a6
->__u6_addr
.__u6_addr32
[3] = htonl(1);
516 /* numeric IPv4 host valid for AF_UNSPEC and AF_INET */
517 numerichost
= inet_pton(AF_INET
, nodename
, a4
);
518 if (numerichost
== 1)
520 if (*family
== AF_UNSPEC
) *family
= AF_INET
;
521 else if (*family
== AF_INET6
) numerichost
= -1;
525 /* numeric IPv6 host valid for AF_UNSPEC and AF_INET6 */
526 numerichost
= inet_pton(AF_INET6
, nodename
, a6
);
527 if (numerichost
== 1)
529 if (*family
== AF_UNSPEC
) *family
= AF_INET6
;
530 else if (*family
== AF_INET
) numerichost
= -1;
538 /* si_addrinfo_list_from_hostent
539 * Returns an addrinfo list from IPv4 and IPv6 hostent entries
541 __private_extern__ si_list_t
*
542 si_addrinfo_list_from_hostent(si_mod_t
*si
, uint32_t socktype
, uint32_t proto
, uint16_t port
, uint16_t scope
, const struct hostent
*h4
, const struct hostent
*h6
)
545 si_list_t
*out
= NULL
;
548 if ((h6
!= NULL
) && (h6
->h_addr_list
!= NULL
))
550 for (i
= 0; h6
->h_addr_list
[i
] != NULL
; i
++)
553 memcpy(&a6
, h6
->h_addr_list
[i
], h6
->h_length
);
554 list
= si_addrinfo_list(si
, socktype
, proto
, NULL
, &a6
, port
, scope
, NULL
, h6
->h_name
);
555 out
= si_list_concat(out
, list
);
556 si_list_release(list
);
560 if ((h4
!= NULL
) && (h4
->h_addr_list
!= NULL
))
562 for (i
= 0; h4
->h_addr_list
[i
] != NULL
; i
++)
565 memcpy(&a4
, h4
->h_addr_list
[i
], h4
->h_length
);
566 list
= si_addrinfo_list(si
, socktype
, proto
, &a4
, NULL
, port
, 0, h4
->h_name
, NULL
);
567 out
= si_list_concat(out
, list
);
568 si_list_release(list
);
576 * Simple lookup via gethostbyname2(3) mechanism.
579 _gai_simple(si_mod_t
*si
, const void *nodeptr
, const void *servptr
, uint32_t family
, uint32_t socktype
, uint32_t proto
, uint32_t flags
, uint32_t *err
)
581 si_item_t
*h4_item
= NULL
, *h6_item
= NULL
;
582 struct hostent
*h4
= NULL
, *h6
= NULL
;
583 si_list_t
*out
= NULL
;
586 if ((flags
& AI_NUMERICSERV
) != 0)
588 port
= *(uint16_t*)servptr
;
592 if (_gai_serv_to_port(servptr
, proto
, &port
) != 0)
594 if (err
) *err
= SI_STATUS_EAI_NONAME
;
599 if ((flags
& AI_NUMERICHOST
) != 0)
601 if (family
== AF_INET
)
603 h4_item
= si_host_byaddr(si
, nodeptr
, AF_INET
, NULL
);
605 else if (family
== AF_INET6
)
607 h6_item
= si_host_byaddr(si
, nodeptr
, AF_INET6
, NULL
);
612 if ((family
== AF_INET
) || (family
== AF_UNSPEC
))
614 h4_item
= si_host_byname(si
, nodeptr
, AF_INET
, NULL
);
616 #if !TARGET_OS_EMBEDDED
617 if ((family
== AF_INET6
) || (family
== AF_UNSPEC
))
619 h6_item
= si_host_byname(si
, nodeptr
, AF_INET6
, NULL
);
621 #endif /* !TARGET_OS_EMBEDDED */
626 h4
= (struct hostent
*)((uintptr_t)h4_item
+ sizeof(si_item_t
));
631 h6
= (struct hostent
*)((uintptr_t)h6_item
+ sizeof(si_item_t
));
634 out
= si_addrinfo_list_from_hostent(si
, socktype
, proto
, port
, 0, h4
, h6
);
635 si_item_release(h4_item
);
636 si_item_release(h6_item
);
641 __private_extern__ si_list_t
*
642 si_srv_byname(si_mod_t
*si
, const char *qname
, uint32_t *err
)
644 if (si
== NULL
) return 0;
645 if (si
->sim_srv_byname
== NULL
) return 0;
647 return si
->sim_srv_byname(si
, qname
, err
);
650 __private_extern__
int
651 si_wants_addrinfo(si_mod_t
*si
)
653 if (si
== NULL
) return 0;
654 if (si
->sim_addrinfo
== NULL
) return 0;
655 if (si
->sim_wants_addrinfo
== NULL
) return 0;
657 return si
->sim_wants_addrinfo(si
);
660 __private_extern__ si_list_t
*
661 si_addrinfo(si_mod_t
*si
, const char *node
, const char *serv
, uint32_t family
, uint32_t socktype
, uint32_t proto
, uint32_t flags
, uint32_t *err
)
663 int i
, lastprio
, numerichost
, numericserv
= 0;
664 const void *nodeptr
= NULL
, *servptr
= NULL
;
666 struct in_addr a4
, *p4
;
667 struct in6_addr a6
, *p6
;
668 char srvnode
[MAXHOSTNAMELEN
];
675 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
679 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
683 /* treat empty strings as NULL */
684 if ((node
!= NULL
) && (node
[0] == '\0')) node
= NULL
;
685 if ((serv
!= NULL
) && (serv
[0] == '\0')) serv
= NULL
;
687 /* make sure we have a query */
688 if ((node
== NULL
) && (serv
== NULL
))
690 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
694 /* verify family is supported */
698 #if TARGET_OS_EMBEDDED
705 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAMILY
;
709 /* verify socket type is supported */
718 if (err
!= NULL
) *err
= SI_STATUS_EAI_BADHINTS
;
722 /* verify protocol is supported */
732 if (err
!= NULL
) *err
= SI_STATUS_EAI_BADHINTS
;
736 /* verify socket type compatible with protocol */
737 if (((socktype
== SOCK_DGRAM
) && (proto
!= IPPROTO_UNSPEC
) && (proto
!= IPPROTO_UDP
)) || ((socktype
== SOCK_STREAM
) && (proto
!= IPPROTO_UNSPEC
) && (proto
!= IPPROTO_TCP
)))
739 if (err
!= NULL
) *err
= SI_STATUS_EAI_BADHINTS
;
743 memset(&a4
, 0, sizeof(struct in_addr
));
744 memset(&a6
, 0, sizeof(struct in6_addr
));
746 /* determine the protocol if possible */
747 if ((proto
== IPPROTO_UNSPEC
) && (socktype
== SOCK_DGRAM
)) proto
= IPPROTO_UDP
;
748 if ((proto
== IPPROTO_UNSPEC
) && (socktype
== SOCK_STREAM
)) proto
= IPPROTO_TCP
;
752 if ((flags
& AI_SRV
) != 0)
757 /* set so that getaddrinfo(3) fails if the SRV fails */
758 flags
|= AI_NUMERICSERV
;
760 /* XXX what if serv is NULL */
761 asprintf(&qname
, "%s.%s", serv
, node
);
762 list
= si_srv_byname(si
, qname
, err
);
767 for (i
= 0; i
< list
->count
; ++i
)
769 item
= list
->entry
[i
];
770 srv
= (si_srv_t
*)((uintptr_t)item
+ sizeof(si_item_t
));
772 if (srv
->priority
< lastprio
)
776 strlcpy(srvnode
, srv
->target
, sizeof(srvnode
));
781 si_list_release(list
);
786 /* Usual service lookup */
787 numericserv
= _gai_numericserv(serv
, &port
);
790 if ((flags
& AI_NUMERICSERV
) && (numericserv
== 0))
792 /* FreeBSD returns SI_STATUS_EAI_SERVICE */
793 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
799 if (numericserv
== 1)
801 flags
|= AI_NUMERICSERV
;
810 numerichost
= _gai_numerichost(node
, &family
, flags
, &a4
, &a6
);
811 if ((numerichost
== -1) || ((flags
& AI_NUMERICHOST
) && (numerichost
== 0)))
813 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
817 if (numerichost
== 1)
819 flags
|= AI_NUMERICHOST
;
820 if (family
== AF_INET
)
824 else if (family
== AF_INET6
)
834 if ((numerichost
== 1) && (numericserv
== 0))
836 /* only service lookup needed. convert to port and perform a trivial getaddrinfo */
837 if (_gai_serv_to_port(serv
, proto
, &port
) != 0)
839 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
844 flags
|= AI_NUMERICSERV
;
850 if ((numerichost
== 1) && (numericserv
== 1))
856 if (family
== AF_INET
) p6
= NULL
;
857 if (family
== AF_INET6
) p4
= NULL
;
858 if (node
== NULL
) cname
= "localhost";
860 /* handle trivial questions */
861 return si_addrinfo_list(si
, socktype
, proto
, p4
, p6
, port
, 0, cname
, cname
);
863 else if ((si
->sim_wants_addrinfo
!= NULL
) && si
->sim_wants_addrinfo(si
))
865 /* or let the current module handle the host lookups intelligently */
866 return si
->sim_addrinfo(si
, nodeptr
, servptr
, family
, socktype
, proto
, flags
, err
);
869 /* fall back to a default path */
870 return _gai_simple(si
, nodeptr
, servptr
, family
, socktype
, proto
, flags
, err
);
873 static struct addrinfo
*
874 si_item_to_addrinfo(si_item_t
*item
)
877 struct addrinfo
*out
;
879 if (item
== NULL
) return NULL
;
881 a
= (si_addrinfo_t
*)((uintptr_t)item
+ sizeof(si_item_t
));
883 out
= (struct addrinfo
*)calloc(1, sizeof(struct addrinfo
));
884 if (out
== NULL
) return NULL
;
886 out
->ai_flags
= a
->ai_flags
;
887 out
->ai_family
= a
->ai_family
;
888 out
->ai_socktype
= a
->ai_socktype
;
889 out
->ai_protocol
= a
->ai_protocol
;
890 out
->ai_addrlen
= a
->ai_addrlen
;
892 out
->ai_addr
= (struct sockaddr
*)calloc(1, out
->ai_addrlen
);
893 if (out
->ai_addr
== NULL
)
899 memcpy(out
->ai_addr
, a
->ai_addr
.x
, out
->ai_addrlen
);
901 if (a
->ai_canonname
!= NULL
)
903 out
->ai_canonname
= strdup(a
->ai_canonname
);
904 if (out
->ai_canonname
== NULL
)
914 __private_extern__
struct addrinfo
*
915 si_list_to_addrinfo(si_list_t
*list
)
917 struct addrinfo
*tail
, *out
;
920 if (list
== NULL
) return NULL
;
921 if (list
->count
== 0) return NULL
;
925 out
= si_item_to_addrinfo(list
->entry
[i
]);
928 for (i
--; i
>= 0; i
--)
930 out
= si_item_to_addrinfo(list
->entry
[i
]);
944 /* getipnodebyname */
947 make_hostent(si_mod_t
*si
, const char *name
, struct in_addr addr
)
953 if (name
== NULL
) return NULL
;
957 addrs
[0] = (char *)&(addr
.s_addr
);
961 return (si_item_t
*)LI_ils_create("L4488s*44a", (unsigned long)si
, CATEGORY_HOST_IPV4
, 1, unused
, unused
, name
, aliases
, AF_INET
, IPV4_ADDR_LEN
, addrs
);
965 make_hostent6(si_mod_t
*si
, const char *name
, struct in6_addr addr
)
971 if (name
== NULL
) return NULL
;
975 addrs
[0] = (char *)&(addr
.__u6_addr
.__u6_addr32
[0]);
979 return (si_item_t
*)LI_ils_create("L4488s*44c", (unsigned long)si
, CATEGORY_HOST_IPV6
, 1, unused
, unused
, name
, aliases
, AF_INET6
, IPV6_ADDR_LEN
, addrs
);
983 lower_case(const char *s
)
988 if (s
== NULL
) return NULL
;
990 t
= malloc(strlen(s
) + 1);
992 for (i
= 0; s
[i
] != '\0'; i
++)
994 if ((s
[i
] >= 'A') && (s
[i
] <= 'Z')) t
[i
] = s
[i
] + 32;
1004 merge_alias(const char *name
, build_hostent_t
*h
)
1008 if (name
== NULL
) return 0;
1009 if (h
== NULL
) return 0;
1011 if ((h
->host
.h_name
!= NULL
) && (string_equal(name
, h
->host
.h_name
))) return 0;
1013 for (i
= 0; i
< h
->alias_count
; i
++)
1015 if (string_equal(name
, h
->host
.h_aliases
[i
])) return 0;
1018 if (h
->alias_count
== 0) h
->host
.h_aliases
= (char **)calloc(2, sizeof(char *));
1019 else h
->host
.h_aliases
= (char **)reallocf(h
->host
.h_aliases
, (h
->alias_count
+ 2) * sizeof(char *));
1021 if (h
->host
.h_aliases
== NULL
)
1027 h
->host
.h_aliases
[h
->alias_count
] = lower_case(name
);
1029 h
->host
.h_aliases
[h
->alias_count
] = NULL
;
1035 append_addr(const char *addr
, uint32_t len
, build_hostent_t
*h
)
1037 if (addr
== NULL
) return 0;
1038 if (h
== NULL
) return 0;
1040 if (h
->addr_count
== 0) h
->host
.h_addr_list
= (char **)calloc(2, sizeof(char *));
1041 else h
->host
.h_addr_list
= (char **)reallocf(h
->host
.h_addr_list
, (h
->addr_count
+ 2) * sizeof(char *));
1043 if (h
->host
.h_addr_list
== NULL
)
1049 h
->host
.h_addr_list
[h
->addr_count
] = malloc(len
);
1050 if (h
->host
.h_addr_list
[h
->addr_count
] == NULL
) return -1;
1052 memcpy(h
->host
.h_addr_list
[h
->addr_count
], addr
, len
);
1054 h
->host
.h_addr_list
[h
->addr_count
] = NULL
;
1060 free_build_hostent(build_hostent_t
*h
)
1065 if (h
== NULL
) return;
1067 if (h
->host
.h_name
!= NULL
) free(h
->host
.h_name
);
1068 h
->host
.h_name
= NULL
;
1070 aliases
= h
->host
.h_aliases
;
1071 if (aliases
!= NULL
)
1073 while (*aliases
!= NULL
) free(*aliases
++);
1074 free(h
->host
.h_aliases
);
1077 h
->host
.h_aliases
= NULL
;
1079 if (h
->host
.h_addr_list
!= NULL
)
1081 for (i
= 0; h
->host
.h_addr_list
[i
] != NULL
; i
++) free(h
->host
.h_addr_list
[i
]);
1082 free(h
->host
.h_addr_list
);
1085 h
->host
.h_addr_list
= NULL
;
1089 __private_extern__ si_item_t
*
1090 si_ipnode_byname(si_mod_t
*si
, const char *name
, int family
, int flags
, uint32_t *err
)
1092 int i
, status
, want
, if4
, if6
;
1093 struct ifaddrs
*ifa
, *ifap
;
1094 struct in_addr addr4
;
1095 struct in6_addr addr6
;
1096 si_item_t
*item4
, *item6
;
1097 build_hostent_t
*out
;
1101 memset(&addr4
, 0, sizeof(struct in_addr
));
1102 memset(&addr6
, 0, sizeof(struct in6_addr
));
1104 if (err
!= NULL
) *err
= 0;
1106 if (family
== AF_INET
)
1108 status
= inet_aton(name
, &addr4
);
1111 /* create a host entry */
1112 item4
= make_hostent(si
, name
, addr4
);
1115 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1122 else if (family
== AF_INET6
)
1124 status
= inet_pton(family
, name
, &addr6
);
1127 /* create a host entry */
1128 item6
= make_hostent6(si
, name
, addr6
);
1131 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1138 status
= inet_aton(name
, &addr4
);
1141 if (!(flags
& (AI_V4MAPPED
| AI_V4MAPPED_CFG
)))
1143 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
1147 addr6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
1148 addr6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
1149 addr6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
1150 memmove(&(addr6
.__u6_addr
.__u6_addr32
[3]), &(addr4
.s_addr
), IPV4_ADDR_LEN
);
1152 /* create a host entry */
1153 item6
= make_hostent6(si
, name
, addr6
);
1156 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1165 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1170 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
1176 if (flags
& AI_ADDRCONFIG
)
1178 if (getifaddrs(&ifa
) < 0)
1180 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1184 for (ifap
= ifa
; ifap
!= NULL
; ifap
= ifap
->ifa_next
)
1186 if (ifap
->ifa_addr
== NULL
) continue;
1187 if ((ifap
->ifa_flags
& IFF_UP
) == 0) continue;
1188 if (ifap
->ifa_addr
->sa_family
== AF_INET
) if4
++;
1189 else if (ifap
->ifa_addr
->sa_family
== AF_INET6
) if6
++;
1194 /* Bail out if there are no interfaces */
1195 if ((if4
== 0) && (if6
== 0))
1197 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1203 * Figure out what we want.
1204 * If user asked for AF_INET, we only want V4 addresses.
1206 want
= WANT_A4_ONLY
;
1208 if (family
== AF_INET
)
1210 if ((flags
& AI_ADDRCONFIG
) && (if4
== 0))
1212 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1216 else if (family
== AF_INET6
)
1218 /* family == AF_INET6 */
1219 want
= WANT_A6_ONLY
;
1221 if (flags
& (AI_V4MAPPED
| AI_V4MAPPED_CFG
))
1225 want
= WANT_A6_PLUS_MAPPED_A4
;
1229 want
= WANT_A6_OR_MAPPED_A4_IF_NO_A6
;
1234 if ((flags
& AI_ADDRCONFIG
) && (if6
== 0))
1236 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1243 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1250 /* fetch IPv6 data if required */
1251 if ((want
== WANT_A6_ONLY
) || (want
== WANT_A6_OR_MAPPED_A4_IF_NO_A6
) || (want
== WANT_A6_PLUS_MAPPED_A4
))
1253 item6
= si_host_byname(si
, name
, AF_INET6
, (uint32_t *)err
);
1256 /* fetch IPv4 data if required */
1257 if ((want
== WANT_A4_ONLY
) || (want
== WANT_A6_PLUS_MAPPED_A4
) || ((want
== WANT_A6_OR_MAPPED_A4_IF_NO_A6
) && (item6
== NULL
)))
1259 item4
= si_host_byname(si
, name
, AF_INET
, (uint32_t *)err
);
1262 if (want
== WANT_A4_ONLY
)
1264 si_item_release(item6
);
1265 if ((item4
== NULL
) && (err
!= NULL
)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
1269 if (want
== WANT_A6_ONLY
)
1271 si_item_release(item4
);
1272 if ((item6
== NULL
) && (err
!= NULL
)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
1276 if ((item6
== NULL
) && (item4
== NULL
))
1278 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
1282 /* output item will have IPv6 + mapped IPv4 addresses */
1284 out
= (build_hostent_t
*)calloc(1, sizeof(build_hostent_t
));
1287 si_item_release(item4
);
1288 si_item_release(item6
);
1289 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1295 h
= (struct hostent
*)((uintptr_t)item4
+ sizeof(si_item_t
));
1297 out
->host
.h_name
= lower_case(h
->h_name
);
1299 if (h
->h_aliases
!= NULL
)
1301 for (i
= 0; h
->h_aliases
[i
] != NULL
; i
++) merge_alias(h
->h_aliases
[i
], out
);
1304 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++)
1306 addr6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
1307 addr6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
1308 addr6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
1309 memmove(&(addr6
.__u6_addr
.__u6_addr32
[3]), h
->h_addr_list
[i
], IPV4_ADDR_LEN
);
1310 append_addr((const char *)&addr6
, IPV6_ADDR_LEN
, out
);
1316 h
= (struct hostent
*)((uintptr_t)item6
+ sizeof(si_item_t
));
1318 if (out
->host
.h_name
== NULL
) out
->host
.h_name
= lower_case(h
->h_name
);
1320 if (h
->h_aliases
!= NULL
)
1322 for (i
= 0; h
->h_aliases
[i
] != NULL
; i
++) merge_alias(h
->h_aliases
[i
], out
);
1325 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++) append_addr((const char *)&(h
->h_addr_list
[i
]), IPV6_ADDR_LEN
, out
);
1328 si_item_release(item4
);
1329 si_item_release(item6
);
1333 item6
= (si_item_t
*)LI_ils_create("L4488s*44c", (unsigned long)si
, CATEGORY_HOST_IPV6
, 1, unused
, unused
, out
->host
.h_name
, out
->host
.h_aliases
, AF_INET6
, IPV6_ADDR_LEN
, out
->host
.h_addr_list
);
1335 free_build_hostent(out
);