#include "eventmon.h"
#include "cache.h"
#include "ev_ipv4.h"
#ifndef kSCEntNetIPv4ARPCollision
#define kSCEntNetIPv4ARPCollision CFSTR("IPv4ARPCollision")
#endif kSCEntNetIPv4ARPCollision
#define IP_FORMAT "%d.%d.%d.%d"
#define IP_CH(ip, i) (((u_char *)(ip))[i])
#define IP_LIST(ip) IP_CH(ip,0),IP_CH(ip,1),IP_CH(ip,2),IP_CH(ip,3)
static void
appendAddress(CFMutableDictionaryRef dict, CFStringRef key, struct in_addr *address)
{
CFStringRef addr;
CFArrayRef addrs;
CFMutableArrayRef newAddrs;
addrs = CFDictionaryGetValue(dict, key);
if (addrs) {
newAddrs = CFArrayCreateMutableCopy(NULL, 0, addrs);
} else {
newAddrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
addr = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(address));
CFArrayAppendValue(newAddrs, addr);
CFRelease(addr);
CFDictionarySetValue(dict, key, newAddrs);
CFRelease(newAddrs);
return;
}
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, kSCPropNetIPv4Addresses);
CFDictionaryRemoveValue(newDict, kSCPropNetIPv4SubnetMasks);
CFDictionaryRemoveValue(newDict, kSCPropNetIPv4DestAddresses);
CFDictionaryRemoveValue(newDict, kSCPropNetIPv4BroadcastAddresses);
}
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_ipv4(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;
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 sockaddr_in *sin;
if (ifa->ifa_addr->sa_family != AF_INET) {
continue;
}
if (if_name) {
if (strncmp(if_name, ifa->ifa_name, IFNAMSIZ) == 0) {
interfaceFound = TRUE;
} else {
continue;
}
}
interface = CFStringCreateWithCString(NULL, ifa->ifa_name, kCFStringEncodingMacRoman);
key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
kSCDynamicStoreDomainState,
interface,
kSCEntNetIPv4);
CFRelease(interface);
newDict = getIF(key, oldIFs, newIFs);
sin = (struct sockaddr_in *)ifa->ifa_addr;
appendAddress(newDict, kSCPropNetIPv4Addresses, &sin->sin_addr);
if (ifa->ifa_flags & IFF_POINTOPOINT) {
struct sockaddr_in *dst;
dst = (struct sockaddr_in *)ifa->ifa_dstaddr;
appendAddress(newDict, kSCPropNetIPv4DestAddresses, &dst->sin_addr);
} else {
struct sockaddr_in *brd;
struct sockaddr_in *msk;
brd = (struct sockaddr_in *)ifa->ifa_broadaddr;
appendAddress(newDict, kSCPropNetIPv4BroadcastAddresses, &brd->sin_addr);
msk = (struct sockaddr_in *)ifa->ifa_netmask;
appendAddress(newDict, kSCPropNetIPv4SubnetMasks, &msk->sin_addr);
}
CFDictionarySetValue(newIFs, key, newDict);
CFRelease(newDict);
CFRelease(key);
}
if (if_name && !interfaceFound) {
interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman);
key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
kSCDynamicStoreDomainState,
interface,
kSCEntNetIPv4);
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);
CFRelease(oldIFs);
CFRelease(newIFs);
return;
}
__private_extern__
void
interface_collision_ipv4(const char *if_name, struct in_addr ip_addr, int hw_len, const void * hw_addr)
{
uint8_t * hw_addr_bytes = (uint8_t *)hw_addr;
int i;
CFStringRef if_name_cf;
CFMutableStringRef key;
CFStringRef prefix;
if_name_cf = CFStringCreateWithCString(NULL, if_name,
kCFStringEncodingASCII);
prefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
kSCDynamicStoreDomainState,
if_name_cf,
kSCEntNetIPv4ARPCollision);
key = CFStringCreateMutableCopy(NULL, 0, prefix);
CFStringAppendFormat(key, NULL, CFSTR("/" IP_FORMAT),
IP_LIST(&ip_addr));
for (i = 0; i < hw_len; i++) {
CFStringAppendFormat(key, NULL, CFSTR("%s%02x"),
(i == 0) ? "/" : ":", hw_addr_bytes[i]);
}
cache_SCDynamicStoreNotifyValue(store, key);
CFRelease(key);
CFRelease(prefix);
CFRelease(if_name_cf);
return;
}