]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/ev_ipv6.c
configd-1061.0.2.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / ev_ipv6.c
1 /*
2 * Copyright (c) 2002-2007, 2011, 2013, 2015, 2017, 2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * August 5, 2002 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include "eventmon.h"
33 #include "ev_ipv6.h"
34
35 #define s6_addr16 __u6_addr.__u6_addr16
36
37 #ifdef NOTYET
38 #ifndef kSCPropNetIPv6ScopeID
39 #define kSCPropNetIPv6ScopeID SCSTR("ScopeID")
40 #endif
41 #endif /* NOTYET */
42
43 #ifndef kSCEntNetIPv6DuplicatedAddress
44 #define kSCEntNetIPv6DuplicatedAddress CFSTR("IPv6DuplicatedAddress")
45 #endif /* kSCEntNetIPv6DuplicatedAddress */
46
47 static void
48 appendAddress(CFMutableDictionaryRef dict, CFStringRef key, struct sockaddr_in6 *sin6)
49 {
50 CFStringRef addr;
51 CFArrayRef addrs;
52 CFMutableArrayRef newAddrs;
53 char str[INET6_ADDRSTRLEN];
54
55 addrs = CFDictionaryGetValue(dict, key);
56 if (addrs) {
57 newAddrs = CFArrayCreateMutableCopy(NULL, 0, addrs);
58 } else {
59 newAddrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
60 }
61
62 if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr, str, sizeof(str)) == NULL) {
63 SC_log(LOG_INFO, "inet_ntop() failed: %s", strerror(errno));
64 str[0] = '\0';
65 }
66
67 addr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), str);
68 CFArrayAppendValue(newAddrs, addr);
69 CFRelease(addr);
70
71 CFDictionarySetValue(dict, key, newAddrs);
72 CFRelease(newAddrs);
73 return;
74 }
75
76
77 static void
78 appendFlags(CFMutableDictionaryRef dict, int flags6)
79 {
80 CFArrayRef flags;
81 CFMutableArrayRef newFlags;
82 CFNumberRef v6Flags;
83
84 flags = CFDictionaryGetValue(dict, kSCPropNetIPv6Flags);
85 if (flags) {
86 newFlags = CFArrayCreateMutableCopy(NULL, 0, flags);
87 } else {
88 newFlags = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
89 }
90
91 v6Flags = CFNumberCreate(NULL, kCFNumberIntType, &flags6);
92 CFArrayAppendValue(newFlags, v6Flags);
93 CFRelease(v6Flags);
94
95 CFDictionarySetValue(dict, kSCPropNetIPv6Flags, newFlags);
96 CFRelease(newFlags);
97 return;
98 }
99
100
101 static void
102 appendPrefixLen(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6)
103 {
104 register u_int8_t *name = &sin6->sin6_addr.s6_addr[0];
105 CFNumberRef prefixLen;
106 CFArrayRef prefixLens;
107 CFMutableArrayRef newPrefixLens;
108
109 register size_t byte;
110 register int bit;
111 int plen = 0;
112
113 for (byte = 0; byte < sizeof(struct in6_addr); byte++, plen += 8) {
114 if (name[byte] != 0xff) {
115 break;
116 }
117 }
118
119 if (byte == sizeof(struct in6_addr)) {
120 goto append;
121 }
122
123 for (bit = 7; bit != 0; bit--, plen++) {
124 if (!(name[byte] & (1 << bit))) {
125 break;
126 }
127 }
128
129 for (; bit != 0; bit--) {
130 if (name[byte] & (1 << bit)) {
131 plen = 0;
132 goto append;
133 }
134 }
135
136 byte++;
137 for (; byte < sizeof(struct in6_addr); byte++) {
138 if (name[byte]) {
139 plen = 0;
140 goto append;
141 }
142 }
143
144 append :
145
146 prefixLens = CFDictionaryGetValue(dict, kSCPropNetIPv6PrefixLength);
147 if (prefixLens) {
148 newPrefixLens = CFArrayCreateMutableCopy(NULL, 0, prefixLens);
149 } else {
150 newPrefixLens = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
151 }
152
153 prefixLen = CFNumberCreate(NULL, kCFNumberIntType, &plen);
154 CFArrayAppendValue(newPrefixLens, prefixLen);
155 CFRelease(prefixLen);
156
157 CFDictionarySetValue(dict, kSCPropNetIPv6PrefixLength, newPrefixLens);
158 CFRelease(newPrefixLens);
159 return;
160 }
161
162
163 #ifdef NOTYET
164 static void
165 appendScopeID(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6)
166 {
167 CFNumberRef scope;
168 CFArrayRef scopes;
169 CFMutableArrayRef newScopes;
170
171 scopes = CFDictionaryGetValue(dict, kSCPropNetIPv6ScopeID);
172 if (scopes) {
173 newScopes = CFArrayCreateMutableCopy(NULL, 0, scopes);
174 } else {
175 newScopes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
176 }
177
178 scope = CFNumberCreate(NULL, kCFNumberSInt32Type, &sin6->sin6_scope_id);
179 CFArrayAppendValue(newScopes, scope);
180 CFRelease(scope);
181
182 CFDictionarySetValue(dict, kSCPropNetIPv6ScopeID, newScopes);
183 CFRelease(newScopes);
184 return;
185 }
186 #endif /* NOTYET */
187
188
189 static CFMutableDictionaryRef
190 copyIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs)
191 {
192 CFDictionaryRef dict = NULL;
193 CFMutableDictionaryRef newDict = NULL;
194
195 if (CFDictionaryGetValueIfPresent(newIFs, key, (const void **)&dict)) {
196 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
197 } else {
198 dict = SCDynamicStoreCopyValue(store, key);
199 if (dict) {
200 CFDictionarySetValue(oldIFs, key, dict);
201 if (isA_CFDictionary(dict)) {
202 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
203 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6Addresses);
204 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6DestAddresses);
205 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6Flags);
206 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6PrefixLength);
207 #ifdef NOTYET
208 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6ScopeID);
209 #endif /* NOTYET */
210 }
211 CFRelease(dict);
212 }
213 }
214
215 if (!newDict) {
216 newDict = CFDictionaryCreateMutable(NULL,
217 0,
218 &kCFTypeDictionaryKeyCallBacks,
219 &kCFTypeDictionaryValueCallBacks);
220 }
221
222 return newDict;
223 }
224
225
226 static void
227 updateStore(const void *key, const void *value, void *context)
228 {
229 CFDictionaryRef dict;
230 CFDictionaryRef newDict = (CFDictionaryRef)value;
231 CFDictionaryRef oldIFs = (CFDictionaryRef)context;
232
233 dict = CFDictionaryGetValue(oldIFs, key);
234
235 if (!dict || !CFEqual(dict, newDict)) {
236 if (CFDictionaryGetCount(newDict) > 0) {
237 SC_log(LOG_DEBUG, "Update interface configuration: %@: %@", key, newDict);
238 SCDynamicStoreSetValue(store, key, newDict);
239 } else if (dict) {
240 CFDictionaryRef oldDict;
241
242 oldDict = SCDynamicStoreCopyValue(store, key);
243 if (oldDict != NULL) {
244 SC_log(LOG_DEBUG, "Update interface configuration: %@: <removed>", key);
245 CFRelease(oldDict);
246 }
247 SCDynamicStoreRemoveValue(store, key);
248 }
249 network_changed = TRUE;
250 }
251
252 return;
253 }
254
255
256 __private_extern__
257 void
258 interface_update_ipv6(struct ifaddrs *ifap, const char *if_name)
259 {
260 struct ifaddrs *ifa;
261 struct ifaddrs *ifap_temp = NULL;
262 CFStringRef interface;
263 boolean_t interfaceFound = FALSE;
264 CFStringRef key = NULL;
265 CFMutableDictionaryRef oldIFs;
266 CFMutableDictionaryRef newDict = NULL;
267 CFMutableDictionaryRef newIFs;
268 int sock = -1;
269
270 oldIFs = CFDictionaryCreateMutable(NULL,
271 0,
272 &kCFTypeDictionaryKeyCallBacks,
273 &kCFTypeDictionaryValueCallBacks);
274 newIFs = CFDictionaryCreateMutable(NULL,
275 0,
276 &kCFTypeDictionaryKeyCallBacks,
277 &kCFTypeDictionaryValueCallBacks);
278
279 if (!ifap) {
280 if (getifaddrs(&ifap_temp) == -1) {
281 SC_log(LOG_NOTICE, "getifaddrs() failed: %s", strerror(errno));
282 goto error;
283 }
284 ifap = ifap_temp;
285 }
286
287 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
288 struct in6_ifreq ifr6;
289 #define flags6 ifr6.ifr_ifru.ifru_flags6
290 struct sockaddr_in6 *sin6;
291
292 if (ifa->ifa_addr->sa_family != AF_INET6) {
293 continue; /* sorry, not interested */
294 }
295
296 /* check if this is the requested interface */
297 if (if_name) {
298 if (strncmp(if_name, ifa->ifa_name, IFNAMSIZ) == 0) {
299 interfaceFound = TRUE; /* yes, this is the one I want */
300 } else {
301 continue; /* sorry, not interested */
302 }
303 }
304
305 if (sock == -1) {
306 sock = dgram_socket(AF_INET6);
307 if (sock == -1) {
308 goto error;
309 }
310 }
311
312 /* get the current cache information */
313 interface = CFStringCreateWithCString(NULL, ifa->ifa_name, kCFStringEncodingMacRoman);
314 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
315 kSCDynamicStoreDomainState,
316 interface,
317 kSCEntNetIPv6);
318 CFRelease(interface);
319
320 newDict = copyIF(key, oldIFs, newIFs);
321
322 /* ALIGN: ifa->ifa_addr aligned (getifaddrs), cast ok. */
323 sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
324
325 /* XXX: embedded link local addr check */
326 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
327 u_int16_t index;
328
329 index = sin6->sin6_addr.s6_addr16[1];
330 if (index != 0) {
331 sin6->sin6_addr.s6_addr16[1] = 0;
332 if (sin6->sin6_scope_id == 0) {
333 sin6->sin6_scope_id = ntohs(index);
334 }
335 }
336 }
337
338 memset((char *)&ifr6, 0, sizeof(ifr6));
339 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
340 ifr6.ifr_addr = *sin6;
341 if (ioctl(sock, SIOCGIFAFLAG_IN6, &ifr6) == -1) {
342 /* if flags not available for this address */
343 SC_log((errno != EADDRNOTAVAIL) ? LOG_NOTICE : LOG_DEBUG, "ioctl() failed: %s",
344 strerror(errno));
345 }
346
347 appendAddress (newDict, kSCPropNetIPv6Addresses, sin6);
348 #ifdef NOTYET
349 appendScopeID (newDict, sin6);
350 #endif /* NOTYET */
351 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok.
352 * appendPrefixLen expect byte alignment */
353 appendPrefixLen(newDict, (struct sockaddr_in6 *)(void *)ifa->ifa_netmask);
354 appendFlags (newDict, flags6);
355
356
357 if (ifa->ifa_flags & IFF_POINTOPOINT
358 && ifa->ifa_dstaddr != NULL) {
359 struct sockaddr_in6 *dst6;
360
361 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */
362 dst6 = (struct sockaddr_in6 *)(void *)ifa->ifa_dstaddr;
363
364 /* XXX: embedded link local addr check */
365 if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6->sin6_addr)) {
366 u_int16_t index;
367
368 index = dst6->sin6_addr.s6_addr16[1];
369 if (index != 0) {
370 dst6->sin6_addr.s6_addr16[1] = 0;
371 if (dst6->sin6_scope_id == 0) {
372 dst6->sin6_scope_id = ntohs(index);
373 }
374 }
375 }
376
377 appendAddress(newDict, kSCPropNetIPv6DestAddresses, dst6);
378 }
379
380 CFDictionarySetValue(newIFs, key, newDict);
381 CFRelease(newDict);
382 CFRelease(key);
383 }
384
385 /* if the last address[es] were removed from the target interface */
386 if (if_name && !interfaceFound) {
387 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
388 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
389 kSCDynamicStoreDomainState,
390 interface,
391 kSCEntNetIPv6);
392 CFRelease(interface);
393
394 newDict = copyIF(key, oldIFs, newIFs);
395
396 CFDictionarySetValue(newIFs, key, newDict);
397 CFRelease(newDict);
398 CFRelease(key);
399 }
400
401 CFDictionaryApplyFunction(newIFs, updateStore, oldIFs);
402
403 error :
404
405 if (ifap_temp) freeifaddrs(ifap_temp);
406 if (sock != -1) close(sock);
407 CFRelease(oldIFs);
408 CFRelease(newIFs);
409
410 return;
411 }
412
413 __private_extern__
414 void
415 ipv6_duplicated_address(const char * if_name, const struct in6_addr * addr,
416 int hw_len, const void * hw_addr)
417 {
418 uint8_t * hw_addr_bytes = (uint8_t *)hw_addr;
419 int i;
420 CFStringRef if_name_cf;
421 CFMutableStringRef key;
422 char ntopbuf[INET6_ADDRSTRLEN];
423 CFStringRef prefix;
424
425 if_name_cf = CFStringCreateWithCString(NULL, if_name,
426 kCFStringEncodingASCII);
427 prefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
428 kSCDynamicStoreDomainState,
429 if_name_cf,
430 kSCEntNetIPv6DuplicatedAddress);
431 ntopbuf[0] = '\0';
432 (void)inet_ntop(AF_INET6, addr, ntopbuf, sizeof(ntopbuf));
433 key = CFStringCreateMutableCopy(NULL, 0, prefix);
434 CFStringAppendFormat(key, NULL, CFSTR("/%s"), ntopbuf);
435 for (i = 0; i < hw_len; i++) {
436 CFStringAppendFormat(key, NULL, CFSTR("%s%02x"),
437 (i == 0) ? "/" : ":", hw_addr_bytes[i]);
438 }
439 SCDynamicStoreNotifyValue(store, key);
440 CFRelease(key);
441 CFRelease(prefix);
442 CFRelease(if_name_cf);
443 }
444
445 __private_extern__
446 void
447 nat64_prefix_request(const char *if_name)
448 {
449 CFStringRef if_name_cf;
450 CFStringRef key;
451
452 if_name_cf = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
453 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
454 kSCDynamicStoreDomainState,
455 if_name_cf,
456 kSCEntNetNAT64PrefixRequest);
457 CFRelease(if_name_cf);
458 SC_log(LOG_DEBUG, "Post NAT64 prefix request: %@", key);
459 SCDynamicStoreNotifyValue(store, key);
460 CFRelease(key);
461 }
462
463 __private_extern__ void
464 ipv6_router_expired(const char *if_name)
465 {
466 CFStringRef if_name_cf;
467 CFStringRef key;
468
469 if_name_cf = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
470 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
471 kSCDynamicStoreDomainState,
472 if_name_cf,
473 kSCEntNetIPv6RouterExpired);
474 CFRelease(if_name_cf);
475 SC_log(LOG_DEBUG, "Post IPv6 Router Expired: %@", key);
476 SCDynamicStoreNotifyValue(store, key);
477 CFRelease(key);
478 }