summaryrefslogtreecommitdiff
path: root/src/libhydra/plugins/kernel_pfkey
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2014-07-11 07:23:31 +0200
committerYves-Alexis Perez <corsac@debian.org>2014-07-11 07:23:31 +0200
commit81c63b0eed39432878f78727f60a1e7499645199 (patch)
tree82387d8fecd1c20788fd8bd784a9b0bde091fb6b /src/libhydra/plugins/kernel_pfkey
parentc5ebfc7b9c16551fe825dc1d79c3f7e2f096f6c9 (diff)
downloadvyos-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.am2
-rw-r--r--src/libhydra/plugins/kernel_pfkey/Makefile.in8
-rw-r--r--src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c206
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);
}