Introduction
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.
Prerequisites
First of all, you must have two servers with root access. 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 do:
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 - 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 do:
ping 10.0.0.2
And on Server B do:
ping 10.0.0.1
If the ping works then the GRE tunnel is correctly set up.
Step 3 - New routes implementation
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:
curl http://www.cpanel.net/showip.cgi --interface 10.0.0.2
At the end you should see Server A's IP.
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 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
.
Conclusions
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
.