Linux NAT GRE Tunnel

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

1
2
3
4
5
6
7
8
9
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:

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

Remote

1
2
3
4
5
6
7
8
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
1
2
3
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
1
2
3
4
# 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

1
2
3
4
5
6
7
8
9
10
11
12
[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