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