]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/ip_plugin.c
configd-210.tar.gz
[apple/configd.git] / Plugins / IPMonitor / ip_plugin.c
1 /*
2 * Copyright (c) 2000-2007 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 * ip_plugin.c
26 * - decides which interface will be made the "primary" interface,
27 * that is, the one with the default route assigned
28 */
29
30 /*
31 * Modification History
32 *
33 * July 19, 2000 Dieter Siegmund (dieter@apple.com)
34 * - initial revision
35 *
36 * November 15, 2000 Dieter Siegmund (dieter@apple.com)
37 * - changed to use new configuration model
38 *
39 * March 19, 2001 Dieter Siegmund (dieter@apple.com)
40 * - use service state instead of interface state
41 *
42 * July 16, 2001 Allan Nathanson (ajn@apple.com)
43 * - update to public SystemConfiguration.framework APIs
44 *
45 * August 28, 2001 Dieter Siegmund (dieter@apple.com)
46 * - specify the interface name when installing the default route
47 * - this ensures that default traffic goes to the highest priority
48 * service when multiple interfaces are configured to be on the same subnet
49 *
50 * September 16, 2002 Dieter Siegmund (dieter@apple.com)
51 * - don't elect a link-local service to be primary unless it's the only
52 * one that's available
53 *
54 * July 16, 2003 Dieter Siegmund (dieter@apple.com)
55 * - modifications to support IPv6
56 * - don't elect a service to be primary if it doesn't have a default route
57 *
58 * July 29, 2003 Dieter Siegmund (dieter@apple.com)
59 * - support installing a default route to a router that's not on our subnet
60 *
61 * March 22, 2004 Allan Nathanson (ajn@apple.com)
62 * - create expanded DNS configuration
63 *
64 * June 20, 2006 Allan Nathanson (ajn@apple.com)
65 * - add SMB configuration
66 */
67
68 #include <stdlib.h>
69 #include <unistd.h>
70 #include <string.h>
71 #include <stdio.h>
72 #include <sys/fcntl.h>
73 #include <sys/types.h>
74 #include <sys/socket.h>
75 #include <net/route.h>
76 #include <net/if.h>
77 #include <net/if_dl.h>
78 #include <netinet/in.h>
79 #include <arpa/inet.h>
80 #include <sys/sysctl.h>
81 #include <limits.h>
82 #include <notify.h>
83
84 #include <SystemConfiguration/SystemConfiguration.h>
85 #include <SystemConfiguration/SCValidation.h>
86 #include <SystemConfiguration/SCPrivate.h> /* for SCLog() */
87 #include <dnsinfo.h>
88
89 #include <dns_sd.h>
90 #ifndef kDNSServiceCompPrivateDNS
91 #define kDNSServiceCompPrivateDNS "PrivateDNS"
92 #endif
93
94 #include "set-hostname.h"
95 #include "dns-configuration.h"
96 #include "smb-configuration.h"
97
98 #define IP_FORMAT "%d.%d.%d.%d"
99 #define IP_CH(ip) ((u_char *)(ip))
100 #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
101
102 /* debug output on/off */
103 static boolean_t S_IPMonitor_debug = FALSE;
104
105 /* are we netbooted? If so, don't touch the default route */
106 static boolean_t S_netboot = FALSE;
107
108 /* dictionary to hold per-service state: key is the serviceID */
109 static CFMutableDictionaryRef S_service_state_dict = NULL;
110
111 /* if set, a PPP interface overrides the primary */
112 static boolean_t S_ppp_override_primary = FALSE;
113
114 /* the current primary serviceID's */
115 static CFStringRef S_primary_ipv4 = NULL;
116 static CFStringRef S_primary_ipv6 = NULL;
117 static CFStringRef S_primary_dns = NULL;
118 static CFStringRef S_primary_proxies = NULL;
119 static CFStringRef S_primary_smb = NULL;
120
121 static CFStringRef S_state_global_ipv4 = NULL;
122 static CFStringRef S_state_global_ipv6 = NULL;
123 static CFStringRef S_state_global_dns = NULL;
124 static CFStringRef S_state_global_proxies = NULL;
125 static CFStringRef S_state_global_smb = NULL;
126 static CFStringRef S_state_service_prefix = NULL;
127 static CFStringRef S_setup_global_ipv4 = NULL;
128 static CFStringRef S_setup_global_proxies = NULL;
129 static CFStringRef S_setup_global_smb = NULL;
130 static CFStringRef S_setup_service_prefix = NULL;
131
132 static CFStringRef S_private_resolvers = NULL;
133
134 static struct in_addr S_router_subnet = { 0 };
135 static struct in_addr S_router_subnet_mask = { 0 };
136
137 static const struct in_addr S_ip_zeros = { 0 };
138 static const struct in6_addr S_ip6_zeros = IN6ADDR_ANY_INIT;
139
140
141 #define kRouterNeedsLocalIP CFSTR("com.apple.IPMonitor.RouterNeedsLocalIP")
142 #define kRouterIsDirect CFSTR("com.apple.IPMonitor.IsDirect")
143
144 #define VAR_RUN_RESOLV_CONF "/var/run/resolv.conf"
145
146 #ifndef KERN_NETBOOT
147 #define KERN_NETBOOT 40 /* int: are we netbooted? 1=yes,0=no */
148 #endif KERN_NETBOOT
149
150 /**
151 ** entityType*, GetEntityChanges*
152 ** - definitions for the entity types we handle
153 **/
154 #define ENTITY_TYPES_COUNT 5
155 enum {
156 kEntityTypeIPv4 = 0,
157 kEntityTypeIPv6 = 1,
158 kEntityTypeDNS = 2,
159 kEntityTypeProxies = 3,
160 kEntityTypeSMB = 4,
161 };
162 typedef uint32_t EntityType;
163
164 static CFStringRef entityTypeNames[ENTITY_TYPES_COUNT];
165
166 typedef boolean_t (GetEntityChangesFunc)(CFStringRef serviceID,
167 CFDictionaryRef state_dict,
168 CFDictionaryRef setup_dict,
169 CFDictionaryRef info);
170 typedef GetEntityChangesFunc * GetEntityChangesFuncRef;
171
172 static GetEntityChangesFunc get_ipv4_changes;
173 static GetEntityChangesFunc get_ipv6_changes;
174 static GetEntityChangesFunc get_dns_changes;
175 static GetEntityChangesFunc get_proxies_changes;
176 static GetEntityChangesFunc get_smb_changes;
177
178 static void
179 my_CFRelease(void * t);
180
181 static void
182 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new);
183
184 static void
185 my_CFArrayRemoveValue(CFMutableArrayRef arr, CFStringRef key);
186
187 static const GetEntityChangesFuncRef entityChangeFunc[ENTITY_TYPES_COUNT] = {
188 get_ipv4_changes, /* 0 */
189 get_ipv6_changes, /* 1 */
190 get_dns_changes, /* 2 */
191 get_proxies_changes,/* 3 */
192 get_smb_changes, /* 4 */
193 };
194
195 /**
196 ** keyChangeList
197 ** - mechanism to do an atomic update of the SCDynamicStore
198 ** when the content needs to be changed across multiple functions
199 **/
200 typedef struct {
201 CFMutableArrayRef notify;
202 CFMutableArrayRef remove;
203 CFMutableDictionaryRef set;
204 } keyChangeList, * keyChangeListRef;
205
206 static void
207 keyChangeListInit(keyChangeListRef keys)
208 {
209 keys->notify = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
210 keys->remove = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
211 keys->set = CFDictionaryCreateMutable(NULL, 0,
212 &kCFTypeDictionaryKeyCallBacks,
213 &kCFTypeDictionaryValueCallBacks);
214 return;
215 }
216
217 static void
218 keyChangeListFree(keyChangeListRef keys)
219 {
220 my_CFRelease(&keys->notify);
221 my_CFRelease(&keys->remove);
222 my_CFRelease(&keys->set);
223 return;
224 }
225
226 static void
227 keyChangeListNotifyKey(keyChangeListRef keys, CFStringRef key)
228 {
229 my_CFArrayAppendUniqueValue(keys->notify, key);
230 return;
231 }
232
233 static void
234 keyChangeListRemoveValue(keyChangeListRef keys, CFStringRef key)
235 {
236 my_CFArrayAppendUniqueValue(keys->remove, key);
237 CFDictionaryRemoveValue(keys->set, key);
238 return;
239 }
240
241 static void
242 keyChangeListSetValue(keyChangeListRef keys, CFStringRef key, CFTypeRef value)
243 {
244 my_CFArrayRemoveValue(keys->remove, key);
245 CFDictionarySetValue(keys->set, key, value);
246 return;
247 }
248
249 static void
250 keyChangeListApplyToStore(keyChangeListRef keys, SCDynamicStoreRef session)
251 {
252 CFArrayRef notify = keys->notify;
253 CFArrayRef remove = keys->remove;
254 CFDictionaryRef set = keys->set;
255 int status;
256
257 if (CFArrayGetCount(notify) == 0) {
258 notify = NULL;
259 }
260 if (CFArrayGetCount(remove) == 0) {
261 remove = NULL;
262 }
263 if (CFDictionaryGetCount(set) == 0) {
264 set = NULL;
265 }
266 if (set == NULL && remove == NULL && notify == NULL) {
267 return;
268 }
269 if (S_IPMonitor_debug) {
270 if (set != NULL) {
271 SCLog(TRUE, LOG_INFO, CFSTR("IPMonitor: Setting:\n%@\n"), set);
272 }
273 if (remove != NULL) {
274 SCLog(TRUE, LOG_INFO, CFSTR("IPMonitor: Removing:\n%@\n"), remove);
275 }
276 if (notify != NULL) {
277 SCLog(TRUE, LOG_INFO, CFSTR("IPMonitor: Notifying:\n%@\n"), notify);
278 }
279 }
280 (void)SCDynamicStoreSetMultiple(session, set, remove, notify);
281
282 status = notify_post("com.apple.system.config.network_change");
283 if (status == NOTIFY_STATUS_OK) {
284 SCLog(TRUE, LOG_INFO, CFSTR("network configuration changed."));
285 } else {
286 SCLog(TRUE, LOG_INFO,
287 CFSTR("IPMonitor: notify_post() failed: error=%ld"), status);
288 }
289
290 return;
291 }
292
293 static boolean_t
294 S_netboot_root()
295 {
296 int mib[2];
297 size_t len;
298 int netboot = 0;
299
300 mib[0] = CTL_KERN;
301 mib[1] = KERN_NETBOOT;
302 len = sizeof(netboot);
303 sysctl(mib, 2, &netboot, &len, NULL, 0);
304 return (netboot);
305 }
306
307 static void
308 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new)
309 {
310 CFIndex n = CFArrayGetCount(arr);
311
312 if (CFArrayContainsValue(arr, CFRangeMake(0, n), new)) {
313 return;
314 }
315 CFArrayAppendValue(arr, new);
316 return;
317 }
318
319 static void
320 my_CFArrayRemoveValue(CFMutableArrayRef arr, CFStringRef key)
321 {
322 CFIndex i;
323
324 i = CFArrayGetFirstIndexOfValue(arr,
325 CFRangeMake(0, CFArrayGetCount(arr)),
326 key);
327 if (i != kCFNotFound) {
328 CFArrayRemoveValueAtIndex(arr, i);
329 }
330 return;
331 }
332
333 static void
334 my_CFRelease(void * t)
335 {
336 void * * obj = (void * *)t;
337
338 if (obj && *obj) {
339 CFRelease(*obj);
340 *obj = NULL;
341 }
342 return;
343 }
344
345 static CFDictionaryRef
346 my_CFDictionaryGetDictionary(CFDictionaryRef dict, CFStringRef key)
347 {
348 if (isA_CFDictionary(dict) == NULL) {
349 return (NULL);
350 }
351 return (isA_CFDictionary(CFDictionaryGetValue(dict, key)));
352 }
353
354 static boolean_t
355 cfstring_to_ipvx(int family, CFStringRef str, void * addr, int addr_size)
356 {
357 char buf[128];
358
359 if (isA_CFString(str) == NULL) {
360 goto done;
361 }
362
363 switch (family) {
364 case AF_INET:
365 if (addr_size < sizeof(struct in_addr)) {
366 goto done;
367 }
368 break;
369 case AF_INET6:
370 if (addr_size < sizeof(struct in6_addr)) {
371 goto done;
372 }
373 break;
374 default:
375 goto done;
376 }
377 (void)_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII);
378 if (inet_pton(family, buf, addr) == 1) {
379 return (TRUE);
380 }
381 done:
382 bzero(addr, addr_size);
383 return (FALSE);
384 }
385
386 static boolean_t
387 cfstring_to_ip(CFStringRef str, struct in_addr * ip_p)
388 {
389 return (cfstring_to_ipvx(AF_INET, str, ip_p, sizeof(*ip_p)));
390 }
391
392 static boolean_t
393 cfstring_to_ip6(CFStringRef str, struct in6_addr * ip6_p)
394 {
395 return (cfstring_to_ipvx(AF_INET6, str, ip6_p, sizeof(*ip6_p)));
396 }
397
398 /*
399 * Function: parse_component
400 * Purpose:
401 * Given a string 'key' and a string prefix 'prefix',
402 * return the next component in the slash '/' separated
403 * key.
404 *
405 * Examples:
406 * 1. key = "a/b/c" prefix = "a/"
407 * returns "b"
408 * 2. key = "a/b/c" prefix = "a/b/"
409 * returns "c"
410 */
411 static CFStringRef
412 parse_component(CFStringRef key, CFStringRef prefix)
413 {
414 CFMutableStringRef comp;
415 CFRange range;
416
417 if (CFStringHasPrefix(key, prefix) == FALSE) {
418 return (NULL);
419 }
420 comp = CFStringCreateMutableCopy(NULL, 0, key);
421 if (comp == NULL) {
422 return (NULL);
423 }
424 CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
425 range = CFStringFind(comp, CFSTR("/"), 0);
426 if (range.location == kCFNotFound) {
427 return (comp);
428 }
429 range.length = CFStringGetLength(comp) - range.location;
430 CFStringDelete(comp, range);
431 return (comp);
432 }
433
434 static CFMutableDictionaryRef
435 service_dict_copy(CFStringRef serviceID)
436 {
437 CFDictionaryRef d = NULL;
438 CFMutableDictionaryRef service_dict;
439
440 /* create a modifyable dictionary, a copy or a new one */
441 d = CFDictionaryGetValue(S_service_state_dict, serviceID);
442 if (d == NULL) {
443 service_dict
444 = CFDictionaryCreateMutable(NULL, 0,
445 &kCFTypeDictionaryKeyCallBacks,
446 &kCFTypeDictionaryValueCallBacks);
447 }
448 else {
449 service_dict = CFDictionaryCreateMutableCopy(NULL, 0, d);
450 }
451 return (service_dict);
452 }
453
454 static boolean_t
455 service_dict_set(CFStringRef serviceID, CFStringRef entity,
456 CFDictionaryRef new_dict)
457 {
458 boolean_t changed = FALSE;
459 CFDictionaryRef old;
460 CFMutableDictionaryRef service_dict;
461
462 service_dict = service_dict_copy(serviceID);
463 old = CFDictionaryGetValue(service_dict, entity);
464 if (new_dict == NULL) {
465 if (old != NULL) {
466 SCLog(S_IPMonitor_debug, LOG_INFO,
467 CFSTR("IPMonitor: serviceID %@ removed %@ dictionary = %@"),
468 serviceID, entity, old);
469 CFDictionaryRemoveValue(service_dict, entity);
470 changed = TRUE;
471 }
472 }
473 else {
474 if (old == NULL || CFEqual(new_dict, old) == FALSE) {
475 SCLog(S_IPMonitor_debug, LOG_INFO,
476 CFSTR("IPMonitor: serviceID %@ changed %@"
477 " dictionary\nold %@\nnew %@"), serviceID, entity,
478 (old != NULL) ? (CFTypeRef)old : (CFTypeRef)CFSTR("<none>"),
479 new_dict);
480 CFDictionarySetValue(service_dict, entity, new_dict);
481 changed = TRUE;
482 }
483 }
484 if (CFDictionaryGetCount(service_dict) == 0) {
485 CFDictionaryRemoveValue(S_service_state_dict, serviceID);
486 }
487 else {
488 CFDictionarySetValue(S_service_state_dict, serviceID, service_dict);
489 }
490 my_CFRelease(&service_dict);
491 return (changed);
492 }
493
494 static CFDictionaryRef
495 service_dict_get(CFStringRef serviceID, CFStringRef entity)
496 {
497 CFDictionaryRef service_dict;
498
499 service_dict = CFDictionaryGetValue(S_service_state_dict, serviceID);
500 if (service_dict == NULL) {
501 return (NULL);
502 }
503 return (CFDictionaryGetValue(service_dict, entity));
504 }
505
506 #define ALLOW_EMTPY_STRING 1<<0
507
508 static CFTypeRef
509 sanitize_prop(CFTypeRef val, uint32_t flags)
510 {
511 if (val != NULL) {
512 if (isA_CFString(val)) {
513 CFMutableStringRef str;
514
515 str = CFStringCreateMutableCopy(NULL, 0, (CFStringRef)val);
516 CFStringTrimWhitespace(str);
517 if (!(flags & ALLOW_EMTPY_STRING) && (CFStringGetLength(str) == 0)) {
518 CFRelease(str);
519 str = NULL;
520 }
521 val = str;
522 } else {
523 CFRetain(val);
524 }
525 }
526
527 return val;
528 }
529
530 static void
531 merge_array_prop(CFMutableDictionaryRef dict,
532 CFStringRef key,
533 CFDictionaryRef state_dict,
534 CFDictionaryRef setup_dict,
535 uint32_t flags,
536 Boolean append)
537 {
538 CFMutableArrayRef merge_prop;
539 CFArrayRef setup_prop = NULL;
540 CFArrayRef state_prop = NULL;
541
542 if (setup_dict != NULL) {
543 setup_prop = isA_CFArray(CFDictionaryGetValue(setup_dict, key));
544 }
545 if (state_dict != NULL) {
546 state_prop = isA_CFArray(CFDictionaryGetValue(state_dict, key));
547 }
548
549 if ((setup_prop == NULL) && (state_prop == NULL)) {
550 return;
551 }
552
553 merge_prop = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
554 if (setup_prop != NULL) {
555 CFIndex i;
556 CFIndex n;
557
558 n = CFArrayGetCount(setup_prop);
559 for (i = 0; i < n; i++) {
560 CFTypeRef val;
561
562 val = CFArrayGetValueAtIndex(setup_prop, i);
563 val = sanitize_prop(val, flags);
564 if (val != NULL) {
565 CFArrayAppendValue(merge_prop, val);
566 CFRelease(val);
567 }
568 }
569 }
570 if (state_prop != NULL) {
571 CFIndex i;
572 CFIndex n;
573 CFRange setup_range = CFRangeMake(0, CFArrayGetCount(merge_prop));
574
575 n = CFArrayGetCount(state_prop);
576 for (i = 0; i < n; i++) {
577 CFTypeRef val;
578
579 val = CFArrayGetValueAtIndex(state_prop, i);
580 val = sanitize_prop(val, flags);
581 if (val != NULL) {
582 if (append || !CFArrayContainsValue(merge_prop, setup_range, val)) {
583 CFArrayAppendValue(merge_prop, val);
584 }
585 CFRelease(val);
586 }
587 }
588 }
589 if (CFArrayGetCount(merge_prop) > 0) {
590 CFDictionarySetValue(dict, key, merge_prop);
591 }
592 CFRelease(merge_prop);
593 return;
594 }
595
596 static void
597 pick_prop(CFMutableDictionaryRef dict,
598 CFStringRef key,
599 CFDictionaryRef state_dict,
600 CFDictionaryRef setup_dict,
601 uint32_t flags)
602 {
603 CFTypeRef val = NULL;
604
605 if (setup_dict != NULL) {
606 val = CFDictionaryGetValue(setup_dict, key);
607 val = sanitize_prop(val, flags);
608 }
609 if (val == NULL && state_dict != NULL) {
610 val = CFDictionaryGetValue(state_dict, key);
611 val = sanitize_prop(val, flags);
612 }
613 if (val != NULL) {
614 CFDictionarySetValue(dict, key, val);
615 CFRelease(val);
616 }
617
618 return;
619 }
620
621 /**
622 ** GetEntityChangesFunc functions
623 **/
624 static __inline__ struct in_addr
625 subnet_addr(struct in_addr addr, struct in_addr mask)
626 {
627 struct in_addr net;
628
629 net.s_addr = htonl((uint32_t)ntohl(addr.s_addr)
630 & (uint32_t)ntohl(mask.s_addr));
631 return (net);
632 }
633
634 static boolean_t
635 get_ipv4_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
636 CFDictionaryRef setup_dict, CFDictionaryRef info)
637 {
638 struct in_addr addr = { 0 };
639 CFArrayRef addrs;
640 boolean_t changed = FALSE;
641 CFMutableDictionaryRef dict = NULL;
642 struct in_addr mask = { 0 };
643 CFArrayRef masks;
644 CFDictionaryRef new_dict = NULL;
645 CFStringRef router = NULL;
646 boolean_t valid_ip = FALSE;
647 boolean_t valid_mask = FALSE;
648
649 if (state_dict == NULL) {
650 goto done;
651 }
652 addrs = isA_CFArray(CFDictionaryGetValue(state_dict,
653 kSCPropNetIPv4Addresses));
654 if (addrs != NULL && CFArrayGetCount(addrs) > 0) {
655 valid_ip = cfstring_to_ip(CFArrayGetValueAtIndex(addrs, 0), &addr);
656 }
657 masks = isA_CFArray(CFDictionaryGetValue(state_dict,
658 kSCPropNetIPv4SubnetMasks));
659 if (masks != NULL && CFArrayGetCount(masks) > 0) {
660 valid_mask = cfstring_to_ip(CFArrayGetValueAtIndex(masks, 0), &mask);
661 }
662 if (valid_ip == FALSE) {
663 SCLog(S_IPMonitor_debug, LOG_INFO,
664 CFSTR("IPMonitor: %@ has no valid IP address, ignoring"),
665 serviceID);
666 goto done;
667 }
668 dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict);
669 if (setup_dict != NULL) {
670 router = CFDictionaryGetValue(setup_dict,
671 kSCPropNetIPv4Router);
672 if (router != NULL) {
673 CFDictionarySetValue(dict,
674 kSCPropNetIPv4Router,
675 router);
676 }
677 }
678
679 /* check whether the router is direct, or non-local */
680 router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
681 if (router != NULL) {
682 struct in_addr router_ip;
683
684 if (cfstring_to_ip(router, &router_ip)) {
685 if (router_ip.s_addr == addr.s_addr) {
686 /* default route routes directly to the interface */
687 CFDictionarySetValue(dict, kRouterIsDirect, kCFBooleanTrue);
688 }
689 else if (valid_mask
690 && subnet_addr(addr, mask).s_addr
691 != subnet_addr(router_ip, mask).s_addr) {
692 /* router is not on the same subnet */
693 CFDictionarySetValue(dict, kRouterNeedsLocalIP,
694 kCFBooleanTrue);
695 }
696 }
697 }
698 new_dict = dict;
699
700 done:
701 changed = service_dict_set(serviceID, kSCEntNetIPv4, new_dict);
702 my_CFRelease(&new_dict);
703 return (changed);
704 }
705
706 static boolean_t
707 get_ipv6_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
708 CFDictionaryRef setup_dict, CFDictionaryRef info)
709 {
710 struct in6_addr addr;
711 CFArrayRef addrs;
712 boolean_t changed = FALSE;
713 CFMutableDictionaryRef dict = NULL;
714 CFDictionaryRef new_dict = NULL;
715 CFStringRef router = NULL;
716 boolean_t valid_ip = FALSE;
717
718 if (state_dict == NULL) {
719 goto done;
720 }
721 addrs = isA_CFArray(CFDictionaryGetValue(state_dict,
722 kSCPropNetIPv6Addresses));
723 if (addrs != NULL && CFArrayGetCount(addrs) > 0) {
724 valid_ip = cfstring_to_ip6(CFArrayGetValueAtIndex(addrs, 0), &addr);
725 }
726 if (valid_ip == FALSE) {
727 SCLog(S_IPMonitor_debug, LOG_INFO,
728 CFSTR("IPMonitor: %@ has no valid IPv6 address, ignoring"),
729 serviceID);
730 goto done;
731 }
732 dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict);
733 if (setup_dict != NULL) {
734 router = CFDictionaryGetValue(setup_dict,
735 kSCPropNetIPv6Router);
736 if (router != NULL) {
737 CFDictionarySetValue(dict,
738 kSCPropNetIPv6Router,
739 router);
740 }
741 }
742 new_dict = dict;
743 done:
744 changed = service_dict_set(serviceID, kSCEntNetIPv6, new_dict);
745 my_CFRelease(&new_dict);
746 return (changed);
747 }
748
749 static boolean_t
750 dns_has_supplemental(CFStringRef serviceID)
751 {
752 CFDictionaryRef dns_dict;
753 CFDictionaryRef service_dict;
754
755 service_dict = CFDictionaryGetValue(S_service_state_dict, serviceID);
756 if (service_dict == NULL) {
757 return FALSE;
758 }
759
760 dns_dict = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
761 if (dns_dict == NULL) {
762 return FALSE;
763 }
764
765 return CFDictionaryContainsKey(dns_dict, kSCPropNetDNSSupplementalMatchDomains);
766 }
767
768 static boolean_t
769 get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
770 CFDictionaryRef setup_dict, CFDictionaryRef info)
771 {
772 boolean_t changed = FALSE;
773 CFStringRef domain;
774 int i;
775 struct {
776 CFStringRef key;
777 uint32_t flags;
778 Boolean append;
779 } merge_list[] = {
780 { kSCPropNetDNSSearchDomains, 0, FALSE },
781 { kSCPropNetDNSServerAddresses, 0, FALSE },
782 { kSCPropNetDNSSortList, 0, FALSE },
783 { kSCPropNetDNSSupplementalMatchDomains, ALLOW_EMTPY_STRING, TRUE },
784 { kSCPropNetDNSSupplementalMatchOrders, 0, TRUE },
785 };
786 CFMutableDictionaryRef new_dict = NULL;
787 CFStringRef pick_list[] = {
788 kSCPropNetDNSDomainName,
789 kSCPropNetDNSOptions,
790 kSCPropNetDNSSearchOrder,
791 kSCPropNetDNSServerPort,
792 kSCPropNetDNSServerTimeout,
793 };
794
795 if ((state_dict == NULL) && (setup_dict == NULL)) {
796 /* there is no DNS */
797 goto done;
798 }
799
800 if ((service_dict_get(serviceID, kSCEntNetIPv4) == NULL) &&
801 (service_dict_get(serviceID, kSCEntNetIPv6) == NULL)) {
802 /* there is no IPv4 nor IPv6 */
803 goto done;
804 }
805
806 // merge DNS configuration
807 new_dict = CFDictionaryCreateMutable(NULL, 0,
808 &kCFTypeDictionaryKeyCallBacks,
809 &kCFTypeDictionaryValueCallBacks);
810
811 for (i = 0; i < sizeof(merge_list)/sizeof(merge_list[0]); i++) {
812 merge_array_prop(new_dict,
813 merge_list[i].key,
814 state_dict,
815 setup_dict,
816 merge_list[i].flags,
817 merge_list[i].append);
818 }
819 for (i = 0; i < sizeof(pick_list)/sizeof(pick_list[0]); i++) {
820 pick_prop(new_dict,
821 pick_list[i],
822 state_dict,
823 setup_dict,
824 0);
825 }
826
827 if (CFDictionaryGetCount(new_dict) == 0) {
828 my_CFRelease(&new_dict);
829 goto done;
830 }
831
832 /*
833 * ensure any specified domain name (e.g. the domain returned by
834 * a DHCP server) is in the search list.
835 */
836 domain = CFDictionaryGetValue(new_dict, kSCPropNetDNSDomainName);
837 if (isA_CFString(domain)) {
838 CFArrayRef search;
839
840 search = CFDictionaryGetValue(new_dict, kSCPropNetDNSSearchDomains);
841 if (isA_CFArray(search) &&
842 !CFArrayContainsValue(search, CFRangeMake(0, CFArrayGetCount(search)), domain)) {
843 CFMutableArrayRef new_search;
844
845 new_search = CFArrayCreateMutableCopy(NULL, 0, search);
846 CFArrayAppendValue(new_search, domain);
847 CFDictionarySetValue(new_dict, kSCPropNetDNSSearchDomains, new_search);
848 my_CFRelease(&new_search);
849 }
850 }
851
852 done:
853 changed = service_dict_set(serviceID, kSCEntNetDNS, new_dict);
854 my_CFRelease(&new_dict);
855 return (changed);
856 }
857
858 static boolean_t
859 get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
860 CFDictionaryRef setup_dict, CFDictionaryRef info)
861 {
862 boolean_t changed = FALSE;
863 CFDictionaryRef new_dict = NULL;
864
865 if ((service_dict_get(serviceID, kSCEntNetIPv4) == NULL) &&
866 (service_dict_get(serviceID, kSCEntNetIPv6) == NULL)) {
867 /* there is no IPv4 nor IPv6 */
868 goto done;
869 }
870 if (setup_dict != NULL) {
871 new_dict = setup_dict;
872 }
873 else {
874 new_dict = state_dict;
875 }
876 done:
877 changed = service_dict_set(serviceID, kSCEntNetProxies, new_dict);
878 return (changed);
879 }
880
881 static boolean_t
882 get_smb_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
883 CFDictionaryRef setup_dict, CFDictionaryRef info)
884 {
885 boolean_t changed = FALSE;
886 int i;
887 CFMutableDictionaryRef new_dict = NULL;
888 CFStringRef pick_list[] = {
889 kSCPropNetSMBNetBIOSName,
890 kSCPropNetSMBNetBIOSNodeType,
891 kSCPropNetSMBNetBIOSScope,
892 kSCPropNetSMBWorkgroup,
893 };
894
895 if (service_dict_get(serviceID, kSCEntNetIPv4) == NULL) {
896 /* there is no IPv4 */
897 goto done;
898 }
899
900 if (state_dict == NULL && setup_dict == NULL) {
901 /* there is no SMB */
902 goto done;
903 }
904
905 // merge SMB configuration
906 new_dict = CFDictionaryCreateMutable(NULL, 0,
907 &kCFTypeDictionaryKeyCallBacks,
908 &kCFTypeDictionaryValueCallBacks);
909
910 merge_array_prop(new_dict,
911 kSCPropNetSMBWINSAddresses,
912 state_dict,
913 setup_dict,
914 0,
915 FALSE);
916 for (i = 0; i < sizeof(pick_list)/sizeof(pick_list[0]); i++) {
917 pick_prop(new_dict,
918 pick_list[i],
919 state_dict,
920 setup_dict,
921 0);
922 }
923
924 if (CFDictionaryGetCount(new_dict) == 0) {
925 my_CFRelease(&new_dict);
926 goto done;
927 }
928
929 done:
930 changed = service_dict_set(serviceID, kSCEntNetSMB, new_dict);
931 my_CFRelease(&new_dict);
932 return (changed);
933 }
934
935 static CFStringRef
936 state_service_key(CFStringRef serviceID, CFStringRef entity)
937 {
938 return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
939 kSCDynamicStoreDomainState,
940 serviceID,
941 entity));
942 }
943
944 static CFStringRef
945 setup_service_key(CFStringRef serviceID, CFStringRef entity)
946 {
947 return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
948 kSCDynamicStoreDomainSetup,
949 serviceID,
950 entity));
951 }
952
953 static CFDictionaryRef
954 services_info_copy(SCDynamicStoreRef session, CFArrayRef service_list)
955 {
956 int count;
957 CFMutableArrayRef get_keys;
958 int i;
959 int s;
960 CFDictionaryRef info;
961
962 count = CFArrayGetCount(service_list);
963 get_keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
964
965 CFArrayAppendValue(get_keys, S_setup_global_ipv4);
966 CFArrayAppendValue(get_keys, S_setup_global_proxies);
967 CFArrayAppendValue(get_keys, S_setup_global_smb);
968 CFArrayAppendValue(get_keys, S_private_resolvers);
969
970 for (s = 0; s < count; s++) {
971 CFStringRef serviceID = CFArrayGetValueAtIndex(service_list, s);
972
973 for (i = 0; i < ENTITY_TYPES_COUNT; i++) {
974 CFStringRef setup_key;
975 CFStringRef state_key;
976
977 setup_key = setup_service_key(serviceID, entityTypeNames[i]);
978 state_key = state_service_key(serviceID, entityTypeNames[i]);
979 CFArrayAppendValue(get_keys, setup_key);
980 CFArrayAppendValue(get_keys, state_key);
981 my_CFRelease(&setup_key);
982 my_CFRelease(&state_key);
983 }
984 }
985
986 info = SCDynamicStoreCopyMultiple(session, get_keys, NULL);
987 my_CFRelease(&get_keys);
988 return (info);
989 }
990
991 static CFDictionaryRef
992 get_service_setup_entity(CFDictionaryRef service_info, CFStringRef serviceID,
993 CFStringRef entity)
994 {
995 CFStringRef setup_key;
996 CFDictionaryRef setup_dict;
997
998 setup_key = setup_service_key(serviceID, entity);
999 setup_dict = my_CFDictionaryGetDictionary(service_info, setup_key);
1000 my_CFRelease(&setup_key);
1001 return (setup_dict);
1002 }
1003
1004 static CFDictionaryRef
1005 get_service_state_entity(CFDictionaryRef service_info, CFStringRef serviceID,
1006 CFStringRef entity)
1007 {
1008 CFStringRef state_key;
1009 CFDictionaryRef state_dict;
1010
1011 state_key = state_service_key(serviceID, entity);
1012 state_dict = my_CFDictionaryGetDictionary(service_info, state_key);
1013 my_CFRelease(&state_key);
1014 return (state_dict);
1015 }
1016
1017 static int rtm_seq = 0;
1018
1019 static boolean_t
1020 ipv4_route(int cmd, struct in_addr gateway, struct in_addr netaddr,
1021 struct in_addr netmask, char * ifname, struct in_addr ifa,
1022 boolean_t is_direct)
1023 {
1024 boolean_t default_route = (netaddr.s_addr == 0);
1025 int len;
1026 boolean_t ret = TRUE;
1027 struct {
1028 struct rt_msghdr hdr;
1029 struct sockaddr_in dst;
1030 struct sockaddr_in gway;
1031 struct sockaddr_in mask;
1032 struct sockaddr_dl ifp;
1033 struct sockaddr_in ifa;
1034 } rtmsg;
1035 int sockfd = -1;
1036
1037 if (default_route && S_netboot) {
1038 return (TRUE);
1039 }
1040
1041 if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) == -1) {
1042 SCLog(TRUE, LOG_INFO,
1043 CFSTR("IPMonitor: ipv4_route: open routing socket failed, %s"),
1044 strerror(errno));
1045 return (FALSE);
1046 }
1047
1048 memset(&rtmsg, 0, sizeof(rtmsg));
1049 rtmsg.hdr.rtm_type = cmd;
1050 if (default_route) {
1051 if (is_direct) {
1052 /* if router is directly reachable, don't set the gateway flag */
1053 rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
1054 }
1055 else {
1056 rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
1057 }
1058 }
1059 else {
1060 rtmsg.hdr.rtm_flags = RTF_UP | RTF_CLONING | RTF_STATIC;
1061 }
1062 rtmsg.hdr.rtm_version = RTM_VERSION;
1063 rtmsg.hdr.rtm_seq = ++rtm_seq;
1064 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
1065 rtmsg.dst.sin_len = sizeof(rtmsg.dst);
1066 rtmsg.dst.sin_family = AF_INET;
1067 rtmsg.dst.sin_addr = netaddr;
1068 rtmsg.gway.sin_len = sizeof(rtmsg.gway);
1069 rtmsg.gway.sin_family = AF_INET;
1070 rtmsg.gway.sin_addr = gateway;
1071 rtmsg.mask.sin_len = sizeof(rtmsg.mask);
1072 rtmsg.mask.sin_family = AF_INET;
1073 rtmsg.mask.sin_addr = netmask;
1074
1075 len = sizeof(rtmsg);
1076 if (ifname) {
1077 rtmsg.hdr.rtm_addrs |= RTA_IFP | RTA_IFA;
1078 /* copy the interface name */
1079 rtmsg.ifp.sdl_len = sizeof(rtmsg.ifp);
1080 rtmsg.ifp.sdl_family = AF_LINK;
1081 rtmsg.ifp.sdl_nlen = strlen(ifname);
1082 bcopy(ifname, rtmsg.ifp.sdl_data, rtmsg.ifp.sdl_nlen);
1083 /* and the interface address */
1084 rtmsg.ifa.sin_len = sizeof(rtmsg.ifa);
1085 rtmsg.ifa.sin_family = AF_INET;
1086 rtmsg.ifa.sin_addr = ifa;
1087 }
1088 else {
1089 /* no ifp/ifa information */
1090 len -= sizeof(rtmsg.ifp) + sizeof(rtmsg.ifa);
1091 }
1092 rtmsg.hdr.rtm_msglen = len;
1093 if (write(sockfd, &rtmsg, len) == -1) {
1094 if ((cmd == RTM_ADD) && (errno == EEXIST)) {
1095 /* no sense complaining about a route that already exists */
1096 }
1097 else if ((cmd == RTM_DELETE) && (errno == ESRCH)) {
1098 /* no sense complaining about a route that isn't there */
1099 }
1100 else {
1101 SCLog(S_IPMonitor_debug, LOG_INFO,
1102 CFSTR("IPMonitor ipv4_route: "
1103 "write routing socket failed, %s"), strerror(errno));
1104 ret = FALSE;
1105 }
1106 }
1107
1108 close(sockfd);
1109 return (ret);
1110 }
1111
1112 static boolean_t
1113 ipv6_route(int cmd, struct in6_addr gateway, struct in6_addr netaddr,
1114 struct in6_addr netmask, char * ifname, boolean_t is_direct)
1115 {
1116 boolean_t default_route;
1117 int len;
1118 boolean_t ret = TRUE;
1119 struct {
1120 struct rt_msghdr hdr;
1121 struct sockaddr_in6 dst;
1122 struct sockaddr_in6 gway;
1123 struct sockaddr_in6 mask;
1124 struct sockaddr_dl ifp;
1125 } rtmsg;
1126 int sockfd = -1;
1127 struct in6_addr zeroes = IN6ADDR_ANY_INIT;
1128
1129 default_route = (bcmp(&zeroes, &netaddr, sizeof(netaddr)) == 0);
1130
1131 if (IN6_IS_ADDR_LINKLOCAL(&gateway) && ifname != NULL) {
1132 unsigned int index = if_nametoindex(ifname);
1133
1134 /* add the scope id to the link local address */
1135 gateway.__u6_addr.__u6_addr16[1] = (uint16_t)htons(index);
1136 }
1137 if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) == -1) {
1138 SCLog(TRUE, LOG_INFO,
1139 CFSTR("IPMonitor ipv6_route: open routing socket failed, %s"),
1140 strerror(errno));
1141 return (FALSE);
1142 }
1143 memset(&rtmsg, 0, sizeof(rtmsg));
1144 rtmsg.hdr.rtm_type = cmd;
1145 if (default_route) {
1146 if (is_direct) {
1147 /* if router is directly reachable, don't set the gateway flag */
1148 rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
1149 }
1150 else {
1151 rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
1152 }
1153 }
1154 else {
1155 rtmsg.hdr.rtm_flags = RTF_UP | RTF_CLONING | RTF_STATIC;
1156 }
1157 rtmsg.hdr.rtm_version = RTM_VERSION;
1158 rtmsg.hdr.rtm_seq = ++rtm_seq;
1159 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
1160 rtmsg.dst.sin6_len = sizeof(rtmsg.dst);
1161 rtmsg.dst.sin6_family = AF_INET6;
1162 rtmsg.dst.sin6_addr = netaddr;
1163 rtmsg.gway.sin6_len = sizeof(rtmsg.gway);
1164 rtmsg.gway.sin6_family = AF_INET6;
1165 rtmsg.gway.sin6_addr = gateway;
1166 rtmsg.mask.sin6_len = sizeof(rtmsg.mask);
1167 rtmsg.mask.sin6_family = AF_INET6;
1168 rtmsg.mask.sin6_addr = netmask;
1169
1170 len = sizeof(rtmsg);
1171 if (ifname) {
1172 rtmsg.ifp.sdl_len = sizeof(rtmsg.ifp);
1173 rtmsg.ifp.sdl_family = AF_LINK;
1174 rtmsg.ifp.sdl_nlen = strlen(ifname);
1175 rtmsg.hdr.rtm_addrs |= RTA_IFP;
1176 bcopy(ifname, rtmsg.ifp.sdl_data, rtmsg.ifp.sdl_nlen);
1177 }
1178 else {
1179 /* no ifp information */
1180 len -= sizeof(rtmsg.ifp);
1181 }
1182 rtmsg.hdr.rtm_msglen = len;
1183 if (write(sockfd, &rtmsg, len) == -1) {
1184 if ((cmd == RTM_ADD) && (errno == EEXIST)) {
1185 /* no sense complaining about a route that already exists */
1186 }
1187 else if ((cmd == RTM_DELETE) && (errno == ESRCH)) {
1188 /* no sense complaining about a route that isn't there */
1189 }
1190 else {
1191 SCLog(S_IPMonitor_debug, LOG_INFO,
1192 CFSTR("IPMonitor ipv6_route: write routing"
1193 " socket failed, %s"), strerror(errno));
1194 ret = FALSE;
1195 }
1196 }
1197
1198 close(sockfd);
1199 return (ret);
1200 }
1201
1202 static boolean_t
1203 ipv4_subnet_route_add(struct in_addr local_ip,
1204 struct in_addr subnet, struct in_addr mask, char * ifname)
1205 {
1206 if (S_IPMonitor_debug) {
1207 SCLog(TRUE, LOG_INFO,
1208 CFSTR("IPMonitor: IPv4 route add -net "
1209 IP_FORMAT " -netmask %s interface %s"),
1210 IP_LIST(&subnet), inet_ntoa(mask), ifname);
1211 }
1212 return (ipv4_route(RTM_ADD, local_ip, subnet, mask, ifname, local_ip,
1213 FALSE));
1214 }
1215
1216 static boolean_t
1217 ipv4_subnet_route_delete(struct in_addr subnet, struct in_addr mask)
1218 {
1219 if (S_IPMonitor_debug) {
1220 SCLog(TRUE, LOG_INFO,
1221 CFSTR("IPMonitor: IPv4 route delete -net "
1222 IP_FORMAT " %s"),
1223 IP_LIST(&subnet), inet_ntoa(mask));
1224 }
1225 return (ipv4_route(RTM_DELETE, S_ip_zeros, subnet, mask, NULL,
1226 S_ip_zeros, FALSE));
1227 }
1228
1229
1230 static boolean_t
1231 ipv4_default_route_delete(void)
1232 {
1233 if (S_IPMonitor_debug) {
1234 SCLog(TRUE, LOG_INFO, CFSTR("IPMonitor: IPv4 route delete default"));
1235 }
1236 return (ipv4_route(RTM_DELETE, S_ip_zeros, S_ip_zeros, S_ip_zeros, NULL,
1237 S_ip_zeros, FALSE));
1238 }
1239
1240 static boolean_t
1241 ipv4_default_route_add(struct in_addr router, char * ifname,
1242 struct in_addr local_ip, boolean_t is_direct)
1243 {
1244 if (S_IPMonitor_debug) {
1245 SCLog(TRUE, LOG_INFO,
1246 CFSTR("IPMonitor: IPv4 route add default"
1247 " %s interface %s direct %d"),
1248 inet_ntoa(router), ifname, is_direct);
1249 }
1250 return (ipv4_route(RTM_ADD, router, S_ip_zeros, S_ip_zeros, ifname,
1251 local_ip, is_direct));
1252 }
1253
1254 static boolean_t
1255 ipv4_default_route_change(struct in_addr router, char * ifname,
1256 struct in_addr local_ip, boolean_t is_direct)
1257 {
1258 if (S_IPMonitor_debug) {
1259 SCLog(TRUE, LOG_INFO,
1260 CFSTR("IPMonitor: IPv4 route change default"
1261 " %s interface %s direct %d"),
1262 inet_ntoa(router), ifname, is_direct);
1263 }
1264 return (ipv4_route(RTM_CHANGE, router, S_ip_zeros, S_ip_zeros, ifname,
1265 local_ip, is_direct));
1266 }
1267
1268 static boolean_t
1269 ipv6_default_route_delete(void)
1270 {
1271 if (S_IPMonitor_debug) {
1272 SCLog(TRUE, LOG_INFO, CFSTR("IPMonitor: IPv6 route delete default"));
1273 }
1274 return (ipv6_route(RTM_DELETE, S_ip6_zeros, S_ip6_zeros, S_ip6_zeros, NULL, FALSE));
1275 }
1276
1277 static boolean_t
1278 ipv6_default_route_add(struct in6_addr router, char * ifname,
1279 boolean_t is_direct)
1280 {
1281 if (S_IPMonitor_debug) {
1282 char str[128];
1283
1284 str[0] = '\0';
1285
1286 inet_ntop(AF_INET6, &router, str, sizeof(str));
1287 SCLog(TRUE,LOG_INFO,
1288 CFSTR("IPMonitor: IPv6 route add default"
1289 " %s interface %s direct %d"),
1290 str, ifname, is_direct);
1291 }
1292 return (ipv6_route(RTM_ADD, router, S_ip6_zeros, S_ip6_zeros, ifname, is_direct));
1293 }
1294
1295
1296 static boolean_t
1297 multicast_route_delete()
1298 {
1299 struct in_addr gateway = { htonl(INADDR_LOOPBACK) };
1300 struct in_addr netaddr = { htonl(INADDR_UNSPEC_GROUP) };
1301 struct in_addr netmask = { htonl(IN_CLASSD_NET) };
1302
1303 return (ipv4_route(RTM_DELETE, gateway, netaddr, netmask, "lo0",
1304 gateway, FALSE));
1305 }
1306
1307 static boolean_t
1308 multicast_route_add()
1309 {
1310 struct in_addr gateway = { htonl(INADDR_LOOPBACK) };
1311 struct in_addr netaddr = { htonl(INADDR_UNSPEC_GROUP) };
1312 struct in_addr netmask = { htonl(IN_CLASSD_NET) };
1313
1314 return (ipv4_route(RTM_ADD, gateway, netaddr, netmask, "lo0",
1315 gateway, FALSE));
1316 }
1317
1318 static void
1319 set_ipv4_router(struct in_addr * router, char * ifname,
1320 struct in_addr * local_ip, boolean_t is_direct)
1321 {
1322 if (S_router_subnet.s_addr != 0) {
1323 ipv4_subnet_route_delete(S_router_subnet, S_router_subnet_mask);
1324 S_router_subnet.s_addr = S_router_subnet_mask.s_addr = 0;
1325 }
1326 /* assign the new default route, ensure local multicast route available */
1327 (void)ipv4_default_route_delete();
1328 if (router != NULL) {
1329 (void)ipv4_default_route_add(*router, ifname,
1330 (local_ip != NULL)
1331 ? *local_ip : S_ip_zeros,
1332 is_direct);
1333 (void)multicast_route_delete();
1334 }
1335 else {
1336 (void)multicast_route_add();
1337 }
1338
1339 return;
1340 }
1341
1342 static void
1343 set_ipv6_router(struct in6_addr * router, char * ifname, boolean_t is_direct)
1344 {
1345 /* assign the new default route, ensure local multicast route available */
1346 (void)ipv6_default_route_delete();
1347 if (router != NULL) {
1348 (void)ipv6_default_route_add(*router, ifname, is_direct);
1349 }
1350 return;
1351 }
1352
1353 static __inline__ void
1354 empty_dns()
1355 {
1356 (void)unlink(VAR_RUN_RESOLV_CONF);
1357 }
1358
1359 static void
1360 set_dns(CFArrayRef val_search_domains,
1361 CFStringRef val_domain_name,
1362 CFArrayRef val_servers,
1363 CFArrayRef val_sortlist)
1364 {
1365 FILE * f = fopen(VAR_RUN_RESOLV_CONF "-", "w");
1366
1367 /* publish new resolv.conf */
1368 if (f) {
1369 CFIndex i;
1370 CFIndex n;
1371
1372 if (isA_CFString(val_domain_name)) {
1373 SCPrint(TRUE, f, CFSTR("domain %@\n"), val_domain_name);
1374 }
1375
1376 if (isA_CFArray(val_search_domains)) {
1377 SCPrint(TRUE, f, CFSTR("search"));
1378 n = CFArrayGetCount(val_search_domains);
1379 for (i = 0; i < n; i++) {
1380 CFStringRef domain;
1381
1382 domain = CFArrayGetValueAtIndex(val_search_domains, i);
1383 if (isA_CFString(domain)) {
1384 SCPrint(TRUE, f, CFSTR(" %@"), domain);
1385 }
1386 }
1387 SCPrint(TRUE, f, CFSTR("\n"));
1388 }
1389
1390 if (isA_CFArray(val_servers)) {
1391 n = CFArrayGetCount(val_servers);
1392 for (i = 0; i < n; i++) {
1393 CFStringRef nameserver;
1394
1395 nameserver = CFArrayGetValueAtIndex(val_servers, i);
1396 if (isA_CFString(nameserver)) {
1397 SCPrint(TRUE, f, CFSTR("nameserver %@\n"), nameserver);
1398 }
1399 }
1400 }
1401
1402 if (isA_CFArray(val_sortlist)) {
1403 SCPrint(TRUE, f, CFSTR("sortlist"));
1404 n = CFArrayGetCount(val_sortlist);
1405 for (i = 0; i < n; i++) {
1406 CFStringRef address;
1407
1408 address = CFArrayGetValueAtIndex(val_sortlist, i);
1409 if (isA_CFString(address)) {
1410 SCPrint(TRUE, f, CFSTR(" %@"), address);
1411 }
1412 }
1413 SCPrint(TRUE, f, CFSTR("\n"));
1414 }
1415
1416 fclose(f);
1417 rename(VAR_RUN_RESOLV_CONF "-", VAR_RUN_RESOLV_CONF);
1418 }
1419 return;
1420 }
1421
1422 static boolean_t
1423 router_is_our_ipv6_address(CFStringRef router, CFArrayRef addr_list)
1424 {
1425 CFIndex i;
1426 CFIndex n = CFArrayGetCount(addr_list);
1427 struct in6_addr r;
1428
1429 (void)cfstring_to_ip6(router, &r);
1430 for (i = 0; i < n; i++) {
1431 struct in6_addr ip;
1432
1433 if (cfstring_to_ip6(CFArrayGetValueAtIndex(addr_list, i), &ip)
1434 && bcmp(&r, &ip, sizeof(r)) == 0) {
1435 return (TRUE);
1436 }
1437 }
1438 return (FALSE);
1439 }
1440
1441 static void
1442 update_ipv4(CFDictionaryRef service_info,
1443 CFStringRef primary,
1444 keyChangeListRef keys)
1445 {
1446 CFDictionaryRef ipv4_dict = NULL;
1447
1448 if (primary != NULL) {
1449 CFDictionaryRef service_dict;
1450
1451 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
1452 if (service_dict != NULL) {
1453 ipv4_dict = CFDictionaryGetValue(service_dict, kSCEntNetIPv4);
1454 }
1455 }
1456 if (ipv4_dict != NULL) {
1457 CFMutableDictionaryRef dict = NULL;
1458 CFStringRef if_name = NULL;
1459 char ifn[IFNAMSIZ + 1] = { '\0' };
1460 char * ifn_p = NULL;
1461 boolean_t is_direct = FALSE;
1462 struct in_addr local_ip = { 0 };
1463 CFStringRef local_ip_cf;
1464 CFArrayRef local_ip_list;
1465 boolean_t needs_local_ip = FALSE;
1466 struct in_addr router = { 0 };
1467 CFStringRef val_router = NULL;
1468
1469 dict = CFDictionaryCreateMutable(NULL, 0,
1470 &kCFTypeDictionaryKeyCallBacks,
1471 &kCFTypeDictionaryValueCallBacks);
1472 local_ip_list = CFDictionaryGetValue(ipv4_dict,
1473 kSCPropNetIPv4Addresses);
1474 local_ip_cf = CFArrayGetValueAtIndex(local_ip_list, 0);
1475 cfstring_to_ip(local_ip_cf, &local_ip);
1476 val_router = CFDictionaryGetValue(ipv4_dict, kSCPropNetIPv4Router);
1477 if (val_router != NULL) {
1478 cfstring_to_ip(val_router, &router);
1479 CFDictionarySetValue(dict, kSCPropNetIPv4Router, val_router);
1480 if (CFDictionaryContainsKey(ipv4_dict, kRouterIsDirect)) {
1481 is_direct = TRUE;
1482 }
1483 else if (CFDictionaryContainsKey(ipv4_dict, kRouterNeedsLocalIP)) {
1484 needs_local_ip = TRUE;
1485 }
1486 }
1487 else {
1488 is_direct = TRUE;
1489 router = local_ip;
1490 }
1491 if_name = CFDictionaryGetValue(ipv4_dict, kSCPropInterfaceName);
1492 if (if_name) {
1493 CFDictionarySetValue(dict,
1494 kSCDynamicStorePropNetPrimaryInterface,
1495 if_name);
1496 if (CFStringGetCString(if_name, ifn, sizeof(ifn),
1497 kCFStringEncodingASCII)) {
1498 ifn_p = ifn;
1499 }
1500 }
1501 CFDictionarySetValue(dict, kSCDynamicStorePropNetPrimaryService,
1502 primary);
1503 keyChangeListSetValue(keys, S_state_global_ipv4, dict);
1504 CFRelease(dict);
1505
1506 /* route add default ... */
1507 if (needs_local_ip) {
1508 struct in_addr m;
1509
1510 m.s_addr = htonl(INADDR_BROADCAST);
1511 ipv4_subnet_route_add(local_ip, router, m, ifn_p);
1512 set_ipv4_router(&local_ip, ifn_p, &local_ip, FALSE);
1513 ipv4_default_route_change(router, ifn_p, local_ip, FALSE);
1514 S_router_subnet = router;
1515 S_router_subnet_mask = m;
1516 }
1517 else {
1518 set_ipv4_router(&router, ifn_p, &local_ip, is_direct);
1519 }
1520 }
1521 else {
1522 keyChangeListRemoveValue(keys, S_state_global_ipv4);
1523 set_ipv4_router(NULL, NULL, NULL, FALSE);
1524 }
1525 return;
1526 }
1527
1528 static void
1529 update_ipv6(CFDictionaryRef service_info,
1530 CFStringRef primary,
1531 keyChangeListRef keys)
1532 {
1533 CFDictionaryRef ipv6_dict = NULL;
1534
1535 if (primary != NULL) {
1536 CFDictionaryRef service_dict;
1537
1538 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
1539 if (service_dict != NULL) {
1540 ipv6_dict = CFDictionaryGetValue(service_dict, kSCEntNetIPv6);
1541 }
1542 }
1543 if (ipv6_dict != NULL) {
1544 CFArrayRef addrs;
1545 CFMutableDictionaryRef dict = NULL;
1546 CFStringRef if_name = NULL;
1547 char ifn[IFNAMSIZ + 1] = { '\0' };
1548 char * ifn_p = NULL;
1549 boolean_t is_direct = FALSE;
1550 CFStringRef val_router = NULL;
1551
1552 dict = CFDictionaryCreateMutable(NULL, 0,
1553 &kCFTypeDictionaryKeyCallBacks,
1554 &kCFTypeDictionaryValueCallBacks);
1555 val_router = CFDictionaryGetValue(ipv6_dict, kSCPropNetIPv6Router);
1556 addrs = CFDictionaryGetValue(ipv6_dict,
1557 kSCPropNetIPv6Addresses);
1558 if (val_router != NULL) {
1559 /* no router if router is one of our IP addresses */
1560 is_direct = router_is_our_ipv6_address(val_router, addrs);
1561 CFDictionarySetValue(dict, kSCPropNetIPv6Router,
1562 val_router);
1563 }
1564 else {
1565 val_router = CFArrayGetValueAtIndex(addrs, 0);
1566 is_direct = TRUE;
1567 }
1568 if_name = CFDictionaryGetValue(ipv6_dict, kSCPropInterfaceName);
1569 if (if_name) {
1570 CFDictionarySetValue(dict,
1571 kSCDynamicStorePropNetPrimaryInterface,
1572 if_name);
1573 if (CFStringGetCString(if_name, ifn, sizeof(ifn),
1574 kCFStringEncodingASCII)) {
1575 ifn_p = ifn;
1576 }
1577 }
1578 CFDictionarySetValue(dict, kSCDynamicStorePropNetPrimaryService,
1579 primary);
1580 keyChangeListSetValue(keys, S_state_global_ipv6, dict);
1581 CFRelease(dict);
1582
1583 { /* route add default ... */
1584 struct in6_addr router;
1585
1586 (void)cfstring_to_ip6(val_router, &router);
1587 set_ipv6_router(&router, ifn_p, is_direct);
1588 }
1589 }
1590 else {
1591 keyChangeListRemoveValue(keys, S_state_global_ipv6);
1592 set_ipv6_router(NULL, NULL, FALSE);
1593 }
1594 return;
1595 }
1596
1597 static void
1598 update_dns(CFDictionaryRef service_info,
1599 CFStringRef primary,
1600 keyChangeListRef keys)
1601 {
1602 CFDictionaryRef dict = NULL;
1603
1604 if (primary != NULL) {
1605 CFDictionaryRef service_dict;
1606
1607 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
1608 if (service_dict != NULL) {
1609 dict = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
1610 }
1611 }
1612 if (dict == NULL) {
1613 empty_dns();
1614 keyChangeListRemoveValue(keys, S_state_global_dns);
1615 }
1616 else {
1617 set_dns(CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains),
1618 CFDictionaryGetValue(dict, kSCPropNetDNSDomainName),
1619 CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses),
1620 CFDictionaryGetValue(dict, kSCPropNetDNSSortList));
1621 keyChangeListSetValue(keys, S_state_global_dns, dict);
1622 }
1623 return;
1624 }
1625
1626 static void
1627 update_dnsinfo(CFDictionaryRef service_info,
1628 CFStringRef primary,
1629 keyChangeListRef keys,
1630 CFArrayRef service_order)
1631 {
1632 CFArrayRef privateResolvers;
1633
1634 privateResolvers = CFDictionaryGetValue(service_info, S_private_resolvers);
1635
1636 if (primary == NULL) {
1637 dns_configuration_set(NULL, NULL, NULL, privateResolvers);
1638 } else {
1639 CFDictionaryRef dict = NULL;
1640 CFDictionaryRef service_dict;
1641
1642 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
1643 if (service_dict != NULL) {
1644 dict = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
1645 }
1646
1647 dns_configuration_set(dict, S_service_state_dict, service_order, privateResolvers);
1648 }
1649 keyChangeListNotifyKey(keys, S_state_global_dns);
1650 return;
1651 }
1652
1653 static void
1654 update_proxies(CFDictionaryRef service_info,
1655 CFStringRef primary,
1656 keyChangeListRef keys)
1657 {
1658 CFDictionaryRef dict = NULL;
1659
1660 if (primary != NULL) {
1661 CFDictionaryRef service_dict;
1662
1663 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
1664 if (service_dict != NULL) {
1665 dict = CFDictionaryGetValue(service_dict, kSCEntNetProxies);
1666 if (dict == NULL) {
1667 dict = my_CFDictionaryGetDictionary(service_info,
1668 S_setup_global_proxies);
1669 }
1670 }
1671 }
1672 if (dict == NULL) {
1673 keyChangeListRemoveValue(keys, S_state_global_proxies);
1674 }
1675 else {
1676 keyChangeListSetValue(keys, S_state_global_proxies, dict);
1677 }
1678 return;
1679 }
1680
1681 static void
1682 update_smb(CFDictionaryRef service_info,
1683 CFStringRef primary,
1684 keyChangeListRef keys)
1685 {
1686 CFDictionaryRef dict = NULL;
1687
1688 if (primary != NULL) {
1689 CFDictionaryRef service_dict;
1690
1691 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
1692 if (service_dict != NULL) {
1693 dict = CFDictionaryGetValue(service_dict, kSCEntNetSMB);
1694 if (dict == NULL) {
1695 dict = my_CFDictionaryGetDictionary(service_info,
1696 S_setup_global_smb);
1697 }
1698 }
1699 }
1700 if (dict == NULL) {
1701 keyChangeListRemoveValue(keys, S_state_global_smb);
1702 }
1703 else {
1704 keyChangeListSetValue(keys, S_state_global_smb, dict);
1705 }
1706
1707 return;
1708 }
1709
1710 static unsigned int
1711 get_service_rank(CFStringRef proto_key, CFArrayRef order, CFStringRef serviceID)
1712 {
1713 CFDictionaryRef d;
1714 CFIndex i;
1715 CFDictionaryRef proto_dict;
1716
1717 if (serviceID == NULL) {
1718 goto done;
1719 }
1720 d = CFDictionaryGetValue(S_service_state_dict, serviceID);
1721 if (d == NULL) {
1722 goto done;
1723 }
1724
1725 proto_dict = CFDictionaryGetValue(d, proto_key);
1726 if (proto_dict) {
1727 CFStringRef if_name;
1728 CFNumberRef override = NULL;
1729
1730 if_name = CFDictionaryGetValue(proto_dict, kSCPropInterfaceName);
1731 if (S_ppp_override_primary == TRUE
1732 && if_name != NULL
1733 && CFStringHasPrefix(if_name, CFSTR("ppp"))) {
1734 /* PPP override: make ppp* look the best */
1735 /* Hack: should use interface type, not interface name */
1736 return (0);
1737 }
1738 /* check for the "OverridePrimary" property */
1739 override = CFDictionaryGetValue(proto_dict, kSCPropNetOverridePrimary);
1740 if (isA_CFNumber(override) != NULL) {
1741 int val = 0;
1742
1743 CFNumberGetValue(override, kCFNumberIntType, &val);
1744 if (val != 0) {
1745 return (0);
1746 }
1747 }
1748 }
1749
1750 if (serviceID != NULL && order != NULL) {
1751 CFIndex n = CFArrayGetCount(order);
1752
1753 for (i = 0; i < n; i++) {
1754 CFStringRef s = isA_CFString(CFArrayGetValueAtIndex(order, i));
1755
1756 if (s == NULL) {
1757 continue;
1758 }
1759 if (CFEqual(serviceID, s)) {
1760 return (i + 1);
1761 }
1762 }
1763 }
1764
1765 done:
1766 return (UINT_MAX);
1767 }
1768
1769 /**
1770 ** Service election:
1771 **/
1772 typedef boolean_t (*routerCheckFunc)(CFStringRef str);
1773
1774 static boolean_t
1775 check_ipv4_router(CFStringRef router)
1776 {
1777 struct in_addr ip;
1778
1779 return (cfstring_to_ip(router, &ip));
1780 }
1781
1782 static boolean_t
1783 check_ipv6_router(CFStringRef router)
1784 {
1785 struct in6_addr ip6;
1786
1787 return (cfstring_to_ip6(router, &ip6));
1788 }
1789
1790 struct election_state {
1791 routerCheckFunc router_check;
1792 CFStringRef proto_key; /* e.g. kSCEntNetIPv4 */
1793 CFStringRef router_key;/* e.g. kSCPropNetIPv4Router */
1794 CFArrayRef order;
1795 CFStringRef new_primary;
1796 boolean_t new_has_router;
1797 unsigned int new_primary_index;
1798 };
1799
1800 static void
1801 elect_protocol(const void * key, const void * value, void * context)
1802 {
1803 struct election_state * elect_p = (struct election_state *)context;
1804 CFDictionaryRef proto_dict = NULL;
1805 CFStringRef router;
1806 boolean_t router_valid = FALSE;
1807 CFStringRef serviceID = (CFStringRef)key;
1808 CFDictionaryRef service_dict = (CFDictionaryRef)value;
1809 unsigned int service_index;
1810
1811 proto_dict = CFDictionaryGetValue(service_dict, elect_p->proto_key);
1812 if (proto_dict == NULL) {
1813 return;
1814 }
1815 router = CFDictionaryGetValue(proto_dict, elect_p->router_key);
1816 router_valid = (*elect_p->router_check)(router);
1817 if (router_valid == FALSE && elect_p->new_has_router == TRUE) {
1818 /* skip it */
1819 return;
1820 }
1821 service_index
1822 = get_service_rank(elect_p->proto_key, elect_p->order, serviceID);
1823 if (elect_p->new_primary == NULL
1824 || service_index < elect_p->new_primary_index
1825 || (router_valid && elect_p->new_has_router == FALSE)) {
1826 my_CFRelease(&elect_p->new_primary);
1827 elect_p->new_primary = CFRetain(serviceID);
1828 elect_p->new_primary_index = service_index;
1829 elect_p->new_has_router = router_valid;
1830 }
1831 return;
1832 }
1833
1834 static CFStringRef
1835 elect_new_primary(CFArrayRef order, CFStringRef proto_key,
1836 CFStringRef router_key)
1837 {
1838 struct election_state elect;
1839
1840 if (CFEqual(proto_key, kSCEntNetIPv4)) {
1841 elect.router_check = check_ipv4_router;
1842 }
1843 else if (CFEqual(proto_key, kSCEntNetIPv6)) {
1844 elect.router_check = check_ipv6_router;
1845 }
1846 else {
1847 return (NULL);
1848 }
1849 elect.order = order;
1850 elect.new_primary = NULL;
1851 elect.new_primary_index = 0;
1852 elect.new_has_router = FALSE;
1853 elect.proto_key = proto_key;
1854 elect.router_key = router_key;
1855 CFDictionaryApplyFunction(S_service_state_dict, elect_protocol, &elect);
1856 return (elect.new_primary);
1857 }
1858
1859 static uint32_t
1860 service_changed(CFDictionaryRef services_info, CFStringRef serviceID)
1861 {
1862 uint32_t changed = 0;
1863 int i;
1864
1865 for (i = 0; i < ENTITY_TYPES_COUNT; i++) {
1866 GetEntityChangesFuncRef func = entityChangeFunc[i];
1867 if ((*func)(serviceID,
1868 get_service_state_entity(services_info, serviceID,
1869 entityTypeNames[i]),
1870 get_service_setup_entity(services_info, serviceID,
1871 entityTypeNames[i]),
1872 services_info)) {
1873 changed |= (1 << i);
1874 }
1875 }
1876 return (changed);
1877 }
1878
1879 static CFArrayRef
1880 service_order_get(CFDictionaryRef services_info)
1881 {
1882 CFArrayRef order = NULL;
1883 CFDictionaryRef ipv4_dict;
1884
1885 ipv4_dict = my_CFDictionaryGetDictionary(services_info,
1886 S_setup_global_ipv4);
1887 if (ipv4_dict != NULL) {
1888 CFNumberRef ppp_override;
1889 int ppp_val = 0;
1890
1891 order = CFDictionaryGetValue(ipv4_dict, kSCPropNetServiceOrder);
1892 order = isA_CFArray(order);
1893
1894 /* get ppp override primary */
1895 ppp_override = CFDictionaryGetValue(ipv4_dict,
1896 kSCPropNetPPPOverridePrimary);
1897 ppp_override = isA_CFNumber(ppp_override);
1898 if (ppp_override != NULL) {
1899 CFNumberGetValue(ppp_override, kCFNumberIntType, &ppp_val);
1900 }
1901 S_ppp_override_primary = (ppp_val != 0) ? TRUE : FALSE;
1902 }
1903 else {
1904 S_ppp_override_primary = FALSE;
1905 }
1906 return (order);
1907 }
1908
1909 static boolean_t
1910 set_new_primary(CFStringRef * primary_p, CFStringRef new_primary,
1911 const char * entity)
1912 {
1913 boolean_t changed = FALSE;
1914 CFStringRef primary = *primary_p;
1915
1916 if (new_primary != NULL) {
1917 if (primary != NULL && CFEqual(new_primary, primary)) {
1918 SCLog(S_IPMonitor_debug, LOG_INFO,
1919 CFSTR("IPMonitor: %@ is still primary %s"),
1920 new_primary, entity);
1921 }
1922 else {
1923 my_CFRelease(primary_p);
1924 *primary_p = CFRetain(new_primary);
1925 SCLog(S_IPMonitor_debug, LOG_INFO,
1926 CFSTR("IPMonitor: %@ is the new primary %s"),
1927 new_primary, entity);
1928 changed = TRUE;
1929 }
1930 }
1931 else if (primary != NULL) {
1932 SCLog(S_IPMonitor_debug, LOG_INFO,
1933 CFSTR("IPMonitor: %@ is no longer primary %s"), primary, entity);
1934 my_CFRelease(primary_p);
1935 changed = TRUE;
1936 }
1937 return (changed);
1938 }
1939
1940 static unsigned int
1941 rank_service_entity(CFArrayRef order, CFStringRef primary,
1942 CFStringRef proto_key, CFStringRef entity)
1943 {
1944 CFDictionaryRef dict;
1945 dict = service_dict_get(primary, entity);
1946 if (dict == NULL) {
1947 return (UINT_MAX);
1948 }
1949 return (get_service_rank(proto_key, order, primary));
1950 }
1951
1952 static void
1953 IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
1954 void * not_used)
1955 {
1956 CFIndex count;
1957 boolean_t dnsinfo_changed = FALSE;
1958 boolean_t global_ipv4_changed = FALSE;
1959 boolean_t global_ipv6_changed = FALSE;
1960 keyChangeList keys;
1961 int i;
1962 CFIndex n;
1963 CFArrayRef service_order;
1964 CFMutableArrayRef service_changes = NULL;
1965 CFDictionaryRef services_info = NULL;
1966
1967 count = CFArrayGetCount(changed_keys);
1968 if (count == 0) {
1969 return;
1970 }
1971
1972 SCLog(S_IPMonitor_debug, LOG_INFO,
1973 CFSTR("IPMonitor: changes %@ (%d)"), changed_keys, count);
1974
1975 keyChangeListInit(&keys);
1976 service_changes = CFArrayCreateMutable(NULL, 0,
1977 &kCFTypeArrayCallBacks);
1978 for (i = 0; i < count; i++) {
1979 CFStringRef change = CFArrayGetValueAtIndex(changed_keys, i);
1980 if (CFEqual(change, S_setup_global_ipv4)) {
1981 global_ipv4_changed = TRUE;
1982 global_ipv6_changed = TRUE;
1983 }
1984 else if (CFEqual(change, S_setup_global_proxies)) {
1985 if (S_primary_proxies != NULL) {
1986 my_CFArrayAppendUniqueValue(service_changes, S_primary_proxies);
1987 }
1988 }
1989 else if (CFEqual(change, S_setup_global_smb)) {
1990 if (S_primary_smb != NULL) {
1991 my_CFArrayAppendUniqueValue(service_changes, S_primary_smb);
1992 }
1993 }
1994 else if (CFEqual(change, S_private_resolvers)) {
1995 dnsinfo_changed = TRUE;
1996 }
1997 else if (CFStringHasPrefix(change, S_state_service_prefix)) {
1998 CFStringRef serviceID = parse_component(change,
1999 S_state_service_prefix);
2000 if (serviceID) {
2001 my_CFArrayAppendUniqueValue(service_changes, serviceID);
2002 CFRelease(serviceID);
2003 }
2004 }
2005 else if (CFStringHasPrefix(change, S_setup_service_prefix)) {
2006 CFStringRef serviceID = parse_component(change,
2007 S_setup_service_prefix);
2008 if (serviceID) {
2009 my_CFArrayAppendUniqueValue(service_changes, serviceID);
2010 CFRelease(serviceID);
2011 }
2012 }
2013 }
2014
2015 /* grab a snapshot of everything we need */
2016 services_info = services_info_copy(session, service_changes);
2017 service_order = service_order_get(services_info);
2018 if (service_order != NULL) {
2019 SCLog(S_IPMonitor_debug, LOG_INFO,
2020 CFSTR("IPMonitor: service_order %@ "), service_order);
2021 }
2022 n = CFArrayGetCount(service_changes);
2023 for (i = 0; i < n; i++) {
2024 uint32_t changes;
2025 CFStringRef serviceID;
2026 Boolean wasSupplemental;
2027
2028 serviceID = CFArrayGetValueAtIndex(service_changes, i);
2029 wasSupplemental = dns_has_supplemental(serviceID);
2030 changes = service_changed(services_info, serviceID);
2031
2032 if (S_primary_ipv4 != NULL && CFEqual(S_primary_ipv4, serviceID)) {
2033 if ((changes & (1 << kEntityTypeIPv4)) != 0) {
2034 update_ipv4(services_info, serviceID, &keys);
2035 global_ipv4_changed = TRUE;
2036 }
2037 }
2038 else if ((changes & (1 << kEntityTypeIPv4)) != 0) {
2039 global_ipv4_changed = TRUE;
2040 }
2041 if ((changes & (1 << kEntityTypeIPv6)) != 0) {
2042 if (S_primary_ipv6 != NULL && CFEqual(S_primary_ipv6, serviceID)) {
2043 update_ipv6(services_info, serviceID, &keys);
2044 }
2045 global_ipv6_changed = TRUE;
2046 }
2047 if ((changes & (1 << kEntityTypeDNS)) != 0) {
2048 if (S_primary_dns != NULL && CFEqual(S_primary_dns, serviceID)) {
2049 update_dns(services_info, serviceID, &keys);
2050 dnsinfo_changed = TRUE;
2051 }
2052 else if (wasSupplemental || dns_has_supplemental(serviceID)) {
2053 dnsinfo_changed = TRUE;
2054 }
2055 }
2056 if ((changes & (1 << kEntityTypeProxies)) != 0) {
2057 if (S_primary_proxies != NULL && CFEqual(S_primary_proxies, serviceID)) {
2058 update_proxies(services_info, serviceID, &keys);
2059 }
2060 }
2061 if ((changes & (1 << kEntityTypeSMB)) != 0) {
2062 if (S_primary_smb != NULL && CFEqual(S_primary_smb, serviceID)) {
2063 update_smb(services_info, serviceID, &keys);
2064 }
2065 }
2066 }
2067
2068 if (global_ipv4_changed) {
2069 CFStringRef new_primary;
2070
2071 SCLog(S_IPMonitor_debug, LOG_INFO,
2072 CFSTR("IPMonitor: IPv4 service election"));
2073 new_primary = elect_new_primary(service_order,
2074 kSCEntNetIPv4, kSCPropNetIPv4Router);
2075 if (set_new_primary(&S_primary_ipv4, new_primary, "IPv4")) {
2076 update_ipv4(services_info, S_primary_ipv4, &keys);
2077 }
2078 my_CFRelease(&new_primary);
2079 }
2080 if (global_ipv6_changed) {
2081 CFStringRef new_primary;
2082
2083 SCLog(S_IPMonitor_debug, LOG_INFO,
2084 CFSTR("IPMonitor: IPv6 service election"));
2085 new_primary = elect_new_primary(service_order,
2086 kSCEntNetIPv6, kSCPropNetIPv6Router);
2087 if (set_new_primary(&S_primary_ipv6, new_primary, "IPv6")) {
2088 update_ipv6(services_info, S_primary_ipv6, &keys);
2089 }
2090 my_CFRelease(&new_primary);
2091 }
2092 if (global_ipv4_changed || global_ipv6_changed) {
2093 CFStringRef new_primary_dns;
2094 CFStringRef new_primary_proxies;
2095 CFStringRef new_primary_smb;
2096
2097 if (S_primary_ipv4 != NULL && S_primary_ipv6 != NULL) {
2098 /* decide between IPv4 and IPv6 */
2099 if (rank_service_entity(service_order, S_primary_ipv4,
2100 kSCEntNetIPv4, kSCEntNetDNS)
2101 <= rank_service_entity(service_order, S_primary_ipv6,
2102 kSCEntNetIPv6, kSCEntNetDNS)) {
2103 new_primary_dns = S_primary_ipv4;
2104 }
2105 else {
2106 new_primary_dns = S_primary_ipv6;
2107 }
2108 if (rank_service_entity(service_order, S_primary_ipv4,
2109 kSCEntNetIPv4, kSCEntNetProxies)
2110 <= rank_service_entity(service_order, S_primary_ipv6,
2111 kSCEntNetIPv6, kSCEntNetProxies)) {
2112 new_primary_proxies = S_primary_ipv4;
2113 }
2114 else {
2115 new_primary_proxies = S_primary_ipv6;
2116 }
2117 if (rank_service_entity(service_order, S_primary_ipv4,
2118 kSCEntNetIPv4, kSCEntNetSMB)
2119 <= rank_service_entity(service_order, S_primary_ipv6,
2120 kSCEntNetIPv6, kSCEntNetSMB)) {
2121 new_primary_smb = S_primary_ipv4;
2122 }
2123 else {
2124 new_primary_smb = S_primary_ipv6;
2125 }
2126
2127 }
2128 else if (S_primary_ipv6 != NULL) {
2129 new_primary_dns = S_primary_ipv6;
2130 new_primary_proxies = S_primary_ipv6;
2131 new_primary_smb = S_primary_ipv6;
2132 }
2133 else if (S_primary_ipv4 != NULL) {
2134 new_primary_dns = S_primary_ipv4;
2135 new_primary_proxies = S_primary_ipv4;
2136 new_primary_smb = S_primary_ipv4;
2137 }
2138 else {
2139 new_primary_dns = NULL;
2140 new_primary_proxies = NULL;
2141 new_primary_smb = NULL;
2142 }
2143
2144 if (set_new_primary(&S_primary_dns, new_primary_dns, "DNS")) {
2145 update_dns(services_info, S_primary_dns, &keys);
2146 dnsinfo_changed = TRUE;
2147 }
2148 if (set_new_primary(&S_primary_proxies, new_primary_proxies, "Proxies")) {
2149 update_proxies(services_info, S_primary_proxies, &keys);
2150 }
2151 if (set_new_primary(&S_primary_smb, new_primary_smb, "SMB")) {
2152 update_smb(services_info, S_primary_smb, &keys);
2153 }
2154 }
2155 if (dnsinfo_changed) {
2156 update_dnsinfo(services_info, S_primary_dns, &keys, service_order);
2157 }
2158 my_CFRelease(&service_changes);
2159 my_CFRelease(&services_info);
2160 keyChangeListApplyToStore(&keys, session);
2161 keyChangeListFree(&keys);
2162 return;
2163 }
2164
2165 static void
2166 initEntityNames(void)
2167 {
2168 entityTypeNames[0] = kSCEntNetIPv4; /* 0 */
2169 entityTypeNames[1] = kSCEntNetIPv6; /* 1 */
2170 entityTypeNames[2] = kSCEntNetDNS; /* 2 */
2171 entityTypeNames[3] = kSCEntNetProxies; /* 3 */
2172 entityTypeNames[4] = kSCEntNetSMB; /* 4 */
2173 return;
2174 }
2175
2176 static void
2177 ip_plugin_init()
2178 {
2179 int i;
2180 CFStringRef key;
2181 CFMutableArrayRef keys = NULL;
2182 CFMutableArrayRef patterns = NULL;
2183 CFRunLoopSourceRef rls = NULL;
2184 SCDynamicStoreRef session = NULL;
2185
2186 initEntityNames();
2187 if (S_netboot_root() != 0) {
2188 S_netboot = TRUE;
2189 }
2190 session = SCDynamicStoreCreate(NULL, CFSTR("IPMonitor"),
2191 IPMonitorNotify, NULL);
2192 if (session == NULL) {
2193 SCLog(TRUE, LOG_ERR,
2194 CFSTR("IPMonitor ip_plugin_init SCDynamicStoreCreate failed: %s"),
2195 SCErrorString(SCError()));
2196 return;
2197 }
2198 S_state_global_ipv4
2199 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2200 kSCDynamicStoreDomainState,
2201 kSCEntNetIPv4);
2202 S_state_global_ipv6
2203 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2204 kSCDynamicStoreDomainState,
2205 kSCEntNetIPv6);
2206 S_state_global_dns
2207 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2208 kSCDynamicStoreDomainState,
2209 kSCEntNetDNS);
2210 S_state_global_proxies
2211 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2212 kSCDynamicStoreDomainState,
2213 kSCEntNetProxies);
2214 S_state_global_smb
2215 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2216 kSCDynamicStoreDomainState,
2217 kSCEntNetSMB);
2218 S_setup_global_ipv4
2219 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2220 kSCDynamicStoreDomainSetup,
2221 kSCEntNetIPv4);
2222 S_setup_global_proxies
2223 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2224 kSCDynamicStoreDomainSetup,
2225 kSCEntNetProxies);
2226 S_setup_global_smb
2227 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2228 kSCDynamicStoreDomainSetup,
2229 kSCEntNetSMB);
2230 S_state_service_prefix
2231 = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@/"),
2232 kSCDynamicStoreDomainState,
2233 kSCCompNetwork,
2234 kSCCompService);
2235 S_setup_service_prefix
2236 = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@/"),
2237 kSCDynamicStoreDomainSetup,
2238 kSCCompNetwork,
2239 kSCCompService);
2240 S_service_state_dict
2241 = CFDictionaryCreateMutable(NULL, 0,
2242 &kCFTypeDictionaryKeyCallBacks,
2243 &kCFTypeDictionaryValueCallBacks);
2244
2245 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2246 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2247
2248 /* register for State: and Setup: per-service notifications */
2249 for (i = 0; i < ENTITY_TYPES_COUNT; i++) {
2250 key = state_service_key(kSCCompAnyRegex, entityTypeNames[i]);
2251 CFArrayAppendValue(patterns, key);
2252 CFRelease(key);
2253 key = setup_service_key(kSCCompAnyRegex, entityTypeNames[i]);
2254 CFArrayAppendValue(patterns, key);
2255 CFRelease(key);
2256 }
2257
2258 /* add notifier for ServiceOrder/PPPOverridePrimary changes for IPv4 */
2259 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
2260 kSCDynamicStoreDomainSetup,
2261 kSCEntNetIPv4);
2262 CFArrayAppendValue(keys, key);
2263 CFRelease(key);
2264
2265 /* add notifier for Private DNS configuration */
2266 S_private_resolvers = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
2267 kSCDynamicStoreDomainState,
2268 kSCCompNetwork,
2269 CFSTR(kDNSServiceCompPrivateDNS));
2270 CFArrayAppendValue(keys, S_private_resolvers);
2271
2272 if (!SCDynamicStoreSetNotificationKeys(session, keys, patterns)) {
2273 SCLog(TRUE, LOG_ERR,
2274 CFSTR("IPMonitor ip_plugin_init "
2275 "SCDynamicStoreSetNotificationKeys failed: %s"),
2276 SCErrorString(SCError()));
2277 goto done;
2278 }
2279
2280 rls = SCDynamicStoreCreateRunLoopSource(NULL, session, 0);
2281 if (rls == NULL) {
2282 SCLog(TRUE, LOG_ERR,
2283 CFSTR("IPMonitor ip_plugin_init "
2284 "SCDynamicStoreCreateRunLoopSource failed: %s"),
2285 SCErrorString(SCError()));
2286 goto done;
2287 }
2288
2289 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
2290 CFRelease(rls);
2291
2292 /* initialize dns configuration */
2293 dns_configuration_set(NULL, NULL, NULL, NULL);
2294 empty_dns();
2295 (void)SCDynamicStoreRemoveValue(session, S_state_global_dns);
2296
2297 /* initialize SMB configuration */
2298 (void)SCDynamicStoreRemoveValue(session, S_state_global_smb);
2299
2300 done:
2301 my_CFRelease(&keys);
2302 my_CFRelease(&patterns);
2303 my_CFRelease(&session);
2304 return;
2305 }
2306
2307 __private_extern__
2308 void
2309 prime_IPMonitor()
2310 {
2311 /* initialize multicast route */
2312 set_ipv4_router(NULL, NULL, NULL, FALSE);
2313 }
2314
2315 __private_extern__
2316 void
2317 load_IPMonitor(CFBundleRef bundle, Boolean bundleVerbose)
2318 {
2319 if (bundleVerbose) {
2320 S_IPMonitor_debug = 1;
2321 }
2322
2323 dns_configuration_init(bundle);
2324 ip_plugin_init();
2325
2326 load_hostname(S_IPMonitor_debug);
2327 load_smb_configuration(S_IPMonitor_debug);
2328
2329 return;
2330 }
2331
2332
2333 #ifdef MAIN
2334 #undef MAIN
2335 #include "dns-configuration.c"
2336 #include "set-hostname.c"
2337
2338 int
2339 main(int argc, char **argv)
2340 {
2341 _sc_log = FALSE;
2342 _sc_verbose = (argc > 1) ? TRUE : FALSE;
2343
2344 load_IPMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
2345 prime_IPMonitor();
2346 CFRunLoopRun();
2347 /* not reached */
2348 exit(0);
2349 return 0;
2350 }
2351 #endif
2352