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