Iptables forward traffic to vpn tunnel if open

forwardingiptablesopenvpntunneling

I've used the following guide to set up my raspberry pi as an access point:

Raspberry Pi 3 as wifi access point

I'm forwarding wlan0 to eth0 and NATing all my traffic. Works great!

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE  
sudo iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT  
sudo iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT 

Now I want to set up the same rules except use interface tun0-00 and forward all my traffic through my vpn tunnel. I do want to send all of it, don't want anything leaking out into the host network. Thinkin it goes something like this:

sudo iptables -t nat -A POSTROUTING -o tun0-00 -j MASQUERADE
sudo iptables -A FORWARD -i tun0-00 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i wlan0 -o tun0-00 -j ACCEPT

Unfortunately I know that these iptables rules aren't complete… The trouble is that eth0 stays up; the original rule to forward traffic to eth0 still exists.

I want to send all my traffic through the tunnel if the tunnel is open; if not, I'm good with it using eth0.

Update:

Used the -I flag to insert my rules:

sudo iptables -t nat -I POSTROUTING 1 -o tun0-00 -j MASQUERADE
sudo iptables -I FORWARD 1 -i tun0-00 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -I FORWARD 1 -i wlan0 -o tun0-00 -j ACCEPT

The FORWARD chain:

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 ACCEPT     all  --  wlan0  tun0-00  0.0.0.0/0            0.0.0.0/0           
2        0     0 ACCEPT     all  --  tun0-00 wlan0   0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
3        0     0 ACCEPT     all  --  eth0   wlan0   0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
4        0     0 ACCEPT     all  --  wlan0  eth0    0.0.0.0/0            0.0.0.0/0           
5        0     0 ACCEPT     all  --  wlan1  wlan0   0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
6        0     0 ACCEPT     all  --  wlan0  wlan1   0.0.0.0/0            0.0.0.0/0           

Still no joy, the forwarding doesn't seem to work.

Client VPN Config

I've scrubbed out things that looked sensitive:

dev tun
persist-tun
persist-key
cipher AES-256-CBC
auth SHA1
tls-client
client
resolv-retry infinite
remote XXX.XXX.XXX.XXX PORT_NUM udp
lport XXX
verify-x509-name "VPN_Certificate" name
pkcs12 CERT_NAME.p12
tls-auth CERTIFICATE-tls.key 1
ns-cert-type server
redirect-gateway local def1

The pi connects just fine and reflects a different public IP. The clients still show the pi as their gateway but they can't connect anymore.

Solution

First I needed to add redirect-gateway def1 into the .ovpn file on the pi.

Then I needed to actually type my interface name in correctly… Ugh. I feel like a crazy person, but apparently I saw tun0-00 in the beginning and that was the only time it existed. The interface is actually just tun0.

So the appropriate iptables commands were:

sudo iptables -t nat -I POSTROUTING 1 -o tun0 -j MASQUERADE
sudo iptables -I FORWARD 1 -i tun0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -I FORWARD 1 -i wlan0 -o tun0 -j ACCEPT

Works great now!

Best Answer

You will need both sets of rules within iptables. The two rulesets ensure that traffic leaving by the specified interfaces is appropriately masqueraded. Here is my suggestion, which is a little simpler than yours:

# Masquerade outgoing traffic
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

# Allow return traffic
iptables -A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT

# Forward everything
iptables -A FORWARD -j ACCEPT

The part of the puzzle that's missing is the routing. If the tunnel is up you want "all" outgoing traffic to use it. Otherwise use the normal route.

This is handled within OpenVPN using the redirect-gateway def1 parameter in your client configuration.

Related Question