]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/nat64-configuration.c
configd-1061.40.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 remove_resolver = 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 _nat64_prefix_set(request->if_name,
411 num_prefixes, prefixes);
412 remove_resolver = TRUE;
413 } else {
414 SC_log(LOG_ERR, "%s: NAT64 no prefixes",
415 request->if_name);
416 }
417 _nat64_prefix_post(request->if_name_cf,
418 num_prefixes, prefixes, start_time);
419 #if TEST_NAT64_CONFIGURATION
420 if (G_set_prefixes_force_failure) {
421 remove_resolver = TRUE;
422 }
423 #endif /* TEST_NAT64_CONFIGURATION */
424 if (remove_resolver) {
425 /* remove resolver */
426 NAT64PrefixRequestInvalidate(request);
427 NAT64PrefixRequestRelease(request);
428 return;
429 }
430 };
431 nw_nat64_prefixes_resolver_set_cancel_handler(resolver, cancel_handler);
432 nw_nat64_prefixes_resolver_set_update_handler(resolver,
433 nat64_dispatch_queue(),
434 handler);
435 nw_nat64_prefixes_resolver_start(resolver);
436 request->resolver = resolver;
437 return;
438 }
439
440 /**
441 ** Set iterators
442 **/
443 static void
444 _nat64_process_prefix_request(const void *value, void *context)
445 {
446 #pragma unused(context)
447 CFStringRef interface = (CFStringRef)value;
448 NAT64PrefixRequestRef request;
449
450 request = NAT64PrefixRequestFindInterface(interface);
451 if (request != NULL) {
452 return;
453 }
454
455 /* start a new request */
456 request = NAT64PrefixRequestCreate(interface);
457 if (request != NULL) {
458 NAT64PrefixRequestStart(request);
459 }
460 return;
461 }
462
463 static void
464 _nat64_process_prefix_update(const void *value, void *context)
465 {
466 #pragma unused(context)
467 CFStringRef interface = (CFStringRef)value;
468 NAT64PrefixRequestRef request;
469
470 request = NAT64PrefixRequestFindInterface(interface);
471 if (request == NULL) {
472 SC_log(LOG_DEBUG, "%@ %s: no existing request",
473 interface, __FUNCTION__);
474 return;
475 }
476
477 /* destroy the old one, start a new one */
478 SC_log(LOG_INFO, "%@: %s", interface, __FUNCTION__);
479 NAT64PrefixRequestInvalidate(request);
480 NAT64PrefixRequestRelease(request);
481
482 /* start a new request */
483 request = NAT64PrefixRequestCreate(interface);
484 if (request != NULL) {
485 NAT64PrefixRequestStart(request);
486 }
487 return;
488 }
489
490 static void
491 _nat64_process_cancel_request(const void * value, void * context)
492 {
493 #pragma unused(context)
494 CFStringRef interface = (CFStringRef)value;
495 NAT64PrefixRequestRef request;
496
497 /* if there's an in-flight request, remove it */
498 request = NAT64PrefixRequestFindInterface(interface);
499 if (request == NULL) {
500 /* no resolver */
501 SC_log(LOG_DEBUG, "%@ %s: no active NAT64 request",
502 interface, __FUNCTION__);
503 return;
504 }
505 SC_log(LOG_DEBUG, "%s %s: removing NAT64 request",
506 request->if_name, __FUNCTION__);
507 _nat64_prefix_set(request->if_name, 0, NULL);
508 NAT64PrefixRequestInvalidate(request);
509 NAT64PrefixRequestRelease(request);
510 return;
511 }
512
513
514 #pragma mark -
515 #pragma mark NAT64 prefix functions (for IPMonitor)
516
517
518 __private_extern__
519 Boolean
520 is_nat64_prefix_request(CFStringRef change, CFStringRef *interface)
521 {
522 CFArrayRef components;
523 static CFStringRef prefix = NULL;
524 Boolean yn = FALSE;
525 static dispatch_once_t once;
526
527 dispatch_once(&once, ^{
528 prefix = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState);
529 });
530
531 *interface = NULL;
532 if (!CFStringHasPrefix(change, prefix) ||
533 !CFStringHasSuffix(change, kSCEntNetNAT64PrefixRequest)) {
534 return FALSE;
535 }
536
537 components = CFStringCreateArrayBySeparatingStrings(NULL, change, CFSTR("/"));
538 if (CFArrayGetCount(components) == 5) {
539 *interface = CFArrayGetValueAtIndex(components, 3);
540 CFRetain(*interface);
541 yn = TRUE;
542 }
543 CFRelease(components);
544
545 return yn;
546 }
547
548
549 __private_extern__ void
550 nat64_prefix_request_add_pattern(CFMutableArrayRef patterns)
551 {
552 CFStringRef pattern;
553
554 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
555 kSCDynamicStoreDomainState,
556 kSCCompAnyRegex,
557 kSCEntNetNAT64PrefixRequest);
558 CFArrayAppendValue(patterns, pattern);
559 CFRelease(pattern);
560 return;
561 }
562
563 static void
564 nat64_configuration_update_locked(CFSetRef requests, CFSetRef updates,
565 CFSetRef cancellations)
566 {
567 if (cancellations != NULL) {
568 CFSetApplyFunction(cancellations,
569 _nat64_process_cancel_request,
570 NULL);
571 }
572 // for any interface that changed, refresh the nat64 prefix
573 if (updates != NULL) {
574 CFSetApplyFunction(updates, _nat64_process_prefix_update, NULL);
575 }
576
577 // for any requested interface, query the nat64 prefix
578 if (requests != NULL) {
579 CFSetApplyFunction(requests, _nat64_process_prefix_request,
580 NULL);
581 }
582 return;
583 }
584
585 __private_extern__
586 void
587 nat64_configuration_update(CFSetRef requests, CFSetRef updates,
588 CFSetRef cancellations)
589 {
590 dispatch_block_t update_block;
591
592 if (requests != NULL) {
593 CFRetain(requests);
594 }
595 if (updates != NULL) {
596 CFRetain(updates);
597 }
598 if (cancellations != NULL) {
599 CFRetain(cancellations);
600 }
601 update_block = ^{
602 SC_log(LOG_DEBUG,
603 "NAT64 requests %@ updates %@ cancellations %@",
604 requests, updates, cancellations);
605 nat64_configuration_update_locked(requests, updates,
606 cancellations);
607 if (requests != NULL) {
608 CFRelease(requests);
609 }
610 if (updates != NULL) {
611 CFRelease(updates);
612 }
613 if (cancellations != NULL) {
614 CFRelease(cancellations);
615 }
616 };
617 dispatch_async(nat64_dispatch_queue(), update_block);
618 return;
619 }
620
621 #if TEST_NAT64_CONFIGURATION
622 int
623 main(int argc, char * argv[])
624 {
625 CFStringRef if_name_cf;
626 CFMutableSetRef set;
627
628 set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
629 for (int i = 1; i < argc; i++) {
630 if_name_cf = CFStringCreateWithCString(NULL,
631 argv[i],
632 kCFStringEncodingASCII);
633 CFSetAddValue(set, if_name_cf);
634 CFRelease(if_name_cf);
635 }
636 if (CFSetGetCount(set) == 0) {
637 fprintf(stderr, "nothing to do\n");
638 exit(0);
639 }
640 SC_log(LOG_NOTICE, "Starting %@", set);
641 nat64_configuration_update(set, NULL, NULL);
642 sleep(2);
643
644 SC_log(LOG_NOTICE, "Starting 2 %@", set);
645 nat64_configuration_update(set, NULL, NULL);
646 sleep(2);
647
648 SC_log(LOG_NOTICE, "Updating");
649 nat64_configuration_update(NULL, set, NULL);
650 sleep(2);
651
652 SC_log(LOG_NOTICE, "Cancelling");
653 nat64_configuration_update(NULL, NULL, set);
654 sleep(2);
655
656 G_set_prefixes_force_failure = TRUE;
657 SC_log(LOG_NOTICE, "Starting (with forced failure) %@", set);
658 nat64_configuration_update(set, NULL, NULL);
659 sleep(2);
660
661 SC_log(LOG_NOTICE, "Starting (with forced failure 2) %@", set);
662 nat64_configuration_update(set, NULL, NULL);
663
664 dispatch_main();
665 exit(0);
666 return (0);
667 }
668 #endif /* TEST_NAT64_CONFIGURATION */