I got a question from a reader about how to test if a VPN connection is active and terminate an app if it isn’t. There’s probably a way to do this with Keyboard Maestro or BetterTouchTool or something, but to keep things interesting, I wanted to find a way to do it with just shell scripts.

Update: after publishing this I found a better way to do it, see the next post.

VPN connection indicators

I think the easiest, most universal way to determine if a VPN is connected is by searching for a specific interface that changes when connected. When I connect Nord, for example, I get a new network interface called utun4. I don’t know how universal this is, but you can figure out what changes happen in interfaces by comparing the output of ifconfig when the VPN is connected vs. disconnected.

The following instructions are Mac-specific, using the tools pbcopy and pbpaste to access the system clipboard rather than creating multiple files. In fact, I’m not even positive ifconfig is available on all systems, so if anyone wants to contribute instructions for other platforms, please do.

Caveat: I do not understand the ifconfig command at all and have never used it for anything but listing network interfaces. There may be a far more succinct way to do the following.

To determine the interface changes on a Mac:

In Bash:

# Disconnect VPN
$ ifconfig -a | pbcopy
# Connect VPN
$ diff <(ifconfig -a) <(pbpaste)

In Zsh:

# Disconnect VPN
$ ifconfig -a | pbcopy
# Connect VPN
$ diff =(ifconfig -a) =(pbpaste)

In Fish:

# Disconnect VPN
$ ifconfig -a | pbcopy
# Connect VPN
$ diff (ifconfig -a|psub) (pbpaste|psub)

The result should look something like:

> utun4: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1420
>       inet --> netmask 0xffff0000
>       nd6 options=201<PERFORMNUD,DAD>

Testing for connection

Now you have an interface name (utun4 above) that you can grep for to test whether the VPN is active. A simple loop in a Bash script will allow you to take action when the connection is disconnected. This little script assumes the VPN is connected when it starts, loops until the network interface we’re looking for disappears (grep --count returns 0), then executes the command after the loop.


while true; do
  RES=`ifconfig -a | grep -c utun4`
  [[ $RES == 0 ]] && break
  sleep 1

say "VPN disconnected"

Perfect if you wanted to, say, stop a torrent client if the VPN wasn’t active. You could embelish it into a launch script that checked for the VPN first, launching an app when the VPN is connected, then polled for the VPN to be disconnected, terminating the app if it is.

Of course, the simple ifconfig -a | grep -c utun4 line could be used as part of a BetterTouchTool widget to display an alert on your Stream Deck when the VPN was connected, or to run any kind of automations on a polling basis. If I had more complex applications for this, I’d switch over to using BetterTouchTool.