1/* 2 * Copyright (c) 2002-2014 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 * - split code out from eventmon.c 29 */ 30 31#include "eventmon.h" 32#include "cache.h" 33#include "ev_ipv4.h" 34 35#ifndef kSCEntNetIPv4ARPCollision 36#define kSCEntNetIPv4ARPCollision CFSTR("IPv4ARPCollision") 37#endif /* kSCEntNetIPv4ARPCollision */ 38 39#if !TARGET_OS_IPHONE 40#ifndef kSCEntNetIPv4PortInUse 41#define kSCEntNetIPv4PortInUse CFSTR("PortInUse") 42#endif /* kSCEntNetIPv4PortInUse */ 43#endif /* !TARGET_OS_IPHONE */ 44 45#define IP_FORMAT "%d.%d.%d.%d" 46#define IP_CH(ip, i) (((u_char *)(ip))[i]) 47#define IP_LIST(ip) IP_CH(ip,0),IP_CH(ip,1),IP_CH(ip,2),IP_CH(ip,3) 48 49 50static void 51appendAddress(CFMutableDictionaryRef dict, CFStringRef key, struct in_addr *address) 52{ 53 CFStringRef addr; 54 CFArrayRef addrs; 55 CFMutableArrayRef newAddrs; 56 57 addrs = CFDictionaryGetValue(dict, key); 58 if (addrs) { 59 newAddrs = CFArrayCreateMutableCopy(NULL, 0, addrs); 60 } else { 61 newAddrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 62 } 63 64 addr = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(address)); 65 CFArrayAppendValue(newAddrs, addr); 66 CFRelease(addr); 67 68 CFDictionarySetValue(dict, key, newAddrs); 69 CFRelease(newAddrs); 70 return; 71} 72 73 74static CFMutableDictionaryRef 75copyIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs) 76{ 77 CFDictionaryRef dict = NULL; 78 CFMutableDictionaryRef newDict = NULL; 79 80 if (CFDictionaryGetValueIfPresent(newIFs, key, (const void **)&dict)) { 81 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 82 } else { 83 dict = cache_SCDynamicStoreCopyValue(store, key); 84 if (dict) { 85 CFDictionarySetValue(oldIFs, key, dict); 86 if (isA_CFDictionary(dict)) { 87 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 88 CFDictionaryRemoveValue(newDict, kSCPropNetIPv4Addresses); 89 CFDictionaryRemoveValue(newDict, kSCPropNetIPv4SubnetMasks); 90 CFDictionaryRemoveValue(newDict, kSCPropNetIPv4DestAddresses); 91 CFDictionaryRemoveValue(newDict, kSCPropNetIPv4BroadcastAddresses); 92 } 93 CFRelease(dict); 94 } 95 } 96 97 if (!newDict) { 98 newDict = CFDictionaryCreateMutable(NULL, 99 0, 100 &kCFTypeDictionaryKeyCallBacks, 101 &kCFTypeDictionaryValueCallBacks); 102 } 103 104 return newDict; 105} 106 107 108static void 109updateStore(const void *key, const void *value, void *context) 110{ 111 CFDictionaryRef dict; 112 CFDictionaryRef newDict = (CFDictionaryRef)value; 113 CFDictionaryRef oldIFs = (CFDictionaryRef)context; 114 115 dict = CFDictionaryGetValue(oldIFs, key); 116 117 if (!dict || !CFEqual(dict, newDict)) { 118 if (CFDictionaryGetCount(newDict) > 0) { 119 cache_SCDynamicStoreSetValue(store, key, newDict); 120 } else if (dict) { 121 cache_SCDynamicStoreRemoveValue(store, key); 122 } 123 network_changed = TRUE; 124 } 125 126 return; 127} 128 129 130__private_extern__ 131void 132ipv4_interface_update(struct ifaddrs *ifap, const char *if_name) 133{ 134 struct ifaddrs *ifa; 135 struct ifaddrs *ifap_temp = NULL; 136 CFStringRef interface; 137 boolean_t interfaceFound = FALSE; 138 CFStringRef key = NULL; 139 CFMutableDictionaryRef oldIFs; 140 CFMutableDictionaryRef newDict = NULL; 141 CFMutableDictionaryRef newIFs; 142 143 oldIFs = CFDictionaryCreateMutable(NULL, 144 0, 145 &kCFTypeDictionaryKeyCallBacks, 146 &kCFTypeDictionaryValueCallBacks); 147 newIFs = CFDictionaryCreateMutable(NULL, 148 0, 149 &kCFTypeDictionaryKeyCallBacks, 150 &kCFTypeDictionaryValueCallBacks); 151 152 if (!ifap) { 153 if (getifaddrs(&ifap_temp) == -1) { 154 SCLog(TRUE, LOG_ERR, CFSTR("getifaddrs() failed: %s"), strerror(errno)); 155 goto error; 156 } 157 ifap = ifap_temp; 158 } 159 160 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 161 struct sockaddr_in *sin; 162 163 if (ifa->ifa_addr->sa_family != AF_INET) { 164 continue; /* sorry, not interested */ 165 } 166 167 /* check if this is the requested interface */ 168 if (if_name) { 169 if (strncmp(if_name, ifa->ifa_name, IFNAMSIZ) == 0) { 170 interfaceFound = TRUE; /* yes, this is the one I want */ 171 } else { 172 continue; /* sorry, not interested */ 173 } 174 } 175 176 interface = CFStringCreateWithCString(NULL, ifa->ifa_name, kCFStringEncodingMacRoman); 177 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 178 kSCDynamicStoreDomainState, 179 interface, 180 kSCEntNetIPv4); 181 CFRelease(interface); 182 183 newDict = copyIF(key, oldIFs, newIFs); 184 185 /* ALIGN: cast ok, this should be aligned (getifaddrs). */ 186 sin = (struct sockaddr_in *)(void *)ifa->ifa_addr; 187 appendAddress(newDict, kSCPropNetIPv4Addresses, &sin->sin_addr); 188 189 if (ifa->ifa_flags & IFF_POINTOPOINT) { 190 struct sockaddr_in *dst; 191 192 /* ALIGN: cast ok, this should be aligned (getifaddrs). */ 193 dst = (struct sockaddr_in *)(void *)ifa->ifa_dstaddr; 194 appendAddress(newDict, kSCPropNetIPv4DestAddresses, &dst->sin_addr); 195 } else { 196 struct sockaddr_in *brd; 197 struct sockaddr_in *msk; 198 199 /* ALIGN: cast ok, this should be aligned (getifaddrs). */ 200 brd = (struct sockaddr_in *)(void *)ifa->ifa_broadaddr; 201 appendAddress(newDict, kSCPropNetIPv4BroadcastAddresses,&brd->sin_addr); 202 203 /* ALIGN: cast ok, this should be aligned (getifaddrs). */ 204 msk = (struct sockaddr_in *)(void *)ifa->ifa_netmask; 205 appendAddress(newDict, kSCPropNetIPv4SubnetMasks, &msk->sin_addr); 206 } 207 208 CFDictionarySetValue(newIFs, key, newDict); 209 CFRelease(newDict); 210 CFRelease(key); 211 } 212 213 /* if the last address[es] were removed from the target interface */ 214 if (if_name && !interfaceFound) { 215 interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman); 216 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 217 kSCDynamicStoreDomainState, 218 interface, 219 kSCEntNetIPv4); 220 CFRelease(interface); 221 222 newDict = copyIF(key, oldIFs, newIFs); 223 224 CFDictionarySetValue(newIFs, key, newDict); 225 CFRelease(newDict); 226 CFRelease(key); 227 } 228 229 CFDictionaryApplyFunction(newIFs, updateStore, oldIFs); 230 231 error : 232 233 if (ifap_temp) freeifaddrs(ifap_temp); 234 CFRelease(oldIFs); 235 CFRelease(newIFs); 236 237 return; 238} 239 240__private_extern__ 241void 242ipv4_arp_collision(const char *if_name, struct in_addr ip_addr, int hw_len, const void * hw_addr) 243{ 244 uint8_t * hw_addr_bytes = (uint8_t *)hw_addr; 245 int i; 246 CFStringRef if_name_cf; 247 CFMutableStringRef key; 248 CFStringRef prefix; 249 250 if_name_cf = CFStringCreateWithCString(NULL, if_name, 251 kCFStringEncodingASCII); 252 prefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 253 kSCDynamicStoreDomainState, 254 if_name_cf, 255 kSCEntNetIPv4ARPCollision); 256 key = CFStringCreateMutableCopy(NULL, 0, prefix); 257 CFStringAppendFormat(key, NULL, CFSTR("/" IP_FORMAT), 258 IP_LIST(&ip_addr)); 259 for (i = 0; i < hw_len; i++) { 260 CFStringAppendFormat(key, NULL, CFSTR("%s%02x"), 261 (i == 0) ? "/" : ":", hw_addr_bytes[i]); 262 } 263 cache_SCDynamicStoreNotifyValue(store, key); 264 CFRelease(key); 265 CFRelease(prefix); 266 CFRelease(if_name_cf); 267 return; 268} 269 270#if !TARGET_OS_IPHONE 271__private_extern__ 272void 273ipv4_port_in_use(uint16_t port, pid_t req_pid) 274{ 275 CFStringRef key; 276 277 key = SCDynamicStoreKeyCreate(NULL, 278 CFSTR("%@/%@/Protocol/%@/%@/%d/%d"), 279 kSCDynamicStoreDomainState, 280 kSCCompNetwork, 281 kSCEntNetIPv4, 282 kSCEntNetIPv4PortInUse, 283 port, req_pid); 284 cache_SCDynamicStoreNotifyValue(store, key); 285 CFRelease(key); 286 return; 287} 288#endif /* !TARGET_OS_IPHONE */ 289 290static void 291interface_notify_entity(const char * if_name, CFStringRef entity) 292{ 293 CFStringRef if_name_cf; 294 CFStringRef key; 295 296 if_name_cf = CFStringCreateWithCString(NULL, if_name, 297 kCFStringEncodingASCII); 298 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 299 kSCDynamicStoreDomainState, 300 if_name_cf, 301 entity); 302 CFRelease(if_name_cf); 303 cache_SCDynamicStoreNotifyValue(store, key); 304 CFRelease(key); 305 return; 306} 307 308__private_extern__ void 309ipv4_router_arp_failure(const char * if_name) 310{ 311 interface_notify_entity(if_name, kSCEntNetIPv4RouterARPFailure); 312 return; 313} 314 315__private_extern__ void 316ipv4_router_arp_alive(const char * if_name) 317{ 318 interface_notify_entity(if_name, kSCEntNetIPv4RouterARPAlive); 319 return; 320} 321