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