]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkSignature.c
2be8e9b079744504aa75ad033dcbd8454103ed71
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkSignature.c
1 /*
2 * Copyright (c) 2006, 2011 Apple Computer, 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 * SCNetworkSignature.c
26 * - implementation of SCNetworkSignatureRef API that allows access to
27 network identification information
28 *
29 */
30 /*
31 * Modification History
32 *
33 * November 6, 2006 Dieter Siegmund (dieter@apple.com)
34 * - initial revision
35 */
36
37
38 #include <netinet/in.h>
39 #include <CoreFoundation/CFDictionary.h>
40 #include <CoreFoundation/CFString.h>
41 #include <CoreFoundation/CFArray.h>
42 #include <CoreFoundation/CFRuntime.h>
43 #include <SystemConfiguration/SCDynamicStore.h>
44 #include <SystemConfiguration/SCValidation.h>
45 #include <SystemConfiguration/SCPrivate.h>
46 #include "SCNetworkSignature.h"
47 #include "SCNetworkSignaturePrivate.h"
48 #include <arpa/inet.h>
49
50 const char * kSCNetworkSignatureActiveChangedNotifyName = NETWORK_ID_KEY ".active";
51
52 #pragma mark SCNetworkSignature Supporting APIs
53
54 static CFStringRef
55 create_global_state_v4_key(void)
56 {
57 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
58 kSCDynamicStoreDomainState,
59 kSCEntNetIPv4);
60
61 }
62
63 static CFStringRef
64 create_global_setup_v4_key(void)
65 {
66 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
67 kSCDynamicStoreDomainSetup,
68 kSCEntNetIPv4);
69 }
70
71 static CFStringRef
72 create_ipv4_services_pattern(void)
73 {
74 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
75 kSCDynamicStoreDomainState,
76 kSCCompAnyRegex,
77 kSCEntNetIPv4);
78 }
79
80 static CFStringRef
81 create_ipv6_services_pattern(void)
82 {
83 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
84 kSCDynamicStoreDomainState,
85 kSCCompAnyRegex,
86 kSCEntNetIPv6);
87 }
88
89 static CFDictionaryRef
90 copy_services_for_address_family(CFAllocatorRef alloc,
91 int af)
92 {
93 CFDictionaryRef info;
94 CFArrayRef patterns;
95 CFStringRef pattern;
96 CFStringRef prop;
97
98 prop = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6;
99 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
100 kSCDynamicStoreDomainState,
101 kSCCompAnyRegex,
102 prop);
103 patterns = CFArrayCreate(NULL,
104 (const void * *)&pattern, 1,
105 &kCFTypeArrayCallBacks);
106 CFRelease(pattern);
107 info = SCDynamicStoreCopyMultiple(NULL, NULL, patterns);
108 CFRelease(patterns);
109
110 return (info);
111 }
112
113
114 static CF_RETURNS_RETAINED CFStringRef
115 my_IPAddressToCFString(int af, const void * src_p)
116 {
117 char ntopbuf[INET6_ADDRSTRLEN];
118
119 if (inet_ntop(af, src_p, ntopbuf, sizeof(ntopbuf)) != NULL) {
120 return (CFStringCreateWithCString(NULL, ntopbuf,
121 kCFStringEncodingASCII));
122 }
123 return (NULL);
124 }
125
126 #pragma mark -
127
128
129 #pragma mark SCNetworkSignature APIs
130
131 CFStringRef
132 SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc,
133 const struct sockaddr * addr)
134 {
135 CFStringRef ident = NULL;
136 CFDictionaryRef info = NULL;
137 CFStringRef global_state_v4_key = NULL;
138 CFDictionaryRef global_v4_state_dict = NULL;
139 CFArrayRef keys = NULL;
140 CFArrayRef patterns = NULL;
141 in_addr_t s_addr;
142 CFStringRef service = NULL;
143 CFDictionaryRef service_dict = NULL;
144 CFStringRef service_id = NULL;
145 struct sockaddr_in * sin_p;
146 CFStringRef v4_service_pattern = NULL;
147
148 /* only accept 0.0.0.0 (i.e. default) for now */
149 if (addr == NULL
150 || addr->sa_family != AF_INET
151 || addr->sa_len != sizeof(struct sockaddr_in)){
152 _SCErrorSet(kSCStatusInvalidArgument);
153 goto done;
154 }
155
156 /* ALIGN: force alignment */
157 sin_p = (struct sockaddr_in *)(void *)addr;
158 bcopy(&sin_p->sin_addr.s_addr, &s_addr, sizeof(s_addr));
159 if (s_addr != 0) {
160 _SCErrorSet(kSCStatusInvalidArgument);
161 goto done;
162 }
163
164 global_state_v4_key = create_global_state_v4_key();
165 keys = CFArrayCreate(NULL, (const void * *)&global_state_v4_key,
166 1, &kCFTypeArrayCallBacks);
167
168 v4_service_pattern = create_ipv4_services_pattern();
169 patterns = CFArrayCreate(NULL, (const void * *)&v4_service_pattern, 1,
170 &kCFTypeArrayCallBacks);
171
172 info = SCDynamicStoreCopyMultiple(NULL, keys, patterns);
173
174 if (info == NULL
175 || CFDictionaryGetCount(info) == 0) {
176 goto done;
177 }
178
179 global_v4_state_dict = CFDictionaryGetValue(info, global_state_v4_key);
180
181 if (isA_CFDictionary(global_v4_state_dict) == NULL) {
182 goto done;
183 }
184
185 service_id = CFDictionaryGetValue(global_v4_state_dict,
186 kSCDynamicStorePropNetPrimaryService);
187
188 if (isA_CFString(service_id) == NULL) {
189 goto done;
190 }
191
192 service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
193 kSCDynamicStoreDomainState,
194 service_id, kSCEntNetIPv4);
195
196 service_dict = CFDictionaryGetValue(info, service);
197
198
199 if (isA_CFDictionary(service_dict) == NULL
200 || CFDictionaryGetCount(service_dict) == 0) {
201 goto done;
202 }
203
204 ident = CFDictionaryGetValue(service_dict, kStoreKeyNetworkSignature);
205 ident = isA_CFString(ident);
206 done:
207 if (ident != NULL) {
208 CFRetain(ident);
209 } else {
210 _SCErrorSet(kSCStatusFailed);
211 }
212 if (info != NULL) {
213 CFRelease(info);
214 }
215 if (global_state_v4_key != NULL) {
216 CFRelease(global_state_v4_key);
217 }
218 if (service != NULL) {
219 CFRelease(service);
220 }
221 if (keys != NULL) {
222 CFRelease(keys);
223 }
224 if (patterns != NULL) {
225 CFRelease(patterns);
226 }
227 if (v4_service_pattern != NULL) {
228 CFRelease(v4_service_pattern);
229 }
230 return (ident);
231 }
232
233 CFArrayRef /* of CFStringRef's */
234 SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc)
235 {
236 CFMutableArrayRef active = NULL;
237 int count = 0;
238 CFStringRef global_setup_v4_key = NULL;
239 CFDictionaryRef global_v4_dict;
240 int i;
241 CFDictionaryRef info = NULL;
242 CFArrayRef keys = NULL;
243 CFMutableArrayRef patterns = NULL;
244 CFRange range;
245 CFMutableDictionaryRef services_dict = NULL;
246 CFArrayRef service_order;
247 CFStringRef v4_service_pattern = NULL;
248 CFStringRef v6_service_pattern = NULL;
249 const void * * values = NULL;
250 #define KEYS_STATIC_COUNT 10
251 const void * values_static[KEYS_STATIC_COUNT];
252
253 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
254
255 global_setup_v4_key = create_global_setup_v4_key();
256 keys = CFArrayCreate(NULL, (const void * *)&global_setup_v4_key, 1,
257 &kCFTypeArrayCallBacks);
258
259 v4_service_pattern = create_ipv4_services_pattern();
260 CFArrayAppendValue(patterns, v4_service_pattern);
261
262 v6_service_pattern = create_ipv6_services_pattern();
263 CFArrayAppendValue(patterns, v6_service_pattern);
264
265 info = SCDynamicStoreCopyMultiple(NULL, keys, patterns);
266
267 if (info == NULL
268 || CFDictionaryGetCount(info) == 0) {
269 goto done;
270 }
271
272 services_dict = CFDictionaryCreateMutableCopy(NULL, 0, info);
273 /*
274 * The service_dict should only contain services and once each
275 * service has been visited, it will be removed from the dictionary.
276 */
277 CFDictionaryRemoveValue(services_dict, global_setup_v4_key);
278
279 global_v4_dict = CFDictionaryGetValue(info, global_setup_v4_key);
280
281 if (isA_CFDictionary(global_v4_dict) == NULL) {
282 service_order = CFDictionaryGetValue(global_v4_dict,
283 kSCPropNetServiceOrder);
284 if (isA_CFArray(service_order) != NULL) {
285 count = CFArrayGetCount(service_order);
286 }
287 }
288
289 active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
290
291 range = CFRangeMake(0, 0);
292
293 for (i = 0; i < count ; i++) {
294 int j;
295 CFStringRef network_sig;
296 CFStringRef service;
297 CFStringRef service_id;
298 CFDictionaryRef service_info;
299 CFStringRef afs[2] = {kSCEntNetIPv4, kSCEntNetIPv6};
300
301 service_id = CFArrayGetValueAtIndex(service_order, i);
302
303 if (isA_CFString(service_id) == NULL) {
304 continue;
305 }
306
307 for (j = 0; j < 2; j++) {
308 service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
309 kSCDynamicStoreDomainState,
310 service_id, afs[j]);
311
312 service_info = CFDictionaryGetValue(services_dict, service);
313
314 /* Does this service have a signature? */
315 if (isA_CFDictionary(service_info) != NULL) {
316 network_sig = CFDictionaryGetValue(service_info, kStoreKeyNetworkSignature);
317 if (isA_CFString(network_sig) != NULL
318 && CFArrayContainsValue(active, range, network_sig) == FALSE) {
319 CFArrayAppendValue(active, network_sig);
320 network_sig = NULL;
321 range.length++;
322 }
323 CFDictionaryRemoveValue(services_dict, service);
324 }
325 CFRelease(service);
326 }
327 }
328
329 count = CFDictionaryGetCount(services_dict);
330
331 if (count != 0) {
332 if (count > KEYS_STATIC_COUNT) {
333 values = (const void * *)malloc(sizeof(*values) * count);
334 } else {
335 values = values_static;
336 }
337 CFDictionaryGetKeysAndValues(services_dict, NULL,
338 (const void * *)values);
339 }
340
341 for (i = 0; i < count; i++) {
342 CFStringRef network_sig;
343 CFDictionaryRef service_dict = (CFDictionaryRef)values[i];
344
345 if (isA_CFDictionary(service_dict) == NULL) {
346 continue;
347 }
348
349 network_sig = CFDictionaryGetValue(service_dict,
350 kStoreKeyNetworkSignature);
351 /* Does this service have a signature? */
352 if (isA_CFString(network_sig) != NULL
353 && CFArrayContainsValue(active, range, network_sig) == FALSE) {
354 CFArrayAppendValue(active, network_sig);
355 range.length++;
356 network_sig = NULL;
357 }
358 }
359 done:
360 if (info != NULL) {
361 CFRelease(info);
362 }
363 if (services_dict != NULL) {
364 CFRelease(services_dict);
365 }
366 if (global_setup_v4_key != NULL) {
367 CFRelease(global_setup_v4_key);
368 }
369 if (v4_service_pattern != NULL) {
370 CFRelease(v4_service_pattern);
371 }
372 if (v6_service_pattern != NULL) {
373 CFRelease(v6_service_pattern);
374 }
375 if (values != NULL && values != values_static) {
376 free(values);
377 }
378 if (keys != NULL) {
379 CFRelease(keys);
380 }
381 if (patterns != NULL) {
382 CFRelease(patterns);
383 }
384 if (active != NULL && CFArrayGetCount(active) == 0) {
385 CFRelease(active);
386 active = NULL;
387 }
388 if (active == NULL) {
389 _SCErrorSet(kSCStatusFailed);
390 }
391 return (active);
392 }
393
394
395 CFStringRef
396 SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc,
397 int sock_fd)
398 {
399 CFStringRef addresses_key;
400 int af;
401 int count;
402 int i;
403 const void * * keys = NULL;
404 #define KEYS_STATIC_COUNT 10
405 const void * keys_static[KEYS_STATIC_COUNT];
406 const void * local_ip_p;
407 CFStringRef local_ip_str = NULL;
408 CFStringRef ret_signature = NULL;
409 CFDictionaryRef service_info = NULL;
410 union {
411 struct sockaddr_in inet;
412 struct sockaddr_in6 inet6;
413 struct sockaddr sa;
414 } ss;
415 socklen_t ss_len = sizeof(ss);
416 int status = kSCStatusFailed;
417
418 if (getsockname(sock_fd, &ss.sa, &ss_len) != 0) {
419 status = kSCStatusInvalidArgument;
420 goto done;
421 }
422 af = ss.inet.sin_family;
423 switch (af) {
424 case AF_INET:
425 addresses_key = kSCPropNetIPv4Addresses;
426 local_ip_p = &ss.inet.sin_addr;
427 break;
428 case AF_INET6:
429 addresses_key = kSCPropNetIPv6Addresses;
430 local_ip_p = &ss.inet6.sin6_addr;
431 break;
432 default:
433 status = kSCStatusInvalidArgument;
434 goto done;
435 }
436
437 /* find a service matching the local IP and get its network signature */
438 service_info = copy_services_for_address_family(alloc, af);
439 if (service_info == NULL) {
440 goto done;
441 }
442 local_ip_str = my_IPAddressToCFString(af, local_ip_p);
443 if (local_ip_str == NULL) {
444 goto done;
445 }
446 count = CFDictionaryGetCount(service_info);
447 if (count > KEYS_STATIC_COUNT) {
448 keys = (const void * *)malloc(sizeof(*keys) * count);
449 }
450 else {
451 keys = keys_static;
452 }
453 CFDictionaryGetKeysAndValues(service_info, keys, NULL);
454 for (i = 0; i < count; i++) {
455 CFArrayRef addrs;
456 CFRange range;
457 CFStringRef signature;
458 CFDictionaryRef value;
459
460 value = CFDictionaryGetValue(service_info, keys[i]);
461 if (isA_CFDictionary(value) == NULL) {
462 continue;
463 }
464 signature = CFDictionaryGetValue(value,
465 kStoreKeyNetworkSignature);
466 if (isA_CFString(signature) == NULL) {
467 /* no signature */
468 continue;
469 }
470 addrs = CFDictionaryGetValue(value, addresses_key);
471 if (isA_CFArray(addrs) == NULL) {
472 continue;
473 }
474 range = CFRangeMake(0, CFArrayGetCount(addrs));
475 if (CFArrayContainsValue(addrs, range, local_ip_str)) {
476 ret_signature = CFRetain(signature);
477 status = kSCStatusOK;
478 break;
479 }
480 }
481
482 done:
483 if (local_ip_str != NULL) {
484 CFRelease(local_ip_str);
485 }
486 if (keys != NULL && keys != keys_static) {
487 free(keys);
488 }
489 if (service_info != NULL) {
490 CFRelease(service_info);
491 }
492 if (status != kSCStatusOK) {
493 _SCErrorSet(status);
494 }
495 return (ret_signature);
496 }
497
498 #pragma mark -