Created
October 12, 2011 18:30
-
-
Save davidbarral/1282101 to your computer and use it in GitHub Desktop.
Tunnelblick "Set nameserver (alternate 1)" up script modified to support multiple search domains
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash -e | |
# | |
# 2011-04-18 Changed from client.up.tunnelblick.sh to client.3.up.tunnelblick.sh and to use leasewatch3 | |
trap "" TSTP | |
trap "" HUP | |
trap "" INT | |
export PATH="/bin:/sbin:/usr/sbin:/usr/bin" | |
# Process optional arguments (if any) for the script | |
# Each one begins with a "-" | |
# They come from Tunnelblick, and come first, before the OpenVPN arguments | |
# So we set ARG_ script variables to their values and shift them out of the argument list | |
# When we're done, only the OpenVPN arguments remain for the rest of the script to use | |
ARG_MONITOR_NETWORK_CONFIGURATION="false" | |
ARG_RESTORE_ON_DNS_RESET="false" | |
ARG_RESTORE_ON_WINS_RESET="false" | |
ARG_TAP="false" | |
while [ {$#} ] ; do | |
if [ "$1" = "-m" ] ; then # Handle the arguments we know about | |
ARG_MONITOR_NETWORK_CONFIGURATION="true" # by setting ARG_ script variables to their values | |
shift # Then shift them out | |
elif [ "$1" = "-d" ] ; then | |
ARG_RESTORE_ON_DNS_RESET="true" | |
shift | |
elif [ "$1" = "-w" ] ; then | |
ARG_RESTORE_ON_WINS_RESET="true" | |
shift | |
elif [ "$1" = "-a" ] ; then | |
ARG_TAP="true" | |
shift | |
else | |
if [ "${1:0:1}" = "-" ] ; then # Shift out Tunnelblick arguments (they start with "-") that we don't understand | |
shift # so the rest of the script sees only the OpenVPN arguments | |
else | |
break | |
fi | |
fi | |
done | |
TBCONFIG="$config" | |
# Note: The script log path name is constructed from the path of the regular config file, not the shadow copy | |
# if the config is shadow copy, e.g. /Library/Application Support/Tunnelblick/Users/Jonathan/Folder/Subfolder/config.ovpn | |
# then convert to regular config /Users/Jonathan/Library/Application Support/Tunnelblick/Configurations/Folder/Subfolder/config.ovpn | |
# to get the script log path | |
# "/Users/..." works even if the home directory has a different path; it is used in the name of the log file, and is not used as a path to get to anything. | |
TBALTPREFIX="/Library/Application Support/Tunnelblick/Users/" | |
TBALTPREFIXLEN="${#TBALTPREFIX}" | |
TBCONFIGSTART="${TBCONFIG:0:$TBALTPREFIXLEN}" | |
if [ "$TBCONFIGSTART" = "$TBALTPREFIX" ] ; then | |
TBBASE="${TBCONFIG:$TBALTPREFIXLEN}" | |
TBSUFFIX="${TBBASE#*/}" | |
TBUSERNAME="${TBBASE%%/*}" | |
TBCONFIG="/Users/$TBUSERNAME/Library/Application Support/Tunnelblick/Configurations/$TBSUFFIX" | |
fi | |
CONFIG_PATH_DASHES_SLASHES="$(echo "${TBCONFIG}" | sed -e 's/-/--/g' | sed -e 's/\//-S/g')" | |
SCRIPT_LOG_FILE="/Library/Application Support/Tunnelblick/Logs/${CONFIG_PATH_DASHES_SLASHES}.script.log" | |
# Do something only if the server pushed something | |
if [ "$foreign_option_1" == "" ]; then | |
echo "$(date '+%a %b %e %T %Y') *Tunnelblick client.3.up.tunnelblick.sh: No network configuration changes need to be made" >> "${SCRIPT_LOG_FILE}" | |
if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then | |
echo "$(date '+%a %b %e %T %Y') *Tunnelblick client.3.up.tunnelblick.sh: Will NOT monitor for other network configuration changes" >> "${SCRIPT_LOG_FILE}" | |
fi | |
exit 0 | |
fi | |
trim() { | |
echo ${@} | |
} | |
LEASEWATCHER_PLIST_PATH="/Library/Application Support/Tunnelblick/LeaseWatch3.plist" | |
OSVER="$(sw_vers | grep 'ProductVersion:' | grep -o '10\.[0-9]*')" | |
case "${OSVER}" in | |
10.4 | 10.5 ) | |
HIDE_SNOW_LEOPARD="" | |
HIDE_LEOPARD="#" | |
;; | |
10.6 | 10.7 ) | |
HIDE_SNOW_LEOPARD="#" | |
HIDE_LEOPARD="" | |
;; | |
esac | |
nOptionIndex=1 | |
nNameServerIndex=1 | |
nWINSServerIndex=1 | |
nDomainSearchIndex=1 | |
unset vForOptions | |
unset vSEARCH | |
unset vDNS | |
unset vWINS | |
unset vOptions | |
# We sleep here to allow time for OS X to process DHCP, DNS, and WINS settings | |
sleep 2 | |
while vForOptions=foreign_option_$nOptionIndex; [ -n "${!vForOptions}" ]; do | |
{ | |
vOptions[nOptionIndex-1]=${!vForOptions} | |
case ${vOptions[nOptionIndex-1]} in | |
*DOMAIN* ) | |
vSEARCH[nDomainSearchIndex-1]="$(trim "${vOptions[nOptionIndex-1]//dhcp-option DOMAIN /}")" | |
let nDomainSearchIndex++ | |
;; | |
*DNS* ) | |
vDNS[nNameServerIndex-1]="$(trim "${vOptions[nOptionIndex-1]//dhcp-option DNS /}")" | |
let nNameServerIndex++ | |
;; | |
*WINS* ) | |
vWINS[nWINSServerIndex-1]="$(trim "${vOptions[nOptionIndex-1]//dhcp-option WINS /}")" | |
let nWINSServerIndex++ | |
;; | |
esac | |
let nOptionIndex++ | |
} | |
done | |
# set domain to a default value when no domain is being transmitted | |
if [ ${#vSEARCH[*]} -eq 0 ]; then | |
domain="openvpn" | |
else | |
domain=${vSEARCH[0]} | |
fi | |
PSID=$( (scutil | grep PrimaryService | sed -e 's/.*PrimaryService : //')<<- EOF | |
open | |
show State:/Network/Global/IPv4 | |
quit | |
EOF | |
) | |
STATIC_DNS_CONFIG="$( (scutil | sed -e 's/^[[:space:]]*[[:digit:]]* : //g' | tr '\n' ' ')<<- EOF | |
open | |
show Setup:/Network/Service/${PSID}/DNS | |
quit | |
EOF | |
)" | |
if echo "${STATIC_DNS_CONFIG}" | grep -q "ServerAddresses" ; then | |
readonly STATIC_DNS="$(trim "$( echo "${STATIC_DNS_CONFIG}" | sed -e 's/^.*ServerAddresses[^{]*{[[:space:]]*\([^}]*\)[[:space:]]*}.*$/\1/g' )")" | |
fi | |
if echo "${STATIC_DNS_CONFIG}" | grep -q "SearchDomains" ; then | |
readonly STATIC_SEARCH="$(trim "$( echo "${STATIC_DNS_CONFIG}" | sed -e 's/^.*SearchDomains[^{]*{[[:space:]]*\([^}]*\)[[:space:]]*}.*$/\1/g' )")" | |
fi | |
STATIC_WINS_CONFIG="$( (scutil | sed -e 's/^[[:space:]]*[[:digit:]]* : //g' | tr '\n' ' ')<<- EOF | |
open | |
show Setup:/Network/Service/${PSID}/SMB | |
quit | |
EOF | |
)" | |
if echo "${STATIC_WINS_CONFIG}" | grep -q "WINSAddresses" ; then | |
readonly STATIC_WINS="$(trim "$( echo "${STATIC_WINS_CONFIG}" | sed -e 's/^.*WINSAddresses[^{]*{[[:space:]]*\([^}]*\)[[:space:]]*}.*$/\1/g' )")" | |
fi | |
if [ -n "${STATIC_WINS_CONFIG}" ] ; then | |
readonly STATIC_WORKGROUP="$(trim "$( echo "${STATIC_WINS_CONFIG}" | sed -e 's/^.*Workgroup : \([^[:space:]]*\).*$/\1/g' )")" | |
fi | |
if [ ${#vDNS[*]} -eq 0 ] ; then | |
DYN_DNS="false" | |
ALL_DNS="${STATIC_DNS}" | |
elif [ -n "${STATIC_DNS}" ] ; then | |
case "${OSVER}" in | |
10.6 | 10.7 ) | |
# Do nothing - in 10.6 we don't aggregate our configurations, apparently | |
DYN_DNS="false" | |
ALL_DNS="${STATIC_DNS}" | |
;; | |
10.4 | 10.5 ) | |
DYN_DNS="true" | |
# We need to remove duplicate DNS entries, so that our reference list matches MacOSX's | |
SDNS="$(echo "${STATIC_DNS}" | tr ' ' '\n')" | |
(( i=0 )) | |
for n in "${vDNS[@]}" ; do | |
if echo "${SDNS}" | grep -q "${n}" ; then | |
unset vDNS[${i}] | |
fi | |
(( i++ )) | |
done | |
if [ ${#vDNS[*]} -gt 0 ] ; then | |
ALL_DNS="$(trim "${STATIC_DNS}" "${vDNS[*]}")" | |
else | |
DYN_DNS="false" | |
ALL_DNS="${STATIC_DNS}" | |
fi | |
;; | |
esac | |
else | |
DYN_DNS="true" | |
ALL_DNS="$(trim "${vDNS[*]}")" | |
fi | |
readonly DYN_DNS ALL_DNS | |
if [ ${#vWINS[*]} -eq 0 ] ; then | |
DYN_WINS="false" | |
ALL_WINS="${STATIC_WINS}" | |
elif [ -n "${STATIC_WINS}" ] ; then | |
case "${OSVER}" in | |
10.6 | 10.7 ) | |
# Do nothing - in 10.6 we don't aggregate our configurations, apparently | |
DYN_WINS="false" | |
ALL_WINS="${STATIC_WINS}" | |
;; | |
10.4 | 10.5 ) | |
DYN_WINS="true" | |
# We need to remove duplicate WINS entries, so that our reference list matches MacOSX's | |
SWINS="$(echo "${STATIC_WINS}" | tr ' ' '\n')" | |
(( i=0 )) | |
for n in "${vWINS[@]}" ; do | |
if echo "${SWINS}" | grep -q "${n}" ; then | |
unset vWINS[${i}] | |
fi | |
(( i++ )) | |
done | |
if [ ${#vWINS[*]} -gt 0 ] ; then | |
ALL_WINS="$(trim "${STATIC_WINS}" "${vWINS[*]}")" | |
else | |
DYN_WINS="false" | |
ALL_WINS="${STATIC_WINS}" | |
fi | |
;; | |
esac | |
else | |
DYN_WINS="true" | |
ALL_WINS="$(trim "${vWINS[*]}")" | |
fi | |
readonly DYN_WINS ALL_WINS | |
if [ ${#vSEARCH[*]} -eq 0 ] ; then | |
DYN_SEARCH="false" | |
ALL_SEARCH="${STATIC_SEARCH}" | |
elif [ -n "${STATIC_SEARCH}" ] ; then | |
case "${OSVER}" in | |
10.6 ) | |
# Do nothing - in 10.6 we don't aggregate our configurations, apparently | |
DYN_SEARCH="false" | |
ALL_SEARCH="${STATIC_SEARCH}" | |
;; | |
10.4 | 10.5 ) | |
DYN_SEARCH="true" | |
# We need to remove duplicate SEARCH entries, so that our reference list matches MacOSX's | |
SSEARCH="$(echo "${STATIC_SEARCH}" | tr ' ' '\n')" | |
(( i=0 )) | |
for n in "${vSEARCH[@]}" ; do | |
if echo "${SSEARCH}" | grep -q "${n}" ; then | |
unset vSEARCH[${i}] | |
fi | |
(( i++ )) | |
done | |
if [ ${#vSEARCH[*]} -gt 0 ] ; then | |
ALL_SEARCH="$(trim "${STATIC_SEARCH}" "${vSEARCH[*]}")" | |
else | |
DYN_SEARCH="false" | |
ALL_SEARCH="${STATIC_SEARCH}" | |
fi | |
;; | |
esac | |
else | |
DYN_SEARCH="true" | |
ALL_SEARCH="$(trim "${vSEARCH[*]}")" | |
fi | |
readonly DYN_SEARCH ALL_SEARCH | |
if ! ${DYN_DNS} ; then | |
NO_DNS="#" | |
fi | |
if ! ${DYN_WINS} ; then | |
NO_WINS="#" | |
fi | |
if ! ${DYN_SEARCH} ; then | |
NO_SEARCH="#" | |
fi | |
if [ -z "${STATIC_WORKGROUP}" ] ; then | |
NO_WG="#" | |
fi | |
if [ -z "${ALL_DNS}" ] ; then | |
AGG_DNS="#" | |
fi | |
if [ -z "${ALL_SEARCH}" ] ; then | |
AGG_SEARCH="#" | |
fi | |
if [ -z "${ALL_WINS}" ] ; then | |
AGG_WINS="#" | |
fi | |
# Now, do the aggregation | |
# Save the openvpn process ID and the Network Primary Service ID, leasewather.plist path, logfile path, and optional arguments from Tunnelblick, | |
# then save old and new DNS and WINS settings | |
# PPID is a bash-script variable that contains the process ID of the parent of the process running the script (i.e., OpenVPN's process ID) | |
# config is an environmental variable set to the configuration path by OpenVPN prior to running this up script | |
echo "$(date '+%a %b %e %T %Y') *Tunnelblick client.3.up.tunnelblick.sh: Up to two 'No such key' warnings are normal and may be ignored" >> "${SCRIPT_LOG_FILE}" | |
scutil <<- EOF | |
open | |
d.init | |
d.add PID # ${PPID} | |
d.add Service ${PSID} | |
d.add LeaseWatcherPlistPath "${LEASEWATCHER_PLIST_PATH}" | |
d.add ScriptLogFile "${SCRIPT_LOG_FILE}" | |
d.add MonitorNetwork "${ARG_MONITOR_NETWORK_CONFIGURATION}" | |
d.add RestoreOnDNSReset "${ARG_RESTORE_ON_DNS_RESET}" | |
d.add RestoreOnWINSReset "${ARG_RESTORE_ON_WINS_RESET}" | |
set State:/Network/OpenVPN | |
# First, back up the device's current DNS and WINS configurations | |
# Indicate 'no such key' by a dictionary with a single entry: "TunnelblickNoSuchKey : true" | |
d.init | |
d.add TunnelblickNoSuchKey true | |
get State:/Network/Service/${PSID}/DNS | |
set State:/Network/OpenVPN/OldDNS | |
d.init | |
d.add TunnelblickNoSuchKey true | |
get State:/Network/Service/${PSID}/SMB | |
set State:/Network/OpenVPN/OldSMB | |
# Second, initialize the new DNS map | |
d.init | |
${HIDE_SNOW_LEOPARD}d.add DomainName ${domain} | |
${NO_DNS}d.add ServerAddresses * ${vDNS[*]} | |
${NO_SEARCH}d.add SearchDomains * ${vSEARCH[*]} | |
${HIDE_LEOPARD}d.add DomainName ${domain} | |
set State:/Network/Service/${PSID}/DNS | |
# Third, initialize the WINS map | |
d.init | |
${HIDE_SNOW_LEOPARD}${NO_WG}d.add Workgroup ${STATIC_WORKGROUP} | |
${NO_WINS}d.add WINSAddresses * ${vWINS[*]} | |
${HIDE_LEOPARD}${NO_WG}d.add Workgroup ${STATIC_WORKGROUP} | |
set State:/Network/Service/${PSID}/SMB | |
# Now, initialize the maps that will be compared against the system-generated map | |
# which means that we will have to aggregate configurations of statically-configured | |
# nameservers, and statically-configured search domains | |
d.init | |
${HIDE_SNOW_LEOPARD}d.add DomainName ${domain} | |
${AGG_DNS}d.add ServerAddresses * ${ALL_DNS} | |
${AGG_SEARCH}d.add SearchDomains * ${ALL_SEARCH} | |
${HIDE_LEOPARD}d.add DomainName ${domain} | |
set State:/Network/OpenVPN/DNS | |
d.init | |
${HIDE_SNOW_LEOPARD}${NO_WG}d.add Workgroup ${STATIC_WORKGROUP} | |
${AGG_WINS}d.add WINSAddresses * ${ALL_WINS} | |
${HIDE_LEOPARD}${NO_WG}d.add Workgroup ${STATIC_WORKGROUP} | |
set State:/Network/OpenVPN/SMB | |
# We're done | |
quit | |
EOF | |
echo "$(date '+%a %b %e %T %Y') *Tunnelblick client.3.up.tunnelblick.sh: Saved the DNS and WINS configurations for later use" >> "${SCRIPT_LOG_FILE}" | |
if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then | |
# Generate an updated plist with a per-configuration path | |
LEASEWATCHER_TEMPLATE_PATH="$(dirname "${0}")/LeaseWatch3.plist.template" | |
sed -e "s|\${DIR}|$(dirname "${0}")|g" "${LEASEWATCHER_TEMPLATE_PATH}" > "${LEASEWATCHER_PLIST_PATH}" | |
launchctl load "${LEASEWATCHER_PLIST_PATH}" | |
echo "$(date '+%a %b %e %T %Y') *Tunnelblick client.3.up.tunnelblick.sh: Set up to monitor system configuration with leasewatch" >> "${SCRIPT_LOG_FILE}" | |
fi | |
exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91a92 | |
> nDomainSearchIndex=1 | |
92a94 | |
> unset vSEARCH | |
105c107,108 | |
< domain="$(trim "${vOptions[nOptionIndex-1]//dhcp-option DOMAIN /}")" | |
--- | |
> vSEARCH[nDomainSearchIndex-1]="$(trim "${vOptions[nOptionIndex-1]//dhcp-option DOMAIN /}")" | |
> let nDomainSearchIndex++ | |
121c124 | |
< if [ "$domain" == "" ]; then | |
--- | |
> if [ ${#vSEARCH[*]} -eq 0 ]; then | |
122a126,127 | |
> else | |
> domain=${vSEARCH[0]} | |
228,244c233,240 | |
< # We double-check that our search domain isn't already on the list | |
< SEARCH_DOMAIN="${domain}" | |
< case "${OSVER}" in | |
< 10.6 | 10.7 ) | |
< # Do nothing - in 10.6 we don't aggregate our configurations, apparently | |
< if [ -n "${STATIC_SEARCH}" ] ; then | |
< ALL_SEARCH="${STATIC_SEARCH}" | |
< SEARCH_DOMAIN="" | |
< else | |
< ALL_SEARCH="${SEARCH_DOMAIN}" | |
< fi | |
< ;; | |
< 10.4 | 10.5 ) | |
< if echo "${STATIC_SEARCH}" | tr ' ' '\n' | grep -q "${SEARCH_DOMAIN}" ; then | |
< SEARCH_DOMAIN="" | |
< fi | |
< if [ -z "${SEARCH_DOMAIN}" ] ; then | |
--- | |
> if [ ${#vSEARCH[*]} -eq 0 ] ; then | |
> DYN_SEARCH="false" | |
> ALL_SEARCH="${STATIC_SEARCH}" | |
> elif [ -n "${STATIC_SEARCH}" ] ; then | |
> case "${OSVER}" in | |
> 10.6 ) | |
> # Do nothing - in 10.6 we don't aggregate our configurations, apparently | |
> DYN_SEARCH="false" | |
246,251c242,266 | |
< else | |
< ALL_SEARCH="$(trim "${STATIC_SEARCH}" "${SEARCH_DOMAIN}")" | |
< fi | |
< ;; | |
< esac | |
< readonly SEARCH_DOMAIN ALL_SEARCH | |
--- | |
> ;; | |
> 10.4 | 10.5 ) | |
> DYN_SEARCH="true" | |
> # We need to remove duplicate SEARCH entries, so that our reference list matches MacOSX's | |
> SSEARCH="$(echo "${STATIC_SEARCH}" | tr ' ' '\n')" | |
> (( i=0 )) | |
> for n in "${vSEARCH[@]}" ; do | |
> if echo "${SSEARCH}" | grep -q "${n}" ; then | |
> unset vSEARCH[${i}] | |
> fi | |
> (( i++ )) | |
> done | |
> if [ ${#vSEARCH[*]} -gt 0 ] ; then | |
> ALL_SEARCH="$(trim "${STATIC_SEARCH}" "${vSEARCH[*]}")" | |
> else | |
> DYN_SEARCH="false" | |
> ALL_SEARCH="${STATIC_SEARCH}" | |
> fi | |
> ;; | |
> esac | |
> else | |
> DYN_SEARCH="true" | |
> ALL_SEARCH="$(trim "${vSEARCH[*]}")" | |
> fi | |
> readonly DYN_SEARCH ALL_SEARCH | |
259c274 | |
< if [ -z "${SEARCH_DOMAIN}" ] ; then | |
--- | |
> if ! ${DYN_SEARCH} ; then | |
309c324 | |
< ${NO_SEARCH}d.add SearchDomains * ${SEARCH_DOMAIN} | |
--- | |
> ${NO_SEARCH}d.add SearchDomains * ${vSEARCH[*]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment