aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Benc <jbenc@redhat.com>2015-08-28 14:48:20 -0400
committerDavid S. Miller <davem@davemloft.net>2015-08-29 16:07:54 -0400
commit7f9562a1f405306eacb97f95d78cb996e33f27f5 (patch)
tree298378f868e85024a908e9bae1e0754fc59e169e
parent46fa062ad63146dd138ec0f017e71224471e8ea5 (diff)
ip_tunnels: record IP version in tunnel info
There's currently nothing preventing directing packets with IPv6 encapsulation data to IPv4 tunnels (and vice versa). If this happens, IPv6 addresses are incorrectly interpreted as IPv4 ones. Track whether the given ip_tunnel_key contains IPv4 or IPv6 data. Store this in ip_tunnel_info. Reject packets at appropriate places if they are supposed to be encapsulated into an incompatible protocol. Signed-off-by: Jiri Benc <jbenc@redhat.com> Acked-by: Alexei Starovoitov <ast@plumgrid.com> Acked-by: Thomas Graf <tgraf@suug.ch> Acked-by: Pravin B Shelar <pshelar@nicira.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/geneve.c2
-rw-r--r--drivers/net/vxlan.c2
-rw-r--r--include/net/dst_metadata.h1
-rw-r--r--include/net/ip_tunnels.h10
-rw-r--r--net/core/filter.c2
-rw-r--r--net/ipv4/ip_gre.c3
-rw-r--r--net/ipv4/ip_tunnel_core.c2
-rw-r--r--net/openvswitch/flow.c2
-rw-r--r--net/openvswitch/vport.c2
9 files changed, 24 insertions, 2 deletions
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 4a39c09f144c..3908a22f23d1 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -627,6 +627,8 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
627 netdev_dbg(dev, "no tunnel metadata\n"); 627 netdev_dbg(dev, "no tunnel metadata\n");
628 goto tx_error; 628 goto tx_error;
629 } 629 }
630 if (info && ip_tunnel_info_af(info) != AF_INET)
631 goto tx_error;
630 } 632 }
631 633
632 rt = geneve_get_rt(skb, dev, &fl4, info); 634 rt = geneve_get_rt(skb, dev, &fl4, info);
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index bd1b8cdf2bf6..e3adfe0ef66b 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1903,6 +1903,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
1903 dev->name); 1903 dev->name);
1904 goto drop; 1904 goto drop;
1905 } 1905 }
1906 if (family != ip_tunnel_info_af(info))
1907 goto drop;
1906 1908
1907 dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port; 1909 dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port;
1908 vni = be64_to_cpu(info->key.tun_id); 1910 vni = be64_to_cpu(info->key.tun_id);
diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h
index 2b83f0d232e0..d32f49cc621d 100644
--- a/include/net/dst_metadata.h
+++ b/include/net/dst_metadata.h
@@ -105,6 +105,7 @@ static inline struct metadata_dst *ipv6_tun_rx_dst(struct sk_buff *skb,
105 info->key.u.ipv6.dst = ip6h->daddr; 105 info->key.u.ipv6.dst = ip6h->daddr;
106 info->key.tos = ipv6_get_dsfield(ip6h); 106 info->key.tos = ipv6_get_dsfield(ip6h);
107 info->key.ttl = ip6h->hop_limit; 107 info->key.ttl = ip6h->hop_limit;
108 info->mode = IP_TUNNEL_INFO_IPV6;
108 return tun_dst; 109 return tun_dst;
109} 110}
110 111
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 9bdb3948798f..2b4fa06e91bd 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -4,6 +4,7 @@
4#include <linux/if_tunnel.h> 4#include <linux/if_tunnel.h>
5#include <linux/netdevice.h> 5#include <linux/netdevice.h>
6#include <linux/skbuff.h> 6#include <linux/skbuff.h>
7#include <linux/socket.h>
7#include <linux/types.h> 8#include <linux/types.h>
8#include <linux/u64_stats_sync.h> 9#include <linux/u64_stats_sync.h>
9#include <net/dsfield.h> 10#include <net/dsfield.h>
@@ -52,6 +53,7 @@ struct ip_tunnel_key {
52 53
53/* Flags for ip_tunnel_info mode. */ 54/* Flags for ip_tunnel_info mode. */
54#define IP_TUNNEL_INFO_TX 0x01 /* represents tx tunnel parameters */ 55#define IP_TUNNEL_INFO_TX 0x01 /* represents tx tunnel parameters */
56#define IP_TUNNEL_INFO_IPV6 0x02 /* key contains IPv6 addresses */
55 57
56struct ip_tunnel_info { 58struct ip_tunnel_info {
57 struct ip_tunnel_key key; 59 struct ip_tunnel_key key;
@@ -208,6 +210,8 @@ static inline void __ip_tunnel_info_init(struct ip_tunnel_info *tun_info,
208 210
209 tun_info->options = opts; 211 tun_info->options = opts;
210 tun_info->options_len = opts_len; 212 tun_info->options_len = opts_len;
213
214 tun_info->mode = 0;
211} 215}
212 216
213static inline void ip_tunnel_info_init(struct ip_tunnel_info *tun_info, 217static inline void ip_tunnel_info_init(struct ip_tunnel_info *tun_info,
@@ -221,6 +225,12 @@ static inline void ip_tunnel_info_init(struct ip_tunnel_info *tun_info,
221 tun_id, tun_flags, opts, opts_len); 225 tun_id, tun_flags, opts, opts_len);
222} 226}
223 227
228static inline unsigned short ip_tunnel_info_af(const struct ip_tunnel_info
229 *tun_info)
230{
231 return tun_info->mode & IP_TUNNEL_INFO_IPV6 ? AF_INET6 : AF_INET;
232}
233
224#ifdef CONFIG_INET 234#ifdef CONFIG_INET
225 235
226int ip_tunnel_init(struct net_device *dev); 236int ip_tunnel_init(struct net_device *dev);
diff --git a/net/core/filter.c b/net/core/filter.c
index 66500d490995..13079f03902e 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1493,6 +1493,8 @@ static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
1493 1493
1494 if (unlikely(size != sizeof(struct bpf_tunnel_key) || flags || !info)) 1494 if (unlikely(size != sizeof(struct bpf_tunnel_key) || flags || !info))
1495 return -EINVAL; 1495 return -EINVAL;
1496 if (ip_tunnel_info_af(info) != AF_INET)
1497 return -EINVAL;
1496 1498
1497 to->tunnel_id = be64_to_cpu(info->key.tun_id); 1499 to->tunnel_id = be64_to_cpu(info->key.tun_id);
1498 to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src); 1500 to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 1e813a9f9378..bd0679d90519 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -511,7 +511,8 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
511 int err; 511 int err;
512 512
513 tun_info = skb_tunnel_info(skb); 513 tun_info = skb_tunnel_info(skb);
514 if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX))) 514 if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
515 ip_tunnel_info_af(tun_info) != AF_INET))
515 goto err_free_skb; 516 goto err_free_skb;
516 517
517 key = &tun_info->key; 518 key = &tun_info->key;
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
index 934f2ac8ad61..0c756ade1cf7 100644
--- a/net/ipv4/ip_tunnel_core.c
+++ b/net/ipv4/ip_tunnel_core.c
@@ -356,7 +356,7 @@ static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr,
356 if (tb[LWTUNNEL_IP6_FLAGS]) 356 if (tb[LWTUNNEL_IP6_FLAGS])
357 tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP6_FLAGS]); 357 tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP6_FLAGS]);
358 358
359 tun_info->mode = IP_TUNNEL_INFO_TX; 359 tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6;
360 tun_info->options = NULL; 360 tun_info->options = NULL;
361 tun_info->options_len = 0; 361 tun_info->options_len = 0;
362 362
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 5a3195e538ce..9760dc43bdb9 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -688,6 +688,8 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
688{ 688{
689 /* Extract metadata from packet. */ 689 /* Extract metadata from packet. */
690 if (tun_info) { 690 if (tun_info) {
691 if (ip_tunnel_info_af(tun_info) != AF_INET)
692 return -EINVAL;
691 memcpy(&key->tun_key, &tun_info->key, sizeof(key->tun_key)); 693 memcpy(&key->tun_key, &tun_info->key, sizeof(key->tun_key));
692 694
693 if (tun_info->options) { 695 if (tun_info->options) {
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index e2dc9dac59e6..40164037928e 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -587,6 +587,8 @@ int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info,
587 587
588 if (unlikely(!tun_info)) 588 if (unlikely(!tun_info))
589 return -EINVAL; 589 return -EINVAL;
590 if (ip_tunnel_info_af(tun_info) != AF_INET)
591 return -EINVAL;
590 592
591 tun_key = &tun_info->key; 593 tun_key = &tun_info->key;
592 594