2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
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>.
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
16 /* Windows 7, for some fwpmu.h functionality */
17 #define _WIN32_WINNT 0x0601
19 #include "kernel_wfp_compat.h"
20 #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 typedef struct private_kernel_wfp_ipsec_t private_kernel_wfp_ipsec_t
;
32 struct private_kernel_wfp_ipsec_t
{
37 kernel_wfp_ipsec_t
public;
40 * Next SPI to allocate
45 * Mix value to distribute SPI allocation randomly
50 * IKE bypass filters, as UINT64 filter LUID
55 * Temporary SAD/SPD entries referenced reqid, as uintptr_t => entry_t
60 * SAD/SPD entries referenced by inbound SA, as sa_entry_t => entry_t
65 * SAD/SPD entries referenced by outbound SA, as sa_entry_t => entry_t
70 * Installed routes, as route_t => route_t
75 * Installed traps, as trap_t => trap_t
80 * Mutex for accessing entries
90 * Provider charon registers as
92 FWPM_PROVIDER0 provider
;
101 * Security association entry
104 /** SPI for this SA */
106 /** protocol, IPPROTO_ESP/IPPROTO_AH */
108 /** hard lifetime of SA */
110 /** destination host address for this SPI */
121 * Hash function for sas lookup table
123 static u_int
hash_sa(sa_entry_t
*key
)
125 return chunk_hash_inc(chunk_from_thing(key
->spi
),
126 chunk_hash(key
->dst
->get_address(key
->dst
)));
130 * equals function for sas lookup table
132 static bool equals_sa(sa_entry_t
*a
, sa_entry_t
*b
)
134 return a
->spi
== b
->spi
&& a
->dst
->ip_equals(a
->dst
, b
->dst
);
138 * Security policy entry
141 /** policy source addresses */
142 traffic_selector_t
*src
;
143 /** policy destinaiton addresses */
144 traffic_selector_t
*dst
;
145 /** WFP allocated LUID for inbound filter ID */
147 /** WFP allocated LUID for outbound filter ID */
148 u_int64_t policy_out
;
149 /** WFP allocated LUID for forward inbound filter ID, tunnel mode only */
150 u_int64_t policy_fwd_in
;
151 /** WFP allocated LUID for forward outbound filter ID, tunnel mode only */
152 u_int64_t policy_fwd_out
;
153 /** have installed a route for it? */
158 * Destroy an SP entry
160 static void sp_entry_destroy(sp_entry_t
*sp
)
162 sp
->src
->destroy(sp
->src
);
163 sp
->dst
->destroy(sp
->dst
);
168 * Collection of SA/SP database entries for a reqid
171 /** reqid of entry */
173 /** outer address on local host */
175 /** outer address on remote host */
177 /** inbound SA entry */
179 /** outbound SA entry */
181 /** associated (outbound) policies, as sp_entry_t* */
183 /** IPsec mode, tunnel|transport */
185 /** UDP encapsulation */
187 /** provider context, for tunnel mode only */
189 /** WFP allocated LUID for SA context */
197 /** destination net of route */
199 /** prefix length of dst */
201 /** source address for route */
203 /** gateway of route, NULL if directly attached */
205 /** references for route */
212 static void destroy_route(route_t
*this)
214 this->dst
->destroy(this->dst
);
215 this->src
->destroy(this->src
);
216 DESTROY_IF(this->gtw
);
221 * Hashtable equals function for routes
223 static bool equals_route(route_t
*a
, route_t
*b
)
225 return a
->mask
== b
->mask
&&
226 a
->dst
->ip_equals(a
->dst
, b
->dst
) &&
227 a
->src
->ip_equals(a
->src
, b
->src
);
231 * Hashtable hash function for routes
233 static u_int
hash_route(route_t
*route
)
235 return chunk_hash_inc(route
->src
->get_address(route
->src
),
236 chunk_hash_inc(route
->dst
->get_address(route
->dst
), route
->mask
));
239 /** forward declaration */
240 static bool manage_routes(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
,
244 * Remove policies associated to an entry from kernel
246 static void cleanup_policies(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
248 enumerator_t
*enumerator
;
251 if (entry
->mode
== MODE_TUNNEL
)
253 manage_routes(this, entry
, FALSE
);
256 enumerator
= array_create_enumerator(entry
->sps
);
257 while (enumerator
->enumerate(enumerator
, &sp
))
261 FwpmFilterDeleteById0(this->handle
, sp
->policy_in
);
266 FwpmFilterDeleteById0(this->handle
, sp
->policy_out
);
269 if (sp
->policy_fwd_in
)
271 FwpmFilterDeleteById0(this->handle
, sp
->policy_fwd_in
);
272 sp
->policy_fwd_in
= 0;
274 if (sp
->policy_fwd_out
)
276 FwpmFilterDeleteById0(this->handle
, sp
->policy_fwd_out
);
277 sp
->policy_fwd_out
= 0;
280 enumerator
->destroy(enumerator
);
284 * Destroy a SA/SP entry set
286 static void entry_destroy(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
290 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
294 FwpmProviderContextDeleteById0(this->handle
, entry
->provider
);
296 cleanup_policies(this, entry
);
297 array_destroy_function(entry
->sps
, (void*)sp_entry_destroy
, NULL
);
298 entry
->local
->destroy(entry
->local
);
299 entry
->remote
->destroy(entry
->remote
);
300 chunk_clear(&entry
->isa
.integ
.key
);
301 chunk_clear(&entry
->isa
.encr
.key
);
302 chunk_clear(&entry
->osa
.integ
.key
);
303 chunk_clear(&entry
->osa
.encr
.key
);
308 * Append/Realloc a filter condition to an existing condition set
310 static FWPM_FILTER_CONDITION0
*append_condition(FWPM_FILTER_CONDITION0
*conds
[],
313 FWPM_FILTER_CONDITION0
*cond
;
316 *conds
= realloc(*conds
, *count
* sizeof(*cond
));
317 cond
= *conds
+ *count
- 1;
318 memset(cond
, 0, sizeof(*cond
));
324 * Convert an IPv4 prefix to a host order subnet mask
326 static u_int32_t
prefix2mask(u_int8_t prefix
)
328 u_int8_t netmask
[4] = {};
331 for (i
= 0; i
< sizeof(netmask
); i
++)
335 netmask
[i
] = 0xFF << (8 - prefix
);
341 return untoh32(netmask
);
345 * Convert a 16-bit range to a WFP condition
347 static void range2cond(FWPM_FILTER_CONDITION0
*cond
,
348 u_int16_t from
, u_int16_t to
)
352 cond
->matchType
= FWP_MATCH_EQUAL
;
353 cond
->conditionValue
.type
= FWP_UINT16
;
354 cond
->conditionValue
.uint16
= from
;
358 cond
->matchType
= FWP_MATCH_RANGE
;
359 cond
->conditionValue
.type
= FWP_RANGE_TYPE
;
360 cond
->conditionValue
.rangeValue
= calloc(1, sizeof(FWP_RANGE0
));
361 cond
->conditionValue
.rangeValue
->valueLow
.type
= FWP_UINT16
;
362 cond
->conditionValue
.rangeValue
->valueLow
.uint16
= from
;
363 cond
->conditionValue
.rangeValue
->valueHigh
.type
= FWP_UINT16
;
364 cond
->conditionValue
.rangeValue
->valueHigh
.uint16
= to
;
369 * (Re-)allocate filter conditions for given local or remote traffic selector
371 static bool ts2condition(traffic_selector_t
*ts
, const GUID
*target
,
372 FWPM_FILTER_CONDITION0
*conds
[], int *count
)
374 FWPM_FILTER_CONDITION0
*cond
;
375 FWP_BYTE_ARRAY16
*addr
;
377 u_int16_t from_port
, to_port
;
383 from
= ts
->get_from_address(ts
).ptr
;
384 to
= ts
->get_to_address(ts
).ptr
;
385 from_port
= ts
->get_from_port(ts
);
386 to_port
= ts
->get_to_port(ts
);
388 cond
= append_condition(conds
, count
);
389 cond
->fieldKey
= *target
;
390 if (ts
->is_host(ts
, NULL
))
392 cond
->matchType
= FWP_MATCH_EQUAL
;
393 switch (ts
->get_type(ts
))
395 case TS_IPV4_ADDR_RANGE
:
396 cond
->conditionValue
.type
= FWP_UINT32
;
397 cond
->conditionValue
.uint32
= untoh32(from
);
399 case TS_IPV6_ADDR_RANGE
:
400 cond
->conditionValue
.type
= FWP_BYTE_ARRAY16_TYPE
;
401 cond
->conditionValue
.byteArray16
= addr
= malloc(sizeof(*addr
));
402 memcpy(addr
, from
, sizeof(*addr
));
408 else if (ts
->to_subnet(ts
, &net
, &prefix
))
410 FWP_V6_ADDR_AND_MASK
*m6
;
411 FWP_V4_ADDR_AND_MASK
*m4
;
413 cond
->matchType
= FWP_MATCH_EQUAL
;
414 switch (net
->get_family(net
))
417 cond
->conditionValue
.type
= FWP_V4_ADDR_MASK
;
418 cond
->conditionValue
.v4AddrMask
= m4
= calloc(1, sizeof(*m4
));
419 m4
->addr
= untoh32(from
);
420 m4
->mask
= prefix2mask(prefix
);
423 cond
->conditionValue
.type
= FWP_V6_ADDR_MASK
;
424 cond
->conditionValue
.v6AddrMask
= m6
= calloc(1, sizeof(*m6
));
425 memcpy(m6
->addr
, from
, sizeof(m6
->addr
));
426 m6
->prefixLength
= prefix
;
436 cond
->matchType
= FWP_MATCH_RANGE
;
437 cond
->conditionValue
.type
= FWP_RANGE_TYPE
;
438 cond
->conditionValue
.rangeValue
= range
= calloc(1, sizeof(*range
));
439 switch (ts
->get_type(ts
))
441 case TS_IPV4_ADDR_RANGE
:
442 range
->valueLow
.type
= FWP_UINT32
;
443 range
->valueLow
.uint32
= untoh32(from
);
444 range
->valueHigh
.type
= FWP_UINT32
;
445 range
->valueHigh
.uint32
= untoh32(to
);
447 case TS_IPV6_ADDR_RANGE
:
448 range
->valueLow
.type
= FWP_BYTE_ARRAY16_TYPE
;
449 range
->valueLow
.byteArray16
= addr
= malloc(sizeof(*addr
));
450 memcpy(addr
, from
, sizeof(*addr
));
451 range
->valueHigh
.type
= FWP_BYTE_ARRAY16_TYPE
;
452 range
->valueHigh
.byteArray16
= addr
= malloc(sizeof(*addr
));
453 memcpy(addr
, to
, sizeof(*addr
));
460 proto
= ts
->get_protocol(ts
);
461 if (proto
&& target
== &FWPM_CONDITION_IP_LOCAL_ADDRESS
)
463 cond
= append_condition(conds
, count
);
464 cond
->fieldKey
= FWPM_CONDITION_IP_PROTOCOL
;
465 cond
->matchType
= FWP_MATCH_EQUAL
;
466 cond
->conditionValue
.type
= FWP_UINT8
;
467 cond
->conditionValue
.uint8
= proto
;
470 if (proto
== IPPROTO_ICMP
)
472 if (target
== &FWPM_CONDITION_IP_LOCAL_ADDRESS
)
474 u_int8_t from_type
, to_type
, from_code
, to_code
;
476 from_type
= traffic_selector_icmp_type(from_port
);
477 to_type
= traffic_selector_icmp_type(to_port
);
478 from_code
= traffic_selector_icmp_code(from_port
);
479 to_code
= traffic_selector_icmp_code(to_port
);
481 if (from_type
!= 0 || to_type
!= 0xFF)
483 cond
= append_condition(conds
, count
);
484 cond
->fieldKey
= FWPM_CONDITION_ICMP_TYPE
;
485 range2cond(cond
, from_type
, to_type
);
487 if (from_code
!= 0 || to_code
!= 0xFF)
489 cond
= append_condition(conds
, count
);
490 cond
->fieldKey
= FWPM_CONDITION_ICMP_CODE
;
491 range2cond(cond
, from_code
, to_code
);
495 else if (from_port
!= 0 || to_port
!= 0xFFFF)
497 if (target
== &FWPM_CONDITION_IP_LOCAL_ADDRESS
)
499 cond
= append_condition(conds
, count
);
500 cond
->fieldKey
= FWPM_CONDITION_IP_LOCAL_PORT
;
501 range2cond(cond
, from_port
, to_port
);
503 if (target
== &FWPM_CONDITION_IP_REMOTE_ADDRESS
)
505 cond
= append_condition(conds
, count
);
506 cond
->fieldKey
= FWPM_CONDITION_IP_REMOTE_PORT
;
507 range2cond(cond
, from_port
, to_port
);
514 * Free memory associated to a single condition
516 static void free_condition(FWP_DATA_TYPE type
, void *value
)
522 case FWP_BYTE_ARRAY16_TYPE
:
523 case FWP_V4_ADDR_MASK
:
524 case FWP_V6_ADDR_MASK
:
529 free_condition(range
->valueLow
.type
, range
->valueLow
.sd
);
530 free_condition(range
->valueHigh
.type
, range
->valueHigh
.sd
);
539 * Free memory used by a set of conditions
541 static void free_conditions(FWPM_FILTER_CONDITION0
*conds
, int count
)
545 for (i
= 0; i
< count
; i
++)
547 free_condition(conds
[i
].conditionValue
.type
, conds
[i
].conditionValue
.sd
);
553 * Find the callout GUID for given parameters
555 static bool find_callout(bool tunnel
, bool v6
, bool inbound
, bool forward
,
556 GUID
*layer
, GUID
*sublayer
, GUID
*callout
)
564 const GUID
*sublayer
;
567 { 0, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4
, NULL
,
568 &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4
},
569 { 0, 0, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4
, NULL
,
570 &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4
},
571 { 0, 1, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6
, NULL
,
572 &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6
},
573 { 0, 1, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6
, NULL
,
574 &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6
},
575 { 1, 0, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4
,
576 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
577 &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4
},
578 { 1, 0, 0, 1, &FWPM_LAYER_IPFORWARD_V4
,
579 &FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL
,
580 &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4
},
581 { 1, 0, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V4
,
582 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
583 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4
},
584 { 1, 0, 1, 1, &FWPM_LAYER_IPFORWARD_V4
,
585 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
586 &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4
},
587 { 1, 1, 0, 0, &FWPM_LAYER_OUTBOUND_TRANSPORT_V6
,
588 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
589 &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6
},
590 { 1, 1, 0, 1, &FWPM_LAYER_IPFORWARD_V6
,
591 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
592 &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6
},
593 { 1, 1, 1, 0, &FWPM_LAYER_INBOUND_TRANSPORT_V6
,
594 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
595 &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6
},
596 { 1, 1, 1, 1, &FWPM_LAYER_IPFORWARD_V6
,
597 &FWPM_SUBLAYER_IPSEC_TUNNEL
,
598 &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6
},
602 for (i
= 0; i
< countof(map
); i
++)
604 if (tunnel
== map
[i
].tunnel
&&
606 inbound
== map
[i
].inbound
&&
607 forward
== map
[i
].forward
)
609 *callout
= *map
[i
].callout
;
610 *layer
= *map
[i
].layer
;
613 *sublayer
= *map
[i
].sublayer
;
622 * Install a single policy in to the kernel
624 static bool install_sp(private_kernel_wfp_ipsec_t
*this, sp_entry_t
*sp
,
625 GUID
*context
, bool inbound
, bool fwd
, UINT64
*filter_id
)
627 FWPM_FILTER_CONDITION0
*conds
= NULL
;
628 traffic_selector_t
*local
, *remote
;
629 const GUID
*ltarget
, *rtarget
;
633 FWPM_FILTER0 filter
= {
635 .name
= L
"charon IPsec policy",
638 .type
= FWP_ACTION_CALLOUT_TERMINATING
,
644 filter
.flags
|= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT
;
645 filter
.providerKey
= (GUID
*)&this->provider
.providerKey
;
646 filter
.providerContextKey
= *context
;
649 v6
= sp
->src
->get_type(sp
->src
) == TS_IPV6_ADDR_RANGE
;
650 if (!find_callout(context
!= NULL
, v6
, inbound
, fwd
,
651 &filter
.layerKey
, &filter
.subLayerKey
,
652 &filter
.action
.calloutKey
))
669 ltarget
= &FWPM_CONDITION_IP_SOURCE_ADDRESS
;
670 rtarget
= &FWPM_CONDITION_IP_DESTINATION_ADDRESS
;
674 ltarget
= &FWPM_CONDITION_IP_LOCAL_ADDRESS
;
675 rtarget
= &FWPM_CONDITION_IP_REMOTE_ADDRESS
;
677 if (!ts2condition(local
, ltarget
, &conds
, &count
) ||
678 !ts2condition(remote
, rtarget
, &conds
, &count
))
680 free_conditions(conds
, count
);
684 filter
.numFilterConditions
= count
;
685 filter
.filterCondition
= conds
;
687 res
= FwpmFilterAdd0(this->handle
, &filter
, NULL
, filter_id
);
688 free_conditions(conds
, count
);
689 if (res
!= ERROR_SUCCESS
)
691 DBG1(DBG_KNL
, "installing %s%sbound WFP filter failed: 0x%08x",
692 fwd ?
"forward " : "", inbound ?
"in" : "out", res
);
699 * Install a set of policies in to the kernel
701 static bool install_sps(private_kernel_wfp_ipsec_t
*this,
702 entry_t
*entry
, GUID
*context
)
704 enumerator_t
*enumerator
;
707 enumerator
= array_create_enumerator(entry
->sps
);
708 while (enumerator
->enumerate(enumerator
, &sp
))
711 if (!install_sp(this, sp
, context
, TRUE
, FALSE
, &sp
->policy_in
))
713 enumerator
->destroy(enumerator
);
716 /* outbound policy */
717 if (!install_sp(this, sp
, context
, FALSE
, FALSE
, &sp
->policy_out
))
719 enumerator
->destroy(enumerator
);
724 if (!sp
->src
->is_host(sp
->src
, entry
->local
) ||
725 !sp
->dst
->is_host(sp
->dst
, entry
->remote
))
727 /* inbound forward policy, from decapsulation */
728 if (!install_sp(this, sp
, context
,
729 TRUE
, TRUE
, &sp
->policy_fwd_in
))
731 enumerator
->destroy(enumerator
);
734 /* outbound forward policy, to encapsulate */
735 if (!install_sp(this, sp
, context
,
736 FALSE
, TRUE
, &sp
->policy_fwd_out
))
738 enumerator
->destroy(enumerator
);
744 enumerator
->destroy(enumerator
);
750 * Convert a chunk_t to a WFP FWP_BYTE_BLOB
752 static inline FWP_BYTE_BLOB
chunk2blob(chunk_t chunk
)
754 return (FWP_BYTE_BLOB
){
761 * Convert an integrity_algorithm_t to a WFP IPSEC_AUTH_TRANFORM_ID0
763 static bool alg2auth(integrity_algorithm_t alg
,
764 IPSEC_SA_AUTH_INFORMATION0
*info
)
767 integrity_algorithm_t alg
;
768 IPSEC_AUTH_TRANSFORM_ID0 transform
;
770 { AUTH_HMAC_MD5_96
, IPSEC_AUTH_TRANSFORM_ID_HMAC_MD5_96
},
771 { AUTH_HMAC_SHA1_96
, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96
},
772 { AUTH_HMAC_SHA2_256_128
, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_256_128
},
773 { AUTH_AES_128_GMAC
, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_128
},
774 { AUTH_AES_192_GMAC
, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_192
},
775 { AUTH_AES_256_GMAC
, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_256
},
779 for (i
= 0; i
< countof(map
); i
++)
781 if (map
[i
].alg
== alg
)
783 info
->authTransform
.authTransformId
= map
[i
].transform
;
791 * Convert an encryption_algorithm_t to a WFP IPSEC_CIPHER_TRANFORM_ID0
793 static bool alg2cipher(encryption_algorithm_t alg
, int keylen
,
794 IPSEC_SA_CIPHER_INFORMATION0
*info
)
797 encryption_algorithm_t alg
;
799 IPSEC_CIPHER_TRANSFORM_ID0 transform
;
801 { ENCR_DES
, 8, IPSEC_CIPHER_TRANSFORM_ID_CBC_DES
},
802 { ENCR_3DES
, 24, IPSEC_CIPHER_TRANSFORM_ID_CBC_3DES
},
803 { ENCR_AES_CBC
, 16, IPSEC_CIPHER_TRANSFORM_ID_AES_128
},
804 { ENCR_AES_CBC
, 24, IPSEC_CIPHER_TRANSFORM_ID_AES_192
},
805 { ENCR_AES_CBC
, 32, IPSEC_CIPHER_TRANSFORM_ID_AES_256
},
806 { ENCR_AES_GCM_ICV16
, 20, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_128
},
807 { ENCR_AES_GCM_ICV16
, 28, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_192
},
808 { ENCR_AES_GCM_ICV16
, 36, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_256
},
812 for (i
= 0; i
< countof(map
); i
++)
814 if (map
[i
].alg
== alg
&& map
[i
].keylen
== keylen
)
816 info
->cipherTransform
.cipherTransformId
= map
[i
].transform
;
824 * Get the integrity algorithm used for an AEAD transform
826 static integrity_algorithm_t
encr2integ(encryption_algorithm_t encr
, int keylen
)
829 encryption_algorithm_t encr
;
831 integrity_algorithm_t integ
;
833 { ENCR_NULL_AUTH_AES_GMAC
, 20, AUTH_AES_128_GMAC
},
834 { ENCR_NULL_AUTH_AES_GMAC
, 28, AUTH_AES_192_GMAC
},
835 { ENCR_NULL_AUTH_AES_GMAC
, 36, AUTH_AES_256_GMAC
},
836 { ENCR_AES_GCM_ICV16
, 20, AUTH_AES_128_GMAC
},
837 { ENCR_AES_GCM_ICV16
, 28, AUTH_AES_192_GMAC
},
838 { ENCR_AES_GCM_ICV16
, 36, AUTH_AES_256_GMAC
},
842 for (i
= 0; i
< countof(map
); i
++)
844 if (map
[i
].encr
== encr
&& map
[i
].keylen
== keylen
)
849 return AUTH_UNDEFINED
;
853 * Install a single SA
855 static bool install_sa(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
,
856 bool inbound
, sa_entry_t
*sa
, FWP_IP_VERSION version
)
858 IPSEC_SA_AUTH_AND_CIPHER_INFORMATION0 info
= {};
860 .spi
= ntohl(sa
->spi
),
862 IPSEC_SA_BUNDLE0 bundle
= {
864 .lifetimeSeconds
= inbound ? entry
->isa
.lifetime
865 : entry
->osa
.lifetime
,
869 .ipVersion
= version
,
874 } integ
= {}, encr
= {};
877 switch (sa
->protocol
)
880 ipsec
.saTransformType
= IPSEC_TRANSFORM_AH
;
881 ipsec
.ahInformation
= &info
.saAuthInformation
;
882 integ
.key
= sa
->integ
.key
;
883 integ
.alg
= sa
->integ
.alg
;
886 if (sa
->encr
.alg
== ENCR_NULL
||
887 sa
->encr
.alg
== ENCR_NULL_AUTH_AES_GMAC
)
889 ipsec
.saTransformType
= IPSEC_TRANSFORM_ESP_AUTH
;
890 ipsec
.espAuthInformation
= &info
.saAuthInformation
;
894 ipsec
.saTransformType
= IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER
;
895 ipsec
.espAuthAndCipherInformation
= &info
;
896 encr
.key
= sa
->encr
.key
;
897 encr
.alg
= sa
->encr
.alg
;
899 if (encryption_algorithm_is_aead(sa
->encr
.alg
))
901 integ
.alg
= encr2integ(sa
->encr
.alg
, sa
->encr
.key
.len
);
902 integ
.key
= sa
->encr
.key
;
906 integ
.alg
= sa
->integ
.alg
;
907 integ
.key
= sa
->integ
.key
;
916 info
.saAuthInformation
.authKey
= chunk2blob(integ
.key
);
917 if (!alg2auth(integ
.alg
, &info
.saAuthInformation
))
919 DBG1(DBG_KNL
, "integrity algorithm %N not supported by WFP",
920 integrity_algorithm_names
, integ
.alg
);
926 info
.saCipherInformation
.cipherKey
= chunk2blob(encr
.key
);
927 if (!alg2cipher(encr
.alg
, encr
.key
.len
, &info
.saCipherInformation
))
929 DBG1(DBG_KNL
, "encryption algorithm %N not supported by WFP",
930 encryption_algorithm_names
, encr
.alg
);
937 res
= IPsecSaContextAddInbound0(this->handle
, entry
->sa_id
, &bundle
);
941 bundle
.flags
|= IPSEC_SA_BUNDLE_FLAG_ASSUME_UDP_CONTEXT_OUTBOUND
;
942 res
= IPsecSaContextAddOutbound0(this->handle
, entry
->sa_id
, &bundle
);
944 if (res
!= ERROR_SUCCESS
)
946 DBG1(DBG_KNL
, "adding %sbound WFP SA failed: 0x%08x",
947 inbound ?
"in" : "out", res
);
954 * Convert an IPv6 host address to WFP representation
956 static void host2address6(host_t
*host
, void *out
)
958 u_int32_t
*src
, *dst
= out
;
960 src
= (u_int32_t
*)host
->get_address(host
).ptr
;
962 dst
[0] = untoh32(&src
[3]);
963 dst
[1] = untoh32(&src
[2]);
964 dst
[2] = untoh32(&src
[1]);
965 dst
[3] = untoh32(&src
[0]);
969 * Fill in traffic structure from entry addresses
971 static bool hosts2traffic(private_kernel_wfp_ipsec_t
*this,
972 host_t
*l
, host_t
*r
, IPSEC_TRAFFIC1
*traffic
)
974 if (l
->get_family(l
) != r
->get_family(r
))
978 switch (l
->get_family(l
))
981 traffic
->ipVersion
= FWP_IP_VERSION_V4
;
982 traffic
->localV4Address
= untoh32(l
->get_address(l
).ptr
);
983 traffic
->remoteV4Address
= untoh32(r
->get_address(r
).ptr
);
986 traffic
->ipVersion
= FWP_IP_VERSION_V6
;
987 host2address6(l
, &traffic
->localV6Address
);
988 host2address6(r
, &traffic
->remoteV6Address
);
996 * Install SAs to the kernel
998 static bool install_sas(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
,
999 IPSEC_TRAFFIC_TYPE type
)
1001 IPSEC_TRAFFIC1 traffic
= {
1002 .trafficType
= type
,
1004 IPSEC_GETSPI1 spi
= {
1005 .inboundIpsecTraffic
= {
1006 .trafficType
= type
,
1009 enumerator_t
*enumerator
;
1013 if (type
== IPSEC_TRAFFIC_TYPE_TRANSPORT
)
1015 enumerator
= array_create_enumerator(entry
->sps
);
1016 if (enumerator
->enumerate(enumerator
, &sp
))
1018 traffic
.ipsecFilterId
= sp
->policy_out
;
1019 spi
.inboundIpsecTraffic
.ipsecFilterId
= sp
->policy_in
;
1023 enumerator
->destroy(enumerator
);
1026 enumerator
->destroy(enumerator
);
1030 traffic
.tunnelPolicyId
= entry
->provider
;
1031 spi
.inboundIpsecTraffic
.tunnelPolicyId
= entry
->provider
;
1034 if (!hosts2traffic(this, entry
->local
, entry
->remote
, &traffic
))
1039 res
= IPsecSaContextCreate1(this->handle
, &traffic
, NULL
, NULL
,
1041 if (res
!= ERROR_SUCCESS
)
1043 DBG1(DBG_KNL
, "creating WFP SA context failed: 0x%08x", res
);
1047 memcpy(spi
.inboundIpsecTraffic
.localV6Address
, traffic
.localV6Address
,
1048 sizeof(traffic
.localV6Address
));
1049 memcpy(spi
.inboundIpsecTraffic
.remoteV6Address
, traffic
.remoteV6Address
,
1050 sizeof(traffic
.remoteV6Address
));
1051 spi
.ipVersion
= traffic
.ipVersion
;
1053 res
= IPsecSaContextSetSpi0(this->handle
, entry
->sa_id
, &spi
,
1054 ntohl(entry
->isa
.spi
));
1055 if (res
!= ERROR_SUCCESS
)
1057 DBG1(DBG_KNL
, "setting WFP SA SPI failed: 0x%08x", res
);
1058 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
1063 if (!install_sa(this, entry
, TRUE
, &entry
->isa
, spi
.ipVersion
) ||
1064 !install_sa(this, entry
, FALSE
, &entry
->osa
, spi
.ipVersion
))
1066 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
1073 IPSEC_V4_UDP_ENCAPSULATION0 encap
= {
1074 .localUdpEncapPort
= entry
->local
->get_port(entry
->local
),
1075 .remoteUdpEncapPort
= entry
->remote
->get_port(entry
->remote
),
1077 IPSEC_SA_CONTEXT1
*ctx
;
1079 res
= IPsecSaContextGetById1(this->handle
, entry
->sa_id
, &ctx
);
1080 if (res
!= ERROR_SUCCESS
)
1082 DBG1(DBG_KNL
, "getting WFP SA for UDP encap failed: 0x%08x", res
);
1083 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
1087 ctx
->inboundSa
->udpEncapsulation
= &encap
;
1088 ctx
->outboundSa
->udpEncapsulation
= &encap
;
1090 res
= IPsecSaContextUpdate0(this->handle
,
1091 IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION
, ctx
);
1092 FwpmFreeMemory0((void**)&ctx
);
1093 if (res
!= ERROR_SUCCESS
)
1095 DBG1(DBG_KNL
, "enable WFP UDP encap failed: 0x%08x", res
);
1096 IPsecSaContextDeleteById0(this->handle
, entry
->sa_id
);
1106 * Install a transport mode SA/SP set to the kernel
1108 static bool install_transport(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
1110 if (install_sps(this, entry
, NULL
) &&
1111 install_sas(this, entry
, IPSEC_TRAFFIC_TYPE_TRANSPORT
))
1115 cleanup_policies(this, entry
);
1120 * Generate a new GUID, random
1122 static bool generate_guid(private_kernel_wfp_ipsec_t
*this, GUID
*guid
)
1127 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
1132 ok
= rng
->get_bytes(rng
, sizeof(GUID
), (u_int8_t
*)guid
);
1138 * Register a dummy tunnel provider to associate tunnel filters to
1140 static bool add_tunnel_provider(private_kernel_wfp_ipsec_t
*this,
1141 entry_t
*entry
, GUID
*guid
, UINT64
*luid
)
1145 IPSEC_AUTH_TRANSFORM0 transform
= {
1146 /* Create any valid proposal. This is actually not used, as we
1147 * don't create an SA from this information. */
1148 .authTransformId
= IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96
,
1150 IPSEC_SA_TRANSFORM0 transforms
= {
1151 .ipsecTransformType
= IPSEC_TRANSFORM_ESP_AUTH
,
1152 .espAuthTransform
= &transform
,
1154 IPSEC_PROPOSAL0 proposal
= {
1156 /* We need a valid lifetime, even if we don't create any SA
1157 * from these values. Pick some values accepted. */
1158 .lifetimeSeconds
= 0xFFFF,
1159 .lifetimeKilobytes
= 0xFFFFFFFF,
1160 .lifetimePackets
= 0xFFFFFFFF,
1162 .numSaTransforms
= 1,
1163 .saTransforms
= &transforms
,
1165 IPSEC_TUNNEL_POLICY0 policy
= {
1166 .numIpsecProposals
= 1,
1167 .ipsecProposals
= &proposal
,
1169 /* not used, set to lifetime for maximum */
1170 .idleTimeoutSeconds
= proposal
.lifetime
.lifetimeSeconds
,
1171 .idleTimeoutSecondsFailOver
= proposal
.lifetime
.lifetimeSeconds
,
1174 FWPM_PROVIDER_CONTEXT0 qm
= {
1176 .name
= L
"charon tunnel provider",
1178 .providerKey
= (GUID
*)&this->provider
.providerKey
,
1179 .type
= FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT
,
1180 .ikeQmTunnelPolicy
= &policy
,
1183 switch (entry
->local
->get_family(entry
->local
))
1186 policy
.tunnelEndpoints
.ipVersion
= FWP_IP_VERSION_V4
;
1187 policy
.tunnelEndpoints
.localV4Address
=
1188 untoh32(entry
->local
->get_address(entry
->local
).ptr
);
1189 policy
.tunnelEndpoints
.remoteV4Address
=
1190 untoh32(entry
->remote
->get_address(entry
->remote
).ptr
);
1193 policy
.tunnelEndpoints
.ipVersion
= FWP_IP_VERSION_V6
;
1194 host2address6(entry
->local
, &policy
.tunnelEndpoints
.localV6Address
);
1195 host2address6(entry
->remote
, &policy
.tunnelEndpoints
.remoteV6Address
);
1201 if (!generate_guid(this, &qm
.providerContextKey
))
1206 res
= FwpmProviderContextAdd0(this->handle
, &qm
, NULL
, luid
);
1207 if (res
!= ERROR_SUCCESS
)
1209 DBG1(DBG_KNL
, "adding provider context failed: 0x%08x", res
);
1212 *guid
= qm
.providerContextKey
;
1217 * Install tunnel mode SPs to the kernel
1219 static bool install_tunnel_sps(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
1223 if (!add_tunnel_provider(this, entry
, &guid
, &entry
->provider
))
1227 if (!install_sps(this, entry
, &guid
))
1235 * Reduce refcount, or uninstall a route if all refs gone
1237 static bool uninstall_route(private_kernel_wfp_ipsec_t
*this,
1238 host_t
*dst
, u_int8_t mask
, host_t
*src
, host_t
*gtw
)
1240 route_t
*route
, key
= {
1248 this->mutex
->lock(this->mutex
);
1249 route
= this->routes
->get(this->routes
, &key
);
1252 if (--route
->refs
== 0)
1254 if (hydra
->kernel_interface
->get_interface(hydra
->kernel_interface
,
1257 res
= hydra
->kernel_interface
->del_route(hydra
->kernel_interface
,
1258 dst
->get_address(dst
), mask
, gtw
, src
, name
) == SUCCESS
;
1261 route
= this->routes
->remove(this->routes
, route
);
1264 destroy_route(route
);
1272 this->mutex
->unlock(this->mutex
);
1278 * Install a single route, or refcount if exists
1280 static bool install_route(private_kernel_wfp_ipsec_t
*this,
1281 host_t
*dst
, u_int8_t mask
, host_t
*src
, host_t
*gtw
)
1283 route_t
*route
, key
= {
1291 this->mutex
->lock(this->mutex
);
1292 route
= this->routes
->get(this->routes
, &key
);
1300 if (hydra
->kernel_interface
->get_interface(hydra
->kernel_interface
,
1303 if (hydra
->kernel_interface
->add_route(hydra
->kernel_interface
,
1304 dst
->get_address(dst
), mask
, gtw
, src
, name
) == SUCCESS
)
1307 .dst
= dst
->clone(dst
),
1309 .src
= src
->clone(src
),
1310 .gtw
= gtw ? gtw
->clone(gtw
) : NULL
,
1313 route
= this->routes
->put(this->routes
, route
, route
);
1316 destroy_route(route
);
1323 this->mutex
->unlock(this->mutex
);
1329 * (Un)-install a single route
1331 static bool manage_route(private_kernel_wfp_ipsec_t
*this,
1332 host_t
*local
, host_t
*remote
,
1333 traffic_selector_t
*src_ts
, traffic_selector_t
*dst_ts
,
1336 host_t
*src
, *dst
, *gtw
;
1340 if (!dst_ts
->to_subnet(dst_ts
, &dst
, &mask
))
1344 if (hydra
->kernel_interface
->get_address_by_ts(hydra
->kernel_interface
,
1345 src_ts
, &src
, NULL
) != SUCCESS
)
1350 gtw
= hydra
->kernel_interface
->get_nexthop(hydra
->kernel_interface
,
1354 done
= install_route(this, dst
, mask
, src
, gtw
);
1358 done
= uninstall_route(this, dst
, mask
, src
, gtw
);
1366 DBG1(DBG_KNL
, "%sinstalling route for policy %R === %R failed",
1367 add ?
"" : "un", src_ts
, dst_ts
);
1373 * (Un)-install routes for IPsec policies
1375 static bool manage_routes(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
,
1378 enumerator_t
*enumerator
;
1381 enumerator
= array_create_enumerator(entry
->sps
);
1382 while (enumerator
->enumerate(enumerator
, &sp
))
1384 if (add
&& sp
->route
)
1388 if (!add
&& !sp
->route
)
1392 if (manage_route(this, entry
->local
, entry
->remote
,
1393 sp
->src
, sp
->dst
, add
))
1398 enumerator
->destroy(enumerator
);
1404 * Install a tunnel mode SA/SP set to the kernel
1406 static bool install_tunnel(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
1408 if (install_tunnel_sps(this, entry
) &&
1409 manage_routes(this, entry
, TRUE
) &&
1410 install_sas(this, entry
, IPSEC_TRAFFIC_TYPE_TUNNEL
))
1414 cleanup_policies(this, entry
);
1419 * Install a SA/SP set to the kernel
1421 static bool install(private_kernel_wfp_ipsec_t
*this, entry_t
*entry
)
1423 switch (entry
->mode
)
1425 case MODE_TRANSPORT
:
1426 return install_transport(this, entry
);
1428 return install_tunnel(this, entry
);
1436 * Installed trap entry
1439 /** reqid this trap is installed for */
1441 /** is this a forward policy trap for tunnel mode? */
1443 /** do we have installed a route for this trap policy? */
1445 /** local address of associated route */
1447 /** remote address of associated route */
1449 /** src traffic selector */
1450 traffic_selector_t
*src
;
1451 /** dst traffic selector */
1452 traffic_selector_t
*dst
;
1453 /** LUID of installed tunnel policy filter */
1458 * Destroy a trap entry
1460 static void destroy_trap(trap_t
*this)
1462 this->local
->destroy(this->local
);
1463 this->remote
->destroy(this->remote
);
1464 this->src
->destroy(this->src
);
1465 this->dst
->destroy(this->dst
);
1470 * Hashtable equals function for traps
1472 static bool equals_trap(trap_t
*a
, trap_t
*b
)
1474 return a
->filter_id
== b
->filter_id
;
1478 * Hashtable hash function for traps
1480 static u_int
hash_trap(trap_t
*trap
)
1482 return chunk_hash(chunk_from_thing(trap
->filter_id
));
1486 * Send an acquire for an installed trap filter
1488 static void acquire(private_kernel_wfp_ipsec_t
*this, UINT64 filter_id
,
1489 traffic_selector_t
*src
, traffic_selector_t
*dst
)
1491 u_int32_t reqid
= 0;
1492 trap_t
*trap
, key
= {
1493 .filter_id
= filter_id
,
1496 this->mutex
->lock(this->mutex
);
1497 trap
= this->traps
->get(this->traps
, &key
);
1500 reqid
= trap
->reqid
;
1502 this->mutex
->unlock(this->mutex
);
1506 src
= src ? src
->clone(src
) : NULL
;
1507 dst
= dst ? dst
->clone(dst
) : NULL
;
1508 hydra
->kernel_interface
->acquire(hydra
->kernel_interface
, reqid
,
1514 * Create a single host traffic selector from an FWP address definition
1516 static traffic_selector_t
*addr2ts(FWP_IP_VERSION version
, void *data
,
1517 u_int8_t protocol
, u_int16_t from_port
, u_int16_t to_port
)
1525 case FWP_IP_VERSION_V4
:
1526 ints
[0] = untoh32(data
);
1527 addr
= chunk_from_thing(ints
[0]);
1528 type
= TS_IPV4_ADDR_RANGE
;
1530 case FWP_IP_VERSION_V6
:
1531 ints
[3] = untoh32(data
);
1532 ints
[2] = untoh32(data
+ 4);
1533 ints
[1] = untoh32(data
+ 8);
1534 ints
[0] = untoh32(data
+ 12);
1535 addr
= chunk_from_thing(ints
);
1536 type
= TS_IPV6_ADDR_RANGE
;
1541 return traffic_selector_create_from_bytes(protocol
, type
, addr
, from_port
,
1546 * FwpmNetEventSubscribe0() callback
1548 static void WINAPI
event_callback(void *user
, const FWPM_NET_EVENT1
*event
)
1550 private_kernel_wfp_ipsec_t
*this = user
;
1551 traffic_selector_t
*local
= NULL
, *remote
= NULL
;
1552 u_int8_t protocol
= 0;
1553 u_int16_t from_local
= 0, to_local
= 65535;
1554 u_int16_t from_remote
= 0, to_remote
= 65535;
1556 if ((event
->header
.flags
& FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET
) &&
1557 (event
->header
.flags
& FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET
))
1559 if (event
->header
.flags
& FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET
)
1561 from_local
= to_local
= event
->header
.localPort
;
1563 if (event
->header
.flags
& FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET
)
1565 from_remote
= to_remote
= event
->header
.remotePort
;
1567 if (event
->header
.flags
& FWPM_NET_EVENT_FLAG_IP_PROTOCOL_SET
)
1569 protocol
= event
->header
.ipProtocol
;
1572 local
= addr2ts(event
->header
.ipVersion
,
1573 (void*)&event
->header
.localAddrV6
,
1574 protocol
, from_local
, to_local
);
1575 remote
= addr2ts(event
->header
.ipVersion
,
1576 (void*)&event
->header
.remoteAddrV6
,
1577 protocol
, from_remote
, to_remote
);
1580 switch (event
->type
)
1582 case FWPM_NET_EVENT_TYPE_CLASSIFY_DROP
:
1583 acquire(this, event
->classifyDrop
->filterId
, local
, remote
);
1585 case FWPM_NET_EVENT_TYPE_IKEEXT_MM_FAILURE
:
1586 case FWPM_NET_EVENT_TYPE_IKEEXT_QM_FAILURE
:
1587 case FWPM_NET_EVENT_TYPE_IKEEXT_EM_FAILURE
:
1588 case FWPM_NET_EVENT_TYPE_IPSEC_KERNEL_DROP
:
1589 DBG1(DBG_KNL
, "IPsec kernel drop: %R === %R, error 0x%08x, "
1590 "SPI 0x%08x, %s filterId %llu", local
, remote
,
1591 event
->ipsecDrop
->failureStatus
, event
->ipsecDrop
->spi
,
1592 event
->ipsecDrop
->direction ?
"in" : "out",
1593 event
->ipsecDrop
->filterId
);
1595 case FWPM_NET_EVENT_TYPE_IPSEC_DOSP_DROP
:
1605 * Register for net events
1607 static bool register_events(private_kernel_wfp_ipsec_t
*this)
1609 FWPM_NET_EVENT_SUBSCRIPTION0 subscription
= {};
1612 res
= FwpmNetEventSubscribe0(this->handle
, &subscription
,
1613 event_callback
, this, &this->event
);
1614 if (res
!= ERROR_SUCCESS
)
1616 DBG1(DBG_KNL
, "registering for WFP events failed: 0x%08x", res
);
1623 * Install a trap policy to kernel
1625 static bool install_trap(private_kernel_wfp_ipsec_t
*this, trap_t
*trap
)
1627 FWPM_FILTER_CONDITION0
*conds
= NULL
;
1630 const GUID
*starget
, *dtarget
;
1631 UINT64 weight
= 0x000000000000ff00;
1632 FWPM_FILTER0 filter
= {
1634 .name
= L
"charon IPsec trap",
1637 .type
= FWP_ACTION_BLOCK
,
1647 if (trap
->src
->get_type(trap
->src
) == TS_IPV4_ADDR_RANGE
)
1649 filter
.layerKey
= FWPM_LAYER_IPFORWARD_V4
;
1653 filter
.layerKey
= FWPM_LAYER_IPFORWARD_V6
;
1655 starget
= &FWPM_CONDITION_IP_SOURCE_ADDRESS
;
1656 dtarget
= &FWPM_CONDITION_IP_DESTINATION_ADDRESS
;
1660 if (trap
->src
->get_type(trap
->src
) == TS_IPV4_ADDR_RANGE
)
1662 filter
.layerKey
= FWPM_LAYER_OUTBOUND_TRANSPORT_V4
;
1666 filter
.layerKey
= FWPM_LAYER_OUTBOUND_TRANSPORT_V6
;
1668 starget
= &FWPM_CONDITION_IP_LOCAL_ADDRESS
;
1669 dtarget
= &FWPM_CONDITION_IP_REMOTE_ADDRESS
;
1672 if (!ts2condition(trap
->src
, starget
, &conds
, &count
) ||
1673 !ts2condition(trap
->dst
, dtarget
, &conds
, &count
))
1675 free_conditions(conds
, count
);
1679 filter
.numFilterConditions
= count
;
1680 filter
.filterCondition
= conds
;
1682 res
= FwpmFilterAdd0(this->handle
, &filter
, NULL
, &trap
->filter_id
);
1683 free_conditions(conds
, count
);
1684 if (res
!= ERROR_SUCCESS
)
1686 DBG1(DBG_KNL
, "installing WFP trap filter failed: 0x%08x", res
);
1693 * Uninstall a trap policy from kernel
1695 static bool uninstall_trap(private_kernel_wfp_ipsec_t
*this, trap_t
*trap
)
1699 res
= FwpmFilterDeleteById0(this->handle
, trap
->filter_id
);
1700 if (res
!= ERROR_SUCCESS
)
1702 DBG1(DBG_KNL
, "uninstalling WFP trap filter failed: 0x%08x", res
);
1709 * Create and install a new trap entry
1711 static bool add_trap(private_kernel_wfp_ipsec_t
*this,
1712 u_int32_t reqid
, bool fwd
, host_t
*local
, host_t
*remote
,
1713 traffic_selector_t
*src
, traffic_selector_t
*dst
)
1720 .src
= src
->clone(src
),
1721 .dst
= dst
->clone(dst
),
1722 .local
= local
->clone(local
),
1723 .remote
= remote
->clone(remote
),
1726 if (!install_trap(this, trap
))
1732 trap
->route
= manage_route(this, local
, remote
, src
, dst
, TRUE
);
1734 this->mutex
->lock(this->mutex
);
1735 this->traps
->put(this->traps
, trap
, trap
);
1736 this->mutex
->unlock(this->mutex
);
1741 * Uninstall and remove a new trap entry
1743 static bool remove_trap(private_kernel_wfp_ipsec_t
*this,
1744 u_int32_t reqid
, bool fwd
,
1745 traffic_selector_t
*src
, traffic_selector_t
*dst
)
1747 enumerator_t
*enumerator
;
1748 trap_t
*trap
, *found
= NULL
;
1750 this->mutex
->lock(this->mutex
);
1751 enumerator
= this->traps
->create_enumerator(this->traps
);
1752 while (enumerator
->enumerate(enumerator
, NULL
, &trap
))
1754 if (reqid
== trap
->reqid
&&
1756 src
->equals(src
, trap
->src
) &&
1757 dst
->equals(dst
, trap
->dst
))
1759 this->traps
->remove_at(this->traps
, enumerator
);
1764 enumerator
->destroy(enumerator
);
1765 this->mutex
->unlock(this->mutex
);
1771 trap
->route
= !manage_route(this, trap
->local
, trap
->remote
,
1774 uninstall_trap(this, found
);
1775 destroy_trap(found
);
1781 METHOD(kernel_ipsec_t
, get_features
, kernel_feature_t
,
1782 private_kernel_wfp_ipsec_t
*this)
1784 return KERNEL_ESP_V3_TFC
| KERNEL_NO_POLICY_UPDATES
;
1788 * Initialize seeds for SPI generation
1790 static bool init_spi(private_kernel_wfp_ipsec_t
*this)
1795 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_STRONG
);
1800 ok
= rng
->get_bytes(rng
, sizeof(this->nextspi
), (u_int8_t
*)&this->nextspi
);
1803 ok
= rng
->get_bytes(rng
, sizeof(this->mixspi
), (u_int8_t
*)&this->mixspi
);
1810 * Map an integer x with a one-to-one function using quadratic residues.
1812 static u_int
permute(u_int x
, u_int p
)
1817 qr
= ((u_int64_t
)x
* x
) % p
;
1825 METHOD(kernel_ipsec_t
, get_spi
, status_t
,
1826 private_kernel_wfp_ipsec_t
*this, host_t
*src
, host_t
*dst
,
1827 u_int8_t protocol
, u_int32_t reqid
, u_int32_t
*spi
)
1829 /* To avoid sequencial SPIs, we use a one-to-one permuation function on
1830 * an incrementing counter, that is a full period PRNG for the range we
1831 * allocate SPIs in. We add some randomness using a fixed XOR and start
1832 * the counter at random position. This is not cryptographically safe,
1833 * but that is actually not required.
1834 * The selected prime should be smaller than the range we allocate SPIs
1835 * in, and it must satisfy p % 4 == 3 to map x > p/2 using p - qr. */
1836 static const u_int p
= 268435399, offset
= 0xc0000000;
1838 *spi
= htonl(offset
+ permute(ref_get(&this->nextspi
) ^ this->mixspi
, p
));
1842 METHOD(kernel_ipsec_t
, get_cpi
, status_t
,
1843 private_kernel_wfp_ipsec_t
*this, host_t
*src
, host_t
*dst
,
1844 u_int32_t reqid
, u_int16_t
*cpi
)
1846 return NOT_SUPPORTED
;
1850 * Data for an expire callback job
1853 /* backref to kernel backend */
1854 private_kernel_wfp_ipsec_t
*this;
1855 /* SPI of expiring SA */
1857 /* destination address of expiring SA */
1859 /* is this a hard expire, or a rekey request? */
1864 * Clean up expire data
1866 static void expire_data_destroy(expire_data_t
*data
)
1868 data
->dst
->destroy(data
->dst
);
1873 * Callback job for SA expiration
1875 static job_requeue_t
expire_job(expire_data_t
*data
)
1877 private_kernel_wfp_ipsec_t
*this = data
->this;
1878 u_int32_t reqid
= 0;
1888 this->mutex
->lock(this->mutex
);
1889 entry
= this->isas
->remove(this->isas
, &key
);
1890 this->mutex
->unlock(this->mutex
);
1893 protocol
= entry
->isa
.protocol
;
1894 reqid
= entry
->reqid
;
1897 key
.dst
= entry
->osa
.dst
;
1898 key
.spi
= entry
->osa
.spi
;
1899 this->osas
->remove(this->osas
, &key
);
1901 entry_destroy(this, entry
);
1906 this->mutex
->lock(this->mutex
);
1907 entry
= this->isas
->get(this->isas
, &key
);
1910 protocol
= entry
->isa
.protocol
;
1911 reqid
= entry
->reqid
;
1913 this->mutex
->unlock(this->mutex
);
1918 hydra
->kernel_interface
->expire(hydra
->kernel_interface
,
1919 reqid
, protocol
, data
->spi
, data
->hard
);
1922 return JOB_REQUEUE_NONE
;
1926 * Schedule an expire event for an SA
1928 static void schedule_expire(private_kernel_wfp_ipsec_t
*this, u_int32_t spi
,
1929 host_t
*dst
, u_int32_t lifetime
, bool hard
)
1931 expire_data_t
*data
;
1936 .dst
= dst
->clone(dst
),
1940 lib
->scheduler
->schedule_job(lib
->scheduler
, (job_t
*)
1941 callback_job_create((void*)expire_job
, data
,
1942 (void*)expire_data_destroy
, NULL
),
1946 METHOD(kernel_ipsec_t
, add_sa
, status_t
,
1947 private_kernel_wfp_ipsec_t
*this, host_t
*src
, host_t
*dst
,
1948 u_int32_t spi
, u_int8_t protocol
, u_int32_t reqid
, mark_t mark
,
1949 u_int32_t tfc
, lifetime_cfg_t
*lifetime
, u_int16_t enc_alg
, chunk_t enc_key
,
1950 u_int16_t int_alg
, chunk_t int_key
, ipsec_mode_t mode
, u_int16_t ipcomp
,
1951 u_int16_t cpi
, bool initiator
, bool encap
, bool esn
, bool inbound
,
1952 traffic_selector_t
*src_ts
, traffic_selector_t
*dst_ts
)
1954 host_t
*local
, *remote
;
1959 /* comes first, create new entry */
1960 local
= dst
->clone(dst
);
1961 remote
= src
->clone(src
);
1968 .protocol
= protocol
,
1969 .lifetime
= lifetime
->time
.life
,
1972 .key
= chunk_clone(enc_key
),
1976 .key
= chunk_clone(int_key
),
1979 .sps
= array_create(0, 0),
1986 if (lifetime
->time
.life
)
1988 schedule_expire(this, spi
, local
, lifetime
->time
.life
, TRUE
);
1990 if (lifetime
->time
.rekey
&& lifetime
->time
.rekey
!= lifetime
->time
.life
)
1992 schedule_expire(this, spi
, local
, lifetime
->time
.rekey
, FALSE
);
1995 this->mutex
->lock(this->mutex
);
1996 this->tsas
->put(this->tsas
, (void*)(uintptr_t)reqid
, entry
);
1997 this->isas
->put(this->isas
, &entry
->isa
, entry
);
1998 this->mutex
->unlock(this->mutex
);
2002 /* comes after inbound, update entry */
2003 this->mutex
->lock(this->mutex
);
2004 entry
= this->tsas
->remove(this->tsas
, (void*)(uintptr_t)reqid
);
2005 this->mutex
->unlock(this->mutex
);
2009 DBG1(DBG_KNL
, "adding outbound SA failed, no inbound SA found "
2010 "for reqid %u ", reqid
);
2013 /* TODO: should we check for local/remote, mode etc.? */
2015 entry
->osa
= (sa_entry_t
){
2017 .dst
= entry
->remote
,
2018 .protocol
= protocol
,
2019 .lifetime
= lifetime
->time
.life
,
2022 .key
= chunk_clone(enc_key
),
2026 .key
= chunk_clone(int_key
),
2030 this->mutex
->lock(this->mutex
);
2031 this->osas
->put(this->osas
, &entry
->osa
, entry
);
2032 this->mutex
->unlock(this->mutex
);
2038 METHOD(kernel_ipsec_t
, update_sa
, status_t
,
2039 private_kernel_wfp_ipsec_t
*this, u_int32_t spi
, u_int8_t protocol
,
2040 u_int16_t cpi
, host_t
*src
, host_t
*dst
, host_t
*new_src
, host_t
*new_dst
,
2041 bool encap
, bool new_encap
, mark_t mark
)
2049 IPSEC_SA_CONTEXT1
*ctx
;
2050 IPSEC_V4_UDP_ENCAPSULATION0 ports
;
2051 UINT32 flags
= IPSEC_SA_DETAILS_UPDATE_TRAFFIC
;
2054 this->mutex
->lock(this->mutex
);
2055 entry
= this->osas
->get(this->osas
, &key
);
2056 this->mutex
->unlock(this->mutex
);
2060 /* outbound entry, nothing to do */
2064 this->mutex
->lock(this->mutex
);
2065 entry
= this->isas
->get(this->isas
, &key
);
2068 /* inbound entry, do update */
2069 sa_id
= entry
->sa_id
;
2070 ports
.localUdpEncapPort
= entry
->local
->get_port(entry
->local
);
2071 ports
.remoteUdpEncapPort
= entry
->remote
->get_port(entry
->remote
);
2073 this->mutex
->unlock(this->mutex
);
2080 res
= IPsecSaContextGetById1(this->handle
, sa_id
, &ctx
);
2081 if (res
!= ERROR_SUCCESS
)
2083 DBG1(DBG_KNL
, "getting WFP SA context for updated failed: 0x%08x", res
);
2086 if (!hosts2traffic(this, new_dst
, new_src
, &ctx
->inboundSa
->traffic
) ||
2087 !hosts2traffic(this, new_dst
, new_src
, &ctx
->outboundSa
->traffic
))
2089 FwpmFreeMemory0((void**)&ctx
);
2093 if (new_encap
!= encap
)
2097 ctx
->inboundSa
->udpEncapsulation
= &ports
;
2098 ctx
->outboundSa
->udpEncapsulation
= &ports
;
2102 ctx
->inboundSa
->udpEncapsulation
= NULL
;
2103 ctx
->outboundSa
->udpEncapsulation
= NULL
;
2105 flags
|= IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION
;
2108 res
= IPsecSaContextUpdate0(this->handle
, flags
, ctx
);
2109 FwpmFreeMemory0((void**)&ctx
);
2110 if (res
!= ERROR_SUCCESS
)
2112 DBG1(DBG_KNL
, "updating WFP SA context failed: 0x%08x", res
);
2116 this->mutex
->lock(this->mutex
);
2117 entry
= this->isas
->remove(this->isas
, &key
);
2120 key
.spi
= entry
->osa
.spi
;
2121 key
.dst
= entry
->osa
.dst
;
2122 this->osas
->remove(this->osas
, &key
);
2124 entry
->local
->destroy(entry
->local
);
2125 entry
->remote
->destroy(entry
->remote
);
2126 entry
->local
= new_dst
->clone(new_dst
);
2127 entry
->remote
= new_src
->clone(new_src
);
2128 entry
->isa
.dst
= entry
->local
;
2129 entry
->osa
.dst
= entry
->remote
;
2131 this->isas
->put(this->isas
, &entry
->isa
, entry
);
2132 this->osas
->put(this->osas
, &entry
->osa
, entry
);
2134 manage_routes(this, entry
, FALSE
);
2135 manage_routes(this, entry
, TRUE
);
2137 this->mutex
->unlock(this->mutex
);
2142 METHOD(kernel_ipsec_t
, query_sa
, status_t
,
2143 private_kernel_wfp_ipsec_t
*this, host_t
*src
, host_t
*dst
,
2144 u_int32_t spi
, u_int8_t protocol
, mark_t mark
, u_int64_t
*bytes
,
2145 u_int64_t
*packets
, time_t *time
)
2147 /* It does not seem that WFP provides any means of getting per-SA traffic
2148 * statistics. IPsecGetStatistics0/1() provides global stats, and
2149 * IPsecSaContextEnum0/1() and IPsecSaEnum0/1() return the configured
2151 return NOT_SUPPORTED
;
2154 METHOD(kernel_ipsec_t
, del_sa
, status_t
,
2155 private_kernel_wfp_ipsec_t
*this, host_t
*src
, host_t
*dst
,
2156 u_int32_t spi
, u_int8_t protocol
, u_int16_t cpi
, mark_t mark
)
2164 this->mutex
->lock(this->mutex
);
2165 entry
= this->isas
->remove(this->isas
, &key
);
2166 this->mutex
->unlock(this->mutex
);
2170 /* keep entry until removal of outbound */
2174 this->mutex
->lock(this->mutex
);
2175 entry
= this->osas
->remove(this->osas
, &key
);
2176 this->mutex
->unlock(this->mutex
);
2180 entry_destroy(this, entry
);
2187 METHOD(kernel_ipsec_t
, flush_sas
, status_t
,
2188 private_kernel_wfp_ipsec_t
*this)
2190 return NOT_SUPPORTED
;
2193 METHOD(kernel_ipsec_t
, add_policy
, status_t
,
2194 private_kernel_wfp_ipsec_t
*this, host_t
*src
, host_t
*dst
,
2195 traffic_selector_t
*src_ts
, traffic_selector_t
*dst_ts
,
2196 policy_dir_t direction
, policy_type_t type
, ipsec_sa_cfg_t
*sa
, mark_t mark
,
2197 policy_priority_t priority
)
2199 status_t status
= SUCCESS
;
2203 .spi
= sa
->esp
.use ? sa
->esp
.spi
: sa
->ah
.spi
,
2207 if (sa
->esp
.use
&& sa
->ah
.use
)
2209 return NOT_SUPPORTED
;
2218 return NOT_SUPPORTED
;
2230 return NOT_SUPPORTED
;
2235 case POLICY_PRIORITY_DEFAULT
:
2237 case POLICY_PRIORITY_ROUTED
:
2238 if (!add_trap(this, sa
->reqid
, FALSE
, src
, dst
, src_ts
, dst_ts
))
2242 if (sa
->mode
== MODE_TUNNEL
)
2244 if (!add_trap(this, sa
->reqid
, TRUE
, src
, dst
, src_ts
, dst_ts
))
2250 case POLICY_PRIORITY_FALLBACK
:
2252 return NOT_SUPPORTED
;
2255 this->mutex
->lock(this->mutex
);
2256 entry
= this->osas
->get(this->osas
, &key
);
2259 if (sa
->mode
== MODE_TUNNEL
|| array_count(entry
->sps
) == 0)
2262 .src
= src_ts
->clone(src_ts
),
2263 .dst
= dst_ts
->clone(dst_ts
),
2265 array_insert(entry
->sps
, -1, sp
);
2266 if (array_count(entry
->sps
) == sa
->policy_count
)
2268 if (!install(this, entry
))
2276 /* TODO: reinstall with a filter using multiple TS?
2277 * Filters are ANDed for a match, but we could install a filter
2278 * with the inverse TS set using NOT-matches... */
2279 DBG1(DBG_KNL
, "multiple transport mode traffic selectors not "
2280 "supported by WFP");
2281 status
= NOT_SUPPORTED
;
2286 DBG1(DBG_KNL
, "adding SP failed, no SA found for SPI 0x%08x", key
.spi
);
2289 this->mutex
->unlock(this->mutex
);
2294 METHOD(kernel_ipsec_t
, query_policy
, status_t
,
2295 private_kernel_wfp_ipsec_t
*this, traffic_selector_t
*src_ts
,
2296 traffic_selector_t
*dst_ts
, policy_dir_t direction
, mark_t mark
,
2299 /* see query_sa() for some notes */
2300 return NOT_SUPPORTED
;
2303 METHOD(kernel_ipsec_t
, del_policy
, status_t
,
2304 private_kernel_wfp_ipsec_t
*this, traffic_selector_t
*src_ts
,
2305 traffic_selector_t
*dst_ts
, policy_dir_t direction
, u_int32_t reqid
,
2306 mark_t mark
, policy_priority_t priority
)
2308 if (direction
== POLICY_OUT
&& priority
== POLICY_PRIORITY_ROUTED
)
2310 if (remove_trap(this, reqid
, FALSE
, src_ts
, dst_ts
))
2312 remove_trap(this, reqid
, TRUE
, src_ts
, dst_ts
);
2317 /* not required, as we delete the whole SA/SP set during del_sa() */
2321 METHOD(kernel_ipsec_t
, flush_policies
, status_t
,
2322 private_kernel_wfp_ipsec_t
*this)
2324 return NOT_SUPPORTED
;
2328 * Add a bypass policy for a specific UDP port
2330 static bool add_bypass(private_kernel_wfp_ipsec_t
*this,
2331 int family
, u_int16_t port
, bool inbound
, UINT64
*luid
)
2333 FWPM_FILTER_CONDITION0
*cond
, *conds
= NULL
;
2336 UINT64 weight
= 0xff00000000000000;
2337 FWPM_FILTER0 filter
= {
2339 .name
= L
"charon IKE bypass",
2342 .type
= FWP_ACTION_PERMIT
,
2353 filter
.layerKey
= inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V4
2354 : FWPM_LAYER_OUTBOUND_TRANSPORT_V4
;
2357 filter
.layerKey
= inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V6
2358 : FWPM_LAYER_OUTBOUND_TRANSPORT_V6
;
2364 cond
= append_condition(&conds
, &count
);
2365 cond
->fieldKey
= FWPM_CONDITION_IP_PROTOCOL
;
2366 cond
->matchType
= FWP_MATCH_EQUAL
;
2367 cond
->conditionValue
.type
= FWP_UINT8
;
2368 cond
->conditionValue
.uint8
= IPPROTO_UDP
;
2370 cond
= append_condition(&conds
, &count
);
2371 cond
->fieldKey
= FWPM_CONDITION_IP_LOCAL_PORT
;
2372 cond
->matchType
= FWP_MATCH_EQUAL
;
2373 cond
->conditionValue
.type
= FWP_UINT16
;
2374 cond
->conditionValue
.uint16
= port
;
2376 filter
.numFilterConditions
= count
;
2377 filter
.filterCondition
= conds
;
2379 res
= FwpmFilterAdd0(this->handle
, &filter
, NULL
, luid
);
2380 free_conditions(conds
, count
);
2381 if (res
!= ERROR_SUCCESS
)
2383 DBG1(DBG_KNL
, "installing WFP bypass filter failed: 0x%08x", res
);
2389 METHOD(kernel_ipsec_t
, bypass_socket
, bool,
2390 private_kernel_wfp_ipsec_t
*this, int fd
, int family
)
2397 int addrlen
= sizeof(saddr
);
2398 UINT64 filter_out
, filter_in
= 0;
2401 if (getsockname(fd
, &saddr
.sa
, &addrlen
) == SOCKET_ERROR
)
2408 port
= ntohs(saddr
.in
.sin_port
);
2411 port
= ntohs(saddr
.in6
.sin6_port
);
2417 if (!add_bypass(this, family
, port
, TRUE
, &filter_in
) ||
2418 !add_bypass(this, family
, port
, FALSE
, &filter_out
))
2422 FwpmFilterDeleteById0(this->handle
, filter_in
);
2427 this->mutex
->lock(this->mutex
);
2428 array_insert(this->bypass
, ARRAY_TAIL
, &filter_in
);
2429 array_insert(this->bypass
, ARRAY_TAIL
, &filter_out
);
2430 this->mutex
->unlock(this->mutex
);
2435 METHOD(kernel_ipsec_t
, enable_udp_decap
, bool,
2436 private_kernel_wfp_ipsec_t
*this, int fd
, int family
, u_int16_t port
)
2441 METHOD(kernel_ipsec_t
, destroy
, void,
2442 private_kernel_wfp_ipsec_t
*this)
2446 while (array_remove(this->bypass
, ARRAY_TAIL
, &filter
))
2448 FwpmFilterDeleteById0(this->handle
, filter
);
2454 FwpmNetEventUnsubscribe0(this->handle
, this->event
);
2456 FwpmProviderDeleteByKey0(this->handle
, &this->provider
.providerKey
);
2457 FwpmEngineClose0(this->handle
);
2459 array_destroy(this->bypass
);
2460 this->tsas
->destroy(this->tsas
);
2461 this->isas
->destroy(this->isas
);
2462 this->osas
->destroy(this->osas
);
2463 this->routes
->destroy(this->routes
);
2464 this->traps
->destroy(this->traps
);
2465 this->mutex
->destroy(this->mutex
);
2470 * Described in header.
2472 kernel_wfp_ipsec_t
*kernel_wfp_ipsec_create()
2474 private_kernel_wfp_ipsec_t
*this;
2476 FWPM_SESSION0 session
= {
2479 .description
= L
"strongSwan IKE kernel-wfp backend",
2486 .get_features
= _get_features
,
2487 .get_spi
= _get_spi
,
2488 .get_cpi
= _get_cpi
,
2490 .update_sa
= _update_sa
,
2491 .query_sa
= _query_sa
,
2493 .flush_sas
= _flush_sas
,
2494 .add_policy
= _add_policy
,
2495 .query_policy
= _query_policy
,
2496 .del_policy
= _del_policy
,
2497 .flush_policies
= _flush_policies
,
2498 .bypass_socket
= _bypass_socket
,
2499 .enable_udp_decap
= _enable_udp_decap
,
2500 .destroy
= _destroy
,
2506 .description
= L
"strongSwan IKE kernel-wfp backend",
2508 .providerKey
= { 0x59cdae2e, 0xf6bb, 0x4c09,
2509 { 0xa9,0x59,0x9d,0x91,0xac,0xaf,0xf9,0x19 }},
2511 .mutex
= mutex_create(MUTEX_TYPE_RECURSIVE
),
2512 .bypass
= array_create(sizeof(UINT64
), 2),
2513 .tsas
= hashtable_create(hashtable_hash_ptr
, hashtable_equals_ptr
, 4),
2514 .isas
= hashtable_create((void*)hash_sa
, (void*)equals_sa
, 4),
2515 .osas
= hashtable_create((void*)hash_sa
, (void*)equals_sa
, 4),
2516 .routes
= hashtable_create((void*)hash_route
, (void*)equals_route
, 4),
2517 .traps
= hashtable_create((void*)hash_trap
, (void*)equals_trap
, 4),
2520 if (!init_spi(this))
2526 res
= FwpmEngineOpen0(NULL
, RPC_C_AUTHN_WINNT
, NULL
, &session
,
2528 if (res
!= ERROR_SUCCESS
)
2530 DBG1(DBG_KNL
, "opening WFP engine failed: 0x%08x", res
);
2535 res
= FwpmProviderAdd0(this->handle
, &this->provider
, NULL
);
2536 if (res
!= ERROR_SUCCESS
&& res
!= FWP_E_ALREADY_EXISTS
)
2538 DBG1(DBG_KNL
, "registering WFP provider failed: 0x%08x", res
);
2543 if (!register_events(this))
2549 return &this->public;