Release 4.11 net/ipv6/sit.c
/*
* IPv6 over IPv4 tunnel device - Simple Internet Transition (SIT)
* Linux INET6 implementation
*
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Changes:
* Roger Venning <r.venning@telstra.com>: 6to4 support
* Nate Thompson <nate@thebog.net>: 6to4 support
* Fred Templin <fred.l.templin@boeing.com>: isatap support
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/icmp.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/netfilter_ipv4.h>
#include <linux/if_ether.h>
#include <net/sock.h>
#include <net/snmp.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/transp_v6.h>
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/icmp.h>
#include <net/ip_tunnels.h>
#include <net/inet_ecn.h>
#include <net/xfrm.h>
#include <net/dsfield.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
/*
This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c
For comments look at net/ipv4/ip_gre.c --ANK
*/
#define IP6_SIT_HASH_SIZE 16
#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
static bool log_ecn_error = true;
module_param(log_ecn_error, bool, 0644);
MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
static int ipip6_tunnel_init(struct net_device *dev);
static void ipip6_tunnel_setup(struct net_device *dev);
static void ipip6_dev_free(struct net_device *dev);
static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst,
__be32 *v4dst);
static struct rtnl_link_ops sit_link_ops __read_mostly;
static unsigned int sit_net_id __read_mostly;
struct sit_net {
struct ip_tunnel __rcu *tunnels_r_l[IP6_SIT_HASH_SIZE];
struct ip_tunnel __rcu *tunnels_r[IP6_SIT_HASH_SIZE];
struct ip_tunnel __rcu *tunnels_l[IP6_SIT_HASH_SIZE];
struct ip_tunnel __rcu *tunnels_wc[1];
struct ip_tunnel __rcu **tunnels[4];
struct net_device *fb_tunnel_dev;
};
/*
* Must be invoked with rcu_read_lock
*/
static struct ip_tunnel *ipip6_tunnel_lookup(struct net *net,
struct net_device *dev, __be32 remote, __be32 local)
{
unsigned int h0 = HASH(remote);
unsigned int h1 = HASH(local);
struct ip_tunnel *t;
struct sit_net *sitn = net_generic(net, sit_net_id);
for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) {
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
(!dev || !t->parms.link || dev->ifindex == t->parms.link) &&
(t->dev->flags & IFF_UP))
return t;
}
for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) {
if (remote == t->parms.iph.daddr &&
(!dev || !t->parms.link || dev->ifindex == t->parms.link) &&
(t->dev->flags & IFF_UP))
return t;
}
for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) {
if (local == t->parms.iph.saddr &&
(!dev || !t->parms.link || dev->ifindex == t->parms.link) &&
(t->dev->flags & IFF_UP))
return t;
}
t = rcu_dereference(sitn->tunnels_wc[0]);
if (t && (t->dev->flags & IFF_UP))
return t;
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 147 | 55.26% | 2 | 20.00% |
Sascha Hlusiak | 72 | 27.07% | 1 | 10.00% |
Pavel Emelyanov | 19 | 7.14% | 2 | 20.00% |
Eric Dumazet | 17 | 6.39% | 2 | 20.00% |
Américo Wang | 6 | 2.26% | 1 | 10.00% |
Shmulik Ladkani | 3 | 1.13% | 1 | 10.00% |
Al Viro | 2 | 0.75% | 1 | 10.00% |
Total | 266 | 100.00% | 10 | 100.00% |
static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn,
struct ip_tunnel_parm *parms)
{
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
unsigned int h = 0;
int prio = 0;
if (remote) {
prio |= 2;
h ^= HASH(remote);
}
if (local) {
prio |= 1;
h ^= HASH(local);
}
return &sitn->tunnels[prio][h];
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 79 | 83.16% | 1 | 16.67% |
Pavel Emelyanov | 7 | 7.37% | 2 | 33.33% |
Hideaki Yoshifuji / 吉藤英明 | 5 | 5.26% | 1 | 16.67% |
Al Viro | 2 | 2.11% | 1 | 16.67% |
Eric Dumazet | 2 | 2.11% | 1 | 16.67% |
Total | 95 | 100.00% | 6 | 100.00% |
static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn,
struct ip_tunnel *t)
{
return __ipip6_bucket(sitn, &t->parms);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 24 | 75.00% | 1 | 33.33% |
Pavel Emelyanov | 7 | 21.88% | 1 | 33.33% |
Eric Dumazet | 1 | 3.12% | 1 | 33.33% |
Total | 32 | 100.00% | 3 | 100.00% |
static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
{
struct ip_tunnel __rcu **tp;
struct ip_tunnel *iter;
for (tp = ipip6_bucket(sitn, t);
(iter = rtnl_dereference(*tp)) != NULL;
tp = &iter->next) {
if (t == iter) {
rcu_assign_pointer(*tp, t->next);
break;
}
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 53 | 67.09% | 2 | 40.00% |
Eric Dumazet | 19 | 24.05% | 2 | 40.00% |
Pavel Emelyanov | 7 | 8.86% | 1 | 20.00% |
Total | 79 | 100.00% | 5 | 100.00% |
static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
{
struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t);
rcu_assign_pointer(t->next, rtnl_dereference(*tp));
rcu_assign_pointer(*tp, t);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 33 | 64.71% | 2 | 33.33% |
Eric Dumazet | 11 | 21.57% | 3 | 50.00% |
Pavel Emelyanov | 7 | 13.73% | 1 | 16.67% |
Total | 51 | 100.00% | 6 | 100.00% |
static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
{
#ifdef CONFIG_IPV6_SIT_6RD
struct ip_tunnel *t = netdev_priv(dev);
if (t->dev == sitn->fb_tunnel_dev) {
ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0);
t->ip6rd.relay_prefix = 0;
t->ip6rd.prefixlen = 16;
t->ip6rd.relay_prefixlen = 0;
} else {
struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev);
memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd));
}
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 123 | 100.00% | 2 | 100.00% |
Total | 123 | 100.00% | 2 | 100.00% |
static int ipip6_tunnel_create(struct net_device *dev)
{
struct ip_tunnel *t = netdev_priv(dev);
struct net *net = dev_net(dev);
struct sit_net *sitn = net_generic(net, sit_net_id);
int err;
memcpy(dev->dev_addr, &t->parms.iph.saddr, 4);
memcpy(dev->broadcast, &t->parms.iph.daddr, 4);
if ((__force u16)t->parms.i_flags & SIT_ISATAP)
dev->priv_flags |= IFF_ISATAP;
dev->rtnl_link_ops = &sit_link_ops;
err = register_netdevice(dev);
if (err < 0)
goto out;
ipip6_tunnel_clone_6rd(dev, sitn);
dev_hold(dev);
ipip6_tunnel_link(sitn, t);
return 0;
out:
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nicolas Dichtel | 115 | 75.66% | 2 | 50.00% |
Steffen Klassert | 30 | 19.74% | 1 | 25.00% |
Thadeu Lima de Souza Cascardo | 7 | 4.61% | 1 | 25.00% |
Total | 152 | 100.00% | 4 | 100.00% |
static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
struct ip_tunnel_parm *parms, int create)
{
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
struct ip_tunnel *t, *nt;
struct ip_tunnel __rcu **tp;
struct net_device *dev;
char name[IFNAMSIZ];
struct sit_net *sitn = net_generic(net, sit_net_id);
for (tp = __ipip6_bucket(sitn, parms);
(t = rtnl_dereference(*tp)) != NULL;
tp = &t->next) {
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
parms->link == t->parms.link) {
if (create)
return NULL;
else
return t;
}
}
if (!create)
goto failed;
if (parms->name[0])
strlcpy(name, parms->name, IFNAMSIZ);
else
strcpy(name, "sit%d");
dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
ipip6_tunnel_setup);
if (!dev)
return NULL;
dev_net_set(dev, net);
nt = netdev_priv(dev);
nt->parms = *parms;
if (ipip6_tunnel_create(dev) < 0)
goto failed_free;
return nt;
failed_free:
ipip6_dev_free(dev);
failed:
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 135 | 51.33% | 4 | 19.05% |
Stephen Hemminger | 41 | 15.59% | 1 | 4.76% |
Pavel Emelyanov | 33 | 12.55% | 3 | 14.29% |
Sascha Hlusiak | 20 | 7.60% | 2 | 9.52% |
Eric Dumazet | 14 | 5.32% | 2 | 9.52% |
Linus Torvalds | 4 | 1.52% | 1 | 4.76% |
Hideaki Yoshifuji / 吉藤英明 | 4 | 1.52% | 1 | 4.76% |
Patrick McHardy | 3 | 1.14% | 1 | 4.76% |
Al Viro | 2 | 0.76% | 1 | 4.76% |
Tom Gundersen | 2 | 0.76% | 1 | 4.76% |
David S. Miller | 2 | 0.76% | 1 | 4.76% |
Stephen Rothwell | 1 | 0.38% | 1 | 4.76% |
Ian Morris | 1 | 0.38% | 1 | 4.76% |
Nicolas Dichtel | 1 | 0.38% | 1 | 4.76% |
Total | 263 | 100.00% | 21 | 100.00% |
#define for_each_prl_rcu(start) \
for (prl = rcu_dereference(start); \
prl; \
prl = rcu_dereference(prl->next))
static struct ip_tunnel_prl_entry *
__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
{
struct ip_tunnel_prl_entry *prl;
for_each_prl_rcu(t->prl)
if (prl->addr == addr)
break;
return prl;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Fred L. Templin | 18 | 48.65% | 1 | 20.00% |
Linus Torvalds (pre-git) | 11 | 29.73% | 2 | 40.00% |
Eric Dumazet | 7 | 18.92% | 1 | 20.00% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 2.70% | 1 | 20.00% |
Total | 37 | 100.00% | 5 | 100.00% |
static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
struct ip_tunnel_prl __user *a)
{
struct ip_tunnel_prl kprl, *kp;
struct ip_tunnel_prl_entry *prl;
unsigned int cmax, c = 0, ca, len;
int ret = 0;
if (copy_from_user(&kprl, a, sizeof(kprl)))
return -EFAULT;
cmax = kprl.datalen / sizeof(kprl);
if (cmax > 1 && kprl.addr != htonl(INADDR_ANY))
cmax = 1;
/* For simple GET or for root users,
* we try harder to allocate.
*/
kp = (cmax <= 1 || capable(CAP_NET_ADMIN)) ?
kcalloc(cmax, sizeof(*kp), GFP_KERNEL) :
NULL;
rcu_read_lock();
ca = t->prl_count < cmax ? t->prl_count : cmax;
if (!kp) {
/* We don't try hard to allocate much memory for
* non-root users.
* For root users, retry allocating enough memory for
* the answer.
*/
kp = kcalloc(ca, sizeof(*kp), GFP_ATOMIC);
if (!kp) {
ret = -ENOMEM;
goto out;
}
}
c = 0;
for_each_prl_rcu(t->prl) {
if (c >= cmax)
break;
if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr)
continue;
kp[c].addr = prl->addr;
kp[c].flags = prl->flags;
c++;
if (kprl.addr != htonl(INADDR_ANY))
break;
}
out:
rcu_read_unlock();
len = sizeof(*kp) * c;
ret = 0;
if ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen))
ret = -EFAULT;
kfree(kp);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 303 | 97.12% | 2 | 50.00% |
Eric Dumazet | 8 | 2.56% | 1 | 25.00% |
Sascha Hlusiak | 1 | 0.32% | 1 | 25.00% |
Total | 312 | 100.00% | 4 | 100.00% |
static int
ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
{
struct ip_tunnel_prl_entry *p;
int err = 0;
if (a->addr == htonl(INADDR_ANY))
return -EINVAL;
ASSERT_RTNL();
for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) {
if (p->addr == a->addr) {
if (chg) {
p->flags = a->flags;
goto out;
}
err = -EEXIST;
goto out;
}
}
if (chg) {
err = -ENXIO;
goto out;
}
p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL);
if (!p) {
err = -ENOBUFS;
goto out;
}
p->next = t->prl;
p->addr = a->addr;
p->flags = a->flags;
t->prl_count++;
rcu_assign_pointer(t->prl, p);
out:
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 65 | 33.68% | 3 | 23.08% |
Fred L. Templin | 61 | 31.61% | 1 | 7.69% |
Eric Dumazet | 36 | 18.65% | 4 | 30.77% |
Linus Torvalds (pre-git) | 28 | 14.51% | 3 | 23.08% |
Kazunori Miyazawa | 2 | 1.04% | 1 | 7.69% |
Stephen Rothwell | 1 | 0.52% | 1 | 7.69% |
Total | 193 | 100.00% | 13 | 100.00% |
static void prl_list_destroy_rcu(struct rcu_head *head)
{
struct ip_tunnel_prl_entry *p, *n;
p = container_of(head, struct ip_tunnel_prl_entry, rcu_head);
do {
n = rcu_dereference_protected(p->next, 1);
kfree(p);
p = n;
} while (p);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric Dumazet | 59 | 100.00% | 2 | 100.00% |
Total | 59 | 100.00% | 2 | 100.00% |
static int
ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
{
struct ip_tunnel_prl_entry *x;
struct ip_tunnel_prl_entry __rcu **p;
int err = 0;
ASSERT_RTNL();
if (a && a->addr != htonl(INADDR_ANY)) {
for (p = &t->prl;
(x = rtnl_dereference(*p)) != NULL;
p = &x->next) {
if (x->addr == a->addr) {
*p = x->next;
kfree_rcu(x, rcu_head);
t->prl_count--;
goto out;
}
}
err = -ENXIO;
} else {
x = rtnl_dereference(t->prl);
if (x) {
t->prl_count = 0;
call_rcu(&x->rcu_head, prl_list_destroy_rcu);
t->prl = NULL;
}
}
out:
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Fred L. Templin | 79 | 47.88% | 1 | 10.00% |
Eric Dumazet | 39 | 23.64% | 3 | 30.00% |
Hideaki Yoshifuji / 吉藤英明 | 31 | 18.79% | 3 | 30.00% |
Linus Torvalds (pre-git) | 13 | 7.88% | 1 | 10.00% |
Paul E. McKenney | 2 | 1.21% | 1 | 10.00% |
Sascha Hlusiak | 1 | 0.61% | 1 | 10.00% |
Total | 165 | 100.00% | 10 | 100.00% |
static int
isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t)
{
struct ip_tunnel_prl_entry *p;
int ok = 1;
rcu_read_lock();
p = __ipip6_tunnel_locate_prl(t, iph->saddr);
if (p) {
if (p->flags & PRL_DEFAULT)
skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT;
else
skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT;
} else {
const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr;
if (ipv6_addr_is_isatap(addr6) &&
(addr6->s6_addr32[3] == iph->saddr) &&
ipv6_chk_prefix(addr6, t->dev))
skb->ndisc_nodetype = NDISC_NODETYPE_HOST;
else
ok = 0;
}
rcu_read_unlock();
return ok;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Fred L. Templin | 113 | 83.09% | 1 | 16.67% |
Hideaki Yoshifuji / 吉藤英明 | 12 | 8.82% | 2 | 33.33% |
Eric Dumazet | 6 | 4.41% | 2 | 33.33% |
Linus Torvalds (pre-git) | 5 | 3.68% | 1 | 16.67% |
Total | 136 | 100.00% | 6 | 100.00% |
static void ipip6_tunnel_uninit(struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
struct sit_net *sitn = net_generic(tunnel->net, sit_net_id);
if (dev == sitn->fb_tunnel_dev) {
RCU_INIT_POINTER(sitn->tunnels_wc[0], NULL);
} else {
ipip6_tunnel_unlink(sitn, tunnel);
ipip6_tunnel_del_prl(tunnel, NULL);
}
dst_cache_reset(&tunnel->dst_cache);
dev_put(dev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Fred L. Templin | 41 | 47.13% | 1 | 9.09% |
Pavel Emelyanov | 26 | 29.89% | 3 | 27.27% |
Nicolas Dichtel | 11 | 12.64% | 2 | 18.18% |
Paolo Abeni | 4 | 4.60% | 1 | 9.09% |
Eric Dumazet | 2 | 2.30% | 1 | 9.09% |
Stephen Hemminger | 1 | 1.15% | 1 | 9.09% |
Linus Torvalds (pre-git) | 1 | 1.15% | 1 | 9.09% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 1.15% | 1 | 9.09% |
Total | 87 | 100.00% | 11 | 100.00% |
static int ipip6_err(struct sk_buff *skb, u32 info)
{
const struct iphdr *iph = (const struct iphdr *)skb->data;
const int type = icmp_hdr(skb)->type;
const int code = icmp_hdr(skb)->code;
unsigned int data_len = 0;
struct ip_tunnel *t;
int err;
switch (type) {
default:
case ICMP_PARAMETERPROB:
return 0;
case ICMP_DEST_UNREACH:
switch (code) {
case ICMP_SR_FAILED:
/* Impossible event. */
return 0;
default:
/* All others are translated to HOST_UNREACH.
rfc2003 contains "deep thoughts" about NET_UNREACH,
I believe they are just ether pollution. --ANK
*/
break;
}
break;
case ICMP_TIME_EXCEEDED:
if (code != ICMP_EXC_TTL)
return 0;
data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */
break;
case ICMP_REDIRECT:
break;
}
err = -ENOENT;
t = ipip6_tunnel_lookup(dev_net(skb->dev),
skb->dev,
iph->daddr,
iph->saddr);
if (!t)
goto out;
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
ipv4_update_pmtu(skb, dev_net(skb->dev), info,
t->parms.link, 0, iph->protocol, 0);
err = 0;
goto out;
}
if (type == ICMP_REDIRECT) {
ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
iph->protocol, 0);
err = 0;
goto out;
}
err = 0;
if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len))
goto out;
if (t->parms.iph.daddr == 0)
goto out;
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
goto out;
if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
t->err_count++;
else
t->err_count = 1;
t->err_time = jiffies;
out:
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 92 | 26.06% | 1 | 5.56% |
David S. Miller | 84 | 23.80% | 2 | 11.11% |
Fred L. Templin | 74 | 20.96% | 1 | 5.56% |
Eric Dumazet | 51 | 14.45% | 4 | 22.22% |
Oussama Ghorbel | 10 | 2.83% | 1 | 5.56% |
Arnaldo Carvalho de Melo | 8 | 2.27% | 1 | 5.56% |
Pavel Emelyanov | 7 | 1.98% | 2 | 11.11% |
Dmitry Popov | 6 | 1.70% | 1 | 5.56% |
Simon Horman | 6 | 1.70% | 1 | 5.56% |
Kazunori Miyazawa | 5 | 1.42% | 1 | 5.56% |
Wei Yongjun | 5 | 1.42% | 1 | 5.56% |
Sascha Hlusiak | 4 | 1.13% | 1 | 5.56% |
Ian Morris | 1 | 0.28% | 1 | 5.56% |
Total | 353 | 100.00% | 18 | 100.00% |
static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr,
const struct in6_addr *v6addr)
{
__be32 v4embed = 0;
if (check_6rd(tunnel, v6addr, &v4embed) && v4addr != v4embed)
return true;
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hannes Frederic Sowa | 49 | 100.00% | 1 | 100.00% |
Total | 49 | 100.00% | 1 | 100.00% |
/* Checks if an address matches an address on the tunnel interface.
* Used to detect the NAT of proto 41 packets and let them pass spoofing test.
* Long story:
* This function is called after we considered the packet as spoofed
* in is_spoofed_6rd.
* We may have a router that is doing NAT for proto 41 packets
* for an internal station. Destination a.a.a.a/PREFIX:bbbb:bbbb
* will be translated to n.n.n.n/PREFIX:bbbb:bbbb. And is_spoofed_6rd
* function will return true, dropping the packet.
* But, we can still check if is spoofed against the IP
* addresses associated with the interface.
*/
static bool only_dnatted(const struct ip_tunnel *tunnel,
const struct in6_addr *v6dst)
{
int prefix_len;
#ifdef CONFIG_IPV6_SIT_6RD
prefix_len = tunnel->ip6rd.prefixlen + 32
- tunnel->ip6rd.relay_prefixlen;
#else
prefix_len = 48;
#endif
return ipv6_chk_custom_prefix(v6dst, prefix_len, tunnel->dev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin(ux aka Dino) M. Boie | 60 | 100.00% | 1 | 100.00% |
Total | 60 | 100.00% | 1 | 100.00% |
/* Returns true if a packet is spoofed */
static bool packet_is_spoofed(struct sk_buff *skb,
const struct iphdr *iph,
struct ip_tunnel *tunnel)
{
const struct ipv6hdr *ipv6h;
if (tunnel->dev->priv_flags & IFF_ISATAP) {
if (!isatap_chksrc(skb, iph, tunnel))
return true;
return false;
}
if (tunnel->dev->flags & IFF_POINTOPOINT)
return false;
ipv6h = ipv6_hdr(skb);
if (unlikely(is_spoofed_6rd(tunnel, iph->saddr, &ipv6h->saddr))) {
net_warn_ratelimited("Src spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
&iph->saddr, &ipv6h->saddr,
&iph->daddr, &ipv6h->daddr);
return true;
}
if (likely(!is_spoofed_6rd(tunnel, iph->daddr, &ipv6h->daddr)))
return false;
if (only_dnatted(tunnel, &ipv6h->daddr))
return false;
net_warn_ratelimited("Dst spoofed %pI4/%pI6c -> %pI4/%pI6c\n",
&iph->saddr, &ipv6h->saddr,
&iph->daddr, &ipv6h->daddr);
return true;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin(ux aka Dino) M. Boie | 193 | 100.00% | 1 | 100.00% |
Total | 193 | 100.00% | 1 | 100.00% |
static int ipip6_rcv(struct sk_buff *sk