There’s quite a few different ways in which to set up tunnels between Linux machines, and using GRE tunnels is probably the quickest. There’s a number of reasons why it might not be the best for you, but for certain things it gets the job done.
GRE (Generic Routing Encapsulation) is a tunnelling protocol (protocol 47 - cheers Wikipedia) developed by Cisco. Since this is a quick guide I won’t bore you with the details, but if you’re interested the Wikipedia article linked in the previous sentence is a good start.
So why might you want to use it? I’ve used it in the past to create a ‘private network’ between my box at home and my hosted box, and in turn used it to route parts of my IPv6 block over. It’s also useful to allow one private network access to another, where normally (i.e. directly over the Internet) it wouldn’t be possible. Whatever the reason, setting it up takes less than a couple of minutes.
I mentioned earlier that there’s a number of reasons why this may not be what you want. Two of the main ones are:-
NAT - if either of the boxes at either end of the proposed tunnel are behind a NATed IP, forget it. You may be able to magic something up that will look like it works, but it won’t. For the time it’d take to fart about getting round this, you’d be better off using something like OpenVPN. This also has the advantage of covering the next one…
Security - if you want an encrypted tunnel, then this isn’t for you. You should treat anything going over the tunnel as if you were sending it over the public Internet - which, in reality, you are. The packets are merely encapsulated (i.e. ‘wrapped up’) in an extra layer of routing, which is then de-encapsulated at the other end. Examining the contents of the packets whilst in transit across the internet would be no more difficult that peeking into normal, non-GRE packets. Overall, this means you should still use SSH, and use SSL for anything you consider sensitive. Or, as above, use a proper VPN solution.
Once you’ve considered the above, it’s time to get stuck in.
Let’s assume you have two boxes, named ‘tea’ (with a public IP of 192.168.10.1) and ‘coffee’ (192.168.20.1). Glossing over my flagrant abuse of RFC1918 addresses, we’ll assume that ordinarily these machines can see each other over the public internet. Behind each machine is a network - tea has 10.0.10.0/24, and coffee has 10.0.20.0/24.
At this point I’ll introduce you to ‘ip‘, which is part of the iproute2 suite. If you’re running a distro made this century, chances are it’ll already be there, waiting to be used. The ip command serves as a replacement for ifconfig, netstat -rn and a whole host of other things, but that’s out of the scope of this post…
Anyhow, before we start it may be neccessary to turn on IP forwarding in the kernel on both machines. If they’re being used as an internet gateway then it’s probably already turned on. To check:-
tea:~# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
If it’s a 1, it’s on. 0 (suprise suprise) is off. To turn it on:-
tea:~# sysctl -w net.ipv4.ip_forward
net.ipv4.ip_forward = 1
You can also use the older method:-
tea:~# echo 1 >/proc/sys/net/ipv4/ip_forward
Once you’ve finished with that, we can get started on the tunnel. To get started, on tea do:-
ip tunnel add mytun mode gre local 192.168.10.1 remote 192.168.20.1 ttl 255
ip link set mytun up
…and on coffee:-
ip tunnel add mytun mode gre local 192.168.20.1 remote 192.168.10.1 ttl 255
ip link set mytun up
…and that’s it. You should now see an interface appear on both machines called ‘mytun’. The name isn’t important, and doesn’t have to be the same on both ends, so feel free to choose something more descriptive.
At this point, the tunnel is pretty useless. Before we can use it properly we need to assign an IP to each end of the tunnel. As I mentioned earlier, ip lets us do this pretty quickly:-
on tea:-
ip addr add 10.0.30.1/30 dev mytun
and on coffee:-
ip addr add 10.0.30.2/30 dev mytun
As you can see, we now have two IPs from a small /30 subnet assigned to either end of our tunnel. To test this, try pinging one end of the tunnel from the other:-
tea:~# ping 10.0.30.2
PING 10.0.30.2 (10.0.30.2) 56(84) bytes of data.
64 bytes from 10.0.30.2: icmp_seq=1 ttl=64 time=51.6 ms
If you’re seeing responses, it’s working, and you can give yourself a pat on the back.
The final part of this is to add some routing into the mix, to allow our private networks to see each other. Again, with ip this is a doddle:-
on tea:-
ip route add 10.0.20.0/24 via 10.0.30.2 dev mytun
on coffee:-
ip route add 10.0.10.0/24 via 10.0.30.1 dev mytun
And that’s it. As an example, a host named ‘biscuit’ (IP 10.0.10.2, behind ‘tea’), and another host named ‘cake’ (IP 10.0.20.2, behind coffee) should now be able to route to each other. This assumes tea and coffee are their respective default gateways - if not, then routes will need to be added on them. This can then be tested with a traceroute:-
on biscuit:-
biscuit:~# traceroute 10.0.20.2
traceroute to 10.0.20.2 (10.0.20.2), 30 hops max, 46 byte packets
1 10.0.30.2 (10.0.30.2) 53.798 ms 52.029 ms 52.037 ms
2 10.0.20.2 (10.0.30.2) 51.609 ms 53.006 ms 51.176 ms
At this point, you’re done! If you were to draw a little diagram, it would probably look a bit like this:-
[biscuit]<->[tea](192.168.10.1) <-- *internet* --> (192.168.20.1)[coffee]<->[cake]
10.0.10.2 [(10.0.30.1) <--tunnel--> (10.0.30.2)] 10.0.20.2
Problems?
There’s a couple of things you may run into. If this doesn’t work for you, check:-
that you’re not blocking incoming GRE packets at one (or both) end(s). You can allow this by doing something like:-
iptables -I INPUT -s -p gre -j ACCEPT
that you’re not blocking outgoing GRE packets. See above.
Otherwise, it might be time to break out tcpdump. tcpdump will allow you to sniff on the virtual ‘mytun’ device, and you’ll see only traffic related to the tunnel.