I have a device where eth0 is connected to the internet, a VPN running on tun0 through eth0, and all traffic for any devices connected on wlan0 is being routed through tun0.

This works great with:

# echo "Main"; sudo iptables -S; echo "NAT"; sudo iptables -t nat -S
-A FORWARD -i tun0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i wlan0 -o tun0 -j ACCEPT

What I would like to do now is route traffic to one external address outside of the VPN. For instance:

wlan0 -> A.B.C.D -> eth0
wlan0 -> ALL OTHER HOSTS -> tun0

How would I go about doing this?


Iptables ( Netfilter ) does not manage routing , it manage filtering or alterating packets .

You need to modify your kernel route table .

In you case when the vpn is up it add a default route to go thru tun0 , so the solution is to add another static route for A.B.C.D

  • So I did try route add A.B.C.D dev eth0 and route add A.B.C.D gw to no avail. The first didn't change anything, and the second allowed me to ping A.B.C.D from the host router but cut off all access from devices connected to wlan0. In this setup, all trafic from wlan0 goes through tun0, but none of the traffic from the host (router) does, it all goes through eth0. Changing the route only doesn't seem to work for connected devices. Could you supply the syntax you would recommend? – Fmstrat Jun 26 '18 at 13:45
  • Do you have any policy routing rules in place to force traffic from wlan0 through tun0? If so you have to modify appropriate routing table and you will have to use ip route and not old route command alone. – Tomek Jun 26 '18 at 16:14
  • @Fmstrat Could you possibly attach the output of ip route? – Kevin K. Jun 28 '18 at 12:10
  • ip route: pastebin.com/9NcAVFYn You'll notice I was able to do a sudo route add A.B.C.D dev eth0 that got me halfway there. It allows the device I'm routing on to skip the VPN when going to A.B.C.D, but devices connected via wlan0 now just can't access the host at all (while previously they could through the VPN) – Fmstrat Jul 11 '18 at 15:40
  • Marking this as the answer since it helped me, however the final commands can be found in my answer below. – Fmstrat Jul 11 '18 at 16:13

And the final answer:

sudo ip route add A.B.C.D dev eth0
sudo ip route add default via A.B.C.D dev eth0 table 3
sudo ip rule add fwmark 0x1 table 3
sudo iptables -A OUTPUT -t mangle -o tun0 -d A.B.C.D -j MARK --set-mark 1
sudo iptables -A POSTROUTING -t nat -o eth0 -d A.B.C.D -j SNAT --to <IP_OF_ETH0>
sudo ip route flush cache

This creates the route, makes a table that's marked, and sets marked traffic to route back through.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.