1 /* posix.c
2  *
3  * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
4  *
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  * utility functions common to all posix implementations (e.g., MacOS, Linux).
18  */
19 
20 #define _GNU_SOURCE
21 
22 #include <netinet/in.h>
23 #include <net/if.h>
24 #include <netinet/in_var.h>
25 #include <sys/ioctl.h>
26 #include <errno.h>
27 #include <ifaddrs.h>
28 #include <stdlib.h>
29 #include <dirent.h>
30 #include <arpa/inet.h>
31 #include "dns_sd.h"
32 #include "srp.h"
33 #include "dns-msg.h"
34 #include "ioloop.h"
35 
36 typedef struct interface_addr interface_addr_t;
37 struct interface_addr {
38     interface_addr_t *next;
39     char *name;
40     addr_t addr;
41     addr_t mask;
42     uint32_t flags;
43 };
44 interface_addr_t *interface_addresses;
45 
46 bool
ioloop_map_interface_addresses(void * context,interface_callback_t callback)47 ioloop_map_interface_addresses(void *context, interface_callback_t callback)
48 {
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;
53 
54     if (getifaddrs(&ifaddrs) < 0) {
55         ERROR("getifaddrs failed: " PUB_S_SRP, strerror(errno));
56         return false;
57     }
58 
59     for (ifp = ifaddrs; ifp; ifp = ifp->ifa_next) {
60         bool remove = false;
61         bool keep = true;
62 
63         // Check for temporary addresses, etc.
64         if (ifp->ifa_addr != NULL && ifp->ifa_addr->sa_family == AF_INET6) {
65             struct in6_ifreq ifreq;
66             int sock;
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));
70                 continue;
71             }
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));
75                 close(sock);
76                 continue;
77             }
78             uint32_t flags = ifreq.ifr_ifru.ifru_flags6;
79             if (flags & (IN6_IFF_ANYCAST | IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_TEMPORARY)) {
80                 keep = false;
81             }
82             if (flags & IN6_IFF_DEPRECATED) {
83                 remove = true;
84             }
85             close(sock);
86         }
87 
88 #ifdef DEBUG_AF_LINK
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]);
95         }
96 #endif // DEBUG_AF_LINK
97 
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)
102              ) &&
103             (ifp->ifa_flags & IFF_UP))
104         {
105             keep = false;
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))))))
122                 {
123                     *ip = ia->next;
124                     *ki_end = ia;
125                     ki_end = &ia->next;
126                     ia->next = NULL;
127                     keep = true;
128                     break;
129                 } else {
130                     ip = &ia->next;
131                 }
132             }
133             // If keep is false, this is a new interface/address.
134             if (!keep) {
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.
139                 if (nif != NULL) {
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);
145 
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);
153 
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));
159                     } else {
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);
165                         } else {
166                             nif->addr.ether_addr.len = 0;
167                         }
168                         nif->addr.ether_addr.index = sdl->sdl_index;
169                         nif->addr.ether_addr.family = AF_LINK;
170                     }
171                     nif->flags = ifp->ifa_flags;
172                     *ni_end = nif;
173                     ni_end = &nif->next;
174                 }
175             }
176         }
177     }
178 
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) {
184             bool drop = true;
185             for (nif = new_ifaddrs; nif; nif = nif->next) {
186                 if (nif != *ip && !strcmp(nif->name, (*ip)->name)) {
187                     drop = false;
188                     break;
189                 }
190             }
191             if (drop) {
192                 nif = *ip;
193                 *ip = nif->next;
194                 free(nif);
195             } else {
196                 ip = &(*ip)->next;
197             }
198         } else {
199             ip = &(*ip)->next;
200         }
201     }
202 
203 #ifdef TOO_MUCH_INFO
204     char infobuf[1000];
205     int i;
206     for (i = 0; i < 3; i++) {
207         char *infop = infobuf;
208         int len, lim = sizeof infobuf;
209         const char *title;
210         switch(i) {
211         case 0:
212             title = "deleted";
213             nif = interface_addresses;
214             break;
215         case 1:
216             title = "   kept";
217             nif = kept_ifaddrs;
218             break;
219         case 2:
220             title = "    new";
221             nif = new_ifaddrs;
222             break;
223         default:
224             abort();
225         }
226         for (; nif; nif = nif->next) {
227             snprintf(infop, lim, " %p (", nif);
228             len = (int)strlen(infop);
229             lim -= len;
230             infop += len;
231             inet_ntop(AF_INET6, &nif->addr.sin6.sin6_addr, infop, lim);
232             len = (int)strlen(infop);
233             lim -= len;
234             infop += len;
235             if (lim > 1) {
236                 *infop++ = ')';
237                 lim--;
238             }
239         }
240         *infop = 0;
241         INFO(PUB_S_SRP ":" PUB_S_SRP, title, infobuf);
242     }
243 #endif
244 
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);
249         free(nif);
250         nif = next;
251     }
252 
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);
256     }
257 
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);
261     }
262 
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)
266         ;
267     *ip = new_ifaddrs;
268     freeifaddrs(ifaddrs);
269     return true;
270 }
271 
272 ssize_t
ioloop_recvmsg(int sock,uint8_t * buffer,size_t buffer_length,int * ifindex,int * hop_limit,addr_t * source,addr_t * destination)273 ioloop_recvmsg(int sock, uint8_t *buffer, size_t buffer_length, int *ifindex, int *hop_limit, addr_t *source,
274                addr_t *destination)
275 {
276     ssize_t rv;
277     struct msghdr msg;
278     struct iovec bufp;
279     char cmsgbuf[128];
280     struct cmsghdr *cmh;
281 
282     bufp.iov_base = buffer;
283     bufp.iov_len = buffer_length;
284     msg.msg_iov = &bufp;
285     msg.msg_iovlen = 1;
286     msg.msg_name = source;
287     msg.msg_namelen = sizeof(*source);
288     msg.msg_control = cmsgbuf;
289     msg.msg_controllen = sizeof(cmsgbuf);
290 
291     rv = recvmsg(sock, &msg, 0);
292     if (rv < 0) {
293         return rv;
294     }
295 
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)))
301         {
302             struct in6_pktinfo pktinfo;
303 
304             memcpy(&pktinfo, CMSG_DATA(cmh), sizeof pktinfo);
305             *ifindex = pktinfo.ipi6_ifindex;
306 
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);
313 #endif
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;
317 
318             memcpy(&pktinfo, CMSG_DATA(cmh), sizeof pktinfo);
319             *ifindex = pktinfo.ipi_ifindex;
320 
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);
326 #endif
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);
330         }
331     }
332     return rv;
333 }
334 
335 #ifdef DEBUG_FD_LEAKS
336 int
get_num_fds(void)337 get_num_fds(void)
338 {
339     DIR *dirfd = opendir("/dev/fd");
340     int num = 0;
341     if (dirfd == NULL) {
342         return -1;
343     }
344     while (readdir(dirfd) != NULL) {
345         num++;
346     }
347     closedir(dirfd);
348     return num;
349 }
350 #endif // DEBUG_VERBOSE
351 
352 // Local Variables:
353 // mode: C
354 // tab-width: 4
355 // c-file-style: "bsd"
356 // c-basic-offset: 4
357 // fill-column: 108
358 // indent-tabs-mode: nil
359 // End:
360