Introduction
Here I explain a strong solution to route traffic to a VPN using the group of the processes. We discuss security at the end. After the configuration, if you want to run ktorrent using the VPN you just have to run sudo -g vpn_euro ktorrent
. You will be able to use serveral VPN and no VPN the same time, per process.
How it works
We create one group per VPN. Using nftables we mark traffic from process using these groups (one mark per group). We use one routing table per VPN and we add a rule to use these table using the marks. We reject IPv6 output traffic from processes with these group. If the VPN is off then the routing table exists but the traffic is dropped (to avoid using a non VPN when the VPN connection droped).
Thanks
Thanks to this article from where I took a lot of materials.
Warning
I’m not a network administrator but just a tech guy who use linux perhaps before your birth and who manage a personal VPS and some computers.
How to
Create groups
Create one group per VPN, for example
groupadd vpn_euro
groupadd vpn_us
Declare the routing tables
Modifie /etc/iproute2/rt_tables , add 2 lines (for 2 VPN) :
1 vpn_euro
2 vpn_us
Add the routing table before the network
You will need to add a service to systemd to run a script to add the tables.
The script to run (file /root/bin/route-vpn-init.sh):
#!/bin/bash
# The "local-route" script, used for the VPN.
ip rule add fwmark 1 table vpn_euro
ip route flush table vpn_euro
ip route add prohibit default table vpn_euro
ip rule add fwmark 2 table vpn_us
ip route flush table vpn_us
ip route add prohibit default table vpn_us
ip route flush cache
The service to install (file /etc/systemd/system/local-route.service)
[Unit]
DefaultDependencies=no
Description=The "local-route" script, used for the VPN.
Before=network-pre.target
Wants=network-pre.target
[Service]
Type=oneshot
ExecStart=/root/bin/route-vpn-init.sh
TimeoutSec=0
RemainAfterExit=yes
[Install]
RequiredBy=local-fs.target
You need to add the service : systemctl enable local-route.service
Configure the firewall
Mark IPv4 packets
Exception for X11 remote ports (6000-6007) to allow graphic applications to contact the X11 remote server in the local network.
table ip mangle {
chain OUTPUT {
type route hook output priority -150; policy accept;
tcp dport 6000-6007 return
skgid vpn_euro tcp dport != 6000-6007 meta mark set 0x1
skgid vpn_us tcp dport != 6000-6007 meta mark set 0x2
}
}
Reject IPv6 for these groups
table ip6 removeip6 {
chain OUTPUT {
type route hook output priority -120; policy accept;
skgid vpn_euro counter reject;
skgid vpn_us counter reject;
}
}
Accept tunnel traffic
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# For the vpn
iifname "tun_*" ct state established,related counter accept
Masquerade traffic to the tunnel
table ip nat {
chain POSTROUTING {
type nat hook postrouting priority 100; policy accept;
oifname "tun_*" counter masquerade
}
}
Configure the VPNs
This is instructions for openvpn, adapt them to your vpn software.
In the .conf file for the VPN, force the device name :
dev tun_euro
and add these lines :
# LOCAL
route-nopull
up-restart
script-security 2
up /etc/openvpn/airvpn/up-euro.sh
- route-nopull avoid automatic route configuration
- up-restart tell to call the up and down script on restart
- script-security 2 allow the call of external configured scripts
- up : the script to call
/etc/openvpn/airvpn/up-euro.sh :
#!/bin/bash
set -x
ip route add 0.0.0.0/1 via $ifconfig_local table vpn_euro
ip route add 128.0.0.0/1 via $ifconfig_local table vpn_euro
Why not adding the route in one line : because it doesn’t work, I forgot the reason except I know it’s a strange behavior of the routing system.
Configure the interfaces
This is for the Debian /etc/network/interfaces, adapt it to your distribution:
iface tun_euro inet manual
openvpn air_euro
iface tun_us inet manual
openvpn air_us
Test it
I don’t know how to reload the routing table configured in /etc/iproute2/rt_tables, so, hum, yes, shame on me, … lets reboot.
Search “my ip” with a web navigator (run it with sudo -g …) to check if it uses the VPN. It if doesn’t work, did you kill the navigator before to avoid the use of the same process ? (see also firefox -P -no-remote).
To debug, use these commands :
ip rule show
ip route show table vpn_euro
nft list ruleset
tcpdump -n -i tun_euro
Use the counters in the firewall to see where things goes.
Security
When a VPN solution can leaks :
When the VPN is down
You feel safe behind the VPN but knock knock the FBI is at your door. Oops the VPN was down and your traffic was not protected (real story, a hacker has been caught with that error).
The solution exposed here avoid this error because the traffic of processes using special groups can’t go, at anytime, anywhere else but in the tunnel.
By DNS
If your local internet is spied, your need to secure every traffic that you wants to hide, like DNS requests. This is not done here.
By IPv6 hell
Generally you are behind a firewall from your internet provider and your host use the local IPv4 to identify itself. So when this address is leaked you don’t care because it doesn’t carry valuable information. This is not the case with IPv6, where addresses identifies hosts. To avoid this here, we reject anytime all outgoing IPv6 traffic from processes with the specials vpn groups.
When the VPN is up
Seriously, you think that the NSA is sleeping ? VPN providers are very good spots to track people. So be careful if you are a good guy because there is a lot of bad guys on top. Hopefully they don’t track little hackers.