Return to kernel_wfp_ipsec.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / kernel_wfp |
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: }