Skip to content

Instantly share code, notes, and snippets.

@p120ph37
Created June 30, 2014 16:27
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save p120ph37/7ac3f857886069e2bc4f to your computer and use it in GitHub Desktop.
Save p120ph37/7ac3f857886069e2bc4f to your computer and use it in GitHub Desktop.
PPP VPN split-network/split-DNS script for OSX
#!/bin/sh
####################################################
## ##
## PPP VPN split-network/split-DNS script for OSX ##
## by Aaron Meriwether ##
## ##
## installation: ##
## sudo cp thisfile /etc/ppp/ip-up ##
## sudo chmod 755 /etc/ppp/ip-up ##
## ##
####################################################
##################
## begin config...
# Define per-VPN-server settings here...
SERVERS[0]="vpn.example.org" # must match the server name set in Network Preferences.
NETWORKS[0]="192.168.2.0/24 192.168.3.0/24" # only networks besides the VPN LAN itself!
DOMAINS[0]="example.org" # domains which should use the VPN's DNS resolver when connected.
SERVERS[1]="vpn.mit.edu"
NETWORKS[1]="" # an empty network list is acceptable if you are only interested in the DNS aspects
DOMAINS[1]="staff.mit.edu athena.mit.edu"
SERVERS[2]="vpn.rogers.com"
NETWORKS[2]="172.16.7.128/25 205.150.67.0/24"
DOMAINS[2]="" # likewise, an empty DNS list is acceptable if you are only interested in the network aspects
# set to /dev/null if you object to debugging output.
DEBUGFILE=/tmp/ip-up-debug.txt
## end config...
#################
# When the ppp link comes up, this script is called with the following
# parameters
# $1 the interface name used by pppd (e.g. ppp3)
# $2 the tty device name
# $3 the tty device speed
# $4 the local IP address for the interface
# $5 the remote IP address
# $6 the parameter specified by the 'ipparam' option to pppd
# (when used with a VPN configured via Network Preferences,
# $6 seems to contain the IP address of the gateway over
# which the VPN traffic passes. This might be useful in
# ip-up scripts which need to avoid breaking the route
# used by pppd itself.)
PATH=/usr/bin:/bin:/usr/sbin:/sbin
# Generic array operation.
# e.g.: indexOf "something" "${myArray[@]}"
# note the double quotes around the array and the use of [@] not [*]
indexOf() {
local s="$1"; shift; local a=( "$@" ) i
for (( i = 0; i < ${#@}; i++ )); do
if [ "${a[$i]}" == "$s" ]; then echo $i; return; fi
done
}
# Given an interface name, find the corresponding scutil service key.
if2service() {
local i
for i in $(echo "list State:/Network/Service/[^/]+/PPP" | scutil | cut -d/ -f4); do
if [ "$(echo show State:/Network/Service/$i/PPP | scutil | grep InterfaceName | cut -d' ' -f5)" == "$1" ]; then echo $i; return; fi
done
}
# Given a network service key (specifically a PPP service), get the server name (as set in Network Preferences).
getPppServerName() {
echo show Setup:/Network/Service/$1/PPP | scutil | grep CommRemoteAddress | cut -d' ' -f5
}
echo "$(date +'%Y-%m-%d %T %Z') $0 1=$1 2=$2 3=$3 4=$4 5=$5 6=$6" >> $DEBUGFILE
SERVICE="$(if2service $1)"
echo "Service: $SERVICE" >> $DEBUGFILE
SERVER="$(getPppServerName $SERVICE)"
echo "Server Name: $SERVER" >> $DEBUGFILE
i=$(indexOf "$SERVER" "${SERVERS[@]}")
if [ -z "$i" ]; then
echo "No special configuration found for this VPN server." >> $DEBUGFILE
exit
fi
if [ -n "$(echo show State:/Network/Service/$SERVICE/IPv4 | scutil | grep OverridePrimary)" ]; then
echo "Clearing the 'Send all traffic over VPN connection' flag" >> $DEBUGFILE
scutil <<-END
get State:/Network/Service/$SERVICE/IPv4
d.remove OverridePrimary
set State:/Network/Service/$SERVICE/IPv4
END
fi
if [ -n "${NETWORKS[$i]}" ]; then
for n in ${NETWORKS[$i]}; do
echo "Adding route for network $n" >> $DEBUGFILE
route -n add -net $n $5
done
fi
if [ -n "${DOMAINS[$i]}" ]; then
echo "Limiting DNS over the VPN to these domains: ${DOMAINS[$i]}"
scutil <<-END
get State:/Network/Service/$SERVICE/DNS
d.add SupplementalMatchDomains * ${DOMAINS[$i]}
set State:/Network/Service/$SERVICE/DNS
END
fi
@bdickason
Copy link

Created fork here that removes the example servers and adds support for EHV vpn. I haven't tested EHV yet (waiting on credentials) so I may need to modify the IP.

https://gist.github.com/bdickason/937fcf5cc975aecb484b

@donikatz
Copy link

Have you confirmed multiple search domains works? It doesn't for me with Yosemite, at least. Adding multiple search domains results in none added to the resolver. I haven't been able to get SupplementalMatchDomains to work at all.

@steve-jansen
Copy link

This is awesome stuff. Thank you for sharing! 😄

@aequitas
Copy link

Nice script, only I have problem running it under El Capitan getting the split-dns to work. I can see the SupplementalMatchDomains being set initially after the ipsec tunnel is up. But after a few seconds the PPP somehow seems to reset this change. From /var/log/ppp.log:

Tue May 17 13:39:56 2016 : Received acsp/dhcp dictionaries
Tue May 17 13:39:56 2016 : Committed PPP store on install command

Have you found any way to work around this?

@nicx
Copy link

nicx commented Oct 10, 2017

I have the same problem like @aequitas: its working directly after the ppp connection comes up, after 2 seconds the chage is reverted by the system. Any solution?

@nicx
Copy link

nicx commented Oct 13, 2017

just as a workaround I added a "sleep 20" between line 103 and 104. With this its working. I think the problem is Mac OS related:

Fri Oct 13 12:18:00 2017 : l2tp_wait_input: Address added. previous interface setting (name: en4, address: 10.18.89.2), current interface setting (name: ppp0, family: PPP, address: 192.168.1.1, subnet: 255.255.255.0, destination: 10.255.255.0).
Fri Oct 13 12:18:00 2017 : Committed PPP store on install command
Fri Oct 13 12:18:00 2017 : L2TP port-mapping for en4, interfaceIndex: 0, Protocol: None, Private Port: 0, Public Address: 0, Public Port: 0, TTL: 0.
Fri Oct 13 12:18:00 2017 : L2TP port-mapping for en4 inconsistent. is Connected: 1, Previous interface: 6, Current interface 0
Fri Oct 13 12:18:03 2017 : sent [IP data <src addr 192.168.1.1> <dst addr 255.255.255.255> <BOOTP Request> <type INFORM> <client id 0x08000000010000> <parameters = 0x6 0x2c 0x2b 0x1 0xf9 0xf>]
Fri Oct 13 12:18:09 2017 : sent [IP data <src addr 192.168.1.1> <dst addr 255.255.255.255> <BOOTP Request> <type INFORM> <client id 0x08000000010000> <parameters = 0x6 0x2c 0x2b 0x1 0xf9 0xf>]
Fri Oct 13 12:18:12 2017 : sent [IP data <src addr 192.168.1.1> <dst addr 255.255.255.255> <BOOTP Request> <type INFORM> <client id 0x08000000010000> <parameters = 0x6 0x2c 0x2b 0x1 0xf9 0xf>]
Fri Oct 13 12:18:15 2017 : No DHCP server replied

It seems that the Mac OS links the ppp interface to the en4 interface with some inconsistencies, and that is generating a new DHCP BOOTP request.

In the end it resets the changes of the script here. So my workaround is just a delayed run of the setting by the script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment