]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/ip_plugin.c
configd-888.1.2.tar.gz
[apple/configd.git] / Plugins / IPMonitor / ip_plugin.c
1 /*
2 * Copyright (c) 2000-2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * ip_plugin.c
26 * - decides which interface will be made the "primary" interface,
27 * that is, the one with the default route assigned
28 */
29
30 /*
31 * Modification History
32 *
33 * July 19, 2000 Dieter Siegmund (dieter@apple.com)
34 * - initial revision
35 *
36 * November 15, 2000 Dieter Siegmund (dieter@apple.com)
37 * - changed to use new configuration model
38 *
39 * March 19, 2001 Dieter Siegmund (dieter@apple.com)
40 * - use service state instead of interface state
41 *
42 * July 16, 2001 Allan Nathanson (ajn@apple.com)
43 * - update to public SystemConfiguration.framework APIs
44 *
45 * August 28, 2001 Dieter Siegmund (dieter@apple.com)
46 * - specify the interface name when installing the default route
47 * - this ensures that default traffic goes to the highest priority
48 * service when multiple interfaces are configured to be on the same subnet
49 *
50 * September 16, 2002 Dieter Siegmund (dieter@apple.com)
51 * - don't elect a link-local service to be primary unless it's the only
52 * one that's available
53 *
54 * July 16, 2003 Dieter Siegmund (dieter@apple.com)
55 * - modifications to support IPv6
56 * - don't elect a service to be primary if it doesn't have a default route
57 *
58 * July 29, 2003 Dieter Siegmund (dieter@apple.com)
59 * - support installing a default route to a router that's not on our subnet
60 *
61 * March 22, 2004 Allan Nathanson (ajn@apple.com)
62 * - create expanded DNS configuration
63 *
64 * June 20, 2006 Allan Nathanson (ajn@apple.com)
65 * - add SMB configuration
66 *
67 * December 5, 2007 Dieter Siegmund (dieter@apple.com)
68 * - added support for multiple scoped routes
69 *
70 * November 13, 2013 Dieter Siegmund (dieter@apple.com)
71 * - added generic IPv4 routing support
72 */
73
74 #include <stdlib.h>
75 #include <unistd.h>
76 #include <string.h>
77 #include <stdio.h>
78 #include <sys/fcntl.h>
79 #include <sys/ioctl.h>
80 #include <sys/types.h>
81 #include <sys/socket.h>
82 #include <net/route.h>
83 #include <net/if.h>
84 #include <net/if_dl.h>
85 #include <netinet/in.h>
86 #include <netinet/icmp6.h>
87 #include <netinet6/in6_var.h>
88 #include <netinet6/nd6.h>
89 #include <network/sa_compare.h>
90 #include <arpa/inet.h>
91 #include <sys/sysctl.h>
92 #include <limits.h>
93 #include <notify.h>
94 #include <mach/mach_time.h>
95 #include <dispatch/dispatch.h>
96 #include <CommonCrypto/CommonDigest.h>
97
98 #include <SystemConfiguration/SystemConfiguration.h>
99 #include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
100 #include <SystemConfiguration/SCValidation.h>
101 #include <SystemConfiguration/scprefs_observer.h>
102 #include <SystemConfiguration/SCPrivate.h>
103 #include "SCNetworkReachabilityInternal.h"
104 #include "SCNetworkSignaturePrivate.h"
105 #include <dnsinfo.h>
106 #include "dnsinfo_server.h"
107
108 #include <ppp/PPPControllerPriv.h>
109
110 #include <dns_sd.h>
111 #include <dns_sd_private.h>
112
113 #include <network_information.h>
114 #include "network_state_information_priv.h"
115 #include "network_information_server.h"
116 #include <ppp/ppp_msg.h>
117 #include "ip_plugin.h"
118 #if !TARGET_OS_SIMULATOR
119 #include "set-hostname.h"
120 #endif /* !TARGET_OS_SIMULATOR */
121
122 #include "dns-configuration.h"
123 #include "proxy-configuration.h"
124
125 #if !TARGET_OS_SIMULATOR
126 #include "agent-monitor.h"
127 #endif // !TARGET_OS_SIMULATOR
128
129 #if !TARGET_OS_IPHONE
130 #include "smb-configuration.h"
131 #endif /* !TARGET_OS_IPHONE */
132
133 #define kLoopbackInterface "lo0"
134 #define EROUTENOTAPPLIED 1001
135
136 typedef CF_ENUM(uint8_t, ProtocolFlags) {
137 kProtocolFlagsNone = 0x0,
138 kProtocolFlagsIPv4 = 0x1,
139 kProtocolFlagsIPv6 = 0x2
140 };
141
142 enum {
143 kDebugFlag1 = 0x00000001,
144 kDebugFlag2 = 0x00000002,
145 kDebugFlag4 = 0x00000004,
146 kDebugFlag8 = 0x00000008,
147 kDebugFlagDefault = kDebugFlag1,
148 kDebugFlagAll = 0xffffffff
149 };
150
151 typedef unsigned int IFIndex;
152
153
154 #pragma mark -
155 #pragma mark Logging
156
157
158 __private_extern__ os_log_t
159 __log_IPMonitor()
160 {
161 static os_log_t log = NULL;
162
163 if (log == NULL) {
164 log = os_log_create("com.apple.SystemConfiguration", "IPMonitor");
165 }
166
167 return log;
168 }
169
170
171 #pragma mark -
172 #pragma mark interface index
173
174
175 #ifndef TEST_ROUTELIST
176
177 #define ROUTELIST_DEBUG(flag, fmt, ...)
178
179 static struct if_nameindex * S_if_nameindex_cache;
180
181 __private_extern__ IFIndex
182 my_if_nametoindex(const char * ifname)
183 {
184 IFIndex idx = 0;
185 struct if_nameindex * scan;
186
187 if (S_if_nameindex_cache == NULL) {
188 return (if_nametoindex(ifname));
189 }
190 for (scan = S_if_nameindex_cache;
191 scan->if_index != 0 && scan->if_name != NULL;
192 scan++) {
193 if (strcmp(scan->if_name, ifname) == 0) {
194 idx = scan->if_index;
195 break;
196 }
197 }
198 return (idx);
199 }
200
201 __private_extern__ const char *
202 my_if_indextoname(IFIndex idx, char if_name[IFNAMSIZ])
203 {
204 const char * name = NULL;
205 struct if_nameindex * scan;
206
207 if (S_if_nameindex_cache == NULL) {
208 return (if_indextoname(idx, if_name));
209 }
210 for (scan = S_if_nameindex_cache;
211 scan->if_index != 0 && scan->if_name != NULL;
212 scan++) {
213 if (scan->if_index == idx) {
214 name = if_name;
215 strlcpy(if_name, scan->if_name, IFNAMSIZ);
216 break;
217 }
218 }
219 return (name);
220 }
221
222 static void
223 my_if_freenameindex(void)
224 {
225 if (S_if_nameindex_cache != NULL) {
226 if_freenameindex(S_if_nameindex_cache);
227 S_if_nameindex_cache = NULL;
228 }
229 return;
230 }
231
232 static void
233 my_if_nameindex(void)
234 {
235 my_if_freenameindex();
236 S_if_nameindex_cache = if_nameindex();
237 return;
238 }
239
240
241 #else /* TEST_ROUTELIST */
242
243 #define ROUTELIST_DEBUG(flags, format, ...) { if (((S_IPMonitor_debug & (flags)) != 0)) printf((format), ## __VA_ARGS__ ); }
244
245
246 static const char * * list;
247 static int list_count;
248 static int list_size;
249
250 __private_extern__ IFIndex
251 my_if_nametoindex(const char * ifname)
252 {
253 IFIndex ret;
254
255 if (list == NULL) {
256 list_size = 4;
257 list_count = 2;
258 list = (const char * *)malloc(sizeof(*list) * list_size);
259 list[0] = strdup("");
260 list[1] = strdup(kLoopbackInterface);
261 }
262 else {
263 int i;
264
265 for (i = 1; i < list_count; i++) {
266 if (strcmp(list[i], ifname) == 0) {
267 ret = i;
268 goto done;
269 }
270 }
271 }
272 if (list_count == list_size) {
273 list_size += 2;
274 list = (const char * *)realloc(list, sizeof(*list) * list_size);
275 }
276 list[list_count] = strdup(ifname);
277 ret = list_count;
278 list_count++;
279 done:
280 return (ret);
281 }
282
283 __private_extern__ const char *
284 my_if_indextoname(IFIndex idx, char if_name[IFNAMSIZ])
285 {
286 const char * name = NULL;
287
288 if (idx < list_count) {
289 name = if_name;
290 strlcpy(if_name, list[idx], IFNAMSIZ);
291 }
292 return (name);
293 }
294
295 static void
296 my_if_nameindex(void)
297 {
298 }
299
300 static void
301 my_if_freenameindex(void)
302 {
303 }
304
305 #endif /* TEST_ROUTELIST */
306
307 static const char *
308 my_if_indextoname2(IFIndex ifindex, char ifname[IFNAMSIZ])
309 {
310 if (ifindex == 0) {
311 return (NULL);
312 }
313 if (my_if_indextoname(ifindex, ifname) == NULL) {
314 snprintf(ifname, IFNAMSIZ, "[%d]", ifindex);
315 }
316 return (ifname);
317 }
318
319
320 static IFIndex
321 lo0_ifindex(void)
322 {
323 static IFIndex idx;
324
325 if (idx == 0) {
326 idx = my_if_nametoindex(kLoopbackInterface);
327 }
328 return (idx);
329 }
330
331
332 #pragma mark -
333
334
335 /*
336 * Property: kServiceOptionRankAssertion
337 * Purpose:
338 * Key used in the service options dictionary to hold the RankAssertion
339 * derived from the kSCPropNetServicePrimaryRank string.
340 */
341 #define kServiceOptionRankAssertion CFSTR("RankAssertion") /* number */
342
343 /*
344 * Property: kIPIsCoupled
345 * Purpose:
346 * Used to indicate that the IPv4 and IPv6 services are coupled.
347 * Neither the IPv4 part nor the IPv6 part of a coupled service
348 * may become primary if IPv4 or IPv6 is primary for another interface.
349 *
350 * For example, if the service over en3 is "coupled" and has IPv6,
351 * and en0 is primary for just IPv4, IPv6 over en3 is not eligible
352 * to become primary for IPv6.
353 */
354 #define kIPIsCoupled CFSTR("IPIsCoupled")
355
356 #define PPP_PREFIX "ppp"
357
358 #define IP_FORMAT "%d.%d.%d.%d"
359 #define IP_CH(ip) ((u_char *)(ip))
360 #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
361
362 static SCLoggerRef S_IPMonitor_logger;
363
364 static Boolean S_bundle_logging_verbose;
365
366 /*
367 * IPv4 Route management
368 */
369
370 typedef CF_ENUM(uint16_t, RouteFlags) {
371 kRouteFlagsIsScoped = 0x0001,
372 kRouteFlagsHasGateway = 0x0002,
373 kRouteFlagsIsHost = 0x0004,
374 kRouteFlagsIsNULL = 0x0008,
375 kRouteFlagsKernelManaged = 0x0010
376 };
377
378 typedef CF_ENUM(uint16_t, ControlFlags) {
379 kControlFlagsProcessed = 0x0001,
380 kControlFlagsAdded = 0x0002,
381 };
382
383 #define ROUTE_COMMON \
384 int prefix_length; \
385 IFIndex ifindex; \
386 IFIndex exclude_ifindex; \
387 Rank rank; \
388 RouteFlags flags; \
389 ControlFlags control_flags;
390
391 typedef struct {
392 ROUTE_COMMON
393 } Route, * RouteRef;
394
395 #define PREFIX_LENGTH_IN_CLASSC 24
396 #define PREFIX_LENGTH_IN_CLASSD 4
397
398 typedef struct {
399 ROUTE_COMMON
400 struct in_addr dest;
401 struct in_addr mask;
402 struct in_addr gateway;
403 struct in_addr ifa;
404 } IPv4Route, * IPv4RouteRef;
405
406 typedef struct {
407 ROUTE_COMMON
408 struct in6_addr dest;
409 struct in6_addr gateway;
410 struct in6_addr ifa;
411 } IPv6Route, * IPv6RouteRef;
412
413 typedef CF_ENUM(uint16_t, RouteListFlags) {
414 kRouteListFlagsExcludeNWI = 0x0001,
415 kRouteListFlagsHasDefault = 0x0002,
416 kRouteListFlagsScopedOnly = 0x0004
417 };
418
419 #define ROUTELIST_COMMON \
420 int count; \
421 int size; \
422 RouteListFlags flags;
423
424 typedef struct {
425 ROUTELIST_COMMON
426 } RouteListCommon, * RouteListRef;
427
428 typedef struct {
429 ROUTELIST_COMMON
430 IPv4Route list[1]; /* variable length */
431 } IPv4RouteList, * IPv4RouteListRef;
432
433 typedef struct {
434 ROUTELIST_COMMON
435 IPv6Route list[1]; /* variable length */
436 } IPv6RouteList, * IPv6RouteListRef;
437
438 typedef union {
439 void * ptr;
440 RouteListRef common;
441 IPv4RouteListRef v4;
442 IPv6RouteListRef v6;
443 } RouteListUnion;
444
445 typedef enum {
446 kRouteCommandAdd,
447 kRouteCommandRemove
448 } RouteCommand;
449
450 /*
451 * Election Information
452 * - information about the current best services
453 */
454 typedef union {
455 struct in_addr v4;
456 struct in6_addr v6;
457 } in_addr;
458
459 typedef union {
460 struct sockaddr_in v4;
461 struct sockaddr_in6 v6;
462 } in_sockaddr;
463
464 typedef struct Candidate {
465 CFStringRef serviceID;
466 CFStringRef if_name;
467 Rank rank;
468 boolean_t ip_is_coupled;
469 boolean_t ineligible;
470 SCNetworkReachabilityFlags reachability_flags;
471 in_addr addr;
472 in_sockaddr vpn_server_addr;
473 CFStringRef signature;
474 } Candidate, * CandidateRef;
475
476 typedef struct ElectionResults {
477 int af;
478 int count;
479 int size;
480 Candidate candidates[1];
481 } ElectionResults, * ElectionResultsRef;
482
483 static __inline__ size_t
484 ElectionResultsComputeSize(unsigned int n)
485 {
486 return (offsetof(ElectionResults, candidates[n]));
487 }
488
489 /*
490 * Type: Rank
491 * Purpose:
492 * A 32-bit value to encode the relative rank of a service.
493 *
494 * The top 8 bits are used to hold the rank assertion (first, default, last,
495 * never, scoped);
496 *
497 * The bottom 24 bits are used to store the service index (i.e. the
498 * position within the service order array).
499 */
500 #define RANK_ASSERTION_MAKE(r) ((Rank)(r) << 24)
501 #define kRankAssertionFirst RANK_ASSERTION_MAKE(0)
502 #define kRankAssertionDefault RANK_ASSERTION_MAKE(1)
503 #define kRankAssertionLast RANK_ASSERTION_MAKE(2)
504 #define kRankAssertionNever RANK_ASSERTION_MAKE(3)
505 #define kRankAssertionScoped RANK_ASSERTION_MAKE(4)
506 #define kRankAssertionMask RANK_ASSERTION_MAKE(0xff)
507 #define RANK_ASSERTION_MASK(r) ((Rank)(r) & kRankAssertionMask)
508 #define RANK_ASSERTION_GET(r) ((Rank)(r) >> 24)
509 #define RANK_INDEX_MAKE(r) ((Rank)(r))
510 #define kRankIndexMask RANK_INDEX_MAKE(0xffffff)
511 #define RANK_INDEX_MASK(r) ((Rank)(r) & kRankIndexMask)
512
513 static __inline__ Rank
514 RankMake(uint32_t service_index, Rank primary_rank)
515 {
516 return (RANK_INDEX_MASK(service_index) | RANK_ASSERTION_MASK(primary_rank));
517 }
518
519 static Rank
520 InterfaceRankGetRankAssertion(CFNumberRef rank_cf, Boolean * ret_is_set)
521 {
522 SCNetworkServicePrimaryRank if_rank;
523 Boolean is_set = FALSE;
524 Rank rank = kRankAssertionDefault;
525
526 if (rank_cf != NULL
527 && CFNumberGetValue(rank_cf, kCFNumberSInt32Type, &if_rank)
528 && if_rank != kSCNetworkServicePrimaryRankDefault) {
529 if (if_rank == kSCNetworkServicePrimaryRankFirst) {
530 rank = kRankAssertionFirst;
531 }
532 else {
533 rank = RANK_ASSERTION_MAKE(if_rank);
534 }
535 is_set = TRUE;
536 }
537 if (ret_is_set != NULL) {
538 *ret_is_set = is_set;
539 }
540 return (rank);
541 }
542
543 static Rank
544 PrimaryRankGetRankAssertion(CFStringRef rank_str, Boolean * is_set)
545 {
546 int i;
547 struct {
548 const CFStringRef * name;
549 Rank rank_assertion;
550 } values[] = {
551 { &kSCValNetServicePrimaryRankFirst, kRankAssertionFirst },
552 { &kSCValNetServicePrimaryRankLast, kRankAssertionLast },
553 { &kSCValNetServicePrimaryRankNever, kRankAssertionNever },
554 { &kSCValNetServicePrimaryRankScoped, kRankAssertionScoped }
555 };
556
557 if (rank_str != NULL) {
558 for (i = 0; i < countof(values); i++) {
559 if (CFEqual(rank_str, *(values[i].name))) {
560 if (is_set != NULL) {
561 *is_set = TRUE;
562 }
563 return (values[i].rank_assertion);
564 }
565 }
566 }
567 if (is_set != NULL) {
568 *is_set = FALSE;
569 }
570 return (kRankAssertionDefault);
571 }
572
573 /* SCDynamicStore session */
574 static SCDynamicStoreRef S_session = NULL;
575
576 /* debug output flags */
577 static uint32_t S_IPMonitor_debug = 0;
578 static Boolean S_IPMonitor_verbose = FALSE;
579
580 /* are we netbooted? If so, don't touch the default route */
581 static boolean_t S_netboot = FALSE;
582
583 /* dictionary to hold per-service state: key is the serviceID */
584 static CFMutableDictionaryRef S_service_state_dict = NULL;
585 static CFMutableDictionaryRef S_ipv4_service_rank_dict = NULL;
586 static CFMutableDictionaryRef S_ipv6_service_rank_dict = NULL;
587
588 /* dictionary to hold per-interface rank information */
589 static CFDictionaryRef S_if_rank_dict;
590
591 /* if set, a PPP interface overrides the primary */
592 static boolean_t S_ppp_override_primary = FALSE;
593
594 /* the current primary serviceID's */
595 static CFStringRef S_primary_ipv4 = NULL;
596 static CFStringRef S_primary_ipv6 = NULL;
597 static CFStringRef S_primary_dns = NULL;
598 static CFStringRef S_primary_proxies = NULL;
599
600 /* the current election results */
601 static ElectionResultsRef S_ipv4_results;
602 static ElectionResultsRef S_ipv6_results;
603
604 static CFStringRef S_state_global_ipv4 = NULL;
605 static CFStringRef S_state_global_ipv6 = NULL;
606 static CFStringRef S_state_global_dns = NULL;
607 static CFStringRef S_state_global_proxies = NULL;
608 static CFStringRef S_state_service_prefix = NULL;
609 static CFStringRef S_setup_global_ipv4 = NULL;
610 static CFStringRef S_setup_service_prefix = NULL;
611
612 static CFStringRef S_multicast_resolvers = NULL;
613 static CFStringRef S_private_resolvers = NULL;
614
615 #if !TARGET_OS_SIMULATOR
616 static IPv4RouteListRef S_ipv4_routelist = NULL;
617 static IPv6RouteListRef S_ipv6_routelist = NULL;
618
619 #endif /* !TARGET_OS_SIMULATOR */
620
621 static boolean_t S_append_state = FALSE;
622
623 static CFDictionaryRef S_dns_dict = NULL;
624
625 static Boolean S_dnsinfo_synced = TRUE;
626
627 static nwi_state_t S_nwi_state = NULL;
628 static Boolean S_nwi_synced = TRUE;
629
630 static CFDictionaryRef S_proxies_dict = NULL;
631
632 // Note: access should be gated with __network_change_queue()
633 static uint32_t S_network_change_needed = 0;
634 #define NETWORK_CHANGE_NET 1<<0
635 #define NETWORK_CHANGE_DNS 1<<1
636 #define NETWORK_CHANGE_PROXY 1<<2
637 #if !TARGET_OS_IPHONE
638 #define NETWORK_CHANGE_SMB 1<<3
639 #endif /* !TARGET_OS_IPHONE */
640 static struct timeval S_network_change_start;
641 static Boolean S_network_change_timeout = FALSE;
642 static dispatch_source_t S_network_change_timer = NULL;
643
644 #if !TARGET_OS_IPHONE
645 static CFStringRef S_primary_smb = NULL;
646 static CFStringRef S_state_global_smb = NULL;
647 static CFDictionaryRef S_smb_dict = NULL;
648 #endif /* !TARGET_OS_IPHONE */
649
650 #if !TARGET_OS_IPHONE
651 #define VAR_RUN_RESOLV_CONF "/var/run/resolv.conf"
652 #endif /* !TARGET_OS_IPHONE */
653
654 #ifndef KERN_NETBOOT
655 #define KERN_NETBOOT 40 /* int: are we netbooted? 1=yes,0=no */
656 #endif /* KERN_NETBOOT */
657
658 /**
659 ** entityType*, GetEntityChanges*
660 ** - definitions for the entity types we handle
661 **/
662 typedef enum {
663 kEntityTypeIPv4 = 0,
664 kEntityTypeIPv6,
665 kEntityTypeDNS,
666 kEntityTypeProxies,
667 #if !TARGET_OS_IPHONE
668 kEntityTypeSMB,
669 #endif /* !TARGET_OS_IPHONE */
670 ENTITY_TYPES_COUNT,
671 kEntityTypeTransientStatus,
672 kEntityTypeServiceOptions = 31
673 } EntityType;
674
675 static const CFStringRef *entityTypeNames[ENTITY_TYPES_COUNT] = {
676 &kSCEntNetIPv4, /* 0 */
677 &kSCEntNetIPv6, /* 1 */
678 &kSCEntNetDNS, /* 2 */
679 &kSCEntNetProxies, /* 3 */
680 #if !TARGET_OS_IPHONE
681 &kSCEntNetSMB, /* 4 */
682 #endif /* !TARGET_OS_IPHONE */
683 };
684
685 static Boolean
686 S_dict_get_boolean(CFDictionaryRef dict, CFStringRef key, Boolean def_value);
687
688 static __inline__ char
689 ipvx_char(int af)
690 {
691 return ((af == AF_INET) ? '4' : '6');
692 }
693
694 static __inline__ char
695 ipvx_other_char(int af)
696 {
697 return ((af == AF_INET) ? '6' : '4');
698 }
699
700 /*
701 * IPv4/IPv6 Service Dict keys: kIPDictRoutes, IPDictService
702 *
703 * The IPv4/IPv6 service dictionary contains two sub-dictionaries:
704 * Routes CFData containing IPv4RouteList/IPv6RouteList
705 * Service dictionary containing kSCEntNetIPv[46] service entity
706 */
707 #define kIPDictRoutes CFSTR("Routes") /* data */
708 #define kIPDictService CFSTR("Service") /* dict */
709
710 static CFDictionaryRef
711 ipdict_create(CFDictionaryRef dict, CFDataRef routes_data)
712 {
713 CFStringRef keys[2];
714 CFTypeRef values[2];
715
716 keys[0] = kIPDictService;
717 values[0] = dict;
718 keys[1] = kIPDictRoutes;
719 values[1] = routes_data;
720 return (CFDictionaryCreate(NULL,
721 (const void * *)keys,
722 values,
723 countof(keys),
724 &kCFTypeDictionaryKeyCallBacks,
725 &kCFTypeDictionaryValueCallBacks));
726 }
727
728 static void *
729 ipdict_get_routelist(CFDictionaryRef dict)
730 {
731 void * routes_list = NULL;
732
733 if (dict != NULL) {
734 CFDataRef routes;
735
736 routes = CFDictionaryGetValue(dict, kIPDictRoutes);
737 if (routes != NULL) {
738 routes_list = (void *)CFDataGetBytePtr(routes);
739 }
740 }
741 return (routes_list);
742 }
743
744 static CFDictionaryRef
745 ipdict_get_service(CFDictionaryRef dict)
746 {
747 CFDictionaryRef ip_dict = NULL;
748
749 if (dict != NULL) {
750 ip_dict = CFDictionaryGetValue(dict, kIPDictService);
751 }
752 return (ip_dict);
753 }
754
755 static CFStringRef
756 ipdict_get_ifname(CFDictionaryRef dict)
757 {
758 CFStringRef ifname = NULL;
759 CFDictionaryRef ip_dict;
760
761 ip_dict = ipdict_get_service(dict);
762 if (ip_dict != NULL) {
763 ifname = CFDictionaryGetValue(ip_dict, kSCPropInterfaceName);
764 }
765 return (ifname);
766 }
767
768 typedef boolean_t GetEntityChangesFunc(CFStringRef serviceID,
769 CFDictionaryRef state_dict,
770 CFDictionaryRef setup_dict,
771 CFDictionaryRef info);
772 typedef GetEntityChangesFunc * GetEntityChangesFuncRef;
773
774 static GetEntityChangesFunc get_ipv4_changes;
775 static GetEntityChangesFunc get_ipv6_changes;
776 static GetEntityChangesFunc get_dns_changes;
777 static GetEntityChangesFunc get_proxies_changes;
778 #if !TARGET_OS_IPHONE
779 static GetEntityChangesFunc get_smb_changes;
780 #endif /* !TARGET_OS_IPHONE */
781
782 static __inline__ void
783 my_CFRelease(void * t)
784 {
785 void * * obj = (void * *)t;
786
787 if (obj && *obj) {
788 CFRelease(*obj);
789 *obj = NULL;
790 }
791 return;
792 }
793
794 static void
795 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new);
796
797 static void
798 my_CFArrayRemoveValue(CFMutableArrayRef arr, CFStringRef key);
799
800 static const GetEntityChangesFuncRef entityChangeFunc[ENTITY_TYPES_COUNT] = {
801 get_ipv4_changes, /* 0 */
802 get_ipv6_changes, /* 1 */
803 get_dns_changes, /* 2 */
804 get_proxies_changes,/* 3 */
805 #if !TARGET_OS_IPHONE
806 get_smb_changes, /* 4 */
807 #endif /* !TARGET_OS_IPHONE */
808 };
809
810 /**
811 ** keyChangeList
812 ** - mechanism to do an atomic update of the SCDynamicStore
813 ** when the content needs to be changed across multiple functions
814 **/
815 typedef struct {
816 CFMutableArrayRef notify;
817 CFMutableArrayRef remove;
818 CFMutableDictionaryRef set;
819 } keyChangeList, * keyChangeListRef;
820
821 static void
822 keyChangeListInit(keyChangeListRef keys)
823 {
824 keys->notify = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
825 keys->remove = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
826 keys->set = CFDictionaryCreateMutable(NULL, 0,
827 &kCFTypeDictionaryKeyCallBacks,
828 &kCFTypeDictionaryValueCallBacks);
829 return;
830 }
831
832 static void
833 keyChangeListFree(keyChangeListRef keys)
834 {
835 my_CFRelease(&keys->notify);
836 my_CFRelease(&keys->remove);
837 my_CFRelease(&keys->set);
838 return;
839 }
840
841 static Boolean
842 keyChangeListActive(keyChangeListRef keys)
843 {
844 return ((CFDictionaryGetCount(keys->set) > 0) ||
845 (CFArrayGetCount(keys->remove) > 0) ||
846 (CFArrayGetCount(keys->notify) > 0));
847 }
848
849 static void
850 keyChangeListNotifyKey(keyChangeListRef keys, CFStringRef key)
851 {
852 my_CFArrayAppendUniqueValue(keys->notify, key);
853 return;
854 }
855
856 static void
857 keyChangeListRemoveValue(keyChangeListRef keys, CFStringRef key)
858 {
859 my_CFArrayAppendUniqueValue(keys->remove, key);
860 CFDictionaryRemoveValue(keys->set, key);
861 return;
862 }
863
864 static void
865 keyChangeListSetValue(keyChangeListRef keys, CFStringRef key, CFTypeRef value)
866 {
867 my_CFArrayRemoveValue(keys->remove, key);
868 CFDictionarySetValue(keys->set, key, value);
869 return;
870 }
871
872 static void
873 keyChangeListApplyToStore(keyChangeListRef keys, SCDynamicStoreRef session)
874 {
875 CFArrayRef notify = keys->notify;
876 CFArrayRef remove = keys->remove;
877 CFDictionaryRef set = keys->set;
878
879 if (CFArrayGetCount(notify) == 0) {
880 notify = NULL;
881 }
882 if (CFArrayGetCount(remove) == 0) {
883 remove = NULL;
884 }
885 if (CFDictionaryGetCount(set) == 0) {
886 set = NULL;
887 }
888 if (set == NULL && remove == NULL && notify == NULL) {
889 return;
890 }
891 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
892 if (set != NULL) {
893 my_log(LOG_DEBUG, "Setting:\n%@", set);
894 }
895 if (remove != NULL) {
896 my_log(LOG_DEBUG, "Removing:\n%@", remove);
897 }
898 if (notify != NULL) {
899 my_log(LOG_DEBUG, "Notifying:\n%@", notify);
900 }
901 }
902 (void)SCDynamicStoreSetMultiple(session, set, remove, notify);
903
904 return;
905 }
906
907 static void
908 S_nwi_ifstate_dump(nwi_ifstate_t ifstate, int i)
909 {
910 const char * addr_str;
911 void * address;
912 char ntopbuf[INET6_ADDRSTRLEN];
913 char vpn_ntopbuf[INET6_ADDRSTRLEN];
914 const struct sockaddr * vpn_addr;
915
916 address = nwi_ifstate_get_address(ifstate);
917 addr_str = inet_ntop(ifstate->af, address, ntopbuf, sizeof(ntopbuf));
918 vpn_addr = nwi_ifstate_get_vpn_server(ifstate);
919 if (vpn_addr != NULL) {
920 _SC_sockaddr_to_string(nwi_ifstate_get_vpn_server(ifstate),
921 vpn_ntopbuf,
922 sizeof(vpn_ntopbuf));
923 }
924 my_log(LOG_INFO,
925 " [%d]: %s%s%s%s rank 0x%x iaddr %s%s%s reach_flags 0x%x",
926 i, ifstate->ifname,
927 nwi_ifstate_get_diff_str(ifstate),
928 (ifstate->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0
929 ? " dns" : "",
930 (ifstate->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0
931 ? " never" : "",
932 ifstate->rank,
933 addr_str,
934 (vpn_addr != NULL) ? " vpn_server_addr: " : "",
935 (vpn_addr != NULL) ? vpn_ntopbuf : "",
936 ifstate->reach_flags);
937 return;
938 }
939
940 static void
941 S_nwi_state_dump(nwi_state_t state)
942 {
943 int i;
944 nwi_ifstate_t scan;
945
946 if (state == NULL) {
947 my_log(LOG_INFO, "nwi_state = <none>");
948 return;
949 }
950 my_log(LOG_INFO,
951 "nwi_state = { "
952 "gen=%llu size=%lu #v4=%u #v6=%u "
953 "reach_flags=(v4=0x%x, v6=0x%x) }",
954 state->generation_count,
955 nwi_state_size(state),
956 state->ipv4_count,
957 state->ipv6_count,
958 nwi_state_get_reachability_flags(state, AF_INET),
959 nwi_state_get_reachability_flags(state, AF_INET6));
960 if (state->ipv4_count) {
961 my_log(LOG_INFO, "IPv4:");
962 for (i = 0, scan = nwi_state_ifstate_list(state, AF_INET);
963 i < state->ipv4_count; i++, scan++) {
964 S_nwi_ifstate_dump(scan, i);
965 }
966 }
967 if (state->ipv6_count) {
968 my_log(LOG_INFO, "IPv6:");
969 for (i = 0, scan = nwi_state_ifstate_list(state, AF_INET6);
970 i < state->ipv6_count; i++, scan++) {
971 S_nwi_ifstate_dump(scan, i);
972 }
973 }
974 if (state->max_if_count) {
975 nwi_ifindex_t * ifindex;
976
977 my_log(LOG_INFO, "%d interfaces:", state->if_list_count);
978 for (i = 0, ifindex = nwi_state_if_list(state);
979 i < state->if_list_count;
980 i++, ifindex++) {
981 my_log(LOG_INFO, "%s", state->ifstate_list[*ifindex].ifname);
982 }
983 }
984 return;
985 }
986
987 static boolean_t
988 S_is_network_boot()
989 {
990 int mib[2];
991 size_t len;
992 int netboot = 0;
993
994 mib[0] = CTL_KERN;
995 mib[1] = KERN_NETBOOT;
996 len = sizeof(netboot);
997 sysctl(mib, 2, &netboot, &len, NULL, 0);
998 return (netboot);
999 }
1000
1001 static int rtm_seq = 0;
1002
1003 #if !TARGET_OS_SIMULATOR
1004 static int
1005 open_routing_socket(void)
1006 {
1007 int sockfd;
1008
1009 if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) == -1) {
1010 my_log(LOG_ERR, "socket() failed: %s", strerror(errno));
1011 }
1012 return (sockfd);
1013 }
1014
1015 static __inline__ int
1016 inet6_dgram_socket(void)
1017 {
1018 int sockfd;
1019
1020 sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
1021 if (sockfd == -1) {
1022 my_log(LOG_ERR, "socket() failed: %s", strerror(errno));
1023 }
1024
1025 return sockfd;
1026 }
1027
1028 static int
1029 siocdradd_in6(int s, int if_index, const struct in6_addr * addr, u_char flags)
1030 {
1031 struct in6_defrouter dr;
1032 struct sockaddr_in6 * sin6;
1033
1034 bzero(&dr, sizeof(dr));
1035 sin6 = &dr.rtaddr;
1036 sin6->sin6_len = sizeof(struct sockaddr_in6);
1037 sin6->sin6_family = AF_INET6;
1038 sin6->sin6_addr = *addr;
1039 dr.flags = flags;
1040 dr.if_index = if_index;
1041 return (ioctl(s, SIOCDRADD_IN6, &dr));
1042 }
1043
1044 static int
1045 siocdrdel_in6(int s, int if_index, const struct in6_addr * addr)
1046 {
1047 struct in6_defrouter dr;
1048 struct sockaddr_in6 * sin6;
1049
1050 bzero(&dr, sizeof(dr));
1051 sin6 = &dr.rtaddr;
1052 sin6->sin6_len = sizeof(struct sockaddr_in6);
1053 sin6->sin6_family = AF_INET6;
1054 sin6->sin6_addr = *addr;
1055 dr.if_index = if_index;
1056 return (ioctl(s, SIOCDRDEL_IN6, &dr));
1057 }
1058
1059 #endif /* !TARGET_OS_SIMULATOR */
1060
1061 static void
1062 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new)
1063 {
1064 CFIndex n = CFArrayGetCount(arr);
1065
1066 if (CFArrayContainsValue(arr, CFRangeMake(0, n), new)) {
1067 return;
1068 }
1069 CFArrayAppendValue(arr, new);
1070 return;
1071 }
1072
1073 static void
1074 my_CFArrayRemoveValue(CFMutableArrayRef arr, CFStringRef key)
1075 {
1076 CFIndex i;
1077
1078 i = CFArrayGetFirstIndexOfValue(arr,
1079 CFRangeMake(0, CFArrayGetCount(arr)),
1080 key);
1081 if (i != kCFNotFound) {
1082 CFArrayRemoveValueAtIndex(arr, i);
1083 }
1084 return;
1085 }
1086
1087 static CFArrayRef
1088 my_CFArrayCreateCombinedArray(CFArrayRef array1, CFArrayRef array2)
1089 {
1090 CFMutableArrayRef combined;
1091
1092 combined = CFArrayCreateMutableCopy(NULL, 0, array1);
1093 CFArrayAppendArray(combined,
1094 array2,
1095 CFRangeMake(0, CFArrayGetCount(array2)));
1096 return (combined);
1097 }
1098
1099 static CFDictionaryRef
1100 my_CFDictionaryGetDictionary(CFDictionaryRef dict, CFStringRef key)
1101 {
1102 if (isA_CFDictionary(dict) == NULL) {
1103 return (NULL);
1104 }
1105 return (isA_CFDictionary(CFDictionaryGetValue(dict, key)));
1106 }
1107
1108 static CFArrayRef
1109 my_CFDictionaryGetArray(CFDictionaryRef dict, CFStringRef key)
1110 {
1111 if (isA_CFDictionary(dict) == NULL) {
1112 return (NULL);
1113 }
1114 return (isA_CFArray(CFDictionaryGetValue(dict, key)));
1115 }
1116
1117 static boolean_t
1118 cfstring_to_ipvx(int family, CFStringRef str, void * addr, int addr_size)
1119 {
1120 char buf[128];
1121
1122 if (isA_CFString(str) == NULL) {
1123 goto done;
1124 }
1125
1126 switch (family) {
1127 case AF_INET:
1128 if (addr_size < sizeof(struct in_addr)) {
1129 goto done;
1130 }
1131 break;
1132 case AF_INET6:
1133 if (addr_size < sizeof(struct in6_addr)) {
1134 goto done;
1135 }
1136 break;
1137 default:
1138 goto done;
1139 }
1140 (void)_SC_cfstring_to_cstring(str, buf, sizeof(buf), kCFStringEncodingASCII);
1141 if (inet_pton(family, buf, addr) == 1) {
1142 return (TRUE);
1143 }
1144 done:
1145 bzero(addr, addr_size);
1146 return (FALSE);
1147 }
1148
1149 __private_extern__
1150 boolean_t
1151 cfstring_to_ip(CFStringRef str, struct in_addr * ip_p)
1152 {
1153 return (cfstring_to_ipvx(AF_INET, str, ip_p, sizeof(*ip_p)));
1154 }
1155
1156 __private_extern__
1157 boolean_t
1158 cfstring_to_ip6(CFStringRef str, struct in6_addr * ip6_p)
1159 {
1160 return (cfstring_to_ipvx(AF_INET6, str, ip6_p, sizeof(*ip6_p)));
1161 }
1162
1163 static boolean_t
1164 cfnumber_to_int(CFNumberRef num, int * int_val)
1165 {
1166 if (isA_CFNumber(num) == NULL) {
1167 return (FALSE);
1168 }
1169 return (CFNumberGetValue(num, kCFNumberIntType, int_val));
1170 }
1171
1172 static CF_RETURNS_RETAINED CFStringRef
1173 setup_service_key(CFStringRef serviceID, CFStringRef entity)
1174 {
1175 return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1176 kSCDynamicStoreDomainSetup,
1177 serviceID,
1178 entity));
1179 }
1180
1181 static CF_RETURNS_RETAINED CFStringRef
1182 state_service_key(CFStringRef serviceID, CFStringRef entity)
1183 {
1184 return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1185 kSCDynamicStoreDomainState,
1186 serviceID,
1187 entity));
1188 }
1189
1190 static CFStringRef
1191 interface_entity_key_copy(CFStringRef ifname, CFStringRef entity)
1192 {
1193 return (SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
1194 kSCDynamicStoreDomainState,
1195 ifname,
1196 entity));
1197 }
1198
1199 static CFDictionaryRef
1200 get_service_setup_entity(CFDictionaryRef services_info, CFStringRef serviceID,
1201 CFStringRef entity)
1202 {
1203 CFStringRef setup_key;
1204 CFDictionaryRef setup_dict;
1205
1206 setup_key = setup_service_key(serviceID, entity);
1207 setup_dict = my_CFDictionaryGetDictionary(services_info, setup_key);
1208 my_CFRelease(&setup_key);
1209 return (setup_dict);
1210 }
1211
1212 static CFDictionaryRef
1213 get_service_state_entity(CFDictionaryRef services_info, CFStringRef serviceID,
1214 CFStringRef entity)
1215 {
1216 CFStringRef state_key;
1217 CFDictionaryRef state_dict;
1218
1219 state_key = state_service_key(serviceID, entity);
1220 state_dict = my_CFDictionaryGetDictionary(services_info, state_key);
1221 my_CFRelease(&state_key);
1222 return (state_dict);
1223 }
1224
1225 static boolean_t
1226 dict_get_first_ip(CFDictionaryRef dict, CFStringRef prop, struct in_addr * ip_p)
1227 {
1228 CFArrayRef ip_list;
1229
1230 ip_list = CFDictionaryGetValue(dict, prop);
1231 if (isA_CFArray(ip_list) != NULL
1232 && CFArrayGetCount(ip_list) > 0
1233 && cfstring_to_ip(CFArrayGetValueAtIndex(ip_list, 0), ip_p)) {
1234 return (TRUE);
1235 }
1236 return (FALSE);
1237 }
1238
1239 static boolean_t
1240 dict_get_first_ipv6(CFDictionaryRef dict, CFStringRef prop,
1241 struct in6_addr * ip_p)
1242 {
1243 CFArrayRef ip_list;
1244
1245 ip_list = CFDictionaryGetValue(dict, prop);
1246 if (isA_CFArray(ip_list) != NULL
1247 && CFArrayGetCount(ip_list) > 0
1248 && cfstring_to_ip6(CFArrayGetValueAtIndex(ip_list, 0), ip_p)) {
1249 return (TRUE);
1250 }
1251 return (FALSE);
1252 }
1253
1254 static boolean_t
1255 dict_get_first_int(CFDictionaryRef dict, CFStringRef prop,
1256 int * val)
1257 {
1258 CFArrayRef list;
1259
1260 list = CFDictionaryGetValue(dict, prop);
1261 if (isA_CFArray(list) != NULL
1262 && CFArrayGetCount(list) > 0
1263 && cfnumber_to_int(CFArrayGetValueAtIndex(list, 0), val)) {
1264 return (TRUE);
1265 }
1266 return (FALSE);
1267 }
1268
1269 static boolean_t
1270 dict_get_ip(CFDictionaryRef dict, CFStringRef prop, struct in_addr * ip_p)
1271 {
1272 CFStringRef val;
1273
1274 val = CFDictionaryGetValue(dict, prop);
1275 return (cfstring_to_ip(val, ip_p));
1276 }
1277
1278 static boolean_t
1279 dict_get_ipv6(CFDictionaryRef dict, CFStringRef prop, struct in6_addr * ip_p)
1280 {
1281 CFStringRef val;
1282
1283 val = CFDictionaryGetValue(dict, prop);
1284 return (cfstring_to_ip6(val, ip_p));
1285 }
1286
1287 static boolean_t
1288 dict_get_int(CFDictionaryRef dict, CFStringRef prop, int * intval)
1289 {
1290 CFNumberRef val;
1291
1292 val = CFDictionaryGetValue(dict, prop);
1293 return (cfnumber_to_int(val, intval));
1294 }
1295
1296 static boolean_t
1297 get_override_primary(CFDictionaryRef dict)
1298 {
1299 CFTypeRef override;
1300
1301 override = CFDictionaryGetValue(dict, kSCPropNetOverridePrimary);
1302 if (isA_CFNumber(override) != NULL) {
1303 int val = 0;
1304
1305 CFNumberGetValue((CFNumberRef)override, kCFNumberIntType, &val);
1306 if (val != 0) {
1307 return (TRUE);
1308 }
1309 }
1310 else if (isA_CFBoolean(override) != NULL) {
1311 if (CFBooleanGetValue(override)) {
1312 return (TRUE);
1313 }
1314 }
1315 return (FALSE);
1316 }
1317
1318 /**
1319 ** Route*
1320 **/
1321
1322 typedef size_t
1323 (*RouteListComputeSize)(CFIndex n);
1324
1325 typedef boolean_t
1326 (*RouteIsEqual)(RouteRef a, RouteRef b);
1327
1328 typedef int
1329 (*RouteApply)(RouteRef route, int cmd, int sockfd);
1330
1331 typedef const void *
1332 (*RouteGateway)(RouteRef route);
1333
1334 typedef void
1335 (*RouteSetGateway)(RouteRef route, const void * address);
1336
1337 typedef const void *
1338 (*RouteDestination)(RouteRef route);
1339
1340 typedef boolean_t
1341 (*RouteSameSubnet)(RouteRef route, const void * address);
1342
1343 typedef CFStringRef
1344 (*RouteCopyDescription)(RouteRef route);
1345
1346 typedef void
1347 (*RouteLog)(int priority, RouteRef route, const char * msg);
1348
1349 typedef struct {
1350 RouteListComputeSize list_compute_size;
1351
1352 RouteIsEqual route_equal;
1353 RouteApply route_apply;
1354 RouteGateway route_gateway;
1355 RouteSetGateway route_set_gateway;
1356 RouteDestination route_destination;
1357 RouteSameSubnet route_same_subnet;
1358 RouteLog route_log;
1359 RouteCopyDescription route_copy_description;
1360
1361 int element_size;
1362 int address_size;
1363 int all_bits_set;
1364 } RouteListInfo;
1365
1366 typedef const RouteListInfo * RouteListInfoRef;
1367
1368 typedef struct {
1369 RouteListInfoRef info;
1370 RouteListRef old_routes;
1371 RouteListRef new_routes;
1372 int sockfd;
1373 int depth;
1374 } RouteListApplyContext, * RouteListApplyContextRef;
1375
1376
1377 static int
1378 RouteAddressCompare(RouteListInfoRef info,
1379 const void * addr1,
1380 const void * addr2)
1381 {
1382 return (memcmp(addr1, addr2, info->address_size));
1383 }
1384
1385 static int
1386 RouteCompare(RouteListInfoRef info,
1387 RouteRef a, Rank a_rank,
1388 RouteRef b, Rank b_rank, boolean_t * same_dest)
1389 {
1390 int cmp;
1391 RouteDestination route_destination;
1392 RouteCopyDescription route_copy_description;
1393
1394 *same_dest = FALSE;
1395 route_destination = info->route_destination;
1396 route_copy_description = info->route_copy_description;
1397 cmp = RouteAddressCompare(info,
1398 (*route_destination)(a),
1399 (*route_destination)(b));
1400 if (cmp == 0) {
1401 cmp = a->prefix_length - b->prefix_length;
1402 if (cmp == 0) {
1403 int index_cmp = a->ifindex - b->ifindex;
1404
1405 if (index_cmp == 0) {
1406 cmp = 0;
1407 }
1408 else if ((a->ifindex == 0 || b->ifindex == 0)
1409 && (a->flags & kRouteFlagsIsScoped) == 0
1410 && (b->flags & kRouteFlagsIsScoped) == 0) {
1411 /*
1412 * Either of the routes specifies no interface and neither
1413 * route is scoped. Claim they are equal to eliminate the
1414 * duplicate route.
1415 */
1416 cmp = 0;
1417 }
1418 else {
1419 *same_dest = TRUE;
1420 cmp = RankCompare(a_rank, b_rank);
1421 if (cmp == 0) {
1422 cmp = index_cmp;
1423 }
1424 }
1425 }
1426 }
1427 if ((S_IPMonitor_debug & kDebugFlag8) != 0) {
1428 CFStringRef a_str;
1429 CFStringRef b_str;
1430 char ch;
1431
1432 if (cmp < 0) {
1433 ch = '<';
1434 }
1435 else if (cmp == 0) {
1436 ch = '=';
1437 }
1438 else {
1439 ch = '>';
1440 }
1441 a_str = (*route_copy_description)(a);
1442 b_str = (*route_copy_description)(b);
1443 my_log(LOG_DEBUG, "%@ rank 0x%x %c %@ rank 0x%x",
1444 a_str, a_rank, ch, b_str, b_rank);
1445 CFRelease(a_str);
1446 CFRelease(b_str);
1447 }
1448 return (cmp);
1449 }
1450
1451 static RouteRef
1452 RouteListGetRouteAtIndexSimple(RouteListInfoRef info, RouteListRef routes,
1453 CFIndex where)
1454 {
1455 return ((void *)routes + (*info->list_compute_size)(where));
1456 }
1457
1458 static RouteRef
1459 RouteListGetRouteAtIndex(RouteListInfoRef info, RouteListRef routes,
1460 CFIndex where)
1461 {
1462 if (routes->count == 0
1463 || where >= routes->count) {
1464 return (NULL);
1465 }
1466 return (RouteListGetRouteAtIndexSimple(info, routes, where));
1467 }
1468
1469 static RouteRef
1470 RouteListGetFirstRoute(RouteListInfoRef info, RouteListRef routes)
1471 {
1472 return (RouteListGetRouteAtIndexSimple(info, routes, 0));
1473 }
1474
1475 #if !TARGET_OS_SIMULATOR
1476 static CFIndex
1477 RouteListRouteIndex(RouteListInfoRef info, RouteListRef routes,
1478 RouteRef route)
1479 {
1480 return (((void *)route
1481 - (void *)RouteListGetFirstRoute(info, routes))
1482 / info->element_size);
1483 }
1484 #endif /* !TARGET_OS_SIMULATOR */
1485
1486 static RouteRef
1487 RouteGetNextRoute(RouteListInfoRef info, RouteRef route)
1488 {
1489 return ((RouteRef)(((void *)route) + info->element_size));
1490 }
1491
1492 static RouteRef
1493 RouteListAddRouteAtIndex(RouteListInfoRef info, RouteListRef routes,
1494 RouteRef this_route, CFIndex where)
1495 {
1496 RouteRef insert_route;
1497
1498 if (where == kCFNotFound) {
1499 /* add it to the end */
1500 insert_route
1501 = RouteListGetRouteAtIndexSimple(info, routes, routes->count);
1502 }
1503 else {
1504 /* make space at [where] */
1505 insert_route = RouteListGetRouteAtIndexSimple(info, routes, where);
1506 bcopy(insert_route,
1507 (void *)insert_route + info->element_size,
1508 info->element_size * (routes->count - where));
1509 }
1510 /* copy the route */
1511 bcopy(this_route, insert_route, info->element_size);
1512 routes->count++;
1513 return (insert_route);
1514 }
1515
1516 static void
1517 RouteListRemoveRouteAtIndex(RouteListInfoRef info, RouteListRef routes,
1518 CFIndex where)
1519 {
1520 if (routes->count == 0
1521 || where >= routes->count) {
1522 return;
1523 }
1524 routes->count--;
1525 if (where == routes->count) {
1526 /* last slot, decrementing gets rid of it */
1527 }
1528 else {
1529 RouteRef remove_route;
1530
1531 remove_route = RouteListGetRouteAtIndexSimple(info, routes, where);
1532 bcopy((void *)remove_route + info->element_size,
1533 remove_route,
1534 info->element_size * (routes->count - where));
1535 }
1536 return;
1537 }
1538
1539 /*
1540 * Function: RouteListAddRoute
1541 *
1542 * Purpose:
1543 * Add the given route to the list of routes, eliminating lower-ranked
1544 * duplicates on the same interface, and marking any lower ranked duplicates
1545 * on other interfaces with kRouteFlagsIsScoped.
1546 *
1547 * This routine assumes that if routes is not NULL, it is malloc'd memory.
1548 *
1549 * Returns:
1550 * Route list updated with the given route, possibly a different pointer,
1551 * due to using realloc'd memory.
1552 */
1553
1554 typedef enum {
1555 kScopeNone = 0,
1556 kScopeThis = 1,
1557 kScopeNext = 2
1558 } Scope;
1559
1560 static RouteListRef
1561 RouteListAddRoute(RouteListInfoRef info,
1562 RouteListRef routes, int init_size,
1563 RouteRef this_route, Rank this_rank)
1564 {
1565 CFIndex i;
1566 RouteRef first_scan = NULL;
1567 RouteFlags flags;
1568 RouteRef scan;
1569 Scope scope_which = kScopeNone;
1570 CFIndex where = kCFNotFound;
1571
1572 if (routes == NULL) {
1573 size_t alloc_size = (*info->list_compute_size)(init_size);
1574
1575 routes = (RouteListRef)malloc(alloc_size);
1576 bzero(routes, sizeof(*routes));
1577 routes->size = init_size;
1578 }
1579 for (i = 0, scan = RouteListGetFirstRoute(info, routes);
1580 i < routes->count;
1581 i++, scan = RouteGetNextRoute(info, scan)) {
1582 int cmp;
1583 boolean_t same_dest;
1584
1585 cmp = RouteCompare(info, this_route, this_rank, scan, scan->rank,
1586 &same_dest);
1587 if (same_dest && (first_scan == NULL)) {
1588 first_scan = scan;
1589 }
1590 if (cmp < 0) {
1591 if (where == kCFNotFound) {
1592 if (same_dest
1593 && (first_scan != NULL)
1594 && (first_scan->flags & kRouteFlagsIsScoped) == 0) {
1595 if ((scan->flags & kRouteFlagsIsScoped) != 0) {
1596 ROUTELIST_DEBUG(kDebugFlag8,
1597 "Hit 1: set scope on self\n");
1598 scope_which = kScopeThis;
1599 }
1600 else {
1601 ROUTELIST_DEBUG(kDebugFlag8,
1602 "Hit 2: set scope on next\n");
1603 scope_which = kScopeNext;
1604 }
1605 }
1606 /* remember our insertion point, but keep going to find a dup */
1607 where = i;
1608 }
1609 }
1610 else if (cmp == 0) {
1611 /* exact match */
1612 /* exact match */
1613 if (where != kCFNotFound
1614 && scan->ifindex == this_route->ifindex
1615 && scan->exclude_ifindex == 0
1616 && this_route->exclude_ifindex == 0) {
1617 /* this route is a duplicate */
1618 ROUTELIST_DEBUG(kDebugFlag8, "Hit 3: removing [%ld]\n", i);
1619 RouteListRemoveRouteAtIndex(info, routes, i);
1620 break;
1621 }
1622 /*
1623 * this_route is "better" than scan if this_route is not excluded
1624 * and scan is excluded or this_route sorts ahead of scan
1625 */
1626 if (this_route->exclude_ifindex == 0
1627 && (scan->exclude_ifindex != 0 || this_rank < scan->rank)) {
1628 IFIndex ifindex = 0;
1629 boolean_t is_scoped = FALSE;
1630
1631 if (scan->flags & kRouteFlagsIsScoped) {
1632 is_scoped = TRUE;
1633 }
1634 if (this_rank < scan->rank) {
1635 ROUTELIST_DEBUG(kDebugFlag8,
1636 "Hit 4a: replacing [%ld]"
1637 " rank 0x%x < 0x%x\n",
1638 i, this_rank, scan->rank);
1639 }
1640 else {
1641 ROUTELIST_DEBUG(kDebugFlag8,
1642 "Hit 4b: replacing [%ld] excluded route\n",
1643 i);
1644 }
1645 if (scan->ifindex != 0) {
1646 ifindex = scan->ifindex;
1647 }
1648 else if (this_route->ifindex != 0) {
1649 ifindex = this_route->ifindex;
1650 }
1651 bcopy(this_route, scan, info->element_size);
1652 scan->rank = this_rank;
1653 scan->ifindex = ifindex;
1654 scan->exclude_ifindex = 0;
1655 if (is_scoped) {
1656 /* preserve whether route was scoped */
1657 ROUTELIST_DEBUG(kDebugFlag8, "Hit 5: preserved scope\n");
1658 scan->flags |= kRouteFlagsIsScoped;
1659 }
1660 }
1661 /* we're done */
1662 goto done;
1663 }
1664 else {
1665 if (same_dest) {
1666 if (scope_which == kScopeNone) {
1667 ROUTELIST_DEBUG(kDebugFlag8, "Hit 6: set scope on self\n");
1668 scope_which = kScopeThis;
1669 }
1670 }
1671 #ifdef TEST_ROUTELIST
1672 else if (where != kCFNotFound) {
1673 /* not possible because we maintain a sorted list */
1674 fprintf(stderr,
1675 "Hit 7: moved past routes - can't happen\n");
1676 exit(2);
1677 break;
1678 }
1679 #endif /* TEST_ROUTELIST */
1680 }
1681 }
1682
1683 if (routes->size == routes->count) {
1684 int how_many;
1685 RouteListRef new_routes;
1686 int old_size;
1687
1688 /* double the size */
1689 old_size = routes->size;
1690 how_many = old_size * 2;
1691 new_routes = (RouteListRef)
1692 reallocf(routes, (*info->list_compute_size)(how_many));
1693 if (new_routes == NULL) {
1694 /* no memory */
1695 routes = NULL;
1696 goto done;
1697 }
1698 ROUTELIST_DEBUG(kDebugFlag8, "increasing size from %d to %d\n",
1699 old_size, how_many);
1700 new_routes->size = how_many;
1701 routes = new_routes;
1702 }
1703
1704 /* add/insert the new route */
1705 this_route = RouteListAddRouteAtIndex(info, routes, this_route, where);
1706 this_route->rank = this_rank;
1707 flags = 0;
1708 if (RANK_ASSERTION_MASK(this_rank) == kRankAssertionNever) {
1709 flags |= kRouteFlagsIsScoped;
1710 }
1711 switch (scope_which) {
1712 case kScopeThis:
1713 flags |= kRouteFlagsIsScoped;
1714 break;
1715 case kScopeNext:
1716 this_route = RouteListGetRouteAtIndex(info, routes, where + 1);
1717 flags |= kRouteFlagsIsScoped;
1718 break;
1719 default:
1720 case kScopeNone:
1721 break;
1722 }
1723 if (this_route != NULL && flags != 0) {
1724 this_route->flags |= flags;
1725 }
1726
1727 done:
1728 return (routes);
1729 }
1730
1731 /*
1732 * Function: RouteListAddRouteList
1733 * Purpose:
1734 * Invoke RouteListAddRoute for each route in the given list
1735 * 'service_routes' combining them into a combined list 'routes'.
1736 *
1737 * Returns:
1738 * See RouteListAddRoute for more information.
1739 */
1740 static RouteListRef
1741 RouteListAddRouteList(RouteListInfoRef info,
1742 RouteListRef routes, int init_size,
1743 RouteListRef service_routes, Rank rank)
1744 {
1745 int i;
1746 RouteRef scan;
1747
1748 for (i = 0, scan = RouteListGetFirstRoute(info, service_routes);
1749 i < service_routes->count;
1750 i++, scan = RouteGetNextRoute(info, scan)) {
1751 Rank this_rank;
1752
1753 if (i == 0
1754 && (service_routes->flags & kRouteListFlagsHasDefault) != 0) {
1755 /* only apply rank to first element of the list (default route) */
1756 this_rank = rank;
1757 }
1758 else {
1759 this_rank = RANK_INDEX_MASK(rank) | RANK_ASSERTION_MASK(scan->rank);
1760 }
1761 routes = RouteListAddRoute(info, routes, init_size, scan, this_rank);
1762 }
1763 return (routes);
1764 }
1765
1766 static void
1767 RouteAddInterfaceToDescription(RouteRef r, CFMutableStringRef str)
1768 {
1769 char if_name[IFNAMSIZ];
1770
1771 if (my_if_indextoname2(r->ifindex, if_name) != NULL) {
1772 CFStringAppendFormat(str, NULL,
1773 CFSTR(" Ifp %s"),
1774 if_name);
1775 }
1776 if (my_if_indextoname2(r->exclude_ifindex, if_name) != NULL) {
1777 CFStringAppendFormat(str, NULL,
1778 CFSTR(" !Ifp %s"),
1779 if_name);
1780 }
1781 return;
1782 }
1783
1784 static void
1785 RouteAddFlagsToDescription(RouteRef r, CFMutableStringRef str)
1786 {
1787 if ((r->flags & kRouteFlagsIsNULL) != 0) {
1788 CFStringAppend(str, CFSTR(" [null]"));
1789 }
1790 else {
1791 Rank rank_assertion = RANK_ASSERTION_MASK(r->rank);
1792
1793 switch (rank_assertion) {
1794 case kRankAssertionFirst:
1795 CFStringAppend(str, CFSTR(" [first]"));
1796 break;
1797 case kRankAssertionLast:
1798 CFStringAppend(str, CFSTR(" [last]"));
1799 break;
1800 case kRankAssertionNever:
1801 CFStringAppend(str, CFSTR(" [never]"));
1802 break;
1803 default:
1804 break;
1805 }
1806 if ((r->flags & kRouteFlagsKernelManaged) != 0) {
1807 CFStringAppend(str, CFSTR(" [kern]"));
1808 }
1809 if ((r->flags & kRouteFlagsIsScoped) != 0) {
1810 CFStringAppend(str, CFSTR(" [SCOPED]"));
1811 }
1812 }
1813 return;
1814 }
1815
1816 #if !TARGET_OS_SIMULATOR
1817 static RouteRef
1818 RouteListFindRoute(RouteListInfoRef info, RouteListRef routes, RouteRef route)
1819 {
1820 int i;
1821 RouteRef match = NULL;
1822 RouteRef scan;
1823
1824 for (i = 0, scan = RouteListGetFirstRoute(info, routes);
1825 i < routes->count;
1826 i++, scan = RouteGetNextRoute(info, scan)) {
1827 if ((*info->route_equal)(scan, route)) {
1828 match = scan;
1829 break;
1830 }
1831
1832 }
1833 return (match);
1834 }
1835
1836 typedef enum {
1837 kRouteLookupFlagsNone = 0x0,
1838 kRouteLookupFlagsExcludeInterface = 0x1
1839 } RouteLookupFlags;
1840
1841 static RouteRef
1842 RouteListLookup(RouteListInfoRef info,
1843 RouteListRef routes,
1844 const void * address,
1845 int n_bits,
1846 IFIndex ifindex,
1847 RouteLookupFlags lookup_flags)
1848 {
1849 RouteRef best_match = NULL;
1850 RouteRef candidate;
1851 int i;
1852
1853 for (i = 0, candidate = RouteListGetFirstRoute(info, routes);
1854 i < routes->count;
1855 i++, candidate = RouteGetNextRoute(info, candidate)) {
1856 if (candidate->ifindex == 0 || candidate->exclude_ifindex != 0) {
1857 /* ignore exclude routes */
1858 continue;
1859 }
1860 if ((lookup_flags & kRouteLookupFlagsExcludeInterface) != 0) {
1861 /* exclude interfaces with the same interface index */
1862 if (ifindex == candidate->ifindex) {
1863 continue;
1864 }
1865 }
1866 else if (ifindex != candidate->ifindex) {
1867 continue;
1868 }
1869 if ((candidate->flags & kRouteFlagsHasGateway) != 0
1870 && RouteAddressCompare(info,
1871 (*info->route_gateway)(candidate),
1872 address) == 0) {
1873 /* skip route whose gateway is the address we're looking for */
1874 continue;
1875 }
1876 if ((candidate->flags & kRouteFlagsIsHost) != 0) {
1877 /* if host route and we're looking for an exact match */
1878 if (n_bits == info->all_bits_set
1879 && RouteAddressCompare(info,
1880 (*info->route_destination)(candidate),
1881 address) == 0) {
1882 /* found exact match */
1883 best_match = candidate;
1884 break;
1885 }
1886 /* skip it */
1887 continue;
1888 }
1889 /* verify that address is on the same subnet */
1890 if ((*info->route_same_subnet)(candidate, address) == FALSE) {
1891 /* different subnet */
1892 continue;
1893 }
1894
1895 if (candidate->prefix_length == n_bits) {
1896 /* exact match */
1897 best_match = candidate;
1898 break;
1899 }
1900 if (candidate->prefix_length > n_bits) {
1901 /* matched too many bits */
1902 continue;
1903 }
1904 if (best_match == NULL
1905 || candidate->prefix_length > best_match->prefix_length) {
1906 best_match = candidate;
1907 }
1908 }
1909 return (best_match);
1910 }
1911
1912
1913 /*
1914 * Function: RouteProcess
1915 * Purpose:
1916 * Function to process adding or removing the specified route.
1917 * In the case of adding, that may involve first processing the gateway
1918 * route (recursively).
1919 */
1920 static boolean_t
1921 RouteProcess(RouteRef route,
1922 RouteCommand cmd,
1923 RouteListApplyContextRef context)
1924 {
1925 RouteLog route_log = context->info->route_log;
1926 RouteApply route_apply = context->info->route_apply;
1927 RouteGateway route_gateway = context->info->route_gateway;
1928 int retval;
1929
1930 switch (cmd) {
1931 case kRouteCommandAdd:
1932 if ((route->control_flags & kControlFlagsProcessed) != 0) {
1933 return ((route->control_flags & kControlFlagsAdded) != 0);
1934 }
1935 route->control_flags |= kControlFlagsProcessed;
1936 if ((route->flags & kRouteFlagsHasGateway) != 0) {
1937 boolean_t added;
1938 RouteRef gateway_route;
1939
1940 gateway_route
1941 = RouteListLookup(context->info,
1942 context->new_routes,
1943 (*route_gateway)(route),
1944 context->info->all_bits_set,
1945 route->ifindex,
1946 kRouteLookupFlagsNone);
1947 if (gateway_route == NULL) {
1948 (*route_log)(LOG_NOTICE, route, "no gateway route");
1949 }
1950 else {
1951 #define MAX_RECURSE_DEPTH 10
1952 /* avoid infinite recursion */
1953 if (context->depth == MAX_RECURSE_DEPTH) {
1954 (*route_log)(LOG_NOTICE, route, "routing loop detected, not adding");
1955 return (FALSE);
1956 }
1957 /* recurse to add gateway route */
1958 context->depth++;
1959 added = RouteProcess(gateway_route,
1960 kRouteCommandAdd,
1961 context);
1962 context->depth--;
1963 if (!added) {
1964 (*route_log)(LOG_NOTICE, route, "failed to add");
1965 return (FALSE);
1966 }
1967 }
1968 }
1969 retval = (*route_apply)(route, RTM_ADD, context->sockfd);
1970 if (retval == EEXIST) {
1971 /* delete and add again */
1972 (void)(*route_apply)(route, RTM_DELETE, context->sockfd);
1973 retval = (*route_apply)(route, RTM_ADD, context->sockfd);
1974 }
1975 switch (retval) {
1976 default:
1977 my_log(LOG_NOTICE,
1978 "failed to add route, %s:",
1979 strerror(retval));
1980 (*route_log)(LOG_NOTICE, route, NULL);
1981 break;
1982 case 0:
1983 case EROUTENOTAPPLIED:
1984 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
1985 char buf[64];
1986 const char * str;
1987
1988 str = (retval == EROUTENOTAPPLIED) ? "!" : "";
1989 snprintf(buf, sizeof(buf), "%sAdd new[%ld]",
1990 str,
1991 RouteListRouteIndex(context->info,
1992 context->new_routes,
1993 route));
1994 (*route_log)(LOG_DEBUG, route, buf);
1995 }
1996 route->control_flags |= kControlFlagsAdded;
1997 break;
1998 }
1999 break;
2000 case kRouteCommandRemove:
2001 retval = (*route_apply)(route, RTM_DELETE, context->sockfd);
2002 switch (retval) {
2003 case 0:
2004 case ESRCH:
2005 case EROUTENOTAPPLIED:
2006 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
2007 char buf[64];
2008 const char * str;
2009
2010 str = (retval == EROUTENOTAPPLIED) ? "!" : "";
2011 snprintf(buf, sizeof(buf), "%sRemove old[%ld]%s",
2012 str,
2013 RouteListRouteIndex(context->info,
2014 context->old_routes,
2015 route),
2016 (retval == ESRCH) ? "(ESRCH)" : "");
2017 (*route_log)(LOG_DEBUG, route, buf);
2018 }
2019 break;
2020 default:
2021 my_log(LOG_NOTICE,
2022 "failed to remove route, %s",
2023 strerror(retval));
2024 (*route_log)(LOG_NOTICE, route, NULL);
2025 break;
2026 }
2027 break;
2028 default:
2029 break;
2030 }
2031 return (TRUE);
2032 }
2033
2034 static void
2035 RouteListApply(RouteListInfoRef info,
2036 RouteListRef old_routes, RouteListRef new_routes,
2037 int sockfd)
2038 {
2039 RouteListApplyContext context;
2040 int i;
2041 RouteRef scan;
2042
2043 if (old_routes == new_routes && old_routes == NULL) {
2044 /* both old and new are NULL, so there's nothing to do */
2045 return;
2046 }
2047 bzero(&context, sizeof(context));
2048 context.old_routes = old_routes;
2049 context.new_routes = new_routes;
2050 context.sockfd = sockfd;
2051 context.info = info;
2052 if (old_routes != NULL) {
2053 for (i = 0, scan = RouteListGetFirstRoute(info, old_routes);
2054 i < old_routes->count;
2055 i++, scan = RouteGetNextRoute(info, scan)) {
2056 RouteRef new_route = NULL;
2057
2058 if (new_routes != NULL) {
2059 new_route = RouteListFindRoute(info, new_routes, scan);
2060 }
2061 if (new_route == NULL) {
2062 if ((scan->control_flags & kControlFlagsAdded) != 0) {
2063 RouteProcess(scan, kRouteCommandRemove, &context);
2064 }
2065 }
2066 }
2067 }
2068 if (new_routes != NULL) {
2069 if (old_routes != NULL) {
2070 /* preserve the control flags from any old routes */
2071 for (i = 0, scan = RouteListGetFirstRoute(info, new_routes);
2072 i < new_routes->count;
2073 i++, scan = RouteGetNextRoute(info, scan)) {
2074 RouteRef old_route = NULL;
2075
2076 old_route = RouteListFindRoute(info, old_routes, scan);
2077 if (old_route != NULL) {
2078 /* preserve the control state in the new route */
2079 scan->control_flags = old_route->control_flags;
2080 }
2081 }
2082 }
2083 /* add any routes that need to be added */
2084 for (i = 0, scan = RouteListGetFirstRoute(info, new_routes);
2085 i < new_routes->count;
2086 i++, scan = RouteGetNextRoute(info, scan)) {
2087 if ((scan->control_flags & kControlFlagsProcessed) != 0) {
2088 continue;
2089 }
2090 RouteProcess(scan, kRouteCommandAdd, &context);
2091 }
2092 }
2093 return;
2094 }
2095 /*
2096 * Function: RouteListFinalize
2097 * Purpose:
2098 * Look for excluded routes. If the excluded route does not have an assigned
2099 * interface, search for a route that *does not* go over the excluded
2100 * interface.
2101 *
2102 * If the excluded route does have an assigned interface, search for a route
2103 * that *does* go over the assigned interface.
2104 *
2105 * Set the gateway on the excluded route to match the gateway of the found
2106 * route.
2107 */
2108 static void
2109 RouteListFinalize(RouteListInfoRef info, RouteListRef routes)
2110 {
2111 int i;
2112 RouteRef scan;
2113
2114 if (routes == NULL) {
2115 return;
2116 }
2117 for (i = 0, scan = RouteListGetFirstRoute(info, routes);
2118 i < routes->count;
2119 i++, scan = RouteGetNextRoute(info, scan)) {
2120 RouteRef route;
2121 IFIndex ifindex;
2122 RouteLookupFlags flags;
2123
2124 if (scan->exclude_ifindex == 0) {
2125 continue;
2126 }
2127 if (scan->ifindex == 0) {
2128 ifindex = scan->exclude_ifindex;
2129 flags = kRouteLookupFlagsExcludeInterface;
2130 }
2131 else {
2132 ifindex = scan->ifindex;
2133 flags = kRouteLookupFlagsNone;
2134 }
2135 route = RouteListLookup(info, routes,
2136 (*info->route_destination)(scan),
2137 scan->prefix_length, ifindex, flags);
2138 if (route == NULL) {
2139 (*info->route_log)(LOG_NOTICE, (RouteRef)scan, "can't resolve excluded route");
2140 }
2141 else {
2142 if ((S_IPMonitor_debug & kDebugFlag8) != 0) {
2143 (*info->route_log)(LOG_DEBUG, (RouteRef)scan, "Excluded route");
2144 (*info->route_log)(LOG_DEBUG, (RouteRef)route, "Resolved to");
2145 }
2146 scan->ifindex = route->ifindex;
2147 if ((route->flags & kRouteFlagsHasGateway) != 0) {
2148 (*info->route_set_gateway)(scan, (*info->route_gateway)(route));
2149 scan->flags |= kRouteFlagsHasGateway;
2150 if (scan->prefix_length == info->all_bits_set) {
2151 scan->flags |= kRouteFlagsIsHost;
2152 }
2153 }
2154 else {
2155 /* routes directly to interface */
2156 scan->flags &= ~(kRouteFlagsHasGateway | kRouteFlagsIsHost);
2157 }
2158 }
2159 }
2160 return;
2161 }
2162 #endif /* !TARGET_OS_SIMULATOR */
2163
2164 /**
2165 ** IPv4Route*
2166 **/
2167
2168 #define IPV4_ROUTE_ALL_BITS_SET 32
2169
2170 static __inline__ struct in_addr
2171 subnet_addr(struct in_addr addr, struct in_addr mask)
2172 {
2173 struct in_addr net;
2174
2175 net.s_addr = addr.s_addr & mask.s_addr;
2176 return (net);
2177 }
2178
2179 static void
2180 IPv4RouteCopyDescriptionWithString(IPv4RouteRef r, CFMutableStringRef str)
2181 {
2182 if ((r->flags & kRouteFlagsIsHost) != 0) {
2183 CFStringAppendFormat(str, NULL,
2184 CFSTR("Host " IP_FORMAT),
2185 IP_LIST(&r->dest));
2186 }
2187 else {
2188 CFStringAppendFormat(str, NULL,
2189 CFSTR("Net " IP_FORMAT),
2190 IP_LIST(&r->dest));
2191 CFStringAppendFormat(str, NULL, CFSTR("/%d"),
2192 r->prefix_length);
2193 }
2194 if ((r->flags & kRouteFlagsHasGateway) != 0) {
2195 CFStringAppendFormat(str, NULL,
2196 CFSTR(" Gate " IP_FORMAT),
2197 IP_LIST(&r->gateway));
2198 }
2199 RouteAddInterfaceToDescription((RouteRef)r, str);
2200 if (r->ifa.s_addr != 0) {
2201 CFStringAppendFormat(str, NULL,
2202 CFSTR(" Ifa " IP_FORMAT),
2203 IP_LIST(&r->ifa));
2204 }
2205 RouteAddFlagsToDescription((RouteRef)r, str);
2206 return;
2207 }
2208
2209 static CFStringRef
2210 IPv4RouteCopyDescription(RouteRef r)
2211 {
2212 CFMutableStringRef str;
2213
2214 str = CFStringCreateMutable(NULL, 0);
2215 IPv4RouteCopyDescriptionWithString((IPv4RouteRef)r, str);
2216 return (str);
2217 }
2218
2219 #ifdef TEST_IPV4_ROUTELIST
2220 static CFMutableStringRef
2221 IPv4RouteListCopyDescription(IPv4RouteListRef routes);
2222
2223 static void
2224 IPv4RouteLog(int level, RouteRef route, const char * msg)
2225 {
2226 CFStringRef str = IPv4RouteCopyDescription(route);
2227
2228 if (msg == NULL) {
2229 SCPrint(TRUE, stdout, CFSTR("%@\n"), str);
2230 }
2231 else {
2232 SCPrint(TRUE, stdout, CFSTR("%s: %@\n"), msg, str);
2233 }
2234 CFRelease(str);
2235 return;
2236 }
2237
2238 static __inline__ void
2239 IPv4RouteListPrint(IPv4RouteListRef routes)
2240 {
2241 CFStringRef str = IPv4RouteListCopyDescription(routes);
2242
2243 SCPrint(TRUE, stdout, CFSTR("%@\n"), str);
2244 CFRelease(str);
2245 return;
2246 }
2247
2248 #else /* TEST_IPV4_ROUTELIST */
2249
2250 static __inline__ void
2251 IPv4RouteLog(int level, RouteRef route, const char * msg)
2252 {
2253 CFStringRef str = IPv4RouteCopyDescription(route);
2254
2255 if (msg == NULL) {
2256 my_log(level, "%@", str);
2257 }
2258 else {
2259 my_log(level, "%s: %@", msg, str);
2260 }
2261 CFRelease(str);
2262 return;
2263 }
2264
2265 #endif /* TEST_IPV4_ROUTELIST */
2266
2267 static boolean_t
2268 IPv4RouteIsEqual(RouteRef r_scan, RouteRef r_route)
2269 {
2270 IPv4RouteRef route = (IPv4RouteRef)r_route;
2271 IPv4RouteRef scan = (IPv4RouteRef)r_scan;
2272
2273 return ((scan->dest.s_addr == route->dest.s_addr)
2274 && (scan->mask.s_addr == route->mask.s_addr)
2275 && (scan->ifindex == route->ifindex)
2276 && (scan->ifa.s_addr == route->ifa.s_addr)
2277 && (scan->gateway.s_addr == route->gateway.s_addr)
2278 && (scan->flags == route->flags));
2279 }
2280
2281 static CFMutableStringRef
2282 IPv4RouteListCopyDescription(IPv4RouteListRef routes)
2283 {
2284 int i;
2285 IPv4RouteRef r;
2286 CFMutableStringRef str;
2287
2288 str = CFStringCreateMutable(NULL, 0);
2289 CFStringAppendFormat(str, NULL, CFSTR("<IPv4RouteList[%d]> = {"),
2290 routes->count);
2291 for (i = 0, r = routes->list; i < routes->count; i++, r++) {
2292 CFStringAppendFormat(str, NULL, CFSTR("\n%2d. "), i);
2293 IPv4RouteCopyDescriptionWithString(r, str);
2294 }
2295 CFStringAppend(str, CFSTR("\n}"));
2296 return (str);
2297 }
2298
2299 static size_t
2300 IPv4RouteListComputeSize(CFIndex n)
2301 {
2302 return (offsetof(IPv4RouteList, list[n]));
2303 }
2304
2305 static int
2306 count_prefix_bits_set(uint32_t n)
2307 {
2308 int count;
2309 const static int8_t bits[16] = {
2310 0, /* 0000 */
2311 -1, /* 0001 */
2312 -1, /* 0010 */
2313 -1, /* 0011 */
2314 -1, /* 0100 */
2315 -1, /* 0101 */
2316 -1, /* 0110 */
2317 -1, /* 0111 */
2318 1, /* 1000 */
2319 -1, /* 1001 */
2320 -1, /* 1010 */
2321 -1, /* 1011 */
2322 2, /* 1100 */
2323 -1, /* 1101 */
2324 3, /* 1110 */
2325 4, /* 1111 */
2326 };
2327
2328 for (count = 0; n != 0; n >>= 4) {
2329 int nbits = bits[n & 0x0f];
2330
2331 if (nbits < 0) {
2332 return (-1);
2333 }
2334 count += nbits;
2335 }
2336 return (count);
2337 }
2338
2339 static uint32_t
2340 prefix_to_mask32(unsigned int prefix_length)
2341 {
2342 if (prefix_length > 32 || prefix_length == 0) {
2343 return (0);
2344 }
2345 return (0xffffffff << (32 - prefix_length));
2346 }
2347
2348 static int
2349 mask_get_prefix_length(struct in_addr mask)
2350 {
2351 int count;
2352
2353 count = count_prefix_bits_set(mask.s_addr);
2354 if (count >= 0) {
2355 uint32_t val;
2356
2357 val = prefix_to_mask32(count);
2358 if (ntohl(mask.s_addr) != val) {
2359 /* expected mask based on prefix length doesn't match */
2360 return (-1);
2361 }
2362 }
2363 return (count);
2364 }
2365
2366 static boolean_t
2367 IPv4RouteSetPrefixLength(IPv4RouteRef route)
2368 {
2369 int length;
2370
2371 length = mask_get_prefix_length(route->mask);
2372 if (length < 0) {
2373 return (FALSE);
2374 }
2375 route->prefix_length = length;
2376 return (TRUE);
2377 }
2378
2379 static const void *
2380 IPv4RouteGateway(RouteRef r_route)
2381 {
2382 IPv4RouteRef route = (IPv4RouteRef)r_route;
2383 return (&route->gateway);
2384 }
2385
2386 static void
2387 IPv4RouteSetGateway(RouteRef r_route, const void * address)
2388 {
2389 IPv4RouteRef route = (IPv4RouteRef)r_route;
2390
2391 route->gateway = *((struct in_addr *)address);
2392 return;
2393 }
2394
2395 static const void *
2396 IPv4RouteDestination(RouteRef r_route)
2397 {
2398 IPv4RouteRef route = (IPv4RouteRef)r_route;
2399 return (&route->dest);
2400 }
2401
2402 static boolean_t
2403 IPv4RouteSameSubnet(RouteRef r_route, const void * addr)
2404 {
2405 const struct in_addr * address;
2406 IPv4RouteRef route = (IPv4RouteRef)r_route;
2407
2408 address = (const struct in_addr *)addr;
2409 return ((address->s_addr & route->mask.s_addr) == route->dest.s_addr);
2410 }
2411
2412 /*
2413 * Define: ROUTE_MSG_ADDRS_SPACE
2414 * Purpose:
2415 * Since sizeof(sockaddr_dl) > sizeof(sockaddr_in), we need space for
2416 * 3 sockaddr_in's and 2 sockaddr_dl's, but pad it just in case
2417 * someone changes the code and doesn't think to modify this.
2418 */
2419 #define ROUTE_MSG_ADDRS_SPACE (3 * sizeof(struct sockaddr_in) \
2420 + 2 * sizeof(struct sockaddr_dl) \
2421 + 128)
2422 typedef struct {
2423 struct rt_msghdr hdr;
2424 char addrs[ROUTE_MSG_ADDRS_SPACE];
2425 } route_msg;
2426
2427 /*
2428 * Function: IPv4RouteApply
2429 * Purpose:
2430 * Add or remove the specified route to/from the kernel routing table.
2431 */
2432 static int
2433 IPv4RouteApply(RouteRef r_route, int cmd, int sockfd)
2434 {
2435 size_t len;
2436 int ret = 0;
2437 IPv4RouteRef route = (IPv4RouteRef)r_route;
2438 route_msg rtmsg;
2439 union {
2440 struct sockaddr_in * in_p;
2441 struct sockaddr_dl * dl_p;
2442 void * ptr;
2443 } rtaddr;
2444
2445 if (S_netboot && route->dest.s_addr == 0) {
2446 /* don't touch the default route */
2447 return (EROUTENOTAPPLIED);
2448 }
2449 if ((route->flags & kRouteFlagsIsNULL) != 0) {
2450 return (EROUTENOTAPPLIED);
2451 }
2452 if (route->ifindex == 0) {
2453 my_log(LOG_NOTICE,
2454 IP_FORMAT " no interface specified, ignoring",
2455 IP_LIST(&route->dest));
2456 return (ENXIO);
2457 }
2458 if (sockfd == -1) {
2459 #ifdef TEST_IPV4_ROUTELIST
2460 return (0);
2461 #else /* TEST_IPV4_ROUTELIST */
2462 return (EBADF);
2463 #endif /* TEST_IPV4_ROUTELIST */
2464 }
2465 memset(&rtmsg, 0, sizeof(rtmsg));
2466 rtmsg.hdr.rtm_type = cmd;
2467 rtmsg.hdr.rtm_version = RTM_VERSION;
2468 rtmsg.hdr.rtm_seq = ++rtm_seq;
2469 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_IFP;
2470 if (route->ifa.s_addr != 0) {
2471 rtmsg.hdr.rtm_addrs |= RTA_IFA;
2472 }
2473 rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
2474 if ((route->flags & kRouteFlagsIsHost) != 0) {
2475 rtmsg.hdr.rtm_flags |= RTF_HOST;
2476 }
2477 else {
2478 rtmsg.hdr.rtm_addrs |= RTA_NETMASK;
2479 if ((route->flags & kRouteFlagsHasGateway) == 0) {
2480 rtmsg.hdr.rtm_flags |= RTF_CLONING;
2481 }
2482 }
2483 if ((route->flags & kRouteFlagsHasGateway) != 0) {
2484 rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
2485 }
2486 if ((route->flags & kRouteFlagsIsScoped) != 0) {
2487 rtmsg.hdr.rtm_index = route->ifindex;
2488 rtmsg.hdr.rtm_flags |= RTF_IFSCOPE;
2489 }
2490
2491 rtaddr.ptr = rtmsg.addrs;
2492
2493 /* dest */
2494 rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
2495 rtaddr.in_p->sin_family = AF_INET;
2496 rtaddr.in_p->sin_addr = route->dest;
2497 rtaddr.ptr += sizeof(*rtaddr.in_p);
2498
2499 /* gateway */
2500 if ((rtmsg.hdr.rtm_flags & RTF_GATEWAY) != 0) {
2501 /* gateway is an IP address */
2502 rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
2503 rtaddr.in_p->sin_family = AF_INET;
2504 rtaddr.in_p->sin_addr = route->gateway;
2505 rtaddr.ptr += sizeof(*rtaddr.in_p);
2506 }
2507 else {
2508 /* gateway is the interface itself */
2509 rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
2510 rtaddr.dl_p->sdl_family = AF_LINK;
2511 rtaddr.dl_p->sdl_index = route->ifindex;
2512 rtaddr.ptr += sizeof(*rtaddr.dl_p);
2513 }
2514
2515 /* mask */
2516 if ((rtmsg.hdr.rtm_addrs & RTA_NETMASK) != 0) {
2517 rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
2518 rtaddr.in_p->sin_family = AF_INET;
2519 rtaddr.in_p->sin_addr = route->mask;
2520 rtaddr.ptr += sizeof(*rtaddr.in_p);
2521 }
2522
2523 /* interface */
2524 if ((rtmsg.hdr.rtm_addrs & RTA_IFP) != 0) {
2525 rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
2526 rtaddr.dl_p->sdl_family = AF_LINK;
2527 rtaddr.dl_p->sdl_index = route->ifindex;
2528 rtaddr.ptr += sizeof(*rtaddr.dl_p);
2529 }
2530 /* interface address */
2531 if ((rtmsg.hdr.rtm_addrs & RTA_IFA) != 0) {
2532 rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
2533 rtaddr.in_p->sin_family = AF_INET;
2534 rtaddr.in_p->sin_addr = route->ifa;
2535 rtaddr.ptr += sizeof(*rtaddr.in_p);
2536 }
2537
2538 /* apply the route */
2539 len = (int)(sizeof(rtmsg.hdr) + (rtaddr.ptr - (void *)rtmsg.addrs));
2540 rtmsg.hdr.rtm_msglen = len;
2541 if (write(sockfd, &rtmsg, len) == -1) {
2542 ret = errno;
2543 }
2544 return (ret);
2545 }
2546
2547 static const RouteListInfo IPv4RouteListInfo = {
2548 IPv4RouteListComputeSize,
2549
2550 IPv4RouteIsEqual,
2551 IPv4RouteApply,
2552 IPv4RouteGateway,
2553 IPv4RouteSetGateway,
2554 IPv4RouteDestination,
2555 IPv4RouteSameSubnet,
2556 IPv4RouteLog,
2557 IPv4RouteCopyDescription,
2558
2559 sizeof(IPv4Route),
2560 sizeof(struct in_addr),
2561 IPV4_ROUTE_ALL_BITS_SET
2562 };
2563
2564 #if !TARGET_OS_SIMULATOR
2565 static __inline__ void
2566 IPv4RouteListLog(int level, IPv4RouteListRef routes)
2567 {
2568 CFStringRef str = IPv4RouteListCopyDescription(routes);
2569
2570 my_log(level, "%@", str);
2571 CFRelease(str);
2572 return;
2573 }
2574
2575 static void
2576 IPv4RouteListApply(IPv4RouteListRef old_routes, IPv4RouteListRef new_routes,
2577 int sockfd)
2578 {
2579 RouteListApply(&IPv4RouteListInfo,
2580 (RouteListRef)old_routes, (RouteListRef)new_routes,
2581 sockfd);
2582 return;
2583 }
2584
2585 static void
2586 IPv4RouteListFinalize(IPv4RouteListRef routes)
2587 {
2588 RouteListFinalize(&IPv4RouteListInfo, (RouteListRef)routes);
2589 return;
2590 }
2591 #endif /* !TARGET_OS_SIMULATOR */
2592
2593 #ifdef TEST_IPV4_ROUTELIST
2594 static IPv4RouteListRef
2595 IPv4RouteListAddRouteList(IPv4RouteListRef routes, int init_size,
2596 IPv4RouteListRef service_routes, Rank rank)
2597 {
2598 return ((IPv4RouteListRef)
2599 RouteListAddRouteList(&IPv4RouteListInfo,
2600 (RouteListRef)routes, init_size,
2601 (RouteListRef)service_routes, rank));
2602 }
2603 #endif /* TEST_IPV4_ROUTELIST */
2604
2605 static CFStringRef
2606 plist_get_string(CFDictionaryRef dict, CFStringRef prop_name,
2607 char * buf, int buf_size)
2608 {
2609 CFStringRef val;
2610
2611 val = CFDictionaryGetValue(dict, prop_name);
2612 if (isA_CFString(val) == NULL) {
2613 return (NULL);
2614 }
2615 if (!CFStringGetCString(val, buf, buf_size, kCFStringEncodingUTF8)) {
2616 return (NULL);
2617 }
2618 return (val);
2619 }
2620
2621 typedef struct {
2622 struct in_addr addr;
2623 int * count_p;
2624 IFIndex ifindex;
2625 IFIndex exclude_ifindex;
2626 IPv4RouteRef * route_p;
2627 Rank rank;
2628 const char * descr;
2629 } AddIPv4RouteContext, * AddIPv4RouteContextRef;
2630
2631 static void
2632 AddIPv4Route(const void * value, void * context)
2633 {
2634 AddIPv4RouteContextRef ctx = (AddIPv4RouteContextRef)context;
2635 CFDictionaryRef dict = (CFDictionaryRef)value;
2636 IPv4RouteRef r = *ctx->route_p;
2637
2638 dict = isA_CFDictionary(dict);
2639 if (dict == NULL
2640 || !dict_get_ip(dict, kSCPropNetIPv4RouteDestinationAddress, &r->dest)
2641 || !dict_get_ip(dict, kSCPropNetIPv4RouteSubnetMask, &r->mask)) {
2642 /* one less route than we expected */
2643 if (dict == NULL) {
2644 my_log(LOG_NOTICE, "%s route is not a dictionary",
2645 ctx->descr);
2646 }
2647 else {
2648 my_log(LOG_NOTICE, "%s route is invalid, %@",
2649 ctx->descr, dict);
2650 }
2651 goto skip;
2652 }
2653 if (!IPv4RouteSetPrefixLength(r)) {
2654 my_log(LOG_NOTICE, "%s route has invalid subnet mask, %@",
2655 ctx->descr, dict);
2656 goto skip;
2657 }
2658 r->rank = ctx->rank;
2659 r->exclude_ifindex = ctx->exclude_ifindex;
2660 if (ctx->ifindex != 0) {
2661 r->ifindex = ctx->ifindex;
2662 r->ifa = ctx->addr;
2663 if (ctx->exclude_ifindex == 0
2664 && dict_get_ip(dict,
2665 kSCPropNetIPv4RouteGatewayAddress,
2666 &r->gateway)) {
2667 r->flags |= kRouteFlagsHasGateway;
2668 if (r->prefix_length == IPV4_ROUTE_ALL_BITS_SET) {
2669 r->flags |= kRouteFlagsIsHost;
2670 }
2671 }
2672 }
2673 else {
2674 char ifname[IFNAMSIZ];
2675
2676 if (plist_get_string(dict, kSCPropNetIPv4RouteInterfaceName,
2677 ifname, sizeof(ifname)) != NULL) {
2678 IFIndex ifindex;
2679
2680 ifindex = my_if_nametoindex(ifname);
2681 if (ifindex == 0) {
2682 my_log(LOG_NOTICE,
2683 "%s: interface %s does not exist, %@",
2684 ctx->descr, ifname, dict);
2685 goto skip;
2686 }
2687 else if (ifindex == ctx->ifindex) {
2688 my_log(LOG_NOTICE,
2689 "%s: interface %s unexpected, %@",
2690 ctx->descr, ifname, dict);
2691 goto skip;
2692 }
2693 r->ifindex = ifindex;
2694 }
2695 }
2696 (*ctx->route_p)++;
2697 return;
2698
2699 skip:
2700 (*ctx->count_p)--;
2701 return;
2702
2703 }
2704
2705 static boolean_t
2706 confirm_interface_name(CFDictionaryRef dict, CFStringRef ifname)
2707 {
2708 CFStringRef confirmed_ifname;
2709 boolean_t confirmed;
2710
2711 confirmed_ifname
2712 = CFDictionaryGetValue(dict, kSCPropConfirmedInterfaceName);
2713 if (isA_CFString(confirmed_ifname) != NULL) {
2714 confirmed = CFEqual(confirmed_ifname, ifname);
2715 }
2716 else {
2717 confirmed = TRUE;
2718 }
2719 return (confirmed);
2720 }
2721
2722 /*
2723 * Function: IPv4RouteListCreateWithDictionary
2724 *
2725 * Purpose:
2726 * Given the service ipv4 entity dictionary, generate the list of routes.
2727 * Currently, this includes just the default route and subnet route,
2728 * if the service has a subnet mask.
2729 *
2730 * Returns:
2731 * If the passed in route_list is NULL or too small, this routine
2732 * allocates malloc'd memory to hold the routes.
2733 */
2734 static IPv4RouteListRef
2735 IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes,
2736 CFDictionaryRef dict,
2737 CFNumberRef rank_assertion)
2738 {
2739 boolean_t add_broadcast_multicast = FALSE;
2740 boolean_t add_default = FALSE;
2741 boolean_t add_router_subnet = FALSE;
2742 boolean_t add_subnet = FALSE;
2743 struct in_addr addr = { 0 };
2744 CFArrayRef additional_routes = NULL;
2745 CFIndex additional_routes_count;
2746 boolean_t allow_additional_routes = FALSE;
2747 boolean_t exclude_from_nwi = FALSE;
2748 CFArrayRef excluded_routes = NULL;
2749 CFIndex excluded_routes_count;
2750 RouteFlags flags = 0;
2751 IFIndex ifindex;
2752 char ifname[IFNAMSIZ];
2753 CFStringRef ifname_cf;
2754 struct in_addr mask = { 0 };
2755 int n = 0;
2756 int prefix_length = 0;
2757 Rank primary_rank = kRankAssertionDefault;
2758 IPv4RouteRef r;
2759 Rank rank = kRankAssertionDefault;
2760 struct in_addr router = { 0 };
2761 boolean_t scoped_only = FALSE;
2762 struct in_addr subnet = { 0 };
2763
2764 if (dict == NULL) {
2765 return (NULL);
2766 }
2767 ifname_cf = plist_get_string(dict, kSCPropInterfaceName,
2768 ifname, sizeof(ifname));
2769 if (ifname_cf == NULL) {
2770 return (NULL);
2771 }
2772 ifindex = my_if_nametoindex(ifname);
2773 if (ifindex == 0) {
2774 /* interface doesn't exist */
2775 return (NULL);
2776 }
2777 allow_additional_routes = confirm_interface_name(dict, ifname_cf);
2778 if (!dict_get_ip(dict, kSCPropNetIPv4Router, &router)) {
2779 (void)dict_get_first_ip(dict, kSCPropNetIPv4DestAddresses, &router);
2780 }
2781 if (dict_get_first_ip(dict, kSCPropNetIPv4Addresses, &addr)
2782 && dict_get_first_ip(dict, kSCPropNetIPv4SubnetMasks, &mask)) {
2783 /* subnet route */
2784 subnet = subnet_addr(addr, mask);
2785 prefix_length = mask_get_prefix_length(mask);
2786 if (prefix_length < 0) {
2787 my_log(LOG_NOTICE,
2788 "ignoring bad subnet mask "
2789 IP_FORMAT " on %s",
2790 IP_LIST(&mask), ifname);
2791 }
2792 else {
2793 add_subnet = TRUE;
2794 n++;
2795 }
2796 }
2797 if (addr.s_addr == 0) {
2798 /* invalid/non-existent address */
2799 return (NULL);
2800 }
2801 if (rank_assertion != NULL) {
2802 (void)CFNumberGetValue(rank_assertion, kCFNumberSInt32Type,
2803 &primary_rank);
2804 }
2805 if (router.s_addr == 0) {
2806 /* if no router is configured, demote the rank if necessary */
2807 switch (primary_rank) {
2808 case kRankAssertionLast:
2809 case kRankAssertionNever:
2810 case kRankAssertionScoped:
2811 /* rank is already demoted */
2812 break;
2813 default:
2814 /* demote to RankLast */
2815 primary_rank = kRankAssertionLast;
2816 break;
2817 }
2818 }
2819 else {
2820 /*
2821 * If the router address is our address and the subnet mask is
2822 * not 255.255.255.255, assume all routes are local to the interface.
2823 */
2824 if (addr.s_addr == router.s_addr
2825 && mask.s_addr != INADDR_BROADCAST) {
2826 ; /* all routes local */
2827 }
2828 else {
2829 flags |= kRouteFlagsHasGateway;
2830 }
2831 if (rank_assertion == NULL && get_override_primary(dict)) {
2832 primary_rank = kRankAssertionFirst;
2833 }
2834 }
2835
2836 if (S_dict_get_boolean(dict, kIsNULL, FALSE)) {
2837 exclude_from_nwi = TRUE;
2838 flags |= kRouteFlagsIsNULL;
2839 }
2840
2841 switch (primary_rank) {
2842 case kRankAssertionScoped:
2843 /* Scoped means all routes for the service get scoped */
2844 primary_rank = rank = kRankAssertionNever;
2845 flags |= kRouteFlagsIsScoped;
2846 scoped_only = TRUE;
2847 break;
2848 case kRankAssertionNever:
2849 /* Never means just the default route gets scoped */
2850 rank = kRankAssertionLast;
2851 flags |= kRouteFlagsIsScoped;
2852 break;
2853 default:
2854 rank = primary_rank;
2855 break;
2856 }
2857
2858 if ((flags & kRouteFlagsHasGateway) != 0) {
2859 add_router_subnet = TRUE;
2860 n++;
2861 }
2862
2863 if (ifindex != lo0_ifindex()) {
2864 if (router.s_addr != 0) {
2865 add_default = TRUE;
2866 n++;
2867 }
2868 add_broadcast_multicast = TRUE;
2869 n += 2;
2870 }
2871 if (allow_additional_routes) {
2872 additional_routes
2873 = CFDictionaryGetValue(dict, kSCPropNetIPv4AdditionalRoutes);
2874 additional_routes = isA_CFArray(additional_routes);
2875 if (additional_routes != NULL) {
2876 additional_routes_count = CFArrayGetCount(additional_routes);
2877 n += additional_routes_count;
2878 }
2879 excluded_routes
2880 = CFDictionaryGetValue(dict, kSCPropNetIPv4ExcludedRoutes);
2881 excluded_routes = isA_CFArray(excluded_routes);
2882 if (excluded_routes != NULL) {
2883 excluded_routes_count = CFArrayGetCount(excluded_routes);
2884 n += excluded_routes_count;
2885 }
2886 }
2887 if (routes == NULL || routes->size < n) {
2888 routes = (IPv4RouteListRef)malloc(IPv4RouteListComputeSize(n));
2889 bzero(routes, IPv4RouteListComputeSize(n));
2890 routes->size = n;
2891 }
2892 else {
2893 bzero(routes->list, sizeof(routes->list[0]) * n);
2894 }
2895 routes->count = n;
2896 if (exclude_from_nwi) {
2897 routes->flags |= kRouteListFlagsExcludeNWI;
2898 }
2899 else if (scoped_only) {
2900 routes->flags |= kRouteListFlagsScopedOnly;
2901 }
2902
2903 /* start at the beginning */
2904 r = routes->list;
2905
2906 if (add_default) {
2907 /* add the default route */
2908 routes->flags |= kRouteListFlagsHasDefault;
2909 r->ifindex = ifindex;
2910 r->ifa = addr;
2911 r->flags = flags;
2912 if ((flags & kRouteFlagsHasGateway) != 0) {
2913 r->gateway = router;
2914 }
2915 else {
2916 r->gateway = addr;
2917 }
2918 r->rank = primary_rank;
2919 r++;
2920 }
2921 if (add_broadcast_multicast) {
2922 /* add the broadcast route (rdar://problem/22149738) */
2923 if ((flags & kRouteFlagsIsNULL) != 0) {
2924 r->flags |= kRouteFlagsIsNULL;
2925 }
2926 r->dest.s_addr = INADDR_BROADCAST;
2927 r->mask.s_addr = INADDR_BROADCAST;
2928 r->prefix_length = IPV4_ROUTE_ALL_BITS_SET;
2929 r->ifindex = ifindex;
2930 r->ifa = addr;
2931 r->rank = primary_rank;
2932 r++;
2933
2934 /* add multicast route (rdar://problem/26457121) */
2935 if ((flags & kRouteFlagsIsNULL) != 0) {
2936 r->flags |= kRouteFlagsIsNULL;
2937 }
2938 r->dest.s_addr = htonl(INADDR_UNSPEC_GROUP);
2939 r->mask.s_addr = htonl(IN_CLASSD_NET);
2940 r->prefix_length = PREFIX_LENGTH_IN_CLASSD;
2941 r->ifindex = ifindex;
2942 r->ifa = addr;
2943 r->rank = primary_rank;
2944 r++;
2945
2946 }
2947
2948 /* add the subnet route */
2949 if (add_subnet) {
2950 if ((flags & kRouteFlagsIsNULL) != 0) {
2951 r->flags |= kRouteFlagsIsNULL;
2952 }
2953 r->ifindex = ifindex;
2954 r->gateway = addr;
2955 r->dest = subnet;
2956 r->mask = mask;
2957 r->prefix_length = prefix_length;
2958 r->ifa = addr;
2959 r->rank = rank;
2960 r++;
2961 }
2962
2963 /* add the router subnet route */
2964 if (add_router_subnet) {
2965 if ((flags & kRouteFlagsIsNULL) != 0) {
2966 r->flags |= kRouteFlagsIsNULL;
2967 }
2968 r->ifindex = ifindex;
2969 r->gateway = addr;
2970 r->dest = router;
2971 r->mask.s_addr = INADDR_BROADCAST;
2972 r->prefix_length = IPV4_ROUTE_ALL_BITS_SET;
2973 r->ifa = addr;
2974 r->rank = rank;
2975 r++;
2976 }
2977
2978 if (additional_routes != NULL || excluded_routes != NULL) {
2979 AddIPv4RouteContext context;
2980
2981 bzero(&context, sizeof(context));
2982 context.count_p = &routes->count;
2983 context.route_p = &r;
2984 context.rank = rank;
2985
2986 /* additional routes */
2987 if (additional_routes != NULL) {
2988 context.ifindex = ifindex;
2989 context.addr = addr;
2990 context.descr = "AdditionalRoutes";
2991 CFArrayApplyFunction(additional_routes,
2992 CFRangeMake(0, additional_routes_count),
2993 AddIPv4Route, &context);
2994 }
2995 /* excluded routes */
2996 if (excluded_routes != NULL) {
2997 context.descr = "ExcludedRoutes";
2998 /* exclude this interface */
2999 context.ifindex = 0;
3000 context.exclude_ifindex = ifindex;
3001 CFArrayApplyFunction(excluded_routes,
3002 CFRangeMake(0, excluded_routes_count),
3003 AddIPv4Route, &context);
3004 }
3005 }
3006 return (routes);
3007 }
3008
3009 #if !TARGET_OS_SIMULATOR
3010 static IPv4RouteListRef
3011 IPv4RouteListCopyMulticastLoopback(void)
3012 {
3013 IPv4RouteRef r;
3014 IPv4RouteListRef routes;
3015
3016 routes = (IPv4RouteListRef)malloc(IPv4RouteListComputeSize(1));
3017 bzero(routes, IPv4RouteListComputeSize(1));
3018 routes->count = routes->size = 1;
3019
3020 r = routes->list;
3021 r->dest.s_addr = htonl(INADDR_UNSPEC_GROUP);
3022 r->mask.s_addr = htonl(IN_CLASSC_NET);
3023 r->prefix_length = PREFIX_LENGTH_IN_CLASSC;
3024 r->ifindex = lo0_ifindex();
3025 return (routes);
3026 }
3027 #endif /* !TARGET_OS_SIMULATOR */
3028
3029 /**
3030 ** IPv6Route*
3031 **/
3032 #define IPV6_ROUTE_ALL_BITS_SET 128
3033
3034 static boolean_t
3035 ipv6_prefix_length_is_valid(int prefix_length)
3036 {
3037 if (prefix_length < 0 || prefix_length > IPV6_ROUTE_ALL_BITS_SET) {
3038 return (FALSE);
3039 }
3040 return (TRUE);
3041 }
3042
3043 /*
3044 * from netinet6/in6.c
3045 */
3046 static void
3047 in6_len2mask(struct in6_addr * mask, int len)
3048 {
3049 int i;
3050
3051 bzero(mask, sizeof(*mask));
3052 for (i = 0; i < len / 8; i++)
3053 mask->s6_addr[i] = 0xff;
3054 if (len % 8)
3055 mask->s6_addr[i] = (0xff00 >> (len % 8)) & 0xff;
3056 }
3057
3058 static void
3059 in6_maskaddr(struct in6_addr * addr, const struct in6_addr * mask)
3060 {
3061 int i;
3062
3063 for (i = 0; i < sizeof(addr->s6_addr); i++) {
3064 addr->s6_addr[i] &= mask->s6_addr[i];
3065 }
3066 return;
3067 }
3068
3069 static void
3070 in6_netaddr(struct in6_addr * addr, int len)
3071 {
3072 struct in6_addr mask;
3073
3074 in6_len2mask(&mask, len);
3075 in6_maskaddr(addr, &mask);
3076 return;
3077 }
3078
3079 static void
3080 in6_addr_scope_linklocal(struct in6_addr * addr, IFIndex ifindex)
3081 {
3082 if (IN6_IS_ADDR_LINKLOCAL(addr)) {
3083 addr->__u6_addr.__u6_addr16[1] = htons(ifindex);
3084 }
3085 return;
3086 }
3087
3088 static void
3089 string_append_in6_addr(CFMutableStringRef str, const struct in6_addr * addr)
3090 {
3091 char ntopbuf[INET6_ADDRSTRLEN];
3092
3093 CFStringAppendCString(str,
3094 inet_ntop(AF_INET6, addr, ntopbuf, sizeof(ntopbuf)),
3095 kCFStringEncodingASCII);
3096 return;
3097 }
3098
3099 static void
3100 IPv6RouteCopyDescriptionWithString(IPv6RouteRef r, CFMutableStringRef str)
3101 {
3102 if ((r->flags & kRouteFlagsIsHost) != 0) {
3103 CFStringAppend(str, CFSTR("Host "));
3104 string_append_in6_addr(str, &r->dest);
3105 }
3106 else {
3107 CFStringAppend(str, CFSTR("Net "));
3108 string_append_in6_addr(str, &r->dest);
3109 CFStringAppendFormat(str, NULL, CFSTR("/%d"),
3110 r->prefix_length);
3111 }
3112 if ((r->flags & kRouteFlagsHasGateway) != 0) {
3113 CFStringAppend(str, CFSTR(" Gate "));
3114 string_append_in6_addr(str, &r->gateway);
3115 }
3116 RouteAddInterfaceToDescription((RouteRef)r, str);
3117 if (!IN6_ARE_ADDR_EQUAL(&r->ifa, &in6addr_any)) {
3118 CFStringAppend(str, CFSTR(" Ifa "));
3119 string_append_in6_addr(str, &r->ifa);
3120 }
3121 RouteAddFlagsToDescription((RouteRef)r, str);
3122 return;
3123 }
3124
3125 static CFStringRef
3126 IPv6RouteCopyDescription(RouteRef r)
3127 {
3128 CFMutableStringRef str;
3129
3130 str = CFStringCreateMutable(NULL, 0);
3131 IPv6RouteCopyDescriptionWithString((IPv6RouteRef)r, str);
3132 return (str);
3133 }
3134
3135 static CFMutableStringRef
3136 IPv6RouteListCopyDescription(IPv6RouteListRef routes)
3137 {
3138 int i;
3139 IPv6RouteRef r;
3140 CFMutableStringRef str;
3141
3142 str = CFStringCreateMutable(NULL, 0);
3143 CFStringAppendFormat(str, NULL, CFSTR("<IPv6RouteList[%d]> = {"),
3144 routes->count);
3145 for (i = 0, r = routes->list; i < routes->count; i++, r++) {
3146 CFStringAppendFormat(str, NULL, CFSTR("\n%2d. "), i);
3147 IPv6RouteCopyDescriptionWithString(r, str);
3148 }
3149 CFStringAppend(str, CFSTR("\n}"));
3150 return (str);
3151 }
3152
3153 #ifdef TEST_IPV6_ROUTELIST
3154
3155 static void
3156 IPv6RouteLog(int level, RouteRef route, const char * msg)
3157 {
3158 CFStringRef str = IPv6RouteCopyDescription(route);
3159
3160 if (msg == NULL) {
3161 SCPrint(TRUE, stdout, CFSTR("%@\n"), str);
3162 }
3163 else {
3164 SCPrint(TRUE, stdout, CFSTR("%s: %@\n"), msg, str);
3165 }
3166 CFRelease(str);
3167 return;
3168 }
3169
3170 static __inline__ void
3171 IPv6RouteListPrint(IPv6RouteListRef routes)
3172 {
3173 CFStringRef str = IPv6RouteListCopyDescription(routes);
3174
3175 SCPrint(TRUE, stdout, CFSTR("%@\n"), str);
3176 CFRelease(str);
3177 return;
3178 }
3179
3180 #else /* TEST_IPV6_ROUTELIST */
3181
3182 static __inline__ void
3183 IPv6RouteLog(int level, RouteRef route, const char * msg)
3184 {
3185 CFStringRef str = IPv6RouteCopyDescription(route);
3186
3187 if (msg == NULL) {
3188 my_log(level, "%@", str);
3189 }
3190 else {
3191 my_log(level, "%s: %@", msg, str);
3192 }
3193 CFRelease(str);
3194 return;
3195 }
3196
3197 #endif /* TEST_IPV6_ROUTELIST */
3198
3199 static size_t
3200 IPv6RouteListComputeSize(CFIndex n)
3201 {
3202 return (offsetof(IPv6RouteList, list[n]));
3203 }
3204
3205
3206 typedef struct {
3207 struct in6_addr * addr;
3208 int * count_p;
3209 IFIndex ifindex;
3210 IFIndex exclude_ifindex;
3211 IPv6RouteRef * route_p;
3212 Rank rank;
3213 const char * descr;
3214 } AddIPv6RouteContext, * AddIPv6RouteContextRef;
3215
3216 static void
3217 AddIPv6Route(const void * value, void * context)
3218 {
3219 AddIPv6RouteContextRef ctx = (AddIPv6RouteContextRef)context;
3220 CFDictionaryRef dict = (CFDictionaryRef)value;
3221 IPv6RouteRef r = *ctx->route_p;
3222
3223 dict = isA_CFDictionary(dict);
3224 if (dict == NULL
3225 || !dict_get_ipv6(dict, kSCPropNetIPv6RouteDestinationAddress, &r->dest)
3226 || !dict_get_int(dict, kSCPropNetIPv6RoutePrefixLength,
3227 &r->prefix_length)
3228 || !ipv6_prefix_length_is_valid(r->prefix_length)) {
3229 /* one less route than we expected */
3230 if (dict == NULL) {
3231 my_log(LOG_NOTICE, "%s route is not a dictionary",
3232 ctx->descr);
3233 }
3234 else {
3235 my_log(LOG_NOTICE, "%s route is invalid, %@",
3236 ctx->descr, dict);
3237 }
3238 goto skip;
3239 }
3240 r->rank = ctx->rank;
3241 r->exclude_ifindex = ctx->exclude_ifindex;
3242 if (ctx->ifindex != 0) {
3243 r->ifindex = ctx->ifindex;
3244 r->ifa = *ctx->addr;
3245 if (ctx->exclude_ifindex == 0
3246 && dict_get_ipv6(dict,
3247 kSCPropNetIPv6RouteGatewayAddress,
3248 &r->gateway)) {
3249 r->flags |= kRouteFlagsHasGateway;
3250 if (r->prefix_length == IPV6_ROUTE_ALL_BITS_SET) {
3251 r->flags |= kRouteFlagsIsHost;
3252 }
3253 }
3254 }
3255 else {
3256 char ifname[IFNAMSIZ];
3257
3258 if (plist_get_string(dict, kSCPropNetIPv6RouteInterfaceName,
3259 ifname, sizeof(ifname)) != NULL) {
3260 IFIndex ifindex;
3261
3262 ifindex = my_if_nametoindex(ifname);
3263 if (ifindex == 0) {
3264 my_log(LOG_NOTICE,
3265 "%s: interface %s does not exist, %@",
3266 ctx->descr, ifname, dict);
3267 goto skip;
3268 }
3269 else if (ifindex == ctx->ifindex) {
3270 my_log(LOG_NOTICE,
3271 "%s: interface %s unexpected, %@",
3272 ctx->descr, ifname, dict);
3273 goto skip;
3274 }
3275 r->ifindex = ifindex;
3276 }
3277 }
3278 (*ctx->route_p)++;
3279 return;
3280
3281 skip:
3282 (*ctx->count_p)--;
3283 return;
3284
3285 }
3286
3287 /*
3288 * Function: IPv6RouteListCreateWithDictionary
3289 *
3290 * Purpose:
3291 * Given the service IPv6 entity dictionary, generate the list of routes.
3292 *
3293 * Returns:
3294 * If the passed in route_list is NULL or too small, this routine
3295 * allocates malloc'd memory to hold the routes.
3296 */
3297 static IPv6RouteListRef
3298 IPv6RouteListCreateWithDictionary(IPv6RouteListRef routes,
3299 CFDictionaryRef dict,
3300 CFNumberRef rank_assertion)
3301 {
3302 boolean_t add_default = FALSE;
3303 boolean_t add_prefix = FALSE;
3304 struct in6_addr addr;
3305 CFArrayRef additional_routes = NULL;
3306 CFIndex additional_routes_count;
3307 boolean_t allow_additional_routes = FALSE;
3308 boolean_t exclude_from_nwi = FALSE;
3309 CFArrayRef excluded_routes = NULL;
3310 CFIndex excluded_routes_count;
3311 RouteFlags flags = 0;
3312 IFIndex ifindex;
3313 char ifname[IFNAMSIZ];
3314 CFStringRef ifname_cf;
3315 int n = 0;
3316 int prefix_length = 0;
3317 Rank primary_rank = kRankAssertionDefault;
3318 IPv6RouteRef r;
3319 Rank rank = kRankAssertionDefault;
3320 struct in6_addr router = in6addr_any;
3321 boolean_t scoped_only = FALSE;
3322
3323 if (dict == NULL) {
3324 return (NULL);
3325 }
3326 ifname_cf = plist_get_string(dict, kSCPropInterfaceName,
3327 ifname, sizeof(ifname));
3328 if (ifname_cf == NULL) {
3329 return (NULL);
3330 }
3331 ifindex = my_if_nametoindex(ifname);
3332 if (ifindex == 0) {
3333 /* interface doesn't exist */
3334 return (NULL);
3335 }
3336 allow_additional_routes = confirm_interface_name(dict, ifname_cf);
3337 if (!dict_get_ipv6(dict, kSCPropNetIPv6Router, &router)) {
3338 (void)dict_get_first_ipv6(dict, kSCPropNetIPv6DestAddresses, &router);
3339 }
3340 if (dict_get_first_ipv6(dict, kSCPropNetIPv6Addresses, &addr)) {
3341 if (IN6_IS_ADDR_UNSPECIFIED(&addr)) {
3342 return (NULL);
3343 }
3344 if (dict_get_first_int(dict, kSCPropNetIPv6PrefixLength,
3345 &prefix_length)
3346 && !IN6_IS_ADDR_LINKLOCAL(&addr)
3347 && ipv6_prefix_length_is_valid(prefix_length)) {
3348 add_prefix = TRUE;
3349 n++;
3350 }
3351 else {
3352 prefix_length = 0;
3353 }
3354 }
3355 else {
3356 /* no addresses */
3357 return (NULL);
3358 }
3359 if (rank_assertion != NULL) {
3360 (void)CFNumberGetValue(rank_assertion, kCFNumberSInt32Type,
3361 &primary_rank);
3362 }
3363 if (!IN6_IS_ADDR_UNSPECIFIED(&router)) {
3364 if (ifindex != lo0_ifindex()) {
3365 add_default = TRUE;
3366 n++;
3367 }
3368 /*
3369 * If the router address is our address and the prefix length is
3370 * not 128, assume all routes are local to the interface.
3371 */
3372 if (IN6_ARE_ADDR_EQUAL(&router, &addr)
3373 && prefix_length != IPV6_ROUTE_ALL_BITS_SET) {
3374 ; /* all routes local */
3375 }
3376 else {
3377 flags |= kRouteFlagsHasGateway;
3378 }
3379 if (rank_assertion == NULL && get_override_primary(dict)) {
3380 primary_rank = kRankAssertionFirst;
3381 }
3382 }
3383 if (S_dict_get_boolean(dict, kIsNULL, FALSE)) {
3384 exclude_from_nwi = TRUE;
3385 flags |= kRouteFlagsIsNULL;
3386 }
3387
3388 switch (primary_rank) {
3389 case kRankAssertionScoped:
3390 /* Scoped means all routes for the service get scoped */
3391 primary_rank = rank = kRankAssertionNever;
3392 flags |= kRouteFlagsIsScoped;
3393 scoped_only = TRUE;
3394 break;
3395 case kRankAssertionNever:
3396 /* Never means just the default route gets scoped */
3397 rank = kRankAssertionLast;
3398 flags |= kRouteFlagsIsScoped;
3399 break;
3400 default:
3401 rank = primary_rank;
3402 break;
3403 }
3404
3405 if (allow_additional_routes) {
3406 additional_routes
3407 = CFDictionaryGetValue(dict, kSCPropNetIPv6AdditionalRoutes);
3408 additional_routes = isA_CFArray(additional_routes);
3409 if (additional_routes != NULL) {
3410 additional_routes_count = CFArrayGetCount(additional_routes);
3411 n += additional_routes_count;
3412 }
3413 excluded_routes = CFDictionaryGetValue(dict,
3414 kSCPropNetIPv6ExcludedRoutes);
3415 excluded_routes = isA_CFArray(excluded_routes);
3416 if (excluded_routes != NULL) {
3417 excluded_routes_count = CFArrayGetCount(excluded_routes);
3418 n += excluded_routes_count;
3419 }
3420 }
3421 if (n == 0) {
3422 return (NULL);
3423 }
3424
3425 /* need IPv6LL subnet route */
3426 n++;
3427
3428 if (routes == NULL || routes->size < n) {
3429 routes = (IPv6RouteListRef)malloc(IPv6RouteListComputeSize(n));
3430 bzero(routes, IPv6RouteListComputeSize(n));
3431 routes->size = n;
3432 }
3433 else {
3434 bzero(routes->list, sizeof(routes->list[0]) * n);
3435 }
3436 routes->count = n;
3437 if (exclude_from_nwi) {
3438 routes->flags |= kRouteListFlagsExcludeNWI;
3439 }
3440 else if (scoped_only) {
3441 routes->flags |= kRouteListFlagsScopedOnly;
3442 }
3443
3444 /* start at the beginning */
3445 r = routes->list;
3446 if (add_default) {
3447 /* add the default route */
3448 routes->flags |= kRouteListFlagsHasDefault;
3449 r->ifindex = ifindex;
3450 r->ifa = addr;
3451 r->flags = flags;
3452 if ((flags & kRouteFlagsHasGateway) != 0) {
3453 r->gateway = router;
3454 }
3455 else {
3456 r->gateway = addr;
3457 }
3458 r->rank = primary_rank;
3459 r->flags |= kRouteFlagsKernelManaged;
3460 r++;
3461 }
3462
3463
3464 /* add IPv6LL route */
3465 r->ifindex = ifindex;
3466 r->dest.s6_addr[0] = 0xfe;
3467 r->dest.s6_addr[1] = 0x80;
3468 r->prefix_length = 64;
3469 r->rank = rank;
3470 r->flags |= kRouteFlagsKernelManaged;
3471 r++;
3472
3473
3474 /* add the prefix route(s) */
3475 if (add_prefix) {
3476 r->flags |= kRouteFlagsKernelManaged;
3477 if ((flags & kRouteFlagsIsNULL) != 0) {
3478 r->flags |= kRouteFlagsIsNULL;
3479 }
3480 r->ifindex = ifindex;
3481 r->gateway = addr;
3482 r->dest = addr;
3483 in6_netaddr(&r->dest, prefix_length);
3484 r->prefix_length = prefix_length;
3485 r->ifa = addr;
3486 r->rank = rank;
3487 r++;
3488 }
3489
3490 if (additional_routes != NULL || excluded_routes != NULL) {
3491 AddIPv6RouteContext context;
3492
3493 bzero(&context, sizeof(context));
3494 context.count_p = &routes->count;
3495 context.route_p = &r;
3496 context.rank = rank;
3497
3498 /* additional routes */
3499 if (additional_routes != NULL) {
3500 context.ifindex = ifindex;
3501 context.addr = &addr;
3502 context.descr = "AdditionalRoutes";
3503 CFArrayApplyFunction(additional_routes,
3504 CFRangeMake(0, additional_routes_count),
3505 AddIPv6Route, &context);
3506 }
3507 /* excluded routes */
3508 if (excluded_routes != NULL) {
3509 context.descr = "ExcludedRoutes";
3510 /* exclude this interface */
3511 context.ifindex = 0;
3512 context.exclude_ifindex = ifindex;
3513 context.addr = NULL;
3514 CFArrayApplyFunction(excluded_routes,
3515 CFRangeMake(0, excluded_routes_count),
3516 AddIPv6Route, &context);
3517 }
3518 }
3519 return (routes);
3520 }
3521
3522 static const void *
3523 IPv6RouteGateway(RouteRef r_route)
3524 {
3525 IPv6RouteRef route = (IPv6RouteRef)r_route;
3526 return (&route->gateway);
3527 }
3528
3529 static void
3530 IPv6RouteSetGateway(RouteRef r_route, const void * address)
3531 {
3532 IPv6RouteRef route = (IPv6RouteRef)r_route;
3533
3534 route->gateway = *((struct in6_addr *)address);
3535 return;
3536 }
3537
3538 static const void *
3539 IPv6RouteDestination(RouteRef r_route)
3540 {
3541 IPv6RouteRef route = (IPv6RouteRef)r_route;
3542 return (&route->dest);
3543 }
3544
3545 static __inline__ int
3546 in6_addr_cmp(const struct in6_addr * a, const struct in6_addr * b)
3547 {
3548 return (memcmp(a->s6_addr, b->s6_addr, sizeof(struct in6_addr)));
3549 }
3550
3551 static boolean_t
3552 IPv6RouteIsEqual(RouteRef r_route1, RouteRef r_route2)
3553 {
3554 IPv6RouteRef route1 = (IPv6RouteRef)r_route1;
3555 IPv6RouteRef route2 = (IPv6RouteRef)r_route2;
3556
3557 return (route1->prefix_length == route2->prefix_length
3558 && route1->ifindex == route2->ifindex
3559 && route1->flags == route2->flags
3560 && in6_addr_cmp(&route1->dest, &route2->dest) == 0
3561 && in6_addr_cmp(&route1->ifa, &route2->ifa) == 0
3562 && in6_addr_cmp(&route1->gateway, &route2->gateway) == 0);
3563 }
3564
3565 static boolean_t
3566 IPv6RouteSameSubnet(RouteRef r_route, const void * addr)
3567 {
3568 const struct in6_addr * address = (const struct in6_addr *)addr;
3569 struct in6_addr netaddr;
3570 IPv6RouteRef route = (IPv6RouteRef)r_route;
3571
3572 netaddr = *address;
3573 in6_netaddr(&netaddr, route->prefix_length);
3574 return (in6_addr_cmp(&netaddr, &route->dest) == 0);
3575 }
3576
3577
3578 #define V6_ROUTE_MSG_ADDRS_SPACE (5 * sizeof(struct sockaddr_dl) + 128)
3579
3580 typedef struct {
3581 struct rt_msghdr hdr;
3582 char addrs[V6_ROUTE_MSG_ADDRS_SPACE];
3583 } v6_route_msg;
3584
3585 /*
3586 * Function: IPv6RouteApply
3587 * Purpose:
3588 * Add or remove the specified route to/from the kernel routing table.
3589 */
3590 static int
3591 IPv6RouteApply(RouteRef r_route, int cmd, int sockfd)
3592 {
3593 int len;
3594 int ret = 0;
3595 IPv6RouteRef route = (IPv6RouteRef)r_route;
3596 v6_route_msg rtmsg;
3597 union {
3598 struct sockaddr_in6 * in_p;
3599 struct sockaddr_dl * dl_p;
3600 void * ptr;
3601 } rtaddr;
3602
3603 if ((route->flags & kRouteFlagsKernelManaged) != 0) {
3604 /* the kernel manages this route, don't touch it */
3605 return (EROUTENOTAPPLIED);
3606 }
3607 if ((route->flags & kRouteFlagsIsNULL) != 0) {
3608 return (EROUTENOTAPPLIED);
3609 }
3610 if (route->ifindex == 0) {
3611 IPv6RouteLog(LOG_NOTICE, (RouteRef)route,
3612 "no interface specified");
3613 return (ENXIO);
3614 }
3615 if (sockfd == -1) {
3616 #ifdef TEST_IPV6_ROUTELIST
3617 return (0);
3618 #else /* TEST_IPV6_ROUTELIST */
3619 return (EBADF);
3620 #endif /* TEST_IPV6_ROUTELIST */
3621 }
3622 memset(&rtmsg, 0, sizeof(rtmsg));
3623 rtmsg.hdr.rtm_type = cmd;
3624 rtmsg.hdr.rtm_version = RTM_VERSION;
3625 rtmsg.hdr.rtm_seq = ++rtm_seq;
3626 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_IFP;
3627 if (!IN6_IS_ADDR_UNSPECIFIED(&route->ifa)) {
3628 rtmsg.hdr.rtm_addrs |= RTA_IFA;
3629 }
3630 rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
3631 if ((route->flags & kRouteFlagsIsHost) != 0) {
3632 rtmsg.hdr.rtm_flags |= RTF_HOST;
3633 }
3634 else {
3635 rtmsg.hdr.rtm_addrs |= RTA_NETMASK;
3636 if ((route->flags & kRouteFlagsHasGateway) == 0) {
3637 rtmsg.hdr.rtm_flags |= RTF_CLONING;
3638 }
3639 }
3640 if ((route->flags & kRouteFlagsHasGateway) != 0) {
3641 rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
3642 }
3643 if ((route->flags & kRouteFlagsIsScoped) != 0) {
3644 rtmsg.hdr.rtm_index = route->ifindex;
3645 rtmsg.hdr.rtm_flags |= RTF_IFSCOPE;
3646 }
3647
3648 rtaddr.ptr = rtmsg.addrs;
3649
3650 /* dest */
3651 rtaddr.in_p->sin6_len = sizeof(*rtaddr.in_p);
3652 rtaddr.in_p->sin6_family = AF_INET6;
3653 rtaddr.in_p->sin6_addr = route->dest;
3654 in6_addr_scope_linklocal(&rtaddr.in_p->sin6_addr, route->ifindex);
3655 rtaddr.ptr += sizeof(*rtaddr.in_p);
3656
3657 /* gateway */
3658 if ((rtmsg.hdr.rtm_flags & RTF_GATEWAY) != 0) {
3659 /* gateway is an IP address */
3660 rtaddr.in_p->sin6_len = sizeof(*rtaddr.in_p);
3661 rtaddr.in_p->sin6_family = AF_INET6;
3662 rtaddr.in_p->sin6_addr = route->gateway;
3663 in6_addr_scope_linklocal(&rtaddr.in_p->sin6_addr, route->ifindex);
3664 rtaddr.ptr += sizeof(*rtaddr.in_p);
3665 }
3666 else {
3667 /* gateway is the interface itself */
3668 rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
3669 rtaddr.dl_p->sdl_family = AF_LINK;
3670 rtaddr.dl_p->sdl_index = route->ifindex;
3671 rtaddr.ptr += sizeof(*rtaddr.dl_p);
3672 }
3673
3674 /* mask */
3675 if ((rtmsg.hdr.rtm_addrs & RTA_NETMASK) != 0) {
3676 rtaddr.in_p->sin6_len = sizeof(*rtaddr.in_p);
3677 rtaddr.in_p->sin6_family = AF_INET6;
3678 in6_len2mask(&rtaddr.in_p->sin6_addr, route->prefix_length);
3679 rtaddr.ptr += sizeof(*rtaddr.in_p);
3680 }
3681
3682 /* interface */
3683 if ((rtmsg.hdr.rtm_addrs & RTA_IFP) != 0) {
3684 rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
3685 rtaddr.dl_p->sdl_family = AF_LINK;
3686 rtaddr.dl_p->sdl_index = route->ifindex;
3687 rtaddr.ptr += sizeof(*rtaddr.dl_p);
3688 }
3689 /* interface address */
3690 if ((rtmsg.hdr.rtm_addrs & RTA_IFA) != 0) {
3691 rtaddr.in_p->sin6_len = sizeof(*rtaddr.in_p);
3692 rtaddr.in_p->sin6_family = AF_INET6;
3693 rtaddr.in_p->sin6_addr = route->ifa;
3694 rtaddr.ptr += sizeof(*rtaddr.in_p);
3695 }
3696
3697 /* apply the route */
3698 len = (int)(sizeof(rtmsg.hdr) + (rtaddr.ptr - (void *)rtmsg.addrs));
3699 rtmsg.hdr.rtm_msglen = len;
3700 if (write(sockfd, &rtmsg, len) == -1) {
3701 ret = errno;
3702 }
3703 return (ret);
3704 }
3705
3706 static const RouteListInfo IPv6RouteListInfo = {
3707 IPv6RouteListComputeSize,
3708
3709 IPv6RouteIsEqual,
3710 IPv6RouteApply,
3711 IPv6RouteGateway,
3712 IPv6RouteSetGateway,
3713 IPv6RouteDestination,
3714 IPv6RouteSameSubnet,
3715 IPv6RouteLog,
3716 IPv6RouteCopyDescription,
3717
3718 sizeof(IPv6Route),
3719 sizeof(struct in6_addr),
3720 IPV6_ROUTE_ALL_BITS_SET
3721 };
3722
3723 #ifdef TEST_IPV6_ROUTELIST
3724 static IPv6RouteListRef
3725 IPv6RouteListAddRouteList(IPv6RouteListRef routes, int init_size,
3726 IPv6RouteListRef service_routes, Rank rank)
3727 {
3728 return ((IPv6RouteListRef)
3729 RouteListAddRouteList(&IPv6RouteListInfo,
3730 (RouteListRef)routes, init_size,
3731 (RouteListRef)service_routes, rank));
3732 }
3733 #endif /* TEST_IPV6_ROUTELIST */
3734
3735 #if !TARGET_OS_SIMULATOR
3736 static __inline__ void
3737 IPv6RouteListLog(int level, IPv6RouteListRef routes)
3738 {
3739 CFStringRef str = IPv6RouteListCopyDescription(routes);
3740
3741 my_log(level, "%@", str);
3742 CFRelease(str);
3743 return;
3744 }
3745
3746 static void
3747 IPv6RouteListFinalize(IPv6RouteListRef routes)
3748 {
3749 RouteListFinalize(&IPv6RouteListInfo, (RouteListRef)routes);
3750 return;
3751 }
3752
3753 static void
3754 IPv6RouteListApply(IPv6RouteListRef old_routes, IPv6RouteListRef new_routes,
3755 int sockfd)
3756 {
3757 RouteListApply(&IPv6RouteListInfo,
3758 (RouteListRef)old_routes, (RouteListRef)new_routes,
3759 sockfd);
3760 return;
3761 }
3762 #endif /* !TARGET_OS_SIMULATOR */
3763
3764 /*
3765 * Function: parse_component
3766 * Purpose:
3767 * Given a string 'key' and a string prefix 'prefix',
3768 * return the next component in the slash '/' separated
3769 * key.
3770 *
3771 * Examples:
3772 * 1. key = "a/b/c" prefix = "a/"
3773 * returns "b"
3774 * 2. key = "a/b/c" prefix = "a/b/"
3775 * returns "c"
3776 */
3777 static CF_RETURNS_RETAINED CFStringRef
3778 parse_component(CFStringRef key, CFStringRef prefix)
3779 {
3780 CFMutableStringRef comp;
3781 CFRange range;
3782
3783 if (!CFStringHasPrefix(key, prefix)) {
3784 return (NULL);
3785 }
3786 comp = CFStringCreateMutableCopy(NULL, 0, key);
3787 if (comp == NULL) {
3788 return (NULL);
3789 }
3790 CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
3791 range = CFStringFind(comp, CFSTR("/"), 0);
3792 if (range.location == kCFNotFound) {
3793 return (comp);
3794 }
3795 range.length = CFStringGetLength(comp) - range.location;
3796 CFStringDelete(comp, range);
3797 return (comp);
3798 }
3799
3800 __private_extern__ boolean_t
3801 service_contains_protocol(CFDictionaryRef service, int af)
3802 {
3803 boolean_t contains_protocol = FALSE;
3804 CFStringRef entity;
3805 RouteListRef routes;
3806 CFDictionaryRef dict;
3807
3808 entity = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6;
3809 dict = CFDictionaryGetValue(service, entity);
3810 if (dict == NULL) {
3811 goto done;
3812 }
3813 routes = ipdict_get_routelist(dict);
3814 if (routes == NULL) {
3815 goto done;
3816 }
3817 if ((routes->flags & kRouteListFlagsExcludeNWI) != 0) {
3818 goto done;
3819 }
3820 contains_protocol = TRUE;
3821
3822 done:
3823 return (contains_protocol);
3824 }
3825
3826
3827 static CFMutableDictionaryRef
3828 service_dict_copy(CFStringRef serviceID)
3829 {
3830 CFDictionaryRef d = NULL;
3831 CFMutableDictionaryRef service_dict;
3832
3833 /* create a modifyable dictionary, a copy or a new one */
3834 d = CFDictionaryGetValue(S_service_state_dict, serviceID);
3835 if (d == NULL) {
3836 service_dict
3837 = CFDictionaryCreateMutable(NULL, 0,
3838 &kCFTypeDictionaryKeyCallBacks,
3839 &kCFTypeDictionaryValueCallBacks);
3840 }
3841 else {
3842 service_dict = CFDictionaryCreateMutableCopy(NULL, 0, d);
3843 }
3844 return (service_dict);
3845 }
3846
3847 __private_extern__ boolean_t
3848 service_is_scoped_only(CFDictionaryRef service_dict)
3849 {
3850 nwi_ifstate_t alias;
3851 CFDictionaryRef dict;
3852 char ifname[IFNAMSIZ];
3853 nwi_ifstate_t ifstate;
3854 CFStringRef interface = NULL;
3855
3856 // get IPv4 (or IPv6) info
3857 dict = CFDictionaryGetValue(service_dict, kSCEntNetIPv4);
3858 if (dict == NULL) {
3859 dict = CFDictionaryGetValue(service_dict, kSCEntNetIPv6);
3860 }
3861 if (dict == NULL) {
3862 // if no connectivity
3863 return FALSE;
3864 }
3865
3866 // get interface
3867 interface = ipdict_get_ifname(dict);
3868 if ((interface == NULL) ||
3869 !CFStringGetCString(interface, ifname, sizeof(ifname), kCFStringEncodingUTF8)) {
3870 // if no interface / interface name
3871 return FALSE;
3872 }
3873
3874 #ifdef TEST_DNS
3875 if (S_nwi_state == NULL) {
3876 S_nwi_state = nwi_state_copy();
3877 }
3878 #endif // TEST_DNS
3879
3880 // get [nwi] interface state
3881 ifstate = nwi_state_get_ifstate(S_nwi_state, ifname);
3882 if (ifstate == NULL) {
3883 // if unknown state
3884 return FALSE;
3885 } else if ((ifstate->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0) {
3886 // if scoped (i.e. not in list)
3887 return TRUE;
3888 }
3889
3890 // check both both IPv4 and IPv6
3891 alias = nwi_ifstate_get_alias(ifstate, ifstate->af == AF_INET ? AF_INET6 : AF_INET);
3892 if (alias == NULL) {
3893 // if only one address family
3894 return FALSE;
3895 } else if ((alias->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0) {
3896 // if scoped (i.e. not in list)
3897 return TRUE;
3898 }
3899
3900 return FALSE;
3901 }
3902
3903 static void
3904 log_service_entity(int level, CFStringRef serviceID, CFStringRef entity,
3905 CFStringRef operation, CFTypeRef val)
3906 {
3907 CFMutableStringRef this_val = NULL;
3908
3909 if (val != NULL) {
3910 boolean_t is_ipv4;
3911 boolean_t is_ipv6;
3912
3913 if ((is_ipv4 = CFEqual(entity, kSCEntNetIPv4))
3914 || (is_ipv6 = CFEqual(entity, kSCEntNetIPv6))) {
3915 RouteListUnion routes;
3916
3917 routes.ptr = ipdict_get_routelist(val);
3918 if (routes.ptr != NULL) {
3919 CFDictionaryRef service_dict = NULL;
3920
3921 if (is_ipv4) {
3922 this_val = IPv4RouteListCopyDescription(routes.v4);
3923 }
3924 else {
3925 this_val = IPv6RouteListCopyDescription(routes.v6);
3926 }
3927 service_dict = ipdict_get_service(val);
3928 if (service_dict != NULL) {
3929 CFStringAppendFormat(this_val, NULL,
3930 CFSTR("\n<Service> = %@"),
3931 service_dict);
3932 }
3933 val = this_val;
3934 }
3935 }
3936 }
3937 if (val == NULL) {
3938 val = CFSTR("<none>");
3939 }
3940 my_log(level, "serviceID %@ %@ %@ value = %@",
3941 serviceID, operation, entity, val);
3942 my_CFRelease(&this_val);
3943 return;
3944 }
3945
3946 static boolean_t
3947 service_dict_set(CFStringRef serviceID, CFStringRef entity,
3948 CFTypeRef new_val)
3949 {
3950 boolean_t changed = FALSE;
3951 CFTypeRef old_val;
3952 CFMutableDictionaryRef service_dict;
3953
3954 service_dict = service_dict_copy(serviceID);
3955 old_val = CFDictionaryGetValue(service_dict, entity);
3956 if (new_val == NULL) {
3957 if (old_val != NULL) {
3958 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
3959 log_service_entity(LOG_DEBUG, serviceID, entity,
3960 CFSTR("Removed:"), old_val);
3961 }
3962 CFDictionaryRemoveValue(service_dict, entity);
3963 changed = TRUE;
3964 }
3965 }
3966 else {
3967 if (old_val == NULL || !CFEqual(new_val, old_val)) {
3968 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
3969 log_service_entity(LOG_DEBUG, serviceID, entity,
3970 CFSTR("Changed: old"), old_val);
3971 log_service_entity(LOG_DEBUG, serviceID, entity,
3972 CFSTR("Changed: new"), new_val);
3973 }
3974 CFDictionarySetValue(service_dict, entity, new_val);
3975 changed = TRUE;
3976 }
3977 }
3978 if (CFDictionaryGetCount(service_dict) == 0) {
3979 CFDictionaryRemoveValue(S_service_state_dict, serviceID);
3980 }
3981 else {
3982 CFDictionarySetValue(S_service_state_dict, serviceID, service_dict);
3983 }
3984 my_CFRelease(&service_dict);
3985 return (changed);
3986 }
3987
3988 static CFDictionaryRef
3989 service_dict_get(CFStringRef serviceID, CFStringRef entity)
3990 {
3991 CFDictionaryRef service_dict;
3992
3993 if (S_service_state_dict == NULL) {
3994 return (NULL);
3995 }
3996 service_dict = CFDictionaryGetValue(S_service_state_dict, serviceID);
3997 if (service_dict == NULL) {
3998 return (NULL);
3999 }
4000 return (CFDictionaryGetValue(service_dict, entity));
4001 }
4002
4003 #ifndef kSCPropNetHostname
4004 #define kSCPropNetHostname CFSTR("Hostname")
4005 #endif
4006
4007 __private_extern__
4008 CFStringRef
4009 copy_dhcp_hostname(CFStringRef serviceID)
4010 {
4011 CFDictionaryRef dict = NULL;
4012 CFStringRef hostname = NULL;
4013 CFDictionaryRef service_dict = NULL;
4014
4015 dict = service_dict_get(serviceID, kSCEntNetIPv4);
4016 if (dict == NULL) {
4017 return (NULL);
4018 }
4019 service_dict = ipdict_get_service(dict);
4020 if (service_dict == NULL) {
4021 return (NULL);
4022 }
4023 hostname = CFDictionaryGetValue(service_dict, kSCPropNetHostname);
4024 if (hostname != NULL) {
4025 CFRetain(hostname);
4026 }
4027 return (hostname);
4028 }
4029
4030 #if !TARGET_OS_SIMULATOR
4031
4032 static struct in6_addr *
4033 ipv6_service_get_router(CFDictionaryRef service,
4034 IFIndex * ifindex_p, CFStringRef * ifname_p)
4035 {
4036 IPv6RouteListRef routes;
4037 struct in6_addr * router = NULL;
4038
4039 routes = ipdict_get_routelist(service);
4040 if (routes != NULL
4041 && (routes->flags & kRouteListFlagsExcludeNWI) == 0
4042 && (routes->flags & kRouteListFlagsHasDefault) != 0) {
4043 router = &routes->list[0].gateway;
4044 if (*ifindex_p == 0) {
4045 *ifindex_p = routes->list[0].ifindex;
4046 }
4047 if (*ifname_p == NULL) {
4048 *ifname_p = ipdict_get_ifname(service);
4049 }
4050 }
4051 return (router);
4052 }
4053
4054 static void
4055 ipv6_service_update_router(CFStringRef serviceID, CFDictionaryRef new_service)
4056 {
4057 IFIndex ifindex = 0;
4058 CFStringRef ifname = NULL;
4059 char ntopbuf[INET6_ADDRSTRLEN];
4060 CFDictionaryRef old_service;
4061 struct in6_addr * old_router;
4062 struct in6_addr * new_router;
4063 int s = -1;
4064
4065 old_service = service_dict_get(serviceID, kSCEntNetIPv6);
4066 old_router = ipv6_service_get_router(old_service, &ifindex, &ifname);
4067 new_router = ipv6_service_get_router(new_service, &ifindex, &ifname);
4068 if (ifname == NULL || ifindex == 0) {
4069 return;
4070 }
4071 s = inet6_dgram_socket();
4072 if (s < 0) {
4073 goto done;
4074 }
4075 /* remove the old router if it was defined */
4076 if (old_router != NULL
4077 && (new_router == NULL
4078 || !IN6_ARE_ADDR_EQUAL(old_router, new_router))) {
4079 if (siocdrdel_in6(s, ifindex, old_router) < 0) {
4080 my_log((errno == EINVAL) ? LOG_DEBUG : LOG_ERR,
4081 "siocdrdel_in6(%@, %s) failed: %s",
4082 ifname,
4083 inet_ntop(AF_INET6, old_router,
4084 ntopbuf, sizeof(ntopbuf)),
4085 strerror(errno));
4086 }
4087 else {
4088 my_log(LOG_INFO,
4089 "%@ removed default route %s",
4090 ifname,
4091 inet_ntop(AF_INET6, old_router, ntopbuf, sizeof(ntopbuf)));
4092 }
4093 }
4094 /* add the new router if it is defined */
4095 if (new_router != NULL
4096 && (old_router == NULL
4097 || !IN6_ARE_ADDR_EQUAL(old_router, new_router))) {
4098 if (siocdradd_in6(s, ifindex, new_router, 0) < 0) {
4099 my_log((errno == EINVAL) ? LOG_DEBUG : LOG_ERR,
4100 "siocdradd_in6(%@, %s) failed: %s",
4101 ifname,
4102 inet_ntop(AF_INET6, new_router,
4103 ntopbuf, sizeof(ntopbuf)),
4104 strerror(errno));
4105 }
4106 else {
4107 my_log(LOG_INFO,
4108 "%@ added default route %s",
4109 ifname,
4110 inet_ntop(AF_INET6, new_router, ntopbuf, sizeof(ntopbuf)));
4111 }
4112 }
4113 close(s);
4114
4115 done:
4116 return;
4117 }
4118 #endif /* !TARGET_OS_SIMULATOR */
4119
4120 #define ALLOW_EMPTY_STRING 0x1
4121
4122 static CF_RETURNS_RETAINED CFTypeRef
4123 sanitize_prop(CFTypeRef val, uint32_t flags)
4124 {
4125 if (val != NULL) {
4126 if (isA_CFString(val)) {
4127 CFMutableStringRef str;
4128
4129 str = CFStringCreateMutableCopy(NULL, 0, (CFStringRef)val);
4130 CFStringTrimWhitespace(str);
4131 if (!(flags & ALLOW_EMPTY_STRING) && (CFStringGetLength(str) == 0)) {
4132 CFRelease(str);
4133 str = NULL;
4134 }
4135 val = str;
4136 } else {
4137 CFRetain(val);
4138 }
4139 }
4140
4141 return val;
4142 }
4143
4144 static void
4145 merge_array_prop(CFMutableDictionaryRef dict,
4146 CFStringRef key,
4147 CFDictionaryRef state_dict,
4148 CFDictionaryRef setup_dict,
4149 uint32_t flags,
4150 Boolean append)
4151 {
4152 CFMutableArrayRef merge_prop;
4153 CFArrayRef setup_prop = NULL;
4154 CFArrayRef state_prop = NULL;
4155
4156 if (setup_dict != NULL) {
4157 setup_prop = isA_CFArray(CFDictionaryGetValue(setup_dict, key));
4158 }
4159 if (state_dict != NULL) {
4160 state_prop = isA_CFArray(CFDictionaryGetValue(state_dict, key));
4161 }
4162
4163 if ((setup_prop == NULL) && (state_prop == NULL)) {
4164 return;
4165 }
4166
4167 merge_prop = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4168 if (setup_prop != NULL) {
4169 CFIndex i;
4170 CFIndex n;
4171
4172 n = CFArrayGetCount(setup_prop);
4173 for (i = 0; i < n; i++) {
4174 CFTypeRef val;
4175
4176 val = CFArrayGetValueAtIndex(setup_prop, i);
4177 val = sanitize_prop(val, flags);
4178 if (val != NULL) {
4179 CFArrayAppendValue(merge_prop, val);
4180 CFRelease(val);
4181 }
4182 }
4183 }
4184 if (state_prop != NULL
4185 && (setup_prop == NULL || S_append_state)) {
4186 CFIndex i;
4187 CFIndex n;
4188 CFRange setup_range = CFRangeMake(0, CFArrayGetCount(merge_prop));
4189
4190 n = CFArrayGetCount(state_prop);
4191 for (i = 0; i < n; i++) {
4192 CFTypeRef val;
4193
4194 val = CFArrayGetValueAtIndex(state_prop, i);
4195 val = sanitize_prop(val, flags);
4196 if (val != NULL) {
4197 if (append || !CFArrayContainsValue(merge_prop, setup_range, val)) {
4198 CFArrayAppendValue(merge_prop, val);
4199 }
4200 CFRelease(val);
4201 }
4202 }
4203 }
4204 if (CFArrayGetCount(merge_prop) > 0) {
4205 CFDictionarySetValue(dict, key, merge_prop);
4206 }
4207 CFRelease(merge_prop);
4208 return;
4209 }
4210
4211 static void
4212 pick_prop(CFMutableDictionaryRef dict,
4213 CFStringRef key,
4214 CFDictionaryRef state_dict,
4215 CFDictionaryRef setup_dict,
4216 uint32_t flags)
4217 {
4218 CFTypeRef val = NULL;
4219
4220 if (setup_dict != NULL) {
4221 val = CFDictionaryGetValue(setup_dict, key);
4222 val = sanitize_prop(val, flags);
4223 }
4224 if (val == NULL && state_dict != NULL) {
4225 val = CFDictionaryGetValue(state_dict, key);
4226 val = sanitize_prop(val, flags);
4227 }
4228 if (val != NULL) {
4229 CFDictionarySetValue(dict, key, val);
4230 CFRelease(val);
4231 }
4232
4233 return;
4234 }
4235
4236 /**
4237 ** GetEntityChangesFunc functions
4238 **/
4239 #define IPV4_ROUTES_N_STATIC 5
4240 #define IPV4_ROUTES_ALIGN_BUF_SIZE_UINT32 \
4241 (roundup(IPv4RouteListComputeSize(IPV4_ROUTES_N_STATIC), \
4242 sizeof(uint32_t)) \
4243 / sizeof(uint32_t))
4244
4245 #define IPV4_ROUTES_BUF_DECL(routes) \
4246 IPv4RouteListRef routes; \
4247 uint32_t routes_buf[IPV4_ROUTES_ALIGN_BUF_SIZE_UINT32]; \
4248 \
4249 routes = (IPv4RouteListRef)(void *)routes_buf; \
4250 routes->size = IPV4_ROUTES_N_STATIC; \
4251 routes->count = 0; \
4252 routes->flags = 0;
4253
4254 static CFDataRef
4255 IPv4RouteListDataCreate(CFDictionaryRef dict, CFNumberRef rank_assertion)
4256 {
4257 IPv4RouteListRef r;
4258 CFDataRef routes_data;
4259 IPV4_ROUTES_BUF_DECL(routes);
4260
4261 r = IPv4RouteListCreateWithDictionary(routes, dict, rank_assertion);
4262 if (r != NULL) {
4263 routes_data = CFDataCreate(NULL,
4264 (const void *)r,
4265 IPv4RouteListComputeSize(r->count));
4266 if (r != routes) {
4267 free(r);
4268 }
4269 }
4270 else {
4271 routes_data = NULL;
4272 }
4273 return (routes_data);
4274 }
4275 #define IPV6_ROUTES_N_STATIC 3
4276 #define IPV6_ROUTES_ALIGN_BUF_SIZE_UINT32 \
4277 (roundup(IPv6RouteListComputeSize(IPV6_ROUTES_N_STATIC), \
4278 sizeof(uint32_t)) \
4279 / sizeof(uint32_t))
4280
4281 #define IPV6_ROUTES_BUF_DECL(routes) \
4282 IPv6RouteListRef routes; \
4283 uint32_t routes_buf[IPV6_ROUTES_ALIGN_BUF_SIZE_UINT32]; \
4284 \
4285 routes = (IPv6RouteListRef)(void *)routes_buf; \
4286 routes->size = IPV6_ROUTES_N_STATIC; \
4287 routes->count = 0; \
4288 routes->flags = 0;
4289
4290 static CFDataRef
4291 IPv6RouteListDataCreate(CFDictionaryRef dict, CFNumberRef rank_assertion)
4292 {
4293 IPv6RouteListRef r;
4294 CFDataRef routes_data;
4295 IPV6_ROUTES_BUF_DECL(routes);
4296
4297 r = IPv6RouteListCreateWithDictionary(routes, dict, rank_assertion);
4298 if (r != NULL) {
4299 routes_data = CFDataCreate(NULL,
4300 (const void *)r,
4301 IPv6RouteListComputeSize(r->count));
4302 if (r != routes) {
4303 free(r);
4304 }
4305 }
4306 else {
4307 routes_data = NULL;
4308 }
4309 return (routes_data);
4310 }
4311
4312 static CFDictionaryRef
4313 IPDictCreate(int af, CFDictionaryRef state_dict, CFDictionaryRef setup_dict,
4314 CFNumberRef rank_assertion)
4315 {
4316 CFDictionaryRef aggregated_dict = NULL;
4317 CFDictionaryRef dict;
4318 CFMutableDictionaryRef modified_dict = NULL;
4319 CFDataRef routes_data;
4320
4321 dict = state_dict;
4322 if (dict != NULL && setup_dict != NULL) {
4323 /* look for keys in Setup: that override/merge with State: */
4324 CFArrayRef additional_routes;
4325 CFStringRef router;
4326 in_addr router_ip;
4327 CFStringRef router_prop;
4328 CFStringRef route_list_prop;
4329
4330 /* Router */
4331 switch (af) {
4332 case AF_INET:
4333 router_prop = kSCPropNetIPv4Router;
4334 route_list_prop = kSCPropNetIPv4AdditionalRoutes;
4335 break;
4336 default:
4337 case AF_INET6:
4338 router_prop = kSCPropNetIPv6Router;
4339 route_list_prop = kSCPropNetIPv6AdditionalRoutes;
4340 break;
4341 }
4342 router = CFDictionaryGetValue(setup_dict, router_prop);
4343 if (router != NULL
4344 && !cfstring_to_ipvx(af, router, &router_ip, sizeof(router_ip))) {
4345 router = NULL;
4346 }
4347
4348 /* AdditionalRoutes */
4349 additional_routes
4350 = CFDictionaryGetValue(setup_dict, route_list_prop);
4351 additional_routes = isA_CFArray(additional_routes);
4352
4353 if (router != NULL || additional_routes != NULL) {
4354 modified_dict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
4355 if (router != NULL) {
4356 CFDictionarySetValue(modified_dict,
4357 router_prop,
4358 router);
4359 }
4360 if (additional_routes != NULL) {
4361 CFArrayRef combined_routes = NULL;
4362 CFArrayRef state_routes;
4363
4364 state_routes
4365 = CFDictionaryGetValue(state_dict,
4366 route_list_prop);
4367 if (isA_CFArray(state_routes) != NULL) {
4368 combined_routes
4369 = my_CFArrayCreateCombinedArray(additional_routes,
4370 state_routes);
4371 additional_routes = combined_routes;
4372 }
4373 CFDictionarySetValue(modified_dict,
4374 route_list_prop,
4375 additional_routes);
4376 if (combined_routes != NULL) {
4377 CFRelease(combined_routes);
4378 }
4379 }
4380 dict = modified_dict;
4381 }
4382 }
4383 switch (af) {
4384 case AF_INET:
4385 routes_data = IPv4RouteListDataCreate(dict, rank_assertion);
4386 break;
4387 default:
4388 case AF_INET6:
4389 routes_data = IPv6RouteListDataCreate(dict, rank_assertion);
4390 break;
4391 }
4392 if (routes_data != NULL) {
4393 aggregated_dict = ipdict_create(dict, routes_data);
4394 CFRelease(routes_data);
4395 }
4396 if (modified_dict != NULL) {
4397 CFRelease(modified_dict);
4398 }
4399 return (aggregated_dict);
4400 }
4401
4402 static boolean_t
4403 get_ipv4_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
4404 CFDictionaryRef setup_dict, CFDictionaryRef info)
4405 {
4406 CFDictionaryRef dict = NULL;
4407 boolean_t changed = FALSE;
4408 CFNumberRef rank_assertion = NULL;
4409 CFDictionaryRef service_options;
4410
4411 if (state_dict == NULL) {
4412 goto done;
4413 }
4414 service_options = service_dict_get(serviceID, kSCEntNetService);
4415 if (service_options != NULL) {
4416 rank_assertion
4417 = CFDictionaryGetValue(service_options,
4418 kServiceOptionRankAssertion);
4419 }
4420 dict = IPDictCreate(AF_INET, state_dict, setup_dict, rank_assertion);
4421
4422 done:
4423 changed = service_dict_set(serviceID, kSCEntNetIPv4, dict);
4424 if (dict == NULL) {
4425 /* clean up the rank too */
4426 CFDictionaryRemoveValue(S_ipv4_service_rank_dict, serviceID);
4427 }
4428 my_CFRelease(&dict);
4429 return (changed);
4430 }
4431
4432 static boolean_t
4433 get_ipv6_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
4434 CFDictionaryRef setup_dict, CFDictionaryRef info)
4435 {
4436 CFDictionaryRef dict = NULL;
4437 boolean_t changed = FALSE;
4438 CFNumberRef rank_assertion = NULL;
4439 CFDictionaryRef service_options;
4440
4441 if (state_dict == NULL) {
4442 goto done;
4443 }
4444 service_options = service_dict_get(serviceID, kSCEntNetService);
4445 if (service_options != NULL) {
4446 rank_assertion
4447 = CFDictionaryGetValue(service_options,
4448 kServiceOptionRankAssertion);
4449 }
4450 dict = IPDictCreate(AF_INET6, state_dict, setup_dict, rank_assertion);
4451
4452 done:
4453 #if !TARGET_OS_SIMULATOR
4454 ipv6_service_update_router(serviceID, dict);
4455 #endif /* !TARGET_OS_SIMULATOR */
4456 changed = service_dict_set(serviceID, kSCEntNetIPv6, dict);
4457 if (dict == NULL) {
4458 /* clean up the rank too */
4459 CFDictionaryRemoveValue(S_ipv6_service_rank_dict, serviceID);
4460 }
4461 my_CFRelease(&dict);
4462 return (changed);
4463 }
4464
4465
4466 #ifdef TEST_DNS
4467 __private_extern__ CFDictionaryRef
4468 ipv4_dict_create(CFDictionaryRef state_dict)
4469 {
4470 return (IPDictCreate(AF_INET, state_dict, NULL, NULL));
4471 }
4472
4473 __private_extern__ CFDictionaryRef
4474 ipv6_dict_create(CFDictionaryRef state_dict)
4475 {
4476 return (IPDictCreate(AF_INET6, state_dict, NULL, NULL));
4477 }
4478
4479 #endif /* TEST_DNS */
4480
4481 static void
4482 accumulate_dns_servers(CFArrayRef in_servers, ProtocolFlags active_protos,
4483 CFMutableArrayRef out_servers, CFStringRef interface)
4484 {
4485 CFIndex count;
4486 CFIndex i;
4487
4488 count = CFArrayGetCount(in_servers);
4489 for (i = 0; i < count; i++) {
4490 CFStringRef addr;
4491 struct in6_addr ipv6_addr;
4492 struct in_addr ip_addr;
4493
4494 addr = CFArrayGetValueAtIndex(in_servers, i);
4495 assert(addr != NULL);
4496
4497 if (cfstring_to_ip(addr, &ip_addr)) {
4498 /* IPv4 address */
4499 if ((active_protos & kProtocolFlagsIPv4) == 0
4500 && ntohl(ip_addr.s_addr) != INADDR_LOOPBACK) {
4501 my_log(LOG_INFO,
4502 "no IPv4 connectivity, "
4503 "ignoring DNS server address " IP_FORMAT,
4504 IP_LIST(&ip_addr));
4505 continue;
4506 }
4507
4508 CFRetain(addr);
4509 }
4510 else if (cfstring_to_ip6(addr, &ipv6_addr)) {
4511 /* IPv6 address */
4512 if ((active_protos & kProtocolFlagsIPv6) == 0
4513 && !IN6_IS_ADDR_LOOPBACK(&ipv6_addr)) {
4514 char ntopbuf[INET6_ADDRSTRLEN];
4515
4516 my_log(LOG_INFO,
4517 "no IPv6 connectivity, "
4518 "ignoring DNS server address %s",
4519 inet_ntop(AF_INET6, &ipv6_addr,
4520 ntopbuf, sizeof(ntopbuf)));
4521 continue;
4522 }
4523
4524 if ((IN6_IS_ADDR_LINKLOCAL(&ipv6_addr) ||
4525 IN6_IS_ADDR_MC_LINKLOCAL(&ipv6_addr))
4526 && (interface != NULL)
4527 && (CFStringFind(addr, CFSTR("%"), 0).location == kCFNotFound)) {
4528 // append interface name to IPv6 link local address
4529 addr = CFStringCreateWithFormat(NULL, NULL,
4530 CFSTR("%@%%%@"),
4531 addr,
4532 interface);
4533 } else {
4534 CFRetain(addr);
4535 }
4536 }
4537 else {
4538 /* bad IP address */
4539 my_log(LOG_NOTICE, "ignoring bad DNS server address '%@'", addr);
4540 continue;
4541 }
4542
4543 /* DNS server is valid and one we want */
4544 CFArrayAppendValue(out_servers, addr);
4545 CFRelease(addr);
4546 }
4547 return;
4548 }
4549
4550 static CF_RETURNS_RETAINED CFArrayRef
4551 order_dns_servers(CFArrayRef servers, ProtocolFlags active_protos)
4552 {
4553 Boolean favor_v4 = FALSE;
4554 CFMutableArrayRef ordered_servers;
4555 ProtocolFlags proto_last = kProtocolFlagsIPv4;
4556 struct sockaddr_in v4_dns1 = { .sin_family = AF_INET,
4557 .sin_len = sizeof(struct sockaddr_in) };
4558 CFIndex v4_n = 0;
4559 struct sockaddr_in6 v6_dns1 = { .sin6_family = AF_INET6,
4560 .sin6_len = sizeof(struct sockaddr_in6),
4561 .sin6_scope_id = 0 };
4562 CFIndex v6_n = 0;
4563
4564 if (((active_protos & kProtocolFlagsIPv4) == 0) ||
4565 ((active_protos & kProtocolFlagsIPv6) == 0)) {
4566 /* only one protocol */
4567 #ifdef TEST_DNS_ORDER
4568 printf("only one protocol\n");
4569 #endif // TEST_DNS_ORDER
4570 return CFRetain(servers);
4571 }
4572
4573 ordered_servers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4574 for (CFIndex i = 0, n = CFArrayGetCount(servers); i < n; i++) {
4575 struct in_addr ia;
4576 struct in6_addr ia6;
4577 ProtocolFlags proto;
4578 CFStringRef server;
4579
4580 server = CFArrayGetValueAtIndex(servers, i);
4581 if (cfstring_to_ip(server, &ia)) {
4582 proto = kProtocolFlagsIPv4;
4583 if (v4_n++ == 0) {
4584 v4_dns1.sin_addr = ia;
4585 }
4586 } else if (cfstring_to_ip6(server, &ia6)) {
4587 proto = kProtocolFlagsIPv6;
4588 if (v6_n++ == 0) {
4589 bcopy(&ia6, &v6_dns1.sin6_addr, sizeof(ia6));
4590 }
4591 } else {
4592 CFRelease(ordered_servers);
4593 return CFRetain(servers);
4594 }
4595
4596 if ((i > 0) && (proto != proto_last)) {
4597 /* if the protocol of the server addresses changed */
4598 if (((proto == kProtocolFlagsIPv4) && (v4_n == 1)) ||
4599 ((proto == kProtocolFlagsIPv6) && (v6_n == 1))) {
4600 /* if we now have the 1st server address of another protocol */
4601 favor_v4 = (sa_dst_compare_no_stats((struct sockaddr *)&v4_dns1,
4602 (struct sockaddr *)&v6_dns1,
4603 0) >= 0);
4604 #ifdef TEST_DNS_ORDER
4605 char v4_buf[INET_ADDRSTRLEN];
4606 char v6_buf[INET6_ADDRSTRLEN];
4607 printf("comparing %s vs %s, favoring %s\n",
4608 inet_ntop(v4_dns1.sin_family, &v4_dns1.sin_addr, v4_buf, sizeof(v4_buf)),
4609 inet_ntop(v6_dns1.sin6_family, &v6_dns1.sin6_addr, v6_buf, sizeof(v6_buf)),
4610 favor_v4 ? "v4" : "v6");
4611 #endif // TEST_DNS_ORDER
4612 } else {
4613 /* if the server addresses array is randomly mixed */
4614 #ifdef TEST_DNS_ORDER
4615 printf("v4/v6 not ordered\n");
4616 #endif // TEST_DNS_ORDER
4617 CFRelease(ordered_servers);
4618 return CFRetain(servers);
4619 }
4620 }
4621 proto_last = proto;
4622
4623 if ((proto == kProtocolFlagsIPv4) && favor_v4) {
4624 CFArrayInsertValueAtIndex(ordered_servers, v4_n - 1, server);
4625 } else if ((proto == kProtocolFlagsIPv6) && !favor_v4) {
4626 CFArrayInsertValueAtIndex(ordered_servers, v6_n - 1, server);
4627 } else {
4628 CFArrayAppendValue(ordered_servers, server);
4629 }
4630 }
4631
4632 return ordered_servers;
4633 }
4634
4635 static void
4636 merge_dns_servers(CFMutableDictionaryRef new_dict,
4637 CFArrayRef state_servers,
4638 CFArrayRef setup_servers,
4639 Boolean have_setup,
4640 Boolean trust_state,
4641 ProtocolFlags active_protos,
4642 CFStringRef interface)
4643 {
4644 CFMutableArrayRef dns_servers;
4645 Boolean have_dns_setup = FALSE;
4646
4647 if (state_servers == NULL && setup_servers == NULL) {
4648 /* no DNS servers */
4649 return;
4650 }
4651 dns_servers = CFArrayCreateMutable(NULL, 0,
4652 &kCFTypeArrayCallBacks);
4653 if (setup_servers != NULL) {
4654 accumulate_dns_servers(setup_servers, active_protos,
4655 dns_servers, interface);
4656 if (CFArrayGetCount(dns_servers) > 0) {
4657 have_dns_setup = TRUE;
4658 }
4659 }
4660 if ((CFArrayGetCount(dns_servers) == 0 || S_append_state)
4661 && state_servers != NULL) {
4662 CFArrayRef ordered_servers;
4663
4664 ordered_servers = order_dns_servers(state_servers, active_protos);
4665 accumulate_dns_servers(ordered_servers, active_protos,
4666 dns_servers, NULL);
4667 CFRelease(ordered_servers);
4668 }
4669
4670 /*
4671 * Here, we determine whether or not we want all queries for this DNS
4672 * configuration to be bound to the associated network interface.
4673 *
4674 * For dynamically derived network configurations (i.e. from State:)
4675 * this would be the preferred option using the argument "Hey, the
4676 * server told us to use these servers on this network so let's not
4677 * argue".
4678 *
4679 * But, when a DNS configuration has been provided by the user/admin
4680 * via the Network pref pane (i.e. from Setup:) we opt to not force
4681 * binding of the outbound queries. The simplest example why we take
4682 * this stance is with a multi-homing configuration. Consider a system
4683 * with one network service associated with "en0" and a second service
4684 * associated with "en1". The "en0" service has been set higher in
4685 * the network service order so it would be primary but the user/admin
4686 * wants the DNS queries to go to a server only accessible via "en1".
4687 * Without this exception we would take the DNS server addresses from
4688 * the Network pref pane (for "en0") and have the queries bound to
4689 * "en0" where they'd never reach their intended destination (via
4690 * "en1"). So, our exception to the rule is that we will not bind
4691 * user/admin configurations to any specific network interface.
4692 *
4693 * We also add an exception to the "follow the dynamically derived
4694 * network configuration" path for on-the-fly (no Setup: content)
4695 * network services.
4696 *
4697 * But, we add an exception to the exception to support our own
4698 * VPN code. Here, we look for a "ServiceID" property in the DNS
4699 * entity. If present, and if it matches, then we extend our
4700 * trust even when there is no Setup: content.
4701 */
4702 if (CFArrayGetCount(dns_servers) != 0) {
4703 CFDictionarySetValue(new_dict,
4704 kSCPropNetDNSServerAddresses, dns_servers);
4705 if ((have_setup && !have_dns_setup) || (!have_setup && trust_state)) {
4706 // if this is a "setup"+"state" service with only "state" DNS content (i.e. no
4707 // setup override) or this is a TRUSTED "state"-only service
4708 CFDictionarySetValue(new_dict, DNS_CONFIGURATION_SCOPED_QUERY_KEY, kCFBooleanTrue);
4709 }
4710 }
4711
4712 my_CFRelease(&dns_servers);
4713 return;
4714 }
4715
4716
4717 static boolean_t
4718 get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
4719 CFDictionaryRef setup_dict, CFDictionaryRef info)
4720 {
4721 ProtocolFlags active_protos = kProtocolFlagsNone;
4722 boolean_t changed = FALSE;
4723 CFStringRef domain;
4724 Boolean have_setup = FALSE;
4725 CFStringRef interface = NULL;
4726 CFDictionaryRef ipv4;
4727 CFDictionaryRef ipv6;
4728 int i;
4729 const struct {
4730 CFStringRef key;
4731 uint32_t flags;
4732 Boolean append;
4733 } merge_list[] = {
4734 { kSCPropNetDNSSearchDomains, 0, FALSE },
4735 { kSCPropNetDNSSortList, 0, FALSE },
4736 { kSCPropNetDNSSupplementalMatchDomains, ALLOW_EMPTY_STRING, TRUE },
4737 { kSCPropNetDNSSupplementalMatchOrders, 0, TRUE },
4738 };
4739 CFMutableDictionaryRef new_dict = NULL;
4740 const CFStringRef pick_list[] = {
4741 kSCPropNetDNSDomainName,
4742 kSCPropNetDNSOptions,
4743 kSCPropNetDNSSearchOrder,
4744 kSCPropNetDNSServerPort,
4745 kSCPropNetDNSServerTimeout,
4746 kSCPropNetDNSServiceIdentifier,
4747 kSCPropNetDNSSupplementalMatchDomainsNoSearch,
4748 };
4749 Boolean trust_state = FALSE;
4750
4751 if ((state_dict == NULL) && (setup_dict == NULL)) {
4752 /* there is no DNS content */
4753 goto done;
4754 }
4755
4756 ipv4 = service_dict_get(serviceID, kSCEntNetIPv4);
4757 if (ipv4 != NULL) {
4758 if (get_service_setup_entity(info, serviceID, kSCEntNetIPv4) != NULL) {
4759 have_setup = TRUE;
4760 }
4761 active_protos |= kProtocolFlagsIPv4;
4762 interface = ipdict_get_ifname(ipv4);
4763 }
4764
4765 ipv6 = service_dict_get(serviceID, kSCEntNetIPv6);
4766 if (ipv6 != NULL) {
4767 if (!have_setup
4768 && (get_service_setup_entity(info, serviceID, kSCEntNetIPv6)
4769 != NULL)) {
4770 have_setup = TRUE;
4771 }
4772 active_protos |= kProtocolFlagsIPv6;
4773 if (interface == NULL) {
4774 interface = ipdict_get_ifname(ipv6);
4775 }
4776 }
4777
4778
4779 if (active_protos == kProtocolFlagsNone) {
4780 /* there is no IPv4 nor IPv6 */
4781 if (state_dict == NULL) {
4782 /* ... and no DNS content that we care about */
4783 goto done;
4784 }
4785 setup_dict = NULL;
4786 }
4787
4788 if (state_dict != NULL) {
4789 CFStringRef state_serviceID = NULL;
4790
4791 if (CFDictionaryGetValueIfPresent(state_dict,
4792 kSCPropNetDNSConfirmedServiceID,
4793 (const void **)&state_serviceID) &&
4794 isA_CFString(state_serviceID) &&
4795 CFEqual(serviceID, state_serviceID)) {
4796 trust_state = TRUE;
4797 }
4798 }
4799
4800 /* merge DNS configuration */
4801 new_dict = CFDictionaryCreateMutable(NULL, 0,
4802 &kCFTypeDictionaryKeyCallBacks,
4803 &kCFTypeDictionaryValueCallBacks);
4804
4805 if (active_protos == kProtocolFlagsNone) {
4806 merge_dns_servers(new_dict,
4807 my_CFDictionaryGetArray(state_dict,
4808 kSCPropNetDNSServerAddresses),
4809 NULL,
4810 FALSE,
4811 trust_state,
4812 kProtocolFlagsIPv4 | kProtocolFlagsIPv6,
4813 NULL);
4814 }
4815 else {
4816 merge_dns_servers(new_dict,
4817 my_CFDictionaryGetArray(state_dict,
4818 kSCPropNetDNSServerAddresses),
4819 my_CFDictionaryGetArray(setup_dict,
4820 kSCPropNetDNSServerAddresses),
4821 have_setup,
4822 trust_state,
4823 active_protos,
4824 interface);
4825 }
4826
4827 for (i = 0; i < countof(merge_list); i++) {
4828 merge_array_prop(new_dict,
4829 merge_list[i].key,
4830 state_dict,
4831 setup_dict,
4832 merge_list[i].flags,
4833 merge_list[i].append);
4834 }
4835
4836 for (i = 0; i < countof(pick_list); i++) {
4837 pick_prop(new_dict,
4838 pick_list[i],
4839 state_dict,
4840 setup_dict,
4841 0);
4842 }
4843
4844 if (active_protos == kProtocolFlagsNone) {
4845 /* there is no IPv4 nor IPv6, only supplemental or service-specific DNS */
4846 if (CFDictionaryContainsKey(new_dict,
4847 kSCPropNetDNSSupplementalMatchDomains)) {
4848 /* only keep State: supplemental */
4849 CFDictionaryRemoveValue(new_dict, kSCPropNetDNSDomainName);
4850 CFDictionaryRemoveValue(new_dict, kSCPropNetDNSSearchDomains);
4851 CFDictionaryRemoveValue(new_dict, kSCPropNetDNSSearchOrder);
4852 CFDictionaryRemoveValue(new_dict, kSCPropNetDNSSortList);
4853
4854 if ((interface == NULL) && (setup_dict == NULL) && (state_dict != NULL)) {
4855 /*
4856 * for supplemental-only configurations, add any scoped (or
4857 * wild-card "*") interface
4858 */
4859 interface = CFDictionaryGetValue(state_dict, kSCPropInterfaceName);
4860 }
4861 } else if (CFDictionaryContainsKey(new_dict, kSCPropNetDNSServiceIdentifier) &&
4862 (interface == NULL) &&
4863 (state_dict != NULL)) {
4864 interface = CFDictionaryGetValue(state_dict, kSCPropInterfaceName);
4865 } else {
4866 goto done;
4867 }
4868 }
4869
4870 if (CFDictionaryGetCount(new_dict) == 0) {
4871 my_CFRelease(&new_dict);
4872 goto done;
4873 }
4874
4875 if (interface != NULL) {
4876 CFDictionarySetValue(new_dict, kSCPropInterfaceName, interface);
4877 }
4878
4879 if (S_append_state) {
4880 /*
4881 * ensure any specified domain name (e.g. the domain returned by
4882 * a DHCP server) is in the search list.
4883 */
4884 domain = CFDictionaryGetValue(new_dict, kSCPropNetDNSDomainName);
4885 if (isA_CFString(domain)) {
4886 CFArrayRef search;
4887
4888 search = CFDictionaryGetValue(new_dict, kSCPropNetDNSSearchDomains);
4889 if (isA_CFArray(search) &&
4890 !CFArrayContainsValue(search, CFRangeMake(0, CFArrayGetCount(search)), domain)) {
4891 CFMutableArrayRef new_search;
4892
4893 new_search = CFArrayCreateMutableCopy(NULL, 0, search);
4894 CFArrayAppendValue(new_search, domain);
4895 CFDictionarySetValue(new_dict, kSCPropNetDNSSearchDomains, new_search);
4896 my_CFRelease(&new_search);
4897 }
4898 }
4899 }
4900
4901 done:
4902 changed = service_dict_set(serviceID, kSCEntNetDNS, new_dict);
4903 my_CFRelease(&new_dict);
4904 return (changed);
4905 }
4906
4907 static void
4908 merge_dict(const void *key, const void *value, void *context)
4909 {
4910 CFMutableDictionaryRef dict = (CFMutableDictionaryRef)context;
4911
4912 CFDictionarySetValue(dict, key, value);
4913 return;
4914 }
4915
4916 #define PROXY_AUTO_DISCOVERY_URL 252
4917
4918 static CF_RETURNS_RETAINED CFStringRef
4919 wpadURL_dhcp(CFDictionaryRef dhcp_options)
4920 {
4921 CFStringRef urlString = NULL;
4922
4923 if (dhcp_options != NULL) {
4924 CFDataRef data;
4925
4926 data = DHCPInfoGetOptionData(dhcp_options, PROXY_AUTO_DISCOVERY_URL);
4927 if (data != NULL) {
4928 CFURLRef url;
4929 const UInt8 *urlBytes;
4930 CFIndex urlLen;
4931
4932 urlBytes = CFDataGetBytePtr(data);
4933 urlLen = CFDataGetLength(data);
4934 while ((urlLen > 0) && (urlBytes[urlLen - 1] == 0)) {
4935 // remove trailing NUL
4936 urlLen--;
4937 }
4938
4939 if (urlLen <= 0) {
4940 return NULL;
4941 }
4942
4943 url = CFURLCreateWithBytes(NULL, urlBytes, urlLen, kCFStringEncodingUTF8, NULL);
4944 if (url != NULL) {
4945 urlString = CFURLGetString(url);
4946 if (urlString != NULL) {
4947 CFRetain(urlString);
4948 }
4949 CFRelease(url);
4950 }
4951 }
4952 }
4953
4954 return urlString;
4955 }
4956
4957 static CF_RETURNS_RETAINED CFStringRef
4958 wpadURL_dns(void)
4959 {
4960 CFURLRef url;
4961 CFStringRef urlString = NULL;
4962
4963 url = CFURLCreateWithString(NULL, CFSTR("http://wpad/wpad.dat"), NULL);
4964 if (url != NULL) {
4965 urlString = CFURLGetString(url);
4966 if (urlString != NULL) {
4967 CFRetain(urlString);
4968 }
4969 CFRelease(url);
4970 }
4971
4972 return urlString;
4973 }
4974
4975 static boolean_t
4976 get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
4977 CFDictionaryRef setup_dict, CFDictionaryRef info)
4978 {
4979 ProtocolFlags active_protos = kProtocolFlagsNone;
4980 boolean_t changed = FALSE;
4981 CFStringRef interface = NULL;
4982 CFDictionaryRef ipv4;
4983 CFDictionaryRef ipv6;
4984 CFMutableDictionaryRef new_dict = NULL;
4985 const struct {
4986 CFStringRef key;
4987 uint32_t flags;
4988 Boolean append;
4989 } merge_list[] = {
4990 { kSCPropNetProxiesSupplementalMatchDomains, ALLOW_EMPTY_STRING, TRUE },
4991 { kSCPropNetProxiesSupplementalMatchOrders, 0, TRUE },
4992 };
4993 const struct {
4994 CFStringRef key1; /* an "enable" key */
4995 CFStringRef key2;
4996 CFStringRef key3;
4997 } pick_list[] = {
4998 { kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy, kSCPropNetProxiesFTPPort },
4999 { kSCPropNetProxiesGopherEnable, kSCPropNetProxiesGopherProxy, kSCPropNetProxiesGopherPort },
5000 { kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort },
5001 { kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy, kSCPropNetProxiesHTTPSPort },
5002 { kSCPropNetProxiesRTSPEnable, kSCPropNetProxiesRTSPProxy, kSCPropNetProxiesRTSPPort },
5003 { kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort },
5004 { kSCPropNetProxiesProxyAutoConfigEnable,
5005 kSCPropNetProxiesProxyAutoConfigURLString,
5006 kSCPropNetProxiesProxyAutoConfigJavaScript, },
5007 { kSCPropNetProxiesProxyAutoDiscoveryEnable,
5008 NULL,
5009 NULL, }
5010 };
5011
5012 if ((state_dict == NULL) && (setup_dict == NULL)) {
5013 /* there is no proxy content */
5014 goto done;
5015 }
5016 ipv4 = service_dict_get(serviceID, kSCEntNetIPv4);
5017 if (ipdict_get_routelist(ipv4) != NULL) {
5018 active_protos |= kProtocolFlagsIPv4;
5019 interface = ipdict_get_ifname(ipv4);
5020 }
5021 ipv6 = service_dict_get(serviceID, kSCEntNetIPv6);
5022 if (ipdict_get_routelist(ipv6) != NULL) {
5023 active_protos |= kProtocolFlagsIPv6;
5024 if (interface == NULL) {
5025 interface = ipdict_get_ifname(ipv6);
5026 }
5027 }
5028 if (active_protos == kProtocolFlagsNone) {
5029 /* there is no IPv4 nor IPv6 */
5030 if (state_dict == NULL) {
5031 /* ... and no proxy content that we care about */
5032 goto done;
5033 }
5034 setup_dict = NULL;
5035 }
5036
5037 if ((setup_dict != NULL) && (state_dict != NULL)) {
5038 CFIndex i;
5039 CFMutableDictionaryRef setup_copy;
5040
5041 /*
5042 * Merge the per-service "Setup:" and "State:" proxy information with
5043 * the "Setup:" information always taking precedence. Additionally,
5044 * ensure that if any group of "Setup:" values (e.g. Enabled, Proxy,
5045 * Port) is defined than all of the values for that group will be
5046 * used. That is, we don't allow mixing some of the values from
5047 * the "Setup:" keys and others from the "State:" keys.
5048 */
5049 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict);
5050 for (i = 0; i < countof(merge_list); i++) {
5051 merge_array_prop(new_dict,
5052 merge_list[i].key,
5053 state_dict,
5054 setup_dict,
5055 merge_list[i].flags,
5056 merge_list[i].append);
5057 }
5058
5059 setup_copy = CFDictionaryCreateMutableCopy(NULL, 0, setup_dict);
5060 for (i = 0; i < countof(pick_list); i++) {
5061 if (CFDictionaryContainsKey(setup_copy, pick_list[i].key1)) {
5062 /*
5063 * if a "Setup:" enabled key has been provided than we want to
5064 * ignore all of the "State:" keys
5065 */
5066 CFDictionaryRemoveValue(new_dict, pick_list[i].key1);
5067 if (pick_list[i].key2 != NULL) {
5068 CFDictionaryRemoveValue(new_dict, pick_list[i].key2);
5069 }
5070 if (pick_list[i].key3 != NULL) {
5071 CFDictionaryRemoveValue(new_dict, pick_list[i].key3);
5072 }
5073 } else if (CFDictionaryContainsKey(state_dict, pick_list[i].key1) ||
5074 ((pick_list[i].key2 != NULL) && CFDictionaryContainsKey(state_dict, pick_list[i].key2)) ||
5075 ((pick_list[i].key3 != NULL) && CFDictionaryContainsKey(state_dict, pick_list[i].key3))) {
5076 /*
5077 * if a "Setup:" enabled key has not been provided and we have
5078 * some" "State:" keys than we remove all of of "Setup:" keys
5079 */
5080 CFDictionaryRemoveValue(setup_copy, pick_list[i].key1);
5081 if (pick_list[i].key2 != NULL) {
5082 CFDictionaryRemoveValue(setup_copy, pick_list[i].key2);
5083 }
5084 if (pick_list[i].key3 != NULL) {
5085 CFDictionaryRemoveValue(setup_copy, pick_list[i].key3);
5086 }
5087 }
5088 }
5089
5090 /* merge the "Setup:" keys */
5091 CFDictionaryApplyFunction(setup_copy, merge_dict, new_dict);
5092 CFRelease(setup_copy);
5093 }
5094 else if (setup_dict != NULL) {
5095 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, setup_dict);
5096 }
5097 else if (state_dict != NULL) {
5098 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, state_dict);
5099 }
5100
5101 if ((new_dict != NULL) && (CFDictionaryGetCount(new_dict) == 0)) {
5102 CFRelease(new_dict);
5103 new_dict = NULL;
5104 }
5105
5106 if ((new_dict != NULL) && (interface != NULL)) {
5107 CFDictionarySetValue(new_dict, kSCPropInterfaceName, interface);
5108 }
5109
5110 /* process WPAD */
5111 if (new_dict != NULL) {
5112 CFDictionaryRef dhcp_options;
5113 CFNumberRef num;
5114 CFNumberRef wpad = NULL;
5115 int wpadEnabled = 0;
5116 CFStringRef wpadURL = NULL;
5117
5118 if (CFDictionaryGetValueIfPresent(new_dict,
5119 kSCPropNetProxiesProxyAutoDiscoveryEnable,
5120 (const void **)&num) &&
5121 isA_CFNumber(num)) {
5122 /* if we have a WPAD key */
5123 wpad = num;
5124 if (!CFNumberGetValue(num, kCFNumberIntType, &wpadEnabled)) {
5125 /* if we don't like the enabled key/value */
5126 wpadEnabled = 0;
5127 }
5128 }
5129
5130 if (wpadEnabled) {
5131 int pacEnabled = 0;
5132
5133 num = CFDictionaryGetValue(new_dict, kSCPropNetProxiesProxyAutoConfigEnable);
5134 if (!isA_CFNumber(num) ||
5135 !CFNumberGetValue(num, kCFNumberIntType, &pacEnabled)) {
5136 /* if we don't like the enabled key/value */
5137 pacEnabled = 0;
5138 }
5139
5140 if (pacEnabled) {
5141 CFStringRef pacURL;
5142
5143 pacURL = CFDictionaryGetValue(new_dict, kSCPropNetProxiesProxyAutoConfigURLString);
5144 if (pacURL != NULL) {
5145 if (!isA_CFString(pacURL) || (CFStringGetLength(pacURL) == 0)) {
5146 /* if we don't like the PAC URL */
5147 pacEnabled = 0;
5148 }
5149 } else {
5150 CFStringRef pacJS;
5151
5152 pacJS = CFDictionaryGetValue(new_dict, kSCPropNetProxiesProxyAutoConfigJavaScript);
5153 if (!isA_CFString(pacJS) || (CFStringGetLength(pacJS) == 0)) {
5154 /* if we don't have (or like) the PAC JavaScript */
5155 pacEnabled = 0;
5156 }
5157 }
5158 }
5159
5160 if (pacEnabled) {
5161 /*
5162 * we already have a PAC URL so disable WPAD.
5163 */
5164 wpadEnabled = 0;
5165 goto setWPAD;
5166 }
5167
5168 /*
5169 * if WPAD is enabled and we don't already have a PAC URL then
5170 * we check for a DHCP provided URL. If not available, we use
5171 * a PAC URL pointing to a well-known file (wpad.dat) on a
5172 * well-known host (wpad.<domain>).
5173 */
5174 dhcp_options = get_service_state_entity(info, serviceID, kSCEntNetDHCP);
5175 wpadURL = wpadURL_dhcp(dhcp_options);
5176 if (wpadURL == NULL) {
5177 wpadURL = wpadURL_dns();
5178 }
5179 if (wpadURL == NULL) {
5180 wpadEnabled = 0; /* if we don't have a WPAD URL */
5181 goto setWPAD;
5182 }
5183
5184 pacEnabled = 1;
5185 num = CFNumberCreate(NULL, kCFNumberIntType, &pacEnabled);
5186 CFDictionarySetValue(new_dict,
5187 kSCPropNetProxiesProxyAutoConfigEnable,
5188 num);
5189 CFRelease(num);
5190 CFDictionarySetValue(new_dict,
5191 kSCPropNetProxiesProxyAutoConfigURLString,
5192 wpadURL);
5193 CFRelease(wpadURL);
5194 }
5195
5196 setWPAD:
5197 if (wpad != NULL) {
5198 num = CFNumberCreate(NULL, kCFNumberIntType, &wpadEnabled);
5199 CFDictionarySetValue(new_dict,
5200 kSCPropNetProxiesProxyAutoDiscoveryEnable,
5201 num);
5202 CFRelease(num);
5203 }
5204 }
5205
5206 done:
5207 changed = service_dict_set(serviceID, kSCEntNetProxies, new_dict);
5208 my_CFRelease(&new_dict);
5209 return (changed);
5210 }
5211
5212 #if !TARGET_OS_IPHONE
5213 static boolean_t
5214 get_smb_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
5215 CFDictionaryRef setup_dict, CFDictionaryRef info)
5216 {
5217 boolean_t changed = FALSE;
5218 int i;
5219 CFMutableDictionaryRef new_dict = NULL;
5220 const CFStringRef pick_list[] = {
5221 kSCPropNetSMBNetBIOSName,
5222 kSCPropNetSMBNetBIOSNodeType,
5223 #ifdef ADD_NETBIOS_SCOPE
5224 kSCPropNetSMBNetBIOSScope,
5225 #endif // ADD_NETBIOS_SCOPE
5226 kSCPropNetSMBWorkgroup,
5227 };
5228
5229 if (state_dict == NULL && setup_dict == NULL) {
5230 /* there is no SMB */
5231 goto done;
5232 }
5233 if (service_dict_get(serviceID, kSCEntNetIPv4) == NULL
5234 && service_dict_get(serviceID, kSCEntNetIPv6) == NULL) {
5235 /* there is no IPv4 or IPv6 */
5236 goto done;
5237 }
5238
5239 /* merge SMB configuration */
5240 new_dict = CFDictionaryCreateMutable(NULL, 0,
5241 &kCFTypeDictionaryKeyCallBacks,
5242 &kCFTypeDictionaryValueCallBacks);
5243 merge_array_prop(new_dict,
5244 kSCPropNetSMBWINSAddresses,
5245 state_dict,
5246 setup_dict,
5247 0,
5248 FALSE);
5249 for (i = 0; i < countof(pick_list); i++) {
5250 pick_prop(new_dict,
5251 pick_list[i],
5252 state_dict,
5253 setup_dict,
5254 0);
5255 }
5256
5257 if (CFDictionaryGetCount(new_dict) == 0) {
5258 my_CFRelease(&new_dict);
5259 goto done;
5260 }
5261
5262 done:
5263 changed = service_dict_set(serviceID, kSCEntNetSMB, new_dict);
5264 my_CFRelease(&new_dict);
5265 return (changed);
5266 }
5267 #endif /* !TARGET_OS_IPHONE */
5268
5269 static CFStringRef
5270 services_info_get_interface(CFDictionaryRef services_info,
5271 CFStringRef serviceID)
5272 {
5273 CFStringRef interface = NULL;
5274 CFDictionaryRef ipv4_dict;
5275
5276 ipv4_dict = get_service_state_entity(services_info, serviceID,
5277 kSCEntNetIPv4);
5278 if (ipv4_dict != NULL) {
5279 interface = CFDictionaryGetValue(ipv4_dict, kSCPropInterfaceName);
5280 }
5281 else {
5282 CFDictionaryRef ipv6_dict;
5283
5284 ipv6_dict = get_service_state_entity(services_info, serviceID,
5285 kSCEntNetIPv6);
5286 if (ipv6_dict != NULL) {
5287 interface = CFDictionaryGetValue(ipv6_dict, kSCPropInterfaceName);
5288 }
5289 }
5290 return (interface);
5291 }
5292
5293
5294 static const struct {
5295 const CFStringRef * entityName;
5296 const CFStringRef * statusKey;
5297 } transientServiceInfo[] = {
5298 { &kSCEntNetIPSec, &kSCPropNetIPSecStatus },
5299 { &kSCEntNetPPP, &kSCPropNetPPPStatus },
5300 { &kSCEntNetVPN, &kSCPropNetVPNStatus },
5301 };
5302
5303 static Boolean
5304 get_transient_status_changes(CFStringRef serviceID,
5305 CFDictionaryRef services_info)
5306 {
5307 boolean_t changed = FALSE;
5308 int i;
5309
5310 for (i = 0; i < countof(transientServiceInfo); i++) {
5311 CFDictionaryRef dict;
5312 CFNumberRef status = NULL;
5313 CFMutableDictionaryRef ts_dict = NULL;
5314
5315 dict = get_service_state_entity(services_info, serviceID,
5316 *transientServiceInfo[i].entityName);
5317
5318 if (dict != NULL) {
5319 status = CFDictionaryGetValue(dict,
5320 *transientServiceInfo[i].statusKey);
5321 }
5322
5323 if (isA_CFNumber(status) != NULL) {
5324 ts_dict = CFDictionaryCreateMutable(NULL,
5325 0,
5326 &kCFTypeDictionaryKeyCallBacks,
5327 &kCFTypeDictionaryValueCallBacks);
5328 CFDictionaryAddValue(ts_dict,
5329 *transientServiceInfo[i].statusKey,
5330 status);
5331 }
5332
5333 if (service_dict_set(serviceID, *transientServiceInfo[i].entityName,
5334 ts_dict)) {
5335 changed = TRUE;
5336 }
5337
5338 if (ts_dict != NULL) {
5339 CFRelease(ts_dict);
5340 }
5341 }
5342 return (changed);
5343 }
5344
5345 static boolean_t
5346 if_dict_is_expensive(CFDictionaryRef if_dict)
5347 {
5348 boolean_t is_expensive = FALSE;
5349
5350 if (isA_CFDictionary(if_dict) != NULL) {
5351 CFBooleanRef expensive;
5352 expensive = CFDictionaryGetValue(if_dict, kSCPropNetLinkExpensive);
5353 if (isA_CFBoolean(expensive) != NULL
5354 && CFBooleanGetValue(expensive)) {
5355 is_expensive = TRUE;
5356 }
5357 }
5358 return is_expensive;
5359 }
5360
5361 static boolean_t
5362 service_is_expensive(CFStringRef serviceID, CFDictionaryRef services_info)
5363 {
5364 CFStringRef ifname;
5365 boolean_t is_expensive = FALSE;
5366
5367 ifname = services_info_get_interface(services_info, serviceID);
5368 if (ifname != NULL) {
5369 CFDictionaryRef if_dict;
5370 CFStringRef key;
5371
5372 key = interface_entity_key_copy(ifname, kSCEntNetLink);
5373 if_dict = CFDictionaryGetValue(services_info, key);
5374 CFRelease(key);
5375 is_expensive = if_dict_is_expensive(if_dict);
5376 }
5377 return (is_expensive);
5378 }
5379
5380 static boolean_t
5381 interface_is_expensive(CFStringRef ifname)
5382 {
5383 boolean_t is_expensive = FALSE;
5384
5385 if (ifname != NULL) {
5386 CFDictionaryRef if_dict;
5387 CFStringRef key;
5388
5389 key = interface_entity_key_copy(ifname, kSCEntNetLink);
5390 if_dict = SCDynamicStoreCopyValue(S_session, key);
5391 CFRelease(key);
5392 if (if_dict != NULL) {
5393 is_expensive = if_dict_is_expensive(if_dict);
5394 CFRelease(if_dict);
5395 }
5396 }
5397 return (is_expensive);
5398 }
5399
5400 static CFNumberRef
5401 service_rank_entity_get_index(CFDictionaryRef dict, CFStringRef serviceID,
5402 CFStringRef which, uint32_t * ret_val)
5403 {
5404 CFNumberRef service_index = NULL;
5405
5406 if (dict != NULL) {
5407 service_index = CFDictionaryGetValue(dict,
5408 kSCPropNetServiceServiceIndex);
5409 service_index = isA_CFNumber(service_index);
5410 }
5411 if (service_index != NULL) {
5412 SInt32 index_val;
5413
5414 if (!CFNumberGetValue(service_index, kCFNumberSInt32Type,
5415 &index_val)
5416 || index_val <= 0) {
5417 /* ServiceIndex must be >= 1 */
5418 my_log(LOG_NOTICE,
5419 "%@%@ ServiceIndex %@ is invalid, ignoring",
5420 which, serviceID, service_index);
5421 service_index = NULL;
5422 }
5423 else if (ret_val != NULL) {
5424 *ret_val = (uint32_t)index_val;
5425 }
5426 }
5427 return (service_index);
5428 }
5429
5430 static boolean_t
5431 get_rank_changes(CFStringRef serviceID, CFDictionaryRef state_options,
5432 CFDictionaryRef setup_options, CFDictionaryRef services_info)
5433 {
5434 boolean_t changed = FALSE;
5435 boolean_t ip_is_coupled = FALSE;
5436 CFMutableDictionaryRef new_dict = NULL;
5437 Rank rank_assertion = kRankAssertionDefault;
5438 Boolean rank_assertion_is_set = FALSE;
5439 CFStringRef setup_rank = NULL;
5440 CFStringRef state_rank = NULL;
5441 CFNumberRef service_index = NULL;
5442
5443
5444 if (setup_options != NULL) {
5445 CFBooleanRef coupled;
5446
5447 setup_rank
5448 = CFDictionaryGetValue(setup_options, kSCPropNetServicePrimaryRank);
5449 setup_rank = isA_CFString(setup_rank);
5450 coupled = CFDictionaryGetValue(setup_options, kIPIsCoupled);
5451 if (isA_CFBoolean(coupled) != NULL && CFBooleanGetValue(coupled)) {
5452 ip_is_coupled = TRUE;
5453 }
5454 service_index
5455 = service_rank_entity_get_index(setup_options,
5456 serviceID,
5457 kSCDynamicStoreDomainSetup,
5458 NULL);
5459 }
5460 if (state_options != NULL) {
5461 CFBooleanRef coupled;
5462
5463 state_rank
5464 = CFDictionaryGetValue(state_options, kSCPropNetServicePrimaryRank);
5465 state_rank = isA_CFString(state_rank);
5466 coupled = CFDictionaryGetValue(state_options, kIPIsCoupled);
5467 if (isA_CFBoolean(coupled) != NULL && CFBooleanGetValue(coupled)) {
5468 ip_is_coupled = TRUE;
5469 }
5470 if (service_index == NULL) {
5471 service_index
5472 = service_rank_entity_get_index(state_options,
5473 serviceID,
5474 kSCDynamicStoreDomainState,
5475 NULL);
5476 }
5477 }
5478
5479 if (!ip_is_coupled) {
5480 ip_is_coupled = service_is_expensive(serviceID, services_info);
5481 }
5482 if (setup_rank != NULL || state_rank != NULL) {
5483 /* rank assertion is set on the service */
5484 Rank setup_assertion;
5485 Boolean setup_assertion_is_set = FALSE;
5486 Rank state_assertion;
5487 Boolean state_assertion_is_set = FALSE;
5488
5489 setup_assertion = PrimaryRankGetRankAssertion(setup_rank,
5490 &setup_assertion_is_set);
5491 state_assertion = PrimaryRankGetRankAssertion(state_rank,
5492 &state_assertion_is_set);
5493 if (setup_assertion_is_set && state_assertion_is_set) {
5494 if (setup_assertion > state_assertion) {
5495 rank_assertion = setup_assertion;
5496 }
5497 else {
5498 rank_assertion = state_assertion;
5499 }
5500 rank_assertion_is_set = TRUE;
5501 }
5502 else if (setup_assertion_is_set) {
5503 rank_assertion = setup_assertion;
5504 rank_assertion_is_set = TRUE;
5505 }
5506 else if (state_assertion_is_set) {
5507 rank_assertion = state_assertion;
5508 rank_assertion_is_set = TRUE;
5509 }
5510 }
5511
5512 if (!rank_assertion_is_set) {
5513 /* check for a rank assertion on the interface */
5514 CFStringRef interface;
5515
5516 interface = services_info_get_interface(services_info, serviceID);
5517 if (interface != NULL) {
5518 CFNumberRef if_rank = NULL;
5519
5520 if (S_if_rank_dict != NULL) {
5521 if_rank = CFDictionaryGetValue(S_if_rank_dict, interface);
5522 }
5523 rank_assertion
5524 = InterfaceRankGetRankAssertion(if_rank,
5525 &rank_assertion_is_set);
5526 my_log(LOG_INFO,
5527 "serviceID %@ interface %@ rank = %@",
5528 serviceID,
5529 interface,
5530 (if_rank != NULL) ? (CFTypeRef)if_rank : (CFTypeRef)CFSTR("Not set)"));
5531 }
5532 }
5533
5534
5535 if (service_index != NULL || rank_assertion_is_set || ip_is_coupled) {
5536 new_dict = CFDictionaryCreateMutable(NULL, 0,
5537 &kCFTypeDictionaryKeyCallBacks,
5538 &kCFTypeDictionaryValueCallBacks);
5539 if (rank_assertion_is_set) {
5540 CFNumberRef new_rank;
5541
5542 new_rank = CFNumberCreate(NULL, kCFNumberSInt32Type,
5543 (const void *)&rank_assertion);
5544 CFDictionarySetValue(new_dict, kServiceOptionRankAssertion,
5545 new_rank);
5546 CFRelease(new_rank);
5547 }
5548 if (ip_is_coupled) {
5549 CFDictionarySetValue(new_dict, kIPIsCoupled, kCFBooleanTrue);
5550 }
5551 if (service_index != NULL) {
5552 CFDictionarySetValue(new_dict, kSCPropNetServiceServiceIndex,
5553 service_index);
5554 }
5555 }
5556 changed = service_dict_set(serviceID, kSCEntNetService, new_dict);
5557 my_CFRelease(&new_dict);
5558 return (changed);
5559 }
5560
5561 static void
5562 add_service_keys(CFStringRef serviceID,
5563 CFMutableArrayRef keys, CFMutableArrayRef patterns)
5564 {
5565 int i;
5566 CFStringRef key;
5567
5568 if (CFEqual(serviceID, kSCCompAnyRegex)) {
5569 keys = patterns;
5570 }
5571
5572 for (i = 0; i < ENTITY_TYPES_COUNT; i++) {
5573 key = setup_service_key(serviceID, *entityTypeNames[i]);
5574 CFArrayAppendValue(keys, key);
5575 CFRelease(key);
5576 key = state_service_key(serviceID, *entityTypeNames[i]);
5577 CFArrayAppendValue(keys, key);
5578 CFRelease(key);
5579 }
5580
5581 key = state_service_key(serviceID, kSCEntNetDHCP);
5582 CFArrayAppendValue(patterns, key);
5583 CFRelease(key);
5584
5585 key = setup_service_key(serviceID, NULL);
5586 CFArrayAppendValue(patterns, key);
5587 CFRelease(key);
5588 key = state_service_key(serviceID, NULL);
5589 CFArrayAppendValue(patterns, key);
5590 CFRelease(key);
5591
5592 return;
5593 }
5594
5595 static void
5596 add_transient_status_keys(CFStringRef service_id, CFMutableArrayRef patterns)
5597 {
5598 int i;
5599
5600 for (i = 0; i < countof(transientServiceInfo); i++) {
5601 CFStringRef pattern;
5602
5603 pattern = state_service_key(service_id,
5604 *transientServiceInfo[i].entityName);
5605 CFArrayAppendValue(patterns, pattern);
5606 CFRelease(pattern);
5607 }
5608
5609 return;
5610 }
5611
5612 static const CFStringRef *reachabilitySetupKeys[] = {
5613 &kSCEntNetPPP,
5614 &kSCEntNetInterface,
5615 &kSCEntNetIPv4,
5616 &kSCEntNetIPv6,
5617 };
5618
5619
5620 static void
5621 add_reachability_patterns(CFMutableArrayRef patterns)
5622 {
5623 int i;
5624
5625 for (i = 0; i < countof(reachabilitySetupKeys); i++) {
5626 CFStringRef pattern;
5627 pattern = setup_service_key(kSCCompAnyRegex, *reachabilitySetupKeys[i]);
5628 CFArrayAppendValue(patterns, pattern);
5629 CFRelease(pattern);
5630 }
5631 }
5632
5633
5634 static void
5635 add_vpn_pattern(CFMutableArrayRef patterns)
5636 {
5637 CFStringRef pattern;
5638
5639 pattern = setup_service_key(kSCCompAnyRegex, kSCEntNetVPN);
5640 CFArrayAppendValue(patterns, pattern);
5641 CFRelease(pattern);
5642 }
5643
5644 static void
5645 add_interface_link_pattern(CFMutableArrayRef patterns)
5646 {
5647 CFStringRef pattern;
5648
5649 pattern = interface_entity_key_copy(kSCCompAnyRegex, kSCEntNetLink);
5650 CFArrayAppendValue(patterns, pattern);
5651 CFRelease(pattern);
5652 }
5653
5654 static CFDictionaryRef
5655 services_info_copy(SCDynamicStoreRef session, CFArrayRef service_list)
5656 {
5657 CFIndex count;
5658 CFMutableArrayRef get_keys;
5659 CFMutableArrayRef get_patterns;
5660 CFDictionaryRef info;
5661 CFIndex s;
5662
5663 count = CFArrayGetCount(service_list);
5664 get_keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5665 get_patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
5666
5667 CFArrayAppendValue(get_keys, S_setup_global_ipv4);
5668 CFArrayAppendValue(get_keys, S_multicast_resolvers);
5669 CFArrayAppendValue(get_keys, S_private_resolvers);
5670
5671 for (s = 0; s < count; s++) {
5672 CFStringRef serviceID = CFArrayGetValueAtIndex(service_list, s);
5673
5674 add_service_keys(serviceID, get_keys, get_patterns);
5675 add_transient_status_keys(serviceID, get_keys);
5676 }
5677
5678 add_reachability_patterns(get_patterns);
5679
5680 add_vpn_pattern(get_patterns);
5681
5682 add_interface_link_pattern(get_patterns);
5683
5684 info = SCDynamicStoreCopyMultiple(session, get_keys, get_patterns);
5685 my_CFRelease(&get_keys);
5686 my_CFRelease(&get_patterns);
5687 return (info);
5688 }
5689
5690 #if !TARGET_OS_SIMULATOR
5691
5692 static boolean_t
5693 set_ipv6_default_interface(IFIndex ifindex)
5694 {
5695 struct in6_ndifreq ndifreq;
5696 int sock;
5697 boolean_t success = FALSE;
5698
5699 bzero((char *)&ndifreq, sizeof(ndifreq));
5700 strlcpy(ndifreq.ifname, kLoopbackInterface, sizeof(ndifreq.ifname));
5701 if (ifindex != 0) {
5702 ndifreq.ifindex = ifindex;
5703 }
5704 else {
5705 ndifreq.ifindex = lo0_ifindex();
5706 }
5707 sock = inet6_dgram_socket();
5708 if (sock < 0) {
5709 goto done;
5710 }
5711 if (ioctl(sock, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) == -1) {
5712 my_log(LOG_ERR,
5713 "ioctl(SIOCSDEFIFACE_IN6) failed: %s",
5714 strerror(errno));
5715 }
5716 else {
5717 success = TRUE;
5718 }
5719 close(sock);
5720 done:
5721 return (success);
5722 }
5723
5724 #endif /* !TARGET_OS_SIMULATOR */
5725
5726 #if !TARGET_OS_IPHONE
5727 static __inline__ void
5728 empty_dns()
5729 {
5730 (void)unlink(VAR_RUN_RESOLV_CONF);
5731 }
5732
5733 static void
5734 set_dns(CFArrayRef val_search_domains,
5735 CFStringRef val_domain_name,
5736 CFArrayRef val_servers,
5737 CFArrayRef val_sortlist)
5738 {
5739 FILE * f = fopen(VAR_RUN_RESOLV_CONF "-", "w");
5740
5741 /* publish new resolv.conf */
5742 if (f) {
5743 CFIndex i;
5744 CFIndex n;
5745
5746 SCPrint(TRUE, f, CFSTR("#\n"));
5747 SCPrint(TRUE, f, CFSTR("# Mac OS X Notice\n"));
5748 SCPrint(TRUE, f, CFSTR("#\n"));
5749 SCPrint(TRUE, f, CFSTR("# This file is not used by the host name and address resolution\n"));
5750 SCPrint(TRUE, f, CFSTR("# or the DNS query routing mechanisms used by most processes on\n"));
5751 SCPrint(TRUE, f, CFSTR("# this Mac OS X system.\n"));
5752 SCPrint(TRUE, f, CFSTR("#\n"));
5753 SCPrint(TRUE, f, CFSTR("# This file is automatically generated.\n"));
5754 SCPrint(TRUE, f, CFSTR("#\n"));
5755
5756 if (isA_CFArray(val_search_domains)) {
5757 SCPrint(TRUE, f, CFSTR("search"));
5758 n = CFArrayGetCount(val_search_domains);
5759 for (i = 0; i < n; i++) {
5760 CFStringRef domain;
5761
5762 domain = CFArrayGetValueAtIndex(val_search_domains, i);
5763 if (isA_CFString(domain)) {
5764 SCPrint(TRUE, f, CFSTR(" %@"), domain);
5765 }
5766 }
5767 SCPrint(TRUE, f, CFSTR("\n"));
5768 }
5769 else if (isA_CFString(val_domain_name)) {
5770 SCPrint(TRUE, f, CFSTR("domain %@\n"), val_domain_name);
5771 }
5772
5773 if (isA_CFArray(val_servers)) {
5774 n = CFArrayGetCount(val_servers);
5775 for (i = 0; i < n; i++) {
5776 CFStringRef nameserver;
5777
5778 nameserver = CFArrayGetValueAtIndex(val_servers, i);
5779 if (isA_CFString(nameserver)) {
5780 SCPrint(TRUE, f, CFSTR("nameserver %@\n"), nameserver);
5781 }
5782 }
5783 }
5784
5785 if (isA_CFArray(val_sortlist)) {
5786 SCPrint(TRUE, f, CFSTR("sortlist"));
5787 n = CFArrayGetCount(val_sortlist);
5788 for (i = 0; i < n; i++) {
5789 CFStringRef address;
5790
5791 address = CFArrayGetValueAtIndex(val_sortlist, i);
5792 if (isA_CFString(address)) {
5793 SCPrint(TRUE, f, CFSTR(" %@"), address);
5794 }
5795 }
5796 SCPrint(TRUE, f, CFSTR("\n"));
5797 }
5798
5799 fclose(f);
5800 (void)rename(VAR_RUN_RESOLV_CONF "-", VAR_RUN_RESOLV_CONF);
5801 }
5802 return;
5803 }
5804 #endif /* !TARGET_OS_IPHONE */
5805
5806 static boolean_t
5807 service_get_ip_is_coupled(CFStringRef serviceID)
5808 {
5809 CFDictionaryRef dict;
5810 boolean_t ip_is_coupled = FALSE;
5811
5812 dict = service_dict_get(serviceID, kSCEntNetService);
5813 if (dict != NULL) {
5814 if (CFDictionaryContainsKey(dict, kIPIsCoupled)) {
5815 ip_is_coupled = TRUE;
5816 }
5817 }
5818 return (ip_is_coupled);
5819 }
5820
5821 static CFStringRef
5822 my_CFStringCreateWithInAddr(struct in_addr ip)
5823 {
5824 CFStringRef str;
5825
5826 str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&ip));
5827 return (str);
5828 }
5829
5830 static CFStringRef
5831 my_CFStringCreateWithIn6Addr(const struct in6_addr * ip)
5832 {
5833 char ntopbuf[INET6_ADDRSTRLEN];
5834
5835 (void)inet_ntop(AF_INET6, ip, ntopbuf, sizeof(ntopbuf));
5836 return (CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), ntopbuf));
5837 }
5838
5839 /*
5840 * Function: update_ipv4
5841 * Purpose:
5842 * Update the IPv4 configuration based on the latest information.
5843 * Publish the State:/Network/Global/IPv4 information, and update the
5844 * IPv4 routing table.
5845 */
5846 static void
5847 update_ipv4(CFStringRef primary,
5848 IPv4RouteListRef new_routelist,
5849 keyChangeListRef keys)
5850 {
5851 #if !TARGET_OS_SIMULATOR
5852 int sockfd;
5853 #endif /* !TARGET_OS_SIMULATOR */
5854
5855 if (keys != NULL) {
5856 if (new_routelist != NULL && primary != NULL) {
5857 const char * ifn_p = NULL;
5858 char ifname[IFNAMSIZ];
5859 IPv4RouteRef r;
5860 CFMutableDictionaryRef dict = NULL;
5861
5862 dict = CFDictionaryCreateMutable(NULL, 0,
5863 &kCFTypeDictionaryKeyCallBacks,
5864 &kCFTypeDictionaryValueCallBacks);
5865 /* the first entry is the default route */
5866 r = new_routelist->list;
5867 if (r->gateway.s_addr != 0) {
5868 CFStringRef str;
5869
5870 str = my_CFStringCreateWithInAddr(r->gateway);
5871 CFDictionarySetValue(dict, kSCPropNetIPv4Router, str);
5872 CFRelease(str);
5873 }
5874 ifn_p = my_if_indextoname(r->ifindex, ifname);
5875 if (ifn_p != NULL) {
5876 CFStringRef ifname_cf;
5877
5878 ifname_cf = CFStringCreateWithCString(NULL,
5879 ifn_p,
5880 kCFStringEncodingASCII);
5881 if (ifname_cf != NULL) {
5882 CFDictionarySetValue(dict,
5883 kSCDynamicStorePropNetPrimaryInterface,
5884 ifname_cf);
5885 CFRelease(ifname_cf);
5886 }
5887 }
5888 CFDictionarySetValue(dict, kSCDynamicStorePropNetPrimaryService,
5889 primary);
5890 keyChangeListSetValue(keys, S_state_global_ipv4, dict);
5891 CFRelease(dict);
5892 }
5893 else {
5894 keyChangeListRemoveValue(keys, S_state_global_ipv4);
5895 }
5896 }
5897
5898 #if !TARGET_OS_SIMULATOR
5899 sockfd = open_routing_socket();
5900 if (sockfd != -1) {
5901 /* go through routelist and bind any unbound routes */
5902 if (new_routelist != NULL) {
5903 IPv4RouteListFinalize(new_routelist);
5904 }
5905 else {
5906 /* provide a routelist with just loopback multicast */
5907 new_routelist = IPv4RouteListCopyMulticastLoopback();
5908 }
5909 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
5910 if (S_ipv4_routelist == NULL) {
5911 my_log(LOG_DEBUG, "Old Routes = <none>");
5912 }
5913 else {
5914 my_log(LOG_DEBUG, "Old Routes = ");
5915 IPv4RouteListLog(LOG_DEBUG, S_ipv4_routelist);
5916 }
5917 if (new_routelist == NULL) {
5918 my_log(LOG_DEBUG, "New Routes = <none>");
5919 }
5920 else {
5921 my_log(LOG_DEBUG, "New Routes = ");
5922 IPv4RouteListLog(LOG_DEBUG, new_routelist);
5923 }
5924 }
5925 IPv4RouteListApply(S_ipv4_routelist, new_routelist, sockfd);
5926 close(sockfd);
5927 }
5928 if (S_ipv4_routelist != NULL) {
5929 free(S_ipv4_routelist);
5930 }
5931 S_ipv4_routelist = new_routelist;
5932 #else /* !TARGET_OS_SIMULATOR */
5933 if (new_routelist != NULL) {
5934 free(new_routelist);
5935 }
5936 #endif /* !TARGET_OS_SIMULATOR */
5937
5938 return;
5939 }
5940
5941 /*
5942 * Function: update_ipv6
5943 * Purpose:
5944 * Update the IPv6 configuration based on the latest information.
5945 * Publish the State:/Network/Global/IPv6 information, and update the
5946 * IPv6 routing table.
5947 */
5948 static void
5949 update_ipv6(CFStringRef primary,
5950 IPv6RouteListRef new_routelist,
5951 keyChangeListRef keys)
5952 {
5953 #if !TARGET_OS_SIMULATOR
5954 int sockfd;
5955 #endif /* !TARGET_OS_SIMULATOR */
5956
5957 if (keys != NULL) {
5958 if (new_routelist != NULL && primary != NULL) {
5959 const char * ifn_p = NULL;
5960 char ifname[IFNAMSIZ];
5961 IPv6RouteRef r;
5962 CFMutableDictionaryRef dict = NULL;
5963
5964 dict = CFDictionaryCreateMutable(NULL, 0,
5965 &kCFTypeDictionaryKeyCallBacks,
5966 &kCFTypeDictionaryValueCallBacks);
5967 /* the first entry is the default route */
5968 r = new_routelist->list;
5969 if ((r->flags & kRouteFlagsHasGateway) != 0) {
5970 CFStringRef router;
5971
5972 router = my_CFStringCreateWithIn6Addr(&r->gateway);
5973 CFDictionarySetValue(dict, kSCPropNetIPv6Router, router);
5974 CFRelease(router);
5975 }
5976 ifn_p = my_if_indextoname(r->ifindex, ifname);
5977 if (ifn_p != NULL) {
5978 CFStringRef ifname_cf;
5979
5980 ifname_cf = CFStringCreateWithCString(NULL,
5981 ifn_p,
5982 kCFStringEncodingASCII);
5983 if (ifname_cf != NULL) {
5984 CFDictionarySetValue(dict,
5985 kSCDynamicStorePropNetPrimaryInterface,
5986 ifname_cf);
5987 CFRelease(ifname_cf);
5988 }
5989 }
5990 CFDictionarySetValue(dict, kSCDynamicStorePropNetPrimaryService,
5991 primary);
5992 keyChangeListSetValue(keys, S_state_global_ipv6, dict);
5993 CFRelease(dict);
5994 #if !TARGET_OS_SIMULATOR
5995 set_ipv6_default_interface(r->ifindex);
5996 #endif /* !TARGET_OS_SIMULATOR */
5997 }
5998 else {
5999 #if !TARGET_OS_SIMULATOR
6000 set_ipv6_default_interface(0);
6001 #endif /* !TARGET_OS_SIMULATOR */
6002 keyChangeListRemoveValue(keys, S_state_global_ipv6);
6003 }
6004 }
6005
6006 #if !TARGET_OS_SIMULATOR
6007 sockfd = open_routing_socket();
6008 if (sockfd != -1) {
6009 /* go through routelist and bind any unbound routes */
6010 IPv6RouteListFinalize(new_routelist);
6011 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
6012 if (S_ipv6_routelist == NULL) {
6013 my_log(LOG_DEBUG, "Old Routes = <none>");
6014 }
6015 else {
6016 my_log(LOG_DEBUG, "Old Routes = ");
6017 IPv6RouteListLog(LOG_DEBUG, S_ipv6_routelist);
6018 }
6019 if (new_routelist == NULL) {
6020 my_log(LOG_DEBUG, "New Routes = <none>");
6021 }
6022 else {
6023 my_log(LOG_DEBUG, "New Routes = ");
6024 IPv6RouteListLog(LOG_DEBUG, new_routelist);
6025 }
6026 }
6027 IPv6RouteListApply(S_ipv6_routelist, new_routelist, sockfd);
6028 close(sockfd);
6029 }
6030 if (S_ipv6_routelist != NULL) {
6031 free(S_ipv6_routelist);
6032 }
6033 S_ipv6_routelist = new_routelist;
6034 #else /* !TARGET_OS_SIMULATOR */
6035 if (new_routelist != NULL) {
6036 free(new_routelist);
6037 }
6038 #endif /* !TARGET_OS_SIMULATOR */
6039
6040 return;
6041 }
6042
6043 static Boolean
6044 update_dns(CFDictionaryRef services_info,
6045 CFStringRef primary,
6046 keyChangeListRef keys)
6047 {
6048 Boolean changed = FALSE;
6049 CFDictionaryRef dict = NULL;
6050
6051 if (primary != NULL) {
6052 CFDictionaryRef service_dict;
6053
6054 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
6055 if (service_dict != NULL) {
6056 dict = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
6057 }
6058 }
6059
6060 if (!_SC_CFEqual(S_dns_dict, dict)) {
6061 if (dict == NULL) {
6062 #if !TARGET_OS_IPHONE
6063 empty_dns();
6064 #endif /* !TARGET_OS_IPHONE */
6065 keyChangeListRemoveValue(keys, S_state_global_dns);
6066 } else {
6067 CFMutableDictionaryRef new_dict;
6068
6069 #if !TARGET_OS_IPHONE
6070 set_dns(CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains),
6071 CFDictionaryGetValue(dict, kSCPropNetDNSDomainName),
6072 CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses),
6073 CFDictionaryGetValue(dict, kSCPropNetDNSSortList));
6074 #endif /* !TARGET_OS_IPHONE */
6075 new_dict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
6076 CFDictionaryRemoveValue(new_dict, kSCPropInterfaceName);
6077 CFDictionaryRemoveValue(new_dict, kSCPropNetDNSSupplementalMatchDomains);
6078 CFDictionaryRemoveValue(new_dict, kSCPropNetDNSSupplementalMatchOrders);
6079 CFDictionaryRemoveValue(new_dict, DNS_CONFIGURATION_SCOPED_QUERY_KEY);
6080 keyChangeListSetValue(keys, S_state_global_dns, new_dict);
6081 CFRelease(new_dict);
6082 }
6083 changed = TRUE;
6084 }
6085
6086 if (dict != NULL) CFRetain(dict);
6087 if (S_dns_dict != NULL) CFRelease(S_dns_dict);
6088 S_dns_dict = dict;
6089
6090 return changed;
6091 }
6092
6093 static Boolean
6094 update_dnsinfo(CFDictionaryRef services_info,
6095 CFStringRef primary,
6096 keyChangeListRef keys,
6097 CFArrayRef service_order)
6098 {
6099 Boolean changed;
6100 CFDictionaryRef dict = NULL;
6101 CFArrayRef multicastResolvers;
6102 CFArrayRef privateResolvers;
6103
6104 multicastResolvers = CFDictionaryGetValue(services_info, S_multicast_resolvers);
6105 privateResolvers = CFDictionaryGetValue(services_info, S_private_resolvers);
6106
6107 if (primary != NULL) {
6108 CFDictionaryRef service_dict;
6109
6110 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
6111 if (service_dict != NULL) {
6112 dict = CFDictionaryGetValue(service_dict, kSCEntNetDNS);
6113 }
6114 }
6115
6116 changed = dns_configuration_set(dict,
6117 S_service_state_dict,
6118 service_order,
6119 multicastResolvers,
6120 privateResolvers);
6121 if (changed) {
6122 keyChangeListNotifyKey(keys, S_state_global_dns);
6123 }
6124 return changed;
6125 }
6126
6127 static Boolean
6128 update_nwi(nwi_state_t state)
6129 {
6130 unsigned char signature[CC_SHA1_DIGEST_LENGTH];
6131 static unsigned char signature_last[CC_SHA1_DIGEST_LENGTH];
6132
6133 _nwi_state_compute_sha1_hash(state, signature);
6134 if (bcmp(signature, signature_last, sizeof(signature)) == 0) {
6135 my_log(LOG_DEBUG, "Not updating network information");
6136 return FALSE;
6137 }
6138
6139 // save [new] signature
6140 bcopy(signature, signature_last, sizeof(signature));
6141
6142 // save [new] configuration
6143 my_log(LOG_INFO, "Updating network information");
6144 S_nwi_state_dump(state);
6145
6146 if (!_nwi_state_store(state)) {
6147 my_log(LOG_ERR, "Notifying nwi_state_store failed");
6148 }
6149
6150 return TRUE;
6151 }
6152
6153 static Boolean
6154 update_proxies(CFDictionaryRef services_info,
6155 CFStringRef primary,
6156 keyChangeListRef keys,
6157 CFArrayRef service_order)
6158 {
6159 Boolean changed = FALSE;
6160 CFDictionaryRef dict = NULL;
6161 CFDictionaryRef new_dict;
6162
6163 if (primary != NULL) {
6164 CFDictionaryRef service_dict;
6165
6166 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
6167 if (service_dict != NULL) {
6168 dict = CFDictionaryGetValue(service_dict, kSCEntNetProxies);
6169 }
6170 }
6171
6172 new_dict = proxy_configuration_update(dict,
6173 S_service_state_dict,
6174 service_order,
6175 services_info);
6176 if (!_SC_CFEqual(S_proxies_dict, new_dict)) {
6177 if (new_dict == NULL) {
6178 keyChangeListRemoveValue(keys, S_state_global_proxies);
6179 } else {
6180 keyChangeListSetValue(keys, S_state_global_proxies, new_dict);
6181 }
6182 changed = TRUE;
6183 }
6184
6185 if (S_proxies_dict != NULL) CFRelease(S_proxies_dict);
6186 S_proxies_dict = new_dict;
6187
6188 return changed;
6189 }
6190
6191 #if !TARGET_OS_IPHONE
6192 static Boolean
6193 update_smb(CFDictionaryRef services_info,
6194 CFStringRef primary,
6195 keyChangeListRef keys)
6196 {
6197 Boolean changed = FALSE;
6198 CFDictionaryRef dict = NULL;
6199
6200 if (primary != NULL) {
6201 CFDictionaryRef service_dict;
6202
6203 service_dict = CFDictionaryGetValue(S_service_state_dict, primary);
6204 if (service_dict != NULL) {
6205 dict = CFDictionaryGetValue(service_dict, kSCEntNetSMB);
6206 }
6207 }
6208
6209 if (!_SC_CFEqual(S_smb_dict, dict)) {
6210 if (dict == NULL) {
6211 keyChangeListRemoveValue(keys, S_state_global_smb);
6212 } else {
6213 keyChangeListSetValue(keys, S_state_global_smb, dict);
6214 }
6215 changed = TRUE;
6216 }
6217
6218 if (dict != NULL) CFRetain(dict);
6219 if (S_smb_dict != NULL) CFRelease(S_smb_dict);
6220 S_smb_dict = dict;
6221
6222 return changed;
6223 }
6224 #endif /* !TARGET_OS_IPHONE */
6225
6226 static Rank
6227 get_service_index(CFDictionaryRef rank_entity,
6228 CFArrayRef order, CFIndex n_order, CFStringRef serviceID)
6229 {
6230 CFIndex i;
6231 Rank rank = kRankIndexMask;
6232 CFNumberRef service_index;
6233
6234 service_index
6235 = service_rank_entity_get_index(rank_entity,
6236 serviceID,
6237 CFSTR(""),
6238 &rank);
6239 if (service_index != NULL) {
6240 /* ServiceIndex specified in service entity */
6241 rank += n_order;
6242 my_log(LOG_INFO,
6243 "%@ specifies ServiceIndex %@, effective index is %d",
6244 serviceID, service_index, rank);
6245 }
6246 else if (serviceID != NULL && order != NULL && n_order > 0) {
6247 for (i = 0; i < n_order; i++) {
6248 CFStringRef s = isA_CFString(CFArrayGetValueAtIndex(order, i));
6249
6250 if (s == NULL) {
6251 continue;
6252 }
6253 if (CFEqual(serviceID, s)) {
6254 rank = (Rank)i + 1;
6255 break;
6256 }
6257 }
6258 }
6259 return (rank);
6260 }
6261
6262 /**
6263 ** Service election:
6264 **/
6265 /*
6266 * Function: rank_dict_get_service_rank
6267 * Purpose:
6268 * Retrieve the service rank in the given dictionary.
6269 */
6270 static Rank
6271 rank_dict_get_service_rank(CFDictionaryRef rank_dict, CFStringRef serviceID)
6272 {
6273 CFNumberRef rank;
6274 Rank rank_val = kRankAssertionDefault;
6275
6276 rank_val = RankMake(kRankIndexMask, kRankAssertionDefault);
6277 rank = CFDictionaryGetValue(rank_dict, serviceID);
6278 if (rank != NULL) {
6279 if (!CFNumberGetValue(rank, kCFNumberSInt32Type, &rank_val)) {
6280 /* if we don't like the rank value */
6281 rank_val = kRankAssertionDefault;
6282 }
6283
6284 }
6285 return (rank_val);
6286 }
6287
6288 /*
6289 * Function: rank_dict_set_service_rank
6290 * Purpose:
6291 * Save the results of ranking the service so we can look it up later without
6292 * repeating all of the ranking code.
6293 */
6294 static void
6295 rank_dict_set_service_rank(CFMutableDictionaryRef rank_dict,
6296 CFStringRef serviceID, Rank rank_val)
6297 {
6298 CFNumberRef rank;
6299
6300 rank = CFNumberCreate(NULL, kCFNumberSInt32Type, (const void *)&rank_val);
6301 if (rank != NULL) {
6302 CFDictionarySetValue(rank_dict, serviceID, rank);
6303 CFRelease(rank);
6304 }
6305 return;
6306 }
6307
6308 static const CFStringRef *transientInterfaceEntityNames[] = {
6309 &kSCEntNetPPP,
6310 };
6311
6312
6313 static void
6314 CollectTransientServices(const void * key,
6315 const void * value,
6316 void * context)
6317 {
6318 int i;
6319 CFStringRef service = key;
6320 CFMutableArrayRef vif_setup_keys = context;
6321
6322 /* This service is either a vpn type service or a comm center service */
6323 if (!CFStringHasPrefix(service, kSCDynamicStoreDomainSetup)) {
6324 return;
6325 }
6326
6327 for (i = 0; i < countof(transientInterfaceEntityNames); i++) {
6328 if (CFStringHasSuffix(service, *transientInterfaceEntityNames[i])) {
6329 CFArrayAppendValue(vif_setup_keys, service);
6330 break;
6331 }
6332 }
6333
6334 return;
6335 }
6336
6337
6338 static SCNetworkReachabilityFlags
6339 GetReachabilityFlagsFromVPN(CFDictionaryRef services_info,
6340 CFStringRef service_id,
6341 CFStringRef entity,
6342 CFStringRef vpn_setup_key)
6343 {
6344 CFStringRef key;
6345 CFDictionaryRef dict;
6346 SCNetworkReachabilityFlags flags = 0;
6347
6348
6349 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
6350 kSCDynamicStoreDomainSetup,
6351 service_id,
6352 kSCEntNetInterface);
6353 dict = CFDictionaryGetValue(services_info, key);
6354 CFRelease(key);
6355
6356 if (isA_CFDictionary(dict)
6357 && CFDictionaryContainsKey(dict, kSCPropNetInterfaceDeviceName)) {
6358
6359 flags = (kSCNetworkReachabilityFlagsReachable
6360 | kSCNetworkReachabilityFlagsTransientConnection
6361 | kSCNetworkReachabilityFlagsConnectionRequired);
6362
6363 if (CFEqual(entity, kSCEntNetPPP)) {
6364 CFNumberRef num;
6365 CFDictionaryRef p_dict = CFDictionaryGetValue(services_info, vpn_setup_key);
6366
6367 if (!isA_CFDictionary(p_dict)) {
6368 return (flags);
6369 }
6370
6371 // get PPP dial-on-traffic status
6372 num = CFDictionaryGetValue(p_dict, kSCPropNetPPPDialOnDemand);
6373 if (isA_CFNumber(num)) {
6374 int32_t ppp_demand;
6375
6376 if (CFNumberGetValue(num, kCFNumberSInt32Type, &ppp_demand)) {
6377 if (ppp_demand) {
6378 flags |= kSCNetworkReachabilityFlagsConnectionOnTraffic;
6379 }
6380 }
6381 }
6382 }
6383 }
6384 return (flags);
6385 }
6386
6387 static Boolean
6388 S_dict_get_boolean(CFDictionaryRef dict, CFStringRef key, Boolean def_value)
6389 {
6390 Boolean ret = def_value;
6391
6392 if (dict != NULL) {
6393 CFBooleanRef val;
6394
6395 val = CFDictionaryGetValue(dict, key);
6396 if (isA_CFBoolean(val) != NULL) {
6397 ret = CFBooleanGetValue(val);
6398 }
6399 }
6400 return (ret);
6401 }
6402
6403
6404 static void
6405 GetReachabilityFlagsFromTransientServices(CFDictionaryRef services_info,
6406 SCNetworkReachabilityFlags *reach_flags_v4,
6407 SCNetworkReachabilityFlags *reach_flags_v6)
6408 {
6409 CFIndex i;
6410 CFIndex count;
6411 CFMutableArrayRef vif_setup_keys;
6412
6413 vif_setup_keys = CFArrayCreateMutable(NULL,
6414 0,
6415 &kCFTypeArrayCallBacks);
6416 CFDictionaryApplyFunction(services_info, CollectTransientServices,
6417 vif_setup_keys);
6418 count = CFArrayGetCount(vif_setup_keys);
6419 for (i = 0; i < count; i++) {
6420 CFArrayRef components = NULL;
6421 CFStringRef entity;
6422 CFStringRef service_id;
6423 CFStringRef vif_setup_key;
6424
6425 vif_setup_key = CFArrayGetValueAtIndex(vif_setup_keys, i);
6426
6427 /*
6428 * setup key in the following format:
6429 * Setup:/Network/Service/<Service ID>/<Entity>
6430 */
6431 components = CFStringCreateArrayBySeparatingStrings(NULL, vif_setup_key, CFSTR("/"));
6432
6433 if (CFArrayGetCount(components) != 5) {
6434 // invalid Setup key encountered
6435 goto skip;
6436 }
6437
6438 /* service id is the 3rd element */
6439 service_id = CFArrayGetValueAtIndex(components, 3);
6440
6441 /* entity id is the 4th element */
6442 entity = CFArrayGetValueAtIndex(components, 4);
6443
6444
6445 if (CFEqual(entity, kSCEntNetPPP)) {
6446 SCNetworkReachabilityFlags flags;
6447 CFStringRef key;
6448
6449 flags = GetReachabilityFlagsFromVPN(services_info,
6450 service_id,
6451 entity,
6452 vif_setup_key);
6453
6454 /* Check for the v4 reachability flags */
6455 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
6456 kSCDynamicStoreDomainSetup,
6457 service_id,
6458 kSCEntNetIPv4);
6459
6460 if (CFDictionaryContainsKey(services_info, key)) {
6461 *reach_flags_v4 |= flags;
6462 my_log(LOG_DEBUG, "Service %@ setting ipv4 reach flags: %d", service_id, *reach_flags_v4);
6463 }
6464
6465 CFRelease(key);
6466
6467 /* Check for the v6 reachability flags */
6468 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
6469 kSCDynamicStoreDomainSetup,
6470 service_id,
6471 kSCEntNetIPv6);
6472
6473 if (CFDictionaryContainsKey(services_info, key)) {
6474 *reach_flags_v6 |= flags;
6475 my_log(LOG_DEBUG, "Service %@ setting ipv6 reach flags: %d", service_id, *reach_flags_v6);
6476 }
6477 CFRelease(key);
6478
6479 if (flags != 0) {
6480 if (components != NULL) {
6481 CFRelease(components);
6482 }
6483 goto done;
6484 }
6485 }
6486 skip:
6487 if (components != NULL) {
6488 CFRelease(components);
6489 }
6490 }
6491 done:
6492 CFRelease(vif_setup_keys);
6493 return;
6494 }
6495
6496 static SCNetworkReachabilityFlags
6497 GetReachFlagsFromStatus(CFStringRef entity, int status)
6498 {
6499 SCNetworkReachabilityFlags flags = 0;
6500
6501 if (CFEqual(entity, kSCEntNetPPP)) {
6502 switch (status) {
6503 case PPP_RUNNING :
6504 /* if we're really UP and RUNNING */
6505 break;
6506 case PPP_ONHOLD :
6507 /* if we're effectively UP and RUNNING */
6508 break;
6509 case PPP_IDLE :
6510 /* if we're not connected at all */
6511 flags |= kSCNetworkReachabilityFlagsConnectionRequired;
6512 break;
6513 case PPP_STATERESERVED :
6514 // if we're not connected at all
6515 flags |= kSCNetworkReachabilityFlagsConnectionRequired;
6516 break;
6517 default :
6518 /* if we're in the process of [dis]connecting */
6519 flags |= kSCNetworkReachabilityFlagsConnectionRequired;
6520 break;
6521 }
6522 }
6523 else if (CFEqual(entity, kSCEntNetIPSec)) {
6524 switch (status) {
6525 case IPSEC_RUNNING :
6526 /* if we're really UP and RUNNING */
6527 break;
6528 case IPSEC_IDLE :
6529 /* if we're not connected at all */
6530 flags |= kSCNetworkReachabilityFlagsConnectionRequired;
6531 break;
6532 default :
6533 /* if we're in the process of [dis]connecting */
6534 flags |= kSCNetworkReachabilityFlagsConnectionRequired;
6535 break;
6536 }
6537 }
6538 else if (CFEqual(entity, kSCEntNetVPN)) {
6539 switch (status) {
6540 case VPN_RUNNING :
6541 /* if we're really UP and RUNNING */
6542 break;
6543 case VPN_IDLE :
6544 case VPN_LOADING :
6545 case VPN_LOADED :
6546 case VPN_UNLOADING :
6547 /* if we're not connected at all */
6548 flags |= kSCNetworkReachabilityFlagsConnectionRequired;
6549 break;
6550 default :
6551 /* if we're in the process of [dis]connecting */
6552 flags |= kSCNetworkReachabilityFlagsConnectionRequired;
6553 break;
6554 }
6555 }
6556 return (flags);
6557 }
6558
6559 static void
6560 VPNAttributesGet(CFStringRef service_id,
6561 CFDictionaryRef services_info,
6562 SCNetworkReachabilityFlags *flags,
6563 CFStringRef *server_address,
6564 int af)
6565 {
6566 int i;
6567 CFDictionaryRef entity_dict;
6568 CFNumberRef num;
6569 CFDictionaryRef p_state = NULL;
6570 int status = 0;
6571 CFStringRef transient_entity = NULL;
6572
6573 if (af == AF_INET) {
6574 entity_dict = service_dict_get(service_id, kSCEntNetIPv4);
6575 }
6576 else {
6577 entity_dict = service_dict_get(service_id, kSCEntNetIPv6);
6578 }
6579 entity_dict = ipdict_get_service(entity_dict);
6580 if (entity_dict == NULL) {
6581 return;
6582 }
6583
6584 for (i = 0; i < countof(transientServiceInfo); i++) {
6585 CFStringRef entity = *transientServiceInfo[i].entityName;
6586
6587 p_state = service_dict_get(service_id, entity);
6588
6589 /* ensure that this is a VPN Type service */
6590 if (isA_CFDictionary(p_state)) {
6591 transient_entity = entity;
6592 break;
6593 }
6594 }
6595
6596 /* Did we find a vpn type service? If not, we are done.*/
6597 if (transient_entity == NULL) {
6598 return;
6599 }
6600
6601 *flags |= (kSCNetworkReachabilityFlagsReachable
6602 | kSCNetworkReachabilityFlagsTransientConnection);
6603
6604 /* Get the Server Address */
6605 if (server_address != NULL) {
6606 *server_address = CFDictionaryGetValue(entity_dict,
6607 CFSTR("ServerAddress"));
6608 *server_address = isA_CFString(*server_address);
6609 if (*server_address != NULL) {
6610 CFRetain(*server_address);
6611 }
6612 }
6613
6614 /* get status */
6615 if (!CFDictionaryGetValueIfPresent(p_state,
6616 kSCPropNetVPNStatus, // IPSecStatus, PPPStatus, VPNStatus
6617 (const void **)&num) ||
6618 !isA_CFNumber(num) ||
6619 !CFNumberGetValue(num, kCFNumberIntType, &status)) {
6620 return;
6621 }
6622
6623 *flags |= GetReachFlagsFromStatus(transient_entity, status);
6624 if (CFEqual(transient_entity, kSCEntNetPPP)) {
6625 CFStringRef key;
6626 CFDictionaryRef p_setup;
6627 int ppp_demand;
6628
6629 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
6630 kSCDynamicStoreDomainSetup,
6631 service_id,
6632 kSCEntNetPPP);
6633 p_setup = CFDictionaryGetValue(services_info, key);
6634 CFRelease(key);
6635
6636 /* get dial-on-traffic status */
6637 if (isA_CFDictionary(p_setup) &&
6638 CFDictionaryGetValueIfPresent(p_setup,
6639 kSCPropNetPPPDialOnDemand,
6640 (const void **)&num) &&
6641 isA_CFNumber(num) &&
6642 CFNumberGetValue(num, kCFNumberIntType, &ppp_demand) &&
6643 (ppp_demand != 0)) {
6644 *flags |= kSCNetworkReachabilityFlagsConnectionOnTraffic;
6645 if (status == PPP_IDLE) {
6646 *flags |= kSCNetworkReachabilityFlagsInterventionRequired;
6647 }
6648 }
6649 }
6650 return;
6651 }
6652
6653
6654 typedef struct ElectionInfo {
6655 int af;
6656 CFStringRef entity;
6657 int n_services;
6658 CFArrayRef order;
6659 CFIndex n_order;
6660 ElectionResultsRef results;
6661 CFMutableDictionaryRef rank_dict;
6662 } ElectionInfo, * ElectionInfoRef;
6663
6664 typedef CFDictionaryApplierFunction ElectionFuncRef;
6665
6666 static void
6667 CandidateRelease(CandidateRef candidate)
6668 {
6669 my_CFRelease(&candidate->serviceID);
6670 my_CFRelease(&candidate->if_name);
6671 my_CFRelease(&candidate->signature);
6672 return;
6673 }
6674
6675 static void
6676 CandidateCopy(CandidateRef dest, CandidateRef src)
6677 {
6678 *dest = *src;
6679 if (dest->serviceID) {
6680 CFRetain(dest->serviceID);
6681 }
6682 if (dest->if_name) {
6683 CFRetain(dest->if_name);
6684 }
6685 if(dest->signature) {
6686 CFRetain(dest->signature);
6687 }
6688 return;
6689 }
6690
6691 static ElectionResultsRef
6692 ElectionResultsAlloc(int af, int size)
6693 {
6694 ElectionResultsRef results;
6695
6696 results = (ElectionResultsRef)malloc(ElectionResultsComputeSize(size));
6697 results->af = af;
6698 results->count = 0;
6699 results->size = size;
6700 return (results);
6701 }
6702
6703 static void
6704 ElectionResultsRelease(ElectionResultsRef results)
6705 {
6706 int i;
6707 CandidateRef scan;
6708
6709 for (i = 0, scan = results->candidates;
6710 i < results->count;
6711 i++, scan++) {
6712 CandidateRelease(scan);
6713 }
6714 free(results);
6715 return;
6716 }
6717
6718 static void
6719 ElectionResultsLog(int level, ElectionResultsRef results, const char * prefix)
6720 {
6721 int i;
6722 CandidateRef scan;
6723
6724 if (results == NULL) {
6725 my_log(level, "%s: no candidates", prefix);
6726 return;
6727 }
6728 my_log(level, "%s: %d candidates", prefix, results->count);
6729 for (i = 0, scan = results->candidates;
6730 i < results->count;
6731 i++, scan++) {
6732 char ntopbuf[INET6_ADDRSTRLEN];
6733
6734 (void)inet_ntop(results->af, &scan->addr, ntopbuf, sizeof(ntopbuf));
6735 my_log(level, "%d. %@ serviceID=%@ addr=%s rank=0x%x%s",
6736 i, scan->if_name, scan->serviceID, ntopbuf, scan->rank,
6737 scan->ineligible ? " [ineligible]" : "");
6738 }
6739 return;
6740 }
6741
6742 /*
6743 * Function: ElectionResultsAddCandidate
6744 * Purpose:
6745 * Add the candidate into the election results. Find the insertion point
6746 * by comparing the rank of the candidate with existing entries.
6747 */
6748 static void
6749 ElectionResultsAddCandidate(ElectionResultsRef results, CandidateRef candidate)
6750 {
6751 CFIndex i;
6752 CFIndex where;
6753
6754 if (results->count == results->size) {
6755 /* this should not happen */
6756 my_log(LOG_NOTICE, "can't fit another candidate");
6757 return;
6758 }
6759
6760 /* find the insertion point */
6761 where = kCFNotFound;
6762 for (i = 0; i < results->count; i++) {
6763 CandidateRef this_candidate = results->candidates + i;
6764
6765 if (candidate->rank < this_candidate->rank) {
6766 where = i;
6767 break;
6768 }
6769 }
6770 /* add it to the end */
6771 if (where == kCFNotFound) {
6772 CandidateCopy(results->candidates + results->count, candidate);
6773 results->count++;
6774 return;
6775 }
6776 /* slide existing entries over */
6777 for (i = results->count; i > where; i--) {
6778 results->candidates[i] = results->candidates[i - 1];
6779 }
6780 /* insert element */
6781 CandidateCopy(results->candidates + where, candidate);
6782 results->count++;
6783 return;
6784 }
6785
6786 static void
6787 elect_ip(const void * key, const void * value, void * context);
6788
6789 /*
6790 * Function: ElectionResultsCopy
6791 * Purpose:
6792 * Visit all of the services and invoke the protocol-specific election
6793 * function. Return the results of the election.
6794 */
6795 static ElectionResultsRef
6796 ElectionResultsCopy(int af, CFArrayRef order)
6797 {
6798 int count;
6799 ElectionInfo info;
6800
6801 count = (int)CFDictionaryGetCount(S_service_state_dict);
6802 if (count == 0) {
6803 return (NULL);
6804 }
6805 info.af = af;
6806 if (af == AF_INET) {
6807 info.entity = kSCEntNetIPv4;
6808 info.rank_dict = S_ipv4_service_rank_dict;
6809 }
6810 else {
6811 info.entity = kSCEntNetIPv6;
6812 info.rank_dict = S_ipv6_service_rank_dict;
6813 }
6814 info.results = ElectionResultsAlloc(af, count);
6815 info.n_services = count;
6816 info.order = order;
6817 if (order != NULL) {
6818 info.n_order = CFArrayGetCount(order);
6819 }
6820 else {
6821 info.order = 0;
6822 }
6823 CFDictionaryApplyFunction(S_service_state_dict, elect_ip, (void *)&info);
6824 if (info.results->count == 0) {
6825 ElectionResultsRelease(info.results);
6826 info.results = NULL;
6827 }
6828 return (info.results);
6829 }
6830
6831 /*
6832 * Function: ElectionResultsCandidateNeedsDemotion
6833 * Purpose:
6834 * Check whether the given candidate requires demotion. A candidate
6835 * might need to be demoted if its IPv4 and IPv6 services must be coupled
6836 * but a higher ranked service has IPv4 or IPv6.
6837 */
6838 static Boolean
6839 ElectionResultsCandidateNeedsDemotion(ElectionResultsRef other_results,
6840 CandidateRef candidate)
6841 {
6842 CandidateRef other_candidate;
6843 Boolean ret = FALSE;
6844
6845 if (other_results == NULL
6846 || !candidate->ip_is_coupled
6847 || RANK_ASSERTION_MASK(candidate->rank) == kRankAssertionNever) {
6848 goto done;
6849 }
6850 other_candidate = other_results->candidates;
6851 if (CFEqual(other_candidate->if_name, candidate->if_name)) {
6852 /* they are over the same interface, no need to demote */
6853 goto done;
6854 }
6855 if (CFStringHasPrefix(other_candidate->if_name, CFSTR("stf"))) {
6856 /* avoid creating a feedback loop */
6857 goto done;
6858 }
6859 if (RANK_ASSERTION_MASK(other_candidate->rank) == kRankAssertionNever) {
6860 /* the other candidate isn't eligible to become primary, ignore */
6861 goto done;
6862 }
6863 if (candidate->rank < other_candidate->rank) {
6864 /* we're higher ranked than the other candidate, ignore */
6865 goto done;
6866 }
6867 ret = TRUE;
6868
6869 done:
6870 return (ret);
6871
6872 }
6873
6874
6875 static void
6876 get_signature_sha1(CFStringRef signature,
6877 unsigned char * sha1)
6878 {
6879 CC_SHA1_CTX ctx;
6880 CFDataRef signature_data;
6881
6882 signature_data = CFStringCreateExternalRepresentation(NULL,
6883 signature,
6884 kCFStringEncodingUTF8,
6885 0);
6886
6887 CC_SHA1_Init(&ctx);
6888 CC_SHA1_Update(&ctx,
6889 CFDataGetBytePtr(signature_data),
6890 (CC_LONG)CFDataGetLength(signature_data));
6891 CC_SHA1_Final(sha1, &ctx);
6892
6893 CFRelease(signature_data);
6894
6895 return;
6896 }
6897
6898
6899 static void
6900 add_candidate_to_nwi_state(nwi_state_t nwi_state, int af,
6901 CandidateRef candidate, Boolean not_in_list,
6902 Boolean not_in_iflist)
6903 {
6904 uint64_t flags = 0;
6905 char ifname[IFNAMSIZ];
6906 nwi_ifstate_t ifstate;
6907
6908 if (nwi_state == NULL) {
6909 /* can't happen */
6910 return;
6911 }
6912 if (not_in_list
6913 || RANK_ASSERTION_MASK(candidate->rank) == kRankAssertionNever) {
6914 flags |= NWI_IFSTATE_FLAGS_NOT_IN_LIST;
6915 }
6916 if (not_in_iflist) {
6917 flags |= NWI_IFSTATE_FLAGS_NOT_IN_IFLIST;
6918 }
6919 if (service_dict_get(candidate->serviceID, kSCEntNetDNS) != NULL) {
6920 flags |= NWI_IFSTATE_FLAGS_HAS_DNS;
6921 }
6922 CFStringGetCString(candidate->if_name, ifname, sizeof(ifname),
6923 kCFStringEncodingASCII);
6924 if ((S_IPMonitor_debug & kDebugFlag2) != 0) {
6925 char ntopbuf[INET6_ADDRSTRLEN];
6926
6927 (void)inet_ntop(af, &candidate->addr, ntopbuf, sizeof(ntopbuf));
6928 my_log(LOG_DEBUG,
6929 "Adding IPv%c [%s] %s "
6930 "with flags 0x%llx rank 0x%x reach_flags 0x%x",
6931 ipvx_char(af), ifname, ntopbuf,
6932 flags, candidate->rank, candidate->reachability_flags);
6933 }
6934 ifstate = nwi_state_add_ifstate(nwi_state, ifname, af, flags,
6935 candidate->rank,
6936 (void *)&candidate->addr,
6937 (void *)&candidate->vpn_server_addr,
6938 candidate->reachability_flags);
6939 if (ifstate != NULL && candidate->signature) {
6940 uint8_t hash[CC_SHA1_DIGEST_LENGTH];
6941
6942 get_signature_sha1(candidate->signature, hash);
6943 nwi_ifstate_set_signature(ifstate, hash);
6944 }
6945 return;
6946 }
6947
6948
6949 static void
6950 add_reachability_flags_to_candidate(CandidateRef candidate, CFDictionaryRef services_info, int af)
6951 {
6952 SCNetworkReachabilityFlags flags = kSCNetworkReachabilityFlagsReachable;
6953 CFStringRef vpn_server_address = NULL;
6954
6955 VPNAttributesGet(candidate->serviceID,
6956 services_info,
6957 &flags,
6958 &vpn_server_address,
6959 af);
6960
6961 candidate->reachability_flags = flags;
6962
6963 if (vpn_server_address == NULL) {
6964 bzero(&candidate->vpn_server_addr, sizeof(candidate->vpn_server_addr));
6965 } else {
6966 char buf[128];
6967
6968 CFStringGetCString(vpn_server_address, buf, sizeof(buf),
6969 kCFStringEncodingASCII);
6970 _SC_string_to_sockaddr(buf,
6971 AF_UNSPEC,
6972 (void *)&candidate->vpn_server_addr,
6973 sizeof(candidate->vpn_server_addr));
6974
6975 CFRelease(vpn_server_address);
6976 }
6977 return;
6978 }
6979 /*
6980 * Function: ElectionResultsCopyPrimary
6981 * Purpose:
6982 * Use the results of the current protocol and the other protocol to
6983 * determine which service should become primary.
6984 *
6985 * At the same time, generate the IPv4/IPv6 routing table and
6986 * the nwi_state for the protocol.
6987 */
6988 static CFStringRef
6989 ElectionResultsCopyPrimary(ElectionResultsRef results,
6990 ElectionResultsRef other_results,
6991 nwi_state_t nwi_state, int af,
6992 RouteListRef * ret_routes,
6993 CFDictionaryRef services_info)
6994 {
6995 CFStringRef primary = NULL;
6996 Boolean primary_is_null = FALSE;
6997 RouteListRef routes = NULL;
6998
6999 if (results != NULL) {
7000 CandidateRef deferred[results->count];
7001 int deferred_count;
7002 CFStringRef entity_name;
7003 int i;
7004 int initial_size;
7005 RouteListInfoRef info;
7006 CandidateRef scan;
7007
7008 switch (af) {
7009 case AF_INET:
7010 entity_name = kSCEntNetIPv4;
7011 info = &IPv4RouteListInfo;
7012 initial_size = results->count * IPV4_ROUTES_N_STATIC;
7013 break;
7014 default:
7015 case AF_INET6:
7016 entity_name = kSCEntNetIPv6;
7017 info = &IPv6RouteListInfo;
7018 initial_size = results->count * IPV6_ROUTES_N_STATIC;
7019 break;
7020 }
7021 deferred_count = 0;
7022 for (i = 0, scan = results->candidates;
7023 i < results->count;
7024 i++, scan++) {
7025 Boolean is_primary = FALSE;
7026 CFDictionaryRef service_dict;
7027 RouteListRef service_routes;
7028 Boolean skip = FALSE;
7029
7030 if (!scan->ineligible
7031 && primary == NULL
7032 && RANK_ASSERTION_MASK(scan->rank) != kRankAssertionNever) {
7033 if (ElectionResultsCandidateNeedsDemotion(other_results,
7034 scan)) {
7035 /* demote the service */
7036 my_log(LOG_NOTICE,
7037 "IPv%c over %@ demoted: not primary for IPv%c",
7038 ipvx_char(af), scan->if_name, ipvx_other_char(af));
7039 deferred[deferred_count++] = scan;
7040 skip = TRUE;
7041 }
7042 else {
7043 primary = CFRetain(scan->serviceID);
7044 is_primary = TRUE;
7045 }
7046 }
7047 /* contribute to the routing table */
7048 service_dict = service_dict_get(scan->serviceID, entity_name);
7049 service_routes = ipdict_get_routelist(service_dict);
7050 if (service_routes != NULL) {
7051 Rank rank = scan->rank;
7052
7053 if (skip) {
7054 /* routes are RankNever to prevent becoming primary */
7055 rank = RankMake(rank, kRankAssertionNever);
7056 }
7057 routes = RouteListAddRouteList(info, routes, initial_size,
7058 service_routes, rank);
7059 if ((service_routes->flags & kRouteListFlagsExcludeNWI) != 0) {
7060 skip = TRUE;
7061 }
7062 }
7063 else {
7064 skip = TRUE;
7065 }
7066 if (skip) {
7067 /* if we're skipping the primary, it's NULL */
7068 if (is_primary) {
7069 primary_is_null = TRUE;
7070 }
7071 }
7072 else if (!scan->ineligible) {
7073 Boolean not_in_iflist;
7074
7075 add_reachability_flags_to_candidate(scan, services_info, af);
7076 not_in_iflist
7077 = (service_routes->flags & kRouteListFlagsScopedOnly) != 0;
7078 add_candidate_to_nwi_state(nwi_state, af, scan,
7079 primary_is_null,
7080 not_in_iflist);
7081 }
7082 }
7083 for (i = 0; i < deferred_count; i++) {
7084 CandidateRef candidate = deferred[i];
7085
7086 add_reachability_flags_to_candidate(candidate, services_info, af);
7087 add_candidate_to_nwi_state(nwi_state, af, candidate, TRUE, FALSE);
7088 }
7089 }
7090 if (ret_routes != NULL) {
7091 *ret_routes = routes;
7092 }
7093 else if (routes != NULL) {
7094 free(routes);
7095 }
7096 if (primary_is_null) {
7097 my_CFRelease(&primary);
7098 }
7099 return (primary);
7100 }
7101
7102
7103 static inline
7104 CFStringRef
7105 service_dict_get_signature(CFDictionaryRef service_dict)
7106 {
7107 CFStringRef ifname;
7108
7109 ifname = CFDictionaryGetValue(service_dict, kSCPropInterfaceName);
7110 if (isA_CFString(ifname) == NULL
7111 || !confirm_interface_name(service_dict, ifname)) {
7112 return (NULL);
7113 }
7114 return (CFDictionaryGetValue(service_dict, kStoreKeyNetworkSignature));
7115 }
7116
7117 /*
7118 * Function: elect_ip
7119 * Purpose:
7120 * Evaluate the service and determine what rank the service should have.
7121 * If it's a suitable candidate, add it to the election results.
7122 */
7123 static void
7124 elect_ip(const void * key, const void * value, void * context)
7125 {
7126 CFDictionaryRef all_entities_dict = (CFDictionaryRef)value;
7127 Candidate candidate;
7128 Rank default_rank;
7129 ElectionInfoRef elect_info;
7130 CFStringRef if_name;
7131 CFDictionaryRef ipdict;
7132 Rank primary_rank;
7133 CFDictionaryRef rank_entity;
7134 RouteListUnion routelist;
7135 CFDictionaryRef service_dict;
7136
7137 elect_info = (ElectionInfoRef)context;
7138 ipdict = CFDictionaryGetValue(all_entities_dict, elect_info->entity);
7139 if (ipdict != NULL) {
7140 routelist.ptr = ipdict_get_routelist(ipdict);
7141 service_dict = ipdict_get_service(ipdict);
7142 }
7143 else {
7144 routelist.ptr = NULL;
7145 }
7146 if (routelist.ptr == NULL || service_dict == NULL) {
7147 /* no connectivity */
7148 return;
7149 }
7150 if_name = CFDictionaryGetValue(service_dict, kSCPropInterfaceName);
7151 if (if_name == NULL) {
7152 /* need an interface name */
7153 return;
7154 }
7155 if (CFEqual(if_name, CFSTR(kLoopbackInterface))) {
7156 /* don't process loopback */
7157 return;
7158 }
7159 bzero(&candidate, sizeof(candidate));
7160 candidate.serviceID = (CFStringRef)key;
7161 if ((routelist.common->flags & kRouteListFlagsHasDefault) == 0) {
7162 /* no default route means it's ineligible to become primary */
7163 candidate.ineligible = TRUE;
7164 }
7165 rank_entity = CFDictionaryGetValue(all_entities_dict, kSCEntNetService);
7166 candidate.rank = get_service_index(rank_entity,
7167 elect_info->order, elect_info->n_order,
7168 candidate.serviceID);
7169 if (elect_info->af == AF_INET) {
7170 default_rank = routelist.v4->list->rank;
7171 candidate.addr.v4 = routelist.v4->list->ifa;
7172 }
7173 else {
7174 default_rank = routelist.v6->list->rank;
7175 candidate.addr.v6 = routelist.v6->list->ifa;
7176 }
7177 primary_rank = RANK_ASSERTION_MASK(default_rank);
7178 if (S_ppp_override_primary) {
7179 char ifn[IFNAMSIZ];
7180
7181 if (CFStringGetCString(if_name, ifn, sizeof(ifn),
7182 kCFStringEncodingASCII)
7183 && (strncmp(PPP_PREFIX, ifn, sizeof(PPP_PREFIX) - 1) == 0)) {
7184 /* PPP override: make ppp* look the best */
7185 primary_rank = kRankAssertionFirst;
7186 }
7187 }
7188 candidate.rank = RankMake(candidate.rank, primary_rank);
7189 candidate.ip_is_coupled = service_get_ip_is_coupled(candidate.serviceID);
7190 candidate.if_name = if_name;
7191 rank_dict_set_service_rank(elect_info->rank_dict,
7192 candidate.serviceID, candidate.rank);
7193 candidate.signature = service_dict_get_signature(service_dict);
7194 ElectionResultsAddCandidate(elect_info->results, &candidate);
7195 return;
7196 }
7197
7198
7199 static uint32_t
7200 service_changed(CFDictionaryRef services_info, CFStringRef serviceID)
7201 {
7202 uint32_t changed = 0;
7203 int i;
7204
7205 /* update service options first (e.g. rank) */
7206 if (get_rank_changes(serviceID,
7207 get_service_state_entity(services_info, serviceID,
7208 NULL),
7209 get_service_setup_entity(services_info, serviceID,
7210 NULL),
7211 services_info)) {
7212 changed |= (1 << kEntityTypeServiceOptions);
7213 }
7214 /* update IPv4, IPv6, DNS, Proxies, SMB, ... */
7215 for (i = 0; i < ENTITY_TYPES_COUNT; i++) {
7216 GetEntityChangesFuncRef func = entityChangeFunc[i];
7217 if ((*func)(serviceID,
7218 get_service_state_entity(services_info, serviceID,
7219 *entityTypeNames[i]),
7220 get_service_setup_entity(services_info, serviceID,
7221 *entityTypeNames[i]),
7222 services_info)) {
7223 changed |= (1 << i);
7224 }
7225 }
7226
7227 if (get_transient_status_changes(serviceID, services_info)) {
7228 changed |= (1 << kEntityTypeTransientStatus);
7229 }
7230
7231 return (changed);
7232 }
7233
7234 static CFStringRef
7235 serviceID_get_ifname(CFStringRef serviceID)
7236 {
7237 CFDictionaryRef entity_dict;
7238 CFStringRef ifname = NULL;
7239
7240 entity_dict = service_dict_get(serviceID, kSCEntNetIPv4);
7241 if (entity_dict == NULL) {
7242 entity_dict = service_dict_get(serviceID, kSCEntNetIPv6);
7243 }
7244 if (entity_dict != NULL) {
7245 ifname = ipdict_get_ifname(entity_dict);
7246 }
7247 return (ifname);
7248 }
7249
7250 __private_extern__ boolean_t
7251 check_if_service_expensive(CFStringRef serviceID)
7252 {
7253 CFStringRef ifname;
7254 ifname = serviceID_get_ifname(serviceID);
7255
7256 return interface_is_expensive(ifname);
7257 }
7258
7259 static CFArrayRef
7260 service_order_get(CFDictionaryRef services_info)
7261 {
7262 CFArrayRef order = NULL;
7263 CFDictionaryRef ipv4_dict;
7264
7265 ipv4_dict = my_CFDictionaryGetDictionary(services_info,
7266 S_setup_global_ipv4);
7267 if (ipv4_dict != NULL) {
7268 CFNumberRef ppp_override;
7269 int ppp_val = 0;
7270
7271 order = CFDictionaryGetValue(ipv4_dict, kSCPropNetServiceOrder);
7272 order = isA_CFArray(order);
7273
7274 /* get ppp override primary */
7275 ppp_override = CFDictionaryGetValue(ipv4_dict,
7276 kSCPropNetPPPOverridePrimary);
7277 ppp_override = isA_CFNumber(ppp_override);
7278 if (ppp_override != NULL) {
7279 CFNumberGetValue(ppp_override, kCFNumberIntType, &ppp_val);
7280 }
7281 S_ppp_override_primary = (ppp_val != 0) ? TRUE : FALSE;
7282 }
7283 else {
7284 S_ppp_override_primary = FALSE;
7285 }
7286 return (order);
7287 }
7288
7289 static boolean_t
7290 set_new_primary(CFStringRef * primary_p, CFStringRef new_primary,
7291 const char * entity)
7292 {
7293 boolean_t changed = FALSE;
7294 CFStringRef primary = *primary_p;
7295
7296 if (new_primary != NULL) {
7297 if (primary != NULL && CFEqual(new_primary, primary)) {
7298 my_log(LOG_INFO, "%@ is still primary %s", new_primary, entity);
7299 }
7300 else {
7301 my_CFRelease(primary_p);
7302 *primary_p = CFRetain(new_primary);
7303 my_log(LOG_INFO, "%@ is the new primary %s", new_primary, entity);
7304 changed = TRUE;
7305 }
7306 }
7307 else if (primary != NULL) {
7308 my_log(LOG_INFO, "%@ is no longer primary %s", primary, entity);
7309 my_CFRelease(primary_p);
7310 changed = TRUE;
7311 }
7312 return (changed);
7313 }
7314
7315 static Rank
7316 rank_service_entity(CFDictionaryRef rank_dict, CFStringRef serviceID,
7317 CFStringRef entity)
7318 {
7319 if (service_dict_get(serviceID, entity) == NULL) {
7320 return (RankMake(kRankIndexMask, kRankAssertionDefault));
7321 }
7322 return (rank_dict_get_service_rank(rank_dict, serviceID));
7323 }
7324
7325 static void
7326 append_serviceIDs_for_interface(CFMutableArrayRef services_changed,
7327 CFStringRef ifname)
7328 {
7329 CFIndex count;
7330 CFIndex i;
7331 void * * keys;
7332 #define N_KEYS_VALUES_STATIC 10
7333 void * keys_values_buf[N_KEYS_VALUES_STATIC * 2];
7334 void * * values;
7335
7336 count = CFDictionaryGetCount(S_service_state_dict);
7337 if (count <= N_KEYS_VALUES_STATIC) {
7338 keys = keys_values_buf;
7339 } else {
7340 keys = (void * *)malloc(sizeof(*keys) * count * 2);
7341 }
7342 values = keys + count;
7343 CFDictionaryGetKeysAndValues(S_service_state_dict,
7344 (const void * *)keys,
7345 (const void * *)values);
7346
7347 for (i = 0; i < count; i++) {
7348 CFDictionaryRef ipdict = NULL;
7349 CFStringRef interface = NULL;
7350 CFStringRef serviceID;
7351 CFDictionaryRef service_dict;
7352
7353 serviceID = (CFStringRef)keys[i];
7354 service_dict = (CFDictionaryRef)values[i];
7355
7356 /* check whether service has IPv4 or IPv6 */
7357 ipdict = CFDictionaryGetValue(service_dict, kSCEntNetIPv4);
7358 if (ipdict == NULL) {
7359 ipdict = CFDictionaryGetValue(service_dict, kSCEntNetIPv6);
7360 if (ipdict == NULL) {
7361 continue;
7362 }
7363 }
7364 interface = ipdict_get_ifname(ipdict);
7365 if (interface != NULL && CFEqual(interface, ifname)) {
7366 my_log(LOG_DEBUG,
7367 "Found IP service %@ on interface %@",
7368 serviceID, ifname);
7369 my_CFArrayAppendUniqueValue(services_changed, serviceID);
7370 }
7371 }
7372 if (keys != keys_values_buf) {
7373 free(keys);
7374 }
7375 return;
7376 }
7377
7378 static __inline__ const char *
7379 get_changed_str(CFStringRef serviceID, CFStringRef entity,
7380 CFDictionaryRef old_dict)
7381 {
7382 CFDictionaryRef new_dict = NULL;
7383
7384 if (serviceID != NULL) {
7385 new_dict = service_dict_get(serviceID, entity);
7386 }
7387
7388 if (old_dict == NULL) {
7389 if (new_dict != NULL) {
7390 return "+";
7391 }
7392 } else {
7393 if (new_dict == NULL) {
7394 return "-";
7395 } else if (!CFEqual(old_dict, new_dict)) {
7396 return "!";
7397 }
7398 }
7399 return "";
7400 }
7401
7402 #if !TARGET_OS_SIMULATOR
7403
7404 #ifdef SIOCSIFORDER
7405 #define MANAGE_IF_ORDER
7406 #define MANAGE_IF_IOCTL
7407 #endif /* SIOCSIFORDER */
7408
7409 #ifdef SIOCSIFNETSIGNATURE
7410 #define MANAGE_IF_SIGNATURE
7411 #define MANAGE_IF_IOCTL
7412 #endif /* SIOCSIFNETSIGNATURE */
7413
7414 #ifdef MANAGE_IF_IOCTL
7415 static int
7416 inet_dgram_socket(void)
7417 {
7418 int sockfd;
7419
7420 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
7421 if (sockfd == -1) {
7422 my_log(LOG_ERR, "socket() failed: %s", strerror(errno));
7423 }
7424
7425 return sockfd;
7426 }
7427 #endif /* MANAGE_IF_IOCTL */
7428
7429 #ifdef MANAGE_IF_ORDER
7430 static Boolean
7431 interface_order_changed(nwi_state_t old_state, nwi_state_t new_state)
7432 {
7433 if (old_state == NULL && new_state == NULL) {
7434 // Both are NULL, nothing changed
7435 return FALSE;
7436 }
7437
7438 if (old_state == NULL || new_state == NULL) {
7439 // One is NULL, something changed
7440 return TRUE;
7441 }
7442
7443 if (old_state->if_list_count != new_state->if_list_count) {
7444 // Count is different, something changed
7445 return TRUE;
7446 }
7447
7448 if (new_state->if_list_count == 0) {
7449 // Count is same and 0, nothing changed
7450 return FALSE;
7451 }
7452
7453 int i;
7454 nwi_ifindex_t *old_scan;
7455 nwi_ifindex_t *new_scan;
7456 for (i = 0, old_scan = nwi_state_if_list(old_state), new_scan = nwi_state_if_list(new_state);
7457 i < new_state->if_list_count; i++, old_scan++, new_scan++) {
7458 if (strcmp(old_state->ifstate_list[*old_scan].ifname, new_state->ifstate_list[*new_scan].ifname) != 0) {
7459 // Some interface in the list is different, something changed
7460 return TRUE;
7461 }
7462 }
7463
7464 // Count and contents are the same, nothing changed
7465 return FALSE;
7466 }
7467
7468 static Boolean
7469 update_interface_order(nwi_state_t state, int sockfd)
7470 {
7471 Boolean success = FALSE;
7472
7473 // Set interface order into the kernel
7474 struct if_order interface_order;
7475 interface_order.ifo_count = (uint32_t)state->if_list_count;
7476 interface_order.ifo_ordered_indices = calloc((size_t)interface_order.ifo_count, sizeof(uint32_t));
7477 if (((uint32_t *)interface_order.ifo_ordered_indices) != NULL) {
7478 int i;
7479 nwi_ifindex_t *scan;
7480 for (i = 0, scan = nwi_state_if_list(state);
7481 i < state->if_list_count; i++, scan++) {
7482 const char *ifname = state->ifstate_list[*scan].ifname;
7483 ((uint32_t *)interface_order.ifo_ordered_indices)[i] = my_if_nametoindex(ifname);
7484 }
7485 }
7486 if (ioctl(sockfd, SIOCSIFORDER, &interface_order) != 0) {
7487 my_log(LOG_ERR, "SIOCSIFORDER for %u(%p) failed on %d: %s", interface_order.ifo_count, (void *)interface_order.ifo_ordered_indices, sockfd, strerror(errno));
7488 } else {
7489 my_log(LOG_INFO, "Set kernel interface order for %u interfaces", interface_order.ifo_count);
7490 success = TRUE;
7491 }
7492 if (((uint32_t *)interface_order.ifo_ordered_indices) != NULL) {
7493 free(interface_order.ifo_ordered_indices);
7494 interface_order.ifo_ordered_indices = NULL;
7495 }
7496
7497 return success;
7498 }
7499 #endif /* MANAGE_IF_ORDER */
7500
7501 #ifdef MANAGE_IF_SIGNATURE
7502 static int
7503 siocsifnetsignature(int s, const char * ifname, int af,
7504 const uint8_t * signature, int signature_length)
7505 {
7506 struct if_nsreq nsreq;
7507
7508 bzero(&nsreq, sizeof(nsreq));
7509 strlcpy(nsreq.ifnsr_name, ifname, sizeof(nsreq.ifnsr_name));
7510 nsreq.ifnsr_family = af;
7511 if (signature_length > 0) {
7512 if (signature_length > sizeof(nsreq.ifnsr_data)) {
7513 signature_length = sizeof(nsreq.ifnsr_data);
7514 }
7515 nsreq.ifnsr_len = signature_length;
7516 memcpy(nsreq.ifnsr_data, signature, signature_length);
7517 }
7518 return (ioctl(s, SIOCSIFNETSIGNATURE, &nsreq));
7519 }
7520
7521 static void
7522 process_ifstate_difference(nwi_ifstate_t ifstate, int af, int sockfd)
7523 {
7524 nwi_ifstate_difference_t diff;
7525 boolean_t set_signature = FALSE;
7526 int signature_length = 0;
7527
7528 diff = nwi_ifstate_get_difference(ifstate);
7529 switch (diff) {
7530 case knwi_ifstate_difference_changed:
7531 /* set signature for this interface */
7532 set_signature = TRUE;
7533 if ((ifstate->flags & NWI_IFSTATE_FLAGS_HAS_SIGNATURE) != 0) {
7534 signature_length = sizeof(ifstate->signature);
7535 }
7536 break;
7537 case knwi_ifstate_difference_removed:
7538 /* remove signature for this interface */
7539 set_signature = TRUE;
7540 break;
7541 default:
7542 break;
7543 }
7544 if (set_signature) {
7545 if (siocsifnetsignature(sockfd, ifstate->ifname, af,
7546 ifstate->signature,
7547 signature_length) < 0) {
7548 my_log(LOG_ERR,
7549 "siocsifnetsignature(%s, IPv%c, %d) failed: %s",
7550 ifstate->ifname, ipvx_char(af),
7551 signature_length,
7552 strerror(errno));
7553 }
7554 else {
7555 my_log(LOG_DEBUG, "IPv%c Network Signature %s %s",
7556 ipvx_char(af),
7557 (signature_length > 0) ? "Set" : "Cleared",
7558 ifstate->ifname);
7559 if (signature_length > 0
7560 && (S_IPMonitor_debug & kDebugFlag1) != 0) {
7561 int i;
7562 char sig_buf[signature_length * 3 + 1];
7563
7564 sig_buf[0] = '\0';
7565 for (i = 0; i < signature_length; i++) {
7566 char byte_buf[4];
7567
7568 snprintf(byte_buf, sizeof(byte_buf),
7569 "%02x ", ifstate->signature[i]);
7570 strlcat(sig_buf, byte_buf, sizeof(sig_buf));
7571 }
7572 my_log(LOG_DEBUG, "Signature Bytes: %s", sig_buf);
7573 }
7574 }
7575 }
7576 return;
7577 }
7578
7579 static void
7580 process_state_differences(nwi_state_t state, int af, int sockfd)
7581 {
7582 int count;
7583 int i;
7584 nwi_ifstate_t scan;
7585
7586 if (af == AF_INET) {
7587 count = state->ipv4_count;
7588 }
7589 else {
7590 count = state->ipv6_count;
7591 }
7592 for (i = 0, scan = nwi_state_ifstate_list(state, af);
7593 i < count; i++, scan++) {
7594 process_ifstate_difference(scan, af, sockfd);
7595 }
7596 return;
7597 }
7598 #endif /* MANAGE_IF_SIGNATURE */
7599
7600 #endif /* !TARGET_OS_SIMULATOR */
7601
7602 static void
7603 process_nwi_changes(CFMutableStringRef log_output,
7604 nwi_state_t changes_state,
7605 nwi_state_t new_state,
7606 nwi_state_t old_state,
7607 boolean_t dns_changed,
7608 boolean_t dnsinfo_changed,
7609 CFDictionaryRef old_primary_dns,
7610 boolean_t proxy_changed,
7611 CFDictionaryRef old_primary_proxy,
7612 boolean_t smb_changed,
7613 CFDictionaryRef old_primary_smb)
7614 {
7615 int idx;
7616
7617 if (changes_state != NULL) {
7618 const sa_family_t af_list[] = {AF_INET, AF_INET6};
7619 nwi_ifstate_t scan;
7620 #ifdef MANAGE_IF_IOCTL
7621 int sockfd = inet_dgram_socket();
7622 #endif /* MANAGE_IF_IOCTL */
7623
7624 #ifdef MANAGE_IF_ORDER
7625 if (interface_order_changed(new_state, old_state)) {
7626 update_interface_order(new_state, sockfd);
7627 }
7628 #endif /* MANAGE_IF_ORDER */
7629
7630 for (idx = 0; idx < countof(af_list); idx++) {
7631 int af = af_list[idx];
7632 CFMutableStringRef changes = NULL;
7633 CFMutableStringRef primary_str = NULL;
7634
7635 #ifdef MANAGE_IF_SIGNATURE
7636 process_state_differences(changes_state, af, sockfd);
7637 #endif /* MANAGE_IF_SIGNATURE */
7638 scan = nwi_state_get_first_ifstate(changes_state, af);
7639 while (scan != NULL) {
7640 const char * changed_str;
7641
7642 changed_str = nwi_ifstate_get_diff_str(scan);
7643 if (changed_str != NULL) {
7644 void * address;
7645 const char * addr_str;
7646 char ntopbuf[INET6_ADDRSTRLEN];
7647
7648 address = (void *)nwi_ifstate_get_address(scan);
7649 addr_str = inet_ntop(scan->af, address, ntopbuf,
7650 sizeof(ntopbuf));
7651 if (primary_str == NULL) {
7652 primary_str = CFStringCreateMutable(NULL, 0);
7653 CFStringAppendFormat(primary_str, NULL,
7654 CFSTR("%s%s:%s"),
7655 nwi_ifstate_get_ifname(scan),
7656 changed_str, addr_str);
7657 } else {
7658 if (changes == NULL) {
7659 changes = CFStringCreateMutable(NULL, 0);
7660 }
7661 CFStringAppendFormat(changes, NULL, CFSTR(", %s"),
7662 nwi_ifstate_get_ifname(scan));
7663 if (strcmp(changed_str, "") != 0) {
7664 CFStringAppendFormat(changes, NULL, CFSTR("%s:%s"),
7665 changed_str, addr_str);
7666 }
7667 }
7668 }
7669 scan = nwi_ifstate_get_next(scan, scan->af);
7670 }
7671
7672 if (primary_str != NULL) {
7673 CFStringAppendFormat(log_output, NULL, CFSTR(" %s(%@"),
7674 af == AF_INET ? "v4" : "v6",
7675 primary_str);
7676
7677 if (changes != NULL && CFStringGetLength(changes) != 0) {
7678 CFStringAppendFormat(log_output, NULL, CFSTR("%@"),
7679 changes);
7680 }
7681 CFStringAppend(log_output, CFSTR(")"));
7682
7683 my_CFRelease(&primary_str);
7684 my_CFRelease(&changes);
7685 }
7686 }
7687 #ifdef MANAGE_IF_IOCTL
7688 if (sockfd >= 0) {
7689 close(sockfd);
7690 }
7691 #endif /* MANAGE_IF_IOCTL */
7692 }
7693
7694 if (dns_changed || dnsinfo_changed) {
7695 const char *str;
7696
7697 str = get_changed_str(S_primary_dns, kSCEntNetDNS, old_primary_dns);
7698 if ((strcmp(str, "") == 0) && dnsinfo_changed) {
7699 str = "*"; // dnsinfo change w/no change to primary
7700 }
7701 CFStringAppendFormat(log_output, NULL, CFSTR(" DNS%s"), str);
7702 } else if (S_primary_dns != NULL) {
7703 CFStringAppend(log_output, CFSTR(" DNS"));
7704 }
7705
7706 if (proxy_changed) {
7707 const char *str;
7708
7709 str = get_changed_str(S_primary_proxies, kSCEntNetProxies, old_primary_proxy);
7710 CFStringAppendFormat(log_output, NULL, CFSTR(" Proxy%s"), str);
7711 } else if (S_primary_proxies != NULL) {
7712 CFStringAppend(log_output, CFSTR(" Proxy"));
7713 }
7714
7715 #if !TARGET_OS_IPHONE
7716 if (smb_changed) {
7717 const char *str;
7718
7719 str = get_changed_str(S_primary_smb, kSCEntNetSMB, old_primary_smb);
7720 CFStringAppendFormat(log_output, NULL, CFSTR(" SMB%s"), str);
7721 } else if (S_primary_smb != NULL) {
7722 CFStringAppend(log_output, CFSTR(" SMB"));
7723 }
7724 #endif // !TARGET_OS_IPHONE
7725
7726 return;
7727 }
7728
7729 #pragma mark -
7730 #pragma mark Network changed notification
7731
7732 static dispatch_queue_t
7733 __network_change_queue()
7734 {
7735 static dispatch_once_t once;
7736 static dispatch_queue_t q;
7737
7738 dispatch_once(&once, ^{
7739 q = dispatch_queue_create("network change queue", NULL);
7740 });
7741
7742 return q;
7743 }
7744
7745 // Note: must run on __network_change_queue()
7746 static void
7747 post_network_change_when_ready()
7748 {
7749 int status;
7750
7751 if (S_network_change_needed == 0) {
7752 return;
7753 }
7754
7755 if (!S_network_change_timeout &&
7756 (!S_dnsinfo_synced || !S_nwi_synced)) {
7757 // if we [still] need to wait for the DNS configuration
7758 // or network information changes to be ack'd
7759 my_log(LOG_DEBUG,
7760 "Defer \"" _SC_NOTIFY_NETWORK_CHANGE "\" (%s, %s)",
7761 S_dnsinfo_synced ? "DNS" : "!DNS",
7762 S_nwi_synced ? "nwi" : "!nwi");
7763 return;
7764 }
7765
7766 // cancel any running timer
7767 if (S_network_change_timer != NULL) {
7768 dispatch_source_cancel(S_network_change_timer);
7769 dispatch_release(S_network_change_timer);
7770 S_network_change_timer = NULL;
7771 S_network_change_timeout = FALSE;
7772 }
7773
7774 // set (and log?) the post time
7775 {
7776 struct timeval elapsed;
7777 struct timeval end;
7778
7779 (void) gettimeofday(&end, NULL);
7780 timersub(&end, &S_network_change_start, &elapsed);
7781
7782 #define QUERY_TIME__FMT "%ld.%6.6d"
7783 #define QUERY_TIME__DIV 1
7784
7785 my_log(LOG_INFO,
7786 "Post \"" _SC_NOTIFY_NETWORK_CHANGE "\" (%s: " QUERY_TIME__FMT ": 0x%x)",
7787 S_network_change_timeout ? "timeout" : "delayed",
7788 elapsed.tv_sec,
7789 elapsed.tv_usec / QUERY_TIME__DIV,
7790 S_network_change_needed);
7791 }
7792
7793
7794 /* We are about to post a network change to everyone, get the agents up to date */
7795
7796 if ((S_network_change_needed & NETWORK_CHANGE_NET) != 0) {
7797 status = notify_post(_SC_NOTIFY_NETWORK_CHANGE_NWI);
7798 if (status != NOTIFY_STATUS_OK) {
7799 my_log(LOG_ERR,
7800 "notify_post(" _SC_NOTIFY_NETWORK_CHANGE_NWI ") failed: error=%d", status);
7801 }
7802 }
7803
7804 if ((S_network_change_needed & NETWORK_CHANGE_DNS) != 0) {
7805
7806
7807 #if !TARGET_OS_SIMULATOR
7808 /* Setup or Update config agents */
7809 process_AgentMonitor_DNS();
7810 #endif //!TARGET_OS_SIMULATOR
7811 status = notify_post(_SC_NOTIFY_NETWORK_CHANGE_DNS);
7812 if (status != NOTIFY_STATUS_OK) {
7813 my_log(LOG_ERR,
7814 "notify_post(" _SC_NOTIFY_NETWORK_CHANGE_DNS ") failed: error=%d", status);
7815 }
7816 }
7817
7818 if ((S_network_change_needed & NETWORK_CHANGE_PROXY) != 0) {
7819
7820 #if !TARGET_OS_SIMULATOR
7821 /* Setup or Update config agents */
7822 process_AgentMonitor_Proxy();
7823 #endif //!TARGET_OS_SIMULATOR
7824 status = notify_post(_SC_NOTIFY_NETWORK_CHANGE_PROXY);
7825 if (status != NOTIFY_STATUS_OK) {
7826 my_log(LOG_ERR,
7827 "notify_post(" _SC_NOTIFY_NETWORK_CHANGE_PROXY ") failed: error=%d", status);
7828 }
7829 }
7830
7831 status = notify_post(_SC_NOTIFY_NETWORK_CHANGE);
7832 if (status != NOTIFY_STATUS_OK) {
7833 my_log(LOG_ERR,
7834 "notify_post(" _SC_NOTIFY_NETWORK_CHANGE ") failed: error=%d", status);
7835 }
7836
7837 S_network_change_needed = 0;
7838 return;
7839 }
7840
7841 #define TRAILING_EDGE_TIMEOUT_NSEC 5 * NSEC_PER_SEC // 5s
7842
7843 // Note: must run on __network_change_queue()
7844 static void
7845 post_network_change(uint32_t change)
7846 {
7847 if (S_network_change_needed == 0) {
7848 // set the start time
7849 (void) gettimeofday(&S_network_change_start, NULL);
7850 }
7851
7852 // indicate that we need to post a change for ...
7853 S_network_change_needed |= change;
7854
7855 // cancel any running timer
7856 if (S_network_change_timer != NULL) {
7857 dispatch_source_cancel(S_network_change_timer);
7858 dispatch_release(S_network_change_timer);
7859 S_network_change_timer = NULL;
7860 S_network_change_timeout = FALSE;
7861 }
7862
7863 // if needed, start new timer
7864 if (!S_dnsinfo_synced || !S_nwi_synced) {
7865 S_network_change_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
7866 0,
7867 0,
7868 __network_change_queue());
7869 dispatch_source_set_event_handler(S_network_change_timer, ^{
7870 os_activity_t activity;
7871
7872 activity = os_activity_create("posting delayed network change",
7873 OS_ACTIVITY_CURRENT,
7874 OS_ACTIVITY_FLAG_DEFAULT);
7875 os_activity_scope(activity);
7876
7877 S_network_change_timeout = TRUE;
7878 post_network_change_when_ready();
7879
7880 os_release(activity);
7881 });
7882 dispatch_source_set_timer(S_network_change_timer,
7883 dispatch_time(DISPATCH_TIME_NOW,
7884 TRAILING_EDGE_TIMEOUT_NSEC), // start
7885 DISPATCH_TIME_FOREVER, // interval
7886 10 * NSEC_PER_MSEC); // leeway
7887 dispatch_resume(S_network_change_timer);
7888 }
7889
7890 post_network_change_when_ready();
7891
7892 return;
7893 }
7894
7895 #pragma mark -
7896 #pragma mark Process network (SCDynamicStore) changes
7897
7898 static void
7899 IPMonitorProcessChanges(SCDynamicStoreRef session, CFArrayRef changed_keys,
7900 CFArrayRef if_rank_changes)
7901 {
7902 CFIndex count = 0;
7903 uint32_t changes = 0;
7904 nwi_state_t changes_state = NULL;
7905 boolean_t dns_changed = FALSE;
7906 boolean_t dnsinfo_changed = FALSE;
7907 boolean_t global_ipv4_changed = FALSE;
7908 boolean_t global_ipv6_changed = FALSE;
7909 CFIndex i;
7910 keyChangeList keys;
7911 CFIndex n;
7912 CFMutableStringRef network_change_msg = NULL;
7913 int n_services;
7914 nwi_state_t old_nwi_state = NULL;
7915 CFDictionaryRef old_primary_dns = NULL;
7916 CFDictionaryRef old_primary_proxy = NULL;
7917 #if !TARGET_OS_IPHONE
7918 CFDictionaryRef old_primary_smb = NULL;
7919 #endif // !TARGET_OS_IPHONE
7920 boolean_t proxies_changed = FALSE;
7921 boolean_t reachability_changed = FALSE;
7922 CFArrayRef service_order;
7923 CFMutableArrayRef service_changes = NULL;
7924 CFDictionaryRef services_info = NULL;
7925 #if !TARGET_OS_IPHONE
7926 boolean_t smb_changed = FALSE;
7927 #endif // !TARGET_OS_IPHONE
7928
7929 /* populate name/index cache */
7930 my_if_nameindex();
7931
7932 if (changed_keys != NULL) {
7933 count = CFArrayGetCount(changed_keys);
7934 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
7935 my_log(LOG_DEBUG,
7936 "changed keys %@ (%ld)", changed_keys, count);
7937 }
7938 }
7939 if (if_rank_changes == NULL && count == 0) {
7940 return;
7941 }
7942
7943 if (S_primary_dns != NULL) {
7944 old_primary_dns = service_dict_get(S_primary_dns, kSCEntNetDNS);
7945 if (old_primary_dns != NULL) {
7946 old_primary_dns = CFDictionaryCreateCopy(NULL, old_primary_dns);
7947 }
7948 }
7949
7950 if (S_primary_proxies != NULL) {
7951 old_primary_proxy
7952 = service_dict_get(S_primary_proxies, kSCEntNetProxies);
7953 if (old_primary_proxy != NULL) {
7954 old_primary_proxy = CFDictionaryCreateCopy(NULL, old_primary_proxy);
7955 }
7956 }
7957
7958 #if !TARGET_OS_IPHONE
7959 if (S_primary_smb != NULL) {
7960 old_primary_smb = service_dict_get(S_primary_smb, kSCEntNetSMB);
7961 if (old_primary_smb != NULL) {
7962 old_primary_smb = CFDictionaryCreateCopy(NULL, old_primary_smb);
7963 }
7964 }
7965 #endif // !TARGET_OS_IPHONE
7966
7967 keyChangeListInit(&keys);
7968 service_changes = CFArrayCreateMutable(NULL, 0,
7969 &kCFTypeArrayCallBacks);
7970
7971 for (i = 0; i < count; i++) {
7972 CFStringRef change = CFArrayGetValueAtIndex(changed_keys, i);
7973 if (CFEqual(change, S_setup_global_ipv4)) {
7974 global_ipv4_changed = TRUE;
7975 global_ipv6_changed = TRUE;
7976 }
7977 else if (CFEqual(change, S_multicast_resolvers)) {
7978 dnsinfo_changed = TRUE;
7979 }
7980 else if (CFEqual(change, S_private_resolvers)) {
7981 dnsinfo_changed = TRUE;
7982 }
7983 #if !TARGET_OS_IPHONE
7984 else if (CFEqual(change, CFSTR(_PATH_RESOLVER_DIR))) {
7985 dnsinfo_changed = TRUE;
7986 }
7987 #endif /* !TARGET_OS_IPHONE */
7988 else if (CFStringHasPrefix(change, S_state_service_prefix)) {
7989 CFStringRef serviceID;
7990
7991 serviceID = parse_component(change, S_state_service_prefix);
7992 if (serviceID) {
7993 my_CFArrayAppendUniqueValue(service_changes, serviceID);
7994 CFRelease(serviceID);
7995 }
7996 }
7997 else if (CFStringHasPrefix(change, S_setup_service_prefix)) {
7998 int j;
7999
8000 CFStringRef serviceID = parse_component(change,
8001 S_setup_service_prefix);
8002 if (serviceID) {
8003 my_CFArrayAppendUniqueValue(service_changes, serviceID);
8004 CFRelease(serviceID);
8005 }
8006
8007 for (j = 0; j < countof(transientInterfaceEntityNames); j++) {
8008 if (CFStringHasSuffix(change,
8009 *transientInterfaceEntityNames[j])) {
8010 reachability_changed = TRUE;
8011 break;
8012 }
8013 }
8014
8015 if (CFStringHasSuffix(change, kSCEntNetInterface)) {
8016 reachability_changed = TRUE;
8017 }
8018 }
8019 }
8020
8021 /* determine which serviceIDs are impacted by the interface rank changes */
8022 if (if_rank_changes != NULL) {
8023 n = CFArrayGetCount(if_rank_changes);
8024 for (i = 0; i < n; i++) {
8025 CFStringRef ifname = CFArrayGetValueAtIndex(if_rank_changes, i);
8026
8027 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
8028 my_log(LOG_DEBUG, "Interface rank changed %@", ifname);
8029 }
8030 append_serviceIDs_for_interface(service_changes, ifname);
8031 }
8032 }
8033
8034 /* grab a snapshot of everything we need */
8035 services_info = services_info_copy(session, service_changes);
8036 service_order = service_order_get(services_info);
8037 if (service_order != NULL) {
8038 if ((S_IPMonitor_debug & kDebugFlag1) != 0) {
8039 my_log(LOG_DEBUG, "service_order %@ ", service_order);
8040 }
8041 }
8042
8043 n = CFArrayGetCount(service_changes);
8044 for (i = 0; i < n; i++) {
8045 uint32_t changes;
8046 CFStringRef serviceID;
8047
8048 serviceID = CFArrayGetValueAtIndex(service_changes, i);
8049 changes = service_changed(services_info, serviceID);
8050 if ((changes & (1 << kEntityTypeServiceOptions)) != 0) {
8051 /* if __Service__ (e.g. PrimaryRank) changed */
8052 global_ipv4_changed = TRUE;
8053 global_ipv6_changed = TRUE;
8054 }
8055 else {
8056 if ((changes & (1 << kEntityTypeIPv4)) != 0) {
8057 global_ipv4_changed = TRUE;
8058 dnsinfo_changed = TRUE;
8059 proxies_changed = TRUE;
8060 }
8061 if ((changes & (1 << kEntityTypeIPv6)) != 0) {
8062 global_ipv6_changed = TRUE;
8063 dnsinfo_changed = TRUE;
8064 proxies_changed = TRUE;
8065 }
8066 }
8067 if ((changes & (1 << kEntityTypeDNS)) != 0) {
8068 if (S_primary_dns != NULL && CFEqual(S_primary_dns, serviceID)) {
8069 dns_changed = TRUE;
8070 }
8071 dnsinfo_changed = TRUE;
8072 }
8073 if ((changes & (1 << kEntityTypeProxies)) != 0) {
8074 proxies_changed = TRUE;
8075 }
8076 #if !TARGET_OS_IPHONE
8077 if ((changes & (1 << kEntityTypeSMB)) != 0) {
8078 if (S_primary_smb != NULL && CFEqual(S_primary_smb, serviceID)) {
8079 smb_changed = TRUE;
8080 }
8081 }
8082 #endif
8083 if ((changes & (1 << kEntityTypeTransientStatus)) != 0
8084 && (service_dict_get(serviceID, kSCEntNetIPv4) != NULL
8085 || service_dict_get(serviceID, kSCEntNetIPv6) != NULL)) {
8086 dnsinfo_changed = TRUE;
8087 }
8088 }
8089
8090 /* ensure S_nwi_state can hold as many services as we have currently */
8091 n_services = (int)CFDictionaryGetCount(S_service_state_dict);
8092 old_nwi_state = nwi_state_make_copy(S_nwi_state);
8093 S_nwi_state = nwi_state_new(S_nwi_state, n_services);
8094
8095 if (global_ipv4_changed) {
8096 if (S_ipv4_results != NULL) {
8097 ElectionResultsRelease(S_ipv4_results);
8098 }
8099 S_ipv4_results
8100 = ElectionResultsCopy(AF_INET, service_order);
8101 ElectionResultsLog(LOG_INFO, S_ipv4_results, "IPv4");
8102 }
8103 if (global_ipv6_changed) {
8104 if (S_ipv6_results != NULL) {
8105 ElectionResultsRelease(S_ipv6_results);
8106 }
8107 S_ipv6_results
8108 = ElectionResultsCopy(AF_INET6, service_order);
8109 ElectionResultsLog(LOG_INFO, S_ipv6_results, "IPv6");
8110 }
8111 if (global_ipv4_changed || global_ipv6_changed || dnsinfo_changed) {
8112 CFStringRef new_primary;
8113 CFStringRef new_primary_dns = NULL;
8114 CFStringRef new_primary_proxies = NULL;
8115 #if !TARGET_OS_IPHONE
8116 CFStringRef new_primary_smb = NULL;
8117 #endif /* !TARGET_OS_IPHONE */
8118 RouteListUnion new_routelist;
8119
8120 if (S_nwi_state != NULL) {
8121 nwi_state_clear(S_nwi_state, AF_INET);
8122 nwi_state_clear(S_nwi_state, AF_INET6);
8123 }
8124
8125 /* IPv4 */
8126 my_log(LOG_DEBUG, "electing IPv4 primary");
8127 new_routelist.ptr = NULL;
8128 new_primary = ElectionResultsCopyPrimary(S_ipv4_results,
8129 S_ipv6_results,
8130 S_nwi_state, AF_INET,
8131 &new_routelist.common,
8132 services_info);
8133 (void)set_new_primary(&S_primary_ipv4, new_primary, "IPv4");
8134 update_ipv4(S_primary_ipv4, new_routelist.v4, &keys);
8135 my_CFRelease(&new_primary);
8136
8137 /* IPv6 */
8138 my_log(LOG_DEBUG, "electing IPv6 primary");
8139 new_routelist.ptr = NULL;
8140 new_primary = ElectionResultsCopyPrimary(S_ipv6_results,
8141 S_ipv4_results,
8142 S_nwi_state, AF_INET6,
8143 &new_routelist.common,
8144 services_info);
8145 (void)set_new_primary(&S_primary_ipv6, new_primary, "IPv6");
8146 update_ipv6(S_primary_ipv6, new_routelist.v6, &keys);
8147 my_CFRelease(&new_primary);
8148
8149 nwi_state_finalize(S_nwi_state);
8150
8151 if (S_primary_ipv4 != NULL && S_primary_ipv6 != NULL) {
8152 /* decide between IPv4 and IPv6 */
8153 if (rank_service_entity(S_ipv4_service_rank_dict,
8154 S_primary_ipv4, kSCEntNetDNS)
8155 <= rank_service_entity(S_ipv6_service_rank_dict,
8156 S_primary_ipv6, kSCEntNetDNS)) {
8157 new_primary_dns = S_primary_ipv4;
8158 }
8159 else {
8160 new_primary_dns = S_primary_ipv6;
8161 }
8162 if (rank_service_entity(S_ipv4_service_rank_dict,
8163 S_primary_ipv4, kSCEntNetProxies)
8164 <= rank_service_entity(S_ipv6_service_rank_dict,
8165 S_primary_ipv6, kSCEntNetProxies)) {
8166 new_primary_proxies = S_primary_ipv4;
8167 }
8168 else {
8169 new_primary_proxies = S_primary_ipv6;
8170 }
8171 #if !TARGET_OS_IPHONE
8172 if (rank_service_entity(S_ipv4_service_rank_dict,
8173 S_primary_ipv4, kSCEntNetSMB)
8174 <= rank_service_entity(S_ipv6_service_rank_dict,
8175 S_primary_ipv6, kSCEntNetSMB)) {
8176 new_primary_smb = S_primary_ipv4;
8177 }
8178 else {
8179 new_primary_smb = S_primary_ipv6;
8180 }
8181 #endif /* !TARGET_OS_IPHONE */
8182
8183 }
8184 else if (S_primary_ipv6 != NULL) {
8185 new_primary_dns = S_primary_ipv6;
8186 new_primary_proxies = S_primary_ipv6;
8187 #if !TARGET_OS_IPHONE
8188 new_primary_smb = S_primary_ipv6;
8189 #endif /* !TARGET_OS_IPHONE */
8190 }
8191 else if (S_primary_ipv4 != NULL) {
8192 new_primary_dns = S_primary_ipv4;
8193 new_primary_proxies = S_primary_ipv4;
8194 #if !TARGET_OS_IPHONE
8195 new_primary_smb = S_primary_ipv4;
8196 #endif /* !TARGET_OS_IPHONE */
8197 }
8198
8199 if (set_new_primary(&S_primary_dns, new_primary_dns, "DNS")) {
8200 dns_changed = TRUE;
8201 dnsinfo_changed = TRUE;
8202 }
8203 if (set_new_primary(&S_primary_proxies, new_primary_proxies,
8204 "Proxies")) {
8205 proxies_changed = TRUE;
8206 }
8207 #if !TARGET_OS_IPHONE
8208 if (set_new_primary(&S_primary_smb, new_primary_smb, "SMB")) {
8209 smb_changed = TRUE;
8210 }
8211 #endif /* !TARGET_OS_IPHONE */
8212 }
8213
8214 if (!proxies_changed && dnsinfo_changed
8215 && ((G_supplemental_proxies_follow_dns != NULL)
8216 && CFBooleanGetValue(G_supplemental_proxies_follow_dns))) {
8217 proxies_changed = TRUE;
8218 }
8219
8220 changes_state = nwi_state_diff(old_nwi_state, S_nwi_state);
8221
8222 if (global_ipv4_changed || global_ipv6_changed
8223 || dnsinfo_changed || reachability_changed) {
8224 if (S_nwi_state != NULL) {
8225 S_nwi_state->generation_count = mach_absolute_time();
8226 if (global_ipv4_changed || global_ipv6_changed
8227 || reachability_changed) {
8228 SCNetworkReachabilityFlags reach_flags_v4 = 0;
8229 SCNetworkReachabilityFlags reach_flags_v6 = 0;
8230
8231 GetReachabilityFlagsFromTransientServices(services_info,
8232 &reach_flags_v4,
8233 &reach_flags_v6);
8234
8235 _nwi_state_set_reachability_flags(S_nwi_state, reach_flags_v4,
8236 reach_flags_v6);
8237 }
8238
8239 /* Update the per-interface generation count */
8240 _nwi_state_update_interface_generations(old_nwi_state, S_nwi_state,
8241 changes_state);
8242 }
8243
8244 if (update_nwi(S_nwi_state)) {
8245 changes |= NETWORK_CHANGE_NET;
8246
8247 /*
8248 * the DNS configuration includes per-resolver configuration
8249 * reachability flags that are based on the nwi state. Let's
8250 * make sure that we check for changes
8251 */
8252 dnsinfo_changed = TRUE;
8253 }
8254 }
8255 if (dns_changed) {
8256 if (update_dns(services_info, S_primary_dns, &keys)) {
8257 changes |= NETWORK_CHANGE_DNS;
8258 dnsinfo_changed = TRUE;
8259 } else {
8260 dns_changed = FALSE;
8261 }
8262 }
8263 if (dnsinfo_changed) {
8264 if (update_dnsinfo(services_info, S_primary_dns,
8265 &keys, service_order)) {
8266 changes |= NETWORK_CHANGE_DNS;
8267 } else {
8268 dnsinfo_changed = FALSE;
8269 }
8270 }
8271 if (proxies_changed) {
8272 // if proxy change OR supplemental Proxies follow supplemental DNS
8273 if (update_proxies(services_info, S_primary_proxies,
8274 &keys, service_order)) {
8275 changes |= NETWORK_CHANGE_PROXY;
8276 } else {
8277 proxies_changed = FALSE;
8278 }
8279 }
8280 #if !TARGET_OS_IPHONE
8281 if (smb_changed) {
8282 if (update_smb(services_info, S_primary_smb, &keys)) {
8283 changes |= NETWORK_CHANGE_SMB;
8284 } else {
8285 smb_changed = FALSE;
8286 }
8287 }
8288 #endif /* !TARGET_OS_IPHONE */
8289 my_CFRelease(&service_changes);
8290 my_CFRelease(&services_info);
8291
8292 if (changes != 0) {
8293 network_change_msg = CFStringCreateMutable(NULL, 0);
8294 process_nwi_changes(network_change_msg,
8295 changes_state,
8296 S_nwi_state,
8297 old_nwi_state,
8298 dns_changed,
8299 dnsinfo_changed,
8300 old_primary_dns,
8301 proxies_changed,
8302 old_primary_proxy,
8303 #if !TARGET_OS_IPHONE
8304 smb_changed,
8305 old_primary_smb
8306 #else // !TARGET_OS_IPHONE
8307 FALSE, // smb_changed
8308 NULL // old_primary_smb
8309 #endif // !TARGET_OS_IPHONE
8310 );
8311 }
8312
8313 keyChangeListApplyToStore(&keys, session);
8314 my_CFRelease(&old_primary_dns);
8315 my_CFRelease(&old_primary_proxy);
8316 #if !TARGET_OS_IPHONE
8317 my_CFRelease(&old_primary_smb);
8318 #endif // !TARGET_OS_IPHONE
8319
8320 if (changes != 0) {
8321 dispatch_async(__network_change_queue(), ^{
8322 post_network_change(changes);
8323 });
8324 }
8325
8326 if ((network_change_msg != NULL)
8327 && (CFStringGetLength(network_change_msg) != 0)) {
8328 my_log(LOG_NOTICE, "network changed:%@", network_change_msg);
8329 } else if (keyChangeListActive(&keys)) {
8330 my_log(LOG_NOTICE, "network changed");
8331 } else {
8332 my_log(LOG_INFO, "network event w/no changes");
8333 }
8334
8335 my_CFRelease(&network_change_msg);
8336
8337 if (changes_state != NULL) {
8338 nwi_state_free(changes_state);
8339 }
8340 if (old_nwi_state != NULL) {
8341 nwi_state_free(old_nwi_state);
8342 }
8343 keyChangeListFree(&keys);
8344
8345 /* release the name/index cache */
8346 my_if_freenameindex();
8347
8348 return;
8349 }
8350
8351 static void
8352 IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys,
8353 void * not_used)
8354 {
8355 IPMonitorProcessChanges(session, changed_keys, NULL);
8356 return;
8357 }
8358
8359 #if !TARGET_OS_IPHONE
8360 #define PROXY_GLOBAL_OBSERVER_TYPE scprefs_observer_type_mcx
8361 #else
8362 #define PROXY_GLOBAL_OBSERVER_TYPE scprefs_observer_type_global
8363 #endif
8364
8365 static void
8366 watch_proxies()
8367 {
8368 static dispatch_queue_t proxy_cb_queue;
8369
8370 proxy_cb_queue = dispatch_queue_create("com.apple.SystemConfiguration.IPMonitor.proxy", NULL);
8371 _scprefs_observer_watch(PROXY_GLOBAL_OBSERVER_TYPE,
8372 "com.apple.SystemConfiguration.plist",
8373 proxy_cb_queue,
8374 ^{
8375 SCDynamicStoreNotifyValue(NULL, S_state_global_proxies);
8376 #if !TARGET_OS_SIMULATOR
8377 /* Setup or Update config agents */
8378 process_AgentMonitor_Proxy();
8379 #endif //!TARGET_OS_SIMULATOR
8380 (void)notify_post(_SC_NOTIFY_NETWORK_CHANGE_PROXY);
8381 my_log(LOG_INFO, "Notifying:\n%@",
8382 S_state_global_proxies);
8383 });
8384 return;
8385 }
8386
8387 #include "IPMonitorControlPrefs.h"
8388
8389 static void
8390 prefs_changed(__unused SCPreferencesRef prefs)
8391 {
8392 if (S_bundle_logging_verbose || IPMonitorControlPrefsIsVerbose()) {
8393 S_IPMonitor_debug = kDebugFlagDefault;
8394 S_IPMonitor_verbose = TRUE;
8395 SCLoggerSetFlags(S_IPMonitor_logger, kSCLoggerFlagsFile | kSCLoggerFlagsDefault);
8396 my_log(LOG_DEBUG, "Setting logging verbose mode on");
8397 } else {
8398 my_log(LOG_DEBUG, "Setting logging verbose mode off");
8399 S_IPMonitor_debug = 0;
8400 S_IPMonitor_verbose = FALSE;
8401 SCLoggerSetFlags(S_IPMonitor_logger, kSCLoggerFlagsDefault);
8402 }
8403 return;
8404 }
8405
8406 #define LOGGER_ID CFSTR("com.apple.networking.IPMonitor")
8407 static void
8408 my_log_init()
8409 {
8410 S_IPMonitor_logger = SCLoggerCreate(LOGGER_ID);
8411 return;
8412
8413 }
8414
8415
8416 #if !TARGET_OS_SIMULATOR
8417 static int
8418 flush_routes(int s)
8419 {
8420 char * buf = NULL;
8421 int i;
8422 char * lim;
8423 #define N_MIB 6
8424 int mib[N_MIB];
8425 size_t needed;
8426 char * next;
8427 struct rt_msghdr * rtm;
8428 struct sockaddr_in *sin;
8429
8430 mib[0] = CTL_NET;
8431 mib[1] = PF_ROUTE;
8432 mib[2] = 0;
8433 mib[3] = AF_INET;
8434 mib[4] = NET_RT_FLAGS;
8435 mib[5] = RTF_STATIC | RTF_DYNAMIC;
8436 for (i = 0; i < 3; i++) {
8437 if (sysctl(mib, N_MIB, NULL, &needed, NULL, 0) < 0) {
8438 break;
8439 }
8440 if ((buf = malloc(needed)) == NULL) {
8441 break;
8442 }
8443 if (sysctl(mib, N_MIB, buf, &needed, NULL, 0) >= 0) {
8444 break;
8445 }
8446 free(buf);
8447 buf = NULL;
8448 }
8449 if (buf == NULL) {
8450 return (-1);
8451 }
8452 lim = buf + needed;
8453 for (next = buf; next < lim; next += rtm->rtm_msglen) {
8454 uint32_t addr;
8455
8456 /* ALIGN: assume kernel provides necessary alignment */
8457 rtm = (struct rt_msghdr *)(void *)next;
8458 sin = (struct sockaddr_in *)(rtm + 1);
8459
8460 addr = ntohl(sin->sin_addr.s_addr);
8461 if (IN_LOOPBACK(addr)) {
8462 my_log(LOG_DEBUG,
8463 "flush_routes: ignoring loopback route");
8464 continue;
8465 }
8466 if (IN_LOCAL_GROUP(addr)) {
8467 my_log(LOG_DEBUG,
8468 "flush_routes: ignoring multicast route");
8469 continue;
8470 }
8471 rtm->rtm_type = RTM_DELETE;
8472 rtm->rtm_seq = ++rtm_seq;
8473 if (write(s, rtm, rtm->rtm_msglen) < 0) {
8474 my_log(LOG_NOTICE,
8475 "flush_routes: removing route for "
8476 IP_FORMAT " failed: %s",
8477 IP_LIST(&sin->sin_addr),
8478 strerror(errno));
8479 }
8480 else {
8481 my_log(LOG_DEBUG,
8482 "flush_routes: removed route for " IP_FORMAT,
8483 IP_LIST(&sin->sin_addr));
8484 }
8485 }
8486 free(buf);
8487 return (0);
8488 }
8489
8490 static void
8491 flush_inet_routes(void)
8492 {
8493 int s;
8494
8495 s = open_routing_socket();
8496 if (s != -1) {
8497 flush_routes(s);
8498 close(s);
8499 }
8500 }
8501
8502 #else /* !TARGET_OS_SIMULATOR */
8503
8504 static void
8505 flush_inet_routes(void)
8506 {
8507 }
8508
8509 #endif /* !TARGET_OS_SIMULATOR */
8510
8511
8512
8513 static void
8514 ip_plugin_init()
8515 {
8516 CFMutableArrayRef keys = NULL;
8517 CFStringRef pattern;
8518 CFMutableArrayRef patterns = NULL;
8519 CFRunLoopSourceRef rls = NULL;
8520
8521 if (S_is_network_boot() != 0) {
8522 S_netboot = TRUE;
8523 }
8524 else {
8525 /* flush routes */
8526 flush_inet_routes();
8527 }
8528
8529 S_session = SCDynamicStoreCreate(NULL, CFSTR("IPMonitor"),
8530 IPMonitorNotify, NULL);
8531 if (S_session == NULL) {
8532 my_log(LOG_ERR,
8533 "IPMonitor ip_plugin_init SCDynamicStoreCreate failed: %s",
8534 SCErrorString(SCError()));
8535 return;
8536 }
8537 S_state_global_ipv4
8538 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
8539 kSCDynamicStoreDomainState,
8540 kSCEntNetIPv4);
8541 S_state_global_ipv6
8542 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
8543 kSCDynamicStoreDomainState,
8544 kSCEntNetIPv6);
8545 S_state_global_dns
8546 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
8547 kSCDynamicStoreDomainState,
8548 kSCEntNetDNS);
8549 S_state_global_proxies
8550 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
8551 kSCDynamicStoreDomainState,
8552 kSCEntNetProxies);
8553 #if !TARGET_OS_IPHONE
8554 S_state_global_smb
8555 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
8556 kSCDynamicStoreDomainState,
8557 kSCEntNetSMB);
8558 #endif /* !TARGET_OS_IPHONE */
8559 S_setup_global_ipv4
8560 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
8561 kSCDynamicStoreDomainSetup,
8562 kSCEntNetIPv4);
8563 S_state_service_prefix
8564 = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
8565 kSCDynamicStoreDomainState,
8566 CFSTR(""),
8567 NULL);
8568 S_setup_service_prefix
8569 = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
8570 kSCDynamicStoreDomainSetup,
8571 CFSTR(""),
8572 NULL);
8573 S_service_state_dict
8574 = CFDictionaryCreateMutable(NULL, 0,
8575 &kCFTypeDictionaryKeyCallBacks,
8576 &kCFTypeDictionaryValueCallBacks);
8577
8578 S_ipv4_service_rank_dict
8579 = CFDictionaryCreateMutable(NULL, 0,
8580 &kCFTypeDictionaryKeyCallBacks,
8581 &kCFTypeDictionaryValueCallBacks);
8582
8583 S_ipv6_service_rank_dict
8584 = CFDictionaryCreateMutable(NULL, 0,
8585 &kCFTypeDictionaryKeyCallBacks,
8586 &kCFTypeDictionaryValueCallBacks);
8587
8588 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8589 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
8590
8591 /* register for State: and Setup: per-service notifications */
8592 add_service_keys(kSCCompAnyRegex, keys, patterns);
8593
8594 pattern = setup_service_key(kSCCompAnyRegex, kSCEntNetPPP);
8595 CFArrayAppendValue(patterns, pattern);
8596 CFRelease(pattern);
8597
8598 pattern = setup_service_key(kSCCompAnyRegex, kSCEntNetVPN);
8599 CFArrayAppendValue(patterns, pattern);
8600 CFRelease(pattern);
8601
8602 pattern = setup_service_key(kSCCompAnyRegex, kSCEntNetInterface);
8603 CFArrayAppendValue(patterns, pattern);
8604 CFRelease(pattern);
8605
8606 /* register for State: per-service PPP/VPN/IPSec status notifications */
8607 add_transient_status_keys(kSCCompAnyRegex, patterns);
8608
8609 /* add notifier for ServiceOrder/PPPOverridePrimary changes for IPv4 */
8610 CFArrayAppendValue(keys, S_setup_global_ipv4);
8611
8612 /* add notifier for multicast DNS configuration (Bonjour/.local) */
8613 S_multicast_resolvers = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
8614 kSCDynamicStoreDomainState,
8615 kSCCompNetwork,
8616 CFSTR(kDNSServiceCompMulticastDNS));
8617 CFArrayAppendValue(keys, S_multicast_resolvers);
8618
8619 /* add notifier for private DNS configuration (Back to My Mac) */
8620 S_private_resolvers = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@"),
8621 kSCDynamicStoreDomainState,
8622 kSCCompNetwork,
8623 CFSTR(kDNSServiceCompPrivateDNS));
8624 CFArrayAppendValue(keys, S_private_resolvers);
8625
8626 if (!SCDynamicStoreSetNotificationKeys(S_session, keys, patterns)) {
8627 my_log(LOG_ERR,
8628 "SCDynamicStoreSetNotificationKeys() failed: %s",
8629 SCErrorString(SCError()));
8630 goto done;
8631 }
8632
8633 rls = SCDynamicStoreCreateRunLoopSource(NULL, S_session, 0);
8634 if (rls == NULL) {
8635 my_log(LOG_ERR,
8636 "SCDynamicStoreCreateRunLoopSource() failed: %s",
8637 SCErrorString(SCError()));
8638 goto done;
8639 }
8640
8641 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
8642 CFRelease(rls);
8643
8644 /* initialize dns configuration */
8645 (void)dns_configuration_set(NULL, NULL, NULL, NULL, NULL);
8646 #if !TARGET_OS_IPHONE
8647 empty_dns();
8648 #endif /* !TARGET_OS_IPHONE */
8649 (void)SCDynamicStoreRemoveValue(S_session, S_state_global_dns);
8650
8651 #if !TARGET_OS_IPHONE
8652 /* initialize SMB configuration */
8653 (void)SCDynamicStoreRemoveValue(S_session, S_state_global_smb);
8654 #endif /* !TARGET_OS_IPHONE */
8655
8656 watch_proxies();
8657
8658 done:
8659 my_CFRelease(&keys);
8660 my_CFRelease(&patterns);
8661 return;
8662 }
8663
8664 __private_extern__
8665 void
8666 prime_IPMonitor()
8667 {
8668 /* initialize multicast route */
8669 update_ipv4(NULL, NULL, NULL);
8670
8671 #if !TARGET_OS_SIMULATOR
8672 process_AgentMonitor();
8673 #endif // !TARGET_OS_SIMULATOR
8674
8675 return;
8676 }
8677
8678 static boolean_t
8679 S_get_plist_boolean(CFDictionaryRef plist, CFStringRef key,
8680 boolean_t def)
8681 {
8682 CFBooleanRef b;
8683 boolean_t ret = def;
8684
8685 b = isA_CFBoolean(CFDictionaryGetValue(plist, key));
8686 if (b != NULL) {
8687 ret = CFBooleanGetValue(b);
8688 }
8689 return (ret);
8690 }
8691
8692 #if !TARGET_OS_SIMULATOR
8693 #include "IPMonitorControlServer.h"
8694
8695 static void
8696 InterfaceRankChanged(void * info)
8697 {
8698 os_activity_t activity;
8699 CFDictionaryRef assertions = NULL;
8700 CFArrayRef changes;
8701
8702 activity = os_activity_create("processing IPMonitor [rank] change",
8703 OS_ACTIVITY_CURRENT,
8704 OS_ACTIVITY_FLAG_DEFAULT);
8705 os_activity_scope(activity);
8706
8707 changes = IPMonitorControlServerCopyInterfaceRankInformation(&assertions);
8708 if (S_if_rank_dict != NULL) {
8709 CFRelease(S_if_rank_dict);
8710 }
8711 S_if_rank_dict = assertions;
8712 if (changes != NULL) {
8713 IPMonitorProcessChanges(S_session, NULL, changes);
8714 CFRelease(changes);
8715 }
8716
8717 os_release(activity);
8718
8719 return;
8720 }
8721
8722 static void
8723 StartIPMonitorControlServer(void)
8724 {
8725 CFRunLoopSourceContext context;
8726 CFRunLoopSourceRef rls;
8727
8728 bzero(&context, sizeof(context));
8729 context.perform = InterfaceRankChanged;
8730 rls = CFRunLoopSourceCreate(NULL, 0, &context);
8731 if (!IPMonitorControlServerStart(CFRunLoopGetCurrent(),
8732 rls,
8733 &S_bundle_logging_verbose)) {
8734 my_log(LOG_ERR, "IPMonitorControlServerStart failed");
8735 }
8736 else {
8737 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls,
8738 kCFRunLoopDefaultMode);
8739 }
8740 CFRelease(rls);
8741 return;
8742 }
8743
8744 #endif /* !TARGET_OS_SIMULATOR */
8745
8746 __private_extern__
8747 void
8748 load_IPMonitor(CFBundleRef bundle, Boolean bundleVerbose)
8749 {
8750 CFDictionaryRef info_dict;
8751
8752 info_dict = CFBundleGetInfoDictionary(bundle);
8753
8754 if (info_dict != NULL) {
8755 S_append_state
8756 = S_get_plist_boolean(info_dict,
8757 CFSTR("AppendStateArrayToSetupArray"),
8758 FALSE);
8759 }
8760 if (bundleVerbose) {
8761 S_IPMonitor_debug = kDebugFlagDefault;
8762 S_bundle_logging_verbose = TRUE;
8763 S_IPMonitor_verbose = TRUE;
8764 }
8765
8766 my_log_init();
8767
8768 /* register to receive changes to verbose and read the initial setting */
8769 IPMonitorControlPrefsInit(CFRunLoopGetCurrent(), prefs_changed);
8770 prefs_changed(NULL);
8771
8772 load_DNSConfiguration(bundle, // bundle
8773 ^(Boolean inSync) { // syncHandler
8774 dispatch_async(__network_change_queue(), ^{
8775 S_dnsinfo_synced = inSync;
8776
8777 if (inSync &&
8778 ((S_network_change_needed & NETWORK_CHANGE_DNS) == 0)) {
8779 // all of the DNS service ack's should result
8780 // in a [new] network change being posted
8781 post_network_change(NETWORK_CHANGE_DNS);
8782 } else {
8783 post_network_change_when_ready();
8784 }
8785 });
8786 });
8787
8788 load_NetworkInformation(bundle, // bundle
8789 ^(Boolean inSync) { // syncHandler
8790 dispatch_async(__network_change_queue(), ^{
8791 S_nwi_synced = inSync;
8792 post_network_change_when_ready();
8793 });
8794 });
8795 #if !TARGET_OS_SIMULATOR
8796 StartIPMonitorControlServer();
8797 #endif /* !TARGET_OS_IPHONE */
8798
8799 dns_configuration_init(bundle);
8800
8801 proxy_configuration_init(bundle);
8802
8803 ip_plugin_init();
8804
8805 #if !TARGET_OS_IPHONE
8806 if (S_session != NULL) {
8807 dns_configuration_monitor(S_session, IPMonitorNotify);
8808 }
8809 #endif /* !TARGET_OS_IPHONE */
8810
8811 #if !TARGET_OS_SIMULATOR
8812 load_hostname(TRUE);
8813 #endif /* !TARGET_OS_SIMULATOR */
8814
8815 #if !TARGET_OS_IPHONE
8816 load_smb_configuration(TRUE);
8817 #endif /* !TARGET_OS_IPHONE */
8818
8819 return;
8820 }
8821
8822
8823 #pragma mark -
8824 #pragma mark Standalone test code
8825
8826
8827 #ifdef TEST_IPMONITOR
8828
8829 int
8830 main(int argc, char **argv)
8831 {
8832 _sc_log = FALSE;
8833
8834 S_IPMonitor_debug = kDebugFlag1;
8835 if (argc > 1) {
8836 S_IPMonitor_debug = strtoul(argv[1], NULL, 0);
8837 }
8838
8839 load_IPMonitor(CFBundleGetMainBundle(), FALSE);
8840 prime_IPMonitor();
8841 S_IPMonitor_debug = kDebugFlag1;
8842 CFRunLoopRun();
8843 /* not reached */
8844 exit(0);
8845 return 0;
8846 }
8847 #endif /* TEST_IPMONITOR */
8848
8849 #ifdef TEST_ROUTELIST
8850
8851 struct route {
8852 const char * dest;
8853 int prefix_length;
8854 const char * gateway;
8855 const char * ifname;
8856 };
8857
8858 #endif
8859
8860 #ifdef TEST_IPV4_ROUTELIST
8861
8862 typedef struct {
8863 const char * addr;
8864 int prefix_length;
8865 const char * dest;
8866 const char * router;
8867 const char * ifname;
8868 Rank rank;
8869 const CFStringRef * primary_rank;
8870 struct route * additional_routes;
8871 int additional_routes_count;
8872 struct route * excluded_routes;
8873 int excluded_routes_count;
8874 } IPv4ServiceContents;
8875
8876 typedef const IPv4ServiceContents * IPv4ServiceContentsRef;
8877
8878 struct route loop_routelist[] = {
8879 { "1.1.1.1", 32, "1.1.1.2", NULL },
8880 { "1.1.1.2", 32, "1.1.1.3", NULL },
8881 { "1.1.1.3", 32, "1.1.1.4", NULL },
8882 { "1.1.1.4", 32, "1.1.1.5", NULL },
8883 { "1.1.1.5", 32, "1.1.1.6", NULL },
8884 { "1.1.1.6", 32, "1.1.1.7", NULL },
8885 { "1.1.1.7", 32, "1.1.1.8", NULL },
8886 { "1.1.1.8", 32, "1.1.1.9", NULL },
8887 { "1.1.1.9", 32, "1.1.1.10", NULL },
8888 { "1.1.1.10", 32, "1.1.1.11", NULL },
8889 { "1.1.1.11", 32, "1.1.1.1", NULL },
8890 };
8891
8892 struct route vpn_routelist[] = {
8893 { "10.1.3.0", 24, "17.153.46.24", NULL },
8894 { "10.1.4.0", 24, "17.153.46.24", NULL },
8895 { "10.1.5.0", 24, "17.153.46.24", NULL },
8896 { "10.1.6.0", 24, "17.153.46.24", NULL },
8897 { "10.1.7.0", 24, "17.153.46.24", NULL },
8898 { "10.16.0.0", 12, "17.153.46.24", NULL },
8899 { "10.45.0.0", 16, "17.153.46.24", NULL },
8900 { "10.53.0.0", 16, "17.153.46.24", NULL },
8901 { "10.70.0.0", 15, "17.153.46.24", NULL },
8902 { "10.74.0.0", 15, "17.153.46.24", NULL },
8903 { "10.90.0.0", 15, "17.153.46.24", NULL },
8904 { "10.91.0.0", 16, "17.153.46.24", NULL },
8905 { "10.100.0.0", 16, "17.153.46.24", NULL },
8906 { "10.113.0.0", 16, "17.153.46.24", NULL },
8907 { "10.128.0.0", 9, "17.153.46.24", NULL },
8908 { "17.0.0.0", 9, "17.153.46.24", NULL },
8909 { "17.34.0.0", 16, "17.153.46.24", NULL },
8910 { "17.112.156.53", 32, "17.153.46.24", NULL },
8911 { "17.128.0.0", 10, "17.153.46.24", NULL },
8912 { "17.149.0.121", 32, "17.153.46.24", NULL },
8913 { "17.149.7.200", 32, "17.153.46.24", NULL },
8914 { "17.153.46.24", 32, "17.153.46.24", NULL },
8915 { "17.192.0.0", 12, "17.153.46.24", NULL },
8916 { "17.208.0.0", 15, "17.153.46.24", NULL },
8917 { "17.211.0.0", 16, "17.153.46.24", NULL },
8918 { "17.212.0.0", 14, "17.153.46.24", NULL },
8919 { "17.216.0.0", 13, "17.153.46.24", NULL },
8920 { "17.224.0.0", 12, "17.153.46.24", NULL },
8921 { "17.240.0.0", 16, "17.153.46.24", NULL },
8922 { "17.241.0.0", 16, "17.153.46.24", NULL },
8923 { "17.248.0.0", 14, "17.153.46.24", NULL },
8924 { "17.251.104.200", 32, "17.153.46.24", NULL },
8925 { "17.252.0.0", 16, "17.153.46.24", NULL },
8926 { "17.253.0.0", 16, "17.153.46.24", NULL },
8927 { "17.254.0.0", 16, "17.153.46.24", NULL },
8928 { "17.255.0.0", 16, "17.153.46.24", NULL },
8929 { "151.193.141.0", 27, "17.153.46.24", NULL },
8930 { "172.16.2.0", 24, "17.153.46.24", NULL },
8931 { "192.35.50.0", 24, "17.153.46.24", NULL },
8932 { "204.179.20.0", 24, "17.153.46.24", NULL },
8933 { "206.112.116.0", 24, "17.153.46.24", NULL },
8934 };
8935
8936 struct route vpn_routelist_ext[] = {
8937 { "17.151.63.82", 32, "10.0.0.1", "en0" },
8938 { "17.151.63.81", 32, "17.151.63.81", "en0" },
8939 { "17.151.63.80", 32, NULL, NULL },
8940 { "17.1.0.0", 16, NULL, NULL },
8941 { "17.2.0.0", 24, NULL, NULL },
8942 { "10.0.0.0", 24, NULL, NULL },
8943 };
8944
8945 /*
8946 * addr prefix dest router ifname pri rank additional-routes+count excluded-routes+count
8947 */
8948 const IPv4ServiceContents en0_10 = {
8949 "10.0.0.10", 24, NULL, "10.0.0.1", "en0", 10, NULL, NULL, 0, NULL, 0
8950 };
8951
8952 const IPv4ServiceContents en0_15 = {
8953 "10.0.0.19", 24, NULL, "10.0.0.1", "en0", 15, NULL, NULL, 0, NULL, 0
8954 };
8955
8956 const IPv4ServiceContents en0_30 = {
8957 "10.0.0.11", 24, NULL, "10.0.0.1", "en0", 30, NULL, NULL, 0, NULL, 0
8958 };
8959
8960 const IPv4ServiceContents en0_40 = {
8961 "10.0.0.12", 24, NULL, "10.0.0.1", "en0", 40, NULL, NULL, 0, NULL, 0
8962 };
8963
8964 const IPv4ServiceContents en0_50 = {
8965 "10.0.0.13", 24, NULL, "10.0.0.1", "en0", 50, NULL, NULL, 0, NULL, 0
8966 };
8967
8968 const IPv4ServiceContents en0_110 = {
8969 "192.168.2.10", 24, NULL, "192.168.2.1", "en0", 110, NULL, NULL, 0, NULL, 0
8970 };
8971
8972 const IPv4ServiceContents en0_1 = {
8973 "17.202.40.191", 22, NULL, "17.202.20.1", "en0", 1, NULL, NULL, 0, NULL, 0
8974 };
8975
8976 const IPv4ServiceContents en1_20 = {
8977 "10.0.0.20", 24, NULL, "10.0.0.1", "en1", 20, NULL, NULL, 0, NULL, 0
8978 };
8979
8980 const IPv4ServiceContents en1_2 = {
8981 "17.202.42.24", 22, NULL, "17.202.20.1", "en1", 2, NULL, NULL, 0, NULL, 0
8982 };
8983
8984 const IPv4ServiceContents en1_125 = {
8985 "192.168.2.20", 24, NULL, "192.168.2.1", "en1", 125, NULL, NULL, 0, NULL, 0
8986 };
8987
8988 const IPv4ServiceContents fw0_25 = {
8989 "192.168.2.30", 24, NULL, "192.168.2.1", "fw0", 25, NULL, NULL, 0, NULL, 0
8990 };
8991
8992 const IPv4ServiceContents fw0_21 = {
8993 "192.168.3.30", 24, NULL, "192.168.3.1", "fw0", 21, NULL, NULL, 0, NULL, 0
8994 };
8995
8996 const IPv4ServiceContents ppp0_0_1 = {
8997 "17.219.156.22", -1, "17.219.156.1", "17.219.156.1", "ppp0", 0, NULL, NULL, 0, NULL, 0
8998 };
8999
9000 const IPv4ServiceContents utun0 = {
9001 "17.153.46.24", -1, "17.153.46.24", "17.153.46.24", "utun0", 20, NULL, vpn_routelist, countof(vpn_routelist), vpn_routelist_ext, countof(vpn_routelist_ext)
9002 };
9003
9004 const IPv4ServiceContents en0_test6 = {
9005 "17.202.42.113", 22, NULL, "17.202.40.1", "en0", 2, NULL, NULL, 0, NULL, 0
9006 };
9007
9008 const IPv4ServiceContents en1_test6 = {
9009 "17.202.42.111", 22, NULL, "17.202.40.1", "en1", 3, NULL, NULL, 0, NULL, 0
9010 };
9011
9012 const IPv4ServiceContents en2_test6 = {
9013 "17.255.98.164", 20, NULL, "17.255.96.1", "en2", 1, NULL, NULL, 0, NULL, 0
9014 };
9015
9016 const IPv4ServiceContents en0_test7 = {
9017 "17.202.42.113", 22, NULL, "17.202.40.1", "en0", 3, NULL, NULL, 0, NULL, 0
9018 };
9019
9020 const IPv4ServiceContents en1_test7 = {
9021 "17.202.42.111", 22, NULL, "17.202.40.1", "en1", 2, NULL, NULL, 0, NULL, 0
9022 };
9023
9024 const IPv4ServiceContents en2_test7 = {
9025 "17.255.98.164", 20, NULL, "17.255.96.1", "en2", 1, NULL, NULL, 0, NULL, 0
9026 };
9027
9028 const IPv4ServiceContents fw0_test6_and_7 = {
9029 "169.254.11.33", 16, NULL, NULL, "fw0", 0x0ffffff, NULL, NULL, 0, NULL, 0
9030 };
9031
9032 const IPv4ServiceContents en0_10_last = {
9033 "10.0.0.10", 24, NULL, "10.0.0.1", "en0", 10, &kSCValNetServicePrimaryRankLast, NULL, 0, NULL, 0
9034 };
9035
9036 const IPv4ServiceContents en0_10_never = {
9037 "10.0.0.10", 24, NULL, "10.0.0.1", "en0", 10, &kSCValNetServicePrimaryRankNever, NULL, 0, NULL, 0
9038 };
9039
9040 const IPv4ServiceContents en1_20_first = {
9041 "10.0.0.20", 24, NULL, "10.0.0.1", "en1", 20, &kSCValNetServicePrimaryRankFirst, NULL, 0, NULL, 0
9042 };
9043
9044 const IPv4ServiceContents en1_20_never = {
9045 "10.0.0.20", 24, NULL, "10.0.0.1", "en1", 20, &kSCValNetServicePrimaryRankNever, NULL, 0, NULL, 0
9046 };
9047
9048 const IPv4ServiceContents en1_20_other_never = {
9049 "192.168.2.50", 24, NULL, "192.168.2.1", "en1", 20, &kSCValNetServicePrimaryRankNever, NULL, 0, NULL, 0
9050 };
9051
9052 const IPv4ServiceContents en0_linklocal = {
9053 "169.254.22.44", 16, NULL, NULL, "en0", 0xfffff, NULL, NULL, 0, NULL, 0
9054 };
9055
9056 const IPv4ServiceContents en0_route_loop = {
9057 "192.168.130.16", 24, NULL, "192.168.130.1", "en0", 2, NULL, loop_routelist, countof(loop_routelist), NULL, 0
9058 };
9059
9060 typedef struct {
9061 const char * name;
9062 IPv4ServiceContentsRef test[];
9063 } IPv4RouteTest, * IPv4RouteTestRef;
9064
9065 static IPv4RouteTest test1 = {
9066 "test1",
9067 {
9068 &en0_40,
9069 &en0_15,
9070 &fw0_25,
9071 &en0_30,
9072 &en1_20,
9073 &en0_50,
9074 &en0_10,
9075 NULL
9076 }
9077 };
9078
9079 static IPv4RouteTest test2 = {
9080 "test2",
9081 {
9082 &en0_40,
9083 &fw0_25,
9084 &en0_30,
9085 &en1_20,
9086 &en0_50,
9087 &en0_10,
9088 NULL
9089 }
9090 };
9091
9092 static IPv4RouteTest test3 = {
9093 "test3",
9094 {
9095 &en0_40,
9096 &en1_20,
9097 &en0_50,
9098 &en0_10,
9099 &en0_110,
9100 &en1_125,
9101 &fw0_25,
9102 &fw0_21,
9103 &en0_40,
9104 &en0_30,
9105 NULL
9106 }
9107 };
9108
9109 static IPv4RouteTest test4 = {
9110 "test4",
9111 {
9112 &en0_1,
9113 &en0_40,
9114 &en0_30,
9115 &en1_20,
9116 &en1_2,
9117 NULL
9118 }
9119 };
9120
9121 static IPv4RouteTest test5 = {
9122 "test5",
9123 {
9124 &ppp0_0_1,
9125 &en0_1,
9126 &en0_40,
9127 &en0_30,
9128 &en1_20,
9129 &en1_2,
9130 NULL
9131 }
9132 };
9133
9134 static IPv4RouteTest test6 = {
9135 "test6",
9136 {
9137 &en0_test6,
9138 &en1_test6,
9139 &en2_test6,
9140 &fw0_test6_and_7,
9141 NULL
9142 }
9143 };
9144
9145 static IPv4RouteTest test7 = {
9146 "test7",
9147 {
9148 &en0_test7,
9149 &en1_test7,
9150 &en2_test7,
9151 &fw0_test6_and_7,
9152 NULL
9153 }
9154 };
9155
9156 static IPv4RouteTest test8 = {
9157 "test8",
9158 {
9159 &en0_10,
9160 &en1_20,
9161 NULL
9162 }
9163 };
9164
9165 static IPv4RouteTest test9 = {
9166 "test9",
9167 {
9168 &en0_10,
9169 &en1_20_first,
9170 &fw0_25,
9171 NULL
9172 }
9173 };
9174
9175 static IPv4RouteTest test10 = {
9176 "test10",
9177 {
9178 &en0_10_last,
9179 &en1_20,
9180 &fw0_25,
9181 NULL
9182 }
9183 };
9184
9185 static IPv4RouteTest test11 = {
9186 "test11",
9187 {
9188 &en0_10_never,
9189 &en1_20,
9190 &fw0_25,
9191 NULL
9192 }
9193 };
9194
9195 static IPv4RouteTest test12 = {
9196 "test12",
9197 {
9198 &en0_10,
9199 &en1_20,
9200 NULL
9201 }
9202 };
9203
9204 static IPv4RouteTest test13 = {
9205 "test13",
9206 {
9207 &en0_10,
9208 &en1_20_never,
9209 NULL
9210 }
9211 };
9212
9213 static IPv4RouteTest test14 = {
9214 "test14",
9215 {
9216 &en1_20_never,
9217 NULL
9218 }
9219 };
9220
9221 static IPv4RouteTest test15 = {
9222 "test15",
9223 {
9224 &en0_linklocal,
9225 NULL
9226 }
9227 };
9228
9229 static IPv4RouteTest test16 = {
9230 "test16",
9231 {
9232 &en0_10,
9233 &utun0,
9234 NULL
9235 }
9236 };
9237
9238 static IPv4RouteTest test17 = {
9239 "test17",
9240 {
9241 &en0_10,
9242 &en1_20_other_never,
9243 NULL
9244 }
9245 };
9246
9247 static IPv4RouteTest test18 = {
9248 "test18",
9249 {
9250 &en0_route_loop,
9251 NULL
9252 }
9253 };
9254
9255 static IPv4RouteTestRef ipv4_tests[] = {
9256 &test1,
9257 &test2,
9258 &test3,
9259 &test4,
9260 &test5,
9261 &test6,
9262 &test7,
9263 &test8,
9264 &test9,
9265 &test10,
9266 &test11,
9267 &test12,
9268 &test13,
9269 &test14,
9270 &test15,
9271 &test16,
9272 &test17,
9273 &test18,
9274 NULL
9275 };
9276
9277 static boolean_t
9278 ipv4_prefix_length_is_valid(int prefix_length)
9279 {
9280 if (prefix_length < 0 || prefix_length > IPV4_ROUTE_ALL_BITS_SET) {
9281 return (FALSE);
9282 }
9283 return (TRUE);
9284 }
9285
9286 static void
9287 dict_add_string(CFMutableDictionaryRef dict, CFStringRef prop_name,
9288 const char * str)
9289 {
9290 CFStringRef prop_val;
9291
9292 if (str == NULL) {
9293 return;
9294 }
9295 prop_val = CFStringCreateWithCString(NULL,
9296 str,
9297 kCFStringEncodingASCII);
9298 CFDictionarySetValue(dict, prop_name, prop_val);
9299 CFRelease(prop_val);
9300 return;
9301 }
9302
9303 static void
9304 dict_add_string_as_array(CFMutableDictionaryRef dict, CFStringRef prop_name,
9305 const char * str)
9306 {
9307 CFArrayRef array;
9308 CFStringRef prop_val;
9309
9310 if (str == NULL) {
9311 return;
9312 }
9313 prop_val = CFStringCreateWithCString(NULL,
9314 str,
9315 kCFStringEncodingASCII);
9316 array = CFArrayCreate(NULL,
9317 (const void **)&prop_val, 1,
9318 &kCFTypeArrayCallBacks);
9319 CFRelease(prop_val);
9320 CFDictionarySetValue(dict, prop_name, array);
9321 CFRelease(array);
9322 return;
9323 }
9324
9325 static void
9326 dict_add_ip(CFMutableDictionaryRef dict, CFStringRef prop_name,
9327 struct in_addr ip)
9328 {
9329 CFStringRef str;
9330
9331 str = my_CFStringCreateWithInAddr(ip);
9332 CFDictionarySetValue(dict, prop_name, str);
9333 CFRelease(str);
9334 return;
9335 }
9336
9337 static void
9338 dict_add_ip_as_array(CFMutableDictionaryRef dict, CFStringRef prop_name,
9339 struct in_addr ip)
9340 {
9341 CFArrayRef array;
9342 CFStringRef str;
9343
9344 str = my_CFStringCreateWithInAddr(ip);
9345 array = CFArrayCreate(NULL,
9346 (const void **)&str, 1,
9347 &kCFTypeArrayCallBacks);
9348 CFRelease(str);
9349 CFDictionarySetValue(dict, prop_name, array);
9350 CFRelease(array);
9351 return;
9352 }
9353
9354 static void
9355 dict_insert_routes(CFMutableDictionaryRef dict, CFStringRef prop_name,
9356 struct route * routes, int routes_count)
9357 {
9358 int i;
9359 CFMutableArrayRef route_list;
9360 struct route * scan;
9361
9362 if (routes == NULL || routes_count == 0) {
9363 return;
9364 }
9365 route_list = CFArrayCreateMutable(NULL, routes_count,
9366 &kCFTypeArrayCallBacks);
9367 for (i = 0, scan = routes; i < routes_count; i++, scan++) {
9368 struct in_addr mask;
9369 CFMutableDictionaryRef route_dict;
9370
9371 route_dict
9372 = CFDictionaryCreateMutable(NULL, 0,
9373 &kCFTypeDictionaryKeyCallBacks,
9374 &kCFTypeDictionaryValueCallBacks);
9375 dict_add_string(route_dict, kSCPropNetIPv4RouteDestinationAddress,
9376 scan->dest);
9377 if (ipv4_prefix_length_is_valid(scan->prefix_length)) {
9378 mask.s_addr = htonl(prefix_to_mask32(scan->prefix_length));
9379 dict_add_ip(route_dict, kSCPropNetIPv4RouteSubnetMask, mask);
9380 }
9381 dict_add_string(route_dict, kSCPropNetIPv4RouteGatewayAddress,
9382 scan->gateway);
9383 dict_add_string(route_dict, kSCPropNetIPv4RouteInterfaceName,
9384 scan->ifname);
9385 CFArrayAppendValue(route_list, route_dict);
9386 CFRelease(route_dict);
9387 }
9388 CFDictionarySetValue(dict, prop_name, route_list);
9389 CFRelease(route_list);
9390 return;
9391 }
9392
9393 static CFDictionaryRef
9394 make_IPv4_dict(IPv4ServiceContentsRef t)
9395 {
9396 CFMutableDictionaryRef dict;
9397
9398 dict = CFDictionaryCreateMutable(NULL, 0,
9399 &kCFTypeDictionaryKeyCallBacks,
9400 &kCFTypeDictionaryValueCallBacks);
9401 dict_add_string_as_array(dict, kSCPropNetIPv4Addresses, t->addr);
9402 if (ipv4_prefix_length_is_valid(t->prefix_length)) {
9403 struct in_addr mask;
9404
9405 mask.s_addr = htonl(prefix_to_mask32(t->prefix_length));
9406 dict_add_ip_as_array(dict, kSCPropNetIPv4SubnetMasks, mask);
9407 }
9408 dict_add_string_as_array(dict, kSCPropNetIPv4DestAddresses, t->dest);
9409 dict_add_string(dict, kSCPropNetIPv4Router, t->router);
9410 dict_add_string(dict, kSCPropInterfaceName, t->ifname);
9411 dict_add_string(dict, kSCPropConfirmedInterfaceName, t->ifname);
9412 dict_insert_routes(dict, kSCPropNetIPv4AdditionalRoutes,
9413 t->additional_routes, t->additional_routes_count);
9414 dict_insert_routes(dict, kSCPropNetIPv4ExcludedRoutes,
9415 t->excluded_routes, t->excluded_routes_count);
9416 return (dict);
9417 }
9418
9419 typedef enum {
9420 kDirectionForwards = 0,
9421 kDirectionBackwards = 1
9422 } Direction;
9423
9424 typedef enum {
9425 kLogRouteDisabled = 0,
9426 kLogRouteEnabled = 1
9427 } LogRoute;
9428
9429 static IPv4RouteListRef
9430 make_IPv4RouteList_for_test(IPv4RouteListRef list,
9431 IPv4ServiceContentsRef test,
9432 LogRoute log_it)
9433 {
9434 CFDictionaryRef dict;
9435 IPv4RouteListRef r;
9436 Rank rank;
9437 Rank rank_assertion = kRankAssertionDefault;
9438 CFNumberRef rank_assertion_cf = NULL;
9439 Boolean rank_assertion_is_set = FALSE;
9440 IPv4RouteListRef ret = NULL;
9441 IPV4_ROUTES_BUF_DECL(routes);
9442
9443 dict = make_IPv4_dict(test);
9444 if (dict == NULL) {
9445 fprintf(stderr, "make_IPv4_dict failed\n");
9446 exit(1);
9447 }
9448 if (test->primary_rank != NULL) {
9449 rank_assertion
9450 = PrimaryRankGetRankAssertion(*test->primary_rank,
9451 &rank_assertion_is_set);
9452 if (rank_assertion_is_set) {
9453 rank_assertion_cf
9454 = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank_assertion);
9455 }
9456 }
9457 r = IPv4RouteListCreateWithDictionary(routes, dict,
9458 rank_assertion_cf);
9459 my_CFRelease(&rank_assertion_cf);
9460 if (r == NULL) {
9461 fprintf(stderr, "IPv4RouteListCreateWithDictionary failed\n");
9462 exit(1);
9463 }
9464
9465 if (rank_assertion == kRankAssertionScoped) {
9466 rank_assertion = kRankAssertionNever;
9467 }
9468 rank = RankMake(test->rank, rank_assertion);
9469 if (log_it == kLogRouteEnabled
9470 && (S_IPMonitor_debug & kDebugFlag4) != 0) {
9471 CFStringRef descr;
9472
9473 descr = IPv4RouteListCopyDescription(r);
9474 SCPrint(TRUE, stdout, CFSTR("Adding %@"), descr);
9475 CFRelease(descr);
9476 }
9477 ret = IPv4RouteListAddRouteList(list, 1, r, rank);
9478 if (r != routes) {
9479 free(r);
9480 }
9481 CFRelease(dict);
9482 return (ret);
9483 }
9484
9485 static IPv4RouteListRef
9486 make_IPv4RouteList(IPv4ServiceContentsRef * test, Direction direction,
9487 LogRoute log_it)
9488 {
9489 IPv4RouteListRef ret = NULL;
9490 IPv4ServiceContentsRef * scan;
9491
9492 switch (direction) {
9493 case kDirectionBackwards:
9494 for (scan = test; *scan != NULL; scan++) {
9495 /* find the end of the list */
9496 }
9497 for (scan--; scan >= test; scan--) {
9498 ret = make_IPv4RouteList_for_test(ret, *scan, log_it);
9499 }
9500 break;
9501 default:
9502 case kDirectionForwards:
9503 for (scan = test; *scan != NULL; scan++) {
9504 ret = make_IPv4RouteList_for_test(ret, *scan, log_it);
9505 }
9506 break;
9507 }
9508 IPv4RouteListFinalize(ret);
9509 return (ret);
9510 }
9511
9512 #define EMPHASIS_CHARS "================="
9513
9514 /*
9515 * Function: routelist_build_test
9516 * Purpose:
9517 * Runs through the given set of routes first in the forward direction,
9518 * then again backwards. We should end up with exactly the same set of
9519 * routes at the end.
9520 */
9521 static boolean_t
9522 routelist_build_test(IPv4RouteTestRef test)
9523 {
9524 CFStringRef descr;
9525 boolean_t ret = FALSE;
9526 IPv4RouteListRef routes1;
9527 IPv4RouteListRef routes2;
9528
9529 printf("\n" EMPHASIS_CHARS "> RouteList Build '%s' <"
9530 EMPHASIS_CHARS "\n",
9531 test->name);
9532
9533 routes1 = make_IPv4RouteList(test->test, kDirectionForwards,
9534 kLogRouteEnabled);
9535 if ((S_IPMonitor_debug & kDebugFlag4) != 0) {
9536 if (routes1 != NULL) {
9537 descr = IPv4RouteListCopyDescription(routes1);
9538 SCPrint(TRUE, stdout, CFSTR("Routes are %@\n"), descr);
9539 CFRelease(descr);
9540 }
9541 }
9542 routes2 = make_IPv4RouteList(test->test, kDirectionBackwards,
9543 kLogRouteEnabled);
9544 if ((S_IPMonitor_debug & kDebugFlag4) != 0) {
9545 if (routes2 != NULL) {
9546 descr = IPv4RouteListCopyDescription(routes2);
9547 SCPrint(TRUE, stdout, CFSTR("Routes are %@\n"), descr);
9548 CFRelease(descr);
9549 }
9550 }
9551 if ((routes1 != NULL && routes2 == NULL)
9552 || (routes1 == NULL && routes2 != NULL)) {
9553 fprintf(stderr, "routes1 is %sNULL but routes2 is %sNULL\n",
9554 (routes1 != NULL) ? "not " : "",
9555 (routes2 != NULL) ? "not " : "");
9556 }
9557 else if (routes1 != NULL && routes2 != NULL) {
9558 /* check if they are different */
9559 if (routes1->count != routes2->count) {
9560 fprintf(stderr, "routes1 count %d != routes 2 count %d\n",
9561 routes1->count, routes2->count);
9562 }
9563 else if (bcmp(routes1, routes2,
9564 IPv4RouteListComputeSize(routes1->count)) != 0) {
9565 fprintf(stderr, "routes1 and routes2 are different\n");
9566 }
9567 else {
9568 printf("routes1 and routes2 are the same\n");
9569 ret = TRUE;
9570 }
9571 }
9572 if (routes1 != NULL) {
9573 free(routes1);
9574 }
9575 if (routes2 != NULL) {
9576 free(routes2);
9577 }
9578 printf(EMPHASIS_CHARS "> RouteList Build '%s': %s <"
9579 EMPHASIS_CHARS "\n",
9580 test->name, ret ? "PASSED" : "FAILED");
9581 return (ret);
9582 }
9583
9584 static void
9585 apply_test(IPv4RouteTestRef old_test, IPv4RouteTestRef new_test)
9586 {
9587 IPv4RouteListRef new_routes;
9588 IPv4RouteListRef old_routes;
9589
9590 printf("\n" EMPHASIS_CHARS "> Apply '%s', '%s' Begin <"
9591 EMPHASIS_CHARS "\n",
9592 old_test->name, new_test->name);
9593
9594 old_routes = make_IPv4RouteList(old_test->test, kDirectionForwards,
9595 kLogRouteDisabled);
9596 new_routes = make_IPv4RouteList(new_test->test, kDirectionForwards,
9597 kLogRouteDisabled);
9598 if (old_routes == NULL) {
9599 printf("No Old Routes\n");
9600 }
9601 else {
9602 printf("Old routes ('%s') = ", old_test->name);
9603 IPv4RouteListPrint(old_routes);
9604 }
9605
9606 /* apply the old routes */
9607 IPv4RouteListApply(NULL, old_routes, -1);
9608
9609 if (new_routes == NULL) {
9610 printf("No New Routes\n");
9611 }
9612 else {
9613 printf("New Routes ('%s') = ", new_test->name);
9614 IPv4RouteListPrint(new_routes);
9615 }
9616
9617 /* apply the new routes */
9618 IPv4RouteListApply(old_routes, new_routes, -1);
9619
9620 if (old_routes != NULL) {
9621 free(old_routes);
9622 }
9623 if (new_routes != NULL) {
9624 free(new_routes);
9625 }
9626 printf(EMPHASIS_CHARS "> Apply '%s', '%s' End <"
9627 EMPHASIS_CHARS "\n",
9628 old_test->name, new_test->name);
9629 return;
9630 }
9631
9632 int
9633 main(int argc, char **argv)
9634 {
9635 IPv4RouteTestRef * test;
9636
9637 _sc_log = FALSE;
9638 _sc_verbose = (argc > 1) ? TRUE : FALSE;
9639 S_IPMonitor_debug = kDebugFlag1 | kDebugFlag2 | kDebugFlag4;
9640 if (argc > 1) {
9641 S_IPMonitor_debug = strtoul(argv[1], NULL, 0);
9642 }
9643 for (test = ipv4_tests; *test != NULL; test++) {
9644 if (!routelist_build_test(*test)) {
9645 fprintf(stderr, "%s failed\n", (*test)->name);
9646 exit(1);
9647 }
9648 }
9649 for (test = ipv4_tests; *test != NULL; test++) {
9650 IPv4RouteTestRef * test2;
9651
9652 for (test2 = test + 1; *test2 != NULL; test2++) {
9653 apply_test(*test, *test2);
9654 apply_test(*test2, *test);
9655 }
9656 }
9657
9658 {
9659 char cmd[128];
9660
9661 printf("\nChecking for leaks\n");
9662 sprintf(cmd, "leaks %d 2>&1", getpid());
9663 fflush(stdout);
9664 (void)system(cmd);
9665 }
9666 exit(0);
9667 return (0);
9668 }
9669
9670 #endif /* TEST_IPV4_ROUTELIST */
9671
9672 #ifdef TEST_IPV6_ROUTELIST
9673
9674 typedef struct {
9675 const char * addr;
9676 int prefix_length;
9677 const char * dest;
9678 } IPv6Address;
9679
9680 typedef const IPv6Address * IPv6AddressRef;
9681
9682 typedef struct {
9683 IPv6AddressRef addr;
9684 int addr_count;
9685 const char * router;
9686 const char * ifname;
9687 Rank rank;
9688 const CFStringRef * primary_rank;
9689 struct route * additional_routes;
9690 int additional_routes_count;
9691 struct route * excluded_routes;
9692 int excluded_routes_count;
9693 } IPv6ServiceContents;
9694
9695 typedef const IPv6ServiceContents * IPv6ServiceContentsRef;
9696
9697 struct route loop_routelist[] = {
9698 { "2620:149:4:f01:225:ff:fecc:89a1", 128,
9699 "2620:149:4:f01:225:ff:fecc:89a2", NULL },
9700 { "2620:149:4:f01:225:ff:fecc:89a2", 128,
9701 "2620:149:4:f01:225:ff:fecc:89a3", NULL },
9702 { "2620:149:4:f01:225:ff:fecc:89a3", 128,
9703 "2620:149:4:f01:225:ff:fecc:89a4", NULL },
9704 { "2620:149:4:f01:225:ff:fecc:89a4", 128,
9705 "2620:149:4:f01:225:ff:fecc:89a5", NULL },
9706 { "2620:149:4:f01:225:ff:fecc:89a5", 128,
9707 "2620:149:4:f01:225:ff:fecc:89a6", NULL },
9708 { "2620:149:4:f01:225:ff:fecc:89a6", 128,
9709 "2620:149:4:f01:225:ff:fecc:89a7", NULL },
9710 { "2620:149:4:f01:225:ff:fecc:89a7", 128,
9711 "2620:149:4:f01:225:ff:fecc:89a8", NULL },
9712 { "2620:149:4:f01:225:ff:fecc:89a8", 128,
9713 "2620:149:4:f01:225:ff:fecc:89a9", NULL },
9714 { "2620:149:4:f01:225:ff:fecc:89a9", 128,
9715 "2620:149:4:f01:225:ff:fecc:89aa", NULL },
9716 { "2620:149:4:f01:225:ff:fecc:89aa", 128,
9717 "2620:149:4:f01:225:ff:fecc:89ab", NULL },
9718 { "2620:149:4:f01:225:ff:fecc:89ab", 128,
9719 "2620:149:4:f01:225:ff:fecc:89a1", NULL },
9720 };
9721
9722 struct route vpn_routelist[] = {
9723 { "2010:470:1f05:3cb::", 64,
9724 "fe80::2d0:bcff:fe3d:8c00", NULL },
9725 { "2010:222:3fa5:acb::", 48,
9726 "fe80::2d0:bcff:fe3d:8c00", NULL },
9727 { "2010:222:3fa5:1234::", 40,
9728 "fe80::2d0:bcff:fe3d:8c00", NULL },
9729 { "2010:222:3fa5:5678::", 40,
9730 NULL, NULL },
9731 };
9732
9733 struct route vpn_routelist_ext[] = {
9734 { "2020:299:a:e02:825:1ed:fecc:abab", 128, NULL, NULL },
9735 };
9736
9737 struct route en1_routelist_ext[] = {
9738 { "2020:299:abcd:ef12::", 64, NULL, NULL },
9739 };
9740
9741
9742 static const IPv6Address en0_addr1[] = {
9743 { "2001:470:1f05:3cb:cabc:c8ff:fe96:9601", 64, NULL },
9744 { "2001:470:1f05:3cb:5c95:58b1:b956:6101", 64, NULL }
9745 };
9746
9747 static const IPv6Address en0_addr2[] = {
9748 { "2001:470:1f05:3cb:cabc:c8ff:fe96:9602", 64, NULL },
9749 { "2001:470:1f05:3cb:5c95:58b1:b956:6102", 64, NULL }
9750 };
9751
9752 static const IPv6Address en0_addr3[] = {
9753 { "2001:470:1f05:3cb:cabc:c8ff:fe96:9603", 64, NULL },
9754 { "2001:470:1f05:3cb:5c95:58b1:b956:6103", 64, NULL }
9755 };
9756
9757 static const IPv6Address en0_addr4[] = {
9758 { "2001:470:1f05:3cb:cabc:c8ff:fe96:9604", 64, NULL },
9759 { "2001:470:1f05:3cb:5c95:58b1:b956:6104", 64, NULL }
9760 };
9761
9762 static const IPv6Address en0_addr5[] = {
9763 { "2001:470:1f05:3cb:cabc:c8ff:fe96:9605", 64, NULL },
9764 { "2001:470:1f05:3cb:5c95:58b1:b956:6105", 64, NULL }
9765 };
9766
9767 static const IPv6Address en0_addr6[] = {
9768 { "2020:299:abcd:ef12:1:2:3:4", 64, NULL },
9769 };
9770
9771 static const IPv6Address en0_lladdr[] = {
9772 { "fe80::cabc:c8ff:fe96:96af", 64, NULL }
9773 };
9774
9775 static const IPv6Address en1_addr[] = {
9776 { "2001:470:1f05:3cb:cabc:c8ff:fed9:125a", 64, NULL },
9777 { "2001:470:1f05:3cb:2d5e:4ec3:304:5b9c", 64, NULL }
9778 };
9779
9780 static const IPv6Address utun0_addr[] = {
9781 { "2620:149:4:f01:225:ff:fecc:89aa", 64, NULL },
9782 };
9783
9784 static const IPv6Address fw0_addr1[] = {
9785 { "2011:470:1f05:3cb:cabc:c8ff:fe96:ab01", 64, NULL },
9786 { "2011:470:1f05:3cb:5c95:58b1:b956:ab01", 64, NULL }
9787 };
9788
9789 /*
9790 * address+address-count
9791 * router ifname pri rank additional-routes+count excluded-routes+count
9792 */
9793
9794 static const IPv6ServiceContents en0_10 = {
9795 en0_addr1, countof(en0_addr1),
9796 "fe80::21f:f3ff:fe43:1abf", "en0", 10, NULL, NULL, 0, NULL, 0
9797 };
9798
9799 static const IPv6ServiceContents en0_15 = {
9800 en0_addr2, countof(en0_addr2),
9801 "fe80::21f:f3ff:fe43:1abf", "en0", 15, NULL, NULL, 0, NULL, 0
9802 };
9803
9804 static const IPv6ServiceContents en0_30 = {
9805 en0_addr3, countof(en0_addr3),
9806 "fe80::21f:f3ff:fe43:1abf", "en0", 30, NULL, NULL, 0, NULL, 0
9807 };
9808
9809 static const IPv6ServiceContents en0_40 = {
9810 en0_addr4, countof(en0_addr4),
9811 "fe80::21f:f3ff:fe43:1abf", "en0", 40, NULL, NULL, 0, NULL, 0
9812 };
9813
9814 static const IPv6ServiceContents en0_50 = {
9815 en0_addr5, countof(en0_addr5),
9816 "fe80::21f:f3ff:fe43:1abf", "en0", 50, NULL, NULL, 0, NULL, 0
9817 };
9818
9819 static const IPv6ServiceContents en0_10_a = {
9820 en0_addr6, countof(en0_addr6),
9821 "fe80::21f:f3ff:fe43:1abf", "en0", 10, NULL, NULL, 0, NULL, 0
9822 };
9823
9824 static const IPv6ServiceContents fw0_25 = {
9825 fw0_addr1, countof(fw0_addr1),
9826 "fe80::21f:f3ff:fe43:1abf", "fw0", 25, NULL, NULL, 0, NULL, 0
9827 };
9828
9829 static const IPv6ServiceContents en1_20 = {
9830 en1_addr, countof(en1_addr),
9831 "fe80::21f:f3ff:fe43:1abf", "en1", 20, NULL, NULL, 0, NULL, 0
9832 };
9833
9834 static const IPv6ServiceContents en1_10_ext = {
9835 en1_addr, countof(en1_addr),
9836 "fe80::21f:f3ff:fe43:1abf", "en1", 10, NULL, NULL, 0,
9837 en1_routelist_ext, countof(en1_routelist_ext)
9838 };
9839
9840 static const IPv6ServiceContents en0_0_lladdr = {
9841 en0_lladdr, countof(en0_lladdr),
9842 "fe80::21f:f3ff:fe43:1abf", "en0", 20, NULL, NULL, 0, NULL, 0
9843 };
9844
9845 static const IPv6ServiceContents en0_loop = {
9846 en0_addr1, countof(en0_addr1),
9847 "fe80::21f:f3ff:fe43:1abf", "en0", 10, NULL,
9848 loop_routelist, countof(loop_routelist), NULL, 0
9849 };
9850
9851 static const IPv6ServiceContents utun0 = {
9852 utun0_addr, countof(utun0_addr),
9853 "fe80::2d0:bcff:fe3d:8c00", "utun0", 40, NULL,
9854 vpn_routelist, countof(vpn_routelist),
9855 vpn_routelist_ext, countof(vpn_routelist_ext),
9856 };
9857
9858 typedef struct {
9859 const char * name;
9860 IPv6ServiceContentsRef test[];
9861 } IPv6RouteTest, * IPv6RouteTestRef;
9862
9863 static IPv6RouteTest test1 = {
9864 "test1",
9865 {
9866 &en0_40,
9867 &en0_15,
9868 &fw0_25,
9869 &en0_30,
9870 &en1_20,
9871 &en0_50,
9872 &en0_10,
9873 NULL
9874 }
9875 };
9876
9877 static IPv6RouteTest test2 = {
9878 "test2",
9879 {
9880 &en0_40,
9881 &fw0_25,
9882 &en0_30,
9883 &en1_20,
9884 &en0_50,
9885 &en0_10,
9886 NULL
9887 }
9888 };
9889
9890 static IPv6RouteTest test3 = {
9891 "test3",
9892 {
9893 &en0_10_a,
9894 &en1_10_ext,
9895 NULL
9896 }
9897 };
9898
9899 static IPv6RouteTest test4 = {
9900 "test4",
9901 {
9902 &en0_loop,
9903 &en1_20,
9904 NULL
9905 }
9906 };
9907
9908 static IPv6RouteTest test5 = {
9909 "test5",
9910 {
9911 &en0_10,
9912 &utun0,
9913 &en0_0_lladdr,
9914 &en1_20,
9915 NULL
9916 }
9917 };
9918
9919
9920 static IPv6RouteTestRef ipv6_tests[] = {
9921 &test1,
9922 &test2,
9923 &test3,
9924 &test4,
9925 &test5,
9926 NULL
9927 };
9928
9929
9930 static void
9931 dict_add_string(CFMutableDictionaryRef dict, CFStringRef prop_name,
9932 const char * str)
9933 {
9934 CFStringRef prop_val;
9935
9936 if (str == NULL) {
9937 return;
9938 }
9939 prop_val = CFStringCreateWithCString(NULL,
9940 str,
9941 kCFStringEncodingASCII);
9942 CFDictionarySetValue(dict, prop_name, prop_val);
9943 CFRelease(prop_val);
9944 return;
9945 }
9946
9947 static void
9948 dict_add_int(CFMutableDictionaryRef dict, CFStringRef prop_name,
9949 int int_val)
9950 {
9951 CFNumberRef num;
9952
9953 num = CFNumberCreate(NULL, kCFNumberIntType, &int_val);
9954 CFDictionarySetValue(dict, prop_name, num);
9955 CFRelease(num);
9956 return;
9957 }
9958
9959 static void
9960 dict_insert_v6_routes(CFMutableDictionaryRef dict, CFStringRef prop_name,
9961 struct route * routes, int routes_count)
9962 {
9963 int i;
9964 CFMutableArrayRef route_list;
9965 struct route * scan;
9966
9967 if (routes == NULL || routes_count == 0) {
9968 return;
9969 }
9970 route_list = CFArrayCreateMutable(NULL, routes_count,
9971 &kCFTypeArrayCallBacks);
9972 for (i = 0, scan = routes; i < routes_count; i++, scan++) {
9973 CFMutableDictionaryRef route_dict;
9974
9975 route_dict = CFDictionaryCreateMutable(NULL, 0,
9976 &kCFTypeDictionaryKeyCallBacks,
9977 &kCFTypeDictionaryValueCallBacks);
9978 dict_add_string(route_dict, kSCPropNetIPv6RouteDestinationAddress,
9979 scan->dest);
9980 dict_add_int(route_dict, kSCPropNetIPv6PrefixLength,
9981 scan->prefix_length);
9982 dict_add_string(route_dict, kSCPropNetIPv6RouteGatewayAddress,
9983 scan->gateway);
9984 dict_add_string(route_dict, kSCPropNetIPv6RouteInterfaceName,
9985 scan->ifname);
9986 CFArrayAppendValue(route_list, route_dict);
9987 CFRelease(route_dict);
9988 }
9989 CFDictionarySetValue(dict, prop_name, route_list);
9990 CFRelease(route_list);
9991 return;
9992 }
9993
9994 static void
9995 array_add_string(CFMutableArrayRef array, const char * c_str)
9996 {
9997 CFStringRef str;
9998
9999 str = CFStringCreateWithCString(NULL,
10000 c_str,
10001 kCFStringEncodingUTF8);
10002 CFArrayAppendValue(array, str);
10003 CFRelease(str);
10004 return;
10005 }
10006
10007 static void
10008 array_add_int(CFMutableArrayRef array, int int_val)
10009 {
10010 CFNumberRef num;
10011
10012 num = CFNumberCreate(NULL, kCFNumberIntType, &int_val);
10013 CFArrayAppendValue(array, num);
10014 CFRelease(num);
10015 return;
10016 }
10017
10018 static void
10019 dict_add_ipv6_addressing(CFMutableDictionaryRef dict,
10020 IPv6AddressRef list, int list_count)
10021 {
10022 CFMutableArrayRef addr = NULL;
10023 CFMutableArrayRef dest = NULL;
10024 int i;
10025 CFMutableArrayRef prefix = NULL;
10026 IPv6AddressRef scan;
10027
10028 if (list == NULL || list_count == 0) {
10029 return;
10030 }
10031 for (i = 0, scan = list; i < list_count; i++, scan++) {
10032 if (scan->addr != NULL) {
10033 if (addr == NULL) {
10034 addr = CFArrayCreateMutable(NULL, list_count,
10035 &kCFTypeArrayCallBacks);
10036 }
10037 array_add_string(addr, scan->addr);
10038 }
10039 if (scan->prefix_length >= 0) {
10040 if (prefix == NULL) {
10041 prefix = CFArrayCreateMutable(NULL, list_count,
10042 &kCFTypeArrayCallBacks);
10043 }
10044 array_add_int(prefix, scan->prefix_length);
10045 }
10046 if (scan->dest != NULL) {
10047 if (dest == NULL) {
10048 dest = CFArrayCreateMutable(NULL, list_count,
10049 &kCFTypeArrayCallBacks);
10050 }
10051 array_add_string(dest, scan->dest);
10052 }
10053 }
10054 if (addr != NULL) {
10055 CFDictionarySetValue(dict, kSCPropNetIPv6Addresses, addr);
10056 CFRelease(addr);
10057 }
10058 if (dest != NULL) {
10059 CFDictionarySetValue(dict, kSCPropNetIPv6DestAddresses, dest);
10060 CFRelease(dest);
10061 }
10062 if (prefix != NULL) {
10063 CFDictionarySetValue(dict, kSCPropNetIPv6PrefixLength, prefix);
10064 CFRelease(prefix);
10065 }
10066 return;
10067 }
10068
10069 static CFDictionaryRef
10070 make_IPv6_dict(IPv6ServiceContentsRef t)
10071 {
10072 CFMutableDictionaryRef dict;
10073
10074 dict = CFDictionaryCreateMutable(NULL, 0,
10075 &kCFTypeDictionaryKeyCallBacks,
10076 &kCFTypeDictionaryValueCallBacks);
10077 dict_add_ipv6_addressing(dict, t->addr, t->addr_count);
10078 dict_add_string(dict, kSCPropNetIPv6Router, t->router);
10079 dict_add_string(dict, kSCPropInterfaceName, t->ifname);
10080 dict_insert_v6_routes(dict, kSCPropNetIPv6AdditionalRoutes,
10081 t->additional_routes, t->additional_routes_count);
10082 dict_insert_v6_routes(dict, kSCPropNetIPv6ExcludedRoutes,
10083 t->excluded_routes, t->excluded_routes_count);
10084 return (dict);
10085 }
10086
10087 typedef enum {
10088 kDirectionForwards = 0,
10089 kDirectionBackwards = 1
10090 } Direction;
10091
10092 typedef enum {
10093 kLogRouteDisabled = 0,
10094 kLogRouteEnabled = 1
10095 } LogRoute;
10096
10097 static IPv6RouteListRef
10098 make_IPv6RouteList_for_test(IPv6RouteListRef list,
10099 IPv6ServiceContentsRef test,
10100 LogRoute log_it)
10101 {
10102 CFDictionaryRef dict;
10103 IPv6RouteListRef r;
10104 Rank rank;
10105 Rank rank_assertion = kRankAssertionDefault;
10106 CFNumberRef rank_assertion_cf = NULL;
10107 Boolean rank_assertion_is_set = FALSE;
10108 IPv6RouteListRef ret = NULL;
10109 IPV6_ROUTES_BUF_DECL(routes);
10110
10111 dict = make_IPv6_dict(test);
10112 if (dict == NULL) {
10113 fprintf(stderr, "make_IPv6_dict failed\n");
10114 exit(1);
10115 }
10116 if (test->primary_rank != NULL) {
10117 rank_assertion
10118 = PrimaryRankGetRankAssertion(*test->primary_rank,
10119 &rank_assertion_is_set);
10120 if (rank_assertion_is_set) {
10121 rank_assertion_cf
10122 = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank_assertion);
10123 }
10124 }
10125 r = IPv6RouteListCreateWithDictionary(routes, dict,
10126 rank_assertion_cf);
10127 my_CFRelease(&rank_assertion_cf);
10128 if (r == NULL) {
10129 fprintf(stderr, "IPv6RouteListCreateWithDictionary failed\n");
10130 exit(1);
10131 }
10132
10133 if (rank_assertion == kRankAssertionScoped) {
10134 rank_assertion = kRankAssertionNever;
10135 }
10136 rank = RankMake(test->rank, rank_assertion);
10137 if (log_it == kLogRouteEnabled
10138 && (S_IPMonitor_debug & kDebugFlag4) != 0) {
10139 CFStringRef descr;
10140
10141 descr = IPv6RouteListCopyDescription(r);
10142 SCPrint(TRUE, stdout, CFSTR("Adding %@"), descr);
10143 CFRelease(descr);
10144 }
10145 ret = IPv6RouteListAddRouteList(list, 1, r, rank);
10146 if (r != routes) {
10147 free(r);
10148 }
10149 CFRelease(dict);
10150 return (ret);
10151 }
10152
10153 static IPv6RouteListRef
10154 make_IPv6RouteList(IPv6ServiceContentsRef * test, Direction direction,
10155 LogRoute log_it)
10156 {
10157 IPv6RouteListRef ret = NULL;
10158 IPv6ServiceContentsRef * scan;
10159
10160 switch (direction) {
10161 case kDirectionBackwards:
10162 for (scan = test; *scan != NULL; scan++) {
10163 /* find the end of the list */
10164 }
10165 for (scan--; scan >= test; scan--) {
10166 ret = make_IPv6RouteList_for_test(ret, *scan, log_it);
10167 }
10168 break;
10169 default:
10170 case kDirectionForwards:
10171 for (scan = test; *scan != NULL; scan++) {
10172 ret = make_IPv6RouteList_for_test(ret, *scan, log_it);
10173 }
10174 break;
10175 }
10176 IPv6RouteListFinalize(ret);
10177 return (ret);
10178 }
10179
10180 #define EMPHASIS_CHARS "================="
10181
10182 /*
10183 * Function: routelist_build_test
10184 * Purpose:
10185 * Runs through the given set of routes first in the forward direction,
10186 * then again backwards. We should end up with exactly the same set of
10187 * routes at the end.
10188 */
10189 static boolean_t
10190 routelist_build_test(IPv6RouteTestRef test)
10191 {
10192 CFStringRef descr;
10193 boolean_t ret = FALSE;
10194 IPv6RouteListRef routes1;
10195 IPv6RouteListRef routes2;
10196
10197 printf("\n" EMPHASIS_CHARS "> RouteList Build '%s' <"
10198 EMPHASIS_CHARS "\n",
10199 test->name);
10200
10201 routes1 = make_IPv6RouteList(test->test, kDirectionForwards,
10202 kLogRouteEnabled);
10203 if ((S_IPMonitor_debug & kDebugFlag4) != 0) {
10204 if (routes1 != NULL) {
10205 descr = IPv6RouteListCopyDescription(routes1);
10206 SCPrint(TRUE, stdout, CFSTR("Routes are %@\n"), descr);
10207 CFRelease(descr);
10208 }
10209 }
10210 routes2 = make_IPv6RouteList(test->test, kDirectionBackwards,
10211 kLogRouteEnabled);
10212 if ((S_IPMonitor_debug & kDebugFlag4) != 0) {
10213 if (routes2 != NULL) {
10214 descr = IPv6RouteListCopyDescription(routes2);
10215 SCPrint(TRUE, stdout, CFSTR("Routes are %@\n"), descr);
10216 CFRelease(descr);
10217 }
10218 }
10219 if ((routes1 != NULL && routes2 == NULL)
10220 || (routes1 == NULL && routes2 != NULL)) {
10221 fprintf(stderr, "routes1 is %sNULL but routes2 is %sNULL\n",
10222 (routes1 != NULL) ? "not " : "",
10223 (routes2 != NULL) ? "not " : "");
10224 }
10225 else if (routes1 != NULL && routes2 != NULL) {
10226 /* check if they are different */
10227 if (routes1->count != routes2->count) {
10228 fprintf(stderr, "routes1 count %d != routes 2 count %d\n",
10229 routes1->count, routes2->count);
10230 }
10231 else if (bcmp(routes1, routes2,
10232 IPv6RouteListComputeSize(routes1->count)) != 0) {
10233 fprintf(stderr, "routes1 and routes2 are different\n");
10234 }
10235 else {
10236 printf("routes1 and routes2 are the same\n");
10237 ret = TRUE;
10238 }
10239 }
10240 if (routes1 != NULL) {
10241 free(routes1);
10242 }
10243 if (routes2 != NULL) {
10244 free(routes2);
10245 }
10246 printf(EMPHASIS_CHARS "> RouteList Build '%s': %s <"
10247 EMPHASIS_CHARS "\n",
10248 test->name, ret ? "PASSED" : "FAILED");
10249 return (ret);
10250 }
10251
10252 static void
10253 apply_test(IPv6RouteTestRef old_test, IPv6RouteTestRef new_test)
10254 {
10255 IPv6RouteListRef new_routes;
10256 IPv6RouteListRef old_routes;
10257
10258 printf("\n" EMPHASIS_CHARS "> Apply '%s', '%s' Begin <"
10259 EMPHASIS_CHARS "\n",
10260 old_test->name, new_test->name);
10261
10262 old_routes = make_IPv6RouteList(old_test->test, kDirectionForwards,
10263 kLogRouteDisabled);
10264 new_routes = make_IPv6RouteList(new_test->test, kDirectionForwards,
10265 kLogRouteDisabled);
10266 if (old_routes == NULL) {
10267 printf("No Old Routes\n");
10268 }
10269 else {
10270 printf("Old routes ('%s') = ", old_test->name);
10271 IPv6RouteListPrint(old_routes);
10272 }
10273
10274 /* apply the old routes */
10275 IPv6RouteListApply(NULL, old_routes, -1);
10276 if (new_routes == NULL) {
10277 printf("No New Routes\n");
10278 }
10279 else {
10280 printf("New Routes ('%s') = ", new_test->name);
10281 IPv6RouteListPrint(new_routes);
10282 }
10283
10284 /* apply the new routes */
10285 IPv6RouteListApply(old_routes, new_routes, -1);
10286 if (old_routes != NULL) {
10287 free(old_routes);
10288 }
10289 if (new_routes != NULL) {
10290 free(new_routes);
10291 }
10292 printf(EMPHASIS_CHARS "> Apply '%s', '%s' End <"
10293 EMPHASIS_CHARS "\n",
10294 old_test->name, new_test->name);
10295 return;
10296 }
10297
10298 int
10299 main(int argc, char **argv)
10300 {
10301 IPv6RouteTestRef * test;
10302
10303 _sc_log = FALSE;
10304 _sc_verbose = (argc > 1) ? TRUE : FALSE;
10305 S_IPMonitor_debug = kDebugFlag1 | kDebugFlag2 | kDebugFlag4;
10306 if (argc > 1) {
10307 S_IPMonitor_debug = strtoul(argv[1], NULL, 0);
10308 }
10309 for (test = ipv6_tests; *test != NULL; test++) {
10310 if (!routelist_build_test(*test)) {
10311 fprintf(stderr, "%s failed\n", (*test)->name);
10312 exit(1);
10313 }
10314 }
10315 for (test = ipv6_tests; *test != NULL; test++) {
10316 IPv6RouteTestRef * test2;
10317
10318 for (test2 = test + 1; *test2 != NULL; test2++) {
10319 apply_test(*test, *test2);
10320 apply_test(*test2, *test);
10321 }
10322 }
10323
10324 {
10325 char cmd[128];
10326
10327 printf("\nChecking for leaks\n");
10328 sprintf(cmd, "leaks %d 2>&1", getpid());
10329 fflush(stdout);
10330 (void)system(cmd);
10331 }
10332 exit(0);
10333 return (0);
10334 }
10335
10336 #endif /* TEST_IPV6_ROUTELIST */
10337
10338 #ifdef TEST_DNS_ORDER
10339
10340 #define kProtocolFlagsIPv4v6 (kProtocolFlagsIPv4 | kProtocolFlagsIPv6)
10341
10342 #define V4_ADDR_LOOP CFSTR("127.0.0.1")
10343 #define V4_ADDR_1 CFSTR("192.168.1.1")
10344 #define V4_ADDR_2 CFSTR("192.168.1.2")
10345 #define V4_ADDR_3 CFSTR("8.8.8.8")
10346 #define V4_ADDR_4 CFSTR("8.8.4.4")
10347
10348 #define V6_ADDR_LOOP CFSTR("::1")
10349 #define V6_ADDR_1 CFSTR("fe80::0123:4567:89ab:cdef%en0")
10350 #define V6_ADDR_2 CFSTR("fd00::2acf:e9ff:fe14:8c59")
10351 #define V6_ADDR_3 CFSTR("2001:4860:4860::8888")
10352
10353 typedef struct {
10354 const char * name;
10355 const ProtocolFlags flags;
10356 const CFStringRef server_addrs[];
10357 } DNSOrderTest, * DNSOrderTestRef;
10358
10359 static DNSOrderTest test0a = {
10360 "test0a",
10361 kProtocolFlagsIPv4,
10362 {
10363 V4_ADDR_1, V4_ADDR_2, V4_ADDR_3, V4_ADDR_4, NULL
10364 }
10365 };
10366
10367 static DNSOrderTest test0b = {
10368 "test0b",
10369 kProtocolFlagsIPv6,
10370 {
10371 V6_ADDR_1, V6_ADDR_2, V6_ADDR_3, NULL
10372 }
10373 };
10374
10375 static DNSOrderTest test1a = {
10376 "test1a",
10377 kProtocolFlagsIPv4v6,
10378 {
10379 V4_ADDR_1, V6_ADDR_1, NULL
10380 }
10381 };
10382
10383 static DNSOrderTest test2a = {
10384 "test2a",
10385 kProtocolFlagsIPv4v6,
10386 {
10387 V4_ADDR_1, V6_ADDR_2, NULL
10388 }
10389 };
10390
10391 static DNSOrderTest test3a = {
10392 "test3a",
10393 kProtocolFlagsIPv4v6,
10394 {
10395 V4_ADDR_1, V6_ADDR_3, NULL
10396 }
10397 };
10398
10399 static DNSOrderTest test1b = {
10400 "test1b",
10401 kProtocolFlagsIPv4v6,
10402 {
10403 V4_ADDR_3, V6_ADDR_1, NULL
10404 }
10405 };
10406
10407 static DNSOrderTest test2b = {
10408 "test2b",
10409 kProtocolFlagsIPv4v6,
10410 {
10411 V4_ADDR_3, V6_ADDR_2, NULL
10412 }
10413 };
10414
10415 static DNSOrderTest test3b = {
10416 "test3b",
10417 kProtocolFlagsIPv4v6,
10418 {
10419 V4_ADDR_3, V6_ADDR_3, NULL
10420 }
10421 };
10422
10423 static DNSOrderTest test1c = {
10424 "test1c",
10425 kProtocolFlagsIPv4v6,
10426 {
10427 V6_ADDR_1, V4_ADDR_1, NULL
10428 }
10429 };
10430
10431 static DNSOrderTest test2c = {
10432 "test2c",
10433 kProtocolFlagsIPv4v6,
10434 {
10435 V6_ADDR_2, V4_ADDR_1, NULL
10436 }
10437 };
10438
10439 static DNSOrderTest test3c = {
10440 "test3c",
10441 kProtocolFlagsIPv4v6,
10442 {
10443 V6_ADDR_3, V4_ADDR_1, NULL
10444 }
10445 };
10446
10447 static DNSOrderTest test1d = {
10448 "test1d",
10449 kProtocolFlagsIPv4v6,
10450 {
10451 V6_ADDR_1, V4_ADDR_3, NULL
10452 }
10453 };
10454
10455 static DNSOrderTest test2d = {
10456 "test2d",
10457 kProtocolFlagsIPv4v6,
10458 {
10459 V6_ADDR_2, V4_ADDR_3, NULL
10460 }
10461 };
10462
10463 static DNSOrderTest test3d = {
10464 "test3d",
10465 kProtocolFlagsIPv4v6,
10466 {
10467 V6_ADDR_3, V4_ADDR_3, NULL
10468 }
10469 };
10470
10471 static DNSOrderTest test4 = {
10472 "test4",
10473 kProtocolFlagsIPv4v6,
10474 {
10475 V4_ADDR_LOOP, V4_ADDR_3, V6_ADDR_2, NULL
10476 }
10477 };
10478
10479 static DNSOrderTest test5 = {
10480 "test5",
10481 kProtocolFlagsIPv4v6,
10482 {
10483 V4_ADDR_3, V6_ADDR_LOOP, V6_ADDR_2, NULL
10484 }
10485 };
10486
10487 static DNSOrderTest test6 = {
10488 "test6",
10489 kProtocolFlagsIPv4v6,
10490 {
10491 V4_ADDR_1, V4_ADDR_2, V4_ADDR_3, V4_ADDR_4, V6_ADDR_1, V6_ADDR_2, V6_ADDR_3, NULL
10492 }
10493 };
10494
10495 static DNSOrderTest test7 = {
10496 "test7",
10497 kProtocolFlagsIPv4v6,
10498 {
10499 V4_ADDR_1, V6_ADDR_1, V4_ADDR_3, V6_ADDR_2, NULL
10500 }
10501 };
10502
10503 static DNSOrderTestRef dns_order_tests[] = {
10504 &test0a, &test0b,
10505 &test1a, &test2a, &test3a,
10506 &test1b, &test2b, &test3b,
10507 &test1c, &test2c, &test3c,
10508 &test1d, &test2d, &test3d,
10509 &test4,
10510 &test5,
10511 &test6,
10512 &test7,
10513 NULL
10514 };
10515
10516 #define EMPHASIS_CHARS "================="
10517
10518 static void
10519 apply_order(CFArrayRef servers, ProtocolFlags flags)
10520 {
10521 CFArrayRef ordered_servers;
10522
10523 ordered_servers = order_dns_servers(servers, flags);
10524 if (ordered_servers != NULL) {
10525 SCPrint(TRUE, stdout, CFSTR("After :\n%@\n"), ordered_servers);
10526 CFRelease(ordered_servers);
10527 } else {
10528 printf("FAIL: No ordered servers\n");
10529 }
10530
10531 return;
10532 }
10533
10534 static void
10535 apply_test(DNSOrderTestRef test)
10536 {
10537 CFMutableArrayRef servers;
10538
10539 printf("\n" EMPHASIS_CHARS "> '%s' Begin <" EMPHASIS_CHARS "\n\n", test->name);
10540
10541 servers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
10542 for (int i = 0; test->server_addrs[i] != NULL; i++) {
10543 CFStringRef server_addr = test->server_addrs[i];
10544
10545 CFArrayAppendValue(servers, server_addr);
10546 }
10547
10548 SCPrint(TRUE, stdout, CFSTR("Before :\n%@\n"), servers);
10549
10550 apply_order(servers, test->flags);
10551
10552 CFRelease(servers);
10553
10554 return;
10555 }
10556
10557 int
10558 main(int argc, char **argv)
10559 {
10560 _sc_log = FALSE;
10561 _sc_verbose = (argc > 1) ? TRUE : FALSE;
10562 S_IPMonitor_debug = kDebugFlag1 | kDebugFlag2 | kDebugFlag4;
10563 if (argc > 1) {
10564 S_IPMonitor_debug = (uint32)strtoul(argv[1], NULL, 0);
10565 }
10566
10567 for (DNSOrderTestRef * test = dns_order_tests; *test != NULL; test++) {
10568 apply_test(*test);
10569 }
10570
10571 {
10572 char cmd[128];
10573
10574 printf("\nChecking for leaks\n");
10575 sprintf(cmd, "leaks %d 2>&1", getpid());
10576 fflush(stdout);
10577 (void)system(cmd);
10578 }
10579
10580 exit(0);
10581 return (0);
10582 }
10583
10584 #endif /* TEST_DNS_ORDER */