]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
kernel-interface: Optionally pass CPU ID for which an acquire was triggered
[thirdparty/strongswan.git] / src / libcharon / plugins / kernel_wfp / kernel_wfp_ipsec.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 *
4 * Copyright (C) secunet Security Networks AG
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 /* Windows 7, for some fwpmu.h functionality */
18 #define _WIN32_WINNT 0x0601
19
20 #include "kernel_wfp_compat.h"
21 #include "kernel_wfp_ipsec.h"
22
23 #include <daemon.h>
24 #include <threading/mutex.h>
25 #include <collections/array.h>
26 #include <collections/hashtable.h>
27 #include <processing/jobs/callback_job.h>
28
29 #ifndef IPPROTO_IPIP
30 #define IPPROTO_IPIP 4
31 #endif
32 #ifndef IPPROTO_IPV6
33 #define IPPROTO_IPV6 41
34 #endif
35
36 typedef struct private_kernel_wfp_ipsec_t private_kernel_wfp_ipsec_t;
37
38 struct private_kernel_wfp_ipsec_t {
39
40 /**
41 * Public interface
42 */
43 kernel_wfp_ipsec_t public;
44
45 /**
46 * Next SPI to allocate
47 */
48 refcount_t nextspi;
49
50 /**
51 * Mix value to distribute SPI allocation randomly
52 */
53 uint32_t mixspi;
54
55 /**
56 * IKE bypass filters, as UINT64 filter LUID
57 */
58 array_t *bypass;
59
60 /**
61 * Temporary SAD/SPD entries referenced reqid, as uintptr_t => entry_t
62 */
63 hashtable_t *tsas;
64
65 /**
66 * SAD/SPD entries referenced by inbound SA, as sa_entry_t => entry_t
67 */
68 hashtable_t *isas;
69
70 /**
71 * SAD/SPD entries referenced by outbound SA, as sa_entry_t => entry_t
72 */
73 hashtable_t *osas;
74
75 /**
76 * Installed routes, as route_t => route_t
77 */
78 hashtable_t *routes;
79
80 /**
81 * Installed traps, as trap_t => trap_t
82 */
83 hashtable_t *traps;
84
85 /**
86 * Mutex for accessing entries
87 */
88 mutex_t *mutex;
89
90 /**
91 * WFP session handle
92 */
93 HANDLE handle;
94
95 /**
96 * Provider charon registers as
97 */
98 FWPM_PROVIDER0 provider;
99
100 /**
101 * Event handle
102 */
103 HANDLE event;
104 };
105
106 /**
107 * Security association entry
108 */
109 typedef struct {
110 /** SPI for this SA */
111 uint32_t spi;
112 /** protocol, IPPROTO_ESP/IPPROTO_AH */
113 uint8_t protocol;
114 /** hard lifetime of SA */
115 uint32_t lifetime;
116 /** destination host address for this SPI */
117 host_t *dst;
118 struct {
119 /** algorithm */
120 uint16_t alg;
121 /** key */
122 chunk_t key;
123 } integ, encr;
124 } sa_entry_t;
125
126 /**
127 * Hash function for sas lookup table
128 */
129 static u_int hash_sa(sa_entry_t *key)
130 {
131 return chunk_hash_inc(chunk_from_thing(key->spi),
132 chunk_hash(key->dst->get_address(key->dst)));
133 }
134
135 /**
136 * equals function for sas lookup table
137 */
138 static bool equals_sa(sa_entry_t *a, sa_entry_t *b)
139 {
140 return a->spi == b->spi && a->dst->ip_equals(a->dst, b->dst);
141 }
142
143 /**
144 * Security policy entry
145 */
146 typedef struct {
147 /** policy source addresses */
148 traffic_selector_t *src;
149 /** policy destination addresses */
150 traffic_selector_t *dst;
151 /** WFP allocated LUID for inbound filter ID */
152 uint64_t policy_in;
153 /** WFP allocated LUID for outbound filter ID */
154 uint64_t policy_out;
155 /** WFP allocated LUID for forward inbound filter ID, tunnel mode only */
156 uint64_t policy_fwd_in;
157 /** WFP allocated LUID for forward outbound filter ID, tunnel mode only */
158 uint64_t policy_fwd_out;
159 /** have installed a route for it? */
160 bool route;
161 } sp_entry_t;
162
163 /**
164 * Destroy an SP entry
165 */
166 static void sp_entry_destroy(sp_entry_t *sp)
167 {
168 sp->src->destroy(sp->src);
169 sp->dst->destroy(sp->dst);
170 free(sp);
171 }
172
173 /**
174 * Collection of SA/SP database entries for a reqid
175 */
176 typedef struct {
177 /** reqid of entry */
178 uint32_t reqid;
179 /** outer address on local host */
180 host_t *local;
181 /** outer address on remote host */
182 host_t *remote;
183 /** inbound SA entry */
184 sa_entry_t isa;
185 /** outbound SA entry */
186 sa_entry_t osa;
187 /** associated (outbound) policies, as sp_entry_t* */
188 array_t *sps;
189 /** IPsec mode, tunnel|transport */
190 ipsec_mode_t mode;
191 /** UDP encapsulation */
192 bool encap;
193 /** provider context, for tunnel mode only */
194 uint64_t provider;
195 /** WFP allocated LUID for SA context */
196 uint64_t sa_id;
197 /** WFP allocated LUID for tunnel mode IP-IPv4 inbound filter */
198 uint64_t ip_ipv4_in;
199 /** WFP allocated LUID for tunnel mode IP-IPv4 outbound filter */
200 uint64_t ip_ipv4_out;
201 /** WFP allocated LUID for tunnel mode IP-IPv6 inbound filter */
202 uint64_t ip_ipv6_in;
203 /** WFP allocated LUID for tunnel mode IP-IPv6 outbound filter */
204 uint64_t ip_ipv6_out;
205 } entry_t;
206
207 /**
208 * Installed route
209 */
210 typedef struct {
211 /** destination net of route */
212 host_t *dst;
213 /** prefix length of dst */
214 uint8_t mask;
215 /** source address for route */
216 host_t *src;
217 /** gateway of route, NULL if directly attached */
218 host_t *gtw;
219 /** references for route */
220 u_int refs;
221 } route_t;
222
223 /**
224 * Destroy a route_t
225 */
226 static void destroy_route(route_t *this)
227 {
228 this->dst->destroy(this->dst);
229 this->src->destroy(this->src);
230 DESTROY_IF(this->gtw);
231 free(this);
232 }
233
234 /**
235 * Hashtable equals function for routes
236 */
237 static bool equals_route(route_t *a, route_t *b)
238 {
239 return a->mask == b->mask &&
240 a->dst->ip_equals(a->dst, b->dst) &&
241 a->src->ip_equals(a->src, b->src);
242 }
243
244 /**
245 * Hashtable hash function for routes
246 */
247 static u_int hash_route(route_t *route)
248 {
249 return chunk_hash_inc(route->src->get_address(route->src),
250 chunk_hash_inc(route->dst->get_address(route->dst), route->mask));
251 }
252
253 /** forward declaration */
254 static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry,
255 bool add);
256
257 /**
258 * Remove policies associated to an entry from kernel
259 */
260 static void cleanup_policies(private_kernel_wfp_ipsec_t *this, entry_t *entry)
261 {
262 enumerator_t *enumerator;
263 sp_entry_t *sp;
264
265 if (entry->mode == MODE_TUNNEL)
266 {
267 manage_routes(this, entry, FALSE);
268 }
269
270 enumerator = array_create_enumerator(entry->sps);
271 while (enumerator->enumerate(enumerator, &sp))
272 {
273 if (sp->policy_in)
274 {
275 FwpmFilterDeleteById0(this->handle, sp->policy_in);
276 sp->policy_in = 0;
277 }
278 if (sp->policy_out)
279 {
280 FwpmFilterDeleteById0(this->handle, sp->policy_out);
281 sp->policy_out = 0;
282 }
283 if (sp->policy_fwd_in)
284 {
285 FwpmFilterDeleteById0(this->handle, sp->policy_fwd_in);
286 sp->policy_fwd_in = 0;
287 }
288 if (sp->policy_fwd_out)
289 {
290 FwpmFilterDeleteById0(this->handle, sp->policy_fwd_out);
291 sp->policy_fwd_out = 0;
292 }
293 }
294 enumerator->destroy(enumerator);
295 }
296
297 /**
298 * Destroy a SA/SP entry set
299 */
300 static void entry_destroy(private_kernel_wfp_ipsec_t *this, entry_t *entry)
301 {
302 if (entry->ip_ipv4_in)
303 {
304 FwpmFilterDeleteById0(this->handle, entry->ip_ipv4_in);
305 }
306 if (entry->ip_ipv4_out)
307 {
308 FwpmFilterDeleteById0(this->handle, entry->ip_ipv4_out);
309 }
310 if (entry->ip_ipv6_in)
311 {
312 FwpmFilterDeleteById0(this->handle, entry->ip_ipv6_in);
313 }
314 if (entry->ip_ipv6_out)
315 {
316 FwpmFilterDeleteById0(this->handle, entry->ip_ipv6_out);
317 }
318 if (entry->sa_id)
319 {
320 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
321 }
322 if (entry->provider)
323 {
324 FwpmProviderContextDeleteById0(this->handle, entry->provider);
325 }
326 cleanup_policies(this, entry);
327 array_destroy_function(entry->sps, (void*)sp_entry_destroy, NULL);
328 entry->local->destroy(entry->local);
329 entry->remote->destroy(entry->remote);
330 chunk_clear(&entry->isa.integ.key);
331 chunk_clear(&entry->isa.encr.key);
332 chunk_clear(&entry->osa.integ.key);
333 chunk_clear(&entry->osa.encr.key);
334 free(entry);
335 }
336
337 /**
338 * Append/Realloc a filter condition to an existing condition set
339 */
340 static FWPM_FILTER_CONDITION0 *append_condition(FWPM_FILTER_CONDITION0 *conds[],
341 int *count)
342 {
343 FWPM_FILTER_CONDITION0 *cond;
344
345 (*count)++;
346 *conds = realloc(*conds, *count * sizeof(*cond));
347 cond = *conds + *count - 1;
348 memset(cond, 0, sizeof(*cond));
349
350 return cond;
351 }
352
353 /**
354 * Convert an IPv4 prefix to a host order subnet mask
355 */
356 static uint32_t prefix2mask(uint8_t prefix)
357 {
358 uint8_t netmask[4] = {};
359 int i;
360
361 for (i = 0; i < sizeof(netmask); i++)
362 {
363 if (prefix < 8)
364 {
365 netmask[i] = 0xFF << (8 - prefix);
366 break;
367 }
368 netmask[i] = 0xFF;
369 prefix -= 8;
370 }
371 return untoh32(netmask);
372 }
373
374 /**
375 * Convert a 16-bit range to a WFP condition
376 */
377 static void range2cond(FWPM_FILTER_CONDITION0 *cond,
378 uint16_t from, uint16_t to)
379 {
380 if (from == to)
381 {
382 cond->matchType = FWP_MATCH_EQUAL;
383 cond->conditionValue.type = FWP_UINT16;
384 cond->conditionValue.uint16 = from;
385 }
386 else
387 {
388 cond->matchType = FWP_MATCH_RANGE;
389 cond->conditionValue.type = FWP_RANGE_TYPE;
390 cond->conditionValue.rangeValue = calloc(1, sizeof(FWP_RANGE0));
391 cond->conditionValue.rangeValue->valueLow.type = FWP_UINT16;
392 cond->conditionValue.rangeValue->valueLow.uint16 = from;
393 cond->conditionValue.rangeValue->valueHigh.type = FWP_UINT16;
394 cond->conditionValue.rangeValue->valueHigh.uint16 = to;
395 }
396 }
397
398 /**
399 * (Re-)allocate filter conditions for given local or remote traffic selector
400 */
401 static bool ts2condition(traffic_selector_t *ts, const GUID *target,
402 FWPM_FILTER_CONDITION0 *conds[], int *count)
403 {
404 FWPM_FILTER_CONDITION0 *cond;
405 FWP_BYTE_ARRAY16 *addr;
406 FWP_RANGE0 *range;
407 uint16_t from_port, to_port;
408 void *from, *to;
409 uint8_t proto;
410 host_t *net;
411 uint8_t prefix;
412
413 from = ts->get_from_address(ts).ptr;
414 to = ts->get_to_address(ts).ptr;
415 from_port = ts->get_from_port(ts);
416 to_port = ts->get_to_port(ts);
417
418 cond = append_condition(conds, count);
419 cond->fieldKey = *target;
420 if (ts->is_host(ts, NULL))
421 {
422 cond->matchType = FWP_MATCH_EQUAL;
423 switch (ts->get_type(ts))
424 {
425 case TS_IPV4_ADDR_RANGE:
426 cond->conditionValue.type = FWP_UINT32;
427 cond->conditionValue.uint32 = untoh32(from);
428 break;
429 case TS_IPV6_ADDR_RANGE:
430 cond->conditionValue.type = FWP_BYTE_ARRAY16_TYPE;
431 cond->conditionValue.byteArray16 = addr = malloc(sizeof(*addr));
432 memcpy(addr, from, sizeof(*addr));
433 break;
434 default:
435 return FALSE;
436 }
437 }
438 else if (ts->to_subnet(ts, &net, &prefix))
439 {
440 FWP_V6_ADDR_AND_MASK *m6;
441 FWP_V4_ADDR_AND_MASK *m4;
442
443 cond->matchType = FWP_MATCH_EQUAL;
444 switch (net->get_family(net))
445 {
446 case AF_INET:
447 cond->conditionValue.type = FWP_V4_ADDR_MASK;
448 cond->conditionValue.v4AddrMask = m4 = calloc(1, sizeof(*m4));
449 m4->addr = untoh32(from);
450 m4->mask = prefix2mask(prefix);
451 break;
452 case AF_INET6:
453 cond->conditionValue.type = FWP_V6_ADDR_MASK;
454 cond->conditionValue.v6AddrMask = m6 = calloc(1, sizeof(*m6));
455 memcpy(m6->addr, from, sizeof(m6->addr));
456 m6->prefixLength = prefix;
457 break;
458 default:
459 net->destroy(net);
460 return FALSE;
461 }
462 net->destroy(net);
463 }
464 else
465 {
466 cond->matchType = FWP_MATCH_RANGE;
467 cond->conditionValue.type = FWP_RANGE_TYPE;
468 cond->conditionValue.rangeValue = range = calloc(1, sizeof(*range));
469 switch (ts->get_type(ts))
470 {
471 case TS_IPV4_ADDR_RANGE:
472 range->valueLow.type = FWP_UINT32;
473 range->valueLow.uint32 = untoh32(from);
474 range->valueHigh.type = FWP_UINT32;
475 range->valueHigh.uint32 = untoh32(to);
476 break;
477 case TS_IPV6_ADDR_RANGE:
478 range->valueLow.type = FWP_BYTE_ARRAY16_TYPE;
479 range->valueLow.byteArray16 = addr = malloc(sizeof(*addr));
480 memcpy(addr, from, sizeof(*addr));
481 range->valueHigh.type = FWP_BYTE_ARRAY16_TYPE;
482 range->valueHigh.byteArray16 = addr = malloc(sizeof(*addr));
483 memcpy(addr, to, sizeof(*addr));
484 break;
485 default:
486 return FALSE;
487 }
488 }
489
490 proto = ts->get_protocol(ts);
491 if (proto && target == &FWPM_CONDITION_IP_LOCAL_ADDRESS)
492 {
493 cond = append_condition(conds, count);
494 cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL;
495 cond->matchType = FWP_MATCH_EQUAL;
496 cond->conditionValue.type = FWP_UINT8;
497 cond->conditionValue.uint8 = proto;
498 }
499
500 if (proto == IPPROTO_ICMP)
501 {
502 if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS)
503 {
504 uint8_t from_type, to_type, from_code, to_code;
505
506 from_type = traffic_selector_icmp_type(from_port);
507 to_type = traffic_selector_icmp_type(to_port);
508 from_code = traffic_selector_icmp_code(from_port);
509 to_code = traffic_selector_icmp_code(to_port);
510
511 if (from_type != 0 || to_type != 0xFF)
512 {
513 cond = append_condition(conds, count);
514 cond->fieldKey = FWPM_CONDITION_ICMP_TYPE;
515 range2cond(cond, from_type, to_type);
516 }
517 if (from_code != 0 || to_code != 0xFF)
518 {
519 cond = append_condition(conds, count);
520 cond->fieldKey = FWPM_CONDITION_ICMP_CODE;
521 range2cond(cond, from_code, to_code);
522 }
523 }
524 }
525 else if (from_port != 0 || to_port != 0xFFFF)
526 {
527 if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS)
528 {
529 cond = append_condition(conds, count);
530 cond->fieldKey = FWPM_CONDITION_IP_LOCAL_PORT;
531 range2cond(cond, from_port, to_port);
532 }
533 if (target == &FWPM_CONDITION_IP_REMOTE_ADDRESS)
534 {
535 cond = append_condition(conds, count);
536 cond->fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
537 range2cond(cond, from_port, to_port);
538 }
539 }
540 return TRUE;
541 }
542
543 /**
544 * Free memory associated to a single condition
545 */
546 static void free_condition(FWP_DATA_TYPE type, void *value)
547 {
548 FWP_RANGE0 *range;
549
550 switch (type)
551 {
552 case FWP_BYTE_ARRAY16_TYPE:
553 case FWP_V4_ADDR_MASK:
554 case FWP_V6_ADDR_MASK:
555 free(value);
556 break;
557 case FWP_RANGE_TYPE:
558 range = value;
559 free_condition(range->valueLow.type, range->valueLow.sd);
560 free_condition(range->valueHigh.type, range->valueHigh.sd);
561 free(range);
562 break;
563 default:
564 break;
565 }
566 }
567
568 /**
569 * Free memory used by a set of conditions
570 */
571 static void free_conditions(FWPM_FILTER_CONDITION0 *conds, int count)
572 {
573 int i;
574
575 for (i = 0; i < count; i++)
576 {
577 free_condition(conds[i].conditionValue.type, conds[i].conditionValue.sd);
578 }
579 free(conds);
580 }
581
582 /**
583 * Find the callout GUID for given parameters
584 */
585 static bool find_callout(bool tunnel, bool v6, bool inbound, bool forward,
586 bool ale, GUID *layer, GUID *sublayer, GUID *callout)
587 {
588 struct {
589 bool tunnel;
590 bool v6;
591 bool inbound;
592 bool forward;
593 bool ale;
594 const GUID *layer;
595 const GUID *sublayer;
596 const GUID *callout;
597 } map[] = {
598 { 0, 0, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4, NULL,
599 &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4 },
600 { 0, 0, 1, 0, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4, NULL,
601 &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 },
602 { 0, 1, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6, NULL,
603 &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6 },
604 { 0, 1, 1, 0, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6, NULL,
605 &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6 },
606 { 1, 0, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4,
607 &FWPM_SUBLAYER_IPSEC_TUNNEL,
608 &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4 },
609 { 1, 0, 0, 1, 0, &FWPM_LAYER_IPFORWARD_V4,
610 &FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL,
611 &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4 },
612 { 1, 0, 1, 0, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4,
613 &FWPM_SUBLAYER_IPSEC_TUNNEL,
614 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4 },
615 { 1, 0, 1, 1, 0, &FWPM_LAYER_IPFORWARD_V4,
616 &FWPM_SUBLAYER_IPSEC_TUNNEL,
617 &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4 },
618 { 1, 0, 0, 0, 1, &FWPM_LAYER_ALE_AUTH_CONNECT_V4, NULL,
619 &FWPM_CALLOUT_IPSEC_ALE_CONNECT_V4 },
620 { 1, 0, 1, 0, 1, &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, NULL,
621 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V4},
622 { 1, 1, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6,
623 &FWPM_SUBLAYER_IPSEC_TUNNEL,
624 &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6 },
625 { 1, 1, 0, 1, 0, &FWPM_LAYER_IPFORWARD_V6,
626 &FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL,
627 &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6 },
628 { 1, 1, 1, 0, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6,
629 &FWPM_SUBLAYER_IPSEC_TUNNEL,
630 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6 },
631 { 1, 1, 1, 1, 0, &FWPM_LAYER_IPFORWARD_V6,
632 &FWPM_SUBLAYER_IPSEC_TUNNEL,
633 &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6 },
634 { 1, 1, 0, 0, 1, &FWPM_LAYER_ALE_AUTH_CONNECT_V6, NULL,
635 &FWPM_CALLOUT_IPSEC_ALE_CONNECT_V6 },
636 { 1, 1, 1, 0, 1, &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, NULL,
637 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V6},
638 };
639 int i;
640
641 for (i = 0; i < countof(map); i++)
642 {
643 if (tunnel == map[i].tunnel &&
644 v6 == map[i].v6 &&
645 inbound == map[i].inbound &&
646 forward == map[i].forward &&
647 ale == map[i].ale)
648 {
649 *callout = *map[i].callout;
650 *layer = *map[i].layer;
651 if (map[i].sublayer)
652 {
653 *sublayer = *map[i].sublayer;
654 }
655 return TRUE;
656 }
657 }
658 return FALSE;
659 }
660
661 /**
662 * Install a single policy in to the kernel
663 */
664 static bool install_sp(private_kernel_wfp_ipsec_t *this, sp_entry_t *sp,
665 GUID *context, bool inbound, bool fwd, UINT64 *filter_id)
666 {
667 FWPM_FILTER_CONDITION0 *conds = NULL;
668 traffic_selector_t *local, *remote;
669 const GUID *ltarget, *rtarget;
670 int count = 0;
671 bool v6;
672 DWORD res;
673 FWPM_FILTER0 filter = {
674 .displayData = {
675 .name = L"charon IPsec policy",
676 },
677 .action = {
678 .type = FWP_ACTION_CALLOUT_TERMINATING,
679 },
680 };
681
682 if (context)
683 {
684 filter.flags |= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT;
685 filter.providerKey = (GUID*)&this->provider.providerKey;
686 filter.providerContextKey = *context;
687 }
688
689 v6 = sp->src->get_type(sp->src) == TS_IPV6_ADDR_RANGE;
690 if (!find_callout(context != NULL, v6, inbound, fwd, FALSE,
691 &filter.layerKey, &filter.subLayerKey,
692 &filter.action.calloutKey))
693 {
694 return FALSE;
695 }
696
697 if (inbound && fwd)
698 {
699 local = sp->dst;
700 remote = sp->src;
701 }
702 else
703 {
704 local = sp->src;
705 remote = sp->dst;
706 }
707 if (fwd)
708 {
709 ltarget = &FWPM_CONDITION_IP_SOURCE_ADDRESS;
710 rtarget = &FWPM_CONDITION_IP_DESTINATION_ADDRESS;
711 }
712 else
713 {
714 ltarget = &FWPM_CONDITION_IP_LOCAL_ADDRESS;
715 rtarget = &FWPM_CONDITION_IP_REMOTE_ADDRESS;
716 }
717 if (!ts2condition(local, ltarget, &conds, &count) ||
718 !ts2condition(remote, rtarget, &conds, &count))
719 {
720 free_conditions(conds, count);
721 return FALSE;
722 }
723
724 filter.numFilterConditions = count;
725 filter.filterCondition = conds;
726
727 res = FwpmFilterAdd0(this->handle, &filter, NULL, filter_id);
728 free_conditions(conds, count);
729 if (res != ERROR_SUCCESS)
730 {
731 DBG1(DBG_KNL, "installing IPv%d %s%sbound %s WFP filter failed: 0x%08x",
732 v6 ? 6 : 4, fwd ? "forward " : "", inbound ? "in" : "out",
733 context ? "tunnel" : "transport", res);
734 return FALSE;
735 }
736 return TRUE;
737 }
738
739 /**
740 * Install an IP-IP allow filter for SA specific hosts
741 */
742 static bool install_ipip_ale(private_kernel_wfp_ipsec_t *this,
743 host_t *local, host_t *remote, GUID *context,
744 bool inbound, int proto, uint64_t *filter_id)
745 {
746 traffic_selector_t *lts, *rts;
747 FWPM_FILTER_CONDITION0 *conds = NULL;
748 int count = 0;
749 bool v6;
750 DWORD res;
751 FWPM_FILTER0 filter = {
752 .displayData = {
753 .name = L"charon IPsec IP-in-IP ALE policy",
754 },
755 .action = {
756 .type = FWP_ACTION_CALLOUT_TERMINATING,
757 },
758 };
759
760 if (context)
761 {
762 filter.flags |= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT;
763 filter.providerKey = (GUID*)&this->provider.providerKey;
764 filter.providerContextKey = *context;
765 }
766
767 v6 = local->get_family(local) == AF_INET6;
768 if (!find_callout(TRUE, v6, inbound, FALSE, TRUE, &filter.layerKey,
769 &filter.subLayerKey, &filter.action.calloutKey))
770 {
771 return FALSE;
772 }
773
774 lts = traffic_selector_create_from_subnet(local->clone(local),
775 v6 ? 128 : 32 , proto, 0, 65535);
776 rts = traffic_selector_create_from_subnet(remote->clone(remote),
777 v6 ? 128 : 32 , proto, 0, 65535);
778 if (!ts2condition(lts, &FWPM_CONDITION_IP_LOCAL_ADDRESS, &conds, &count) ||
779 !ts2condition(rts, &FWPM_CONDITION_IP_REMOTE_ADDRESS, &conds, &count))
780 {
781 free_conditions(conds, count);
782 lts->destroy(lts);
783 rts->destroy(rts);
784 return FALSE;
785 }
786 lts->destroy(lts);
787 rts->destroy(rts);
788
789 filter.numFilterConditions = count;
790 filter.filterCondition = conds;
791
792 res = FwpmFilterAdd0(this->handle, &filter, NULL, filter_id);
793 free_conditions(conds, count);
794 if (res != ERROR_SUCCESS)
795 {
796 DBG1(DBG_KNL, "installing IP-IPv%d %s ALE WFP filter failed: 0x%08x",
797 v6 ? 6 : 4, inbound ? "inbound" : "outbound", res);
798 return FALSE;
799 }
800 return TRUE;
801 }
802
803 /**
804 * Install a set of policies in to the kernel
805 */
806 static bool install_sps(private_kernel_wfp_ipsec_t *this,
807 entry_t *entry, GUID *context)
808 {
809 enumerator_t *enumerator;
810 sp_entry_t *sp;
811 bool has_v4 = FALSE, has_v6 = FALSE;
812
813 enumerator = array_create_enumerator(entry->sps);
814 while (enumerator->enumerate(enumerator, &sp))
815 {
816 switch (sp->src->get_type(sp->src))
817 {
818 case TS_IPV4_ADDR_RANGE:
819 has_v4 = TRUE;
820 break;
821 case TS_IPV6_ADDR_RANGE:
822 has_v6 = TRUE;
823 break;
824 default:
825 continue;
826 }
827
828 /* inbound policy */
829 if (!install_sp(this, sp, context, TRUE, FALSE, &sp->policy_in))
830 {
831 enumerator->destroy(enumerator);
832 return FALSE;
833 }
834 /* outbound policy */
835 if (!install_sp(this, sp, context, FALSE, FALSE, &sp->policy_out))
836 {
837 enumerator->destroy(enumerator);
838 return FALSE;
839 }
840
841 if (context)
842 {
843 if (!sp->src->is_host(sp->src, entry->local) ||
844 !sp->dst->is_host(sp->dst, entry->remote))
845 {
846 /* inbound forward policy, from decapsulation */
847 if (!install_sp(this, sp, context, TRUE, TRUE,
848 &sp->policy_fwd_in))
849 {
850 enumerator->destroy(enumerator);
851 return FALSE;
852 }
853 /* outbound forward policy, to encapsulate */
854 if (!install_sp(this, sp, context, FALSE, TRUE,
855 &sp->policy_fwd_out))
856 {
857 enumerator->destroy(enumerator);
858 return FALSE;
859 }
860 }
861 }
862 }
863 enumerator->destroy(enumerator);
864
865 if (context)
866 {
867 /* In tunnel mode, Windows does firewall filtering on decrypted but
868 * non-unwrapped packets: It sees them as IP-in-IP packets. When using
869 * a default-drop policy, we need to allow such packets explicitly. */
870 if (has_v4)
871 {
872 if (!install_ipip_ale(this, entry->local, entry->remote, context,
873 TRUE, IPPROTO_IPIP, &entry->ip_ipv4_in))
874 {
875 return FALSE;
876 }
877 if (!install_ipip_ale(this, entry->local, entry->remote, NULL,
878 FALSE, IPPROTO_IPIP, &entry->ip_ipv4_out))
879 {
880 return FALSE;
881 }
882 }
883 if (has_v6)
884 {
885 if (!install_ipip_ale(this, entry->local, entry->remote, context,
886 TRUE, IPPROTO_IPV6, &entry->ip_ipv6_in))
887 {
888 return FALSE;
889 }
890 if (!install_ipip_ale(this, entry->local, entry->remote, NULL,
891 FALSE, IPPROTO_IPV6, &entry->ip_ipv6_out))
892 {
893 return FALSE;
894 }
895 }
896 }
897 return TRUE;
898 }
899
900 /**
901 * Convert a chunk_t to a WFP FWP_BYTE_BLOB
902 */
903 static inline FWP_BYTE_BLOB chunk2blob(chunk_t chunk)
904 {
905 return (FWP_BYTE_BLOB){
906 .size = chunk.len,
907 .data = chunk.ptr,
908 };
909 }
910
911 /**
912 * Convert an integrity_algorithm_t to a WFP IPSEC_AUTH_TRANFORM_ID0
913 */
914 static bool alg2auth(integrity_algorithm_t alg,
915 IPSEC_SA_AUTH_INFORMATION0 *info)
916 {
917 struct {
918 integrity_algorithm_t alg;
919 IPSEC_AUTH_TRANSFORM_ID0 transform;
920 } map[] = {
921 { AUTH_HMAC_MD5_96, IPSEC_AUTH_TRANSFORM_ID_HMAC_MD5_96 },
922 { AUTH_HMAC_SHA1_96, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96 },
923 { AUTH_HMAC_SHA2_256_128, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_256_128},
924 { AUTH_AES_128_GMAC, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_128 },
925 { AUTH_AES_192_GMAC, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_192 },
926 { AUTH_AES_256_GMAC, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_256 },
927 };
928 int i;
929
930 for (i = 0; i < countof(map); i++)
931 {
932 if (map[i].alg == alg)
933 {
934 info->authTransform.authTransformId = map[i].transform;
935 return TRUE;
936 }
937 }
938 return FALSE;
939 }
940
941 /**
942 * Convert an encryption_algorithm_t to a WFP IPSEC_CIPHER_TRANFORM_ID0
943 */
944 static bool alg2cipher(encryption_algorithm_t alg, int keylen,
945 IPSEC_SA_CIPHER_INFORMATION0 *info)
946 {
947 struct {
948 encryption_algorithm_t alg;
949 int keylen;
950 IPSEC_CIPHER_TRANSFORM_ID0 transform;
951 } map[] = {
952 { ENCR_DES, 8, IPSEC_CIPHER_TRANSFORM_ID_CBC_DES },
953 { ENCR_3DES, 24, IPSEC_CIPHER_TRANSFORM_ID_CBC_3DES },
954 { ENCR_AES_CBC, 16, IPSEC_CIPHER_TRANSFORM_ID_AES_128 },
955 { ENCR_AES_CBC, 24, IPSEC_CIPHER_TRANSFORM_ID_AES_192 },
956 { ENCR_AES_CBC, 32, IPSEC_CIPHER_TRANSFORM_ID_AES_256 },
957 { ENCR_AES_GCM_ICV16, 20, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_128 },
958 { ENCR_AES_GCM_ICV16, 28, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_192 },
959 { ENCR_AES_GCM_ICV16, 36, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_256 },
960 };
961 int i;
962
963 for (i = 0; i < countof(map); i++)
964 {
965 if (map[i].alg == alg && map[i].keylen == keylen)
966 {
967 info->cipherTransform.cipherTransformId = map[i].transform;
968 return TRUE;
969 }
970 }
971 return FALSE;
972 }
973
974 /**
975 * Get the integrity algorithm used for an AEAD transform
976 */
977 static integrity_algorithm_t encr2integ(encryption_algorithm_t encr, int keylen)
978 {
979 struct {
980 encryption_algorithm_t encr;
981 int keylen;
982 integrity_algorithm_t integ;
983 } map[] = {
984 { ENCR_NULL_AUTH_AES_GMAC, 20, AUTH_AES_128_GMAC },
985 { ENCR_NULL_AUTH_AES_GMAC, 28, AUTH_AES_192_GMAC },
986 { ENCR_NULL_AUTH_AES_GMAC, 36, AUTH_AES_256_GMAC },
987 { ENCR_AES_GCM_ICV16, 20, AUTH_AES_128_GMAC },
988 { ENCR_AES_GCM_ICV16, 28, AUTH_AES_192_GMAC },
989 { ENCR_AES_GCM_ICV16, 36, AUTH_AES_256_GMAC },
990 };
991 int i;
992
993 for (i = 0; i < countof(map); i++)
994 {
995 if (map[i].encr == encr && map[i].keylen == keylen)
996 {
997 return map[i].integ;
998 }
999 }
1000 return AUTH_UNDEFINED;
1001 }
1002
1003 /**
1004 * Install a single SA
1005 */
1006 static bool install_sa(private_kernel_wfp_ipsec_t *this, entry_t *entry,
1007 bool inbound, sa_entry_t *sa, FWP_IP_VERSION version)
1008 {
1009 IPSEC_SA_AUTH_AND_CIPHER_INFORMATION0 info = {};
1010 IPSEC_SA0 ipsec = {
1011 .spi = ntohl(sa->spi),
1012 };
1013 IPSEC_SA_BUNDLE0 bundle = {
1014 .lifetime = {
1015 .lifetimeSeconds = inbound ? entry->isa.lifetime
1016 : entry->osa.lifetime,
1017 },
1018 .saList = &ipsec,
1019 .numSAs = 1,
1020 .ipVersion = version,
1021 };
1022 struct {
1023 uint16_t alg;
1024 chunk_t key;
1025 } integ = {}, encr = {};
1026 DWORD res;
1027
1028 switch (sa->protocol)
1029 {
1030 case IPPROTO_AH:
1031 ipsec.saTransformType = IPSEC_TRANSFORM_AH;
1032 ipsec.ahInformation = &info.saAuthInformation;
1033 integ.key = sa->integ.key;
1034 integ.alg = sa->integ.alg;
1035 break;
1036 case IPPROTO_ESP:
1037 if (sa->encr.alg == ENCR_NULL ||
1038 sa->encr.alg == ENCR_NULL_AUTH_AES_GMAC)
1039 {
1040 ipsec.saTransformType = IPSEC_TRANSFORM_ESP_AUTH;
1041 ipsec.espAuthInformation = &info.saAuthInformation;
1042 }
1043 else
1044 {
1045 ipsec.saTransformType = IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER;
1046 ipsec.espAuthAndCipherInformation = &info;
1047 encr.key = sa->encr.key;
1048 encr.alg = sa->encr.alg;
1049 }
1050 if (encryption_algorithm_is_aead(sa->encr.alg))
1051 {
1052 integ.alg = encr2integ(sa->encr.alg, sa->encr.key.len);
1053 integ.key = sa->encr.key;
1054 }
1055 else
1056 {
1057 integ.alg = sa->integ.alg;
1058 integ.key = sa->integ.key;
1059 }
1060 break;
1061 default:
1062 return FALSE;
1063 }
1064
1065 if (integ.alg)
1066 {
1067 info.saAuthInformation.authKey = chunk2blob(integ.key);
1068 if (!alg2auth(integ.alg, &info.saAuthInformation))
1069 {
1070 DBG1(DBG_KNL, "integrity algorithm %N not supported by WFP",
1071 integrity_algorithm_names, integ.alg);
1072 return FALSE;
1073 }
1074 }
1075 if (encr.alg)
1076 {
1077 info.saCipherInformation.cipherKey = chunk2blob(encr.key);
1078 if (!alg2cipher(encr.alg, encr.key.len, &info.saCipherInformation))
1079 {
1080 DBG1(DBG_KNL, "encryption algorithm %N not supported by WFP",
1081 encryption_algorithm_names, encr.alg);
1082 return FALSE;
1083 }
1084 }
1085
1086 if (inbound)
1087 {
1088 res = IPsecSaContextAddInbound0(this->handle, entry->sa_id, &bundle);
1089 }
1090 else
1091 {
1092 bundle.flags |= IPSEC_SA_BUNDLE_FLAG_ASSUME_UDP_CONTEXT_OUTBOUND;
1093 res = IPsecSaContextAddOutbound0(this->handle, entry->sa_id, &bundle);
1094 }
1095 if (res != ERROR_SUCCESS)
1096 {
1097 DBG1(DBG_KNL, "adding %sbound WFP SA failed: 0x%08x",
1098 inbound ? "in" : "out", res);
1099 return FALSE;
1100 }
1101 return TRUE;
1102 }
1103
1104 /**
1105 * Convert an IPv6 host address to WFP representation
1106 */
1107 static void host2address6(host_t *host, void *out)
1108 {
1109 uint32_t *src, *dst = out;
1110
1111 src = (uint32_t*)host->get_address(host).ptr;
1112
1113 dst[0] = untoh32(&src[3]);
1114 dst[1] = untoh32(&src[2]);
1115 dst[2] = untoh32(&src[1]);
1116 dst[3] = untoh32(&src[0]);
1117 }
1118
1119 /**
1120 * Fill in traffic structure from entry addresses
1121 */
1122 static bool hosts2traffic(private_kernel_wfp_ipsec_t *this,
1123 host_t *l, host_t *r, IPSEC_TRAFFIC1 *traffic)
1124 {
1125 if (l->get_family(l) != r->get_family(r))
1126 {
1127 return FALSE;
1128 }
1129 switch (l->get_family(l))
1130 {
1131 case AF_INET:
1132 traffic->ipVersion = FWP_IP_VERSION_V4;
1133 traffic->localV4Address = untoh32(l->get_address(l).ptr);
1134 traffic->remoteV4Address = untoh32(r->get_address(r).ptr);
1135 return TRUE;
1136 case AF_INET6:
1137 traffic->ipVersion = FWP_IP_VERSION_V6;
1138 host2address6(l, &traffic->localV6Address);
1139 host2address6(r, &traffic->remoteV6Address);
1140 return TRUE;
1141 default:
1142 return FALSE;
1143 }
1144 }
1145
1146 /**
1147 * Install SAs to the kernel
1148 */
1149 static bool install_sas(private_kernel_wfp_ipsec_t *this, entry_t *entry,
1150 IPSEC_TRAFFIC_TYPE type)
1151 {
1152 IPSEC_TRAFFIC1 traffic = {
1153 .trafficType = type,
1154 };
1155 IPSEC_GETSPI1 spi = {
1156 .inboundIpsecTraffic = {
1157 .trafficType = type,
1158 },
1159 };
1160 enumerator_t *enumerator;
1161 sp_entry_t *sp;
1162 DWORD res;
1163
1164 if (type == IPSEC_TRAFFIC_TYPE_TRANSPORT)
1165 {
1166 enumerator = array_create_enumerator(entry->sps);
1167 if (enumerator->enumerate(enumerator, &sp))
1168 {
1169 traffic.ipsecFilterId = sp->policy_out;
1170 spi.inboundIpsecTraffic.ipsecFilterId = sp->policy_in;
1171 }
1172 else
1173 {
1174 enumerator->destroy(enumerator);
1175 return FALSE;
1176 }
1177 enumerator->destroy(enumerator);
1178 }
1179 else
1180 {
1181 traffic.tunnelPolicyId = entry->provider;
1182 spi.inboundIpsecTraffic.tunnelPolicyId = entry->provider;
1183 }
1184
1185 if (!hosts2traffic(this, entry->local, entry->remote, &traffic))
1186 {
1187 return FALSE;
1188 }
1189
1190 res = IPsecSaContextCreate1(this->handle, &traffic, NULL, NULL,
1191 &entry->sa_id);
1192 if (res != ERROR_SUCCESS)
1193 {
1194 DBG1(DBG_KNL, "creating WFP SA context failed: 0x%08x", res);
1195 return FALSE;
1196 }
1197
1198 memcpy(spi.inboundIpsecTraffic.localV6Address, traffic.localV6Address,
1199 sizeof(traffic.localV6Address));
1200 memcpy(spi.inboundIpsecTraffic.remoteV6Address, traffic.remoteV6Address,
1201 sizeof(traffic.remoteV6Address));
1202 spi.ipVersion = traffic.ipVersion;
1203
1204 res = IPsecSaContextSetSpi0(this->handle, entry->sa_id, &spi,
1205 ntohl(entry->isa.spi));
1206 if (res != ERROR_SUCCESS)
1207 {
1208 DBG1(DBG_KNL, "setting WFP SA SPI failed: 0x%08x", res);
1209 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
1210 entry->sa_id = 0;
1211 return FALSE;
1212 }
1213
1214 if (!install_sa(this, entry, TRUE, &entry->isa, spi.ipVersion) ||
1215 !install_sa(this, entry, FALSE, &entry->osa, spi.ipVersion))
1216 {
1217 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
1218 entry->sa_id = 0;
1219 return FALSE;
1220 }
1221
1222 if (entry->encap)
1223 {
1224 IPSEC_V4_UDP_ENCAPSULATION0 encap = {
1225 .localUdpEncapPort = entry->local->get_port(entry->local),
1226 .remoteUdpEncapPort = entry->remote->get_port(entry->remote),
1227 };
1228 IPSEC_SA_CONTEXT1 *ctx;
1229
1230 res = IPsecSaContextGetById1(this->handle, entry->sa_id, &ctx);
1231 if (res != ERROR_SUCCESS)
1232 {
1233 DBG1(DBG_KNL, "getting WFP SA for UDP encap failed: 0x%08x", res);
1234 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
1235 entry->sa_id = 0;
1236 return FALSE;
1237 }
1238 ctx->inboundSa->udpEncapsulation = &encap;
1239 ctx->outboundSa->udpEncapsulation = &encap;
1240
1241 res = IPsecSaContextUpdate0(this->handle,
1242 IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION, ctx);
1243 FwpmFreeMemory0((void**)&ctx);
1244 if (res != ERROR_SUCCESS)
1245 {
1246 DBG1(DBG_KNL, "enable WFP UDP encap failed: 0x%08x", res);
1247 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
1248 entry->sa_id = 0;
1249 return FALSE;
1250 }
1251 }
1252
1253 return TRUE;
1254 }
1255
1256 /**
1257 * Install a transport mode SA/SP set to the kernel
1258 */
1259 static bool install_transport(private_kernel_wfp_ipsec_t *this, entry_t *entry)
1260 {
1261 if (install_sps(this, entry, NULL) &&
1262 install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TRANSPORT))
1263 {
1264 return TRUE;
1265 }
1266 cleanup_policies(this, entry);
1267 return FALSE;
1268 }
1269
1270 /**
1271 * Generate a new GUID, random
1272 */
1273 static bool generate_guid(private_kernel_wfp_ipsec_t *this, GUID *guid)
1274 {
1275 bool ok;
1276 rng_t *rng;
1277
1278 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
1279 if (!rng)
1280 {
1281 return FALSE;
1282 }
1283 ok = rng->get_bytes(rng, sizeof(GUID), (uint8_t*)guid);
1284 rng->destroy(rng);
1285 return ok;
1286 }
1287
1288 /**
1289 * Register a dummy tunnel provider to associate tunnel filters to
1290 */
1291 static bool add_tunnel_provider(private_kernel_wfp_ipsec_t *this,
1292 entry_t *entry, GUID *guid, UINT64 *luid)
1293 {
1294 DWORD res;
1295
1296 IPSEC_AUTH_TRANSFORM0 transform = {
1297 /* Create any valid proposal. This is actually not used, as we
1298 * don't create an SA from this information. */
1299 .authTransformId = IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96,
1300 };
1301 IPSEC_SA_TRANSFORM0 transforms = {
1302 .ipsecTransformType = IPSEC_TRANSFORM_ESP_AUTH,
1303 .espAuthTransform = &transform,
1304 };
1305 IPSEC_PROPOSAL0 proposal = {
1306 .lifetime = {
1307 /* We need a valid lifetime, even if we don't create any SA
1308 * from these values. Pick some values accepted. */
1309 .lifetimeSeconds = 0xFFFF,
1310 .lifetimeKilobytes = 0xFFFFFFFF,
1311 .lifetimePackets = 0xFFFFFFFF,
1312 },
1313 .numSaTransforms = 1,
1314 .saTransforms = &transforms,
1315 };
1316 IPSEC_TUNNEL_POLICY0 policy = {
1317 .numIpsecProposals = 1,
1318 .ipsecProposals = &proposal,
1319 .saIdleTimeout = {
1320 /* not used, set to lifetime for maximum */
1321 .idleTimeoutSeconds = proposal.lifetime.lifetimeSeconds,
1322 .idleTimeoutSecondsFailOver = proposal.lifetime.lifetimeSeconds,
1323 },
1324 };
1325 FWPM_PROVIDER_CONTEXT0 qm = {
1326 .displayData = {
1327 .name = L"charon tunnel provider",
1328 },
1329 .providerKey = (GUID*)&this->provider.providerKey,
1330 .type = FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT,
1331 .ikeQmTunnelPolicy = &policy,
1332 };
1333
1334 switch (entry->local->get_family(entry->local))
1335 {
1336 case AF_INET:
1337 policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V4;
1338 policy.tunnelEndpoints.localV4Address =
1339 untoh32(entry->local->get_address(entry->local).ptr);
1340 policy.tunnelEndpoints.remoteV4Address =
1341 untoh32(entry->remote->get_address(entry->remote).ptr);
1342 break;
1343 case AF_INET6:
1344 policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V6;
1345 host2address6(entry->local, &policy.tunnelEndpoints.localV6Address);
1346 host2address6(entry->remote, &policy.tunnelEndpoints.remoteV6Address);
1347 break;
1348 default:
1349 return FALSE;
1350 }
1351
1352 if (!generate_guid(this, &qm.providerContextKey))
1353 {
1354 return FALSE;
1355 }
1356
1357 res = FwpmProviderContextAdd0(this->handle, &qm, NULL, luid);
1358 if (res != ERROR_SUCCESS)
1359 {
1360 DBG1(DBG_KNL, "adding provider context failed: 0x%08x", res);
1361 return FALSE;
1362 }
1363 *guid = qm.providerContextKey;
1364 return TRUE;
1365 }
1366
1367 /**
1368 * Install tunnel mode SPs to the kernel
1369 */
1370 static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry)
1371 {
1372 GUID guid;
1373
1374 if (!add_tunnel_provider(this, entry, &guid, &entry->provider))
1375 {
1376 return FALSE;
1377 }
1378 if (!install_sps(this, entry, &guid))
1379 {
1380 return FALSE;
1381 }
1382 return TRUE;
1383 }
1384
1385 /**
1386 * Reduce refcount, or uninstall a route if all refs gone
1387 */
1388 static bool uninstall_route(private_kernel_wfp_ipsec_t *this,
1389 host_t *dst, uint8_t mask, host_t *src, host_t *gtw)
1390 {
1391 route_t *route, key = {
1392 .dst = dst,
1393 .mask = mask,
1394 .src = src,
1395 };
1396 char *name;
1397 bool res = FALSE;
1398
1399 this->mutex->lock(this->mutex);
1400 route = this->routes->get(this->routes, &key);
1401 if (route)
1402 {
1403 if (--route->refs == 0)
1404 {
1405 if (charon->kernel->get_interface(charon->kernel, src, &name))
1406 {
1407 res = charon->kernel->del_route(charon->kernel,
1408 dst->get_address(dst), mask, gtw, src,
1409 name, FALSE) == SUCCESS;
1410 free(name);
1411 }
1412 route = this->routes->remove(this->routes, route);
1413 if (route)
1414 {
1415 destroy_route(route);
1416 }
1417 }
1418 else
1419 {
1420 res = TRUE;
1421 }
1422 }
1423 this->mutex->unlock(this->mutex);
1424
1425 return res;
1426 }
1427
1428 /**
1429 * Install a single route, or refcount if exists
1430 */
1431 static bool install_route(private_kernel_wfp_ipsec_t *this,
1432 host_t *dst, uint8_t mask, host_t *src, host_t *gtw)
1433 {
1434 route_t *route, key = {
1435 .dst = dst,
1436 .mask = mask,
1437 .src = src,
1438 };
1439 char *name;
1440 bool res = FALSE;
1441
1442 this->mutex->lock(this->mutex);
1443 route = this->routes->get(this->routes, &key);
1444 if (route)
1445 {
1446 route->refs++;
1447 res = TRUE;
1448 }
1449 else
1450 {
1451 if (charon->kernel->get_interface(charon->kernel, src, &name))
1452 {
1453 if (charon->kernel->add_route(charon->kernel, dst->get_address(dst),
1454 mask, gtw, src, name, FALSE) == SUCCESS)
1455 {
1456 INIT(route,
1457 .dst = dst->clone(dst),
1458 .mask = mask,
1459 .src = src->clone(src),
1460 .gtw = gtw ? gtw->clone(gtw) : NULL,
1461 .refs = 1,
1462 );
1463 route = this->routes->put(this->routes, route, route);
1464 if (route)
1465 {
1466 destroy_route(route);
1467 }
1468 res = TRUE;
1469 }
1470 free(name);
1471 }
1472 }
1473 this->mutex->unlock(this->mutex);
1474
1475 return res;
1476 }
1477
1478 /**
1479 * (Un)-install a single route
1480 */
1481 static bool manage_route(private_kernel_wfp_ipsec_t *this,
1482 host_t *local, host_t *remote,
1483 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
1484 bool add)
1485 {
1486 host_t *src, *dst, *gtw;
1487 uint8_t mask;
1488 bool done;
1489
1490 if (!dst_ts->to_subnet(dst_ts, &dst, &mask))
1491 {
1492 return FALSE;
1493 }
1494 if (charon->kernel->get_address_by_ts(charon->kernel, src_ts, &src,
1495 NULL) != SUCCESS)
1496 {
1497 dst->destroy(dst);
1498 return FALSE;
1499 }
1500 gtw = charon->kernel->get_nexthop(charon->kernel, remote, -1, local, NULL);
1501 if (add)
1502 {
1503 done = install_route(this, dst, mask, src, gtw);
1504 }
1505 else
1506 {
1507 done = uninstall_route(this, dst, mask, src, gtw);
1508 }
1509 dst->destroy(dst);
1510 src->destroy(src);
1511 DESTROY_IF(gtw);
1512
1513 if (!done)
1514 {
1515 DBG1(DBG_KNL, "%sinstalling route for policy %R === %R failed",
1516 add ? "" : "un", src_ts, dst_ts);
1517 }
1518 return done;
1519 }
1520
1521 /**
1522 * (Un)-install routes for IPsec policies
1523 */
1524 static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry,
1525 bool add)
1526 {
1527 enumerator_t *enumerator;
1528 sp_entry_t *sp;
1529
1530 enumerator = array_create_enumerator(entry->sps);
1531 while (enumerator->enumerate(enumerator, &sp))
1532 {
1533 if (add && sp->route)
1534 {
1535 continue;
1536 }
1537 if (!add && !sp->route)
1538 {
1539 continue;
1540 }
1541 if (manage_route(this, entry->local, entry->remote,
1542 sp->src, sp->dst, add))
1543 {
1544 sp->route = add;
1545 }
1546 }
1547 enumerator->destroy(enumerator);
1548
1549 return TRUE;
1550 }
1551
1552 /**
1553 * Install a tunnel mode SA/SP set to the kernel
1554 */
1555 static bool install_tunnel(private_kernel_wfp_ipsec_t *this, entry_t *entry)
1556 {
1557 if (install_tunnel_sps(this, entry) &&
1558 manage_routes(this, entry, TRUE) &&
1559 install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TUNNEL))
1560 {
1561 return TRUE;
1562 }
1563 cleanup_policies(this, entry);
1564 return FALSE;
1565 }
1566
1567 /**
1568 * Install a SA/SP set to the kernel
1569 */
1570 static bool install(private_kernel_wfp_ipsec_t *this, entry_t *entry)
1571 {
1572 switch (entry->mode)
1573 {
1574 case MODE_TRANSPORT:
1575 return install_transport(this, entry);
1576 case MODE_TUNNEL:
1577 return install_tunnel(this, entry);
1578 case MODE_BEET:
1579 default:
1580 return FALSE;
1581 }
1582 }
1583
1584 /**
1585 * Installed trap entry
1586 */
1587 typedef struct {
1588 /** reqid this trap is installed for */
1589 uint32_t reqid;
1590 /** is this a forward policy trap for tunnel mode? */
1591 bool fwd;
1592 /** do we have installed a route for this trap policy? */
1593 bool route;
1594 /** local address of associated route */
1595 host_t *local;
1596 /** remote address of associated route */
1597 host_t *remote;
1598 /** src traffic selector */
1599 traffic_selector_t *src;
1600 /** dst traffic selector */
1601 traffic_selector_t *dst;
1602 /** LUID of installed tunnel policy filter */
1603 UINT64 filter_id;
1604 } trap_t;
1605
1606 /**
1607 * Destroy a trap entry
1608 */
1609 static void destroy_trap(trap_t *this)
1610 {
1611 this->local->destroy(this->local);
1612 this->remote->destroy(this->remote);
1613 this->src->destroy(this->src);
1614 this->dst->destroy(this->dst);
1615 free(this);
1616 }
1617
1618 /**
1619 * Hashtable equals function for traps
1620 */
1621 static bool equals_trap(trap_t *a, trap_t *b)
1622 {
1623 return a->filter_id == b->filter_id;
1624 }
1625
1626 /**
1627 * Hashtable hash function for traps
1628 */
1629 static u_int hash_trap(trap_t *trap)
1630 {
1631 return chunk_hash(chunk_from_thing(trap->filter_id));
1632 }
1633
1634 /**
1635 * Send an acquire for an installed trap filter
1636 */
1637 static void acquire(private_kernel_wfp_ipsec_t *this, UINT64 filter_id,
1638 traffic_selector_t *src, traffic_selector_t *dst)
1639 {
1640 kernel_acquire_data_t data = {
1641 .cpu = CPU_ID_MAX,
1642 };
1643 uint32_t reqid = 0;
1644 trap_t *trap, key = {
1645 .filter_id = filter_id,
1646 };
1647
1648 this->mutex->lock(this->mutex);
1649 trap = this->traps->get(this->traps, &key);
1650 if (trap)
1651 {
1652 reqid = trap->reqid;
1653 }
1654 this->mutex->unlock(this->mutex);
1655
1656 if (reqid)
1657 {
1658 data.src = src ? src->clone(src) : NULL;
1659 data.dst = dst ? dst->clone(dst) : NULL;
1660
1661 charon->kernel->acquire(charon->kernel, reqid, &data);
1662
1663 DESTROY_IF(data.src);
1664 DESTROY_IF(data.dst);
1665 }
1666 }
1667
1668 /**
1669 * Create a single host traffic selector from an FWP address definition
1670 */
1671 static traffic_selector_t *addr2ts(FWP_IP_VERSION version, void *data,
1672 uint8_t protocol, uint16_t from_port, uint16_t to_port)
1673 {
1674 ts_type_t type;
1675 UINT32 ints[4];
1676 chunk_t addr;
1677
1678 switch (version)
1679 {
1680 case FWP_IP_VERSION_V4:
1681 ints[0] = untoh32(data);
1682 addr = chunk_from_thing(ints[0]);
1683 type = TS_IPV4_ADDR_RANGE;
1684 break;
1685 case FWP_IP_VERSION_V6:
1686 ints[3] = untoh32(data);
1687 ints[2] = untoh32(data + 4);
1688 ints[1] = untoh32(data + 8);
1689 ints[0] = untoh32(data + 12);
1690 addr = chunk_from_thing(ints);
1691 type = TS_IPV6_ADDR_RANGE;
1692 break;
1693 default:
1694 return NULL;
1695 }
1696 return traffic_selector_create_from_bytes(protocol, type, addr, from_port,
1697 addr, to_port);
1698 }
1699
1700 /**
1701 * FwpmNetEventSubscribe0() callback
1702 */
1703 static void WINAPI event_callback(void *user, const FWPM_NET_EVENT1 *event)
1704 {
1705 private_kernel_wfp_ipsec_t *this = user;
1706 traffic_selector_t *local = NULL, *remote = NULL;
1707 uint8_t protocol = 0;
1708 uint16_t from_local = 0, to_local = 65535;
1709 uint16_t from_remote = 0, to_remote = 65535;
1710
1711 if ((event->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET) &&
1712 (event->header.flags & FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET))
1713 {
1714 if (event->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET)
1715 {
1716 from_local = to_local = event->header.localPort;
1717 }
1718 if (event->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET)
1719 {
1720 from_remote = to_remote = event->header.remotePort;
1721 }
1722 if (event->header.flags & FWPM_NET_EVENT_FLAG_IP_PROTOCOL_SET)
1723 {
1724 protocol = event->header.ipProtocol;
1725 }
1726
1727 local = addr2ts(event->header.ipVersion,
1728 (void*)&event->header.localAddrV6,
1729 protocol, from_local, to_local);
1730 remote = addr2ts(event->header.ipVersion,
1731 (void*)&event->header.remoteAddrV6,
1732 protocol, from_remote, to_remote);
1733 }
1734
1735 switch (event->type)
1736 {
1737 case FWPM_NET_EVENT_TYPE_CLASSIFY_DROP:
1738 acquire(this, event->classifyDrop->filterId, local, remote);
1739 break;
1740 case FWPM_NET_EVENT_TYPE_IKEEXT_MM_FAILURE:
1741 DBG1(DBG_KNL, "WFP MM failure: %R === %R, 0x%08x, filterId %llu",
1742 local, remote, event->ikeMmFailure->failureErrorCode,
1743 event->ikeMmFailure->mmFilterId);
1744 break;
1745 case FWPM_NET_EVENT_TYPE_IKEEXT_QM_FAILURE:
1746 DBG1(DBG_KNL, "WFP QM failure: %R === %R, 0x%08x, filterId %llu",
1747 local, remote, event->ikeQmFailure->failureErrorCode,
1748 event->ikeQmFailure->qmFilterId);
1749 break;
1750 case FWPM_NET_EVENT_TYPE_IKEEXT_EM_FAILURE:
1751 DBG1(DBG_KNL, "WFP EM failure: %R === %R, 0x%08x, filterId %llu",
1752 local, remote, event->ikeEmFailure->failureErrorCode,
1753 event->ikeEmFailure->qmFilterId);
1754 break;
1755 case FWPM_NET_EVENT_TYPE_IPSEC_KERNEL_DROP:
1756 DBG1(DBG_KNL, "IPsec kernel drop: %R === %R, error 0x%08x, "
1757 "SPI 0x%08x, %s filterId %llu", local, remote,
1758 event->ipsecDrop->failureStatus, event->ipsecDrop->spi,
1759 event->ipsecDrop->direction ? "in" : "out",
1760 event->ipsecDrop->filterId);
1761 break;
1762 case FWPM_NET_EVENT_TYPE_IPSEC_DOSP_DROP:
1763 default:
1764 break;
1765 }
1766
1767 DESTROY_IF(local);
1768 DESTROY_IF(remote);
1769 }
1770
1771 /**
1772 * Register for net events
1773 */
1774 static bool register_events(private_kernel_wfp_ipsec_t *this)
1775 {
1776 FWPM_NET_EVENT_SUBSCRIPTION0 subscription = {};
1777 DWORD res;
1778
1779 res = FwpmNetEventSubscribe0(this->handle, &subscription,
1780 event_callback, this, &this->event);
1781 if (res != ERROR_SUCCESS)
1782 {
1783 DBG1(DBG_KNL, "registering for WFP events failed: 0x%08x", res);
1784 return FALSE;
1785 }
1786 return TRUE;
1787 }
1788
1789 /**
1790 * Install a trap policy to kernel
1791 */
1792 static bool install_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap)
1793 {
1794 FWPM_FILTER_CONDITION0 *conds = NULL;
1795 int count = 0;
1796 DWORD res;
1797 const GUID *starget, *dtarget;
1798 UINT64 weight = 0x000000000000ff00;
1799 FWPM_FILTER0 filter = {
1800 .displayData = {
1801 .name = L"charon IPsec trap",
1802 },
1803 .action = {
1804 .type = FWP_ACTION_BLOCK,
1805 },
1806 .weight = {
1807 .type = FWP_UINT64,
1808 .uint64 = &weight,
1809 },
1810 };
1811
1812 if (trap->fwd)
1813 {
1814 if (trap->src->get_type(trap->src) == TS_IPV4_ADDR_RANGE)
1815 {
1816 filter.layerKey = FWPM_LAYER_IPFORWARD_V4;
1817 }
1818 else
1819 {
1820 filter.layerKey = FWPM_LAYER_IPFORWARD_V6;
1821 }
1822 starget = &FWPM_CONDITION_IP_SOURCE_ADDRESS;
1823 dtarget = &FWPM_CONDITION_IP_DESTINATION_ADDRESS;
1824 }
1825 else
1826 {
1827 if (trap->src->get_type(trap->src) == TS_IPV4_ADDR_RANGE)
1828 {
1829 filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
1830 }
1831 else
1832 {
1833 filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V6;
1834 }
1835 starget = &FWPM_CONDITION_IP_LOCAL_ADDRESS;
1836 dtarget = &FWPM_CONDITION_IP_REMOTE_ADDRESS;
1837 }
1838
1839 if (!ts2condition(trap->src, starget, &conds, &count) ||
1840 !ts2condition(trap->dst, dtarget, &conds, &count))
1841 {
1842 free_conditions(conds, count);
1843 return FALSE;
1844 }
1845
1846 filter.numFilterConditions = count;
1847 filter.filterCondition = conds;
1848
1849 res = FwpmFilterAdd0(this->handle, &filter, NULL, &trap->filter_id);
1850 free_conditions(conds, count);
1851 if (res != ERROR_SUCCESS)
1852 {
1853 DBG1(DBG_KNL, "installing WFP trap filter failed: 0x%08x", res);
1854 return FALSE;
1855 }
1856 return TRUE;
1857 }
1858
1859 /**
1860 * Uninstall a trap policy from kernel
1861 */
1862 static bool uninstall_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap)
1863 {
1864 DWORD res;
1865
1866 res = FwpmFilterDeleteById0(this->handle, trap->filter_id);
1867 if (res != ERROR_SUCCESS)
1868 {
1869 DBG1(DBG_KNL, "uninstalling WFP trap filter failed: 0x%08x", res);
1870 return FALSE;
1871 }
1872 return TRUE;
1873 }
1874
1875 /**
1876 * Create and install a new trap entry
1877 */
1878 static bool add_trap(private_kernel_wfp_ipsec_t *this,
1879 uint32_t reqid, bool fwd, host_t *local, host_t *remote,
1880 traffic_selector_t *src, traffic_selector_t *dst)
1881 {
1882 trap_t *trap;
1883
1884 INIT(trap,
1885 .reqid = reqid,
1886 .fwd = fwd,
1887 .src = src->clone(src),
1888 .dst = dst->clone(dst),
1889 .local = local->clone(local),
1890 .remote = remote->clone(remote),
1891 );
1892
1893 if (!install_trap(this, trap))
1894 {
1895 destroy_trap(trap);
1896 return FALSE;
1897 }
1898
1899 trap->route = manage_route(this, local, remote, src, dst, TRUE);
1900
1901 this->mutex->lock(this->mutex);
1902 this->traps->put(this->traps, trap, trap);
1903 this->mutex->unlock(this->mutex);
1904 return TRUE;
1905 }
1906
1907 /**
1908 * Uninstall and remove a new trap entry
1909 */
1910 static bool remove_trap(private_kernel_wfp_ipsec_t *this,
1911 uint32_t reqid, bool fwd,
1912 traffic_selector_t *src, traffic_selector_t *dst)
1913 {
1914 enumerator_t *enumerator;
1915 trap_t *trap, *found = NULL;
1916
1917 this->mutex->lock(this->mutex);
1918 enumerator = this->traps->create_enumerator(this->traps);
1919 while (enumerator->enumerate(enumerator, NULL, &trap))
1920 {
1921 if (reqid == trap->reqid &&
1922 fwd == trap->fwd &&
1923 src->equals(src, trap->src) &&
1924 dst->equals(dst, trap->dst))
1925 {
1926 this->traps->remove_at(this->traps, enumerator);
1927 found = trap;
1928 break;
1929 }
1930 }
1931 enumerator->destroy(enumerator);
1932 this->mutex->unlock(this->mutex);
1933
1934 if (found)
1935 {
1936 if (trap->route)
1937 {
1938 trap->route = !manage_route(this, trap->local, trap->remote,
1939 src, dst, FALSE);
1940 }
1941 uninstall_trap(this, found);
1942 destroy_trap(found);
1943 return TRUE;
1944 }
1945 return FALSE;
1946 }
1947
1948 METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
1949 private_kernel_wfp_ipsec_t *this)
1950 {
1951 return KERNEL_ESP_V3_TFC | KERNEL_NO_POLICY_UPDATES;
1952 }
1953
1954 /**
1955 * Initialize seeds for SPI generation
1956 */
1957 static bool init_spi(private_kernel_wfp_ipsec_t *this)
1958 {
1959 bool ok = TRUE;
1960 rng_t *rng;
1961
1962 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
1963 if (!rng)
1964 {
1965 return FALSE;
1966 }
1967 ok = rng->get_bytes(rng, sizeof(this->nextspi), (uint8_t*)&this->nextspi);
1968 if (ok)
1969 {
1970 ok = rng->get_bytes(rng, sizeof(this->mixspi), (uint8_t*)&this->mixspi);
1971 }
1972 rng->destroy(rng);
1973 return ok;
1974 }
1975
1976 /**
1977 * Map an integer x with a one-to-one function using quadratic residues.
1978 */
1979 static u_int permute(u_int x, u_int p)
1980 {
1981 u_int qr;
1982
1983 x = x % p;
1984 qr = ((uint64_t)x * x) % p;
1985 if (x <= p / 2)
1986 {
1987 return qr;
1988 }
1989 return p - qr;
1990 }
1991
1992 METHOD(kernel_ipsec_t, get_spi, status_t,
1993 private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
1994 uint8_t protocol, uint32_t *spi)
1995 {
1996 /* To avoid sequential SPIs, we use a one-to-one permutation function on
1997 * an incrementing counter, that is a full period PRNG for the range we
1998 * allocate SPIs in. We add some randomness using a fixed XOR and start
1999 * the counter at random position. This is not cryptographically safe,
2000 * but that is actually not required.
2001 * The selected prime should be smaller than the range we allocate SPIs
2002 * in, and it must satisfy p % 4 == 3 to map x > p/2 using p - qr. */
2003 static const u_int p = 268435399, offset = 0xc0000000;
2004
2005 *spi = htonl(offset + permute(ref_get(&this->nextspi) ^ this->mixspi, p));
2006 return SUCCESS;
2007 }
2008
2009 METHOD(kernel_ipsec_t, get_cpi, status_t,
2010 private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
2011 uint16_t *cpi)
2012 {
2013 return NOT_SUPPORTED;
2014 }
2015
2016 /**
2017 * Data for an expire callback job
2018 */
2019 typedef struct {
2020 /* backref to kernel backend */
2021 private_kernel_wfp_ipsec_t *this;
2022 /* SPI of expiring SA */
2023 uint32_t spi;
2024 /* destination address of expiring SA */
2025 host_t *dst;
2026 /* is this a hard expire, or a rekey request? */
2027 bool hard;
2028 } expire_data_t;
2029
2030 /**
2031 * Clean up expire data
2032 */
2033 static void expire_data_destroy(expire_data_t *data)
2034 {
2035 data->dst->destroy(data->dst);
2036 free(data);
2037 }
2038
2039 /**
2040 * Callback job for SA expiration
2041 */
2042 static job_requeue_t expire_job(expire_data_t *data)
2043 {
2044 private_kernel_wfp_ipsec_t *this = data->this;
2045 uint8_t protocol;
2046 entry_t *entry = NULL;
2047 sa_entry_t key = {
2048 .spi = data->spi,
2049 .dst = data->dst,
2050 };
2051
2052 if (data->hard)
2053 {
2054 this->mutex->lock(this->mutex);
2055 entry = this->isas->remove(this->isas, &key);
2056 this->mutex->unlock(this->mutex);
2057 if (entry)
2058 {
2059 protocol = entry->isa.protocol;
2060 if (entry->osa.dst)
2061 {
2062 key.dst = entry->osa.dst;
2063 key.spi = entry->osa.spi;
2064 this->osas->remove(this->osas, &key);
2065 }
2066 entry_destroy(this, entry);
2067 }
2068 }
2069 else
2070 {
2071 this->mutex->lock(this->mutex);
2072 entry = this->isas->get(this->isas, &key);
2073 if (entry)
2074 {
2075 protocol = entry->isa.protocol;
2076 }
2077 this->mutex->unlock(this->mutex);
2078 }
2079
2080 if (entry)
2081 {
2082 charon->kernel->expire(charon->kernel, protocol, data->spi, data->dst,
2083 data->hard);
2084 }
2085
2086 return JOB_REQUEUE_NONE;
2087 }
2088
2089 /**
2090 * Schedule an expire event for an SA
2091 */
2092 static void schedule_expire(private_kernel_wfp_ipsec_t *this, uint32_t spi,
2093 host_t *dst, uint32_t lifetime, bool hard)
2094 {
2095 expire_data_t *data;
2096
2097 INIT(data,
2098 .this = this,
2099 .spi = spi,
2100 .dst = dst->clone(dst),
2101 .hard = hard,
2102 );
2103
2104 lib->scheduler->schedule_job(lib->scheduler, (job_t*)
2105 callback_job_create((void*)expire_job, data,
2106 (void*)expire_data_destroy, NULL),
2107 lifetime);
2108 }
2109
2110 METHOD(kernel_ipsec_t, add_sa, status_t,
2111 private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
2112 kernel_ipsec_add_sa_t *data)
2113 {
2114 host_t *local, *remote;
2115 entry_t *entry;
2116
2117 if (data->inbound)
2118 {
2119 /* comes first, create new entry */
2120 local = id->dst->clone(id->dst);
2121 remote = id->src->clone(id->src);
2122
2123 INIT(entry,
2124 .reqid = data->reqid,
2125 .isa = {
2126 .spi = id->spi,
2127 .dst = local,
2128 .protocol = id->proto,
2129 .lifetime = data->lifetime->time.life,
2130 .encr = {
2131 .alg = data->enc_alg,
2132 .key = chunk_clone(data->enc_key),
2133 },
2134 .integ = {
2135 .alg = data->int_alg,
2136 .key = chunk_clone(data->int_key),
2137 },
2138 },
2139 .sps = array_create(0, 0),
2140 .local = local,
2141 .remote = remote,
2142 .mode = data->mode,
2143 .encap = data->encap,
2144 );
2145
2146 if (data->lifetime->time.life)
2147 {
2148 schedule_expire(this, id->spi, local,
2149 data->lifetime->time.life, TRUE);
2150 }
2151 if (data->lifetime->time.rekey &&
2152 data->lifetime->time.rekey != data->lifetime->time.life)
2153 {
2154 schedule_expire(this, id->spi, local,
2155 data->lifetime->time.rekey, FALSE);
2156 }
2157
2158 this->mutex->lock(this->mutex);
2159 this->tsas->put(this->tsas, (void*)(uintptr_t)data->reqid, entry);
2160 this->isas->put(this->isas, &entry->isa, entry);
2161 this->mutex->unlock(this->mutex);
2162 }
2163 else
2164 {
2165 /* comes after inbound, update entry */
2166 this->mutex->lock(this->mutex);
2167 entry = this->tsas->remove(this->tsas, (void*)(uintptr_t)data->reqid);
2168 this->mutex->unlock(this->mutex);
2169
2170 if (!entry)
2171 {
2172 DBG1(DBG_KNL, "adding outbound SA failed, no inbound SA found "
2173 "for reqid %u ", data->reqid);
2174 return NOT_FOUND;
2175 }
2176 /* TODO: should we check for local/remote, mode etc.? */
2177
2178 entry->osa = (sa_entry_t){
2179 .spi = id->spi,
2180 .dst = entry->remote,
2181 .protocol = id->proto,
2182 .lifetime = data->lifetime->time.life,
2183 .encr = {
2184 .alg = data->enc_alg,
2185 .key = chunk_clone(data->enc_key),
2186 },
2187 .integ = {
2188 .alg = data->int_alg,
2189 .key = chunk_clone(data->int_key),
2190 },
2191 };
2192
2193 this->mutex->lock(this->mutex);
2194 this->osas->put(this->osas, &entry->osa, entry);
2195 this->mutex->unlock(this->mutex);
2196 }
2197
2198 return SUCCESS;
2199 }
2200
2201 METHOD(kernel_ipsec_t, update_sa, status_t,
2202 private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
2203 kernel_ipsec_update_sa_t *data)
2204 {
2205 entry_t *entry;
2206 sa_entry_t key = {
2207 .dst = id->dst,
2208 .spi = id->spi,
2209 };
2210 UINT64 sa_id = 0;
2211 IPSEC_SA_CONTEXT1 *ctx;
2212 IPSEC_V4_UDP_ENCAPSULATION0 ports;
2213 UINT32 flags = IPSEC_SA_DETAILS_UPDATE_TRAFFIC;
2214 DWORD res;
2215
2216 this->mutex->lock(this->mutex);
2217 entry = this->osas->get(this->osas, &key);
2218 this->mutex->unlock(this->mutex);
2219
2220 if (entry)
2221 {
2222 /* outbound entry, nothing to do */
2223 return SUCCESS;
2224 }
2225
2226 this->mutex->lock(this->mutex);
2227 entry = this->isas->get(this->isas, &key);
2228 if (entry)
2229 {
2230 /* inbound entry, do update */
2231 sa_id = entry->sa_id;
2232 ports.localUdpEncapPort = data->new_dst->get_port(data->new_dst);
2233 ports.remoteUdpEncapPort = data->new_src->get_port(data->new_src);
2234 }
2235 this->mutex->unlock(this->mutex);
2236
2237 if (!sa_id)
2238 {
2239 return NOT_FOUND;
2240 }
2241
2242 res = IPsecSaContextGetById1(this->handle, sa_id, &ctx);
2243 if (res != ERROR_SUCCESS)
2244 {
2245 DBG1(DBG_KNL, "getting WFP SA context for updated failed: 0x%08x", res);
2246 return FAILED;
2247 }
2248 if (!hosts2traffic(this, data->new_dst, data->new_src, &ctx->inboundSa->traffic) ||
2249 !hosts2traffic(this, data->new_dst, data->new_src, &ctx->outboundSa->traffic))
2250 {
2251 FwpmFreeMemory0((void**)&ctx);
2252 return FAILED;
2253 }
2254
2255 if (data->new_encap != data->encap)
2256 {
2257 if (data->new_encap)
2258 {
2259 ctx->inboundSa->udpEncapsulation = &ports;
2260 ctx->outboundSa->udpEncapsulation = &ports;
2261 }
2262 else
2263 {
2264 ctx->inboundSa->udpEncapsulation = NULL;
2265 ctx->outboundSa->udpEncapsulation = NULL;
2266 }
2267 flags |= IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION;
2268 }
2269
2270 res = IPsecSaContextUpdate0(this->handle, flags, ctx);
2271 FwpmFreeMemory0((void**)&ctx);
2272 if (res != ERROR_SUCCESS)
2273 {
2274 DBG1(DBG_KNL, "updating WFP SA context failed: 0x%08x", res);
2275 return FAILED;
2276 }
2277
2278 this->mutex->lock(this->mutex);
2279 entry = this->isas->remove(this->isas, &key);
2280 if (entry)
2281 {
2282 key.spi = entry->osa.spi;
2283 key.dst = entry->osa.dst;
2284 this->osas->remove(this->osas, &key);
2285
2286 if (data->new_reqid)
2287 {
2288 entry->reqid = data->new_reqid;
2289 }
2290 entry->local->destroy(entry->local);
2291 entry->remote->destroy(entry->remote);
2292 entry->local = data->new_dst->clone(data->new_dst);
2293 entry->remote = data->new_src->clone(data->new_src);
2294 entry->isa.dst = entry->local;
2295 entry->osa.dst = entry->remote;
2296
2297 this->isas->put(this->isas, &entry->isa, entry);
2298 this->osas->put(this->osas, &entry->osa, entry);
2299
2300 manage_routes(this, entry, FALSE);
2301 manage_routes(this, entry, TRUE);
2302 }
2303 this->mutex->unlock(this->mutex);
2304
2305 return SUCCESS;
2306 }
2307
2308 METHOD(kernel_ipsec_t, query_sa, status_t,
2309 private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
2310 kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
2311 time_t *time)
2312 {
2313 /* It does not seem that WFP provides any means of getting per-SA traffic
2314 * statistics. IPsecGetStatistics0/1() provides global stats, and
2315 * IPsecSaContextEnum0/1() and IPsecSaEnum0/1() return the configured
2316 * values only. */
2317 return NOT_SUPPORTED;
2318 }
2319
2320 METHOD(kernel_ipsec_t, del_sa, status_t,
2321 private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
2322 kernel_ipsec_del_sa_t *data)
2323 {
2324 entry_t *entry;
2325 sa_entry_t key = {
2326 .dst = id->dst,
2327 .spi = id->spi,
2328 };
2329
2330 this->mutex->lock(this->mutex);
2331 entry = this->isas->remove(this->isas, &key);
2332 this->mutex->unlock(this->mutex);
2333
2334 if (entry)
2335 {
2336 /* keep entry until removal of outbound */
2337 return SUCCESS;
2338 }
2339
2340 this->mutex->lock(this->mutex);
2341 entry = this->osas->remove(this->osas, &key);
2342 this->mutex->unlock(this->mutex);
2343
2344 if (entry)
2345 {
2346 entry_destroy(this, entry);
2347 return SUCCESS;
2348 }
2349
2350 return NOT_FOUND;
2351 }
2352
2353 METHOD(kernel_ipsec_t, flush_sas, status_t,
2354 private_kernel_wfp_ipsec_t *this)
2355 {
2356 return NOT_SUPPORTED;
2357 }
2358
2359 METHOD(kernel_ipsec_t, add_policy, status_t,
2360 private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id,
2361 kernel_ipsec_manage_policy_t *data)
2362 {
2363 status_t status = SUCCESS;
2364 entry_t *entry;
2365 sp_entry_t *sp;
2366 sa_entry_t key = {
2367 .spi = data->sa->esp.use ? data->sa->esp.spi : data->sa->ah.spi,
2368 .dst = data->dst,
2369 };
2370
2371 if (data->sa->esp.use && data->sa->ah.use)
2372 {
2373 return NOT_SUPPORTED;
2374 }
2375
2376 switch (data->type)
2377 {
2378 case POLICY_IPSEC:
2379 break;
2380 case POLICY_PASS:
2381 case POLICY_DROP:
2382 return NOT_SUPPORTED;
2383 }
2384
2385 switch (id->dir)
2386 {
2387 case POLICY_OUT:
2388 break;
2389 case POLICY_IN:
2390 case POLICY_FWD:
2391 /* not required */
2392 return SUCCESS;
2393 default:
2394 return NOT_SUPPORTED;
2395 }
2396
2397 switch (data->prio)
2398 {
2399 case POLICY_PRIORITY_DEFAULT:
2400 break;
2401 case POLICY_PRIORITY_ROUTED:
2402 if (!add_trap(this, data->sa->reqid, FALSE, data->src, data->dst,
2403 id->src_ts, id->dst_ts))
2404 {
2405 return FAILED;
2406 }
2407 if (data->sa->mode == MODE_TUNNEL)
2408 {
2409 if (!add_trap(this, data->sa->reqid, TRUE, data->src, data->dst,
2410 id->src_ts, id->dst_ts))
2411 {
2412 return FAILED;
2413 }
2414 }
2415 return SUCCESS;
2416 case POLICY_PRIORITY_FALLBACK:
2417 default:
2418 return NOT_SUPPORTED;
2419 }
2420
2421 this->mutex->lock(this->mutex);
2422 entry = this->osas->get(this->osas, &key);
2423 if (entry)
2424 {
2425 if (data->sa->mode == MODE_TUNNEL || array_count(entry->sps) == 0)
2426 {
2427 INIT(sp,
2428 .src = id->src_ts->clone(id->src_ts),
2429 .dst = id->dst_ts->clone(id->dst_ts),
2430 );
2431 array_insert(entry->sps, -1, sp);
2432 if (array_count(entry->sps) == data->sa->policy_count)
2433 {
2434 if (!install(this, entry))
2435 {
2436 status = FAILED;
2437 }
2438 }
2439 }
2440 else
2441 {
2442 /* TODO: reinstall with a filter using multiple TS?
2443 * Filters are ANDed for a match, but we could install a filter
2444 * with the inverse TS set using NOT-matches... */
2445 DBG1(DBG_KNL, "multiple transport mode traffic selectors not "
2446 "supported by WFP");
2447 status = NOT_SUPPORTED;
2448 }
2449 }
2450 else
2451 {
2452 DBG1(DBG_KNL, "adding SP failed, no SA found for SPI 0x%08x", key.spi);
2453 status = FAILED;
2454 }
2455 this->mutex->unlock(this->mutex);
2456
2457 return status;
2458 }
2459
2460 METHOD(kernel_ipsec_t, query_policy, status_t,
2461 private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id,
2462 kernel_ipsec_query_policy_t *data, time_t *use_time)
2463 {
2464 /* see query_sa() for some notes */
2465 return NOT_SUPPORTED;
2466 }
2467
2468 METHOD(kernel_ipsec_t, del_policy, status_t,
2469 private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id,
2470 kernel_ipsec_manage_policy_t *data)
2471 {
2472 if (id->dir == POLICY_OUT && data->prio == POLICY_PRIORITY_ROUTED)
2473 {
2474 if (remove_trap(this, data->sa->reqid, FALSE, id->src_ts,
2475 id->dst_ts))
2476 {
2477 remove_trap(this, data->sa->reqid, TRUE, id->src_ts,
2478 id->dst_ts);
2479 return SUCCESS;
2480 }
2481 return NOT_FOUND;
2482 }
2483 /* not required, as we delete the whole SA/SP set during del_sa() */
2484 return SUCCESS;
2485 }
2486
2487 METHOD(kernel_ipsec_t, flush_policies, status_t,
2488 private_kernel_wfp_ipsec_t *this)
2489 {
2490 return NOT_SUPPORTED;
2491 }
2492
2493 /**
2494 * Add a bypass policy for a specific UDP port
2495 */
2496 static bool add_bypass(private_kernel_wfp_ipsec_t *this,
2497 int family, uint16_t port, bool inbound, bool tunnel,
2498 UINT64 *luid)
2499 {
2500 FWPM_FILTER_CONDITION0 *cond, *conds = NULL;
2501 int count = 0;
2502 DWORD res;
2503 UINT64 weight = 0xff00000000000000;
2504 FWPM_FILTER0 filter = {
2505 .displayData = {
2506 .name = L"charon IKE bypass",
2507 },
2508 .action = {
2509 .type = FWP_ACTION_PERMIT,
2510 },
2511 .weight = {
2512 .type = FWP_UINT64,
2513 .uint64 = &weight,
2514 },
2515 };
2516
2517 switch (family)
2518 {
2519 case AF_INET:
2520 filter.layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V4
2521 : FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
2522 break;
2523 case AF_INET6:
2524 filter.layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V6
2525 : FWPM_LAYER_OUTBOUND_TRANSPORT_V6;
2526 break;
2527 default:
2528 return FALSE;
2529 }
2530
2531 if (tunnel)
2532 {
2533 filter.subLayerKey = FWPM_SUBLAYER_IPSEC_TUNNEL;
2534 }
2535
2536 cond = append_condition(&conds, &count);
2537 cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL;
2538 cond->matchType = FWP_MATCH_EQUAL;
2539 cond->conditionValue.type = FWP_UINT8;
2540 cond->conditionValue.uint8 = IPPROTO_UDP;
2541
2542 cond = append_condition(&conds, &count);
2543 cond->fieldKey = FWPM_CONDITION_IP_LOCAL_PORT;
2544 cond->matchType = FWP_MATCH_EQUAL;
2545 cond->conditionValue.type = FWP_UINT16;
2546 cond->conditionValue.uint16 = port;
2547
2548 filter.numFilterConditions = count;
2549 filter.filterCondition = conds;
2550
2551 res = FwpmFilterAdd0(this->handle, &filter, NULL, luid);
2552 free_conditions(conds, count);
2553 if (res != ERROR_SUCCESS)
2554 {
2555 DBG1(DBG_KNL, "installing WFP bypass filter failed: 0x%08x", res);
2556 return FALSE;
2557 }
2558 return TRUE;
2559 }
2560
2561 METHOD(kernel_ipsec_t, bypass_socket, bool,
2562 private_kernel_wfp_ipsec_t *this, int fd, int family)
2563 {
2564 union {
2565 struct sockaddr sa;
2566 SOCKADDR_IN in;
2567 SOCKADDR_IN6 in6;
2568 } saddr;
2569 int addrlen = sizeof(saddr), i;
2570 UINT64 filters[4] = { 0 };
2571 uint16_t port;
2572
2573 if (getsockname(fd, &saddr.sa, &addrlen) == SOCKET_ERROR)
2574 {
2575 return FALSE;
2576 }
2577 switch (family)
2578 {
2579 case AF_INET:
2580 port = ntohs(saddr.in.sin_port);
2581 break;
2582 case AF_INET6:
2583 port = ntohs(saddr.in6.sin6_port);
2584 break;
2585 default:
2586 return FALSE;
2587 }
2588
2589 if (!add_bypass(this, family, port, TRUE, FALSE, &filters[0]) ||
2590 !add_bypass(this, family, port, TRUE, TRUE, &filters[1]) ||
2591 !add_bypass(this, family, port, FALSE, FALSE, &filters[2]) ||
2592 !add_bypass(this, family, port, FALSE, TRUE, &filters[3]))
2593 {
2594 for (i = 0; i < countof(filters); i++)
2595 {
2596 if (filters[i])
2597 {
2598 FwpmFilterDeleteById0(this->handle, filters[i]);
2599 }
2600 }
2601 return FALSE;
2602 }
2603
2604 this->mutex->lock(this->mutex);
2605 for (i = 0; i < countof(filters); i++)
2606 {
2607 array_insert(this->bypass, ARRAY_TAIL, &filters[i]);
2608 }
2609 this->mutex->unlock(this->mutex);
2610
2611 return TRUE;
2612 }
2613
2614 METHOD(kernel_ipsec_t, enable_udp_decap, bool,
2615 private_kernel_wfp_ipsec_t *this, int fd, int family, uint16_t port)
2616 {
2617 return FALSE;
2618 }
2619
2620 METHOD(kernel_ipsec_t, destroy, void,
2621 private_kernel_wfp_ipsec_t *this)
2622 {
2623 UINT64 filter;
2624
2625 while (array_remove(this->bypass, ARRAY_TAIL, &filter))
2626 {
2627 FwpmFilterDeleteById0(this->handle, filter);
2628 }
2629 if (this->handle)
2630 {
2631 if (this->event)
2632 {
2633 FwpmNetEventUnsubscribe0(this->handle, this->event);
2634 }
2635 FwpmProviderDeleteByKey0(this->handle, &this->provider.providerKey);
2636 FwpmEngineClose0(this->handle);
2637 }
2638 array_destroy(this->bypass);
2639 this->tsas->destroy(this->tsas);
2640 this->isas->destroy(this->isas);
2641 this->osas->destroy(this->osas);
2642 this->routes->destroy(this->routes);
2643 this->traps->destroy(this->traps);
2644 this->mutex->destroy(this->mutex);
2645 free(this);
2646 }
2647
2648 /*
2649 * Described in header.
2650 */
2651 kernel_wfp_ipsec_t *kernel_wfp_ipsec_create()
2652 {
2653 private_kernel_wfp_ipsec_t *this;
2654 DWORD res;
2655 FWPM_SESSION0 session = {
2656 .displayData = {
2657 .name = L"charon",
2658 .description = L"strongSwan IKE kernel-wfp backend",
2659 },
2660 };
2661
2662 INIT(this,
2663 .public = {
2664 .interface = {
2665 .get_features = _get_features,
2666 .get_spi = _get_spi,
2667 .get_cpi = _get_cpi,
2668 .add_sa = _add_sa,
2669 .update_sa = _update_sa,
2670 .query_sa = _query_sa,
2671 .del_sa = _del_sa,
2672 .flush_sas = _flush_sas,
2673 .add_policy = _add_policy,
2674 .query_policy = _query_policy,
2675 .del_policy = _del_policy,
2676 .flush_policies = _flush_policies,
2677 .bypass_socket = _bypass_socket,
2678 .enable_udp_decap = _enable_udp_decap,
2679 .destroy = _destroy,
2680 },
2681 },
2682 .provider = {
2683 .displayData = {
2684 .name = L"charon",
2685 .description = L"strongSwan IKE kernel-wfp backend",
2686 },
2687 .providerKey = { 0x59cdae2e, 0xf6bb, 0x4c09,
2688 { 0xa9,0x59,0x9d,0x91,0xac,0xaf,0xf9,0x19 }},
2689 },
2690 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
2691 .bypass = array_create(sizeof(UINT64), 2),
2692 .tsas = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4),
2693 .isas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
2694 .osas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
2695 .routes = hashtable_create((void*)hash_route, (void*)equals_route, 4),
2696 .traps = hashtable_create((void*)hash_trap, (void*)equals_trap, 4),
2697 );
2698
2699 if (!init_spi(this))
2700 {
2701 destroy(this);
2702 return NULL;
2703 }
2704
2705 res = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session,
2706 &this->handle);
2707 if (res != ERROR_SUCCESS)
2708 {
2709 DBG1(DBG_KNL, "opening WFP engine failed: 0x%08x", res);
2710 destroy(this);
2711 return NULL;
2712 }
2713
2714 res = FwpmProviderAdd0(this->handle, &this->provider, NULL);
2715 if (res != ERROR_SUCCESS && res != FWP_E_ALREADY_EXISTS)
2716 {
2717 DBG1(DBG_KNL, "registering WFP provider failed: 0x%08x", res);
2718 destroy(this);
2719 return NULL;
2720 }
2721
2722 if (!register_events(this))
2723 {
2724 destroy(this);
2725 return NULL;
2726 }
2727
2728 return &this->public;
2729 }