Merge branch 'xfrm-set-mark'
This adds the ability to configure marks the in- and/or outbound SA should apply to packets after processing on Linux. Configuring such a mark for outbound SAs requires at least a 4.14 kernel. The ability to set a mask and configuring a mark/mask for inbound SAs will be added with the upcoming 4.19 kernel.
This commit is contained in:
@@ -302,8 +302,11 @@ enum xfrm_attr_type_t {
|
|||||||
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
|
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
|
||||||
XFRMA_PAD,
|
XFRMA_PAD,
|
||||||
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
|
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
|
||||||
|
XFRMA_SET_MARK, /* __u32 */
|
||||||
|
XFRMA_SET_MARK_MASK, /* __u32 */
|
||||||
__XFRMA_MAX
|
__XFRMA_MAX
|
||||||
|
|
||||||
|
#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */
|
||||||
#define XFRMA_MAX (__XFRMA_MAX - 1)
|
#define XFRMA_MAX (__XFRMA_MAX - 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2008-2017 Tobias Brunner
|
* Copyright (C) 2008-2018 Tobias Brunner
|
||||||
* Copyright (C) 2016 Andreas Steffen
|
* Copyright (C) 2016 Andreas Steffen
|
||||||
* Copyright (C) 2005-2007 Martin Willi
|
* Copyright (C) 2005-2007 Martin Willi
|
||||||
* Copyright (C) 2005 Jan Hutter
|
* Copyright (C) 2005 Jan Hutter
|
||||||
@@ -123,6 +123,16 @@ struct private_child_cfg_t {
|
|||||||
*/
|
*/
|
||||||
mark_t mark_out;
|
mark_t mark_out;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional mark to set to packets after inbound processing
|
||||||
|
*/
|
||||||
|
mark_t set_mark_in;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional mark to set to packets after outbound processing
|
||||||
|
*/
|
||||||
|
mark_t set_mark_out;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Traffic Flow Confidentiality padding, if enabled
|
* Traffic Flow Confidentiality padding, if enabled
|
||||||
*/
|
*/
|
||||||
@@ -547,6 +557,12 @@ METHOD(child_cfg_t, get_mark, mark_t,
|
|||||||
return inbound ? this->mark_in : this->mark_out;
|
return inbound ? this->mark_in : this->mark_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(child_cfg_t, get_set_mark, mark_t,
|
||||||
|
private_child_cfg_t *this, bool inbound)
|
||||||
|
{
|
||||||
|
return inbound ? this->set_mark_in : this->set_mark_out;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(child_cfg_t, get_tfc, uint32_t,
|
METHOD(child_cfg_t, get_tfc, uint32_t,
|
||||||
private_child_cfg_t *this)
|
private_child_cfg_t *this)
|
||||||
{
|
{
|
||||||
@@ -620,6 +636,10 @@ METHOD(child_cfg_t, equals, bool,
|
|||||||
this->mark_in.mask == other->mark_in.mask &&
|
this->mark_in.mask == other->mark_in.mask &&
|
||||||
this->mark_out.value == other->mark_out.value &&
|
this->mark_out.value == other->mark_out.value &&
|
||||||
this->mark_out.mask == other->mark_out.mask &&
|
this->mark_out.mask == other->mark_out.mask &&
|
||||||
|
this->set_mark_in.value == other->set_mark_in.value &&
|
||||||
|
this->set_mark_in.mask == other->set_mark_in.mask &&
|
||||||
|
this->set_mark_out.value == other->set_mark_out.value &&
|
||||||
|
this->set_mark_out.mask == other->set_mark_out.mask &&
|
||||||
this->tfc == other->tfc &&
|
this->tfc == other->tfc &&
|
||||||
this->manual_prio == other->manual_prio &&
|
this->manual_prio == other->manual_prio &&
|
||||||
this->replay_window == other->replay_window &&
|
this->replay_window == other->replay_window &&
|
||||||
@@ -676,6 +696,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
|
|||||||
.get_inactivity = _get_inactivity,
|
.get_inactivity = _get_inactivity,
|
||||||
.get_reqid = _get_reqid,
|
.get_reqid = _get_reqid,
|
||||||
.get_mark = _get_mark,
|
.get_mark = _get_mark,
|
||||||
|
.get_set_mark = _get_set_mark,
|
||||||
.get_tfc = _get_tfc,
|
.get_tfc = _get_tfc,
|
||||||
.get_manual_prio = _get_manual_prio,
|
.get_manual_prio = _get_manual_prio,
|
||||||
.get_interface = _get_interface,
|
.get_interface = _get_interface,
|
||||||
@@ -698,6 +719,8 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
|
|||||||
.close_action = data->close_action,
|
.close_action = data->close_action,
|
||||||
.mark_in = data->mark_in,
|
.mark_in = data->mark_in,
|
||||||
.mark_out = data->mark_out,
|
.mark_out = data->mark_out,
|
||||||
|
.set_mark_in = data->set_mark_in,
|
||||||
|
.set_mark_out = data->set_mark_out,
|
||||||
.lifetime = data->lifetime,
|
.lifetime = data->lifetime,
|
||||||
.inactivity = data->inactivity,
|
.inactivity = data->inactivity,
|
||||||
.tfc = data->tfc,
|
.tfc = data->tfc,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2008-2017 Tobias Brunner
|
* Copyright (C) 2008-2018 Tobias Brunner
|
||||||
* Copyright (C) 2016 Andreas Steffen
|
* Copyright (C) 2016 Andreas Steffen
|
||||||
* Copyright (C) 2005-2007 Martin Willi
|
* Copyright (C) 2005-2007 Martin Willi
|
||||||
* Copyright (C) 2005 Jan Hutter
|
* Copyright (C) 2005 Jan Hutter
|
||||||
@@ -227,13 +227,21 @@ struct child_cfg_t {
|
|||||||
uint32_t (*get_reqid)(child_cfg_t *this);
|
uint32_t (*get_reqid)(child_cfg_t *this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional mark for CHILD_SA.
|
* Optional mark to set on policies/SAs.
|
||||||
*
|
*
|
||||||
* @param inbound TRUE for inbound, FALSE for outbound
|
* @param inbound TRUE for inbound, FALSE for outbound
|
||||||
* @return mark
|
* @return mark
|
||||||
*/
|
*/
|
||||||
mark_t (*get_mark)(child_cfg_t *this, bool inbound);
|
mark_t (*get_mark)(child_cfg_t *this, bool inbound);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional mark the SAs should apply after processing packets.
|
||||||
|
*
|
||||||
|
* @param inbound TRUE for inbound, FALSE for outbound
|
||||||
|
* @return mark
|
||||||
|
*/
|
||||||
|
mark_t (*get_set_mark)(child_cfg_t *this, bool inbound);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the TFC padding value to use for CHILD_SA.
|
* Get the TFC padding value to use for CHILD_SA.
|
||||||
*
|
*
|
||||||
@@ -346,6 +354,10 @@ struct child_cfg_create_t {
|
|||||||
mark_t mark_in;
|
mark_t mark_in;
|
||||||
/** Optional outbound mark */
|
/** Optional outbound mark */
|
||||||
mark_t mark_out;
|
mark_t mark_out;
|
||||||
|
/** Optional inbound mark the SA should apply to traffic */
|
||||||
|
mark_t set_mark_in;
|
||||||
|
/** Optional outbound mark the SA should apply to traffic */
|
||||||
|
mark_t set_mark_out;
|
||||||
/** Mode to propose for CHILD_SA */
|
/** Mode to propose for CHILD_SA */
|
||||||
ipsec_mode_t mode;
|
ipsec_mode_t mode;
|
||||||
/** TFC padding size, 0 to disable, -1 to pad to PMTU */
|
/** TFC padding size, 0 to disable, -1 to pad to PMTU */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 Andreas Steffen
|
* Copyright (C) 2016 Andreas Steffen
|
||||||
* Copyright (C) 2006-2016 Tobias Brunner
|
* Copyright (C) 2006-2018 Tobias Brunner
|
||||||
* Copyright (C) 2006 Daniel Roethlisberger
|
* Copyright (C) 2006 Daniel Roethlisberger
|
||||||
* Copyright (C) 2005-2006 Martin Willi
|
* Copyright (C) 2005-2006 Martin Willi
|
||||||
* Copyright (C) 2005 Jan Hutter
|
* Copyright (C) 2005 Jan Hutter
|
||||||
@@ -93,6 +93,8 @@ struct kernel_ipsec_add_sa_t {
|
|||||||
bool encap;
|
bool encap;
|
||||||
/** no (disabled), yes (enabled), auto (enabled if supported) */
|
/** no (disabled), yes (enabled), auto (enabled if supported) */
|
||||||
hw_offload_t hw_offload;
|
hw_offload_t hw_offload;
|
||||||
|
/** Mark the SA should apply to packets after processing */
|
||||||
|
mark_t mark;
|
||||||
/** TRUE to use Extended Sequence Numbers */
|
/** TRUE to use Extended Sequence Numbers */
|
||||||
bool esn;
|
bool esn;
|
||||||
/** TRUE to copy the DF bit to the outer IPv4 header in tunnel mode */
|
/** TRUE to copy the DF bit to the outer IPv4 header in tunnel mode */
|
||||||
|
|||||||
@@ -1335,6 +1335,23 @@ static bool add_mark(struct nlmsghdr *hdr, int buflen, mark_t mark)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a uint32 attribute to message
|
||||||
|
*/
|
||||||
|
static bool add_uint32(struct nlmsghdr *hdr, int buflen,
|
||||||
|
enum xfrm_attr_type_t type, uint32_t value)
|
||||||
|
{
|
||||||
|
uint32_t *xvalue;
|
||||||
|
|
||||||
|
xvalue = netlink_reserve(hdr, buflen, type, sizeof(*xvalue));
|
||||||
|
if (!xvalue)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
*xvalue = value;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if kernel supports HW offload
|
* Check if kernel supports HW offload
|
||||||
*/
|
*/
|
||||||
@@ -1616,16 +1633,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
|||||||
case DSCP_COPY_IN_ONLY:
|
case DSCP_COPY_IN_ONLY:
|
||||||
case DSCP_COPY_NO:
|
case DSCP_COPY_NO:
|
||||||
{
|
{
|
||||||
uint32_t *xflags;
|
/* currently the only extra flag */
|
||||||
|
if (!add_uint32(hdr, sizeof(request), XFRMA_SA_EXTRA_FLAGS,
|
||||||
xflags = netlink_reserve(hdr, sizeof(request),
|
XFRM_SA_XFLAG_DONT_ENCAP_DSCP))
|
||||||
XFRMA_SA_EXTRA_FLAGS, sizeof(*xflags));
|
|
||||||
if (!xflags)
|
|
||||||
{
|
{
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
/* currently the only extra flag */
|
|
||||||
*xflags |= XFRM_SA_XFLAG_DONT_ENCAP_DSCP;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1876,17 +1889,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ipcomp == IPCOMP_NONE && (data->mark.value | data->mark.mask))
|
||||||
|
{
|
||||||
|
if (!add_uint32(hdr, sizeof(request), XFRMA_SET_MARK,
|
||||||
|
data->mark.value) ||
|
||||||
|
!add_uint32(hdr, sizeof(request), XFRMA_SET_MARK_MASK,
|
||||||
|
data->mark.mask))
|
||||||
|
{
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (data->tfc && id->proto == IPPROTO_ESP && mode == MODE_TUNNEL)
|
if (data->tfc && id->proto == IPPROTO_ESP && mode == MODE_TUNNEL)
|
||||||
{ /* the kernel supports TFC padding only for tunnel mode ESP SAs */
|
{ /* the kernel supports TFC padding only for tunnel mode ESP SAs */
|
||||||
uint32_t *tfcpad;
|
if (!add_uint32(hdr, sizeof(request), XFRMA_TFCPAD, data->tfc))
|
||||||
|
|
||||||
tfcpad = netlink_reserve(hdr, sizeof(request), XFRMA_TFCPAD,
|
|
||||||
sizeof(*tfcpad));
|
|
||||||
if (!tfcpad)
|
|
||||||
{
|
{
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
*tfcpad = data->tfc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id->proto != IPPROTO_COMP)
|
if (id->proto != IPPROTO_COMP)
|
||||||
|
|||||||
@@ -2925,7 +2925,7 @@ static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type,
|
|||||||
msg->rtm_flags |= FIB_RULE_INVERT;
|
msg->rtm_flags |= FIB_RULE_INVERT;
|
||||||
fwmark++;
|
fwmark++;
|
||||||
}
|
}
|
||||||
if (mark_from_string(fwmark, &mark))
|
if (mark_from_string(fwmark, MARK_OP_NONE, &mark))
|
||||||
{
|
{
|
||||||
chunk = chunk_from_thing(mark.value);
|
chunk = chunk_from_thing(mark.value);
|
||||||
netlink_add_attribute(hdr, FRA_FWMARK, chunk, sizeof(request));
|
netlink_add_attribute(hdr, FRA_FWMARK, chunk, sizeof(request));
|
||||||
|
|||||||
@@ -745,7 +745,7 @@ static int open_socket(private_socket_default_socket_t *this,
|
|||||||
|
|
||||||
fwmark = lib->settings->get_str(lib->settings,
|
fwmark = lib->settings->get_str(lib->settings,
|
||||||
"%s.plugins.socket-default.fwmark", NULL, lib->ns);
|
"%s.plugins.socket-default.fwmark", NULL, lib->ns);
|
||||||
if (fwmark && mark_from_string(fwmark, &mark))
|
if (fwmark && mark_from_string(fwmark, MARK_OP_NONE, &mark))
|
||||||
{
|
{
|
||||||
if (setsockopt(skt, SOL_SOCKET, SO_MARK, &mark.value,
|
if (setsockopt(skt, SOL_SOCKET, SO_MARK, &mark.value,
|
||||||
sizeof(mark.value)) < 0)
|
sizeof(mark.value)) < 0)
|
||||||
|
|||||||
@@ -528,6 +528,10 @@ static void log_child_data(child_data_t *data, char *name)
|
|||||||
DBG2(DBG_CFG, " mark_in_sa = %u", has_opt(OPT_MARK_IN_SA));
|
DBG2(DBG_CFG, " mark_in_sa = %u", has_opt(OPT_MARK_IN_SA));
|
||||||
DBG2(DBG_CFG, " mark_out = %u/%u",
|
DBG2(DBG_CFG, " mark_out = %u/%u",
|
||||||
cfg->mark_out.value, cfg->mark_out.mask);
|
cfg->mark_out.value, cfg->mark_out.mask);
|
||||||
|
DBG2(DBG_CFG, " set_mark_in = %u/%u",
|
||||||
|
cfg->set_mark_in.value, cfg->set_mark_in.mask);
|
||||||
|
DBG2(DBG_CFG, " set_mark_out = %u/%u",
|
||||||
|
cfg->set_mark_out.value, cfg->set_mark_out.mask);
|
||||||
DBG2(DBG_CFG, " inactivity = %llu", cfg->inactivity);
|
DBG2(DBG_CFG, " inactivity = %llu", cfg->inactivity);
|
||||||
DBG2(DBG_CFG, " proposals = %#P", data->proposals);
|
DBG2(DBG_CFG, " proposals = %#P", data->proposals);
|
||||||
DBG2(DBG_CFG, " local_ts = %#R", data->local_ts);
|
DBG2(DBG_CFG, " local_ts = %#R", data->local_ts);
|
||||||
@@ -1177,7 +1181,22 @@ CALLBACK(parse_mark, bool,
|
|||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return mark_from_string(buf, out);
|
return mark_from_string(buf, MARK_OP_UNIQUE, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a mark_t when using it as set_mark.
|
||||||
|
*/
|
||||||
|
CALLBACK(parse_set_mark, bool,
|
||||||
|
mark_t *out, chunk_t v)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
if (!vici_stringify(v, buf, sizeof(buf)))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return mark_from_string(buf, MARK_OP_SAME, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1639,6 +1658,8 @@ CALLBACK(child_kv, bool,
|
|||||||
{ "mark_in", parse_mark, &child->cfg.mark_in },
|
{ "mark_in", parse_mark, &child->cfg.mark_in },
|
||||||
{ "mark_in_sa", parse_opt_mark_in, &child->cfg.options },
|
{ "mark_in_sa", parse_opt_mark_in, &child->cfg.options },
|
||||||
{ "mark_out", parse_mark, &child->cfg.mark_out },
|
{ "mark_out", parse_mark, &child->cfg.mark_out },
|
||||||
|
{ "set_mark_in", parse_set_mark, &child->cfg.set_mark_in },
|
||||||
|
{ "set_mark_out", parse_set_mark, &child->cfg.set_mark_out },
|
||||||
{ "tfc_padding", parse_tfc, &child->cfg.tfc },
|
{ "tfc_padding", parse_tfc, &child->cfg.tfc },
|
||||||
{ "priority", parse_uint32, &child->cfg.priority },
|
{ "priority", parse_uint32, &child->cfg.priority },
|
||||||
{ "interface", parse_string, &child->cfg.interface },
|
{ "interface", parse_string, &child->cfg.interface },
|
||||||
|
|||||||
@@ -890,6 +890,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
|
|||||||
.cpi = cpi,
|
.cpi = cpi,
|
||||||
.encap = this->encap,
|
.encap = this->encap,
|
||||||
.hw_offload = this->config->get_hw_offload(this->config),
|
.hw_offload = this->config->get_hw_offload(this->config),
|
||||||
|
.mark = this->config->get_set_mark(this->config, inbound),
|
||||||
.esn = esn,
|
.esn = esn,
|
||||||
.copy_df = !this->config->has_option(this->config, OPT_NO_COPY_DF),
|
.copy_df = !this->config->has_option(this->config, OPT_NO_COPY_DF),
|
||||||
.copy_ecn = !this->config->has_option(this->config, OPT_NO_COPY_ECN),
|
.copy_ecn = !this->config->has_option(this->config, OPT_NO_COPY_ECN),
|
||||||
@@ -899,6 +900,11 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
|
|||||||
.update = update,
|
.update = update,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (sa.mark.value == MARK_SAME)
|
||||||
|
{
|
||||||
|
sa.mark.value = inbound ? this->mark_in.value : this->mark_out.value;
|
||||||
|
}
|
||||||
|
|
||||||
status = charon->kernel->add_sa(charon->kernel, &id, &sa);
|
status = charon->kernel->add_sa(charon->kernel, &id, &sa);
|
||||||
|
|
||||||
my_ts->destroy(my_ts);
|
my_ts->destroy(my_ts);
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ bool ipsec_sa_cfg_equals(ipsec_sa_cfg_t *a, ipsec_sa_cfg_t *b)
|
|||||||
/*
|
/*
|
||||||
* See header
|
* See header
|
||||||
*/
|
*/
|
||||||
bool mark_from_string(const char *value, mark_t *mark)
|
bool mark_from_string(const char *value, mark_op_t ops, mark_t *mark)
|
||||||
{
|
{
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
|
||||||
@@ -79,6 +79,11 @@ bool mark_from_string(const char *value, mark_t *mark)
|
|||||||
}
|
}
|
||||||
if (strcasepfx(value, "%unique"))
|
if (strcasepfx(value, "%unique"))
|
||||||
{
|
{
|
||||||
|
if (!(ops & MARK_OP_UNIQUE))
|
||||||
|
{
|
||||||
|
DBG1(DBG_APP, "unexpected use of %%unique mark", value);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
endptr = (char*)value + strlen("%unique");
|
endptr = (char*)value + strlen("%unique");
|
||||||
if (strcasepfx(endptr, "-dir"))
|
if (strcasepfx(endptr, "-dir"))
|
||||||
{
|
{
|
||||||
@@ -95,6 +100,24 @@ bool mark_from_string(const char *value, mark_t *mark)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcasepfx(value, "%same"))
|
||||||
|
{
|
||||||
|
if (!(ops & MARK_OP_SAME))
|
||||||
|
{
|
||||||
|
DBG1(DBG_APP, "unexpected use of %%same mark", value);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
endptr = (char*)value + strlen("%same");
|
||||||
|
if (!*endptr || *endptr == '/')
|
||||||
|
{
|
||||||
|
mark->value = MARK_SAME;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_APP, "invalid mark value: %s", value);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mark->value = strtoul(value, &endptr, 0);
|
mark->value = strtoul(value, &endptr, 0);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ typedef enum policy_priority_t policy_priority_t;
|
|||||||
typedef enum ipcomp_transform_t ipcomp_transform_t;
|
typedef enum ipcomp_transform_t ipcomp_transform_t;
|
||||||
typedef enum hw_offload_t hw_offload_t;
|
typedef enum hw_offload_t hw_offload_t;
|
||||||
typedef enum dscp_copy_t dscp_copy_t;
|
typedef enum dscp_copy_t dscp_copy_t;
|
||||||
|
typedef enum mark_op_t mark_op_t;
|
||||||
typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t;
|
typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t;
|
||||||
typedef struct lifetime_cfg_t lifetime_cfg_t;
|
typedef struct lifetime_cfg_t lifetime_cfg_t;
|
||||||
typedef struct mark_t mark_t;
|
typedef struct mark_t mark_t;
|
||||||
@@ -214,15 +215,29 @@ struct mark_t {
|
|||||||
*/
|
*/
|
||||||
#define MARK_UNIQUE (0xFFFFFFFF)
|
#define MARK_UNIQUE (0xFFFFFFFF)
|
||||||
#define MARK_UNIQUE_DIR (0xFFFFFFFE)
|
#define MARK_UNIQUE_DIR (0xFFFFFFFE)
|
||||||
|
#define MARK_SAME (0xFFFFFFFF)
|
||||||
#define MARK_IS_UNIQUE(m) ((m) == MARK_UNIQUE || (m) == MARK_UNIQUE_DIR)
|
#define MARK_IS_UNIQUE(m) ((m) == MARK_UNIQUE || (m) == MARK_UNIQUE_DIR)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special mark operations to accept when parsing marks.
|
||||||
|
*/
|
||||||
|
enum mark_op_t {
|
||||||
|
/** none of the following */
|
||||||
|
MARK_OP_NONE = 0,
|
||||||
|
/** %unique and %unique-dir */
|
||||||
|
MARK_OP_UNIQUE = (1<<0),
|
||||||
|
/** %same */
|
||||||
|
MARK_OP_SAME = (1<<1),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to parse a mark_t from the given string of the form mark[/mask].
|
* Try to parse a mark_t from the given string of the form mark[/mask].
|
||||||
*
|
*
|
||||||
* @param value string to parse
|
* @param value string to parse
|
||||||
|
* @param ops operations to accept
|
||||||
* @param mark mark to fill
|
* @param mark mark to fill
|
||||||
* @return TRUE if parsing was successful
|
* @return TRUE if parsing was successful
|
||||||
*/
|
*/
|
||||||
bool mark_from_string(const char *value, mark_t *mark);
|
bool mark_from_string(const char *value, mark_op_t ops, mark_t *mark);
|
||||||
|
|
||||||
#endif /** IPSEC_TYPES_H_ @}*/
|
#endif /** IPSEC_TYPES_H_ @}*/
|
||||||
|
|||||||
@@ -860,47 +860,75 @@ END_TEST
|
|||||||
static struct {
|
static struct {
|
||||||
char *s;
|
char *s;
|
||||||
bool ok;
|
bool ok;
|
||||||
|
mark_op_t ops;
|
||||||
mark_t m;
|
mark_t m;
|
||||||
} mark_data[] = {
|
} mark_data[] = {
|
||||||
{NULL, FALSE, { 0 }},
|
{NULL, FALSE, MARK_OP_NONE, { 0 }},
|
||||||
{"", TRUE, { 0, 0xffffffff }},
|
{"", TRUE, MARK_OP_NONE, { 0, 0xffffffff }},
|
||||||
{"/", TRUE, { 0, 0 }},
|
{"/", TRUE, MARK_OP_NONE, { 0, 0 }},
|
||||||
{"42", TRUE, { 42, 0xffffffff }},
|
{"42", TRUE, MARK_OP_NONE, { 42, 0xffffffff }},
|
||||||
{"0x42", TRUE, { 0x42, 0xffffffff }},
|
{"0x42", TRUE, MARK_OP_NONE, { 0x42, 0xffffffff }},
|
||||||
{"x", FALSE, { 0 }},
|
{"x", FALSE, MARK_OP_NONE, { 0 }},
|
||||||
{"42/", TRUE, { 0, 0 }},
|
{"42/", TRUE, MARK_OP_NONE, { 0, 0 }},
|
||||||
{"42/0", TRUE, { 0, 0 }},
|
{"42/0", TRUE, MARK_OP_NONE, { 0, 0 }},
|
||||||
{"42/x", FALSE, { 0 }},
|
{"42/x", FALSE, MARK_OP_NONE, { 0 }},
|
||||||
{"42/42", TRUE, { 42, 42 }},
|
{"42/42", TRUE, MARK_OP_NONE, { 42, 42 }},
|
||||||
{"42/0xff", TRUE, { 42, 0xff }},
|
{"42/0xff", TRUE, MARK_OP_NONE, { 42, 0xff }},
|
||||||
{"0x42/0xff", TRUE, { 0x42, 0xff }},
|
{"0x42/0xff", TRUE, MARK_OP_NONE, { 0x42, 0xff }},
|
||||||
{"/0xff", TRUE, { 0, 0xff }},
|
{"/0xff", TRUE, MARK_OP_NONE, { 0, 0xff }},
|
||||||
{"/x", FALSE, { 0 }},
|
{"/x", FALSE, MARK_OP_NONE, { 0 }},
|
||||||
{"x/x", FALSE, { 0 }},
|
{"x/x", FALSE, MARK_OP_NONE, { 0 }},
|
||||||
{"0xfffffff0/0x0000ffff", TRUE, { 0x0000fff0, 0x0000ffff }},
|
{"0xfffffff0/0x0000ffff", TRUE, MARK_OP_UNIQUE,
|
||||||
{"%unique", TRUE, { MARK_UNIQUE, 0xffffffff }},
|
{ 0x0000fff0, 0x0000ffff }},
|
||||||
{"%unique/", TRUE, { MARK_UNIQUE, 0 }},
|
{"%unique", TRUE, MARK_OP_UNIQUE,
|
||||||
{"%unique/0x0000ffff", TRUE, { MARK_UNIQUE, 0x0000ffff }},
|
{ MARK_UNIQUE, 0xffffffff }},
|
||||||
{"%unique/0xffffffff", TRUE, { MARK_UNIQUE, 0xffffffff }},
|
{"%unique/", TRUE, MARK_OP_UNIQUE,
|
||||||
{"%unique0xffffffffff", FALSE, { 0, 0 }},
|
{ MARK_UNIQUE, 0 }},
|
||||||
{"0xffffffff/0x0000ffff", TRUE, { MARK_UNIQUE, 0x0000ffff }},
|
{"%unique", FALSE, MARK_OP_NONE,
|
||||||
{"0xffffffff/0xffffffff", TRUE, { MARK_UNIQUE, 0xffffffff }},
|
{ 0, 0 }},
|
||||||
{"%unique-dir", TRUE, { MARK_UNIQUE_DIR, 0xffffffff }},
|
{"%unique/0x0000ffff", TRUE, MARK_OP_UNIQUE,
|
||||||
{"%unique-dir/", TRUE, { MARK_UNIQUE_DIR, 0 }},
|
{ MARK_UNIQUE, 0x0000ffff }},
|
||||||
{"%unique-dir/0x0000ffff", TRUE, { MARK_UNIQUE_DIR, 0x0000ffff }},
|
{"%unique/0xffffffff", TRUE, MARK_OP_UNIQUE,
|
||||||
{"%unique-dir/0xffffffff", TRUE, { MARK_UNIQUE_DIR, 0xffffffff }},
|
{ MARK_UNIQUE, 0xffffffff }},
|
||||||
{"%unique-dir0xffffffff", FALSE, { 0, 0 }},
|
{"%unique0xffffffffff", FALSE, MARK_OP_UNIQUE,
|
||||||
{"0xfffffffe/0x0000ffff", TRUE, { MARK_UNIQUE_DIR, 0x0000ffff }},
|
{ 0, 0 }},
|
||||||
{"0xfffffffe/0xffffffff", TRUE, { MARK_UNIQUE_DIR, 0xffffffff }},
|
{"0xffffffff/0x0000ffff", TRUE, MARK_OP_UNIQUE,
|
||||||
{"%unique-/0xffffffff", FALSE, { 0, 0 }},
|
{ MARK_UNIQUE, 0x0000ffff }},
|
||||||
{"%unique-foo/0xffffffff", FALSE, { 0, 0 }},
|
{"0xffffffff/0xffffffff", TRUE, MARK_OP_UNIQUE,
|
||||||
|
{ MARK_UNIQUE, 0xffffffff }},
|
||||||
|
{"%unique-dir", TRUE, MARK_OP_UNIQUE,
|
||||||
|
{ MARK_UNIQUE_DIR, 0xffffffff }},
|
||||||
|
{"%unique-dir/", TRUE, MARK_OP_UNIQUE,
|
||||||
|
{ MARK_UNIQUE_DIR, 0 }},
|
||||||
|
{"%unique-dir", FALSE, MARK_OP_NONE,
|
||||||
|
{ 0, 0 }},
|
||||||
|
{"%unique-dir/0x0000ffff", TRUE, MARK_OP_UNIQUE,
|
||||||
|
{ MARK_UNIQUE_DIR, 0x0000ffff }},
|
||||||
|
{"%unique-dir/0xffffffff", TRUE, MARK_OP_UNIQUE,
|
||||||
|
{ MARK_UNIQUE_DIR, 0xffffffff }},
|
||||||
|
{"%unique-dir0xffffffff", FALSE, MARK_OP_UNIQUE,
|
||||||
|
{ 0, 0 }},
|
||||||
|
{"0xfffffffe/0x0000ffff", TRUE, MARK_OP_UNIQUE,
|
||||||
|
{ MARK_UNIQUE_DIR, 0x0000ffff }},
|
||||||
|
{"0xfffffffe/0xffffffff", TRUE, MARK_OP_UNIQUE,
|
||||||
|
{ MARK_UNIQUE_DIR, 0xffffffff }},
|
||||||
|
{"%unique-/0xffffffff", FALSE, MARK_OP_UNIQUE,
|
||||||
|
{ 0, 0 }},
|
||||||
|
{"%unique-foo/0xffffffff", FALSE, MARK_OP_UNIQUE,
|
||||||
|
{ 0, 0 }},
|
||||||
|
{"%same", TRUE, MARK_OP_SAME,
|
||||||
|
{ MARK_SAME, 0xffffffff }},
|
||||||
|
{"%same/0x0000ffff", TRUE, MARK_OP_SAME,
|
||||||
|
{ MARK_SAME, 0x0000ffff }},
|
||||||
|
{"%%same", FALSE, MARK_OP_NONE,
|
||||||
|
{ 0, 0 }},
|
||||||
};
|
};
|
||||||
|
|
||||||
START_TEST(test_mark_from_string)
|
START_TEST(test_mark_from_string)
|
||||||
{
|
{
|
||||||
mark_t mark;
|
mark_t mark;
|
||||||
|
|
||||||
if (mark_from_string(mark_data[_i].s, &mark))
|
if (mark_from_string(mark_data[_i].s, mark_data[_i].ops, &mark))
|
||||||
{
|
{
|
||||||
ck_assert_int_eq(mark.value, mark_data[_i].m.value);
|
ck_assert_int_eq(mark.value, mark_data[_i].m.value);
|
||||||
ck_assert_int_eq(mark.mask, mark_data[_i].m.mask);
|
ck_assert_int_eq(mark.mask, mark_data[_i].m.mask);
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ static void handle_keyword(kw_token_t token, starter_conn_t *conn, char *key,
|
|||||||
KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_COMPRESS)
|
KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_COMPRESS)
|
||||||
break;
|
break;
|
||||||
case KW_MARK:
|
case KW_MARK:
|
||||||
if (!mark_from_string(value, &conn->mark_in))
|
if (!mark_from_string(value, MARK_OP_UNIQUE, &conn->mark_in))
|
||||||
{
|
{
|
||||||
cfg->err++;
|
cfg->err++;
|
||||||
break;
|
break;
|
||||||
@@ -452,13 +452,13 @@ static void handle_keyword(kw_token_t token, starter_conn_t *conn, char *key,
|
|||||||
conn->mark_out = conn->mark_in;
|
conn->mark_out = conn->mark_in;
|
||||||
break;
|
break;
|
||||||
case KW_MARK_IN:
|
case KW_MARK_IN:
|
||||||
if (!mark_from_string(value, &conn->mark_in))
|
if (!mark_from_string(value, MARK_OP_UNIQUE, &conn->mark_in))
|
||||||
{
|
{
|
||||||
cfg->err++;
|
cfg->err++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case KW_MARK_OUT:
|
case KW_MARK_OUT:
|
||||||
if (!mark_from_string(value, &conn->mark_out))
|
if (!mark_from_string(value, MARK_OP_UNIQUE, &conn->mark_out))
|
||||||
{
|
{
|
||||||
cfg->err++;
|
cfg->err++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -910,6 +910,37 @@ connections.<conn>.children.<child>.mark_out = 0/0x00000000
|
|||||||
An additional mask may be appended to the mark, separated by _/_. The
|
An additional mask may be appended to the mark, separated by _/_. The
|
||||||
default mask if omitted is 0xffffffff.
|
default mask if omitted is 0xffffffff.
|
||||||
|
|
||||||
|
connections.<conn>.children.<child>.set_mark_in = 0/0x00000000
|
||||||
|
Netfilter mark applied to packets after the inbound IPsec SA processed them.
|
||||||
|
|
||||||
|
Netfilter mark applied to packets after the inbound IPsec SA processed them.
|
||||||
|
This way it's not necessary to mark packets via Netfilter before decryption
|
||||||
|
or right afterwards to match policies or process them differently (e.g. via
|
||||||
|
policy routing).
|
||||||
|
|
||||||
|
An additional mask may be appended to the mark, separated by _/_. The
|
||||||
|
default mask if omitted is 0xffffffff. The special value _%same_ uses
|
||||||
|
the value (but not the mask) from **mark_in** as mark value, which can be
|
||||||
|
fixed, _%unique_ or _%unique-dir_.
|
||||||
|
|
||||||
|
Setting marks in XFRM input requires Linux 4.19 or higher.
|
||||||
|
|
||||||
|
connections.<conn>.children.<child>.set_mark_out = 0/0x00000000
|
||||||
|
Netfilter mark applied to packets after the outbound IPsec SA processed
|
||||||
|
them.
|
||||||
|
|
||||||
|
Netfilter mark applied to packets after the outbound IPsec SA processed
|
||||||
|
them. This allows processing ESP packets differently than the original
|
||||||
|
traffic (e.g. via policy routing).
|
||||||
|
|
||||||
|
An additional mask may be appended to the mark, separated by _/_. The
|
||||||
|
default mask if omitted is 0xffffffff. The special value _%same_ uses
|
||||||
|
the value (but not the mask) from **mark_out** as mark value, which can be
|
||||||
|
fixed, _%unique_ or _%unique-dir_.
|
||||||
|
|
||||||
|
Setting marks in XFRM output is supported since Linux 4.14. Setting a mask
|
||||||
|
requires at least Linux 4.19.
|
||||||
|
|
||||||
connections.<conn>.children.<child>.tfc_padding = 0
|
connections.<conn>.children.<child>.tfc_padding = 0
|
||||||
Traffic Flow Confidentiality padding.
|
Traffic Flow Confidentiality padding.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user