]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel: Add options to control DF and ECN header bits/fields via XFRM
authorTobias Brunner <tobias@strongswan.org>
Mon, 11 Jun 2018 08:49:16 +0000 (10:49 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 29 Aug 2018 09:36:04 +0000 (11:36 +0200)
The options control whether the DF and ECN header bits/fields are copied
from the unencrypted packets to the encrypted packets in tunnel mode (DF only
for IPv4), and for ECN whether the same is done for inbound packets.

Note: This implementation only works with Linux/Netlink/XFRM.

Based on a patch by Markus Sattler.

src/libcharon/config/child_cfg.h
src/libcharon/kernel/kernel_ipsec.h
src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/libcharon/plugins/vici/vici_config.c
src/libcharon/sa/child_sa.c
src/swanctl/swanctl.opt

index 2defd03301d8d38b75f0d8a3fe7a046ca49cfa71..2b41a0cc4ef19bb67942b7745f5d327be2cb73d9 100644 (file)
@@ -319,6 +319,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),
 };
 
 /**
index 94b9c284bc7276f75dceb968ff1d4773ebc715d8..3feacb27e57abebac610ef769164741a55a15e11 100644 (file)
@@ -95,6 +95,10 @@ 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;
        /** TRUE if initiator of the exchange creating the SA */
        bool initiator;
        /** TRUE if this is an inbound SA */
index 4926c3de87511b860e71a35cbf5bfed017190b54..9751933e36d94d78d5744d63498943c1f301e351 100644 (file)
@@ -1586,6 +1586,17 @@ 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;
+       }
+
        switch (mode)
        {
                case MODE_TUNNEL:
index dfb4c84f3804a5d09a5581af4a9cc584922e7333..394d21997a38c4e8fd19ec2cee3fc58ff509f01f 100644 (file)
@@ -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,8 @@ 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));
 }
 
 /**
@@ -847,16 +848,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 +873,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 +891,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 +900,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 +918,25 @@ 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);
 }
 
 /**
@@ -1567,7 +1595,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 +1621,8 @@ 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                                     },
        };
 
        return parse_rules(rules, countof(rules), name, value,
@@ -1802,7 +1832,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 +1887,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);
 
index 49717703c991ef1f313d5c87bc53bc49aba6f5d8..b0efec54a7255d30d08bdbdcfc4ff05e3945cce7 100644 (file)
@@ -891,6 +891,8 @@ 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),
                .initiator = initiator,
                .inbound = inbound,
                .update = update,
index 120e5812e35dc204a3b26cb633dc35042914727b..d1e823a16ba7cfb2ea88f873eb3cdf24ec87c1a4 100644 (file)
@@ -937,6 +937,21 @@ 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).  Disabling this 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.
+
 connections.<conn>.children.<child>.start_action = none
        Action to perform after loading the configuration (_none_, _trap_, _start_).