I have installed the NordVPN app and AdGuard home on my Pi. I also configured the AdGuard home to act as dns-over-tls server and exposed it to the Internet (forwarded the appropriate ports). I did this to be able to block ads on my mobile phone not only when it is connected to the home wifi, but also when it uses cellular data (you can configure this under Settings → Network & internet → Advanced → Private DNS menu of your Android phone).
To access my private AdGuard DNS I use the subdomain which is linked to the IP from my ISP. This works fine until I establish a VPN connection. In this case all traffic is routed through the VPN tunnel and I cannot connect to my DNS server from the Internet. I cannot link my subdomain to the VPN IP address because it doesn’t support port forwarding and blocks all incoming (not established/related) connections. Thus I need to somehow route traffic generated by the Pi itself or which is intended to the Pi through ISP and route forwarded (from LAN clients) traffic through the VPN tunnel. In other words I want any device connected to LAN to use the Pi as a VPN gateway, but route its own traffic through ISP, not through the VPN tunnel.
It was quite simple to configure the Pi as a VPN gateway and route all traffic through tunnel, but I have no idea how to route only forwarded traffic through tunnel. Could somebody helm me with the set up? My LAN network is: 10.10.10.0/24, ISP router: 10.10.10.1, VPN tunnel name: nordlynx.
Add the following script when the tunnel comes up:
#!/bin/sh
ip route add to default via 10.10.10.1 table 100
ip rule add iif lo to 10.10.10.0/24 lookup main prio 16000
ip rule add iif lo to default lookup 100 prio 16010
I created a script with the provided contents, but it returns the following error: “Error: argument “internet” is wrong: invalid table ID”
That’s how my routing looks when VPN is connected and script is executed:
$ sudo ip route show table all
default via 10.10.10.1 dev eth0 table 100
default dev nordlynx table 51820 scope link
default via 10.10.10.1 dev eth0 onlink
10.5.0.0/16 dev nordlynx proto kernel scope link src 10.5.0.2
10.10.10.0/24 dev eth0 proto kernel scope link src 10.10.10.100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
broadcast 10.5.0.0 dev nordlynx table local proto kernel scope link src 10.5.0.2
local 10.5.0.2 dev nordlynx table local proto kernel scope host src 10.5.0.2
broadcast 10.5.255.255 dev nordlynx table local proto kernel scope link src 10.5.0.2
broadcast 10.10.10.0 dev eth0 table local proto kernel scope link src 10.10.10.100
local 10.10.10.100 dev eth0 table local proto kernel scope host src 10.10.10.100
broadcast 10.10.10.255 dev eth0 table local proto kernel scope link src 10.10.10.100
broadcast 127.0.0.0 dev lo table local proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1
broadcast 172.17.0.0 dev docker0 table local proto kernel scope link src 172.17.0.1
local 172.17.0.1 dev docker0 table local proto kernel scope host src 172.17.0.1
broadcast 172.17.255.255 dev docker0 table local proto kernel scope link src 172.17.0.1
Two little remarks for those who might want repeat the process.
I. You should also create a script:
#!/bin/sh
ip rule del from all to 10.10.10.0/24 iif lo lookup main
ip rule del from all iif lo lookup 100
and run it (as root) after the vpn is disconnected. Otherwise the NordVPN app will create its forwarding rules with lower priority thus local traffic will be forwarded through vpn next time you connect.
II. If you have similar to the following firewall rules in FORWARD section:
Accept if input interface is eth0 and output interface is nordlynx
Accept if input interface is nordlynx and state of connection is established, related
Then the KillSwitch feature will also work. To disable it you should delete “nordlynx” protocol from both of these rules:
Accept if input interface is eth0
Accept if output interface is eth0 and state of connection is established, related
The default action should be set to DROP.
trendy, thank you very much for the help!
A question for the possible future improvement: is it possible to forward a certain traffic (which goes to/from a certain port or address) to be forwarded into the vpn tunnel? Or even reverse the configuration, i.e. forward everything except certain traffic (DNS, and http server)?
All forwarded (i.e. from LAN clients) traffic should go through VPN tunnel; Local traffic should go through ISP by default, except traffic from Transmission (which listens to port 22333) or traffic which goes to 173.194.73.101. These two types of traffic also should go through VPN tunnel.
All forwarded (i.e. from LAN clients) traffic should go through VPN tunnel; Local traffic should also go through VPN tunnel by default, except traffic from AdGuard (which listens to ports 853 TCP and 8434 TCP) or traffic which goes to 173.194.73.101. These two types of traffic should go through ISP.
I think such setup is much more complex. I also try to learn some networking on my setup…
Forwarded packets from lan hosts will use the main routing table. So you should have the tunnel interface with lower metric for that.
You can apply some exceptions based on ports.
dietpi@RockPi:[~]$ ip rule help
Usage: ip rule { add | del } SELECTOR ACTION
ip rule { flush | save | restore }
ip rule [ list [ SELECTOR ]]
SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]
[ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]
[ uidrange NUMBER-NUMBER ]
[ ipproto PROTOCOL ]
[ sport [ NUMBER | NUMBER-NUMBER ]
[ dport [ NUMBER | NUMBER-NUMBER ] ]
ACTION := [ table TABLE_ID ]
[ protocol PROTO ]
[ nat ADDRESS ]
[ realms [SRCREALM/]DSTREALM ]
[ goto NUMBER ]
SUPPRESSOR
SUPPRESSOR := [ suppress_prefixlength NUMBER ]
[ suppress_ifgroup DEVGROUP ]
TABLE_ID := [ local | main | default | NUMBER ]
sport can be used for transmission and to PREFIX for the IP.
Looks like I found one disadvantage: if I use this configuration, then the connection speed for Pi traffic (through ISP) drops significantly. And what is more important for the AdGuard DNS - the ping increases.
This is the speedtest result with default routing and no vpn connection:
Hosted by ... [0.39 km]: 4.25 ms
Testing download speed................................................................................
Download: 540.49 Mbit/s
Testing upload speed......................................................................................................
Upload: 168.20 Mbit/s
And this is the speedtest with VPN connection running, but all Pi’s traffic being routed through ISP (I used the same server for testing):
Hosted by ... [0.39 km]: 119.784 ms
Testing download speed................................................................................
Download: 51.55 Mbit/s
Testing upload speed......................................................................................................
Upload: 11.65 Mbit/s
The second result is not the speed via VPN - it also shows speed when traffic from Pi is routed through ISP directly, but traffic from other LAN clients is routed through VPN.
The first result:
VPN is turned off. No forwarded traffic is allowed (since the VPN is turned off). Pi is connected directly to the ISP and the test results show connection speed between Pi and ISP.
The second result:
VPN is connected, but Pi’s own traffic still goes directly through ISP. Forwarded traffic (from LAN clients) goes through VPN. To route Pi’s own traffic through ISP (not through VPN) I use three routing rules provided by trendy earlier in this thread. The test results also show connection speed between Pi and ISP. To get “clean” results - non of the LAN clients use Pi as a gateway during the speed test.
When I use routing rules provided earlier - it affects the connection speed of Pi itself very much. It it possible to fix this?
Speedtest from Pi itself through ISP. VPN is connected, but Pi’s own traffic is routed through ISP.
Speedtest from one of the LAN clients which used Pi as a VPN gateway. Client’s traffic is routed through VPN.
Case 1 one more time.
Case 2 one more time.
Got the following results:
Down: 69 Mb/s; Up: 11 Mb/s; Ping: 119
Down: 142 Mb/s; Up: 95 Mb/s; Ping: 48
Down: 51 Mb/s; Up: 11 Mb/s; Ping: 121
Down: 141 Mb/s; Up: 81 Mb/s; Ping: 49
You can see the CPU load for each case on the graph below (I used the netdata to collect the information).
It looks like that Pi doesn’t subject to a high CPU load when it routes its own traffic, but still gets poor speeds. And the Pi’s CPU load is high when routing LAN client’s traffic, but the client still gets quite high speeds.
I have tested 2 more cases when both own Pi’s traffic and LAN clients traffic are routed through VPN (by Pi):
5. Speedtest from Pi. Down: 120 Mb/s; Up: 193 Mb/s; Ping: 37
6. Speedtest form one of the LAN clients, whose traffic is routed through Pi. Down: 150 Mb/s; Up: 91 Mb/s; Ping: 25.