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