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