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