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