]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/ev_ipv6.c
configd-801.1.1.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / ev_ipv6.c
1 /*
2 * Copyright (c) 2002-2007, 2011, 2013, 2015 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 int 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 SC_log(LOG_DEBUG, "Update interface configuration: %@: <removed>", key);
242 cache_SCDynamicStoreRemoveValue(store, key);
243 }
244 network_changed = TRUE;
245 }
246
247 return;
248 }
249
250
251 __private_extern__
252 void
253 interface_update_ipv6(struct ifaddrs *ifap, const char *if_name)
254 {
255 struct ifaddrs *ifa;
256 struct ifaddrs *ifap_temp = NULL;
257 CFStringRef interface;
258 boolean_t interfaceFound = FALSE;
259 CFStringRef key = NULL;
260 CFMutableDictionaryRef oldIFs;
261 CFMutableDictionaryRef newDict = NULL;
262 CFMutableDictionaryRef newIFs;
263 int sock = -1;
264
265 oldIFs = CFDictionaryCreateMutable(NULL,
266 0,
267 &kCFTypeDictionaryKeyCallBacks,
268 &kCFTypeDictionaryValueCallBacks);
269 newIFs = CFDictionaryCreateMutable(NULL,
270 0,
271 &kCFTypeDictionaryKeyCallBacks,
272 &kCFTypeDictionaryValueCallBacks);
273
274 if (!ifap) {
275 if (getifaddrs(&ifap_temp) == -1) {
276 SC_log(LOG_NOTICE, "getifaddrs() failed: %s", strerror(errno));
277 goto error;
278 }
279 ifap = ifap_temp;
280 }
281
282 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
283 struct in6_ifreq ifr6;
284 #define flags6 ifr6.ifr_ifru.ifru_flags6
285 struct sockaddr_in6 *sin6;
286
287 if (ifa->ifa_addr->sa_family != AF_INET6) {
288 continue; /* sorry, not interested */
289 }
290
291 /* check if this is the requested interface */
292 if (if_name) {
293 if (strncmp(if_name, ifa->ifa_name, IFNAMSIZ) == 0) {
294 interfaceFound = TRUE; /* yes, this is the one I want */
295 } else {
296 continue; /* sorry, not interested */
297 }
298 }
299
300 if (sock == -1) {
301 sock = dgram_socket(AF_INET6);
302 if (sock == -1) {
303 goto error;
304 }
305 }
306
307 /* get the current cache information */
308 interface = CFStringCreateWithCString(NULL, ifa->ifa_name, kCFStringEncodingMacRoman);
309 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
310 kSCDynamicStoreDomainState,
311 interface,
312 kSCEntNetIPv6);
313 CFRelease(interface);
314
315 newDict = copyIF(key, oldIFs, newIFs);
316
317 /* ALIGN: ifa->ifa_addr aligned (getifaddrs), cast ok. */
318 sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
319
320 /* XXX: embedded link local addr check */
321 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
322 u_int16_t index;
323
324 index = sin6->sin6_addr.s6_addr16[1];
325 if (index != 0) {
326 sin6->sin6_addr.s6_addr16[1] = 0;
327 if (sin6->sin6_scope_id == 0) {
328 sin6->sin6_scope_id = ntohs(index);
329 }
330 }
331 }
332
333 bzero((char *)&ifr6, sizeof(ifr6));
334 strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
335 ifr6.ifr_addr = *sin6;
336 if (ioctl(sock, SIOCGIFAFLAG_IN6, &ifr6) == -1) {
337 /* if flags not available for this address */
338 SC_log((errno != EADDRNOTAVAIL) ? LOG_NOTICE : LOG_DEBUG, "ioctl() failed: %s",
339 strerror(errno));
340 }
341
342 appendAddress (newDict, kSCPropNetIPv6Addresses, sin6);
343 #ifdef NOTYET
344 appendScopeID (newDict, sin6);
345 #endif /* NOTYET */
346 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok.
347 * appendPrefixLen expect byte alignment */
348 appendPrefixLen(newDict, (struct sockaddr_in6 *)(void *)ifa->ifa_netmask);
349 appendFlags (newDict, flags6);
350
351
352 if (ifa->ifa_flags & IFF_POINTOPOINT
353 && ifa->ifa_dstaddr != NULL) {
354 struct sockaddr_in6 *dst6;
355
356 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */
357 dst6 = (struct sockaddr_in6 *)(void *)ifa->ifa_dstaddr;
358
359 /* XXX: embedded link local addr check */
360 if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6->sin6_addr)) {
361 u_int16_t index;
362
363 index = dst6->sin6_addr.s6_addr16[1];
364 if (index != 0) {
365 dst6->sin6_addr.s6_addr16[1] = 0;
366 if (dst6->sin6_scope_id == 0) {
367 dst6->sin6_scope_id = ntohs(index);
368 }
369 }
370 }
371
372 appendAddress(newDict, kSCPropNetIPv6DestAddresses, dst6);
373 }
374
375 CFDictionarySetValue(newIFs, key, newDict);
376 CFRelease(newDict);
377 CFRelease(key);
378 }
379
380 /* if the last address[es] were removed from the target interface */
381 if (if_name && !interfaceFound) {
382 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
383 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
384 kSCDynamicStoreDomainState,
385 interface,
386 kSCEntNetIPv6);
387 CFRelease(interface);
388
389 newDict = copyIF(key, oldIFs, newIFs);
390
391 CFDictionarySetValue(newIFs, key, newDict);
392 CFRelease(newDict);
393 CFRelease(key);
394 }
395
396 CFDictionaryApplyFunction(newIFs, updateStore, oldIFs);
397
398 error :
399
400 if (ifap_temp) freeifaddrs(ifap_temp);
401 if (sock != -1) close(sock);
402 CFRelease(oldIFs);
403 CFRelease(newIFs);
404
405 return;
406 }
407
408 __private_extern__
409 void
410 ipv6_duplicated_address(const char * if_name, const struct in6_addr * addr,
411 int hw_len, const void * hw_addr)
412 {
413 uint8_t * hw_addr_bytes = (uint8_t *)hw_addr;
414 int i;
415 CFStringRef if_name_cf;
416 CFMutableStringRef key;
417 char ntopbuf[INET6_ADDRSTRLEN];
418 CFStringRef prefix;
419
420 if_name_cf = CFStringCreateWithCString(NULL, if_name,
421 kCFStringEncodingASCII);
422 prefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
423 kSCDynamicStoreDomainState,
424 if_name_cf,
425 kSCEntNetIPv6DuplicatedAddress);
426 ntopbuf[0] = '\0';
427 (void)inet_ntop(AF_INET6, addr, ntopbuf, sizeof(ntopbuf));
428 key = CFStringCreateMutableCopy(NULL, 0, prefix);
429 CFStringAppendFormat(key, NULL, CFSTR("/%s"), ntopbuf);
430 for (i = 0; i < hw_len; i++) {
431 CFStringAppendFormat(key, NULL, CFSTR("%s%02x"),
432 (i == 0) ? "/" : ":", hw_addr_bytes[i]);
433 }
434 cache_SCDynamicStoreNotifyValue(store, key);
435 CFRelease(key);
436 CFRelease(prefix);
437 CFRelease(if_name_cf);
438 }