State Machine Overview
The tunnel state machine manages the lifecycle of VPN connections:Except for explicitly allowed traffic, all network packets are blocked in every state. The sections below describe what is allowed; everything else is blocked.
Always-Allowed Traffic
The following traffic is allowed or blocked independent of state:1. Loopback Traffic
All traffic on loopback adapters is always allowed:127.0.0.0/8(IPv4)::1(IPv6)
2. DHCP Traffic
DHCPv4 and DHCPv6 are always allowed for network configuration: DHCPv4:- Outgoing UDP:
*:68→255.255.255.255:67(client to server) - Incoming UDP:
*:67→*:68(server to client)
- Outgoing UDP:
[fe80::]/10:546→[ff02::1:2]:547and[ff05::1:3]:547 - Incoming UDP:
[fe80::]/10:547→[fe80::]/10:546
3. Neighbor Discovery Protocol (NDP)
A subset of NDP is allowed for IPv6 operation:- Router Solicitation (ICMPv6 type 133, code 0):
- Outgoing to
ff02::2
- Outgoing to
- Router Advertisement (ICMPv6 type 134, code 0):
- Incoming from
fe80::/10
- Incoming from
- Redirect (ICMPv6 type 137, code 0):
- Incoming from
fe80::/10
- Incoming from
- Neighbor Solicitation (ICMPv6 type 135, code 0):
- Outgoing to
ff02::1:ff00:0/104andfe80::/10 - Incoming from
fe80::/10
- Outgoing to
- Neighbor Advertisement (ICMPv6 type 136, code 0):
- Outgoing to
fe80::/10 - Incoming from any source
- Outgoing to
4. Allow LAN Setting
If the “Allow LAN” setting is enabled, additional traffic is allowed: Private Networks (Bidirectional):10.0.0.0/8172.16.0.0/12192.168.0.0/16169.254.0.0/16(Link-local IPv4)fe80::/10(Link-local IPv6)fc00::/7(Unique local address)
224.0.0.0/24(Local subnet IPv4)239.0.0.0/8(Administratively scoped IPv4 - SSDP, mDNS)255.255.255.255/32(Local broadcast)ff01::/16throughff05::/16(Various IPv6 multicast scopes)
- Incoming UDP:
*:68→255.255.255.255:67 - Outgoing UDP:
*:67→*:68
5. Mullvad API Access
The firewall allows traffic to the Mullvad API in all states:- Connected state: API traffic only allowed inside the tunnel
- Other states: API traffic bypasses the firewall
- Windows: Only Mullvad service and problem report tool can reach API in blocking states
- macOS/Linux: All processes running as root can reach API in blocking states
6. Packet Forwarding (Linux Only)
On Linux, situations that permit incoming or outgoing traffic also allow that traffic to be forwarded. All other forward traffic is rejected.State: Disconnected
The Disconnected state is the initial state when the daemon starts.When Active
- System boot (unless auto-connect is enabled)
- After user explicitly clicks disconnect/cancel
- NOT active during server changes or unexpected tunnel failures
Security Behavior
Disconnected state behaves differently based on the “Lockdown mode” setting: Without Lockdown Mode (Default):- No firewall rules enforced
- Traffic flows freely as if daemon wasn’t running
- Normal internet access without VPN
- Behaves like Error state
- Blocks all traffic except always-allowed exceptions
- No internet access without VPN connection
The Disconnected state is the only state where the app doesn’t enforce firewall rules by default. This is intentional—when you explicitly disconnect, you regain normal internet access.
Allowed Traffic
Without lockdown mode:- Everything - No firewall restrictions
- Only the always-allowed traffic
Typical Duration
- Initial state at daemon start
- Remains until user requests connection
- Returns only when user explicitly disconnects
State: Connecting
The Connecting state is active while establishing a VPN tunnel.When Active
- User requests connection
- Automatic reconnection after tunnel loss
- Server change initiated by user
- Setting change requires tunnel restart
Security Behavior
Strict firewall rules allow only tunnel establishment traffic:Allowed Traffic
- Always-allowed traffic (loopback, DHCP, NDP, etc.)
- VPN server connection:
- Traffic to VPN server IP + port + protocol
- Outgoing tunnel establishment packets
- Incoming responses to tunnel traffic
- Process restrictions apply (see below)
- Mullvad API access (bypasses firewall)
Process/User Restrictions
To prevent fingerprinting, only privileged processes can reach the VPN server: Windows:- Only processes from specific paths (e.g.,
mullvad-daemon.exe) - Prevents unprivileged apps from leaking to VPN server IP
- Only processes running as
root
- Only packets with firewall mark
0x6d6f6c65set, OR - Only processes running as
root(fallback if marks not supported)
DNS Behavior
DNS requests are blocked in the Connecting state.Example Scenarios
Single-hop WireGuard:- Allow: UDP to
198.51.100.10:51820from privileged processes - Block: Everything else
- Entry server:
203.0.113.50:51820 - Exit server:
198.51.100.10:51820 - Allow: UDP to entry server
203.0.113.50:51820only - Block: Direct communication with exit server
- Block: Everything else
Transition to Connected
When using WireGuard, traffic inside the tunnel is permitted immediately after the tunnel device is created. The state transitions to Connected once the tunnel is verified working.Typical Duration
Few seconds to establish tunnel (varies by network conditions).State: Connected
The Connected state is active when a VPN tunnel is fully established and verified working.When Active
- After Connecting state successfully establishes tunnel
- Remains active until:
- User requests disconnect/quit
- User requests server change
- Setting change requires tunnel restart
- Tunnel goes down unexpectedly
Security Behavior
All traffic must flow through the encrypted tunnel:In the Connected state, traffic is only allowed through the tunnel interface. Traffic not using the tunnel is blocked, ensuring no leaks.
Allowed Traffic
- Always-allowed traffic (loopback, DHCP, NDP, etc.)
- Tunnel traffic:
- All traffic in both directions over the tunnel interface
- Except: DNS to non-approved servers (see below)
- VPN server connection:
- Traffic to/from VPN server IP + port + protocol
- Required to maintain the tunnel
- Same process restrictions as Connecting state
- Mullvad API access (inside tunnel only in this state)
DNS Behavior
DNS is strictly controlled in the Connected state: Allowed:- DNS to the gateway IP on the tunnel interface (default)
- DNS to custom DNS servers (if configured)
- DNS to any other address
- Both TCP and UDP port 53 blocked for non-approved destinations
- Public custom DNS: Queries go through tunnel
- Private IP custom DNS (
192.168.0.0/16, etc.): Bypass tunnel - Loopback custom DNS (
127.0.0.1,::1): Bypass tunnel
Example: Connected State Traffic
Allowed:- HTTPS to any server (through tunnel interface
wg-mullvad) - DNS to
10.66.0.1(tunnel gateway) - UDP to
198.51.100.10:51820(maintain tunnel)
- DNS to
8.8.8.8(would leak DNS) - Direct traffic not using tunnel interface
- Any traffic trying to bypass the tunnel
Typical Duration
Remains active as long as VPN is connected and working (hours, days, or until user disconnects).State: Disconnecting
The Disconnecting state is active while closing a VPN tunnel.When Active
- User requests disconnect
- User requests quit
- User requests server change (closing old tunnel before opening new)
- Setting change requires closing tunnel
Security Behavior
The Disconnecting state does not apply its own security policy.The Disconnecting state maintains the firewall rules from the previous state. It’s a short transition while waiting for the tunnel to close cleanly.
Allowed Traffic
Same as the previous state (typically Connected or Connecting).Typical Duration
Very brief (milliseconds to a few seconds) while tunnel closes and cleans up.Transitions From Disconnecting
The Disconnecting state can transition to:- Disconnected: User requested disconnect/quit
- Connecting: User requested server change or reconnect
- Error: Problem occurred during disconnection
State: Error
The Error state is active when a problem prevents establishing a tunnel.When Active
- Account runs out of time
- Computer is offline
- Internal error parsing system config (routing, DNS, etc.)
- Tunnel fails and cannot reconnect
- Any unrecoverable error in Connecting or Connected states
Security Behavior
Strict blocking to prevent leaks when tunnel cannot be established:Allowed Traffic
Only the always-allowed traffic:- Loopback traffic
- DHCP (IPv4 and IPv6)
- NDP subset
- Allow LAN traffic (if enabled)
- Mullvad API access
- All regular application traffic
- DNS requests
- Everything not explicitly allowed above
Rationale
When the app can’t establish a tunnel but the user has requested VPN protection, it’s better to have no internet access than to leak unencrypted traffic. This is the “fail closed” principle.User Action Required
To regain internet access from Error state:- Fix the underlying issue (add time, restore connectivity, etc.), OR
- Explicitly click disconnect in the app
Firewall Integration Failure
Typical Duration
- Remains active until user fixes the issue or explicitly disconnects
- Can last indefinitely if user doesn’t take action
State Machine Inputs
The tunnel state machine reacts to two types of inputs:Commands
Commands sent to the state machine:- Connect: Establish a secure VPN connection
- Disconnect: Tear down VPN and return to Disconnected state
- Allow LAN: Enable/disable local network sharing
- Block when disconnected: Enable/disable lockdown mode
External Events
Events the state machine listens for:- Tunnel is Up: Tunnel monitor reports tunnel is working
- Tunnel is Down: Tunnel monitor reports tunnel disconnected
- Tunnel Monitor Stopped: Communication to tunnel monitor lost
- Is Offline: OS is not connected to any network
State Machine Outputs
Every state change produces aTunnelStateTransition output:
- Disconnected: No metadata
- Connecting: Includes endpoint being connected to
- Connected: Includes endpoint connected to
- Disconnecting: Includes action after disconnected:
- Nothing: Proceed to Disconnected
- Block: Proceed to Error
- Reconnect: Proceed to Connecting
- Error: Includes error cause and whether blocking succeeded
Security Guarantees Summary
| State | Regular Traffic | DNS | VPN Server | API |
|---|---|---|---|---|
| Disconnected | ✅ Allowed (default) ❌ Blocked (lockdown) | ✅ Allowed (default) ❌ Blocked (lockdown) | ❌ Blocked | ✅ Bypass |
| Connecting | ❌ Blocked | ❌ Blocked | ✅ Privileged only | ✅ Bypass |
| Connected | ✅ Tunnel only | ✅ Tunnel only | ✅ Privileged only | ✅ Tunnel only |
| Disconnecting | (Previous state) | (Previous state) | (Previous state) | (Previous state) |
| Error | ❌ Blocked | ❌ Blocked | ❌ Blocked | ✅ Bypass |
Always-allowed traffic (loopback, DHCP, NDP, Allow LAN) is permitted in all states.
Testing State Transitions
You can observe state transitions: CLI:- Current state displayed in the app header
- Color coding indicates state (green = connected, yellow = connecting, red = error)
Related Documentation
- Leak Protection - Detailed leak prevention in each state
- Kill Switch - Always-on protection mechanism
- Firewall Integration - How states apply firewall rules
- Architecture - Tunnel state machine implementation
Source Code References
- Tunnel state machine:
talpid-core/src/tunnel_state_machine/ - State definitions:
mullvad-types/src/states.rs - Architecture documentation:
docs/architecture.md(source:72-188)