Re: IPIP Tunnelling.

David Woodhouse (D.W.Woodhouse@nortel.co.uk)
Fri, 15 Aug 1997 08:52:29 +0100


alan@lxorguk.ukuu.org.uk said:
> > Why can't we just refuse to IP-encapsulate any packets which are
> > already IP-encapsulated?

> Becuase we might legally be doing it. Secure IP tunnels over IP
> mobile do this for example.

OK, then we can refuse to IP-encap any IPIP packet which has already been
IPIP-encapsulated at the local host. All we do is:

count=0;
while (iph->protocol == IP_PROTO_IPIP)
{
iph += (iph->ihl << 2);
if ( (&iph->saddr)+1 > skb->tail || /* iph->saddr is local */ )
{
kfree_skb(skb);
stats.tx_dropped++;
printk(KERN_WARN "%s: IPIP-in-IPIP loop, depth %d "
"- shutting down before something dies!\n", dev->name, count);
dev->flags &= ~IFF_UP;
tunnel_close(dev);
return 0;
}
count++;
}

That way, the interface will close down if it detects a packet which has ever
been routed through an IPIP tunnel locally (that won't catch IPsec or IPPCP,
etc), OR if the IPIP-in-IPIP-in-IPIP is so deep that the packet is full of
IPIP headers with no actual data.

OK, so that's not a nice way to close, but it can be done properly if I
actually write the code. Printing the IP addresses of the offending host(s)
would be a good idea, too.

I've set up the tunnel drivers to use the default ttl, and sorted out the
address checks. I now find that when I'm routing public addresses through IPIP
over a large private network, all seems perfect - traceroute shows the hops it
should do, using only their public IP addresses, etc.

I made ipip.c note the tunnel device on which the packets were arriving and
adjust the statistics accordingly. This also means that ICMP Time Exceeded
messages get sent back the right way, and with the correct (public/private) IP
address.

I'm trying to use IPIP for transparently routing public IP over a private IP
network, and the only way to make it transparent seems to be to make changes
like this. It seems that the RFC was designed with that kind of thing in mind,
which would explain the ttl and ICMP handling guidelines. The main problem
with my modified code as it stands is that it can cause horrible loops _if_
people badly misconfigure their tunnels.
So the question is: should I keep going and try to sort that out as well as I
can, or should I just let it lie and use my new code locally without trying to
make it fit for inclusion?

Using tdev->saddr as the IPIP packet's source address in tunnel.c, I put
something like this in ipip.c:

if (!ip_route_output(&rt, skb->nh.iph->saddr, iph->daddr,
RT_TOS(iph->tos), NULL))
{
dev = rt->u.dst.dev;
ip_rt_put(rt);
}
else
{
/* No route to the tunnelling host */
#ifndef TUNNEL_DEBUG
if (net_ratelimit())
#endif
{

printk(KERN_INFO "IPIP packet received with payload from "
"unreachable host %d.%d.%d.%d\n",
MKDIGITS(skb->nh.iph->saddr));
}
kfree_skb(skb, FREE_READ);
return -EINVAL;

}

}

if (dev->type == ARPHRD_TUNNEL)
{
/* Increase the no. of packets received on the interface */
((struct net_device_stats *)(dev->priv))->rx_packets++;
}
else
{
#ifndef TUNNEL_DEBUG
if (net_ratelimit())
#endif
{
printk(KERN_INFO "IPIP packet received from non-tunnel "
"host %d.%d.%d.%d\n",
MKDIGITS(skb->nh.iph->saddr));
}
kfree_skb(skb, FREE_READ);
return -EINVAL;
}

skb->dev = dev;

-- 
David Woodhouse,	CB3 9AN		http://dwmw2.robinson.cam.ac.uk/
	dwmw2@cam.ac.uk 		 Tel: 0976 658355        
	D.W.Woodhouse@nortel.co.uk	 Tel: 01279 402332