]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/ev_ipv6.c
configd-596.15.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / ev_ipv6.c
1 /*
2 * Copyright (c) 2002-2007, 2011, 2013 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
45 static void
46 appendAddress(CFMutableDictionaryRef dict, CFStringRef key, struct sockaddr_in6 *sin6)
47 {
48 CFStringRef addr;
49 CFArrayRef addrs;
50 CFMutableArrayRef newAddrs;
51 char str[64];
52
53 addrs = CFDictionaryGetValue(dict, key);
54 if (addrs) {
55 newAddrs = CFArrayCreateMutableCopy(NULL, 0, addrs);
56 } else {
57 newAddrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
58 }
59
60 if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr, str, sizeof(str)) == NULL) {
61 SCLog(TRUE, LOG_ERR, CFSTR("inet_ntop() failed: %s"), strerror(errno));
62 str[0] = '\0';
63 }
64
65 addr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), str);
66 CFArrayAppendValue(newAddrs, addr);
67 CFRelease(addr);
68
69 CFDictionarySetValue(dict, key, newAddrs);
70 CFRelease(newAddrs);
71 return;
72 }
73
74
75 static void
76 appendFlags(CFMutableDictionaryRef dict, int flags6)
77 {
78 CFArrayRef flags;
79 CFMutableArrayRef newFlags;
80 CFNumberRef v6Flags;
81
82 flags = CFDictionaryGetValue(dict, kSCPropNetIPv6Flags);
83 if (flags) {
84 newFlags = CFArrayCreateMutableCopy(NULL, 0, flags);
85 } else {
86 newFlags = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
87 }
88
89 v6Flags = CFNumberCreate(NULL, kCFNumberIntType, &flags6);
90 CFArrayAppendValue(newFlags, v6Flags);
91 CFRelease(v6Flags);
92
93 CFDictionarySetValue(dict, kSCPropNetIPv6Flags, newFlags);
94 CFRelease(newFlags);
95 return;
96 }
97
98
99 static void
100 appendPrefixLen(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6)
101 {
102 register u_int8_t *name = &sin6->sin6_addr.s6_addr[0];
103 CFNumberRef prefixLen;
104 CFArrayRef prefixLens;
105 CFMutableArrayRef newPrefixLens;
106
107 register int byte;
108 register int bit;
109 int plen = 0;
110
111 for (byte = 0; byte < sizeof(struct in6_addr); byte++, plen += 8) {
112 if (name[byte] != 0xff) {
113 break;
114 }
115 }
116
117 if (byte == sizeof(struct in6_addr)) {
118 goto append;
119 }
120
121 for (bit = 7; bit != 0; bit--, plen++) {
122 if (!(name[byte] & (1 << bit))) {
123 break;
124 }
125 }
126
127 for (; bit != 0; bit--) {
128 if (name[byte] & (1 << bit)) {
129 plen = 0;
130 goto append;
131 }
132 }
133
134 byte++;
135 for (; byte < sizeof(struct in6_addr); byte++) {
136 if (name[byte]) {
137 plen = 0;
138 goto append;
139 }
140 }
141
142 append :
143
144 prefixLens = CFDictionaryGetValue(dict, kSCPropNetIPv6PrefixLength);
145 if (prefixLens) {
146 newPrefixLens = CFArrayCreateMutableCopy(NULL, 0, prefixLens);
147 } else {
148 newPrefixLens = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
149 }
150
151 prefixLen = CFNumberCreate(NULL, kCFNumberIntType, &plen);
152 CFArrayAppendValue(newPrefixLens, prefixLen);
153 CFRelease(prefixLen);
154
155 CFDictionarySetValue(dict, kSCPropNetIPv6PrefixLength, newPrefixLens);
156 CFRelease(newPrefixLens);
157 return;
158 }
159
160
161 #ifdef NOTYET
162 static void
163 appendScopeID(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6)
164 {
165 CFNumberRef scope;
166 CFArrayRef scopes;
167 CFMutableArrayRef newScopes;
168
169 scopes = CFDictionaryGetValue(dict, kSCPropNetIPv6ScopeID);
170 if (scopes) {
171 newScopes = CFArrayCreateMutableCopy(NULL, 0, scopes);
172 } else {
173 newScopes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
174 }
175
176 scope = CFNumberCreate(NULL, kCFNumberSInt32Type, &sin6->sin6_scope_id);
177 CFArrayAppendValue(newScopes, scope);
178 CFRelease(scope);
179
180 CFDictionarySetValue(dict, kSCPropNetIPv6ScopeID, newScopes);
181 CFRelease(newScopes);
182 return;
183 }
184 #endif /* NOTYET */
185
186
187 static CFMutableDictionaryRef
188 copyIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs)
189 {
190 CFDictionaryRef dict = NULL;
191 CFMutableDictionaryRef newDict = NULL;
192
193 if (CFDictionaryGetValueIfPresent(newIFs, key, (const void **)&dict)) {
194 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
195 } else {
196 dict = cache_SCDynamicStoreCopyValue(store, key);
197 if (dict) {
198 CFDictionarySetValue(oldIFs, key, dict);
199 if (isA_CFDictionary(dict)) {
200 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
201 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6Addresses);
202 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6DestAddresses);
203 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6Flags);
204 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6PrefixLength);
205 #ifdef NOTYET
206 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6ScopeID);
207 #endif /* NOTYET */
208 }
209 CFRelease(dict);
210 }
211 }
212
213 if (!newDict) {
214 newDict = CFDictionaryCreateMutable(NULL,
215 0,
216 &kCFTypeDictionaryKeyCallBacks,
217 &kCFTypeDictionaryValueCallBacks);
218 }
219
220 return newDict;
221 }
222
223
224 static void
225 updateStore(const void *key, const void *value, void *context)
226 {
227 CFDictionaryRef dict;
228 CFDictionaryRef newDict = (CFDictionaryRef)value;
229 CFDictionaryRef oldIFs = (CFDictionaryRef)context;
230
231 dict = CFDictionaryGetValue(oldIFs, key);
232
233 if (!dict || !CFEqual(dict, newDict)) {
234 if (CFDictionaryGetCount(newDict) > 0) {
235 cache_SCDynamicStoreSetValue(store, key, newDict);
236 } else if (dict) {
237 cache_SCDynamicStoreRemoveValue(store, key);
238 }
239 network_changed = TRUE;
240 }
241
242 return;
243 }
244
245
246 __private_extern__
247 void
248 interface_update_ipv6(struct ifaddrs *ifap, const char *if_name)
249 {
250 struct ifaddrs *ifa;
251 struct ifaddrs *ifap_temp = NULL;
252 CFStringRef interface;
253 boolean_t interfaceFound = FALSE;
254 CFStringRef key = NULL;
255 CFMutableDictionaryRef oldIFs;
256 CFMutableDictionaryRef newDict = NULL;
257 CFMutableDictionaryRef newIFs;
258 int sock = -1;
259
260 oldIFs = CFDictionaryCreateMutable(NULL,
261 0,
262 &kCFTypeDictionaryKeyCallBacks,
263 &kCFTypeDictionaryValueCallBacks);
264 newIFs = CFDictionaryCreateMutable(NULL,
265 0,
266 &kCFTypeDictionaryKeyCallBacks,
267 &kCFTypeDictionaryValueCallBacks);
268
269 if (!ifap) {
270 if (getifaddrs(&ifap_temp) == -1) {
271 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno));
272 goto error;
273 }
274 ifap = ifap_temp;
275 }
276
277 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
278 struct in6_ifreq ifr6;
279 #define flags6 ifr6.ifr_ifru.ifru_flags6
280 struct sockaddr_in6 *sin6;
281
282 if (ifa->ifa_addr->sa_family != AF_INET6) {
283 continue; /* sorry, not interested */
284 }
285
286 /* check if this is the requested interface */
287 if (if_name) {
288 if (strncmp(if_name, ifa->ifa_name, IFNAMSIZ) == 0) {
289 interfaceFound = TRUE; /* yes, this is the one I want */
290 } else {
291 continue; /* sorry, not interested */
292 }
293 }
294
295 if (sock == -1) {
296 sock = dgram_socket(AF_INET6);
297 if (sock == -1) {
298 SCLog(TRUE, LOG_NOTICE, CFSTR("interface_update_ipv6: socket open failed, %s"), strerror(errno));
299 goto error;
300 }
301 }
302
303 /* get the current cache information */
304 interface = CFStringCreateWithCString(NULL, ifa->ifa_name, kCFStringEncodingMacRoman);
305 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
306 kSCDynamicStoreDomainState,
307 interface,
308 kSCEntNetIPv6);
309 CFRelease(interface);
310
311 newDict = copyIF(key, oldIFs, newIFs);
312
313 /* ALIGN: ifa->ifa_addr aligned (getifaddrs), cast ok. */
314 sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
315
316 /* XXX: embedded link local addr check */
317 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
318 u_int16_t index;
319
320 index = sin6->sin6_addr.s6_addr16[1];
321 if (index != 0) {
322 sin6->sin6_addr.s6_addr16[1] = 0;
323 if (sin6->sin6_scope_id == 0) {
324 sin6->sin6_scope_id = ntohs(index);
325 }
326 }
327 }
328
329 bzero((char *)&ifr6, sizeof(ifr6));
330 strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
331 ifr6.ifr_addr = *sin6;
332 if (ioctl(sock, SIOCGIFAFLAG_IN6, &ifr6) == -1) {
333 /* if flags not available for this address */
334 SCLog(TRUE, LOG_NOTICE, CFSTR("interface_update_ipv6: ioctl failed, %s"), strerror(errno));
335 }
336
337 appendAddress (newDict, kSCPropNetIPv6Addresses, sin6);
338 #ifdef NOTYET
339 appendScopeID (newDict, sin6);
340 #endif /* NOTYET */
341 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok.
342 * appendPrefixLen expect byte alignment */
343 appendPrefixLen(newDict, (struct sockaddr_in6 *)(void *)ifa->ifa_netmask);
344 appendFlags (newDict, flags6);
345
346
347 if (ifa->ifa_flags & IFF_POINTOPOINT
348 && ifa->ifa_dstaddr != NULL) {
349 struct sockaddr_in6 *dst6;
350
351 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */
352 dst6 = (struct sockaddr_in6 *)(void *)ifa->ifa_dstaddr;
353
354 /* XXX: embedded link local addr check */
355 if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6->sin6_addr)) {
356 u_int16_t index;
357
358 index = dst6->sin6_addr.s6_addr16[1];
359 if (index != 0) {
360 dst6->sin6_addr.s6_addr16[1] = 0;
361 if (dst6->sin6_scope_id == 0) {
362 dst6->sin6_scope_id = ntohs(index);
363 }
364 }
365 }
366
367 appendAddress(newDict, kSCPropNetIPv6DestAddresses, dst6);
368 }
369
370 CFDictionarySetValue(newIFs, key, newDict);
371 CFRelease(newDict);
372 CFRelease(key);
373 }
374
375 /* if the last address[es] were removed from the target interface */
376 if (if_name && !interfaceFound) {
377 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
378 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
379 kSCDynamicStoreDomainState,
380 interface,
381 kSCEntNetIPv6);
382 CFRelease(interface);
383
384 newDict = copyIF(key, oldIFs, newIFs);
385
386 CFDictionarySetValue(newIFs, key, newDict);
387 CFRelease(newDict);
388 CFRelease(key);
389 }
390
391 CFDictionaryApplyFunction(newIFs, updateStore, oldIFs);
392
393 error :
394
395 if (ifap_temp) freeifaddrs(ifap_temp);
396 if (sock != -1) close(sock);
397 CFRelease(oldIFs);
398 CFRelease(newIFs);
399
400 return;
401 }