Skip to content

Instantly share code, notes, and snippets.

@davidsmalley
Created September 16, 2009 13:54
Show Gist options
  • Save davidsmalley/188051 to your computer and use it in GitHub Desktop.
Save davidsmalley/188051 to your computer and use it in GitHub Desktop.
#!/bin/sh
#
# openvpn-tap-up-down.sh
#
#
# A script to be used as an OpenVPN bridged (tap) up/down script on Mac OSX 10.4
# - uses ipconfig to acquire a DHCP lease via the OpenVPN tap interface, and scutil to
# incorporate the DHCP-supplied DNS configuration
#
# Use in your OpenVPN config file as follows:
#
# up openvpn-tap-up-down.sh
#
# - up: openvpn calls the 'up' script after the tun/tap interface is created, but before the link
# to the server is available for use (ditto 'up-delay' at least for UDP)
# - on testing w/ openvpn 2.0.5, and tcpdump on the tap interface as soon as it comes up,
# packets are queued up on the interface (and not actually sent over the openvpn tunnel)
# until *after* this script returns; this makes sense: this script could fail in which
# case the connection is invalid
# - this means the DHCP acquisition can't complete until after this script exits
# - that's not directly a problem as the OS X DHCP client should do everything we need
# to make the interface functional, all by itself - *except* for one small thing: as of
# OS X 10.4.7 the DHCP-acquired DNS information is not "merged" into the System
# Configuration (OS X bug?)
# - thus we have a chicken-and-egg situation: we need to manually fixup the DNS config,
# but can't until we get the DHCP lease; we won't get the lease until we this script exits
# - the solution is to spawn a little "helper" that waits until the lease is acquired,
# and then does the DNS fixup
#
# - down: the only sensible 'down' action is to release the DHCP lease (as a courtesy to the
# DHCP server), alas it's too late to do this *after* the connection has been shutdown (as
# of OpenVPN 2.0 there's no "pre-disconnect" script option; note that both 'down' and
# 'down-pre' are called only after the connection to the server is closed ('down-pre' before
# closing the tun/tap device, 'down' after)
# - OS X automatically cleans up the System Config keys created from ipconfig, but we need to
# manually remove the DNS fixup
#
# 2006-09-21 Ben Low original
#
# 200x-xx-xx name
#
if [ -z "$dev" ]; then echo "$0: \$dev not defined, exiting"; exit 1; fi
# relevant script_type values are 'up' or 'down'
case "$script_type" in
up)
# bring the interface up and set it to DHCP
# - System Configuration dynamic store will be automatically updated, with the
# State:/Network/Service/DHCP-tap0
# data store created.
# - the ipconfig man page notes that it should only be used for "test and debug" purposes,
# and that you're supposed to use the SystemConfiguration APIs to manipulate the network
# configuration
# - alas, there appears to be no CLI utility other than ipconfig
/usr/sbin/ipconfig set "$dev" DHCP
# spawn our little DNS-fixerupper
{
# whilst ipconfig will have created the neccessary Network Service keys, the DNS
# settings won't actually be used by OS X unless the SupplementalMatchDomains key
# is added
# ref. <http://lists.apple.com/archives/Macnetworkprog/2005/Jun/msg00011.html>
# - is there a way to extract the domains from the SC dictionary and re-insert
# as SupplementalMatchDomains? i.e. not requiring the ipconfig domain_name call?
# - wait until we get a lease before extracting the DNS domain name and merging into SC
# - despite it's name, ipconfig waitall doesn't (but maybe one day it will :-)
/usr/sbin/ipconfig waitall
# usually takes at least a few seconds to get a DHCP lease
sleep 3
n=0
while [ -z "$domain_name" -a $n -lt 5 ]
do
sleep $n
n=`expr $n + 1`
domain_name=`/usr/sbin/ipconfig getoption $dev domain_name 2>/dev/null`
done
if [ "$domain_name" ]; then
/usr/sbin/scutil <<EOF
d.init
get State:/Network/Service/DHCP-$dev/DNS
d.add SupplementalMatchDomains * $domain_name
set State:/Network/Service/DHCP-$dev/DNS
EOF
fi
} &
;;
down)
# for completeness...
if [ `/usr/bin/id -u` -eq 0 ]; then
/usr/sbin/ipconfig set "$dev" NONE
fi
;;
*) echo "$0: invalid script_type" && exit 1 ;;
esac
##### FIN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment