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