]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
child-sa: Allow requesting different unique marks for in/out
authorEyal Birger <eyal.birger@gmail.com>
Fri, 28 Jul 2017 09:18:52 +0000 (12:18 +0300)
committerTobias Brunner <tobias@strongswan.org>
Mon, 7 Aug 2017 12:22:27 +0000 (14:22 +0200)
When requiring unique flags for CHILD_SAs, allow the configuration to
request different marks for each direction by using the %unique-dir keyword.

This is useful when different marks are desired for each direction but the
number of peers is not predefined.

An example use case is when implementing a site-to-site route-based VPN
without VTI devices.

A use of 0.0.0.0/0 - 0.0.0.0/0 traffic selectors with identical in/out marks
results in outbound traffic being wrongfully matched against the 'fwd'
policy - for which the underlay 'template' does not match - and dropped.

Using different marks for each direction avoids this issue as the 'fwd' policy
uses the 'in' mark will not match outbound traffic.

Closes strongswan/strongswan#78.

man/ipsec.conf.5.in
src/libcharon/sa/child_sa.c
src/libstrongswan/ipsec/ipsec_types.c
src/libstrongswan/ipsec/ipsec_types.h
src/swanctl/swanctl.opt

index fef44ae21255e8812285ad25a1ec73eedb1d72d9..69aeba8cba1508309aaf313fc23cf19cf86acd37 100644 (file)
@@ -1037,7 +1037,10 @@ mask of
 .B 0xffffffff
 is assumed. The special value
 .B %unique
-assigns a unique value to each newly created IPsec SA.
+assigns a unique value to each newly created IPsec SA. To additionally
+make the mark unique for each IPsec SA direction (in/out) the special value
+.B %unique-dir
+may be used.
 .TP
 .BR mark_in " = <value>[/<mask>]"
 sets an XFRM mark in the inbound IPsec SA and
index 4225267748ac19644258c4cf2dc02f31e9147fac..4133d9182e6b45bdadf2916f3ccc80f85832e064 100644 (file)
@@ -1745,7 +1745,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
 {
        private_child_sa_t *this;
        static refcount_t unique_id = 0, unique_mark = 0;
-       refcount_t mark;
+       refcount_t mark = 0;
 
        INIT(this,
                .public = {
@@ -1818,16 +1818,33 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
        {
                this->mark_out.value = mark_out;
        }
-       if (this->mark_in.value == MARK_UNIQUE ||
-               this->mark_out.value == MARK_UNIQUE)
+
+       if (MARK_IS_UNIQUE(this->mark_in.value) ||
+               MARK_IS_UNIQUE(this->mark_out.value))
        {
-               mark = ref_get(&unique_mark);
-               if (this->mark_in.value == MARK_UNIQUE)
+               bool unique_dir;
+
+               unique_dir = this->mark_in.value == MARK_UNIQUE_DIR ||
+                                        this->mark_out.value == MARK_UNIQUE_DIR;
+
+               if (!unique_dir)
+               {
+                       mark = ref_get(&unique_mark);
+               }
+               if (MARK_IS_UNIQUE(this->mark_in.value))
                {
+                       if (unique_dir)
+                       {
+                               mark = ref_get(&unique_mark);
+                       }
                        this->mark_in.value = mark;
                }
-               if (this->mark_out.value == MARK_UNIQUE)
+               if (MARK_IS_UNIQUE(this->mark_out.value))
                {
+                       if (unique_dir)
+                       {
+                               mark = ref_get(&unique_mark);
+                       }
                        this->mark_out.value = mark;
                }
        }
index a52a1eb5175428933c681860cec272ad8e4aae94..68c3935b9dd6a7c938bbbf1e02bd5a79865974c7 100644 (file)
@@ -66,8 +66,21 @@ bool mark_from_string(const char *value, mark_t *mark)
        }
        if (strcasepfx(value, "%unique"))
        {
-               mark->value = MARK_UNIQUE;
                endptr = (char*)value + strlen("%unique");
+               if (strcasepfx(endptr, "-dir"))
+               {
+                       mark->value = MARK_UNIQUE_DIR;
+                       endptr += strlen("-dir");
+               }
+               else if (!*endptr || *endptr == '/')
+               {
+                       mark->value = MARK_UNIQUE;
+               }
+               else
+               {
+                       DBG1(DBG_APP, "invalid mark value: %s", value);
+                       return FALSE;
+               }
        }
        else
        {
index c93d955622f8f8dbdea9bdfa6526d8091a6ea0a5..1db78ba6fc64fa064da780243cd27a2777bf4384 100644 (file)
@@ -178,9 +178,11 @@ struct mark_t {
 };
 
 /**
- * Special mark value that uses a unique mark for each CHILD_SA
+ * Special mark value that uses a unique mark for each CHILD_SA (and direction)
  */
 #define MARK_UNIQUE (0xFFFFFFFF)
+#define MARK_UNIQUE_DIR (0xFFFFFFFE)
+#define MARK_IS_UNIQUE(m) ((m) == MARK_UNIQUE || (m) == MARK_UNIQUE_DIR)
 
 /**
  * Try to parse a mark_t from the given string of the form mark[/mask].
index 634271d26467847751d914ecb8637d3eea1aa565..d0a0d21dd74cea16c16cbd452ed8642774cabbce 100644 (file)
@@ -870,7 +870,9 @@ connections.<conn>.children.<child>.mark_in = 0/0x00000000
        Netfilter mark and mask for input traffic. On Linux Netfilter may require
        marks on each packet to match an SA having that option set. This allows
        Netfilter rules to select specific tunnels for incoming traffic. The
-       special value _%unique_ sets a unique mark on each CHILD_SA instance.
+       special value _%unique_ sets a unique mark on each CHILD_SA instance,
+       beyond that the value _%unique-dir_ assigns a different unique mark for each
+       CHILD_SA direction (in/out).
 
        An additional mask may be appended to the mark, separated by _/_. The
        default mask if omitted is 0xffffffff.
@@ -881,7 +883,9 @@ connections.<conn>.children.<child>.mark_out = 0/0x00000000
        Netfilter mark and mask for output traffic. On Linux Netfilter may require
        marks on each packet to match a policy having that option set. This allows
        Netfilter rules to select specific tunnels for outgoing traffic. The
-       special value _%unique_ sets a unique mark on each CHILD_SA instance.
+       special value _%unique_ sets a unique mark on each CHILD_SA instance,
+       beyond that the value _%unique-dir_ assigns a different unique mark for each
+       CHILD_SA direction (in/out).
 
        An additional mask may be appended to the mark, separated by _/_. The
        default mask if omitted is 0xffffffff.