0

I'm setting up an IKEv2 VPN in macOS 10.12.3. It's working, but I'd like to configure specific websites to bypass the VPN.

I'm aware of a method using the route command to add a static route, but that only works for a specific IP address. If the site I'm connecting to changes its IP (which is a distinct possibility) then its traffic will start going through the VPN again.

How can I bypass the VPN using the site's hostname? e.g. any request to www.somewebsite.com will not use the VPN, regardless of what IP address www.somewebsite.com resolves to?

1

The most simple way to create a static and persistent route to a host is creating a script addroute.sh (root:wheel 755) in /usr/local/bin. Replace the host name and the gateway though.

#!/bin/bash

sleep 10
route -n add -host $(dig +short example.com) 192.168.0.1

and load the script with a launch daemon usr.addroute.plist (root:wheel 644) in /Library/LaunchDaemon/:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>usr.addroute</string>
        <key>ProgramArguments</key>
            <array>
                <string>/bin/sh</string>
                <string>-c</string>
                <string>/usr/local/bin/addroute.sh</string>
            </array>
        <key>RunAtLoad</key>
        <true/>
        <key>StandardErrorPath</key>
        <string>/tmp/usr.addroute.err</string>
        <key>StandardOutPath</key>
        <string>/tmp/usr.addroute.out</string>
</dict>
</plist>

Load it with: sudo launchctl load /Library/LaunchDaemon/usr.addroute.plist.

If everything works remove the Standard* keys/strings in the plist and the related files in /tmp.

The sleep 10 line is a sledgehammer approach - a route can only be added after a certain point in time: network has to be up for the specific interface - and may be replaced with something more elegant outlined in this answer here.


Depending on the VPN's or your default environment's DNS capabilities you may also have to add a route for a DNS server (e.g. Google's 8.8.8.8) and modify the dig command to dig @8.8.8.8 +short example.com.


If you reboot your host rarely and the remote hosts' IPs change often, use the following script (which can be improved probably):

#!/bin/bash

sleep 10

Hostname=hostname
GateWay=gateway_IP
IPHost=$(dig +short $Hostname)
RouteExist=$(netstat -nr -f inet | grep $IPHost | wc -l)
NewRoute=$(netstat -nr -f inet | grep $IPHost | awk '{print $1}')
OldHost=$(cat /usr/local/bin/addroute)

if [ $RouteExist -eq 0 ]
then
    route -n add -host $IPHost $GateWay
    RouteExist=1
    NewRoute=$(netstat -nr -f inet | grep $IPHost | awk '{print $1}')
    echo $NewRoute > /usr/local/bin/addroute 
fi

if [ $IPHost != $OldHost ]

then
    route -n delete -host $OldHost $GateWay
    NewRoute=$(netstat -nr -f inet | grep $IPHost | awk '{print $1}')
    echo $NewRoute > /usr/local/bin/addroute  
fi

and plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>usr.addroute</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/sh</string>
        <string>-c</string>
        <string>/usr/local/bin/addroute.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardErrorPath</key>
    <string>/tmp/usr.addroute.err</string>
    <key>StandardOutPath</key>
    <string>/tmp/usr.addroute.out</string>
    <key>StartInterval</key>
    <integer>60</integer>
</dict>
</plist>

An additional proxy file is needed:

sudo touch /usr/local/bin/addroute 

Please adjust the StartInterval (in seconds) in your plist as required and enter a proper host name and gateway IP in the shell script.

The first if routine adds a route to a remote host after booting your host and - later - a new route if the remote host's IP changes. The second if routine removes an outdated route.

  • I was thinking of doing something like this approach. Is it an issue if the script gradually increases the number of static routes as the host's IP address changes? I don't expect that to happen very quickly but some of my systems almost never get rebooted. – GuyGizmo Mar 30 '17 at 22:32
  • @GuyGizmo The static routes don't survive reboots. Therefore it has to be created while booting. The daemon only checks the ip once. If you never or rarely boot your host(s) then some mods have to be made in the shell script and the plist – klanomath Mar 30 '17 at 22:44
  • I see now, the launchd job you posted only runs once at startup. It'll be necessary for it to run periodically and update the static route as the host's IP address changes, and my concern is that it will gradually leave behind more and more static routes as time goes on. Not sure if that's really a problem, though. If I do need to address that I'm considering writing a more complex script that removes old routes as the IP changes. – GuyGizmo Mar 30 '17 at 22:47
  • @GuyGizmo Which polling frequency do you prefer? – klanomath Mar 30 '17 at 22:49
  • Probably something like every couple of minutes should be fine – GuyGizmo Mar 31 '17 at 1:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .