Setup

What a VPN kill switch actually does

7 min read

A kill switch is a firewall rule, not a watchdog waiting for the connection to drop. The client writes a block-by-default rule set onto the device: deny everything, then allow the VPN server's address and the tunnel interface. Nothing has to detect a failure — the physical interface never had permission to carry your traffic.

Two implementations, and they fail differently

Block-by-default firewall rules. Filters go into the OS firewall engine itself: the Windows Filtering Platform, packet filtering or a Network Extension on macOS, nftables on Linux, the system VPN lockdown on Android. Enforcement is in the kernel, so if the tunnel process dies the rules stay loaded and traffic still goes nowhere.

An application-level watchdog. The client samples the tunnel — handshake age, a heartbeat, the adapter's link state — and once it decides the tunnel is gone, tears it down or asks the OS to disconnect. Something fails, something notices, and only then is anything blocked. The interval between those events is real traffic on the physical interface.

Where the gaps live

  • Boot until the client starts. The machine has a link and a default route before the VPN service is scheduled. Filters installed persistently at boot close this window; rules added when the tunnel comes up do not.
  • Sleep and wake. The link comes back first, the tunnel renegotiates after, and mail, sync and push reconnect in between.
  • Switching networks. Wi-Fi to cellular means a new interface and a new default route. Rules pinned to the interface that existed when they were written do not automatically cover the new one.
  • The client crashing, hanging, or updating. Firewall rules survive it. A watchdog is the thing that just died.

Be skeptical of any specific number for these windows. It depends on the device, on whether the app was cold-started, and on how fast the server answers the first handshake. Ask what closes the window.

LAN exceptions, and what they cost

A strict rule also blocks the printer, the NAS and the router's admin page at 192.168.1.1, so most clients ship an exception for private ranges, link-local and multicast. Apple exposes a switch to exclude local networks, on by default on iOS. WireGuard for Windows goes the other way: with a full tunnel and the kill switch on, the LAN is blocked too, and switching it off is the only supported way back. The exception is written in terms of addresses, not trust: a network you did not build hands out the same ranges.

The address family nobody blocked

The classic hole is a rule set that exists in iptables and not in ip6tables, or a tunnel with AllowedIPs = 0.0.0.0/0 and no ::/0. On an IPv4-only network nothing happens and the setup looks fine for months. On dual-stack, a destination publishing both record types is usually reached over IPv6, on the physical interface, while the kill switch guards an address family nobody is using.

A second category is traffic that never reaches the filter at all. The wg-quick manual says as much about its own sample kill-switch rule: most DHCP traffic still gets through, because DHCP clients typically use PF_PACKET sockets, which bypass netfilter. Platform-level exemptions exist too, and they change between releases.

Android: two switches, not one

Android gives a consumer app the strongest version of this: the block is enforced by the system, not the app. Always-on VPN (Android 7 and later) restarts the VPN service after boot and keeps it running. Block connections without VPN (Android 8 and later, sometimes called lockdown) drops traffic outside the tunnel. The first alone gives reconnection, not blocking.

  1. 1Open Settings and find the VPN screen, usually under Network & internet; wording differs by manufacturer.
  2. 2Tap the settings icon next to your VPN app's entry, not the entry itself.
  3. 3Turn on Always-on VPN. If the toggle is unavailable, the app has not declared support for it.
  4. 4Turn on Block connections without VPN separately. This one is the kill switch.
  5. 5Reboot and confirm traffic is blocked before the app reports a connection.

One documented caveat: Android runs its own connectivity and captive-portal checks outside the tunnel, which is how it spots a network that wants you to log in. Reported publicly in 2022, closed as intended behavior: some VPN apps rely on those checks.

iPhone: the constraint is the platform

Apple's Always On VPN — the mode where the device refuses to move traffic unless the tunnel is up — is a managed-device feature. It needs a supervised device enrolled in mobile device management, a configuration profile to install it, and the built-in IKEv2 client to run it. An App Store app has no mechanism to install that rule. This is a platform boundary, not a provider cutting corners.

What a consumer app can do is mark the tunnel to include all networks, so the system drops traffic while the tunnel is unavailable, and add on-demand rules so it reconnects. That behaves like a kill switch most of the time, but it is not the managed rule: Apple documents the flag as routing all traffic through the tunnel with some exclusions, and the ones for cellular services, push notifications and nearby-device communication are on unless the app turns them off.

Desktop: the OS firewall underneath

On desktops the kill switch is a thin layer over what the OS already provides, which is why two clients speaking the same protocol can behave differently. The wg-quick manual's Linux example rejects any outbound packet that is neither leaving on the tunnel interface nor carrying the tunnel's firewall mark; a Windows client registers equivalent filters with the OS filtering engine.

Do not hand-edit firewall rules on a machine you reach over the network. A block-by-default rule applied over SSH kills the session that applied it, including the one you would use to undo it. Work at the console, or schedule an automatic revert first.

What a kill switch does not do

  • It does not conceal that a tunnel is in use. Whoever sees your link still sees an encrypted session to a server address, at the same times and volumes.
  • It does not help when the tunnel is up but routing is wrong: split tunneling, an app bound to one interface, a resolver queried outside the tunnel. The rules force traffic into the tunnel, not to where you assume it goes.
  • It does not retroactively protect what left during the window before it took effect.
  • It does nothing for other devices on the same network, and it is not a DNS check.

How to test one honestly

  1. 1Start a continuous ping to an outside address, so you can see the moment traffic stops.
  2. 2Do not press Disconnect. That is the cooperative path, and it proves nothing.
  3. 3Kill the tunnel process instead: end the task on Windows, kill -9 on macOS or Linux, force-stop the app on Android.
  4. 4Watch the ping. Anything still flowing is the gap, and the block lived in the app rather than the firewall.
  5. 5Reboot with the client set to start automatically, and compare when the network came up with when the tunnel did.
  6. 6Repeat against an IPv6 destination on a dual-stack network, then switch networks mid-transfer.

Does a kill switch guarantee that nothing ever leaves outside the tunnel?

No, and a page promising zero leakage is overstating it. A firewall rule blocks traffic only on the interfaces it covers, from the moment it is installed, for the address families it names.

Why can't an iPhone app install a real always-on kill switch?

Apple's Always On VPN is limited to supervised devices enrolled in mobile device management, delivered as a configuration profile for the built-in IKEv2 client. An App Store app has no API for it, so apps approximate it by tunneling all networks and reconnecting on demand.

Is Android's Always-on VPN the same as a kill switch?

No, they are two separate switches on the same screen. Always-on keeps the VPN service running; Block connections without VPN is what drops traffic outside the tunnel. Enable both, per VPN app.

My whole connection died after the VPN dropped. Is something broken?

That is usually the kill switch working. If the block persists after a normal disconnect, restarting the client clears the leftover rules; on Android, turn off the blocking toggle in the VPN settings screen.

Did this help?

Nothing follows from the answer; only we see it.

Send this to someone

Useful to anyone with the same problem.