child-sa: Use SA matching mark as SA set mark if the latter is %same
authorMartin Willi <martin@strongswan.org>
Wed, 9 May 2018 11:40:36 +0000 (13:40 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 31 Aug 2018 10:26:40 +0000 (12:26 +0200)
For inbound processing, it can be rather useful to apply the mark to the
packet in the SA, so the associated policy with that mark implicitly matches.
When using %unique as match mark, we don't know the mark beforehand, so
we most likely want to set the mark we match against.

src/libcharon/plugins/vici/vici_config.c
src/libcharon/sa/child_sa.c
src/libstrongswan/ipsec/ipsec_types.c
src/libstrongswan/ipsec/ipsec_types.h
src/libstrongswan/tests/suites/test_utils.c
src/swanctl/swanctl.opt

index 98f6826..8afefaa 100644 (file)
@@ -1185,6 +1185,21 @@ CALLBACK(parse_mark, bool,
 }
 
 /**
+ * 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);
+}
+
+/**
  * Parse TFC padding option
  */
 CALLBACK(parse_tfc, bool,
@@ -1643,8 +1658,8 @@ CALLBACK(child_kv, bool,
                { "mark_in",                    parse_mark,                     &child->cfg.mark_in                                     },
                { "mark_in_sa",                 parse_opt_mark_in,      &child->cfg.options                                     },
                { "mark_out",                   parse_mark,                     &child->cfg.mark_out                            },
-               { "set_mark_in",                parse_mark,                     &child->cfg.set_mark_in                         },
-               { "set_mark_out",               parse_mark,                     &child->cfg.set_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                                         },
                { "priority",                   parse_uint32,           &child->cfg.priority                            },
                { "interface",                  parse_string,           &child->cfg.interface                           },
index efa790f..c33398b 100644 (file)
@@ -900,6 +900,11 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
                .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);
 
        my_ts->destroy(my_ts);
index 7eed156..6f19cc7 100644 (file)
@@ -100,6 +100,24 @@ bool mark_from_string(const char *value, mark_op_t ops, mark_t *mark)
                        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
        {
                mark->value = strtoul(value, &endptr, 0);
index 5b17351..7b7bd37 100644 (file)
@@ -215,6 +215,7 @@ struct mark_t {
  */
 #define MARK_UNIQUE (0xFFFFFFFF)
 #define MARK_UNIQUE_DIR (0xFFFFFFFE)
+#define MARK_SAME (0xFFFFFFFF)
 #define MARK_IS_UNIQUE(m) ((m) == MARK_UNIQUE || (m) == MARK_UNIQUE_DIR)
 
 /**
@@ -225,6 +226,8 @@ enum mark_op_t {
        MARK_OP_NONE = 0,
        /** %unique and %unique-dir */
        MARK_OP_UNIQUE = (1<<0),
+       /** %same */
+       MARK_OP_SAME = (1<<1),
 };
 
 /**
index 5a854f3..f1d46ee 100644 (file)
@@ -916,6 +916,12 @@ static struct {
                { 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)
index 79655ed..5b44c54 100644 (file)
@@ -919,7 +919,9 @@ connections.<conn>.children.<child>.set_mark_in = 0/0x00000000
        policy routing).
 
        An additional mask may be appended to the mark, separated by _/_. The
-       default mask if omitted is 0xffffffff.
+       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.
 
@@ -932,7 +934,9 @@ connections.<conn>.children.<child>.set_mark_out = 0/0x00000000
        traffic (e.g. via policy routing).
 
        An additional mask may be appended to the mark, separated by _/_. The
-       default mask if omitted is 0xffffffff.
+       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.