2 * Copyright (c) 2008-2018 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@
24 #include "libinfo_common.h"
28 #include <sys/types.h>
32 #include <sys/socket.h>
34 #include <netinet/in.h>
36 #include <arpa/inet.h>
40 #include <sys/param.h>
42 #include <notify_keys.h>
44 #include <TargetConditionals.h>
45 #include "netdb_async.h"
46 #include "si_compare.h"
47 #include "si_module.h"
50 #define IPPROTO_UNSPEC 0
52 #define IPV6_ADDR_LEN 16
53 #define IPV4_ADDR_LEN 4
55 #define WANT_NOTHING 0
56 #define WANT_A4_ONLY 1
57 #define WANT_A6_ONLY 2
58 #define WANT_A6_PLUS_MAPPED_A4 3
59 #define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4
61 #define V6TO4_PREFIX_16 0x2002
63 static int net_config_token
= -1;
64 static uint32_t net_v4_count
= 0;
65 static uint32_t net_v6_count
= 0; // includes 6to4 addresses
66 static pthread_mutex_t net_config_mutex
= PTHREAD_MUTEX_INITIALIZER
;
67 static os_log_t _gai_log
= OS_LOG_DEFAULT
;
70 int _inet_aton_check(const char *cp
, struct in_addr
*addr
, int strict
);
80 gai_child_has_forked(void)
82 // Cannot use os_log_t object from parent process in child process.
83 _gai_log
= OS_LOG_DEFAULT
;
89 _gai_log
= os_log_create("com.apple.network.libinfo", "getaddrinfo");
90 (void)pthread_atfork(NULL
, NULL
, gai_child_has_forked
);
96 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
97 pthread_once(&once
, gai_log_init
);
101 __private_extern__
int
102 si_inet_config(uint32_t *inet4
, uint32_t *inet6
)
105 struct ifaddrs
*ifa
, *ifap
;
107 pthread_mutex_lock(&net_config_mutex
);
111 if (net_config_token
< 0)
113 status
= notify_register_check(kNotifySCNetworkChange
, &net_config_token
);
114 if (status
!= 0) net_config_token
= -1;
117 if (net_config_token
>= 0)
119 status
= notify_check(net_config_token
, &checkit
);
120 if (status
!= 0) checkit
= 1;
127 if (getifaddrs(&ifa
) < 0)
136 for (ifap
= ifa
; ifap
!= NULL
; ifap
= ifap
->ifa_next
)
138 if (ifap
->ifa_addr
== NULL
) continue;
139 if ((ifap
->ifa_flags
& IFF_UP
) == 0) continue;
141 if (ifap
->ifa_addr
->sa_family
== AF_INET
)
145 else if (ifap
->ifa_addr
->sa_family
== AF_INET6
)
155 if (inet4
!= NULL
) *inet4
= net_v4_count
;
156 if (inet6
!= NULL
) *inet6
= net_v6_count
;
158 pthread_mutex_unlock(&net_config_mutex
);
165 freeaddrinfo(struct addrinfo
*a
)
167 struct addrinfo
*next
;
172 if (a
->ai_addr
!= NULL
) free(a
->ai_addr
);
173 if (a
->ai_canonname
!= NULL
) free(a
->ai_canonname
);
181 gai_strerror(int32_t err
)
185 case EAI_ADDRFAMILY
: return "Address family for nodename not supported";
186 case EAI_AGAIN
: return "Temporary failure in name resolution";
187 case EAI_BADFLAGS
: return "Invalid value for ai_flags";
188 case EAI_FAIL
: return "Non-recoverable failure in name resolution";
189 case EAI_FAMILY
: return "ai_family not supported";
190 case EAI_MEMORY
: return "Memory allocation failure";
191 case EAI_NODATA
: return "No address associated with nodename";
192 case EAI_NONAME
: return "nodename nor servname provided, or not known";
193 case EAI_SERVICE
: return "servname not supported for ai_socktype";
194 case EAI_SOCKTYPE
: return "ai_socktype not supported";
195 case EAI_SYSTEM
: return "System error";
196 case EAI_BADHINTS
: return "Bad hints";
197 case EAI_PROTOCOL
: return "ai_protocol not supported";
198 case EAI_OVERFLOW
: return "argument buffer overflow";
201 return "Unknown error";
207 * We handle some "trival" cases locally. If the caller passes
208 * NI_NUMERICHOST (only), then this call turns into a getservbyport
209 * to get the service name + inet_pton() to create a host string.
210 * If the caller passes NI_NUMERICSERV (only), then we zero out the port
211 * number, complete the getnameinfo, and use printf() to create a service
212 * string. If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV,
213 * we inet_ntop() and printf() and return the results.
217 si_nameinfo(si_mod_t
*si
, const struct sockaddr
*sa
, int flags
, const char *interface
, uint32_t *err
)
219 si_item_t
*out
= NULL
;
220 const struct sockaddr
*lookup_sa
;
221 struct sockaddr_in s4
;
224 const uint64_t unused
= 0;
231 int do_host_lookup
= ((flags
& NI_NUMERICHOST
) == 0);
232 int do_serv_lookup
= ((flags
& NI_NUMERICSERV
) == 0);
235 if ((si
== NULL
) || (sa
== NULL
))
237 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
241 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
245 if (sa
->sa_family
== AF_INET
)
247 struct sockaddr_in
*s4
= (struct sockaddr_in
*)sa
;
248 memcpy(&a4
, &s4
->sin_addr
, sizeof(a4
));
252 else if (sa
->sa_family
== AF_INET6
)
254 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)sa
;
255 memcpy(&a6
, &s6
->sin6_addr
, sizeof(a6
));
256 port
= s6
->sin6_port
;
258 /* Look for scope id in IPv6 Link Local, Multicast Node Local, and Multicast Link Local */
259 if (IN6_IS_ADDR_LINKLOCAL(&s6
->sin6_addr
) || IN6_IS_ADDR_MC_NODELOCAL(&s6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&s6
->sin6_addr
))
261 ifnum
= ntohs(a6
.__u6_addr
.__u6_addr16
[1]);
264 ifnum
= s6
->sin6_scope_id
;
265 a6
.__u6_addr
.__u6_addr16
[1] = htons(ifnum
);
268 if ((ifnum
!= s6
->sin6_scope_id
) && (s6
->sin6_scope_id
!= 0))
270 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
275 /* v4 mapped and compat addresses are converted to plain v4 */
276 if (IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
) || IN6_IS_ADDR_V4COMPAT(&s6
->sin6_addr
))
278 memcpy(&a4
, &s6
->sin6_addr
.s6_addr
[12], sizeof(a4
));
280 memset(&s4
, 0, sizeof(s4
));
281 s4
.sin_len
= sizeof(s4
);
282 s4
.sin_family
= AF_INET
;
284 memcpy(&s4
.sin_addr
, &a4
, sizeof(s4
.sin_addr
));
285 lookup_sa
= (const struct sockaddr
*)&s4
;
294 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAMILY
;
298 if (do_host_lookup
== 1)
300 si_item_t
*item
= si_host_byaddr(si
, addr
, lookup_sa
->sa_family
, interface
, NULL
);
304 h
= (struct hostent
*)((uintptr_t)item
+ sizeof(si_item_t
));
305 if (h
->h_name
== NULL
)
307 si_item_release(item
);
308 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
312 host
= strdup(h
->h_name
);
313 si_item_release(item
);
316 if (err
!= NULL
) *err
= SI_STATUS_EAI_MEMORY
;
322 if ((do_serv_lookup
== 1) && (port
!= 0))
324 si_item_t
*item
= si_service_byport(si
, port
, NULL
);
328 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
329 if (s
->s_name
== NULL
)
331 si_item_release(item
);
333 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
337 serv
= strdup(s
->s_name
);
338 si_item_release(item
);
342 if (err
!= NULL
) *err
= SI_STATUS_EAI_MEMORY
;
349 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not
350 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME).
352 if ((host
== NULL
) && ((flags
& NI_NAMEREQD
) == 0))
354 char tmp
[INET6_ADDRSTRLEN
+ 1 + IF_NAMESIZE
+ 1];
356 if (sa
->sa_family
== AF_INET
)
358 char buf
[INET_ADDRSTRLEN
];
359 if (inet_ntop(AF_INET
, &a4
, buf
, sizeof(buf
)) != 0)
364 else if (sa
->sa_family
== AF_INET6
)
366 char buf
[INET6_ADDRSTRLEN
];
368 /* zero the embedded scope ID */
371 a6
.__u6_addr
.__u6_addr16
[1] = 0;
374 if (inet_ntop(AF_INET6
, &a6
, buf
, sizeof(buf
)) != 0)
378 char ifname
[IF_NAMESIZE
];
379 if (if_indextoname(ifnum
, ifname
) != NULL
)
381 asprintf(&host
, "%s%%%s", buf
, ifname
);
386 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
399 /* Return numeric service name for NI_NUMERICSERV or if lookup failed. */
402 asprintf(&serv
, "%hu", ntohs(port
));
405 if ((host
== NULL
) || (serv
== NULL
))
409 if ((flags
& NI_NAMEREQD
) != 0)
411 *err
= SI_STATUS_EAI_NONAME
;
415 *err
= SI_STATUS_EAI_MEMORY
;
421 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_NAMEINFO
, 1, unused
, unused
, host
, serv
);
430 _gai_numericserv(const char *serv
, uint16_t *port
)
445 num
= strtol(serv
, &endptr
, 10);
446 if ((serv
[0] != '\0') && (*endptr
== '\0') && (num
>= 0) && (num
<= UINT16_MAX
))
449 if (port
!= NULL
) *port
= (uint16_t)num
;
458 _gai_serv_to_port(const char *serv
, uint32_t proto
, uint16_t *port
)
462 const char *protoname
= NULL
;
464 if (_gai_numericserv(serv
, port
)) return 0;
466 if (proto
== IPPROTO_UDP
) protoname
= "udp";
467 if (proto
== IPPROTO_TCP
) protoname
= "tcp";
469 item
= si_service_byname(si_search(), serv
, protoname
);
470 if (item
== NULL
) return -1;
472 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
473 if (port
) *port
= ntohs(s
->s_port
);
474 si_item_release(item
);
481 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
)
483 socket_data_t sockdata
;
484 struct sockaddr_in
*sa
;
489 len
= sizeof(struct sockaddr_in
);
490 memset(&sockdata
, 0, sizeof(socket_data_t
));
491 sa
= (struct sockaddr_in
*)&sockdata
;
494 sa
->sin_family
= AF_INET
;
495 sa
->sin_port
= htons(port
);
496 memcpy(&sa
->sin_addr
, addr
, sizeof(sa
->sin_addr
));
498 /* Kludge: Jam the interface number into sin_zero (4 bytes). */
500 memmove(sa
->sin_zero
, &v32
, sizeof(uint32_t));
502 return (si_item_t
*)LI_ils_create("L448844444Ss", (unsigned long)si
, CATEGORY_ADDRINFO
, 1, unused
, unused
, flags
, AF_INET
, sock
, proto
, len
, sockdata
, cname
);
507 si_addrinfo_v4_mapped(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
)
509 socket_data_t sockdata
;
510 struct sockaddr_in6
*sa
;
515 len
= sizeof(struct sockaddr_in6
);
516 memset(&sockdata
, 0, sizeof(socket_data_t
));
517 sa
= (struct sockaddr_in6
*)&sockdata
;
520 sa
->sin6_family
= AF_INET6
;
521 sa
->sin6_port
= htons(port
);
522 memset(&(sa
->sin6_addr
.__u6_addr
.__u6_addr8
[10]), 0xff, 2);
523 memcpy(&(sa
->sin6_addr
.__u6_addr
.__u6_addr8
[12]), addr
, sizeof(struct in_addr
));
525 /* sin6_scope_id is in host byte order */
526 sa
->sin6_scope_id
= iface
;
528 return (si_item_t
*)LI_ils_create("L448844444Ss", (unsigned long)si
, CATEGORY_ADDRINFO
, 1, unused
, unused
, flags
, AF_INET6
, sock
, proto
, len
, sockdata
, cname
);
534 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
)
536 socket_data_t sockdata
;
537 struct sockaddr_in6
*sa
;
542 len
= sizeof(struct sockaddr_in6
);
543 memset(&sockdata
, 0, sizeof(socket_data_t
));
544 sa
= (struct sockaddr_in6
*)&sockdata
;
547 sa
->sin6_family
= AF_INET6
;
548 sa
->sin6_port
= htons(port
);
549 memcpy(&sa
->sin6_addr
, addr
, sizeof(sa
->sin6_addr
));
551 /* sin6_scope_id is in host byte order */
552 sa
->sin6_scope_id
= iface
;
554 if (IN6_IS_ADDR_LINKLOCAL(&sa
->sin6_addr
))
556 /* check for embedded scopeid */
557 uint16_t esid
= ntohs(sa
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
560 sa
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
561 if (iface
== 0) sa
->sin6_scope_id
= esid
;
565 return (si_item_t
*)LI_ils_create("L448844444Ss", (unsigned long)si
, CATEGORY_ADDRINFO
, 1, unused
, unused
, flags
, AF_INET6
, sock
, proto
, len
, sockdata
, cname
);
570 si_addrinfo_list(si_mod_t
*si
, uint32_t flags
, int socktype
, int proto
, struct in_addr
*a4
, struct in6_addr
*a6
, int port
, int scopeid
, const char *cname4
, const char *cname6
)
573 si_item_t
*item
= NULL
;
574 si_list_t
*out4
= NULL
, *out6
= NULL
;
576 if ((flags
& AI_V4MAPPED
) && ((flags
& AI_ALL
) || (a6
== NULL
))) do_map
= 1;
580 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
582 item
= si_addrinfo_v6(si
, 0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a6
, scopeid
, cname6
);
583 out6
= si_list_add(out6
, item
);
584 si_item_release(item
);
587 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
589 item
= si_addrinfo_v6(si
, 0, SOCK_STREAM
, IPPROTO_TCP
, port
, a6
, scopeid
, cname6
);
590 out6
= si_list_add(out6
, item
);
591 si_item_release(item
);
594 if (proto
== IPPROTO_ICMPV6
)
596 item
= si_addrinfo_v6(si
, 0, SOCK_RAW
, IPPROTO_ICMPV6
, port
, a6
, scopeid
, cname6
);
597 out6
= si_list_add(out6
, item
);
598 si_item_release(item
);
604 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
608 item
= si_addrinfo_v4(si
, 0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, cname4
);
609 out4
= si_list_add(out4
, item
);
613 item
= si_addrinfo_v4_mapped(si
, 0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, cname4
);
614 out6
= si_list_add(out6
, item
);
617 si_item_release(item
);
620 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
624 item
= si_addrinfo_v4(si
, 0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, cname4
);
625 out4
= si_list_add(out4
, item
);
629 item
= si_addrinfo_v4_mapped(si
, 0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, cname4
);
630 out6
= si_list_add(out6
, item
);
633 si_item_release(item
);
636 if (proto
== IPPROTO_ICMP
)
640 item
= si_addrinfo_v4(si
, 0, SOCK_RAW
, IPPROTO_ICMP
, port
, a4
, 0, cname4
);
641 out4
= si_list_add(out4
, item
);
645 item
= si_addrinfo_v4_mapped(si
, 0, SOCK_RAW
, IPPROTO_ICMP
, port
, a4
, 0, cname4
);
646 out6
= si_list_add(out6
, item
);
649 si_item_release(item
);
653 out6
= si_list_concat(out6
, out4
);
654 si_list_release(out4
);
661 * Determines whether the given host name is a numeric IPv4 or IPv6 address,
662 * based on the address family input value. If the input addres family is
663 * unspecified, a more specific value will be provided on output if possible.
664 * Returns 1 if host name is numeric or 0 if not, or -1 on error.
667 _gai_numerichost(const char* nodename
, uint32_t *family
, int flags
, struct in_addr
*a4
, struct in6_addr
*a6
, int *scope
)
669 int numerichost
, passive
;
673 if (nodename
== NULL
)
675 /* return loopback or passive addresses */
676 passive
= (flags
& AI_PASSIVE
);
678 if (((*family
== AF_UNSPEC
) || (*family
== AF_INET
)) || ((*family
== AF_INET6
) && (flags
& AI_V4MAPPED
) && (flags
& AI_ALL
)))
680 if (passive
) a4
->s_addr
= 0;
681 else a4
->s_addr
= htonl(INADDR_LOOPBACK
);
684 if ((*family
== AF_UNSPEC
) || (*family
== AF_INET6
))
686 memset(a6
, 0, sizeof(*a6
));
687 if (!passive
) a6
->__u6_addr
.__u6_addr32
[3] = htonl(1);
695 * numeric IPv4 host valid for AF_UNSPEC and AF_INET
696 * also valid for AF_INET6 with AI_V4MAPPED
698 numerichost
= inet_pton(AF_INET
, nodename
, a4
);
699 if (numerichost
== 0)
701 /* inet_pton doesn't allow "a", "a.b", or "a.b.c" forms, so we re-check */
702 numerichost
= _inet_aton_check(nodename
, a4
, 1);
705 if (numerichost
== 1)
707 if (*family
== AF_UNSPEC
)
711 else if (*family
== AF_INET6
)
713 if (flags
& AI_V4MAPPED
)
715 memset(a6
, 0, sizeof(struct in6_addr
));
716 memset(&(a6
->__u6_addr
.__u6_addr8
[10]), 0xff, 2);
717 memcpy(&(a6
->__u6_addr
.__u6_addr8
[12]), a4
, sizeof(struct in_addr
));
728 /* numeric IPv6 host valid for AF_UNSPEC and AF_INET6 */
729 numerichost
= inet_pton(AF_INET6
, nodename
, a6
);
730 if (numerichost
== 1)
732 /* check for scope/zone id */
733 char *p
= strrchr(nodename
, SCOPE_DELIMITER
);
741 for (x
= p
; (*x
!= '\0') && (d
== 1); x
++)
747 if (d
== 1) *scope
= atoi(p
);
748 else *scope
= if_nametoindex(p
);
751 if (*family
== AF_UNSPEC
) *family
= AF_INET6
;
752 else if (*family
== AF_INET
) numerichost
= -1;
761 /* si_addrinfo_list_from_hostent
762 * Returns an addrinfo list from IPv4 and IPv6 hostent entries
766 si_addrinfo_list_from_hostent(si_mod_t
*si
, uint32_t flags
, uint32_t socktype
, uint32_t proto
, uint16_t port
, uint16_t scope
, const struct hostent
*h4
, const struct hostent
*h6
)
769 si_list_t
*out
= NULL
;
772 if ((h6
!= NULL
) && (h6
->h_addr_list
!= NULL
))
774 for (i
= 0; h6
->h_addr_list
[i
] != NULL
; i
++)
777 memcpy(&a6
, h6
->h_addr_list
[i
], h6
->h_length
);
778 list
= si_addrinfo_list(si
, flags
, socktype
, proto
, NULL
, &a6
, port
, scope
, NULL
, h6
->h_name
);
779 out
= si_list_concat(out
, list
);
780 si_list_release(list
);
784 if ((h4
!= NULL
) && (h4
->h_addr_list
!= NULL
))
786 for (i
= 0; h4
->h_addr_list
[i
] != NULL
; i
++)
789 memcpy(&a4
, h4
->h_addr_list
[i
], h4
->h_length
);
790 list
= si_addrinfo_list(si
, flags
, socktype
, proto
, &a4
, NULL
, port
, 0, h4
->h_name
, NULL
);
791 out
= si_list_concat(out
, list
);
792 si_list_release(list
);
800 _gai_addr_sort(const void *a
, const void *b
)
802 si_item_t
**item_a
, **item_b
;
803 si_addrinfo_t
*p
, *q
;
804 struct sockaddr
*sp
, *sq
;
806 item_a
= (si_item_t
**)a
;
807 item_b
= (si_item_t
**)b
;
809 p
= (si_addrinfo_t
*)((uintptr_t)*item_a
+ sizeof(si_item_t
));
810 q
= (si_addrinfo_t
*)((uintptr_t)*item_b
+ sizeof(si_item_t
));
812 sp
= (struct sockaddr
*)p
->ai_addr
.x
;
813 sq
= (struct sockaddr
*)q
->ai_addr
.x
;
816 * si_destination_compare(A,B) returns -1 if A is less desirable than B,
817 * 0 if they are equally desirable, and 1 if A is more desirable.
818 * qsort() expects the inverse, so we swap sp and sq.
820 return si_destination_compare(sq
, 0, sp
, 0, true);
824 _gai_sort_list(si_list_t
*in
, uint32_t flags
)
829 uint32_t v4mapped_count
= 0;
830 uint32_t v6_count
= 0;
833 if (in
== NULL
) return NULL
;
835 for (i
= 0; i
< in
->count
; i
++)
837 a
= (si_addrinfo_t
*)((uintptr_t)in
->entry
[i
] + sizeof(si_item_t
));
838 if (a
->ai_family
== AF_INET6
)
840 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)a
->ai_addr
.x
;
841 if (IN6_IS_ADDR_V4MAPPED(&(s6
->sin6_addr
))) v4mapped_count
++;
847 if ((flags
& AI_V4MAPPED
) && ((v6_count
== 0) || (flags
& AI_ALL
))) filter_mapped
= 0;
851 if ((filter_mapped
== 1) && (v4mapped_count
> 0))
853 i
= in
->count
- v4mapped_count
;
854 if (i
== 0) return NULL
;
856 out
= (si_list_t
*)calloc(1, sizeof(si_list_t
));
857 if (out
== NULL
) return in
;
860 out
->refcount
= in
->refcount
;
862 out
->entry
= (si_item_t
**)calloc(out
->count
, sizeof(si_item_t
*));
863 if (out
->entry
== NULL
)
871 for (i
= 0; i
< in
->count
; i
++)
873 a
= (si_addrinfo_t
*)((uintptr_t)in
->entry
[i
] + sizeof(si_item_t
));
874 if (a
->ai_family
== AF_INET6
)
876 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)a
->ai_addr
.x
;
877 if (IN6_IS_ADDR_V4MAPPED(&(s6
->sin6_addr
)))
879 si_item_release(in
->entry
[i
]);
884 out
->entry
[out
->curr
++] = in
->entry
[i
];
893 qsort(&out
->entry
[0], out
->count
, sizeof(si_item_t
*), _gai_addr_sort
);
898 * Simple lookup via gethostbyname2(3) mechanism.
902 _gai_simple(si_mod_t
*si
, const void *nodeptr
, const void *servptr
, uint32_t family
, uint32_t socktype
, uint32_t proto
, uint32_t flags
, const char *interface
, uint32_t *err
)
904 si_item_t
*h4_item
= NULL
, *h6_item
= NULL
;
905 struct hostent
*h4
= NULL
, *h6
= NULL
;
906 si_list_t
*out
= NULL
;
909 if ((flags
& AI_NUMERICSERV
) != 0)
913 if (err
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
916 port
= *(uint16_t*)servptr
;
920 if (_gai_serv_to_port(servptr
, proto
, &port
) != 0)
922 if (err
) *err
= SI_STATUS_EAI_NONAME
;
927 if ((flags
& AI_NUMERICHOST
) != 0)
929 if (family
== AF_INET
)
931 h4_item
= si_host_byaddr(si
, nodeptr
, AF_INET
, interface
, NULL
);
933 else if (family
== AF_INET6
)
935 h6_item
= si_host_byaddr(si
, nodeptr
, AF_INET6
, interface
, NULL
);
940 if ((family
== AF_INET
) || (family
== AF_UNSPEC
))
942 h4_item
= si_host_byname(si
, nodeptr
, AF_INET
, interface
, NULL
);
945 if ((family
== AF_INET6
) || (family
== AF_UNSPEC
))
947 h6_item
= si_host_byname(si
, nodeptr
, AF_INET6
, interface
, NULL
);
953 h4
= (struct hostent
*)((uintptr_t)h4_item
+ sizeof(si_item_t
));
958 h6
= (struct hostent
*)((uintptr_t)h6_item
+ sizeof(si_item_t
));
961 out
= si_addrinfo_list_from_hostent(si
, flags
, socktype
, proto
, port
, 0, h4
, h6
);
962 si_item_release(h4_item
);
963 si_item_release(h6_item
);
965 return _gai_sort_list(out
, flags
);
970 si_srv_byname(si_mod_t
*si
, const char *qname
, const char *interface
, uint32_t *err
)
972 if (si
== NULL
) return 0;
973 if (si
->vtable
->sim_srv_byname
== NULL
) return 0;
975 return si
->vtable
->sim_srv_byname(si
, qname
, interface
, err
);
980 si_wants_addrinfo(si_mod_t
*si
)
982 if (si
== NULL
) return 0;
983 if (si
->vtable
->sim_addrinfo
== NULL
) return 0;
984 if (si
->vtable
->sim_wants_addrinfo
== NULL
) return 0;
986 return si
->vtable
->sim_wants_addrinfo(si
);
990 _gai_srv(si_mod_t
*si
, const char *node
, const char *serv
, uint32_t family
, uint32_t socktype
, uint32_t proto
, uint32_t flags
, const char *interface
, uint32_t *err
)
997 si_list_t
*list
= NULL
;
998 si_list_t
*result
= NULL
;
1000 /* Minimum SRV priority is zero. Start below that. */
1004 if (node
== NULL
|| serv
== NULL
) return NULL
;
1006 asprintf(&qname
, "%s.%s", serv
, node
);
1007 list
= si_srv_byname(si
, qname
, interface
, err
);
1010 /* Iterate the SRV records starting at lowest priority and attempt to
1011 * lookup the target host name. Returns the first successful lookup.
1012 * It's an O(n^2) algorithm but data sets are small (less than 100) and
1013 * sorting overhead is dwarfed by network I/O for each element.
1015 while (list
!= NULL
&& result
== NULL
)
1017 /* Find the next lowest priority level. */
1018 /* Maximum SRV priority is UINT16_MAX. Start above that. */
1021 for (i
= 0; i
< list
->count
; ++i
)
1023 item
= list
->entry
[i
];
1024 srv
= (si_srv_t
*)((uintptr_t)item
+ sizeof(si_item_t
));
1026 if (srv
->priority
> lastprio
&& srv
->priority
< currprio
)
1028 currprio
= srv
->priority
;
1032 if (currprio
== INT_MAX
)
1034 /* All priorities have been evaluated. Done. */
1039 lastprio
= currprio
;
1042 /* Lookup hosts at the current priority level. Return first match. */
1043 for (i
= 0; i
< list
->count
; ++i
)
1045 item
= list
->entry
[i
];
1046 srv
= (si_srv_t
*)((uintptr_t)item
+ sizeof(si_item_t
));
1048 if (srv
->priority
== currprio
)
1050 /* So that _gai_simple expects an integer service. */
1051 flags
|= AI_NUMERICSERV
;
1053 result
= _gai_simple(si
, srv
->target
, &srv
->port
, family
, socktype
, proto
, flags
, interface
, err
);
1064 si_list_release(list
);
1070 #pragma mark -- NAT64 --
1072 static bool (*nat64_v4_requires_synthesis
)(const struct in_addr
*ipv4_addr
) = NULL
;
1073 static int (*nat64_v4_synthesize
)(uint32_t *index
, const struct in_addr
*ipv4
, struct in6_addr
**out_ipv6_addrs
) = NULL
;
1075 #if !TARGET_OS_SIMULATOR
1076 static void _gai_load_libnetwork_once(void)
1078 // If the function pointers are already loaded, we don't need to call dlopen
1079 if (nat64_v4_requires_synthesis
!= NULL
&& nat64_v4_synthesize
!= NULL
) {
1083 // Using dlopen will trigger libnetwork's init functions which should call
1084 // si_set_nat64_v4_synthesize and si_set_nat64_v4_requires_synthesis
1085 static void *handle
;
1086 os_log_debug(gai_log(), "Opening libnetwork.dylib");
1087 handle
= dlopen("/usr/lib/libnetwork.dylib", RTLD_LAZY
| RTLD_LOCAL
);
1088 if (handle
== NULL
) {
1089 const char *error_description
= dlerror();
1090 os_log_error(gai_log(), "dlopen(\"...libnetwork.dylib\") failed: %{public}s",
1091 error_description
? error_description
: "?");
1093 if (nat64_v4_requires_synthesis
== NULL
) {
1094 os_log_error(gai_log(), "libnetwork.dylib did not set nat64_v4_requires_synthesis");
1096 if (nat64_v4_synthesize
== NULL
) {
1097 os_log_error(gai_log(), "libnetwork.dylib did not set nat64_v4_synthesize");
1102 static void _gai_load_libnetwork(void)
1104 static pthread_once_t load_once
= PTHREAD_ONCE_INIT
;
1105 pthread_once(&load_once
, _gai_load_libnetwork_once
);
1108 static void _gai_load_libnetwork(void)
1113 static bool _gai_nat64_v4_address_requires_synthesis(const struct in_addr
*ipv4_addr
)
1115 _gai_load_libnetwork();
1116 if (nat64_v4_requires_synthesis
== NULL
) {
1119 bool result
= nat64_v4_requires_synthesis(ipv4_addr
);
1120 os_log_debug(gai_log(), "nat64_v4_requires_synthesis(%{network:in_addr}d) == %{bool}d", ipv4_addr
->s_addr
, result
);
1124 static int _gai_nat64_v4_synthesize(uint32_t *index
, const struct in_addr
*ipv4
, struct in6_addr
**out_ipv6_addrs
)
1126 _gai_load_libnetwork();
1127 if (nat64_v4_synthesize
== NULL
) {
1130 const int result
= nat64_v4_synthesize(index
, ipv4
, out_ipv6_addrs
);
1131 os_log_debug(gai_log(), "nat64_v4_synthesize(%d, %{network:in_addr}d, ...) returned %d", index
!= NULL
? *index
: 0,
1132 ipv4
->s_addr
, result
);
1137 void si_set_nat64_v4_requires_synthesis(bool (*new_requires_synthesis
)(const struct in_addr
*ipv4_addr
))
1139 if (new_requires_synthesis
== NULL
) {
1140 os_log_fault(gai_log(), "new_requires_synthesis is NULL");
1143 nat64_v4_requires_synthesis
= new_requires_synthesis
;
1147 void si_set_nat64_v4_synthesize(int (*new_synthesize
)(uint32_t *index
, const struct in_addr
*ipv4
,
1148 struct in6_addr
**out_ipv6_addrs
))
1150 if (new_synthesize
== NULL
) {
1151 os_log_fault(gai_log(), "new_synthesize is NULL");
1154 nat64_v4_synthesize
= new_synthesize
;
1158 bool _gai_nat64_can_v4_address_be_synthesized(const struct in_addr
*ipv4_addr
)
1160 if (ipv4_addr
== NULL
) {
1161 os_log_fault(gai_log(), "ipv4_addr is NULL");
1165 const in_addr_t addr_hbo
= ntohl(ipv4_addr
->s_addr
); // host byte order
1167 if (IN_ZERONET(addr_hbo
) || // 0.0.0.0/8 Source hosts on local network
1168 IN_LOOPBACK(addr_hbo
) || // 127.0.0.0/8 Loopback
1169 IN_LINKLOCAL(addr_hbo
) || // 169.254.0.0/16 Link Local
1170 IN_DS_LITE(addr_hbo
) || // 192.0.0.0/29 DS-Lite
1171 IN_6TO4_RELAY_ANYCAST(addr_hbo
) || // 192.88.99.0/24 6to4 Relay Anycast
1172 IN_MULTICAST(addr_hbo
) || // 224.0.0.0/4 Multicast
1173 INADDR_BROADCAST
== addr_hbo
) { // 255.255.255.255/32 Limited Broadcast
1181 _gai_nat64_synthesis(si_mod_t
*si
, const char *node
, const void *servptr
, int numericserv
,
1182 uint32_t family
, uint32_t socktype
, uint32_t proto
, uint32_t flags
, const char *interface
)
1189 /* validate AI_NUMERICHOST */
1190 if ((flags
& AI_NUMERICHOST
) != 0)
1195 /* validate family */
1196 if ((AF_UNSPEC
!= family
) && (AF_INET6
!= family
))
1201 /* validate that node is an IPv4 address */
1203 if (1 != inet_pton(AF_INET
, node
, &a4
))
1208 /* validate that IPv4 address is eligible for NAT64 synthesis */
1209 if (!_gai_nat64_can_v4_address_be_synthesized(&a4
)) {
1213 /* validate that there is at least an IPv6 address configured */
1214 uint32_t num_inet6
= 0;
1215 if ((si_inet_config(NULL
, &num_inet6
) < 0) || (0 == num_inet6
))
1220 /* validate interface name and convert to index */
1221 uint32_t ifindex
= 0;
1222 if (NULL
!= interface
)
1224 ifindex
= if_nametoindex(interface
);
1231 /* validate serv and convert to port */
1233 if (0 == numericserv
)
1235 if (_gai_serv_to_port((const char *)servptr
, proto
, &port
) != 0)
1241 flags
|= AI_NUMERICSERV
;
1244 else if (NULL
!= servptr
)
1246 port
= *((const uint16_t *)servptr
);
1249 /* query NAT64 prefixes */
1250 struct in6_addr
*synthesized
= NULL
;
1251 const size_t count
= _gai_nat64_v4_synthesize(&ifindex
, &a4
, &synthesized
);
1252 if (count
<= 0 || (NULL
== synthesized
)) {
1256 /* add every address to results */
1257 si_list_t
*out_list
= NULL
;
1258 for (size_t i
= 0; i
< count
; i
++)
1260 si_list_t
*temp_list
= si_addrinfo_list(si
, flags
, socktype
, proto
, NULL
, &synthesized
[i
], port
, 0, NULL
, NULL
);
1261 if (NULL
== temp_list
)
1265 if (NULL
!= out_list
)
1267 out_list
= si_list_concat(out_list
, temp_list
);
1268 si_list_release(temp_list
);
1272 out_list
= temp_list
;
1278 /* return to standard code path if no NAT64 addresses could be synthesized */
1279 if (NULL
== out_list
)
1284 /* add IPv4 addresses and IPv4-mapped IPv6 addresses if appropriate */
1285 if (((AF_UNSPEC
== family
) && ((flags
& AI_ADDRCONFIG
) == 0)) ||
1286 ((AF_INET6
== family
) && ((flags
& AI_ALL
) != 0) && ((flags
& AI_V4MAPPED
) != 0)))
1288 si_list_t
*list4
= si_addrinfo_list(si
, flags
, socktype
, proto
, &a4
, NULL
, port
, 0, NULL
, NULL
);
1291 out_list
= si_list_concat(out_list
, list4
);
1292 si_list_release(list4
);
1296 return _gai_sort_list(out_list
, flags
);
1300 _gai_nat64_second_pass(si_list_t
*out
, si_mod_t
*si
, const char *serv
, uint32_t family
, uint32_t socktype
,
1301 uint32_t proto
, uint32_t flags
, const char *interface
)
1303 if (out
== NULL
|| out
->count
== 0)
1308 /* validate AI_NUMERICHOST */
1309 if ((flags
& AI_NUMERICHOST
) != 0)
1314 /* validate family */
1315 if ((AF_UNSPEC
!= family
) && (AF_INET6
!= family
))
1320 /* skip if we already have an IPv6 address (unless it is v4-mapped) */
1321 for (uint32_t i
= 0; i
< out
->count
; i
++)
1323 si_addrinfo_t
*a
= (si_addrinfo_t
*)((uintptr_t)out
->entry
[i
] + sizeof(si_item_t
));
1324 if (a
->ai_family
== AF_INET6
)
1326 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)a
->ai_addr
.x
;
1327 if (!IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
))
1334 si_list_t
*out_list
= NULL
;
1335 const uint32_t flags2
= flags
& (~(AI_V4MAPPED
| AI_V4MAPPED_CFG
));
1337 for (uint32_t i
= 0; i
< out
->count
; i
++)
1339 si_addrinfo_t
*a
= (si_addrinfo_t
*)((uintptr_t)out
->entry
[i
] + sizeof(si_item_t
));
1340 struct in_addr
*addr4
= NULL
;
1341 if (a
->ai_family
== AF_INET
)
1343 addr4
= &((struct sockaddr_in
*)a
->ai_addr
.x
)->sin_addr
;
1345 else if (a
->ai_family
== AF_INET6
)
1347 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)a
->ai_addr
.x
;
1348 addr4
= (struct in_addr
*)&(s6
->sin6_addr
.__u6_addr
.__u6_addr32
[3]);
1355 if (!_gai_nat64_v4_address_requires_synthesis(addr4
))
1360 char v4_str
[INET_ADDRSTRLEN
] = {0};
1361 if (NULL
== inet_ntop(AF_INET
, addr4
, v4_str
, sizeof(v4_str
)))
1366 uint32_t err
= SI_STATUS_NO_ERROR
;
1367 si_list_t
*temp_list
= si_addrinfo(si
, v4_str
, serv
, AF_INET6
, socktype
, proto
, flags2
, interface
, &err
);
1368 if (NULL
== temp_list
)
1372 if (err
!= SI_STATUS_NO_ERROR
)
1374 si_list_release(temp_list
);
1377 if (NULL
!= out_list
)
1379 out_list
= si_list_concat(out_list
, temp_list
);
1380 si_list_release(temp_list
);
1384 out_list
= temp_list
;
1390 #pragma mark -- /NAT64 --
1394 si_addrinfo(si_mod_t
*si
, const char *node
, const char *serv
, uint32_t family
, uint32_t socktype
, uint32_t proto
, uint32_t flags
, const char *interface
, uint32_t *err
)
1396 const uint32_t family_ori
= family
, flags_ori
= flags
;
1397 int numerichost
, numericserv
= 0;
1399 const void *nodeptr
= NULL
, *servptr
= NULL
;
1401 struct in_addr a4
, *p4
;
1402 struct in6_addr a6
, *p6
;
1406 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
1410 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
1414 /* treat empty strings as NULL */
1415 if ((node
!= NULL
) && (node
[0] == '\0')) node
= NULL
;
1416 if ((serv
!= NULL
) && (serv
[0] == '\0')) serv
= NULL
;
1418 /* make sure we have a query */
1419 if ((node
== NULL
) && (serv
== NULL
))
1421 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
1425 /* verify family is supported */
1433 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAMILY
;
1437 /* verify socket type is supported */
1446 if (err
!= NULL
) *err
= SI_STATUS_EAI_BADHINTS
;
1450 /* verify protocol is supported */
1453 case IPPROTO_UNSPEC
:
1457 case IPPROTO_ICMPV6
:
1460 if (err
!= NULL
) *err
= SI_STATUS_EAI_BADHINTS
;
1464 /* verify socket type compatible with protocol */
1465 if (((socktype
== SOCK_DGRAM
) && (proto
!= IPPROTO_UNSPEC
) && (proto
!= IPPROTO_UDP
)) || ((socktype
== SOCK_STREAM
) && (proto
!= IPPROTO_UNSPEC
) && (proto
!= IPPROTO_TCP
)))
1467 if (err
!= NULL
) *err
= SI_STATUS_EAI_BADHINTS
;
1471 /* replace AI_V4MAPPED_CFG with AI_V4MAPPED */
1472 if ((flags
& AI_V4MAPPED_CFG
) != 0)
1474 flags
= (flags
& ~AI_V4MAPPED_CFG
) | AI_V4MAPPED
;
1477 /* check AI_V4MAPPED and AI_ALL */
1478 if (family
!= AF_INET6
)
1480 /* unset AI_V4MAPPED and AI_ALL unless family is AF_INET6 */
1481 flags
&= ~(AI_V4MAPPED
| AI_ALL
);
1483 else if ((flags
& AI_V4MAPPED
) == 0)
1485 /* unset AI_ALL unless family is AF_INET6 and AI_V4MAPPED is set */
1489 memset(&a4
, 0, sizeof(struct in_addr
));
1490 memset(&a6
, 0, sizeof(struct in6_addr
));
1492 /* determine the protocol if possible */
1493 if ((proto
== IPPROTO_UNSPEC
) && (socktype
== SOCK_DGRAM
)) proto
= IPPROTO_UDP
;
1494 if ((proto
== IPPROTO_UNSPEC
) && (socktype
== SOCK_STREAM
)) proto
= IPPROTO_TCP
;
1498 if ((flags
& AI_SRV
) != 0)
1501 out
= _gai_srv(si
, node
, serv
, family
, socktype
, proto
, flags
, interface
, err
);
1502 return _gai_sort_list(out
, flags
);
1506 /* Usual service lookup */
1507 numericserv
= _gai_numericserv(serv
, &port
);
1510 if ((flags
& AI_NUMERICSERV
) && (numericserv
== 0))
1512 /* FreeBSD returns SI_STATUS_EAI_SERVICE */
1513 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
1517 if ((serv
!= NULL
) && (strcmp(serv
, "0") != 0))
1519 if (numericserv
== 1)
1521 flags
|= AI_NUMERICSERV
;
1530 /* NAT64 IPv6 address synthesis support */
1531 si_list_t
*nat64_list
= _gai_nat64_synthesis(si
, node
, servptr
, numericserv
, family
, socktype
, proto
, flags
, interface
);
1532 if (NULL
!= nat64_list
)
1537 numerichost
= _gai_numerichost(node
, &family
, flags
, &a4
, &a6
, &scope
);
1538 if ((numerichost
== -1) || ((flags
& AI_NUMERICHOST
) && (numerichost
== 0)))
1540 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
1544 if (numerichost
== 1)
1546 flags
|= AI_NUMERICHOST
;
1547 if (family
== AF_INET
)
1551 else if (family
== AF_INET6
)
1561 if ((numerichost
== 1) && (numericserv
== 0))
1563 /* only service lookup needed. convert to port and perform a trivial getaddrinfo */
1564 if (_gai_serv_to_port(serv
, proto
, &port
) != 0)
1566 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
1571 flags
|= AI_NUMERICSERV
;
1577 if ((numerichost
== 1) && (numericserv
== 1))
1583 if (family
== AF_INET
) p6
= NULL
;
1584 if (family
== AF_INET6
) p4
= NULL
;
1585 if (node
== NULL
) cname
= "localhost";
1587 /* allow nodename to be a mapped IPv4 address, e.g. "::ffff:10.0.0.1" */
1588 if (p6
!= NULL
) flags
|= AI_V4MAPPED
;
1590 /* handle trivial questions */
1591 out
= si_addrinfo_list(si
, flags
, socktype
, proto
, p4
, p6
, port
, scope
, cname
, cname
);
1592 return _gai_sort_list(out
, flags
);
1594 else if (si_wants_addrinfo(si
))
1596 /* or let the current module handle the host lookups intelligently */
1597 out
= si
->vtable
->sim_addrinfo(si
, nodeptr
, servptr
, family
, socktype
, proto
, flags
, interface
, err
);
1599 /* run a second NAT64 pass in case a hostname was resolved over VPN to an IPv4 address
1600 and it needs to be synthesized in order to be used on IPv6-only cellular */
1601 si_list_t
*nat64_list2
= _gai_nat64_second_pass(out
, si
, serv
, family_ori
, socktype
,
1602 proto
, flags_ori
, interface
);
1603 if (nat64_list2
!= NULL
)
1605 out
= si_list_concat(out
, nat64_list2
);
1608 return _gai_sort_list(out
, flags
);
1611 /* fall back to a default path */
1612 out
= _gai_simple(si
, nodeptr
, servptr
, family
, socktype
, proto
, flags
, interface
, err
);
1613 return _gai_sort_list(out
, flags
);
1616 static struct addrinfo
*
1617 si_item_to_addrinfo(si_item_t
*item
)
1620 struct addrinfo
*out
;
1622 if (item
== NULL
) return NULL
;
1624 a
= (si_addrinfo_t
*)((uintptr_t)item
+ sizeof(si_item_t
));
1626 out
= (struct addrinfo
*)calloc(1, sizeof(struct addrinfo
));
1627 if (out
== NULL
) return NULL
;
1629 out
->ai_flags
= a
->ai_flags
;
1630 out
->ai_family
= a
->ai_family
;
1631 out
->ai_socktype
= a
->ai_socktype
;
1632 out
->ai_protocol
= a
->ai_protocol
;
1633 out
->ai_addrlen
= a
->ai_addrlen
;
1635 out
->ai_addr
= (struct sockaddr
*)calloc(1, out
->ai_addrlen
);
1636 if (out
->ai_addr
== NULL
)
1642 memcpy(out
->ai_addr
, a
->ai_addr
.x
, out
->ai_addrlen
);
1644 if (a
->ai_canonname
!= NULL
)
1646 out
->ai_canonname
= strdup(a
->ai_canonname
);
1647 if (out
->ai_canonname
== NULL
)
1658 si_list_to_addrinfo(si_list_t
*list
)
1660 struct addrinfo
*tail
, *out
;
1663 if (list
== NULL
) return NULL
;
1664 if (list
->count
== 0) return NULL
;
1666 i
= list
->count
- 1;
1668 out
= si_item_to_addrinfo(list
->entry
[i
]);
1671 for (i
--; i
>= 0; i
--)
1673 out
= si_item_to_addrinfo(list
->entry
[i
]);
1680 out
->ai_next
= tail
;
1687 /* getipnodebyname */
1690 make_hostent(si_mod_t
*si
, const char *name
, struct in_addr addr
)
1696 if (name
== NULL
) return NULL
;
1700 addrs
[0] = (char *)&(addr
.s_addr
);
1704 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
);
1708 make_hostent6(si_mod_t
*si
, const char *name
, struct in6_addr addr
)
1714 if (name
== NULL
) return NULL
;
1718 addrs
[0] = (char *)&(addr
.__u6_addr
.__u6_addr32
[0]);
1722 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
);
1726 lower_case(const char *s
)
1731 if (s
== NULL
) return NULL
;
1733 t
= malloc(strlen(s
) + 1);
1734 if (t
== NULL
) return NULL
;
1736 for (i
= 0; s
[i
] != '\0'; i
++)
1738 if ((s
[i
] >= 'A') && (s
[i
] <= 'Z')) t
[i
] = s
[i
] + 32;
1748 merge_alias(const char *name
, build_hostent_t
*h
)
1752 if (name
== NULL
) return 0;
1753 if (h
== NULL
) return 0;
1754 if (h
->host
.h_name
== NULL
) return 0;
1756 if ((h
->host
.h_name
!= NULL
) && (string_equal(name
, h
->host
.h_name
))) return 0;
1758 for (i
= 0; i
< h
->alias_count
; i
++)
1760 if (string_equal(name
, h
->host
.h_aliases
[i
])) return 0;
1763 if (h
->alias_count
== 0) h
->host
.h_aliases
= (char **)calloc(2, sizeof(char *));
1764 else h
->host
.h_aliases
= (char **)reallocf(h
->host
.h_aliases
, (h
->alias_count
+ 2) * sizeof(char *));
1766 if (h
->host
.h_aliases
== NULL
)
1772 h
->host
.h_aliases
[h
->alias_count
] = lower_case(name
);
1774 h
->host
.h_aliases
[h
->alias_count
] = NULL
;
1780 append_addr(const char *addr
, uint32_t len
, build_hostent_t
*h
)
1782 if (addr
== NULL
) return 0;
1783 if (h
== NULL
) return 0;
1785 if (h
->addr_count
== 0) h
->host
.h_addr_list
= (char **)calloc(2, sizeof(char *));
1786 else h
->host
.h_addr_list
= (char **)reallocf(h
->host
.h_addr_list
, (h
->addr_count
+ 2) * sizeof(char *));
1788 if (h
->host
.h_addr_list
== NULL
)
1794 h
->host
.h_addr_list
[h
->addr_count
] = malloc(len
);
1795 if (h
->host
.h_addr_list
[h
->addr_count
] == NULL
) return -1;
1797 memcpy(h
->host
.h_addr_list
[h
->addr_count
], addr
, len
);
1799 h
->host
.h_addr_list
[h
->addr_count
] = NULL
;
1805 free_build_hostent(build_hostent_t
*h
)
1810 if (h
== NULL
) return;
1812 if (h
->host
.h_name
!= NULL
) free(h
->host
.h_name
);
1813 h
->host
.h_name
= NULL
;
1815 aliases
= h
->host
.h_aliases
;
1816 if (aliases
!= NULL
)
1818 while (*aliases
!= NULL
) free(*aliases
++);
1819 free(h
->host
.h_aliases
);
1822 h
->host
.h_aliases
= NULL
;
1824 if (h
->host
.h_addr_list
!= NULL
)
1826 for (i
= 0; h
->host
.h_addr_list
[i
] != NULL
; i
++) free(h
->host
.h_addr_list
[i
]);
1827 free(h
->host
.h_addr_list
);
1830 h
->host
.h_addr_list
= NULL
;
1836 si_ipnode_byname(si_mod_t
*si
, const char *name
, int family
, int flags
, const char *interface
, uint32_t *err
)
1838 int i
, status
, want
;
1840 struct in_addr addr4
;
1841 struct in6_addr addr6
;
1842 si_item_t
*item4
, *item6
;
1843 build_hostent_t
*out
;
1847 memset(&addr4
, 0, sizeof(struct in_addr
));
1848 memset(&addr6
, 0, sizeof(struct in6_addr
));
1850 if (err
!= NULL
) *err
= 0;
1852 if (family
== AF_INET
)
1854 status
= inet_aton(name
, &addr4
);
1857 /* create a host entry */
1858 item4
= make_hostent(si
, name
, addr4
);
1861 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1868 else if (family
== AF_INET6
)
1870 status
= inet_pton(family
, name
, &addr6
);
1873 /* create a host entry */
1874 item6
= make_hostent6(si
, name
, addr6
);
1877 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1884 status
= inet_aton(name
, &addr4
);
1887 if (!(flags
& (AI_V4MAPPED
| AI_V4MAPPED_CFG
)))
1889 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
1893 addr6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
1894 addr6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
1895 addr6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
1896 memmove(&(addr6
.__u6_addr
.__u6_addr32
[3]), &(addr4
.s_addr
), IPV4_ADDR_LEN
);
1898 /* create a host entry */
1899 item6
= make_hostent6(si
, name
, addr6
);
1902 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1911 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1916 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
1922 if (flags
& AI_ADDRCONFIG
)
1924 if (si_inet_config(&if4
, &if6
) < 0)
1926 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1930 /* Bail out if there are no interfaces */
1931 if ((if4
== 0) && (if6
== 0))
1933 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1939 * Figure out what we want.
1940 * If user asked for AF_INET, we only want V4 addresses.
1942 want
= WANT_A4_ONLY
;
1944 if (family
== AF_INET
)
1946 if ((flags
& AI_ADDRCONFIG
) && (if4
== 0))
1948 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1952 else if (family
== AF_INET6
)
1954 /* family == AF_INET6 */
1955 want
= WANT_A6_ONLY
;
1957 if (flags
& (AI_V4MAPPED
| AI_V4MAPPED_CFG
))
1961 want
= WANT_A6_PLUS_MAPPED_A4
;
1965 want
= WANT_A6_OR_MAPPED_A4_IF_NO_A6
;
1970 if ((flags
& AI_ADDRCONFIG
) && (if6
== 0))
1972 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1979 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1986 /* fetch IPv6 data if required */
1987 if ((want
== WANT_A6_ONLY
) || (want
== WANT_A6_OR_MAPPED_A4_IF_NO_A6
) || (want
== WANT_A6_PLUS_MAPPED_A4
))
1989 item6
= si_host_byname(si
, name
, AF_INET6
, interface
, (uint32_t *)err
);
1992 /* fetch IPv4 data if required */
1993 if ((want
== WANT_A4_ONLY
) || (want
== WANT_A6_PLUS_MAPPED_A4
) || ((want
== WANT_A6_OR_MAPPED_A4_IF_NO_A6
) && (item6
== NULL
)))
1995 item4
= si_host_byname(si
, name
, AF_INET
, interface
, (uint32_t *)err
);
1998 if (want
== WANT_A4_ONLY
)
2000 si_item_release(item6
);
2001 if ((item4
== NULL
) && (err
!= NULL
)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
2005 if (want
== WANT_A6_ONLY
)
2007 si_item_release(item4
);
2008 if ((item6
== NULL
) && (err
!= NULL
)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
2012 if ((item6
== NULL
) && (item4
== NULL
))
2014 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
2018 /* output item will have IPv6 + mapped IPv4 addresses */
2020 out
= (build_hostent_t
*)calloc(1, sizeof(build_hostent_t
));
2023 si_item_release(item4
);
2024 si_item_release(item6
);
2025 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
2031 h
= (struct hostent
*)((uintptr_t)item4
+ sizeof(si_item_t
));
2033 out
->host
.h_name
= lower_case(h
->h_name
);
2035 if (h
->h_aliases
!= NULL
)
2037 for (i
= 0; h
->h_aliases
[i
] != NULL
; i
++) merge_alias(h
->h_aliases
[i
], out
);
2040 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++)
2042 addr6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
2043 addr6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
2044 addr6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
2045 memmove(&(addr6
.__u6_addr
.__u6_addr32
[3]), h
->h_addr_list
[i
], IPV4_ADDR_LEN
);
2046 append_addr((const char *)&addr6
, IPV6_ADDR_LEN
, out
);
2052 h
= (struct hostent
*)((uintptr_t)item6
+ sizeof(si_item_t
));
2054 if (out
->host
.h_name
== NULL
) out
->host
.h_name
= lower_case(h
->h_name
);
2056 if (h
->h_aliases
!= NULL
)
2058 for (i
= 0; h
->h_aliases
[i
] != NULL
; i
++) merge_alias(h
->h_aliases
[i
], out
);
2061 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++) append_addr(h
->h_addr_list
[i
], IPV6_ADDR_LEN
, out
);
2064 si_item_release(item4
);
2065 si_item_release(item6
);
2069 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
);
2071 free_build_hostent(out
);