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 45static void 46appendAddress(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 75static void 76appendFlags(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 99static void 100appendPrefixLen(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 162static void 163appendScopeID(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 187static CFMutableDictionaryRef 188copyIF(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 224static void 225updateStore(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__ 247void 248interface_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, 335 (errno != EADDRNOTAVAIL) ? LOG_NOTICE : LOG_DEBUG, 336 CFSTR("interface_update_ipv6: ioctl failed, %s"), 337 strerror(errno)); 338 } 339 340 appendAddress (newDict, kSCPropNetIPv6Addresses, sin6); 341#ifdef NOTYET 342 appendScopeID (newDict, sin6); 343#endif /* NOTYET */ 344 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. 345 * appendPrefixLen expect byte alignment */ 346 appendPrefixLen(newDict, (struct sockaddr_in6 *)(void *)ifa->ifa_netmask); 347 appendFlags (newDict, flags6); 348 349 350 if (ifa->ifa_flags & IFF_POINTOPOINT 351 && ifa->ifa_dstaddr != NULL) { 352 struct sockaddr_in6 *dst6; 353 354 /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */ 355 dst6 = (struct sockaddr_in6 *)(void *)ifa->ifa_dstaddr; 356 357 /* XXX: embedded link local addr check */ 358 if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6->sin6_addr)) { 359 u_int16_t index; 360 361 index = dst6->sin6_addr.s6_addr16[1]; 362 if (index != 0) { 363 dst6->sin6_addr.s6_addr16[1] = 0; 364 if (dst6->sin6_scope_id == 0) { 365 dst6->sin6_scope_id = ntohs(index); 366 } 367 } 368 } 369 370 appendAddress(newDict, kSCPropNetIPv6DestAddresses, dst6); 371 } 372 373 CFDictionarySetValue(newIFs, key, newDict); 374 CFRelease(newDict); 375 CFRelease(key); 376 } 377 378 /* if the last address[es] were removed from the target interface */ 379 if (if_name && !interfaceFound) { 380 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman); 381 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 382 kSCDynamicStoreDomainState, 383 interface, 384 kSCEntNetIPv6); 385 CFRelease(interface); 386 387 newDict = copyIF(key, oldIFs, newIFs); 388 389 CFDictionarySetValue(newIFs, key, newDict); 390 CFRelease(newDict); 391 CFRelease(key); 392 } 393 394 CFDictionaryApplyFunction(newIFs, updateStore, oldIFs); 395 396 error : 397 398 if (ifap_temp) freeifaddrs(ifap_temp); 399 if (sock != -1) close(sock); 400 CFRelease(oldIFs); 401 CFRelease(newIFs); 402 403 return; 404} 405