]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/nat64-configuration.c
configd-1061.0.2.tar.gz
[apple/configd.git] / Plugins / IPMonitor / nat64-configuration.c
1 /*
2 * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * April 17, 2017 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include "nat64-configuration.h"
33
34 #include <TargetConditionals.h>
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <SystemConfiguration/SystemConfiguration.h>
37 #include <SystemConfiguration/SCPrivate.h>
38 #if TEST_NAT64_CONFIGURATION
39 static Boolean G_set_prefixes_force_failure;
40 #define my_if_nametoindex if_nametoindex
41 #else
42 #include "ip_plugin.h"
43 #endif
44
45 #define INET6 1
46
47 #include <string.h>
48 #include <net/if.h>
49 #include <sys/ioctl.h>
50 #include <sys/socket.h>
51 #include <sys/sockio.h>
52 #include <netinet/in.h>
53 #include <nw/private.h>
54 #include <sys/queue.h>
55
56
57 /**
58 ** Support functions
59 **/
60 static dispatch_queue_t
61 nat64_dispatch_queue(void)
62 {
63 static dispatch_once_t once;
64 static dispatch_queue_t q;
65
66 dispatch_once(&once, ^{
67 q = dispatch_queue_create("nat64 prefix request queue", NULL);
68 });
69
70 return q;
71 }
72
73 static Boolean
74 _nat64_prefix_set(const char *if_name,
75 int32_t num_prefixes,
76 nw_nat64_prefix_t *prefixes)
77 {
78 struct if_nat64req req;
79 int ret;
80 int s;
81
82 // pass NAT64 prefixes to the kernel
83 memset(&req, 0, sizeof(req));
84 strlcpy(req.ifnat64_name, if_name, sizeof(req.ifnat64_name));
85
86 if (num_prefixes == 0) {
87 SC_log(LOG_NOTICE, "%s: nat64 prefix unavailable", if_name);
88 }
89
90 for (int32_t i = 0; i < num_prefixes; i++) {
91 char prefix_str[NW_NAT64_PREFIX_STR_LENGTH] = {0};
92
93 nw_nat64_write_prefix_to_string(&prefixes[i], prefix_str, sizeof(prefix_str));
94 SC_log(LOG_NOTICE, "%s: nat64 prefix[%d] = %s", if_name, i, prefix_str);
95
96 if (i < NAT64_MAX_NUM_PREFIXES) {
97 req.ifnat64_prefixes[i].prefix_len = prefixes[i].length;
98 memcpy(&req.ifnat64_prefixes[i].ipv6_prefix,
99 &prefixes[i].data,
100 MIN(sizeof(req.ifnat64_prefixes[i].ipv6_prefix), sizeof(prefixes[i].data))); // MIN(16, 12)
101 }
102 }
103
104 s = socket(AF_INET, SOCK_DGRAM, 0);
105 if (s == -1) {
106 SC_log(LOG_ERR, "socket() failed: %s", strerror(errno));
107 return (FALSE);
108 }
109 ret = ioctl(s, SIOCSIFNAT64PREFIX, &req);
110 close(s);
111 if (ret == -1) {
112 if ((errno != ENOENT) || (num_prefixes != 0)) {
113 SC_log(LOG_ERR, "%s: ioctl(SIOCSIFNAT64PREFIX) failed: %s", if_name, strerror(errno));
114 }
115 return (FALSE);
116 }
117
118 SC_log(LOG_NOTICE, "%s: nat64 prefix%s updated", if_name, (num_prefixes != 1) ? "es" : "");
119 return (TRUE);
120 }
121
122
123 static void
124 _nat64_prefix_post(CFStringRef interface,
125 int32_t num_prefixes,
126 nw_nat64_prefix_t *prefixes,
127 CFAbsoluteTime start_time)
128 {
129 #if TEST_NAT64_CONFIGURATION
130 #pragma unused(interface)
131 #pragma unused(num_prefixes)
132 #pragma unused(prefixes)
133 #pragma unused(start_time)
134 return;
135 #else /* TEST_NAT64_CONFIGURATION */
136
137 CFStringRef key;
138
139 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
140 kSCDynamicStoreDomainState,
141 interface,
142 kSCEntNetNAT64);
143 if (num_prefixes >= 0) {
144 CFDateRef date;
145 CFMutableDictionaryRef plat_dict;
146
147 plat_dict = CFDictionaryCreateMutable(NULL,
148 0,
149 &kCFTypeDictionaryKeyCallBacks,
150 &kCFTypeDictionaryValueCallBacks);
151 /* prefixes (if available) */
152 if (num_prefixes > 0) {
153 CFMutableArrayRef prefix_array;
154
155 prefix_array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
156 for (int32_t i = 0; i < num_prefixes; i++) {
157 char prefix_str[NW_NAT64_PREFIX_STR_LENGTH] = {0};
158 CFStringRef str;
159
160 nw_nat64_write_prefix_to_string(&prefixes[i], prefix_str, sizeof(prefix_str));
161 str = CFStringCreateWithCString(NULL, prefix_str, kCFStringEncodingASCII);
162 CFArrayAppendValue(prefix_array, str);
163 CFRelease(str);
164 }
165 CFDictionarySetValue(plat_dict, kSCPropNetNAT64PrefixList, prefix_array);
166 CFRelease(prefix_array);
167 }
168 /* start time */
169 date = CFDateCreate(NULL, start_time);
170 CFDictionarySetValue(plat_dict,
171 kSCPropNetNAT64PLATDiscoveryStartTime,
172 date);
173 CFRelease(date);
174
175 /* completion time */
176 date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
177 CFDictionarySetValue(plat_dict,
178 kSCPropNetNAT64PLATDiscoveryCompletionTime,
179 date);
180 CFRelease(date);
181
182 (void)SCDynamicStoreSetValue(NULL, key, plat_dict);
183 SC_log(LOG_NOTICE, "%@: PLAT discovery complete %@",
184 interface, plat_dict);
185 CFRelease(plat_dict);
186 } else {
187 (void)SCDynamicStoreRemoveValue(NULL, key);
188 }
189 CFRelease(key);
190 #endif /* TEST_NAT64_CONFIGURATION */
191 return;
192 }
193
194 static nw_nat64_prefixes_resolver_t
195 _nat64_resolver_create(unsigned int if_index)
196 {
197 nw_interface_t interface;
198 nw_parameters_t params;
199 nw_nat64_prefixes_resolver_t resolver;
200
201 params = nw_parameters_create();
202 interface = nw_interface_create_with_index(if_index);
203 if (interface == NULL) {
204 SC_log(LOG_NOTICE,
205 "nw_interface_create_with_index(%u) failed",
206 if_index);
207 return (NULL);
208 }
209 nw_parameters_require_interface(params, interface);
210 nw_parameters_set_required_address_family(params, AF_INET6);
211 nw_release(interface);
212 resolver = nw_nat64_prefixes_resolver_create(params);
213 nw_release(params);
214 return (resolver);
215 }
216
217 /**
218 ** NAT64PrefixRequest
219 **/
220 struct NAT64PrefixRequest;
221 typedef struct NAT64PrefixRequest NAT64PrefixRequest, * NAT64PrefixRequestRef;
222 #define NAT64PrefixRequest_LIST_ENTRY LIST_ENTRY(NAT64PrefixRequest)
223 #define NAT64PrefixRequest_LIST_HEAD LIST_HEAD(NAT64PrefixRequestHead, \
224 NAT64PrefixRequest)
225 static NAT64PrefixRequest_LIST_HEAD S_request_head;
226 static struct NAT64PrefixRequestHead * S_request_head_p = &S_request_head;
227
228 typedef CF_ENUM(uint16_t, RequestFlags) {
229 kRequestFlagsNone = 0x0000,
230 kRequestFlagsValid = 0x0001,
231 };
232
233 struct NAT64PrefixRequest {
234 NAT64PrefixRequest_LIST_ENTRY link;
235 nw_nat64_prefixes_resolver_t resolver;
236 const char * if_name;
237 CFStringRef if_name_cf;
238 unsigned int if_index;
239 unsigned int retain_count;
240 RequestFlags flags;
241 };
242
243 static Boolean
244 NAT64PrefixRequestFlagsIsSet(NAT64PrefixRequestRef request, RequestFlags flags)
245 {
246 return ((request->flags & flags) != 0);
247 }
248
249 static void
250 NAT64PrefixRequestFlagsSet(NAT64PrefixRequestRef request, RequestFlags flags)
251 {
252 request->flags |= flags;
253 }
254
255 static void
256 NAT64PrefixRequestFlagsClear(NAT64PrefixRequestRef request, RequestFlags flags)
257 {
258 request->flags &= ~flags;
259 }
260
261 static NAT64PrefixRequestRef
262 NAT64PrefixRequestFindInterface(CFStringRef if_name_cf)
263 {
264 NAT64PrefixRequestRef scan;
265
266 LIST_FOREACH(scan, S_request_head_p, link) {
267 if (CFEqual(if_name_cf, scan->if_name_cf)) {
268 return (scan);
269 }
270 }
271 return (NULL);
272 }
273
274 static void
275 NAT64PrefixRequestRetain(NAT64PrefixRequestRef request)
276 {
277 request->retain_count++;
278 SC_log(LOG_DEBUG, "%s: %s %p %u",
279 request->if_name, __FUNCTION__,
280 request, request->retain_count);
281 return;
282 }
283
284 static NAT64PrefixRequestRef
285 NAT64PrefixRequestCreate(CFStringRef if_name_cf)
286 {
287 unsigned int if_index;
288 char * if_name;
289 NAT64PrefixRequestRef request;
290
291 if_name = _SC_cfstring_to_cstring(if_name_cf, NULL, 0,
292 kCFStringEncodingASCII);
293 if (if_name == NULL) {
294 SC_log(LOG_ERR,
295 "%@: could not convert interface name",
296 if_name_cf);
297 return (NULL);
298 }
299 if_index = my_if_nametoindex(if_name);
300 if (if_index == 0) {
301 SC_log(LOG_NOTICE,
302 "%s: interface does not exist", if_name);
303 CFAllocatorDeallocate(NULL, if_name);
304 return (NULL);
305 }
306 request = malloc(sizeof(*request));
307 SC_log(LOG_DEBUG, "%@: %s %p", if_name_cf, __FUNCTION__, request);
308 bzero(request, sizeof(*request));
309 request->if_name_cf = CFRetain(if_name_cf);
310 request->if_name = if_name;
311 request->if_index = if_index;
312 LIST_INSERT_HEAD(S_request_head_p, request, link);
313 NAT64PrefixRequestFlagsSet(request, kRequestFlagsValid);
314 NAT64PrefixRequestRetain(request);
315 return (request);
316 }
317
318 static void
319 NAT64PrefixRequestStopResolver(NAT64PrefixRequestRef request)
320 {
321 if (request->resolver != NULL) {
322 SC_log(LOG_DEBUG, "%s: %s",
323 request->if_name, __FUNCTION__);
324 nw_nat64_prefixes_resolver_cancel(request->resolver);
325 nw_release(request->resolver);
326 request->resolver = NULL;
327 }
328 return;
329 }
330
331 static void
332 NAT64PrefixRequestInvalidate(NAT64PrefixRequestRef request)
333 {
334 SC_log(LOG_DEBUG, "%s: %s", request->if_name, __FUNCTION__);
335 NAT64PrefixRequestStopResolver(request);
336 if (NAT64PrefixRequestFlagsIsSet(request, kRequestFlagsValid)) {
337 NAT64PrefixRequestFlagsClear(request, kRequestFlagsValid);
338 LIST_REMOVE(request, link);
339 }
340 return;
341 }
342
343 static void
344 NAT64PrefixRequestRelease(NAT64PrefixRequestRef request)
345 {
346 if (request->retain_count == 0) {
347 SC_log(LOG_ERR, "%s: retain count is zero %p",
348 __FUNCTION__, request);
349 return;
350 }
351 request->retain_count--;
352 SC_log(LOG_DEBUG,
353 "%s: %s %p %u",
354 request->if_name, __FUNCTION__, request, request->retain_count);
355 if (request->retain_count != 0) {
356 return;
357 }
358 NAT64PrefixRequestInvalidate(request);
359 SC_log(LOG_DEBUG, "%s %s: deallocate %p",
360 request->if_name, __FUNCTION__, request);
361 if (request->if_name_cf != NULL) {
362 CFRelease(request->if_name_cf);
363 request->if_name_cf = NULL;
364 }
365 if (request->if_name != NULL) {
366 CFAllocatorDeallocate(NULL, (void *)request->if_name);
367 request->if_name = NULL;
368 }
369 free(request);
370 return;
371 }
372
373 static void
374 NAT64PrefixRequestStart(NAT64PrefixRequestRef request)
375 {
376 dispatch_block_t cancel_handler;
377 nw_nat64_copy_prefixes_block_t handler;
378 nw_nat64_prefixes_resolver_t resolver;
379 CFAbsoluteTime start_time;
380
381 SC_log(LOG_INFO, "%s: %s", request->if_name, __FUNCTION__);
382 if (request->resolver != NULL) {
383 SC_log(LOG_DEBUG, "%s %s: resolver is already active",
384 request->if_name, __FUNCTION__);
385 return;
386 }
387 resolver = _nat64_resolver_create(request->if_index);
388 if (resolver == NULL) {
389 return;
390 }
391 NAT64PrefixRequestRetain(request);
392 cancel_handler = ^{
393 SC_log(LOG_DEBUG, "%s: NAT64 resolver cancelled",
394 request->if_name);
395 NAT64PrefixRequestRelease(request);
396 return;
397 };
398 start_time = CFAbsoluteTimeGetCurrent();
399 handler = ^(int32_t num_prefixes, nw_nat64_prefix_t *prefixes) {
400 Boolean set_prefix_failed = FALSE;
401
402 if (!NAT64PrefixRequestFlagsIsSet(request,
403 kRequestFlagsValid)) {
404 SC_log(LOG_INFO, "%s: NAT64 request is stale %p",
405 request->if_name, request);
406 return;
407 }
408 if (prefixes != NULL) {
409 /* set prefixes on the interface */
410 if (!_nat64_prefix_set(request->if_name,
411 num_prefixes, prefixes)) {
412 set_prefix_failed = TRUE;
413 }
414 } else {
415 SC_log(LOG_ERR, "%s: NAT64 no prefixes",
416 request->if_name);
417 }
418 _nat64_prefix_post(request->if_name_cf,
419 num_prefixes, prefixes, start_time);
420 #if TEST_NAT64_CONFIGURATION
421 if (G_set_prefixes_force_failure) {
422 set_prefix_failed = TRUE;
423 }
424 #endif /* TEST_NAT64_CONFIGURATION */
425 if (set_prefix_failed) {
426 /* remove resolver */
427 NAT64PrefixRequestInvalidate(request);
428 NAT64PrefixRequestRelease(request);
429 return;
430 }
431 };
432 nw_nat64_prefixes_resolver_set_cancel_handler(resolver, cancel_handler);
433 nw_nat64_prefixes_resolver_set_update_handler(resolver,
434 nat64_dispatch_queue(),
435 handler);
436 nw_nat64_prefixes_resolver_start(resolver);
437 request->resolver = resolver;
438 return;
439 }
440
441 /**
442 ** Set iterators
443 **/
444 static void
445 _nat64_process_prefix_request(const void *value, void *context)
446 {
447 #pragma unused(context)
448 CFStringRef interface = (CFStringRef)value;
449 NAT64PrefixRequestRef request;
450
451 request = NAT64PrefixRequestFindInterface(interface);
452 if (request != NULL) {
453 return;
454 }
455
456 /* start a new request */
457 request = NAT64PrefixRequestCreate(interface);
458 if (request != NULL) {
459 NAT64PrefixRequestStart(request);
460 }
461 return;
462 }
463
464 static void
465 _nat64_process_prefix_update(const void *value, void *context)
466 {
467 #pragma unused(context)
468 CFStringRef interface = (CFStringRef)value;
469 NAT64PrefixRequestRef request;
470
471 request = NAT64PrefixRequestFindInterface(interface);
472 if (request == NULL) {
473 SC_log(LOG_DEBUG, "%@ %s: no existing request",
474 interface, __FUNCTION__);
475 return;
476 }
477
478 /* destroy the old one, start a new one */
479 SC_log(LOG_INFO, "%@: %s", interface, __FUNCTION__);
480 NAT64PrefixRequestInvalidate(request);
481 NAT64PrefixRequestRelease(request);
482
483 /* start a new request */
484 request = NAT64PrefixRequestCreate(interface);
485 if (request != NULL) {
486 NAT64PrefixRequestStart(request);
487 }
488 return;
489 }
490
491 static void
492 _nat64_process_cancel_request(const void * value, void * context)
493 {
494 #pragma unused(context)
495 CFStringRef interface = (CFStringRef)value;
496 NAT64PrefixRequestRef request;
497
498 /* if there's an in-flight request, remove it */
499 request = NAT64PrefixRequestFindInterface(interface);
500 if (request == NULL) {
501 /* no resolver */
502 SC_log(LOG_DEBUG, "%@ %s: no active NAT64 request",
503 interface, __FUNCTION__);
504 return;
505 }
506 SC_log(LOG_DEBUG, "%s %s: removing NAT64 request",
507 request->if_name, __FUNCTION__);
508 _nat64_prefix_set(request->if_name, 0, NULL);
509 NAT64PrefixRequestInvalidate(request);
510 NAT64PrefixRequestRelease(request);
511 return;
512 }
513
514
515 #pragma mark -
516 #pragma mark NAT64 prefix functions (for IPMonitor)
517
518
519 __private_extern__
520 Boolean
521 is_nat64_prefix_request(CFStringRef change, CFStringRef *interface)
522 {
523 CFArrayRef components;
524 static CFStringRef prefix = NULL;
525 Boolean yn = FALSE;
526 static dispatch_once_t once;
527
528 dispatch_once(&once, ^{
529 prefix = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState);
530 });
531
532 *interface = NULL;
533 if (!CFStringHasPrefix(change, prefix) ||
534 !CFStringHasSuffix(change, kSCEntNetNAT64PrefixRequest)) {
535 return FALSE;
536 }
537
538 components = CFStringCreateArrayBySeparatingStrings(NULL, change, CFSTR("/"));
539 if (CFArrayGetCount(components) == 5) {
540 *interface = CFArrayGetValueAtIndex(components, 3);
541 CFRetain(*interface);
542 yn = TRUE;
543 }
544 CFRelease(components);
545
546 return yn;
547 }
548
549
550 __private_extern__ void
551 nat64_prefix_request_add_pattern(CFMutableArrayRef patterns)
552 {
553 CFStringRef pattern;
554
555 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
556 kSCDynamicStoreDomainState,
557 kSCCompAnyRegex,
558 kSCEntNetNAT64PrefixRequest);
559 CFArrayAppendValue(patterns, pattern);
560 CFRelease(pattern);
561 return;
562 }
563
564 static void
565 nat64_configuration_update_locked(CFSetRef requests, CFSetRef updates,
566 CFSetRef cancellations)
567 {
568 if (cancellations != NULL) {
569 CFSetApplyFunction(cancellations,
570 _nat64_process_cancel_request,
571 NULL);
572 }
573 // for any interface that changed, refresh the nat64 prefix
574 if (updates != NULL) {
575 CFSetApplyFunction(updates, _nat64_process_prefix_update, NULL);
576 }
577
578 // for any requested interface, query the nat64 prefix
579 if (requests != NULL) {
580 CFSetApplyFunction(requests, _nat64_process_prefix_request,
581 NULL);
582 }
583 return;
584 }
585
586 __private_extern__
587 void
588 nat64_configuration_update(CFSetRef requests, CFSetRef updates,
589 CFSetRef cancellations)
590 {
591 dispatch_block_t update_block;
592
593 if (requests != NULL) {
594 CFRetain(requests);
595 }
596 if (updates != NULL) {
597 CFRetain(updates);
598 }
599 if (cancellations != NULL) {
600 CFRetain(cancellations);
601 }
602 update_block = ^{
603 SC_log(LOG_DEBUG,
604 "NAT64 requests %@ updates %@ cancellations %@",
605 requests, updates, cancellations);
606 nat64_configuration_update_locked(requests, updates,
607 cancellations);
608 if (requests != NULL) {
609 CFRelease(requests);
610 }
611 if (updates != NULL) {
612 CFRelease(updates);
613 }
614 if (cancellations != NULL) {
615 CFRelease(cancellations);
616 }
617 };
618 dispatch_async(nat64_dispatch_queue(), update_block);
619 return;
620 }
621
622 #if TEST_NAT64_CONFIGURATION
623 int
624 main(int argc, char * argv[])
625 {
626 CFStringRef if_name_cf;
627 CFMutableSetRef set;
628
629 set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
630 for (int i = 1; i < argc; i++) {
631 if_name_cf = CFStringCreateWithCString(NULL,
632 argv[i],
633 kCFStringEncodingASCII);
634 CFSetAddValue(set, if_name_cf);
635 CFRelease(if_name_cf);
636 }
637 if (CFSetGetCount(set) == 0) {
638 fprintf(stderr, "nothing to do\n");
639 exit(0);
640 }
641 SC_log(LOG_NOTICE, "Starting %@", set);
642 nat64_configuration_update(set, NULL, NULL);
643 sleep(2);
644
645 SC_log(LOG_NOTICE, "Starting 2 %@", set);
646 nat64_configuration_update(set, NULL, NULL);
647 sleep(2);
648
649 SC_log(LOG_NOTICE, "Updating");
650 nat64_configuration_update(NULL, set, NULL);
651 sleep(2);
652
653 SC_log(LOG_NOTICE, "Cancelling");
654 nat64_configuration_update(NULL, NULL, set);
655 sleep(2);
656
657 G_set_prefixes_force_failure = TRUE;
658 SC_log(LOG_NOTICE, "Starting (with forced failure) %@", set);
659 nat64_configuration_update(set, NULL, NULL);
660 sleep(2);
661
662 SC_log(LOG_NOTICE, "Starting (with forced failure 2) %@", set);
663 nat64_configuration_update(set, NULL, NULL);
664
665 dispatch_main();
666 exit(0);
667 return (0);
668 }
669 #endif /* TEST_NAT64_CONFIGURATION */