AP routing by VPN and rest by default
I have an orangepi (armbian) with an Ethernet interface (eth0) where I set up an interface (wlan0) for an AccessPoint and installed a VPN client (tun0).
The objective is:
All traffic from the wlan0 AP is directed to the vpn (tun0) and vice versa
All traffic from system processes, programs, etc. is routed by default to 192.168.1.1 ISP destination
------------------- | | 10.8.3.2/24---|tun0 wlan0 |----192.168.2.1/24 192.168.1.31/24---|eth0 | WIFI AP | | -------------------
I have activated Forwarding: net.ipv4.ip_forward=1
And added rule in iptables: iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
Result: Access through AP OK and always routed through the VPN OK
All traffic is routed through the VPN and the idea is that the traffic generated by the processes is routed through the default 192.168.1.1
If from a terminal I perform ping, traceroute, etc. it routes tun0, I understand why it assigns tun0’s 10.8.3.2 as the source IP and I think this is where the problem is, if it assigned eth0’s 192.168.1.31, it would route by default 192.168. 1.1 and it would be solved.
The VPN client creates the default:
0.0.0.0 10.8.3.1 126.96.36.199 UG 0 0 0 tun0
Even if I delete it, everything remains the same.
What needs to be configured so that the rest of the traffic is routed by default to 192.168.1.1 ISP destination?
Destination Gateway Genmask Flags MSS Window irtt Iface 0.0.0.0 10.8.3.1 188.8.131.52 UG 0 0 0 tun0 0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0 10.8.3.0 0.0.0.0 255.255.255.0 U 0 0 0 tun0 184.108.40.206 10.8.3.1 220.127.116.11 UG 0 0 0 tun0 169.254.0.0 0.0.0.0 255.255.0.0 U 0 0 0 wlan0 18.104.22.168 192.168.1.1 255.255.255.255 UGH 0 0 0 eth0 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 192.168.2.0 0.0.0.0 255.255.255.0 U 0 0 0 wlan0 eth0: flags=4163 <UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.31 netmask 255.255.255.0 broadcast 192.168.1.255 ether 02:81:91:07:0c:a5 txqueuelen 1000 (Ethernet) lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500 inet 10.8.3.2 netmask 255.255.255.0 destination 10.8.3.2 unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC) wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.2.1 netmask 255.255.255.0 broadcast 192.168.2.255 ether 00:e0:4c:81:79:8a txqueuelen 1000 (Ethernet)
route should not be used anymore on Linux because they use a deprecated and obsolete Linux kernel API. They should be replaced with
ip addr and
ip route (and various additional commands from the iproute2 suite).
Policy-based routing cannot be achieved with the deprecated commands on Linux but only with the iproute2 suite’s commands.
The current routing setup takes care of overriding the original default route by using two "half-default" routes instead of a default route (for example this is called
def1 by OpenVPN when the server pushes a route or the client overrides it), so the actual VPN routes are both:
0.0.0.0 10.8.3.1 22.214.171.124 UG 0 0 0 tun0 126.96.36.199 10.8.3.1 188.8.131.52 UG 0 0 0 tun0
and because they are narrower than the default route, they override it for any destination (not in an other routing entry, such as the VPN remote endpoint explicitly added to avoid a routing loop for the tunnel envelope).
So removing only the first entry will still affect about half of Internet (eg: if
www.armbian.com resolves as 184.108.40.206 it won’t be reached through the tunnel anymore, but if
www.debian.org resolves as 220.127.116.11 then it will reached through the tunnel). Removing both of course will just more or less disable using the tunnel. These actions would affect the host and the nodes behind wlan0.
Here policy-based routing can be used to distinguish routed/forwarded traffic and traffic originating from the host itself to have a different routing outcome.
OP’s goal is to have the VPN used by the nodes behind the host (at the LAN behind wlan0) but not the host itself. Without any other change to the current setup, this can be manually accomplished by policy routing rules + a routing table overriding the current override: only for the host ignore routes with CIDR of 0 (0.0.0.0/0) or 1 (0.0.0.0/1 and 18.104.22.168/1: OpenVPN’s def1 method) and respecify a new default route (which will be the original default route).
The 3 commands below are sufficient to solve this:
ip route add default via 192.168.1.1 dev eth0 table 1000 ip rule add pref 1000 iif lo lookup main suppress_prefixlength 1 ip rule add pref 1001 iif lo lookup 1000
only for the host itself (special syntax
iif lofor host-originating traffic) but not for routed/forwarded traffic (which would match
iif tun0depending on where from, instead) use the main routing table to retrieve a route as long as the route doesn’t come from the default route or the two def1 "half-default" routes, thanks to the
still only for the host itself if no route was found then use the original default route that was duplicated in routing table 1000.
thus by default allowing the host to reach Internet without using the VPN.
any routed/forwarded traffic is left unaffected by this setting
and will thus continue as before to reach Internet through the VPN.
return traffic to the host itself is always handled first by the local routing table so unaffected by this setup. Indeed the very first routing rule at preference 0 handles the local routing table, as seen below:
# ip rule 0: from all lookup local 1000: from all iif lo lookup main suppress_prefixlength 1 1001: from all iif lo lookup 1000 32766: from all lookup main 32767: from all lookup default
the host can still reach nodes at 10.8.3.0/24 as usual using the VPN or nodes at 192.168.2.0/24 through wireless since their routes have a CIDR of 24 which is superior to 1 and is thus not suppressed.
Caveat: whenever the interface eth0 is administratively put down (then up) the entry in routing table 1000 has to be put back because it will be deleted, just as what happens in the main routing table: this should be integrated in the eth0 interface setup rather than just at boot.
Other methods that don’t need to know explicitly the gateway or would automate this certainly exist, but they would likely involve the VPN setup. Either these commands could be run as a script by the VPN tool (which would probably be able to provide the gateway in a variable) or the VPN’s configuration might be able to provide direct solutions to solve this. I can’t know with available information.