Merge branch 'xfrmi'

This adds support for XFRM interfaces, which replace VTI devices and are
available with 4.19+ Linux kernels.

IPsec SAs and policies are associated with such interfaces via interface
IDs that can be configured on the CHILD_SA-level (dynamic IDs may
optionally be allocated for each instance and even direction) or on the
IKE_SA-level (again, dynamic IDs may be optionally allocated per IKE_SA).
IDs on an IKE_SA are inherited by all CHILD_SAs created under it, unless
the child configuration overrides them.

The effect the interface ID has on policies is similar to that of marks,
i.e. they won't match packets unless they are routed via interface with
matching interface ID.  So it's possible to negotiate e.g. 0.0.0.0/0 as
traffic selector on both sides and then control the affected traffic via
routes/firewall.

It's possible to use separate interfaces for in- and outbound traffic (or
only use an interface in one direction and regular policies in the other).

Since iproute2 does not yet support XFRM interfaces, a small utility is
provided that allows creating and listing XFRM interfaces.

Interfaces may be created dynamically via updown/vici scripts or
statically (before or after establishing the SAs).  Routes must be added
manually as needed (the daemon will not install any routes for outbound
policies with an interface ID).

When moving XFRM interfaces to other network namespaces they retain access
to the SAs and policies created in the original namespace, which allows
providing IPsec tunnels for processes in other network namespaces without
giving them access to the IPsec keys or IKE credentials.

