2 * Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 * - decides which interface will be made the "primary" interface,
27 * that is, the one with the default route assigned
31 * Modification History
33 * July 19, 2000 Dieter Siegmund (dieter@apple.com)
36 * November 15, 2000 Dieter Siegmund (dieter@apple.com)
37 * - changed to use new configuration model
39 * March 19, 2001 Dieter Siegmund (dieter@apple.com)
40 * - use service state instead of interface state
42 * July 16, 2001 Allan Nathanson (ajn@apple.com)
43 * - update to public SystemConfiguration.framework APIs
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
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
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
58 * July 29, 2003 Dieter Siegmund (dieter@apple.com)
59 * - support installing a default route to a router that's not on our subnet
61 * March 22, 2004 Allan Nathanson (ajn@apple.com)
62 * - create expanded DNS configuration
64 * June 20, 2006 Allan Nathanson (ajn@apple.com)
65 * - add SMB configuration
72 #include <sys/fcntl.h>
73 #include <sys/types.h>
74 #include <sys/socket.h>
75 #include <net/route.h>
77 #include <net/if_dl.h>
78 #include <netinet/in.h>
79 #include <arpa/inet.h>
80 #include <sys/sysctl.h>
84 #include <SystemConfiguration/SystemConfiguration.h>
85 #include <SystemConfiguration/SCValidation.h>
86 #include <SystemConfiguration/SCPrivate.h> /* for SCLog() */
90 #ifndef kDNSServiceCompPrivateDNS
91 #define kDNSServiceCompPrivateDNS "PrivateDNS"
94 #include "set-hostname.h"
95 #include "dns-configuration.h"
96 #include "smb-configuration.h"
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]
102 /* debug output on/off */
103 static boolean_t S_IPMonitor_debug
= FALSE
;
105 /* are we netbooted? If so, don't touch the default route */
106 static boolean_t S_netboot
= FALSE
;
108 /* dictionary to hold per-service state: key is the serviceID */
109 static CFMutableDictionaryRef S_service_state_dict
= NULL
;
111 /* if set, a PPP interface overrides the primary */
112 static boolean_t S_ppp_override_primary
= FALSE
;
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
;
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
;
132 static CFStringRef S_private_resolvers
= NULL
;
134 static struct in_addr S_router_subnet
= { 0 };
135 static struct in_addr S_router_subnet_mask
= { 0 };
137 static const struct in_addr S_ip_zeros
= { 0 };
138 static const struct in6_addr S_ip6_zeros
= IN6ADDR_ANY_INIT
;
141 #define kRouterNeedsLocalIP CFSTR("com.apple.IPMonitor.RouterNeedsLocalIP")
142 #define kRouterIsDirect CFSTR("com.apple.IPMonitor.IsDirect")
144 #define VAR_RUN_RESOLV_CONF "/var/run/resolv.conf"
147 #define KERN_NETBOOT 40 /* int: are we netbooted? 1=yes,0=no */
151 ** entityType*, GetEntityChanges*
152 ** - definitions for the entity types we handle
154 #define ENTITY_TYPES_COUNT 5
159 kEntityTypeProxies
= 3,
162 typedef uint32_t EntityType
;
164 static CFStringRef entityTypeNames
[ENTITY_TYPES_COUNT
];
166 typedef boolean_t (GetEntityChangesFunc
)(CFStringRef serviceID
,
167 CFDictionaryRef state_dict
,
168 CFDictionaryRef setup_dict
,
169 CFDictionaryRef info
);
170 typedef GetEntityChangesFunc
* GetEntityChangesFuncRef
;
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
;
179 my_CFRelease(void * t
);
182 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr
, CFTypeRef
new);
185 my_CFArrayRemoveValue(CFMutableArrayRef arr
, CFStringRef key
);
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 */
197 ** - mechanism to do an atomic update of the SCDynamicStore
198 ** when the content needs to be changed across multiple functions
201 CFMutableArrayRef notify
;
202 CFMutableArrayRef remove
;
203 CFMutableDictionaryRef set
;
204 } keyChangeList
, * keyChangeListRef
;
207 keyChangeListInit(keyChangeListRef keys
)
209 keys
->notify
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
210 keys
->remove
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
211 keys
->set
= CFDictionaryCreateMutable(NULL
, 0,
212 &kCFTypeDictionaryKeyCallBacks
,
213 &kCFTypeDictionaryValueCallBacks
);
218 keyChangeListFree(keyChangeListRef keys
)
220 my_CFRelease(&keys
->notify
);
221 my_CFRelease(&keys
->remove
);
222 my_CFRelease(&keys
->set
);
227 keyChangeListNotifyKey(keyChangeListRef keys
, CFStringRef key
)
229 my_CFArrayAppendUniqueValue(keys
->notify
, key
);
234 keyChangeListRemoveValue(keyChangeListRef keys
, CFStringRef key
)
236 my_CFArrayAppendUniqueValue(keys
->remove
, key
);
237 CFDictionaryRemoveValue(keys
->set
, key
);
242 keyChangeListSetValue(keyChangeListRef keys
, CFStringRef key
, CFTypeRef value
)
244 my_CFArrayRemoveValue(keys
->remove
, key
);
245 CFDictionarySetValue(keys
->set
, key
, value
);
250 keyChangeListApplyToStore(keyChangeListRef keys
, SCDynamicStoreRef session
)
252 CFArrayRef notify
= keys
->notify
;
253 CFArrayRef remove
= keys
->remove
;
254 CFDictionaryRef set
= keys
->set
;
257 if (CFArrayGetCount(notify
) == 0) {
260 if (CFArrayGetCount(remove
) == 0) {
263 if (CFDictionaryGetCount(set
) == 0) {
266 if (set
== NULL
&& remove
== NULL
&& notify
== NULL
) {
269 if (S_IPMonitor_debug
) {
271 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: Setting:\n%@\n"), set
);
273 if (remove
!= NULL
) {
274 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: Removing:\n%@\n"), remove
);
276 if (notify
!= NULL
) {
277 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: Notifying:\n%@\n"), notify
);
280 (void)SCDynamicStoreSetMultiple(session
, set
, remove
, notify
);
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."));
286 SCLog(TRUE
, LOG_INFO
,
287 CFSTR("IPMonitor: notify_post() failed: error=%ld"), status
);
301 mib
[1] = KERN_NETBOOT
;
302 len
= sizeof(netboot
);
303 sysctl(mib
, 2, &netboot
, &len
, NULL
, 0);
308 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr
, CFTypeRef
new)
310 CFIndex n
= CFArrayGetCount(arr
);
312 if (CFArrayContainsValue(arr
, CFRangeMake(0, n
), new)) {
315 CFArrayAppendValue(arr
, new);
320 my_CFArrayRemoveValue(CFMutableArrayRef arr
, CFStringRef key
)
324 i
= CFArrayGetFirstIndexOfValue(arr
,
325 CFRangeMake(0, CFArrayGetCount(arr
)),
327 if (i
!= kCFNotFound
) {
328 CFArrayRemoveValueAtIndex(arr
, i
);
334 my_CFRelease(void * t
)
336 void * * obj
= (void * *)t
;
345 static CFDictionaryRef
346 my_CFDictionaryGetDictionary(CFDictionaryRef dict
, CFStringRef key
)
348 if (isA_CFDictionary(dict
) == NULL
) {
351 return (isA_CFDictionary(CFDictionaryGetValue(dict
, key
)));
355 cfstring_to_ipvx(int family
, CFStringRef str
, void * addr
, int addr_size
)
359 if (isA_CFString(str
) == NULL
) {
365 if (addr_size
< sizeof(struct in_addr
)) {
370 if (addr_size
< sizeof(struct in6_addr
)) {
377 (void)_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
);
378 if (inet_pton(family
, buf
, addr
) == 1) {
382 bzero(addr
, addr_size
);
387 cfstring_to_ip(CFStringRef str
, struct in_addr
* ip_p
)
389 return (cfstring_to_ipvx(AF_INET
, str
, ip_p
, sizeof(*ip_p
)));
393 cfstring_to_ip6(CFStringRef str
, struct in6_addr
* ip6_p
)
395 return (cfstring_to_ipvx(AF_INET6
, str
, ip6_p
, sizeof(*ip6_p
)));
399 * Function: parse_component
401 * Given a string 'key' and a string prefix 'prefix',
402 * return the next component in the slash '/' separated
406 * 1. key = "a/b/c" prefix = "a/"
408 * 2. key = "a/b/c" prefix = "a/b/"
412 parse_component(CFStringRef key
, CFStringRef prefix
)
414 CFMutableStringRef comp
;
417 if (CFStringHasPrefix(key
, prefix
) == FALSE
) {
420 comp
= CFStringCreateMutableCopy(NULL
, 0, key
);
424 CFStringDelete(comp
, CFRangeMake(0, CFStringGetLength(prefix
)));
425 range
= CFStringFind(comp
, CFSTR("/"), 0);
426 if (range
.location
== kCFNotFound
) {
429 range
.length
= CFStringGetLength(comp
) - range
.location
;
430 CFStringDelete(comp
, range
);
434 static CFMutableDictionaryRef
435 service_dict_copy(CFStringRef serviceID
)
437 CFDictionaryRef d
= NULL
;
438 CFMutableDictionaryRef service_dict
;
440 /* create a modifyable dictionary, a copy or a new one */
441 d
= CFDictionaryGetValue(S_service_state_dict
, serviceID
);
444 = CFDictionaryCreateMutable(NULL
, 0,
445 &kCFTypeDictionaryKeyCallBacks
,
446 &kCFTypeDictionaryValueCallBacks
);
449 service_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, d
);
451 return (service_dict
);
455 service_dict_set(CFStringRef serviceID
, CFStringRef entity
,
456 CFDictionaryRef new_dict
)
458 boolean_t changed
= FALSE
;
460 CFMutableDictionaryRef service_dict
;
462 service_dict
= service_dict_copy(serviceID
);
463 old
= CFDictionaryGetValue(service_dict
, entity
);
464 if (new_dict
== NULL
) {
466 SCLog(S_IPMonitor_debug
, LOG_INFO
,
467 CFSTR("IPMonitor: serviceID %@ removed %@ dictionary = %@"),
468 serviceID
, entity
, old
);
469 CFDictionaryRemoveValue(service_dict
, entity
);
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>"),
480 CFDictionarySetValue(service_dict
, entity
, new_dict
);
484 if (CFDictionaryGetCount(service_dict
) == 0) {
485 CFDictionaryRemoveValue(S_service_state_dict
, serviceID
);
488 CFDictionarySetValue(S_service_state_dict
, serviceID
, service_dict
);
490 my_CFRelease(&service_dict
);
494 static CFDictionaryRef
495 service_dict_get(CFStringRef serviceID
, CFStringRef entity
)
497 CFDictionaryRef service_dict
;
499 service_dict
= CFDictionaryGetValue(S_service_state_dict
, serviceID
);
500 if (service_dict
== NULL
) {
503 return (CFDictionaryGetValue(service_dict
, entity
));
506 #define ALLOW_EMTPY_STRING 1<<0
509 sanitize_prop(CFTypeRef val
, uint32_t flags
)
512 if (isA_CFString(val
)) {
513 CFMutableStringRef str
;
515 str
= CFStringCreateMutableCopy(NULL
, 0, (CFStringRef
)val
);
516 CFStringTrimWhitespace(str
);
517 if (!(flags
& ALLOW_EMTPY_STRING
) && (CFStringGetLength(str
) == 0)) {
531 merge_array_prop(CFMutableDictionaryRef dict
,
533 CFDictionaryRef state_dict
,
534 CFDictionaryRef setup_dict
,
538 CFMutableArrayRef merge_prop
;
539 CFArrayRef setup_prop
= NULL
;
540 CFArrayRef state_prop
= NULL
;
542 if (setup_dict
!= NULL
) {
543 setup_prop
= isA_CFArray(CFDictionaryGetValue(setup_dict
, key
));
545 if (state_dict
!= NULL
) {
546 state_prop
= isA_CFArray(CFDictionaryGetValue(state_dict
, key
));
549 if ((setup_prop
== NULL
) && (state_prop
== NULL
)) {
553 merge_prop
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
554 if (setup_prop
!= NULL
) {
558 n
= CFArrayGetCount(setup_prop
);
559 for (i
= 0; i
< n
; i
++) {
562 val
= CFArrayGetValueAtIndex(setup_prop
, i
);
563 val
= sanitize_prop(val
, flags
);
565 CFArrayAppendValue(merge_prop
, val
);
570 if (state_prop
!= NULL
) {
573 CFRange setup_range
= CFRangeMake(0, CFArrayGetCount(merge_prop
));
575 n
= CFArrayGetCount(state_prop
);
576 for (i
= 0; i
< n
; i
++) {
579 val
= CFArrayGetValueAtIndex(state_prop
, i
);
580 val
= sanitize_prop(val
, flags
);
582 if (append
|| !CFArrayContainsValue(merge_prop
, setup_range
, val
)) {
583 CFArrayAppendValue(merge_prop
, val
);
589 if (CFArrayGetCount(merge_prop
) > 0) {
590 CFDictionarySetValue(dict
, key
, merge_prop
);
592 CFRelease(merge_prop
);
597 pick_prop(CFMutableDictionaryRef dict
,
599 CFDictionaryRef state_dict
,
600 CFDictionaryRef setup_dict
,
603 CFTypeRef val
= NULL
;
605 if (setup_dict
!= NULL
) {
606 val
= CFDictionaryGetValue(setup_dict
, key
);
607 val
= sanitize_prop(val
, flags
);
609 if (val
== NULL
&& state_dict
!= NULL
) {
610 val
= CFDictionaryGetValue(state_dict
, key
);
611 val
= sanitize_prop(val
, flags
);
614 CFDictionarySetValue(dict
, key
, val
);
622 ** GetEntityChangesFunc functions
624 static __inline__
struct in_addr
625 subnet_addr(struct in_addr addr
, struct in_addr mask
)
629 net
.s_addr
= htonl((uint32_t)ntohl(addr
.s_addr
)
630 & (uint32_t)ntohl(mask
.s_addr
));
635 get_ipv4_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
636 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
638 struct in_addr addr
= { 0 };
640 boolean_t changed
= FALSE
;
641 CFMutableDictionaryRef dict
= NULL
;
642 struct in_addr mask
= { 0 };
644 CFDictionaryRef new_dict
= NULL
;
645 CFStringRef router
= NULL
;
646 boolean_t valid_ip
= FALSE
;
647 boolean_t valid_mask
= FALSE
;
649 if (state_dict
== NULL
) {
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
);
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
);
662 if (valid_ip
== FALSE
) {
663 SCLog(S_IPMonitor_debug
, LOG_INFO
,
664 CFSTR("IPMonitor: %@ has no valid IP address, ignoring"),
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
,
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
;
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
);
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
,
701 changed
= service_dict_set(serviceID
, kSCEntNetIPv4
, new_dict
);
702 my_CFRelease(&new_dict
);
707 get_ipv6_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
708 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
710 struct in6_addr addr
;
712 boolean_t changed
= FALSE
;
713 CFMutableDictionaryRef dict
= NULL
;
714 CFDictionaryRef new_dict
= NULL
;
715 CFStringRef router
= NULL
;
716 boolean_t valid_ip
= FALSE
;
718 if (state_dict
== NULL
) {
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
);
726 if (valid_ip
== FALSE
) {
727 SCLog(S_IPMonitor_debug
, LOG_INFO
,
728 CFSTR("IPMonitor: %@ has no valid IPv6 address, ignoring"),
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
,
744 changed
= service_dict_set(serviceID
, kSCEntNetIPv6
, new_dict
);
745 my_CFRelease(&new_dict
);
750 dns_has_supplemental(CFStringRef serviceID
)
752 CFDictionaryRef dns_dict
;
753 CFDictionaryRef service_dict
;
755 service_dict
= CFDictionaryGetValue(S_service_state_dict
, serviceID
);
756 if (service_dict
== NULL
) {
760 dns_dict
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
761 if (dns_dict
== NULL
) {
765 return CFDictionaryContainsKey(dns_dict
, kSCPropNetDNSSupplementalMatchDomains
);
769 get_dns_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
770 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
772 boolean_t changed
= FALSE
;
780 { kSCPropNetDNSSearchDomains
, 0, FALSE
},
781 { kSCPropNetDNSServerAddresses
, 0, FALSE
},
782 { kSCPropNetDNSSortList
, 0, FALSE
},
783 { kSCPropNetDNSSupplementalMatchDomains
, ALLOW_EMTPY_STRING
, TRUE
},
784 { kSCPropNetDNSSupplementalMatchOrders
, 0, TRUE
},
786 CFMutableDictionaryRef new_dict
= NULL
;
787 CFStringRef pick_list
[] = {
788 kSCPropNetDNSDomainName
,
789 kSCPropNetDNSOptions
,
790 kSCPropNetDNSSearchOrder
,
791 kSCPropNetDNSServerPort
,
792 kSCPropNetDNSServerTimeout
,
795 if ((state_dict
== NULL
) && (setup_dict
== NULL
)) {
796 /* there is no DNS */
800 if ((service_dict_get(serviceID
, kSCEntNetIPv4
) == NULL
) &&
801 (service_dict_get(serviceID
, kSCEntNetIPv6
) == NULL
)) {
802 /* there is no IPv4 nor IPv6 */
806 // merge DNS configuration
807 new_dict
= CFDictionaryCreateMutable(NULL
, 0,
808 &kCFTypeDictionaryKeyCallBacks
,
809 &kCFTypeDictionaryValueCallBacks
);
811 for (i
= 0; i
< sizeof(merge_list
)/sizeof(merge_list
[0]); i
++) {
812 merge_array_prop(new_dict
,
817 merge_list
[i
].append
);
819 for (i
= 0; i
< sizeof(pick_list
)/sizeof(pick_list
[0]); i
++) {
827 if (CFDictionaryGetCount(new_dict
) == 0) {
828 my_CFRelease(&new_dict
);
833 * ensure any specified domain name (e.g. the domain returned by
834 * a DHCP server) is in the search list.
836 domain
= CFDictionaryGetValue(new_dict
, kSCPropNetDNSDomainName
);
837 if (isA_CFString(domain
)) {
840 search
= CFDictionaryGetValue(new_dict
, kSCPropNetDNSSearchDomains
);
841 if (isA_CFArray(search
) &&
842 !CFArrayContainsValue(search
, CFRangeMake(0, CFArrayGetCount(search
)), domain
)) {
843 CFMutableArrayRef new_search
;
845 new_search
= CFArrayCreateMutableCopy(NULL
, 0, search
);
846 CFArrayAppendValue(new_search
, domain
);
847 CFDictionarySetValue(new_dict
, kSCPropNetDNSSearchDomains
, new_search
);
848 my_CFRelease(&new_search
);
853 changed
= service_dict_set(serviceID
, kSCEntNetDNS
, new_dict
);
854 my_CFRelease(&new_dict
);
859 get_proxies_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
860 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
862 boolean_t changed
= FALSE
;
863 CFDictionaryRef new_dict
= NULL
;
865 if ((service_dict_get(serviceID
, kSCEntNetIPv4
) == NULL
) &&
866 (service_dict_get(serviceID
, kSCEntNetIPv6
) == NULL
)) {
867 /* there is no IPv4 nor IPv6 */
870 if (setup_dict
!= NULL
) {
871 new_dict
= setup_dict
;
874 new_dict
= state_dict
;
877 changed
= service_dict_set(serviceID
, kSCEntNetProxies
, new_dict
);
882 get_smb_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
883 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
885 boolean_t changed
= FALSE
;
887 CFMutableDictionaryRef new_dict
= NULL
;
888 CFStringRef pick_list
[] = {
889 kSCPropNetSMBNetBIOSName
,
890 kSCPropNetSMBNetBIOSNodeType
,
891 kSCPropNetSMBNetBIOSScope
,
892 kSCPropNetSMBWorkgroup
,
895 if (service_dict_get(serviceID
, kSCEntNetIPv4
) == NULL
) {
896 /* there is no IPv4 */
900 if (state_dict
== NULL
&& setup_dict
== NULL
) {
901 /* there is no SMB */
905 // merge SMB configuration
906 new_dict
= CFDictionaryCreateMutable(NULL
, 0,
907 &kCFTypeDictionaryKeyCallBacks
,
908 &kCFTypeDictionaryValueCallBacks
);
910 merge_array_prop(new_dict
,
911 kSCPropNetSMBWINSAddresses
,
916 for (i
= 0; i
< sizeof(pick_list
)/sizeof(pick_list
[0]); i
++) {
924 if (CFDictionaryGetCount(new_dict
) == 0) {
925 my_CFRelease(&new_dict
);
930 changed
= service_dict_set(serviceID
, kSCEntNetSMB
, new_dict
);
931 my_CFRelease(&new_dict
);
936 state_service_key(CFStringRef serviceID
, CFStringRef entity
)
938 return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
939 kSCDynamicStoreDomainState
,
945 setup_service_key(CFStringRef serviceID
, CFStringRef entity
)
947 return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
948 kSCDynamicStoreDomainSetup
,
953 static CFDictionaryRef
954 services_info_copy(SCDynamicStoreRef session
, CFArrayRef service_list
)
957 CFMutableArrayRef get_keys
;
960 CFDictionaryRef info
;
962 count
= CFArrayGetCount(service_list
);
963 get_keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
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
);
970 for (s
= 0; s
< count
; s
++) {
971 CFStringRef serviceID
= CFArrayGetValueAtIndex(service_list
, s
);
973 for (i
= 0; i
< ENTITY_TYPES_COUNT
; i
++) {
974 CFStringRef setup_key
;
975 CFStringRef state_key
;
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
);
986 info
= SCDynamicStoreCopyMultiple(session
, get_keys
, NULL
);
987 my_CFRelease(&get_keys
);
991 static CFDictionaryRef
992 get_service_setup_entity(CFDictionaryRef service_info
, CFStringRef serviceID
,
995 CFStringRef setup_key
;
996 CFDictionaryRef setup_dict
;
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
);
1004 static CFDictionaryRef
1005 get_service_state_entity(CFDictionaryRef service_info
, CFStringRef serviceID
,
1008 CFStringRef state_key
;
1009 CFDictionaryRef state_dict
;
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
);
1017 static int rtm_seq
= 0;
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
)
1024 boolean_t default_route
= (netaddr
.s_addr
== 0);
1026 boolean_t ret
= TRUE
;
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
;
1037 if (default_route
&& S_netboot
) {
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"),
1048 memset(&rtmsg
, 0, sizeof(rtmsg
));
1049 rtmsg
.hdr
.rtm_type
= cmd
;
1050 if (default_route
) {
1052 /* if router is directly reachable, don't set the gateway flag */
1053 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_STATIC
;
1056 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_STATIC
;
1060 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_CLONING
| RTF_STATIC
;
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
;
1075 len
= sizeof(rtmsg
);
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
;
1089 /* no ifp/ifa information */
1090 len
-= sizeof(rtmsg
.ifp
) + sizeof(rtmsg
.ifa
);
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 */
1097 else if ((cmd
== RTM_DELETE
) && (errno
== ESRCH
)) {
1098 /* no sense complaining about a route that isn't there */
1101 SCLog(S_IPMonitor_debug
, LOG_INFO
,
1102 CFSTR("IPMonitor ipv4_route: "
1103 "write routing socket failed, %s"), strerror(errno
));
1113 ipv6_route(int cmd
, struct in6_addr gateway
, struct in6_addr netaddr
,
1114 struct in6_addr netmask
, char * ifname
, boolean_t is_direct
)
1116 boolean_t default_route
;
1118 boolean_t ret
= TRUE
;
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
;
1127 struct in6_addr zeroes
= IN6ADDR_ANY_INIT
;
1129 default_route
= (bcmp(&zeroes
, &netaddr
, sizeof(netaddr
)) == 0);
1131 if (IN6_IS_ADDR_LINKLOCAL(&gateway
) && ifname
!= NULL
) {
1132 unsigned int index
= if_nametoindex(ifname
);
1134 /* add the scope id to the link local address */
1135 gateway
.__u6_addr
.__u6_addr16
[1] = (uint16_t)htons(index
);
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"),
1143 memset(&rtmsg
, 0, sizeof(rtmsg
));
1144 rtmsg
.hdr
.rtm_type
= cmd
;
1145 if (default_route
) {
1147 /* if router is directly reachable, don't set the gateway flag */
1148 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_STATIC
;
1151 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_STATIC
;
1155 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_CLONING
| RTF_STATIC
;
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
;
1170 len
= sizeof(rtmsg
);
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
);
1179 /* no ifp information */
1180 len
-= sizeof(rtmsg
.ifp
);
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 */
1187 else if ((cmd
== RTM_DELETE
) && (errno
== ESRCH
)) {
1188 /* no sense complaining about a route that isn't there */
1191 SCLog(S_IPMonitor_debug
, LOG_INFO
,
1192 CFSTR("IPMonitor ipv6_route: write routing"
1193 " socket failed, %s"), strerror(errno
));
1203 ipv4_subnet_route_add(struct in_addr local_ip
,
1204 struct in_addr subnet
, struct in_addr mask
, char * ifname
)
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
);
1212 return (ipv4_route(RTM_ADD
, local_ip
, subnet
, mask
, ifname
, local_ip
,
1217 ipv4_subnet_route_delete(struct in_addr subnet
, struct in_addr mask
)
1219 if (S_IPMonitor_debug
) {
1220 SCLog(TRUE
, LOG_INFO
,
1221 CFSTR("IPMonitor: IPv4 route delete -net "
1223 IP_LIST(&subnet
), inet_ntoa(mask
));
1225 return (ipv4_route(RTM_DELETE
, S_ip_zeros
, subnet
, mask
, NULL
,
1226 S_ip_zeros
, FALSE
));
1231 ipv4_default_route_delete(void)
1233 if (S_IPMonitor_debug
) {
1234 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: IPv4 route delete default"));
1236 return (ipv4_route(RTM_DELETE
, S_ip_zeros
, S_ip_zeros
, S_ip_zeros
, NULL
,
1237 S_ip_zeros
, FALSE
));
1241 ipv4_default_route_add(struct in_addr router
, char * ifname
,
1242 struct in_addr local_ip
, boolean_t is_direct
)
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
);
1250 return (ipv4_route(RTM_ADD
, router
, S_ip_zeros
, S_ip_zeros
, ifname
,
1251 local_ip
, is_direct
));
1255 ipv4_default_route_change(struct in_addr router
, char * ifname
,
1256 struct in_addr local_ip
, boolean_t is_direct
)
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
);
1264 return (ipv4_route(RTM_CHANGE
, router
, S_ip_zeros
, S_ip_zeros
, ifname
,
1265 local_ip
, is_direct
));
1269 ipv6_default_route_delete(void)
1271 if (S_IPMonitor_debug
) {
1272 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: IPv6 route delete default"));
1274 return (ipv6_route(RTM_DELETE
, S_ip6_zeros
, S_ip6_zeros
, S_ip6_zeros
, NULL
, FALSE
));
1278 ipv6_default_route_add(struct in6_addr router
, char * ifname
,
1279 boolean_t is_direct
)
1281 if (S_IPMonitor_debug
) {
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
);
1292 return (ipv6_route(RTM_ADD
, router
, S_ip6_zeros
, S_ip6_zeros
, ifname
, is_direct
));
1297 multicast_route_delete()
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
) };
1303 return (ipv4_route(RTM_DELETE
, gateway
, netaddr
, netmask
, "lo0",
1308 multicast_route_add()
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
) };
1314 return (ipv4_route(RTM_ADD
, gateway
, netaddr
, netmask
, "lo0",
1319 set_ipv4_router(struct in_addr
* router
, char * ifname
,
1320 struct in_addr
* local_ip
, boolean_t is_direct
)
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;
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
,
1331 ? *local_ip
: S_ip_zeros
,
1333 (void)multicast_route_delete();
1336 (void)multicast_route_add();
1343 set_ipv6_router(struct in6_addr
* router
, char * ifname
, boolean_t is_direct
)
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
);
1353 static __inline__
void
1356 (void)unlink(VAR_RUN_RESOLV_CONF
);
1360 set_dns(CFArrayRef val_search_domains
,
1361 CFStringRef val_domain_name
,
1362 CFArrayRef val_servers
,
1363 CFArrayRef val_sortlist
)
1365 FILE * f
= fopen(VAR_RUN_RESOLV_CONF
"-", "w");
1367 /* publish new resolv.conf */
1372 if (isA_CFString(val_domain_name
)) {
1373 SCPrint(TRUE
, f
, CFSTR("domain %@\n"), val_domain_name
);
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
++) {
1382 domain
= CFArrayGetValueAtIndex(val_search_domains
, i
);
1383 if (isA_CFString(domain
)) {
1384 SCPrint(TRUE
, f
, CFSTR(" %@"), domain
);
1387 SCPrint(TRUE
, f
, CFSTR("\n"));
1390 if (isA_CFArray(val_servers
)) {
1391 n
= CFArrayGetCount(val_servers
);
1392 for (i
= 0; i
< n
; i
++) {
1393 CFStringRef nameserver
;
1395 nameserver
= CFArrayGetValueAtIndex(val_servers
, i
);
1396 if (isA_CFString(nameserver
)) {
1397 SCPrint(TRUE
, f
, CFSTR("nameserver %@\n"), nameserver
);
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
;
1408 address
= CFArrayGetValueAtIndex(val_sortlist
, i
);
1409 if (isA_CFString(address
)) {
1410 SCPrint(TRUE
, f
, CFSTR(" %@"), address
);
1413 SCPrint(TRUE
, f
, CFSTR("\n"));
1417 rename(VAR_RUN_RESOLV_CONF
"-", VAR_RUN_RESOLV_CONF
);
1423 router_is_our_ipv6_address(CFStringRef router
, CFArrayRef addr_list
)
1426 CFIndex n
= CFArrayGetCount(addr_list
);
1429 (void)cfstring_to_ip6(router
, &r
);
1430 for (i
= 0; i
< n
; i
++) {
1433 if (cfstring_to_ip6(CFArrayGetValueAtIndex(addr_list
, i
), &ip
)
1434 && bcmp(&r
, &ip
, sizeof(r
)) == 0) {
1442 update_ipv4(CFDictionaryRef service_info
,
1443 CFStringRef primary
,
1444 keyChangeListRef keys
)
1446 CFDictionaryRef ipv4_dict
= NULL
;
1448 if (primary
!= NULL
) {
1449 CFDictionaryRef service_dict
;
1451 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1452 if (service_dict
!= NULL
) {
1453 ipv4_dict
= CFDictionaryGetValue(service_dict
, kSCEntNetIPv4
);
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
;
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
)) {
1483 else if (CFDictionaryContainsKey(ipv4_dict
, kRouterNeedsLocalIP
)) {
1484 needs_local_ip
= TRUE
;
1491 if_name
= CFDictionaryGetValue(ipv4_dict
, kSCPropInterfaceName
);
1493 CFDictionarySetValue(dict
,
1494 kSCDynamicStorePropNetPrimaryInterface
,
1496 if (CFStringGetCString(if_name
, ifn
, sizeof(ifn
),
1497 kCFStringEncodingASCII
)) {
1501 CFDictionarySetValue(dict
, kSCDynamicStorePropNetPrimaryService
,
1503 keyChangeListSetValue(keys
, S_state_global_ipv4
, dict
);
1506 /* route add default ... */
1507 if (needs_local_ip
) {
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
;
1518 set_ipv4_router(&router
, ifn_p
, &local_ip
, is_direct
);
1522 keyChangeListRemoveValue(keys
, S_state_global_ipv4
);
1523 set_ipv4_router(NULL
, NULL
, NULL
, FALSE
);
1529 update_ipv6(CFDictionaryRef service_info
,
1530 CFStringRef primary
,
1531 keyChangeListRef keys
)
1533 CFDictionaryRef ipv6_dict
= NULL
;
1535 if (primary
!= NULL
) {
1536 CFDictionaryRef service_dict
;
1538 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1539 if (service_dict
!= NULL
) {
1540 ipv6_dict
= CFDictionaryGetValue(service_dict
, kSCEntNetIPv6
);
1543 if (ipv6_dict
!= NULL
) {
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
;
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
,
1565 val_router
= CFArrayGetValueAtIndex(addrs
, 0);
1568 if_name
= CFDictionaryGetValue(ipv6_dict
, kSCPropInterfaceName
);
1570 CFDictionarySetValue(dict
,
1571 kSCDynamicStorePropNetPrimaryInterface
,
1573 if (CFStringGetCString(if_name
, ifn
, sizeof(ifn
),
1574 kCFStringEncodingASCII
)) {
1578 CFDictionarySetValue(dict
, kSCDynamicStorePropNetPrimaryService
,
1580 keyChangeListSetValue(keys
, S_state_global_ipv6
, dict
);
1583 { /* route add default ... */
1584 struct in6_addr router
;
1586 (void)cfstring_to_ip6(val_router
, &router
);
1587 set_ipv6_router(&router
, ifn_p
, is_direct
);
1591 keyChangeListRemoveValue(keys
, S_state_global_ipv6
);
1592 set_ipv6_router(NULL
, NULL
, FALSE
);
1598 update_dns(CFDictionaryRef service_info
,
1599 CFStringRef primary
,
1600 keyChangeListRef keys
)
1602 CFDictionaryRef dict
= NULL
;
1604 if (primary
!= NULL
) {
1605 CFDictionaryRef service_dict
;
1607 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1608 if (service_dict
!= NULL
) {
1609 dict
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1614 keyChangeListRemoveValue(keys
, S_state_global_dns
);
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
);
1627 update_dnsinfo(CFDictionaryRef service_info
,
1628 CFStringRef primary
,
1629 keyChangeListRef keys
,
1630 CFArrayRef service_order
)
1632 CFArrayRef privateResolvers
;
1634 privateResolvers
= CFDictionaryGetValue(service_info
, S_private_resolvers
);
1636 if (primary
== NULL
) {
1637 dns_configuration_set(NULL
, NULL
, NULL
, privateResolvers
);
1639 CFDictionaryRef dict
= NULL
;
1640 CFDictionaryRef service_dict
;
1642 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1643 if (service_dict
!= NULL
) {
1644 dict
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1647 dns_configuration_set(dict
, S_service_state_dict
, service_order
, privateResolvers
);
1649 keyChangeListNotifyKey(keys
, S_state_global_dns
);
1654 update_proxies(CFDictionaryRef service_info
,
1655 CFStringRef primary
,
1656 keyChangeListRef keys
)
1658 CFDictionaryRef dict
= NULL
;
1660 if (primary
!= NULL
) {
1661 CFDictionaryRef service_dict
;
1663 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1664 if (service_dict
!= NULL
) {
1665 dict
= CFDictionaryGetValue(service_dict
, kSCEntNetProxies
);
1667 dict
= my_CFDictionaryGetDictionary(service_info
,
1668 S_setup_global_proxies
);
1673 keyChangeListRemoveValue(keys
, S_state_global_proxies
);
1676 keyChangeListSetValue(keys
, S_state_global_proxies
, dict
);
1682 update_smb(CFDictionaryRef service_info
,
1683 CFStringRef primary
,
1684 keyChangeListRef keys
)
1686 CFDictionaryRef dict
= NULL
;
1688 if (primary
!= NULL
) {
1689 CFDictionaryRef service_dict
;
1691 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1692 if (service_dict
!= NULL
) {
1693 dict
= CFDictionaryGetValue(service_dict
, kSCEntNetSMB
);
1695 dict
= my_CFDictionaryGetDictionary(service_info
,
1696 S_setup_global_smb
);
1701 keyChangeListRemoveValue(keys
, S_state_global_smb
);
1704 keyChangeListSetValue(keys
, S_state_global_smb
, dict
);
1711 get_service_rank(CFStringRef proto_key
, CFArrayRef order
, CFStringRef serviceID
)
1715 CFDictionaryRef proto_dict
;
1717 if (serviceID
== NULL
) {
1720 d
= CFDictionaryGetValue(S_service_state_dict
, serviceID
);
1725 proto_dict
= CFDictionaryGetValue(d
, proto_key
);
1727 CFStringRef if_name
;
1728 CFNumberRef override
= NULL
;
1730 if_name
= CFDictionaryGetValue(proto_dict
, kSCPropInterfaceName
);
1731 if (S_ppp_override_primary
== TRUE
1733 && CFStringHasPrefix(if_name
, CFSTR("ppp"))) {
1734 /* PPP override: make ppp* look the best */
1735 /* Hack: should use interface type, not interface name */
1738 /* check for the "OverridePrimary" property */
1739 override
= CFDictionaryGetValue(proto_dict
, kSCPropNetOverridePrimary
);
1740 if (isA_CFNumber(override
) != NULL
) {
1743 CFNumberGetValue(override
, kCFNumberIntType
, &val
);
1750 if (serviceID
!= NULL
&& order
!= NULL
) {
1751 CFIndex n
= CFArrayGetCount(order
);
1753 for (i
= 0; i
< n
; i
++) {
1754 CFStringRef s
= isA_CFString(CFArrayGetValueAtIndex(order
, i
));
1759 if (CFEqual(serviceID
, s
)) {
1770 ** Service election:
1772 typedef boolean_t (*routerCheckFunc
)(CFStringRef str
);
1775 check_ipv4_router(CFStringRef router
)
1779 return (cfstring_to_ip(router
, &ip
));
1783 check_ipv6_router(CFStringRef router
)
1785 struct in6_addr ip6
;
1787 return (cfstring_to_ip6(router
, &ip6
));
1790 struct election_state
{
1791 routerCheckFunc router_check
;
1792 CFStringRef proto_key
; /* e.g. kSCEntNetIPv4 */
1793 CFStringRef router_key
;/* e.g. kSCPropNetIPv4Router */
1795 CFStringRef new_primary
;
1796 boolean_t new_has_router
;
1797 unsigned int new_primary_index
;
1801 elect_protocol(const void * key
, const void * value
, void * context
)
1803 struct election_state
* elect_p
= (struct election_state
*)context
;
1804 CFDictionaryRef proto_dict
= NULL
;
1806 boolean_t router_valid
= FALSE
;
1807 CFStringRef serviceID
= (CFStringRef
)key
;
1808 CFDictionaryRef service_dict
= (CFDictionaryRef
)value
;
1809 unsigned int service_index
;
1811 proto_dict
= CFDictionaryGetValue(service_dict
, elect_p
->proto_key
);
1812 if (proto_dict
== NULL
) {
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
) {
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
;
1835 elect_new_primary(CFArrayRef order
, CFStringRef proto_key
,
1836 CFStringRef router_key
)
1838 struct election_state elect
;
1840 if (CFEqual(proto_key
, kSCEntNetIPv4
)) {
1841 elect
.router_check
= check_ipv4_router
;
1843 else if (CFEqual(proto_key
, kSCEntNetIPv6
)) {
1844 elect
.router_check
= check_ipv6_router
;
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
);
1860 service_changed(CFDictionaryRef services_info
, CFStringRef serviceID
)
1862 uint32_t changed
= 0;
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
]),
1873 changed
|= (1 << i
);
1880 service_order_get(CFDictionaryRef services_info
)
1882 CFArrayRef order
= NULL
;
1883 CFDictionaryRef ipv4_dict
;
1885 ipv4_dict
= my_CFDictionaryGetDictionary(services_info
,
1886 S_setup_global_ipv4
);
1887 if (ipv4_dict
!= NULL
) {
1888 CFNumberRef ppp_override
;
1891 order
= CFDictionaryGetValue(ipv4_dict
, kSCPropNetServiceOrder
);
1892 order
= isA_CFArray(order
);
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
);
1901 S_ppp_override_primary
= (ppp_val
!= 0) ? TRUE
: FALSE
;
1904 S_ppp_override_primary
= FALSE
;
1910 set_new_primary(CFStringRef
* primary_p
, CFStringRef new_primary
,
1911 const char * entity
)
1913 boolean_t changed
= FALSE
;
1914 CFStringRef primary
= *primary_p
;
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
);
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
);
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
);
1941 rank_service_entity(CFArrayRef order
, CFStringRef primary
,
1942 CFStringRef proto_key
, CFStringRef entity
)
1944 CFDictionaryRef dict
;
1945 dict
= service_dict_get(primary
, entity
);
1949 return (get_service_rank(proto_key
, order
, primary
));
1953 IPMonitorNotify(SCDynamicStoreRef session
, CFArrayRef changed_keys
,
1957 boolean_t dnsinfo_changed
= FALSE
;
1958 boolean_t global_ipv4_changed
= FALSE
;
1959 boolean_t global_ipv6_changed
= FALSE
;
1963 CFArrayRef service_order
;
1964 CFMutableArrayRef service_changes
= NULL
;
1965 CFDictionaryRef services_info
= NULL
;
1967 count
= CFArrayGetCount(changed_keys
);
1972 SCLog(S_IPMonitor_debug
, LOG_INFO
,
1973 CFSTR("IPMonitor: changes %@ (%d)"), changed_keys
, count
);
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
;
1984 else if (CFEqual(change
, S_setup_global_proxies
)) {
1985 if (S_primary_proxies
!= NULL
) {
1986 my_CFArrayAppendUniqueValue(service_changes
, S_primary_proxies
);
1989 else if (CFEqual(change
, S_setup_global_smb
)) {
1990 if (S_primary_smb
!= NULL
) {
1991 my_CFArrayAppendUniqueValue(service_changes
, S_primary_smb
);
1994 else if (CFEqual(change
, S_private_resolvers
)) {
1995 dnsinfo_changed
= TRUE
;
1997 else if (CFStringHasPrefix(change
, S_state_service_prefix
)) {
1998 CFStringRef serviceID
= parse_component(change
,
1999 S_state_service_prefix
);
2001 my_CFArrayAppendUniqueValue(service_changes
, serviceID
);
2002 CFRelease(serviceID
);
2005 else if (CFStringHasPrefix(change
, S_setup_service_prefix
)) {
2006 CFStringRef serviceID
= parse_component(change
,
2007 S_setup_service_prefix
);
2009 my_CFArrayAppendUniqueValue(service_changes
, serviceID
);
2010 CFRelease(serviceID
);
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
);
2022 n
= CFArrayGetCount(service_changes
);
2023 for (i
= 0; i
< n
; i
++) {
2025 CFStringRef serviceID
;
2026 Boolean wasSupplemental
;
2028 serviceID
= CFArrayGetValueAtIndex(service_changes
, i
);
2029 wasSupplemental
= dns_has_supplemental(serviceID
);
2030 changes
= service_changed(services_info
, serviceID
);
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
;
2038 else if ((changes
& (1 << kEntityTypeIPv4
)) != 0) {
2039 global_ipv4_changed
= TRUE
;
2041 if ((changes
& (1 << kEntityTypeIPv6
)) != 0) {
2042 if (S_primary_ipv6
!= NULL
&& CFEqual(S_primary_ipv6
, serviceID
)) {
2043 update_ipv6(services_info
, serviceID
, &keys
);
2045 global_ipv6_changed
= TRUE
;
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
;
2052 else if (wasSupplemental
|| dns_has_supplemental(serviceID
)) {
2053 dnsinfo_changed
= TRUE
;
2056 if ((changes
& (1 << kEntityTypeProxies
)) != 0) {
2057 if (S_primary_proxies
!= NULL
&& CFEqual(S_primary_proxies
, serviceID
)) {
2058 update_proxies(services_info
, serviceID
, &keys
);
2061 if ((changes
& (1 << kEntityTypeSMB
)) != 0) {
2062 if (S_primary_smb
!= NULL
&& CFEqual(S_primary_smb
, serviceID
)) {
2063 update_smb(services_info
, serviceID
, &keys
);
2068 if (global_ipv4_changed
) {
2069 CFStringRef new_primary
;
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
);
2078 my_CFRelease(&new_primary
);
2080 if (global_ipv6_changed
) {
2081 CFStringRef new_primary
;
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
);
2090 my_CFRelease(&new_primary
);
2092 if (global_ipv4_changed
|| global_ipv6_changed
) {
2093 CFStringRef new_primary_dns
;
2094 CFStringRef new_primary_proxies
;
2095 CFStringRef new_primary_smb
;
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
;
2106 new_primary_dns
= S_primary_ipv6
;
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
;
2115 new_primary_proxies
= S_primary_ipv6
;
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
;
2124 new_primary_smb
= S_primary_ipv6
;
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
;
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
;
2139 new_primary_dns
= NULL
;
2140 new_primary_proxies
= NULL
;
2141 new_primary_smb
= NULL
;
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
;
2148 if (set_new_primary(&S_primary_proxies
, new_primary_proxies
, "Proxies")) {
2149 update_proxies(services_info
, S_primary_proxies
, &keys
);
2151 if (set_new_primary(&S_primary_smb
, new_primary_smb
, "SMB")) {
2152 update_smb(services_info
, S_primary_smb
, &keys
);
2155 if (dnsinfo_changed
) {
2156 update_dnsinfo(services_info
, S_primary_dns
, &keys
, service_order
);
2158 my_CFRelease(&service_changes
);
2159 my_CFRelease(&services_info
);
2160 keyChangeListApplyToStore(&keys
, session
);
2161 keyChangeListFree(&keys
);
2166 initEntityNames(void)
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 */
2181 CFMutableArrayRef keys
= NULL
;
2182 CFMutableArrayRef patterns
= NULL
;
2183 CFRunLoopSourceRef rls
= NULL
;
2184 SCDynamicStoreRef session
= NULL
;
2187 if (S_netboot_root() != 0) {
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()));
2199 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2200 kSCDynamicStoreDomainState
,
2203 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2204 kSCDynamicStoreDomainState
,
2207 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2208 kSCDynamicStoreDomainState
,
2210 S_state_global_proxies
2211 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2212 kSCDynamicStoreDomainState
,
2215 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2216 kSCDynamicStoreDomainState
,
2219 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2220 kSCDynamicStoreDomainSetup
,
2222 S_setup_global_proxies
2223 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2224 kSCDynamicStoreDomainSetup
,
2227 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2228 kSCDynamicStoreDomainSetup
,
2230 S_state_service_prefix
2231 = SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@/"),
2232 kSCDynamicStoreDomainState
,
2235 S_setup_service_prefix
2236 = SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@/"),
2237 kSCDynamicStoreDomainSetup
,
2240 S_service_state_dict
2241 = CFDictionaryCreateMutable(NULL
, 0,
2242 &kCFTypeDictionaryKeyCallBacks
,
2243 &kCFTypeDictionaryValueCallBacks
);
2245 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2246 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
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
);
2253 key
= setup_service_key(kSCCompAnyRegex
, entityTypeNames
[i
]);
2254 CFArrayAppendValue(patterns
, key
);
2258 /* add notifier for ServiceOrder/PPPOverridePrimary changes for IPv4 */
2259 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2260 kSCDynamicStoreDomainSetup
,
2262 CFArrayAppendValue(keys
, key
);
2265 /* add notifier for Private DNS configuration */
2266 S_private_resolvers
= SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@"),
2267 kSCDynamicStoreDomainState
,
2269 CFSTR(kDNSServiceCompPrivateDNS
));
2270 CFArrayAppendValue(keys
, S_private_resolvers
);
2272 if (!SCDynamicStoreSetNotificationKeys(session
, keys
, patterns
)) {
2273 SCLog(TRUE
, LOG_ERR
,
2274 CFSTR("IPMonitor ip_plugin_init "
2275 "SCDynamicStoreSetNotificationKeys failed: %s"),
2276 SCErrorString(SCError()));
2280 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, session
, 0);
2282 SCLog(TRUE
, LOG_ERR
,
2283 CFSTR("IPMonitor ip_plugin_init "
2284 "SCDynamicStoreCreateRunLoopSource failed: %s"),
2285 SCErrorString(SCError()));
2289 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
2292 /* initialize dns configuration */
2293 dns_configuration_set(NULL
, NULL
, NULL
, NULL
);
2295 (void)SCDynamicStoreRemoveValue(session
, S_state_global_dns
);
2297 /* initialize SMB configuration */
2298 (void)SCDynamicStoreRemoveValue(session
, S_state_global_smb
);
2301 my_CFRelease(&keys
);
2302 my_CFRelease(&patterns
);
2303 my_CFRelease(&session
);
2311 /* initialize multicast route */
2312 set_ipv4_router(NULL
, NULL
, NULL
, FALSE
);
2317 load_IPMonitor(CFBundleRef bundle
, Boolean bundleVerbose
)
2319 if (bundleVerbose
) {
2320 S_IPMonitor_debug
= 1;
2323 dns_configuration_init(bundle
);
2326 load_hostname(S_IPMonitor_debug
);
2327 load_smb_configuration(S_IPMonitor_debug
);
2335 #include "dns-configuration.c"
2336 #include "set-hostname.c"
2339 main(int argc
, char **argv
)
2342 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2344 load_IPMonitor(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);