From: Martin Willi Date: Wed, 9 May 2018 11:40:36 +0000 (+0200) Subject: child-sa: Use SA matching mark as SA set mark if the latter is %same X-Git-Tag: 5.7.0rc1~28^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=902dc29f7a3c5e2597b4a59718c6f8b34bf893f2;p=thirdparty%2Fstrongswan.git child-sa: Use SA matching mark as SA set mark if the latter is %same 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. --- diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 98f68264c2..8afefaa094 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -1184,6 +1184,21 @@ CALLBACK(parse_mark, bool, 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); +} + /** * Parse TFC padding option */ @@ -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 }, diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index efa790fc5e..c33398beeb 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -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); diff --git a/src/libstrongswan/ipsec/ipsec_types.c b/src/libstrongswan/ipsec/ipsec_types.c index 7eed1566a8..6f19cc7513 100644 --- a/src/libstrongswan/ipsec/ipsec_types.c +++ b/src/libstrongswan/ipsec/ipsec_types.c @@ -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); diff --git a/src/libstrongswan/ipsec/ipsec_types.h b/src/libstrongswan/ipsec/ipsec_types.h index 5b1735178a..7b7bd3743e 100644 --- a/src/libstrongswan/ipsec/ipsec_types.h +++ b/src/libstrongswan/ipsec/ipsec_types.h @@ -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), }; /** diff --git a/src/libstrongswan/tests/suites/test_utils.c b/src/libstrongswan/tests/suites/test_utils.c index 5a854f3f67..f1d46ee6be 100644 --- a/src/libstrongswan/tests/suites/test_utils.c +++ b/src/libstrongswan/tests/suites/test_utils.c @@ -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) diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt index 79655ed357..5b44c541bb 100644 --- a/src/swanctl/swanctl.opt +++ b/src/swanctl/swanctl.opt @@ -919,7 +919,9 @@ connections..children..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..children..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.