How to route or exclude a network or service specific or China only traffic through a VPN using IP based split tunneling on GNU Linux?
Long gone are the days when a website was hosted on a single server with a static IP for years. In today's web, redundancy and robust content delivery networks are taking over from traditional web server systems. I am sure you have often struggled with IPs and routing table tricks when trying to route or exclude certain websites when connected to a VPN.
Complex routing improves two aspects:
-
Privacy and security: route "bad" websites through VPN and use your connection for "good" websites and you getting a privacy bonus 'cause tracking a device with two IP addresses is harder.
-
Speed: surfing on normal "good" websites feels fast like before 'cause no VPN - no speed tax to pay.
-
Time: you don't have to waste your time turning your VPN on and off anymore, just enable it permanently.
Let us simplify the process for you, so you can easily route just a single network or service specific traffic over VPN with confidence and little effort.
Cloudflare
The Cloudflare IP ranges available here: IPv4 and IPv6. Let's collect them and use to change routing.
Wireguard
Wireguard supports the option AllowedIPs
, which does two things: adds a route to the networks and will allows packets with the source IPs list to be routed from the given peer on the WireGuard interface. AllowedIPs
accepts IP and subnets in the following format:
AllowedIPs=1.1.1.1,1.0.0.1/32,::1
We need to do a simple text conversion to get IP list, compatible with Wireguard format.
V4=$(curl -s https://www.cloudflare.com/ips-v4 | tr '\n' ',')
V6=$(curl -s https://www.cloudflare.com/ips-v6 | tr '\n' ',')
echo "AllowedIPs=$V4,$v6"
We use tr
command to join multiple lines into single line.
Finally, we got the completed Wireguard configuration:
AllowedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32
Now add this line to your wg-quick.conf
file or /etc/NetworkManager/system-connections/CONNECTION_ID.nmconnection
if you are using NetworkManager on Linux. The Network manager option name is slightly different - allowed-ips
, the format is still the same.
OpenVPN
For OpenVPN we will use network routing and change it with the ip route
command. Let's create script called vpn-cloudflare.sh
:
#!/bin/bash
V4=$(curl -s https://www.cloudflare.com/ips-v4 | tr '\n' ' ')
V6=$(curl -s https://www.cloudflare.com/ips-v6 | tr '\n' ' ')
# VPN gateway
GW=111.111.111.111
for H in $V4
do
ip route add "$H" via "$GW"
done
for H in $V6
do
ip -6 route add "$H" via "$GW"
done
Let's give it executeable permission and run:
chmod +x vpn-cloudflare.sh && sudo ./vpn-cloudlfare.sh
As you can see, there are minimal changes in comparision with Wireguard: we use the tr '\n' '
command to replace newline characters with spaces and use two loops - one with IPv4 addresses, the second with IPv6 addresses.
Let's create another script to undo all changes called vpn-cloudflare-reset.sh
:
#!/bin/bash
V4=$(curl -s https://www.cloudflare.com/ips-v4 | tr '\n' ' ')
V6=$(curl -s https://www.cloudflare.com/ips-v6 | tr '\n' ' ')
# VPN gateway
GW=111.111.111.111
for H in $V4
do
ip route del "$H" via "$GW"
done
for H in $V6
do
ip -6 route del "$H" via "$GW"
done
Give it the executeable permission and run:
chmod +x vpn-cloudflare-reset.sh && sudo ./vpn-cloudlfare-reset.sh
Google IP addresses are publicly available in two lists:
- IP ranges that Google makes available to users on the internet
- Global and regional external IP address ranges for customers' Google Cloud resources
Wireguard
Let's extract IP addresses from both lists and convert them into Wireguard configuration format:
LIST1=$(curl -s https://www.gstatic.com/ipranges/goog.json | grep -oP '"*Prefix": "\K(.*)(?=")' | tr '\n' ',')
LIST2=$(curl -s https://www.gstatic.com/ipranges/cloud.json | grep -oP '"*Prefix": "\K(.*)(?=")' | tr '\n' ',')
echo "AllowedIPs=$LIST1,$LIST2"
Regular expressions explanations:
\K
resets the starting point of the reported match(.*)
1st Capturing Group - matches any characters between zero and unlimited times(?=")
positive localhead matches the character"
We got the complete configuration for Wireguard:
AllowedIPs=8.8.4.0/24,8.8.8.0/24,8.34.208.0/20,8.35.192.0/20,23.236.48.0/20...
Now add this line to your wg-quick.conf
file or /etc/NetworkManager/system-connections/CONNECTION_ID.nmconnection
if you use NetworkManager on Linux.
OpenVPN
The OpenVPN script called vpn-google.sh
will be very similar to Cloudflare version:
#!/bin/bash
LIST1V4=$(curl -s https://www.gstatic.com/ipranges/goog.json | grep -oP '"ipv4Prefix": "\K(.*)(?=")' | tr '\n' ',')
LIST2V4=$(curl -s https://www.gstatic.com/ipranges/cloud.json | grep -oP '"ipv4Prefix": "\K(.*)(?=")' | tr '\n' ',')
LIST1V6=$(curl -s https://www.gstatic.com/ipranges/goog.json | grep -oP '"ipv6Prefix": "\K(.*)(?=")' | tr '\n' ',')
LIST2V6=$(curl -s https://www.gstatic.com/ipranges/cloud.json | grep -oP '"ipv6Prefix": "\K(.*)(?=")' | tr '\n' ',')
# VPN gateway
GW=111.111.111.111
for H in "$LIST1V4 $LIST2V4"
do
ip route add "$H" via "$GW"
done
for H in "$LIST1V46 $LIST2V6"
do
ip -6 route add "$H" via "$GW"
done
Let's give it the executeable permission and run:
chmod +x vpn-cloudflare.sh && sudo ./vpn-cloudlfare.sh
China
Well, we hope you are all aware of the privacy and human rights situation in China. If you don't want to give Winnie the Pooh your personal information, it's time to get a VPN.
Chinese IP can be obtained from several sources, but we recommend the nice repository on Github - 17mon/china_ip_list.
Wireguard
LIST=$(curl -s -L https://github.com/17mon/china_ip_list/raw/master/china_ip_list.txt | tr '\n' ',')
echo "AllowedIPs=$LIST"
We're using tr
command to join multiple lines into single line. And got the Wireguard configuration:
AllowedIPs=1.0.1.0/24,1.0.2.0/23,1.0.8.0/21,1.0.32.0/19,1.1.0.0/24...
Now add this line to your wg-quick.conf
file or /etc/NetworkManager/system-connections/CONNECTION_ID.nmconnection
if you use NetworkManager on Linux.
OpenVPN
For OpenVPN we will use network routing and change it with the ip route
command. Let's create script called vpn-cloudflare.sh
:
#!/bin/bash
LIST=$(curl -s https://raw.githubusercontent.com/17mon/china_ip_list/master/china_ip_list.txt | tr '\n' ' ')
# VPN gateway
GW=111.111.111.111
for H in $LIST
do
ip route add "$H" via "$GW"
done
Let's give it the executeable permission and run:
chmod +x vpn-china.sh && sudo ./vpn-china.sh
Let's create the another sript to undo all changes called vpn-china-reset.sh
:
#!/bin/bash
LIST=$(curl -s https://raw.githubusercontent.com/17mon/china_ip_list/master/china_ip_list.txt | tr '\n' ' ')
# VPN gateway
GW=111.111.111.111
for H in "$LIST"
do
ip route del "$H" via "$GW"
done
Give it the executeable permission and run:
chmod +x vpn-china-reset.sh && sudo ./vpn-cloudlfare-reset.sh
How to exclude Netflix only traffic VPN Gateway?
If you're using VPN - Netflix hates you! They invest a lot of resources for VPN detection and improve it regularly. We can't call them the greedy service 'cause different regions with different prices and different laws, so Netflix should handle this well.
All Netflix IP addresses are available on their Help Center.
OpenVPN
Let's collect all IP addresses from Neflix website and store them in a variable called ADDRS
. GW
is the default gateway when VPN is down ('cause we will route all Netflix traffix through this gateway), you can get it from the ip route show
command output. METRIC
is for route priority, lower is better.
And save all into script called netflix-out-vpn.sh
:
#!/bin/sh
ADDRS="52.0.131.132/32 3.221.228.214/32 18.207.84.236 54.204.25.0/28 23.23.189.144/28 34.195.253.0/25 52.89.201.64/32 54.149.90.167/32 54.186.44.22/32 54.201.152.16 35.165.74.28/32 35.167.141.219/32 44.224.174.227/32"
GW=192.168.1.1
METRIC=7
for IP in $ADDRS
do
sudo ip route add "$IP" via "$GW" metric "$METRIC"
done
To undo all changes, let's create another script called netflix-out-vpn-reset.sh
:
#!/bin/sh
ADDRS="52.0.131.132/32 3.221.228.214/32 18.207.84.236 54.204.25.0/28 23.23.189.144/28 34.195.253.0/25 52.89.201.64/32 54.149.90.167/32 54.186.44.22/32 54.201.152.16 35.165.74.28/32 35.167.141.219/32 44.224.174.227/32"
GW=192.168.1.1
METRIC=7
for IP in $ADDRS
do
sudo ip route del "$IP" via "$GW" metric "$METRIC"
done
Wireguard
Wireguard config supports PostUp
and PreDown
route options. For example:
PostUp = ip route add 192.168.1.42/24 via 192.168.1.1, ip route add 192.168.1.42/32 via 192.168.1.1;
PreDown
is similar, so we can use ip route del
commands here.
Let's rewrite our netflix-out-vpn.sh
script to get the generated PostUp
and PreDown
lines.
#!/bin/sh
ADDRS="52.0.131.132/32 3.221.228.214/32 18.207.84.236 54.204.25.0/28 23.23.189.144/28 34.195.253.0/25 52.89.201.64/32 54.149.90.167/32 54.186.44.22/32 54.201.152.16 35.165.74.28/32 35.167.141.219/32 44.224.174.227/32"
GW=192.168.1.1
METRIC=7
for IP in $ADDRS
do
echo "PostUp=ip route add $i via $GW metric $METRIC;"
echo "PreDown=ip route del $i via $GW metric $METRIC;"
done
We are going to get a big list of PostUp
and PreDown
commands, just copy it and paste it into your Wireguard configuration file.
How to exclude Microsoft Exchange only traffic from a VPN Gateway?
The Exchange services are not happy when you use them with VPN, so we can make your life easier with better routing.
OpenVPN
For OpenVPN we'll reuse our Netflix knownledge with ADDRS
, GW
and METRIC
. MS Exchange IP subnet list can be found here, this list also available in JSON format.
We need to copy all IPv4 addresses to the ADDRS
and all IPv6 addresses to the ADDRS6
variables.
Save all the logic in to exchange-out-vpn.sh
script:
#!/bin/sh
ADDRS="13.107.6.152/31 13.107.18.10/31 13.107.128.0/22"
ADDRS6="2620:1ec:4::152/128 2620:1ec:4::153/128 2620:1ec:c::10/128"
GW=192.168.1.1
METRIC=7
for IP in $ADDRS
do
sudo ip route add "$IP" via "$GW" metric "$METRIC"
done
for IP in $ADDRS6
do
sudo ip -6 route add "$IP" via "$GW" metric "$METRIC"
done
And exchange-out-vpn-reset.sh
script to undo all changes:
#!/bin/sh
ADDRS="13.107.6.152/31 13.107.18.10/31 13.107.128.0/22"
ADDRS6="2620:1ec:4::152/128 2620:1ec:4::153/128 2620:1ec:c::10/128"
GW=192.168.1.1
METRIC=7
for IP in $ADDRS
do
sudo ip route del "$IP" via "$GW" metric "$METRIC"
done
for IP in $ADDRS6
do
sudo ip -6 route del "$IP" via "$GW" metric "$METRIC"
done
Wireguard
Wireguard is very similar to the Netflix section, but here we need handle IPv6.
#!/bin/sh
ADDRS="13.107.6.152/31 13.107.18.10/31 13.107.128.0/22"
ADDRS6="2620:1ec:4::152/128 2620:1ec:4::153/128 2620:1ec:c::10/128"
GW=192.168.1.1
METRIC=7
for IP in $ADDRS
do
echo "PostUp=ip route add $i via $GW metric $METRIC;"
echo "PreDown=ip route del $i via $GW metric $METRIC;"
done
for IP in $ADDRS6
do
echo "PostUp=ip -6 route add $i via $GW metric $METRIC;"
echo "PreDown=ip -6 route del $i via $GW metric $METRIC;"
done
You can now copy the output to the Wireguard configuration file.
How to exclude local Chinese traffic from a VPN Gateway when connecting to outside from China?
Wireguard
Create the next script:
#!/bin/sh
ADDRS=$(curl -s -L https://github.com/17mon/china_ip_list/raw/master/china_ip_list.txt | tr '\n' ' ')
GW=192.168.1.1
METRIC=7
for IP in $ADDRS
do
echo "PostUp=ip route add $i via $GW metric $METRIC;"
echo "PreDown=ip route del $i via $GW metric $METRIC;"
done
We're using tr
command to join multiple lines into single line and printing multiple PostUp
and PreDown
options for each subnet.
Now run this script and lines from the output to your wg-quick.conf
file or /etc/NetworkManager/system-connections/CONNECTION_ID.nmconnection
if you use NetworkManager on Linux.
OpenVPN
For OpenVPN we will use network routing and change it with the ip route
command. Make sure your gateway works when VPN is down, check it with ip route show
command. Let's create script called vpn-cloudflare.sh
:
#!/bin/bash
LIST=$(curl -s https://raw.githubusercontent.com/17mon/china_ip_list/master/china_ip_list.txt | tr '\n' ' ')
# VPN gateway
GW=192.168.1.1
# Metric
METRIC=7
for H in $LIST
do
ip route add "$H" via "$GW" metric "$METRIC"
done
Let's give it the executeable permission and run:
chmod +x vpn-china.sh && sudo ./vpn-china.sh
And create the another sript to undo all changes called vpn-china-reset.sh
:
#!/bin/bash
LIST=$(curl -s https://raw.githubusercontent.com/17mon/china_ip_list/master/china_ip_list.txt | tr '\n' ' ')
# VPN gateway
GW=192.168.1.1
for H in "$LIST"
do
ip route del "$H" via "$GW"
done
Give it the executeable permission and run:
chmod +x vpn-china-reset.sh && sudo ./vpn-cloudlfare-reset.sh
Stay safe and thank you for reading!