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