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