Merge branch 'ip-header-fields'
Adds new options that allow configuring how/whether certain fields in the IP headers are copied during IPsec processing. Currently only allows configuration on Linux. Closes strongswan/strongswan#104.
This commit is contained in:
commit
d98df236a9
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
@ -319,6 +326,12 @@ enum child_cfg_option_t {
|
|||
|
||||
/** Set mark on inbound SAs */
|
||||
OPT_MARK_IN_SA = (1<<6),
|
||||
|
||||
/** Disable copying the DF bit to the outer IPv4 header in tunnel mode */
|
||||
OPT_NO_COPY_DF = (1<<7),
|
||||
|
||||
/** Disable copying the ECN header field in tunnel mode */
|
||||
OPT_NO_COPY_ECN = (1<<8),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -355,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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -95,6 +95,12 @@ struct kernel_ipsec_add_sa_t {
|
|||
hw_offload_t hw_offload;
|
||||
/** TRUE to use Extended Sequence Numbers */
|
||||
bool esn;
|
||||
/** TRUE to copy the DF bit to the outer IPv4 header in tunnel mode */
|
||||
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 */
|
||||
|
|
|
@ -1586,6 +1586,53 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
|||
sa->id.proto = id->proto;
|
||||
sa->family = id->src->get_family(id->src);
|
||||
sa->mode = mode2kernel(mode);
|
||||
|
||||
if (!data->copy_df)
|
||||
{
|
||||
sa->flags |= XFRM_STATE_NOPMTUDISC;
|
||||
}
|
||||
|
||||
if (!data->copy_ecn)
|
||||
{
|
||||
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:
|
||||
|
|
|
@ -484,7 +484,6 @@ typedef struct {
|
|||
linked_list_t *local_ts;
|
||||
linked_list_t *remote_ts;
|
||||
uint32_t replay_window;
|
||||
bool policies;
|
||||
child_cfg_create_t cfg;
|
||||
} child_data_t;
|
||||
|
||||
|
@ -511,7 +510,7 @@ static void log_child_data(child_data_t *data, char *name)
|
|||
DBG2(DBG_CFG, " ipcomp = %u", has_opt(OPT_IPCOMP));
|
||||
DBG2(DBG_CFG, " mode = %N%s", ipsec_mode_names, cfg->mode,
|
||||
has_opt(OPT_PROXY_MODE) ? "_PROXY" : "");
|
||||
DBG2(DBG_CFG, " policies = %u", data->policies);
|
||||
DBG2(DBG_CFG, " policies = %u", !has_opt(OPT_NO_POLICIES));
|
||||
DBG2(DBG_CFG, " policies_fwd_out = %u", has_opt(OPT_FWD_OUT_POLICIES));
|
||||
if (data->replay_window != REPLAY_UNDEFINED)
|
||||
{
|
||||
|
@ -535,6 +534,9 @@ static void log_child_data(child_data_t *data, char *name)
|
|||
DBG2(DBG_CFG, " remote_ts = %#R", data->remote_ts);
|
||||
DBG2(DBG_CFG, " hw_offload = %N", hw_offload_names, cfg->hw_offload);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -847,16 +849,17 @@ CALLBACK(parse_mode, bool,
|
|||
}
|
||||
|
||||
/**
|
||||
* Enable a child_cfg_option_t
|
||||
* Enable a child_cfg_option_t, the flag controls whether the option is enabled
|
||||
* if the parsed value is TRUE or FALSE.
|
||||
*/
|
||||
static bool parse_option(child_cfg_option_t *out, child_cfg_option_t opt,
|
||||
chunk_t v)
|
||||
chunk_t v, bool add_if_true)
|
||||
{
|
||||
bool val;
|
||||
|
||||
if (parse_bool(&val, v))
|
||||
{
|
||||
if (val)
|
||||
if (val == add_if_true)
|
||||
{
|
||||
*out |= opt;
|
||||
}
|
||||
|
@ -871,7 +874,16 @@ static bool parse_option(child_cfg_option_t *out, child_cfg_option_t opt,
|
|||
CALLBACK(parse_opt_haccess, bool,
|
||||
child_cfg_option_t *out, chunk_t v)
|
||||
{
|
||||
return parse_option(out, OPT_HOSTACCESS, v);
|
||||
return parse_option(out, OPT_HOSTACCESS, v, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse OPT_NO_POLICIES option
|
||||
*/
|
||||
CALLBACK(parse_opt_policies, bool,
|
||||
child_cfg_option_t *out, chunk_t v)
|
||||
{
|
||||
return parse_option(out, OPT_NO_POLICIES, v, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -880,7 +892,7 @@ CALLBACK(parse_opt_haccess, bool,
|
|||
CALLBACK(parse_opt_fwd_out, bool,
|
||||
child_cfg_option_t *out, chunk_t v)
|
||||
{
|
||||
return parse_option(out, OPT_FWD_OUT_POLICIES, v);
|
||||
return parse_option(out, OPT_FWD_OUT_POLICIES, v, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -889,17 +901,16 @@ CALLBACK(parse_opt_fwd_out, bool,
|
|||
CALLBACK(parse_opt_ipcomp, bool,
|
||||
child_cfg_option_t *out, chunk_t v)
|
||||
{
|
||||
return parse_option(out, OPT_IPCOMP, v);
|
||||
return parse_option(out, OPT_IPCOMP, v, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse OPT_SHA256_96 option
|
||||
*/
|
||||
CALLBACK(parse_opt_sha256_96, bool,
|
||||
child_cfg_option_t *out, chunk_t v)
|
||||
{
|
||||
return parse_option(out, OPT_SHA256_96, v);
|
||||
return parse_option(out, OPT_SHA256_96, v, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -908,7 +919,47 @@ CALLBACK(parse_opt_sha256_96, bool,
|
|||
CALLBACK(parse_opt_mark_in, bool,
|
||||
child_cfg_option_t *out, chunk_t v)
|
||||
{
|
||||
return parse_option(out, OPT_MARK_IN_SA, v);
|
||||
return parse_option(out, OPT_MARK_IN_SA, v, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse OPT_NO_COPY_DF option
|
||||
*/
|
||||
CALLBACK(parse_opt_copy_df, bool,
|
||||
child_cfg_option_t *out, chunk_t v)
|
||||
{
|
||||
return parse_option(out, OPT_NO_COPY_DF, v, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse OPT_NO_COPY_ECN option
|
||||
*/
|
||||
CALLBACK(parse_opt_copy_ecn, bool,
|
||||
child_cfg_option_t *out, chunk_t v)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1567,7 +1618,7 @@ CALLBACK(child_kv, bool,
|
|||
{ "updown", parse_string, &child->cfg.updown },
|
||||
{ "hostaccess", parse_opt_haccess, &child->cfg.options },
|
||||
{ "mode", parse_mode, &child->cfg },
|
||||
{ "policies", parse_bool, &child->policies },
|
||||
{ "policies", parse_opt_policies, &child->cfg.options },
|
||||
{ "policies_fwd_out", parse_opt_fwd_out, &child->cfg.options },
|
||||
{ "replay_window", parse_uint32, &child->replay_window },
|
||||
{ "rekey_time", parse_time, &child->cfg.lifetime.time.rekey },
|
||||
|
@ -1593,6 +1644,9 @@ CALLBACK(child_kv, bool,
|
|||
{ "interface", parse_string, &child->cfg.interface },
|
||||
{ "hw_offload", parse_hw_offload, &child->cfg.hw_offload },
|
||||
{ "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,
|
||||
|
@ -1802,7 +1856,6 @@ CALLBACK(children_sn, bool,
|
|||
.proposals = linked_list_create(),
|
||||
.local_ts = linked_list_create(),
|
||||
.remote_ts = linked_list_create(),
|
||||
.policies = TRUE,
|
||||
.replay_window = REPLAY_UNDEFINED,
|
||||
.cfg = {
|
||||
.mode = MODE_TUNNEL,
|
||||
|
@ -1858,7 +1911,6 @@ CALLBACK(children_sn, bool,
|
|||
child.proposals->insert_last(child.proposals, proposal);
|
||||
}
|
||||
}
|
||||
child.cfg.options |= child.policies ? 0 : OPT_NO_POLICIES;
|
||||
|
||||
check_lifetimes(&child.cfg.lifetime);
|
||||
|
||||
|
|
|
@ -891,6 +891,9 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
|
|||
.encap = this->encap,
|
||||
.hw_offload = this->config->get_hw_offload(this->config),
|
||||
.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,
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -937,6 +937,35 @@ connections.<conn>.children.<child>.hw_offload = no
|
|||
enables offloading, if it's supported, but the installation does not fail
|
||||
otherwise.
|
||||
|
||||
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). 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. 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_).
|
||||
|
||||
|
|
Loading…
Reference in New Issue