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