Skip to content

Commit

Permalink
ip_tunnels: record IP version in tunnel info
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Alexei Starovoitov <[email protected]>
Acked-by: Thomas Graf <[email protected]>
Acked-by: Pravin B Shelar <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Jiri Benc authored and davem330 committed Aug 29, 2015
1 parent 46fa062 commit 7f9562a
Show file tree
Hide file tree
Showing 9 changed files with 24 additions and 2 deletions.
2 changes: 2 additions & 0 deletions drivers/net/geneve.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,8 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_dbg(dev, "no tunnel metadata\n");
goto tx_error;
}
if (info && ip_tunnel_info_af(info) != AF_INET)
goto tx_error;
}

rt = geneve_get_rt(skb, dev, &fl4, info);
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1903,6 +1903,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
dev->name);
goto drop;
}
if (family != ip_tunnel_info_af(info))
goto drop;

dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port;
vni = be64_to_cpu(info->key.tun_id);
Expand Down
1 change: 1 addition & 0 deletions include/net/dst_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ static inline struct metadata_dst *ipv6_tun_rx_dst(struct sk_buff *skb,
info->key.u.ipv6.dst = ip6h->daddr;
info->key.tos = ipv6_get_dsfield(ip6h);
info->key.ttl = ip6h->hop_limit;
info->mode = IP_TUNNEL_INFO_IPV6;
return tun_dst;
}

Expand Down
10 changes: 10 additions & 0 deletions include/net/ip_tunnels.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <linux/if_tunnel.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/types.h>
#include <linux/u64_stats_sync.h>
#include <net/dsfield.h>
Expand Down Expand Up @@ -52,6 +53,7 @@ struct ip_tunnel_key {

/* Flags for ip_tunnel_info mode. */
#define IP_TUNNEL_INFO_TX 0x01 /* represents tx tunnel parameters */
#define IP_TUNNEL_INFO_IPV6 0x02 /* key contains IPv6 addresses */

struct ip_tunnel_info {
struct ip_tunnel_key key;
Expand Down Expand Up @@ -208,6 +210,8 @@ static inline void __ip_tunnel_info_init(struct ip_tunnel_info *tun_info,

tun_info->options = opts;
tun_info->options_len = opts_len;

tun_info->mode = 0;
}

static inline void ip_tunnel_info_init(struct ip_tunnel_info *tun_info,
Expand All @@ -221,6 +225,12 @@ static inline void ip_tunnel_info_init(struct ip_tunnel_info *tun_info,
tun_id, tun_flags, opts, opts_len);
}

static inline unsigned short ip_tunnel_info_af(const struct ip_tunnel_info
*tun_info)
{
return tun_info->mode & IP_TUNNEL_INFO_IPV6 ? AF_INET6 : AF_INET;
}

#ifdef CONFIG_INET

int ip_tunnel_init(struct net_device *dev);
Expand Down
2 changes: 2 additions & 0 deletions net/core/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -1493,6 +1493,8 @@ static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)

if (unlikely(size != sizeof(struct bpf_tunnel_key) || flags || !info))
return -EINVAL;
if (ip_tunnel_info_af(info) != AF_INET)
return -EINVAL;

to->tunnel_id = be64_to_cpu(info->key.tun_id);
to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src);
Expand Down
3 changes: 2 additions & 1 deletion net/ipv4/ip_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,8 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
int err;

tun_info = skb_tunnel_info(skb);
if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX)))
if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) ||
ip_tunnel_info_af(tun_info) != AF_INET))
goto err_free_skb;

key = &tun_info->key;
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/ip_tunnel_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr,
if (tb[LWTUNNEL_IP6_FLAGS])
tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP6_FLAGS]);

tun_info->mode = IP_TUNNEL_INFO_TX;
tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6;
tun_info->options = NULL;
tun_info->options_len = 0;

Expand Down
2 changes: 2 additions & 0 deletions net/openvswitch/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,8 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
{
/* Extract metadata from packet. */
if (tun_info) {
if (ip_tunnel_info_af(tun_info) != AF_INET)
return -EINVAL;
memcpy(&key->tun_key, &tun_info->key, sizeof(key->tun_key));

if (tun_info->options) {
Expand Down
2 changes: 2 additions & 0 deletions net/openvswitch/vport.c
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@ int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info,

if (unlikely(!tun_info))
return -EINVAL;
if (ip_tunnel_info_af(tun_info) != AF_INET)
return -EINVAL;

tun_key = &tun_info->key;

Expand Down

0 comments on commit 7f9562a

Please sign in to comment.