Fixes #2845.
This commit is contained in:
Tobias Brunner
2019-04-04 10:41:01 +02:00
85 changed files with 1955 additions and 171 deletions
+2 -1
View File
@@ -1312,7 +1312,7 @@ fi
AM_CONDITIONAL(RUBY_GEMS_INSTALL, [test "x$ruby_gems_install" = xtrue])
if test x$python_eggs = xtrue; then
PYTHON_PACKAGE_VERSION=`echo "$PACKAGE_VERSION" | $SED 's/dr/dev/'`
PYTHON_PACKAGE_VERSION=`echo "$PACKAGE_VERSION" | $SED 's/dr/.dev/'`
AC_SUBST([PYTHON_PACKAGE_VERSION])
if test x$python_eggs_install = xtrue; then
AC_PATH_PROG([EASY_INSTALL], [easy_install], [], [$PATH:/bin:/usr/bin:/usr/local/bin])
@@ -2009,6 +2009,7 @@ AC_CONFIG_FILES([
src/sw-collector/Makefile
src/sec-updater/Makefile
src/swanctl/Makefile
src/xfrmi/Makefile
scripts/Makefile
testing/Makefile
])
+4
View File
@@ -143,3 +143,7 @@ endif
if USE_TPM
SUBDIRS += tpm_extendpcr
endif
if USE_KERNEL_NETLINK
SUBDIRS += xfrmi
endif
+6
View File
@@ -119,6 +119,12 @@
# PLUTO_MARK_OUT
# is an optional XFRM mark set on the outbound IPsec SA
#
# PLUTO_IF_ID_IN
# is an optional XFRM interface ID set on the inbound IPsec SA
#
# PLUTO_IF_ID_OUT
# is an optional XFRM interface ID set on the outbound IPsec SA
#
# PLUTO_UDP_ENC
# contains the remote UDP port in the case of ESP_IN_UDP
# encapsulation
+1
View File
@@ -304,6 +304,7 @@ enum xfrm_attr_type_t {
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
XFRMA_SET_MARK, /* __u32 */
XFRMA_SET_MARK_MASK, /* __u32 */
XFRMA_IF_ID, /* __u32 */
__XFRMA_MAX
#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */
+22 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2018 Tobias Brunner
* Copyright (C) 2008-2019 Tobias Brunner
* Copyright (C) 2016 Andreas Steffen
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -113,6 +113,16 @@ struct private_child_cfg_t {
*/
uint32_t reqid;
/**
* Optionl interface ID to use for inbound CHILD_SA
*/
uint32_t if_id_in;
/**
* Optionl interface ID to use for outbound CHILD_SA
*/
uint32_t if_id_out;
/**
* Optional mark to install inbound CHILD_SA with
*/
@@ -551,6 +561,12 @@ METHOD(child_cfg_t, get_reqid, uint32_t,
return this->reqid;
}
METHOD(child_cfg_t, get_if_id, uint32_t,
private_child_cfg_t *this, bool inbound)
{
return inbound ? this->if_id_in : this->if_id_out;
}
METHOD(child_cfg_t, get_mark, mark_t,
private_child_cfg_t *this, bool inbound)
{
@@ -632,6 +648,8 @@ METHOD(child_cfg_t, equals, bool,
LIFETIME_EQUALS(this->lifetime, other->lifetime) &&
this->inactivity == other->inactivity &&
this->reqid == other->reqid &&
this->if_id_in == other->if_id_in &&
this->if_id_out == other->if_id_out &&
this->mark_in.value == other->mark_in.value &&
this->mark_in.mask == other->mark_in.mask &&
this->mark_out.value == other->mark_out.value &&
@@ -695,6 +713,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
.get_dh_group = _get_dh_group,
.get_inactivity = _get_inactivity,
.get_reqid = _get_reqid,
.get_if_id = _get_if_id,
.get_mark = _get_mark,
.get_set_mark = _get_set_mark,
.get_tfc = _get_tfc,
@@ -713,6 +732,8 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
.options = data->options,
.updown = strdupnull(data->updown),
.reqid = data->reqid,
.if_id_in = data->if_id_in,
.if_id_out = data->if_id_out,
.mode = data->mode,
.start_action = data->start_action,
.dpd_action = data->dpd_action,
+13 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2018 Tobias Brunner
* Copyright (C) 2008-2019 Tobias Brunner
* Copyright (C) 2016 Andreas Steffen
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -226,6 +226,14 @@ struct child_cfg_t {
*/
uint32_t (*get_reqid)(child_cfg_t *this);
/**
* Optional interface ID to set on policies/SAs.
*
* @param inbound TRUE for inbound, FALSE for outbound
* @return interface ID
*/
uint32_t (*get_if_id)(child_cfg_t *this, bool inbound);
/**
* Optional mark to set on policies/SAs.
*
@@ -350,6 +358,10 @@ struct child_cfg_create_t {
child_cfg_option_t options;
/** Specific reqid to use for CHILD_SA, 0 for auto assignment */
uint32_t reqid;
/** Optional inbound interface ID */
uint32_t if_id_in;
/** Optional outbound interface ID */
uint32_t if_id_out;
/** Optional inbound mark */
mark_t mark_in;
/** Optional outbound mark */
+22 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2018 Tobias Brunner
* Copyright (C) 2007-2019 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
@@ -155,6 +155,16 @@ struct private_peer_cfg_t {
*/
linked_list_t *remote_auth;
/**
* Optionl interface ID to use for inbound CHILD_SA
*/
uint32_t if_id_in;
/**
* Optionl interface ID to use for outbound CHILD_SA
*/
uint32_t if_id_out;
/**
* PPK ID
*/
@@ -587,6 +597,12 @@ METHOD(peer_cfg_t, create_auth_cfg_enumerator, enumerator_t*,
return this->remote_auth->create_enumerator(this->remote_auth);
}
METHOD(peer_cfg_t, get_if_id, uint32_t,
private_peer_cfg_t *this, bool inbound)
{
return inbound ? this->if_id_in : this->if_id_out;
}
METHOD(peer_cfg_t, get_ppk_id, identification_t*,
private_peer_cfg_t *this)
{
@@ -715,6 +731,8 @@ METHOD(peer_cfg_t, equals, bool,
this->aggressive == other->aggressive &&
this->pull_mode == other->pull_mode &&
auth_cfg_equal(this, other) &&
this->if_id_in == other->if_id_in &&
this->if_id_out == other->if_id_out &&
this->ppk_required == other->ppk_required &&
id_equal(this->ppk_id, other->ppk_id)
#ifdef ME
@@ -805,6 +823,7 @@ peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg,
.create_pool_enumerator = _create_pool_enumerator,
.add_auth_cfg = _add_auth_cfg,
.create_auth_cfg_enumerator = _create_auth_cfg_enumerator,
.get_if_id = _get_if_id,
.get_ppk_id = _get_ppk_id,
.ppk_required = _ppk_required,
.equals = (void*)_equals,
@@ -832,6 +851,8 @@ peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg,
.pull_mode = !data->push_mode,
.dpd = data->dpd,
.dpd_timeout = data->dpd_timeout,
.if_id_in = data->if_id_in,
.if_id_out = data->if_id_out,
.ppk_id = data->ppk_id,
.ppk_required = data->ppk_required,
.vips = linked_list_create(),
+13 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2018 Tobias Brunner
* Copyright (C) 2007-2019 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
@@ -311,6 +311,14 @@ struct peer_cfg_t {
*/
enumerator_t* (*create_pool_enumerator)(peer_cfg_t *this);
/**
* Optional interface ID to set on policies/SAs.
*
* @param inbound TRUE for inbound, FALSE for outbound
* @return interface ID
*/
uint32_t (*get_if_id)(peer_cfg_t *this, bool inbound);
/**
* Get the PPK ID to use with this peer.
*
@@ -407,6 +415,10 @@ struct peer_cfg_create_t {
uint32_t dpd;
/** DPD timeout interval (IKEv1 only), if 0 default applies */
uint32_t dpd_timeout;
/** Optional inbound interface ID */
uint32_t if_id_in;
/** Optional outbound interface ID */
uint32_t if_id_out;
/** Postquantum Preshared Key ID (adopted) */
identification_t *ppk_id;
/** TRUE if a PPK is required, FALSE if it's optional */
+23 -6
View File
@@ -199,6 +199,10 @@ typedef struct {
mark_t mark_in;
/** outbound mark used for SA */
mark_t mark_out;
/** inbound interface ID used for SA */
uint32_t if_id_in;
/** outbound interface ID used for SA */
uint32_t if_id_out;
/** local traffic selectors */
array_t *local;
/** remote traffic selectors */
@@ -222,7 +226,9 @@ static u_int hash_reqid(reqid_entry_t *entry)
{
return chunk_hash_inc(chunk_from_thing(entry->reqid),
chunk_hash_inc(chunk_from_thing(entry->mark_in),
chunk_hash(chunk_from_thing(entry->mark_out))));
chunk_hash_inc(chunk_from_thing(entry->mark_out),
chunk_hash_inc(chunk_from_thing(entry->if_id_in),
chunk_hash(chunk_from_thing(entry->if_id_out))))));
}
/**
@@ -234,7 +240,9 @@ static bool equals_reqid(reqid_entry_t *a, reqid_entry_t *b)
a->mark_in.value == b->mark_in.value &&
a->mark_in.mask == b->mark_in.mask &&
a->mark_out.value == b->mark_out.value &&
a->mark_out.mask == b->mark_out.mask;
a->mark_out.mask == b->mark_out.mask &&
a->if_id_in == b->if_id_in &&
a->if_id_out == b->if_id_out;
}
/**
@@ -262,7 +270,9 @@ static u_int hash_reqid_by_ts(reqid_entry_t *entry)
{
return hash_ts_array(entry->local, hash_ts_array(entry->remote,
chunk_hash_inc(chunk_from_thing(entry->mark_in),
chunk_hash(chunk_from_thing(entry->mark_out)))));
chunk_hash_inc(chunk_from_thing(entry->mark_out),
chunk_hash_inc(chunk_from_thing(entry->if_id_in),
chunk_hash(chunk_from_thing(entry->if_id_out)))))));
}
/**
@@ -301,7 +311,9 @@ static bool equals_reqid_by_ts(reqid_entry_t *a, reqid_entry_t *b)
a->mark_in.value == b->mark_in.value &&
a->mark_in.mask == b->mark_in.mask &&
a->mark_out.value == b->mark_out.value &&
a->mark_out.mask == b->mark_out.mask;
a->mark_out.mask == b->mark_out.mask &&
a->if_id_in == b->if_id_in &&
a->if_id_out == b->if_id_out;
}
/**
@@ -328,7 +340,8 @@ static array_t *array_from_ts_list(linked_list_t *list)
METHOD(kernel_interface_t, alloc_reqid, status_t,
private_kernel_interface_t *this,
linked_list_t *local_ts, linked_list_t *remote_ts,
mark_t mark_in, mark_t mark_out, uint32_t *reqid)
mark_t mark_in, mark_t mark_out, uint32_t if_id_in, uint32_t if_id_out,
uint32_t *reqid)
{
static uint32_t counter = 0;
reqid_entry_t *entry = NULL, *tmpl;
@@ -339,6 +352,8 @@ METHOD(kernel_interface_t, alloc_reqid, status_t,
.remote = array_from_ts_list(remote_ts),
.mark_in = mark_in,
.mark_out = mark_out,
.if_id_in = if_id_in,
.if_id_out = if_id_out,
.reqid = *reqid,
);
@@ -381,12 +396,14 @@ METHOD(kernel_interface_t, alloc_reqid, status_t,
METHOD(kernel_interface_t, release_reqid, status_t,
private_kernel_interface_t *this, uint32_t reqid,
mark_t mark_in, mark_t mark_out)
mark_t mark_in, mark_t mark_out, uint32_t if_id_in, uint32_t if_id_out)
{
reqid_entry_t *entry, tmpl = {
.reqid = reqid,
.mark_in = mark_in,
.mark_out = mark_out,
.if_id_in = if_id_in,
.if_id_out = if_id_out,
};
this->mutex->lock(this->mutex);
+8 -3
View File
@@ -143,13 +143,15 @@ struct kernel_interface_t {
* @param remote_ts traffic selectors of remote side for SA
* @param mark_in inbound mark on SA
* @param mark_out outbound mark on SA
* @param if_id_in inbound interface ID on SA
* @param if_id_out outbound interface ID on SA
* @param reqid allocated reqid
* @return SUCCESS if reqid allocated
*/
status_t (*alloc_reqid)(kernel_interface_t *this,
linked_list_t *local_ts, linked_list_t *remote_ts,
mark_t mark_in, mark_t mark_out,
uint32_t *reqid);
mark_t mark_in, mark_t mark_out, uint32_t if_id_in,
uint32_t if_id_out, uint32_t *reqid);
/**
* Release a previously allocated reqid.
@@ -157,10 +159,13 @@ struct kernel_interface_t {
* @param reqid reqid to release
* @param mark_in inbound mark on SA
* @param mark_out outbound mark on SA
* @param if_id_in inbound interface ID on SA
* @param if_id_out outbound interface ID on SA
* @return SUCCESS if reqid released
*/
status_t (*release_reqid)(kernel_interface_t *this, uint32_t reqid,
mark_t mark_in, mark_t mark_out);
mark_t mark_in, mark_t mark_out,
uint32_t if_id_in, uint32_t if_id_out);
/**
* Add an SA to the SAD.
+4
View File
@@ -55,6 +55,8 @@ struct kernel_ipsec_sa_id_t {
uint8_t proto;
/** Optional mark */
mark_t mark;
/** Optional interface ID */
uint32_t if_id;
};
/**
@@ -154,6 +156,8 @@ struct kernel_ipsec_policy_id_t {
traffic_selector_t *dst_ts;
/** Optional mark */
mark_t mark;
/** Optional interface ID */
uint32_t if_id;
/** Network interface restricting policy */
char *interface;
};
+4 -3
View File
@@ -743,10 +743,11 @@ static void process_child_add(private_ha_dispatcher_t *this,
return;
}
child_sa_create_t data = {
.encap = ike_sa->has_condition(ike_sa, COND_NAT_ANY),
};
child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
ike_sa->get_other_host(ike_sa), config, 0,
ike_sa->has_condition(ike_sa, COND_NAT_ANY),
0, 0);
ike_sa->get_other_host(ike_sa), config, &data);
child_sa->set_mode(child_sa, mode);
child_sa->set_protocol(child_sa, PROTO_ESP);
child_sa->set_ipcomp(child_sa, ipcomp);
@@ -24,7 +24,6 @@ libstrongswan_kernel_netlink_la_LIBADD = $(DLLIB)
libstrongswan_kernel_netlink_la_LDFLAGS = -module -avoid-version
TESTS = kernel_netlink_tests
check_PROGRAMS = $(TESTS)
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2018 Tobias Brunner
* Copyright (C) 2006-2019 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2008-2016 Andreas Steffen
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
@@ -430,6 +430,9 @@ struct ipsec_sa_t {
/** Optional mark */
mark_t mark;
/** Optional mark */
uint32_t if_id;
/** Description of this SA */
ipsec_sa_cfg_t cfg;
@@ -445,7 +448,8 @@ static u_int ipsec_sa_hash(ipsec_sa_t *sa)
return chunk_hash_inc(sa->src->get_address(sa->src),
chunk_hash_inc(sa->dst->get_address(sa->dst),
chunk_hash_inc(chunk_from_thing(sa->mark),
chunk_hash(chunk_from_thing(sa->cfg)))));
chunk_hash_inc(chunk_from_thing(sa->if_id),
chunk_hash(chunk_from_thing(sa->cfg))))));
}
/**
@@ -457,6 +461,7 @@ static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa)
sa->dst->ip_equals(sa->dst, other_sa->dst) &&
sa->mark.value == other_sa->mark.value &&
sa->mark.mask == other_sa->mark.mask &&
sa->if_id == other_sa->if_id &&
ipsec_sa_cfg_equals(&sa->cfg, &other_sa->cfg);
}
@@ -465,13 +470,14 @@ static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa)
*/
static ipsec_sa_t *ipsec_sa_create(private_kernel_netlink_ipsec_t *this,
host_t *src, host_t *dst, mark_t mark,
ipsec_sa_cfg_t *cfg)
uint32_t if_id, ipsec_sa_cfg_t *cfg)
{
ipsec_sa_t *sa, *found;
INIT(sa,
.src = src,
.dst = dst,
.mark = mark,
.if_id = if_id,
.cfg = *cfg,
);
found = this->sas->get(this->sas, sa);
@@ -546,7 +552,7 @@ struct policy_sa_out_t {
static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this,
policy_dir_t dir, policy_type_t type, host_t *src, host_t *dst,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, mark_t mark,
ipsec_sa_cfg_t *cfg)
uint32_t if_id, ipsec_sa_cfg_t *cfg)
{
policy_sa_t *policy;
@@ -564,7 +570,7 @@ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this,
INIT(policy, .priority = 0);
}
policy->type = type;
policy->sa = ipsec_sa_create(this, src, dst, mark, cfg);
policy->sa = ipsec_sa_create(this, src, dst, mark, if_id, cfg);
return policy;
}
@@ -610,6 +616,9 @@ struct policy_entry_t {
/** Optional mark */
uint32_t mark;
/** Optional interface ID */
uint32_t if_id;
/** Associated route installed for this policy */
route_entry_t *route;
@@ -651,7 +660,8 @@ static void policy_entry_destroy(private_kernel_netlink_ipsec_t *this,
static u_int policy_hash(policy_entry_t *key)
{
chunk_t chunk = chunk_from_thing(key->sel);
return chunk_hash_inc(chunk, chunk_hash(chunk_from_thing(key->mark)));
return chunk_hash_inc(chunk, chunk_hash_inc(chunk_from_thing(key->mark),
chunk_hash(chunk_from_thing(key->if_id))));
}
/**
@@ -661,6 +671,7 @@ static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key)
{
return memeq(&key->sel, &other_key->sel, sizeof(struct xfrm_selector)) &&
key->mark == other_key->mark &&
key->if_id == other_key->if_id &&
key->direction == other_key->direction;
}
@@ -1577,6 +1588,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
.spi = htonl(ntohs(data->cpi)),
.proto = IPPROTO_COMP,
.mark = id->mark,
.if_id = id->if_id,
};
kernel_ipsec_add_sa_t ipcomp_sa = {
.reqid = data->reqid,
@@ -1902,6 +1914,11 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
goto failed;
}
if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id))
{
goto failed;
}
if (ipcomp == IPCOMP_NONE && (data->mark.value | data->mark.mask))
{
if (!add_uint32(hdr, sizeof(request), XFRMA_SET_MARK,
@@ -2034,6 +2051,10 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this,
{
return;
}
if (sa->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, sa->if_id))
{
return;
}
if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
@@ -2132,6 +2153,10 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
{
return FAILED;
}
if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id))
{
return FAILED;
}
if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
@@ -2236,6 +2261,10 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
{
return FAILED;
}
if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id))
{
return FAILED;
}
switch (this->socket_xfrm->send_ack(this->socket_xfrm, hdr))
{
@@ -2282,6 +2311,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
.spi = htonl(ntohs(data->cpi)),
.proto = IPPROTO_COMP,
.mark = id->mark,
.if_id = id->if_id,
};
kernel_ipsec_update_sa_t ipcomp = {
.new_src = data->new_src,
@@ -2312,6 +2342,10 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
{
return FAILED;
}
if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id))
{
return FAILED;
}
if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
@@ -2786,6 +2820,12 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
policy_change_done(this, policy);
return FAILED;
}
if (ipsec->if_id &&
!add_uint32(hdr, sizeof(request), XFRMA_IF_ID, ipsec->if_id))
{
policy_change_done(this, policy);
return FAILED;
}
this->mutex->unlock(this->mutex);
status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr);
@@ -2806,10 +2846,12 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
* - this is an outbound policy (to just get one for each child)
* - routing is not disabled via strongswan.conf
* - the selector is not for a specific protocol/port
* - no XFRM interface ID is configured
* - we are in tunnel/BEET mode or install a bypass policy
*/
if (policy->direction == POLICY_OUT && this->install_routes &&
!policy->sel.proto && !policy->sel.dport && !policy->sel.sport)
!policy->sel.proto && !policy->sel.dport && !policy->sel.sport &&
!policy->if_id)
{
if (mapping->type == POLICY_PASS ||
(mapping->type == POLICY_IPSEC && ipsec->cfg.mode != MODE_TRANSPORT))
@@ -2837,6 +2879,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
INIT(policy,
.sel = ts2selector(id->src_ts, id->dst_ts, id->interface),
.mark = id->mark.value & id->mark.mask,
.if_id = id->if_id,
.direction = id->dir,
.reqid = data->sa->reqid,
);
@@ -2882,7 +2925,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
/* cache the assigned IPsec SA */
assigned_sa = policy_sa_create(this, id->dir, data->type, data->src,
data->dst, id->src_ts, id->dst_ts, id->mark, data->sa);
data->dst, id->src_ts, id->dst_ts, id->mark,
id->if_id, data->sa);
assigned_sa->auto_priority = get_priority(policy, data->prio, id->interface);
assigned_sa->priority = this->get_priority ? this->get_priority(id, data)
: data->manual_prio;
@@ -2980,6 +3024,10 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
{
return FAILED;
}
if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id))
{
return FAILED;
}
if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
@@ -3048,6 +3096,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
.src = data->src,
.dst = data->dst,
.mark = id->mark,
.if_id = id->if_id,
.cfg = *data->sa,
};
char markstr[32] = "";
@@ -3063,6 +3112,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
memset(&policy, 0, sizeof(policy_entry_t));
policy.sel = ts2selector(id->src_ts, id->dst_ts, id->interface);
policy.mark = id->mark.value & id->mark.mask;
policy.if_id = id->if_id;
policy.direction = id->dir;
/* find the policy */
@@ -3153,6 +3203,11 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
policy_change_done(this, current);
return FAILED;
}
if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id))
{
policy_change_done(this, current);
return FAILED;
}
if (current->route)
{
@@ -1,7 +1,8 @@
/*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
* Copyright (C) 2008 Tobias Brunner
*
* Copyright (C) 2008-2019 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -687,8 +688,8 @@ netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names,
return &this->public;
}
/**
* Described in header.
/*
* Described in header
*/
void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
size_t buflen)
@@ -705,13 +706,14 @@ void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
rta->rta_type = rta_type;
rta->rta_len = RTA_LENGTH(data.len);
memcpy(RTA_DATA(rta), data.ptr, data.len);
hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len);
}
/**
* Described in header.
* Add an attribute to the given Netlink message
*/
void* netlink_reserve(struct nlmsghdr *hdr, int buflen, int type, int len)
static struct rtattr *add_rtattr(struct nlmsghdr *hdr, int buflen, int type,
int len)
{
struct rtattr *rta;
@@ -724,7 +726,44 @@ void* netlink_reserve(struct nlmsghdr *hdr, int buflen, int type, int len)
rta = ((void*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len);
rta->rta_type = type;
rta->rta_len = RTA_LENGTH(len);
hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len);
return rta;
}
/*
* Described in header
*/
void *netlink_nested_start(struct nlmsghdr *hdr, size_t buflen, int type)
{
return add_rtattr(hdr, buflen, type, 0);
}
/*
* Described in header
*/
void netlink_nested_end(struct nlmsghdr *hdr, void *attr)
{
struct rtattr *rta = attr;
void *end;
if (attr)
{
end = (char*)hdr + NLMSG_ALIGN(hdr->nlmsg_len);
rta->rta_len = end - attr;
}
}
/*
* Described in header
*/
void *netlink_reserve(struct nlmsghdr *hdr, int buflen, int type, int len)
{
struct rtattr *rta;
rta = add_rtattr(hdr, buflen, type, len);
if (!rta)
{
return NULL;
}
return RTA_DATA(rta);
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2008-2019 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -90,6 +90,28 @@ netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names,
void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
size_t buflen);
/**
* Creates an rtattr under which other rtattrs are nested to the given netlink
* message.
*
* The returned pointer has to be passed to netlink_nested_end() after the
* nested attributes have been added to the message.
*
* @param hdr netlink message
* @param buflen size of full netlink buffer
* @param type RTA type
* @return attribute pointer
*/
void *netlink_nested_start(struct nlmsghdr *hdr, size_t buflen, int type);
/**
* Updates the length of the given attribute after nested attributes were added.
*
* @param hdr netlink message
* @param attr attribute returned from netlink_nested_start()
*/
void netlink_nested_end(struct nlmsghdr *hdr, void *attr);
/**
* Reserve space in a netlink message for given size and type, returning buffer.
*
@@ -258,6 +258,7 @@ static void invoke_once(private_updown_listener_t *this, ike_sa_t *ike_sa,
host_t *me, *other, *host;
char *iface;
uint8_t mask;
uint32_t if_id;
mark_t mark;
bool is_host, is_ipv6;
int out;
@@ -356,6 +357,16 @@ static void invoke_once(private_updown_listener_t *this, ike_sa_t *ike_sa,
push_env(envp, countof(envp), "PLUTO_MARK_OUT=%u/0x%08x",
mark.value, mark.mask);
}
if_id = child_sa->get_if_id(child_sa, TRUE);
if (if_id)
{
push_env(envp, countof(envp), "PLUTO_IF_ID_IN=%u", if_id);
}
if_id = child_sa->get_if_id(child_sa, FALSE);
if (if_id)
{
push_env(envp, countof(envp), "PLUTO_IF_ID_OUT=%u", if_id);
}
if (ike_sa->has_condition(ike_sa, COND_NAT_ANY))
{
push_env(envp, countof(envp), "PLUTO_UDP_ENC=%u",
+4
View File
@@ -772,6 +772,8 @@ command.
nat-remote = <yes, if remote endpoint is behind a NAT>
nat-fake = <yes, if NAT situation has been faked as responder>
nat-any = <yes, if any endpoint is behind a NAT (also if faked)>
if-id-in = <hex encoded default inbound XFRM interface ID>
if-id-out = <hex encoded default outbound XFRM interface ID>
encr-alg = <IKE encryption algorithm string>
encr-keysize = <key size for encr-alg, if applicable>
integ-alg = <IKE integrity algorithm string>
@@ -813,6 +815,8 @@ command.
mark-mask-in = <hex encoded inbound Netfilter mark mask>
mark-out = <hex encoded outbound Netfilter mark value>
mark-mask-out = <hex encoded outbound Netfilter mark mask>
if-id-in = <hex encoded inbound XFRM interface ID>
if-id-out = <hex encoded outbound XFRM interface ID>
encr-alg = <ESP encryption algorithm name, if any>
encr-keysize = <ESP encryption key size, if applicable>
integ-alg = <ESP or AH integrity algorithm name, if any>
+27
View File
@@ -327,6 +327,8 @@ typedef struct {
uint64_t over_time;
uint64_t rand_time;
uint8_t dscp;
uint32_t if_id_in;
uint32_t if_id_out;
#ifdef ME
bool mediation;
char *mediated_by;
@@ -421,6 +423,8 @@ static void log_peer_data(peer_data_t *data)
DBG2(DBG_CFG, " over_time = %llu", data->over_time);
DBG2(DBG_CFG, " rand_time = %llu", data->rand_time);
DBG2(DBG_CFG, " proposals = %#P", data->proposals);
DBG2(DBG_CFG, " if_id_in = %u", data->if_id_in);
DBG2(DBG_CFG, " if_id_out = %u", data->if_id_out);
#ifdef ME
DBG2(DBG_CFG, " mediation = %u", data->mediation);
if (data->mediated_by)
@@ -528,6 +532,8 @@ static void log_child_data(child_data_t *data, char *name)
DBG2(DBG_CFG, " tfc = %d", cfg->tfc);
DBG2(DBG_CFG, " priority = %d", cfg->priority);
DBG2(DBG_CFG, " interface = %s", cfg->interface);
DBG2(DBG_CFG, " if_id_in = %u", cfg->if_id_in);
DBG2(DBG_CFG, " if_id_out = %u", cfg->if_id_out);
DBG2(DBG_CFG, " mark_in = %u/%u",
cfg->mark_in.value, cfg->mark_in.mask);
DBG2(DBG_CFG, " mark_in_sa = %u", has_opt(OPT_MARK_IN_SA));
@@ -1220,6 +1226,21 @@ CALLBACK(parse_set_mark, bool,
return mark_from_string(buf, MARK_OP_SAME, out);
}
/**
* Parse interface ID
*/
CALLBACK(parse_if_id, bool,
uint32_t *out, chunk_t v)
{
char buf[32];
if (!vici_stringify(v, buf, sizeof(buf)))
{
return FALSE;
}
return if_id_from_string(buf, out);
}
/**
* Parse TFC padding option
*/
@@ -1688,6 +1709,8 @@ CALLBACK(child_kv, bool,
{ "copy_df", parse_opt_copy_df, &child->cfg.options },
{ "copy_ecn", parse_opt_copy_ecn, &child->cfg.options },
{ "copy_dscp", parse_copy_dscp, &child->cfg.copy_dscp },
{ "if_id_in", parse_if_id, &child->cfg.if_id_in },
{ "if_id_out", parse_if_id, &child->cfg.if_id_out },
};
return parse_rules(rules, countof(rules), name, value,
@@ -1766,6 +1789,8 @@ CALLBACK(peer_kv, bool,
{ "rand_time", parse_time, &peer->rand_time },
{ "ppk_id", parse_peer_id, &peer->ppk_id },
{ "ppk_required", parse_bool, &peer->ppk_required },
{ "if_id_in", parse_if_id, &peer->if_id_in },
{ "if_id_out", parse_if_id, &peer->if_id_out },
#ifdef ME
{ "mediation", parse_bool, &peer->mediation },
{ "mediated_by", parse_string, &peer->mediated_by },
@@ -2504,6 +2529,8 @@ CALLBACK(config_sn, bool,
.dpd_timeout = peer.dpd_timeout,
.ppk_id = peer.ppk_id ? peer.ppk_id->clone(peer.ppk_id) : NULL,
.ppk_required = peer.ppk_required,
.if_id_in = peer.if_id_in,
.if_id_out = peer.if_id_out,
};
#ifdef ME
cfg.mediation = peer.mediation;
+23
View File
@@ -155,6 +155,7 @@ static void list_child(private_vici_query_t *this, vici_builder_t *b,
{
time_t t;
uint64_t bytes, packets;
uint32_t if_id;
uint16_t alg, ks;
proposal_t *proposal;
enumerator_t *enumerator;
@@ -185,6 +186,16 @@ static void list_child(private_vici_query_t *this, vici_builder_t *b,
}
add_mark(b, child->get_mark(child, TRUE), "mark-in", "mark-mask-in");
add_mark(b, child->get_mark(child, FALSE), "mark-out", "mark-mask-out");
if_id = child->get_if_id(child, TRUE);
if (if_id)
{
b->add_kv(b, "if-id-in", "%.8x", if_id);
}
if_id = child->get_if_id(child, FALSE);
if (if_id)
{
b->add_kv(b, "if-id-out", "%.8x", if_id);
}
proposal = child->get_proposal(child);
if (proposal)
{
@@ -343,6 +354,7 @@ static void list_ike(private_vici_query_t *this, vici_builder_t *b,
ike_sa_id_t *id;
identification_t *eap;
proposal_t *proposal;
uint32_t if_id;
uint16_t alg, ks;
host_t *host;
@@ -389,6 +401,17 @@ static void list_ike(private_vici_query_t *this, vici_builder_t *b,
add_condition(b, ike_sa, "nat-fake", COND_NAT_FAKE);
add_condition(b, ike_sa, "nat-any", COND_NAT_ANY);
if_id = ike_sa->get_if_id(ike_sa, TRUE);
if (if_id)
{
b->add_kv(b, "if-id-in", "%.8x", if_id);
}
if_id = ike_sa->get_if_id(ike_sa, FALSE);
if (if_id)
{
b->add_kv(b, "if-id-out", "%.8x", if_id);
}
proposal = ike_sa->get_proposal(ike_sa);
if (proposal)
{
+66 -35
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2018 Tobias Brunner
* Copyright (C) 2006-2019 Tobias Brunner
* Copyright (C) 2016 Andreas Steffen
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger
@@ -153,6 +153,16 @@ struct private_child_sa_t {
*/
bool policies_fwd_out;
/**
* Inbound interface ID
*/
uint32_t if_id_in;
/**
* Outbound interface ID
*/
uint32_t if_id_out;
/**
* inbound mark used for this child_sa
*/
@@ -539,6 +549,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
.spi = this->my_spi,
.proto = proto_ike2ip(this->protocol),
.mark = mark_in_sa(this),
.if_id = this->if_id_in,
};
kernel_ipsec_query_sa_t query = {};
@@ -572,6 +583,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
.spi = this->other_spi,
.proto = proto_ike2ip(this->protocol),
.mark = this->mark_out,
.if_id = this->if_id_out,
};
kernel_ipsec_query_sa_t query = {};
@@ -619,6 +631,7 @@ static bool update_usetime(private_child_sa_t *this, bool inbound)
.src_ts = other_ts,
.dst_ts = my_ts,
.mark = this->mark_in,
.if_id = this->if_id_in,
};
kernel_ipsec_query_policy_t query = {};
@@ -644,6 +657,7 @@ static bool update_usetime(private_child_sa_t *this, bool inbound)
.src_ts = my_ts,
.dst_ts = other_ts,
.mark = this->mark_out,
.if_id = this->if_id_out,
.interface = this->config->get_interface(this->config),
};
kernel_ipsec_query_policy_t query = {};
@@ -707,11 +721,13 @@ METHOD(child_sa_t, get_usestats, void,
METHOD(child_sa_t, get_mark, mark_t,
private_child_sa_t *this, bool inbound)
{
if (inbound)
{
return this->mark_in;
}
return this->mark_out;
return inbound ? this->mark_in : this->mark_out;
}
METHOD(child_sa_t, get_if_id, uint32_t,
private_child_sa_t *this, bool inbound)
{
return inbound ? this->if_id_in : this->if_id_out;
}
METHOD(child_sa_t, get_lifetime, time_t,
@@ -832,7 +848,8 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
if (!this->reqid_allocated && !this->static_reqid)
{
status = charon->kernel->alloc_reqid(charon->kernel, my_ts, other_ts,
this->mark_in, this->mark_out, &this->reqid);
this->mark_in, this->mark_out, this->if_id_in,
this->if_id_out, &this->reqid);
if (status != SUCCESS)
{
my_ts->destroy(my_ts);
@@ -872,6 +889,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
.spi = spi,
.proto = proto_ike2ip(this->protocol),
.mark = inbound ? mark_in_sa(this) : this->mark_out,
.if_id = inbound ? this->if_id_in : this->if_id_out,
};
sa = (kernel_ipsec_add_sa_t){
.reqid = this->reqid,
@@ -991,6 +1009,7 @@ static status_t install_policies_inbound(private_child_sa_t *this,
.src_ts = other_ts,
.dst_ts = my_ts,
.mark = this->mark_in,
.if_id = this->if_id_in,
};
kernel_ipsec_manage_policy_t in_policy = {
.type = type,
@@ -1025,6 +1044,7 @@ static status_t install_policies_outbound(private_child_sa_t *this,
.src_ts = my_ts,
.dst_ts = other_ts,
.mark = this->mark_out,
.if_id = this->if_id_out,
.interface = this->config->get_interface(this->config),
};
kernel_ipsec_manage_policy_t out_policy = {
@@ -1098,6 +1118,7 @@ static void del_policies_inbound(private_child_sa_t *this,
.src_ts = other_ts,
.dst_ts = my_ts,
.mark = this->mark_in,
.if_id = this->if_id_in,
};
kernel_ipsec_manage_policy_t in_policy = {
.type = type,
@@ -1131,6 +1152,7 @@ static void del_policies_outbound(private_child_sa_t *this,
.src_ts = my_ts,
.dst_ts = other_ts,
.mark = this->mark_out,
.if_id = this->if_id_out,
.interface = this->config->get_interface(this->config),
};
kernel_ipsec_manage_policy_t out_policy = {
@@ -1228,7 +1250,8 @@ METHOD(child_sa_t, install_policies, status_t,
array_create_enumerator(this->other_ts));
status = charon->kernel->alloc_reqid(
charon->kernel, my_ts_list, other_ts_list,
this->mark_in, this->mark_out, &this->reqid);
this->mark_in, this->mark_out, this->if_id_in,
this->if_id_out, &this->reqid);
my_ts_list->destroy(my_ts_list);
other_ts_list->destroy(other_ts_list);
if (status != SUCCESS)
@@ -1403,6 +1426,7 @@ METHOD(child_sa_t, remove_outbound, void,
.spi = this->other_spi,
.proto = proto_ike2ip(this->protocol),
.mark = this->mark_out,
.if_id = this->if_id_out,
};
kernel_ipsec_del_sa_t sa = {
.cpi = this->other_cpi,
@@ -1453,6 +1477,7 @@ static status_t update_sas(private_child_sa_t *this, host_t *me, host_t *other,
.spi = this->my_spi,
.proto = proto_ike2ip(this->protocol),
.mark = mark_in_sa(this),
.if_id = this->if_id_in,
};
kernel_ipsec_update_sa_t sa = {
.cpi = this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0,
@@ -1477,6 +1502,7 @@ static status_t update_sas(private_child_sa_t *this, host_t *me, host_t *other,
.spi = this->other_spi,
.proto = proto_ike2ip(this->protocol),
.mark = this->mark_out,
.if_id = this->if_id_out,
};
kernel_ipsec_update_sa_t sa = {
.cpi = this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0,
@@ -1679,6 +1705,7 @@ METHOD(child_sa_t, destroy, void,
.spi = this->my_spi,
.proto = proto_ike2ip(this->protocol),
.mark = mark_in_sa(this),
.if_id = this->if_id_in,
};
kernel_ipsec_del_sa_t sa = {
.cpi = this->my_cpi,
@@ -1693,6 +1720,7 @@ METHOD(child_sa_t, destroy, void,
.spi = this->other_spi,
.proto = proto_ike2ip(this->protocol),
.mark = this->mark_out,
.if_id = this->if_id_out,
};
kernel_ipsec_del_sa_t sa = {
.cpi = this->other_cpi,
@@ -1703,7 +1731,8 @@ METHOD(child_sa_t, destroy, void,
if (this->reqid_allocated)
{
if (charon->kernel->release_reqid(charon->kernel,
this->reqid, this->mark_in, this->mark_out) != SUCCESS)
this->reqid, this->mark_in, this->mark_out,
this->if_id_in, this->if_id_out) != SUCCESS)
{
DBG1(DBG_CHD, "releasing reqid %u failed", this->reqid);
}
@@ -1755,16 +1784,14 @@ static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
return host;
}
/**
* Described in header.
/*
* Described in header
*/
child_sa_t * child_sa_create(host_t *me, host_t* other,
child_cfg_t *config, uint32_t reqid, bool encap,
u_int mark_in, u_int mark_out)
child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
child_sa_create_t *data)
{
private_child_sa_t *this;
static refcount_t unique_id = 0, unique_mark = 0;
refcount_t mark = 0;
INIT(this,
.public = {
@@ -1787,6 +1814,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.get_installtime = _get_installtime,
.get_usestats = _get_usestats,
.get_mark = _get_mark,
.get_if_id = _get_if_id,
.has_encap = _has_encap,
.get_ipcomp = _get_ipcomp,
.set_ipcomp = _set_ipcomp,
@@ -1809,7 +1837,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.create_policy_enumerator = _create_policy_enumerator,
.destroy = _destroy,
},
.encap = encap,
.encap = data->encap,
.ipcomp = IPCOMP_NONE,
.state = CHILD_CREATED,
.my_ts = array_create(0, 0),
@@ -1822,6 +1850,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.unique_id = ref_get(&unique_id),
.mark_in = config->get_mark(config, TRUE),
.mark_out = config->get_mark(config, FALSE),
.if_id_in = config->get_if_id(config, TRUE) ?: data->if_id_in_def,
.if_id_out = config->get_if_id(config, FALSE) ?: data->if_id_out_def,
.install_time = time_monotonic(NULL),
.policies_fwd_out = config->has_option(config, OPT_FWD_OUT_POLICIES),
);
@@ -1829,22 +1859,31 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->config = config;
config->get_ref(config);
if (mark_in)
if (data->mark_in)
{
this->mark_in.value = mark_in;
this->mark_in.value = data->mark_in;
}
if (mark_out)
if (data->mark_out)
{
this->mark_out.value = mark_out;
this->mark_out.value = data->mark_out;
}
if (data->if_id_in)
{
this->if_id_in = data->if_id_in;
}
if (data->if_id_out)
{
this->if_id_out = data->if_id_out;
}
allocate_unique_if_ids(&this->if_id_in, &this->if_id_out);
if (MARK_IS_UNIQUE(this->mark_in.value) ||
MARK_IS_UNIQUE(this->mark_out.value))
{
bool unique_dir;
unique_dir = this->mark_in.value == MARK_UNIQUE_DIR ||
this->mark_out.value == MARK_UNIQUE_DIR;
refcount_t mark = 0;
bool unique_dir = this->mark_in.value == MARK_UNIQUE_DIR ||
this->mark_out.value == MARK_UNIQUE_DIR;
if (!unique_dir)
{
@@ -1852,19 +1891,11 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
}
if (MARK_IS_UNIQUE(this->mark_in.value))
{
if (unique_dir)
{
mark = ref_get(&unique_mark);
}
this->mark_in.value = mark;
this->mark_in.value = unique_dir ? ref_get(&unique_mark) : mark;
}
if (MARK_IS_UNIQUE(this->mark_out.value))
{
if (unique_dir)
{
mark = ref_get(&unique_mark);
}
this->mark_out.value = mark;
this->mark_out.value = unique_dir ? ref_get(&unique_mark) : mark;
}
}
@@ -1878,7 +1909,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
* replace the temporary SA on the kernel level. Rekeying such an SA
* requires an explicit reqid, as the cache currently knows the original
* selectors only for that reqid. */
this->reqid = reqid;
this->reqid = data->reqid;
}
else
{
+37 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2017 Tobias Brunner
* Copyright (C) 2006-2019 Tobias Brunner
* Copyright (C) 2006-2008 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger
* HSR Hochschule fuer Technik Rapperswil
@@ -26,6 +26,7 @@
typedef enum child_sa_state_t child_sa_state_t;
typedef enum child_sa_outbound_state_t child_sa_outbound_state_t;
typedef struct child_sa_t child_sa_t;
typedef struct child_sa_create_t child_sa_create_t;
#include <library.h>
#include <crypto/prf_plus.h>
@@ -360,6 +361,14 @@ struct child_sa_t {
*/
mark_t (*get_mark)(child_sa_t *this, bool inbound);
/**
* Get the interface ID used with this CHILD_SA.
*
* @param inbound TRUE to get inbound ID, FALSE for outbound
* @return interface ID used with this CHILD_SA
*/
uint32_t (*get_if_id)(child_sa_t *this, bool inbound);
/**
* Create an enumerator over traffic selectors of one side.
*
@@ -504,20 +513,40 @@ struct child_sa_t {
void (*destroy) (child_sa_t *this);
};
/**
* Data passed to the constructor of a child_sa_t object.
*/
struct child_sa_create_t {
/** Optional reqid of old CHILD_SA when rekeying */
uint32_t reqid;
/** Optional inbound mark when rekeying */
uint32_t mark_in;
/** Optional outbound mark when rekeying */
uint32_t mark_out;
/** Optional inbound interface ID when rekeying */
uint32_t if_id_in;
/** Optional outbound interface ID when rekeying */
uint32_t if_id_out;
/** Optional default inbound interface ID, if neither if_id_in, nor config
* sets one */
uint32_t if_id_in_def;
/** Optional default outbound interface ID, if neither if_id_out, nor config
* sets one */
uint32_t if_id_out_def;
/** TRUE to enable UDP encapsulation (NAT traversal) */
bool encap;
};
/**
* Constructor to create a child SA negotiated with IKE.
*
* @param me own address
* @param other remote address
* @param config config to use for this CHILD_SA
* @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise
* @param encap TRUE to enable UDP encapsulation (NAT traversal)
* @param mark_in explicit inbound mark value to use, 0 for config
* @param mark_out explicit outbound mark value to use, 0 for config
* @param data data for this CHILD_SA
* @return child_sa_t object
*/
child_sa_t * child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
uint32_t reqid, bool encap,
u_int mark_in, u_int mark_out);
child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
child_sa_create_t *data);
#endif /** CHILD_SA_H_ @}*/
+25 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2018 Tobias Brunner
* Copyright (C) 2006-2019 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -296,6 +296,16 @@ struct private_ike_sa_t {
* Timestamps of redirect attempts to handle loops
*/
array_t *redirected_at;
/**
* Inbound interface ID
*/
uint32_t if_id_in;
/**
* Outbound interface ID
*/
uint32_t if_id_out;
};
/**
@@ -419,11 +429,15 @@ METHOD(ike_sa_t, set_peer_cfg, void,
DESTROY_IF(this->peer_cfg);
this->peer_cfg = peer_cfg;
if (this->ike_cfg == NULL)
if (!this->ike_cfg)
{
this->ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
this->ike_cfg->get_ref(this->ike_cfg);
}
this->if_id_in = peer_cfg->get_if_id(peer_cfg, TRUE);
this->if_id_out = peer_cfg->get_if_id(peer_cfg, FALSE);
allocate_unique_if_ids(&this->if_id_in, &this->if_id_out);
}
METHOD(ike_sa_t, get_auth_cfg, auth_cfg_t*,
@@ -1656,6 +1670,12 @@ METHOD(ike_sa_t, set_other_id, void,
this->other_id = other;
}
METHOD(ike_sa_t, get_if_id, uint32_t,
private_ike_sa_t *this, bool inbound)
{
return inbound ? this->if_id_in : this->if_id_out;
}
METHOD(ike_sa_t, add_child_sa, void,
private_ike_sa_t *this, child_sa_t *child_sa)
{
@@ -2810,6 +2830,8 @@ METHOD(ike_sa_t, inherit_post, void,
this->other_host = other->other_host->clone(other->other_host);
this->my_id = other->my_id->clone(other->my_id);
this->other_id = other->other_id->clone(other->other_id);
this->if_id_in = other->if_id_in;
this->if_id_out = other->if_id_out;
/* apply assigned virtual IPs... */
while (array_remove(other->my_vips, ARRAY_HEAD, &vip))
@@ -3087,6 +3109,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.create_virtual_ip_enumerator = _create_virtual_ip_enumerator,
.add_configuration_attribute = _add_configuration_attribute,
.create_attribute_enumerator = _create_attribute_enumerator,
.get_if_id = _get_if_id,
.set_kmaddress = _set_kmaddress,
.create_task_enumerator = _create_task_enumerator,
.remove_task = _remove_task,
+9 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2018 Tobias Brunner
* Copyright (C) 2006-2019 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -1068,6 +1068,14 @@ struct ike_sa_t {
*/
void (*clear_virtual_ips) (ike_sa_t *this, bool local);
/**
* Get interface ID to use as default for children of this IKE_SA.
*
* @param inbound TRUE for inbound interface ID
* @return interface ID
*/
uint32_t (*get_if_id)(ike_sa_t *this, bool inbound);
/**
* Create an enumerator over virtual IPs.
*
+2
View File
@@ -1843,6 +1843,8 @@ METHOD(task_manager_t, queue_child_rekey, void,
task->use_reqid(task, child_sa->get_reqid(child_sa));
task->use_marks(task, child_sa->get_mark(child_sa, TRUE).value,
child_sa->get_mark(child_sa, FALSE).value);
task->use_if_ids(task, child_sa->get_if_id(child_sa, TRUE),
child_sa->get_if_id(child_sa, FALSE));
task->rekey(task, child_sa->get_spi(child_sa, TRUE));
queue_task(this, &task->task);
+45 -42
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2012-2019 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2011 Martin Willi
@@ -151,19 +151,9 @@ struct private_quick_mode_t {
uint64_t lifebytes;
/**
* Reqid to use, 0 for auto-allocate
* Data collected to create the CHILD_SA
*/
uint32_t reqid;
/**
* Explicit inbound mark value to use, if any
*/
u_int mark_in;
/**
* Explicit inbound mark value to use, if any
*/
u_int mark_out;
child_sa_create_t child;
/**
* SPI of SA we rekey
@@ -185,11 +175,6 @@ struct private_quick_mode_t {
*/
protocol_id_t proto;
/**
* Use UDP encapsulation
*/
bool udp;
/**
* Message ID of handled quick mode exchange
*/
@@ -627,7 +612,7 @@ static bool get_ts(private_quick_mode_t *this, message_t *message)
tsr = traffic_selector_create_from_subnet(hsr->clone(hsr),
hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0, 65535);
}
if (this->mode == MODE_TRANSPORT && this->udp &&
if (this->mode == MODE_TRANSPORT && this->child.encap &&
(!tsi->is_host(tsi, hsi) || !tsr->is_host(tsr, hsr)))
{ /* change TS in case of a NAT in transport mode */
DBG2(DBG_IKE, "changing received traffic selectors %R=== %R due to NAT",
@@ -839,15 +824,19 @@ METHOD(task_t, build_i, status_t,
diffie_hellman_group_t group;
encap_t encap;
this->udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
this->mode = this->config->get_mode(this->config);
this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa,
TRUE);
this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa,
FALSE);
this->child.encap = this->ike_sa->has_condition(this->ike_sa,
COND_NAT_ANY);
this->child_sa = child_sa_create(
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->config, this->reqid, this->udp,
this->mark_in, this->mark_out);
this->config, &this->child);
if (this->udp && this->mode == MODE_TRANSPORT)
if (this->child.encap && this->mode == MODE_TRANSPORT)
{
/* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
add_nat_oa_payloads(this, message);
@@ -914,7 +903,7 @@ METHOD(task_t, build_i, status_t,
}
get_lifetimes(this);
encap = get_encap(this->ike_sa, this->udp);
encap = get_encap(this->ike_sa, this->child.encap);
sa_payload = sa_payload_create_from_proposals_v1(list,
this->lifetime, this->lifebytes, AUTH_NONE,
this->mode, encap, this->cpi_i);
@@ -1026,7 +1015,7 @@ static void check_for_rekeyed_child(private_quick_mode_t *this, bool responder)
name = this->config->get_name(this->config);
enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
while (this->reqid == 0 && enumerator->enumerate(enumerator, &child_sa))
while (!this->child.reqid && enumerator->enumerate(enumerator, &child_sa))
{
if (streq(child_sa->get_name(child_sa), name))
{
@@ -1041,12 +1030,16 @@ static void check_for_rekeyed_child(private_quick_mode_t *this, bool responder)
remote->equals(remote, other_ts) &&
this->proposal->equals(this->proposal, proposal))
{
this->reqid = child_sa->get_reqid(child_sa);
this->rekey = child_sa->get_spi(child_sa, TRUE);
this->mark_in = child_sa->get_mark(child_sa,
TRUE).value;
this->mark_out = child_sa->get_mark(child_sa,
FALSE).value;
this->child.reqid = child_sa->get_reqid(child_sa);
this->child.mark_in = child_sa->get_mark(child_sa,
TRUE).value;
this->child.mark_out = child_sa->get_mark(child_sa,
FALSE).value;
this->child.if_id_in = child_sa->get_if_id(child_sa,
TRUE);
this->child.if_id_out = child_sa->get_if_id(child_sa,
FALSE);
child_sa->set_state(child_sa, CHILD_REKEYING);
DBG1(DBG_IKE, "detected rekeying of CHILD_SA %s{%u}",
child_sa->get_name(child_sa),
@@ -1089,7 +1082,8 @@ METHOD(task_t, process_r, status_t,
return send_notify(this, INVALID_PAYLOAD_TYPE);
}
this->mode = sa_payload->get_encap_mode(sa_payload, &this->udp);
this->mode = sa_payload->get_encap_mode(sa_payload,
&this->child.encap);
if (!get_ts(this, message))
{
@@ -1180,12 +1174,14 @@ METHOD(task_t, process_r, status_t,
}
check_for_rekeyed_child(this, TRUE);
this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa,
TRUE);
this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa,
FALSE);
this->child_sa = child_sa_create(
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->config, this->reqid, this->udp,
this->mark_in, this->mark_out);
this->config, &this->child);
tsi = linked_list_create_with_items(this->tsi, NULL);
tsr = linked_list_create_with_items(this->tsr, NULL);
@@ -1277,13 +1273,13 @@ METHOD(task_t, build_r, status_t,
}
}
if (this->udp && this->mode == MODE_TRANSPORT)
if (this->child.encap && this->mode == MODE_TRANSPORT)
{
/* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */
add_nat_oa_payloads(this, message);
}
encap = get_encap(this->ike_sa, this->udp);
encap = get_encap(this->ike_sa, this->child.encap);
sa_payload = sa_payload_create_from_proposal_v1(this->proposal,
this->lifetime, this->lifebytes, AUTH_NONE,
this->mode, encap, this->cpi_r);
@@ -1408,14 +1404,21 @@ METHOD(quick_mode_t, get_mid, uint32_t,
METHOD(quick_mode_t, use_reqid, void,
private_quick_mode_t *this, uint32_t reqid)
{
this->reqid = reqid;
this->child.reqid = reqid;
}
METHOD(quick_mode_t, use_marks, void,
private_quick_mode_t *this, u_int in, u_int out)
private_quick_mode_t *this, uint32_t in, uint32_t out)
{
this->mark_in = in;
this->mark_out = out;
this->child.mark_in = in;
this->child.mark_out = out;
}
METHOD(quick_mode_t, use_if_ids, void,
private_quick_mode_t *this, uint32_t in, uint32_t out)
{
this->child.if_id_in = in;
this->child.if_id_out = out;
}
METHOD(quick_mode_t, rekey, void,
@@ -1446,8 +1449,7 @@ METHOD(task_t, migrate, void,
this->dh = NULL;
this->spi_i = 0;
this->spi_r = 0;
this->mark_in = 0;
this->mark_out = 0;
this->child = (child_sa_create_t){};
if (!this->initiator)
{
@@ -1488,6 +1490,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
.get_mid = _get_mid,
.use_reqid = _use_reqid,
.use_marks = _use_marks,
.use_if_ids = _use_if_ids,
.rekey = _rekey,
},
.ike_sa = ike_sa,
+10 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Tobias Brunner
* Copyright (C) 2015-2019 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2011 Martin Willi
@@ -61,7 +61,15 @@ struct quick_mode_t {
* @param in inbound mark value
* @param out outbound mark value
*/
void (*use_marks)(quick_mode_t *this, u_int in, u_int out);
void (*use_marks)(quick_mode_t *this, uint32_t in, uint32_t out);
/**
* Use specific interface IDs, overriding configuration.
*
* @param in inbound interface ID
* @param out outbound interface ID
*/
void (*use_if_ids)(quick_mode_t *this, uint32_t in, uint32_t out);
/**
* Set the SPI of the old SA, if rekeying.
+2
View File
@@ -1874,6 +1874,8 @@ static void trigger_mbb_reauth(private_task_manager_t *this)
child_create->use_marks(child_create,
child_sa->get_mark(child_sa, TRUE).value,
child_sa->get_mark(child_sa, FALSE).value);
/* interface IDs are not migrated as the new CHILD_SAs on old and new
* IKE_SA go though regular updown events */
new->queue_task(new, &child_create->task);
children = TRUE;
}
+32 -29
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2018 Tobias Brunner
* Copyright (C) 2008-2019 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
@@ -169,19 +169,9 @@ struct private_child_create_t {
uint16_t other_cpi;
/**
* reqid to use if we are rekeying
* Data collected to create the CHILD_SA
*/
uint32_t reqid;
/**
* Explicit inbound mark value
*/
u_int mark_in;
/**
* Explicit outbound mark value
*/
u_int mark_out;
child_sa_create_t child;
/**
* CHILD_SA which gets established
@@ -217,7 +207,10 @@ static void schedule_delayed_retry(private_child_create_t *this)
task = child_create_create(this->ike_sa,
this->config->get_ref(this->config), FALSE,
this->packet_tsi, this->packet_tsr);
task->use_reqid(task, this->reqid);
task->use_reqid(task, this->child.reqid);
task->use_marks(task, this->child.mark_in, this->child.mark_out);
task->use_if_ids(task, this->child.if_id_in, this->child.if_id_out);
DBG1(DBG_IKE, "creating CHILD_SA failed, trying again in %d seconds",
retry);
this->ike_sa->queue_task_delayed(this->ike_sa, (task_t*)task, retry);
@@ -1107,16 +1100,18 @@ METHOD(task_t, build_i, status_t,
this->dh_group == MODP_NONE);
this->mode = this->config->get_mode(this->config);
this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa, TRUE);
this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa, FALSE);
this->child.encap = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid,
this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY),
this->mark_in, this->mark_out);
this->ike_sa->get_other_host(this->ike_sa),
this->config, &this->child);
if (this->reqid)
if (this->child.reqid)
{
DBG0(DBG_IKE, "establishing CHILD_SA %s{%d} reqid %d",
this->child_sa->get_name(this->child_sa),
this->child_sa->get_unique_id(this->child_sa), this->reqid);
this->child_sa->get_unique_id(this->child_sa), this->child.reqid);
}
else
{
@@ -1392,10 +1387,12 @@ METHOD(task_t, build_r, status_t,
}
enumerator->destroy(enumerator);
this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa, TRUE);
this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa, FALSE);
this->child.encap = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid,
this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY),
this->mark_in, this->mark_out);
this->ike_sa->get_other_host(this->ike_sa),
this->config, &this->child);
if (this->ipcomp_received != IPCOMP_NONE)
{
@@ -1660,14 +1657,21 @@ METHOD(task_t, process_i, status_t,
METHOD(child_create_t, use_reqid, void,
private_child_create_t *this, uint32_t reqid)
{
this->reqid = reqid;
this->child.reqid = reqid;
}
METHOD(child_create_t, use_marks, void,
private_child_create_t *this, u_int in, u_int out)
private_child_create_t *this, uint32_t in, uint32_t out)
{
this->mark_in = in;
this->mark_out = out;
this->child.mark_in = in;
this->child.mark_out = out;
}
METHOD(child_create_t, use_if_ids, void,
private_child_create_t *this, uint32_t in, uint32_t out)
{
this->child.if_id_in = in;
this->child.if_id_out = out;
}
METHOD(child_create_t, use_dh_group, void,
@@ -1745,10 +1749,8 @@ METHOD(task_t, migrate, void,
this->ipcomp = IPCOMP_NONE;
this->ipcomp_received = IPCOMP_NONE;
this->other_cpi = 0;
this->reqid = 0;
this->mark_in = 0;
this->mark_out = 0;
this->established = FALSE;
this->child = (child_sa_create_t){};
}
METHOD(task_t, destroy, void,
@@ -1797,6 +1799,7 @@ child_create_t *child_create_create(ike_sa_t *ike_sa,
.get_lower_nonce = _get_lower_nonce,
.use_reqid = _use_reqid,
.use_marks = _use_marks,
.use_if_ids = _use_if_ids,
.use_dh_group = _use_dh_group,
.task = {
.get_type = _get_type,
+10 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Tobias Brunner
* Copyright (C) 2018-2019 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* HSR Hochschule fuer Technik Rapperswil
*
@@ -58,7 +58,15 @@ struct child_create_t {
* @param in inbound mark value
* @param out outbound mark value
*/
void (*use_marks)(child_create_t *this, u_int in, u_int out);
void (*use_marks)(child_create_t *this, uint32_t in, uint32_t out);
/**
* Use specific interface IDs, overriding configuration.
*
* @param in inbound interface ID
* @param out outbound interface ID
*/
void (*use_if_ids)(child_create_t *this, uint32_t in, uint32_t out);
/**
* Initially propose a specific DH group to override configuration.
@@ -207,6 +207,9 @@ METHOD(task_t, build_i, status_t,
this->child_create->use_marks(this->child_create,
this->child_sa->get_mark(this->child_sa, TRUE).value,
this->child_sa->get_mark(this->child_sa, FALSE).value);
this->child_create->use_if_ids(this->child_create,
this->child_sa->get_if_id(this->child_sa, TRUE),
this->child_sa->get_if_id(this->child_sa, FALSE));
if (this->child_create->task.build(&this->child_create->task,
message) != NEED_MORE)
@@ -266,6 +269,9 @@ METHOD(task_t, build_r, status_t,
this->child_create->use_marks(this->child_create,
this->child_sa->get_mark(this->child_sa, TRUE).value,
this->child_sa->get_mark(this->child_sa, FALSE).value);
this->child_create->use_if_ids(this->child_create,
this->child_sa->get_if_id(this->child_sa, TRUE),
this->child_sa->get_if_id(this->child_sa, FALSE));
config = this->child_sa->get_config(this->child_sa);
this->child_create->set_config(this->child_create, config->get_ref(config));
this->child_create->task.build(&this->child_create->task, message);
+8 -1
View File
@@ -293,7 +293,14 @@ METHOD(trap_manager_t, install, bool,
this->lock->unlock(this->lock);
/* create and route CHILD_SA */
child_sa = child_sa_create(me, other, child, 0, FALSE, 0, 0);
child_sa_create_t child_data = {
/* TODO: no reason to allocate unique interface IDs, there is currently
* no event to use them upon trap installation and we'd also have to
* pass them in a later initiate() call */
.if_id_in_def = peer->get_if_id(peer, TRUE),
.if_id_out_def = peer->get_if_id(peer, FALSE),
};
child_sa = child_sa_create(me, other, child, &child_data);
list = linked_list_create_with_items(me, NULL);
my_ts = child->get_traffic_selectors(child, TRUE, NULL, list, FALSE);
+69
View File
@@ -147,3 +147,72 @@ bool mark_from_string(const char *value, mark_op_t ops, mark_t *mark)
}
return TRUE;
}
/*
* Described in header
*/
bool if_id_from_string(const char *value, uint32_t *if_id)
{
char *endptr;
if (!value)
{
return FALSE;
}
if (strcasepfx(value, "%unique"))
{
endptr = (char*)value + strlen("%unique");
if (strcasepfx(endptr, "-dir"))
{
*if_id = IF_ID_UNIQUE_DIR;
endptr += strlen("-dir");
}
else if (!*endptr)
{
*if_id = IF_ID_UNIQUE;
}
else
{
DBG1(DBG_APP, "invalid interface ID: %s", value);
return FALSE;
}
}
else
{
*if_id = strtoul(value, &endptr, 0);
}
if (*endptr)
{
DBG1(DBG_APP, "invalid interface ID: %s", value);
return FALSE;
}
return TRUE;
}
/*
* Described in header
*/
void allocate_unique_if_ids(uint32_t *in, uint32_t *out)
{
static refcount_t unique_if_id = 0;
if (IF_ID_IS_UNIQUE(*in) || IF_ID_IS_UNIQUE(*out))
{
refcount_t if_id = 0;
bool unique_dir = *in == IF_ID_UNIQUE_DIR ||
*out == IF_ID_UNIQUE_DIR;
if (!unique_dir)
{
if_id = ref_get(&unique_if_id);
}
if (IF_ID_IS_UNIQUE(*in))
{
*in = unique_dir ? ref_get(&unique_if_id) : if_id;
}
if (IF_ID_IS_UNIQUE(*out))
{
*out = unique_dir ? ref_get(&unique_if_id) : if_id;
}
}
}
+24
View File
@@ -240,4 +240,28 @@ enum mark_op_t {
*/
bool mark_from_string(const char *value, mark_op_t ops, mark_t *mark);
/**
* Special interface ID values to allocate a unique ID for each CHILD_SA/dir
*/
#define IF_ID_UNIQUE (0xFFFFFFFF)
#define IF_ID_UNIQUE_DIR (0xFFFFFFFE)
#define IF_ID_IS_UNIQUE(m) ((m) == IF_ID_UNIQUE || (m) == IF_ID_UNIQUE_DIR)
/**
* Try to parse an interface ID from the given string.
*
* @param value string to parse
* @param if_id interface ID to fill
* @return TRUE if parsing was successful
*/
bool if_id_from_string(const char *value, uint32_t *if_id);
/**
* Allocate up to two unique interface IDs depending on the given values.
*
* @param[out] in inbound interface ID
* @param[out] out outbound interface ID
*/
void allocate_unique_if_ids(uint32_t *in, uint32_t *out);
#endif /** IPSEC_TYPES_H_ @}*/
@@ -940,6 +940,84 @@ START_TEST(test_mark_from_string)
}
END_TEST
/*******************************************************************************
* if_id_from_string
*/
static struct {
char *s;
bool ok;
uint32_t i;
} if_id_data[] = {
{NULL, FALSE, 0 },
{"", TRUE, 0 },
{"/", FALSE, 0 },
{"42", TRUE, 42 },
{"0x42", TRUE, 0x42 },
{"x", FALSE, 0 },
{"42/", FALSE, 0 },
{"42/0", FALSE, 0 },
{"%unique", TRUE, IF_ID_UNIQUE },
{"%unique/", FALSE, 0},
{"%unique0xffffffffff", FALSE, 0},
{"0xffffffff", TRUE, IF_ID_UNIQUE},
{"%unique-dir", TRUE, IF_ID_UNIQUE_DIR},
{"%unique-dir/",FALSE, 0},
{"0xfffffffe", TRUE, IF_ID_UNIQUE_DIR},
{"%unique-", FALSE, 0},
{"%unique-foo", FALSE, 0},
};
START_TEST(test_if_id_from_string)
{
uint32_t if_id;
if (if_id_from_string(if_id_data[_i].s, &if_id))
{
ck_assert_int_eq(if_id, if_id_data[_i].i);
}
else
{
ck_assert(!if_id_data[_i].ok);
}
}
END_TEST
/*******************************************************************************
* allocate_unique_if_ids
*/
static struct {
uint32_t in;
uint32_t out;
uint32_t exp_in;
uint32_t exp_out;
} unique_if_id_data[] = {
{0, 0, 0, 0 },
{42, 42, 42, 42 },
{42, 1337, 42, 1337 },
/* each call increases the internal counter by 1 or 2*/
{IF_ID_UNIQUE, 42, 1, 42 },
{42, IF_ID_UNIQUE, 42, 2 },
{IF_ID_UNIQUE_DIR, 42, 3, 42 },
{42, IF_ID_UNIQUE_DIR, 42, 4 },
{IF_ID_UNIQUE, IF_ID_UNIQUE, 5, 5 },
{IF_ID_UNIQUE_DIR, IF_ID_UNIQUE, 6, 7 },
{IF_ID_UNIQUE, IF_ID_UNIQUE_DIR, 8, 9 },
{IF_ID_UNIQUE_DIR, IF_ID_UNIQUE_DIR, 10, 11 },
};
START_TEST(test_allocate_unique_if_ids)
{
uint32_t if_id_in = unique_if_id_data[_i].in,
if_id_out = unique_if_id_data[_i].out;
allocate_unique_if_ids(&if_id_in, &if_id_out);
ck_assert_int_eq(if_id_in, unique_if_id_data[_i].exp_in);
ck_assert_int_eq(if_id_out, unique_if_id_data[_i].exp_out);
}
END_TEST
/*******************************************************************************
* signature_schemes_for_key
*/
@@ -1087,6 +1165,14 @@ Suite *utils_suite_create()
tcase_add_loop_test(tc, test_mark_from_string, 0, countof(mark_data));
suite_add_tcase(s, tc);
tc = tcase_create("if_id_from_string");
tcase_add_loop_test(tc, test_if_id_from_string, 0, countof(if_id_data));
suite_add_tcase(s, tc);
tc = tcase_create("allocate_unique_if_ids");
tcase_add_loop_test(tc, test_allocate_unique_if_ids, 0, countof(unique_if_id_data));
suite_add_tcase(s, tc);
tc = tcase_create("signature_schemes_for_key");
tcase_add_loop_test(tc, test_signature_schemes_for_key, 0, countof(scheme_data));
suite_add_tcase(s, tc);
+32 -8
View File
@@ -166,12 +166,24 @@ CALLBACK(child_sas, int,
printf(" in %s%s%s", child->get(child, "spi-in"),
child->get(child, "cpi-in") ? "/" : "",
child->get(child, "cpi-in") ?: "");
if (child->get(child, "mark-in"))
if (child->get(child, "mark-in") || child->get(child, "if-id-in"))
{
printf(" (0x%s", child->get(child, "mark-in"));
if (child->get(child, "mark-mask-in"))
printf(" (");
if (child->get(child, "mark-in"))
{
printf("/0x%s", child->get(child, "mark-mask-in"));
printf("0x%s", child->get(child, "mark-in"));
if (child->get(child, "mark-mask-in"))
{
printf("/0x%s", child->get(child, "mark-mask-in"));
}
}
else
{
printf("-");
}
if (child->get(child, "if-id-in"))
{
printf("|0x%s", child->get(child, "if-id-in"));
}
printf(")");
}
@@ -186,12 +198,24 @@ CALLBACK(child_sas, int,
printf(" out %s%s%s", child->get(child, "spi-out"),
child->get(child, "cpi-out") ? "/" : "",
child->get(child, "cpi-out") ?: "");
if (child->get(child, "mark-out"))
if (child->get(child, "mark-out") || child->get(child, "if-id-out"))
{
printf(" (0x%s", child->get(child, "mark-out"));
if (child->get(child, "mark-mask-out"))
printf(" (");
if (child->get(child, "mark-out"))
{
printf("/0x%s", child->get(child, "mark-mask-out"));
printf("0x%s", child->get(child, "mark-out"));
if (child->get(child, "mark-mask-out"))
{
printf("/0x%s", child->get(child, "mark-mask-out"));
}
}
else
{
printf("-");
}
if (child->get(child, "if-id-out"))
{
printf("|0x%s", child->get(child, "if-id-out"));
}
printf(")");
}
+32
View File
@@ -280,6 +280,18 @@ connections.<conn>.pools =
other configuration attributes from. Each name references a pool by name
from either the **pools** section or an external pool.
connections.<conn>.if_id_in = 0
Default inbound XFRM interface ID for children.
XFRM interface ID set on inbound policies/SA, can be overridden by child
config, see there for details.
connections.<conn>.if_id_out = 0
Default outbound XFRM interface ID for children.
XFRM interface ID set on outbound policies/SA, can be overridden by child
cofnig, see there for details.
connections.<conn>.mediation = no
Whether this connection is a mediation connection.
@@ -916,6 +928,26 @@ connections.<conn>.children.<child>.mark_out = 0/0x00000000
An additional mask may be appended to the mark, separated by _/_. The
default mask if omitted is 0xffffffff.
connections.<conn>.children.<child>.if_id_in = 0
Inbound XFRM interface ID.
XFRM interface ID set on inbound policies/SA. This allows installing
duplicate policies/SAs and associates them with an interface with the same
ID. The special value _%unique_ sets a unique interface ID on each CHILD_SA
instance, beyond that the value _%unique-dir_ assigns a different unique
interface ID for each CHILD_SA direction (in/out).
connections.<conn>.children.<child>.if_id_out = 0
Outbound XFRM interface ID.
XFRM interface ID set on outbound policies/SA. This allows installing
duplicate policies/SAs and associates them with an interface with the same
ID. The special value _%unique_ sets a unique interface ID on each CHILD_SA
instance, beyond that the value _%unique-dir_ assigns a different unique
interface ID for each CHILD_SA direction (in/out).
The daemon will not install routes for CHILD_SAs that have this option set.
connections.<conn>.children.<child>.set_mark_in = 0/0x00000000
Netfilter mark applied to packets after the inbound IPsec SA processed them.
+1
View File
@@ -0,0 +1 @@
xfrmi
+13
View File
@@ -0,0 +1,13 @@
ipsec_PROGRAMS = xfrmi
xfrmi_SOURCES = xfrmi.c
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libcharon \
-I$(top_srcdir)/src/libcharon/plugins/kernel_netlink
xfrmi_LDADD = \
$(top_builddir)/src/libcharon/plugins/kernel_netlink/libstrongswan-kernel-netlink.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(top_builddir)/src/libcharon/libcharon.la
+322
View File
@@ -0,0 +1,322 @@
/*
* Copyright (C) 2019 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <net/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include "kernel_netlink_shared.h"
#ifndef IFLA_XFRM_MAX
enum {
IFLA_XFRM_UNSPEC,
IFLA_XFRM_LINK,
IFLA_XFRM_IF_ID,
__IFLA_XFRM_MAX
};
#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1)
#endif
/**
* Create an XFRM interface with the given ID and underlying interface
*/
static int add_xfrm_interface(char *name, uint32_t xfrm_id, uint32_t ifindex)
{
netlink_buf_t request;
struct nlmsghdr *hdr;
struct ifinfomsg *msg;
struct rtattr *linkinfo, *info_data;
netlink_socket_t *socket;
int status = 1;
socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE);
if (!socket)
{
return 1;
}
memset(&request, 0, sizeof(request));
hdr = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
hdr->nlmsg_type = RTM_NEWLINK;
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
msg = NLMSG_DATA(hdr);
msg->ifi_family = AF_UNSPEC;
netlink_add_attribute(hdr, IFLA_IFNAME, chunk_from_str(name),
sizeof(request));
linkinfo = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
sizeof(request));
info_data = netlink_nested_start(hdr, sizeof(request), IFLA_INFO_DATA);
netlink_add_attribute(hdr, IFLA_XFRM_IF_ID, chunk_from_thing(xfrm_id),
sizeof(request));
netlink_add_attribute(hdr, IFLA_XFRM_LINK, chunk_from_thing(ifindex),
sizeof(request));
netlink_nested_end(hdr, info_data);
netlink_nested_end(hdr, linkinfo);
switch (socket->send_ack(socket, hdr))
{
case SUCCESS:
status = 0;
break;
case ALREADY_DONE:
fprintf(stderr, "XFRM interface already exists\n");
break;
default:
fprintf(stderr, "failed to create XFRM interface\n");
break;
}
socket->destroy(socket);
return status;
}
/**
* Parse attributes nested in IFLA_INFO_DATA
*/
static void parse_info_data(struct rtattr *rta, size_t rtasize, char *phys,
uint32_t *if_id)
{
uint32_t ifindex;
while (RTA_OK(rta, rtasize))
{
switch (rta->rta_type)
{
case IFLA_XFRM_IF_ID:
if (RTA_PAYLOAD(rta) == sizeof(*if_id))
{
*if_id = *(uint32_t*)RTA_DATA(rta);
}
break;
case IFLA_XFRM_LINK:
if (RTA_PAYLOAD(rta) == sizeof(ifindex))
{
ifindex = *(uint32_t*)RTA_DATA(rta);
if_indextoname(ifindex, phys);
}
break;
default:
break;
}
rta = RTA_NEXT(rta, rtasize);
}
}
/**
* Parse attributes nested in IFLA_LINKINFO
*/
static void parse_linkinfo(struct rtattr *rta, size_t rtasize, char *phys,
uint32_t *if_id)
{
while (RTA_OK(rta, rtasize))
{
switch (rta->rta_type)
{
case IFLA_INFO_DATA:
parse_info_data(RTA_DATA(rta), RTA_PAYLOAD(rta), phys, if_id);
break;
default:
break;
}
rta = RTA_NEXT(rta, rtasize);
}
}
/**
* List all installed XFRM interfaces
*/
static int list_xfrm_interfaces()
{
netlink_buf_t request;
struct nlmsghdr *hdr, *out, *current;
struct ifinfomsg *msg;
struct rtattr *linkinfo;
netlink_socket_t *socket;
size_t len;
int status = 0;
socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE);
if (!socket)
{
return 1;
}
memset(&request, 0, sizeof(request));
hdr = &request.hdr;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
hdr->nlmsg_type = RTM_GETLINK;
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
msg = NLMSG_DATA(hdr);
msg->ifi_family = AF_UNSPEC;
linkinfo = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
sizeof(request));
netlink_nested_end(hdr, linkinfo);
if (socket->send(socket, hdr, &out, &len) != SUCCESS)
{
return FAILED;
}
current = out;
while (NLMSG_OK(current, len))
{
switch (current->nlmsg_type)
{
case NLMSG_DONE:
break;
case RTM_NEWLINK:
msg = NLMSG_DATA(current);
struct rtattr *rta = IFLA_RTA(msg);
size_t rtasize = IFLA_PAYLOAD(current);
char *name = NULL, phys[IF_NAMESIZE] = {};
uint32_t if_id = 0;
while (RTA_OK(rta, rtasize))
{
switch (rta->rta_type)
{
case IFLA_IFNAME:
name = RTA_DATA(rta);
break;
case IFLA_LINKINFO:
parse_linkinfo(RTA_DATA(rta), RTA_PAYLOAD(rta),
phys, &if_id);
break;
default:
break;
}
rta = RTA_NEXT(rta, rtasize);
}
if (name)
{
printf("%2u: %-16s dev %-8s if_id 0x%.8x [%u]\n",
msg->ifi_index, name, phys, if_id, if_id);
}
/* fall through */
default:
current = NLMSG_NEXT(current, len);
continue;
}
break;
}
free(out);
socket->destroy(socket);
return status;
}
static void usage(FILE *out, char *name)
{
fprintf(out, "Create XFRM interfaces\n\n");
fprintf(out, "%s [OPTIONS]\n\n", name);
fprintf(out, "Options:\n");
fprintf(out, " -h, --help print this help.\n");
fprintf(out, " -v, --debug set debug level, default: 1.\n");
fprintf(out, " -l, --list list XFRM interfaces.\n");
fprintf(out, " -n, --name=NAME name of the XFRM interface.\n");
fprintf(out, " -i, --id=ID optional numeric XFRM ID.\n");
fprintf(out, " -d, --dev=DEVICE underlying physical interface.\n");
fprintf(out, "\n");
}
int main(int argc, char *argv[])
{
char *name = NULL, *dev = NULL, *end;
uint32_t xfrm_id = 0;
u_int ifindex;
library_init(NULL, "xfrmi");
atexit(library_deinit);
while (true)
{
struct option long_opts[] = {
{"help", no_argument, NULL, 'h' },
{"debug", no_argument, NULL, 'v' },
{"list", no_argument, NULL, 'l' },
{"name", required_argument, NULL, 'n' },
{"id", required_argument, NULL, 'i' },
{"dev", required_argument, NULL, 'd' },
{0,0,0,0 },
};
switch (getopt_long(argc, argv, "hvln:i:d:", long_opts, NULL))
{
case EOF:
break;
case 'h':
usage(stdout, argv[0]);
return 0;
case 'l':
list_xfrm_interfaces();
return 0;
case 'v':
dbg_default_set_level(atoi(optarg));
continue;
case 'n':
name = optarg;
continue;
case 'i':
errno = 0;
xfrm_id = strtoul(optarg, &end, 0);
if (errno || *end)
{
fprintf(stderr, "invalid XFRM ID: %s\n",
errno ? strerror(errno) : end);
return 1;
}
continue;
case 'd':
dev = optarg;
continue;
default:
usage(stderr, argv[0]);
return 1;
}
break;
}
if (!name || !dev)
{
fprintf(stderr, "please specify a name and a physical interface\n");
return 1;
}
ifindex = if_nametoindex(dev);
if (!ifindex)
{
fprintf(stderr, "physical interface %s not found\n", dev);
return 1;
}
return add_xfrm_interface(name, xfrm_id, ifindex);
}
+4 -4
View File
@@ -1,6 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 4.19.0 Kernel Configuration
# Linux/x86 4.19.23 Kernel Configuration
#
#
@@ -132,7 +132,7 @@ CONFIG_NAMESPACES=y
# CONFIG_IPC_NS is not set
# CONFIG_USER_NS is not set
# CONFIG_PID_NS is not set
# CONFIG_NET_NS is not set
CONFIG_NET_NS=y
# CONFIG_CHECKPOINT_RESTORE is not set
# CONFIG_SCHED_AUTOGROUP is not set
# CONFIG_SYSFS_DEPRECATED is not set
@@ -691,7 +691,7 @@ CONFIG_TLS=y
CONFIG_XFRM=y
CONFIG_XFRM_ALGO=y
CONFIG_XFRM_USER=y
# CONFIG_XFRM_INTERFACE is not set
CONFIG_XFRM_INTERFACE=y
CONFIG_XFRM_SUB_POLICY=y
CONFIG_XFRM_MIGRATE=y
CONFIG_XFRM_STATISTICS=y
@@ -1849,6 +1849,7 @@ CONFIG_USB_PCI=y
# CONFIG_NOP_USB_XCEIV is not set
# CONFIG_USB_GADGET is not set
# CONFIG_TYPEC is not set
# CONFIG_USB_ROLE_SWITCH is not set
# CONFIG_USB_ULPI_BUS is not set
# CONFIG_UWB is not set
# CONFIG_MMC is not set
@@ -2365,7 +2366,6 @@ CONFIG_CRYPTO_SERPENT_SSE2_X86_64=y
CONFIG_CRYPTO_SERPENT_AVX_X86_64=y
CONFIG_CRYPTO_SERPENT_AVX2_X86_64=y
CONFIG_CRYPTO_SM4=y
# CONFIG_CRYPTO_SPECK is not set
CONFIG_CRYPTO_TEA=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_TWOFISH_COMMON=y
+2 -2
View File
@@ -135,7 +135,7 @@ CONFIG_NAMESPACES=y
# CONFIG_IPC_NS is not set
# CONFIG_USER_NS is not set
# CONFIG_PID_NS is not set
# CONFIG_NET_NS is not set
CONFIG_NET_NS=y
# CONFIG_CHECKPOINT_RESTORE is not set
# CONFIG_SCHED_AUTOGROUP is not set
# CONFIG_SYSFS_DEPRECATED is not set
@@ -649,7 +649,7 @@ CONFIG_TLS=y
CONFIG_XFRM=y
CONFIG_XFRM_ALGO=y
CONFIG_XFRM_USER=y
# CONFIG_XFRM_INTERFACE is not set
CONFIG_XFRM_INTERFACE=y
CONFIG_XFRM_SUB_POLICY=y
CONFIG_XFRM_MIGRATE=y
CONFIG_XFRM_STATISTICS=y
+4
View File
@@ -59,6 +59,10 @@ log_action "Mounting $SWANDIR as /root/strongswan"
execute "bindfs -u $SRCUID -g $SRCGID $SWANDIR $LOOPDIR/root/strongswan"
do_on_exit umount $LOOPDIR/root/strongswan
log_action "Copy /etc/resolv.conf"
execute "cp /etc/resolv.conf $LOOPDIR/etc/resolv.conf"
do_on_exit rm $LOOPDIR/etc/resolv.conf
log_action "Remove SWID tags of previous versions"
execute_chroot "find /usr/local/share -path '*strongswan*' -name *.swidtag -delete"
+4 -1
View File
@@ -105,7 +105,8 @@ CONFIG_OPTS = \
--enable-newhope \
--enable-systemd \
--enable-counters \
--enable-save-keys
--enable-save-keys \
--enable-python-eggs-install
export ADA_PROJECT_PATH=/usr/local/ada/lib/gnat
@@ -126,3 +127,5 @@ build: configure
install: build
cd $(BUILDDIR) && make -j install
# for Python-based updown scripts
pip install python-daemon
@@ -0,0 +1,18 @@
One connection with two CHILD_SAs between the hosts and subnet behind the
gateways <b>moon</b> and <b>sun</b>, respectively, are set up using XFRM
interfaces.
<p/>
The gateways use <b>route-based forwarding</b> with <b>XFRM interfaces</b>, with
firewall rules to allow traffic to pass. Both peers use connection-defined
interface IDs so all CHILD_SAs share the same XFRM interface. The IKE daemon
does not install routes for CHILD_SAs with outbound interface ID, so routes for
the target subnets are installed statically or via updown events.
<p/>
Both gateways use separate interfaces for in- and outbound traffic (which is
completely optional and mainly for testing purposes, a single interface will
usually be enough). Gateway <b>moon</b> creates them before initiating the
connection, while gateway <b>sun</b> dynamically creates the interfaces via
ike-updown event using the passed unique generated interface IDs.
<p/>
Clients <b>alice</b> and <b>venus</b> behind gateway <b>moon</b> ping client
<b>bob</b> located behind gateway <b>sun</b>.
@@ -0,0 +1,6 @@
moon::swanctl --list-sas --ike-id 1 --raw 2> /dev/null::gw.*version=2 state=ESTABLISHED local-host=PH_IP_MOON local-port=4500 local-id=moon.strongswan.org remote-host=PH_IP_SUN remote-port=4500 remote-id=sun.strongswan.org.*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[10.1.0.10/32] remote-ts=\[10.2.0.0/16].*local-ts=\[10.1.0.20/32] remote-ts=\[10.2.0.0/16]::YES
sun::swanctl --list-sas --ike-id 1 --raw 2> /dev/null::gw.*version=2 state=ESTABLISHED local-host=PH_IP_SUN local-port=4500 local-id=sun.strongswan.org remote-host=PH_IP_MOON remote-port=4500 remote-id=moon.strongswan.org.*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[10.2.0.0/16] remote-ts=\[10.1.0.10/32].*local-ts=\[10.2.0.0/16] remote-ts=\[10.1.0.20/32]::YES
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES
venus::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES
sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
@@ -0,0 +1,9 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default updown
}
@@ -0,0 +1,33 @@
connections {
gw-gw {
local_addrs = PH_IP_MOON
remote_addrs = PH_IP_SUN
if_id_out = 1337
if_id_in = 42
local {
auth = pubkey
certs = moonCert.pem
id = moon.strongswan.org
}
remote {
auth = pubkey
id = sun.strongswan.org
}
children {
alice-net {
local_ts = 10.1.0.10/32
remote_ts = 0.0.0.0/0
esp_proposals = aes128gcm128-x25519
}
venus-net : connections.gw-gw.children.alice-net {
local_ts = 10.1.0.20/32
}
}
version = 2
proposals = aes128-sha256-x25519
}
}
@@ -0,0 +1,12 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default
start-scripts {
updown = /usr/bin/python /etc/updown.py
}
}
@@ -0,0 +1,30 @@
connections {
gw-gw {
local_addrs = PH_IP_SUN
remote_addrs = PH_IP_MOON
if_id_in = %unique-dir
if_id_out = %unique-dir
local {
auth = pubkey
certs = sunCert.pem
id = sun.strongswan.org
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
net-net {
local_ts = 10.2.0.0/16
remote_ts = 10.1.0.0/16
esp_proposals = aes128gcm128-x25519
}
}
version = 2
proposals = aes128-sha256-x25519
}
}
@@ -0,0 +1,86 @@
#!/usr/bin/env python
import vici
import daemon
import logging
from logging.handlers import SysLogHandler
import subprocess
logger = logging.getLogger('updownLogger')
handler = SysLogHandler(address='/dev/log', facility=SysLogHandler.LOG_DAEMON)
handler.setFormatter(logging.Formatter('charon-updown: %(message)s'))
logger.addHandler(handler)
logger.setLevel(logging.INFO)
def handle_interfaces(ike_sa, up):
if_id_in = int(ike_sa['if-id-in'], 16)
if_id_out = int(ike_sa['if-id-out'], 16)
ifname_in = "xfrm-{}-in".format(if_id_in)
ifname_out = "xfrm-{}-out".format(if_id_out)
if up:
logger.info("add XFRM interfaces %s and %s", ifname_in, ifname_out)
subprocess.call(["/usr/local/libexec/ipsec/xfrmi", "-n", ifname_out,
"-i", str(if_id_out), "-d", "eth0"])
subprocess.call(["/usr/local/libexec/ipsec/xfrmi", "-n", ifname_in,
"-i", str(if_id_in), "-d", "eth0"])
subprocess.call(["ip", "link", "set", ifname_out, "up"])
subprocess.call(["ip", "link", "set", ifname_in, "up"])
subprocess.call(["iptables", "-A", "FORWARD", "-o", ifname_out,
"-j", "ACCEPT"])
subprocess.call(["iptables", "-A", "FORWARD", "-i", ifname_in,
"-j", "ACCEPT"])
else:
logger.info("delete XFRM interfaces %s and %s", ifname_in, ifname_out)
subprocess.call(["iptables", "-D", "FORWARD", "-o", ifname_out,
"-j", "ACCEPT"])
subprocess.call(["iptables", "-D", "FORWARD", "-i", ifname_in,
"-j", "ACCEPT"])
subprocess.call(["ip", "link", "del", ifname_out])
subprocess.call(["ip", "link", "del", ifname_in])
def install_routes(ike_sa):
if_id_out = int(ike_sa['if-id-out'], 16)
ifname_out = "xfrm-{}-out".format(if_id_out)
child_sa = next(ike_sa["child-sas"].itervalues())
for ts in child_sa['remote-ts']:
logger.info("add route to %s via %s", ts, ifname_out)
subprocess.call(["ip", "route", "add", ts, "dev", ifname_out])
# daemonize and run parallel to the IKE daemon
with daemon.DaemonContext():
logger.debug("starting Python updown listener")
try:
session = vici.Session()
ver = session.version()
logger.info("connected to {daemon} {version} ({sysname}, {release}, "
"{machine})".format(**ver))
except:
logger.error("failed to get status via vici")
sys.exit(1)
try:
for label, event in session.listen(["ike-updown", "child-updown"]):
logger.debug("received event: %s %s", label, repr(event))
name = next((x for x in iter(event) if x != "up"))
up = event.get("up", "") == "yes"
ike_sa = event[name]
if label == "ike-updown":
handle_interfaces(ike_sa, up)
elif label == "child-updown" and up:
install_routes(ike_sa)
except IOError:
logger.error("daemon disconnected")
except:
logger.error("exception while listening for events " +
repr(sys.exc_info()[1]))
@@ -0,0 +1,10 @@
moon::swanctl --terminate --ike gw-gw
moon::systemctl stop strongswan-swanctl
sun::systemctl stop strongswan-swanctl
moon::iptables-restore < /etc/iptables.flush
sun::iptables-restore < /etc/iptables.flush
moon::ip -s link show xfrm-moon-out
moon::ip -s link show xfrm-moon-in
moon::ip link del xfrm-moon-out
moon::ip link del xfrm-moon-in
sun::rm /etc/updown.py
@@ -0,0 +1,15 @@
moon::iptables-restore < /etc/iptables.rules
sun::iptables-restore < /etc/iptables.rules
moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-out -d eth0 -i 1337
moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-in -d eth0 -i 42
moon::ip link set xfrm-moon-out up
moon::ip link set xfrm-moon-in up
moon::ip route add 10.2.0.0/16 dev xfrm-moon-out
moon::iptables -A FORWARD -o xfrm-moon-out -j ACCEPT
moon::iptables -A FORWARD -i xfrm-moon-in -j ACCEPT
moon::systemctl start strongswan-swanctl
sun::systemctl start strongswan-swanctl
moon::expect-connection gw-gw
sun::expect-connection gw-gw
moon::swanctl --initiate --child alice-net
moon::swanctl --initiate --child venus-net
@@ -0,0 +1,25 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice venus moon winnetou sun bob"
# Corresponding block diagram
#
DIAGRAM="a-v-m-w-s-b.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="sun"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon sun"
# charon controlled by swanctl
#
SWANCTL=1
@@ -0,0 +1,22 @@
This scenario demonstrates a property of <b>XFRM interfaces</b> that allows
moving them into network namespaces while retaining access to IPsec SAs and
policies in the original namespace. This enables an IKE daemon in one namespace
to provide IPsec tunnels for processes in other namespaces without having to
give them access to the keys and IKE credentials.
<p/>
The gateways use <b>route-based forwarding</b> with <b>XFRM interfaces</b>, with
firewall rules to allow traffic to pass. The IPsec traffic selector used is
0.0.0.0/0, however, specific routing is achieved with routes on the XFRM
interfaces. The IKE daemon does not install routes for CHILD_SAs with outbound
interface ID, so static routes are installed for the target subnets.
<p/>
The XFRM interface on gateway <b>moon</b> is moved into a new network namespace
from which a ping is sent to client <b>bob</b>. It is then moved back out and
<b>alice</b> sends another ping to <b>bob</b> to test if that works too.
<p/>
Gateway <b>sun</b> dynamically creates the XFRM interface via updown script
using the passed unique generated interface ID.
<p/>
Note that the dropped packet seen on the <b>XFRM interface</b> on <b>moon</b>
is an IPv6 Router Solicitation (NDP) sent from that namespace, which doesn't
match the IPsec policy.
@@ -0,0 +1,18 @@
moon::swanctl --list-sas --ike-id 1 --raw 2> /dev/null::gw.*version=2 state=ESTABLISHED local-host=PH_IP_MOON local-port=4500 local-id=moon.strongswan.org remote-host=PH_IP_SUN remote-port=4500 remote-id=sun.strongswan.org.*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[0.0.0.0/0] remote-ts=\[0.0.0.0/0]::YES
sun::swanctl --list-sas --ike-id 1 --raw 2> /dev/null::gw.*version=2 state=ESTABLISHED local-host=PH_IP_SUN local-port=4500 local-id=sun.strongswan.org remote-host=PH_IP_MOON remote-port=4500 remote-id=moon.strongswan.org.*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[0.0.0.0/0] remote-ts=\[0.0.0.0/0]::YES
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES
moon::ip netns add xfrmi-test::.*::NO
moon::ip link set xfrm-moon netns xfrmi-test::.*::NO
moon::ip netns exec xfrmi-test ip addr add 10.1.0.42/32 dev xfrm-moon::.*::NO
moon::ip netns exec xfrmi-test ip link set dev xfrm-moon up::.*::NO
moon::ip netns exec xfrmi-test ip route add 10.2.0.0/16 dev xfrm-moon src 10.1.0.42::.*::NO
moon::ip netns exec xfrmi-test ip xfrm state::.*::NO
moon::ip netns exec xfrmi-test ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES
alice::ping -c 1 -W 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::NO
moon::ip netns exec xfrmi-test ip link set xfrm-moon netns 1::.*::NO
moon::ip netns del xfrmi-test::.*::NO
moon::ip link set dev xfrm-moon up::.*::NO
moon::ip route add 10.2.0.0/16 dev xfrm-moon::.*::NO
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES
sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
@@ -0,0 +1,9 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default updown
}
@@ -0,0 +1,30 @@
connections {
gw-gw {
local_addrs = PH_IP_MOON
remote_addrs = PH_IP_SUN
local {
auth = pubkey
certs = moonCert.pem
id = moon.strongswan.org
}
remote {
auth = pubkey
id = sun.strongswan.org
}
children {
net-net {
local_ts = 0.0.0.0/0
remote_ts = 0.0.0.0/0
if_id_out = 42
if_id_in = 42
esp_proposals = aes128gcm128-x25519
}
}
version = 2
proposals = aes128-sha256-x25519
}
}
@@ -0,0 +1,9 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default updown
}
@@ -0,0 +1,32 @@
connections {
gw-gw {
local_addrs = PH_IP_SUN
remote_addrs = PH_IP_MOON
local {
auth = pubkey
certs = sunCert.pem
id = sun.strongswan.org
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
net-net {
local_ts = 0.0.0.0/0
remote_ts = 0.0.0.0/0
if_id_out = %unique
if_id_in = %unique
updown = /etc/updown
esp_proposals = aes128gcm128-x25519
}
}
version = 2
proposals = aes128-sha256-x25519
}
}
@@ -0,0 +1,18 @@
#!/bin/bash
IF_NAME="xfrmi-${PLUTO_IF_ID_IN}"
case "${PLUTO_VERB}" in
up-client)
/usr/local/libexec/ipsec/xfrmi -n "${IF_NAME}" -i "${PLUTO_IF_ID_IN}" -d eth0
ip link set "${IF_NAME}" up
ip route add 10.1.0.0/16 dev "${IF_NAME}"
iptables -A FORWARD -i "${IF_NAME}" -j ACCEPT
iptables -A FORWARD -o "${IF_NAME}" -j ACCEPT
;;
down-client)
iptables -D FORWARD -i "${IF_NAME}" -j ACCEPT
iptables -D FORWARD -o "${IF_NAME}" -j ACCEPT
ip link del "${IF_NAME}"
;;
esac
@@ -0,0 +1,8 @@
moon::swanctl --terminate --ike gw-gw
moon::systemctl stop strongswan-swanctl
sun::systemctl stop strongswan-swanctl
moon::iptables-restore < /etc/iptables.flush
sun::iptables-restore < /etc/iptables.flush
moon::ip -s link show xfrm-moon
moon::ip link del xfrm-moon
sun::rm /etc/updown
@@ -0,0 +1,12 @@
moon::iptables-restore < /etc/iptables.rules
sun::iptables-restore < /etc/iptables.rules
moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon -i 42 -d eth0
moon::ip link set xfrm-moon up
moon::ip route add 10.2.0.0/16 dev xfrm-moon
moon::iptables -A FORWARD -i xfrm-moon -j ACCEPT
moon::iptables -A FORWARD -o xfrm-moon -j ACCEPT
moon::systemctl start strongswan-swanctl
sun::systemctl start strongswan-swanctl
moon::expect-connection gw-gw
sun::expect-connection gw-gw
moon::swanctl --initiate --child net-net
@@ -0,0 +1,25 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon winnetou sun bob"
# Corresponding block diagram
#
DIAGRAM="a-m-w-s-b.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="sun"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon sun"
# charon controlled by swanctl
#
SWANCTL=1
@@ -0,0 +1,17 @@
A connection between the subnets behind the gateways <b>moon</b> and <b>sun</b>
is set up using XFRM interfaces.
<p/>
The gateways use <b>route-based forwarding</b> with <b>XFRM interfaces</b>, with
firewall rules to allow traffic to pass. The IPsec traffic selector used is
0.0.0.0/0, however, specific routing is achieved with routes on the XFRM
interfaces. The IKE daemon does not install routes for CHILD_SAs with outbound
interface ID, so static routes are installed for the target subnets.
<p/>
Both gateways use separate interfaces for in- and outbound traffic (which is
completely optional and mainly for testing purposes, a single interface will
usually be enough). Gateway <b>moon</b> creates them before initiating the
connection, while gateway <b>sun</b> dynamically creates the interfaces via
updown script using the passed unique generated interface IDs.
<p/>
Client <b>alice</b> behind gateway <b>moon</b> pings client <b>bob</b> located
behind gateway <b>sun</b>.
@@ -0,0 +1,5 @@
moon::swanctl --list-sas --ike-id 1 --raw 2> /dev/null::gw.*version=2 state=ESTABLISHED local-host=PH_IP_MOON local-port=4500 local-id=moon.strongswan.org remote-host=PH_IP_SUN remote-port=4500 remote-id=sun.strongswan.org.*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[0.0.0.0/0] remote-ts=\[0.0.0.0/0]::YES
sun::swanctl --list-sas --ike-id 1 --raw 2> /dev/null::gw.*version=2 state=ESTABLISHED local-host=PH_IP_SUN local-port=4500 local-id=sun.strongswan.org remote-host=PH_IP_MOON remote-port=4500 remote-id=moon.strongswan.org.*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[0.0.0.0/0] remote-ts=\[0.0.0.0/0]::YES
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_.eq=1::YES
sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
@@ -0,0 +1,9 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default updown
}
@@ -0,0 +1,30 @@
connections {
gw-gw {
local_addrs = PH_IP_MOON
remote_addrs = PH_IP_SUN
local {
auth = pubkey
certs = moonCert.pem
id = moon.strongswan.org
}
remote {
auth = pubkey
id = sun.strongswan.org
}
children {
net-net {
local_ts = 0.0.0.0/0
remote_ts = 0.0.0.0/0
if_id_out = 1337
if_id_in = 42
esp_proposals = aes128gcm128-x25519
}
}
version = 2
proposals = aes128-sha256-x25519
}
}
@@ -0,0 +1,9 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default updown
}
@@ -0,0 +1,32 @@
connections {
gw-gw {
local_addrs = PH_IP_SUN
remote_addrs = PH_IP_MOON
local {
auth = pubkey
certs = sunCert.pem
id = sun.strongswan.org
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
net-net {
local_ts = 0.0.0.0/0
remote_ts = 0.0.0.0/0
if_id_in = %unique-dir
if_id_out = %unique-dir
updown = /etc/updown
esp_proposals = aes128gcm128-x25519
}
}
version = 2
proposals = aes128-sha256-x25519
}
}
@@ -0,0 +1,23 @@
#!/bin/bash
IF_NAME="xfrm-"
IF_NAME_IN="${IF_NAME}${PLUTO_IF_ID_IN}-in"
IF_NAME_OUT="${IF_NAME}${PLUTO_IF_ID_OUT}-out"
case "${PLUTO_VERB}" in
up-client)
/usr/local/libexec/ipsec/xfrmi -n "${IF_NAME_OUT}" -i "${PLUTO_IF_ID_OUT}" -d eth0
/usr/local/libexec/ipsec/xfrmi -n "${IF_NAME_IN}" -i "${PLUTO_IF_ID_IN}" -d eth0
ip link set "${IF_NAME_OUT}" up
ip link set "${IF_NAME_IN}" up
ip route add 10.1.0.0/16 dev "${IF_NAME_OUT}"
iptables -A FORWARD -o "${IF_NAME_OUT}" -j ACCEPT
iptables -A FORWARD -i "${IF_NAME_IN}" -j ACCEPT
;;
down-client)
iptables -D FORWARD -o "${IF_NAME_OUT}" -j ACCEPT
iptables -D FORWARD -i "${IF_NAME_IN}" -j ACCEPT
ip link del "${IF_NAME_OUT}"
ip link del "${IF_NAME_IN}"
;;
esac
@@ -0,0 +1,10 @@
moon::swanctl --terminate --ike gw-gw
moon::systemctl stop strongswan-swanctl
sun::systemctl stop strongswan-swanctl
moon::iptables-restore < /etc/iptables.flush
sun::iptables-restore < /etc/iptables.flush
moon::ip -s link show xfrm-moon-out
moon::ip -s link show xfrm-moon-in
moon::ip link del xfrm-moon-out
moon::ip link del xfrm-moon-in
sun::rm /etc/updown
@@ -0,0 +1,14 @@
moon::iptables-restore < /etc/iptables.rules
sun::iptables-restore < /etc/iptables.rules
moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-out -d eth0 -i 1337
moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-in -d eth0 -i 42
moon::ip link set xfrm-moon-out up
moon::ip link set xfrm-moon-in up
moon::ip route add 10.2.0.0/16 dev xfrm-moon-out
moon::iptables -A FORWARD -o xfrm-moon-out -j ACCEPT
moon::iptables -A FORWARD -i xfrm-moon-in -j ACCEPT
moon::systemctl start strongswan-swanctl
sun::systemctl start strongswan-swanctl
moon::expect-connection gw-gw
sun::expect-connection gw-gw
moon::swanctl --initiate --child net-net
@@ -0,0 +1,25 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon winnetou sun bob"
# Corresponding block diagram
#
DIAGRAM="a-m-w-s-b.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="sun"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon sun"
# charon controlled by swanctl
#
SWANCTL=1
@@ -0,0 +1,12 @@
The roadwarriors <b>carol</b> and <b>dave</b> set up a connection each to
gateway <b>moon</b>. Both <b>carol</b> and <b>dave</b> request a <b>virtual
IP</b> via IKEv2 configuration payload.
<p/>
The gateway <b>moon</b> uses <b>route-based forwarding</b> with an <b>XFRM
interface</b>, with firewall rules to allow traffic to pass. The IKE daemon
does not install routes for CHILD_SAs with outbound interface ID, so a static
route is installed for the virtual IP subnet via XFRM interface.
<p/>
Both <b>carol</b> and <b>dave</b> ping the client <b>alice</b> behind the
gateway <b>moon</b>. The source IP addresses of the two pings will be the
virtual IPs <b>carol1</b> and <b>dave1</b>, respectively.
@@ -0,0 +1,10 @@
carol::swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=PH_IP_CAROL local-port=4500 [email protected] remote-host=PH_IP_MOON remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*child-sas.*home.*state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[10.3.0.1/32] remote-ts=\[10.1.0.0/16]::YES
dave:: swanctl --list-sas --raw 2> /dev/null::home.*version=2 state=ESTABLISHED local-host=PH_IP_DAVE local-port=4500 [email protected] remote-host=PH_IP_MOON remote-port=4500 remote-id=moon.strongswan.org initiator=yes.*child-sas.*home.*state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[10.3.0.2/32] remote-ts=\[10.1.0.0/16]::YES
moon:: swanctl --list-sas --ike-id 1 --raw 2> /dev/null::rw.*version=2 state=ESTABLISHED local-host=PH_IP_MOON local-port=4500 local-id=moon.strongswan.org remote-host=PH_IP_CAROL remote-port=4500 [email protected].*child-sas.*net.*reqid=1 state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[10.1.0.0/16] remote-ts=\[10.3.0.1/32]::YES
moon:: swanctl --list-sas --ike-id 2 --raw 2> /dev/null::rw.*version=2 state=ESTABLISHED local-host=PH_IP_MOON local-port=4500 local-id=moon.strongswan.org remote-host=PH_IP_DAVE remote-port=4500 [email protected].*child-sas.*net.*reqid=2 state=INSTALLED mode=TUNNEL.*ESP.*local-ts=\[10.1.0.0/16] remote-ts=\[10.3.0.2/32]::YES
carol::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_.eq=1::YES
dave::ping -c 1 PH_IP_ALICE::64 bytes from PH_IP_ALICE: icmp_.eq=1::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
moon::tcpdump::IP moon.strongswan.org > dave.strongswan.org: ESP::YES
moon::tcpdump::IP dave.strongswan.org > moon.strongswan.org: ESP::YES
@@ -0,0 +1,9 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 hmac pem pkcs1 x509 revocation curve25519 gmp curl kernel-netlink socket-default updown vici
}
@@ -0,0 +1,28 @@
connections {
home {
local_addrs = PH_IP_CAROL
remote_addrs = PH_IP_MOON
vips = 0.0.0.0
local {
auth = pubkey
certs = carolCert.pem
id = [email protected]
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
home {
remote_ts = 10.1.0.0/16
updown = /usr/local/libexec/ipsec/_updown iptables
esp_proposals = aes128gcm128-x25519
}
}
version = 2
proposals = aes128-sha256-x25519
}
}
@@ -0,0 +1,9 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 hmac pem pkcs1 x509 revocation curve25519 gmp curl kernel-netlink socket-default updown vici
}
@@ -0,0 +1,28 @@
connections {
home {
local_addrs = PH_IP_DAVE
remote_addrs = PH_IP_MOON
vips = 0.0.0.0
local {
auth = pubkey
certs = daveCert.pem
id = [email protected]
}
remote {
auth = pubkey
id = moon.strongswan.org
}
children {
home {
remote_ts = 10.1.0.0/16
updown = /usr/local/libexec/ipsec/_updown iptables
esp_proposals = aes128gcm128-x25519
}
}
version = 2
proposals = aes128-sha256-x25519
}
}
@@ -0,0 +1,9 @@
# /etc/strongswan.conf - strongSwan configuration file
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default updown
}
@@ -0,0 +1,34 @@
connections {
rw {
local_addrs = PH_IP_MOON
pools = rw_pool
local {
auth = pubkey
certs = moonCert.pem
id = moon.strongswan.org
}
remote {
auth = pubkey
}
children {
net {
local_ts = 10.1.0.0/16
if_id_out = 42
if_id_in = 42
esp_proposals = aes128gcm128-x25519
}
}
version = 2
proposals = aes128-sha256-x25519
}
}
pools {
rw_pool {
addrs = 10.3.0.0/28
}
}
@@ -0,0 +1,10 @@
carol::swanctl --terminate --ike home
dave::swanctl --terminate --ike home
moon::systemctl stop strongswan-swanctl
carol::systemctl stop strongswan-swanctl
dave::systemctl stop strongswan-swanctl
moon::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
dave::iptables-restore < /etc/iptables.flush
moon::ip -s link show xfrm-moon
moon::ip link del xfrm-moon
@@ -0,0 +1,16 @@
moon::iptables-restore < /etc/iptables.rules
carol::iptables-restore < /etc/iptables.rules
dave::iptables-restore < /etc/iptables.rules
moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon -i 42 -d eth0
moon::ip link set xfrm-moon up
moon::ip route add 10.3.0.0/28 dev xfrm-moon
moon::iptables -A FORWARD -i xfrm-moon -j ACCEPT
moon::iptables -A FORWARD -o xfrm-moon -j ACCEPT
moon::systemctl start strongswan-swanctl
carol::systemctl start strongswan-swanctl
dave::systemctl start strongswan-swanctl
moon::expect-connection rw
carol::expect-connection home
carol::swanctl --initiate --child home
dave::expect-connection home
dave::swanctl --initiate --child home
@@ -0,0 +1,25 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon carol winnetou dave"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w-d.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol dave"
# charon controlled by swanctl
#
SWANCTL=1