Blob Blame History Raw
Date: Sat Oct 21 00:25:15 2017 +0300
From: Shmulik Ladkani <shmulik.ladkani@gmail.com>
References:  bsc#1166978
Subject: ip6_tunnel: Allow rcv/xmit even if remote address is a local address
Patch-mainline: v4.14-rc5
Git-commit: 908d140a87a794bf89717ceae54aba5ce86c52e4
Acked-by: Otto Hollmann <otto.hollmann@suse.com>

    ip6_tunnel: Allow rcv/xmit even if remote address is a local address
    
    Currently, ip6_tnl_xmit_ctl drops tunneled packets if the remote
    address (outer v6 destination) is one of host's locally configured
    addresses.
    Same applies to ip6_tnl_rcv_ctl: it drops packets if the remote address
    (outer v6 source) is a local address.
    
    This prevents using ipxip6 (and ip6_gre) tunnels whose local/remote
    endpoints are on same host; OTOH v4 tunnels (ipip or gre) allow such
    configurations.
    
    An example where this proves useful is a system where entities are
    identified by their unique v6 addresses, and use tunnels to encapsulate
    traffic between them. The limitation prevents placing several entities
    on same host.
    
    Introduce IP6_TNL_F_ALLOW_LOCAL_REMOTE which allows to bypass this
    restriction.
    
    Signed-off-by: Shmulik Ladkani <shmulik.ladkani@gmail.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

diff --git a/include/uapi/linux/ip6_tunnel.h b/include/uapi/linux/ip6_tunnel.h
index 425926c467d7..ffebbe365478 100644
--- a/include/uapi/linux/ip6_tunnel.h
+++ b/include/uapi/linux/ip6_tunnel.h
@@ -20,6 +20,8 @@
 #define IP6_TNL_F_RCV_DSCP_COPY 0x10
 /* copy fwmark from inner packet */
 #define IP6_TNL_F_USE_ORIG_FWMARK 0x20
+/* allow remote endpoint on the local node */
+#define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
 
 struct ip6_tnl_parm {
 	char name[IFNAMSIZ];	/* name of tunnel device */
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 4212879ff35e..439d65f7e094 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -770,7 +770,8 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
 
 		if ((ipv6_addr_is_multicast(laddr) ||
 		     likely(ipv6_chk_addr(net, laddr, ldev, 0))) &&
-		    likely(!ipv6_chk_addr(net, raddr, NULL, 0)))
+		    ((p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) ||
+		     likely(!ipv6_chk_addr(net, raddr, NULL, 0))))
 			ret = 1;
 	}
 	return ret;
@@ -1000,7 +1001,8 @@ int ip6_tnl_xmit_ctl(struct ip6_tnl *t,
 		if (unlikely(!ipv6_chk_addr(net, laddr, ldev, 0)))
 			pr_warn("%s xmit: Local address not yet configured!\n",
 				p->name);
-		else if (!ipv6_addr_is_multicast(raddr) &&
+		else if (!(p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) &&
+		         !ipv6_addr_is_multicast(raddr) &&
 			 unlikely(ipv6_chk_addr(net, raddr, NULL, 0)))
 			pr_warn("%s xmit: Routing loop! Remote address found on this node!\n",
 				p->name);