X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/4c5e92e2493bdfbbce40e998f3b607c72c47af2c..dbf6a266c384fc8b55e00a396eebe5cb62e21547:/Plugins/KernelEventMonitor/ev_ipv6.c diff --git a/Plugins/KernelEventMonitor/ev_ipv6.c b/Plugins/KernelEventMonitor/ev_ipv6.c new file mode 100644 index 0000000..47705c4 --- /dev/null +++ b/Plugins/KernelEventMonitor/ev_ipv6.c @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Modification History + * + * August 5, 2002 Allan Nathanson + * - initial revision + */ + + +#include "eventmon.h" +#include "cache.h" +#include "ev_ipv6.h" + +#define s6_addr16 __u6_addr.__u6_addr16 + +#ifndef kSCPropNetIPv6DestAddresses +#define kSCPropNetIPv6DestAddresses SCSTR("DestAddresses") +#endif + +#ifndef kSCPropNetIPv6Flags +#define kSCPropNetIPv6Flags SCSTR("Flags") +#endif + +#ifndef kSCPropNetIPv6PrefixLength +#define kSCPropNetIPv6PrefixLength SCSTR("PrefixLength") +#endif + +#ifdef NOTYET +#ifndef kSCPropNetIPv6ScopeID +#define kSCPropNetIPv6ScopeID SCSTR("ScopeID") +#endif +#endif /* NOTYET */ + + +static void +appendAddress(CFMutableDictionaryRef dict, CFStringRef key, struct sockaddr_in6 *sin6) +{ + CFStringRef addr; + CFArrayRef addrs; + CFMutableArrayRef newAddrs; + char str[64]; + + addrs = CFDictionaryGetValue(dict, key); + if (addrs) { + newAddrs = CFArrayCreateMutableCopy(NULL, 0, addrs); + } else { + newAddrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + + if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr, str, sizeof(str)) == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("inet_ntop() failed: %s"), strerror(errno)); + str[0] = '\0'; + } + + addr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), str); + CFArrayAppendValue(newAddrs, addr); + CFRelease(addr); + + CFDictionarySetValue(dict, key, newAddrs); + CFRelease(newAddrs); + return; +} + + +static void +appendFlags(CFMutableDictionaryRef dict, int flags6) +{ + CFArrayRef flags; + CFMutableArrayRef newFlags; + CFNumberRef v6Flags; + + flags = CFDictionaryGetValue(dict, kSCPropNetIPv6Flags); + if (flags) { + newFlags = CFArrayCreateMutableCopy(NULL, 0, flags); + } else { + newFlags = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + + v6Flags = CFNumberCreate(NULL, kCFNumberIntType, &flags6); + CFArrayAppendValue(newFlags, v6Flags); + CFRelease(v6Flags); + + CFDictionarySetValue(dict, kSCPropNetIPv6Flags, newFlags); + CFRelease(newFlags); + return; +} + + +static void +appendPrefixLen(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6) +{ + register u_int8_t *name = &sin6->sin6_addr.s6_addr[0]; + CFNumberRef prefixLen; + CFArrayRef prefixLens; + CFMutableArrayRef newPrefixLens; + + register int byte; + register int bit; + int plen = 0; + + for (byte = 0; byte < sizeof(struct in6_addr); byte++, plen += 8) { + if (name[byte] != 0xff) { + break; + } + } + + if (byte == sizeof(struct in6_addr)) { + goto append; + } + + for (bit = 7; bit != 0; bit--, plen++) { + if (!(name[byte] & (1 << bit))) { + break; + } + } + + for (; bit != 0; bit--) { + if (name[byte] & (1 << bit)) { + plen = 0; + goto append; + } + } + + byte++; + for (; byte < sizeof(struct in6_addr); byte++) { + if (name[byte]) { + plen = 0; + goto append; + } + } + + append : + + prefixLens = CFDictionaryGetValue(dict, kSCPropNetIPv6PrefixLength); + if (prefixLens) { + newPrefixLens = CFArrayCreateMutableCopy(NULL, 0, prefixLens); + } else { + newPrefixLens = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + + prefixLen = CFNumberCreate(NULL, kCFNumberIntType, &plen); + CFArrayAppendValue(newPrefixLens, prefixLen); + CFRelease(prefixLen); + + CFDictionarySetValue(dict, kSCPropNetIPv6PrefixLength, newPrefixLens); + CFRelease(newPrefixLens); + return; +} + + +#ifdef NOTYET +static void +appendScopeID(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6) +{ + CFNumberRef scope; + CFArrayRef scopes; + CFMutableArrayRef newScopes; + + scopes = CFDictionaryGetValue(dict, kSCPropNetIPv6ScopeID); + if (scopes) { + newScopes = CFArrayCreateMutableCopy(NULL, 0, scopes); + } else { + newScopes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + + scope = CFNumberCreate(NULL, kCFNumberSInt32Type, &sin6->sin6_scope_id); + CFArrayAppendValue(newScopes, scope); + CFRelease(scope); + + CFDictionarySetValue(dict, kSCPropNetIPv6ScopeID, newScopes); + CFRelease(newScopes); + return; +} +#endif /* NOTYET */ + + +static CFMutableDictionaryRef +getIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs) +{ + CFDictionaryRef dict = NULL; + CFMutableDictionaryRef newDict = NULL; + + if (CFDictionaryGetValueIfPresent(newIFs, key, (const void **)&dict)) { + newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); + } else { + dict = cache_SCDynamicStoreCopyValue(store, key); + if (dict) { + CFDictionarySetValue(oldIFs, key, dict); + if (isA_CFDictionary(dict)) { + newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); + CFDictionaryRemoveValue(newDict, kSCPropNetIPv6Addresses); + CFDictionaryRemoveValue(newDict, kSCPropNetIPv6DestAddresses); + CFDictionaryRemoveValue(newDict, kSCPropNetIPv6Flags); + CFDictionaryRemoveValue(newDict, kSCPropNetIPv6PrefixLength); +#ifdef NOTYET + CFDictionaryRemoveValue(newDict, kSCPropNetIPv6ScopeID); +#endif /* NOTYET */ + } + CFRelease(dict); + } + } + + if (!newDict) { + newDict = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + + return newDict; +} + + +static void +updateStore(const void *key, const void *value, void *context) +{ + CFDictionaryRef dict; + CFDictionaryRef newDict = (CFDictionaryRef)value; + CFDictionaryRef oldIFs = (CFDictionaryRef)context; + + dict = CFDictionaryGetValue(oldIFs, key); + + if (!dict || !CFEqual(dict, newDict)) { + if (CFDictionaryGetCount(newDict) > 0) { + cache_SCDynamicStoreSetValue(store, key, newDict); + } else if (dict) { + cache_SCDynamicStoreRemoveValue(store, key); + } + } + + return; +} + + +__private_extern__ +void +interface_update_ipv6(struct ifaddrs *ifap, const char *if_name) +{ + struct ifaddrs *ifa; + struct ifaddrs *ifap_temp = NULL; + CFStringRef interface; + boolean_t interfaceFound = FALSE; + CFStringRef key = NULL; + CFMutableDictionaryRef oldIFs; + CFMutableDictionaryRef newDict = NULL; + CFMutableDictionaryRef newIFs; + int sock = -1; + + oldIFs = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + newIFs = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + if (!ifap) { + if (getifaddrs(&ifap_temp) < 0) { + SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno)); + goto error; + } + ifap = ifap_temp; + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + struct in6_ifreq ifr6; +#define flags6 ifr6.ifr_ifru.ifru_flags6 + struct sockaddr_in6 *sin6; + + if (ifa->ifa_addr->sa_family != AF_INET6) { + continue; /* sorry, not interested */ + } + + /* check if this is the requested interface */ + if (if_name) { + if (strncmp(if_name, ifa->ifa_name, IFNAMSIZ) == 0) { + interfaceFound = TRUE; /* yes, this is the one I want */ + } else { + continue; /* sorry, not interested */ + } + } + + if (sock < 0) { + sock = dgram_socket(AF_INET6); + if (sock < 0) { + SCLog(TRUE, LOG_NOTICE, CFSTR("interface_update_ipv6: socket open failed, %s"), strerror(errno)); + goto error; + } + } + + /* get the current cache information */ + interface = CFStringCreateWithCString(NULL, ifa->ifa_name, kCFStringEncodingMacRoman); + key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, + kSCDynamicStoreDomainState, + interface, + kSCEntNetIPv6); + CFRelease(interface); + + newDict = getIF(key, oldIFs, newIFs); + + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + + /* XXX: embedded link local addr check */ + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + u_int16_t index; + + index = sin6->sin6_addr.s6_addr16[1]; + if (index != 0) { + sin6->sin6_addr.s6_addr16[1] = 0; + if (sin6->sin6_scope_id == 0) { + sin6->sin6_scope_id = ntohs(index); + } + } + } + + bzero((char *)&ifr6, sizeof(ifr6)); + strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name)); + ifr6.ifr_addr = *sin6; + if (ioctl(sock, SIOCGIFAFLAG_IN6, &ifr6) == -1) { + /* if flags not available for this address */ + SCLog(TRUE, LOG_NOTICE, CFSTR("interface_update_ipv6: ioctl failed, %s"), strerror(errno)); + } + + appendAddress (newDict, kSCPropNetIPv6Addresses, sin6); +#ifdef NOTYET + appendScopeID (newDict, sin6); +#endif /* NOTYET */ + appendPrefixLen(newDict, (struct sockaddr_in6 *)ifa->ifa_netmask); + appendFlags (newDict, flags6); + + + if (ifa->ifa_flags & IFF_POINTOPOINT) { + struct sockaddr_in6 *dst6; + + dst6 = (struct sockaddr_in6 *)ifa->ifa_dstaddr; + + /* XXX: embedded link local addr check */ + if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) { + u_int16_t index; + + index = dst6->sin6_addr.s6_addr16[1]; + if (index != 0) { + dst6->sin6_addr.s6_addr16[1] = 0; + if (dst6->sin6_scope_id == 0) { + dst6->sin6_scope_id = ntohs(index); + } + } + } + + appendAddress(newDict, kSCPropNetIPv6DestAddresses, dst6); + } + + CFDictionarySetValue(newIFs, key, newDict); + CFRelease(newDict); + CFRelease(key); + } + + /* if the last address[es] were removed from the target interface */ + if (if_name && !interfaceFound) { + interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman); + key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, + kSCDynamicStoreDomainState, + interface, + kSCEntNetIPv6); + CFRelease(interface); + + newDict = getIF(key, oldIFs, newIFs); + + CFDictionarySetValue(newIFs, key, newDict); + CFRelease(newDict); + CFRelease(key); + } + + CFDictionaryApplyFunction(newIFs, updateStore, oldIFs); + + error : + + if (ifap_temp) freeifaddrs(ifap_temp); + if (sock >= 0) close(sock); + CFRelease(oldIFs); + CFRelease(newIFs); + + return; +}