kernel: Add option to control DS field behavior

This commit is contained in:
Tobias Brunner 2018-06-11 12:07:48 +02:00
parent dc8b015d78
commit c993eaf9d1
9 changed files with 129 additions and 4 deletions

View File

@ -147,6 +147,11 @@ struct private_child_cfg_t {
* HW offload mode
*/
hw_offload_t hw_offload;
/**
* DS header field copy mode
*/
dscp_copy_t copy_dscp;
};
METHOD(child_cfg_t, get_name, char*,
@ -487,6 +492,12 @@ METHOD(child_cfg_t, get_hw_offload, hw_offload_t,
return this->hw_offload;
}
METHOD(child_cfg_t, get_copy_dscp, dscp_copy_t,
private_child_cfg_t *this)
{
return this->copy_dscp;
}
METHOD(child_cfg_t, get_dpd_action, action_t,
private_child_cfg_t *this)
{
@ -612,6 +623,8 @@ METHOD(child_cfg_t, equals, bool,
this->tfc == other->tfc &&
this->manual_prio == other->manual_prio &&
this->replay_window == other->replay_window &&
this->hw_offload == other->hw_offload &&
this->copy_dscp == other->copy_dscp &&
streq(this->updown, other->updown) &&
streq(this->interface, other->interface);
}
@ -673,6 +686,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
.get_ref = _get_ref,
.destroy = _destroy,
.get_hw_offload = _get_hw_offload,
.get_copy_dscp = _get_copy_dscp,
},
.name = strdup(name),
.options = data->options,
@ -696,6 +710,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
.replay_window = lib->settings->get_int(lib->settings,
"%s.replay_window", DEFAULT_REPLAY_WINDOW, lib->ns),
.hw_offload = data->hw_offload,
.copy_dscp = data->copy_dscp,
);
return &this->public;

View File

@ -191,6 +191,13 @@ struct child_cfg_t {
*/
hw_offload_t (*get_hw_offload) (child_cfg_t *this);
/**
* Get the copy mode for the DS header field to use for the CHILD_SA.
*
* @return IP header copy mode
*/
dscp_copy_t (*get_copy_dscp) (child_cfg_t *this);
/**
* Action to take if CHILD_SA gets closed.
*
@ -361,6 +368,8 @@ struct child_cfg_create_t {
char *updown;
/** HW offload mode */
hw_offload_t hw_offload;
/** How to handle the DS header field in tunnel mode */
dscp_copy_t copy_dscp;
};
/**

View File

@ -99,6 +99,8 @@ struct kernel_ipsec_add_sa_t {
bool copy_df;
/** TRUE to copy the ECN header field to/from the outer header */
bool copy_ecn;
/** Whether to copy the DSCP header field to/from the outer header */
dscp_copy_t copy_dscp;
/** TRUE if initiator of the exchange creating the SA */
bool initiator;
/** TRUE if this is an inbound SA */

View File

