It looks like you know what network IPs and domain you are connecting to.
A way of achieving this would be to only use the VPN based on which IP/domain you are requesting.
You can do this by using the macOS built-in VPN with "Send all traffic through VPN" unchecked, and define routes.
For instance, if your FTP server is at 1.2.3.4, this command will make sure that traffic to 1.2.3.4 will use the VPN to access the internet:
/sbin/route -n add -net 1.2.3.4/32 -interface ppp0
Note: you can list all existing route with netstat -rn
.
And if you have dynamic IPs behind DNS, you can use dig
to retrieve the IP and add it to routes. (10.11.12.13 is the IP address your got from the VPN).
dig -b 10.11.12.13 +noall +answer ftp.company.example
There is also a hooking mechanism that will look at /etc/ppp/ip-up
and execute it, that helps automate the above process. This bash script can create routes and lookup IP addresses for you automatically.
That's a rough example to give an idea of what can be done:
#!/bin/bash
# change name to whatever your VPN is named in Pref system
vpn_name="Company vpn"
read_args() {
# Example: ppp0 0 10.239.163.212 192.0.2.1 192.168.2.1
iface=$1; shift 3
remote_ip=$1; shift
}
log() {
echo "$@" >&2
echo "$@" 2>/dev/null >> /tmp/vpn-split-tunnel.log
}
get_vpn_iface() {
/usr/sbin/scutil --nc status "$vpn_name" | grep InterfaceName | awk '{ print $3 }'
}
lookup_ips() {
if [ "$MAC_OS_MAJOR_VER" -ge 11 ]; then
xargs dig -b $remote_ip +noall +answer | grep 'IN\s\s*A' | awk '{ print $NF "/32" }'
else
xargs dig +noall +answer | grep 'IN\s\s*A' | awk '{ print $NF "/32" }'
fi
}
init() {
echo "" 2>/dev/null > /tmp/vpn-split-tunnel.log
read_args "$@"
vpn_iface=$(get_vpn_iface)
if [[ "$iface" != "$vpn_iface" && -z "$DEBUG" ]]; then
log "Interface $iface is not for the \"$vpn_name\" connection on interface $vpn_iface"
exit
fi
}
init "$@"
cmd=(/sbin/route -n add -net "1.2.3.4/32" -interface "$iface")
log ">> ${cmd[@]}"
log $(${cmd[@]} 2>&1)