diff --git a/src/include/linux/xfrm.h b/src/include/linux/xfrm.h index dbaa4f128..35261c9a5 100644 --- a/src/include/linux/xfrm.h +++ b/src/include/linux/xfrm.h @@ -302,8 +302,11 @@ enum xfrm_attr_type_t { XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ XFRMA_PAD, XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */ + XFRMA_SET_MARK, /* __u32 */ + XFRMA_SET_MARK_MASK, /* __u32 */ __XFRMA_MAX +#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */ #define XFRMA_MAX (__XFRMA_MAX - 1) }; diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 98c15782b..14148ed03 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2017 Tobias Brunner + * Copyright (C) 2008-2018 Tobias Brunner * Copyright (C) 2016 Andreas Steffen * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -123,6 +123,16 @@ struct private_child_cfg_t { */ mark_t mark_out; + /** + * Optional mark to set to packets after inbound processing + */ + mark_t set_mark_in; + + /** + * Optional mark to set to packets after outbound processing + */ + mark_t set_mark_out; + /** * Traffic Flow Confidentiality padding, if enabled */ @@ -547,6 +557,12 @@ METHOD(child_cfg_t, get_mark, mark_t, return inbound ? this->mark_in : this->mark_out; } +METHOD(child_cfg_t, get_set_mark, mark_t, + private_child_cfg_t *this, bool inbound) +{ + return inbound ? this->set_mark_in : this->set_mark_out; +} + METHOD(child_cfg_t, get_tfc, uint32_t, private_child_cfg_t *this) { @@ -620,6 +636,10 @@ METHOD(child_cfg_t, equals, bool, this->mark_in.mask == other->mark_in.mask && this->mark_out.value == other->mark_out.value && this->mark_out.mask == other->mark_out.mask && + this->set_mark_in.value == other->set_mark_in.value && + this->set_mark_in.mask == other->set_mark_in.mask && + this->set_mark_out.value == other->set_mark_out.value && + this->set_mark_out.mask == other->set_mark_out.mask && this->tfc == other->tfc && this->manual_prio == other->manual_prio && this->replay_window == other->replay_window && @@ -676,6 +696,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .get_inactivity = _get_inactivity, .get_reqid = _get_reqid, .get_mark = _get_mark, + .get_set_mark = _get_set_mark, .get_tfc = _get_tfc, .get_manual_prio = _get_manual_prio, .get_interface = _get_interface, @@ -698,6 +719,8 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data) .close_action = data->close_action, .mark_in = data->mark_in, .mark_out = data->mark_out, + .set_mark_in = data->set_mark_in, + .set_mark_out = data->set_mark_out, .lifetime = data->lifetime, .inactivity = data->inactivity, .tfc = data->tfc, diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index f552dae71..e3b59e656 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2017 Tobias Brunner + * Copyright (C) 2008-2018 Tobias Brunner * Copyright (C) 2016 Andreas Steffen * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -227,13 +227,21 @@ struct child_cfg_t { uint32_t (*get_reqid)(child_cfg_t *this); /** - * Optional mark for CHILD_SA. + * Optional mark to set on policies/SAs. * * @param inbound TRUE for inbound, FALSE for outbound * @return mark */ mark_t (*get_mark)(child_cfg_t *this, bool inbound); + /** + * Optional mark the SAs should apply after processing packets. + * + * @param inbound TRUE for inbound, FALSE for outbound + * @return mark + */ + mark_t (*get_set_mark)(child_cfg_t *this, bool inbound); + /** * Get the TFC padding value to use for CHILD_SA. * @@ -346,6 +354,10 @@ struct child_cfg_create_t { mark_t mark_in; /** Optional outbound mark */ mark_t mark_out; + /** Optional inbound mark the SA should apply to traffic */ + mark_t set_mark_in; + /** Optional outbound mark the SA should apply to traffic */ + mark_t set_mark_out; /** Mode to propose for CHILD_SA */ ipsec_mode_t mode; /** TFC padding size, 0 to disable, -1 to pad to PMTU */ diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h index 195c80cff..4158eb45e 100644 --- a/src/libcharon/kernel/kernel_ipsec.h +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2016 Andreas Steffen - * Copyright (C) 2006-2016 Tobias Brunner + * Copyright (C) 2006-2018 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -93,6 +93,8 @@ struct kernel_ipsec_add_sa_t { bool encap; /** no (disabled), yes (enabled), auto (enabled if supported) */ hw_offload_t hw_offload; + /** Mark the SA should apply to packets after processing */ + mark_t mark; /** TRUE to use Extended Sequence Numbers */ bool esn; /** TRUE to copy the DF bit to the outer IPv4 header in tunnel mode */ diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 33e982d22..1292e0895 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1335,6 +1335,23 @@ static bool add_mark(struct nlmsghdr *hdr, int buflen, mark_t mark) return TRUE; } +/** + * Add a uint32 attribute to message + */ +static bool add_uint32(struct nlmsghdr *hdr, int buflen, + enum xfrm_attr_type_t type, uint32_t value) +{ + uint32_t *xvalue; + + xvalue = netlink_reserve(hdr, buflen, type, sizeof(*xvalue)); + if (!xvalue) + { + return FALSE; + } + *xvalue = value; + return TRUE; +} + /** * Check if kernel supports HW offload */ @@ -1616,16 +1633,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t, 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) + /* currently the only extra flag */ + if (!add_uint32(hdr, sizeof(request), XFRMA_SA_EXTRA_FLAGS, + XFRM_SA_XFLAG_DONT_ENCAP_DSCP)) { goto failed; } - /* currently the only extra flag */ - *xflags |= XFRM_SA_XFLAG_DONT_ENCAP_DSCP; break; } default: @@ -1876,17 +1889,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t, goto failed; } + if (ipcomp == IPCOMP_NONE && (data->mark.value | data->mark.mask)) + { + if (!add_uint32(hdr, sizeof(request), XFRMA_SET_MARK, + data->mark.value) || + !add_uint32(hdr, sizeof(request), XFRMA_SET_MARK_MASK, + data->mark.mask)) + { + goto failed; + } + } + if (data->tfc && id->proto == IPPROTO_ESP && mode == MODE_TUNNEL) { /* the kernel supports TFC padding only for tunnel mode ESP SAs */ - uint32_t *tfcpad; - - tfcpad = netlink_reserve(hdr, sizeof(request), XFRMA_TFCPAD, - sizeof(*tfcpad)); - if (!tfcpad) + if (!add_uint32(hdr, sizeof(request), XFRMA_TFCPAD, data->tfc)) { goto failed; } - *tfcpad = data->tfc; } if (id->proto != IPPROTO_COMP) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c index 3ef3dc712..c9a76ba01 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c @@ -2925,7 +2925,7 @@ static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type, msg->rtm_flags |= FIB_RULE_INVERT; fwmark++; } - if (mark_from_string(fwmark, &mark)) + if (mark_from_string(fwmark, MARK_OP_NONE, &mark)) { chunk = chunk_from_thing(mark.value); netlink_add_attribute(hdr, FRA_FWMARK, chunk, sizeof(request)); diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c index 57e092968..68e5a7a0e 100644 --- a/src/libcharon/plugins/socket_default/socket_default_socket.c +++ b/src/libcharon/plugins/socket_default/socket_default_socket.c @@ -745,7 +745,7 @@ static int open_socket(private_socket_default_socket_t *this, fwmark = lib->settings->get_str(lib->settings, "%s.plugins.socket-default.fwmark", NULL, lib->ns); - if (fwmark && mark_from_string(fwmark, &mark)) + if (fwmark && mark_from_string(fwmark, MARK_OP_NONE, &mark)) { if (setsockopt(skt, SOL_SOCKET, SO_MARK, &mark.value, sizeof(mark.value)) < 0) diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 7a66af1f4..8afefaa09 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -528,6 +528,10 @@ static void log_child_data(child_data_t *data, char *name) DBG2(DBG_CFG, " mark_in_sa = %u", has_opt(OPT_MARK_IN_SA)); DBG2(DBG_CFG, " mark_out = %u/%u", cfg->mark_out.value, cfg->mark_out.mask); + DBG2(DBG_CFG, " set_mark_in = %u/%u", + cfg->set_mark_in.value, cfg->set_mark_in.mask); + DBG2(DBG_CFG, " set_mark_out = %u/%u", + cfg->set_mark_out.value, cfg->set_mark_out.mask); DBG2(DBG_CFG, " inactivity = %llu", cfg->inactivity); DBG2(DBG_CFG, " proposals = %#P", data->proposals); DBG2(DBG_CFG, " local_ts = %#R", data->local_ts); @@ -1177,7 +1181,22 @@ CALLBACK(parse_mark, bool, { return FALSE; } - return mark_from_string(buf, out); + 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); } /** @@ -1639,6 +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_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 d06996e43..c33398bee 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -890,6 +890,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr, .cpi = cpi, .encap = this->encap, .hw_offload = this->config->get_hw_offload(this->config), + .mark = this->config->get_set_mark(this->config, inbound), .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), @@ -899,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 d231bb3a4..6f19cc751 100644 --- a/src/libstrongswan/ipsec/ipsec_types.c +++ b/src/libstrongswan/ipsec/ipsec_types.c @@ -69,7 +69,7 @@ bool ipsec_sa_cfg_equals(ipsec_sa_cfg_t *a, ipsec_sa_cfg_t *b) /* * See header */ -bool mark_from_string(const char *value, mark_t *mark) +bool mark_from_string(const char *value, mark_op_t ops, mark_t *mark) { char *endptr; @@ -79,6 +79,11 @@ bool mark_from_string(const char *value, mark_t *mark) } if (strcasepfx(value, "%unique")) { + if (!(ops & MARK_OP_UNIQUE)) + { + DBG1(DBG_APP, "unexpected use of %%unique mark", value); + return FALSE; + } endptr = (char*)value + strlen("%unique"); if (strcasepfx(endptr, "-dir")) { @@ -95,6 +100,24 @@ bool mark_from_string(const char *value, 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 bd5545e22..7b7bd3743 100644 --- a/src/libstrongswan/ipsec/ipsec_types.h +++ b/src/libstrongswan/ipsec/ipsec_types.h @@ -28,6 +28,7 @@ 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 enum mark_op_t mark_op_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; @@ -214,15 +215,29 @@ 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) +/** + * Special mark operations to accept when parsing marks. + */ +enum mark_op_t { + /** none of the following */ + MARK_OP_NONE = 0, + /** %unique and %unique-dir */ + MARK_OP_UNIQUE = (1<<0), + /** %same */ + MARK_OP_SAME = (1<<1), +}; + /** * Try to parse a mark_t from the given string of the form mark[/mask]. * * @param value string to parse + * @param ops operations to accept * @param mark mark to fill * @return TRUE if parsing was successful */ -bool mark_from_string(const char *value, mark_t *mark); +bool mark_from_string(const char *value, mark_op_t ops, mark_t *mark); #endif /** IPSEC_TYPES_H_ @}*/ diff --git a/src/libstrongswan/tests/suites/test_utils.c b/src/libstrongswan/tests/suites/test_utils.c index 00f000a6a..f1d46ee6b 100644 --- a/src/libstrongswan/tests/suites/test_utils.c +++ b/src/libstrongswan/tests/suites/test_utils.c @@ -860,47 +860,75 @@ END_TEST static struct { char *s; bool ok; + mark_op_t ops; mark_t m; } mark_data[] = { - {NULL, FALSE, { 0 }}, - {"", TRUE, { 0, 0xffffffff }}, - {"/", TRUE, { 0, 0 }}, - {"42", TRUE, { 42, 0xffffffff }}, - {"0x42", TRUE, { 0x42, 0xffffffff }}, - {"x", FALSE, { 0 }}, - {"42/", TRUE, { 0, 0 }}, - {"42/0", TRUE, { 0, 0 }}, - {"42/x", FALSE, { 0 }}, - {"42/42", TRUE, { 42, 42 }}, - {"42/0xff", TRUE, { 42, 0xff }}, - {"0x42/0xff", TRUE, { 0x42, 0xff }}, - {"/0xff", TRUE, { 0, 0xff }}, - {"/x", FALSE, { 0 }}, - {"x/x", FALSE, { 0 }}, - {"0xfffffff0/0x0000ffff", TRUE, { 0x0000fff0, 0x0000ffff }}, - {"%unique", TRUE, { MARK_UNIQUE, 0xffffffff }}, - {"%unique/", TRUE, { MARK_UNIQUE, 0 }}, - {"%unique/0x0000ffff", TRUE, { MARK_UNIQUE, 0x0000ffff }}, - {"%unique/0xffffffff", TRUE, { MARK_UNIQUE, 0xffffffff }}, - {"%unique0xffffffffff", FALSE, { 0, 0 }}, - {"0xffffffff/0x0000ffff", TRUE, { MARK_UNIQUE, 0x0000ffff }}, - {"0xffffffff/0xffffffff", TRUE, { MARK_UNIQUE, 0xffffffff }}, - {"%unique-dir", TRUE, { MARK_UNIQUE_DIR, 0xffffffff }}, - {"%unique-dir/", TRUE, { MARK_UNIQUE_DIR, 0 }}, - {"%unique-dir/0x0000ffff", TRUE, { MARK_UNIQUE_DIR, 0x0000ffff }}, - {"%unique-dir/0xffffffff", TRUE, { MARK_UNIQUE_DIR, 0xffffffff }}, - {"%unique-dir0xffffffff", FALSE, { 0, 0 }}, - {"0xfffffffe/0x0000ffff", TRUE, { MARK_UNIQUE_DIR, 0x0000ffff }}, - {"0xfffffffe/0xffffffff", TRUE, { MARK_UNIQUE_DIR, 0xffffffff }}, - {"%unique-/0xffffffff", FALSE, { 0, 0 }}, - {"%unique-foo/0xffffffff", FALSE, { 0, 0 }}, + {NULL, FALSE, MARK_OP_NONE, { 0 }}, + {"", TRUE, MARK_OP_NONE, { 0, 0xffffffff }}, + {"/", TRUE, MARK_OP_NONE, { 0, 0 }}, + {"42", TRUE, MARK_OP_NONE, { 42, 0xffffffff }}, + {"0x42", TRUE, MARK_OP_NONE, { 0x42, 0xffffffff }}, + {"x", FALSE, MARK_OP_NONE, { 0 }}, + {"42/", TRUE, MARK_OP_NONE, { 0, 0 }}, + {"42/0", TRUE, MARK_OP_NONE, { 0, 0 }}, + {"42/x", FALSE, MARK_OP_NONE, { 0 }}, + {"42/42", TRUE, MARK_OP_NONE, { 42, 42 }}, + {"42/0xff", TRUE, MARK_OP_NONE, { 42, 0xff }}, + {"0x42/0xff", TRUE, MARK_OP_NONE, { 0x42, 0xff }}, + {"/0xff", TRUE, MARK_OP_NONE, { 0, 0xff }}, + {"/x", FALSE, MARK_OP_NONE, { 0 }}, + {"x/x", FALSE, MARK_OP_NONE, { 0 }}, + {"0xfffffff0/0x0000ffff", TRUE, MARK_OP_UNIQUE, + { 0x0000fff0, 0x0000ffff }}, + {"%unique", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE, 0xffffffff }}, + {"%unique/", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE, 0 }}, + {"%unique", FALSE, MARK_OP_NONE, + { 0, 0 }}, + {"%unique/0x0000ffff", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE, 0x0000ffff }}, + {"%unique/0xffffffff", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE, 0xffffffff }}, + {"%unique0xffffffffff", FALSE, MARK_OP_UNIQUE, + { 0, 0 }}, + {"0xffffffff/0x0000ffff", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE, 0x0000ffff }}, + {"0xffffffff/0xffffffff", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE, 0xffffffff }}, + {"%unique-dir", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE_DIR, 0xffffffff }}, + {"%unique-dir/", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE_DIR, 0 }}, + {"%unique-dir", FALSE, MARK_OP_NONE, + { 0, 0 }}, + {"%unique-dir/0x0000ffff", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE_DIR, 0x0000ffff }}, + {"%unique-dir/0xffffffff", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE_DIR, 0xffffffff }}, + {"%unique-dir0xffffffff", FALSE, MARK_OP_UNIQUE, + { 0, 0 }}, + {"0xfffffffe/0x0000ffff", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE_DIR, 0x0000ffff }}, + {"0xfffffffe/0xffffffff", TRUE, MARK_OP_UNIQUE, + { MARK_UNIQUE_DIR, 0xffffffff }}, + {"%unique-/0xffffffff", FALSE, MARK_OP_UNIQUE, + { 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) { mark_t mark; - if (mark_from_string(mark_data[_i].s, &mark)) + if (mark_from_string(mark_data[_i].s, mark_data[_i].ops, &mark)) { ck_assert_int_eq(mark.value, mark_data[_i].m.value); ck_assert_int_eq(mark.mask, mark_data[_i].m.mask); diff --git a/src/starter/confread.c b/src/starter/confread.c index 345d0b60b..407ef5e13 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -444,7 +444,7 @@ static void handle_keyword(kw_token_t token, starter_conn_t *conn, char *key, KW_SA_OPTION_FLAG("yes", "no", SA_OPTION_COMPRESS) break; case KW_MARK: - if (!mark_from_string(value, &conn->mark_in)) + if (!mark_from_string(value, MARK_OP_UNIQUE, &conn->mark_in)) { cfg->err++; break; @@ -452,13 +452,13 @@ static void handle_keyword(kw_token_t token, starter_conn_t *conn, char *key, conn->mark_out = conn->mark_in; break; case KW_MARK_IN: - if (!mark_from_string(value, &conn->mark_in)) + if (!mark_from_string(value, MARK_OP_UNIQUE, &conn->mark_in)) { cfg->err++; } break; case KW_MARK_OUT: - if (!mark_from_string(value, &conn->mark_out)) + if (!mark_from_string(value, MARK_OP_UNIQUE, &conn->mark_out)) { cfg->err++; } diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt index 3f67b938a..5b44c541b 100644 --- a/src/swanctl/swanctl.opt +++ b/src/swanctl/swanctl.opt @@ -910,6 +910,37 @@ connections..children..mark_out = 0/0x00000000 An additional mask may be appended to the mark, separated by _/_. The default mask if omitted is 0xffffffff. +connections..children..set_mark_in = 0/0x00000000 + Netfilter mark applied to packets after the inbound IPsec SA processed them. + + Netfilter mark applied to packets after the inbound IPsec SA processed them. + This way it's not necessary to mark packets via Netfilter before decryption + or right afterwards to match policies or process them differently (e.g. via + policy routing). + + An additional mask may be appended to the mark, separated by _/_. The + 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. + +connections..children..set_mark_out = 0/0x00000000 + Netfilter mark applied to packets after the outbound IPsec SA processed + them. + + Netfilter mark applied to packets after the outbound IPsec SA processed + them. This allows processing ESP packets differently than the original + traffic (e.g. via policy routing). + + An additional mask may be appended to the mark, separated by _/_. The + 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. + connections..children..tfc_padding = 0 Traffic Flow Confidentiality padding.