]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/posix.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / posix.c
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
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
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
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: