]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/controller.m
configd-1109.40.9.tar.gz
[apple/configd.git] / Plugins / IPMonitor / controller.m
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
47 typedef 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)applyPolicies
717 {
718 if (self.controlPolicySession != nil && ![self.controlPolicySession apply]) {
719 SC_log(LOG_ERR, "Failed to apply control policies");
720 }
721 if (self.policySession != nil && ![self.policySession apply]) {
722 SC_log(LOG_ERR, "Failed to apply policies");
723 }
724 }
725
726 - (void)processProxyChanges
727 {
728 CFDictionaryRef proxies;
729
730 proxies = SCDynamicStoreCopyProxiesWithOptions(NULL, NULL);
731 if (proxies == NULL) {
732 SC_log(LOG_INFO, "No proxy information");
733
734 BOOL destroyedAgent = NO;
735 NSMutableDictionary *copy = [self.floatingProxyAgentList copy];
736 for (NSString *entity in copy) {
737 id agent = [copy objectForKey:entity];
738 [self destroyFloatingAgent:agent];
739 destroyedAgent = YES;
740 }
741
742 if (destroyedAgent) {
743 [self applyPolicies];
744 }
745 return;
746 }
747
748 [self processDefaultProxyChanges:proxies];
749 [self processScopedProxyChanges:proxies];
750 [self processSupplementalProxyChanges:proxies];
751 [self processServiceSpecificProxyChanges:proxies];
752
753 [self applyPolicies];
754
755 CFRelease(proxies);
756 }
757
758 /* ========================== DNS agent helpers =========================== */
759 #pragma mark DNS agent helper functions
760
761 - (void)freeResolverList:(resolver_list_t *)resolvers
762 {
763 /* This is a shallow free of resolver_list_t only.
764 * The actual resolver pointers are owned by 'dns_config'
765 */
766 if (resolvers == NULL) {
767 return;
768 }
769
770 if (resolvers->default_resolvers != NULL) {
771 free(resolvers->default_resolvers);
772 }
773 if (resolvers->multicast_resolvers != NULL) {
774 free(resolvers->multicast_resolvers);
775 }
776 if (resolvers->private_resolvers != NULL) {
777 free(resolvers->private_resolvers);
778 }
779
780 free(resolvers);
781 }
782
783 - (resolver_list_t *)copyResolverList:(dns_config_t *)dns_config
784 {
785 resolver_list_t *resolvers = NULL;
786
787 if ((dns_config->n_resolver > 0) && (dns_config->resolver != NULL)) {
788 uint32_t a = 0;
789 uint32_t b = 0;
790 uint32_t c = 0;
791
792 resolvers = calloc(1, sizeof(resolver_list_t));
793 for (int i = 0; i < dns_config->n_resolver; i++) {
794 dns_resolver_t *r = dns_config->resolver[i];
795
796 if ([self isResolverMulticast:r]) {
797 resolvers->n_multicast_resolvers++;
798 continue;
799
800 } else if ([self isResolverPrivate:r]) {
801 resolvers->n_private_resolvers++;
802 continue;
803 }
804
805 // do not consider default resolvers with no nameservers
806 if (r->domain == NULL && r->n_nameserver > 0) {
807 resolvers->n_default_resolvers++;
808 }
809 }
810
811 SC_log(LOG_INFO, "Resolvers: %d default, %d multicast, %d private",
812 resolvers->n_default_resolvers,
813 resolvers->n_multicast_resolvers,
814 resolvers->n_private_resolvers);
815
816 if (resolvers->n_default_resolvers > 0) {
817 resolvers->default_resolvers = calloc(resolvers->n_default_resolvers,
818 sizeof(dns_resolver_t *));
819 }
820 if (resolvers->n_multicast_resolvers > 0) {
821 resolvers->multicast_resolvers = calloc(resolvers->n_multicast_resolvers,
822 sizeof(dns_resolver_t *));
823 }
824 if (resolvers->n_private_resolvers > 0) {
825 resolvers->private_resolvers = calloc(resolvers->n_private_resolvers,
826 sizeof(dns_resolver_t *));
827 }
828
829 for (int i = 0; i < dns_config->n_resolver; i++) {
830 dns_resolver_t *r = dns_config->resolver[i];
831
832 if ([self isResolverMulticast:r] &&
833 (a < resolvers->n_multicast_resolvers)) {
834 resolvers->multicast_resolvers[a++] = r;
835 continue;
836
837 } else if ([self isResolverPrivate:r] &&
838 (b < resolvers->n_private_resolvers)) {
839 resolvers->private_resolvers[b++] = r;
840 continue;
841 }
842
843 if ((r->domain == NULL) &&
844 (r->n_nameserver > 0) &&
845 (c < resolvers->n_default_resolvers)) {
846 resolvers->default_resolvers[c++] = r;
847 }
848 }
849 }
850
851 return resolvers;
852 }
853
854 /*
855 * Generate a data blob for the resolver.
856 * Currently the blob only has:
857 * - nameserver count
858 * - sockaddr structs for each nameserver
859 * - ifindex
860 */
861
862 - (NSData *)dataForResolver:(dns_resolver_t *)resolver
863 {
864 NSData * data = nil;
865 CFMutableDictionaryRef resolverDict = nil;
866
867 if (resolver == NULL) {
868 SC_log(LOG_NOTICE, "Invalid dns resolver");
869 return nil;
870 }
871
872 if (resolver->n_search > 0) {
873 if (resolverDict == nil) {
874 resolverDict = CFDictionaryCreateMutable(NULL,
875 0,
876 &kCFTypeDictionaryKeyCallBacks,
877 &kCFTypeDictionaryValueCallBacks);
878 }
879
880 CFMutableArrayRef searchDomainArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
881
882 /* Append search domains */
883 for (int i = 0; i < resolver->n_search; i++) {
884 CFArrayAppendValue(searchDomainArray, (__bridge CFStringRef)(@(resolver->search[i])));
885 }
886
887 CFDictionaryAddValue(resolverDict, CFSTR(kConfigAgentDNSSearchDomains), searchDomainArray);
888 CFRelease(searchDomainArray);
889 }
890
891 /* Get the count of nameservers */
892 if (resolver->n_nameserver > 0) {
893 if (resolverDict == nil) {
894 resolverDict = CFDictionaryCreateMutable(NULL,
895 0,
896 &kCFTypeDictionaryKeyCallBacks,
897 &kCFTypeDictionaryValueCallBacks);
898 }
899
900 CFMutableArrayRef nameserverArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
901
902 /* Get all the nameservers */
903 for (int i = 0; i < resolver->n_nameserver; i++) {
904 char buf[128] = {0};
905 _SC_sockaddr_to_string(resolver->nameserver[i], buf, sizeof(buf));
906 if (*buf != '\0') {
907 CFArrayAppendValue(nameserverArray, (__bridge CFStringRef)(@(buf)));
908 }
909 }
910
911 CFDictionaryAddValue(resolverDict, CFSTR(kConfigAgentDNSNameServers), nameserverArray);
912 CFRelease(nameserverArray);
913 }
914
915 if (resolverDict != nil) {
916 data = [NSPropertyListSerialization dataWithPropertyList:(__bridge id _Nonnull)(resolverDict)
917 format:NSPropertyListBinaryFormat_v1_0
918 options:0
919 error:nil];
920
921 CFRelease(resolverDict);
922 }
923
924 return (NSData *)data;
925 }
926
927 - (NSData *)getDNSDataFromCurrentConfig:(dns_config_t *)dns_config
928 domain:(NSString *)domain
929 {
930 if (dns_config == NULL || domain == nil) {
931 SC_log(LOG_NOTICE, "Invalid dns_config/domain");
932 return nil;
933 }
934
935 if ((dns_config->n_resolver > 0) && (dns_config->resolver != NULL)) {
936 for (int i = 0; i < dns_config->n_resolver; i++) {
937 dns_resolver_t * resolver;
938
939 resolver = dns_config->resolver[i];
940 if (resolver->domain != NULL &&
941 ![self isResolverMulticast:resolver]) {
942 NSString * ns_domain_name;
943
944 ns_domain_name = @(resolver->domain);
945 if ([ns_domain_name isEqualToString:domain]) {
946 return [self dataForResolver:resolver];
947 } else {
948 continue;
949 }
950 }
951 }
952 }
953
954 return nil;
955 }
956
957 - (BOOL)isResolverMulticast:(dns_resolver_t *)resolver
958 {
959 if (resolver->options == NULL) {
960 return NO;
961 }
962
963 if (!strstr(resolver->options, "mdns")) {
964 return NO;
965 }
966
967 return YES;
968 }
969
970 - (BOOL)isResolverPrivate:(dns_resolver_t *)resolver
971 {
972 if (resolver->options == NULL) {
973 return NO;
974 }
975
976 if (!strstr(resolver->options, "pdns")) {
977 return NO;
978 }
979
980 return YES;
981 }
982
983 - (void)processSupplementalDNSResolvers:(dns_config_t *)dns_config
984 {
985 NSMutableArray * deleteList;
986 NSMutableArray * new_domain_list;
987 NSCountedSet * duplicate_domain_list;
988 NSMutableArray * old_domain_list;
989 NSMutableArray * update_agent_list;
990
991
992 deleteList = [NSMutableArray array];
993 duplicate_domain_list = [[NSCountedSet alloc] initWithCapacity:0];
994 new_domain_list = [NSMutableArray array];
995 update_agent_list = [NSMutableArray array];
996 old_domain_list = [self getAgentList:self.floatingDNSAgentList
997 agentType:kAgentTypeDNS
998 agentSubType:kAgentSubTypeSupplemental];
999
1000 if (dns_config->resolver == NULL) {
1001 dns_config->n_resolver = 0;
1002 }
1003 if (dns_config->n_resolver > 0) {
1004 for (int i = 0; i < dns_config->n_resolver; i++) {
1005 dns_resolver_t * resolver;
1006
1007 resolver = dns_config->resolver[i];
1008 if (resolver->domain != NULL &&
1009 ![self isResolverPrivate:resolver] &&
1010 ![self isResolverMulticast:resolver]) {
1011 NSString * ns_domain_name;
1012
1013 ns_domain_name = [NSString stringWithCString:resolver->domain encoding:NSASCIIStringEncoding];
1014 [new_domain_list addObject:ns_domain_name];
1015 }
1016 }
1017 }
1018
1019 [self cleanConflictingAgentsFromList:old_domain_list
1020 new_list:new_domain_list
1021 agentDictionary:self.floatingDNSAgentList];
1022
1023 /* Sync between controller and current config */
1024 for (NSString *key in old_domain_list) {
1025 BOOL domain_present = NO;
1026
1027 domain_present = [new_domain_list containsObject:key];
1028 if (domain_present == NO) {
1029 id agent;
1030
1031 agent = [self.floatingDNSAgentList objectForKey:key];
1032 [self destroyFloatingAgent:agent];
1033 }
1034 }
1035
1036 /* At this point, whatever is in the controller's floating agent list,
1037 is present in the current DNS config. The current DNS config
1038 might have even more configs, not known to the controller, YET
1039 */
1040
1041 for (NSString *domain in old_domain_list) {
1042 id agent;
1043 id mapped_agent;
1044
1045 agent = [self.floatingDNSAgentList objectForKey:domain];
1046 if (agent == nil) {
1047 continue;
1048 }
1049
1050 /* Am I mapped to some agent? */
1051 mapped_agent = [agent getAgentMapping];
1052 if (mapped_agent) {
1053 /* OK, this agent is mapped to some other agent. We compare this agent's data
1054 * to the current data of the agent to which it is mapped. If different, we destroy
1055 * the agent and later map it to someone else OR spawn a new one.
1056 */
1057 NSData *mapped_agent_data;
1058
1059 mapped_agent_data = [self getDNSDataFromCurrentConfig:dns_config domain:[mapped_agent getAssociatedEntity]];
1060 if (mapped_agent_data == nil || ![[agent getAgentData] isEqual:mapped_agent_data]) {
1061 /* Something changed for mapped agent */
1062 [deleteList addObject:agent];
1063 continue;
1064 }
1065 } else {
1066 /* Since this agent is NOT mapped to any other agent, this agent is
1067 * registered with the kernel. So instead of destroying the agent and
1068 * re-registering it, just update it here.
1069 *
1070 * All the agents which were mapped to this agent, will be deleted and
1071 * re-mapped, if the data changed.
1072 */
1073 NSData *agent_data;
1074
1075 agent_data = [self getDNSDataFromCurrentConfig:dns_config domain:[agent getAssociatedEntity]];
1076 if (![[agent getAgentData] isEqual:agent_data]) {
1077 /* Something changed for agent */
1078 [agent updateAgentData:agent_data];
1079
1080 /* The reason I don't publish the data to agent here is that, if there were
1081 * some agents mapping to this one, they will momentarily have a policy for
1082 * using this agent UUID for some domain based on this agent's previous data.
1083 */
1084 [update_agent_list addObject:agent];
1085
1086 }
1087 }
1088 [new_domain_list removeObject:domain];
1089 }
1090
1091 for (id agent in deleteList) {
1092 SC_log(LOG_INFO, "Destroying agent %@ because something changed!", [agent getAgentName]);
1093 [self destroyFloatingAgent:agent];
1094 }
1095
1096 for (id agent in update_agent_list) {
1097 [self publishToAgent:agent];
1098 }
1099
1100 for (int idx = 0; idx < dns_config->n_resolver; idx++) {
1101 dns_resolver_t * resolver;
1102
1103 resolver = dns_config->resolver[idx];
1104 if (resolver->domain != NULL &&
1105 ![self isResolverPrivate:resolver] &&
1106 ![self isResolverMulticast:resolver]) {
1107 NSData * data;
1108 NSUInteger found;
1109 id mapped_agent;
1110 NSString * ns_domain_name;
1111
1112 ns_domain_name = @(resolver->domain);
1113 found = [new_domain_list indexOfObject:ns_domain_name];
1114 if (found == NSNotFound) {
1115 /* Nothing changed for this agent */
1116 continue;
1117 }
1118
1119 /* We will only process agents which are mapped AND if the agent they were mapped to, changed OR
1120 * agents for domains which we did not know before.
1121 */
1122
1123 NSUInteger domainInstance = [duplicate_domain_list countForObject:ns_domain_name];
1124 if (domainInstance > 0) {
1125 /* domainInstance will be > 0, only if we have conflicting domains */
1126 domainInstance++;
1127 data = [self dataForResolver:resolver];
1128
1129 NSString *ns_domain_name_copy = [NSString stringWithFormat:@"%@" multipleEntitySuffix "%lu", ns_domain_name, (unsigned long)domainInstance];
1130
1131 BOOL ok = [self spawnFloatingAgent:[DNSAgent class]
1132 entity:ns_domain_name_copy
1133 agentSubType:kAgentSubTypeSupplemental
1134 addPolicyOfType:NEPolicyConditionTypeDomain
1135 publishData:data];
1136 if (ok) {
1137 id agent = [self.floatingDNSAgentList objectForKey:ns_domain_name_copy];
1138 SC_log(LOG_INFO, "Duplicate DNS agent %@", [agent getAgentName]);;
1139 }
1140 } else {
1141 data = [self dataForResolver:resolver];
1142 mapped_agent = [self getAgentWithSameDataAndSubType:self.floatingDNSAgentList
1143 data:data
1144 subType:kAgentSubTypeSupplemental];
1145 if (mapped_agent != nil) {
1146 [self spawnMappedFloatingAgent:mapped_agent
1147 entity:ns_domain_name
1148 agentSubType:kAgentSubTypeSupplemental
1149 addPolicyOfType:NEPolicyConditionTypeDomain
1150 updateData:data];
1151 } else {
1152 [self spawnFloatingAgent:[DNSAgent class]
1153 entity:ns_domain_name
1154 agentSubType:kAgentSubTypeSupplemental
1155 addPolicyOfType:NEPolicyConditionTypeDomain
1156 publishData:data];
1157 }
1158 }
1159
1160 [new_domain_list removeObjectAtIndex:found];
1161 [duplicate_domain_list addObject:ns_domain_name];
1162 }
1163 }
1164
1165 return;
1166
1167 }
1168
1169 - (void)processDNSResolvers:(dns_config_t *)dns_config
1170 {
1171 resolver_list_t *resolvers = [self copyResolverList:dns_config];
1172 if (resolvers) {
1173 /* Process Default resolvers */
1174 NSMutableArray *old_default_resolver_list = [self getAgentList:self.floatingDNSAgentList
1175 agentType:kAgentTypeDNS
1176 agentSubType:kAgentSubTypeDefault];
1177
1178 // For default resolvers, their name will be '_defaultDNS', '_defaultDNS #2' so on...
1179 if (resolvers->n_default_resolvers > 0 && resolvers->default_resolvers != NULL) {
1180 for (uint32_t i = 0; i < resolvers->n_default_resolvers; i++) {
1181 dns_resolver_t *default_resolver = resolvers->default_resolvers[i];
1182 NSData * data;
1183 id dnsAgent;
1184 NSString * resolverName;
1185
1186 data = [self dataForResolver:default_resolver];
1187 if (i == 0) {
1188 resolverName = @(dnsAgentDefault);
1189 } else {
1190 resolverName = [NSString stringWithFormat:@dnsAgentDefault multipleEntitySuffix "%d", i+1 ];
1191 }
1192
1193 dnsAgent = [self.floatingDNSAgentList objectForKey:resolverName];
1194
1195 if (dnsAgent != nil) {
1196 [old_default_resolver_list removeObject:resolverName];
1197 if ([data isEqual:[dnsAgent getAgentData]]) {
1198 /* Leave this agent in place. Nothing changed! */
1199 continue;
1200 } else {
1201 [self destroyFloatingAgent:dnsAgent];
1202 }
1203 }
1204
1205 [self spawnFloatingAgent:[DNSAgent class]
1206 entity:resolverName
1207 agentSubType:kAgentSubTypeDefault
1208 addPolicyOfType:NEPolicyConditionTypeNone
1209 publishData:data];
1210 }
1211 }
1212
1213 // Only agents that are NOT present in the new config, will be present in the list
1214 // and they need to be destroyed.
1215 [self deleteAgentList:self.floatingDNSAgentList list:old_default_resolver_list];
1216
1217 /* Process Multicast resolvers */
1218
1219 NSMutableArray *old_multicast_resolver_list = [self getAgentList:self.floatingDNSAgentList
1220 agentType:kAgentTypeDNS
1221 agentSubType:kAgentSubTypeMulticast];
1222
1223 if (resolvers->n_multicast_resolvers > 0 && resolvers->multicast_resolvers != NULL) {
1224 for (uint32_t i = 0; i < resolvers->n_multicast_resolvers; i++) {
1225 dns_resolver_t * multicast_resolver = resolvers->multicast_resolvers[i];
1226 id dnsAgent;
1227 NSString * resolverName;
1228
1229 if (multicast_resolver == NULL) {
1230 continue;
1231 }
1232
1233 if (multicast_resolver->domain == NULL) {
1234 /* Multicast resolvers MUST have a domain */
1235 continue;
1236 }
1237
1238 resolverName = @(multicast_resolver->domain);
1239 if (resolverName == NULL) {
1240 /* Multicast resolvers MUST have a domain */
1241 continue;
1242 }
1243
1244 dnsAgent = [self.floatingDNSAgentList objectForKey:resolverName];
1245 if (dnsAgent != nil) {
1246 [old_multicast_resolver_list removeObject:resolverName];
1247 continue;
1248 }
1249
1250 [self spawnFloatingAgent:[DNSAgent class]
1251 entity:resolverName
1252 agentSubType:kAgentSubTypeMulticast
1253 addPolicyOfType:NEPolicyConditionTypeDomain
1254 publishData:nil];
1255 // Don't care about data for mdns resolvers. Do we?
1256 }
1257 }
1258
1259 [self deleteAgentList:self.floatingDNSAgentList list:old_multicast_resolver_list];
1260
1261 /* Process Private resolvers */
1262
1263 NSMutableArray *old_private_resolver_list = [self getAgentList:self.floatingDNSAgentList
1264 agentType:kAgentTypeDNS
1265 agentSubType:kAgentSubTypePrivate];
1266
1267 if (resolvers->n_private_resolvers > 0 && resolvers->private_resolvers != NULL) {
1268 for (uint32_t i = 0; i < resolvers->n_private_resolvers; i++) {
1269 dns_resolver_t * private_resolver = resolvers->private_resolvers[i];
1270 id dnsAgent;
1271 NSString * resolverName;
1272
1273 if (private_resolver == NULL) {
1274 continue;
1275 }
1276
1277 if (private_resolver->domain == NULL) {
1278 /* private resolvers MUST have a domain */
1279 continue;
1280 }
1281
1282 resolverName = @(private_resolver->domain);
1283 if (resolverName == nil) {
1284 /* Private resolvers MUST have a domain */
1285 continue;
1286 }
1287
1288 dnsAgent = [self.floatingDNSAgentList objectForKey:resolverName];
1289 if (dnsAgent != nil) {
1290 [old_private_resolver_list removeObject:resolverName];
1291 continue;
1292 }
1293
1294 [self spawnFloatingAgent:[DNSAgent class]
1295 entity:resolverName
1296 agentSubType:kAgentSubTypePrivate
1297 addPolicyOfType:NEPolicyConditionTypeDomain
1298 publishData:nil];
1299 // Don't care about data for pdns resolvers. Do we?
1300 }
1301 }
1302
1303 [self deleteAgentList:self.floatingDNSAgentList list:old_private_resolver_list];
1304 }
1305
1306 [self freeResolverList:resolvers];
1307 }
1308
1309 - (void)processScopedDNSResolvers:(dns_config_t *)dns_config
1310 {
1311 NSMutableArray * old_intf_list;
1312 old_intf_list = [self getAgentList:self.floatingDNSAgentList
1313 agentType:kAgentTypeDNS
1314 agentSubType:kAgentSubTypeScoped];
1315
1316 if ((dns_config->n_scoped_resolver > 0) && (dns_config->scoped_resolver != NULL)) {
1317 for (int i = 0; i < dns_config->n_scoped_resolver; i++) {
1318 char buf[IFNAMSIZ];
1319 NSData * data;
1320 id dnsAgent;
1321 NSUInteger idx;
1322 const char * if_name;
1323 NSString * ns_if_name;
1324 NSString * ns_if_name_with_prefix;
1325 dns_resolver_t * resolver;
1326
1327 resolver = dns_config->scoped_resolver[i];
1328 if_name = my_if_indextoname(resolver->if_index, buf);
1329 if (if_name) {
1330 ns_if_name = @(if_name);
1331 ns_if_name_with_prefix = [NSString stringWithFormat:@"%s%@", prefixForInterfaceName, ns_if_name];
1332 } else {
1333 continue;
1334 }
1335
1336 data = [self dataForResolver:resolver];
1337 idx = [old_intf_list indexOfObject:ns_if_name_with_prefix];
1338
1339 if (idx == NSNotFound) {
1340 /* We need to spawn an agent */
1341 [self spawnFloatingAgent:[DNSAgent class]
1342 entity:ns_if_name_with_prefix
1343 agentSubType:kAgentSubTypeScoped
1344 addPolicyOfType:NEPolicyConditionTypeScopedInterface
1345 publishData:data];
1346 continue;
1347 } else {
1348 /* We have an agent on this interface. Update it */
1349 [old_intf_list removeObjectAtIndex:idx];
1350 }
1351
1352 /* Get the DNS agent for this interface? */
1353 dnsAgent = [self.floatingDNSAgentList objectForKey:ns_if_name_with_prefix];
1354 if (dnsAgent != nil) {
1355 /* Do we need to update this agent? */
1356 [dnsAgent updateAgentData:data];
1357 if ([dnsAgent shouldUpdateAgent]) {
1358 [self publishToAgent:dnsAgent];
1359 }
1360 }
1361 }
1362 }
1363
1364 [self deleteAgentList:self.floatingDNSAgentList list:old_intf_list];
1365 }
1366
1367 - (void)processServiceSpecificDNSResolvers:(dns_config_t *)dns_config
1368 {
1369 NSMutableArray * old_service_list;
1370 old_service_list = [self getAgentList:self.floatingDNSAgentList
1371 agentType:kAgentTypeDNS
1372 agentSubType:kAgentSubTypeServiceSpecific];
1373
1374 if ((dns_config->n_service_specific_resolver > 0) && (dns_config->service_specific_resolver != NULL)) {
1375 for (int i = 0; i < dns_config->n_service_specific_resolver; i++) {
1376 NSData * data;
1377 id dnsAgent;
1378 NSUInteger idx;
1379 uint32_t service_identifier;
1380 NSString * ns_service_identifier_with_prefix;
1381 dns_resolver_t * resolver;
1382
1383 resolver = dns_config->service_specific_resolver[i];
1384 service_identifier = resolver->service_identifier;
1385 if (service_identifier != 0) {
1386 ns_service_identifier_with_prefix = [NSString stringWithFormat:@"%s%u", prefixForInterfaceName, service_identifier];
1387 } else {
1388 continue;
1389 }
1390
1391 data = [self dataForResolver:resolver];
1392 idx = [old_service_list indexOfObject:ns_service_identifier_with_prefix];
1393
1394 if (idx == NSNotFound) {
1395 /* We need to spawn an agent */
1396 [self spawnFloatingAgent:[DNSAgent class]
1397 entity:ns_service_identifier_with_prefix
1398 agentSubType:kAgentSubTypeServiceSpecific
1399 addPolicyOfType:(POLICY_TYPE_NO_POLICY) /* Don't install a policy */
1400 publishData:data];
1401 continue;
1402 } else {
1403 /* We have an agent on this interface. Update it */
1404 [old_service_list removeObjectAtIndex:idx];
1405 }
1406
1407 /* Get the DNS agent for this interface? */
1408 dnsAgent = [self.floatingDNSAgentList objectForKey:ns_service_identifier_with_prefix];
1409 if (dnsAgent != nil) {
1410 /* Do we need to update this agent? */
1411 [dnsAgent updateAgentData:data];
1412 if ([dnsAgent shouldUpdateAgent]) {
1413 [self publishToAgent:dnsAgent];
1414 }
1415 }
1416 }
1417 }
1418
1419 [self deleteAgentList:self.floatingDNSAgentList list:old_service_list];
1420 }
1421
1422 #define ONION_RESOLVER_DOMAIN "onion"
1423 - (BOOL)isResolverOnion:(dns_resolver_t *)resolver
1424 {
1425 if (resolver->domain != NULL &&
1426 (strcmp(resolver->domain, ONION_RESOLVER_DOMAIN) == 0)) {
1427 return YES;
1428 }
1429
1430 return NO;
1431 }
1432
1433
1434 - (void)processOnionResolver:(dns_config_t *)dns_config
1435 {
1436 static NSUInteger policy_id = 0;
1437
1438 if (dns_config == NULL) {
1439 goto remove_policy;
1440 }
1441
1442 /* Run through the resolver configurations. We only care for the supplemental resolvers. */
1443 for (int32_t i = 0; i < dns_config->n_resolver; i++) {
1444 dns_resolver_t *resolver = dns_config->resolver[i];
1445 if ([self isResolverOnion:resolver]) {
1446 goto remove_policy;
1447 }
1448 }
1449
1450 /* We do not have any such resolver. Add a system-wide "drop" policy for this domain */
1451 if (policy_id == 0) {
1452 NEPolicy *policy = [[NEPolicy alloc] initWithOrder:INIT_ORDER_FOR_DOMAIN_POLICY
1453 result:[NEPolicyResult drop]
1454 conditions:@[[NEPolicyCondition domain:@ONION_RESOLVER_DOMAIN]]];
1455 if (policy != nil) {
1456 policy_id = [self.policySession addPolicy:policy];
1457 if (![self.policySession apply]) {
1458 policy_id = 0;
1459 SC_log(LOG_NOTICE, "Could not add a [." ONION_RESOLVER_DOMAIN "] drop policy");
1460 } else {
1461 SC_log(LOG_INFO, "Added a [." ONION_RESOLVER_DOMAIN "] drop policy");
1462 }
1463 }
1464 }
1465
1466 return;
1467
1468 remove_policy:
1469
1470 /* We have such a resolver in the config OR no DNS config at all. Remove the system-wide "drop" policy for this domain */
1471 if (policy_id > 0) {
1472 [self.policySession removePolicyWithID:policy_id];
1473 if (![self.policySession apply]) {
1474 SC_log(LOG_NOTICE, "Could not remove the [." ONION_RESOLVER_DOMAIN "] drop policy");
1475 } else {
1476 policy_id = 0;
1477 SC_log(LOG_INFO, "Removed the [." ONION_RESOLVER_DOMAIN "] drop policy");
1478 }
1479 }
1480
1481 return;
1482 }
1483 #undef ONION_RESOLVER_DOMAIN
1484
1485
1486 - (void)processDNSChanges
1487 {
1488 dns_config_t * dns_config;
1489
1490 dns_config = dns_configuration_copy();
1491 if (dns_config == NULL) {
1492 SC_log(LOG_INFO, "No DNS configuration");
1493 NSMutableDictionary *copy = [self.floatingDNSAgentList copy];
1494 for (NSString *entity in copy) {
1495 id agent = [copy objectForKey:entity];
1496
1497 [self destroyFloatingAgent:agent];
1498 }
1499 goto done;
1500 }
1501
1502 [self processDNSResolvers:dns_config];
1503 [self processScopedDNSResolvers:dns_config];
1504 [self processSupplementalDNSResolvers:dns_config];
1505 [self processServiceSpecificDNSResolvers:dns_config];
1506
1507 done:
1508
1509 [self processOnionResolver:dns_config];
1510 [self applyPolicies];
1511
1512 if (dns_config != NULL) {
1513 dns_configuration_free(dns_config);
1514 }
1515 }
1516
1517 #pragma mark Helper functions
1518
1519 - (const void *)copyConfigAgentData:(NSMutableDictionary *)controllerDict
1520 uuid:(uuid_t)requested_uuid
1521 length:(uint64_t *)length
1522 {
1523 if (length == NULL) {
1524 SC_log(LOG_NOTICE, "Invalid parameters for copying agent data");
1525 return NULL;
1526 }
1527
1528 id agent = nil;
1529 void *buffer = NULL;
1530 *length = 0;
1531
1532 for (NSString *key in controllerDict) {
1533 id temp_agent = [controllerDict objectForKey:key];
1534
1535 uuid_t agent_uuid;
1536
1537 [[temp_agent getAgentUUID] getUUIDBytes:agent_uuid];
1538 if (uuid_compare(agent_uuid, requested_uuid) == 0) {
1539 agent = temp_agent;
1540 break;
1541 }
1542 }
1543
1544 if (agent == nil) {
1545 uuid_string_t uuid_str;
1546 uuid_unparse(requested_uuid, uuid_str);
1547 SC_log(LOG_NOTICE, "Invalid config agent uuid %s specified", uuid_str);
1548 return NULL;
1549 }
1550
1551 NSData *data = [agent getAgentData];
1552 uint64_t len = [data length];
1553 if (len > 0) {
1554 *length = len;
1555 buffer = malloc((size_t)len);
1556 memcpy(buffer, [data bytes], len);
1557 }
1558
1559 return (const void *)buffer;
1560 }
1561
1562 - (const void *)copyProxyAgentData:(uuid_t)requested_uuid
1563 length:(uint64_t *)length
1564 {
1565 return [self copyConfigAgentData:self.floatingProxyAgentList
1566 uuid:requested_uuid
1567 length:length];
1568 }
1569
1570 - (const void *)copyDNSAgentData:(uuid_t)requested_uuid
1571 length:(uint64_t *)length
1572 {
1573 return [self copyConfigAgentData:self.floatingDNSAgentList
1574 uuid:requested_uuid
1575 length:length];
1576 }
1577
1578 - (NSData *)dataLengthSanityCheck:(id)agent
1579 {
1580 NSData * data = [agent getAgentData];
1581
1582 if ([data length] > CONFIG_AGENT_DATA_LIMIT) {
1583 /* We impose a limit on the config agent data as 1KB.
1584 * If we have a data blob larger than this limit, do NOT publish it into the agent.
1585 * Instead publish a key which will trigger fetching of the configuration directly
1586 * through NWI server.
1587 */
1588 NSMutableDictionary *data_dict = [NSMutableDictionary dictionary];
1589
1590 NSUUID *uuid = [agent getAgentUUID];
1591 uuid_t c_uuid;
1592 [uuid getUUIDBytes:c_uuid];
1593 NSData *uuid_data = [[NSData alloc] initWithBytes:c_uuid length:sizeof(c_uuid)];
1594 [data_dict setValue:uuid_data forKey:@kConfigAgentOutOfBandDataUUID];
1595
1596 NSData *new_data = [NSPropertyListSerialization dataWithPropertyList:data_dict
1597 format:NSPropertyListBinaryFormat_v1_0
1598 options:0
1599 error:nil];
1600
1601 return new_data;
1602 }
1603
1604 return nil;
1605 }
1606
1607 /*
1608 * For conflicting agents, the convention is that its name & entity,
1609 * will have a suffix " #<number>". This function will sanitize the
1610 * suffix and just return the entity name
1611 */
1612 - (NSString *)sanitizeEntity:(NSString *)entity
1613 {
1614 NSRange range = [entity rangeOfString:@multipleEntitySuffix];
1615 if (range.location != NSNotFound) {
1616 NSString *str = [entity substringToIndex:range.location];
1617 return str;
1618 }
1619
1620 return entity;
1621 }
1622
1623 /*
1624 * For interface names, there is a prefix to differentiate then
1625 * from the domain name (iff there were conflicting domain names).
1626 * Returns the sanitized interface name
1627 */
1628 - (NSString *)sanitizeInterfaceName:(NSString *)intf
1629 {
1630 NSRange range = [intf rangeOfString:@prefixForInterfaceName];
1631 if (range.location != NSNotFound) {
1632 NSString *str = [intf substringFromIndex:(range.location + strlen(prefixForInterfaceName))];
1633 return str;
1634 }
1635
1636 return intf;
1637 }
1638
1639 /*
1640 * For conflicting agents, the convention is that its name & entity,
1641 * will have a suffix " #<number>". This function will return that <number>
1642 */
1643 - (int)entityInstanceNumber:(NSString *)entity
1644 {
1645 NSRange range = [entity rangeOfString:@multipleEntitySuffix];
1646 if (range.location != NSNotFound) {
1647 NSString *str = [entity substringFromIndex:(range.location + strlen(multipleEntitySuffix))];
1648 return str.intValue;
1649 }
1650
1651 return 0;
1652 }
1653
1654 /*
1655 * In case that we have conflicting DNS/Proxy domains
1656 * This function will remove all those conflicting agents,
1657 * so that we can start afresh with the new config
1658 */
1659 - (void)cleanConflictingAgentsFromList:(NSMutableArray *)old_list
1660 new_list:(NSMutableArray *)new_list
1661 agentDictionary:(NSMutableDictionary *)agent_list
1662 {
1663 NSCountedSet * duplicate_domain_list;
1664
1665 for (NSString *domain in old_list) {
1666 /* If we had conflicting domains before, remove all of them */
1667 NSString *sanitizedDomain = [self sanitizeEntity:domain];
1668 if (![sanitizedDomain isEqualToString:domain]) {
1669 /* Destroy the original domain */
1670 id agent = [agent_list objectForKey:sanitizedDomain];
1671 [self destroyFloatingAgent:agent];
1672
1673 /* Destroy the conflicting domain */
1674 agent = [agent_list objectForKey:domain];
1675 [self destroyFloatingAgent:agent];
1676
1677 SC_log(LOG_INFO, "Removing conflicting domain: %@, %@", sanitizedDomain, domain);
1678 }
1679 }
1680
1681 duplicate_domain_list = [[NSCountedSet alloc] initWithArray:new_list];
1682 for (NSString *domain in old_list) {
1683 if ([duplicate_domain_list countForObject:domain] > 1) {
1684 id agent = [agent_list objectForKey:domain];
1685 [self destroyFloatingAgent:agent];
1686 SC_log(LOG_INFO, "Removing domain %@ as it has duplicates in the current config", domain);
1687 }
1688 }
1689 }
1690
1691 /*
1692 * Get the list of agents from a specific dictionary.
1693 * The list of agents will only consist of the ones which
1694 * match the agent type and sub-type
1695 */
1696
1697 - (NSMutableArray *)getAgentList:(NSMutableDictionary *)all_agents
1698 agentType:(AgentType)type
1699 agentSubType:(AgentSubType)subtype
1700 {
1701 NSMutableArray *list = [NSMutableArray array];
1702 NSArray *agentObjects = [all_agents allValues];
1703
1704 for (id agent in agentObjects) {
1705 if (([agent getAgentType] == type) &&
1706 ([agent getAgentSubType] == subtype)) {
1707
1708 [list addObject:[agent getAssociatedEntity]];
1709 }
1710 }
1711
1712 return list;
1713 }
1714
1715 /*
1716 * Destroy all the agents are listed in "list"
1717 */
1718
1719 - (void)deleteAgentList:(NSMutableDictionary *)all_agents
1720 list:(NSMutableArray *)list
1721 {
1722 for (NSString *intf in list) {
1723 id agent;
1724
1725 agent = [all_agents objectForKey:intf];
1726 [self destroyFloatingAgent:agent];
1727 }
1728 }
1729
1730 /*
1731 * In order to not duplicate agents with same content,
1732 * we map an agent X to agent Y, when their content is the same.
1733 *
1734 * This function tries to find that agent Y
1735 */
1736
1737 - (id)getAgentWithSameDataAndSubType:(NSMutableDictionary *)agentList
1738 data:(NSData *)data
1739 subType:(AgentSubType)subtype
1740 {
1741 for (NSString *key in agentList) {
1742 id agent = [agentList objectForKey:key];
1743 if ([[agent getAgentData] isEqual:data]) {
1744 /* Do not map to default agents */
1745 if ([agent getAgentSubType] != subtype) {
1746 continue;
1747 }
1748
1749 /* Return only registered agents */
1750 if ([agent getRegistrationObject] != nil) {
1751 return agent;
1752 }
1753 }
1754 }
1755
1756 return nil;
1757 }
1758
1759 #pragma mark Policy installation function
1760
1761 /*
1762 * Add NECP policies for an agent
1763 */
1764 - (BOOL)addPolicyToFloatingAgent:(id)agent
1765 domain:(NSString *)domain
1766 agentUUIDToUse:(NSUUID *)uuid
1767 policyType:(NEPolicyConditionType)policyType
1768 useControlPolicySession:(BOOL)useControlPolicySession
1769 {
1770 NEPolicyCondition * condition = nil;
1771 NEPolicySession * session;
1772 uint32_t multiple_entity_offset;
1773 NEPolicy * newPolicy;
1774 uint32_t order;
1775 uint32_t orderForSkip;
1776 NSMutableArray * policyArray;
1777 NSUInteger policyID1;
1778 NSUInteger policyID2;
1779 NEPolicyResult * result;
1780 uint32_t skipOrder;
1781 AgentType type;
1782 uint32_t typeOffset;
1783
1784 type = [agent getAgentType];
1785 typeOffset = (type == kAgentTypeDNS) ? 0 : 5000;
1786 skipOrder = (type == kAgentTypeDNS) ? 5000 : 0;
1787
1788 multiple_entity_offset = (uint32_t)[self entityInstanceNumber:domain];
1789 domain = [self sanitizeEntity:domain];
1790
1791 switch (policyType) {
1792 case NEPolicyConditionTypeScopedInterface:
1793 order = INIT_ORDER_FOR_SCOPED_INTERFACE_POLICY + typeOffset + multiple_entity_offset;
1794 domain = [self sanitizeInterfaceName:domain];
1795 condition = [NEPolicyCondition scopedInterface:domain];
1796 orderForSkip = SKIP_ORDER_FOR_SCOPED_INTERFACE_POLICY + typeOffset;
1797 break;
1798
1799 case NEPolicyConditionTypeDomain:
1800 order = INIT_ORDER_FOR_DOMAIN_POLICY + typeOffset + multiple_entity_offset;
1801 condition = [NEPolicyCondition domain:domain];
1802 orderForSkip = SKIP_ORDER_FOR_DOMAIN_POLICY + typeOffset;
1803 break;
1804
1805 case NEPolicyConditionTypeAllInterfaces:
1806 order = INIT_ORDER_FOR_DEFAULT_POLICY + typeOffset + multiple_entity_offset;
1807 condition = [NEPolicyCondition allInterfaces];
1808 orderForSkip = SKIP_ORDER_FOR_DEFAULT_POLICY + typeOffset;
1809 break;
1810
1811 case NEPolicyConditionTypeNone:
1812 order = INIT_ORDER_FOR_DEFAULT_POLICY + typeOffset + multiple_entity_offset;
1813 orderForSkip = SKIP_ORDER_FOR_DEFAULT_POLICY + typeOffset;
1814 break;
1815
1816 default:
1817 SC_log(LOG_NOTICE, "Invalid policy condition specified");
1818 return NO;
1819 }
1820
1821 result = [NEPolicyResult netAgentUUID:uuid];
1822 newPolicy = [[NEPolicy alloc] initWithOrder:order
1823 result:result
1824 conditions: (condition ? @[condition] : nil)];
1825
1826 if (newPolicy == nil) {
1827 SC_log(LOG_NOTICE, "Could not create a policy for agent %@", [agent getAgentName]);
1828 return NO;
1829 }
1830
1831 if (useControlPolicySession) {
1832 if (self.controlPolicySession == nil) {
1833 /* The NE policy session at "control" level for the controller */
1834 self.controlPolicySession = [self createPolicySession];
1835 if (self.controlPolicySession == nil) {
1836 SC_log(LOG_NOTICE, "Could not create a control policy session for agent %@", [agent getAgentName]);
1837 return NO;
1838 }
1839 [self.controlPolicySession setPriority:NEPolicySessionPriorityControl];
1840 }
1841 ((ConfigAgent *)agent).preferredPolicySession = self.controlPolicySession;
1842 } else {
1843 ((ConfigAgent *)agent).preferredPolicySession = self.policySession;
1844 }
1845
1846 session = ((ConfigAgent *)agent).preferredPolicySession;
1847
1848 policyID1 = [session addPolicy:newPolicy];
1849 if (policyID1 == 0) {
1850 SC_log(LOG_NOTICE, "Could not add a netagent policy for agent %@", [agent getAgentName]);
1851 return NO;
1852 }
1853
1854 result = [NEPolicyResult skipWithOrder:skipOrder];
1855 newPolicy = [[NEPolicy alloc] initWithOrder:orderForSkip
1856 result:result
1857 conditions:(condition ? @[condition] : nil)];
1858
1859 if (newPolicy == nil) {
1860 SC_log(LOG_NOTICE, "Could not create a policy for agent %@", [agent getAgentName]);
1861 return NO;
1862 }
1863
1864 policyID2 = [session addPolicy:newPolicy];
1865 if (policyID2 == 0) {
1866 SC_log(LOG_NOTICE, "Could not add a skip policy for agent %@", [agent getAgentName]);
1867 return NO;
1868 }
1869
1870 policyArray = [self.policyDB objectForKey:[agent getAgentName]];
1871 if (policyArray == nil) {
1872 policyArray = [NSMutableArray array];
1873 }
1874
1875 [policyArray addObject:numberToNSNumber(policyID1)];
1876 [policyArray addObject:numberToNSNumber(policyID2)];
1877 [self.policyDB setObject:policyArray forKey:[agent getAgentName]];
1878
1879 return YES;
1880 }
1881
1882 #pragma mark Agent manipulation functions
1883
1884 /*
1885 * Create an agent
1886 */
1887 - (BOOL)spawnFloatingAgent:(Class)agentClass
1888 entity:(NSString *)entity
1889 agentSubType:(AgentSubType)subtype
1890 addPolicyOfType:(NEPolicyConditionType)policyType
1891 publishData:(NSData *)data
1892 {
1893 id agent;
1894 BOOL ok;
1895 NSMutableDictionary * parameters;
1896
1897 parameters =[NSMutableDictionary dictionary];
1898 [parameters setValue:entity forKey:@kEntityName];
1899 [parameters setValue:numberToNSNumber(subtype) forKey:@kAgentSubType];
1900
1901 agent = [[agentClass alloc] initWithParameters:parameters];
1902 ok = [self registerAgent:agent];
1903 if (!ok) {
1904 return NO;
1905 }
1906
1907 if (data) {
1908 /* Since we just spawned this agent, update its data */
1909 [agent updateAgentData:data];
1910 [self publishToAgent:agent];
1911 }
1912
1913 /* Add a policy if there is a valid type. If POLICY_TYPE_NO_POLICY, then ignore policies.
1914 * POLICY_TYPE_NO_POLICY will be set for service-specific agents, in which case we rely on
1915 * service owners to install custom policies to point at the agents. */
1916 if (policyType >= NEPolicyConditionTypeNone) {
1917 BOOL useControlPolicySession = NO;
1918 if (subtype == kAgentSubTypeGlobal) {
1919 /* Policies for a Global scoped agents are at "control" level */
1920 useControlPolicySession = YES;
1921 }
1922
1923 ok = [self addPolicyToFloatingAgent:agent
1924 domain:entity
1925 agentUUIDToUse:[agent agentUUID]
1926 policyType:policyType
1927 useControlPolicySession:useControlPolicySession];
1928
1929 if (!ok) {
1930 [self unregisterAgent:agent];
1931 return NO;
1932 }
1933 }
1934
1935 SC_log(LOG_INFO, "Spawning floating agent for %@", entity);
1936
1937 if ([agent getAgentType] == kAgentTypeProxy) {
1938 [self.floatingProxyAgentList setObject:agent forKey:entity];
1939 } else {
1940 [self.floatingDNSAgentList setObject:agent forKey:entity];
1941 }
1942
1943 return ok;
1944 }
1945
1946 /*
1947 * Create an agent mapped to another agent.
1948 */
1949 - (BOOL)spawnMappedFloatingAgent:(id)mapped_agent
1950 entity:(NSString *)entity
1951 agentSubType:(AgentSubType)subtype
1952 addPolicyOfType:(NEPolicyConditionType)policyType
1953 updateData:(NSData *)data
1954 {
1955 id dummyAgent;
1956 NSMutableDictionary * parameters;
1957
1958 parameters = [NSMutableDictionary dictionary];
1959 [parameters setValue:entity forKey:@kEntityName];
1960 [parameters setValue:numberToNSNumber(subtype) forKey:@kAgentSubType];
1961
1962 dummyAgent = [[[mapped_agent class] alloc] initWithParameters:parameters];
1963
1964 if (data) {
1965 /* Since we just spawned this agent, update its data.
1966 * We do not publish it since this agent is mapped
1967 * to an agent which already has the same data
1968 */
1969 [dummyAgent updateAgentData:data];
1970 }
1971
1972 BOOL useControlPolicySession = NO;
1973 if (subtype == kAgentSubTypeGlobal) {
1974 /* Policies for a Global scoped agents are at "control" level */
1975 useControlPolicySession = YES;
1976 }
1977
1978 BOOL ok = [self addPolicyToFloatingAgent:dummyAgent
1979 domain:entity
1980 agentUUIDToUse:[mapped_agent agentUUID]
1981 policyType:policyType
1982 useControlPolicySession:useControlPolicySession];
1983
1984 if (!ok) {
1985 return NO;
1986 }
1987
1988 if ([mapped_agent getAgentType] == kAgentTypeProxy) {
1989 [self.floatingProxyAgentList setObject:dummyAgent forKey:entity];
1990 } else {
1991 [self.floatingDNSAgentList setObject:dummyAgent forKey:entity];
1992 }
1993
1994 [dummyAgent setAgentMapping:mapped_agent];
1995
1996 SC_log(LOG_INFO, "Mapped floating agent %@ to %@", [dummyAgent getAgentName], [mapped_agent getAgentName]);
1997 return YES;
1998 }
1999
2000 /*
2001 * Write into an agent
2002 */
2003 - (BOOL)publishToAgent:(id)agent
2004 {
2005 /* Before any data goes into the kernel, do a sanity check. */
2006 NSData *sanityCheckData = [self dataLengthSanityCheck:agent];
2007 NSData *tempAgentData = nil;
2008
2009 if (sanityCheckData != nil) {
2010 /* Data length is more than the limit! for updateNetworkAgent, the data blob
2011 * has to be a part of the agent object. Thus the temporary data replacement!
2012 */
2013 tempAgentData = [[agent getAgentData] copy];
2014 [agent updateAgentData:sanityCheckData];
2015 SC_log(LOG_NOTICE, "Data too large for %@ (%lu bytes)!", [agent getAgentName], (unsigned long)[tempAgentData length]);
2016 }
2017
2018 BOOL ok = NO;
2019
2020 NWNetworkAgentRegistration *regObject = [agent valueForKey:@"registrationObject"];
2021 if (regObject != nil) {
2022 SC_log(LOG_NOTICE, "Publishing data to agent %@ (%lu bytes)", [agent getAgentName], (unsigned long)[[agent getAgentData] length]);
2023 ok = [regObject updateNetworkAgent:agent];
2024 if (!ok) {
2025 SC_log(LOG_NOTICE, "Could not update config agent");
2026 }
2027 } else {
2028 SC_log(LOG_NOTICE, "Config Agent not registered. Cannot Update");
2029 }
2030
2031 if (tempAgentData != nil) {
2032 [agent updateAgentData:tempAgentData];
2033 }
2034
2035 return ok;
2036 }
2037
2038 /*
2039 * Destroy an agent
2040 */
2041 - (BOOL)destroyFloatingAgent:(id)agent
2042 {
2043 BOOL ok = NO;
2044
2045 if ( agent != nil) {
2046 NSMutableArray * policyArray;
2047
2048 policyArray = [self.policyDB objectForKey:[agent getAgentName]];
2049 if (policyArray != nil) {
2050 NEPolicySession * session = ((ConfigAgent *)agent).preferredPolicySession;
2051 BOOL result = NO;
2052
2053 for (NSNumber *policyID in policyArray) {
2054 NSUInteger idVal;
2055
2056 idVal = [policyID unsignedIntegerValue];
2057 result = [session removePolicyWithID:idVal];
2058 if (result == NO) {
2059 SC_log(LOG_NOTICE, "Could not remove policy %@ for agent %@", [session policyWithID:idVal], [agent getAgentName]);
2060 }
2061 }
2062
2063 [self.policyDB removeObjectForKey:[agent getAgentName]];
2064 }
2065
2066 if ([agent getAgentType] == kAgentTypeProxy) {
2067 [self.floatingProxyAgentList removeObjectForKey:[agent getAssociatedEntity]];
2068 } else {
2069 [self.floatingDNSAgentList removeObjectForKey:[agent getAssociatedEntity]];
2070 }
2071
2072 if ([agent getRegistrationObject] != nil) {
2073 [self unregisterAgent:agent];
2074 }
2075
2076 SC_log(LOG_INFO, "X - Destroyed agent %@", [agent getAgentName]);
2077
2078 /* Check if we need to close the "control" policy session */
2079 if (self.controlPolicySession != nil) {
2080 NSMutableArray *globalProxyAgentList;
2081 NSMutableArray *globalDNSAgentList;
2082 globalProxyAgentList = [self getAgentList:self.floatingProxyAgentList agentType:kAgentTypeProxy agentSubType:kAgentSubTypeGlobal];
2083 globalDNSAgentList = [self getAgentList:self.floatingDNSAgentList agentType:kAgentTypeDNS agentSubType:kAgentSubTypeGlobal];
2084
2085 if ([globalProxyAgentList count] == 0 &&
2086 [globalDNSAgentList count] == 0) {
2087 ok = [self.controlPolicySession removeAllPolicies];
2088 if (!ok) {
2089 SC_log(LOG_ERR, "Could not remove policies for agent %@", [agent getAgentName]);
2090 }
2091
2092 self.controlPolicySession = nil;
2093 SC_log(LOG_NOTICE, "Closed control policy session");
2094 }
2095 }
2096
2097 ok = YES;
2098 }
2099
2100 return ok;
2101 }
2102
2103 /*
2104 * Register an agent
2105 */
2106 - (BOOL)registerAgent:(id)agent
2107 {
2108 BOOL ok = NO;
2109
2110 NWNetworkAgentRegistration *registration = [[NWNetworkAgentRegistration alloc] initWithNetworkAgentClass:[agent class]];
2111
2112 ok = [registration registerNetworkAgent:agent];
2113 if (!ok) {
2114 SC_log(LOG_NOTICE, "Could not register config agent");
2115 goto done;
2116 }
2117
2118 [agent addAgentRegistrationObject:registration];
2119
2120 done:
2121 return ok;
2122 }
2123
2124 /*
2125 * Unregister an agent
2126 */
2127 - (BOOL)unregisterAgent:(id)agent
2128 {
2129 BOOL ok = false;
2130
2131 NWNetworkAgentRegistration *regObject = [agent valueForKey:@"registrationObject"];
2132 if (regObject != nil) {
2133 ok = [regObject unregisterNetworkAgent];
2134 if (!ok) {
2135 SC_log(LOG_NOTICE, "Could not unregister config agent");
2136 }
2137 } else {
2138 SC_log(LOG_NOTICE, "Config Agent not registered. Cannot unregister");
2139 }
2140
2141 return ok;
2142 }
2143
2144
2145 @end