]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/ev_ipv6.c
configd-130.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / ev_ipv6.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, 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 #ifndef kSCPropNetIPv6DestAddresses
39 #define kSCPropNetIPv6DestAddresses SCSTR("DestAddresses")
40 #endif
41
42 #ifndef kSCPropNetIPv6Flags
43 #define kSCPropNetIPv6Flags SCSTR("Flags")
44 #endif
45
46 #ifndef kSCPropNetIPv6PrefixLength
47 #define kSCPropNetIPv6PrefixLength SCSTR("PrefixLength")
48 #endif
49
50 #ifdef NOTYET
51 #ifndef kSCPropNetIPv6ScopeID
52 #define kSCPropNetIPv6ScopeID SCSTR("ScopeID")
53 #endif
54 #endif /* NOTYET */
55
56
57 static void
58 appendAddress(CFMutableDictionaryRef dict, CFStringRef key, struct sockaddr_in6 *sin6)
59 {
60 CFStringRef addr;
61 CFArrayRef addrs;
62 CFMutableArrayRef newAddrs;
63 char str[64];
64
65 addrs = CFDictionaryGetValue(dict, key);
66 if (addrs) {
67 newAddrs = CFArrayCreateMutableCopy(NULL, 0, addrs);
68 } else {
69 newAddrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
70 }
71
72 if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr, str, sizeof(str)) == NULL) {
73 SCLog(TRUE, LOG_ERR, CFSTR("inet_ntop() failed: %s"), strerror(errno));
74 str[0] = '\0';
75 }
76
77 addr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), str);
78 CFArrayAppendValue(newAddrs, addr);
79 CFRelease(addr);
80
81 CFDictionarySetValue(dict, key, newAddrs);
82 CFRelease(newAddrs);
83 return;
84 }
85
86
87 static void
88 appendFlags(CFMutableDictionaryRef dict, int flags6)
89 {
90 CFArrayRef flags;
91 CFMutableArrayRef newFlags;
92 CFNumberRef v6Flags;
93
94 flags = CFDictionaryGetValue(dict, kSCPropNetIPv6Flags);
95 if (flags) {
96 newFlags = CFArrayCreateMutableCopy(NULL, 0, flags);
97 } else {
98 newFlags = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
99 }
100
101 v6Flags = CFNumberCreate(NULL, kCFNumberIntType, &flags6);
102 CFArrayAppendValue(newFlags, v6Flags);
103 CFRelease(v6Flags);
104
105 CFDictionarySetValue(dict, kSCPropNetIPv6Flags, newFlags);
106 CFRelease(newFlags);
107 return;
108 }
109
110
111 static void
112 appendPrefixLen(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6)
113 {
114 register u_int8_t *name = &sin6->sin6_addr.s6_addr[0];
115 CFNumberRef prefixLen;
116 CFArrayRef prefixLens;
117 CFMutableArrayRef newPrefixLens;
118
119 register int byte;
120 register int bit;
121 int plen = 0;
122
123 for (byte = 0; byte < sizeof(struct in6_addr); byte++, plen += 8) {
124 if (name[byte] != 0xff) {
125 break;
126 }
127 }
128
129 if (byte == sizeof(struct in6_addr)) {
130 goto append;
131 }
132
133 for (bit = 7; bit != 0; bit--, plen++) {
134 if (!(name[byte] & (1 << bit))) {
135 break;
136 }
137 }
138
139 for (; bit != 0; bit--) {
140 if (name[byte] & (1 << bit)) {
141 plen = 0;
142 goto append;
143 }
144 }
145
146 byte++;
147 for (; byte < sizeof(struct in6_addr); byte++) {
148 if (name[byte]) {
149 plen = 0;
150 goto append;
151 }
152 }
153
154 append :
155
156 prefixLens = CFDictionaryGetValue(dict, kSCPropNetIPv6PrefixLength);
157 if (prefixLens) {
158 newPrefixLens = CFArrayCreateMutableCopy(NULL, 0, prefixLens);
159 } else {
160 newPrefixLens = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
161 }
162
163 prefixLen = CFNumberCreate(NULL, kCFNumberIntType, &plen);
164 CFArrayAppendValue(newPrefixLens, prefixLen);
165 CFRelease(prefixLen);
166
167 CFDictionarySetValue(dict, kSCPropNetIPv6PrefixLength, newPrefixLens);
168 CFRelease(newPrefixLens);
169 return;
170 }
171
172
173 #ifdef NOTYET
174 static void
175 appendScopeID(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6)
176 {
177 CFNumberRef scope;
178 CFArrayRef scopes;
179 CFMutableArrayRef newScopes;
180
181 scopes = CFDictionaryGetValue(dict, kSCPropNetIPv6ScopeID);
182 if (scopes) {
183 newScopes = CFArrayCreateMutableCopy(NULL, 0, scopes);
184 } else {
185 newScopes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
186 }
187
188 scope = CFNumberCreate(NULL, kCFNumberSInt32Type, &sin6->sin6_scope_id);
189 CFArrayAppendValue(newScopes, scope);
190 CFRelease(scope);
191
192 CFDictionarySetValue(dict, kSCPropNetIPv6ScopeID, newScopes);
193 CFRelease(newScopes);
194 return;
195 }
196 #endif /* NOTYET */
197
198
199 static CFMutableDictionaryRef
200 getIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs)
201 {
202 CFDictionaryRef dict = NULL;
203 CFMutableDictionaryRef newDict = NULL;
204
205 if (CFDictionaryGetValueIfPresent(newIFs, key, (const void **)&dict)) {
206 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
207 } else {
208 dict = cache_SCDynamicStoreCopyValue(store, key);
209 if (dict) {
210 CFDictionarySetValue(oldIFs, key, dict);
211 if (isA_CFDictionary(dict)) {
212 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
213 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6Addresses);
214 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6DestAddresses);
215 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6Flags);
216 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6PrefixLength);
217 #ifdef NOTYET
218 CFDictionaryRemoveValue(newDict, kSCPropNetIPv6ScopeID);
219 #endif /* NOTYET */
220 }
221 CFRelease(dict);
222 }
223 }
224
225 if (!newDict) {
226 newDict = CFDictionaryCreateMutable(NULL,
227 0,
228 &kCFTypeDictionaryKeyCallBacks,
229 &kCFTypeDictionaryValueCallBacks);
230 }
231
232 return newDict;
233 }
234
235
236 static void
237 updateStore(const void *key, const void *value, void *context)
238 {
239 CFDictionaryRef dict;
240 CFDictionaryRef newDict = (CFDictionaryRef)value;
241 CFDictionaryRef oldIFs = (CFDictionaryRef)context;
242
243 dict = CFDictionaryGetValue(oldIFs, key);
244
245 if (!dict || !CFEqual(dict, newDict)) {
246 if (CFDictionaryGetCount(newDict) > 0) {
247 cache_SCDynamicStoreSetValue(store, key, newDict);
248 } else if (dict) {
249 cache_SCDynamicStoreRemoveValue(store, key);
250 }
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) < 0) {
282 SCLog(TRUE, LOG_ERR, CFSTR("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 < 0) {
307 sock = dgram_socket(AF_INET6);
308 if (sock < 0) {
309 SCLog(TRUE, LOG_NOTICE, CFSTR("interface_update_ipv6: socket open failed, %s"), strerror(errno));
310 goto error;
311 }
312 }
313
314 /* get the current cache information */
315 interface = CFStringCreateWithCString(NULL, ifa->ifa_name, kCFStringEncodingMacRoman);
316 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
317 kSCDynamicStoreDomainState,
318 interface,
319 kSCEntNetIPv6);
320 CFRelease(interface);
321
322 newDict = getIF(key, oldIFs, newIFs);
323
324 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
325
326 /* XXX: embedded link local addr check */
327 if (IN6_IS_ADDR_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 strncpy(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 SCLog(TRUE, LOG_NOTICE, CFSTR("interface_update_ipv6: ioctl failed, %s"), strerror(errno));
345 }
346
347 appendAddress (newDict, kSCPropNetIPv6Addresses, sin6);
348 #ifdef NOTYET
349 appendScopeID (newDict, sin6);
350 #endif /* NOTYET */
351 appendPrefixLen(newDict, (struct sockaddr_in6 *)ifa->ifa_netmask);
352 appendFlags (newDict, flags6);
353
354
355 if (ifa->ifa_flags & IFF_POINTOPOINT) {
356 struct sockaddr_in6 *dst6;
357
358 dst6 = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
359
360 /* XXX: embedded link local addr check */
361 if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) {
362 u_int16_t index;
363
364 index = dst6->sin6_addr.s6_addr16[1];
365 if (index != 0) {
366 dst6->sin6_addr.s6_addr16[1] = 0;
367 if (dst6->sin6_scope_id == 0) {
368 dst6->sin6_scope_id = ntohs(index);
369 }
370 }
371 }
372
373 appendAddress(newDict, kSCPropNetIPv6DestAddresses, dst6);
374 }
375
376 CFDictionarySetValue(newIFs, key, newDict);
377 CFRelease(newDict);
378 CFRelease(key);
379 }
380
381 /* if the last address[es] were removed from the target interface */
382 if (if_name && !interfaceFound) {
383 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
384 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
385 kSCDynamicStoreDomainState,
386 interface,
387 kSCEntNetIPv6);
388 CFRelease(interface);
389
390 newDict = getIF(key, oldIFs, newIFs);
391
392 CFDictionarySetValue(newIFs, key, newDict);
393 CFRelease(newDict);
394 CFRelease(key);
395 }
396
397 CFDictionaryApplyFunction(newIFs, updateStore, oldIFs);
398
399 error :
400
401 if (ifap_temp) freeifaddrs(ifap_temp);
402 if (sock >= 0) close(sock);
403 CFRelease(oldIFs);
404 CFRelease(newIFs);
405
406 return;
407 }