]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/ev_ipv6.c
configd-293.8.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / ev_ipv6.c
1 /*
2 * Copyright (c) 2002-2007 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 getIF(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 = getIF(key, oldIFs, newIFs);
312
313 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
314
315 /* XXX: embedded link local addr check */
316 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
317 u_int16_t index;
318
319 index = sin6->sin6_addr.s6_addr16[1];
320 if (index != 0) {
321 sin6->sin6_addr.s6_addr16[1] = 0;
322 if (sin6->sin6_scope_id == 0) {
323 sin6->sin6_scope_id = ntohs(index);
324 }
325 }
326 }
327
328 bzero((char *)&ifr6, sizeof(ifr6));
329 strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
330 ifr6.ifr_addr = *sin6;
331 if (ioctl(sock, SIOCGIFAFLAG_IN6, &ifr6) == -1) {
332 /* if flags not available for this address */
333 SCLog(TRUE, LOG_NOTICE, CFSTR("interface_update_ipv6: ioctl failed, %s"), strerror(errno));
334 }
335
336 appendAddress (newDict, kSCPropNetIPv6Addresses, sin6);
337 #ifdef NOTYET
338 appendScopeID (newDict, sin6);
339 #endif /* NOTYET */
340 appendPrefixLen(newDict, (struct sockaddr_in6 *)ifa->ifa_netmask);
341 appendFlags (newDict, flags6);
342
343
344 if (ifa->ifa_flags & IFF_POINTOPOINT) {
345 struct sockaddr_in6 *dst6;
346
347 dst6 = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
348
349 /* XXX: embedded link local addr check */
350 if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) {
351 u_int16_t index;
352
353 index = dst6->sin6_addr.s6_addr16[1];
354 if (index != 0) {
355 dst6->sin6_addr.s6_addr16[1] = 0;
356 if (dst6->sin6_scope_id == 0) {
357 dst6->sin6_scope_id = ntohs(index);
358 }
359 }
360 }
361
362 appendAddress(newDict, kSCPropNetIPv6DestAddresses, dst6);
363 }
364
365 CFDictionarySetValue(newIFs, key, newDict);
366 CFRelease(newDict);
367 CFRelease(key);
368 }
369
370 /* if the last address[es] were removed from the target interface */
371 if (if_name && !interfaceFound) {
372 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
373 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
374 kSCDynamicStoreDomainState,
375 interface,
376 kSCEntNetIPv6);
377 CFRelease(interface);
378
379 newDict = getIF(key, oldIFs, newIFs);
380
381 CFDictionarySetValue(newIFs, key, newDict);
382 CFRelease(newDict);
383 CFRelease(key);
384 }
385
386 CFDictionaryApplyFunction(newIFs, updateStore, oldIFs);
387
388 error :
389
390 if (ifap_temp) freeifaddrs(ifap_temp);
391 if (sock != -1) close(sock);
392 CFRelease(oldIFs);
393 CFRelease(newIFs);
394
395 return;
396 }