Two designs promise the same thing: when the tunnel drops, nothing leaves in the clear. One runs a script at teardown and cuts interfaces. The other leaves a firewall rule in force and never asks the VPN client for anything. They differ in who has the privilege to act, in what happens during the gap, and in how the machine gets back online afterwards. Comparing them on those three points is more useful than arguing about which is stricter.

The same job through two mechanisms

The client can run hooks when the tunnel comes up and when it is torn down, provided the profile permits script execution. That hook runs inside the client's lifecycle, at the moment the connection is closing. A firewall rule, by contrast, is owned by the system and does not care whether the client is running, crashed or was killed.

PropertyTeardown scriptFirewall unit
Runs when the client is killedNoYes
Needs privilege at teardown timeUsually yesConfigured once, at boot
Acts on the whole machineOften, including recovery pathsOnly on the flows it matches

That table is the whole argument. A script that only runs on a graceful shutdown covers the case you were least worried about; the case that matters is the crash or the network disappearing, and neither produces a clean teardown.

What the teardown hook can and cannot do

The documented pattern walks the network interfaces and brings down everything except loopback. With the physical device down, nothing can escape outside the tunnel, which is exactly the intent.

#!/bin/sh
for dev in /sys/class/net/*; do
  name=$(basename "$dev")
  [ "$name" = lo ] || ip link set dev "$name" down
done

It also takes down the local network, any service the machine hosts, and the path you would use to fix the problem. On a laptop the wireless device sometimes needs a manual toggle afterwards, so a brief outage becomes a repair session. Worse, the hook may not be permitted to do any of it: when the client drops privileges, the teardown script runs as the unprivileged account, and every interface change fails with a permission error written at the one moment nobody reads the log.

Check how the client is started before trusting the hook. A script that works when run by hand as root proves nothing about the service that starts at boot.

What the firewall rule does differently

A rule that permits only tunnel traffic keeps working when the client process is gone, because the kernel does not depend on that process. The rule is also narrower: it blocks exactly the flows it matches and leaves loopback, the local subnet and the recovery path alone, which is why it does not strand the machine.

The trade is that the rule has to be written and persisted by whoever owns the host firewall, and it has to name the tunnel device the client actually creates. That means the rule and the profile have to be maintained together; a renamed interface leaves a firewall that blocks everything and explains nothing.

Neither mechanism makes the other redundant. A firewall rule that is never reloaded after an edit is as fictional as a script that never runs.

persist-tun decides whether a gap exists

When the tunnel device survives a disconnect, the routes that point into it also survive. Traffic is then dropped rather than redirected, so the default route does not fall back to the physical gateway. This is the behaviour that makes a leak unlikely even before any firewall rule is involved.

Without that setting, the device is removed and the routes with it, and the default route can resolve back to the physical gateway. Whether it does depends on the platform and the client, which is precisely why the state has to be observed rather than assumed. Treat the setting as part of the kill switch, not as a performance option.

Keep the reconnection path alive, then test four states

A strict block can also prevent the client from reconnecting, because the client still needs a route to the server through the physical gateway while everything else is denied. Install a host route for that one address before the tunnel comes up, and resolve the name first, since DNS may be blocked by the time you need it.

ip route add 198.51.100.20/32 via 192.168.0.1 dev wlan0

Then verify the states rather than the label. Exercise four moments deliberately: a cold start with no tunnel, a healthy session, a drop nobody requested, and the session after it recovers. At each moment read the default route and make one request whose exit address is visible. An application that gives up while the tunnel is down says nothing about a mail client or an updater, so repeat the last check with one background application. Write the rule, the interface names and the recovery steps down, because a kill switch nobody can verify is a rumour.

Erthyglow kevrennek