Split Tunneling

Whenever I connect to VPN on my mac, my default route is modified to this:

$ netstat -nr Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default utun1 UCS 34 0 utun1 default 192.168.2.1 UGScI 0 0 en0

What this does is, route all my traffic, even the one which is outside of VPN network routed through the VPN interface utun1 . The second default route via 192.168.1.1 is not even used. This is unnecessary and sometimes counterproductive as the VPN network takes extra load on bandwidth/resources for the IPs outside of its network and even bans sites which do not require banning.

You can easily change your routing table to circumvent this using the script below. This way you access public IPs directly and private IPs over VPN. This concept is called Split Tunneling

Modifying Routing Table

Now to modify routing table for split tunneling, all you need to do is to find out the subnet of the IPs in your VPN you need access to. Let’t take for example, if the subnets of my VPN private space are 10.109.0.0 and 10.110.0.0 (Any IPs starting with 10.109 and 10.110):

#! /usr/bin/env bash if (( EUID != 0 )) ; then echo "Please, run this command with sudo" 1>&2 exit 1 fi WIRELESS_INTERFACE = en0 TUNNEL_INTERFACE = utun0 GATEWAY = $( netstat -nrf inet | grep default | grep $WIRELESS_INTERFACE | awk '{print $2}' ) echo "Resetting routes with gateway => $GATEWAY " echo route -n delete default -ifscope $WIRELESS_INTERFACE route -n delete -net default -interface $TUNNEL_INTERFACE route -n add -net default $GATEWAY for subnet in 10.109 10.110 do route -n add -net $subnet -interface $TUNNEL_INTERFACE done

Just save the script as /usr/bin/vpn and whenever you connect to vpn, just run sudo vpn . This is what the script does:

Finds wireless router IP (en0)

Remove the default routes set by VPN

Set the IP found for en0 as the default gateway

Add the specific routes for your VPN subnet

If you are connecting over wired network, just change the en0 in script to en1 . Don’t change your VPN DNS to make sure you can resolve private domains on the VPN.

Looking at the routing table again after running the script:

$ netstat -nr Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default 192.168.2.1 UGSc 1 0 en0 ... 10.109 utun1 USc 0 0 utun1 10.110 utun1 USc 0 0 utun1

As you can see now, our default gate is back to wifi router IP - 192.168.1.1 on en0 and there are some routes for the subnets inside the VPN.

You can test the route as well with a route command. Route for any IP outside of your VPN:

$ route get google.com route to: lga15s29-in-f5.1e100.net destination: default mask: default gateway: 192.168.1.1 interface: en0 flags: <UP,GATEWAY,DONE,STATIC,PRCLONING> recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire 0 0 0 0 0 0 1500 0

Route for IP inside your VPN:

$ route get 10.109.10.135 route to: 10.109.10.135 destination: 156.107.0.0 mask: 255.255.0.0 interface: utun0 flags: <UP,GATEWAY,DONE,STATIC,PRCLONING> recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire 0 0 0 0 0 0 1280 0

To reset the routing table back, just disconnect from the VPN. Same script can be used on Linux with some modifications.