]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/nat64-configuration.c
configd-963.200.27.tar.gz
[apple/configd.git] / Plugins / IPMonitor / nat64-configuration.c
1 /*
2 * Copyright (c) 2017, 2018 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 #include "ip_plugin.h"
39
40 #define INET6 1
41
42 #include <string.h>
43 #include <net/if.h>
44 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
47 #if __has_include(<nw/private.h>)
48 #include <nw/private.h>
49 #else // __has_include(<nw/private.h>)
50 #include <network/nat64.h>
51 #endif // __has_include(<nw/private.h>)
52
53
54 static CFMutableSetRef nat64_prefix_requests = NULL;
55
56
57 static dispatch_queue_t
58 nat64_dispatch_queue()
59 {
60 static dispatch_once_t once;
61 static dispatch_queue_t q;
62
63 dispatch_once(&once, ^{
64 q = dispatch_queue_create("nat64 prefix request queue", NULL);
65 });
66
67 return q;
68 }
69
70
71 static Boolean
72 _nat64_prefix_set(const char *if_name,
73 int32_t num_prefixes,
74 nw_nat64_prefix_t *prefixes)
75 {
76 struct if_nat64req req;
77 int ret;
78 int s;
79
80 SC_log(LOG_DEBUG, "%s: _nat64_prefix_set", if_name);
81
82 // pass NAT64 prefixes to the kernel
83 bzero(&req, sizeof(req));
84 strlcpy(req.ifnat64_name, if_name, sizeof(req.ifnat64_name));
85
86 if (num_prefixes == 0) {
87 SC_log(LOG_INFO, "%s: nat64 prefix not (or no longer) available", 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_DEBUG, "%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 bcopy(&prefixes[i].data,
99 &req.ifnat64_prefixes[i].ipv6_prefix,
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_INFO, "%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 CFStringRef key;
130
131 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
132 kSCDynamicStoreDomainState,
133 interface,
134 kSCEntNetNAT64);
135 if (num_prefixes >= 0) {
136 CFDateRef date;
137 CFMutableDictionaryRef plat_dict;
138
139 plat_dict = CFDictionaryCreateMutable(NULL,
140 0,
141 &kCFTypeDictionaryKeyCallBacks,
142 &kCFTypeDictionaryValueCallBacks);
143 /* prefixes (if available) */
144 if (num_prefixes > 0) {
145 CFMutableArrayRef prefix_array;
146
147 prefix_array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
148 for (int32_t i = 0; i < num_prefixes; i++) {
149 char prefix_str[NW_NAT64_PREFIX_STR_LENGTH] = {0};
150 CFStringRef str;
151
152 nw_nat64_write_prefix_to_string(&prefixes[i], prefix_str, sizeof(prefix_str));
153 str = CFStringCreateWithCString(NULL, prefix_str, kCFStringEncodingASCII);
154 CFArrayAppendValue(prefix_array, str);
155 CFRelease(str);
156 }
157 CFDictionarySetValue(plat_dict, kSCPropNetNAT64PrefixList, prefix_array);
158 CFRelease(prefix_array);
159 }
160 /* start time */
161 date = CFDateCreate(NULL, start_time);
162 CFDictionarySetValue(plat_dict,
163 kSCPropNetNAT64PLATDiscoveryStartTime,
164 date);
165 CFRelease(date);
166
167 /* completion time */
168 date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
169 CFDictionarySetValue(plat_dict,
170 kSCPropNetNAT64PLATDiscoveryCompletionTime,
171 date);
172 CFRelease(date);
173
174 (void)SCDynamicStoreSetValue(NULL, key, plat_dict);
175 SC_log(LOG_INFO, "%@: PLAT discovery complete %@",
176 interface, plat_dict);
177 CFRelease(plat_dict);
178 } else {
179 (void)SCDynamicStoreRemoveValue(NULL, key);
180 }
181 CFRelease(key);
182 return;
183 }
184
185
186 static void
187 _nat64_prefix_request_start(const void *value)
188 {
189 unsigned int if_index;
190 char *if_name;
191 CFStringRef interface = (CFStringRef)value;
192 bool ok;
193 CFAbsoluteTime start_time;
194
195 SC_log(LOG_DEBUG, "%@: _nat64_prefix_request_start", interface);
196
197 if_name = _SC_cfstring_to_cstring(interface, NULL, 0, kCFStringEncodingASCII);
198 if (if_name == NULL) {
199 SC_log(LOG_NOTICE, "%@: could not convert interface name", interface);
200 return;
201 }
202
203 if_index = my_if_nametoindex(if_name);
204 if (if_index == 0) {
205 SC_log(LOG_NOTICE, "%s: no interface index", if_name);
206 CFAllocatorDeallocate(NULL, if_name);
207 return;
208 }
209
210 // keep track of interfaces with active nat64 prefix requests
211 CFSetAddValue(nat64_prefix_requests, interface);
212
213 CFRetain(interface);
214 start_time = CFAbsoluteTimeGetCurrent();
215 ok = nw_nat64_copy_prefixes_async(&if_index,
216 nat64_dispatch_queue(),
217 ^(int32_t num_prefixes, nw_nat64_prefix_t *prefixes) {
218 if (num_prefixes >= 0) {
219 // update interface
220 if (!_nat64_prefix_set(if_name, num_prefixes, prefixes)) {
221 num_prefixes = -1;
222 }
223 } else {
224 SC_log(LOG_ERR,
225 "%s: nw_nat64_copy_prefixes_async() num_prefixes(%d) < 0",
226 if_name,
227 num_prefixes);
228 }
229
230 if (num_prefixes <= 0) {
231 // remove from active list
232 CFSetRemoveValue(nat64_prefix_requests, interface);
233 }
234
235 _nat64_prefix_post(interface, num_prefixes, prefixes, start_time);
236
237 // cleanup
238 CFRelease(interface);
239 CFAllocatorDeallocate(NULL, if_name);
240 });
241 if (!ok) {
242 SC_log(LOG_ERR, "%s: nw_nat64_copy_prefixes_async() failed", if_name);
243
244 // remove from active list
245 CFSetRemoveValue(nat64_prefix_requests, interface);
246
247 CFRelease(interface);
248 CFAllocatorDeallocate(NULL, if_name);
249 }
250
251 return;
252 }
253
254
255 static void
256 _nat64_prefix_request(const void *value, void *context)
257 {
258 CFSetRef changes = (CFSetRef)context;
259 CFStringRef interface = (CFStringRef)value;
260
261 if (!CFSetContainsValue(nat64_prefix_requests, interface) ||
262 ((changes != NULL) && CFSetContainsValue(changes, interface))) {
263 // if new request
264 // ... or a [refresh] request that hasn't already been started
265 _nat64_prefix_request_start(interface);
266 }
267
268 return;
269 }
270
271
272 static void
273 _nat64_prefix_update(const void *value, void *context)
274 {
275 #pragma unused(context)
276 CFStringRef interface = (CFStringRef)value;
277
278 if (CFSetContainsValue(nat64_prefix_requests, interface)) {
279 _nat64_prefix_request_start(interface);
280 }
281
282 return;
283 }
284
285
286 #pragma mark -
287 #pragma mark NAT64 prefix functions (for IPMonitor)
288
289
290 __private_extern__
291 Boolean
292 is_nat64_prefix_request(CFStringRef change, CFStringRef *interface)
293 {
294 CFArrayRef components;
295 static CFStringRef prefix = NULL;
296 Boolean yn = FALSE;
297 static dispatch_once_t once;
298
299 dispatch_once(&once, ^{
300 prefix = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState);
301 });
302
303 *interface = NULL;
304 if (!CFStringHasPrefix(change, prefix) ||
305 !CFStringHasSuffix(change, kSCEntNetNAT64PrefixRequest)) {
306 return FALSE;
307 }
308
309 components = CFStringCreateArrayBySeparatingStrings(NULL, change, CFSTR("/"));
310 if (CFArrayGetCount(components) == 5) {
311 *interface = CFArrayGetValueAtIndex(components, 3);
312 CFRetain(*interface);
313 yn = TRUE;
314 }
315 CFRelease(components);
316
317 return yn;
318 }
319
320
321 __private_extern__ void
322 nat64_prefix_request_add_pattern(CFMutableArrayRef patterns)
323 {
324 CFStringRef pattern;
325
326 pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
327 kSCDynamicStoreDomainState,
328 kSCCompAnyRegex,
329 kSCEntNetNAT64PrefixRequest);
330 CFArrayAppendValue(patterns, pattern);
331 CFRelease(pattern);
332 return;
333 }
334
335
336 __private_extern__
337 void
338 nat64_configuration_init(CFBundleRef bundle)
339 {
340 #pragma unused(bundle)
341 nat64_prefix_requests = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
342 return;
343 }
344
345
346 __private_extern__
347 void
348 nat64_configuration_update(CFSetRef requests, CFSetRef changes)
349 {
350 // for any interface that changed, refresh the nat64 prefix
351 if (changes != NULL) {
352 CFSetApplyFunction(changes, _nat64_prefix_update, NULL);
353 }
354
355 // for any requested interface, query the nat64 prefix
356 if (requests != NULL) {
357 CFSetApplyFunction(requests, _nat64_prefix_request, (void *)changes);
358 }
359
360 return;
361 }