]>
Commit | Line | Data |
---|---|---|
316670eb A |
1 | /* |
2 | * Copyright (c) 2011-2012 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_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. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | ||
30 | ||
31 | #include <sys/systm.h> | |
32 | #include <sys/socket.h> | |
33 | #include <net/if.h> | |
34 | #include <net/if_types.h> | |
35 | #include <net/if_utun.h> | |
36 | #include <sys/mbuf.h> | |
37 | #include <netinet/in.h> | |
38 | #include <netinet6/in6_var.h> | |
39 | #include <netinet6/in6_var.h> | |
40 | #include <netinet/ip.h> | |
41 | #include <netinet/ip6.h> | |
42 | #include <netinet/ip_var.h> | |
43 | #include <net/if_utun.h> | |
44 | #include <net/if_utun_crypto_ipsec.h> | |
45 | #include <netinet6/esp.h> | |
46 | #include <netinet6/esp6.h> | |
47 | #include <netinet6/ipsec.h> | |
48 | #include <net/bpf.h> | |
49 | ||
50 | extern lck_mtx_t *sadb_mutex; | |
51 | extern int esp_udp_encap_port; // udp encap listening port | |
52 | extern int ipsec_policy_count; | |
53 | extern int ipsec_bypass; | |
54 | extern int natt_keepalive_interval; | |
55 | ||
56 | static int utun_punt_rx_keepalive = 0; // optional global control | |
57 | ||
58 | extern errno_t utun_pkt_input (struct utun_pcb *pcb, mbuf_t m); | |
59 | ||
60 | static u_int8_t | |
61 | utun_ipsec_mode_to_sadb_mode (if_utun_crypto_ipsec_mode_t mode) | |
62 | { | |
63 | switch (mode) { | |
64 | case IF_UTUN_CRYPTO_IPSEC_MODE_TRANSPORT: | |
65 | return IPSEC_MODE_TRANSPORT; | |
66 | case IF_UTUN_CRYPTO_IPSEC_MODE_TUNNEL: | |
67 | return IPSEC_MODE_TUNNEL; | |
68 | default: | |
69 | return 0; | |
70 | } | |
71 | } | |
72 | ||
73 | static u_int16_t | |
74 | utun_ipsec_proto_to_sadb_proto (if_utun_crypto_ipsec_proto_t proto) | |
75 | { | |
76 | switch (proto) { | |
77 | case IF_UTUN_CRYPTO_IPSEC_PROTO_ESP: | |
78 | return IPPROTO_ESP; | |
79 | case IF_UTUN_CRYPTO_IPSEC_PROTO_AH: | |
80 | return IPPROTO_AH; | |
81 | default: | |
82 | return 0; | |
83 | } | |
84 | } | |
85 | ||
86 | static u_int8_t | |
87 | utun_ipsec_proto_to_sadb_satype (if_utun_crypto_ipsec_proto_t proto) | |
88 | { | |
89 | switch (proto) { | |
90 | case IF_UTUN_CRYPTO_IPSEC_PROTO_ESP: | |
91 | return SADB_SATYPE_ESP; | |
92 | case IF_UTUN_CRYPTO_IPSEC_PROTO_AH: | |
93 | return SADB_SATYPE_AH; | |
94 | default: | |
95 | return 0; | |
96 | } | |
97 | } | |
98 | ||
99 | static u_int8_t | |
100 | utun_ipsec_auth_to_sadb_aalg (if_utun_crypto_ipsec_auth_t auth) | |
101 | { | |
102 | switch (auth) { | |
103 | case IF_UTUN_CRYPTO_IPSEC_AUTH_MD5: | |
104 | return SADB_AALG_MD5HMAC; | |
105 | case IF_UTUN_CRYPTO_IPSEC_AUTH_SHA1: | |
106 | return SADB_AALG_SHA1HMAC; | |
107 | case IF_UTUN_CRYPTO_IPSEC_AUTH_SHA256: | |
108 | return SADB_X_AALG_SHA2_256; | |
109 | case IF_UTUN_CRYPTO_IPSEC_AUTH_SHA384: | |
110 | return SADB_X_AALG_SHA2_384; | |
111 | case IF_UTUN_CRYPTO_IPSEC_AUTH_SHA512: | |
112 | return SADB_X_AALG_SHA2_512; | |
113 | default: | |
114 | return 0; | |
115 | } | |
116 | } | |
117 | ||
118 | static u_int8_t | |
119 | utun_ipsec_enc_to_sadb_ealg (if_utun_crypto_ipsec_enc_t enc) | |
120 | { | |
121 | switch (enc) { | |
122 | case IF_UTUN_CRYPTO_IPSEC_ENC_DES: | |
123 | return SADB_EALG_DESCBC; | |
124 | case IF_UTUN_CRYPTO_IPSEC_ENC_3DES: | |
125 | return SADB_EALG_3DESCBC; | |
126 | case IF_UTUN_CRYPTO_IPSEC_ENC_AES128: | |
127 | case IF_UTUN_CRYPTO_IPSEC_ENC_AES256: | |
128 | return SADB_X_EALG_AESCBC; | |
129 | default: | |
130 | return 0; | |
131 | } | |
132 | } | |
133 | ||
134 | static u_int32_t | |
135 | utun_ipsec_keepalive_and_nat_info_to_sadb_flags (if_utun_crypto_ipsec_keepalive_t keepalive, | |
136 | int punt_rx_keepalive, | |
137 | if_utun_crypto_ipsec_natd_t natd, | |
138 | u_int16_t natt_port) | |
139 | { | |
140 | u_int32_t flags = 0; | |
141 | ||
142 | if (natt_port && natt_port != 500) { | |
143 | flags |= SADB_X_EXT_NATT; | |
144 | ||
145 | switch (keepalive) { | |
146 | case IF_UTUN_CRYPTO_IPSEC_KEEPALIVE_NATT: | |
147 | flags |= SADB_X_EXT_NATT_KEEPALIVE; // normal keepalive packet | |
148 | break; | |
149 | case IF_UTUN_CRYPTO_IPSEC_KEEPALIVE_ESP: | |
150 | flags |= (SADB_X_EXT_ESP_KEEPALIVE | SADB_X_EXT_PUNT_RX_KEEPALIVE); // use an EMPTY ESP as a keepalive | |
151 | break; | |
152 | default: | |
153 | break; | |
154 | } | |
155 | ||
156 | switch (natd) { | |
157 | case IF_UTUN_CRYPTO_IPSEC_NATD_PEER: | |
158 | flags |= SADB_X_EXT_NATT_DETECTED_PEER; | |
159 | break; | |
160 | default: | |
161 | break; | |
162 | } | |
163 | } | |
164 | ||
165 | if (punt_rx_keepalive) { | |
166 | flags |= SADB_X_EXT_PUNT_RX_KEEPALIVE; | |
167 | } | |
168 | ||
169 | return flags; | |
170 | } | |
171 | ||
172 | static errno_t | |
173 | utun_ipsec_set_sah (struct secashead **sah, | |
174 | u_int8_t dir, | |
175 | u_int16_t proto, | |
176 | u_int8_t mode, | |
177 | u_int32_t reqid, | |
178 | struct sockaddr_storage *src_addr, | |
179 | struct sockaddr_storage *dst_addr) | |
180 | { | |
181 | struct secasindex saidx; | |
182 | ||
183 | // currently only support tunnel mode and ESP | |
184 | if (proto != IPPROTO_ESP || | |
185 | mode != IPSEC_MODE_TUNNEL) { | |
186 | return EINVAL; | |
187 | } | |
188 | if ((((struct sockaddr *)src_addr)->sa_family != AF_INET && | |
189 | ((struct sockaddr *)src_addr)->sa_family != AF_INET6) || | |
190 | (((struct sockaddr *)dst_addr)->sa_family != AF_INET && | |
191 | ((struct sockaddr *)dst_addr)->sa_family != AF_INET6)) { | |
192 | return EINVAL; | |
193 | } | |
194 | ||
195 | bzero(&saidx, sizeof(saidx)); | |
196 | saidx.proto = proto; | |
197 | saidx.mode = mode; | |
198 | saidx.reqid = reqid; | |
199 | bcopy(src_addr, &saidx.src, sizeof(saidx.src)); | |
200 | bcopy(dst_addr, &saidx.dst, sizeof(saidx.dst)); | |
201 | ||
202 | lck_mtx_lock(sadb_mutex); | |
203 | // TODO: add sah and policy (collision) check and prevention. ensure that there is no conflicting policy. | |
204 | // TDDO: ensure that key_spdaddxxx doesn't add a policy that's conflicting with any of our sahs. | |
205 | *sah = key_newsah2(&saidx, dir); | |
206 | lck_mtx_unlock(sadb_mutex); | |
207 | return 0; | |
208 | } | |
209 | ||
210 | static int | |
211 | utun_ipsec_clr_sahs (struct secashead **sah) | |
212 | { | |
213 | struct secasvar *sav; | |
214 | struct secasvar *nextsav; | |
215 | u_int state; | |
216 | ||
217 | lck_mtx_lock(sadb_mutex); | |
218 | for (state = 0; state < SADB_SASTATE_MAX; state++) { | |
219 | for (sav = LIST_FIRST(&(*sah)->savtree[state]); | |
220 | sav != NULL; | |
221 | sav = nextsav) { | |
222 | nextsav = LIST_NEXT(sav, chain); | |
223 | if (sav->state == SADB_SASTATE_LARVAL || | |
224 | sav->state == SADB_SASTATE_DEAD) { | |
225 | continue; | |
226 | } | |
227 | ||
228 | if (sav->utun_pcb) { | |
229 | sav->utun_pcb = NULL; | |
230 | sav->utun_is_keepalive_fn = NULL; | |
231 | sav->utun_in_fn = NULL; | |
232 | sav->refcnt--; // unlinked from pcb | |
233 | } else { | |
234 | printf("%s: SAV inconsistency\n", __FUNCTION__); | |
235 | } | |
236 | ||
237 | key_sa_chgstate(sav, SADB_SASTATE_DEAD); | |
238 | key_freesav(sav, KEY_SADB_LOCKED); | |
239 | } | |
240 | } | |
241 | ||
242 | // clear the rest of the SAs | |
243 | key_delsah(*sah); | |
244 | lck_mtx_unlock(sadb_mutex); | |
245 | return 0; | |
246 | } | |
247 | ||
248 | static void | |
249 | utun_ipsec_set_udp_encap_listen_port (utun_crypto_dir_t dir, | |
250 | u_int16_t natt_port) | |
251 | { | |
252 | if (dir == UTUN_CRYPTO_DIR_IN) { | |
253 | if (natt_port && natt_port != 500) { | |
254 | esp_udp_encap_port = natt_port; | |
255 | } | |
256 | } | |
257 | } | |
258 | ||
259 | static void | |
260 | utun_set_lifetime (struct sadb_lifetime *lfh, | |
261 | int type, | |
262 | u_int64_t l_time) | |
263 | { | |
264 | lfh->sadb_lifetime_len = (sizeof(*lfh) >> 3); // convert to words | |
265 | lfh->sadb_lifetime_exttype = type; | |
266 | lfh->sadb_lifetime_allocations = 0; | |
267 | lfh->sadb_lifetime_bytes = 0; | |
268 | lfh->sadb_lifetime_addtime = l_time; | |
269 | lfh->sadb_lifetime_usetime = l_time; | |
270 | } | |
271 | ||
272 | static struct sadb_key * | |
273 | utun_ipsec_set_keybuf (u_int16_t type, | |
274 | u_int8_t *key, | |
275 | u_int16_t key_len) | |
276 | { | |
277 | struct sadb_key *new; | |
278 | int len = sizeof(*new) + BITSTOBYTES(key_len); | |
279 | ||
280 | lck_mtx_lock(sadb_mutex); | |
281 | new = utun_alloc(len); | |
282 | if (new == NULL) { | |
283 | return NULL; | |
284 | } | |
285 | lck_mtx_unlock(sadb_mutex); | |
286 | bzero(new, len); | |
287 | new->sadb_key_len = BITSTOBYTES(key_len); | |
288 | new->sadb_key_exttype = type; | |
289 | new->sadb_key_bits = key_len; | |
290 | bcopy(key, &new[1], new->sadb_key_len); | |
291 | return new; | |
292 | } | |
293 | ||
294 | static errno_t | |
295 | utun_ipsec_alloc_sav (struct secashead *sah, | |
296 | struct secasvar **sav, | |
297 | struct utun_pcb *pcb, | |
298 | u_int8_t satype, | |
299 | u_int8_t alg_auth, | |
300 | u_int8_t alg_enc, | |
301 | u_int32_t flags, | |
302 | u_int8_t replay, | |
303 | u_int8_t *key_auth, | |
304 | u_int16_t key_auth_len, | |
305 | u_int8_t *key_enc, | |
306 | u_int16_t key_enc_len, | |
307 | u_int16_t natt_port, | |
308 | u_int32_t seq, | |
309 | u_int32_t spi, | |
310 | u_int32_t pid, | |
311 | u_int64_t lifetime_hard, | |
312 | u_int64_t lifetime_soft) | |
313 | { | |
314 | struct sadb_key *keye, *keya; | |
315 | struct sadb_lifetime lfh, lfs; | |
316 | ||
317 | if (*sav) { | |
318 | return EINVAL; | |
319 | } | |
320 | ||
321 | bzero(&lfh, sizeof(lfh)); | |
322 | utun_set_lifetime(&lfh, SADB_EXT_LIFETIME_HARD, lifetime_hard); | |
323 | bzero(&lfs, sizeof(lfs)); | |
324 | utun_set_lifetime(&lfs, SADB_EXT_LIFETIME_SOFT, lifetime_soft); | |
325 | ||
326 | if ((keya = utun_ipsec_set_keybuf(SADB_EXT_KEY_AUTH, key_auth, key_auth_len)) == NULL) { | |
327 | return ENOBUFS; | |
328 | } | |
329 | if ((keye = utun_ipsec_set_keybuf(SADB_EXT_KEY_ENCRYPT, key_enc, key_enc_len)) == NULL) { | |
330 | utun_free(keya); | |
331 | return ENOBUFS; | |
332 | } | |
333 | ||
334 | lck_mtx_lock(sadb_mutex); | |
335 | if ((*sav = key_newsav2(sah, | |
336 | satype, | |
337 | alg_auth, | |
338 | alg_enc, | |
339 | flags, | |
340 | replay, | |
341 | keya, | |
342 | key_auth_len, | |
343 | keye, | |
344 | key_enc_len, | |
345 | natt_port, | |
346 | seq, | |
347 | spi, | |
348 | pid, | |
349 | &lfh, | |
350 | &lfs)) == NULL) { | |
351 | lck_mtx_unlock(sadb_mutex); | |
352 | utun_free(keya); | |
353 | utun_free(keye); | |
354 | return ENOBUFS; | |
355 | } | |
356 | (*sav)->utun_pcb = (__typeof__((*sav)->utun_pcb))pcb; | |
357 | (*sav)->utun_is_keepalive_fn = (__typeof__((*sav)->utun_is_keepalive_fn))utun_pkt_is_ipsec_keepalive; | |
358 | (*sav)->utun_in_fn = (__typeof__((*sav)->utun_in_fn))utun_pkt_ipsec_input; | |
359 | (*sav)->refcnt++; // for the pcb | |
360 | lck_mtx_unlock(sadb_mutex); | |
361 | utun_free(keya); | |
362 | utun_free(keye); | |
363 | return 0; | |
364 | } | |
365 | ||
366 | static int | |
367 | utun_ipsec_free_sav (struct secasvar **sav) | |
368 | { | |
369 | lck_mtx_lock(sadb_mutex); | |
370 | if ((*sav)->utun_pcb) { | |
371 | (*sav)->utun_pcb = NULL; | |
372 | (*sav)->utun_is_keepalive_fn = NULL; | |
373 | (*sav)->utun_in_fn = NULL; | |
374 | } | |
375 | (*sav)->refcnt--; // unlinked from pcb | |
376 | key_sa_chgstate(*sav, SADB_SASTATE_DEAD); | |
377 | key_freesav(*sav, KEY_SADB_LOCKED); | |
378 | lck_mtx_unlock(sadb_mutex); | |
379 | *sav = NULL; | |
380 | return 0; | |
381 | } | |
382 | ||
383 | static int | |
384 | utun_ipsec_num_savs (struct secashead **sah) | |
385 | { | |
386 | struct secasvar *sav; | |
387 | struct secasvar *nextsav; | |
388 | u_int state; | |
389 | int n = 0; | |
390 | ||
391 | lck_mtx_lock(sadb_mutex); | |
392 | for (state = 0; state < SADB_SASTATE_MAX; state++) { | |
393 | for (sav = LIST_FIRST(&(*sah)->savtree[state]); | |
394 | sav != NULL; | |
395 | sav = nextsav) { | |
396 | nextsav = LIST_NEXT(sav, chain); | |
397 | if (sav->state == SADB_SASTATE_LARVAL || | |
398 | sav->state == SADB_SASTATE_DYING || | |
399 | sav->state == SADB_SASTATE_DEAD) { | |
400 | continue; | |
401 | } | |
402 | ||
403 | if (sav->utun_pcb) { | |
404 | n++; | |
405 | } else { | |
406 | printf("%s: SAV inconsistency\n", __FUNCTION__); | |
407 | } | |
408 | } | |
409 | } | |
410 | lck_mtx_unlock(sadb_mutex); | |
411 | ||
412 | return n; | |
413 | } | |
414 | ||
415 | static errno_t | |
416 | utun_ctl_config_crypto_keys_ipsec_v1 (struct utun_pcb *pcb, | |
417 | utun_crypto_keys_args_t *args, | |
418 | utun_crypto_keys_t *crypto_keys) | |
419 | { | |
420 | utun_crypto_keys_ipsec_args_v1_t *args_ipsec_v1 = &args->u.ipsec_v1; | |
421 | u_int8_t *varargs_buf = UTUN_CRYPTO_KEYS_ARGS_VARARGS_BUF(args); | |
422 | errno_t err; | |
423 | struct secashead *sah; | |
424 | u_int16_t proto; | |
425 | u_int8_t mode; | |
426 | u_int8_t satype, aalg, ealg; | |
427 | u_int32_t flags; | |
428 | ||
429 | if (args_ipsec_v1->key_auth_len > MAX_KEY_AUTH_LEN_BITS) { | |
430 | printf("%s: invalid auth key len %d, max %d\n", __FUNCTION__, | |
431 | args_ipsec_v1->key_auth_len, MAX_KEY_AUTH_LEN_BITS); | |
432 | return EINVAL; | |
433 | } | |
434 | if (args_ipsec_v1->key_enc_len > MAX_KEY_ENC_LEN_BITS) { | |
435 | printf("%s: invalid enc key len %d, max %d\n", __FUNCTION__, | |
436 | args_ipsec_v1->key_enc_len, MAX_KEY_ENC_LEN_BITS); | |
437 | return EINVAL; | |
438 | } | |
439 | if (args->varargs_buflen != (__typeof__(args->varargs_buflen))((BITSTOBYTES(args_ipsec_v1->key_auth_len) + | |
440 | BITSTOBYTES(args_ipsec_v1->key_enc_len)))) { | |
441 | printf("%s: len check failed (%d,%d, %d)\n", __FUNCTION__, | |
442 | args->varargs_buflen, args_ipsec_v1->key_auth_len, args_ipsec_v1->key_enc_len); | |
443 | return EINVAL; | |
444 | } | |
445 | sah = IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAH(crypto_keys); | |
446 | if (!sah) { | |
447 | // TODO: make sure we pass through this once | |
448 | proto = utun_ipsec_proto_to_sadb_proto(args_ipsec_v1->proto); | |
449 | mode = utun_ipsec_mode_to_sadb_mode(args_ipsec_v1->mode); | |
450 | ||
451 | if ((err = utun_ipsec_set_sah(&IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAH(crypto_keys), | |
452 | UTUN_CRYPTO_DIR_TO_IPSEC_DIR(args->dir), | |
453 | proto, | |
454 | mode, | |
455 | args_ipsec_v1->reqid, | |
456 | &args_ipsec_v1->src_addr, | |
457 | &args_ipsec_v1->dst_addr))) { | |
458 | return err; | |
459 | } | |
460 | sah = IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAH(crypto_keys); | |
461 | if (!sah) { | |
462 | return EBADF; | |
463 | } | |
464 | } | |
465 | ||
466 | satype = utun_ipsec_proto_to_sadb_satype(args_ipsec_v1->proto); | |
467 | aalg = utun_ipsec_auth_to_sadb_aalg(args_ipsec_v1->alg_auth); | |
468 | ealg = utun_ipsec_enc_to_sadb_ealg(args_ipsec_v1->alg_enc); | |
469 | flags = utun_ipsec_keepalive_and_nat_info_to_sadb_flags(args_ipsec_v1->keepalive, | |
470 | args_ipsec_v1->punt_rx_keepalive, | |
471 | args_ipsec_v1->natd, | |
472 | args_ipsec_v1->natt_port); | |
473 | ||
474 | if ((err = utun_ipsec_alloc_sav(sah, | |
475 | &IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAV(crypto_keys), | |
476 | pcb, | |
477 | satype, | |
478 | aalg, | |
479 | ealg, | |
480 | flags, | |
481 | args_ipsec_v1->replay, | |
482 | varargs_buf, | |
483 | args_ipsec_v1->key_auth_len, | |
484 | (varargs_buf + BITSTOBYTES(args_ipsec_v1->key_auth_len)), | |
485 | args_ipsec_v1->key_enc_len, | |
486 | args_ipsec_v1->natt_port, | |
487 | args_ipsec_v1->seq, | |
488 | args_ipsec_v1->spi, | |
489 | args_ipsec_v1->pid, | |
490 | args_ipsec_v1->lifetime_hard, | |
491 | args_ipsec_v1->lifetime_soft))) { | |
492 | return err; | |
493 | } | |
494 | crypto_keys->state.u.ipsec.proto = sah->saidx.proto; | |
495 | crypto_keys->state.u.ipsec.mode = sah->saidx.mode; | |
496 | if (((struct sockaddr *)&sah->saidx.src)->sa_family == AF_INET) { | |
497 | crypto_keys->state.u.ipsec.ifamily = IPPROTO_IPV4; | |
498 | } else { | |
499 | crypto_keys->state.u.ipsec.ifamily = IPPROTO_IPV6; | |
500 | } | |
501 | crypto_keys->state.u.ipsec.spi = args_ipsec_v1->spi; | |
502 | utun_ipsec_set_udp_encap_listen_port(args->dir, args_ipsec_v1->natt_port); | |
503 | return 0; | |
504 | } | |
505 | ||
506 | static errno_t | |
507 | utun_ctl_unconfig_crypto_keys_ipsec_v1 (utun_crypto_keys_t *crypto_keys) | |
508 | { | |
509 | if (!IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAH(crypto_keys)) { | |
510 | return EBADF; | |
511 | } | |
512 | if (!IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAV(crypto_keys)) { | |
513 | return EBADF; | |
514 | } | |
515 | if (utun_ipsec_free_sav(&IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAV(crypto_keys))) { | |
516 | return EADDRNOTAVAIL; | |
517 | } | |
518 | if (!utun_ipsec_num_savs(&IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAH(crypto_keys))) { | |
519 | (void)utun_ipsec_clr_sahs(&IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAH(crypto_keys)); | |
520 | ||
521 | // release sah | |
522 | IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAH(crypto_keys) = NULL; | |
523 | } | |
524 | ||
525 | return 0; | |
526 | } | |
527 | ||
528 | static void | |
529 | utun_set_spirange (struct sadb_spirange *spirange, | |
530 | u_int32_t spirange_min, | |
531 | u_int32_t spirange_max) | |
532 | { | |
533 | spirange->sadb_spirange_min = spirange_min; | |
534 | spirange->sadb_spirange_max = spirange_max; | |
535 | } | |
536 | ||
537 | static u_int32_t | |
538 | utun_ipsec_get_spi (struct sockaddr_storage *src_addr, | |
539 | struct sockaddr_storage *dst_addr, | |
540 | u_int16_t proto, | |
541 | u_int8_t mode, | |
542 | u_int32_t reqid, | |
543 | u_int32_t spirange_min, | |
544 | u_int32_t spirange_max) | |
545 | { | |
546 | struct sadb_spirange spirange; | |
547 | utun_set_spirange(&spirange, spirange_min, spirange_max); | |
548 | // TODO: should this allocate an SAH? | |
549 | return key_getspi2((struct sockaddr *)src_addr, | |
550 | (struct sockaddr *)dst_addr, | |
551 | proto, | |
552 | mode, | |
553 | reqid, | |
554 | &spirange); | |
555 | } | |
556 | ||
557 | static errno_t | |
558 | utun_ctl_generate_crypto_keys_idx_ipsec_v1 (utun_crypto_keys_idx_args_t *args) | |
559 | { | |
560 | utun_crypto_keys_idx_ipsec_args_v1_t *args_ipsec_v1 = &args->u.ipsec_v1; | |
561 | u_int16_t proto; | |
562 | u_int8_t mode; | |
563 | ||
564 | proto = utun_ipsec_proto_to_sadb_proto(args_ipsec_v1->proto); | |
565 | mode = utun_ipsec_mode_to_sadb_mode(args_ipsec_v1->mode); | |
566 | ||
567 | args_ipsec_v1->spi = 0; | |
568 | if ((args_ipsec_v1->spi = utun_ipsec_get_spi(&args_ipsec_v1->src_addr, | |
569 | &args_ipsec_v1->dst_addr, | |
570 | proto, | |
571 | mode, | |
572 | args_ipsec_v1->reqid, | |
573 | args_ipsec_v1->spirange_min, | |
574 | args_ipsec_v1->spirange_max)) == 0) { | |
575 | return ENOBUFS; | |
576 | } | |
577 | return 0; | |
578 | } | |
579 | ||
580 | void | |
581 | utun_cleanup_all_crypto_ipsec (struct utun_pcb *pcb) | |
582 | { | |
583 | int idx; | |
584 | utun_crypto_ctx_t *crypto_ctx; | |
585 | utun_crypto_keys_t *cur_crypto_keys, *nxt_crypto_keys; | |
586 | ||
587 | for (idx = 0; idx < UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_MAX); idx++) { | |
588 | crypto_ctx = &pcb->utun_crypto_ctx[idx]; | |
589 | if (!crypto_ctx->valid || | |
590 | crypto_ctx->type != UTUN_CRYPTO_TYPE_IPSEC) { | |
591 | continue; | |
592 | } | |
593 | ||
594 | // flush all crypto materials | |
595 | for (cur_crypto_keys = (__typeof__(cur_crypto_keys))LIST_FIRST(&crypto_ctx->keys_listhead); | |
596 | cur_crypto_keys != NULL; | |
597 | cur_crypto_keys = nxt_crypto_keys) { | |
598 | nxt_crypto_keys = (__typeof__(nxt_crypto_keys))LIST_NEXT(cur_crypto_keys, chain); | |
599 | ||
600 | if (!cur_crypto_keys->valid) { | |
601 | continue; | |
602 | } | |
603 | ||
604 | if (IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAV(cur_crypto_keys)) { | |
605 | (void)utun_ipsec_free_sav(&IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAV(cur_crypto_keys)); | |
606 | } | |
607 | ||
608 | if (IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAH(cur_crypto_keys)) { | |
609 | (void)utun_ipsec_clr_sahs(&IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAH(cur_crypto_keys)); | |
610 | } | |
611 | ||
612 | LIST_REMOVE(cur_crypto_keys, chain); | |
613 | bzero(cur_crypto_keys, sizeof(*cur_crypto_keys)); | |
614 | utun_free(cur_crypto_keys); | |
615 | } | |
616 | ||
617 | bzero(crypto_ctx, sizeof(*crypto_ctx)); | |
618 | } | |
619 | } | |
620 | ||
621 | static errno_t | |
622 | utun_ctl_enable_crypto_ipsec_v1 (__unused utun_crypto_args_t *args) | |
623 | { | |
624 | return 0; | |
625 | } | |
626 | ||
627 | /* | |
628 | * Summary: enables ipsec crypto info for the specified utun. | |
629 | */ | |
630 | void | |
631 | utun_ctl_enable_crypto_ipsec(__unused struct utun_pcb *pcb, | |
632 | utun_crypto_args_t *args) | |
633 | { | |
634 | lck_mtx_lock(sadb_mutex); | |
635 | /* Turn off the ipsec bypass, if already on */ | |
636 | if (ipsec_bypass) { | |
637 | ipsec_bypass = 0; | |
638 | } | |
639 | if (args->ver == UTUN_CRYPTO_KEYS_IPSEC_VER_1) { | |
640 | (void)utun_ctl_enable_crypto_ipsec_v1(args); | |
641 | } | |
642 | lck_mtx_unlock(sadb_mutex); | |
643 | } | |
644 | ||
645 | /* | |
646 | * Summary: disables ipsec crypto info for the specified utun. | |
647 | */ | |
648 | void | |
649 | utun_ctl_disable_crypto_ipsec(__unused struct utun_pcb *pcb) | |
650 | { | |
651 | utun_cleanup_all_crypto_ipsec(pcb); | |
652 | lck_mtx_lock(sadb_mutex); | |
653 | /* Turn on the ipsec bypass, if there are no other policies */ | |
654 | if (!ipsec_policy_count && !ipsec_bypass) // TODO: ipsec_policy_count may be 1 by default | |
655 | ipsec_bypass = 1; | |
656 | utun_punt_rx_keepalive = 0; | |
657 | lck_mtx_unlock(sadb_mutex); | |
658 | } | |
659 | ||
660 | errno_t | |
661 | utun_ctl_config_crypto_keys_ipsec (struct utun_pcb *pcb, | |
662 | utun_crypto_keys_args_t *args, | |
663 | utun_crypto_keys_t *crypto_keys) | |
664 | { | |
665 | if (args->ver == UTUN_CRYPTO_KEYS_IPSEC_VER_1) { | |
666 | return(utun_ctl_config_crypto_keys_ipsec_v1(pcb, args, crypto_keys)); | |
667 | } else { | |
668 | printf("%s: ver unsupported (%d, %d)\n", __FUNCTION__, args->ver, UTUN_CRYPTO_KEYS_IPSEC_VER_1); | |
669 | return EINVAL; | |
670 | } | |
671 | } | |
672 | ||
673 | errno_t | |
674 | utun_ctl_unconfig_crypto_keys_ipsec (utun_crypto_keys_args_t *args, | |
675 | utun_crypto_keys_t *crypto_keys) | |
676 | { | |
677 | if (args->ver == UTUN_CRYPTO_KEYS_IPSEC_VER_1) { | |
678 | return(utun_ctl_unconfig_crypto_keys_ipsec_v1(crypto_keys)); | |
679 | } else { | |
680 | printf("%s: ver unsupported (%d, %d)\n", __FUNCTION__, args->ver, UTUN_CRYPTO_KEYS_IPSEC_VER_1); | |
681 | return EINVAL; | |
682 | } | |
683 | } | |
684 | ||
685 | errno_t | |
686 | utun_ctl_generate_crypto_keys_idx_ipsec (utun_crypto_keys_idx_args_t *args) | |
687 | { | |
688 | if (args->ver == UTUN_CRYPTO_KEYS_IPSEC_VER_1) { | |
689 | return(utun_ctl_generate_crypto_keys_idx_ipsec_v1(args)); | |
690 | } else { | |
691 | printf("%s: ver unsupported (%d, %d)\n", __FUNCTION__, args->ver, UTUN_CRYPTO_KEYS_IPSEC_VER_1); | |
692 | return EINVAL; | |
693 | } | |
694 | } | |
695 | ||
696 | int | |
697 | utun_pkt_ipsec_output (struct utun_pcb *pcb, mbuf_t *pkt) | |
698 | { | |
699 | utun_crypto_keys_t *crypto_keys = IF_UTUN_GET_TX_CRYPTO_KEYS(pcb); | |
700 | struct secasvar *sav; | |
701 | protocol_family_t proto; | |
702 | mbuf_t new; | |
703 | int err; | |
704 | struct route *ro = NULL; | |
705 | struct route ro_copy; | |
706 | struct ip_out_args ipoa = { IFSCOPE_NONE, { 0 }, IPOAF_SELECT_SRCIF }; | |
707 | ||
708 | if (crypto_keys && | |
709 | crypto_keys->state.u.ipsec.proto == IPPROTO_ESP && | |
710 | (sav = IF_UTUN_GET_CRYPTO_KEYS_IPSEC_SAV(crypto_keys)) && | |
711 | sav->state == SADB_SASTATE_MATURE) { | |
712 | // TODO: update stats to increment outgoing packets | |
713 | // TODO: allow empty packets thru | |
714 | ||
715 | proto = ntohl(*(mtod(*pkt, protocol_family_t *))); | |
716 | m_adj(*pkt, sizeof(protocol_family_t)); | |
717 | ||
718 | bzero(&ro_copy, sizeof(ro_copy)); | |
719 | ||
720 | if ((proto == AF_UTUN || proto == AF_INET) && crypto_keys->state.u.ipsec.ifamily == IPPROTO_IPV4) { | |
721 | struct ip *ip; | |
722 | struct sockaddr_in *dst4; | |
723 | ||
724 | if (proto == AF_INET) { | |
725 | if ((*pkt)->m_len < (__typeof__((*pkt)->m_len))sizeof(*ip)) { | |
726 | if (!(*pkt = m_pullup(*pkt, sizeof(*ip)))) { | |
727 | printf("%s: m_pullup failed\n", __FUNCTION__); | |
728 | return 0; | |
729 | } | |
730 | } | |
731 | ||
732 | // split the mbuf chain to put the ip header and payloads in separate mbufs | |
733 | new = ipsec4_splithdr(*pkt); | |
734 | if (!new) { | |
735 | printf("%s: ipsec4_splithdr(1) failed\n", __FUNCTION__); | |
736 | if (ro_copy.ro_rt != NULL) { | |
737 | rtfree(ro_copy.ro_rt); | |
738 | } | |
739 | *pkt = NULL; | |
740 | return 0; | |
741 | } | |
742 | *pkt = new; | |
743 | ||
744 | // encapsulate with the outer header | |
745 | if ((err = ipsec4_encapsulate(new, sav))) { | |
746 | printf("%s: ipsec4_encapsulate failed (%d)\n", __FUNCTION__, err); | |
747 | *pkt = NULL; | |
748 | return 0; | |
749 | } | |
750 | ||
751 | } else { | |
752 | // otherwise it's AF_UTUN which will be a keepalive packet to be encapsulated, encrypted and sent | |
753 | // encapsulate with the outer header | |
754 | if ((err = ipsec4_encapsulate_utun_esp_keepalive(pkt, sav))) { | |
755 | printf("%s: ipsec4_encapsulate failed (%d)\n", __FUNCTION__, err); | |
756 | return 0; | |
757 | } | |
758 | new = *pkt; | |
759 | } | |
760 | ||
761 | ip = mtod(new, __typeof__(ip)); | |
762 | // grab sadb_mutex, to update sah's route cache and get a local copy of it | |
763 | lck_mtx_lock(sadb_mutex); | |
764 | ro = &sav->sah->sa_route; | |
765 | dst4 = (struct sockaddr_in *)(void *)&ro->ro_dst; | |
766 | if (ro->ro_rt) { | |
767 | RT_LOCK(ro->ro_rt); | |
768 | } | |
769 | if (ro->ro_rt != NULL && | |
770 | (ro->ro_rt->generation_id != route_generation || | |
771 | !(ro->ro_rt->rt_flags & RTF_UP) || | |
772 | dst4->sin_addr.s_addr != ip->ip_dst.s_addr)) { | |
773 | RT_UNLOCK(ro->ro_rt); | |
774 | rtfree(ro->ro_rt); | |
775 | ro->ro_rt = NULL; | |
776 | } | |
777 | if (ro->ro_rt == NULL) { | |
778 | dst4->sin_family = AF_INET; | |
779 | dst4->sin_len = sizeof(*dst4); | |
780 | dst4->sin_addr = ip->ip_dst; | |
781 | rtalloc(ro); | |
782 | if (ro->ro_rt) { | |
783 | RT_LOCK(ro->ro_rt); | |
784 | } else { | |
785 | printf("%s: rtalloc(1) failed\n", __FUNCTION__); | |
786 | mbuf_freem(new); | |
787 | *pkt = NULL; | |
788 | return 0; | |
789 | } | |
790 | } | |
791 | if (ro->ro_rt->rt_flags & RTF_GATEWAY) { | |
792 | dst4 = (struct sockaddr_in *)(void *)ro->ro_rt->rt_gateway; | |
793 | } | |
794 | RT_UNLOCK(ro->ro_rt); | |
795 | route_copyout(&ro_copy, ro, sizeof(ro_copy)); | |
796 | // release sadb_mutex, after updating sah's route cache and getting a local copy | |
797 | lck_mtx_unlock(sadb_mutex); | |
798 | ||
799 | // split the mbuf chain to put the ip header and payloads in separate mbufs | |
800 | new = ipsec4_splithdr(*pkt); | |
801 | if (!new) { | |
802 | printf("%s: ipsec4_splithdr(2) failed\n", __FUNCTION__); | |
803 | if (ro_copy.ro_rt != NULL) { | |
804 | rtfree(ro_copy.ro_rt); | |
805 | } | |
806 | *pkt = NULL; | |
807 | return 0; | |
808 | } | |
809 | *pkt = new; | |
810 | ||
811 | if ((err = esp4_output(new, sav))) { | |
812 | printf("%s: esp4_output failed (%d)\n", __FUNCTION__, err); | |
813 | if (ro_copy.ro_rt != NULL) { | |
814 | rtfree(ro_copy.ro_rt); | |
815 | } | |
816 | *pkt = NULL; | |
817 | return 0; // drop | |
818 | } | |
819 | ||
820 | ip = mtod(new, __typeof__(ip)); | |
821 | ip->ip_len = ntohs(ip->ip_len); /* flip len field before calling ip_output */ | |
822 | } else if ((proto == AF_UTUN || proto == AF_INET6) && crypto_keys->state.u.ipsec.ifamily == IPPROTO_IPV6) { | |
823 | int plen; | |
824 | struct ip6_hdr *ip6; | |
825 | struct sockaddr_in6 *dst6; | |
826 | ||
827 | if (proto == AF_INET6) { | |
828 | // split the mbuf chain to put the ip header and payloads in separate mbufs | |
829 | new = ipsec6_splithdr(*pkt); | |
830 | if (!new) { | |
831 | printf("%s: ipsec6_splithdr(1) failed\n", __FUNCTION__); | |
832 | if (ro_copy.ro_rt != NULL) { | |
833 | rtfree(ro_copy.ro_rt); | |
834 | } | |
835 | *pkt = NULL; | |
836 | return 0; | |
837 | } | |
838 | *pkt = new; | |
839 | ||
840 | // encapsulate with the outer header | |
841 | if ((err = ipsec6_encapsulate(new, sav))) { | |
842 | printf("%s: ipsec6_encapsulate failed (%d)\n", __FUNCTION__, err); | |
843 | *pkt = NULL; | |
844 | return 0; | |
845 | } | |
846 | ||
847 | } else { | |
848 | // otherwise it's AF_UTUN which will be a keepalive packet to be encapsulated, encrypted and sent | |
849 | // encapsulate with the outer header | |
850 | if ((err = ipsec6_encapsulate_utun_esp_keepalive(pkt, sav))) { | |
851 | printf("%s: ipsec6_encapsulate failed (%d)\n", __FUNCTION__, err); | |
852 | return 0; | |
853 | } | |
854 | new = *pkt; | |
855 | } | |
856 | ||
857 | ip6 = mtod(new, __typeof__(ip6)); | |
858 | // grab sadb_mutex, before updating sah's route cache | |
859 | lck_mtx_lock(sadb_mutex); | |
860 | ro = &sav->sah->sa_route; | |
861 | dst6 = (struct sockaddr_in6 *)(void *)&ro->ro_dst; | |
862 | if (ro->ro_rt) { | |
863 | RT_LOCK(ro->ro_rt); | |
864 | } | |
865 | if (ro->ro_rt != NULL && | |
866 | (ro->ro_rt->generation_id != route_generation || | |
867 | !(ro->ro_rt->rt_flags & RTF_UP) || | |
868 | !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))) { | |
869 | RT_UNLOCK(ro->ro_rt); | |
870 | rtfree(ro->ro_rt); | |
871 | ro->ro_rt = NULL; | |
872 | } | |
873 | if (ro->ro_rt == NULL) { | |
874 | bzero(dst6, sizeof(*dst6)); | |
875 | dst6->sin6_family = AF_INET6; | |
876 | dst6->sin6_len = sizeof(*dst6); | |
877 | dst6->sin6_addr = ip6->ip6_dst; | |
878 | rtalloc(ro); | |
879 | if (ro->ro_rt) { | |
880 | RT_LOCK(ro->ro_rt); | |
881 | } else { | |
882 | printf("%s: rtalloc(2) failed\n", __FUNCTION__); | |
883 | mbuf_freem(new); | |
884 | *pkt = NULL; | |
885 | return 0; | |
886 | } | |
887 | } | |
888 | if (ro->ro_rt->rt_flags & RTF_GATEWAY) { | |
889 | dst6 = (struct sockaddr_in6 *)(void *)ro->ro_rt->rt_gateway; | |
890 | } | |
891 | RT_UNLOCK(ro->ro_rt); | |
892 | route_copyout(&ro_copy, ro, sizeof(ro_copy)); | |
893 | // release sadb_mutex, after updating sah's route cache and getting a local copy | |
894 | lck_mtx_unlock(sadb_mutex); | |
895 | ||
896 | // split the mbuf chain to put the ip header and payloads in separate mbufs | |
897 | new = ipsec6_splithdr(*pkt); | |
898 | if (!new) { | |
899 | printf("%s: ipsec6_splithdr failed\n", __FUNCTION__); | |
900 | if (ro_copy.ro_rt != NULL) { | |
901 | rtfree(ro_copy.ro_rt); | |
902 | } | |
903 | *pkt = NULL; | |
904 | return 0; | |
905 | } | |
906 | *pkt = new; | |
907 | ||
908 | if ((err = esp6_output(new, mtod(new, u_char *), new->m_next, sav))) { | |
909 | printf("%s: esp6_output failed (%d)\n", __FUNCTION__, err); | |
910 | if (ro_copy.ro_rt != NULL) { | |
911 | rtfree(ro_copy.ro_rt); | |
912 | } | |
913 | *pkt = NULL; | |
914 | return 0; // drop | |
915 | } | |
916 | ||
917 | plen = new->m_pkthdr.len - sizeof(struct ip6_hdr); | |
918 | if (plen > IPV6_MAXPACKET) { | |
919 | printf("%s: esp6_output failed due to invalid len (%d)\n", __FUNCTION__, plen); | |
920 | if (ro_copy.ro_rt != NULL) { | |
921 | rtfree(ro_copy.ro_rt); | |
922 | } | |
923 | mbuf_freem(new); | |
924 | *pkt = NULL; | |
925 | return 0; | |
926 | } | |
927 | ip6 = mtod(new, __typeof__(ip6)); | |
928 | ip6->ip6_plen = ntohs(ip6->ip6_plen); /* flip len field before calling ip_output */ | |
929 | } else { | |
930 | printf("%s: packet's proto (%d) mismatched the context's proto (%d)\n", __FUNCTION__, | |
931 | proto, crypto_keys->state.u.ipsec.ifamily); | |
932 | mbuf_freem(*pkt); | |
933 | *pkt = NULL; | |
934 | return 0; | |
935 | } | |
936 | ||
937 | if (pcb->utun_ifp) { | |
938 | ifnet_stat_increment_out(pcb->utun_ifp, 1, mbuf_pkthdr_len(new), 0); | |
939 | } | |
940 | ||
941 | if ((err = ip_output(new, NULL, &ro_copy, | |
942 | (IP_OUTARGS | IP_NOIPSEC), NULL, &ipoa))) { | |
943 | printf("%s: ip_output failed (%d)\n", __FUNCTION__, err); | |
944 | } | |
945 | lck_mtx_lock(sadb_mutex); | |
946 | route_copyin(&ro_copy, ro, sizeof(*ro)); | |
947 | lck_mtx_unlock(sadb_mutex); | |
948 | return 0; | |
949 | } else { | |
950 | printf("%s: no suitable crypto-mat\n", __FUNCTION__); | |
951 | } | |
952 | return -1; | |
953 | } | |
954 | ||
955 | // returns 0 if false, 1 if true, and -1 if there was a failure | |
956 | int | |
957 | utun_pkt_is_ipsec_keepalive (struct utun_pcb *pcb, mbuf_t *pkt, u_int16_t nxt, u_int32_t flags, size_t offs) | |
958 | { | |
959 | int result; | |
960 | u_int8_t *data; | |
961 | int size_diff; | |
962 | ||
963 | if (!pcb->utun_ctlref) { | |
964 | printf("%s - utun ctlref cleared\n", __FUNCTION__); | |
965 | return 0; | |
966 | } | |
967 | ||
968 | if (!(pcb->utun_flags & UTUN_FLAGS_CRYPTO)) { | |
969 | printf("%s - crypto disabled\n", __FUNCTION__); | |
970 | return 0; | |
971 | } | |
972 | ||
973 | if ((*pkt)->m_pkthdr.len < 0) { | |
974 | printf("%s - invalid hdr len, len %d, offs %lu\n", __FUNCTION__, (*pkt)->m_pkthdr.len, offs); | |
975 | return 0; | |
976 | } | |
977 | ||
978 | if ((size_t)(*pkt)->m_pkthdr.len <= offs) { | |
979 | printf("%s - invalid offset, len %d, offs %lu\n", __FUNCTION__, (*pkt)->m_pkthdr.len, offs); | |
980 | return 0; | |
981 | } | |
982 | ||
983 | if ((*pkt)->m_len < 0) { | |
984 | printf("%s - invalid len, len %d, offs %lu\n", __FUNCTION__, (*pkt)->m_len, offs); | |
985 | return 0; | |
986 | } | |
987 | ||
988 | // pullup offs + 1 bytes | |
989 | if ((size_t)(*pkt)->m_len < (offs + 1)) { | |
990 | if ((*pkt = m_pullup(*pkt, (offs + 1))) == NULL) { | |
991 | printf("%s: m_pullup failed\n", __FUNCTION__); | |
992 | return -1; | |
993 | } | |
994 | } | |
995 | ||
996 | if (pcb->utun_ifp) { | |
997 | ifnet_stat_increment_in(pcb->utun_ifp, 1, mbuf_pkthdr_len(*pkt), 0); | |
998 | } | |
999 | ||
1000 | size_diff = (*pkt)->m_pkthdr.len - offs; | |
1001 | data = mtod(*pkt, __typeof(data)); | |
1002 | data += offs; | |
1003 | ||
1004 | // ESP keepalive meets all these conditions: ESP trailer's next proto indicates IP, the decrypted packet only has one zero'd byte in it. | |
1005 | if (flags & SADB_X_EXT_ESP_KEEPALIVE && | |
1006 | nxt == IPPROTO_IPV4 && | |
1007 | size_diff == 1 && | |
1008 | *data == 0) { | |
1009 | // TODO: update stats to increment keepalives and current timestamp | |
1010 | if (utun_punt_rx_keepalive || | |
1011 | flags & SADB_X_EXT_PUNT_RX_KEEPALIVE) { | |
1012 | ||
1013 | // strip all headers | |
1014 | if ((size_t)(*pkt)->m_len >= (offs + size_diff)) { | |
1015 | ovbcopy((caddr_t)data, (data + offs), size_diff); | |
1016 | (*pkt)->m_data += offs; | |
1017 | (*pkt)->m_len -= offs; | |
1018 | (*pkt)->m_pkthdr.len -= offs; | |
1019 | } else { | |
1020 | struct mbuf *n; | |
1021 | ||
1022 | n = m_split(*pkt, offs, M_DONTWAIT); | |
1023 | if (n == NULL) { | |
1024 | /* *pkt is retained by m_split */ | |
1025 | mbuf_freem(*pkt); | |
1026 | *pkt = NULL; | |
1027 | return -1; | |
1028 | } | |
1029 | m_adj(n, offs); | |
1030 | mbuf_freem(*pkt); | |
1031 | *pkt = n; | |
1032 | } | |
1033 | ||
1034 | // keepalive is being punted up to the control socket, prepend with a special packet type (PF_UTUN) | |
1035 | if (mbuf_prepend(pkt, sizeof(protocol_family_t), MBUF_DONTWAIT) != 0) { | |
1036 | printf("%s - ifnet_output prepend failed\n", __FUNCTION__); | |
1037 | return -1; | |
1038 | } | |
1039 | if ((size_t)(*pkt)->m_len < (sizeof(protocol_family_t) + size_diff)) { | |
1040 | if ((*pkt = m_pullup(*pkt, (sizeof(protocol_family_t) + size_diff))) == NULL) { | |
1041 | printf("%s: m_pullup failed\n", __FUNCTION__); | |
1042 | return -1; | |
1043 | } | |
1044 | } | |
1045 | ||
1046 | // mark UTUN/Keepalive packet | |
1047 | *(protocol_family_t *)mbuf_data(*pkt) = htonl(PF_UTUN); | |
1048 | ||
1049 | result = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, *pkt, CTL_DATA_EOR); | |
1050 | if (result != 0) { | |
1051 | printf("%s: - ctl_enqueuembuf failed: %d\n", __FUNCTION__, result); | |
1052 | mbuf_freem(*pkt); | |
1053 | return -1; | |
1054 | } | |
1055 | *pkt = NULL; | |
1056 | } | |
1057 | return 1; | |
1058 | } | |
1059 | return 0; | |
1060 | } | |
1061 | ||
1062 | int | |
1063 | utun_pkt_ipsec_input (struct utun_pcb *pcb, mbuf_t *pkt, protocol_family_t family) | |
1064 | { | |
1065 | if (!m_tag_locate(*pkt, KERNEL_MODULE_TAG_ID, KERNEL_TAG_TYPE_IPSEC, NULL)) { | |
1066 | return EINVAL; | |
1067 | } | |
1068 | ||
1069 | if (!(pcb->utun_flags & UTUN_FLAGS_CRYPTO)) { | |
1070 | printf("%s - crypto disabled\n", __FUNCTION__); | |
1071 | return EINVAL; | |
1072 | } | |
1073 | ||
1074 | if (!pcb->utun_ifp) { | |
1075 | printf("%s - utun ifp cleared\n", __FUNCTION__); | |
1076 | return EINVAL; | |
1077 | } | |
1078 | ||
1079 | // place protocol number at the beginning of the mbuf | |
1080 | if (mbuf_prepend(pkt, sizeof(protocol_family_t), MBUF_DONTWAIT) != 0) { | |
1081 | printf("%s - ifnet_output prepend failed\n", __FUNCTION__); | |
1082 | return ENOBUFS; | |
1083 | } | |
1084 | *(protocol_family_t *)mbuf_data(*pkt) = htonl(family); | |
1085 | ||
1086 | (void)utun_pkt_input(pcb, *pkt); | |
1087 | return 0; | |
1088 | } |