2 * Copyright (C) 2013 Martin Willi
4 * Copyright (C) secunet Security Networks AG
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 /* Windows 7, for some fwpmu.h functionality */
18 #define _WIN32_WINNT 0x0601
20 #include "kernel_wfp_compat.h"
21 #include "kernel_wfp_ipsec.h"
24 #include <threading/mutex.h>
25 #include <collections/array.h>
26 #include <collections/hashtable.h>
27 #include <processing/jobs/callback_job.h>
30 #define IPPROTO_IPIP 4
33 #define IPPROTO_IPV6 41
36 typedef struct private_kernel_wfp_ipsec_t private_kernel_wfp_ipsec_t
;
38 struct private_kernel_wfp_ipsec_t
{
43 kernel_wfp_ipsec_t
public;
46 * Next SPI to allocate
51 * Mix value to distribute SPI allocation randomly
56 * IKE bypass filters, as UINT64 filter LUID
61 * Temporary SAD/SPD entries referenced reqid, as uintptr_t => entry_t
66 * SAD/SPD entries referenced by inbound SA, as sa_entry_t => entry_t
71 * SAD/SPD entries referenced by outbound SA, as sa_entry_t => entry_t
76 * Installed routes, as route_t => route_t
81 * Installed traps, as trap_t => trap_t
86 * Mutex for accessing entries
96 * Provider charon registers as
98 FWPM_PROVIDER0 provider
;
107 * Security association entry
110 /** SPI for this SA */
112 /** protocol, IPPROTO_ESP/IPPROTO_AH */
114 /** hard lifetime of SA */
116 /** destination host address for this SPI */
127 * Hash function for sas lookup table
129 static u_int
hash_sa(sa_entry_t
*key
)
131 return chunk_hash_inc(chunk_from_thing(key
->spi
),
132 chunk_hash(key
->dst
->get_address(key
->dst
)));
136 * equals function for sas lookup table
138 static bool equals_sa(sa_entry_t
*a
, sa_entry_t
*b
)
140 return a
->spi
== b
->spi
&& a
->dst
->ip_equals(a
->dst
, b
->dst
);
144 * Security policy entry
147 /** policy source addresses */
148 traffic_selector_t
*src
;
149 /** policy destination addresses */
150 traffic_selector_t
*dst
;
151 /** WFP allocated LUID for inbound filter ID */
153 /** WFP allocated LUID for outbound filter ID */
155 /** WFP allocated LUID for forward inbound filter ID, tunnel mode only */
156 uint64_t policy_fwd_in
;
157 /** WFP allocated LUID for forward outbound filter ID, tunnel mode only */
158 uint64_t policy_fwd_out
;
159 /** have installed a route for it? */
164 * Destroy an SP entry
166 static void sp_entry_destroy(sp_entry_t
*sp
)
168 sp
->src
->destroy(sp
->src
);
169 sp
->dst
->destroy(sp
->dst
);
174 * Collection of SA/SP database entries for a reqid
177 /** reqid of entry */
179 /** outer address on local host */
181 /** outer address on remote host */
183 /** inbound SA entry */
185 /** outbound SA entry */
187 /** associated (outbound) policies, as sp_entry_t* */
189 /** IPsec mode, tunnel|transport */
191 /** UDP encapsulation */
193 /** provider context, for tunnel mode only */
195 /** WFP allocated LUID for SA context */
197 /** WFP allocated LUID for tunnel mode IP-IPv4 inbound filter */
199 /** WFP allocated LUID for tunnel mode IP-IPv4 outbound filter */
200 uint64_t ip_ipv4_out
;
201 /** WFP allocated LUID for tunnel mode IP-IPv6 inbound filter */
203 /** WFP allocated LUID for tunnel mode IP-IPv6 outbound filter */
204 uint64_t ip_ipv6_out
;
211 /** destination net of route */
213 /** prefix length of dst */
215 /** source address for route */
217 /** gateway of route, NULL if directly attached */
219 /** references for route */
226 static void destroy_route(route_t
*this)
228 this->dst
->destroy(this->dst
);
229 this->src
->destroy(this->src
);
230 DESTROY_IF(this->gtw
);
235 * Hashtable equals function for routes
237 static bool equals_route(route_t
*a
, route_t
*b
)
239 return a
->mask
== b
->mask
&&
240 a
->dst
->ip_equals(a
->dst
, b
->dst
) &&
241 a
->src
->ip_equals(a
->src
, b
->src
);
245 * Hashtable hash function for routes
247 static u_int
hash_route(route_t
*route
)
249 return chunk_hash_inc(route
->src
->get_address(route
->src
),
250 chunk_hash_inc(route
->dst
->get_address(route
->dst
), route
->mask
));
253 /** forward declaration */
254 static bool manage_routes(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
,
258 * Remove policies associated to an entry from kernel
260 static void cleanup_policies(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
262 enumerator_t
*enumerator
;
265 if (entry
->mode
== MODE_TUNNEL
)
267 manage_routes(this, entry
, FALSE
);
270 enumerator
= array_create_enumerator(entry
->sps
);
271 while (enumerator
->enumerate(enumerator
, &sp
))
275 FwpmFilterDeleteById0(this->handle
, sp
->policy_in
);
280 FwpmFilterDeleteById0(this->handle
, sp
->policy_out
);
283 if (sp
->policy_fwd_in
)
285 FwpmFilterDeleteById0(this->handle
, sp
->policy_fwd_in
);
286 sp
->policy_fwd_in
= 0;
288 if (sp
->policy_fwd_out
)
290 FwpmFilterDeleteById0(this->handle
, sp
->policy_fwd_out
);
291 sp
->policy_fwd_out
= 0;
294 enumerator
->destroy(enumerator
);
298 * Destroy a SA/SP entry set
300 static void entry_destroy(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
302 if (entry
->ip_ipv4_in
)
304 FwpmFilterDeleteById0(this->handle
, entry
->ip_ipv4_in
);
306 if (entry
->ip_ipv4_out
)
308 FwpmFilterDeleteById0(this->handle
, entry
->ip_ipv4_out
);
310 if (entry
->ip_ipv6_in
)
312 FwpmFilterDeleteById0(this->handle
, entry
->ip_ipv6_in
);
314 if (entry
->ip_ipv6_out
)
316 FwpmFilterDeleteById0(this->handle
, entry
->ip_ipv6_out
);
320 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
324 FwpmProviderContextDeleteById0(this->handle
, entry
->provider
);
326 cleanup_policies(this, entry
);
327 array_destroy_function(entry
->sps
, (void*)sp_entry_destroy
, NULL
);
328 entry
->local
->destroy(entry
->local
);
329 entry
->remote
->destroy(entry
->remote
);
330 chunk_clear(&entry
->isa
.integ
.key
);
331 chunk_clear(&entry
->isa
.encr
.key
);
332 chunk_clear(&entry
->osa
.integ
.key
);
333 chunk_clear(&entry
->osa
.encr
.key
);
338 * Append/Realloc a filter condition to an existing condition set
340 static FWPM_FILTER_CONDITION0
*append_condition(FWPM_FILTER_CONDITION0
*conds
[],
343 FWPM_FILTER_CONDITION0
*cond
;
346 *conds
= realloc(*conds
, *count
* sizeof(*cond
));
347 cond
= *conds
+ *count
- 1;
348 memset(cond
, 0, sizeof(*cond
));
354 * Convert an IPv4 prefix to a host order subnet mask
356 static uint32_t prefix2mask(uint8_t prefix
)
358 uint8_t netmask
[4] = {};
361 for (i
= 0; i
< sizeof(netmask
); i
++)
365 netmask
[i
] = 0xFF << (8 - prefix
);
371 return untoh32(netmask
);
375 * Convert a 16-bit range to a WFP condition
377 static void range2cond(FWPM_FILTER_CONDITION0
*cond
,
378 uint16_t from
, uint16_t to
)
382 cond
->matchType
= FWP_MATCH_EQUAL
;
383 cond
->conditionValue
.type
= FWP_UINT16
;
384 cond
->conditionValue
.uint16
= from
;
388 cond
->matchType
= FWP_MATCH_RANGE
;
389 cond
->conditionValue
.type
= FWP_RANGE_TYPE
;
390 cond
->conditionValue
.rangeValue
= calloc(1, sizeof(FWP_RANGE0
));
391 cond
->conditionValue
.rangeValue
->valueLow
.type
= FWP_UINT16
;
392 cond
->conditionValue
.rangeValue
->valueLow
.uint16
= from
;
393 cond
->conditionValue
.rangeValue
->valueHigh
.type
= FWP_UINT16
;
394 cond
->conditionValue
.rangeValue
->valueHigh
.uint16
= to
;
399 * (Re-)allocate filter conditions for given local or remote traffic selector
401 static bool ts2condition(traffic_selector_t
*ts
, const GUID
*target
,
402 FWPM_FILTER_CONDITION0
*conds
[], int *count
)
404 FWPM_FILTER_CONDITION0
*cond
;
405 FWP_BYTE_ARRAY16
*addr
;
407 uint16_t from_port
, to_port
;
413 from
= ts
->get_from_address(ts
).ptr
;
414 to
= ts
->get_to_address(ts
).ptr
;
415 from_port
= ts
->get_from_port(ts
);
416 to_port
= ts
->get_to_port(ts
);
418 cond
= append_condition(conds
, count
);
419 cond
->fieldKey
= *target
;
420 if (ts
->is_host(ts
, NULL
))
422 cond
->matchType
= FWP_MATCH_EQUAL
;
423 switch (ts
->get_type(ts
))
425 case TS_IPV4_ADDR_RANGE
:
426 cond
->conditionValue
.type
= FWP_UINT32
;
427 cond
->conditionValue
.uint32
= untoh32(from
);
429 case TS_IPV6_ADDR_RANGE
:
430 cond
->conditionValue
.type
= FWP_BYTE_ARRAY16_TYPE
;
431 cond
->conditionValue
.byteArray16
= addr
= malloc(sizeof(*addr
));
432 memcpy(addr
, from
, sizeof(*addr
));
438 else if (ts
->to_subnet(ts
, &net
, &prefix
))
440 FWP_V6_ADDR_AND_MASK
*m6
;
441 FWP_V4_ADDR_AND_MASK
*m4
;
443 cond
->matchType
= FWP_MATCH_EQUAL
;
444 switch (net
->get_family(net
))
447 cond
->conditionValue
.type
= FWP_V4_ADDR_MASK
;
448 cond
->conditionValue
.v4AddrMask
= m4
= calloc(1, sizeof(*m4
));
449 m4
->addr
= untoh32(from
);
450 m4
->mask
= prefix2mask(prefix
);
453 cond
->conditionValue
.type
= FWP_V6_ADDR_MASK
;
454 cond
->conditionValue
.v6AddrMask
= m6
= calloc(1, sizeof(*m6
));
455 memcpy(m6
->addr
, from
, sizeof(m6
->addr
));
456 m6
->prefixLength
= prefix
;
466 cond
->matchType
= FWP_MATCH_RANGE
;
467 cond
->conditionValue
.type
= FWP_RANGE_TYPE
;
468 cond
->conditionValue
.rangeValue
= range
= calloc(1, sizeof(*range
));
469 switch (ts
->get_type(ts
))
471 case TS_IPV4_ADDR_RANGE
:
472 range
->valueLow
.type
= FWP_UINT32
;
473 range
->valueLow
.uint32
= untoh32(from
);
474 range
->valueHigh
.type
= FWP_UINT32
;
475 range
->valueHigh
.uint32
= untoh32(to
);
477 case TS_IPV6_ADDR_RANGE
:
478 range
->valueLow
.type
= FWP_BYTE_ARRAY16_TYPE
;
479 range
->valueLow
.byteArray16
= addr
= malloc(sizeof(*addr
));
480 memcpy(addr
, from
, sizeof(*addr
));
481 range
->valueHigh
.type
= FWP_BYTE_ARRAY16_TYPE
;
482 range
->valueHigh
.byteArray16
= addr
= malloc(sizeof(*addr
));
483 memcpy(addr
, to
, sizeof(*addr
));
490 proto
= ts
->get_protocol(ts
);
491 if (proto
&& target
== &FWPM_CONDITION_IP_LOCAL_ADDRESS
)
493 cond
= append_condition(conds
, count
);
494 cond
->fieldKey
= FWPM_CONDITION_IP_PROTOCOL
;
495 cond
->matchType
= FWP_MATCH_EQUAL
;
496 cond
->conditionValue
.type
= FWP_UINT8
;
497 cond
->conditionValue
.uint8
= proto
;
500 if (proto
== IPPROTO_ICMP
)
502 if (target
== &FWPM_CONDITION_IP_LOCAL_ADDRESS
)
504 uint8_t from_type
, to_type
, from_code
, to_code
;
506 from_type
= traffic_selector_icmp_type(from_port
);
507 to_type
= traffic_selector_icmp_type(to_port
);
508 from_code
= traffic_selector_icmp_code(from_port
);
509 to_code
= traffic_selector_icmp_code(to_port
);
511 if (from_type
!= 0 || to_type
!= 0xFF)
513 cond
= append_condition(conds
, count
);
514 cond
->fieldKey
= FWPM_CONDITION_ICMP_TYPE
;
515 range2cond(cond
, from_type
, to_type
);
517 if (from_code
!= 0 || to_code
!= 0xFF)
519 cond
= append_condition(conds
, count
);
520 cond
->fieldKey
= FWPM_CONDITION_ICMP_CODE
;
521 range2cond(cond
, from_code
, to_code
);
525 else if (from_port
!= 0 || to_port
!= 0xFFFF)
527 if (target
== &FWPM_CONDITION_IP_LOCAL_ADDRESS
)
529 cond
= append_condition(conds
, count
);
530 cond
->fieldKey
= FWPM_CONDITION_IP_LOCAL_PORT
;
531 range2cond(cond
, from_port
, to_port
);
533 if (target
== &FWPM_CONDITION_IP_REMOTE_ADDRESS
)
535 cond
= append_condition(conds
, count
);
536 cond
->fieldKey
= FWPM_CONDITION_IP_REMOTE_PORT
;
537 range2cond(cond
, from_port
, to_port
);
544 * Free memory associated to a single condition
546 static void free_condition(FWP_DATA_TYPE type
, void *value
)
552 case FWP_BYTE_ARRAY16_TYPE
:
553 case FWP_V4_ADDR_MASK
:
554 case FWP_V6_ADDR_MASK
:
559 free_condition(range
->valueLow
.type
, range
->valueLow
.sd
);
560 free_condition(range
->valueHigh
.type
, range
->valueHigh
.sd
);
569 * Free memory used by a set of conditions
571 static void free_conditions(FWPM_FILTER_CONDITION0
*conds
, int count
)
575 for (i
= 0; i
< count
; i
++)
577 free_condition(conds
[i
].conditionValue
.type
, conds
[i
].conditionValue
.sd
);
583 * Find the callout GUID for given parameters
585 static bool find_callout(bool tunnel
, bool v6
, bool inbound
, bool forward
,
586 bool ale
, GUID
*layer
, GUID
*sublayer
, GUID
*callout
)
595 const GUID
*sublayer
;
598 { 0, 0, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4
, NULL
,
599 &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4
},
600 { 0, 0, 1, 0, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4
, NULL
,
601 &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4
},
602 { 0, 1, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6
, NULL
,
603 &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6
},
604 { 0, 1, 1, 0, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6
, NULL
,
605 &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6
},
606 { 1, 0, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4
,
607 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
608 &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4
},
609 { 1, 0, 0, 1, 0, &FWPM_LAYER_IPFORWARD_V4
,
610 &FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL
,
611 &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4
},
612 { 1, 0, 1, 0, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4
,
613 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
614 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4
},
615 { 1, 0, 1, 1, 0, &FWPM_LAYER_IPFORWARD_V4
,
616 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
617 &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4
},
618 { 1, 0, 0, 0, 1, &FWPM_LAYER_ALE_AUTH_CONNECT_V4
, NULL
,
619 &FWPM_CALLOUT_IPSEC_ALE_CONNECT_V4
},
620 { 1, 0, 1, 0, 1, &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
, NULL
,
621 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V4
},
622 { 1, 1, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6
,
623 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
624 &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6
},
625 { 1, 1, 0, 1, 0, &FWPM_LAYER_IPFORWARD_V6
,
626 &FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL
,
627 &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6
},
628 { 1, 1, 1, 0, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6
,
629 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
630 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6
},
631 { 1, 1, 1, 1, 0, &FWPM_LAYER_IPFORWARD_V6
,
632 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
633 &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6
},
634 { 1, 1, 0, 0, 1, &FWPM_LAYER_ALE_AUTH_CONNECT_V6
, NULL
,
635 &FWPM_CALLOUT_IPSEC_ALE_CONNECT_V6
},
636 { 1, 1, 1, 0, 1, &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
, NULL
,
637 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V6
},
641 for (i
= 0; i
< countof(map
); i
++)
643 if (tunnel
== map
[i
].tunnel
&&
645 inbound
== map
[i
].inbound
&&
646 forward
== map
[i
].forward
&&
649 *callout
= *map
[i
].callout
;
650 *layer
= *map
[i
].layer
;
653 *sublayer
= *map
[i
].sublayer
;
662 * Install a single policy in to the kernel
664 static bool install_sp(private_kernel_wfp_ipsec_t
*this, sp_entry_t
*sp
,
665 GUID
*context
, bool inbound
, bool fwd
, UINT64
*filter_id
)
667 FWPM_FILTER_CONDITION0
*conds
= NULL
;
668 traffic_selector_t
*local
, *remote
;
669 const GUID
*ltarget
, *rtarget
;
673 FWPM_FILTER0 filter
= {
675 .name
= L
"charon IPsec policy",
678 .type
= FWP_ACTION_CALLOUT_TERMINATING
,
684 filter
.flags
|= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT
;
685 filter
.providerKey
= (GUID
*)&this->provider
.providerKey
;
686 filter
.providerContextKey
= *context
;
689 v6
= sp
->src
->get_type(sp
->src
) == TS_IPV6_ADDR_RANGE
;
690 if (!find_callout(context
!= NULL
, v6
, inbound
, fwd
, FALSE
,
691 &filter
.layerKey
, &filter
.subLayerKey
,
692 &filter
.action
.calloutKey
))
709 ltarget
= &FWPM_CONDITION_IP_SOURCE_ADDRESS
;
710 rtarget
= &FWPM_CONDITION_IP_DESTINATION_ADDRESS
;
714 ltarget
= &FWPM_CONDITION_IP_LOCAL_ADDRESS
;
715 rtarget
= &FWPM_CONDITION_IP_REMOTE_ADDRESS
;
717 if (!ts2condition(local
, ltarget
, &conds
, &count
) ||
718 !ts2condition(remote
, rtarget
, &conds
, &count
))
720 free_conditions(conds
, count
);
724 filter
.numFilterConditions
= count
;
725 filter
.filterCondition
= conds
;
727 res
= FwpmFilterAdd0(this->handle
, &filter
, NULL
, filter_id
);
728 free_conditions(conds
, count
);
729 if (res
!= ERROR_SUCCESS
)
731 DBG1(DBG_KNL
, "installing IPv%d %s%sbound %s WFP filter failed: 0x%08x",
732 v6
? 6 : 4, fwd
? "forward " : "", inbound
? "in" : "out",
733 context
? "tunnel" : "transport", res
);
740 * Install an IP-IP allow filter for SA specific hosts
742 static bool install_ipip_ale(private_kernel_wfp_ipsec_t
*this,
743 host_t
*local
, host_t
*remote
, GUID
*context
,
744 bool inbound
, int proto
, uint64_t *filter_id
)
746 traffic_selector_t
*lts
, *rts
;
747 FWPM_FILTER_CONDITION0
*conds
= NULL
;
751 FWPM_FILTER0 filter
= {
753 .name
= L
"charon IPsec IP-in-IP ALE policy",
756 .type
= FWP_ACTION_CALLOUT_TERMINATING
,
762 filter
.flags
|= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT
;
763 filter
.providerKey
= (GUID
*)&this->provider
.providerKey
;
764 filter
.providerContextKey
= *context
;
767 v6
= local
->get_family(local
) == AF_INET6
;
768 if (!find_callout(TRUE
, v6
, inbound
, FALSE
, TRUE
, &filter
.layerKey
,
769 &filter
.subLayerKey
, &filter
.action
.calloutKey
))
774 lts
= traffic_selector_create_from_subnet(local
->clone(local
),
775 v6
? 128 : 32 , proto
, 0, 65535);
776 rts
= traffic_selector_create_from_subnet(remote
->clone(remote
),
777 v6
? 128 : 32 , proto
, 0, 65535);
778 if (!ts2condition(lts
, &FWPM_CONDITION_IP_LOCAL_ADDRESS
, &conds
, &count
) ||
779 !ts2condition(rts
, &FWPM_CONDITION_IP_REMOTE_ADDRESS
, &conds
, &count
))
781 free_conditions(conds
, count
);
789 filter
.numFilterConditions
= count
;
790 filter
.filterCondition
= conds
;
792 res
= FwpmFilterAdd0(this->handle
, &filter
, NULL
, filter_id
);
793 free_conditions(conds
, count
);
794 if (res
!= ERROR_SUCCESS
)
796 DBG1(DBG_KNL
, "installing IP-IPv%d %s ALE WFP filter failed: 0x%08x",
797 v6
? 6 : 4, inbound
? "inbound" : "outbound", res
);
804 * Install a set of policies in to the kernel
806 static bool install_sps(private_kernel_wfp_ipsec_t
*this,
807 entry_t
*entry
, GUID
*context
)
809 enumerator_t
*enumerator
;
811 bool has_v4
= FALSE
, has_v6
= FALSE
;
813 enumerator
= array_create_enumerator(entry
->sps
);
814 while (enumerator
->enumerate(enumerator
, &sp
))
816 switch (sp
->src
->get_type(sp
->src
))
818 case TS_IPV4_ADDR_RANGE
:
821 case TS_IPV6_ADDR_RANGE
:
829 if (!install_sp(this, sp
, context
, TRUE
, FALSE
, &sp
->policy_in
))
831 enumerator
->destroy(enumerator
);
834 /* outbound policy */
835 if (!install_sp(this, sp
, context
, FALSE
, FALSE
, &sp
->policy_out
))
837 enumerator
->destroy(enumerator
);
843 if (!sp
->src
->is_host(sp
->src
, entry
->local
) ||
844 !sp
->dst
->is_host(sp
->dst
, entry
->remote
))
846 /* inbound forward policy, from decapsulation */
847 if (!install_sp(this, sp
, context
, TRUE
, TRUE
,
850 enumerator
->destroy(enumerator
);
853 /* outbound forward policy, to encapsulate */
854 if (!install_sp(this, sp
, context
, FALSE
, TRUE
,
855 &sp
->policy_fwd_out
))
857 enumerator
->destroy(enumerator
);
863 enumerator
->destroy(enumerator
);
867 /* In tunnel mode, Windows does firewall filtering on decrypted but
868 * non-unwrapped packets: It sees them as IP-in-IP packets. When using
869 * a default-drop policy, we need to allow such packets explicitly. */
872 if (!install_ipip_ale(this, entry
->local
, entry
->remote
, context
,
873 TRUE
, IPPROTO_IPIP
, &entry
->ip_ipv4_in
))
877 if (!install_ipip_ale(this, entry
->local
, entry
->remote
, NULL
,
878 FALSE
, IPPROTO_IPIP
, &entry
->ip_ipv4_out
))
885 if (!install_ipip_ale(this, entry
->local
, entry
->remote
, context
,
886 TRUE
, IPPROTO_IPV6
, &entry
->ip_ipv6_in
))
890 if (!install_ipip_ale(this, entry
->local
, entry
->remote
, NULL
,
891 FALSE
, IPPROTO_IPV6
, &entry
->ip_ipv6_out
))
901 * Convert a chunk_t to a WFP FWP_BYTE_BLOB
903 static inline FWP_BYTE_BLOB
chunk2blob(chunk_t chunk
)
905 return (FWP_BYTE_BLOB
){
912 * Convert an integrity_algorithm_t to a WFP IPSEC_AUTH_TRANFORM_ID0
914 static bool alg2auth(integrity_algorithm_t alg
,
915 IPSEC_SA_AUTH_INFORMATION0
*info
)
918 integrity_algorithm_t alg
;
919 IPSEC_AUTH_TRANSFORM_ID0 transform
;
921 { AUTH_HMAC_MD5_96
, IPSEC_AUTH_TRANSFORM_ID_HMAC_MD5_96
},
922 { AUTH_HMAC_SHA1_96
, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96
},
923 { AUTH_HMAC_SHA2_256_128
, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_256_128
},
924 { AUTH_AES_128_GMAC
, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_128
},
925 { AUTH_AES_192_GMAC
, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_192
},
926 { AUTH_AES_256_GMAC
, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_256
},
930 for (i
= 0; i
< countof(map
); i
++)
932 if (map
[i
].alg
== alg
)
934 info
->authTransform
.authTransformId
= map
[i
].transform
;
942 * Convert an encryption_algorithm_t to a WFP IPSEC_CIPHER_TRANFORM_ID0
944 static bool alg2cipher(encryption_algorithm_t alg
, int keylen
,
945 IPSEC_SA_CIPHER_INFORMATION0
*info
)
948 encryption_algorithm_t alg
;
950 IPSEC_CIPHER_TRANSFORM_ID0 transform
;
952 { ENCR_DES
, 8, IPSEC_CIPHER_TRANSFORM_ID_CBC_DES
},
953 { ENCR_3DES
, 24, IPSEC_CIPHER_TRANSFORM_ID_CBC_3DES
},
954 { ENCR_AES_CBC
, 16, IPSEC_CIPHER_TRANSFORM_ID_AES_128
},
955 { ENCR_AES_CBC
, 24, IPSEC_CIPHER_TRANSFORM_ID_AES_192
},
956 { ENCR_AES_CBC
, 32, IPSEC_CIPHER_TRANSFORM_ID_AES_256
},
957 { ENCR_AES_GCM_ICV16
, 20, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_128
},
958 { ENCR_AES_GCM_ICV16
, 28, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_192
},
959 { ENCR_AES_GCM_ICV16
, 36, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_256
},
963 for (i
= 0; i
< countof(map
); i
++)
965 if (map
[i
].alg
== alg
&& map
[i
].keylen
== keylen
)
967 info
->cipherTransform
.cipherTransformId
= map
[i
].transform
;
975 * Get the integrity algorithm used for an AEAD transform
977 static integrity_algorithm_t
encr2integ(encryption_algorithm_t encr
, int keylen
)
980 encryption_algorithm_t encr
;
982 integrity_algorithm_t integ
;
984 { ENCR_NULL_AUTH_AES_GMAC
, 20, AUTH_AES_128_GMAC
},
985 { ENCR_NULL_AUTH_AES_GMAC
, 28, AUTH_AES_192_GMAC
},
986 { ENCR_NULL_AUTH_AES_GMAC
, 36, AUTH_AES_256_GMAC
},
987 { ENCR_AES_GCM_ICV16
, 20, AUTH_AES_128_GMAC
},
988 { ENCR_AES_GCM_ICV16
, 28, AUTH_AES_192_GMAC
},
989 { ENCR_AES_GCM_ICV16
, 36, AUTH_AES_256_GMAC
},
993 for (i
= 0; i
< countof(map
); i
++)
995 if (map
[i
].encr
== encr
&& map
[i
].keylen
== keylen
)
1000 return AUTH_UNDEFINED
;
1004 * Install a single SA
1006 static bool install_sa(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
,
1007 bool inbound
, sa_entry_t
*sa
, FWP_IP_VERSION version
)
1009 IPSEC_SA_AUTH_AND_CIPHER_INFORMATION0 info
= {};
1011 .spi
= ntohl(sa
->spi
),
1013 IPSEC_SA_BUNDLE0 bundle
= {
1015 .lifetimeSeconds
= inbound
? entry
->isa
.lifetime
1016 : entry
->osa
.lifetime
,
1020 .ipVersion
= version
,
1025 } integ
= {}, encr
= {};
1028 switch (sa
->protocol
)
1031 ipsec
.saTransformType
= IPSEC_TRANSFORM_AH
;
1032 ipsec
.ahInformation
= &info
.saAuthInformation
;
1033 integ
.key
= sa
->integ
.key
;
1034 integ
.alg
= sa
->integ
.alg
;
1037 if (sa
->encr
.alg
== ENCR_NULL
||
1038 sa
->encr
.alg
== ENCR_NULL_AUTH_AES_GMAC
)
1040 ipsec
.saTransformType
= IPSEC_TRANSFORM_ESP_AUTH
;
1041 ipsec
.espAuthInformation
= &info
.saAuthInformation
;
1045 ipsec
.saTransformType
= IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER
;
1046 ipsec
.espAuthAndCipherInformation
= &info
;
1047 encr
.key
= sa
->encr
.key
;
1048 encr
.alg
= sa
->encr
.alg
;
1050 if (encryption_algorithm_is_aead(sa
->encr
.alg
))
1052 integ
.alg
= encr2integ(sa
->encr
.alg
, sa
->encr
.key
.len
);
1053 integ
.key
= sa
->encr
.key
;
1057 integ
.alg
= sa
->integ
.alg
;
1058 integ
.key
= sa
->integ
.key
;
1067 info
.saAuthInformation
.authKey
= chunk2blob(integ
.key
);
1068 if (!alg2auth(integ
.alg
, &info
.saAuthInformation
))
1070 DBG1(DBG_KNL
, "integrity algorithm %N not supported by WFP",
1071 integrity_algorithm_names
, integ
.alg
);
1077 info
.saCipherInformation
.cipherKey
= chunk2blob(encr
.key
);
1078 if (!alg2cipher(encr
.alg
, encr
.key
.len
, &info
.saCipherInformation
))
1080 DBG1(DBG_KNL
, "encryption algorithm %N not supported by WFP",
1081 encryption_algorithm_names
, encr
.alg
);
1088 res
= IPsecSaContextAddInbound0(this->handle
, entry
->sa_id
, &bundle
);
1092 bundle
.flags
|= IPSEC_SA_BUNDLE_FLAG_ASSUME_UDP_CONTEXT_OUTBOUND
;
1093 res
= IPsecSaContextAddOutbound0(this->handle
, entry
->sa_id
, &bundle
);
1095 if (res
!= ERROR_SUCCESS
)
1097 DBG1(DBG_KNL
, "adding %sbound WFP SA failed: 0x%08x",
1098 inbound
? "in" : "out", res
);
1105 * Convert an IPv6 host address to WFP representation
1107 static void host2address6(host_t
*host
, void *out
)
1109 uint32_t *src
, *dst
= out
;
1111 src
= (uint32_t*)host
->get_address(host
).ptr
;
1113 dst
[0] = untoh32(&src
[3]);
1114 dst
[1] = untoh32(&src
[2]);
1115 dst
[2] = untoh32(&src
[1]);
1116 dst
[3] = untoh32(&src
[0]);
1120 * Fill in traffic structure from entry addresses
1122 static bool hosts2traffic(private_kernel_wfp_ipsec_t
*this,
1123 host_t
*l
, host_t
*r
, IPSEC_TRAFFIC1
*traffic
)
1125 if (l
->get_family(l
) != r
->get_family(r
))
1129 switch (l
->get_family(l
))
1132 traffic
->ipVersion
= FWP_IP_VERSION_V4
;
1133 traffic
->localV4Address
= untoh32(l
->get_address(l
).ptr
);
1134 traffic
->remoteV4Address
= untoh32(r
->get_address(r
).ptr
);
1137 traffic
->ipVersion
= FWP_IP_VERSION_V6
;
1138 host2address6(l
, &traffic
->localV6Address
);
1139 host2address6(r
, &traffic
->remoteV6Address
);
1147 * Install SAs to the kernel
1149 static bool install_sas(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
,
1150 IPSEC_TRAFFIC_TYPE type
)
1152 IPSEC_TRAFFIC1 traffic
= {
1153 .trafficType
= type
,
1155 IPSEC_GETSPI1 spi
= {
1156 .inboundIpsecTraffic
= {
1157 .trafficType
= type
,
1160 enumerator_t
*enumerator
;
1164 if (type
== IPSEC_TRAFFIC_TYPE_TRANSPORT
)
1166 enumerator
= array_create_enumerator(entry
->sps
);
1167 if (enumerator
->enumerate(enumerator
, &sp
))
1169 traffic
.ipsecFilterId
= sp
->policy_out
;
1170 spi
.inboundIpsecTraffic
.ipsecFilterId
= sp
->policy_in
;
1174 enumerator
->destroy(enumerator
);
1177 enumerator
->destroy(enumerator
);
1181 traffic
.tunnelPolicyId
= entry
->provider
;
1182 spi
.inboundIpsecTraffic
.tunnelPolicyId
= entry
->provider
;
1185 if (!hosts2traffic(this, entry
->local
, entry
->remote
, &traffic
))
1190 res
= IPsecSaContextCreate1(this->handle
, &traffic
, NULL
, NULL
,
1192 if (res
!= ERROR_SUCCESS
)
1194 DBG1(DBG_KNL
, "creating WFP SA context failed: 0x%08x", res
);
1198 memcpy(spi
.inboundIpsecTraffic
.localV6Address
, traffic
.localV6Address
,
1199 sizeof(traffic
.localV6Address
));
1200 memcpy(spi
.inboundIpsecTraffic
.remoteV6Address
, traffic
.remoteV6Address
,
1201 sizeof(traffic
.remoteV6Address
));
1202 spi
.ipVersion
= traffic
.ipVersion
;
1204 res
= IPsecSaContextSetSpi0(this->handle
, entry
->sa_id
, &spi
,
1205 ntohl(entry
->isa
.spi
));
1206 if (res
!= ERROR_SUCCESS
)
1208 DBG1(DBG_KNL
, "setting WFP SA SPI failed: 0x%08x", res
);
1209 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
1214 if (!install_sa(this, entry
, TRUE
, &entry
->isa
, spi
.ipVersion
) ||
1215 !install_sa(this, entry
, FALSE
, &entry
->osa
, spi
.ipVersion
))
1217 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
1224 IPSEC_V4_UDP_ENCAPSULATION0 encap
= {
1225 .localUdpEncapPort
= entry
->local
->get_port(entry
->local
),
1226 .remoteUdpEncapPort
= entry
->remote
->get_port(entry
->remote
),
1228 IPSEC_SA_CONTEXT1
*ctx
;
1230 res
= IPsecSaContextGetById1(this->handle
, entry
->sa_id
, &ctx
);
1231 if (res
!= ERROR_SUCCESS
)
1233 DBG1(DBG_KNL
, "getting WFP SA for UDP encap failed: 0x%08x", res
);
1234 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
1238 ctx
->inboundSa
->udpEncapsulation
= &encap
;
1239 ctx
->outboundSa
->udpEncapsulation
= &encap
;
1241 res
= IPsecSaContextUpdate0(this->handle
,
1242 IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION
, ctx
);
1243 FwpmFreeMemory0((void**)&ctx
);
1244 if (res
!= ERROR_SUCCESS
)
1246 DBG1(DBG_KNL
, "enable WFP UDP encap failed: 0x%08x", res
);
1247 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
1257 * Install a transport mode SA/SP set to the kernel
1259 static bool install_transport(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
1261 if (install_sps(this, entry
, NULL
) &&
1262 install_sas(this, entry
, IPSEC_TRAFFIC_TYPE_TRANSPORT
))
1266 cleanup_policies(this, entry
);
1271 * Generate a new GUID, random
1273 static bool generate_guid(private_kernel_wfp_ipsec_t
*this, GUID
*guid
)
1278 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
1283 ok
= rng
->get_bytes(rng
, sizeof(GUID
), (uint8_t*)guid
);
1289 * Register a dummy tunnel provider to associate tunnel filters to
1291 static bool add_tunnel_provider(private_kernel_wfp_ipsec_t
*this,
1292 entry_t
*entry
, GUID
*guid
, UINT64
*luid
)
1296 IPSEC_AUTH_TRANSFORM0 transform
= {
1297 /* Create any valid proposal. This is actually not used, as we
1298 * don't create an SA from this information. */
1299 .authTransformId
= IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96
,
1301 IPSEC_SA_TRANSFORM0 transforms
= {
1302 .ipsecTransformType
= IPSEC_TRANSFORM_ESP_AUTH
,
1303 .espAuthTransform
= &transform
,
1305 IPSEC_PROPOSAL0 proposal
= {
1307 /* We need a valid lifetime, even if we don't create any SA
1308 * from these values. Pick some values accepted. */
1309 .lifetimeSeconds
= 0xFFFF,
1310 .lifetimeKilobytes
= 0xFFFFFFFF,
1311 .lifetimePackets
= 0xFFFFFFFF,
1313 .numSaTransforms
= 1,
1314 .saTransforms
= &transforms
,
1316 IPSEC_TUNNEL_POLICY0 policy
= {
1317 .numIpsecProposals
= 1,
1318 .ipsecProposals
= &proposal
,
1320 /* not used, set to lifetime for maximum */
1321 .idleTimeoutSeconds
= proposal
.lifetime
.lifetimeSeconds
,
1322 .idleTimeoutSecondsFailOver
= proposal
.lifetime
.lifetimeSeconds
,
1325 FWPM_PROVIDER_CONTEXT0 qm
= {
1327 .name
= L
"charon tunnel provider",
1329 .providerKey
= (GUID
*)&this->provider
.providerKey
,
1330 .type
= FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT
,
1331 .ikeQmTunnelPolicy
= &policy
,
1334 switch (entry
->local
->get_family(entry
->local
))
1337 policy
.tunnelEndpoints
.ipVersion
= FWP_IP_VERSION_V4
;
1338 policy
.tunnelEndpoints
.localV4Address
=
1339 untoh32(entry
->local
->get_address(entry
->local
).ptr
);
1340 policy
.tunnelEndpoints
.remoteV4Address
=
1341 untoh32(entry
->remote
->get_address(entry
->remote
).ptr
);
1344 policy
.tunnelEndpoints
.ipVersion
= FWP_IP_VERSION_V6
;
1345 host2address6(entry
->local
, &policy
.tunnelEndpoints
.localV6Address
);
1346 host2address6(entry
->remote
, &policy
.tunnelEndpoints
.remoteV6Address
);
1352 if (!generate_guid(this, &qm
.providerContextKey
))
1357 res
= FwpmProviderContextAdd0(this->handle
, &qm
, NULL
, luid
);
1358 if (res
!= ERROR_SUCCESS
)
1360 DBG1(DBG_KNL
, "adding provider context failed: 0x%08x", res
);
1363 *guid
= qm
.providerContextKey
;
1368 * Install tunnel mode SPs to the kernel
1370 static bool install_tunnel_sps(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
1374 if (!add_tunnel_provider(this, entry
, &guid
, &entry
->provider
))
1378 if (!install_sps(this, entry
, &guid
))
1386 * Reduce refcount, or uninstall a route if all refs gone
1388 static bool uninstall_route(private_kernel_wfp_ipsec_t
*this,
1389 host_t
*dst
, uint8_t mask
, host_t
*src
, host_t
*gtw
)
1391 route_t
*route
, key
= {
1399 this->mutex
->lock(this->mutex
);
1400 route
= this->routes
->get(this->routes
, &key
);
1403 if (--route
->refs
== 0)
1405 if (charon
->kernel
->get_interface(charon
->kernel
, src
, &name
))
1407 res
= charon
->kernel
->del_route(charon
->kernel
,
1408 dst
->get_address(dst
), mask
, gtw
, src
,
1409 name
, FALSE
) == SUCCESS
;
1412 route
= this->routes
->remove(this->routes
, route
);
1415 destroy_route(route
);
1423 this->mutex
->unlock(this->mutex
);
1429 * Install a single route, or refcount if exists
1431 static bool install_route(private_kernel_wfp_ipsec_t
*this,
1432 host_t
*dst
, uint8_t mask
, host_t
*src
, host_t
*gtw
)
1434 route_t
*route
, key
= {
1442 this->mutex
->lock(this->mutex
);
1443 route
= this->routes
->get(this->routes
, &key
);
1451 if (charon
->kernel
->get_interface(charon
->kernel
, src
, &name
))
1453 if (charon
->kernel
->add_route(charon
->kernel
, dst
->get_address(dst
),
1454 mask
, gtw
, src
, name
, FALSE
) == SUCCESS
)
1457 .dst
= dst
->clone(dst
),
1459 .src
= src
->clone(src
),
1460 .gtw
= gtw
? gtw
->clone(gtw
) : NULL
,
1463 route
= this->routes
->put(this->routes
, route
, route
);
1466 destroy_route(route
);
1473 this->mutex
->unlock(this->mutex
);
1479 * (Un)-install a single route
1481 static bool manage_route(private_kernel_wfp_ipsec_t
*this,
1482 host_t
*local
, host_t
*remote
,
1483 traffic_selector_t
*src_ts
, traffic_selector_t
*dst_ts
,
1486 host_t
*src
, *dst
, *gtw
;
1490 if (!dst_ts
->to_subnet(dst_ts
, &dst
, &mask
))
1494 if (charon
->kernel
->get_address_by_ts(charon
->kernel
, src_ts
, &src
,
1500 gtw
= charon
->kernel
->get_nexthop(charon
->kernel
, remote
, -1, local
, NULL
);
1503 done
= install_route(this, dst
, mask
, src
, gtw
);
1507 done
= uninstall_route(this, dst
, mask
, src
, gtw
);
1515 DBG1(DBG_KNL
, "%sinstalling route for policy %R === %R failed",
1516 add
? "" : "un", src_ts
, dst_ts
);
1522 * (Un)-install routes for IPsec policies
1524 static bool manage_routes(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
,
1527 enumerator_t
*enumerator
;
1530 enumerator
= array_create_enumerator(entry
->sps
);
1531 while (enumerator
->enumerate(enumerator
, &sp
))
1533 if (add
&& sp
->route
)
1537 if (!add
&& !sp
->route
)
1541 if (manage_route(this, entry
->local
, entry
->remote
,
1542 sp
->src
, sp
->dst
, add
))
1547 enumerator
->destroy(enumerator
);
1553 * Install a tunnel mode SA/SP set to the kernel
1555 static bool install_tunnel(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
1557 if (install_tunnel_sps(this, entry
) &&
1558 manage_routes(this, entry
, TRUE
) &&
1559 install_sas(this, entry
, IPSEC_TRAFFIC_TYPE_TUNNEL
))
1563 cleanup_policies(this, entry
);
1568 * Install a SA/SP set to the kernel
1570 static bool install(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
1572 switch (entry
->mode
)
1574 case MODE_TRANSPORT
:
1575 return install_transport(this, entry
);
1577 return install_tunnel(this, entry
);
1585 * Installed trap entry
1588 /** reqid this trap is installed for */
1590 /** is this a forward policy trap for tunnel mode? */
1592 /** do we have installed a route for this trap policy? */
1594 /** local address of associated route */
1596 /** remote address of associated route */
1598 /** src traffic selector */
1599 traffic_selector_t
*src
;
1600 /** dst traffic selector */
1601 traffic_selector_t
*dst
;
1602 /** LUID of installed tunnel policy filter */
1607 * Destroy a trap entry
1609 static void destroy_trap(trap_t
*this)
1611 this->local
->destroy(this->local
);
1612 this->remote
->destroy(this->remote
);
1613 this->src
->destroy(this->src
);
1614 this->dst
->destroy(this->dst
);
1619 * Hashtable equals function for traps
1621 static bool equals_trap(trap_t
*a
, trap_t
*b
)
1623 return a
->filter_id
== b
->filter_id
;
1627 * Hashtable hash function for traps
1629 static u_int
hash_trap(trap_t
*trap
)
1631 return chunk_hash(chunk_from_thing(trap
->filter_id
));
1635 * Send an acquire for an installed trap filter
1637 static void acquire(private_kernel_wfp_ipsec_t
*this, UINT64 filter_id
,
1638 traffic_selector_t
*src
, traffic_selector_t
*dst
)
1640 kernel_acquire_data_t data
= {
1644 trap_t
*trap
, key
= {
1645 .filter_id
= filter_id
,
1648 this->mutex
->lock(this->mutex
);
1649 trap
= this->traps
->get(this->traps
, &key
);
1652 reqid
= trap
->reqid
;
1654 this->mutex
->unlock(this->mutex
);
1658 data
.src
= src
? src
->clone(src
) : NULL
;
1659 data
.dst
= dst
? dst
->clone(dst
) : NULL
;
1661 charon
->kernel
->acquire(charon
->kernel
, reqid
, &data
);
1663 DESTROY_IF(data
.src
);
1664 DESTROY_IF(data
.dst
);
1669 * Create a single host traffic selector from an FWP address definition
1671 static traffic_selector_t
*addr2ts(FWP_IP_VERSION version
, void *data
,
1672 uint8_t protocol
, uint16_t from_port
, uint16_t to_port
)
1680 case FWP_IP_VERSION_V4
:
1681 ints
[0] = untoh32(data
);
1682 addr
= chunk_from_thing(ints
[0]);
1683 type
= TS_IPV4_ADDR_RANGE
;
1685 case FWP_IP_VERSION_V6
:
1686 ints
[3] = untoh32(data
);
1687 ints
[2] = untoh32(data
+ 4);
1688 ints
[1] = untoh32(data
+ 8);
1689 ints
[0] = untoh32(data
+ 12);
1690 addr
= chunk_from_thing(ints
);
1691 type
= TS_IPV6_ADDR_RANGE
;
1696 return traffic_selector_create_from_bytes(protocol
, type
, addr
, from_port
,
1701 * FwpmNetEventSubscribe0() callback
1703 static void WINAPI
event_callback(void *user
, const FWPM_NET_EVENT1
*event
)
1705 private_kernel_wfp_ipsec_t
*this = user
;
1706 traffic_selector_t
*local
= NULL
, *remote
= NULL
;
1707 uint8_t protocol
= 0;
1708 uint16_t from_local
= 0, to_local
= 65535;
1709 uint16_t from_remote
= 0, to_remote
= 65535;
1711 if ((event
->header
.flags
& FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET
) &&
1712 (event
->header
.flags
& FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET
))
1714 if (event
->header
.flags
& FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET
)
1716 from_local
= to_local
= event
->header
.localPort
;
1718 if (event
->header
.flags
& FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET
)
1720 from_remote
= to_remote
= event
->header
.remotePort
;
1722 if (event
->header
.flags
& FWPM_NET_EVENT_FLAG_IP_PROTOCOL_SET
)
1724 protocol
= event
->header
.ipProtocol
;
1727 local
= addr2ts(event
->header
.ipVersion
,
1728 (void*)&event
->header
.localAddrV6
,
1729 protocol
, from_local
, to_local
);
1730 remote
= addr2ts(event
->header
.ipVersion
,
1731 (void*)&event
->header
.remoteAddrV6
,
1732 protocol
, from_remote
, to_remote
);
1735 switch (event
->type
)
1737 case FWPM_NET_EVENT_TYPE_CLASSIFY_DROP
:
1738 acquire(this, event
->classifyDrop
->filterId
, local
, remote
);
1740 case FWPM_NET_EVENT_TYPE_IKEEXT_MM_FAILURE
:
1741 DBG1(DBG_KNL
, "WFP MM failure: %R === %R, 0x%08x, filterId %llu",
1742 local
, remote
, event
->ikeMmFailure
->failureErrorCode
,
1743 event
->ikeMmFailure
->mmFilterId
);
1745 case FWPM_NET_EVENT_TYPE_IKEEXT_QM_FAILURE
:
1746 DBG1(DBG_KNL
, "WFP QM failure: %R === %R, 0x%08x, filterId %llu",
1747 local
, remote
, event
->ikeQmFailure
->failureErrorCode
,
1748 event
->ikeQmFailure
->qmFilterId
);
1750 case FWPM_NET_EVENT_TYPE_IKEEXT_EM_FAILURE
:
1751 DBG1(DBG_KNL
, "WFP EM failure: %R === %R, 0x%08x, filterId %llu",
1752 local
, remote
, event
->ikeEmFailure
->failureErrorCode
,
1753 event
->ikeEmFailure
->qmFilterId
);
1755 case FWPM_NET_EVENT_TYPE_IPSEC_KERNEL_DROP
:
1756 DBG1(DBG_KNL
, "IPsec kernel drop: %R === %R, error 0x%08x, "
1757 "SPI 0x%08x, %s filterId %llu", local
, remote
,
1758 event
->ipsecDrop
->failureStatus
, event
->ipsecDrop
->spi
,
1759 event
->ipsecDrop
->direction
? "in" : "out",
1760 event
->ipsecDrop
->filterId
);
1762 case FWPM_NET_EVENT_TYPE_IPSEC_DOSP_DROP
:
1772 * Register for net events
1774 static bool register_events(private_kernel_wfp_ipsec_t
*this)
1776 FWPM_NET_EVENT_SUBSCRIPTION0 subscription
= {};
1779 res
= FwpmNetEventSubscribe0(this->handle
, &subscription
,
1780 event_callback
, this, &this->event
);
1781 if (res
!= ERROR_SUCCESS
)
1783 DBG1(DBG_KNL
, "registering for WFP events failed: 0x%08x", res
);
1790 * Install a trap policy to kernel
1792 static bool install_trap(private_kernel_wfp_ipsec_t
*this, trap_t
*trap
)
1794 FWPM_FILTER_CONDITION0
*conds
= NULL
;
1797 const GUID
*starget
, *dtarget
;
1798 UINT64 weight
= 0x000000000000ff00;
1799 FWPM_FILTER0 filter
= {
1801 .name
= L
"charon IPsec trap",
1804 .type
= FWP_ACTION_BLOCK
,
1814 if (trap
->src
->get_type(trap
->src
) == TS_IPV4_ADDR_RANGE
)
1816 filter
.layerKey
= FWPM_LAYER_IPFORWARD_V4
;
1820 filter
.layerKey
= FWPM_LAYER_IPFORWARD_V6
;
1822 starget
= &FWPM_CONDITION_IP_SOURCE_ADDRESS
;
1823 dtarget
= &FWPM_CONDITION_IP_DESTINATION_ADDRESS
;
1827 if (trap
->src
->get_type(trap
->src
) == TS_IPV4_ADDR_RANGE
)
1829 filter
.layerKey
= FWPM_LAYER_OUTBOUND_TRANSPORT_V4
;
1833 filter
.layerKey
= FWPM_LAYER_OUTBOUND_TRANSPORT_V6
;
1835 starget
= &FWPM_CONDITION_IP_LOCAL_ADDRESS
;
1836 dtarget
= &FWPM_CONDITION_IP_REMOTE_ADDRESS
;
1839 if (!ts2condition(trap
->src
, starget
, &conds
, &count
) ||
1840 !ts2condition(trap
->dst
, dtarget
, &conds
, &count
))
1842 free_conditions(conds
, count
);
1846 filter
.numFilterConditions
= count
;
1847 filter
.filterCondition
= conds
;
1849 res
= FwpmFilterAdd0(this->handle
, &filter
, NULL
, &trap
->filter_id
);
1850 free_conditions(conds
, count
);
1851 if (res
!= ERROR_SUCCESS
)
1853 DBG1(DBG_KNL
, "installing WFP trap filter failed: 0x%08x", res
);
1860 * Uninstall a trap policy from kernel
1862 static bool uninstall_trap(private_kernel_wfp_ipsec_t
*this, trap_t
*trap
)
1866 res
= FwpmFilterDeleteById0(this->handle
, trap
->filter_id
);
1867 if (res
!= ERROR_SUCCESS
)
1869 DBG1(DBG_KNL
, "uninstalling WFP trap filter failed: 0x%08x", res
);
1876 * Create and install a new trap entry
1878 static bool add_trap(private_kernel_wfp_ipsec_t
*this,
1879 uint32_t reqid
, bool fwd
, host_t
*local
, host_t
*remote
,
1880 traffic_selector_t
*src
, traffic_selector_t
*dst
)
1887 .src
= src
->clone(src
),
1888 .dst
= dst
->clone(dst
),
1889 .local
= local
->clone(local
),
1890 .remote
= remote
->clone(remote
),
1893 if (!install_trap(this, trap
))
1899 trap
->route
= manage_route(this, local
, remote
, src
, dst
, TRUE
);
1901 this->mutex
->lock(this->mutex
);
1902 this->traps
->put(this->traps
, trap
, trap
);
1903 this->mutex
->unlock(this->mutex
);
1908 * Uninstall and remove a new trap entry
1910 static bool remove_trap(private_kernel_wfp_ipsec_t
*this,
1911 uint32_t reqid
, bool fwd
,
1912 traffic_selector_t
*src
, traffic_selector_t
*dst
)
1914 enumerator_t
*enumerator
;
1915 trap_t
*trap
, *found
= NULL
;
1917 this->mutex
->lock(this->mutex
);
1918 enumerator
= this->traps
->create_enumerator(this->traps
);
1919 while (enumerator
->enumerate(enumerator
, NULL
, &trap
))
1921 if (reqid
== trap
->reqid
&&
1923 src
->equals(src
, trap
->src
) &&
1924 dst
->equals(dst
, trap
->dst
))
1926 this->traps
->remove_at(this->traps
, enumerator
);
1931 enumerator
->destroy(enumerator
);
1932 this->mutex
->unlock(this->mutex
);
1938 trap
->route
= !manage_route(this, trap
->local
, trap
->remote
,
1941 uninstall_trap(this, found
);
1942 destroy_trap(found
);
1948 METHOD(kernel_ipsec_t
, get_features
, kernel_feature_t
,
1949 private_kernel_wfp_ipsec_t
*this)
1951 return KERNEL_ESP_V3_TFC
| KERNEL_NO_POLICY_UPDATES
;
1955 * Initialize seeds for SPI generation
1957 static bool init_spi(private_kernel_wfp_ipsec_t
*this)
1962 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_STRONG
);
1967 ok
= rng
->get_bytes(rng
, sizeof(this->nextspi
), (uint8_t*)&this->nextspi
);
1970 ok
= rng
->get_bytes(rng
, sizeof(this->mixspi
), (uint8_t*)&this->mixspi
);
1977 * Map an integer x with a one-to-one function using quadratic residues.
1979 static u_int
permute(u_int x
, u_int p
)
1984 qr
= ((uint64_t)x
* x
) % p
;
1992 METHOD(kernel_ipsec_t
, get_spi
, status_t
,
1993 private_kernel_wfp_ipsec_t
*this, host_t
*src
, host_t
*dst
,
1994 uint8_t protocol
, uint32_t *spi
)
1996 /* To avoid sequential SPIs, we use a one-to-one permutation function on
1997 * an incrementing counter, that is a full period PRNG for the range we
1998 * allocate SPIs in. We add some randomness using a fixed XOR and start
1999 * the counter at random position. This is not cryptographically safe,
2000 * but that is actually not required.
2001 * The selected prime should be smaller than the range we allocate SPIs
2002 * in, and it must satisfy p % 4 == 3 to map x > p/2 using p - qr. */
2003 static const u_int p
= 268435399, offset
= 0xc0000000;
2005 *spi
= htonl(offset
+ permute(ref_get(&this->nextspi
) ^ this->mixspi
, p
));
2009 METHOD(kernel_ipsec_t
, get_cpi
, status_t
,
2010 private_kernel_wfp_ipsec_t
*this, host_t
*src
, host_t
*dst
,
2013 return NOT_SUPPORTED
;
2017 * Data for an expire callback job
2020 /* backref to kernel backend */
2021 private_kernel_wfp_ipsec_t
*this;
2022 /* SPI of expiring SA */
2024 /* destination address of expiring SA */
2026 /* is this a hard expire, or a rekey request? */
2031 * Clean up expire data
2033 static void expire_data_destroy(expire_data_t
*data
)
2035 data
->dst
->destroy(data
->dst
);
2040 * Callback job for SA expiration
2042 static job_requeue_t
expire_job(expire_data_t
*data
)
2044 private_kernel_wfp_ipsec_t
*this = data
->this;
2046 entry_t
*entry
= NULL
;
2054 this->mutex
->lock(this->mutex
);
2055 entry
= this->isas
->remove(this->isas
, &key
);
2056 this->mutex
->unlock(this->mutex
);
2059 protocol
= entry
->isa
.protocol
;
2062 key
.dst
= entry
->osa
.dst
;
2063 key
.spi
= entry
->osa
.spi
;
2064 this->osas
->remove(this->osas
, &key
);
2066 entry_destroy(this, entry
);
2071 this->mutex
->lock(this->mutex
);
2072 entry
= this->isas
->get(this->isas
, &key
);
2075 protocol
= entry
->isa
.protocol
;
2077 this->mutex
->unlock(this->mutex
);
2082 charon
->kernel
->expire(charon
->kernel
, protocol
, data
->spi
, data
->dst
,
2086 return JOB_REQUEUE_NONE
;
2090 * Schedule an expire event for an SA
2092 static void schedule_expire(private_kernel_wfp_ipsec_t
*this, uint32_t spi
,
2093 host_t
*dst
, uint32_t lifetime
, bool hard
)
2095 expire_data_t
*data
;
2100 .dst
= dst
->clone(dst
),
2104 lib
->scheduler
->schedule_job(lib
->scheduler
, (job_t
*)
2105 callback_job_create((void*)expire_job
, data
,
2106 (void*)expire_data_destroy
, NULL
),
2110 METHOD(kernel_ipsec_t
, add_sa
, status_t
,
2111 private_kernel_wfp_ipsec_t
*this, kernel_ipsec_sa_id_t
*id
,
2112 kernel_ipsec_add_sa_t
*data
)
2114 host_t
*local
, *remote
;
2119 /* comes first, create new entry */
2120 local
= id
->dst
->clone(id
->dst
);
2121 remote
= id
->src
->clone(id
->src
);
2124 .reqid
= data
->reqid
,
2128 .protocol
= id
->proto
,
2129 .lifetime
= data
->lifetime
->time
.life
,
2131 .alg
= data
->enc_alg
,
2132 .key
= chunk_clone(data
->enc_key
),
2135 .alg
= data
->int_alg
,
2136 .key
= chunk_clone(data
->int_key
),
2139 .sps
= array_create(0, 0),
2143 .encap
= data
->encap
,
2146 if (data
->lifetime
->time
.life
)
2148 schedule_expire(this, id
->spi
, local
,
2149 data
->lifetime
->time
.life
, TRUE
);
2151 if (data
->lifetime
->time
.rekey
&&
2152 data
->lifetime
->time
.rekey
!= data
->lifetime
->time
.life
)
2154 schedule_expire(this, id
->spi
, local
,
2155 data
->lifetime
->time
.rekey
, FALSE
);
2158 this->mutex
->lock(this->mutex
);
2159 this->tsas
->put(this->tsas
, (void*)(uintptr_t)data
->reqid
, entry
);
2160 this->isas
->put(this->isas
, &entry
->isa
, entry
);
2161 this->mutex
->unlock(this->mutex
);
2165 /* comes after inbound, update entry */
2166 this->mutex
->lock(this->mutex
);
2167 entry
= this->tsas
->remove(this->tsas
, (void*)(uintptr_t)data
->reqid
);
2168 this->mutex
->unlock(this->mutex
);
2172 DBG1(DBG_KNL
, "adding outbound SA failed, no inbound SA found "
2173 "for reqid %u ", data
->reqid
);
2176 /* TODO: should we check for local/remote, mode etc.? */
2178 entry
->osa
= (sa_entry_t
){
2180 .dst
= entry
->remote
,
2181 .protocol
= id
->proto
,
2182 .lifetime
= data
->lifetime
->time
.life
,
2184 .alg
= data
->enc_alg
,
2185 .key
= chunk_clone(data
->enc_key
),
2188 .alg
= data
->int_alg
,
2189 .key
= chunk_clone(data
->int_key
),
2193 this->mutex
->lock(this->mutex
);
2194 this->osas
->put(this->osas
, &entry
->osa
, entry
);
2195 this->mutex
->unlock(this->mutex
);
2201 METHOD(kernel_ipsec_t
, update_sa
, status_t
,
2202 private_kernel_wfp_ipsec_t
*this, kernel_ipsec_sa_id_t
*id
,
2203 kernel_ipsec_update_sa_t
*data
)
2211 IPSEC_SA_CONTEXT1
*ctx
;
2212 IPSEC_V4_UDP_ENCAPSULATION0 ports
;
2213 UINT32 flags
= IPSEC_SA_DETAILS_UPDATE_TRAFFIC
;
2216 this->mutex
->lock(this->mutex
);
2217 entry
= this->osas
->get(this->osas
, &key
);
2218 this->mutex
->unlock(this->mutex
);
2222 /* outbound entry, nothing to do */
2226 this->mutex
->lock(this->mutex
);
2227 entry
= this->isas
->get(this->isas
, &key
);
2230 /* inbound entry, do update */
2231 sa_id
= entry
->sa_id
;
2232 ports
.localUdpEncapPort
= data
->new_dst
->get_port(data
->new_dst
);
2233 ports
.remoteUdpEncapPort
= data
->new_src
->get_port(data
->new_src
);
2235 this->mutex
->unlock(this->mutex
);
2242 res
= IPsecSaContextGetById1(this->handle
, sa_id
, &ctx
);
2243 if (res
!= ERROR_SUCCESS
)
2245 DBG1(DBG_KNL
, "getting WFP SA context for updated failed: 0x%08x", res
);
2248 if (!hosts2traffic(this, data
->new_dst
, data
->new_src
, &ctx
->inboundSa
->traffic
) ||
2249 !hosts2traffic(this, data
->new_dst
, data
->new_src
, &ctx
->outboundSa
->traffic
))
2251 FwpmFreeMemory0((void**)&ctx
);
2255 if (data
->new_encap
!= data
->encap
)
2257 if (data
->new_encap
)
2259 ctx
->inboundSa
->udpEncapsulation
= &ports
;
2260 ctx
->outboundSa
->udpEncapsulation
= &ports
;
2264 ctx
->inboundSa
->udpEncapsulation
= NULL
;
2265 ctx
->outboundSa
->udpEncapsulation
= NULL
;
2267 flags
|= IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION
;
2270 res
= IPsecSaContextUpdate0(this->handle
, flags
, ctx
);
2271 FwpmFreeMemory0((void**)&ctx
);
2272 if (res
!= ERROR_SUCCESS
)
2274 DBG1(DBG_KNL
, "updating WFP SA context failed: 0x%08x", res
);
2278 this->mutex
->lock(this->mutex
);
2279 entry
= this->isas
->remove(this->isas
, &key
);
2282 key
.spi
= entry
->osa
.spi
;
2283 key
.dst
= entry
->osa
.dst
;
2284 this->osas
->remove(this->osas
, &key
);
2286 if (data
->new_reqid
)
2288 entry
->reqid
= data
->new_reqid
;
2290 entry
->local
->destroy(entry
->local
);
2291 entry
->remote
->destroy(entry
->remote
);
2292 entry
->local
= data
->new_dst
->clone(data
->new_dst
);
2293 entry
->remote
= data
->new_src
->clone(data
->new_src
);
2294 entry
->isa
.dst
= entry
->local
;
2295 entry
->osa
.dst
= entry
->remote
;
2297 this->isas
->put(this->isas
, &entry
->isa
, entry
);
2298 this->osas
->put(this->osas
, &entry
->osa
, entry
);
2300 manage_routes(this, entry
, FALSE
);
2301 manage_routes(this, entry
, TRUE
);
2303 this->mutex
->unlock(this->mutex
);
2308 METHOD(kernel_ipsec_t
, query_sa
, status_t
,
2309 private_kernel_wfp_ipsec_t
*this, kernel_ipsec_sa_id_t
*id
,
2310 kernel_ipsec_query_sa_t
*data
, uint64_t *bytes
, uint64_t *packets
,
2313 /* It does not seem that WFP provides any means of getting per-SA traffic
2314 * statistics. IPsecGetStatistics0/1() provides global stats, and
2315 * IPsecSaContextEnum0/1() and IPsecSaEnum0/1() return the configured
2317 return NOT_SUPPORTED
;
2320 METHOD(kernel_ipsec_t
, del_sa
, status_t
,
2321 private_kernel_wfp_ipsec_t
*this, kernel_ipsec_sa_id_t
*id
,
2322 kernel_ipsec_del_sa_t
*data
)
2330 this->mutex
->lock(this->mutex
);
2331 entry
= this->isas
->remove(this->isas
, &key
);
2332 this->mutex
->unlock(this->mutex
);
2336 /* keep entry until removal of outbound */
2340 this->mutex
->lock(this->mutex
);
2341 entry
= this->osas
->remove(this->osas
, &key
);
2342 this->mutex
->unlock(this->mutex
);
2346 entry_destroy(this, entry
);
2353 METHOD(kernel_ipsec_t
, flush_sas
, status_t
,
2354 private_kernel_wfp_ipsec_t
*this)
2356 return NOT_SUPPORTED
;
2359 METHOD(kernel_ipsec_t
, add_policy
, status_t
,
2360 private_kernel_wfp_ipsec_t
*this, kernel_ipsec_policy_id_t
*id
,
2361 kernel_ipsec_manage_policy_t
*data
)
2363 status_t status
= SUCCESS
;
2367 .spi
= data
->sa
->esp
.use
? data
->sa
->esp
.spi
: data
->sa
->ah
.spi
,
2371 if (data
->sa
->esp
.use
&& data
->sa
->ah
.use
)
2373 return NOT_SUPPORTED
;
2382 return NOT_SUPPORTED
;
2394 return NOT_SUPPORTED
;
2399 case POLICY_PRIORITY_DEFAULT
:
2401 case POLICY_PRIORITY_ROUTED
:
2402 if (!add_trap(this, data
->sa
->reqid
, FALSE
, data
->src
, data
->dst
,
2403 id
->src_ts
, id
->dst_ts
))
2407 if (data
->sa
->mode
== MODE_TUNNEL
)
2409 if (!add_trap(this, data
->sa
->reqid
, TRUE
, data
->src
, data
->dst
,
2410 id
->src_ts
, id
->dst_ts
))
2416 case POLICY_PRIORITY_FALLBACK
:
2418 return NOT_SUPPORTED
;
2421 this->mutex
->lock(this->mutex
);
2422 entry
= this->osas
->get(this->osas
, &key
);
2425 if (data
->sa
->mode
== MODE_TUNNEL
|| array_count(entry
->sps
) == 0)
2428 .src
= id
->src_ts
->clone(id
->src_ts
),
2429 .dst
= id
->dst_ts
->clone(id
->dst_ts
),
2431 array_insert(entry
->sps
, -1, sp
);
2432 if (array_count(entry
->sps
) == data
->sa
->policy_count
)
2434 if (!install(this, entry
))
2442 /* TODO: reinstall with a filter using multiple TS?
2443 * Filters are ANDed for a match, but we could install a filter
2444 * with the inverse TS set using NOT-matches... */
2445 DBG1(DBG_KNL
, "multiple transport mode traffic selectors not "
2446 "supported by WFP");
2447 status
= NOT_SUPPORTED
;
2452 DBG1(DBG_KNL
, "adding SP failed, no SA found for SPI 0x%08x", key
.spi
);
2455 this->mutex
->unlock(this->mutex
);
2460 METHOD(kernel_ipsec_t
, query_policy
, status_t
,
2461 private_kernel_wfp_ipsec_t
*this, kernel_ipsec_policy_id_t
*id
,
2462 kernel_ipsec_query_policy_t
*data
, time_t *use_time
)
2464 /* see query_sa() for some notes */
2465 return NOT_SUPPORTED
;
2468 METHOD(kernel_ipsec_t
, del_policy
, status_t
,
2469 private_kernel_wfp_ipsec_t
*this, kernel_ipsec_policy_id_t
*id
,
2470 kernel_ipsec_manage_policy_t
*data
)
2472 if (id
->dir
== POLICY_OUT
&& data
->prio
== POLICY_PRIORITY_ROUTED
)
2474 if (remove_trap(this, data
->sa
->reqid
, FALSE
, id
->src_ts
,
2477 remove_trap(this, data
->sa
->reqid
, TRUE
, id
->src_ts
,
2483 /* not required, as we delete the whole SA/SP set during del_sa() */
2487 METHOD(kernel_ipsec_t
, flush_policies
, status_t
,
2488 private_kernel_wfp_ipsec_t
*this)
2490 return NOT_SUPPORTED
;
2494 * Add a bypass policy for a specific UDP port
2496 static bool add_bypass(private_kernel_wfp_ipsec_t
*this,
2497 int family
, uint16_t port
, bool inbound
, bool tunnel
,
2500 FWPM_FILTER_CONDITION0
*cond
, *conds
= NULL
;
2503 UINT64 weight
= 0xff00000000000000;
2504 FWPM_FILTER0 filter
= {
2506 .name
= L
"charon IKE bypass",
2509 .type
= FWP_ACTION_PERMIT
,
2520 filter
.layerKey
= inbound
? FWPM_LAYER_INBOUND_TRANSPORT_V4
2521 : FWPM_LAYER_OUTBOUND_TRANSPORT_V4
;
2524 filter
.layerKey
= inbound
? FWPM_LAYER_INBOUND_TRANSPORT_V6
2525 : FWPM_LAYER_OUTBOUND_TRANSPORT_V6
;
2533 filter
.subLayerKey
= FWPM_SUBLAYER_IPSEC_TUNNEL
;
2536 cond
= append_condition(&conds
, &count
);
2537 cond
->fieldKey
= FWPM_CONDITION_IP_PROTOCOL
;
2538 cond
->matchType
= FWP_MATCH_EQUAL
;
2539 cond
->conditionValue
.type
= FWP_UINT8
;
2540 cond
->conditionValue
.uint8
= IPPROTO_UDP
;
2542 cond
= append_condition(&conds
, &count
);
2543 cond
->fieldKey
= FWPM_CONDITION_IP_LOCAL_PORT
;
2544 cond
->matchType
= FWP_MATCH_EQUAL
;
2545 cond
->conditionValue
.type
= FWP_UINT16
;
2546 cond
->conditionValue
.uint16
= port
;
2548 filter
.numFilterConditions
= count
;
2549 filter
.filterCondition
= conds
;
2551 res
= FwpmFilterAdd0(this->handle
, &filter
, NULL
, luid
);
2552 free_conditions(conds
, count
);
2553 if (res
!= ERROR_SUCCESS
)
2555 DBG1(DBG_KNL
, "installing WFP bypass filter failed: 0x%08x", res
);
2561 METHOD(kernel_ipsec_t
, bypass_socket
, bool,
2562 private_kernel_wfp_ipsec_t
*this, int fd
, int family
)
2569 int addrlen
= sizeof(saddr
), i
;
2570 UINT64 filters
[4] = { 0 };
2573 if (getsockname(fd
, &saddr
.sa
, &addrlen
) == SOCKET_ERROR
)
2580 port
= ntohs(saddr
.in
.sin_port
);
2583 port
= ntohs(saddr
.in6
.sin6_port
);
2589 if (!add_bypass(this, family
, port
, TRUE
, FALSE
, &filters
[0]) ||
2590 !add_bypass(this, family
, port
, TRUE
, TRUE
, &filters
[1]) ||
2591 !add_bypass(this, family
, port
, FALSE
, FALSE
, &filters
[2]) ||
2592 !add_bypass(this, family
, port
, FALSE
, TRUE
, &filters
[3]))
2594 for (i
= 0; i
< countof(filters
); i
++)
2598 FwpmFilterDeleteById0(this->handle
, filters
[i
]);
2604 this->mutex
->lock(this->mutex
);
2605 for (i
= 0; i
< countof(filters
); i
++)
2607 array_insert(this->bypass
, ARRAY_TAIL
, &filters
[i
]);
2609 this->mutex
->unlock(this->mutex
);
2614 METHOD(kernel_ipsec_t
, enable_udp_decap
, bool,
2615 private_kernel_wfp_ipsec_t
*this, int fd
, int family
, uint16_t port
)
2620 METHOD(kernel_ipsec_t
, destroy
, void,
2621 private_kernel_wfp_ipsec_t
*this)
2625 while (array_remove(this->bypass
, ARRAY_TAIL
, &filter
))
2627 FwpmFilterDeleteById0(this->handle
, filter
);
2633 FwpmNetEventUnsubscribe0(this->handle
, this->event
);
2635 FwpmProviderDeleteByKey0(this->handle
, &this->provider
.providerKey
);
2636 FwpmEngineClose0(this->handle
);
2638 array_destroy(this->bypass
);
2639 this->tsas
->destroy(this->tsas
);
2640 this->isas
->destroy(this->isas
);
2641 this->osas
->destroy(this->osas
);
2642 this->routes
->destroy(this->routes
);
2643 this->traps
->destroy(this->traps
);
2644 this->mutex
->destroy(this->mutex
);
2649 * Described in header.
2651 kernel_wfp_ipsec_t
*kernel_wfp_ipsec_create()
2653 private_kernel_wfp_ipsec_t
*this;
2655 FWPM_SESSION0 session
= {
2658 .description
= L
"strongSwan IKE kernel-wfp backend",
2665 .get_features
= _get_features
,
2666 .get_spi
= _get_spi
,
2667 .get_cpi
= _get_cpi
,
2669 .update_sa
= _update_sa
,
2670 .query_sa
= _query_sa
,
2672 .flush_sas
= _flush_sas
,
2673 .add_policy
= _add_policy
,
2674 .query_policy
= _query_policy
,
2675 .del_policy
= _del_policy
,
2676 .flush_policies
= _flush_policies
,
2677 .bypass_socket
= _bypass_socket
,
2678 .enable_udp_decap
= _enable_udp_decap
,
2679 .destroy
= _destroy
,
2685 .description
= L
"strongSwan IKE kernel-wfp backend",
2687 .providerKey
= { 0x59cdae2e, 0xf6bb, 0x4c09,
2688 { 0xa9,0x59,0x9d,0x91,0xac,0xaf,0xf9,0x19 }},
2690 .mutex
= mutex_create(MUTEX_TYPE_RECURSIVE
),
2691 .bypass
= array_create(sizeof(UINT64
), 2),
2692 .tsas
= hashtable_create(hashtable_hash_ptr
, hashtable_equals_ptr
, 4),
2693 .isas
= hashtable_create((void*)hash_sa
, (void*)equals_sa
, 4),
2694 .osas
= hashtable_create((void*)hash_sa
, (void*)equals_sa
, 4),
2695 .routes
= hashtable_create((void*)hash_route
, (void*)equals_route
, 4),
2696 .traps
= hashtable_create((void*)hash_trap
, (void*)equals_trap
, 4),
2699 if (!init_spi(this))
2705 res
= FwpmEngineOpen0(NULL
, RPC_C_AUTHN_WINNT
, NULL
, &session
,
2707 if (res
!= ERROR_SUCCESS
)
2709 DBG1(DBG_KNL
, "opening WFP engine failed: 0x%08x", res
);
2714 res
= FwpmProviderAdd0(this->handle
, &this->provider
, NULL
);
2715 if (res
!= ERROR_SUCCESS
&& res
!= FWP_E_ALREADY_EXISTS
)
2717 DBG1(DBG_KNL
, "registering WFP provider failed: 0x%08x", res
);
2722 if (!register_events(this))
2728 return &this->public;