How To Setup GRE Tunnel On Linux Servers
Generic Routing Encapsulation (GRE) is a tunneling protocol developed by Cisco Systems which can encapsulate a wide variety of network layer protocols inside virtual point-to-point links or point-to-multipoint links over an Internet Protocol network.
A GRE tunnel is useful in certain situations, like protecting a server without DDoS protection using another one with the protection, or to enable applications that only allow IPv4 to also accept IPv6.
It is relatively easy to set up and secure GRE tunnel ("pipe") between server A and server B, which will allow packets to be forwarded with minimal resource usage.
How does GRE tunnel work?
When you create a GRE tunnel on the server, your server will act as a virtual router. Keep in mind that both ends will need a public IP address as packets are sent over multiple networks.
GRE tunnel setup prerequisites
First of all, you must have two servers with root access. If you don't have yet, you can obtain and use either Virtual Private Server (VPS) or a Dedicated Server to create GRE Tunnel. In this tutorial they will be called Server A and Server B, and will have the following characteristics:
Server A - the server that all the clients will connect to
- IP: 198.51.100.1
- GRE tunnel internal IP: 10.0.0.1
Server B - the server which is actually running all the applications
- IP: 203.0.113.1
- GRE tunnel internal IP: 10.0.0.2
Step 1 - Module loading
For setting up a GRE tunnel on Linux you must have ip_gre module loaded in your kernel. To make sure it's loaded just run the following SSH commands:
sudo modprobe ip_gre
lsmod | grep gre
And you should see:
ip_gre ##### 0 gre ##### 1 ip_gre
If you see something else it's possible that your kernel does not support GRE.
To forward all the traffic in and out of the GRE tunnel we're going to use iptables and iproute2 that should be already installed in all the major linux distributions. In case they're not installed use the following command
for Debian based distros:
sudo apt install iptables iproute2
for Red Hat based distros:
sudo yum install iptables iproute2
Step 2 - GRE Tunnel setup
First we have to set up our tunnel.
On Server A execute this code to enable ip forwarding:
sudo echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf sudo sysctl -p
Now create a new networking interface which will be the one using the GRE tunnel:
sudo ip tunnel add gre1 mode gre local 198.51.100.1 remote 203.0.113.1 ttl 255 sudo ip addr add 10.0.0.1/30 dev gre1 sudo ip link set gre1 up
Then, do the same on Server B changing the IPs:
sudo ip tunnel add gre1 mode gre local 203.0.113.1 remote 198.51.100.1 ttl 255 sudo ip addr add 10.0.0.2/30 dev gre1 sudo ip link set gre1 up
Step 2.1 - Ping test
On Server A run this SSH command:
ping 10.0.0.2
And on Server B run this command:
ping 10.0.0.1
If the ping works then the GRE tunnel is correctly set up.
Step 3 - Implementing the new routes
A route is required to make sure data that comes in via the GRE tunnel is handled correctly.
On Server B execute:
sudo echo '100 GRE' >> /etc/iproute2/rt_tables sudo ip rule add from 10.0.0.0/30 table GRE sudo ip route add default via 10.0.0.1 table GRE
Step 4 - NAT configuration
NAT is used to pass data over our GRE and out the other end.
On Server A run:
iptables -t nat -A POSTROUTING -s 10.0.0.0/30 ! -o gre+ -j SNAT --to-source 198.51.100.1
To test the outbound connection execute on Server B this commands:
for Debian based distros:
sudo apt install curl
for Red Hat based distros:
sudo yum install curl
And then run the following command:
curl https://www.euro-space.net/show-ip
At the end you should see Server A's IP address.
Step 5 - Port forwarding
On Server A run this commands to allow all the data going to and coming from Server B:
sudo iptables -A FORWARD -d 10.0.0.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT sudo iptables -A FORWARD -s 10.0.0.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
Then, we want to forward all our data from Server A to Server B.
Execute this on Server A:
sudo iptables -t nat -A PREROUTING -d 198.51.100.1 -p PROTO -m PROTO --dport PORT -j DNAT --to-destination 10.0.0.2
replacing PROTO and PORT with your actual ones.
For example, to forward all the data to a Webserver (Port TCP 80) we have to run:
sudo iptables -t nat -A PREROUTING -d 198.51.100.1 -p TCP -m TCP --dport 80 -j DNAT --to-destination 10.0.0.2
We must do it for each port we are using.
Step 6 - Persistence
On a server restart all the things we did will be wiped out. To make sure the GRE tunnel and everything else is going to work after a restart we have to edit the file /etc/rc.local and add all the commands we did (except for the echo ones!) before the exit 0.
Conclusion
Now, if we connect to Server A using the ports we configured (Port TCP 80 for example) we're going instead to connect to Server B without knowing it.
Note: if you use CSF to manage iptables you may have to put all the iptables commands in your /etc/csf/csfpost.sh and insert both servers' IP (also the GRE one) in your /etc/csf/csf.allow.
Published on: 03-10-2020