this repo has no description
at fixPythonPipStalling 2143 lines 64 kB view raw
1/* 2 * Copyright (c) 2015-2017 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#import "controller.h" 25#import <SystemConfiguration/SCPrivate.h> 26#import "ip_plugin.h" 27 28#define numberToNSNumber(x) [NSNumber numberWithUnsignedInteger:x] 29 30#define dnsAgentDefault "_defaultDNS" 31#define proxyAgentDefault "_defaultProxy" 32#define multipleEntitySuffix " #" 33#define prefixForInterfaceName "@" 34 35/* These define the starting and ending order of each policy section */ 36#define INIT_ORDER_FOR_SCOPED_INTERFACE_POLICY 100 37#define INIT_ORDER_FOR_DOMAIN_POLICY 500 38#define INIT_ORDER_FOR_DEFAULT_POLICY 1000 39 40#define SKIP_ORDER_FOR_SCOPED_INTERFACE_POLICY 250 41#define SKIP_ORDER_FOR_DOMAIN_POLICY 750 42#define SKIP_ORDER_FOR_DEFAULT_POLICY 1250 43 44#define POLICY_TYPE_NO_POLICY -1 45#define CONFIG_AGENT_DATA_LIMIT MIN(NETAGENT_MAX_DATA_SIZE, 1024) 46 47typedef struct resolverList { 48 dns_resolver_t **default_resolvers; 49 uint32_t n_default_resolvers; 50 dns_resolver_t **multicast_resolvers; 51 uint32_t n_multicast_resolvers; 52 dns_resolver_t **private_resolvers; 53 uint32_t n_private_resolvers; 54} resolver_list_t; 55 56@interface AgentController() 57 58@property (nonatomic) NSMutableDictionary * floatingProxyAgentList; 59@property (nonatomic) NSMutableDictionary * floatingDNSAgentList; 60@property (nonatomic) NSMutableDictionary * policyDB; 61@property (nonatomic) NEPolicySession * policySession; 62@property (nonatomic) NEPolicySession * controlPolicySession; 63 64@end 65 66@implementation AgentController 67 68#pragma mark Init 69 70+ (AgentController *)sharedController 71{ 72 static AgentController * gController = nil; 73 static dispatch_once_t onceToken; 74 75 dispatch_once(&onceToken, ^{ 76 gController = [[AgentController alloc] init]; 77 }); 78 79 @synchronized (gController) { 80 if (![gController isControllerReady]) { 81 if (![gController initializeController]) { 82 return nil; 83 } 84 } 85 } 86 87 return gController; 88} 89 90- (instancetype)init 91{ 92 self = [super init]; 93 if (self) { 94 [self initializeController]; 95 } 96 97 return self; 98} 99 100- (BOOL)initializeController 101{ 102 const char *errorMessage = NULL; 103 104 do { 105 /* The NE policy session for the controller */ 106 107 if (self.policySession == nil) { 108 self.policySession = [self createPolicySession]; 109 if (self.policySession == nil) { 110 errorMessage = "Failed to create a policy session"; 111 break; 112 } 113 } 114 115 /* A dictionary of all floating proxy agents 116 * Key : <entity-name> (can be an interface name or domain name) 117 * Value : agent object 118 */ 119 120 if (self.floatingProxyAgentList == nil) { 121 self.floatingProxyAgentList = [NSMutableDictionary dictionary]; 122 if (self.floatingProxyAgentList == nil) { 123 errorMessage = "Failed to create a dictionary"; 124 break; 125 } 126 } 127 128 /* A dictionary of all floating dns agents 129 * Key : <entity-name> (can be an interface name or domain name) 130 * Value : agent object 131 */ 132 133 if (self.floatingDNSAgentList == nil) { 134 self.floatingDNSAgentList = [NSMutableDictionary dictionary]; 135 if (self.floatingDNSAgentList == nil) { 136 errorMessage = "Failed to create a dictionary"; 137 break; 138 } 139 } 140 141 /* A dictionary for the maintaining the policy IDs for all installed policy. 142 * These IDs would be necessary to uninstall a policy when an agent goes away 143 * Key : agent name (which can be retrieved by [agent getAgentName]) 144 * Value : An array of integers, each being a policy ID for that agent 145 */ 146 147 if (self.policyDB == nil) { 148 self.policyDB = [NSMutableDictionary dictionary]; 149 if (self.policyDB == nil) { 150 errorMessage = "Failed to create a dictionary"; 151 break; 152 } 153 } 154 155 /* The queue to run the all processing on */ 156 157 if (self.controllerQueue == nil) { 158 self.controllerQueue = dispatch_queue_create("com.apple.SystemConfiguration.controllerQueue", NULL); 159 if (self.controllerQueue == nil) { 160 errorMessage = "Failed to create a queue"; 161 break; 162 } 163 } 164 } while (0); 165 166 if (errorMessage != NULL) { 167 /* Some error occurred. This is unlikely during controller initialization... */ 168 SC_log(LOG_ERR, "Error occured while initializing AgentController: %s", errorMessage); 169 _SC_crash(errorMessage, NULL, NULL); 170 return NO; 171 } 172 173 return YES; 174} 175 176- (NEPolicySession *)createPolicySession 177{ 178 return [[NEPolicySession alloc] init]; 179} 180 181- (BOOL)isControllerReady 182{ 183 /* Make sure that we have all our data structures in place */ 184 return ((self.policySession != nil) && 185 (self.floatingProxyAgentList != nil) && 186 (self.floatingDNSAgentList != nil) && 187 (self.policyDB != nil) && 188 (self.controllerQueue != nil)); 189} 190 191/* ========================== proxy agent helpers =========================== */ 192#pragma mark Proxy agent helper functions 193 194- (NSData *)dataForProxyArray:(CFArrayRef)proxy_array_for_data 195{ 196 CFDataRef data = NULL; 197 (void)_SCSerialize(proxy_array_for_data, &data, NULL, NULL); 198 return (__bridge_transfer NSData *)data; 199} 200 201- (NSData *)dataForProxyDictionary:(CFDictionaryRef)domain_proxy 202{ 203 NSData * data = nil; 204 CFMutableDictionaryRef domain_proxy_dict; 205 206 if (domain_proxy == NULL) { 207 SC_log(LOG_NOTICE, "Invalid domain proxy dict"); 208 return nil; 209 } 210 211 domain_proxy_dict = CFDictionaryCreateMutableCopy(NULL, 0, domain_proxy); 212 CFDictionaryRemoveValue(domain_proxy_dict, kSCPropNetProxiesSupplementalMatchDomain); 213 214 data = (__bridge_transfer NSData *)(SCNetworkProxiesCreateProxyAgentData(domain_proxy_dict)); 215 CFRelease(domain_proxy_dict); 216 217 return data; 218} 219 220- (NSData *)getProxyDataFromCurrentConfig:(CFDictionaryRef)proxies 221 domain:(NSString *)domain 222{ 223 CFIndex count; 224 CFIndex idx; 225 CFArrayRef supplemental; 226 227 if (proxies == NULL || domain == nil) { 228 SC_log(LOG_NOTICE, "Invalid proxies/domain"); 229 return nil; 230 } 231 232 supplemental = CFDictionaryGetValue(proxies, kSCPropNetProxiesSupplemental); 233 count = supplemental ? CFArrayGetCount(supplemental) : 0; 234 235 for (idx = 0; idx < count; idx++) { 236 CFDictionaryRef domain_proxy; 237 CFStringRef match_domain; 238 239 domain_proxy = CFArrayGetValueAtIndex(supplemental, idx); 240 match_domain = CFDictionaryGetValue(domain_proxy, kSCPropNetProxiesSupplementalMatchDomain); 241 if (match_domain != NULL && CFEqual(match_domain, (__bridge CFTypeRef)(domain))) { 242 return [self dataForProxyDictionary:domain_proxy]; 243 } 244 } 245 246 return nil; 247} 248 249- (bool)getIntValue:(CFTypeRef)cf_value 250 valuePtr:(int *) int_value_ptr 251{ 252 bool valid = false; 253 if (cf_value && CFGetTypeID(cf_value) == CFNumberGetTypeID() && CFNumberGetValue(cf_value, kCFNumberIntType, int_value_ptr)) 254 { 255 valid = true; 256 } 257 return valid; 258} 259 260- (int)countProxyEntriesEnabled:(CFDictionaryRef)proxies 261{ 262 int enabled = 0; 263 264 if (proxies == NULL) { 265 SC_log(LOG_NOTICE, "Invalid proxies"); 266 return 0; 267 } 268 269 if (([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesHTTPEnable) valuePtr:&enabled] && enabled > 0) || 270 ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesHTTPSEnable) valuePtr:&enabled] && enabled > 0) || 271 ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesProxyAutoConfigEnable) valuePtr:&enabled] && enabled > 0) || 272 ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesFTPEnable) valuePtr:&enabled] && enabled > 0) || 273 ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesGopherEnable) valuePtr:&enabled] && enabled > 0) || 274 ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesRTSPEnable) valuePtr:&enabled] && enabled > 0) || 275 ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesSOCKSEnable) valuePtr:&enabled] && enabled > 0) || 276 ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesProxyAutoDiscoveryEnable) valuePtr:&enabled] && enabled > 0)) { 277 return enabled; 278 } 279 280 return 0; 281} 282 283- (void)processSupplementalProxyChanges:(CFDictionaryRef)proxies 284{ 285 CFIndex count; 286 NSMutableArray * deleteList; 287 NSCountedSet * duplicate_domain_list; 288 CFIndex idx; 289 NSMutableArray * new_domain_list; 290 NSMutableArray * old_domain_list; 291 CFArrayRef supplemental; 292 NSMutableArray * update_agent_list; 293 294 if (proxies == NULL) { 295 SC_log(LOG_INFO, "No proxy config to process"); 296 return; 297 } 298 299 old_domain_list = [self getAgentList:self.floatingProxyAgentList 300 agentType:kAgentTypeProxy 301 agentSubType:kAgentSubTypeSupplemental]; 302 duplicate_domain_list = [[NSCountedSet alloc] initWithCapacity:0]; 303 new_domain_list = [NSMutableArray array]; 304 update_agent_list = [NSMutableArray array]; 305 supplemental = CFDictionaryGetValue(proxies, kSCPropNetProxiesSupplemental); 306 count = supplemental ? CFArrayGetCount(supplemental) : 0; 307 deleteList = [NSMutableArray array]; 308 309 for (idx = 0; idx < count; idx++) { 310 CFDictionaryRef domain_proxy; 311 CFStringRef match_domain; 312 int proxy_count; 313 314 domain_proxy = CFArrayGetValueAtIndex(supplemental, idx); 315 match_domain = CFDictionaryGetValue(domain_proxy, kSCPropNetProxiesSupplementalMatchDomain); 316 if (match_domain == NULL) { 317 continue; 318 } 319 320 /* This domain is present in current config. But if it has generic (no protocols enabled) 321 * proxy content, there is no real use of that agent. Do NOT add it to 322 * the new_domain_list. 323 * 324 * This way, if there was an agent previously for this domain, 325 * it will be destroyed AND since it is not present in the new domain list, we wont 326 * spawn a new agent too! :) 327 */ 328 329 proxy_count = [self countProxyEntriesEnabled:domain_proxy]; 330 if (proxy_count == 0) { 331 SC_log(LOG_INFO, "Proxy settings on %@ are generic. Not recognizing as new domain", match_domain); 332 continue; 333 } 334 335 [new_domain_list addObject:(__bridge NSString *)match_domain]; 336 } 337 338 [self cleanConflictingAgentsFromList:old_domain_list 339 new_list:new_domain_list 340 agentDictionary:self.floatingProxyAgentList]; 341 342 for (NSString *key in old_domain_list) { 343 BOOL domain_present; 344 345 domain_present = [new_domain_list containsObject:key]; 346 if (domain_present == NO) { 347 id agent; 348 349 agent = [self.floatingProxyAgentList objectForKey:key]; 350 [self destroyFloatingAgent:agent]; 351 } 352 } 353 354 /* At this point, whatever is in the controller's floating agent list, 355 * is present in the current proxy config. The current proxy config 356 * might have even more configs, not known to the controller, YET 357 */ 358 359 for (NSString *domain in old_domain_list) { 360 id agent; 361 id mapped_agent; 362 363 agent = [self.floatingProxyAgentList objectForKey:domain]; 364 if (agent == nil) { 365 continue; 366 } 367 368 /* Am I mapped to some agent? */ 369 mapped_agent = [agent getAgentMapping]; 370 if (mapped_agent) { 371 /* OK, this agent is mapped to some other agent. We compare this agent's data 372 * to the current data of the agent to which it is mapped. If different, we destroy 373 * the agent and later map it to someone else OR spawn a new one. 374 */ 375 NSData * mapped_agent_data; 376 377 mapped_agent_data = [self getProxyDataFromCurrentConfig:proxies domain:[mapped_agent getAssociatedEntity]]; 378 if (mapped_agent_data == nil || ![[agent getAgentData] isEqual:mapped_agent_data]) { 379 /* Something changed for mapped agent */ 380 [deleteList addObject:agent]; 381 continue; 382 } 383 } else { 384 /* Since this agent is NOT mapped to any other agent, this agent is 385 * registered with the kernel. So instead of destroying the agent and 386 * re-registering it, just update it here. 387 * 388 * All the agents which were mapped to this agent, will be deleted and 389 * re-mapped, if the data changed. 390 */ 391 NSData * agent_data; 392 393 agent_data = [self getProxyDataFromCurrentConfig:proxies domain:[agent getAssociatedEntity]]; 394 if (![[agent getAgentData] isEqual:agent_data]) { 395 /* Something changed for agent */ 396 [agent updateAgentData:agent_data]; 397 398 /* The reason I don't publish the data to agent here is that, if there were 399 * some agents mapping to this one, they will momentarily have a policy for 400 * using this agent UUID for some domain based on this agent's previous data. 401 */ 402 [update_agent_list addObject:agent]; 403 } 404 } 405 [new_domain_list removeObject:domain]; 406 } 407 408 for (id agent in deleteList) { 409 SC_log(LOG_INFO, "Destroying agent %@ because something changed!", [agent getAgentName]); 410 [self destroyFloatingAgent:agent]; 411 } 412 413 for (id agent in update_agent_list) { 414 [self publishToAgent:agent]; 415 } 416 417 for (idx = 0; idx < count; idx++) { 418 CFDictionaryRef domain_proxy; 419 CFStringRef match_domain; 420 421 domain_proxy = CFArrayGetValueAtIndex(supplemental, idx); 422 match_domain = CFDictionaryGetValue(domain_proxy, kSCPropNetProxiesSupplementalMatchDomain); 423 424 if (match_domain != NULL) { 425 NSData * data; 426 NSUInteger found; 427 id mapped_agent; 428 429 found = [new_domain_list indexOfObject:(__bridge id _Nonnull)(match_domain)]; 430 if (found == NSNotFound) { 431 continue; 432 } 433 434 /* 435 * We will only process agents which are mapped AND the agent they were mapped to, changed OR 436 * agents for domains which we did not know before. 437 */ 438 439 NSUInteger domainInstance = [duplicate_domain_list countForObject:(__bridge id _Nonnull)(match_domain)]; 440 if (domainInstance > 0) { 441 /* domainInstance will be > 0, only if we have conflicting domains */ 442 domainInstance++; 443 NSString *ns_domain_name_copy = [NSString stringWithFormat:@"%@" multipleEntitySuffix "%lu", match_domain, (unsigned long)domainInstance]; 444 445 data = [self dataForProxyDictionary:domain_proxy]; 446 447 BOOL ok = [self spawnFloatingAgent:[ProxyAgent class] 448 entity:ns_domain_name_copy 449 agentSubType:kAgentSubTypeSupplemental 450 addPolicyOfType:NEPolicyConditionTypeDomain 451 publishData:data]; 452 if (ok) { 453 id agent = [self.floatingProxyAgentList objectForKey:ns_domain_name_copy]; 454 SC_log(LOG_INFO, "Duplicate Proxy agent %@", [agent getAgentName]);; 455 } 456 } else { 457 data = [self dataForProxyDictionary:domain_proxy]; 458 mapped_agent = [self getAgentWithSameDataAndSubType:self.floatingProxyAgentList 459 data:data 460 subType:kAgentSubTypeSupplemental]; 461 if (mapped_agent != nil) { 462 [self spawnMappedFloatingAgent:mapped_agent 463 entity:(__bridge NSString *)(match_domain) 464 agentSubType:kAgentSubTypeSupplemental 465 addPolicyOfType:NEPolicyConditionTypeDomain 466 updateData:data]; 467 } else { 468 [self spawnFloatingAgent:[ProxyAgent class] 469 entity:(__bridge NSString *)(match_domain) 470 agentSubType:kAgentSubTypeSupplemental 471 addPolicyOfType:NEPolicyConditionTypeDomain 472 publishData:data]; 473 } 474 } 475 476 [new_domain_list removeObjectAtIndex:found]; 477 [duplicate_domain_list addObject:(__bridge id _Nonnull)(match_domain)]; 478 } 479 } 480 481 return; 482} 483 484- (void)processScopedProxyChanges:(CFDictionaryRef)proxies 485{ 486 NSMutableArray * old_intf_list; 487 CFDictionaryRef scoped_proxies; 488 CFIndex scoped_proxies_count; 489 490 old_intf_list = [self getAgentList:self.floatingProxyAgentList 491 agentType:kAgentTypeProxy 492 agentSubType:kAgentSubTypeScoped]; 493 494 scoped_proxies = CFDictionaryGetValue(proxies, kSCPropNetProxiesScoped); 495 scoped_proxies_count = scoped_proxies ? CFDictionaryGetCount(scoped_proxies) : 0; 496 497 if (scoped_proxies_count > 0) { 498 const void **keys; 499 500 keys = malloc(scoped_proxies_count * sizeof(void *)); 501 CFDictionaryGetKeysAndValues(scoped_proxies, keys, NULL); 502 503 for (int i = 0; i < scoped_proxies_count; i++) { 504 NSData * data = nil; 505 NSUInteger idx; 506 CFArrayRef matching; 507 NSString * ns_if_name; 508 NSString * ns_if_name_with_prefix; 509 int proxy_count = 0; 510 id proxyAgent; 511 512 ns_if_name = (__bridge NSString *)keys[i]; 513 ns_if_name_with_prefix = [NSString stringWithFormat:@"%s%@", prefixForInterfaceName, ns_if_name]; 514 515 /* Does the proxy config have any protocols enabled? */ 516 proxy_count = [self countProxyEntriesEnabled:CFDictionaryGetValue(scoped_proxies, 517 (__bridge const void *)(ns_if_name))]; 518 519 if (proxy_count == 0) { 520 SC_log(LOG_INFO, "Proxy settings on %@ are generic. Skipping", ns_if_name); 521 continue; 522 } 523 524 idx = [old_intf_list indexOfObject:ns_if_name_with_prefix]; 525 526 matching = SCNetworkProxiesCopyMatching(proxies, NULL, (__bridge CFStringRef)(ns_if_name)); 527 if (matching != NULL) { 528 data = [self dataForProxyArray:matching]; 529 CFRelease(matching); 530 } 531 532 if (idx == NSNotFound) { 533 /* We need to spawn an agent */ 534 [self spawnFloatingAgent:[ProxyAgent class] 535 entity:ns_if_name_with_prefix 536 agentSubType:kAgentSubTypeScoped 537 addPolicyOfType:NEPolicyConditionTypeScopedInterface 538 publishData:data]; 539 540 continue; 541 } else { 542 /* We have an agent for this interface. Update it */ 543 [old_intf_list removeObjectAtIndex:idx]; 544 } 545 546 proxyAgent = [self.floatingProxyAgentList objectForKey:ns_if_name_with_prefix]; 547 if (proxyAgent != nil) { 548 /* Do we need to update this agent? */ 549 [proxyAgent updateAgentData:data]; 550 if ([proxyAgent shouldUpdateAgent]) { 551 [self publishToAgent:proxyAgent]; 552 } 553 } 554 } 555 556 free(keys); 557 } 558 559 [self deleteAgentList:self.floatingProxyAgentList list:old_intf_list]; 560} 561 562- (void)processServiceSpecificProxyChanges:(CFDictionaryRef)proxies 563{ 564 NSMutableArray * old_service_list; 565 CFDictionaryRef service_proxies; 566 CFIndex service_proxies_count; 567 568 old_service_list = [self getAgentList:self.floatingProxyAgentList 569 agentType:kAgentTypeProxy 570 agentSubType:kAgentSubTypeServiceSpecific]; 571 572 service_proxies = CFDictionaryGetValue(proxies, kSCPropNetProxiesServices); 573 service_proxies_count = service_proxies ? CFDictionaryGetCount(service_proxies) : 0; 574 575 if (service_proxies_count > 0) { 576 const void **keys; 577 578 keys = malloc(service_proxies_count * sizeof(void *)); 579 CFDictionaryGetKeysAndValues(service_proxies, keys, NULL); 580 581 for (int i = 0; i < service_proxies_count; i++) { 582 NSData * data = nil; 583 NSUInteger idx; 584 NSString * ns_service_identifier = nil; 585 NSString * ns_service_with_prefix = nil; 586 int proxy_count = 0; 587 id proxyAgent; 588 CFDictionaryRef proxyDict = NULL; 589 590 ns_service_identifier = (__bridge NSString *)keys[i]; 591 ns_service_with_prefix = [NSString stringWithFormat:@"%s%@", prefixForInterfaceName, ns_service_identifier]; 592 593 /* Does the proxy config have any protocols enabled? */ 594 proxy_count = [self countProxyEntriesEnabled:CFDictionaryGetValue(service_proxies, 595 (__bridge const void *)(ns_service_identifier))]; 596 597 if (proxy_count == 0) { 598 SC_log(LOG_INFO, "Proxy settings on %@ are generic. Skipping", ns_service_identifier); 599 continue; 600 } 601 602 proxyDict = CFDictionaryGetValue(service_proxies, (__bridge CFStringRef)ns_service_identifier); 603 if (proxyDict != nil) { 604 data = [self dataForProxyArray:(__bridge CFArrayRef)(@[ (__bridge NSDictionary *)proxyDict ])]; 605 } 606 607 idx = [old_service_list indexOfObject:ns_service_with_prefix]; 608 if (idx == NSNotFound) { 609 /* We need to spawn an agent */ 610 [self spawnFloatingAgent:[ProxyAgent class] 611 entity:ns_service_with_prefix 612 agentSubType:kAgentSubTypeServiceSpecific 613 addPolicyOfType:(POLICY_TYPE_NO_POLICY) /* Don't install a policy */ 614 publishData:data]; 615 616 continue; 617 } else { 618 /* We have an agent for this service. Update it */ 619 [old_service_list removeObjectAtIndex:idx]; 620 } 621 622 proxyAgent = [self.floatingProxyAgentList objectForKey:ns_service_with_prefix]; 623 if (proxyAgent != nil) { 624 /* Do we need to update this agent? */ 625 [proxyAgent updateAgentData:data]; 626 if ([proxyAgent shouldUpdateAgent]) { 627 [self publishToAgent:proxyAgent]; 628 } 629 } 630 } 631 632 free(keys); 633 } 634 635 [self deleteAgentList:self.floatingProxyAgentList list:old_service_list]; 636} 637 638- (BOOL)isGlobalProxy:(CFDictionaryRef)proxies 639{ 640 if (CFDictionaryContainsKey(proxies, kSCPropNetProxiesBypassAllowed)) { 641 /* 642 * Since we did not ask to "bypass" the proxies, this key will always 643 * be present in a managed (global) proxy configuration 644 */ 645 return YES; 646 } 647 648 return NO; 649} 650 651- (void)processDefaultProxyChanges:(CFDictionaryRef)proxies 652{ 653 CFArrayRef global_proxy; 654 CFIndex global_proxy_count; 655 CFMutableDictionaryRef proxies_copy; 656 657 proxies_copy = CFDictionaryCreateMutableCopy(NULL, 0, proxies); 658 CFDictionaryRemoveValue(proxies_copy, kSCPropNetProxiesScoped); 659 CFDictionaryRemoveValue(proxies_copy, kSCPropNetProxiesServices); 660 CFDictionaryRemoveValue(proxies_copy, kSCPropNetProxiesSupplemental); 661 662 global_proxy = CFArrayCreate(NULL, (const void **)&proxies_copy, 1, &kCFTypeArrayCallBacks); 663 global_proxy_count = CFArrayGetCount(global_proxy); 664 if (global_proxy_count > 0 && 665 [self countProxyEntriesEnabled:proxies_copy] == 0) { 666 SC_log(LOG_INFO, "Proxy settings on defaultProxy are generic. Skipping"); 667 global_proxy_count = 0; 668 } 669 CFRelease(proxies_copy); 670 671 if (global_proxy_count > 0) { 672 BOOL spawnAgent = YES; 673 id proxyAgent; 674 NSData * data; 675 676 data = [self dataForProxyArray:global_proxy]; 677 proxyAgent = [self.floatingProxyAgentList objectForKey:@proxyAgentDefault]; 678 if (proxyAgent != nil) { 679 if (![data isEqual:[proxyAgent getAgentData]]) { 680 [self destroyFloatingAgent:proxyAgent]; 681 } else { 682 spawnAgent = NO; 683 } 684 } 685 686 if (spawnAgent) { 687 AgentSubType subtype = kAgentSubTypeDefault; 688 NEPolicyConditionType conditionType = NEPolicyConditionTypeNone; 689 if ([self isGlobalProxy:proxies_copy]) { 690 SC_log(LOG_INFO, "Global proxy detected..."); 691 conditionType = NEPolicyConditionTypeAllInterfaces; 692 subtype = kAgentSubTypeGlobal; 693 } 694 695 [self spawnFloatingAgent:[ProxyAgent class] 696 entity:@proxyAgentDefault 697 agentSubType:subtype 698 addPolicyOfType:conditionType 699 publishData:data]; 700 } 701 } else { 702 /* No default proxy config OR generic (no protocols enabled) default proxy config. 703 * Destroy the default agent if we had one 704 */ 705 id proxyAgent; 706 707 proxyAgent = [self.floatingProxyAgentList objectForKey:@proxyAgentDefault]; 708 if (proxyAgent != nil) { 709 [self destroyFloatingAgent:proxyAgent]; 710 } 711 } 712 713 CFRelease(global_proxy); 714} 715 716- (void)processProxyChanges 717{ 718 CFDictionaryRef proxies; 719 720 proxies = SCDynamicStoreCopyProxiesWithOptions(NULL, NULL); 721 if (proxies == NULL) { 722 SC_log(LOG_INFO, "No proxy information"); 723 724 NSMutableDictionary *copy = [self.floatingProxyAgentList copy]; 725 for (NSString *entity in copy) { 726 id agent = [copy objectForKey:entity]; 727 [self destroyFloatingAgent:agent]; 728 } 729 730 return; 731 } 732 733 [self processDefaultProxyChanges:proxies]; 734 [self processScopedProxyChanges:proxies]; 735 [self processSupplementalProxyChanges:proxies]; 736 [self processServiceSpecificProxyChanges:proxies]; 737 738 CFRelease(proxies); 739} 740 741/* ========================== DNS agent helpers =========================== */ 742#pragma mark DNS agent helper functions 743 744- (void)freeResolverList:(resolver_list_t *)resolvers 745{ 746 /* This is a shallow free of resolver_list_t only. 747 * The actual resolver pointers are owned by 'dns_config' 748 */ 749 if (resolvers == NULL) { 750 return; 751 } 752 753 if (resolvers->default_resolvers != NULL) { 754 free(resolvers->default_resolvers); 755 } 756 if (resolvers->multicast_resolvers != NULL) { 757 free(resolvers->multicast_resolvers); 758 } 759 if (resolvers->private_resolvers != NULL) { 760 free(resolvers->private_resolvers); 761 } 762 763 free(resolvers); 764} 765 766- (resolver_list_t *)copyResolverList:(dns_config_t *)dns_config 767{ 768 resolver_list_t *resolvers = NULL; 769 770 if ((dns_config->n_resolver > 0) && (dns_config->resolver != NULL)) { 771 uint32_t a = 0; 772 uint32_t b = 0; 773 uint32_t c = 0; 774 775 resolvers = calloc(1, sizeof(resolver_list_t)); 776 for (int i = 0; i < dns_config->n_resolver; i++) { 777 dns_resolver_t *r = dns_config->resolver[i]; 778 779 if ([self isResolverMulticast:r]) { 780 resolvers->n_multicast_resolvers++; 781 continue; 782 783 } else if ([self isResolverPrivate:r]) { 784 resolvers->n_private_resolvers++; 785 continue; 786 } 787 788 // do not consider default resolvers with no nameservers 789 if (r->domain == NULL && r->n_nameserver > 0) { 790 resolvers->n_default_resolvers++; 791 } 792 } 793 794 SC_log(LOG_INFO, "Resolvers: %d default, %d multicast, %d private", 795 resolvers->n_default_resolvers, 796 resolvers->n_multicast_resolvers, 797 resolvers->n_private_resolvers); 798 799 if (resolvers->n_default_resolvers > 0) { 800 resolvers->default_resolvers = calloc(resolvers->n_default_resolvers, 801 sizeof(dns_resolver_t *)); 802 } 803 if (resolvers->n_multicast_resolvers > 0) { 804 resolvers->multicast_resolvers = calloc(resolvers->n_multicast_resolvers, 805 sizeof(dns_resolver_t *)); 806 } 807 if (resolvers->n_private_resolvers > 0) { 808 resolvers->private_resolvers = calloc(resolvers->n_private_resolvers, 809 sizeof(dns_resolver_t *)); 810 } 811 812 for (int i = 0; i < dns_config->n_resolver; i++) { 813 dns_resolver_t *r = dns_config->resolver[i]; 814 815 if ([self isResolverMulticast:r] && 816 (a < resolvers->n_multicast_resolvers)) { 817 resolvers->multicast_resolvers[a++] = r; 818 continue; 819 820 } else if ([self isResolverPrivate:r] && 821 (b < resolvers->n_private_resolvers)) { 822 resolvers->private_resolvers[b++] = r; 823 continue; 824 } 825 826 if ((r->domain == NULL) && 827 (r->n_nameserver > 0) && 828 (c < resolvers->n_default_resolvers)) { 829 resolvers->default_resolvers[c++] = r; 830 } 831 } 832 } 833 834 return resolvers; 835} 836 837/* 838 * Generate a data blob for the resolver. 839 * Currently the blob only has: 840 * - nameserver count 841 * - sockaddr structs for each nameserver 842 * - ifindex 843 */ 844 845- (NSData *)dataForResolver:(dns_resolver_t *)resolver 846{ 847 NSData * data = nil; 848 CFMutableDictionaryRef resolverDict = nil; 849 850 if (resolver == NULL) { 851 SC_log(LOG_NOTICE, "Invalid dns resolver"); 852 return nil; 853 } 854 855 if (resolver->n_search > 0) { 856 if (resolverDict == nil) { 857 resolverDict = CFDictionaryCreateMutable(NULL, 858 0, 859 &kCFTypeDictionaryKeyCallBacks, 860 &kCFTypeDictionaryValueCallBacks); 861 } 862 863 CFMutableArrayRef searchDomainArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 864 865 /* Append search domains */ 866 for (int i = 0; i < resolver->n_search; i++) { 867 CFArrayAppendValue(searchDomainArray, (__bridge CFStringRef)(@(resolver->search[i]))); 868 } 869 870 CFDictionaryAddValue(resolverDict, CFSTR(kConfigAgentDNSSearchDomains), searchDomainArray); 871 CFRelease(searchDomainArray); 872 } 873 874 /* Get the count of nameservers */ 875 if (resolver->n_nameserver > 0) { 876 if (resolverDict == nil) { 877 resolverDict = CFDictionaryCreateMutable(NULL, 878 0, 879 &kCFTypeDictionaryKeyCallBacks, 880 &kCFTypeDictionaryValueCallBacks); 881 } 882 883 CFMutableArrayRef nameserverArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 884 885 /* Get all the nameservers */ 886 for (int i = 0; i < resolver->n_nameserver; i++) { 887 char buf[128] = {0}; 888 _SC_sockaddr_to_string(resolver->nameserver[i], buf, sizeof(buf)); 889 if (*buf != '\0') { 890 CFArrayAppendValue(nameserverArray, (__bridge CFStringRef)(@(buf))); 891 } 892 } 893 894 CFDictionaryAddValue(resolverDict, CFSTR(kConfigAgentDNSNameServers), nameserverArray); 895 CFRelease(nameserverArray); 896 } 897 898 if (resolverDict != nil) { 899 data = [NSPropertyListSerialization dataWithPropertyList:(__bridge id _Nonnull)(resolverDict) 900 format:NSPropertyListBinaryFormat_v1_0 901 options:0 902 error:nil]; 903 904 CFRelease(resolverDict); 905 } 906 907 return (NSData *)data; 908} 909 910- (NSData *)getDNSDataFromCurrentConfig:(dns_config_t *)dns_config 911 domain:(NSString *)domain 912{ 913 if (dns_config == NULL || domain == nil) { 914 SC_log(LOG_NOTICE, "Invalid dns_config/domain"); 915 return nil; 916 } 917 918 if ((dns_config->n_resolver > 0) && (dns_config->resolver != NULL)) { 919 for (int i = 0; i < dns_config->n_resolver; i++) { 920 dns_resolver_t * resolver; 921 922 resolver = dns_config->resolver[i]; 923 if (resolver->domain != NULL && 924 ![self isResolverMulticast:resolver]) { 925 NSString * ns_domain_name; 926 927 ns_domain_name = @(resolver->domain); 928 if ([ns_domain_name isEqualToString:domain]) { 929 return [self dataForResolver:resolver]; 930 } else { 931 continue; 932 } 933 } 934 } 935 } 936 937 return nil; 938} 939 940- (BOOL)isResolverMulticast:(dns_resolver_t *)resolver 941{ 942 if (resolver->options == NULL) { 943 return NO; 944 } 945 946 if (!strstr(resolver->options, "mdns")) { 947 return NO; 948 } 949 950 return YES; 951} 952 953- (BOOL)isResolverPrivate:(dns_resolver_t *)resolver 954{ 955 if (resolver->options == NULL) { 956 return NO; 957 } 958 959 if (!strstr(resolver->options, "pdns")) { 960 return NO; 961 } 962 963 return YES; 964} 965 966- (void)processSupplementalDNSResolvers:(dns_config_t *)dns_config 967{ 968 NSMutableArray * deleteList; 969 NSMutableArray * new_domain_list; 970 NSCountedSet * duplicate_domain_list; 971 NSMutableArray * old_domain_list; 972 NSMutableArray * update_agent_list; 973 974 975 deleteList = [NSMutableArray array]; 976 duplicate_domain_list = [[NSCountedSet alloc] initWithCapacity:0]; 977 new_domain_list = [NSMutableArray array]; 978 update_agent_list = [NSMutableArray array]; 979 old_domain_list = [self getAgentList:self.floatingDNSAgentList 980 agentType:kAgentTypeDNS 981 agentSubType:kAgentSubTypeSupplemental]; 982 983 if (dns_config->resolver == NULL) { 984 dns_config->n_resolver = 0; 985 } 986 if (dns_config->n_resolver > 0) { 987 for (int i = 0; i < dns_config->n_resolver; i++) { 988 dns_resolver_t * resolver; 989 990 resolver = dns_config->resolver[i]; 991 if (resolver->domain != NULL && 992 ![self isResolverPrivate:resolver] && 993 ![self isResolverMulticast:resolver]) { 994 NSString * ns_domain_name; 995 996 ns_domain_name = [NSString stringWithCString:resolver->domain encoding:NSASCIIStringEncoding]; 997 [new_domain_list addObject:ns_domain_name]; 998 } 999 } 1000 } 1001 1002 [self cleanConflictingAgentsFromList:old_domain_list 1003 new_list:new_domain_list 1004 agentDictionary:self.floatingDNSAgentList]; 1005 1006 /* Sync between controller and current config */ 1007 for (NSString *key in old_domain_list) { 1008 BOOL domain_present = NO; 1009 1010 domain_present = [new_domain_list containsObject:key]; 1011 if (domain_present == NO) { 1012 id agent; 1013 1014 agent = [self.floatingDNSAgentList objectForKey:key]; 1015 [self destroyFloatingAgent:agent]; 1016 } 1017 } 1018 1019 /* At this point, whatever is in the controller's floating agent list, 1020 is present in the current DNS config. The current DNS config 1021 might have even more configs, not known to the controller, YET 1022 */ 1023 1024 for (NSString *domain in old_domain_list) { 1025 id agent; 1026 id mapped_agent; 1027 1028 agent = [self.floatingDNSAgentList objectForKey:domain]; 1029 if (agent == nil) { 1030 continue; 1031 } 1032 1033 /* Am I mapped to some agent? */ 1034 mapped_agent = [agent getAgentMapping]; 1035 if (mapped_agent) { 1036 /* OK, this agent is mapped to some other agent. We compare this agent's data 1037 * to the current data of the agent to which it is mapped. If different, we destroy 1038 * the agent and later map it to someone else OR spawn a new one. 1039 */ 1040 NSData *mapped_agent_data; 1041 1042 mapped_agent_data = [self getDNSDataFromCurrentConfig:dns_config domain:[mapped_agent getAssociatedEntity]]; 1043 if (mapped_agent_data == nil || ![[agent getAgentData] isEqual:mapped_agent_data]) { 1044 /* Something changed for mapped agent */ 1045 [deleteList addObject:agent]; 1046 continue; 1047 } 1048 } else { 1049 /* Since this agent is NOT mapped to any other agent, this agent is 1050 * registered with the kernel. So instead of destroying the agent and 1051 * re-registering it, just update it here. 1052 * 1053 * All the agents which were mapped to this agent, will be deleted and 1054 * re-mapped, if the data changed. 1055 */ 1056 NSData *agent_data; 1057 1058 agent_data = [self getDNSDataFromCurrentConfig:dns_config domain:[agent getAssociatedEntity]]; 1059 if (![[agent getAgentData] isEqual:agent_data]) { 1060 /* Something changed for agent */ 1061 [agent updateAgentData:agent_data]; 1062 1063 /* The reason I don't publish the data to agent here is that, if there were 1064 * some agents mapping to this one, they will momentarily have a policy for 1065 * using this agent UUID for some domain based on this agent's previous data. 1066 */ 1067 [update_agent_list addObject:agent]; 1068 1069 } 1070 } 1071 [new_domain_list removeObject:domain]; 1072 } 1073 1074 for (id agent in deleteList) { 1075 SC_log(LOG_INFO, "Destroying agent %@ because something changed!", [agent getAgentName]); 1076 [self destroyFloatingAgent:agent]; 1077 } 1078 1079 for (id agent in update_agent_list) { 1080 [self publishToAgent:agent]; 1081 } 1082 1083 for (int idx = 0; idx < dns_config->n_resolver; idx++) { 1084 dns_resolver_t * resolver; 1085 1086 resolver = dns_config->resolver[idx]; 1087 if (resolver->domain != NULL && 1088 ![self isResolverPrivate:resolver] && 1089 ![self isResolverMulticast:resolver]) { 1090 NSData * data; 1091 NSUInteger found; 1092 id mapped_agent; 1093 NSString * ns_domain_name; 1094 1095 ns_domain_name = @(resolver->domain); 1096 found = [new_domain_list indexOfObject:ns_domain_name]; 1097 if (found == NSNotFound) { 1098 /* Nothing changed for this agent */ 1099 continue; 1100 } 1101 1102 /* We will only process agents which are mapped AND if the agent they were mapped to, changed OR 1103 * agents for domains which we did not know before. 1104 */ 1105 1106 NSUInteger domainInstance = [duplicate_domain_list countForObject:ns_domain_name]; 1107 if (domainInstance > 0) { 1108 /* domainInstance will be > 0, only if we have conflicting domains */ 1109 domainInstance++; 1110 data = [self dataForResolver:resolver]; 1111 1112 NSString *ns_domain_name_copy = [NSString stringWithFormat:@"%@" multipleEntitySuffix "%lu", ns_domain_name, (unsigned long)domainInstance]; 1113 1114 BOOL ok = [self spawnFloatingAgent:[DNSAgent class] 1115 entity:ns_domain_name_copy 1116 agentSubType:kAgentSubTypeSupplemental 1117 addPolicyOfType:NEPolicyConditionTypeDomain 1118 publishData:data]; 1119 if (ok) { 1120 id agent = [self.floatingDNSAgentList objectForKey:ns_domain_name_copy]; 1121 SC_log(LOG_INFO, "Duplicate DNS agent %@", [agent getAgentName]);; 1122 } 1123 } else { 1124 data = [self dataForResolver:resolver]; 1125 mapped_agent = [self getAgentWithSameDataAndSubType:self.floatingDNSAgentList 1126 data:data 1127 subType:kAgentSubTypeSupplemental]; 1128 if (mapped_agent != nil) { 1129 [self spawnMappedFloatingAgent:mapped_agent 1130 entity:ns_domain_name 1131 agentSubType:kAgentSubTypeSupplemental 1132 addPolicyOfType:NEPolicyConditionTypeDomain 1133 updateData:data]; 1134 } else { 1135 [self spawnFloatingAgent:[DNSAgent class] 1136 entity:ns_domain_name 1137 agentSubType:kAgentSubTypeSupplemental 1138 addPolicyOfType:NEPolicyConditionTypeDomain 1139 publishData:data]; 1140 } 1141 } 1142 1143 [new_domain_list removeObjectAtIndex:found]; 1144 [duplicate_domain_list addObject:ns_domain_name]; 1145 } 1146 } 1147 1148 return; 1149 1150} 1151 1152- (void)processDNSResolvers:(dns_config_t *)dns_config 1153{ 1154 resolver_list_t *resolvers = [self copyResolverList:dns_config]; 1155 if (resolvers) { 1156 /* Process Default resolvers */ 1157 NSMutableArray *old_default_resolver_list = [self getAgentList:self.floatingDNSAgentList 1158 agentType:kAgentTypeDNS 1159 agentSubType:kAgentSubTypeDefault]; 1160 1161 // For default resolvers, their name will be '_defaultDNS', '_defaultDNS #2' so on... 1162 if (resolvers->n_default_resolvers > 0 && resolvers->default_resolvers != NULL) { 1163 for (uint32_t i = 0; i < resolvers->n_default_resolvers; i++) { 1164 dns_resolver_t *default_resolver = resolvers->default_resolvers[i]; 1165 NSData * data; 1166 id dnsAgent; 1167 NSString * resolverName; 1168 1169 data = [self dataForResolver:default_resolver]; 1170 if (i == 0) { 1171 resolverName = @(dnsAgentDefault); 1172 } else { 1173 resolverName = [NSString stringWithFormat:@dnsAgentDefault multipleEntitySuffix "%d", i+1 ]; 1174 } 1175 1176 dnsAgent = [self.floatingDNSAgentList objectForKey:resolverName]; 1177 1178 if (dnsAgent != nil) { 1179 [old_default_resolver_list removeObject:resolverName]; 1180 if ([data isEqual:[dnsAgent getAgentData]]) { 1181 /* Leave this agent in place. Nothing changed! */ 1182 continue; 1183 } else { 1184 [self destroyFloatingAgent:dnsAgent]; 1185 } 1186 } 1187 1188 [self spawnFloatingAgent:[DNSAgent class] 1189 entity:resolverName 1190 agentSubType:kAgentSubTypeDefault 1191 addPolicyOfType:NEPolicyConditionTypeNone 1192 publishData:data]; 1193 } 1194 } 1195 1196 // Only agents that are NOT present in the new config, will be present in the list 1197 // and they need to be destroyed. 1198 [self deleteAgentList:self.floatingDNSAgentList list:old_default_resolver_list]; 1199 1200 /* Process Multicast resolvers */ 1201 1202 NSMutableArray *old_multicast_resolver_list = [self getAgentList:self.floatingDNSAgentList 1203 agentType:kAgentTypeDNS 1204 agentSubType:kAgentSubTypeMulticast]; 1205 1206 if (resolvers->n_multicast_resolvers > 0 && resolvers->multicast_resolvers != NULL) { 1207 for (uint32_t i = 0; i < resolvers->n_multicast_resolvers; i++) { 1208 dns_resolver_t * multicast_resolver = resolvers->multicast_resolvers[i]; 1209 id dnsAgent; 1210 NSString * resolverName; 1211 1212 if (multicast_resolver == NULL) { 1213 continue; 1214 } 1215 1216 if (multicast_resolver->domain == NULL) { 1217 /* Multicast resolvers MUST have a domain */ 1218 continue; 1219 } 1220 1221 resolverName = @(multicast_resolver->domain); 1222 if (resolverName == NULL) { 1223 /* Multicast resolvers MUST have a domain */ 1224 continue; 1225 } 1226 1227 dnsAgent = [self.floatingDNSAgentList objectForKey:resolverName]; 1228 if (dnsAgent != nil) { 1229 [old_multicast_resolver_list removeObject:resolverName]; 1230 continue; 1231 } 1232 1233 [self spawnFloatingAgent:[DNSAgent class] 1234 entity:resolverName 1235 agentSubType:kAgentSubTypeMulticast 1236 addPolicyOfType:NEPolicyConditionTypeDomain 1237 publishData:nil]; 1238 // Don't care about data for mdns resolvers. Do we? 1239 } 1240 } 1241 1242 [self deleteAgentList:self.floatingDNSAgentList list:old_multicast_resolver_list]; 1243 1244 /* Process Private resolvers */ 1245 1246 NSMutableArray *old_private_resolver_list = [self getAgentList:self.floatingDNSAgentList 1247 agentType:kAgentTypeDNS 1248 agentSubType:kAgentSubTypePrivate]; 1249 1250 if (resolvers->n_private_resolvers > 0 && resolvers->private_resolvers != NULL) { 1251 for (uint32_t i = 0; i < resolvers->n_private_resolvers; i++) { 1252 dns_resolver_t * private_resolver = resolvers->private_resolvers[i]; 1253 id dnsAgent; 1254 NSString * resolverName; 1255 1256 if (private_resolver == NULL) { 1257 continue; 1258 } 1259 1260 if (private_resolver->domain == NULL) { 1261 /* private resolvers MUST have a domain */ 1262 continue; 1263 } 1264 1265 resolverName = @(private_resolver->domain); 1266 if (resolverName == nil) { 1267 /* Private resolvers MUST have a domain */ 1268 continue; 1269 } 1270 1271 dnsAgent = [self.floatingDNSAgentList objectForKey:resolverName]; 1272 if (dnsAgent != nil) { 1273 [old_private_resolver_list removeObject:resolverName]; 1274 continue; 1275 } 1276 1277 [self spawnFloatingAgent:[DNSAgent class] 1278 entity:resolverName 1279 agentSubType:kAgentSubTypePrivate 1280 addPolicyOfType:NEPolicyConditionTypeDomain 1281 publishData:nil]; 1282 // Don't care about data for pdns resolvers. Do we? 1283 } 1284 } 1285 1286 [self deleteAgentList:self.floatingDNSAgentList list:old_private_resolver_list]; 1287 } 1288 1289 [self freeResolverList:resolvers]; 1290} 1291 1292- (void)processScopedDNSResolvers:(dns_config_t *)dns_config 1293{ 1294 NSMutableArray * old_intf_list; 1295 old_intf_list = [self getAgentList:self.floatingDNSAgentList 1296 agentType:kAgentTypeDNS 1297 agentSubType:kAgentSubTypeScoped]; 1298 1299 if ((dns_config->n_scoped_resolver > 0) && (dns_config->scoped_resolver != NULL)) { 1300 for (int i = 0; i < dns_config->n_scoped_resolver; i++) { 1301 char buf[IFNAMSIZ]; 1302 NSData * data; 1303 id dnsAgent; 1304 NSUInteger idx; 1305 const char * if_name; 1306 NSString * ns_if_name; 1307 NSString * ns_if_name_with_prefix; 1308 dns_resolver_t * resolver; 1309 1310 resolver = dns_config->scoped_resolver[i]; 1311 if_name = my_if_indextoname(resolver->if_index, buf); 1312 if (if_name) { 1313 ns_if_name = @(if_name); 1314 ns_if_name_with_prefix = [NSString stringWithFormat:@"%s%@", prefixForInterfaceName, ns_if_name]; 1315 } else { 1316 continue; 1317 } 1318 1319 data = [self dataForResolver:resolver]; 1320 idx = [old_intf_list indexOfObject:ns_if_name_with_prefix]; 1321 1322 if (idx == NSNotFound) { 1323 /* We need to spawn an agent */ 1324 [self spawnFloatingAgent:[DNSAgent class] 1325 entity:ns_if_name_with_prefix 1326 agentSubType:kAgentSubTypeScoped 1327 addPolicyOfType:NEPolicyConditionTypeScopedInterface 1328 publishData:data]; 1329 continue; 1330 } else { 1331 /* We have an agent on this interface. Update it */ 1332 [old_intf_list removeObjectAtIndex:idx]; 1333 } 1334 1335 /* Get the DNS agent for this interface? */ 1336 dnsAgent = [self.floatingDNSAgentList objectForKey:ns_if_name_with_prefix]; 1337 if (dnsAgent != nil) { 1338 /* Do we need to update this agent? */ 1339 [dnsAgent updateAgentData:data]; 1340 if ([dnsAgent shouldUpdateAgent]) { 1341 [self publishToAgent:dnsAgent]; 1342 } 1343 } 1344 } 1345 } 1346 1347 [self deleteAgentList:self.floatingDNSAgentList list:old_intf_list]; 1348} 1349 1350- (void)processServiceSpecificDNSResolvers:(dns_config_t *)dns_config 1351{ 1352 NSMutableArray * old_service_list; 1353 old_service_list = [self getAgentList:self.floatingDNSAgentList 1354 agentType:kAgentTypeDNS 1355 agentSubType:kAgentSubTypeServiceSpecific]; 1356 1357 if ((dns_config->n_service_specific_resolver > 0) && (dns_config->service_specific_resolver != NULL)) { 1358 for (int i = 0; i < dns_config->n_service_specific_resolver; i++) { 1359 NSData * data; 1360 id dnsAgent; 1361 NSUInteger idx; 1362 uint32_t service_identifier; 1363 NSString * ns_service_identifier_with_prefix; 1364 dns_resolver_t * resolver; 1365 1366 resolver = dns_config->service_specific_resolver[i]; 1367 service_identifier = resolver->service_identifier; 1368 if (service_identifier != 0) { 1369 ns_service_identifier_with_prefix = [NSString stringWithFormat:@"%s%u", prefixForInterfaceName, service_identifier]; 1370 } else { 1371 continue; 1372 } 1373 1374 data = [self dataForResolver:resolver]; 1375 idx = [old_service_list indexOfObject:ns_service_identifier_with_prefix]; 1376 1377 if (idx == NSNotFound) { 1378 /* We need to spawn an agent */ 1379 [self spawnFloatingAgent:[DNSAgent class] 1380 entity:ns_service_identifier_with_prefix 1381 agentSubType:kAgentSubTypeServiceSpecific 1382 addPolicyOfType:(POLICY_TYPE_NO_POLICY) /* Don't install a policy */ 1383 publishData:data]; 1384 continue; 1385 } else { 1386 /* We have an agent on this interface. Update it */ 1387 [old_service_list removeObjectAtIndex:idx]; 1388 } 1389 1390 /* Get the DNS agent for this interface? */ 1391 dnsAgent = [self.floatingDNSAgentList objectForKey:ns_service_identifier_with_prefix]; 1392 if (dnsAgent != nil) { 1393 /* Do we need to update this agent? */ 1394 [dnsAgent updateAgentData:data]; 1395 if ([dnsAgent shouldUpdateAgent]) { 1396 [self publishToAgent:dnsAgent]; 1397 } 1398 } 1399 } 1400 } 1401 1402 [self deleteAgentList:self.floatingDNSAgentList list:old_service_list]; 1403} 1404 1405#define ONION_RESOLVER_DOMAIN "onion" 1406- (BOOL)isResolverOnion:(dns_resolver_t *)resolver 1407{ 1408 if (resolver->domain != NULL && 1409 (strcmp(resolver->domain, ONION_RESOLVER_DOMAIN) == 0)) { 1410 return YES; 1411 } 1412 1413 return NO; 1414} 1415 1416 1417- (void)processOnionResolver:(dns_config_t *)dns_config 1418{ 1419 static NSUInteger policy_id = 0; 1420 1421 if (dns_config == NULL) { 1422 goto remove_policy; 1423 } 1424 1425 /* Run through the resolver configurations. We only care for the supplemental resolvers. */ 1426 for (int32_t i = 0; i < dns_config->n_resolver; i++) { 1427 dns_resolver_t *resolver = dns_config->resolver[i]; 1428 if ([self isResolverOnion:resolver]) { 1429 goto remove_policy; 1430 } 1431 } 1432 1433 /* We do not have any such resolver. Add a system-wide "drop" policy for this domain */ 1434 if (policy_id == 0) { 1435 NEPolicy *policy = [[NEPolicy alloc] initWithOrder:INIT_ORDER_FOR_DOMAIN_POLICY 1436 result:[NEPolicyResult drop] 1437 conditions:@[[NEPolicyCondition domain:@ONION_RESOLVER_DOMAIN]]]; 1438 if (policy != nil) { 1439 policy_id = [self.policySession addPolicy:policy]; 1440 if (![self.policySession apply]) { 1441 policy_id = 0; 1442 SC_log(LOG_NOTICE, "Could not add a [." ONION_RESOLVER_DOMAIN "] drop policy"); 1443 } else { 1444 SC_log(LOG_INFO, "Added a [." ONION_RESOLVER_DOMAIN "] drop policy"); 1445 } 1446 } 1447 } 1448 1449 return; 1450 1451remove_policy: 1452 1453 /* We have such a resolver in the config OR no DNS config at all. Remove the system-wide "drop" policy for this domain */ 1454 if (policy_id > 0) { 1455 [self.policySession removePolicyWithID:policy_id]; 1456 if (![self.policySession apply]) { 1457 SC_log(LOG_NOTICE, "Could not remove the [." ONION_RESOLVER_DOMAIN "] drop policy"); 1458 } else { 1459 policy_id = 0; 1460 SC_log(LOG_INFO, "Removed the [." ONION_RESOLVER_DOMAIN "] drop policy"); 1461 } 1462 } 1463 1464 return; 1465} 1466#undef ONION_RESOLVER_DOMAIN 1467 1468 1469- (void)processDNSChanges 1470{ 1471 dns_config_t * dns_config; 1472 1473 dns_config = dns_configuration_copy(); 1474 if (dns_config == NULL) { 1475 SC_log(LOG_INFO, "No DNS configuration"); 1476 NSMutableDictionary *copy = [self.floatingDNSAgentList copy]; 1477 for (NSString *entity in copy) { 1478 id agent = [copy objectForKey:entity]; 1479 1480 [self destroyFloatingAgent:agent]; 1481 } 1482 goto done; 1483 } 1484 1485 [self processDNSResolvers:dns_config]; 1486 [self processScopedDNSResolvers:dns_config]; 1487 [self processSupplementalDNSResolvers:dns_config]; 1488 [self processServiceSpecificDNSResolvers:dns_config]; 1489 1490done: 1491 1492 [self processOnionResolver:dns_config]; 1493 if (dns_config != NULL) { 1494 dns_configuration_free(dns_config); 1495 } 1496} 1497 1498#pragma mark Helper functions 1499 1500- (const void *)copyConfigAgentData:(NSMutableDictionary *)controllerDict 1501 uuid:(uuid_t)requested_uuid 1502 length:(uint64_t *)length 1503{ 1504 if (length == NULL) { 1505 SC_log(LOG_NOTICE, "Invalid parameters for copying agent data"); 1506 return NULL; 1507 } 1508 1509 id agent = nil; 1510 void *buffer = NULL; 1511 *length = 0; 1512 1513 for (NSString *key in controllerDict) { 1514 id temp_agent = [controllerDict objectForKey:key]; 1515 1516 uuid_t agent_uuid; 1517 1518 [[temp_agent getAgentUUID] getUUIDBytes:agent_uuid]; 1519 if (uuid_compare(agent_uuid, requested_uuid) == 0) { 1520 agent = temp_agent; 1521 break; 1522 } 1523 } 1524 1525 if (agent == nil) { 1526 uuid_string_t uuid_str; 1527 uuid_unparse(requested_uuid, uuid_str); 1528 SC_log(LOG_NOTICE, "Invalid config agent uuid %s specified", uuid_str); 1529 return NULL; 1530 } 1531 1532 NSData *data = [agent getAgentData]; 1533 uint64_t len = [data length]; 1534 if (len > 0) { 1535 *length = len; 1536 buffer = malloc((size_t)len); 1537 memcpy(buffer, [data bytes], len); 1538 } 1539 1540 return (const void *)buffer; 1541} 1542 1543- (const void *)copyProxyAgentData:(uuid_t)requested_uuid 1544 length:(uint64_t *)length 1545{ 1546 return [self copyConfigAgentData:self.floatingProxyAgentList 1547 uuid:requested_uuid 1548 length:length]; 1549} 1550 1551- (const void *)copyDNSAgentData:(uuid_t)requested_uuid 1552 length:(uint64_t *)length 1553{ 1554 return [self copyConfigAgentData:self.floatingDNSAgentList 1555 uuid:requested_uuid 1556 length:length]; 1557} 1558 1559- (NSData *)dataLengthSanityCheck:(id)agent 1560{ 1561 NSData * data = [agent getAgentData]; 1562 1563 if ([data length] > CONFIG_AGENT_DATA_LIMIT) { 1564 /* We impose a limit on the config agent data as 1KB. 1565 * If we have a data blob larger than this limit, do NOT publish it into the agent. 1566 * Instead publish a key which will trigger fetching of the configuration directly 1567 * through NWI server. 1568 */ 1569 NSMutableDictionary *data_dict = [NSMutableDictionary dictionary]; 1570 1571 NSUUID *uuid = [agent getAgentUUID]; 1572 uuid_t c_uuid; 1573 [uuid getUUIDBytes:c_uuid]; 1574 NSData *uuid_data = [[NSData alloc] initWithBytes:c_uuid length:sizeof(c_uuid)]; 1575 [data_dict setValue:uuid_data forKey:@kConfigAgentOutOfBandDataUUID]; 1576 1577 NSData *new_data = [NSPropertyListSerialization dataWithPropertyList:data_dict 1578 format:NSPropertyListBinaryFormat_v1_0 1579 options:0 1580 error:nil]; 1581 1582 return new_data; 1583 } 1584 1585 return nil; 1586} 1587 1588/* 1589 * For conflicting agents, the convention is that its name & entity, 1590 * will have a suffix " #<number>". This function will sanitize the 1591 * suffix and just return the entity name 1592 */ 1593- (NSString *)sanitizeEntity:(NSString *)entity 1594{ 1595 NSRange range = [entity rangeOfString:@multipleEntitySuffix]; 1596 if (range.location != NSNotFound) { 1597 NSString *str = [entity substringToIndex:range.location]; 1598 return str; 1599 } 1600 1601 return entity; 1602} 1603 1604/* 1605 * For interface names, there is a prefix to differentiate then 1606 * from the domain name (iff there were conflicting domain names). 1607 * Returns the sanitized interface name 1608 */ 1609- (NSString *)sanitizeInterfaceName:(NSString *)intf 1610{ 1611 NSRange range = [intf rangeOfString:@prefixForInterfaceName]; 1612 if (range.location != NSNotFound) { 1613 NSString *str = [intf substringFromIndex:(range.location + strlen(prefixForInterfaceName))]; 1614 return str; 1615 } 1616 1617 return intf; 1618} 1619 1620/* 1621 * For conflicting agents, the convention is that its name & entity, 1622 * will have a suffix " #<number>". This function will return that <number> 1623 */ 1624- (int)entityInstanceNumber:(NSString *)entity 1625{ 1626 NSRange range = [entity rangeOfString:@multipleEntitySuffix]; 1627 if (range.location != NSNotFound) { 1628 NSString *str = [entity substringFromIndex:(range.location + strlen(multipleEntitySuffix))]; 1629 return str.intValue; 1630 } 1631 1632 return 0; 1633} 1634 1635/* 1636 * In case that we have conflicting DNS/Proxy domains 1637 * This function will remove all those conflicting agents, 1638 * so that we can start afresh with the new config 1639 */ 1640- (void)cleanConflictingAgentsFromList:(NSMutableArray *)old_list 1641 new_list:(NSMutableArray *)new_list 1642 agentDictionary:(NSMutableDictionary *)agent_list 1643{ 1644 NSCountedSet * duplicate_domain_list; 1645 1646 for (NSString *domain in old_list) { 1647 /* If we had conflicting domains before, remove all of them */ 1648 NSString *sanitizedDomain = [self sanitizeEntity:domain]; 1649 if (![sanitizedDomain isEqualToString:domain]) { 1650 /* Destroy the original domain */ 1651 id agent = [agent_list objectForKey:sanitizedDomain]; 1652 [self destroyFloatingAgent:agent]; 1653 1654 /* Destroy the conflicting domain */ 1655 agent = [agent_list objectForKey:domain]; 1656 [self destroyFloatingAgent:agent]; 1657 1658 SC_log(LOG_INFO, "Removing conflicting domain: %@, %@", sanitizedDomain, domain); 1659 } 1660 } 1661 1662 duplicate_domain_list = [[NSCountedSet alloc] initWithArray:new_list]; 1663 for (NSString *domain in old_list) { 1664 if ([duplicate_domain_list countForObject:domain] > 1) { 1665 id agent = [agent_list objectForKey:domain]; 1666 [self destroyFloatingAgent:agent]; 1667 SC_log(LOG_INFO, "Removing domain %@ as it has duplicates in the current config", domain); 1668 } 1669 } 1670} 1671 1672/* 1673 * Get the list of agents from a specific dictionary. 1674 * The list of agents will only consist of the ones which 1675 * match the agent type and sub-type 1676 */ 1677 1678- (NSMutableArray *)getAgentList:(NSMutableDictionary *)all_agents 1679 agentType:(AgentType)type 1680 agentSubType:(AgentSubType)subtype 1681{ 1682 NSMutableArray *list = [NSMutableArray array]; 1683 NSArray *agentObjects = [all_agents allValues]; 1684 1685 for (id agent in agentObjects) { 1686 if (([agent getAgentType] == type) && 1687 ([agent getAgentSubType] == subtype)) { 1688 1689 [list addObject:[agent getAssociatedEntity]]; 1690 } 1691 } 1692 1693 return list; 1694} 1695 1696/* 1697 * Destroy all the agents are listed in "list" 1698 */ 1699 1700- (void)deleteAgentList:(NSMutableDictionary *)all_agents 1701 list:(NSMutableArray *)list 1702{ 1703 for (NSString *intf in list) { 1704 id agent; 1705 1706 agent = [all_agents objectForKey:intf]; 1707 [self destroyFloatingAgent:agent]; 1708 } 1709} 1710 1711/* 1712 * In order to not duplicate agents with same content, 1713 * we map an agent X to agent Y, when their content is the same. 1714 * 1715 * This function tries to find that agent Y 1716 */ 1717 1718- (id)getAgentWithSameDataAndSubType:(NSMutableDictionary *)agentList 1719 data:(NSData *)data 1720 subType:(AgentSubType)subtype 1721{ 1722 for (NSString *key in agentList) { 1723 id agent = [agentList objectForKey:key]; 1724 if ([[agent getAgentData] isEqual:data]) { 1725 /* Do not map to default agents */ 1726 if ([agent getAgentSubType] != subtype) { 1727 continue; 1728 } 1729 1730 /* Return only registered agents */ 1731 if ([agent getRegistrationObject] != nil) { 1732 return agent; 1733 } 1734 } 1735 } 1736 1737 return nil; 1738} 1739 1740#pragma mark Policy installation function 1741 1742/* 1743 * Add NECP policies for an agent 1744 */ 1745- (BOOL)addPolicyToFloatingAgent:(id)agent 1746 domain:(NSString *)domain 1747 agentUUIDToUse:(NSUUID *)uuid 1748 policyType:(NEPolicyConditionType)policyType 1749 useControlPolicySession:(BOOL)useControlPolicySession 1750{ 1751 NEPolicyCondition * condition = nil; 1752 NEPolicySession * session; 1753 uint32_t multiple_entity_offset; 1754 NEPolicy * newPolicy; 1755 BOOL ok; 1756 uint32_t order; 1757 uint32_t orderForSkip; 1758 NSMutableArray * policyArray; 1759 NSUInteger policyID1; 1760 NSUInteger policyID2; 1761 NEPolicyResult * result; 1762 uint32_t skipOrder; 1763 AgentType type; 1764 uint32_t typeOffset; 1765 1766 type = [agent getAgentType]; 1767 typeOffset = (type == kAgentTypeDNS) ? 0 : 5000; 1768 skipOrder = (type == kAgentTypeDNS) ? 5000 : 0; 1769 1770 multiple_entity_offset = (uint32_t)[self entityInstanceNumber:domain]; 1771 domain = [self sanitizeEntity:domain]; 1772 1773 switch (policyType) { 1774 case NEPolicyConditionTypeScopedInterface: 1775 order = INIT_ORDER_FOR_SCOPED_INTERFACE_POLICY + typeOffset + multiple_entity_offset; 1776 domain = [self sanitizeInterfaceName:domain]; 1777 condition = [NEPolicyCondition scopedInterface:domain]; 1778 orderForSkip = SKIP_ORDER_FOR_SCOPED_INTERFACE_POLICY + typeOffset; 1779 break; 1780 1781 case NEPolicyConditionTypeDomain: 1782 order = INIT_ORDER_FOR_DOMAIN_POLICY + typeOffset + multiple_entity_offset; 1783 condition = [NEPolicyCondition domain:domain]; 1784 orderForSkip = SKIP_ORDER_FOR_DOMAIN_POLICY + typeOffset; 1785 break; 1786 1787 case NEPolicyConditionTypeAllInterfaces: 1788 order = INIT_ORDER_FOR_DEFAULT_POLICY + typeOffset + multiple_entity_offset; 1789 condition = [NEPolicyCondition allInterfaces]; 1790 orderForSkip = SKIP_ORDER_FOR_DEFAULT_POLICY + typeOffset; 1791 break; 1792 1793 case NEPolicyConditionTypeNone: 1794 order = INIT_ORDER_FOR_DEFAULT_POLICY + typeOffset + multiple_entity_offset; 1795 orderForSkip = SKIP_ORDER_FOR_DEFAULT_POLICY + typeOffset; 1796 break; 1797 1798 default: 1799 SC_log(LOG_NOTICE, "Invalid policy condition specified"); 1800 return NO; 1801 } 1802 1803 result = [NEPolicyResult netAgentUUID:uuid]; 1804 newPolicy = [[NEPolicy alloc] initWithOrder:order 1805 result:result 1806 conditions: (condition ? @[condition] : nil)]; 1807 1808 if (newPolicy == nil) { 1809 SC_log(LOG_NOTICE, "Could not create a policy for agent %@", [agent getAgentName]); 1810 return NO; 1811 } 1812 1813 if (useControlPolicySession) { 1814 if (self.controlPolicySession == nil) { 1815 /* The NE policy session at "control" level for the controller */ 1816 self.controlPolicySession = [self createPolicySession]; 1817 if (self.controlPolicySession == nil) { 1818 SC_log(LOG_NOTICE, "Could not create a control policy session for agent %@", [agent getAgentName]); 1819 return NO; 1820 } 1821 [self.controlPolicySession setPriority:NEPolicySessionPriorityControl]; 1822 } 1823 ((ConfigAgent *)agent).preferredPolicySession = self.controlPolicySession; 1824 } else { 1825 ((ConfigAgent *)agent).preferredPolicySession = self.policySession; 1826 } 1827 1828 session = ((ConfigAgent *)agent).preferredPolicySession; 1829 1830 policyID1 = [session addPolicy:newPolicy]; 1831 if (policyID1 == 0) { 1832 SC_log(LOG_NOTICE, "Could not add a netagent policy for agent %@", [agent getAgentName]); 1833 return NO; 1834 } 1835 1836 result = [NEPolicyResult skipWithOrder:skipOrder]; 1837 newPolicy = [[NEPolicy alloc] initWithOrder:orderForSkip 1838 result:result 1839 conditions:(condition ? @[condition] : nil)]; 1840 1841 if (newPolicy == nil) { 1842 SC_log(LOG_NOTICE, "Could not create a policy for agent %@", [agent getAgentName]); 1843 return NO; 1844 } 1845 1846 policyID2 = [session addPolicy:newPolicy]; 1847 if (policyID2 == 0) { 1848 SC_log(LOG_NOTICE, "Could not add a skip policy for agent %@", [agent getAgentName]); 1849 return NO; 1850 } 1851 1852 ok = [session apply]; 1853 if (!ok) { 1854 SC_log(LOG_NOTICE, "Could not apply policy for agent %@", [agent getAgentName]); 1855 return NO; 1856 } 1857 1858 policyArray = [self.policyDB objectForKey:[agent getAgentName]]; 1859 if (policyArray == nil) { 1860 policyArray = [NSMutableArray array]; 1861 } 1862 1863 [policyArray addObject:numberToNSNumber(policyID1)]; 1864 [policyArray addObject:numberToNSNumber(policyID2)]; 1865 [self.policyDB setObject:policyArray forKey:[agent getAgentName]]; 1866 1867 return ok; 1868} 1869 1870#pragma mark Agent manipulation functions 1871 1872/* 1873 * Create an agent 1874 */ 1875- (BOOL)spawnFloatingAgent:(Class)agentClass 1876 entity:(NSString *)entity 1877 agentSubType:(AgentSubType)subtype 1878 addPolicyOfType:(NEPolicyConditionType)policyType 1879 publishData:(NSData *)data 1880{ 1881 id agent; 1882 BOOL ok; 1883 NSMutableDictionary * parameters; 1884 1885 parameters =[NSMutableDictionary dictionary]; 1886 [parameters setValue:entity forKey:@kEntityName]; 1887 [parameters setValue:numberToNSNumber(subtype) forKey:@kAgentSubType]; 1888 1889 agent = [[agentClass alloc] initWithParameters:parameters]; 1890 ok = [self registerAgent:agent]; 1891 if (!ok) { 1892 return NO; 1893 } 1894 1895 if (data) { 1896 /* Since we just spawned this agent, update its data */ 1897 [agent updateAgentData:data]; 1898 [self publishToAgent:agent]; 1899 } 1900 1901 /* Add a policy if there is a valid type. If POLICY_TYPE_NO_POLICY, then ignore policies. 1902 * POLICY_TYPE_NO_POLICY will be set for service-specific agents, in which case we rely on 1903 * service owners to install custom policies to point at the agents. */ 1904 if (policyType >= NEPolicyConditionTypeNone) { 1905 BOOL useControlPolicySession = NO; 1906 if (subtype == kAgentSubTypeGlobal) { 1907 /* Policies for a Global scoped agents are at "control" level */ 1908 useControlPolicySession = YES; 1909 } 1910 1911 ok = [self addPolicyToFloatingAgent:agent 1912 domain:entity 1913 agentUUIDToUse:[agent agentUUID] 1914 policyType:policyType 1915 useControlPolicySession:useControlPolicySession]; 1916 1917 if (!ok) { 1918 [self unregisterAgent:agent]; 1919 return NO; 1920 } 1921 } 1922 1923 SC_log(LOG_INFO, "Spawning floating agent for %@", entity); 1924 1925 if ([agent getAgentType] == kAgentTypeProxy) { 1926 [self.floatingProxyAgentList setObject:agent forKey:entity]; 1927 } else { 1928 [self.floatingDNSAgentList setObject:agent forKey:entity]; 1929 } 1930 1931 return ok; 1932} 1933 1934/* 1935 * Create an agent mapped to another agent. 1936 */ 1937- (BOOL)spawnMappedFloatingAgent:(id)mapped_agent 1938 entity:(NSString *)entity 1939 agentSubType:(AgentSubType)subtype 1940 addPolicyOfType:(NEPolicyConditionType)policyType 1941 updateData:(NSData *)data 1942{ 1943 id dummyAgent; 1944 NSMutableDictionary * parameters; 1945 1946 parameters = [NSMutableDictionary dictionary]; 1947 [parameters setValue:entity forKey:@kEntityName]; 1948 [parameters setValue:numberToNSNumber(subtype) forKey:@kAgentSubType]; 1949 1950 dummyAgent = [[[mapped_agent class] alloc] initWithParameters:parameters]; 1951 1952 if (data) { 1953 /* Since we just spawned this agent, update its data. 1954 * We do not publish it since this agent is mapped 1955 * to an agent which already has the same data 1956 */ 1957 [dummyAgent updateAgentData:data]; 1958 } 1959 1960 BOOL useControlPolicySession = NO; 1961 if (subtype == kAgentSubTypeGlobal) { 1962 /* Policies for a Global scoped agents are at "control" level */ 1963 useControlPolicySession = YES; 1964 } 1965 1966 BOOL ok = [self addPolicyToFloatingAgent:dummyAgent 1967 domain:entity 1968 agentUUIDToUse:[mapped_agent agentUUID] 1969 policyType:policyType 1970 useControlPolicySession:useControlPolicySession]; 1971 1972 if (!ok) { 1973 return NO; 1974 } 1975 1976 if ([mapped_agent getAgentType] == kAgentTypeProxy) { 1977 [self.floatingProxyAgentList setObject:dummyAgent forKey:entity]; 1978 } else { 1979 [self.floatingDNSAgentList setObject:dummyAgent forKey:entity]; 1980 } 1981 1982 [dummyAgent setAgentMapping:mapped_agent]; 1983 1984 SC_log(LOG_INFO, "Mapped floating agent %@ to %@", [dummyAgent getAgentName], [mapped_agent getAgentName]); 1985 return YES; 1986} 1987 1988/* 1989 * Write into an agent 1990 */ 1991- (BOOL)publishToAgent:(id)agent 1992{ 1993 /* Before any data goes into the kernel, do a sanity check. */ 1994 NSData *sanityCheckData = [self dataLengthSanityCheck:agent]; 1995 NSData *tempAgentData = nil; 1996 1997 if (sanityCheckData != nil) { 1998 /* Data length is more than the limit! for updateNetworkAgent, the data blob 1999 * has to be a part of the agent object. Thus the temporary data replacement! 2000 */ 2001 tempAgentData = [[agent getAgentData] copy]; 2002 [agent updateAgentData:sanityCheckData]; 2003 SC_log(LOG_NOTICE, "Data too large for %@ (%lu bytes)!", [agent getAgentName], (unsigned long)[tempAgentData length]); 2004 } 2005 2006 BOOL ok = NO; 2007 2008 NWNetworkAgentRegistration *regObject = [agent valueForKey:@"registrationObject"]; 2009 if (regObject != nil) { 2010 SC_log(LOG_NOTICE, "Publishing data to agent %@ (%lu bytes)", [agent getAgentName], (unsigned long)[[agent getAgentData] length]); 2011 ok = [regObject updateNetworkAgent:agent]; 2012 if (!ok) { 2013 SC_log(LOG_NOTICE, "Could not update config agent"); 2014 } 2015 } else { 2016 SC_log(LOG_NOTICE, "Config Agent not registered. Cannot Update"); 2017 } 2018 2019 if (tempAgentData != nil) { 2020 [agent updateAgentData:tempAgentData]; 2021 } 2022 2023 return ok; 2024} 2025 2026/* 2027 * Destroy an agent 2028 */ 2029- (BOOL)destroyFloatingAgent:(id)agent 2030{ 2031 BOOL ok = NO; 2032 2033 if ( agent != nil) { 2034 NSMutableArray * policyArray; 2035 2036 policyArray = [self.policyDB objectForKey:[agent getAgentName]]; 2037 if (policyArray != nil) { 2038 NEPolicySession * session = ((ConfigAgent *)agent).preferredPolicySession; 2039 BOOL result = NO; 2040 2041 for (NSNumber *policyID in policyArray) { 2042 NSUInteger idVal; 2043 2044 idVal = [policyID unsignedIntegerValue]; 2045 result = [session removePolicyWithID:idVal]; 2046 if (result == NO) { 2047 SC_log(LOG_NOTICE, "Could not remove policy %@ for agent %@", [session policyWithID:idVal], [agent getAgentName]); 2048 } 2049 } 2050 2051 result = [session apply]; 2052 if (result == NO) { 2053 SC_log(LOG_NOTICE, "Could not apply removed policies for agent %@", [agent getAgentName]); 2054 } 2055 2056 [self.policyDB removeObjectForKey:[agent getAgentName]]; 2057 } 2058 2059 if ([agent getAgentType] == kAgentTypeProxy) { 2060 [self.floatingProxyAgentList removeObjectForKey:[agent getAssociatedEntity]]; 2061 } else { 2062 [self.floatingDNSAgentList removeObjectForKey:[agent getAssociatedEntity]]; 2063 } 2064 2065 if ([agent getRegistrationObject] != nil) { 2066 [self unregisterAgent:agent]; 2067 } 2068 2069 SC_log(LOG_INFO, "X - Destroyed agent %@", [agent getAgentName]); 2070 2071 /* Check if we need to close the "control" policy session */ 2072 if (self.controlPolicySession != nil) { 2073 NSMutableArray *globalProxyAgentList; 2074 NSMutableArray *globalDNSAgentList; 2075 globalProxyAgentList = [self getAgentList:self.floatingProxyAgentList agentType:kAgentTypeProxy agentSubType:kAgentSubTypeGlobal]; 2076 globalDNSAgentList = [self getAgentList:self.floatingDNSAgentList agentType:kAgentTypeDNS agentSubType:kAgentSubTypeGlobal]; 2077 2078 if ([globalProxyAgentList count] == 0 && 2079 [globalDNSAgentList count] == 0) { 2080 ok = [self.controlPolicySession removeAllPolicies]; 2081 if (!ok) { 2082 SC_log(LOG_ERR, "Could not remove policies for agent %@", [agent getAgentName]); 2083 } 2084 2085 ok = [self.controlPolicySession apply]; 2086 if (!ok) { 2087 SC_log(LOG_ERR, "Could not apply policy change for agent %@", [agent getAgentName]); 2088 } 2089 2090 self.controlPolicySession = nil; 2091 SC_log(LOG_NOTICE, "Closed control policy session"); 2092 } 2093 } 2094 2095 ok = YES; 2096 } 2097 2098 return ok; 2099} 2100 2101/* 2102 * Register an agent 2103 */ 2104- (BOOL)registerAgent:(id)agent 2105{ 2106 BOOL ok = NO; 2107 2108 NWNetworkAgentRegistration *registration = [[NWNetworkAgentRegistration alloc] initWithNetworkAgentClass:[agent class]]; 2109 2110 ok = [registration registerNetworkAgent:agent]; 2111 if (!ok) { 2112 SC_log(LOG_NOTICE, "Could not register config agent"); 2113 goto done; 2114 } 2115 2116 [agent addAgentRegistrationObject:registration]; 2117 2118done: 2119 return ok; 2120} 2121 2122/* 2123 * Unregister an agent 2124 */ 2125- (BOOL)unregisterAgent:(id)agent 2126{ 2127 BOOL ok = false; 2128 2129 NWNetworkAgentRegistration *regObject = [agent valueForKey:@"registrationObject"]; 2130 if (regObject != nil) { 2131 ok = [regObject unregisterNetworkAgent]; 2132 if (!ok) { 2133 SC_log(LOG_NOTICE, "Could not unregister config agent"); 2134 } 2135 } else { 2136 SC_log(LOG_NOTICE, "Config Agent not registered. Cannot unregister"); 2137 } 2138 2139 return ok; 2140} 2141 2142 2143@end