@ -1597,6 +1597,42 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
sa->flags |= XFRM_STATE_NOECN;
}
if (data->inbound)
{
switch (data->copy_dscp)
{
case DSCP_COPY_YES:
case DSCP_COPY_IN_ONLY:
sa->flags |= XFRM_STATE_DECAP_DSCP;
break;
default:
break;
}
}
else
{
switch (data->copy_dscp)
{
case DSCP_COPY_IN_ONLY:
case DSCP_COPY_NO:
{
uint32_t *xflags;
xflags = netlink_reserve(hdr, sizeof(request),
XFRMA_SA_EXTRA_FLAGS, sizeof(*xflags));
if (!xflags)
{
goto failed;
}
/* currently the only extra flag */
*xflags |= XFRM_SA_XFLAG_DONT_ENCAP_DSCP;
break;
}
default:
break;
}
}
switch (mode)
{
case MODE_TUNNEL:

View File

@ -536,6 +536,7 @@ static void log_child_data(child_data_t *data, char *name)
DBG2(DBG_CFG, " sha256_96 = %u", has_opt(OPT_SHA256_96));
DBG2(DBG_CFG, " copy_df = %u", !has_opt(OPT_NO_COPY_DF));
DBG2(DBG_CFG, " copy_ecn = %u", !has_opt(OPT_NO_COPY_ECN));
DBG2(DBG_CFG, " copy_dscp = %N", dscp_copy_names, cfg->copy_dscp);
}
/**
@ -939,6 +940,28 @@ CALLBACK(parse_opt_copy_ecn, bool,
return parse_option(out, OPT_NO_COPY_ECN, v, FALSE);
}
/**
* Parse a dscp_copy_t
*/
CALLBACK(parse_copy_dscp, bool,
dscp_copy_t *out, chunk_t v)
{
enum_map_t map[] = {
{ "no", DSCP_COPY_NO },
{ "in", DSCP_COPY_IN_ONLY },
{ "out", DSCP_COPY_OUT_ONLY },
{ "yes", DSCP_COPY_YES },
};
int d;
if (parse_map(map, countof(map), &d, v))
{
*out = d;
return TRUE;
}
return FALSE;
}
/**
* Parse an action_t
*/
@ -1623,6 +1646,7 @@ CALLBACK(child_kv, bool,
{ "sha256_96", parse_opt_sha256_96,&child->cfg.options },
{ "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 },
};
return parse_rules(rules, countof(rules), name, value,

View File

@ -893,6 +893,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
.esn = esn,
.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_dscp = this->config->get_copy_dscp(this->config),
.initiator = initiator,
.inbound = inbound,
.update = update,

View File

@ -43,6 +43,13 @@ ENUM(hw_offload_names, HW_OFFLOAD_NO, HW_OFFLOAD_AUTO,
"auto",
);
ENUM(dscp_copy_names, DSCP_COPY_OUT_ONLY, DSCP_COPY_NO,
"out",
"in",
"yes",
"no",
);
/*
* See header
*/

View File

@ -27,6 +27,7 @@ typedef enum policy_type_t policy_type_t;
typedef enum policy_priority_t policy_priority_t;
typedef enum ipcomp_transform_t ipcomp_transform_t;
typedef enum hw_offload_t hw_offload_t;
typedef enum dscp_copy_t dscp_copy_t;
typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t;
typedef struct lifetime_cfg_t lifetime_cfg_t;
typedef struct mark_t mark_t;
@ -131,6 +132,22 @@ enum hw_offload_t {
*/
extern enum_name_t *hw_offload_names;
/**
* DSCP header field copy behavior (the default is not to copy from outer
* to inner header)
*/
enum dscp_copy_t {
DSCP_COPY_OUT_ONLY,
DSCP_COPY_IN_ONLY,
DSCP_COPY_YES,
DSCP_COPY_NO,
};
/**
* enum strings for dscp_copy_t.
*/
extern enum_name_t *dscp_copy_names;
/**
* This struct contains details about IPsec SA(s) tied to a policy.
*/

View File

@ -941,16 +941,30 @@ connections.<conn>.children.<child>.copy_df = yes
Whether to copy the DF bit to the outer IPv4 header in tunnel mode.
Whether to copy the DF bit to the outer IPv4 header in tunnel mode. This
effectively disables Path MTU discovery (PMTUD). Disabling this is not
supported by all kernel interfaces.
effectively disables Path MTU discovery (PMTUD). Controlling this behavior
is not supported by all kernel interfaces.
connections.<conn>.children.<child>.copy_ecn = yes
Whether to copy the ECN header field to/from the outer IP header in tunnel
mode.
Whether to copy the ECN (Explicit Congestion Notification) header field
to/from the outer IP header in tunnel mode. Disabling this is not supported
by all kernel interfaces.
to/from the outer IP header in tunnel mode. Controlling this behavior is not
supported by all kernel interfaces.
connections.<conn>.children.<child>.copy_dscp = out
Whether to copy the DSCP header field to/from the outer IP header in tunnel
mode.
Whether to copy the DSCP (Differentiated Services Field Codepoint) header
field to/from the outer IP header in tunnel mode. The value _out_ only
copies the field from the inner to the outer header, the value _in_ does the
opposite and only copies the field from the outer to the inner header when
decapsulating, the value _yes_ copies the field in both directions, and the
value _no_ disables copying the field altogether. Setting this to _yes_ or
_in_ could allow an attacker to adversely affect other traffic at the
receiver, which is why the default is _out_. Controlling this behavior is
not supported by all kernel interfaces.
connections.<conn>.children.<child>.start_action = none
Action to perform after loading the configuration (_none_, _trap_, _start_).