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