diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2014-07-11 07:23:31 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2014-07-11 07:23:31 +0200 |
commit | 81c63b0eed39432878f78727f60a1e7499645199 (patch) | |
tree | 82387d8fecd1c20788fd8bd784a9b0bde091fb6b /src/libhydra/plugins/kernel_pfkey | |
parent | c5ebfc7b9c16551fe825dc1d79c3f7e2f096f6c9 (diff) | |
download | vyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.tar.gz vyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.zip |
Imported Upstream version 5.2.0
Diffstat (limited to 'src/libhydra/plugins/kernel_pfkey')
-rw-r--r-- | src/libhydra/plugins/kernel_pfkey/Makefile.am | 2 | ||||
-rw-r--r-- | src/libhydra/plugins/kernel_pfkey/Makefile.in | 8 | ||||
-rw-r--r-- | src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 206 |
3 files changed, 178 insertions, 38 deletions
diff --git a/src/libhydra/plugins/kernel_pfkey/Makefile.am b/src/libhydra/plugins/kernel_pfkey/Makefile.am index bb5d0d7f7..f645528d9 100644 --- a/src/libhydra/plugins/kernel_pfkey/Makefile.am +++ b/src/libhydra/plugins/kernel_pfkey/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libhydra AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-kernel-pfkey.la diff --git a/src/libhydra/plugins/kernel_pfkey/Makefile.in b/src/libhydra/plugins/kernel_pfkey/Makefile.in index 658ec7bc9..767769698 100644 --- a/src/libhydra/plugins/kernel_pfkey/Makefile.in +++ b/src/libhydra/plugins/kernel_pfkey/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -266,6 +266,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -284,6 +285,7 @@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ @@ -311,6 +313,7 @@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +aikgen_plugins = @aikgen_plugins@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -402,6 +405,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libhydra AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-kernel-pfkey.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-kernel-pfkey.la diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 4704d419f..e1a58aa94 100644 --- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -13,7 +13,29 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ +/* + * Copyright (C) 2014 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include <stdint.h> #include <sys/types.h> #include <sys/socket.h> @@ -24,7 +46,6 @@ #ifdef HAVE_NET_PFKEYV2_H #include <net/pfkeyv2.h> #else -#include <stdint.h> #include <linux/pfkeyv2.h> #endif @@ -114,8 +135,8 @@ #define SOL_UDP IPPROTO_UDP #endif -/** default priority of installed policies */ -#define PRIO_BASE 512 +/** base priority for installed policies */ +#define PRIO_BASE 384 #ifdef __APPLE__ /** from xnu/bsd/net/pfkeyv2.h */ @@ -562,6 +583,9 @@ static inline u_int32_t get_priority(policy_entry_t *policy, priority <<= 1; /* fall-through */ case POLICY_PRIORITY_DEFAULT: + priority <<= 1; + /* fall-trough */ + case POLICY_PRIORITY_PASS: break; } /* calculate priority based on selector size, small size = high prio */ @@ -825,18 +849,20 @@ static kernel_algorithm_t integrity_algs[] = { {END_OF_LIST, 0, }, }; -#if 0 /** * Algorithms for IPComp, unused yet */ static kernel_algorithm_t compression_algs[] = { /* {IPCOMP_OUI, 0 }, */ {IPCOMP_DEFLATE, SADB_X_CALG_DEFLATE }, +#ifdef SADB_X_CALG_LZS {IPCOMP_LZS, SADB_X_CALG_LZS }, +#endif +#ifdef SADB_X_CALG_LZJH {IPCOMP_LZJH, SADB_X_CALG_LZJH }, +#endif {END_OF_LIST, 0 }, }; -#endif /** * Look up a kernel algorithm ID and its key size @@ -854,6 +880,9 @@ static int lookup_algorithm(transform_type_t type, int ikev2) case INTEGRITY_ALGORITHM: list = integrity_algs; break; + case COMPRESSION_ALGORITHM: + list = compression_algs; + break; default: return 0; } @@ -1483,9 +1512,13 @@ static bool receive_events(private_kernel_pfkey_ipsec_t *this, int fd, return TRUE; } -METHOD(kernel_ipsec_t, get_spi, status_t, - private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, - u_int8_t protocol, u_int32_t reqid, u_int32_t *spi) +/** + * Get an SPI for a specific protocol from the kernel. + */ + +static status_t get_spi_internal(private_kernel_pfkey_ipsec_t *this, + host_t *src, host_t *dst, u_int8_t proto, u_int32_t min, u_int32_t max, + u_int32_t reqid, u_int32_t *spi) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -1500,7 +1533,7 @@ METHOD(kernel_ipsec_t, get_spi, status_t, msg = (struct sadb_msg*)request; msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_type = SADB_GETSPI; - msg->sadb_msg_satype = proto2satype(protocol); + msg->sadb_msg_satype = proto2satype(proto); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg); @@ -1515,8 +1548,8 @@ METHOD(kernel_ipsec_t, get_spi, status_t, range = (struct sadb_spirange*)PFKEY_EXT_ADD_NEXT(msg); range->sadb_spirange_exttype = SADB_EXT_SPIRANGE; range->sadb_spirange_len = PFKEY_LEN(sizeof(struct sadb_spirange)); - range->sadb_spirange_min = 0xc0000000; - range->sadb_spirange_max = 0xcFFFFFFF; + range->sadb_spirange_min = min; + range->sadb_spirange_max = max; PFKEY_EXT_ADD(msg, range); if (pfkey_send(this, msg, &out, &len) == SUCCESS) @@ -1542,11 +1575,42 @@ METHOD(kernel_ipsec_t, get_spi, status_t, return SUCCESS; } +METHOD(kernel_ipsec_t, get_spi, status_t, + private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, u_int32_t *spi) +{ + DBG2(DBG_KNL, "getting SPI for reqid {%u}", reqid); + + if (get_spi_internal(this, src, dst, protocol, + 0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS) + { + DBG1(DBG_KNL, "unable to get SPI for reqid {%u}", reqid); + return FAILED; + } + + DBG2(DBG_KNL, "got SPI %.8x for reqid {%u}", ntohl(*spi), reqid); + return SUCCESS; +} + METHOD(kernel_ipsec_t, get_cpi, status_t, private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, u_int32_t reqid, u_int16_t *cpi) { - return FAILED; + u_int32_t received_spi = 0; + + DBG2(DBG_KNL, "getting CPI for reqid {%u}", reqid); + + if (get_spi_internal(this, src, dst, IPPROTO_COMP, + 0x100, 0xEFFF, reqid, &received_spi) != SUCCESS) + { + DBG1(DBG_KNL, "unable to get CPI for reqid {%u}", reqid); + return FAILED; + } + + *cpi = htons((u_int16_t)ntohl(received_spi)); + + DBG2(DBG_KNL, "got CPI %.4x for reqid {%u}", ntohs(*cpi), reqid); + return SUCCESS; } METHOD(kernel_ipsec_t, add_sa, status_t, @@ -1554,8 +1618,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t, u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, - u_int16_t ipcomp, u_int16_t cpi, bool initiator, bool encap, bool esn, - bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts) + u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window, + bool initiator, bool encap, bool esn, bool inbound, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -1565,6 +1630,20 @@ METHOD(kernel_ipsec_t, add_sa, status_t, struct sadb_key *key; size_t len; + /* if IPComp is used, we install an additional IPComp SA. if the cpi is 0 + * we are in the recursive call below */ + if (ipcomp != IPCOMP_NONE && cpi != 0) + { + lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}}; + add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, mark, + tfc, &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, + chunk_empty, mode, ipcomp, 0, 0, FALSE, FALSE, FALSE, inbound, + NULL, NULL); + ipcomp = IPCOMP_NONE; + /* use transport mode ESP SA, IPComp uses tunnel mode */ + mode = MODE_TRANSPORT; + } + memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", @@ -1595,9 +1674,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_len = PFKEY_LEN(len); sa->sadb_sa_spi = spi; - sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32; - sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); - sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); + if (protocol == IPPROTO_COMP) + { + sa->sadb_sa_encrypt = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp); + } + else + { + sa->sadb_sa_replay = min(replay_window, 32); + sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); + sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); + } PFKEY_EXT_ADD(msg, sa); sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg); @@ -1668,11 +1754,6 @@ METHOD(kernel_ipsec_t, add_sa, status_t, PFKEY_EXT_ADD(msg, key); } - if (ipcomp != IPCOMP_NONE) - { - /*TODO*/ - } - #ifdef HAVE_NATT if (encap) { @@ -1719,6 +1800,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t, return NOT_SUPPORTED; } + /* if IPComp is used, we first update the IPComp SA */ + if (cpi) + { + update_sa(this, htonl(ntohs(cpi)), IPPROTO_COMP, 0, + src, dst, new_src, new_dst, FALSE, FALSE, mark); + } + memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi)); @@ -1919,6 +2007,12 @@ METHOD(kernel_ipsec_t, del_sa, status_t, struct sadb_sa *sa; size_t len; + /* if IPComp was used, we first delete the additional IPComp SA */ + if (cpi) + { + del_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, 0, mark); + } + memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi)); @@ -2018,7 +2112,7 @@ static void add_exclude_route(private_kernel_pfkey_ipsec_t *this, { DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src); gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface, - dst, NULL); + dst, -1, NULL); if (gtw) { char *if_name = NULL; @@ -2129,16 +2223,29 @@ static bool install_route(private_kernel_pfkey_ipsec_t *this, INIT(route, .prefixlen = policy->src.mask, .src_ip = host, - .gateway = hydra->kernel_interface->get_nexthop( - hydra->kernel_interface, dst, src), .dst_net = chunk_clone(policy->src.net->get_address(policy->src.net)), ); - /* if the IP is virtual, we install the route over the interface it has - * been installed on. Otherwise we use the interface we use for IKE, as - * this is required for example on Linux. */ - if (is_virtual) + if (!dst->is_anyaddr(dst)) { + route->gateway = hydra->kernel_interface->get_nexthop( + hydra->kernel_interface, dst, -1, src); + + /* if the IP is virtual, we install the route over the interface it has + * been installed on. Otherwise we use the interface we use for IKE, as + * this is required for example on Linux. */ + if (is_virtual) + { + src = route->src_ip; + } + } + else + { /* for shunt policies */ + route->gateway = hydra->kernel_interface->get_nexthop( + hydra->kernel_interface, policy->src.net, + policy->src.mask, route->src_ip); + + /* we don't have a source address, use the address we found */ src = route->src_ip; } @@ -2230,6 +2337,7 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, ipsec_sa_t *ipsec = mapping->sa; pfkey_msg_t response; size_t len; + ipsec_mode_t proto_mode; memset(&request, 0, sizeof(request)); @@ -2251,15 +2359,43 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, /* one or more sadb_x_ipsecrequest extensions are added to the * sadb_x_policy extension */ + proto_mode = ipsec->cfg.mode; + req = (struct sadb_x_ipsecrequest*)(pol + 1); + + if (ipsec->cfg.ipcomp.transform != IPCOMP_NONE) + { + req->sadb_x_ipsecrequest_proto = IPPROTO_COMP; + + /* !!! the length here MUST be in octets instead of 64 bit words */ + req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest); + req->sadb_x_ipsecrequest_mode = mode2kernel(ipsec->cfg.mode); + req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid; + req->sadb_x_ipsecrequest_level = (policy->direction == POLICY_OUT) ? + IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_USE; + if (ipsec->cfg.mode == MODE_TUNNEL) + { + len = hostcpy(req + 1, ipsec->src, FALSE); + req->sadb_x_ipsecrequest_len += len; + len = hostcpy((char*)(req + 1) + len, ipsec->dst, FALSE); + req->sadb_x_ipsecrequest_len += len; + /* use transport mode for other SAs */ + proto_mode = MODE_TRANSPORT; + } + + pol->sadb_x_policy_len += PFKEY_LEN(req->sadb_x_ipsecrequest_len); + req = (struct sadb_x_ipsecrequest*)((char*)(req) + + req->sadb_x_ipsecrequest_len); + } + req->sadb_x_ipsecrequest_proto = ipsec->cfg.esp.use ? IPPROTO_ESP : IPPROTO_AH; /* !!! the length here MUST be in octets instead of 64 bit words */ req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest); - req->sadb_x_ipsecrequest_mode = mode2kernel(ipsec->cfg.mode); + req->sadb_x_ipsecrequest_mode = mode2kernel(proto_mode); req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid; req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE; - if (ipsec->cfg.mode == MODE_TUNNEL) + if (proto_mode == MODE_TUNNEL) { len = hostcpy(req + 1, ipsec->src, FALSE); req->sadb_x_ipsecrequest_len += len; @@ -2324,12 +2460,12 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, free(out); /* install a route, if: - * - this is a forward policy (to just get one for each child) - * - we are in tunnel mode + * - this is an inbound policy (to just get one for each child) + * - we are in tunnel mode or install a bypass policy * - routing is not disabled via strongswan.conf */ - if (policy->direction == POLICY_IN && - ipsec->cfg.mode != MODE_TRANSPORT && this->install_routes) + if (policy->direction == POLICY_IN && this->install_routes && + (mapping->type != POLICY_IPSEC || ipsec->cfg.mode != MODE_TRANSPORT)) { install_route(this, policy, (policy_sa_in_t*)mapping); } |