summaryrefslogtreecommitdiff
path: root/pkg/osx/client.down.sh
diff options
context:
space:
mode:
authorKali Kaneko <kali@leap.se>2016-01-29 13:18:36 -0800
committerKali Kaneko <kali@leap.se>2016-04-18 16:15:21 -0400
commite9e9abc4ec26be29b3a6b09e6a0b67786269183b (patch)
tree698ffd51104e6d391957ba25e31e88a2bbced38a /pkg/osx/client.down.sh
parent0bd65c1d3e6c5ee1d861122ec2cd617ad026de43 (diff)
[feature] privileged bitmask helper
This is still quite untested, and a bit hacky, but the main idea behind let us have a daemonized bitmask helper, that should be installed by the Bitmask installer. Its responsibilities are to launch the vpn process as a privileged user, and start/stop the firewall.
Diffstat (limited to 'pkg/osx/client.down.sh')
-rwxr-xr-xpkg/osx/client.down.sh426
1 files changed, 426 insertions, 0 deletions
diff --git a/pkg/osx/client.down.sh b/pkg/osx/client.down.sh
new file mode 100755
index 00000000..1e173bba
--- /dev/null
+++ b/pkg/osx/client.down.sh
@@ -0,0 +1,426 @@
+#!/bin/bash -e
+# Note: must be bash; uses bash-specific tricks
+#
+# ******************************************************************************************************************
+# Copyright By Tunnelblick. Redistributed with Bitmask under the GPL.
+# This Tunnelblick script does everything! It handles TUN and TAP interfaces,
+# pushed configurations and DHCP leases. :)
+#
+# This is the "Down" version of the script, executed after the connection is
+# closed.
+#
+# Created by: Nick Williams (using original code and parts of old Tblk scripts)
+#
+# ******************************************************************************************************************
+
+# @param String message - The message to log
+logMessage()
+{
+ echo "${@}"
+}
+
+# @param String message - The message to log
+logDebugMessage()
+{
+ echo "${@}" > /dev/null
+}
+
+trim()
+{
+echo ${@}
+}
+
+# @param String list - list of network service names, output from disable_ipv6()
+restore_ipv6() {
+
+ # Undoes the actions performed by the disable_ipv6() routine in client.up.tunnelblick.sh by restoring the IPv6
+ # 'automatic' setting for each network service for which that routine disabled IPv6.
+ #
+ # $1 must contain the output from disable_ipv6() -- the list of network services.
+ #
+ # This routine outputs log messages describing its activities.
+
+ if [ "$1" = "" ] ; then
+ exit
+ fi
+
+ printf %s "$1
+" | \
+ while IFS= read -r ripv6_service ; do
+ networksetup -setv6automatic "$ripv6_service"
+ logMessage "Re-enabled IPv6 (automatic) for '$ripv6_service'"
+ done
+}
+
+##########################################################################################
+flushDNSCache()
+{
+ if ${ARG_FLUSH_DNS_CACHE} ; then
+ set +e # "grep" will return error status (1) if no matches are found, so don't fail on individual errors
+ readonly OSVER="$(sw_vers | grep 'ProductVersion:' | grep -o '10\.[0-9]*')"
+ set -e # We instruct bash that it CAN again fail on errors
+ if [ "${OSVER}" = "10.4" ] ; then
+
+ if [ -f /usr/sbin/lookupd ] ; then
+ set +e # we will catch errors from lookupd
+ /usr/sbin/lookupd -flushcache
+ if [ $? != 0 ] ; then
+ logMessage "WARNING: Unable to flush the DNS cache via lookupd"
+ else
+ logMessage "Flushed the DNS cache via lookupd"
+ fi
+ set -e # bash should again fail on errors
+ else
+ logMessage "WARNING: /usr/sbin/lookupd not present. Not flushing the DNS cache"
+ fi
+
+ else
+
+ if [ -f /usr/bin/dscacheutil ] ; then
+ set +e # we will catch errors from dscacheutil
+ /usr/bin/dscacheutil -flushcache
+ if [ $? != 0 ] ; then
+ logMessage "WARNING: Unable to flush the DNS cache via dscacheutil"
+ else
+ logMessage "Flushed the DNS cache via dscacheutil"
+ fi
+ set -e # bash should again fail on errors
+ else
+ logMessage "WARNING: /usr/bin/dscacheutil not present. Not flushing the DNS cache via dscacheutil"
+ fi
+
+ if [ -f /usr/sbin/discoveryutil ] ; then
+ set +e # we will catch errors from discoveryutil
+ /usr/sbin/discoveryutil udnsflushcaches
+ if [ $? != 0 ] ; then
+ logMessage "WARNING: Unable to flush the DNS cache via discoveryutil udnsflushcaches"
+ else
+ logMessage "Flushed the DNS cache via discoveryutil udnsflushcaches"
+ fi
+ /usr/sbin/discoveryutil mdnsflushcache
+ if [ $? != 0 ] ; then
+ logMessage "WARNING: Unable to flush the DNS cache via discoveryutil mdnsflushcache"
+ else
+ logMessage "Flushed the DNS cache via discoveryutil mdnsflushcache"
+ fi
+ set -e # bash should again fail on errors
+ else
+ logMessage "/usr/sbin/discoveryutil not present. Not flushing the DNS cache via discoveryutil"
+ fi
+
+ set +e # "grep" will return error status (1) if no matches are found, so don't fail on individual errors
+ hands_off_ps="$( ps -ax | grep HandsOffDaemon | grep -v grep.HandsOffDaemon )"
+ set -e # We instruct bash that it CAN again fail on errors
+ if [ "${hands_off_ps}" = "" ] ; then
+ if [ -f /usr/bin/killall ] ; then
+ set +e # ignore errors if mDNSResponder isn't currently running
+ /usr/bin/killall -HUP mDNSResponder
+ if [ $? != 0 ] ; then
+ logMessage "mDNSResponder not running. Not notifying it that the DNS cache was flushed"
+ else
+ logMessage "Notified mDNSResponder that the DNS cache was flushed"
+ fi
+ set -e # bash should again fail on errors
+ else
+ logMessage "WARNING: /usr/bin/killall not present. Not notifying mDNSResponder that the DNS cache was flushed"
+ fi
+ else
+ logMessage "WARNING: Hands Off is running. Not notifying mDNSResponder that the DNS cache was flushed"
+ fi
+
+ fi
+ fi
+}
+
+##########################################################################################
+resetPrimaryInterface()
+{
+ set +e # "grep" will return error status (1) if no matches are found, so don't fail on individual errors
+ WIFI_INTERFACE="$(networksetup -listallhardwareports | awk '$3=="Wi-Fi" {getline; print $2}')"
+ if [ "${WIFI_INTERFACE}" == "" ] ; then
+ WIFI_INTERFACE="$(networksetup -listallhardwareports | awk '$3=="AirPort" {getline; print $2}')"
+ fi
+ PINTERFACE="$( scutil <<-EOF |
+ open
+ show State:/Network/Global/IPv4
+ quit
+EOF
+ grep PrimaryInterface | sed -e 's/.*PrimaryInterface : //'
+ )"
+ set -e # resume abort on error
+
+ if [ "${PINTERFACE}" != "" ] ; then
+ if [ "${PINTERFACE}" == "${WIFI_INTERFACE}" -a "${OSVER}" != "10.4" -a -f /usr/sbin/networksetup ] ; then
+ if [ "${OSVER}" == "10.5" ] ; then
+ logMessage "Resetting primary interface '${PINTERFACE}' via networksetup -setairportpower off/on..."
+ /usr/sbin/networksetup -setairportpower off
+ sleep 2
+ /usr/sbin/networksetup -setairportpower on
+ else
+ logMessage "Resetting primary interface '${PINTERFACE}' via networksetup -setairportpower ${PINTERFACE} off/on..."
+ /usr/sbin/networksetup -setairportpower "${PINTERFACE}" off
+ sleep 2
+ /usr/sbin/networksetup -setairportpower "${PINTERFACE}" on
+ fi
+ else
+ if [ -f /sbin/ifconfig ] ; then
+ logMessage "Resetting primary interface '${PINTERFACE}' via ifconfig ${PINTERFACE} down/up..."
+ /sbin/ifconfig "${PINTERFACE}" down
+ sleep 2
+ /sbin/ifconfig "${PINTERFACE}" up
+ else
+ logMessage "WARNING: Not resetting primary interface because /sbin/ifconfig does not exist."
+ fi
+ fi
+ else
+ logMessage "WARNING: Not resetting primary interface because it cannot be found."
+ fi
+}
+
+##########################################################################################
+trap "" TSTP
+trap "" HUP
+trap "" INT
+export PATH="/bin:/sbin:/usr/sbin:/usr/bin"
+
+readonly OUR_NAME=$(basename "${0}")
+
+logMessage "**********************************************"
+logMessage "Start of output from ${OUR_NAME}"
+
+# Remove the flag file that indicates we need to run the down script
+
+if [ -e "/tmp/bitmask-downscript-needs-to-be-run.txt" ] ; then
+ rm -f "/tmp/bitmask-downscript-needs-to-be-run.txt"
+fi
+
+# Test for the "-r" Bitmask option (Reset primary interface after disconnecting) because we _always_ need its value.
+# Usually we get the value for that option (and the other options) from State:/Network/OpenVPN,
+# but that key may not exist (because, for example, there were no DNS changes).
+# So we get the value from the Bitmask options passed to this script by OpenVPN.
+#
+# We do the same thing for the -f Bitmask option (Flush DNS cache after connecting or disconnecting)
+ARG_RESET_PRIMARY_INTERFACE_ON_DISCONNECT="false"
+ARG_FLUSH_DNS_CACHE="false"
+while [ {$#} ] ; do
+ if [ "${1:0:1}" != "-" ] ; then # Bitmask arguments start with "-" and come first
+ break # so if this one doesn't start with "-" we are done processing Bitmask arguments
+ fi
+ if [ "$1" = "-r" ] ; then
+ ARG_RESET_PRIMARY_INTERFACE_ON_DISCONNECT="true"
+ else
+ if [ "$1" = "-f" ] ; then
+ ARG_FLUSH_DNS_CACHE="true"
+ fi
+ fi
+ shift # Shift arguments to examine the next option (if there is one)
+done
+
+# Quick check - is the configuration there?
+if ! scutil -w State:/Network/OpenVPN &>/dev/null -t 1 ; then
+ # Configuration isn't there
+ logMessage "WARNING: Not restoring DNS settings because no saved Bitmask DNS information was found."
+
+ flushDNSCache
+
+ if ${ARG_RESET_PRIMARY_INTERFACE_ON_DISCONNECT} ; then
+ resetPrimaryInterface
+ fi
+ logMessage "End of output from ${OUR_NAME}"
+ logMessage "**********************************************"
+ exit 0
+fi
+
+# Get info saved by the up script
+TUNNELBLICK_CONFIG="$( scutil <<-EOF
+ open
+ show State:/Network/OpenVPN
+ quit
+EOF
+)"
+
+ARG_MONITOR_NETWORK_CONFIGURATION="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*MonitorNetwork :' | sed -e 's/^.*: //g')"
+LEASEWATCHER_PLIST_PATH="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*LeaseWatcherPlistPath :' | sed -e 's/^.*: //g')"
+REMOVE_LEASEWATCHER_PLIST="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*RemoveLeaseWatcherPlist :' | sed -e 's/^.*: //g')"
+PSID="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*Service :' | sed -e 's/^.*: //g')"
+# Don't need: SCRIPT_LOG_FILE="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*ScriptLogFile :' | sed -e 's/^.*: //g')"
+# Don't need: ARG_RESTORE_ON_DNS_RESET="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*RestoreOnDNSReset :' | sed -e 's/^.*: //g')"
+# Don't need: ARG_RESTORE_ON_WINS_RESET="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*RestoreOnWINSReset :' | sed -e 's/^.*: //g')"
+# Don't need: PROCESS="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*PID :' | sed -e 's/^.*: //g')"
+# Don't need: ARG_IGNORE_OPTION_FLAGS="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*IgnoreOptionFlags :' | sed -e 's/^.*: //g')"
+ARG_TAP="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*IsTapInterface :' | sed -e 's/^.*: //g')"
+ARG_FLUSH_DNS_CACHE="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*FlushDNSCache :' | sed -e 's/^.*: //g')"
+ARG_RESET_PRIMARY_INTERFACE_ON_DISCONNECT="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*ResetPrimaryInterface :' | sed -e 's/^.*: //g')"
+bRouteGatewayIsDhcp="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*RouteGatewayIsDhcp :' | sed -e 's/^.*: //g')"
+bTapDeviceHasBeenSetNone="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*TapDeviceHasBeenSetNone :' | sed -e 's/^.*: //g')"
+bAlsoUsingSetupKeys="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*bAlsoUsingSetupKeys :' | sed -e 's/^.*: //g')"
+sTunnelDevice="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*TunnelDevice :' | sed -e 's/^.*: //g')"
+
+# Note: '\n' was translated into '\t', so we translate it back (it was done because grep and sed only work with single lines)
+sRestoreIpv6Services="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*RestoreIpv6Services :' | sed -e 's/^.*: //g' | tr '\t' '\n')"
+
+# Remove leasewatcher
+if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then
+ launchctl unload "${LEASEWATCHER_PLIST_PATH}"
+ if ${REMOVE_LEASEWATCHER_PLIST} ; then
+ rm -f "${LEASEWATCHER_PLIST_PATH}"
+ fi
+ logMessage "Cancelled monitoring of system configuration changes"
+fi
+
+if ${ARG_TAP} ; then
+ if [ "$bRouteGatewayIsDhcp" == "true" ]; then
+ if [ "$bTapDeviceHasBeenSetNone" == "false" ]; then
+ if [ -z "$dev" ]; then
+ # If $dev is not defined, then use TunnelDevice, which was set from $dev by client.up.tunnelblick.sh
+ # ($def is not defined when this script is called from MenuController to clean up when exiting Bitmask)
+ if [ -n "${sTunnelDevice}" ]; then
+ logMessage "WARNING: \$dev not defined; using TunnelDevice: ${sTunnelDevice}"
+ set +e
+ ipconfig set "${sTunnelDevice}" NONE 2>/dev/null
+ set -e
+ logMessage "Released the DHCP lease via ipconfig set ${sTunnelDevice} NONE."
+ else
+ logMessage "WARNING: Cannot configure TAP interface to NONE without \$dev or State:/Network/OpenVPN/TunnelDevice being defined. Device may not have disconnected properly."
+ fi
+ else
+ set +e
+ ipconfig set "$dev" NONE 2>/dev/null
+ set -e
+ logMessage "Released the DHCP lease via ipconfig set $dev NONE."
+ fi
+ fi
+ fi
+fi
+
+# Issue warning if the primary service ID has changed
+set +e # "grep" will return error status (1) if no matches are found, so don't fail if not found
+PSID_CURRENT="$( scutil <<-EOF |
+ open
+ show State:/Network/OpenVPN
+ quit
+EOF
+grep 'Service : ' | sed -e 's/.*Service : //'
+)"
+set -e # resume abort on error
+if [ "${PSID}" != "${PSID_CURRENT}" ] ; then
+ logMessage "Ignoring change of Network Primary Service from ${PSID} to ${PSID_CURRENT}"
+fi
+
+# Restore configurations
+DNS_OLD="$( scutil <<-EOF
+ open
+ show State:/Network/OpenVPN/OldDNS
+ quit
+EOF
+)"
+SMB_OLD="$( scutil <<-EOF
+ open
+ show State:/Network/OpenVPN/OldSMB
+ quit
+EOF
+)"
+DNS_OLD_SETUP="$( scutil <<-EOF
+ open
+ show State:/Network/OpenVPN/OldDNSSetup
+ quit
+EOF
+)"
+TB_NO_SUCH_KEY="<dictionary> {
+ BitmaskNoSuchKey : true
+}"
+
+if [ "${DNS_OLD}" = "${TB_NO_SUCH_KEY}" ] ; then
+ scutil <<-EOF
+ open
+ remove State:/Network/Service/${PSID}/DNS
+ quit
+EOF
+else
+ scutil <<-EOF
+ open
+ get State:/Network/OpenVPN/OldDNS
+ set State:/Network/Service/${PSID}/DNS
+ quit
+EOF
+fi
+
+if [ "${DNS_OLD_SETUP}" = "${TB_NO_SUCH_KEY}" ] ; then
+ if ${bAlsoUsingSetupKeys} ; then
+ logDebugMessage "DEBUG: Removing 'Setup:' DNS key"
+ scutil <<-EOF
+ open
+ remove Setup:/Network/Service/${PSID}/DNS
+ quit
+EOF
+ else
+ logDebugMessage "DEBUG: Not removing 'Setup:' DNS key"
+ fi
+else
+ if ${bAlsoUsingSetupKeys} ; then
+ logDebugMessage "DEBUG: Restoring 'Setup:' DNS key"
+ scutil <<-EOF
+ open
+ get State:/Network/OpenVPN/OldDNSSetup
+ set Setup:/Network/Service/${PSID}/DNS
+ quit
+EOF
+ else
+ logDebugMessage "DEBUG: Not restoring 'Setup:' DNS key"
+ fi
+fi
+
+if [ "${SMB_OLD}" = "${TB_NO_SUCH_KEY}" ] ; then
+ scutil > /dev/null <<-EOF
+ open
+ remove State:/Network/Service/${PSID}/SMB
+ quit
+EOF
+else
+ scutil > /dev/null <<-EOF
+ open
+ get State:/Network/OpenVPN/OldSMB
+ set State:/Network/Service/${PSID}/SMB
+ quit
+EOF
+fi
+
+logMessage "Restored the DNS and SMB configurations"
+
+set +e # "grep" will return error status (1) if no matches are found, so don't fail if not found
+new_resolver_contents="$( grep -v '#' < /etc/resolv.conf )"
+set -e # resume abort on error
+logDebugMessage "DEBUG:"
+logDebugMessage "DEBUG: /etc/resolve = ${new_resolver_contents}"
+
+set +e # scutil --dns will return error status in case dns is already down, so don't fail if no dns found
+scutil_dns="$( scutil --dns)"
+set -e # resume abort on error
+logDebugMessage "DEBUG:"
+logDebugMessage "DEBUG: scutil --dns = ${scutil_dns}"
+logDebugMessage "DEBUG:"
+
+restore_ipv6 "$sRestoreIpv6Services"
+
+flushDNSCache
+
+# Remove our system configuration data
+scutil <<-EOF
+ open
+ remove State:/Network/OpenVPN/OldDNS
+ remove State:/Network/OpenVPN/OldSMB
+ remove State:/Network/OpenVPN/OldDNSSetup
+ remove State:/Network/OpenVPN/DNS
+ remove State:/Network/OpenVPN/SMB
+ remove State:/Network/OpenVPN
+ quit
+EOF
+
+if ${ARG_RESET_PRIMARY_INTERFACE_ON_DISCONNECT} ; then
+ resetPrimaryInterface
+fi
+
+logMessage "End of output from ${OUR_NAME}"
+logMessage "**********************************************"
+
+exit 0