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