3 * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * utility functions common to all posix implementations (e.g., MacOS, Linux).
22 #include <netinet/in.h>
24 #include <netinet/in_var.h>
25 #include <sys/ioctl.h>
30 #include <arpa/inet.h>
36 typedef struct interface_addr interface_addr_t
;
37 struct interface_addr
{
38 interface_addr_t
*next
;
44 interface_addr_t
*interface_addresses
;
47 ioloop_map_interface_addresses(void *context
, interface_callback_t callback
)
49 struct ifaddrs
*ifaddrs
, *ifp
;
50 interface_addr_t
*kept_ifaddrs
= NULL
, **ki_end
= &kept_ifaddrs
;
51 interface_addr_t
*new_ifaddrs
= NULL
, **ni_end
= &new_ifaddrs
;
52 interface_addr_t
**ip
, *nif
;
54 if (getifaddrs(&ifaddrs
) < 0) {
55 ERROR("getifaddrs failed: " PUB_S_SRP
, strerror(errno
));
59 for (ifp
= ifaddrs
; ifp
; ifp
= ifp
->ifa_next
) {
63 // Check for temporary addresses, etc.
64 if (ifp
->ifa_addr
!= NULL
&& ifp
->ifa_addr
->sa_family
== AF_INET6
) {
65 struct in6_ifreq ifreq
;
67 strlcpy(ifreq
.ifr_name
, ifp
->ifa_name
, sizeof(ifp
->ifa_name
));
68 if ((sock
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
69 ERROR("socket(AF_INET6, SOCK_DGRAM): " PUB_S_SRP
, strerror(errno
));
72 memcpy(&ifreq
.ifr_addr
, ifp
->ifa_addr
, sizeof ifreq
.ifr_addr
);
73 if (ioctl(sock
, SIOCGIFAFLAG_IN6
, &ifreq
) < 0) {
74 ERROR("ioctl(SIOCGIFAFLAG_IN6): " PUB_S_SRP
, strerror(errno
));
78 uint32_t flags
= ifreq
.ifr_ifru
.ifru_flags6
;
79 if (flags
& (IN6_IFF_ANYCAST
| IN6_IFF_TENTATIVE
| IN6_IFF_DETACHED
| IN6_IFF_TEMPORARY
)) {
82 if (flags
& IN6_IFF_DEPRECATED
) {
89 if (ifp
->ifa_addr
!= NULL
&& ifp
->ifa_addr
->sa_family
!= AF_INET
&& ifp
->ifa_addr
->sa_family
!= AF_INET6
) {
90 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifp
->ifa_addr
;
91 const uint8_t *addr
= (uint8_t *)LLADDR(sdl
);
92 INFO("%.*s index %d alen %d dlen %d SDL: %02x:%02x:%02x:%02x:%02x:%02x",
93 sdl
->sdl_nlen
, sdl
->sdl_data
, sdl
->sdl_index
, sdl
->sdl_alen
, sdl
->sdl_slen
,
94 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
96 #endif // DEBUG_AF_LINK
98 // Is this an interface address we can use?
99 if (keep
&& ifp
->ifa_addr
!= NULL
&&
100 (ifp
->ifa_addr
->sa_family
== AF_LINK
||
101 ((ifp
->ifa_addr
->sa_family
== AF_INET6
|| ifp
->ifa_addr
->sa_family
== AF_INET
) && ifp
->ifa_netmask
!= NULL
)
103 (ifp
->ifa_flags
& IFF_UP
))
106 for (ip
= &interface_addresses
; *ip
!= NULL
; ) {
107 interface_addr_t
*ia
= *ip
;
108 // Same interface and address?
109 if (!remove
&& !strcmp(ia
->name
, ifp
->ifa_name
) &&
110 ifp
->ifa_addr
->sa_family
== ia
->addr
.sa
.sa_family
&&
111 (ifp
->ifa_addr
->sa_family
== AF_LINK
||
112 (((ifp
->ifa_addr
->sa_family
== AF_INET
&&
113 ((struct sockaddr_in
*)ifp
->ifa_addr
)->sin_addr
.s_addr
== ia
->addr
.sin
.sin_addr
.s_addr
) ||
114 (ifp
->ifa_addr
->sa_family
== AF_INET6
&&
115 !memcmp(&((struct sockaddr_in6
*)ifp
->ifa_addr
)->sin6_addr
,
116 &ia
->addr
.sin6
.sin6_addr
, sizeof ia
->addr
.sin6
.sin6_addr
))) &&
117 ((ifp
->ifa_netmask
->sa_family
== AF_INET
&&
118 ((struct sockaddr_in
*)ifp
->ifa_netmask
)->sin_addr
.s_addr
== ia
->mask
.sin
.sin_addr
.s_addr
) ||
119 (ifp
->ifa_netmask
->sa_family
== AF_INET6
&&
120 !memcmp(&((struct sockaddr_in6
*)ifp
->ifa_netmask
)->sin6_addr
,
121 &ia
->mask
.sin6
.sin6_addr
, sizeof ia
->mask
.sin6
.sin6_addr
))))))
133 // If keep is false, this is a new interface/address.
135 size_t len
= strlen(ifp
->ifa_name
);
136 nif
= calloc(1, len
+ 1 + sizeof *nif
);
137 // We don't have a way to fix nif being null; what this means is that we don't detect a new
138 // interface address.
140 nif
->name
= (char *)(nif
+ 1);
141 strlcpy(nif
->name
, ifp
->ifa_name
, len
+ 1);
142 if (ifp
->ifa_addr
->sa_family
== AF_INET
) {
143 nif
->addr
.sin
= *((struct sockaddr_in
*)ifp
->ifa_addr
);
144 nif
->mask
.sin
= *((struct sockaddr_in
*)ifp
->ifa_netmask
);
146 IPv4_ADDR_GEN_SRP(&nif
->mask
.sin
.sin_addr
.s_addr
, __new_interface_ipv4_addr
);
147 INFO("ioloop_map_interface_addresses: new IPv4 interface address added - ifname: " PUB_S_SRP
148 ", addr: " PRI_IPv4_ADDR_SRP
, nif
->name
,
149 IPv4_ADDR_PARAM_SRP(&nif
->mask
.sin
.sin_addr
.s_addr
, __new_interface_ipv4_addr
));
150 } else if (ifp
->ifa_addr
->sa_family
== AF_INET6
) {
151 nif
->addr
.sin6
= *((struct sockaddr_in6
*)ifp
->ifa_addr
);
152 nif
->mask
.sin6
= *((struct sockaddr_in6
*)ifp
->ifa_netmask
);
154 SEGMENTED_IPv6_ADDR_GEN_SRP(nif
->addr
.sin6
.sin6_addr
.s6_addr
, __new_interface_ipv6_addr
);
155 INFO("ioloop_map_interface_addresses: new IPv6 interface address added - ifname: " PUB_S_SRP
156 ", addr: " PRI_SEGMENTED_IPv6_ADDR_SRP
, nif
->name
,
157 SEGMENTED_IPv6_ADDR_PARAM_SRP(nif
->addr
.sin6
.sin6_addr
.s6_addr
,
158 __new_interface_ipv6_addr
));
160 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifp
->ifa_addr
;
161 memset(&nif
->mask
, 0, sizeof(nif
->mask
));
162 if (sdl
->sdl_alen
== 6) {
163 nif
->addr
.ether_addr
.len
= 6;
164 memcpy(nif
->addr
.ether_addr
.addr
, LLADDR(sdl
), 6);
166 nif
->addr
.ether_addr
.len
= 0;
168 nif
->addr
.ether_addr
.index
= sdl
->sdl_index
;
169 nif
->addr
.ether_addr
.family
= AF_LINK
;
171 nif
->flags
= ifp
->ifa_flags
;
179 // Get rid of any link-layer addresses for which there is no other address on that interface
180 // This is clunky, but we can't assume that the AF_LINK address will come after some other
181 // address, so there's no more efficient way to do this that I can think of.
182 for (ip
= &new_ifaddrs
; *ip
; ) {
183 if ((*ip
)->addr
.sa
.sa_family
== AF_LINK
) {
185 for (nif
= new_ifaddrs
; nif
; nif
= nif
->next
) {
186 if (nif
!= *ip
&& !strcmp(nif
->name
, (*ip
)->name
)) {
206 for (i
= 0; i
< 3; i
++) {
207 char *infop
= infobuf
;
208 int len
, lim
= sizeof infobuf
;
213 nif
= interface_addresses
;
226 for (; nif
; nif
= nif
->next
) {
227 snprintf(infop
, lim
, " %p (", nif
);
228 len
= (int)strlen(infop
);
231 inet_ntop(AF_INET6
, &nif
->addr
.sin6
.sin6_addr
, infop
, lim
);
232 len
= (int)strlen(infop
);
241 INFO(PUB_S_SRP
":" PUB_S_SRP
, title
, infobuf
);
245 // Report and free deleted interface addresses...
246 for (nif
= interface_addresses
; nif
; ) {
247 interface_addr_t
*next
= nif
->next
;
248 callback(context
, nif
->name
, &nif
->addr
, &nif
->mask
, nif
->flags
, interface_address_deleted
);
253 // Report added interface addresses...
254 for (nif
= new_ifaddrs
; nif
; nif
= nif
->next
) {
255 callback(context
, nif
->name
, &nif
->addr
, &nif
->mask
, nif
->flags
, interface_address_added
);
258 // Report unchanged interface addresses...
259 for (nif
= kept_ifaddrs
; nif
; nif
= nif
->next
) {
260 callback(context
, nif
->name
, &nif
->addr
, &nif
->mask
, nif
->flags
, interface_address_unchanged
);
263 // Restore kept interface addresses and append new addresses to the list.
264 interface_addresses
= kept_ifaddrs
;
265 for (ip
= &interface_addresses
; *ip
; ip
= &(*ip
)->next
)
268 freeifaddrs(ifaddrs
);
273 ioloop_recvmsg(int sock
, uint8_t *buffer
, size_t buffer_length
, int *ifindex
, int *hop_limit
, addr_t
*source
,
282 bufp
.iov_base
= buffer
;
283 bufp
.iov_len
= buffer_length
;
286 msg
.msg_name
= source
;
287 msg
.msg_namelen
= sizeof(*source
);
288 msg
.msg_control
= cmsgbuf
;
289 msg
.msg_controllen
= sizeof(cmsgbuf
);
291 rv
= recvmsg(sock
, &msg
, 0);
296 // For UDP, we use the interface index as part of the validation strategy, so go get
297 // the interface index.
298 for (cmh
= CMSG_FIRSTHDR(&msg
); cmh
; cmh
= CMSG_NXTHDR(&msg
, cmh
)) {
299 if (cmh
->cmsg_level
== IPPROTO_IPV6
&& cmh
->cmsg_type
== IPV6_PKTINFO
&&
300 cmh
->cmsg_len
== CMSG_LEN(sizeof(struct in6_pktinfo
)))
302 struct in6_pktinfo pktinfo
;
304 memcpy(&pktinfo
, CMSG_DATA(cmh
), sizeof pktinfo
);
305 *ifindex
= pktinfo
.ipi6_ifindex
;
307 /* Get the destination address, for use when replying. */
308 destination
->sin6
.sin6_family
= AF_INET6
;
309 destination
->sin6
.sin6_port
= 0;
310 destination
->sin6
.sin6_addr
= pktinfo
.ipi6_addr
;
311 #ifndef NOT_HAVE_SA_LEN
312 destination
->sin6
.sin6_len
= sizeof(destination
->sin6
);
314 } else if (cmh
->cmsg_level
== IPPROTO_IP
&& cmh
->cmsg_type
== IP_PKTINFO
&&
315 cmh
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
316 struct in_pktinfo pktinfo
;
318 memcpy(&pktinfo
, CMSG_DATA(cmh
), sizeof pktinfo
);
319 *ifindex
= pktinfo
.ipi_ifindex
;
321 destination
->sin
.sin_family
= AF_INET
;
322 destination
->sin
.sin_port
= 0;
323 destination
->sin
.sin_addr
= pktinfo
.ipi_addr
;
324 #ifndef NOT_HAVE_SA_LEN
325 destination
->sin
.sin_len
= sizeof(destination
->sin
);
327 } else if (cmh
->cmsg_level
== IPPROTO_IPV6
&& cmh
->cmsg_type
== IPV6_HOPLIMIT
&&
328 cmh
->cmsg_len
== CMSG_LEN(sizeof(int))) {
329 *hop_limit
= *(int *)CMSG_DATA(cmh
);
335 #ifdef DEBUG_FD_LEAKS
339 DIR *dirfd
= opendir("/dev/fd");
344 while (readdir(dirfd
) != NULL
) {
350 #endif // DEBUG_VERBOSE
355 // c-file-style: "bsd"
358 // indent-tabs-mode: nil