f26b60a92ae6fc9eddacfdb3279f6aa335f7cfea
[strongswan.git] / src / libcharon / plugins / kernel_wfp / kernel_wfp_ipsec.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 /* Windows 7, for some fwpmu.h functionality */
17 #define _WIN32_WINNT 0x0601
18
19 #include "kernel_wfp_compat.h"
20 #include "kernel_wfp_ipsec.h"
21
22 #include <daemon.h>
23 #include <hydra.h>
24 #include <threading/mutex.h>
25 #include <collections/array.h>
26 #include <collections/hashtable.h>
27 #include <processing/jobs/callback_job.h>
28
29
30 typedef struct private_kernel_wfp_ipsec_t private_kernel_wfp_ipsec_t;
31
32 struct private_kernel_wfp_ipsec_t {
33
34 /**
35 * Public interface
36 */
37 kernel_wfp_ipsec_t public;
38
39 /**
40 * Next SPI to allocate
41 */
42 refcount_t nextspi;
43
44 /**
45 * Mix value to distribute SPI allocation randomly
46 */
47 u_int32_t mixspi;
48
49 /**
50 * Temporary SAD/SPD entries referenced reqid, as uintptr_t => entry_t
51 */
52 hashtable_t *tsas;
53
54 /**
55 * SAD/SPD entries referenced by inbound SA, as sa_entry_t => entry_t
56 */
57 hashtable_t *isas;
58
59 /**
60 * SAD/SPD entries referenced by outbound SA, as sa_entry_t => entry_t
61 */
62 hashtable_t *osas;
63
64 /**
65 * Installed routes, as route_t => route_t
66 */
67 hashtable_t *routes;
68
69 /**
70 * Mutex for accessing entries
71 */
72 mutex_t *mutex;
73
74 /**
75 * WFP session handle
76 */
77 HANDLE handle;
78
79 /**
80 * Provider charon registers as
81 */
82 FWPM_PROVIDER0 provider;
83 };
84
85 /**
86 * Security association entry
87 */
88 typedef struct {
89 /** SPI for this SA */
90 u_int32_t spi;
91 /** protocol, IPPROTO_ESP/IPPROTO_AH */
92 u_int8_t protocol;
93 /** hard lifetime of SA */
94 u_int32_t lifetime;
95 /** destination host address for this SPI */
96 host_t *dst;
97 struct {
98 /** algorithm */
99 u_int16_t alg;
100 /** key */
101 chunk_t key;
102 } integ, encr;
103 } sa_entry_t;
104
105 /**
106 * Hash function for sas lookup table
107 */
108 static u_int hash_sa(sa_entry_t *key)
109 {
110 return chunk_hash_inc(chunk_from_thing(key->spi),
111 chunk_hash(key->dst->get_address(key->dst)));
112 }
113
114 /**
115 * equals function for sas lookup table
116 */
117 static bool equals_sa(sa_entry_t *a, sa_entry_t *b)
118 {
119 return a->spi == b->spi && a->dst->ip_equals(a->dst, b->dst);
120 }
121
122 /**
123 * Security policy entry
124 */
125 typedef struct {
126 /** policy source addresses */
127 traffic_selector_t *src;
128 /** policy destinaiton addresses */
129 traffic_selector_t *dst;
130 } sp_entry_t;
131
132 /**
133 * Destroy an SP entry
134 */
135 static void sp_entry_destroy(sp_entry_t *sp)
136 {
137 sp->src->destroy(sp->src);
138 sp->dst->destroy(sp->dst);
139 free(sp);
140 }
141
142 /**
143 * Collection of SA/SP database entries for a reqid
144 */
145 typedef struct {
146 /** reqid of entry */
147 u_int32_t reqid;
148 /** outer address on local host */
149 host_t *local;
150 /** outer address on remote host */
151 host_t *remote;
152 /** inbound SA entry */
153 sa_entry_t isa;
154 /** outbound SA entry */
155 sa_entry_t osa;
156 /** associated (outbound) policies, as sp_entry_t* */
157 array_t *sps;
158 /** IPsec mode, tunnel|transport */
159 ipsec_mode_t mode;
160 /** UDP encapsulation */
161 bool encap;
162 /** WFP allocated LUID for inbound filter/tunnel policy ID */
163 u_int64_t policy_in;
164 /** WFP allocated LUID for outbound filter ID, unused for tunnel mode */
165 u_int64_t policy_out;
166 /** WFP allocated LUID for SA context */
167 u_int64_t sa_id;
168 } entry_t;
169
170 /**
171 * Installed route
172 */
173 typedef struct {
174 /** destination net of route */
175 host_t *dst;
176 /** prefix length of dst */
177 u_int8_t mask;
178 /** source address for route */
179 host_t *src;
180 /** gateway of route, NULL if directly attached */
181 host_t *gtw;
182 /** references for route */
183 u_int refs;
184 } route_t;
185
186 /**
187 * Destroy a route_t
188 */
189 static void destroy_route(route_t *this)
190 {
191 this->dst->destroy(this->dst);
192 this->src->destroy(this->src);
193 DESTROY_IF(this->gtw);
194 free(this);
195 }
196
197 /**
198 * Hashtable equals function for routes
199 */
200 static bool equals_route(route_t *a, route_t *b)
201 {
202 return a->mask == b->mask &&
203 a->dst->ip_equals(a->dst, b->dst) &&
204 a->src->ip_equals(a->src, b->src);
205 }
206
207 /**
208 * Hashtable hash function for routes
209 */
210 static u_int hash_route(route_t *route)
211 {
212 return chunk_hash_inc(route->src->get_address(route->src),
213 chunk_hash_inc(route->dst->get_address(route->dst), route->mask));
214 }
215
216 /** forward declaration */
217 static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry,
218 bool add);
219
220 /**
221 * Remove a transport or tunnel policy from kernel
222 */
223 static void cleanup_policy(private_kernel_wfp_ipsec_t *this, bool transport,
224 u_int64_t policy)
225 {
226 if (transport)
227 {
228 FwpmFilterDeleteById0(this->handle, policy);
229 }
230 else
231 {
232 FWPM_PROVIDER_CONTEXT0 *ctx;
233
234 if (FwpmProviderContextGetById0(this->handle, policy,
235 &ctx) == ERROR_SUCCESS)
236 {
237 FwpmIPsecTunnelDeleteByKey0(this->handle, &ctx->providerContextKey);
238 FwpmFreeMemory0((void**)&ctx);
239 }
240 }
241 }
242
243 /**
244 * Remove policies associated to an entry from kernel
245 */
246 static void cleanup_policies(private_kernel_wfp_ipsec_t *this, entry_t *entry)
247 {
248 if (entry->policy_in)
249 {
250 cleanup_policy(this, entry->mode == MODE_TRANSPORT, entry->policy_in);
251 entry->policy_in = 0;
252 }
253 if (entry->policy_out)
254 {
255 cleanup_policy(this, entry->mode == MODE_TRANSPORT, entry->policy_out);
256 entry->policy_out = 0;
257 }
258 if (entry->mode == MODE_TUNNEL)
259 {
260 manage_routes(this, entry, FALSE);
261 }
262 }
263
264 /**
265 * Destroy a SA/SP entry set
266 */
267 static void entry_destroy(private_kernel_wfp_ipsec_t *this, entry_t *entry)
268 {
269 if (entry->sa_id)
270 {
271 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
272 }
273 cleanup_policies(this, entry);
274 array_destroy_function(entry->sps, (void*)sp_entry_destroy, NULL);
275 entry->local->destroy(entry->local);
276 entry->remote->destroy(entry->remote);
277 chunk_clear(&entry->isa.integ.key);
278 chunk_clear(&entry->isa.encr.key);
279 chunk_clear(&entry->osa.integ.key);
280 chunk_clear(&entry->osa.encr.key);
281 free(entry);
282 }
283
284 /**
285 * Append/Realloc a filter condition to an existing condition set
286 */
287 static FWPM_FILTER_CONDITION0 *append_condition(FWPM_FILTER_CONDITION0 *conds[],
288 int *count)
289 {
290 FWPM_FILTER_CONDITION0 *cond;
291
292 (*count)++;
293 *conds = realloc(*conds, *count * sizeof(*cond));
294 cond = *conds + *count - 1;
295 memset(cond, 0, sizeof(*cond));
296
297 return cond;
298 }
299
300 /**
301 * Convert an IPv4 prefix to a host order subnet mask
302 */
303 static u_int32_t prefix2mask(u_int8_t prefix)
304 {
305 u_int8_t netmask[4] = {};
306 int i;
307
308 for (i = 0; i < sizeof(netmask); i++)
309 {
310 if (prefix < 8)
311 {
312 netmask[i] = 0xFF << (8 - prefix);
313 break;
314 }
315 netmask[i] = 0xFF;
316 prefix -= 8;
317 }
318 return untoh32(netmask);
319 }
320
321 /**
322 * Convert a 16-bit range to a WFP condition
323 */
324 static void range2cond(FWPM_FILTER_CONDITION0 *cond,
325 u_int16_t from, u_int16_t to)
326 {
327 if (from == to)
328 {
329 cond->matchType = FWP_MATCH_EQUAL;
330 cond->conditionValue.type = FWP_UINT16;
331 cond->conditionValue.uint16 = from;
332 }
333 else
334 {
335 cond->matchType = FWP_MATCH_RANGE;
336 cond->conditionValue.type = FWP_RANGE_TYPE;
337 cond->conditionValue.rangeValue = calloc(1, sizeof(FWP_RANGE0));
338 cond->conditionValue.rangeValue->valueLow.type = FWP_UINT16;
339 cond->conditionValue.rangeValue->valueLow.uint16 = from;
340 cond->conditionValue.rangeValue->valueHigh.type = FWP_UINT16;
341 cond->conditionValue.rangeValue->valueHigh.uint16 = to;
342 }
343 }
344
345 /**
346 * (Re-)allocate filter conditions for given local or remote traffic selector
347 */
348 static bool ts2condition(traffic_selector_t *ts, bool local,
349 FWPM_FILTER_CONDITION0 *conds[], int *count)
350 {
351 FWPM_FILTER_CONDITION0 *cond;
352 FWP_BYTE_ARRAY16 *addr;
353 FWP_RANGE0 *range;
354 u_int16_t from_port, to_port;
355 void *from, *to;
356 u_int8_t proto;
357 host_t *net;
358 u_int8_t prefix;
359
360 from = ts->get_from_address(ts).ptr;
361 to = ts->get_to_address(ts).ptr;
362 from_port = ts->get_from_port(ts);
363 to_port = ts->get_to_port(ts);
364
365 cond = append_condition(conds, count);
366 if (local)
367 {
368 cond->fieldKey = FWPM_CONDITION_IP_LOCAL_ADDRESS;
369 }
370 else
371 {
372 cond->fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS;
373 }
374 if (ts->is_host(ts, NULL))
375 {
376 cond->matchType = FWP_MATCH_EQUAL;
377 switch (ts->get_type(ts))
378 {
379 case TS_IPV4_ADDR_RANGE:
380 cond->conditionValue.type = FWP_UINT32;
381 cond->conditionValue.uint32 = untoh32(from);
382 break;
383 case TS_IPV6_ADDR_RANGE:
384 cond->conditionValue.type = FWP_BYTE_ARRAY16_TYPE;
385 cond->conditionValue.byteArray16 = addr = malloc(sizeof(*addr));
386 memcpy(addr, from, sizeof(*addr));
387 break;
388 default:
389 return FALSE;
390 }
391 }
392 else if (ts->to_subnet(ts, &net, &prefix))
393 {
394 FWP_V6_ADDR_AND_MASK *m6;
395 FWP_V4_ADDR_AND_MASK *m4;
396
397 cond->matchType = FWP_MATCH_EQUAL;
398 switch (net->get_family(net))
399 {
400 case AF_INET:
401 cond->conditionValue.type = FWP_V4_ADDR_MASK;
402 cond->conditionValue.v4AddrMask = m4 = calloc(1, sizeof(*m4));
403 m4->addr = untoh32(from);
404 m4->mask = prefix2mask(prefix);
405 break;
406 case AF_INET6:
407 cond->conditionValue.type = FWP_V6_ADDR_MASK;
408 cond->conditionValue.v6AddrMask = m6 = calloc(1, sizeof(*m6));
409 memcpy(m6->addr, from, sizeof(m6->addr));
410 m6->prefixLength = prefix;
411 break;
412 default:
413 net->destroy(net);
414 return FALSE;
415 }
416 net->destroy(net);
417 }
418 else
419 {
420 cond->matchType = FWP_MATCH_RANGE;
421 cond->conditionValue.type = FWP_RANGE_TYPE;
422 cond->conditionValue.rangeValue = range = calloc(1, sizeof(*range));
423 switch (ts->get_type(ts))
424 {
425 case TS_IPV4_ADDR_RANGE:
426 range->valueLow.type = FWP_UINT32;
427 range->valueLow.uint32 = untoh32(from);
428 range->valueHigh.type = FWP_UINT32;
429 range->valueHigh.uint32 = untoh32(to);
430 break;
431 case TS_IPV6_ADDR_RANGE:
432 range->valueLow.type = FWP_BYTE_ARRAY16_TYPE;
433 range->valueLow.byteArray16 = addr = malloc(sizeof(*addr));
434 memcpy(addr, from, sizeof(*addr));
435 range->valueHigh.type = FWP_BYTE_ARRAY16_TYPE;
436 range->valueHigh.byteArray16 = addr = malloc(sizeof(*addr));
437 memcpy(addr, to, sizeof(*addr));
438 break;
439 default:
440 return FALSE;
441 }
442 }
443
444 proto = ts->get_protocol(ts);
445 if (proto && local)
446 {
447 cond = append_condition(conds, count);
448 cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL;
449 cond->matchType = FWP_MATCH_EQUAL;
450 cond->conditionValue.type = FWP_UINT8;
451 cond->conditionValue.uint8 = proto;
452 }
453
454 if (proto == IPPROTO_ICMP)
455 {
456 if (local)
457 {
458 u_int8_t from_type, to_type, from_code, to_code;
459
460 from_type = traffic_selector_icmp_type(from_port);
461 to_type = traffic_selector_icmp_type(to_port);
462 from_code = traffic_selector_icmp_code(from_port);
463 to_code = traffic_selector_icmp_code(to_port);
464
465 if (from_type != 0 || to_type != 0xFF)
466 {
467 cond = append_condition(conds, count);
468 cond->fieldKey = FWPM_CONDITION_ICMP_TYPE;
469 range2cond(cond, from_type, to_type);
470 }
471 if (from_code != 0 || to_code != 0xFF)
472 {
473 cond = append_condition(conds, count);
474 cond->fieldKey = FWPM_CONDITION_ICMP_CODE;
475 range2cond(cond, from_code, to_code);
476 }
477 }
478 }
479 else if (from_port != 0 || to_port != 0xFFFF)
480 {
481 cond = append_condition(conds, count);
482 if (local)
483 {
484 cond->fieldKey = FWPM_CONDITION_IP_LOCAL_PORT;
485 }
486 else
487 {
488 cond->fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
489 }
490 range2cond(cond, from_port, to_port);
491 }
492 return TRUE;
493 }
494
495 /**
496 * Free memory associated to a single condition
497 */
498 static void free_condition(FWP_DATA_TYPE type, void *value)
499 {
500 FWP_RANGE0 *range;
501
502 switch (type)
503 {
504 case FWP_BYTE_ARRAY16_TYPE:
505 case FWP_V4_ADDR_MASK:
506 case FWP_V6_ADDR_MASK:
507 free(value);
508 break;
509 case FWP_RANGE_TYPE:
510 range = value;
511 free_condition(range->valueLow.type, range->valueLow.sd);
512 free_condition(range->valueHigh.type, range->valueHigh.sd);
513 free(range);
514 break;
515 default:
516 break;
517 }
518 }
519
520 /**
521 * Free memory used by a set of conditions
522 */
523 static void free_conditions(FWPM_FILTER_CONDITION0 *conds, int count)
524 {
525 int i;
526
527 for (i = 0; i < count; i++)
528 {
529 free_condition(conds[i].conditionValue.type, conds[i].conditionValue.sd);
530 }
531 free(conds);
532 }
533
534 /**
535 * Install transport mode SP to the kernel
536 */
537 static bool install_transport_sp(private_kernel_wfp_ipsec_t *this,
538 entry_t *entry, bool inbound)
539 {
540 FWPM_FILTER_CONDITION0 *conds = NULL;
541 int count = 0;
542 enumerator_t *enumerator;
543 traffic_selector_t *local, *remote;
544 sp_entry_t *sp;
545 DWORD res;
546 FWPM_FILTER0 filter = {
547 .displayData = {
548 .name = L"charon IPsec transport",
549 },
550 .action = {
551 .type = FWP_ACTION_CALLOUT_TERMINATING,
552 .calloutKey = inbound ? FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 :
553 FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4,
554 },
555 .layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V4 :
556 FWPM_LAYER_OUTBOUND_TRANSPORT_V4,
557 };
558
559 enumerator = array_create_enumerator(entry->sps);
560 while (enumerator->enumerate(enumerator, &sp))
561 {
562 if (inbound)
563 {
564 local = sp->dst;
565 remote = sp->src;
566 }
567 else
568 {
569 local = sp->src;
570 remote = sp->dst;
571 }
572
573 if (!ts2condition(local, TRUE, &conds, &count) ||
574 !ts2condition(remote, FALSE, &conds, &count))
575 {
576 free_conditions(conds, count);
577 enumerator->destroy(enumerator);
578 return FALSE;
579 }
580 }
581 enumerator->destroy(enumerator);
582
583 filter.numFilterConditions = count;
584 filter.filterCondition = conds;
585
586 if (inbound)
587 {
588 res = FwpmFilterAdd0(this->handle, &filter, NULL, &entry->policy_in);
589 }
590 else
591 {
592 res = FwpmFilterAdd0(this->handle, &filter, NULL, &entry->policy_out);
593 }
594 free_conditions(conds, count);
595 if (res != ERROR_SUCCESS)
596 {
597 DBG1(DBG_KNL, "installing inbound FWP filter failed: 0x%08x", res);
598 return FALSE;
599 }
600 return TRUE;
601 }
602
603 /**
604 * Convert a chunk_t to a WFP FWP_BYTE_BLOB
605 */
606 static inline FWP_BYTE_BLOB chunk2blob(chunk_t chunk)
607 {
608 return (FWP_BYTE_BLOB){
609 .size = chunk.len,
610 .data = chunk.ptr,
611 };
612 }
613
614 /**
615 * Convert an integrity_algorithm_t to a WFP IPSEC_AUTH_TRANFORM_ID0
616 */
617 static bool alg2auth(integrity_algorithm_t alg,
618 IPSEC_SA_AUTH_INFORMATION0 *info)
619 {
620 struct {
621 integrity_algorithm_t alg;
622 IPSEC_AUTH_TRANSFORM_ID0 transform;
623 } map[] = {
624 { AUTH_HMAC_MD5_96, IPSEC_AUTH_TRANSFORM_ID_HMAC_MD5_96 },
625 { AUTH_HMAC_SHA1_96, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96 },
626 { AUTH_HMAC_SHA2_256_128, IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_256_128},
627 { AUTH_AES_128_GMAC, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_128 },
628 { AUTH_AES_192_GMAC, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_192 },
629 { AUTH_AES_256_GMAC, IPSEC_AUTH_TRANSFORM_ID_GCM_AES_256 },
630 };
631 int i;
632
633 for (i = 0; i < countof(map); i++)
634 {
635 if (map[i].alg == alg)
636 {
637 info->authTransform.authTransformId = map[i].transform;
638 return TRUE;
639 }
640 }
641 return FALSE;
642 }
643
644 /**
645 * Convert an encryption_algorithm_t to a WFP IPSEC_CIPHER_TRANFORM_ID0
646 */
647 static bool alg2cipher(encryption_algorithm_t alg, int keylen,
648 IPSEC_SA_CIPHER_INFORMATION0 *info)
649 {
650 struct {
651 encryption_algorithm_t alg;
652 int keylen;
653 IPSEC_CIPHER_TRANSFORM_ID0 transform;
654 } map[] = {
655 { ENCR_DES, 8, IPSEC_CIPHER_TRANSFORM_ID_CBC_DES },
656 { ENCR_3DES, 24, IPSEC_CIPHER_TRANSFORM_ID_CBC_3DES },
657 { ENCR_AES_CBC, 16, IPSEC_CIPHER_TRANSFORM_ID_AES_128 },
658 { ENCR_AES_CBC, 24, IPSEC_CIPHER_TRANSFORM_ID_AES_192 },
659 { ENCR_AES_CBC, 32, IPSEC_CIPHER_TRANSFORM_ID_AES_256 },
660 { ENCR_AES_GCM_ICV16, 20, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_128 },
661 { ENCR_AES_GCM_ICV16, 28, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_192 },
662 { ENCR_AES_GCM_ICV16, 36, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_256 },
663 };
664 int i;
665
666 for (i = 0; i < countof(map); i++)
667 {
668 if (map[i].alg == alg && map[i].keylen == keylen)
669 {
670 info->cipherTransform.cipherTransformId = map[i].transform;
671 return TRUE;
672 }
673 }
674 return FALSE;
675 }
676
677 /**
678 * Get the integrity algorithm used for an AEAD transform
679 */
680 static integrity_algorithm_t encr2integ(encryption_algorithm_t encr, int keylen)
681 {
682 struct {
683 encryption_algorithm_t encr;
684 int keylen;
685 integrity_algorithm_t integ;
686 } map[] = {
687 { ENCR_NULL_AUTH_AES_GMAC, 20, AUTH_AES_128_GMAC },
688 { ENCR_NULL_AUTH_AES_GMAC, 28, AUTH_AES_192_GMAC },
689 { ENCR_NULL_AUTH_AES_GMAC, 36, AUTH_AES_256_GMAC },
690 { ENCR_AES_GCM_ICV16, 20, AUTH_AES_128_GMAC },
691 { ENCR_AES_GCM_ICV16, 28, AUTH_AES_192_GMAC },
692 { ENCR_AES_GCM_ICV16, 36, AUTH_AES_256_GMAC },
693 };
694 int i;
695
696 for (i = 0; i < countof(map); i++)
697 {
698 if (map[i].encr == encr && map[i].keylen == keylen)
699 {
700 return map[i].integ;
701 }
702 }
703 return AUTH_UNDEFINED;
704 }
705
706 /**
707 * Install a single SA
708 */
709 static bool install_sa(private_kernel_wfp_ipsec_t *this, entry_t *entry,
710 bool inbound, sa_entry_t *sa, FWP_IP_VERSION version)
711 {
712 IPSEC_SA_AUTH_AND_CIPHER_INFORMATION0 info = {};
713 IPSEC_SA0 ipsec = {
714 .spi = ntohl(sa->spi),
715 };
716 IPSEC_SA_BUNDLE0 bundle = {
717 .lifetime = {
718 .lifetimeSeconds = inbound ? entry->isa.lifetime
719 : entry->osa.lifetime,
720 },
721 .saList = &ipsec,
722 .numSAs = 1,
723 .ipVersion = version,
724 };
725 struct {
726 u_int16_t alg;
727 chunk_t key;
728 } integ = {}, encr = {};
729 DWORD res;
730
731 switch (sa->protocol)
732 {
733 case IPPROTO_AH:
734 ipsec.saTransformType = IPSEC_TRANSFORM_AH;
735 ipsec.ahInformation = &info.saAuthInformation;
736 integ.key = sa->integ.key;
737 integ.alg = sa->integ.alg;
738 break;
739 case IPPROTO_ESP:
740 if (sa->encr.alg == ENCR_NULL ||
741 sa->encr.alg == ENCR_NULL_AUTH_AES_GMAC)
742 {
743 ipsec.saTransformType = IPSEC_TRANSFORM_ESP_AUTH;
744 ipsec.espAuthInformation = &info.saAuthInformation;
745 }
746 else
747 {
748 ipsec.saTransformType = IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER;
749 ipsec.espAuthAndCipherInformation = &info;
750 encr.key = sa->encr.key;
751 encr.alg = sa->encr.alg;
752 }
753 if (encryption_algorithm_is_aead(sa->encr.alg))
754 {
755 integ.alg = encr2integ(sa->encr.alg, sa->encr.key.len);
756 integ.key = sa->encr.key;
757 }
758 else
759 {
760 integ.alg = sa->integ.alg;
761 integ.key = sa->integ.key;
762 }
763 break;
764 default:
765 return FALSE;
766 }
767
768 if (integ.alg)
769 {
770 info.saAuthInformation.authKey = chunk2blob(integ.key);
771 if (!alg2auth(integ.alg, &info.saAuthInformation))
772 {
773 DBG1(DBG_KNL, "integrity algorithm %N not supported by WFP",
774 integrity_algorithm_names, integ.alg);
775 return FALSE;
776 }
777 }
778 if (encr.alg)
779 {
780 info.saCipherInformation.cipherKey = chunk2blob(encr.key);
781 if (!alg2cipher(encr.alg, encr.key.len, &info.saCipherInformation))
782 {
783 DBG1(DBG_KNL, "encryption algorithm %N not supported by WFP",
784 encryption_algorithm_names, encr.alg);
785 return FALSE;
786 }
787 }
788
789 if (inbound)
790 {
791 res = IPsecSaContextAddInbound0(this->handle, entry->sa_id, &bundle);
792 }
793 else
794 {
795 res = IPsecSaContextAddOutbound0(this->handle, entry->sa_id, &bundle);
796 }
797 if (res != ERROR_SUCCESS)
798 {
799 DBG1(DBG_KNL, "adding %sbound WFP SA failed: 0x%08x",
800 inbound ? "in" : "out", res);
801 return FALSE;
802 }
803 return TRUE;
804 }
805
806 /**
807 * Fill in traffic structure from entry addresses
808 */
809 static bool hosts2traffic(private_kernel_wfp_ipsec_t *this,
810 host_t *l, host_t *r, IPSEC_TRAFFIC1 *traffic)
811 {
812 if (l->get_family(l) != r->get_family(r))
813 {
814 return FALSE;
815 }
816 switch (l->get_family(l))
817 {
818 case AF_INET:
819 traffic->ipVersion = FWP_IP_VERSION_V4;
820 traffic->localV4Address = untoh32(l->get_address(l).ptr);
821 traffic->remoteV4Address = untoh32(r->get_address(r).ptr);
822 return TRUE;
823 case AF_INET6:
824 traffic->ipVersion = FWP_IP_VERSION_V6;
825 memcpy(&traffic->localV6Address, l->get_address(l).ptr, 16);
826 memcpy(&traffic->remoteV6Address, r->get_address(r).ptr, 16);
827 return TRUE;
828 default:
829 return FALSE;
830 }
831 }
832
833 /**
834 * Install SAs to the kernel
835 */
836 static bool install_sas(private_kernel_wfp_ipsec_t *this, entry_t *entry,
837 IPSEC_TRAFFIC_TYPE type)
838 {
839 IPSEC_TRAFFIC1 traffic = {
840 .trafficType = type,
841 };
842 IPSEC_GETSPI1 spi = {
843 .inboundIpsecTraffic = {
844 .trafficType = type,
845 },
846 };
847 DWORD res;
848
849 if (type == IPSEC_TRAFFIC_TYPE_TRANSPORT)
850 {
851 traffic.ipsecFilterId = entry->policy_out;
852 spi.inboundIpsecTraffic.ipsecFilterId = entry->policy_in;
853 }
854 else
855 {
856 traffic.tunnelPolicyId = entry->policy_in;
857 spi.inboundIpsecTraffic.tunnelPolicyId = entry->policy_in;
858 }
859
860 if (!hosts2traffic(this, entry->local, entry->remote, &traffic))
861 {
862 return FALSE;
863 }
864
865 res = IPsecSaContextCreate1(this->handle, &traffic, NULL, NULL,
866 &entry->sa_id);
867 if (res != ERROR_SUCCESS)
868 {
869 DBG1(DBG_KNL, "creating WFP SA context failed: 0x%08x", res);
870 return FALSE;
871 }
872
873 memcpy(spi.inboundIpsecTraffic.localV6Address, traffic.localV6Address,
874 sizeof(traffic.localV6Address));
875 memcpy(spi.inboundIpsecTraffic.remoteV6Address, traffic.remoteV6Address,
876 sizeof(traffic.remoteV6Address));
877 spi.ipVersion = traffic.ipVersion;
878
879 res = IPsecSaContextSetSpi0(this->handle, entry->sa_id, &spi,
880 ntohl(entry->isa.spi));
881 if (res != ERROR_SUCCESS)
882 {
883 DBG1(DBG_KNL, "setting WFP SA SPI failed: 0x%08x", res);
884 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
885 entry->sa_id = 0;
886 return FALSE;
887 }
888
889 if (!install_sa(this, entry, TRUE, &entry->isa, spi.ipVersion) ||
890 !install_sa(this, entry, FALSE, &entry->osa, spi.ipVersion))
891 {
892 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
893 entry->sa_id = 0;
894 return FALSE;
895 }
896
897 if (entry->encap)
898 {
899 IPSEC_V4_UDP_ENCAPSULATION0 encap = {
900 .localUdpEncapPort = entry->local->get_port(entry->local),
901 .remoteUdpEncapPort = entry->remote->get_port(entry->remote),
902 };
903 IPSEC_SA_CONTEXT1 *ctx;
904
905 res = IPsecSaContextGetById1(this->handle, entry->sa_id, &ctx);
906 if (res != ERROR_SUCCESS)
907 {
908 DBG1(DBG_KNL, "getting WFP SA for UDP encap failed: 0x%08x", res);
909 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
910 entry->sa_id = 0;
911 return FALSE;
912 }
913 ctx->inboundSa->udpEncapsulation = &encap;
914 ctx->outboundSa->udpEncapsulation = &encap;
915
916 res = IPsecSaContextUpdate0(this->handle,
917 IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION, ctx);
918 FwpmFreeMemory0((void**)&ctx);
919 if (res != ERROR_SUCCESS)
920 {
921 DBG1(DBG_KNL, "enable WFP UDP encap failed: 0x%08x", res);
922 IPsecSaContextDeleteById0(this->handle, entry->sa_id);
923 entry->sa_id = 0;
924 return FALSE;
925 }
926 }
927
928 return TRUE;
929 }
930
931 /**
932 * Install a transport mode SA/SP set to the kernel
933 */
934 static bool install_transport(private_kernel_wfp_ipsec_t *this, entry_t *entry)
935 {
936 if (install_transport_sp(this, entry, TRUE) &&
937 install_transport_sp(this, entry, FALSE) &&
938 install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TRANSPORT))
939 {
940 return TRUE;
941 }
942 cleanup_policies(this, entry);
943 return FALSE;
944 }
945
946 /**
947 * Generate a new GUID, random
948 */
949 static bool generate_guid(private_kernel_wfp_ipsec_t *this, GUID *guid)
950 {
951 bool ok;
952 rng_t *rng;
953
954 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
955 if (!rng)
956 {
957 return FALSE;
958 }
959 ok = rng->get_bytes(rng, sizeof(GUID), (u_int8_t*)guid);
960 rng->destroy(rng);
961 return ok;
962 }
963
964 /**
965 * Install tunnel mode SPs to the kernel
966 */
967 static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry)
968 {
969 FWPM_FILTER_CONDITION0 *conds = NULL;
970 int count = 0;
971 enumerator_t *enumerator;
972 sp_entry_t *sp;
973 DWORD res;
974
975 IPSEC_AUTH_TRANSFORM0 transform = {
976 /* Create any valid proposal. This is actually not used, as we
977 * don't create an SA from this information. */
978 .authTransformId = IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96,
979 };
980 IPSEC_SA_TRANSFORM0 transforms = {
981 .ipsecTransformType = IPSEC_TRANSFORM_ESP_AUTH,
982 .espAuthTransform = &transform,
983 };
984 IPSEC_PROPOSAL0 proposal = {
985 .lifetime = {
986 /* We need a valid lifetime, even if we don't create any SA
987 * from these values. Pick some values accepted. */
988 .lifetimeSeconds = 0xFFFF,
989 .lifetimeKilobytes = 0xFFFFFFFF,
990 .lifetimePackets = 0xFFFFFFFF,
991 },
992 .numSaTransforms = 1,
993 .saTransforms = &transforms,
994 };
995 IPSEC_TUNNEL_POLICY0 policy = {
996 .numIpsecProposals = 1,
997 .ipsecProposals = &proposal,
998 .saIdleTimeout = {
999 /* not used, set to lifetime for maximum */
1000 .idleTimeoutSeconds = proposal.lifetime.lifetimeSeconds,
1001 .idleTimeoutSecondsFailOver = proposal.lifetime.lifetimeSeconds,
1002 },
1003 };
1004 FWPM_PROVIDER_CONTEXT0 *ctx, qm = {
1005 .displayData = {
1006 .name = L"charon tunnel provider context",
1007 },
1008 .providerKey = (GUID*)&this->provider.providerKey,
1009 .type = FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT,
1010 .ikeQmTunnelPolicy = &policy,
1011 };
1012
1013 switch (entry->local->get_family(entry->local))
1014 {
1015 case AF_INET:
1016 policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V4;
1017 policy.tunnelEndpoints.localV4Address =
1018 untoh32(entry->local->get_address(entry->local).ptr);
1019 policy.tunnelEndpoints.remoteV4Address =
1020 untoh32(entry->remote->get_address(entry->remote).ptr);
1021 break;
1022 case AF_INET6:
1023 policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V6;
1024 memcpy(&policy.tunnelEndpoints.localV6Address,
1025 entry->local->get_address(entry->local).ptr, 16);
1026 memcpy(&policy.tunnelEndpoints.remoteV6Address,
1027 entry->remote->get_address(entry->remote).ptr, 16);
1028 break;
1029 default:
1030 return FALSE;
1031 }
1032
1033 if (!generate_guid(this, &qm.providerContextKey))
1034 {
1035 return FALSE;
1036 }
1037
1038 enumerator = array_create_enumerator(entry->sps);
1039 while (enumerator->enumerate(enumerator, &sp))
1040 {
1041 if (!ts2condition(sp->src, TRUE, &conds, &count) ||
1042 !ts2condition(sp->dst, FALSE, &conds, &count))
1043 {
1044 free_conditions(conds, count);
1045 enumerator->destroy(enumerator);
1046 return FALSE;
1047 }
1048 }
1049 enumerator->destroy(enumerator);
1050
1051 res = FwpmIPsecTunnelAdd0(this->handle, 0, NULL, &qm, count, conds, NULL);
1052 free_conditions(conds, count);
1053 if (res != ERROR_SUCCESS)
1054 {
1055 DBG1(DBG_KNL, "installing FWP tunnel policy failed: 0x%08x", res);
1056 return FALSE;
1057 }
1058
1059 /* to get the tunnelPolicyId LUID we have to query the context */
1060 res = FwpmProviderContextGetByKey0(this->handle, &qm.providerContextKey,
1061 &ctx);
1062 if (res != ERROR_SUCCESS)
1063 {
1064 DBG1(DBG_KNL, "getting FWP tunnel policy context failed: 0x%08x", res);
1065 return FALSE;
1066 }
1067 entry->policy_in = ctx->providerContextId;
1068 FwpmFreeMemory0((void**)&ctx);
1069
1070 return TRUE;
1071 }
1072
1073 /**
1074 * Reduce refcount, or uninstall a route if all refs gone
1075 */
1076 static bool uninstall_route(private_kernel_wfp_ipsec_t *this,
1077 host_t *dst, u_int8_t mask, host_t *src, host_t *gtw)
1078 {
1079 route_t *route, key = {
1080 .dst = dst,
1081 .mask = mask,
1082 .src = src,
1083 };
1084 char *name;
1085 bool res = FALSE;
1086
1087 this->mutex->lock(this->mutex);
1088 route = this->routes->get(this->routes, &key);
1089 if (route)
1090 {
1091 if (--route->refs == 0)
1092 {
1093 if (hydra->kernel_interface->get_interface(hydra->kernel_interface,
1094 src, &name))
1095 {
1096 res = hydra->kernel_interface->del_route(hydra->kernel_interface,
1097 dst->get_address(dst), mask, gtw, src, name) == SUCCESS;
1098 free(name);
1099 }
1100 route = this->routes->remove(this->routes, route);
1101 if (route)
1102 {
1103 destroy_route(route);
1104 }
1105 }
1106 else
1107 {
1108 res = TRUE;
1109 }
1110 }
1111 this->mutex->unlock(this->mutex);
1112
1113 return res;
1114 }
1115
1116 /**
1117 * Install a single route, or refcount if exists
1118 */
1119 static bool install_route(private_kernel_wfp_ipsec_t *this,
1120 host_t *dst, u_int8_t mask, host_t *src, host_t *gtw)
1121 {
1122 route_t *route, key = {
1123 .dst = dst,
1124 .mask = mask,
1125 .src = src,
1126 };
1127 char *name;
1128 bool res = FALSE;
1129
1130 this->mutex->lock(this->mutex);
1131 route = this->routes->get(this->routes, &key);
1132 if (route)
1133 {
1134 route->refs++;
1135 res = TRUE;
1136 }
1137 else
1138 {
1139 if (hydra->kernel_interface->get_interface(hydra->kernel_interface,
1140 src, &name))
1141 {
1142 if (hydra->kernel_interface->add_route(hydra->kernel_interface,
1143 dst->get_address(dst), mask, gtw, src, name) == SUCCESS)
1144 {
1145 INIT(route,
1146 .dst = dst->clone(dst),
1147 .mask = mask,
1148 .src = src->clone(src),
1149 .gtw = gtw ? gtw->clone(gtw) : NULL,
1150 .refs = 1,
1151 );
1152 route = this->routes->put(this->routes, route, route);
1153 if (route)
1154 {
1155 destroy_route(route);
1156 }
1157 res = TRUE;
1158 }
1159 free(name);
1160 }
1161 }
1162 this->mutex->unlock(this->mutex);
1163
1164 return res;
1165 }
1166
1167 /**
1168 * (Un)-install routes for IPsec policies
1169 */
1170 static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry,
1171 bool add)
1172 {
1173 enumerator_t *enumerator;
1174 host_t *src, *dst, *gtw;
1175 sp_entry_t *sp;
1176 u_int8_t mask;
1177
1178 enumerator = array_create_enumerator(entry->sps);
1179 while (enumerator->enumerate(enumerator, &sp))
1180 {
1181 if (!sp->dst->to_subnet(sp->dst, &dst, &mask))
1182 {
1183 continue;
1184 }
1185 if (hydra->kernel_interface->get_address_by_ts( hydra->kernel_interface,
1186 sp->src, &src, NULL) != SUCCESS)
1187 {
1188 dst->destroy(dst);
1189 continue;
1190 }
1191 gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface,
1192 entry->remote, entry->local);
1193 if (add)
1194 {
1195 if (!install_route(this, dst, mask, src, gtw))
1196 {
1197 DBG1(DBG_KNL, "installing route for policy %R === %R failed",
1198 sp->src, sp->dst);
1199 }
1200 }
1201 else
1202 {
1203 if (!uninstall_route(this, dst, mask, src, gtw))
1204 {
1205 DBG1(DBG_KNL, "uninstalling route for policy %R === %R failed",
1206 sp->src, sp->dst);
1207 }
1208 }
1209 dst->destroy(dst);
1210 src->destroy(src);
1211 DESTROY_IF(gtw);
1212 }
1213 enumerator->destroy(enumerator);
1214
1215 return TRUE;
1216 }
1217
1218 /**
1219 * Install a tunnel mode SA/SP set to the kernel
1220 */
1221 static bool install_tunnel(private_kernel_wfp_ipsec_t *this, entry_t *entry)
1222 {
1223 if (install_tunnel_sps(this, entry) &&
1224 manage_routes(this, entry, TRUE) &&
1225 install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TUNNEL))
1226 {
1227 return TRUE;
1228 }
1229 cleanup_policies(this, entry);
1230 return FALSE;
1231 }
1232
1233 /**
1234 * Install a SA/SP set to the kernel
1235 */
1236 static bool install(private_kernel_wfp_ipsec_t *this, entry_t *entry)
1237 {
1238 switch (entry->mode)
1239 {
1240 case MODE_TRANSPORT:
1241 return install_transport(this, entry);
1242 case MODE_TUNNEL:
1243 return install_tunnel(this, entry);
1244 case MODE_BEET:
1245 default:
1246 return FALSE;
1247 }
1248 }
1249
1250 METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
1251 private_kernel_wfp_ipsec_t *this)
1252 {
1253 return KERNEL_ESP_V3_TFC | KERNEL_NO_POLICY_UPDATES;
1254 }
1255
1256 /**
1257 * Initialize seeds for SPI generation
1258 */
1259 static bool init_spi(private_kernel_wfp_ipsec_t *this)
1260 {
1261 bool ok = TRUE;
1262 rng_t *rng;
1263
1264 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
1265 if (!rng)
1266 {
1267 return FALSE;
1268 }
1269 ok = rng->get_bytes(rng, sizeof(this->nextspi), (u_int8_t*)&this->nextspi);
1270 if (ok)
1271 {
1272 ok = rng->get_bytes(rng, sizeof(this->mixspi), (u_int8_t*)&this->mixspi);
1273 }
1274 rng->destroy(rng);
1275 return ok;
1276 }
1277
1278 /**
1279 * Map an integer x with a one-to-one function using quadratic residues.
1280 */
1281 static u_int permute(u_int x, u_int p)
1282 {
1283 u_int qr;
1284
1285 x = x % p;
1286 qr = ((u_int64_t)x * x) % p;
1287 if (x <= p / 2)
1288 {
1289 return qr;
1290 }
1291 return p - qr;
1292 }
1293
1294 METHOD(kernel_ipsec_t, get_spi, status_t,
1295 private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
1296 u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
1297 {
1298 /* To avoid sequencial SPIs, we use a one-to-one permuation function on
1299 * an incrementing counter, that is a full period PRNG for the range we
1300 * allocate SPIs in. We add some randomness using a fixed XOR and start
1301 * the counter at random position. This is not cryptographically safe,
1302 * but that is actually not required.
1303 * The selected prime should be smaller than the range we allocate SPIs
1304 * in, and it must satisfy p % 4 == 3 to map x > p/2 using p - qr. */
1305 static const u_int p = 268435399, offset = 0xc0000000;
1306
1307 *spi = htonl(offset + permute(ref_get(&this->nextspi) ^ this->mixspi, p));
1308 return SUCCESS;
1309 }
1310
1311 METHOD(kernel_ipsec_t, get_cpi, status_t,
1312 private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
1313 u_int32_t reqid, u_int16_t *cpi)
1314 {
1315 return NOT_SUPPORTED;
1316 }
1317
1318 /**
1319 * Data for an expire callback job
1320 */
1321 typedef struct {
1322 /* backref to kernel backend */
1323 private_kernel_wfp_ipsec_t *this;
1324 /* SPI of expiring SA */
1325 u_int32_t spi;
1326 /* destination address of expiring SA */
1327 host_t *dst;
1328 /* is this a hard expire, or a rekey request? */
1329 bool hard;
1330 } expire_data_t;
1331
1332 /**
1333 * Clean up expire data
1334 */
1335 static void expire_data_destroy(expire_data_t *data)
1336 {
1337 data->dst->destroy(data->dst);
1338 free(data);
1339 }
1340
1341 /**
1342 * Callback job for SA expiration
1343 */
1344 static job_requeue_t expire_job(expire_data_t *data)
1345 {
1346 private_kernel_wfp_ipsec_t *this = data->this;
1347 u_int32_t reqid = 0;
1348 u_int8_t protocol;
1349 entry_t *entry;
1350 sa_entry_t key = {
1351 .spi = data->spi,
1352 .dst = data->dst,
1353 };
1354
1355 if (data->hard)
1356 {
1357 this->mutex->lock(this->mutex);
1358 entry = this->isas->remove(this->isas, &key);
1359 this->mutex->unlock(this->mutex);
1360 if (entry)
1361 {
1362 protocol = entry->isa.protocol;
1363 reqid = entry->reqid;
1364 if (entry->osa.dst)
1365 {
1366 key.dst = entry->osa.dst;
1367 key.spi = entry->osa.spi;
1368 this->osas->remove(this->osas, &key);
1369 }
1370 entry_destroy(this, entry);
1371 }
1372 }
1373 else
1374 {
1375 this->mutex->lock(this->mutex);
1376 entry = this->isas->get(this->isas, &key);
1377 if (entry)
1378 {
1379 protocol = entry->isa.protocol;
1380 reqid = entry->reqid;
1381 }
1382 this->mutex->unlock(this->mutex);
1383 }
1384
1385 if (reqid)
1386 {
1387 hydra->kernel_interface->expire(hydra->kernel_interface,
1388 reqid, protocol, data->spi, data->hard);
1389 }
1390
1391 return JOB_REQUEUE_NONE;
1392 }
1393
1394 /**
1395 * Schedule an expire event for an SA
1396 */
1397 static void schedule_expire(private_kernel_wfp_ipsec_t *this, u_int32_t spi,
1398 host_t *dst, u_int32_t lifetime, bool hard)
1399 {
1400 expire_data_t *data;
1401
1402 INIT(data,
1403 .this = this,
1404 .spi = spi,
1405 .dst = dst->clone(dst),
1406 .hard = hard,
1407 );
1408
1409 lib->scheduler->schedule_job(lib->scheduler, (job_t*)
1410 callback_job_create((void*)expire_job, data,
1411 (void*)expire_data_destroy, NULL),
1412 lifetime);
1413 }
1414
1415 METHOD(kernel_ipsec_t, add_sa, status_t,
1416 private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
1417 u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
1418 u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
1419 u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
1420 u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
1421 traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
1422 {
1423 host_t *local, *remote;
1424 entry_t *entry;
1425
1426 if (inbound)
1427 {
1428 /* comes first, create new entry */
1429 local = dst->clone(dst);
1430 remote = src->clone(src);
1431
1432 INIT(entry,
1433 .reqid = reqid,
1434 .isa = {
1435 .spi = spi,
1436 .dst = local,
1437 .protocol = protocol,
1438 .lifetime = lifetime->time.life,
1439 .encr = {
1440 .alg = enc_alg,
1441 .key = chunk_clone(enc_key),
1442 },
1443 .integ = {
1444 .alg = int_alg,
1445 .key = chunk_clone(int_key),
1446 },
1447 },
1448 .sps = array_create(0, 0),
1449 .local = local,
1450 .remote = remote,
1451 .mode = mode,
1452 .encap = encap,
1453 );
1454
1455 if (lifetime->time.life)
1456 {
1457 schedule_expire(this, spi, local, lifetime->time.life, TRUE);
1458 }
1459 if (lifetime->time.rekey && lifetime->time.rekey != lifetime->time.life)
1460 {
1461 schedule_expire(this, spi, local, lifetime->time.rekey, FALSE);
1462 }
1463
1464 this->mutex->lock(this->mutex);
1465 this->tsas->put(this->tsas, (void*)(uintptr_t)reqid, entry);
1466 this->isas->put(this->isas, &entry->isa, entry);
1467 this->mutex->unlock(this->mutex);
1468 }
1469 else
1470 {
1471 /* comes after inbound, update entry */
1472 this->mutex->lock(this->mutex);
1473 entry = this->tsas->remove(this->tsas, (void*)(uintptr_t)reqid);
1474 this->mutex->unlock(this->mutex);
1475
1476 if (!entry)
1477 {
1478 DBG1(DBG_KNL, "adding outbound SA failed, no inbound SA found "
1479 "for reqid %u ", reqid);
1480 return NOT_FOUND;
1481 }
1482 /* TODO: should we check for local/remote, mode etc.? */
1483
1484 entry->osa = (sa_entry_t){
1485 .spi = spi,
1486 .dst = entry->remote,
1487 .protocol = protocol,
1488 .lifetime = lifetime->time.life,
1489 .encr = {
1490 .alg = enc_alg,
1491 .key = chunk_clone(enc_key),
1492 },
1493 .integ = {
1494 .alg = int_alg,
1495 .key = chunk_clone(int_key),
1496 },
1497 };
1498
1499 this->mutex->lock(this->mutex);
1500 this->osas->put(this->osas, &entry->osa, entry);
1501 this->mutex->unlock(this->mutex);
1502 }
1503
1504 return SUCCESS;
1505 }
1506
1507 METHOD(kernel_ipsec_t, update_sa, status_t,
1508 private_kernel_wfp_ipsec_t *this, u_int32_t spi, u_int8_t protocol,
1509 u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
1510 bool encap, bool new_encap, mark_t mark)
1511 {
1512 return NOT_SUPPORTED;
1513 }
1514
1515 METHOD(kernel_ipsec_t, query_sa, status_t,
1516 private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
1517 u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes,
1518 u_int64_t *packets, time_t *time)
1519 {
1520 /* It does not seem that WFP provides any means of getting per-SA traffic
1521 * statistics. IPsecGetStatistics0/1() provides global stats, and
1522 * IPsecSaContextEnum0/1() and IPsecSaEnum0/1() return the configured
1523 * values only. */
1524 return NOT_SUPPORTED;
1525 }
1526
1527 METHOD(kernel_ipsec_t, del_sa, status_t,
1528 private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
1529 u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark)
1530 {
1531 entry_t *entry;
1532 sa_entry_t key = {
1533 .dst = dst,
1534 .spi = spi,
1535 };
1536
1537 this->mutex->lock(this->mutex);
1538 entry = this->isas->remove(this->isas, &key);
1539 this->mutex->unlock(this->mutex);
1540
1541 if (entry)
1542 {
1543 /* keep entry until removal of outbound */
1544 return SUCCESS;
1545 }
1546
1547 this->mutex->lock(this->mutex);
1548 entry = this->osas->remove(this->osas, &key);
1549 this->mutex->unlock(this->mutex);
1550
1551 if (entry)
1552 {
1553 entry_destroy(this, entry);
1554 return SUCCESS;
1555 }
1556
1557 return NOT_FOUND;
1558 }
1559
1560 METHOD(kernel_ipsec_t, flush_sas, status_t,
1561 private_kernel_wfp_ipsec_t *this)
1562 {
1563 return NOT_SUPPORTED;
1564 }
1565
1566 METHOD(kernel_ipsec_t, add_policy, status_t,
1567 private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
1568 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
1569 policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
1570 policy_priority_t priority)
1571 {
1572 status_t status = SUCCESS;
1573 entry_t *entry;
1574 sp_entry_t *sp;
1575 sa_entry_t key = {
1576 .spi = sa->esp.use ? sa->esp.spi : sa->ah.spi,
1577 .dst = dst,
1578 };
1579
1580 if (sa->esp.use && sa->ah.use)
1581 {
1582 return NOT_SUPPORTED;
1583 }
1584
1585 switch (type)
1586 {
1587 case POLICY_IPSEC:
1588 break;
1589 case POLICY_PASS:
1590 case POLICY_DROP:
1591 return NOT_SUPPORTED;
1592 }
1593
1594 switch (direction)
1595 {
1596 case POLICY_OUT:
1597 break;
1598 case POLICY_IN:
1599 case POLICY_FWD:
1600 /* not required */
1601 return SUCCESS;
1602 default:
1603 return NOT_SUPPORTED;
1604 }
1605
1606 switch (priority)
1607 {
1608 case POLICY_PRIORITY_DEFAULT:
1609 break;
1610 case POLICY_PRIORITY_ROUTED:
1611 /* TODO: install trap policy with low prio */
1612 case POLICY_PRIORITY_FALLBACK:
1613 default:
1614 return NOT_SUPPORTED;
1615 }
1616
1617 this->mutex->lock(this->mutex);
1618 entry = this->osas->get(this->osas, &key);
1619 if (entry)
1620 {
1621 if (array_count(entry->sps) == 0)
1622 {
1623 INIT(sp,
1624 .src = src_ts->clone(src_ts),
1625 .dst = dst_ts->clone(dst_ts),
1626 );
1627 array_insert(entry->sps, -1, sp);
1628 if (!install(this, entry))
1629 {
1630 status = FAILED;
1631 }
1632 }
1633 else
1634 {
1635 /* TODO: reinstall with a filter using multiple TS?
1636 * Filters are ANDed for a match, but we could install a filter
1637 * with the inverse TS set using NOT-matches... */
1638 status = NOT_SUPPORTED;
1639 }
1640 }
1641 else
1642 {
1643 DBG1(DBG_KNL, "adding SP failed, no SA found for SPI 0x%08x", key.spi);
1644 status = FAILED;
1645 }
1646 this->mutex->unlock(this->mutex);
1647
1648 return status;
1649 }
1650
1651 METHOD(kernel_ipsec_t, query_policy, status_t,
1652 private_kernel_wfp_ipsec_t *this, traffic_selector_t *src_ts,
1653 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
1654 time_t *use_time)
1655 {
1656 /* see query_sa() for some notes */
1657 return NOT_SUPPORTED;
1658 }
1659
1660 METHOD(kernel_ipsec_t, del_policy, status_t,
1661 private_kernel_wfp_ipsec_t *this, traffic_selector_t *src_ts,
1662 traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
1663 mark_t mark, policy_priority_t priority)
1664 {
1665 /* not required, as we delete the whole SA/SP set during del_sa() */
1666 return SUCCESS;
1667 }
1668
1669 METHOD(kernel_ipsec_t, flush_policies, status_t,
1670 private_kernel_wfp_ipsec_t *this)
1671 {
1672 return NOT_SUPPORTED;
1673 }
1674
1675 METHOD(kernel_ipsec_t, bypass_socket, bool,
1676 private_kernel_wfp_ipsec_t *this, int fd, int family)
1677 {
1678 return NOT_SUPPORTED;
1679 }
1680
1681 METHOD(kernel_ipsec_t, enable_udp_decap, bool,
1682 private_kernel_wfp_ipsec_t *this, int fd, int family, u_int16_t port)
1683 {
1684 return NOT_SUPPORTED;
1685 }
1686
1687 METHOD(kernel_ipsec_t, destroy, void,
1688 private_kernel_wfp_ipsec_t *this)
1689 {
1690 if (this->handle)
1691 {
1692 FwpmProviderDeleteByKey0(this->handle, &this->provider.providerKey);
1693 FwpmEngineClose0(this->handle);
1694 }
1695 this->tsas->destroy(this->tsas);
1696 this->isas->destroy(this->isas);
1697 this->osas->destroy(this->osas);
1698 this->routes->destroy(this->routes);
1699 this->mutex->destroy(this->mutex);
1700 free(this);
1701 }
1702
1703 /*
1704 * Described in header.
1705 */
1706 kernel_wfp_ipsec_t *kernel_wfp_ipsec_create()
1707 {
1708 private_kernel_wfp_ipsec_t *this;
1709 DWORD res;
1710 FWPM_SESSION0 session = {
1711 .displayData = {
1712 .name = L"charon",
1713 .description = L"strongSwan IKE kernel-wfp backend",
1714 },
1715 };
1716
1717 INIT(this,
1718 .public = {
1719 .interface = {
1720 .get_features = _get_features,
1721 .get_spi = _get_spi,
1722 .get_cpi = _get_cpi,
1723 .add_sa = _add_sa,
1724 .update_sa = _update_sa,
1725 .query_sa = _query_sa,
1726 .del_sa = _del_sa,
1727 .flush_sas = _flush_sas,
1728 .add_policy = _add_policy,
1729 .query_policy = _query_policy,
1730 .del_policy = _del_policy,
1731 .flush_policies = _flush_policies,
1732 .bypass_socket = _bypass_socket,
1733 .enable_udp_decap = _enable_udp_decap,
1734 .destroy = _destroy,
1735 },
1736 },
1737 .provider = {
1738 .displayData = {
1739 .name = L"charon",
1740 .description = L"strongSwan IKE kernel-wfp backend",
1741 },
1742 .providerKey = { 0x59cdae2e, 0xf6bb, 0x4c09,
1743 { 0xa9,0x59,0x9d,0x91,0xac,0xaf,0xf9,0x19 }},
1744 },
1745 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1746 .tsas = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4),
1747 .isas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
1748 .osas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
1749 .routes = hashtable_create((void*)hash_route, (void*)equals_route, 4),
1750 );
1751
1752 if (!init_spi(this))
1753 {
1754 destroy(this);
1755 return NULL;
1756 }
1757
1758 res = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session,
1759 &this->handle);
1760 if (res != ERROR_SUCCESS)
1761 {
1762 DBG1(DBG_KNL, "opening WFP engine failed: 0x%08x", res);
1763 destroy(this);
1764 return NULL;
1765 }
1766
1767 res = FwpmProviderAdd0(this->handle, &this->provider, NULL);
1768 if (res != ERROR_SUCCESS && res != FWP_E_ALREADY_EXISTS)
1769 {
1770 DBG1(DBG_KNL, "registering WFP provider failed: 0x%08x", res);
1771 destroy(this);
1772 return NULL;
1773 }
1774
1775 return &this->public;
1776 }