2 * Copyright (c) 2008-2015 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 <network/sa_compare.h>
33 #include <network/nat64.h>
34 #include <network/path_evaluation.h>
35 #include <arpa/inet.h>
39 #include <sys/param.h>
41 #include <notify_keys.h>
43 #include <TargetConditionals.h>
44 #include "netdb_async.h"
45 #include "si_module.h"
48 #define IPPROTO_UNSPEC 0
50 #define IPV6_ADDR_LEN 16
51 #define IPV4_ADDR_LEN 4
53 #define WANT_NOTHING 0
54 #define WANT_A4_ONLY 1
55 #define WANT_A6_ONLY 2
56 #define WANT_A6_PLUS_MAPPED_A4 3
57 #define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4
59 #define V6TO4_PREFIX_16 0x2002
61 static int net_config_token
= -1;
62 static uint32_t net_v4_count
= 0;
63 static uint32_t net_v6_count
= 0; // includes 6to4 addresses
64 static pthread_mutex_t net_config_mutex
= PTHREAD_MUTEX_INITIALIZER
;
67 int _inet_aton_check(const char *cp
, struct in_addr
*addr
, int strict
);
76 __private_extern__
int
77 si_inet_config(uint32_t *inet4
, uint32_t *inet6
)
80 struct ifaddrs
*ifa
, *ifap
;
82 pthread_mutex_lock(&net_config_mutex
);
86 if (net_config_token
< 0)
88 status
= notify_register_check(kNotifySCNetworkChange
, &net_config_token
);
89 if (status
!= 0) net_config_token
= -1;
92 if (net_config_token
>= 0)
94 status
= notify_check(net_config_token
, &checkit
);
95 if (status
!= 0) checkit
= 1;
102 if (getifaddrs(&ifa
) < 0)
111 for (ifap
= ifa
; ifap
!= NULL
; ifap
= ifap
->ifa_next
)
113 if (ifap
->ifa_addr
== NULL
) continue;
114 if ((ifap
->ifa_flags
& IFF_UP
) == 0) continue;
116 if (ifap
->ifa_addr
->sa_family
== AF_INET
)
120 else if (ifap
->ifa_addr
->sa_family
== AF_INET6
)
130 if (inet4
!= NULL
) *inet4
= net_v4_count
;
131 if (inet6
!= NULL
) *inet6
= net_v6_count
;
133 pthread_mutex_unlock(&net_config_mutex
);
139 freeaddrinfo(struct addrinfo
*a
)
141 struct addrinfo
*next
;
146 if (a
->ai_addr
!= NULL
) free(a
->ai_addr
);
147 if (a
->ai_canonname
!= NULL
) free(a
->ai_canonname
);
154 gai_strerror(int32_t err
)
158 case EAI_ADDRFAMILY
: return "Address family for nodename not supported";
159 case EAI_AGAIN
: return "Temporary failure in name resolution";
160 case EAI_BADFLAGS
: return "Invalid value for ai_flags";
161 case EAI_FAIL
: return "Non-recoverable failure in name resolution";
162 case EAI_FAMILY
: return "ai_family not supported";
163 case EAI_MEMORY
: return "Memory allocation failure";
164 case EAI_NODATA
: return "No address associated with nodename";
165 case EAI_NONAME
: return "nodename nor servname provided, or not known";
166 case EAI_SERVICE
: return "servname not supported for ai_socktype";
167 case EAI_SOCKTYPE
: return "ai_socktype not supported";
168 case EAI_SYSTEM
: return "System error";
169 case EAI_BADHINTS
: return "Bad hints";
170 case EAI_PROTOCOL
: return "ai_protocol not supported";
171 case EAI_OVERFLOW
: return "argument buffer overflow";
174 return "Unknown error";
180 * We handle some "trival" cases locally. If the caller passes
181 * NI_NUMERICHOST (only), then this call turns into a getservbyport
182 * to get the service name + inet_pton() to create a host string.
183 * If the caller passes NI_NUMERICSERV (only), then we zero out the port
184 * number, complete the getnameinfo, and use printf() to create a service
185 * string. If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV,
186 * we inet_ntop() and printf() and return the results.
189 si_nameinfo(si_mod_t
*si
, const struct sockaddr
*sa
, int flags
, const char *interface
, uint32_t *err
)
191 si_item_t
*out
= NULL
;
192 const struct sockaddr
*lookup_sa
;
193 struct sockaddr_in s4
;
196 const uint64_t unused
= 0;
203 int do_host_lookup
= ((flags
& NI_NUMERICHOST
) == 0);
204 int do_serv_lookup
= ((flags
& NI_NUMERICSERV
) == 0);
207 if ((si
== NULL
) || (sa
== NULL
))
209 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
213 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
217 if (sa
->sa_family
== AF_INET
)
219 struct sockaddr_in
*s4
= (struct sockaddr_in
*)sa
;
220 memcpy(&a4
, &s4
->sin_addr
, sizeof(a4
));
224 else if (sa
->sa_family
== AF_INET6
)
226 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)sa
;
227 memcpy(&a6
, &s6
->sin6_addr
, sizeof(a6
));
228 port
= s6
->sin6_port
;
230 /* Look for scope id in IPv6 Link Local, Multicast Node Local, and Multicast Link Local */
231 if (IN6_IS_ADDR_LINKLOCAL(&s6
->sin6_addr
) || IN6_IS_ADDR_MC_NODELOCAL(&s6
->sin6_addr
) || IN6_IS_ADDR_MC_LINKLOCAL(&s6
->sin6_addr
))
233 ifnum
= ntohs(a6
.__u6_addr
.__u6_addr16
[1]);
236 ifnum
= s6
->sin6_scope_id
;
237 a6
.__u6_addr
.__u6_addr16
[1] = htons(ifnum
);
240 if ((ifnum
!= s6
->sin6_scope_id
) && (s6
->sin6_scope_id
!= 0))
242 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
247 /* v4 mapped and compat addresses are converted to plain v4 */
248 if (IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
) || IN6_IS_ADDR_V4COMPAT(&s6
->sin6_addr
))
250 memcpy(&a4
, &s6
->sin6_addr
.s6_addr
[12], sizeof(a4
));
252 memset(&s4
, 0, sizeof(s4
));
253 s4
.sin_len
= sizeof(s4
);
254 s4
.sin_family
= AF_INET
;
256 memcpy(&s4
.sin_addr
, &a4
, sizeof(s4
.sin_addr
));
257 lookup_sa
= (const struct sockaddr
*)&s4
;
266 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAMILY
;
270 if (do_host_lookup
== 1)
272 si_item_t
*item
= si_host_byaddr(si
, addr
, lookup_sa
->sa_family
, interface
, NULL
);
276 h
= (struct hostent
*)((uintptr_t)item
+ sizeof(si_item_t
));
277 if (h
->h_name
== NULL
)
279 si_item_release(item
);
280 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
284 host
= strdup(h
->h_name
);
285 si_item_release(item
);
288 if (err
!= NULL
) *err
= SI_STATUS_EAI_MEMORY
;
294 if ((do_serv_lookup
== 1) && (port
!= 0))
296 si_item_t
*item
= si_service_byport(si
, port
, NULL
);
300 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
301 if (s
->s_name
== NULL
)
303 si_item_release(item
);
305 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
309 serv
= strdup(s
->s_name
);
310 si_item_release(item
);
314 if (err
!= NULL
) *err
= SI_STATUS_EAI_MEMORY
;
321 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not
322 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME).
324 if ((host
== NULL
) && ((flags
& NI_NAMEREQD
) == 0))
326 char tmp
[INET6_ADDRSTRLEN
+ 1 + IF_NAMESIZE
+ 1];
328 if (sa
->sa_family
== AF_INET
)
330 char buf
[INET_ADDRSTRLEN
];
331 if (inet_ntop(AF_INET
, &a4
, buf
, sizeof(buf
)) != 0)
336 else if (sa
->sa_family
== AF_INET6
)
338 char buf
[INET6_ADDRSTRLEN
];
340 /* zero the embedded scope ID */
343 a6
.__u6_addr
.__u6_addr16
[1] = 0;
346 if (inet_ntop(AF_INET6
, &a6
, buf
, sizeof(buf
)) != 0)
350 char ifname
[IF_NAMESIZE
];
351 if (if_indextoname(ifnum
, ifname
) != NULL
)
353 asprintf(&host
, "%s%%%s", buf
, ifname
);
358 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
371 /* Return numeric service name for NI_NUMERICSERV or if lookup failed. */
374 asprintf(&serv
, "%hu", ntohs(port
));
377 if ((host
== NULL
) || (serv
== NULL
))
381 if ((flags
& NI_NAMEREQD
) != 0)
383 *err
= SI_STATUS_EAI_NONAME
;
387 *err
= SI_STATUS_EAI_MEMORY
;
393 out
= (si_item_t
*)LI_ils_create("L4488ss", (unsigned long)si
, CATEGORY_NAMEINFO
, 1, unused
, unused
, host
, serv
);
402 _gai_numericserv(const char *serv
, uint16_t *port
)
417 num
= strtol(serv
, &endptr
, 10);
418 if ((serv
[0] != '\0') && (*endptr
== '\0') && (num
>= 0) && (num
<= UINT16_MAX
))
421 if (port
!= NULL
) *port
= (uint16_t)num
;
429 _gai_serv_to_port(const char *serv
, uint32_t proto
, uint16_t *port
)
433 const char *protoname
= NULL
;
435 if (_gai_numericserv(serv
, port
)) return 0;
437 if (proto
== IPPROTO_UDP
) protoname
= "udp";
438 if (proto
== IPPROTO_TCP
) protoname
= "tcp";
440 item
= si_service_byname(si_search(), serv
, protoname
);
441 if (item
== NULL
) return -1;
443 s
= (struct servent
*)((uintptr_t)item
+ sizeof(si_item_t
));
444 if (port
) *port
= ntohs(s
->s_port
);
445 si_item_release(item
);
451 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
)
453 socket_data_t sockdata
;
454 struct sockaddr_in
*sa
;
459 len
= sizeof(struct sockaddr_in
);
460 memset(&sockdata
, 0, sizeof(socket_data_t
));
461 sa
= (struct sockaddr_in
*)&sockdata
;
464 sa
->sin_family
= AF_INET
;
465 sa
->sin_port
= htons(port
);
466 memcpy(&sa
->sin_addr
, addr
, sizeof(sa
->sin_addr
));
468 /* Kludge: Jam the interface number into sin_zero (4 bytes). */
470 memmove(sa
->sin_zero
, &v32
, sizeof(uint32_t));
472 return (si_item_t
*)LI_ils_create("L448844444Ss", (unsigned long)si
, CATEGORY_ADDRINFO
, 1, unused
, unused
, flags
, AF_INET
, sock
, proto
, len
, sockdata
, cname
);
476 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
)
478 socket_data_t sockdata
;
479 struct sockaddr_in6
*sa
;
484 len
= sizeof(struct sockaddr_in6
);
485 memset(&sockdata
, 0, sizeof(socket_data_t
));
486 sa
= (struct sockaddr_in6
*)&sockdata
;
489 sa
->sin6_family
= AF_INET6
;
490 sa
->sin6_port
= htons(port
);
491 memset(&(sa
->sin6_addr
.__u6_addr
.__u6_addr8
[10]), 0xff, 2);
492 memcpy(&(sa
->sin6_addr
.__u6_addr
.__u6_addr8
[12]), addr
, sizeof(struct in_addr
));
494 /* sin6_scope_id is in host byte order */
495 sa
->sin6_scope_id
= iface
;
497 return (si_item_t
*)LI_ils_create("L448844444Ss", (unsigned long)si
, CATEGORY_ADDRINFO
, 1, unused
, unused
, flags
, AF_INET6
, sock
, proto
, len
, sockdata
, cname
);
502 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
)
504 socket_data_t sockdata
;
505 struct sockaddr_in6
*sa
;
510 len
= sizeof(struct sockaddr_in6
);
511 memset(&sockdata
, 0, sizeof(socket_data_t
));
512 sa
= (struct sockaddr_in6
*)&sockdata
;
515 sa
->sin6_family
= AF_INET6
;
516 sa
->sin6_port
= htons(port
);
517 memcpy(&sa
->sin6_addr
, addr
, sizeof(sa
->sin6_addr
));
519 /* sin6_scope_id is in host byte order */
520 sa
->sin6_scope_id
= iface
;
522 if (IN6_IS_ADDR_LINKLOCAL(&sa
->sin6_addr
))
524 /* check for embedded scopeid */
525 uint16_t esid
= ntohs(sa
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
528 sa
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
529 if (iface
== 0) sa
->sin6_scope_id
= esid
;
533 return (si_item_t
*)LI_ils_create("L448844444Ss", (unsigned long)si
, CATEGORY_ADDRINFO
, 1, unused
, unused
, flags
, AF_INET6
, sock
, proto
, len
, sockdata
, cname
);
537 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
)
540 si_item_t
*item
= NULL
;
541 si_list_t
*out4
= NULL
, *out6
= NULL
;
543 if ((flags
& AI_V4MAPPED
) && ((flags
& AI_ALL
) || (a6
== NULL
))) do_map
= 1;
547 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
549 item
= si_addrinfo_v6(si
, 0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a6
, scopeid
, cname6
);
550 out6
= si_list_add(out6
, item
);
551 si_item_release(item
);
554 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
556 item
= si_addrinfo_v6(si
, 0, SOCK_STREAM
, IPPROTO_TCP
, port
, a6
, scopeid
, cname6
);
557 out6
= si_list_add(out6
, item
);
558 si_item_release(item
);
561 if (proto
== IPPROTO_ICMPV6
)
563 item
= si_addrinfo_v6(si
, 0, SOCK_RAW
, IPPROTO_ICMPV6
, port
, a6
, scopeid
, cname6
);
564 out6
= si_list_add(out6
, item
);
565 si_item_release(item
);
571 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
575 item
= si_addrinfo_v4(si
, 0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, cname4
);
576 out4
= si_list_add(out4
, item
);
580 item
= si_addrinfo_v4_mapped(si
, 0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, cname4
);
581 out6
= si_list_add(out6
, item
);
584 si_item_release(item
);
587 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
591 item
= si_addrinfo_v4(si
, 0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, cname4
);
592 out4
= si_list_add(out4
, item
);
596 item
= si_addrinfo_v4_mapped(si
, 0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, cname4
);
597 out6
= si_list_add(out6
, item
);
600 si_item_release(item
);
603 if (proto
== IPPROTO_ICMP
)
607 item
= si_addrinfo_v4(si
, 0, SOCK_RAW
, IPPROTO_ICMP
, port
, a4
, 0, cname4
);
608 out4
= si_list_add(out4
, item
);
612 item
= si_addrinfo_v4_mapped(si
, 0, SOCK_RAW
, IPPROTO_ICMP
, port
, a4
, 0, cname4
);
613 out6
= si_list_add(out6
, item
);
616 si_item_release(item
);
620 out6
= si_list_concat(out6
, out4
);
621 si_list_release(out4
);
628 * Determines whether the given host name is a numeric IPv4 or IPv6 address,
629 * based on the address family input value. If the input addres family is
630 * unspecified, a more specific value will be provided on output if possible.
631 * Returns 1 if host name is numeric or 0 if not, or -1 on error.
634 _gai_numerichost(const char* nodename
, uint32_t *family
, int flags
, struct in_addr
*a4
, struct in6_addr
*a6
, int *scope
)
636 int numerichost
, passive
;
640 if (nodename
== NULL
)
642 /* return loopback or passive addresses */
643 passive
= (flags
& AI_PASSIVE
);
645 if (((*family
== AF_UNSPEC
) || (*family
== AF_INET
)) || ((*family
== AF_INET6
) && (flags
& AI_V4MAPPED
) && (flags
& AI_ALL
)))
647 if (passive
) a4
->s_addr
= 0;
648 else a4
->s_addr
= htonl(INADDR_LOOPBACK
);
651 if ((*family
== AF_UNSPEC
) || (*family
== AF_INET6
))
653 memset(a6
, 0, sizeof(*a6
));
654 if (!passive
) a6
->__u6_addr
.__u6_addr32
[3] = htonl(1);
662 * numeric IPv4 host valid for AF_UNSPEC and AF_INET
663 * also valid for AF_INET6 with AI_V4MAPPED
665 numerichost
= inet_pton(AF_INET
, nodename
, a4
);
666 if (numerichost
== 0)
668 /* inet_pton doesn't allow "a", "a.b", or "a.b.c" forms, so we re-check */
669 numerichost
= _inet_aton_check(nodename
, a4
, 1);
672 if (numerichost
== 1)
674 if (*family
== AF_UNSPEC
)
678 else if (*family
== AF_INET6
)
680 if (flags
& AI_V4MAPPED
)
682 memset(a6
, 0, sizeof(struct in6_addr
));
683 memset(&(a6
->__u6_addr
.__u6_addr8
[10]), 0xff, 2);
684 memcpy(&(a6
->__u6_addr
.__u6_addr8
[12]), a4
, sizeof(struct in_addr
));
695 /* numeric IPv6 host valid for AF_UNSPEC and AF_INET6 */
696 numerichost
= inet_pton(AF_INET6
, nodename
, a6
);
697 if (numerichost
== 1)
699 /* check for scope/zone id */
700 char *p
= strrchr(nodename
, SCOPE_DELIMITER
);
708 for (x
= p
; (*x
!= '\0') && (d
== 1); x
++)
714 if (d
== 1) *scope
= atoi(p
);
715 else *scope
= if_nametoindex(p
);
718 if (*family
== AF_UNSPEC
) *family
= AF_INET6
;
719 else if (*family
== AF_INET
) numerichost
= -1;
728 /* si_addrinfo_list_from_hostent
729 * Returns an addrinfo list from IPv4 and IPv6 hostent entries
732 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
)
735 si_list_t
*out
= NULL
;
738 if ((h6
!= NULL
) && (h6
->h_addr_list
!= NULL
))
740 for (i
= 0; h6
->h_addr_list
[i
] != NULL
; i
++)
743 memcpy(&a6
, h6
->h_addr_list
[i
], h6
->h_length
);
744 list
= si_addrinfo_list(si
, flags
, socktype
, proto
, NULL
, &a6
, port
, scope
, NULL
, h6
->h_name
);
745 out
= si_list_concat(out
, list
);
746 si_list_release(list
);
750 if ((h4
!= NULL
) && (h4
->h_addr_list
!= NULL
))
752 for (i
= 0; h4
->h_addr_list
[i
] != NULL
; i
++)
755 memcpy(&a4
, h4
->h_addr_list
[i
], h4
->h_length
);
756 list
= si_addrinfo_list(si
, flags
, socktype
, proto
, &a4
, NULL
, port
, 0, h4
->h_name
, NULL
);
757 out
= si_list_concat(out
, list
);
758 si_list_release(list
);
766 _gai_addr_sort(const void *a
, const void *b
)
768 si_item_t
**item_a
, **item_b
;
769 si_addrinfo_t
*p
, *q
;
770 struct sockaddr
*sp
, *sq
;
772 item_a
= (si_item_t
**)a
;
773 item_b
= (si_item_t
**)b
;
775 p
= (si_addrinfo_t
*)((uintptr_t)*item_a
+ sizeof(si_item_t
));
776 q
= (si_addrinfo_t
*)((uintptr_t)*item_b
+ sizeof(si_item_t
));
778 sp
= (struct sockaddr
*)p
->ai_addr
.x
;
779 sq
= (struct sockaddr
*)q
->ai_addr
.x
;
782 * sa_dst_compare(A,B) returns -1 if A is less desirable than B,
783 * 0 if they are equally desirable, and 1 if A is more desirable.
784 * qsort() expects the inverse, so we swap sp and sq.
786 return sa_dst_compare(sq
, sp
, 0);
790 _gai_sort_list(si_list_t
*in
, uint32_t flags
)
795 uint32_t v4mapped_count
= 0;
796 uint32_t v6_count
= 0;
799 if (in
== NULL
) return NULL
;
801 for (i
= 0; i
< in
->count
; i
++)
803 a
= (si_addrinfo_t
*)((uintptr_t)in
->entry
[i
] + sizeof(si_item_t
));
804 if (a
->ai_family
== AF_INET6
)
806 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)a
->ai_addr
.x
;
807 if (IN6_IS_ADDR_V4MAPPED(&(s6
->sin6_addr
))) v4mapped_count
++;
813 if ((flags
& AI_V4MAPPED
) && ((v6_count
== 0) || (flags
& AI_ALL
))) filter_mapped
= 0;
817 if ((filter_mapped
== 1) && (v4mapped_count
> 0))
819 i
= in
->count
- v4mapped_count
;
820 if (i
== 0) return NULL
;
822 out
= (si_list_t
*)calloc(1, sizeof(si_list_t
));
823 if (out
== NULL
) return in
;
826 out
->refcount
= in
->refcount
;
828 out
->entry
= (si_item_t
**)calloc(out
->count
, sizeof(si_item_t
*));
829 if (out
->entry
== NULL
)
837 for (i
= 0; i
< in
->count
; i
++)
839 a
= (si_addrinfo_t
*)((uintptr_t)in
->entry
[i
] + sizeof(si_item_t
));
840 if (a
->ai_family
== AF_INET6
)
842 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)a
->ai_addr
.x
;
843 if (IN6_IS_ADDR_V4MAPPED(&(s6
->sin6_addr
)))
845 si_item_release(in
->entry
[i
]);
850 out
->entry
[out
->curr
++] = in
->entry
[i
];
859 qsort(&out
->entry
[0], out
->count
, sizeof(si_item_t
*), _gai_addr_sort
);
864 * Simple lookup via gethostbyname2(3) mechanism.
867 _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
)
869 si_item_t
*h4_item
= NULL
, *h6_item
= NULL
;
870 struct hostent
*h4
= NULL
, *h6
= NULL
;
871 si_list_t
*out
= NULL
;
874 if ((flags
& AI_NUMERICSERV
) != 0)
878 if (err
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
881 port
= *(uint16_t*)servptr
;
885 if (_gai_serv_to_port(servptr
, proto
, &port
) != 0)
887 if (err
) *err
= SI_STATUS_EAI_NONAME
;
892 if ((flags
& AI_NUMERICHOST
) != 0)
894 if (family
== AF_INET
)
896 h4_item
= si_host_byaddr(si
, nodeptr
, AF_INET
, interface
, NULL
);
898 else if (family
== AF_INET6
)
900 h6_item
= si_host_byaddr(si
, nodeptr
, AF_INET6
, interface
, NULL
);
905 if ((family
== AF_INET
) || (family
== AF_UNSPEC
))
907 h4_item
= si_host_byname(si
, nodeptr
, AF_INET
, interface
, NULL
);
910 if ((family
== AF_INET6
) || (family
== AF_UNSPEC
))
912 h6_item
= si_host_byname(si
, nodeptr
, AF_INET6
, interface
, NULL
);
918 h4
= (struct hostent
*)((uintptr_t)h4_item
+ sizeof(si_item_t
));
923 h6
= (struct hostent
*)((uintptr_t)h6_item
+ sizeof(si_item_t
));
926 out
= si_addrinfo_list_from_hostent(si
, flags
, socktype
, proto
, port
, 0, h4
, h6
);
927 si_item_release(h4_item
);
928 si_item_release(h6_item
);
930 return _gai_sort_list(out
, flags
);
934 si_srv_byname(si_mod_t
*si
, const char *qname
, const char *interface
, uint32_t *err
)
936 if (si
== NULL
) return 0;
937 if (si
->vtable
->sim_srv_byname
== NULL
) return 0;
939 return si
->vtable
->sim_srv_byname(si
, qname
, interface
, err
);
943 si_wants_addrinfo(si_mod_t
*si
)
945 if (si
== NULL
) return 0;
946 if (si
->vtable
->sim_addrinfo
== NULL
) return 0;
947 if (si
->vtable
->sim_wants_addrinfo
== NULL
) return 0;
949 return si
->vtable
->sim_wants_addrinfo(si
);
953 _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
)
960 si_list_t
*list
= NULL
;
961 si_list_t
*result
= NULL
;
963 /* Minimum SRV priority is zero. Start below that. */
967 if (node
== NULL
|| serv
== NULL
) return NULL
;
969 asprintf(&qname
, "%s.%s", serv
, node
);
970 list
= si_srv_byname(si
, qname
, interface
, err
);
973 /* Iterate the SRV records starting at lowest priority and attempt to
974 * lookup the target host name. Returns the first successful lookup.
975 * It's an O(n^2) algorithm but data sets are small (less than 100) and
976 * sorting overhead is dwarfed by network I/O for each element.
978 while (list
!= NULL
&& result
== NULL
)
980 /* Find the next lowest priority level. */
981 /* Maximum SRV priority is UINT16_MAX. Start above that. */
984 for (i
= 0; i
< list
->count
; ++i
)
986 item
= list
->entry
[i
];
987 srv
= (si_srv_t
*)((uintptr_t)item
+ sizeof(si_item_t
));
989 if (srv
->priority
> lastprio
&& srv
->priority
< currprio
)
991 currprio
= srv
->priority
;
995 if (currprio
== INT_MAX
)
997 /* All priorities have been evaluated. Done. */
1002 lastprio
= currprio
;
1005 /* Lookup hosts at the current priority level. Return first match. */
1006 for (i
= 0; i
< list
->count
; ++i
)
1008 item
= list
->entry
[i
];
1009 srv
= (si_srv_t
*)((uintptr_t)item
+ sizeof(si_item_t
));
1011 if (srv
->priority
== currprio
)
1013 /* So that _gai_simple expects an integer service. */
1014 flags
|= AI_NUMERICSERV
;
1016 result
= _gai_simple(si
, srv
->target
, &srv
->port
, family
, socktype
, proto
, flags
, interface
, err
);
1027 si_list_release(list
);
1034 _gai_nat64_synthesis(si_mod_t
*si
, const char *node
, const void *servptr
, int numericserv
,
1035 uint32_t family
, uint32_t socktype
, uint32_t proto
, uint32_t flags
, const char *interface
)
1042 /* validate AI_NUMERICHOST */
1043 if ((flags
& AI_NUMERICHOST
) != 0)
1048 /* validate family */
1049 if ((AF_UNSPEC
!= family
) && (AF_INET6
!= family
))
1054 /* validate that node is an IPv4 address */
1056 if (1 != inet_pton(AF_INET
, node
, &a4
))
1061 /* validate that IPv4 address is eligible for NAT64 synthesis */
1062 #if defined(NW_NAT64_API_VERSION) && NW_NAT64_API_VERSION >= 2
1063 if (!nw_nat64_can_v4_address_be_synthesized(&a4
)) {
1066 #endif // NW_NAT64_API_VERSION
1068 /* validate that there is at least an IPv6 address configured */
1069 uint32_t num_inet6
= 0;
1070 if ((si_inet_config(NULL
, &num_inet6
) < 0) || (0 == num_inet6
))
1075 /* validate interface name and convert to index */
1076 uint32_t ifindex
= 0;
1077 if (NULL
!= interface
)
1079 ifindex
= if_nametoindex(interface
);
1086 /* validate serv and convert to port */
1088 if (0 == numericserv
)
1090 if (_gai_serv_to_port((const char *)servptr
, proto
, &port
) != 0)
1096 flags
|= AI_NUMERICSERV
;
1099 else if (NULL
!= servptr
)
1101 port
= *((const uint16_t *)servptr
);
1104 /* query NAT64 prefixes */
1105 nw_nat64_prefix_t
*prefixes
= NULL
;
1106 const int32_t num_prefixes
= nw_nat64_copy_prefixes(&ifindex
, &prefixes
);
1107 if ((num_prefixes
<= 0) || (NULL
== prefixes
))
1112 /* add every address to results */
1113 si_list_t
*out_list
= NULL
;
1114 for (int32_t i
= 0; i
< num_prefixes
; i
++)
1117 if (!nw_nat64_synthesize_v6(&prefixes
[i
], &a4
, &a6
))
1121 si_list_t
*temp_list
= si_addrinfo_list(si
, flags
, socktype
, proto
, NULL
, &a6
, port
, 0, NULL
, NULL
);
1122 if (NULL
== temp_list
)
1126 if (NULL
!= out_list
)
1128 out_list
= si_list_concat(out_list
, temp_list
);
1129 si_list_release(temp_list
);
1133 out_list
= temp_list
;
1139 /* return to standard code path if no NAT64 addresses could be synthesized */
1140 if (NULL
== out_list
)
1145 /* add IPv4 addresses and IPv4-mapped IPv6 addresses if appropriate */
1146 if (((AF_UNSPEC
== family
) && ((flags
& AI_ADDRCONFIG
) == 0)) ||
1147 ((AF_INET6
== family
) && ((flags
& AI_ALL
) != 0) && ((flags
& AI_V4MAPPED
) != 0)))
1149 si_list_t
*list4
= si_addrinfo_list(si
, flags
, socktype
, proto
, &a4
, NULL
, port
, 0, NULL
, NULL
);
1152 out_list
= si_list_concat(out_list
, list4
);
1153 si_list_release(list4
);
1157 return _gai_sort_list(out_list
, flags
);
1161 _gai_nat64_second_pass(si_list_t
*out
, si_mod_t
*si
, const char *serv
, uint32_t family
, uint32_t socktype
,
1162 uint32_t proto
, uint32_t flags
, const char *interface
)
1164 if (out
== NULL
|| out
->count
== 0)
1169 /* validate AI_NUMERICHOST */
1170 if ((flags
& AI_NUMERICHOST
) != 0)
1175 /* validate family */
1176 if ((AF_UNSPEC
!= family
) && (AF_INET6
!= family
))
1181 /* skip if we already have an IPv6 address (unless it is v4-mapped) */
1182 for (uint32_t i
= 0; i
< out
->count
; i
++)
1184 si_addrinfo_t
*a
= (si_addrinfo_t
*)((uintptr_t)out
->entry
[i
] + sizeof(si_item_t
));
1185 if (a
->ai_family
== AF_INET6
)
1187 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)a
->ai_addr
.x
;
1188 if (!IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
))
1195 si_list_t
*out_list
= NULL
;
1196 const uint32_t flags2
= flags
& (~(AI_V4MAPPED
| AI_V4MAPPED_CFG
));
1198 for (uint32_t i
= 0; i
< out
->count
; i
++)
1200 si_addrinfo_t
*a
= (si_addrinfo_t
*)((uintptr_t)out
->entry
[i
] + sizeof(si_item_t
));
1201 struct in_addr
*addr4
= NULL
;
1202 if (a
->ai_family
== AF_INET
)
1204 addr4
= &((struct sockaddr_in
*)a
->ai_addr
.x
)->sin_addr
;
1206 else if (a
->ai_family
== AF_INET6
)
1208 struct sockaddr_in6
*s6
= (struct sockaddr_in6
*)a
->ai_addr
.x
;
1209 addr4
= (struct in_addr
*)&(s6
->sin6_addr
.__u6_addr
.__u6_addr32
[3]);
1216 /* validate that IPv4 address is eligible for NAT64 synthesis */
1217 #if defined(NW_NAT64_API_VERSION) && NW_NAT64_API_VERSION >= 2
1218 if (!nw_nat64_can_v4_address_be_synthesized(addr4
))
1222 #endif // NW_NAT64_API_VERSION
1224 char v4_str
[INET_ADDRSTRLEN
] = {0};
1225 if (NULL
== inet_ntop(AF_INET
, addr4
, v4_str
, sizeof(v4_str
)))
1230 /* skip if we have a path (route) to this address as it might go through a VPN */
1231 nw_endpoint_t endpoint
= nw_endpoint_create_address((struct sockaddr
*)a
->ai_addr
.x
);
1232 if (endpoint
== NULL
)
1236 nw_path_evaluator_t evaluator
= nw_path_create_evaluator_for_endpoint(endpoint
, NULL
);
1237 network_release(endpoint
);
1238 if (evaluator
== NULL
)
1242 nw_path_t path
= nw_path_evaluator_copy_path(evaluator
);
1243 network_release(evaluator
);
1248 const nw_path_status_t status
= nw_path_get_status(path
);
1249 network_release(path
);
1250 if (status
!= nw_path_status_unsatisfied
)
1255 uint32_t err
= SI_STATUS_NO_ERROR
;
1256 si_list_t
*temp_list
= si_addrinfo(si
, v4_str
, serv
, AF_INET6
, socktype
, proto
, flags2
, interface
, &err
);
1257 if (NULL
== temp_list
)
1261 if (err
!= SI_STATUS_NO_ERROR
)
1263 si_list_release(temp_list
);
1266 if (NULL
!= out_list
)
1268 out_list
= si_list_concat(out_list
, temp_list
);
1269 si_list_release(temp_list
);
1273 out_list
= temp_list
;
1280 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
)
1282 const uint32_t family_ori
= family
, flags_ori
= flags
;
1283 int numerichost
, numericserv
= 0;
1285 const void *nodeptr
= NULL
, *servptr
= NULL
;
1287 struct in_addr a4
, *p4
;
1288 struct in6_addr a6
, *p6
;
1292 if (err
!= NULL
) *err
= SI_STATUS_NO_ERROR
;
1296 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAIL
;
1300 /* treat empty strings as NULL */
1301 if ((node
!= NULL
) && (node
[0] == '\0')) node
= NULL
;
1302 if ((serv
!= NULL
) && (serv
[0] == '\0')) serv
= NULL
;
1304 /* make sure we have a query */
1305 if ((node
== NULL
) && (serv
== NULL
))
1307 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
1311 /* verify family is supported */
1319 if (err
!= NULL
) *err
= SI_STATUS_EAI_FAMILY
;
1323 /* verify socket type is supported */
1332 if (err
!= NULL
) *err
= SI_STATUS_EAI_BADHINTS
;
1336 /* verify protocol is supported */
1339 case IPPROTO_UNSPEC
:
1343 case IPPROTO_ICMPV6
:
1346 if (err
!= NULL
) *err
= SI_STATUS_EAI_BADHINTS
;
1350 /* verify socket type compatible with protocol */
1351 if (((socktype
== SOCK_DGRAM
) && (proto
!= IPPROTO_UNSPEC
) && (proto
!= IPPROTO_UDP
)) || ((socktype
== SOCK_STREAM
) && (proto
!= IPPROTO_UNSPEC
) && (proto
!= IPPROTO_TCP
)))
1353 if (err
!= NULL
) *err
= SI_STATUS_EAI_BADHINTS
;
1357 /* replace AI_V4MAPPED_CFG with AI_V4MAPPED */
1358 if ((flags
& AI_V4MAPPED_CFG
) != 0)
1360 flags
= (flags
& ~AI_V4MAPPED_CFG
) | AI_V4MAPPED
;
1363 /* check AI_V4MAPPED and AI_ALL */
1364 if (family
!= AF_INET6
)
1366 /* unset AI_V4MAPPED and AI_ALL unless family is AF_INET6 */
1367 flags
&= ~(AI_V4MAPPED
| AI_ALL
);
1369 else if ((flags
& AI_V4MAPPED
) == 0)
1371 /* unset AI_ALL unless family is AF_INET6 and AI_V4MAPPED is set */
1375 memset(&a4
, 0, sizeof(struct in_addr
));
1376 memset(&a6
, 0, sizeof(struct in6_addr
));
1378 /* determine the protocol if possible */
1379 if ((proto
== IPPROTO_UNSPEC
) && (socktype
== SOCK_DGRAM
)) proto
= IPPROTO_UDP
;
1380 if ((proto
== IPPROTO_UNSPEC
) && (socktype
== SOCK_STREAM
)) proto
= IPPROTO_TCP
;
1384 if ((flags
& AI_SRV
) != 0)
1387 out
= _gai_srv(si
, node
, serv
, family
, socktype
, proto
, flags
, interface
, err
);
1388 return _gai_sort_list(out
, flags
);
1392 /* Usual service lookup */
1393 numericserv
= _gai_numericserv(serv
, &port
);
1396 if ((flags
& AI_NUMERICSERV
) && (numericserv
== 0))
1398 /* FreeBSD returns SI_STATUS_EAI_SERVICE */
1399 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
1403 if ((serv
!= NULL
) && (strcmp(serv
, "0") != 0))
1405 if (numericserv
== 1)
1407 flags
|= AI_NUMERICSERV
;
1416 /* NAT64 IPv6 address synthesis support */
1417 si_list_t
*nat64_list
= _gai_nat64_synthesis(si
, node
, servptr
, numericserv
, family
, socktype
, proto
, flags
, interface
);
1418 if (NULL
!= nat64_list
)
1423 numerichost
= _gai_numerichost(node
, &family
, flags
, &a4
, &a6
, &scope
);
1424 if ((numerichost
== -1) || ((flags
& AI_NUMERICHOST
) && (numerichost
== 0)))
1426 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
1430 if (numerichost
== 1)
1432 flags
|= AI_NUMERICHOST
;
1433 if (family
== AF_INET
)
1437 else if (family
== AF_INET6
)
1447 if ((numerichost
== 1) && (numericserv
== 0))
1449 /* only service lookup needed. convert to port and perform a trivial getaddrinfo */
1450 if (_gai_serv_to_port(serv
, proto
, &port
) != 0)
1452 if (err
!= NULL
) *err
= SI_STATUS_EAI_NONAME
;
1457 flags
|= AI_NUMERICSERV
;
1463 if ((numerichost
== 1) && (numericserv
== 1))
1469 if (family
== AF_INET
) p6
= NULL
;
1470 if (family
== AF_INET6
) p4
= NULL
;
1471 if (node
== NULL
) cname
= "localhost";
1473 /* allow nodename to be a mapped IPv4 address, e.g. "::ffff:10.0.0.1" */
1474 if (p6
!= NULL
) flags
|= AI_V4MAPPED
;
1476 /* handle trivial questions */
1477 out
= si_addrinfo_list(si
, flags
, socktype
, proto
, p4
, p6
, port
, scope
, cname
, cname
);
1478 return _gai_sort_list(out
, flags
);
1480 else if (si_wants_addrinfo(si
))
1482 /* or let the current module handle the host lookups intelligently */
1483 out
= si
->vtable
->sim_addrinfo(si
, nodeptr
, servptr
, family
, socktype
, proto
, flags
, interface
, err
);
1485 /* run a second NAT64 pass in case a hostname was resolved over VPN to an IPv4 address
1486 and it needs to be synthesized in order to be used on IPv6-only cellular */
1487 si_list_t
*nat64_list2
= _gai_nat64_second_pass(out
, si
, serv
, family_ori
, socktype
,
1488 proto
, flags_ori
, interface
);
1489 if (nat64_list2
!= NULL
)
1491 out
= si_list_concat(out
, nat64_list2
);
1494 return _gai_sort_list(out
, flags
);
1497 /* fall back to a default path */
1498 out
= _gai_simple(si
, nodeptr
, servptr
, family
, socktype
, proto
, flags
, interface
, err
);
1499 return _gai_sort_list(out
, flags
);
1502 static struct addrinfo
*
1503 si_item_to_addrinfo(si_item_t
*item
)
1506 struct addrinfo
*out
;
1508 if (item
== NULL
) return NULL
;
1510 a
= (si_addrinfo_t
*)((uintptr_t)item
+ sizeof(si_item_t
));
1512 out
= (struct addrinfo
*)calloc(1, sizeof(struct addrinfo
));
1513 if (out
== NULL
) return NULL
;
1515 out
->ai_flags
= a
->ai_flags
;
1516 out
->ai_family
= a
->ai_family
;
1517 out
->ai_socktype
= a
->ai_socktype
;
1518 out
->ai_protocol
= a
->ai_protocol
;
1519 out
->ai_addrlen
= a
->ai_addrlen
;
1521 out
->ai_addr
= (struct sockaddr
*)calloc(1, out
->ai_addrlen
);
1522 if (out
->ai_addr
== NULL
)
1528 memcpy(out
->ai_addr
, a
->ai_addr
.x
, out
->ai_addrlen
);
1530 if (a
->ai_canonname
!= NULL
)
1532 out
->ai_canonname
= strdup(a
->ai_canonname
);
1533 if (out
->ai_canonname
== NULL
)
1544 si_list_to_addrinfo(si_list_t
*list
)
1546 struct addrinfo
*tail
, *out
;
1549 if (list
== NULL
) return NULL
;
1550 if (list
->count
== 0) return NULL
;
1552 i
= list
->count
- 1;
1554 out
= si_item_to_addrinfo(list
->entry
[i
]);
1557 for (i
--; i
>= 0; i
--)
1559 out
= si_item_to_addrinfo(list
->entry
[i
]);
1566 out
->ai_next
= tail
;
1573 /* getipnodebyname */
1576 make_hostent(si_mod_t
*si
, const char *name
, struct in_addr addr
)
1582 if (name
== NULL
) return NULL
;
1586 addrs
[0] = (char *)&(addr
.s_addr
);
1590 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
);
1594 make_hostent6(si_mod_t
*si
, const char *name
, struct in6_addr addr
)
1600 if (name
== NULL
) return NULL
;
1604 addrs
[0] = (char *)&(addr
.__u6_addr
.__u6_addr32
[0]);
1608 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
);
1612 lower_case(const char *s
)
1617 if (s
== NULL
) return NULL
;
1619 t
= malloc(strlen(s
) + 1);
1620 if (t
== NULL
) return NULL
;
1622 for (i
= 0; s
[i
] != '\0'; i
++)
1624 if ((s
[i
] >= 'A') && (s
[i
] <= 'Z')) t
[i
] = s
[i
] + 32;
1634 merge_alias(const char *name
, build_hostent_t
*h
)
1638 if (name
== NULL
) return 0;
1639 if (h
== NULL
) return 0;
1640 if (h
->host
.h_name
== NULL
) return 0;
1642 if ((h
->host
.h_name
!= NULL
) && (string_equal(name
, h
->host
.h_name
))) return 0;
1644 for (i
= 0; i
< h
->alias_count
; i
++)
1646 if (string_equal(name
, h
->host
.h_aliases
[i
])) return 0;
1649 if (h
->alias_count
== 0) h
->host
.h_aliases
= (char **)calloc(2, sizeof(char *));
1650 else h
->host
.h_aliases
= (char **)reallocf(h
->host
.h_aliases
, (h
->alias_count
+ 2) * sizeof(char *));
1652 if (h
->host
.h_aliases
== NULL
)
1658 h
->host
.h_aliases
[h
->alias_count
] = lower_case(name
);
1660 h
->host
.h_aliases
[h
->alias_count
] = NULL
;
1666 append_addr(const char *addr
, uint32_t len
, build_hostent_t
*h
)
1668 if (addr
== NULL
) return 0;
1669 if (h
== NULL
) return 0;
1671 if (h
->addr_count
== 0) h
->host
.h_addr_list
= (char **)calloc(2, sizeof(char *));
1672 else h
->host
.h_addr_list
= (char **)reallocf(h
->host
.h_addr_list
, (h
->addr_count
+ 2) * sizeof(char *));
1674 if (h
->host
.h_addr_list
== NULL
)
1680 h
->host
.h_addr_list
[h
->addr_count
] = malloc(len
);
1681 if (h
->host
.h_addr_list
[h
->addr_count
] == NULL
) return -1;
1683 memcpy(h
->host
.h_addr_list
[h
->addr_count
], addr
, len
);
1685 h
->host
.h_addr_list
[h
->addr_count
] = NULL
;
1691 free_build_hostent(build_hostent_t
*h
)
1696 if (h
== NULL
) return;
1698 if (h
->host
.h_name
!= NULL
) free(h
->host
.h_name
);
1699 h
->host
.h_name
= NULL
;
1701 aliases
= h
->host
.h_aliases
;
1702 if (aliases
!= NULL
)
1704 while (*aliases
!= NULL
) free(*aliases
++);
1705 free(h
->host
.h_aliases
);
1708 h
->host
.h_aliases
= NULL
;
1710 if (h
->host
.h_addr_list
!= NULL
)
1712 for (i
= 0; h
->host
.h_addr_list
[i
] != NULL
; i
++) free(h
->host
.h_addr_list
[i
]);
1713 free(h
->host
.h_addr_list
);
1716 h
->host
.h_addr_list
= NULL
;
1721 si_ipnode_byname(si_mod_t
*si
, const char *name
, int family
, int flags
, const char *interface
, uint32_t *err
)
1723 int i
, status
, want
;
1725 struct in_addr addr4
;
1726 struct in6_addr addr6
;
1727 si_item_t
*item4
, *item6
;
1728 build_hostent_t
*out
;
1732 memset(&addr4
, 0, sizeof(struct in_addr
));
1733 memset(&addr6
, 0, sizeof(struct in6_addr
));
1735 if (err
!= NULL
) *err
= 0;
1737 if (family
== AF_INET
)
1739 status
= inet_aton(name
, &addr4
);
1742 /* create a host entry */
1743 item4
= make_hostent(si
, name
, addr4
);
1746 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1753 else if (family
== AF_INET6
)
1755 status
= inet_pton(family
, name
, &addr6
);
1758 /* create a host entry */
1759 item6
= make_hostent6(si
, name
, addr6
);
1762 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1769 status
= inet_aton(name
, &addr4
);
1772 if (!(flags
& (AI_V4MAPPED
| AI_V4MAPPED_CFG
)))
1774 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
1778 addr6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
1779 addr6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
1780 addr6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
1781 memmove(&(addr6
.__u6_addr
.__u6_addr32
[3]), &(addr4
.s_addr
), IPV4_ADDR_LEN
);
1783 /* create a host entry */
1784 item6
= make_hostent6(si
, name
, addr6
);
1787 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1796 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1801 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
1807 if (flags
& AI_ADDRCONFIG
)
1809 if (si_inet_config(&if4
, &if6
) < 0)
1811 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1815 /* Bail out if there are no interfaces */
1816 if ((if4
== 0) && (if6
== 0))
1818 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1824 * Figure out what we want.
1825 * If user asked for AF_INET, we only want V4 addresses.
1827 want
= WANT_A4_ONLY
;
1829 if (family
== AF_INET
)
1831 if ((flags
& AI_ADDRCONFIG
) && (if4
== 0))
1833 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1837 else if (family
== AF_INET6
)
1839 /* family == AF_INET6 */
1840 want
= WANT_A6_ONLY
;
1842 if (flags
& (AI_V4MAPPED
| AI_V4MAPPED_CFG
))
1846 want
= WANT_A6_PLUS_MAPPED_A4
;
1850 want
= WANT_A6_OR_MAPPED_A4_IF_NO_A6
;
1855 if ((flags
& AI_ADDRCONFIG
) && (if6
== 0))
1857 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1864 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1871 /* fetch IPv6 data if required */
1872 if ((want
== WANT_A6_ONLY
) || (want
== WANT_A6_OR_MAPPED_A4_IF_NO_A6
) || (want
== WANT_A6_PLUS_MAPPED_A4
))
1874 item6
= si_host_byname(si
, name
, AF_INET6
, interface
, (uint32_t *)err
);
1877 /* fetch IPv4 data if required */
1878 if ((want
== WANT_A4_ONLY
) || (want
== WANT_A6_PLUS_MAPPED_A4
) || ((want
== WANT_A6_OR_MAPPED_A4_IF_NO_A6
) && (item6
== NULL
)))
1880 item4
= si_host_byname(si
, name
, AF_INET
, interface
, (uint32_t *)err
);
1883 if (want
== WANT_A4_ONLY
)
1885 si_item_release(item6
);
1886 if ((item4
== NULL
) && (err
!= NULL
)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
1890 if (want
== WANT_A6_ONLY
)
1892 si_item_release(item4
);
1893 if ((item6
== NULL
) && (err
!= NULL
)) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
1897 if ((item6
== NULL
) && (item4
== NULL
))
1899 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_HOST_NOT_FOUND
;
1903 /* output item will have IPv6 + mapped IPv4 addresses */
1905 out
= (build_hostent_t
*)calloc(1, sizeof(build_hostent_t
));
1908 si_item_release(item4
);
1909 si_item_release(item6
);
1910 if (err
!= NULL
) *err
= SI_STATUS_H_ERRNO_NO_RECOVERY
;
1916 h
= (struct hostent
*)((uintptr_t)item4
+ sizeof(si_item_t
));
1918 out
->host
.h_name
= lower_case(h
->h_name
);
1920 if (h
->h_aliases
!= NULL
)
1922 for (i
= 0; h
->h_aliases
[i
] != NULL
; i
++) merge_alias(h
->h_aliases
[i
], out
);
1925 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++)
1927 addr6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
1928 addr6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
1929 addr6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
1930 memmove(&(addr6
.__u6_addr
.__u6_addr32
[3]), h
->h_addr_list
[i
], IPV4_ADDR_LEN
);
1931 append_addr((const char *)&addr6
, IPV6_ADDR_LEN
, out
);
1937 h
= (struct hostent
*)((uintptr_t)item6
+ sizeof(si_item_t
));
1939 if (out
->host
.h_name
== NULL
) out
->host
.h_name
= lower_case(h
->h_name
);
1941 if (h
->h_aliases
!= NULL
)
1943 for (i
= 0; h
->h_aliases
[i
] != NULL
; i
++) merge_alias(h
->h_aliases
[i
], out
);
1946 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++) append_addr(h
->h_addr_list
[i
], IPV6_ADDR_LEN
, out
);
1949 si_item_release(item4
);
1950 si_item_release(item6
);
1954 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
);
1956 free_build_hostent(out
);