Commit 50fba2aa authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[INET]: Move no-tunnel ICMP error to tunnel4/tunnel6

This patch moves the sending of ICMP messages when there are no IPv4/IPv6
tunnels present to tunnel4/tunnel6 respectively.  Please note that for now
if xfrm4_tunnel/xfrm6_tunnel is loaded then no ICMP messages will ever be
sent.  This is similar to how we handle AH/ESP/IPCOMP.

This move fixes the bug where we always send an ICMP message when there is
no ip6_tunnel device present for a given packet even if it is later handled
by IPsec.  It also causes ICMP messages to be sent when no IPIP tunnel is
present.

I've decided to use the "port unreachable" ICMP message over the current
value of "address unreachable" (and "protocol unreachable" by GRE) because
it is not ambiguous unlike the other ones which can be triggered by other
conditions.  There seems to be no standard specifying what value must be
used so this change should be OK.  In fact we should change GRE to use
this value as well.

Incidentally, this patch also fixes a fairly serious bug in xfrm6_tunnel
where we don't check whether the embedded IPv6 header is present before
dereferencing it for the inside source address.

This patch is inspired by a previous patch by Hugo Santos <hsantos@av.it.pt>.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2e2f7aef
...@@ -474,9 +474,6 @@ static int ipip_rcv(struct sk_buff *skb) ...@@ -474,9 +474,6 @@ static int ipip_rcv(struct sk_buff *skb)
struct iphdr *iph; struct iphdr *iph;
struct ip_tunnel *tunnel; struct ip_tunnel *tunnel;
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto out;
iph = skb->nh.iph; iph = skb->nh.iph;
read_lock(&ipip_lock); read_lock(&ipip_lock);
...@@ -508,7 +505,6 @@ static int ipip_rcv(struct sk_buff *skb) ...@@ -508,7 +505,6 @@ static int ipip_rcv(struct sk_buff *skb)
} }
read_unlock(&ipip_lock); read_unlock(&ipip_lock);
out:
return -1; return -1;
} }
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/icmp.h>
#include <net/ip.h>
#include <net/protocol.h> #include <net/protocol.h>
#include <net/xfrm.h> #include <net/xfrm.h>
...@@ -70,10 +72,16 @@ static int tunnel4_rcv(struct sk_buff *skb) ...@@ -70,10 +72,16 @@ static int tunnel4_rcv(struct sk_buff *skb)
{ {
struct xfrm_tunnel *handler; struct xfrm_tunnel *handler;
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto drop;
for (handler = tunnel4_handlers; handler; handler = handler->next) for (handler = tunnel4_handlers; handler; handler = handler->next)
if (!handler->handler(skb)) if (!handler->handler(skb))
return 0; return 0;
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
drop:
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
} }
......
...@@ -37,8 +37,6 @@ static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) ...@@ -37,8 +37,6 @@ static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
{ {
switch (nexthdr) { switch (nexthdr) {
case IPPROTO_IPIP: case IPPROTO_IPIP:
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
return -EINVAL;
*spi = skb->nh.iph->saddr; *spi = skb->nh.iph->saddr;
*seq = 0; *seq = 0;
return 0; return 0;
......
...@@ -519,9 +519,6 @@ ip6ip6_rcv(struct sk_buff *skb) ...@@ -519,9 +519,6 @@ ip6ip6_rcv(struct sk_buff *skb)
struct ipv6hdr *ipv6h; struct ipv6hdr *ipv6h;
struct ip6_tnl *t; struct ip6_tnl *t;
if (!pskb_may_pull(skb, sizeof (*ipv6h)))
goto discard;
ipv6h = skb->nh.ipv6h; ipv6h = skb->nh.ipv6h;
read_lock(&ip6ip6_lock); read_lock(&ip6ip6_lock);
...@@ -529,8 +526,7 @@ ip6ip6_rcv(struct sk_buff *skb) ...@@ -529,8 +526,7 @@ ip6ip6_rcv(struct sk_buff *skb)
if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) { if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
read_unlock(&ip6ip6_lock); read_unlock(&ip6ip6_lock);
kfree_skb(skb); goto discard;
return 0;
} }
if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) { if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) {
...@@ -557,9 +553,11 @@ ip6ip6_rcv(struct sk_buff *skb) ...@@ -557,9 +553,11 @@ ip6ip6_rcv(struct sk_buff *skb)
return 0; return 0;
} }
read_unlock(&ip6ip6_lock); read_unlock(&ip6ip6_lock);
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
discard:
return 1; return 1;
discard:
kfree_skb(skb);
return 0;
} }
static inline struct ipv6_txoptions *create_tel(__u8 encap_limit) static inline struct ipv6_txoptions *create_tel(__u8 encap_limit)
......
...@@ -19,11 +19,13 @@ ...@@ -19,11 +19,13 @@
* YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
*/ */
#include <linux/icmpv6.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/ipv6.h>
#include <net/protocol.h> #include <net/protocol.h>
#include <net/xfrm.h> #include <net/xfrm.h>
...@@ -87,10 +89,16 @@ static int tunnel6_rcv(struct sk_buff **pskb) ...@@ -87,10 +89,16 @@ static int tunnel6_rcv(struct sk_buff **pskb)
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct xfrm6_tunnel *handler; struct xfrm6_tunnel *handler;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
goto drop;
for (handler = tunnel6_handlers; handler; handler = handler->next) for (handler = tunnel6_handlers; handler; handler = handler->next)
if (!handler->handler(skb)) if (!handler->handler(skb))
return 0; return 0;
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev);
drop:
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment