Skip to content

Instantly share code, notes, and snippets.

@tomkinsc
Created October 15, 2022 22:25
Show Gist options
  • Save tomkinsc/3a60ccab61feeec8583baabfec8418d5 to your computer and use it in GitHub Desktop.
Save tomkinsc/3a60ccab61feeec8583baabfec8418d5 to your computer and use it in GitHub Desktop.
VPN killswitch to auto re-enable the native VPN built in to macOS if it drops and is not active, or if the Wi-Fi is turned on and connects to a "non-home" network

Native VPN killswitch for macOS

This creates a daemon job to watch VPN and Wi-Fi state to ensure the native macOS VPN is active if it drops and is no longer active, or if there is a change in Wi-Fi state (as in the case of Wi-Fi being turned on).

Install instructions

  • customize the string variables at the top of vpn-killswitch.sh to the name of your Wi-Fi network and VPN configuration
  • Place the vpn-killswitch.sh file somewhere, make it executable (chmod u+x vpn-killswitch.sh)
  • alter the full path to whereever the script was placed in the on-network-change.job.plist file
    • (Change the line with /Users/MYUSERNAME/full/path/to/vpn-killswitch.sh)
  • Save on-network-change.job.plist to within ~/Library/LaunchAgents/
  • load the launch agent to run when needed via launchctl load -w ~/Library/LaunchAgents/on-network-change.job.plist

Caveats

  • One of the files being watched, /private/var/run/ppp0.pid, may only reflect the first of several VPNs, if multiple are present. Change as appropriate.
  • The other file being watched, /private/var/run/resolv.conf can change for other reasons (ex. whenever the DNS servers are updated). It's being used here because it's an easy file for the launch agent to watch without polling via a separate command.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>on_vpn_change</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/MYUSERNAME/full/path/to/vpn-killswitch.sh</string>
</array>
<key>StandardErrorPath</key>
<string>/tmp/on_vpn_change.err</string>
<key>StandardOutPath</key>
<string>/tmp/on_vpn_change.out</string>
<key>WatchPaths</key>
<array>
<string>/private/var/run/ppp0.pid</string>
<string>/private/var/run/resolv.conf</string>
</array>
</dict>
</plist>
#!/bin/bash
# if there is a change to the wifi or vpn state, this script will be triggered and ensure the native VPN is active if it drops or there is a change in Wi-Fi state
# it does not enforce this if on the home network
# Customize these values as appropriate
vpn_name="My VPN" # this is what the VPN is called in System Preferences -> Network; "rename" to copy the current name exactly
homenetwork_ssid="MyHomeWiFiNetworkName"
# ===========================================
# if VPN is enabled
if (scutil --nc list | grep Connected &> /dev/null); then
echo "VPN on"
#networksetup -setairportpower Wi-Fi on # incorrect?
#networksetup -setairportpower en0 on
else
echo "VPN off"
networkssid="$(/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport -I | awk -F' SSID: ' '/ SSID: / {print $2}')"
# if we're not at home
if [[ "$networkssid" != "$homenetwork_ssid" ]]; then
wifistate="$(networksetup -getairportpower en0 off | cut -d':' -f2 | sed 's/ //g')"
# if the wifi is on turn on the VPN on, or failing that disable wifi
if [[ "$wifistate" == "On" ]]; then
networksetup -connectpppoeservice "$vpn_name" || networksetup -setairportpower en0 off
fi
fi
fi
# This relies on a macOS launch agent to watch files responsible for changes in the VPN and Wi-Fi state.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment