]> git.saurik.com Git - apple/configd.git/blame - Plugins/IPMonitor/nat64-configuration.c
configd-1109.40.9.tar.gz
[apple/configd.git] / Plugins / IPMonitor / nat64-configuration.c
CommitLineData
1ef45fa4 1/*
afb19109 2 * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
1ef45fa4
A
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>
afb19109
A
38#if TEST_NAT64_CONFIGURATION
39static Boolean G_set_prefixes_force_failure;
40#define my_if_nametoindex if_nametoindex
41#else
1ef45fa4 42#include "ip_plugin.h"
afb19109 43#endif
1ef45fa4
A
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>
afb19109 52#include <netinet/in.h>
f715d946 53#include <nw/private.h>
afb19109 54#include <sys/queue.h>
1ef45fa4
A
55
56
afb19109
A
57/**
58 ** Support functions
59 **/
1ef45fa4 60static dispatch_queue_t
afb19109 61nat64_dispatch_queue(void)
1ef45fa4
A
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
f715d946
A
73static Boolean
74_nat64_prefix_set(const char *if_name,
75 int32_t num_prefixes,
76 nw_nat64_prefix_t *prefixes)
1ef45fa4
A
77{
78 struct if_nat64req req;
79 int ret;
80 int s;
81
1ef45fa4 82 // pass NAT64 prefixes to the kernel
afb19109 83 memset(&req, 0, sizeof(req));
1ef45fa4
A
84 strlcpy(req.ifnat64_name, if_name, sizeof(req.ifnat64_name));
85
86 if (num_prefixes == 0) {
afb19109 87 SC_log(LOG_NOTICE, "%s: nat64 prefix unavailable", if_name);
1ef45fa4
A
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));
afb19109 94 SC_log(LOG_NOTICE, "%s: nat64 prefix[%d] = %s", if_name, i, prefix_str);
1ef45fa4
A
95
96 if (i < NAT64_MAX_NUM_PREFIXES) {
97 req.ifnat64_prefixes[i].prefix_len = prefixes[i].length;
afb19109
A
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)
1ef45fa4
A
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));
f715d946 107 return (FALSE);
1ef45fa4
A
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 }
f715d946 115 return (FALSE);
1ef45fa4
A
116 }
117
afb19109 118 SC_log(LOG_NOTICE, "%s: nat64 prefix%s updated", if_name, (num_prefixes != 1) ? "es" : "");
f715d946
A
119 return (TRUE);
120}
121
122
123static void
124_nat64_prefix_post(CFStringRef interface,
125 int32_t num_prefixes,
126 nw_nat64_prefix_t *prefixes,
127 CFAbsoluteTime start_time)
128{
afb19109
A
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
f715d946
A
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);
afb19109 183 SC_log(LOG_NOTICE, "%@: PLAT discovery complete %@",
f715d946
A
184 interface, plat_dict);
185 CFRelease(plat_dict);
186 } else {
187 (void)SCDynamicStoreRemoveValue(NULL, key);
188 }
189 CFRelease(key);
afb19109 190#endif /* TEST_NAT64_CONFIGURATION */
1ef45fa4
A
191 return;
192}
193
afb19109
A
194static 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 **/
220struct NAT64PrefixRequest;
221typedef struct NAT64PrefixRequest NAT64PrefixRequest, * NAT64PrefixRequestRef;
222#define NAT64PrefixRequest_LIST_ENTRY LIST_ENTRY(NAT64PrefixRequest)
223#define NAT64PrefixRequest_LIST_HEAD LIST_HEAD(NAT64PrefixRequestHead, \
224 NAT64PrefixRequest)
225static NAT64PrefixRequest_LIST_HEAD S_request_head;
226static struct NAT64PrefixRequestHead * S_request_head_p = &S_request_head;
227
228typedef CF_ENUM(uint16_t, RequestFlags) {
229 kRequestFlagsNone = 0x0000,
230 kRequestFlagsValid = 0x0001,
231};
232
233struct 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
243static Boolean
244NAT64PrefixRequestFlagsIsSet(NAT64PrefixRequestRef request, RequestFlags flags)
245{
246 return ((request->flags & flags) != 0);
247}
1ef45fa4
A
248
249static void
afb19109 250NAT64PrefixRequestFlagsSet(NAT64PrefixRequestRef request, RequestFlags flags)
1ef45fa4 251{
afb19109
A
252 request->flags |= flags;
253}
1ef45fa4 254
afb19109
A
255static void
256NAT64PrefixRequestFlagsClear(NAT64PrefixRequestRef request, RequestFlags flags)
257{
258 request->flags &= ~flags;
259}
1ef45fa4 260
afb19109
A
261static NAT64PrefixRequestRef
262NAT64PrefixRequestFindInterface(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 }
1ef45fa4 270 }
afb19109
A
271 return (NULL);
272}
273
274static void
275NAT64PrefixRequestRetain(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}
1ef45fa4 283
afb19109
A
284static NAT64PrefixRequestRef
285NAT64PrefixRequestCreate(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 }
1ef45fa4
A
299 if_index = my_if_nametoindex(if_name);
300 if (if_index == 0) {
afb19109
A
301 SC_log(LOG_NOTICE,
302 "%s: interface does not exist", if_name);
1ef45fa4 303 CFAllocatorDeallocate(NULL, if_name);
afb19109 304 return (NULL);
1ef45fa4 305 }
afb19109
A
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}
1ef45fa4 317
afb19109
A
318static void
319NAT64PrefixRequestStopResolver(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}
1ef45fa4 330
afb19109
A
331static void
332NAT64PrefixRequestInvalidate(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);
1ef45fa4 339 }
afb19109
A
340 return;
341}
1ef45fa4 342
afb19109
A
343static void
344NAT64PrefixRequestRelease(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);
1ef45fa4
A
370 return;
371}
372
afb19109
A
373static void
374NAT64PrefixRequestStart(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) {
da12db89 400 Boolean remove_resolver = FALSE;
afb19109
A
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 */
da12db89
A
410 _nat64_prefix_set(request->if_name,
411 num_prefixes, prefixes);
412 remove_resolver = TRUE;
afb19109
A
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) {
da12db89 421 remove_resolver = TRUE;
afb19109
A
422 }
423#endif /* TEST_NAT64_CONFIGURATION */
da12db89 424 if (remove_resolver) {
afb19109
A
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}
1ef45fa4 439
afb19109
A
440/**
441 ** Set iterators
442 **/
1ef45fa4 443static void
afb19109 444_nat64_process_prefix_request(const void *value, void *context)
1ef45fa4 445{
afb19109
A
446#pragma unused(context)
447 CFStringRef interface = (CFStringRef)value;
448 NAT64PrefixRequestRef request;
1ef45fa4 449
afb19109
A
450 request = NAT64PrefixRequestFindInterface(interface);
451 if (request != NULL) {
452 return;
1ef45fa4
A
453 }
454
afb19109
A
455 /* start a new request */
456 request = NAT64PrefixRequestCreate(interface);
457 if (request != NULL) {
458 NAT64PrefixRequestStart(request);
459 }
1ef45fa4
A
460 return;
461}
462
1ef45fa4 463static void
afb19109 464_nat64_process_prefix_update(const void *value, void *context)
1ef45fa4
A
465{
466#pragma unused(context)
afb19109
A
467 CFStringRef interface = (CFStringRef)value;
468 NAT64PrefixRequestRef request;
1ef45fa4 469
afb19109
A
470 request = NAT64PrefixRequestFindInterface(interface);
471 if (request == NULL) {
472 SC_log(LOG_DEBUG, "%@ %s: no existing request",
473 interface, __FUNCTION__);
474 return;
1ef45fa4
A
475 }
476
afb19109
A
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
490static 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);
1ef45fa4
A
510 return;
511}
512
513
514#pragma mark -
515#pragma mark NAT64 prefix functions (for IPMonitor)
516
517
518__private_extern__
519Boolean
520is_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
550nat64_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
afb19109
A
563static void
564nat64_configuration_update_locked(CFSetRef requests, CFSetRef updates,
565 CFSetRef cancellations)
1ef45fa4 566{
afb19109
A
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 }
1ef45fa4
A
582 return;
583}
584
1ef45fa4
A
585__private_extern__
586void
afb19109
A
587nat64_configuration_update(CFSetRef requests, CFSetRef updates,
588 CFSetRef cancellations)
1ef45fa4 589{
afb19109 590 dispatch_block_t update_block;
1ef45fa4 591
1ef45fa4 592 if (requests != NULL) {
afb19109 593 CFRetain(requests);
1ef45fa4 594 }
afb19109
A
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);
1ef45fa4
A
618 return;
619}
afb19109
A
620
621#if TEST_NAT64_CONFIGURATION
622int
623main(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 */