2 * Copyright (c) 2000-2004 Apple Computer, 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
69 #include <sys/fcntl.h>
70 #include <sys/types.h>
71 #include <sys/socket.h>
72 #include <net/route.h>
74 #include <net/if_dl.h>
75 #include <netinet/in.h>
76 #include <arpa/inet.h>
77 #include <sys/sysctl.h>
80 #include <SystemConfiguration/SystemConfiguration.h>
81 #include <SystemConfiguration/SCValidation.h>
82 #include <SystemConfiguration/SCPrivate.h> /* for SCLog() */
86 void load_hostname(Boolean verbose
);
87 void dns_configuration_init(CFBundleRef bundle
);
88 void dns_configuration_set(CFDictionaryRef defaultResolver
,
89 CFDictionaryRef services
,
90 CFArrayRef serviceOrder
);
92 #define IP_FORMAT "%d.%d.%d.%d"
93 #define IP_CH(ip) ((u_char *)(ip))
94 #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
96 /* debug output on/off */
97 static boolean_t S_IPMonitor_debug
= FALSE
;
99 /* are we netbooted? If so, don't touch the default route */
100 static boolean_t S_netboot
= FALSE
;
102 /* notification key indicating dns configuration has been changed */
103 static CFStringRef S_notify_dnsinfo
= NULL
;
105 /* dictionary to hold per-service state: key is the serviceID */
106 static CFMutableDictionaryRef S_service_state_dict
= NULL
;
108 /* if set, a PPP interface overrides the primary */
109 static boolean_t S_ppp_override_primary
= TRUE
;
111 /* the current primary serviceID's */
112 static CFStringRef S_primary_ipv4
= NULL
;
113 static CFStringRef S_primary_ipv6
= NULL
;
114 static CFStringRef S_primary_dns
= NULL
;
115 static CFStringRef S_primary_proxies
= NULL
;
117 static CFStringRef S_state_global_ipv4
= NULL
;
118 static CFStringRef S_state_global_ipv6
= NULL
;
119 static CFStringRef S_state_global_dns
= NULL
;
120 static CFStringRef S_state_global_netinfo
= NULL
;
121 static CFStringRef S_state_global_proxies
= NULL
;
122 static CFStringRef S_state_service_prefix
= NULL
;
123 static CFStringRef S_setup_global_ipv4
= NULL
;
124 static CFStringRef S_setup_global_netinfo
= NULL
;
125 static CFStringRef S_setup_global_proxies
= NULL
;
126 static CFStringRef S_setup_service_prefix
= NULL
;
128 static struct in_addr S_router_subnet
= { 0 };
129 static struct in_addr S_router_subnet_mask
= { 0 };
131 static const struct in_addr S_ip_zeros
= { 0 };
132 static const struct in6_addr S_ip6_zeros
= IN6ADDR_ANY_INIT
;
135 #define kRouterNeedsLocalIP CFSTR("com.apple.IPMonitor.RouterNeedsLocalIP")
136 #define kRouterIsDirect CFSTR("com.apple.IPMonitor.IsDirect")
138 #define VAR_RUN_RESOLV_CONF "/var/run/resolv.conf"
139 #define VAR_RUN_NICONFIG_LOCAL_XML "/var/run/niconfig_local.xml"
142 #define KERN_NETBOOT 40 /* int: are we netbooted? 1=yes,0=no */
146 ** entityType*, GetEntityChanges*
147 ** - definitions for the entity types we handle
149 #define ENTITY_TYPES_COUNT 5
154 kEntityTypeNetInfo
= 3,
155 kEntityTypeProxies
= 4,
157 typedef uint32_t EntityType
;
159 static CFStringRef entityTypeNames
[ENTITY_TYPES_COUNT
];
161 typedef boolean_t (GetEntityChangesFunc
)(CFStringRef serviceID
,
162 CFDictionaryRef state_dict
,
163 CFDictionaryRef setup_dict
,
164 CFDictionaryRef info
);
165 typedef GetEntityChangesFunc
* GetEntityChangesFuncRef
;
167 static GetEntityChangesFunc get_ipv4_changes
;
168 static GetEntityChangesFunc get_ipv6_changes
;
169 static GetEntityChangesFunc get_dns_changes
;
170 static GetEntityChangesFunc get_netinfo_changes
;
171 static GetEntityChangesFunc get_proxies_changes
;
174 my_CFRelease(void * t
);
177 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr
, CFTypeRef
new);
180 my_CFArrayRemoveValue(CFMutableArrayRef arr
, CFStringRef key
);
182 static GetEntityChangesFuncRef entityChangeFunc
[ENTITY_TYPES_COUNT
] = {
183 get_ipv4_changes
, /* 0 */
184 get_ipv6_changes
, /* 1 */
185 get_dns_changes
, /* 2 */
186 get_netinfo_changes
,/* 3 */
187 get_proxies_changes
,/* 4 */
192 ** - mechanism to do an atomic update of the SCDynamicStore
193 ** when the content needs to be changed across multiple functions
196 CFMutableArrayRef notify
;
197 CFMutableArrayRef remove
;
198 CFMutableDictionaryRef set
;
199 } keyChangeList
, * keyChangeListRef
;
202 keyChangeListInit(keyChangeListRef keys
)
204 keys
->notify
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
205 keys
->remove
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
206 keys
->set
= CFDictionaryCreateMutable(NULL
, 0,
207 &kCFTypeDictionaryKeyCallBacks
,
208 &kCFTypeDictionaryValueCallBacks
);
213 keyChangeListFree(keyChangeListRef keys
)
215 my_CFRelease(&keys
->notify
);
216 my_CFRelease(&keys
->remove
);
217 my_CFRelease(&keys
->set
);
222 keyChangeListNotifyKey(keyChangeListRef keys
, CFStringRef key
)
224 my_CFArrayAppendUniqueValue(keys
->notify
, key
);
229 keyChangeListRemoveValue(keyChangeListRef keys
, CFStringRef key
)
231 my_CFArrayAppendUniqueValue(keys
->remove
, key
);
232 CFDictionaryRemoveValue(keys
->set
, key
);
237 keyChangeListSetValue(keyChangeListRef keys
, CFStringRef key
, CFTypeRef value
)
239 my_CFArrayRemoveValue(keys
->remove
, key
);
240 CFDictionarySetValue(keys
->set
, key
, value
);
245 keyChangeListApplyToStore(keyChangeListRef keys
, SCDynamicStoreRef session
)
247 CFArrayRef notify
= keys
->notify
;
248 CFArrayRef remove
= keys
->remove
;
249 CFDictionaryRef set
= keys
->set
;
251 if (CFArrayGetCount(notify
) == 0) {
254 if (CFArrayGetCount(remove
) == 0) {
257 if (CFDictionaryGetCount(set
) == 0) {
260 if (set
== NULL
&& remove
== NULL
&& notify
== NULL
) {
263 if (S_IPMonitor_debug
) {
265 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: Setting:\n%@\n"), set
);
267 if (remove
!= NULL
) {
268 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: Removing:\n%@\n"), remove
);
270 if (notify
!= NULL
) {
271 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: Notifying:\n%@\n"), notify
);
274 (void)SCDynamicStoreSetMultiple(session
, set
, remove
, notify
);
286 mib
[1] = KERN_NETBOOT
;
287 len
= sizeof(netboot
);
288 sysctl(mib
, 2, &netboot
, &len
, NULL
, 0);
293 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr
, CFTypeRef
new)
295 CFIndex n
= CFArrayGetCount(arr
);
297 if (CFArrayContainsValue(arr
, CFRangeMake(0, n
), new)) {
300 CFArrayAppendValue(arr
, new);
305 my_CFArrayRemoveValue(CFMutableArrayRef arr
, CFStringRef key
)
309 i
= CFArrayGetFirstIndexOfValue(arr
,
310 CFRangeMake(0, CFArrayGetCount(arr
)),
312 if (i
!= kCFNotFound
) {
313 CFArrayRemoveValueAtIndex(arr
, i
);
319 my_CFRelease(void * t
)
321 void * * obj
= (void * *)t
;
330 static CFDictionaryRef
331 my_CFDictionaryGetDictionary(CFDictionaryRef dict
, CFStringRef key
)
333 if (isA_CFDictionary(dict
) == NULL
) {
336 return (isA_CFDictionary(CFDictionaryGetValue(dict
, key
)));
339 static CFDictionaryRef
340 my_SCDCopy(SCDynamicStoreRef session
, CFStringRef key
)
342 CFDictionaryRef dict
;
344 dict
= SCDynamicStoreCopyValue(session
, key
);
345 if (isA_CFDictionary(dict
) == NULL
) {
352 cfstring_to_ipvx(int family
, CFStringRef str
, void * addr
, int addr_size
)
356 if (isA_CFString(str
) == NULL
) {
362 if (addr_size
< sizeof(struct in_addr
)) {
367 if (addr_size
< sizeof(struct in6_addr
)) {
374 (void)_SC_cfstring_to_cstring(str
, buf
, sizeof(buf
), kCFStringEncodingASCII
);
375 if (inet_pton(family
, buf
, addr
) == 1) {
379 bzero(addr
, addr_size
);
384 cfstring_to_ip(CFStringRef str
, struct in_addr
* ip_p
)
386 return (cfstring_to_ipvx(AF_INET
, str
, ip_p
, sizeof(*ip_p
)));
390 cfstring_to_ip6(CFStringRef str
, struct in6_addr
* ip6_p
)
392 return (cfstring_to_ipvx(AF_INET6
, str
, ip6_p
, sizeof(*ip6_p
)));
396 * Function: parse_component
398 * Given a string 'key' and a string prefix 'prefix',
399 * return the next component in the slash '/' separated
403 * 1. key = "a/b/c" prefix = "a/"
405 * 2. key = "a/b/c" prefix = "a/b/"
409 parse_component(CFStringRef key
, CFStringRef prefix
)
411 CFMutableStringRef comp
;
414 if (CFStringHasPrefix(key
, prefix
) == FALSE
) {
417 comp
= CFStringCreateMutableCopy(NULL
, 0, key
);
421 CFStringDelete(comp
, CFRangeMake(0, CFStringGetLength(prefix
)));
422 range
= CFStringFind(comp
, CFSTR("/"), 0);
423 if (range
.location
== kCFNotFound
) {
426 range
.length
= CFStringGetLength(comp
) - range
.location
;
427 CFStringDelete(comp
, range
);
432 append_netinfo_arrays(CFDictionaryRef dict
, CFMutableArrayRef ni_addrs
,
433 CFMutableArrayRef ni_tags
)
438 if (isA_CFDictionary(dict
) == NULL
)
441 addrs
= isA_CFArray(CFDictionaryGetValue(dict
, kSCPropNetNetInfoServerAddresses
));
442 tags
= isA_CFArray(CFDictionaryGetValue(dict
, kSCPropNetNetInfoServerTags
));
444 CFIndex addrs_count
= CFArrayGetCount(addrs
);
445 CFIndex tags_count
= CFArrayGetCount(tags
);
447 if (addrs_count
> 0) {
448 if (addrs_count
== tags_count
) {
449 CFArrayAppendArray(ni_addrs
, addrs
,
450 CFRangeMake(0, addrs_count
));
451 CFArrayAppendArray(ni_tags
, tags
,
452 CFRangeMake(0, tags_count
));
462 append_netinfo_broadcast_addresses(CFDictionaryRef netinfo_dict
,
463 CFDictionaryRef ipv4_dict
,
464 CFMutableArrayRef ni_addrs
,
465 CFMutableArrayRef ni_tags
)
474 tag
= CFDictionaryGetValue(netinfo_dict
,
475 kSCPropNetNetInfoBroadcastServerTag
);
476 tag
= isA_CFString(tag
);
478 tag
= kSCValNetNetInfoDefaultServerTag
;
480 addrs
= isA_CFArray(CFDictionaryGetValue(ipv4_dict
,
481 kSCPropNetIPv4Addresses
));
482 masks
= isA_CFArray(CFDictionaryGetValue(ipv4_dict
,
483 kSCPropNetIPv4SubnetMasks
));
484 if (addrs
== NULL
|| masks
== NULL
) {
487 masks_count
= CFArrayGetCount(masks
);
488 addrs_count
= CFArrayGetCount(addrs
);
489 if (addrs_count
!= masks_count
) {
493 for (i
= 0; i
< addrs_count
; i
++) {
495 CFStringRef broadcast
= NULL
;
498 if (cfstring_to_ip(CFArrayGetValueAtIndex(addrs
, i
), &addr
)
499 && cfstring_to_ip(CFArrayGetValueAtIndex(masks
, i
), &mask
)) {
502 b
.s_addr
= htonl(ntohl(addr
.s_addr
) | ~ntohl(mask
.s_addr
));
503 broadcast
= CFStringCreateWithFormat(NULL
, NULL
,
506 CFArrayAppendValue(ni_addrs
, broadcast
);
507 CFArrayAppendValue(ni_tags
, tag
);
508 my_CFRelease(&broadcast
);
514 static CFDictionaryRef
515 make_netinfo_dict(CFDictionaryRef state_dict
,
516 CFDictionaryRef setup_dict
,
517 CFDictionaryRef ipv4_dict
)
519 boolean_t has_manual
= FALSE
;
520 boolean_t has_broadcast
= FALSE
;
521 boolean_t has_dhcp
= FALSE
;
525 CFMutableArrayRef ni_addrs
= NULL
;
526 CFMutableDictionaryRef ni_dict
= NULL
;
527 CFMutableArrayRef ni_tags
= NULL
;
529 if (setup_dict
== NULL
|| ipv4_dict
== NULL
) {
532 m
= isA_CFArray(CFDictionaryGetValue(setup_dict
,
533 kSCPropNetNetInfoBindingMethods
));
537 ni_addrs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
538 ni_tags
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
540 /* find out which are configured */
541 n
= CFArrayGetCount(m
);
542 for (i
= 0; i
< n
; i
++) {
543 CFStringRef method
= CFArrayGetValueAtIndex(m
, i
);
546 kSCValNetNetInfoBindingMethodsManual
)) {
549 else if (CFEqual(method
,
550 kSCValNetNetInfoBindingMethodsDHCP
)) {
553 else if (CFEqual(method
,
554 kSCValNetNetInfoBindingMethodsBroadcast
)) {
555 has_broadcast
= TRUE
;
558 if (has_dhcp
&& state_dict
!= NULL
) {
559 append_netinfo_arrays(state_dict
, ni_addrs
, ni_tags
);
562 append_netinfo_arrays(setup_dict
, ni_addrs
, ni_tags
);
565 append_netinfo_broadcast_addresses(setup_dict
, ipv4_dict
,
568 if (CFArrayGetCount(ni_addrs
) == 0) {
571 ni_dict
= CFDictionaryCreateMutable(NULL
, 0,
572 &kCFTypeDictionaryKeyCallBacks
,
573 &kCFTypeDictionaryValueCallBacks
);
574 CFDictionarySetValue(ni_dict
, kSCPropNetNetInfoServerAddresses
,
576 CFDictionarySetValue(ni_dict
, kSCPropNetNetInfoServerTags
,
579 my_CFRelease(&ni_addrs
);
580 my_CFRelease(&ni_tags
);
584 static CFMutableDictionaryRef
585 service_dict_copy(CFStringRef serviceID
)
587 CFDictionaryRef d
= NULL
;
588 CFMutableDictionaryRef service_dict
;
590 /* create a modifyable dictionary, a copy or a new one */
591 d
= CFDictionaryGetValue(S_service_state_dict
, serviceID
);
594 = CFDictionaryCreateMutable(NULL
, 0,
595 &kCFTypeDictionaryKeyCallBacks
,
596 &kCFTypeDictionaryValueCallBacks
);
599 service_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, d
);
601 return (service_dict
);
605 service_dict_set(CFStringRef serviceID
, CFStringRef entity
,
606 CFDictionaryRef new_dict
)
608 boolean_t changed
= FALSE
;
610 CFMutableDictionaryRef service_dict
;
612 service_dict
= service_dict_copy(serviceID
);
613 old
= CFDictionaryGetValue(service_dict
, entity
);
614 if (new_dict
== NULL
) {
616 SCLog(S_IPMonitor_debug
, LOG_INFO
,
617 CFSTR("IPMonitor: serviceID %@ removed %@ dictionary = %@"),
618 serviceID
, entity
, old
);
619 CFDictionaryRemoveValue(service_dict
, entity
);
624 if (old
== NULL
|| CFEqual(new_dict
, old
) == FALSE
) {
625 SCLog(S_IPMonitor_debug
, LOG_INFO
,
626 CFSTR("IPMonitor: serviceID %@ changed %@"
627 " dictionary\nold %@\nnew %@"), serviceID
, entity
,
628 (old
!= NULL
) ? (CFTypeRef
)old
: (CFTypeRef
)CFSTR("<none>"),
630 CFDictionarySetValue(service_dict
, entity
, new_dict
);
634 if (CFDictionaryGetCount(service_dict
) == 0) {
635 CFDictionaryRemoveValue(S_service_state_dict
, serviceID
);
638 CFDictionarySetValue(S_service_state_dict
, serviceID
, service_dict
);
640 my_CFRelease(&service_dict
);
644 static CFDictionaryRef
645 service_dict_get(CFStringRef serviceID
, CFStringRef entity
)
647 CFDictionaryRef service_dict
;
649 service_dict
= CFDictionaryGetValue(S_service_state_dict
, serviceID
);
650 if (service_dict
== NULL
) {
653 return (CFDictionaryGetValue(service_dict
, entity
));
657 ** GetEntityChangesFunc functions
659 static __inline__
struct in_addr
660 subnet_addr(struct in_addr addr
, struct in_addr mask
)
664 net
.s_addr
= htonl((uint32_t)ntohl(addr
.s_addr
)
665 & (uint32_t)ntohl(mask
.s_addr
));
670 get_ipv4_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
671 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
673 struct in_addr addr
= { 0 };
675 boolean_t changed
= FALSE
;
676 CFMutableDictionaryRef dict
= NULL
;
677 struct in_addr mask
= { 0 };
679 CFDictionaryRef new_dict
= NULL
;
680 CFStringRef router
= NULL
;
681 boolean_t valid_ip
= FALSE
;
682 boolean_t valid_mask
= FALSE
;
684 if (state_dict
== NULL
) {
687 addrs
= isA_CFArray(CFDictionaryGetValue(state_dict
,
688 kSCPropNetIPv4Addresses
));
689 if (addrs
!= NULL
&& CFArrayGetCount(addrs
) > 0) {
690 valid_ip
= cfstring_to_ip(CFArrayGetValueAtIndex(addrs
, 0), &addr
);
692 masks
= isA_CFArray(CFDictionaryGetValue(state_dict
,
693 kSCPropNetIPv4SubnetMasks
));
694 if (masks
!= NULL
&& CFArrayGetCount(masks
) > 0) {
695 valid_mask
= cfstring_to_ip(CFArrayGetValueAtIndex(masks
, 0), &mask
);
697 if (valid_ip
== FALSE
) {
698 SCLog(S_IPMonitor_debug
, LOG_INFO
,
699 CFSTR("IPMonitor: %@ has no valid IP address, ignoring"),
703 dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
704 if (setup_dict
!= NULL
) {
705 router
= CFDictionaryGetValue(setup_dict
,
706 kSCPropNetIPv4Router
);
707 if (router
!= NULL
) {
708 CFDictionarySetValue(dict
,
709 kSCPropNetIPv4Router
,
714 /* check whether the router is direct, or non-local */
715 router
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
716 if (router
!= NULL
) {
717 struct in_addr router_ip
;
719 if (cfstring_to_ip(router
, &router_ip
)) {
720 if (router_ip
.s_addr
== addr
.s_addr
) {
721 /* default route routes directly to the interface */
722 CFDictionarySetValue(dict
, kRouterIsDirect
, kCFBooleanTrue
);
725 && subnet_addr(addr
, mask
).s_addr
726 != subnet_addr(router_ip
, mask
).s_addr
) {
727 /* router is not on the same subnet */
728 CFDictionarySetValue(dict
, kRouterNeedsLocalIP
,
729 CFArrayGetValueAtIndex(addrs
, 0));
736 changed
= service_dict_set(serviceID
, kSCEntNetIPv4
, new_dict
);
737 my_CFRelease(&new_dict
);
742 get_ipv6_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
743 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
745 struct in6_addr addr
;
747 boolean_t changed
= FALSE
;
748 CFMutableDictionaryRef dict
= NULL
;
749 CFDictionaryRef new_dict
= NULL
;
750 CFStringRef router
= NULL
;
751 boolean_t valid_ip
= FALSE
;
753 if (state_dict
== NULL
) {
756 addrs
= isA_CFArray(CFDictionaryGetValue(state_dict
,
757 kSCPropNetIPv6Addresses
));
758 if (addrs
!= NULL
&& CFArrayGetCount(addrs
) > 0) {
759 valid_ip
= cfstring_to_ip6(CFArrayGetValueAtIndex(addrs
, 0), &addr
);
761 if (valid_ip
== FALSE
) {
762 SCLog(S_IPMonitor_debug
, LOG_INFO
,
763 CFSTR("IPMonitor: %@ has no valid IPv6 address, ignoring"),
767 dict
= CFDictionaryCreateMutableCopy(NULL
, 0, state_dict
);
768 if (setup_dict
!= NULL
) {
769 router
= CFDictionaryGetValue(setup_dict
,
770 kSCPropNetIPv6Router
);
771 if (router
!= NULL
) {
772 CFDictionarySetValue(dict
,
773 kSCPropNetIPv6Router
,
779 changed
= service_dict_set(serviceID
, kSCEntNetIPv6
, new_dict
);
780 my_CFRelease(&new_dict
);
785 dns_has_supplemental(CFStringRef serviceID
)
787 CFDictionaryRef dns_dict
;
788 CFDictionaryRef service_dict
;
790 service_dict
= CFDictionaryGetValue(S_service_state_dict
, serviceID
);
791 if (service_dict
== NULL
) {
795 dns_dict
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
796 if (dns_dict
== NULL
) {
800 return CFDictionaryContainsKey(dns_dict
, kSCPropNetDNSSupplementalMatchDomains
);
804 merge_dns_prop(CFMutableDictionaryRef dict
, CFStringRef key
,
805 CFDictionaryRef state_dict
, CFDictionaryRef setup_dict
,
808 CFArrayRef setup_prop
= NULL
;
809 CFArrayRef state_prop
= NULL
;
811 if (setup_dict
!= NULL
) {
812 setup_prop
= isA_CFArray(CFDictionaryGetValue(setup_dict
, key
));
814 if (state_dict
!= NULL
) {
815 state_prop
= isA_CFArray(CFDictionaryGetValue(state_dict
, key
));
817 if ((setup_prop
!= NULL
) && (state_prop
!= NULL
)) {
818 CFMutableArrayRef merge_prop
;
820 /* create a new list by merging the setup and state lists */
821 merge_prop
= CFArrayCreateMutableCopy(NULL
, 0, setup_prop
);
823 CFRange state_range
= CFRangeMake(0, CFArrayGetCount(state_prop
));
825 CFArrayAppendArray(merge_prop
, state_prop
, state_range
);
829 CFRange setup_range
= CFRangeMake(0, CFArrayGetCount(setup_prop
));
831 n
= CFArrayGetCount(state_prop
);
832 for (i
= 0; i
< n
; i
++) {
835 val
= CFArrayGetValueAtIndex(state_prop
, i
);
836 if (!CFArrayContainsValue(setup_prop
, setup_range
, val
)) {
837 CFArrayAppendValue(merge_prop
, val
);
841 CFDictionarySetValue(dict
, key
, merge_prop
);
842 my_CFRelease(&merge_prop
);
844 else if (setup_prop
!= NULL
) {
845 CFDictionarySetValue(dict
, key
, setup_prop
);
847 else if (state_prop
!= NULL
) {
848 CFDictionarySetValue(dict
, key
, state_prop
);
854 get_dns_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
855 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
857 boolean_t changed
= FALSE
;
864 { kSCPropNetDNSSearchDomains
, FALSE
},
865 { kSCPropNetDNSServerAddresses
, FALSE
},
866 { kSCPropNetDNSSortList
, FALSE
},
867 { kSCPropNetDNSSupplementalMatchDomains
, TRUE
},
868 { kSCPropNetDNSSupplementalMatchOrders
, TRUE
},
871 CFMutableDictionaryRef new_dict
= NULL
;
872 CFStringRef pick_list
[] = {
873 kSCPropNetDNSDomainName
,
874 kSCPropNetDNSOptions
,
875 kSCPropNetDNSSearchOrder
,
876 kSCPropNetDNSServerPort
,
877 kSCPropNetDNSServerTimeout
,
881 if (state_dict
== NULL
&& setup_dict
== NULL
) {
882 /* there is no DNS */
885 if (service_dict_get(serviceID
, kSCEntNetIPv4
) == NULL
886 && service_dict_get(serviceID
, kSCEntNetIPv6
) == NULL
) {
887 /* no point in remembering the DNS */
891 // merge DNS configuration
892 new_dict
= CFDictionaryCreateMutable(NULL
, 0,
893 &kCFTypeDictionaryKeyCallBacks
,
894 &kCFTypeDictionaryValueCallBacks
);
896 for (i
= 0; merge_list
[i
].key
!= NULL
; i
++) {
897 merge_dns_prop(new_dict
,
901 merge_list
[i
].append
);
903 for (i
= 0; pick_list
[i
]; i
++) {
904 CFTypeRef val
= NULL
;
906 if (setup_dict
!= NULL
) {
907 val
= CFDictionaryGetValue(setup_dict
, pick_list
[i
]);
909 if (val
== NULL
&& state_dict
!= NULL
) {
910 val
= CFDictionaryGetValue(state_dict
, pick_list
[i
]);
913 CFDictionarySetValue(new_dict
, pick_list
[i
], val
);
916 if (CFDictionaryGetCount(new_dict
) == 0) {
917 my_CFRelease(&new_dict
);
922 * ensure any specified domain name (e.g. the domain returned by
923 * a DHCP server) is in the search list.
925 domain
= CFDictionaryGetValue(new_dict
, kSCPropNetDNSDomainName
);
926 if (isA_CFString(domain
)) {
929 search
= CFDictionaryGetValue(new_dict
, kSCPropNetDNSSearchDomains
);
930 if (isA_CFArray(search
) &&
931 !CFArrayContainsValue(search
, CFRangeMake(0, CFArrayGetCount(search
)), domain
)) {
932 CFMutableArrayRef new_search
;
934 new_search
= CFArrayCreateMutableCopy(NULL
, 0, search
);
935 CFArrayAppendValue(new_search
, domain
);
936 CFDictionarySetValue(new_dict
, kSCPropNetDNSSearchDomains
, new_search
);
937 my_CFRelease(&new_search
);
942 changed
= service_dict_set(serviceID
, kSCEntNetDNS
, new_dict
);
943 my_CFRelease(&new_dict
);
948 get_netinfo_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
949 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
951 boolean_t changed
= FALSE
;
952 CFDictionaryRef global_dict
;
953 CFDictionaryRef ipv4_dict
;
954 CFDictionaryRef new_dict
= NULL
;
956 global_dict
= my_CFDictionaryGetDictionary(info
, S_setup_global_netinfo
);
957 ipv4_dict
= service_dict_get(serviceID
, kSCEntNetIPv4
);
958 new_dict
= make_netinfo_dict(state_dict
, global_dict
, ipv4_dict
);
959 changed
= service_dict_set(serviceID
, kSCEntNetNetInfo
, new_dict
);
960 my_CFRelease(&new_dict
);
965 get_proxies_changes(CFStringRef serviceID
, CFDictionaryRef state_dict
,
966 CFDictionaryRef setup_dict
, CFDictionaryRef info
)
968 boolean_t changed
= FALSE
;
969 CFDictionaryRef new_dict
= NULL
;
971 if (service_dict_get(serviceID
, kSCEntNetIPv4
) == NULL
972 && service_dict_get(serviceID
, kSCEntNetIPv6
) == NULL
) {
973 /* no point in remembering the Proxies */
976 if (setup_dict
!= NULL
) {
977 new_dict
= setup_dict
;
980 new_dict
= state_dict
;
983 changed
= service_dict_set(serviceID
, kSCEntNetProxies
, new_dict
);
988 state_service_key(CFStringRef serviceID
, CFStringRef entity
)
990 return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
991 kSCDynamicStoreDomainState
,
997 setup_service_key(CFStringRef serviceID
, CFStringRef entity
)
999 return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1000 kSCDynamicStoreDomainSetup
,
1005 static CFDictionaryRef
1006 services_info_copy(SCDynamicStoreRef session
, CFArrayRef service_list
)
1009 CFMutableArrayRef get_keys
;
1012 CFDictionaryRef info
;
1014 count
= CFArrayGetCount(service_list
);
1015 get_keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1017 CFArrayAppendValue(get_keys
, S_setup_global_netinfo
);
1018 CFArrayAppendValue(get_keys
, S_setup_global_proxies
);
1019 CFArrayAppendValue(get_keys
, S_setup_global_ipv4
);
1021 for (s
= 0; s
< count
; s
++) {
1022 CFStringRef serviceID
= CFArrayGetValueAtIndex(service_list
, s
);
1024 for (i
= 0; i
< ENTITY_TYPES_COUNT
; i
++) {
1025 CFStringRef setup_key
;
1026 CFStringRef state_key
;
1028 setup_key
= setup_service_key(serviceID
, entityTypeNames
[i
]);
1029 state_key
= state_service_key(serviceID
, entityTypeNames
[i
]);
1030 CFArrayAppendValue(get_keys
, setup_key
);
1031 CFArrayAppendValue(get_keys
, state_key
);
1032 my_CFRelease(&setup_key
);
1033 my_CFRelease(&state_key
);
1037 info
= SCDynamicStoreCopyMultiple(session
, get_keys
, NULL
);
1038 my_CFRelease(&get_keys
);
1042 static CFDictionaryRef
1043 get_service_setup_entity(CFDictionaryRef service_info
, CFStringRef serviceID
,
1046 CFStringRef setup_key
;
1047 CFDictionaryRef setup_dict
;
1049 setup_key
= setup_service_key(serviceID
, entity
);
1050 setup_dict
= my_CFDictionaryGetDictionary(service_info
, setup_key
);
1051 my_CFRelease(&setup_key
);
1052 return (setup_dict
);
1055 static CFDictionaryRef
1056 get_service_state_entity(CFDictionaryRef service_info
, CFStringRef serviceID
,
1059 CFStringRef state_key
;
1060 CFDictionaryRef state_dict
;
1062 state_key
= state_service_key(serviceID
, entity
);
1063 state_dict
= my_CFDictionaryGetDictionary(service_info
, state_key
);
1064 my_CFRelease(&state_key
);
1065 return (state_dict
);
1068 static int rtm_seq
= 0;
1071 ipv4_route(int cmd
, struct in_addr gateway
, struct in_addr netaddr
,
1072 struct in_addr netmask
, char * ifname
, boolean_t is_direct
)
1074 boolean_t default_route
= (netaddr
.s_addr
== 0);
1076 boolean_t ret
= TRUE
;
1078 struct rt_msghdr hdr
;
1079 struct sockaddr_in dst
;
1080 struct sockaddr_in gway
;
1081 struct sockaddr_in mask
;
1082 struct sockaddr_dl link
;
1086 if (default_route
&& S_netboot
) {
1090 if ((sockfd
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)) < 0) {
1091 SCLog(TRUE
, LOG_INFO
,
1092 CFSTR("IPMonitor: ipv4_route: open routing socket failed, %s"),
1097 memset(&rtmsg
, 0, sizeof(rtmsg
));
1098 rtmsg
.hdr
.rtm_type
= cmd
;
1099 if (default_route
) {
1101 /* if router is directly reachable, don't set the gateway flag */
1102 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_STATIC
;
1105 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_STATIC
;
1109 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_CLONING
| RTF_STATIC
;
1111 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
1112 rtmsg
.hdr
.rtm_seq
= ++rtm_seq
;
1113 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
| RTA_NETMASK
;
1114 rtmsg
.dst
.sin_len
= sizeof(rtmsg
.dst
);
1115 rtmsg
.dst
.sin_family
= AF_INET
;
1116 rtmsg
.dst
.sin_addr
= netaddr
;
1117 rtmsg
.gway
.sin_len
= sizeof(rtmsg
.gway
);
1118 rtmsg
.gway
.sin_family
= AF_INET
;
1119 rtmsg
.gway
.sin_addr
= gateway
;
1120 rtmsg
.mask
.sin_len
= sizeof(rtmsg
.mask
);
1121 rtmsg
.mask
.sin_family
= AF_INET
;
1122 rtmsg
.mask
.sin_addr
= netmask
;
1124 len
= sizeof(rtmsg
);
1126 rtmsg
.link
.sdl_len
= sizeof(rtmsg
.link
);
1127 rtmsg
.link
.sdl_family
= AF_LINK
;
1128 rtmsg
.link
.sdl_nlen
= strlen(ifname
);
1129 rtmsg
.hdr
.rtm_addrs
|= RTA_IFP
;
1130 bcopy(ifname
, rtmsg
.link
.sdl_data
, rtmsg
.link
.sdl_nlen
);
1133 /* no link information */
1134 len
-= sizeof(rtmsg
.link
);
1136 rtmsg
.hdr
.rtm_msglen
= len
;
1137 if (write(sockfd
, &rtmsg
, len
) < 0) {
1138 if ((cmd
== RTM_ADD
) && (errno
== EEXIST
)) {
1139 /* no sense complaining about a route that already exists */
1141 else if ((cmd
== RTM_DELETE
) && (errno
== ESRCH
)) {
1142 /* no sense complaining about a route that isn't there */
1145 SCLog(S_IPMonitor_debug
, LOG_INFO
,
1146 CFSTR("IPMonitor ipv4_route: "
1147 "write routing socket failed, %s"), strerror(errno
));
1157 ipv6_route(int cmd
, struct in6_addr gateway
, struct in6_addr netaddr
,
1158 struct in6_addr netmask
, char * ifname
, boolean_t is_direct
)
1160 boolean_t default_route
;
1162 boolean_t ret
= TRUE
;
1164 struct rt_msghdr hdr
;
1165 struct sockaddr_in6 dst
;
1166 struct sockaddr_in6 gway
;
1167 struct sockaddr_in6 mask
;
1168 struct sockaddr_dl link
;
1171 struct in6_addr zeroes
= IN6ADDR_ANY_INIT
;
1173 default_route
= (bcmp(&zeroes
, &netaddr
, sizeof(netaddr
)) == 0);
1175 if (IN6_IS_ADDR_LINKLOCAL(&gateway
) && ifname
!= NULL
) {
1176 unsigned int index
= if_nametoindex(ifname
);
1178 /* add the scope id to the link local address */
1179 gateway
.__u6_addr
.__u6_addr16
[1] = (uint16_t)htons(index
);
1181 if ((sockfd
= socket(PF_ROUTE
, SOCK_RAW
, AF_INET
)) < 0) {
1182 SCLog(TRUE
, LOG_INFO
,
1183 CFSTR("IPMonitor ipv6_route: open routing socket failed, %s"),
1187 memset(&rtmsg
, 0, sizeof(rtmsg
));
1188 rtmsg
.hdr
.rtm_type
= cmd
;
1189 if (default_route
) {
1191 /* if router is directly reachable, don't set the gateway flag */
1192 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_STATIC
;
1195 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_GATEWAY
| RTF_STATIC
;
1199 rtmsg
.hdr
.rtm_flags
= RTF_UP
| RTF_CLONING
| RTF_STATIC
;
1201 rtmsg
.hdr
.rtm_version
= RTM_VERSION
;
1202 rtmsg
.hdr
.rtm_seq
= ++rtm_seq
;
1203 rtmsg
.hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
| RTA_NETMASK
;
1204 rtmsg
.dst
.sin6_len
= sizeof(rtmsg
.dst
);
1205 rtmsg
.dst
.sin6_family
= AF_INET6
;
1206 rtmsg
.dst
.sin6_addr
= netaddr
;
1207 rtmsg
.gway
.sin6_len
= sizeof(rtmsg
.gway
);
1208 rtmsg
.gway
.sin6_family
= AF_INET6
;
1209 rtmsg
.gway
.sin6_addr
= gateway
;
1210 rtmsg
.mask
.sin6_len
= sizeof(rtmsg
.mask
);
1211 rtmsg
.mask
.sin6_family
= AF_INET6
;
1212 rtmsg
.mask
.sin6_addr
= netmask
;
1214 len
= sizeof(rtmsg
);
1216 rtmsg
.link
.sdl_len
= sizeof(rtmsg
.link
);
1217 rtmsg
.link
.sdl_family
= AF_LINK
;
1218 rtmsg
.link
.sdl_nlen
= strlen(ifname
);
1219 rtmsg
.hdr
.rtm_addrs
|= RTA_IFP
;
1220 bcopy(ifname
, rtmsg
.link
.sdl_data
, rtmsg
.link
.sdl_nlen
);
1223 /* no link information */
1224 len
-= sizeof(rtmsg
.link
);
1226 rtmsg
.hdr
.rtm_msglen
= len
;
1227 if (write(sockfd
, &rtmsg
, len
) < 0) {
1228 if ((cmd
== RTM_ADD
) && (errno
== EEXIST
)) {
1229 /* no sense complaining about a route that already exists */
1231 else if ((cmd
== RTM_DELETE
) && (errno
== ESRCH
)) {
1232 /* no sense complaining about a route that isn't there */
1235 SCLog(S_IPMonitor_debug
, LOG_INFO
,
1236 CFSTR("IPMonitor ipv6_route: write routing"
1237 " socket failed, %s"), strerror(errno
));
1247 ipv4_subnet_route_add(struct in_addr local_ip
,
1248 struct in_addr subnet
, struct in_addr mask
, char * ifname
)
1250 if (S_IPMonitor_debug
) {
1251 SCLog(TRUE
, LOG_INFO
,
1252 CFSTR("IPMonitor: IPv4 route add -net "
1253 IP_FORMAT
" -netmask %s interface %s"),
1254 IP_LIST(&subnet
), inet_ntoa(mask
), ifname
);
1256 return (ipv4_route(RTM_ADD
, local_ip
, subnet
, mask
, ifname
, FALSE
));
1260 ipv4_subnet_route_delete(struct in_addr subnet
, struct in_addr mask
)
1262 if (S_IPMonitor_debug
) {
1263 SCLog(TRUE
, LOG_INFO
,
1264 CFSTR("IPMonitor: IPv4 route delete -net "
1266 IP_LIST(&subnet
), inet_ntoa(mask
));
1268 return (ipv4_route(RTM_DELETE
, S_ip_zeros
, subnet
, mask
, NULL
, FALSE
));
1273 ipv4_default_route_delete(void)
1275 if (S_IPMonitor_debug
) {
1276 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: IPv4 route delete default"));
1278 return (ipv4_route(RTM_DELETE
, S_ip_zeros
, S_ip_zeros
, S_ip_zeros
, NULL
, FALSE
));
1282 ipv4_default_route_add(struct in_addr router
, char * ifname
,
1283 boolean_t is_direct
)
1285 if (S_IPMonitor_debug
) {
1286 SCLog(TRUE
, LOG_INFO
,
1287 CFSTR("IPMonitor: IPv4 route add default"
1288 " %s interface %s direct %d"),
1289 inet_ntoa(router
), ifname
, is_direct
);
1291 return (ipv4_route(RTM_ADD
, router
, S_ip_zeros
, S_ip_zeros
, ifname
, is_direct
));
1295 ipv4_default_route_change(struct in_addr router
, char * ifname
,
1296 boolean_t is_direct
)
1298 if (S_IPMonitor_debug
) {
1299 SCLog(TRUE
, LOG_INFO
,
1300 CFSTR("IPMonitor: IPv4 route change default"
1301 " %s interface %s direct %d"),
1302 inet_ntoa(router
), ifname
, is_direct
);
1304 return (ipv4_route(RTM_CHANGE
, router
, S_ip_zeros
, S_ip_zeros
, ifname
,
1309 ipv6_default_route_delete(void)
1311 if (S_IPMonitor_debug
) {
1312 SCLog(TRUE
, LOG_INFO
, CFSTR("IPMonitor: IPv6 route delete default"));
1314 return (ipv6_route(RTM_DELETE
, S_ip6_zeros
, S_ip6_zeros
, S_ip6_zeros
, NULL
, FALSE
));
1318 ipv6_default_route_add(struct in6_addr router
, char * ifname
,
1319 boolean_t is_direct
)
1321 if (S_IPMonitor_debug
) {
1326 inet_ntop(AF_INET6
, &router
, str
, sizeof(str
));
1327 SCLog(TRUE
,LOG_INFO
,
1328 CFSTR("IPMonitor: IPv6 route add default"
1329 " %s interface %s direct %d"),
1330 str
, ifname
, is_direct
);
1332 return (ipv6_route(RTM_ADD
, router
, S_ip6_zeros
, S_ip6_zeros
, ifname
, is_direct
));
1337 multicast_route_delete()
1339 struct in_addr gateway
= { htonl(INADDR_LOOPBACK
) };
1340 struct in_addr netaddr
= { htonl(INADDR_UNSPEC_GROUP
) };
1341 struct in_addr netmask
= { htonl(IN_CLASSD_NET
) };
1343 return (ipv4_route(RTM_DELETE
, gateway
, netaddr
, netmask
, "lo0", FALSE
));
1347 multicast_route_add()
1349 struct in_addr gateway
= { htonl(INADDR_LOOPBACK
) };
1350 struct in_addr netaddr
= { htonl(INADDR_UNSPEC_GROUP
) };
1351 struct in_addr netmask
= { htonl(IN_CLASSD_NET
) };
1353 return (ipv4_route(RTM_ADD
, gateway
, netaddr
, netmask
, "lo0", FALSE
));
1357 set_ipv4_router(struct in_addr
* router
, char * ifname
, boolean_t is_direct
)
1359 if (S_router_subnet
.s_addr
!= 0) {
1360 ipv4_subnet_route_delete(S_router_subnet
, S_router_subnet_mask
);
1361 S_router_subnet
.s_addr
= S_router_subnet_mask
.s_addr
= 0;
1363 /* assign the new default route, ensure local multicast route available */
1364 (void)ipv4_default_route_delete();
1365 if (router
!= NULL
) {
1366 (void)ipv4_default_route_add(*router
, ifname
, is_direct
);
1367 (void)multicast_route_delete();
1370 (void)multicast_route_add();
1377 set_ipv6_router(struct in6_addr
* router
, char * ifname
, boolean_t is_direct
)
1379 /* assign the new default route, ensure local multicast route available */
1380 (void)ipv6_default_route_delete();
1381 if (router
!= NULL
) {
1382 (void)ipv6_default_route_add(*router
, ifname
, is_direct
);
1387 static __inline__
void
1390 (void)unlink(VAR_RUN_RESOLV_CONF
);
1394 empty_netinfo(SCDynamicStoreRef session
)
1396 int fd
= open(VAR_RUN_NICONFIG_LOCAL_XML
"-",
1397 O_CREAT
|O_TRUNC
|O_WRONLY
, 0644);
1400 rename(VAR_RUN_NICONFIG_LOCAL_XML
"-", VAR_RUN_NICONFIG_LOCAL_XML
);
1407 set_dns(CFArrayRef val_search_domains
,
1408 CFStringRef val_domain_name
,
1409 CFArrayRef val_servers
,
1410 CFArrayRef val_sortlist
)
1412 FILE * f
= fopen(VAR_RUN_RESOLV_CONF
"-", "w");
1414 /* publish new resolv.conf */
1419 if (isA_CFString(val_domain_name
)) {
1420 SCPrint(TRUE
, f
, CFSTR("domain %@\n"), val_domain_name
);
1423 if (isA_CFArray(val_search_domains
)) {
1424 SCPrint(TRUE
, f
, CFSTR("search"));
1425 n
= CFArrayGetCount(val_search_domains
);
1426 for (i
= 0; i
< n
; i
++) {
1429 domain
= CFArrayGetValueAtIndex(val_search_domains
, i
);
1430 if (isA_CFString(domain
)) {
1431 SCPrint(TRUE
, f
, CFSTR(" %@"), domain
);
1434 SCPrint(TRUE
, f
, CFSTR("\n"));
1437 if (isA_CFArray(val_servers
)) {
1438 n
= CFArrayGetCount(val_servers
);
1439 for (i
= 0; i
< n
; i
++) {
1440 CFStringRef nameserver
;
1442 nameserver
= CFArrayGetValueAtIndex(val_servers
, i
);
1443 if (isA_CFString(nameserver
)) {
1444 SCPrint(TRUE
, f
, CFSTR("nameserver %@\n"), nameserver
);
1449 if (isA_CFArray(val_sortlist
)) {
1450 SCPrint(TRUE
, f
, CFSTR("sortlist"));
1451 n
= CFArrayGetCount(val_sortlist
);
1452 for (i
= 0; i
< n
; i
++) {
1453 CFStringRef address
;
1455 address
= CFArrayGetValueAtIndex(val_sortlist
, i
);
1456 if (isA_CFString(address
)) {
1457 SCPrint(TRUE
, f
, CFSTR(" %@"), address
);
1460 SCPrint(TRUE
, f
, CFSTR("\n"));
1464 rename(VAR_RUN_RESOLV_CONF
"-", VAR_RUN_RESOLV_CONF
);
1470 set_netinfo(CFDictionaryRef dict
)
1472 int fd
= open(VAR_RUN_NICONFIG_LOCAL_XML
"-",
1473 O_CREAT
|O_TRUNC
|O_WRONLY
, 0644);
1475 /* publish new netinfo config */
1477 contents
= CFPropertyListCreateXMLData(NULL
, dict
);
1479 CFIndex len
= CFDataGetLength(contents
);
1481 write(fd
, CFDataGetBytePtr(contents
), len
);
1482 CFRelease(contents
);
1485 rename(VAR_RUN_NICONFIG_LOCAL_XML
"-", VAR_RUN_NICONFIG_LOCAL_XML
);
1491 router_is_our_ipv6_address(CFStringRef router
, CFArrayRef addr_list
)
1494 CFIndex n
= CFArrayGetCount(addr_list
);
1497 (void)cfstring_to_ip6(router
, &r
);
1498 for (i
= 0; i
< n
; i
++) {
1501 if (cfstring_to_ip6(CFArrayGetValueAtIndex(addr_list
, i
), &ip
)
1502 && bcmp(&r
, &ip
, sizeof(r
)) == 0) {
1510 update_ipv4(SCDynamicStoreRef session
, CFDictionaryRef service_info
,
1511 CFStringRef primary
, keyChangeListRef keys
)
1513 CFDictionaryRef ipv4_dict
= NULL
;
1515 if (primary
!= NULL
) {
1516 CFDictionaryRef service_dict
;
1518 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1519 if (service_dict
!= NULL
) {
1520 ipv4_dict
= CFDictionaryGetValue(service_dict
, kSCEntNetIPv4
);
1523 if (ipv4_dict
!= NULL
) {
1524 CFMutableDictionaryRef dict
= NULL
;
1525 CFStringRef if_name
= NULL
;
1526 char ifn
[IFNAMSIZ
+ 1] = { '\0' };
1527 char * ifn_p
= NULL
;
1528 boolean_t is_direct
= FALSE
;
1529 struct in_addr local_ip
= { 0 };
1530 CFStringRef val_router
= NULL
;
1531 struct in_addr router
= { 0 };
1533 dict
= CFDictionaryCreateMutable(NULL
, 0,
1534 &kCFTypeDictionaryKeyCallBacks
,
1535 &kCFTypeDictionaryValueCallBacks
);
1536 val_router
= CFDictionaryGetValue(ipv4_dict
, kSCPropNetIPv4Router
);
1537 if (val_router
!= NULL
) {
1538 cfstring_to_ip(val_router
, &router
);
1539 CFDictionarySetValue(dict
, kSCPropNetIPv4Router
, val_router
);
1540 if (CFDictionaryContainsKey(ipv4_dict
, kRouterIsDirect
)) {
1544 CFStringRef local_ip_str
;
1546 local_ip_str
= CFDictionaryGetValue(ipv4_dict
,
1547 kRouterNeedsLocalIP
);
1548 if (local_ip_str
!= NULL
) {
1549 cfstring_to_ip(local_ip_str
, &local_ip
);
1556 addrs
= CFDictionaryGetValue(ipv4_dict
,
1557 kSCPropNetIPv4Addresses
);
1558 val_router
= CFArrayGetValueAtIndex(addrs
, 0);
1559 cfstring_to_ip(val_router
, &router
);
1562 if_name
= CFDictionaryGetValue(ipv4_dict
, kSCPropInterfaceName
);
1564 CFDictionarySetValue(dict
,
1565 kSCDynamicStorePropNetPrimaryInterface
,
1567 if (CFStringGetCString(if_name
, ifn
, sizeof(ifn
),
1568 kCFStringEncodingASCII
)) {
1572 CFDictionarySetValue(dict
, kSCDynamicStorePropNetPrimaryService
,
1574 keyChangeListSetValue(keys
, S_state_global_ipv4
, dict
);
1577 /* route add default ... */
1578 if (local_ip
.s_addr
!= 0) {
1581 m
.s_addr
= htonl(INADDR_BROADCAST
);
1582 ipv4_subnet_route_add(local_ip
, router
, m
, ifn_p
);
1583 set_ipv4_router(&local_ip
, ifn_p
, FALSE
);
1584 ipv4_default_route_change(router
, ifn_p
, FALSE
);
1585 S_router_subnet
= router
;
1586 S_router_subnet_mask
= m
;
1589 set_ipv4_router(&router
, ifn_p
, is_direct
);
1593 keyChangeListRemoveValue(keys
, S_state_global_ipv4
);
1594 set_ipv4_router(NULL
, NULL
, FALSE
);
1600 update_ipv6(SCDynamicStoreRef session
, CFDictionaryRef service_info
,
1601 CFStringRef primary
, keyChangeListRef keys
)
1603 CFDictionaryRef ipv6_dict
= NULL
;
1605 if (primary
!= NULL
) {
1606 CFDictionaryRef service_dict
;
1608 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1609 if (service_dict
!= NULL
) {
1610 ipv6_dict
= CFDictionaryGetValue(service_dict
, kSCEntNetIPv6
);
1613 if (ipv6_dict
!= NULL
) {
1615 CFMutableDictionaryRef dict
= NULL
;
1616 CFStringRef if_name
= NULL
;
1617 char ifn
[IFNAMSIZ
+ 1] = { '\0' };
1618 char * ifn_p
= NULL
;
1619 boolean_t is_direct
= FALSE
;
1620 CFStringRef val_router
= NULL
;
1622 dict
= CFDictionaryCreateMutable(NULL
, 0,
1623 &kCFTypeDictionaryKeyCallBacks
,
1624 &kCFTypeDictionaryValueCallBacks
);
1625 val_router
= CFDictionaryGetValue(ipv6_dict
, kSCPropNetIPv6Router
);
1626 addrs
= CFDictionaryGetValue(ipv6_dict
,
1627 kSCPropNetIPv6Addresses
);
1628 if (val_router
!= NULL
) {
1629 /* no router if router is one of our IP addresses */
1630 is_direct
= router_is_our_ipv6_address(val_router
, addrs
);
1631 CFDictionarySetValue(dict
, kSCPropNetIPv6Router
,
1635 val_router
= CFArrayGetValueAtIndex(addrs
, 0);
1638 if_name
= CFDictionaryGetValue(ipv6_dict
, kSCPropInterfaceName
);
1640 CFDictionarySetValue(dict
,
1641 kSCDynamicStorePropNetPrimaryInterface
,
1643 if (CFStringGetCString(if_name
, ifn
, sizeof(ifn
),
1644 kCFStringEncodingASCII
)) {
1648 CFDictionarySetValue(dict
, kSCDynamicStorePropNetPrimaryService
,
1650 keyChangeListSetValue(keys
, S_state_global_ipv6
, dict
);
1653 { /* route add default ... */
1654 struct in6_addr router
;
1656 (void)cfstring_to_ip6(val_router
, &router
);
1657 set_ipv6_router(&router
, ifn_p
, is_direct
);
1661 keyChangeListRemoveValue(keys
, S_state_global_ipv6
);
1662 set_ipv6_router(NULL
, NULL
, FALSE
);
1668 update_dns(SCDynamicStoreRef session
, CFDictionaryRef service_info
,
1669 CFStringRef primary
, keyChangeListRef keys
)
1671 CFDictionaryRef dict
= NULL
;
1673 if (primary
!= NULL
) {
1674 CFDictionaryRef service_dict
;
1676 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1677 if (service_dict
!= NULL
) {
1678 dict
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1683 keyChangeListRemoveValue(keys
, S_state_global_dns
);
1686 set_dns(CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
),
1687 CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
),
1688 CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
),
1689 CFDictionaryGetValue(dict
, kSCPropNetDNSSortList
));
1690 keyChangeListSetValue(keys
, S_state_global_dns
, dict
);
1696 update_dnsinfo(CFStringRef primary
, CFArrayRef service_order
, keyChangeListRef keys
)
1698 CFDictionaryRef dict
= NULL
;
1700 if (primary
!= NULL
) {
1701 CFDictionaryRef service_dict
;
1703 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1704 if (service_dict
!= NULL
) {
1705 dict
= CFDictionaryGetValue(service_dict
, kSCEntNetDNS
);
1709 /* update DNS configuration */
1710 dns_configuration_set(NULL
, NULL
, NULL
);
1713 /* update DNS configuration */
1714 dns_configuration_set(dict
, S_service_state_dict
, service_order
);
1716 keyChangeListNotifyKey(keys
, S_notify_dnsinfo
);
1721 update_netinfo(SCDynamicStoreRef session
, CFDictionaryRef service_info
,
1722 CFStringRef primary
, keyChangeListRef keys
)
1724 CFDictionaryRef dict
= NULL
;
1726 if (primary
!= NULL
) {
1727 CFDictionaryRef ipv4_dict
= NULL
;
1728 CFDictionaryRef service_dict
;
1729 CFDictionaryRef setup_dict
;
1730 CFStringRef state_key
;
1731 CFDictionaryRef state_dict
;
1733 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1734 if (service_dict
!= NULL
) {
1735 ipv4_dict
= CFDictionaryGetValue(service_dict
, kSCEntNetIPv4
);
1737 state_key
= state_service_key(primary
, kSCEntNetNetInfo
);
1738 state_dict
= my_CFDictionaryGetDictionary(service_info
, state_key
);
1739 if (state_dict
!= NULL
) {
1740 CFRetain(state_dict
);
1743 state_dict
= my_SCDCopy(session
, state_key
);
1745 setup_dict
= my_CFDictionaryGetDictionary(service_info
,
1746 S_setup_global_netinfo
);
1747 dict
= make_netinfo_dict(state_dict
, setup_dict
, ipv4_dict
);
1748 my_CFRelease(&state_key
);
1749 my_CFRelease(&state_dict
);
1752 empty_netinfo(session
);
1753 keyChangeListRemoveValue(keys
, S_state_global_netinfo
);
1757 keyChangeListSetValue(keys
, S_state_global_netinfo
, dict
);
1758 my_CFRelease(&dict
);
1764 update_proxies(SCDynamicStoreRef session
, CFDictionaryRef service_info
,
1765 CFStringRef primary
, keyChangeListRef keys
)
1767 CFDictionaryRef dict
= NULL
;
1769 if (primary
!= NULL
) {
1770 CFDictionaryRef service_dict
;
1771 service_dict
= CFDictionaryGetValue(S_service_state_dict
, primary
);
1772 if (service_dict
!= NULL
) {
1773 dict
= CFDictionaryGetValue(service_dict
, kSCEntNetProxies
);
1775 dict
= my_CFDictionaryGetDictionary(service_info
,
1776 S_setup_global_proxies
);
1781 keyChangeListRemoveValue(keys
, S_state_global_proxies
);
1784 keyChangeListSetValue(keys
, S_state_global_proxies
, dict
);
1790 get_service_rank(CFStringRef proto_key
, CFArrayRef order
, CFStringRef serviceID
)
1794 CFDictionaryRef proto_dict
;
1796 if (serviceID
== NULL
) {
1799 d
= CFDictionaryGetValue(S_service_state_dict
, serviceID
);
1804 proto_dict
= CFDictionaryGetValue(d
, proto_key
);
1806 CFStringRef if_name
;
1807 CFNumberRef override
= NULL
;
1809 if_name
= CFDictionaryGetValue(proto_dict
, kSCPropInterfaceName
);
1810 if (S_ppp_override_primary
== TRUE
1812 && CFStringHasPrefix(if_name
, CFSTR("ppp"))) {
1813 /* PPP override: make ppp* look the best */
1814 /* Hack: should use interface type, not interface name */
1817 /* check for the "OverridePrimary" property */
1818 override
= CFDictionaryGetValue(proto_dict
, kSCPropNetOverridePrimary
);
1819 if (isA_CFNumber(override
) != NULL
) {
1822 CFNumberGetValue(override
, kCFNumberIntType
, &val
);
1829 if (serviceID
!= NULL
&& order
!= NULL
) {
1830 CFIndex n
= CFArrayGetCount(order
);
1832 for (i
= 0; i
< n
; i
++) {
1833 CFStringRef s
= isA_CFString(CFArrayGetValueAtIndex(order
, i
));
1838 if (CFEqual(serviceID
, s
)) {
1849 ** Service election:
1851 typedef boolean_t (*routerCheckFunc
)(CFStringRef str
);
1854 check_ipv4_router(CFStringRef router
)
1858 return (cfstring_to_ip(router
, &ip
));
1862 check_ipv6_router(CFStringRef router
)
1864 struct in6_addr ip6
;
1866 return (cfstring_to_ip6(router
, &ip6
));
1869 struct election_state
{
1870 routerCheckFunc router_check
;
1871 CFStringRef proto_key
; /* e.g. kSCEntNetIPv4 */
1872 CFStringRef router_key
;/* e.g. kSCPropNetIPv4Router */
1874 CFStringRef new_primary
;
1875 boolean_t new_has_router
;
1876 unsigned int new_primary_index
;
1880 elect_protocol(const void * key
, const void * value
, void * context
)
1882 struct election_state
* elect_p
= (struct election_state
*)context
;
1883 CFDictionaryRef proto_dict
= NULL
;
1885 boolean_t router_valid
= FALSE
;
1886 CFStringRef serviceID
= (CFStringRef
)key
;
1887 CFDictionaryRef service_dict
= (CFDictionaryRef
)value
;
1888 unsigned int service_index
;
1890 proto_dict
= CFDictionaryGetValue(service_dict
, elect_p
->proto_key
);
1891 if (proto_dict
== NULL
) {
1894 router
= CFDictionaryGetValue(proto_dict
, elect_p
->router_key
);
1895 router_valid
= (*elect_p
->router_check
)(router
);
1896 if (router_valid
== FALSE
&& elect_p
->new_has_router
== TRUE
) {
1901 = get_service_rank(elect_p
->proto_key
, elect_p
->order
, serviceID
);
1902 if (elect_p
->new_primary
== NULL
1903 || service_index
< elect_p
->new_primary_index
1904 || (router_valid
&& elect_p
->new_has_router
== FALSE
)) {
1905 my_CFRelease(&elect_p
->new_primary
);
1906 elect_p
->new_primary
= CFRetain(serviceID
);
1907 elect_p
->new_primary_index
= service_index
;
1908 elect_p
->new_has_router
= router_valid
;
1914 elect_new_primary(CFArrayRef order
, CFStringRef proto_key
,
1915 CFStringRef router_key
)
1917 struct election_state elect
;
1919 if (CFEqual(proto_key
, kSCEntNetIPv4
)) {
1920 elect
.router_check
= check_ipv4_router
;
1922 else if (CFEqual(proto_key
, kSCEntNetIPv6
)) {
1923 elect
.router_check
= check_ipv6_router
;
1928 elect
.order
= order
;
1929 elect
.new_primary
= NULL
;
1930 elect
.new_primary_index
= 0;
1931 elect
.new_has_router
= FALSE
;
1932 elect
.proto_key
= proto_key
;
1933 elect
.router_key
= router_key
;
1934 CFDictionaryApplyFunction(S_service_state_dict
, elect_protocol
, &elect
);
1935 return (elect
.new_primary
);
1939 service_changed(CFDictionaryRef services_info
, CFStringRef serviceID
)
1941 uint32_t changed
= 0;
1944 for (i
= 0; i
< ENTITY_TYPES_COUNT
; i
++) {
1945 GetEntityChangesFuncRef func
= entityChangeFunc
[i
];
1946 if ((*func
)(serviceID
,
1947 get_service_state_entity(services_info
, serviceID
,
1948 entityTypeNames
[i
]),
1949 get_service_setup_entity(services_info
, serviceID
,
1950 entityTypeNames
[i
]),
1952 changed
|= (1 << i
);
1959 service_order_get(CFDictionaryRef services_info
)
1961 CFArrayRef order
= NULL
;
1962 CFNumberRef ppp_override
= NULL
;
1964 CFDictionaryRef ipv4_dict
= NULL
;
1966 ipv4_dict
= my_CFDictionaryGetDictionary(services_info
,
1967 S_setup_global_ipv4
);
1968 if (ipv4_dict
!= NULL
) {
1969 order
= CFDictionaryGetValue(ipv4_dict
, kSCPropNetServiceOrder
);
1970 order
= isA_CFArray(order
);
1972 /* get ppp override primary */
1973 ppp_override
= CFDictionaryGetValue(ipv4_dict
,
1974 kSCPropNetPPPOverridePrimary
);
1975 ppp_override
= isA_CFNumber(ppp_override
);
1976 if (ppp_override
!= NULL
) {
1977 CFNumberGetValue(ppp_override
, kCFNumberIntType
, &ppp_val
);
1979 S_ppp_override_primary
= (ppp_val
!= 0) ? TRUE
: FALSE
;
1982 S_ppp_override_primary
= TRUE
;
1988 set_new_primary(CFStringRef
* primary_p
, CFStringRef new_primary
,
1989 const char * entity
)
1991 boolean_t changed
= FALSE
;
1992 CFStringRef primary
= *primary_p
;
1994 if (new_primary
!= NULL
) {
1995 if (primary
!= NULL
&& CFEqual(new_primary
, primary
)) {
1996 SCLog(S_IPMonitor_debug
, LOG_INFO
,
1997 CFSTR("IPMonitor: %@ is still primary %s"),
1998 new_primary
, entity
);
2001 my_CFRelease(primary_p
);
2002 *primary_p
= CFRetain(new_primary
);
2003 SCLog(S_IPMonitor_debug
, LOG_INFO
,
2004 CFSTR("IPMonitor: %@ is the new primary %s"),
2005 new_primary
, entity
);
2009 else if (primary
!= NULL
) {
2010 SCLog(S_IPMonitor_debug
, LOG_INFO
,
2011 CFSTR("IPMonitor: %@ is no longer primary %s"), primary
, entity
);
2012 my_CFRelease(primary_p
);
2019 rank_service_entity(CFArrayRef order
, CFStringRef primary
,
2020 CFStringRef proto_key
, CFStringRef entity
)
2022 CFDictionaryRef dict
;
2023 dict
= service_dict_get(primary
, entity
);
2027 return (get_service_rank(proto_key
, order
, primary
));
2031 IPMonitorNotify(SCDynamicStoreRef session
, CFArrayRef changed_keys
,
2035 boolean_t dnsinfo_changed
= FALSE
;
2036 boolean_t global_ipv4_changed
= FALSE
;
2037 boolean_t global_ipv6_changed
= FALSE
;
2041 CFArrayRef service_order
;
2042 CFMutableArrayRef service_changes
= NULL
;
2043 CFDictionaryRef services_info
= NULL
;
2045 count
= CFArrayGetCount(changed_keys
);
2050 SCLog(S_IPMonitor_debug
, LOG_INFO
,
2051 CFSTR("IPMonitor: changes %@ (%d)"), changed_keys
, count
);
2053 keyChangeListInit(&keys
);
2054 service_changes
= CFArrayCreateMutable(NULL
, 0,
2055 &kCFTypeArrayCallBacks
);
2056 for (i
= 0; i
< count
; i
++) {
2057 CFStringRef change
= CFArrayGetValueAtIndex(changed_keys
, i
);
2058 if (CFEqual(change
, S_setup_global_ipv4
)) {
2059 global_ipv4_changed
= TRUE
;
2060 global_ipv6_changed
= TRUE
;
2062 else if (CFEqual(change
, S_setup_global_netinfo
)) {
2063 if (S_primary_ipv4
!= NULL
) {
2064 my_CFArrayAppendUniqueValue(service_changes
, S_primary_ipv4
);
2067 else if (CFEqual(change
, S_setup_global_proxies
)) {
2068 if (S_primary_proxies
!= NULL
) {
2069 my_CFArrayAppendUniqueValue(service_changes
, S_primary_proxies
);
2072 else if (CFStringHasPrefix(change
, S_state_service_prefix
)) {
2073 CFStringRef serviceID
= parse_component(change
,
2074 S_state_service_prefix
);
2076 my_CFArrayAppendUniqueValue(service_changes
, serviceID
);
2077 CFRelease(serviceID
);
2080 else if (CFStringHasPrefix(change
, S_setup_service_prefix
)) {
2081 CFStringRef serviceID
= parse_component(change
,
2082 S_setup_service_prefix
);
2084 my_CFArrayAppendUniqueValue(service_changes
, serviceID
);
2085 CFRelease(serviceID
);
2090 /* grab a snapshot of everything we need */
2091 services_info
= services_info_copy(session
, service_changes
);
2092 service_order
= service_order_get(services_info
);
2093 if (service_order
!= NULL
) {
2094 SCLog(S_IPMonitor_debug
, LOG_INFO
,
2095 CFSTR("IPMonitor: service_order %@ "), service_order
);
2097 n
= CFArrayGetCount(service_changes
);
2098 for (i
= 0; i
< n
; i
++) {
2100 CFStringRef serviceID
;
2101 Boolean wasSupplemental
;
2103 serviceID
= CFArrayGetValueAtIndex(service_changes
, i
);
2104 wasSupplemental
= dns_has_supplemental(serviceID
);
2105 changes
= service_changed(services_info
, serviceID
);
2107 if (S_primary_ipv4
!= NULL
&& CFEqual(S_primary_ipv4
, serviceID
)) {
2108 if ((changes
& (1 << kEntityTypeIPv4
)) != 0) {
2109 update_ipv4(session
, services_info
, serviceID
, &keys
);
2110 global_ipv4_changed
= TRUE
;
2112 if ((changes
& (1 << kEntityTypeNetInfo
)) != 0) {
2113 update_netinfo(session
, services_info
, serviceID
, &keys
);
2116 else if ((changes
& (1 << kEntityTypeIPv4
)) != 0) {
2117 global_ipv4_changed
= TRUE
;
2119 if ((changes
& (1 << kEntityTypeIPv6
)) != 0) {
2120 if (S_primary_ipv6
!= NULL
&& CFEqual(S_primary_ipv6
, serviceID
)) {
2121 update_ipv6(session
, services_info
, serviceID
, &keys
);
2123 global_ipv6_changed
= TRUE
;
2125 if ((changes
& (1 << kEntityTypeDNS
)) != 0) {
2126 if (S_primary_dns
!= NULL
&& CFEqual(S_primary_dns
, serviceID
)) {
2127 update_dns(session
, services_info
, serviceID
, &keys
);
2128 dnsinfo_changed
= TRUE
;
2130 else if (wasSupplemental
|| dns_has_supplemental(serviceID
)) {
2131 dnsinfo_changed
= TRUE
;
2134 if ((changes
& (1 << kEntityTypeProxies
)) != 0) {
2135 if (S_primary_proxies
!= NULL
&& CFEqual(S_primary_proxies
, serviceID
)) {
2136 update_proxies(session
, services_info
, serviceID
, &keys
);
2141 if (global_ipv4_changed
) {
2142 CFStringRef new_primary
;
2144 SCLog(S_IPMonitor_debug
, LOG_INFO
,
2145 CFSTR("IPMonitor: IPv4 service election"));
2146 new_primary
= elect_new_primary(service_order
,
2147 kSCEntNetIPv4
, kSCPropNetIPv4Router
);
2148 if (set_new_primary(&S_primary_ipv4
, new_primary
, "IPv4")) {
2149 update_ipv4(session
, services_info
, S_primary_ipv4
, &keys
);
2150 update_netinfo(session
, services_info
, S_primary_ipv4
, &keys
);
2152 my_CFRelease(&new_primary
);
2154 if (global_ipv6_changed
) {
2155 CFStringRef new_primary
;
2157 SCLog(S_IPMonitor_debug
, LOG_INFO
,
2158 CFSTR("IPMonitor: IPv6 service election"));
2159 new_primary
= elect_new_primary(service_order
,
2160 kSCEntNetIPv6
, kSCPropNetIPv6Router
);
2161 if (set_new_primary(&S_primary_ipv6
, new_primary
, "IPv6")) {
2162 update_ipv6(session
, services_info
, S_primary_ipv6
, &keys
);
2164 my_CFRelease(&new_primary
);
2166 if (global_ipv4_changed
|| global_ipv6_changed
) {
2167 CFStringRef new_primary_dns
;
2168 CFStringRef new_primary_proxies
;
2170 if (S_primary_ipv4
!= NULL
&& S_primary_ipv6
!= NULL
) {
2171 /* decide between IPv4 and IPv6 */
2172 if (rank_service_entity(service_order
, S_primary_ipv4
,
2173 kSCEntNetIPv4
, kSCEntNetDNS
)
2174 <= rank_service_entity(service_order
, S_primary_ipv6
,
2175 kSCEntNetIPv6
, kSCEntNetDNS
)) {
2176 new_primary_dns
= S_primary_ipv4
;
2179 new_primary_dns
= S_primary_ipv6
;
2181 if (rank_service_entity(service_order
, S_primary_ipv4
,
2182 kSCEntNetIPv4
, kSCEntNetProxies
)
2183 <= rank_service_entity(service_order
, S_primary_ipv6
,
2184 kSCEntNetIPv6
, kSCEntNetProxies
)) {
2185 new_primary_proxies
= S_primary_ipv4
;
2188 new_primary_proxies
= S_primary_ipv6
;
2192 else if (S_primary_ipv6
!= NULL
) {
2193 new_primary_dns
= new_primary_proxies
= S_primary_ipv6
;
2195 else if (S_primary_ipv4
!= NULL
) {
2196 new_primary_dns
= new_primary_proxies
= S_primary_ipv4
;
2199 new_primary_dns
= new_primary_proxies
= NULL
;
2202 if (set_new_primary(&S_primary_dns
, new_primary_dns
, "DNS")) {
2203 update_dns(session
, services_info
, S_primary_dns
, &keys
);
2204 dnsinfo_changed
= TRUE
;
2206 if (set_new_primary(&S_primary_proxies
, new_primary_proxies
, "Proxies")) {
2207 update_proxies(session
, services_info
, S_primary_proxies
, &keys
);
2210 if (dnsinfo_changed
) {
2211 update_dnsinfo(S_primary_dns
, service_order
, &keys
);
2213 my_CFRelease(&service_changes
);
2214 my_CFRelease(&services_info
);
2215 keyChangeListApplyToStore(&keys
, session
);
2216 keyChangeListFree(&keys
);
2221 initEntityNames(void)
2223 entityTypeNames
[0] = kSCEntNetIPv4
; /* 0 */
2224 entityTypeNames
[1] = kSCEntNetIPv6
; /* 1 */
2225 entityTypeNames
[2] = kSCEntNetDNS
; /* 2 */
2226 entityTypeNames
[3] = kSCEntNetNetInfo
; /* 3 */
2227 entityTypeNames
[4] = kSCEntNetProxies
; /* 4 */
2236 CFMutableArrayRef keys
= NULL
;
2237 CFMutableArrayRef patterns
= NULL
;
2238 CFRunLoopSourceRef rls
= NULL
;
2239 SCDynamicStoreRef session
= NULL
;
2242 if (S_netboot_root() != 0) {
2245 session
= SCDynamicStoreCreate(NULL
, CFSTR("IPMonitor"),
2246 IPMonitorNotify
, NULL
);
2247 if (session
== NULL
) {
2248 SCLog(TRUE
, LOG_ERR
,
2249 CFSTR("IPMonitor ip_plugin_init SCDynamicStoreCreate failed: %s"),
2250 SCErrorString(SCError()));
2254 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2255 kSCDynamicStoreDomainState
,
2258 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2259 kSCDynamicStoreDomainState
,
2262 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2263 kSCDynamicStoreDomainState
,
2265 S_state_global_netinfo
2266 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2267 kSCDynamicStoreDomainState
,
2269 S_state_global_proxies
2270 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2271 kSCDynamicStoreDomainState
,
2274 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2275 kSCDynamicStoreDomainSetup
,
2277 S_setup_global_netinfo
2278 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2279 kSCDynamicStoreDomainSetup
,
2281 S_setup_global_proxies
2282 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2283 kSCDynamicStoreDomainSetup
,
2285 S_state_service_prefix
2286 = SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@/"),
2287 kSCDynamicStoreDomainState
,
2290 S_setup_service_prefix
2291 = SCDynamicStoreKeyCreate(NULL
, CFSTR("%@/%@/%@/"),
2292 kSCDynamicStoreDomainSetup
,
2295 S_service_state_dict
2296 = CFDictionaryCreateMutable(NULL
, 0,
2297 &kCFTypeDictionaryKeyCallBacks
,
2298 &kCFTypeDictionaryValueCallBacks
);
2300 key
= CFStringCreateWithCString(NULL
,
2301 dns_configuration_notify_key(),
2302 kCFStringEncodingASCII
);
2303 S_notify_dnsinfo
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("Notify:%@"), key
);
2306 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2307 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2309 /* register for State: and Setup: per-service notifications */
2310 for (i
= 0; i
< ENTITY_TYPES_COUNT
; i
++) {
2311 key
= state_service_key(kSCCompAnyRegex
, entityTypeNames
[i
]);
2312 CFArrayAppendValue(patterns
, key
);
2314 key
= setup_service_key(kSCCompAnyRegex
, entityTypeNames
[i
]);
2315 CFArrayAppendValue(patterns
, key
);
2319 /* add notifier for setup global netinfo */
2320 CFArrayAppendValue(keys
, S_setup_global_netinfo
);
2322 /* add notifier for ServiceOrder/PPPOverridePrimary changes for IPv4 */
2323 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
2324 kSCDynamicStoreDomainSetup
,
2326 CFArrayAppendValue(keys
, key
);
2329 if (!SCDynamicStoreSetNotificationKeys(session
, keys
, patterns
)) {
2330 SCLog(TRUE
, LOG_ERR
,
2331 CFSTR("IPMonitor ip_plugin_init "
2332 "SCDynamicStoreSetNotificationKeys failed: %s"),
2333 SCErrorString(SCError()));
2337 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, session
, 0);
2339 SCLog(TRUE
, LOG_ERR
,
2340 CFSTR("IPMonitor ip_plugin_init "
2341 "SCDynamicStoreCreateRunLoopSource failed: %s"),
2342 SCErrorString(SCError()));
2346 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
2349 /* initialize dns configuration */
2350 dns_configuration_set(NULL
, NULL
, NULL
);
2352 (void)SCDynamicStoreRemoveValue(session
, S_state_global_dns
);
2354 /* initialize netinfo state */
2355 empty_netinfo(session
);
2356 (void)SCDynamicStoreRemoveValue(session
, S_state_global_netinfo
);
2359 my_CFRelease(&keys
);
2360 my_CFRelease(&patterns
);
2361 my_CFRelease(&session
);
2369 /* initialize multicast route */
2370 set_ipv4_router(NULL
, NULL
, FALSE
);
2375 load_IPMonitor(CFBundleRef bundle
, Boolean bundleVerbose
)
2377 if (bundleVerbose
) {
2378 S_IPMonitor_debug
= 1;
2381 dns_configuration_init(bundle
);
2384 load_hostname(S_IPMonitor_debug
);
2392 #include "dns-configuration.c"
2393 #include "set-hostname.c"
2396 main(int argc
, char **argv
)
2399 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
2401 load_IPMonitor(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);