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