]>
Commit | Line | Data |
---|---|---|
dbf6a266 A |
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 | } |