Linux NAT GRE Tunnel
Oct 21, 2017

You will need to allow GRE traffic on your router to be passed to the local machine. This is pretty easy with an EdgeMAX router.

$PUBLIC_IP - your local public IP address (https://ipv4.icanhazip.com) $LAN_IP - your machines local LAN IP (ip a) $REMOTE_IP - IP address of the remote Linux server you are tunneling to

If your local network uses the 192.168.0.x subnet, be sure to change it to something else like 192.168.1.x

Local

auto gre1
iface gre1 inet tunnel
	address 192.168.0.2
	netmask 255.255.255.252
	mtu 1420
	mode gre
	endpoint $REMOTE_IP
	ttl 255
	post-up ip rule add from 192.168.0.0/30 table GRE && ip route add default via 192.168.0.1 table GRE

Run this once:

echo '500 GRE' >> /etc/iproute2/rt_tables
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o gre+ -j TCPMSS --clamp-mss-to-pmtu

Remote

auto gre1
iface gre1 inet tunnel
	address 192.168.0.1
	netmask 255.255.255.252
	mtu 1420
	mode gre
	endpoint $PUBLIC_IP
	ttl 255
iptables -A INPUT -p gre -s $PUBLIC_IP -j ACCEPT
iptables -t nat -A POSTROUTING -s 192.168.0.0/30 ! -o gre+ -j SNAT --to-source $REMOTE_IP
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o gre+ -j TCPMSS --clamp-mss-to-pmtu
# Port forwarding
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 443 -j DNAT --to 192.168.0.2:443
iptables -A FORWARD -d 192.168.0.2 -p tcp --dport 443 -j ACCEPT

Make sure net.ipv4.ip_forward=1 and net.ipv4.conf.all.proxy_arp=1 are enabled and net.ipv4.conf.all.rp_filter=0 is off.

Using a GRE tunnel instead of SSH/OpenVPN allows for the remote IP addresses to show up correctly instead of localhost or the tunnel IP.

I’ve had issues where the GRE tunnel times out or disconnects causing the tunnel to stop functioning. I’m not sure what the cause is and it could be an issue with the remote server.

EdgeMAX

Inbound Interface: Internet facing interface Translations Address: Local LAN IP Protocol: gre Src Address: Remote server

Ubiquiti EdgeMAX

Keep Alive

The tunnel appears to become unreachable after a certain amount of time when no data is being passed between the ends. Any iptables forward rules will not reach the destination in this case. I could not find any information about setting a keepalive variable in the interfaces file for Debian. So, the easiest thing is to setup a systemd service with a ping interval of 5 seconds.

/etc/systemd/system/tunnel-keepalive.service

[Unit]
Description=Tunnel Keepalive
After=network.target

[Service]
Type=simple
Restart=always
RestartSec=5
ExecStart=/bin/ping -q -i 5 192.168.0.1

[Install]
WantedBy=multi-user.target
Comments