Skip to main content
RunBook Academy

OPNsenseXXIII · VPN TroubleshootingRouting failures

VPN routing failures — when the tunnel is up but traffic does not reach the remote subnet

Advanced⏱ ~14 min🧪 Lab requiredswanctlwgroutenetstattcpdumppfctl

What you'll learn

  • Diagnose route-based IPsec tunnels where traffic does not reach the remote subnet
  • Diagnose policy-based IPsec tunnels where Phase 2 selectors miss traffic
  • Diagnose WireGuard AllowedIPs misconfigurations that block traffic
  • Identify asymmetric routing across multi-WAN and IPsec interactions
  • Apply the routing diagnostic workflow: route lookup, swanctl, wg show, tcpdump

Prerequisites

Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-15

Not yet marked complete on this device.

A VPN tunnel that is established but does not carry traffic is, by volume, the most common VPN failure mode. Phase 1 is up. Phase 2 SAs are ESTABLISHED. The byte counters in swanctl --list-sas are at zero. Or they tick upward on one side and never on the other. The cause sits in routing — the firewall’s table does not send traffic through the tunnel, or sends it the wrong way. This lesson covers the recurring routing failures for IPsec (route-based and policy-based) and WireGuard, the asymmetric-routing cases that arise in multi-WAN estates, and the diagnostic workflow that walks from the routing table to the live packet stream.

The routing failure landscape

Three routing failure modes dominate:

FailureIPsec route-basedIPsec policy-basedWireGuard
Tunnel is up, but traffic does not leaveRoute through the VTI is missingPhase 2 traffic selector misses the subnetAllowedIPs on the peer does not include the subnet
Tunnel is up, traffic leaves but never returnsRemote side has no return routeRemote side has no Phase 2 selector for our subnetRemote side’s AllowedIPs on the local peer is wrong
Tunnel is up, traffic flows both ways but only for some subnetsA second route is missing for additional subnetsA second Phase 2 selector is missingAllowedIPs on the right peer covers the subnet

The pattern in each case is “the tunnel is right but the routing is wrong”. The diagnostic finds the missing or misconfigured routing entry.

IPsec route-based: VTI not in the route lookup

A VTI is enabled, Phase 2 is ESTABLISHED, byte counters are zero. The diagnostic:

Read-only / Saferoute lookup via WAN
$ route -n get 10.1.0.50
route to: 10.1.0.50
destination: 10.1.0.0/24
interface: igb1
gateway: 198.51.100.1
     fib: 0
flags: <UP,DONE>
recvpipe  sendpipe  ssthresh  rtt,msec  mtu  1500

Illustrative output

route -n get 10.1.0.50 showing interface: igb1 (the WAN) instead of interface: ipsec0 (the VTI) is the failure pattern. The remote subnet is being routed through the WAN, so packets leave unencrypted, hit the peer’s WAN IP, the peer’s strongSwan does not understand them as ESP, the peer drops them silently.

The fix: under System → Routes → Configuration, add a static route for 10.1.0.0/24 with the gateway being the peer IP on the VTI (typically 10.10.10.2). After the route is added, route -n get 10.1.0.50 should return interface: ipsec0. Once this is in place, packets from the LAN destined for the remote subnet are routed through the VTI, encapsulated as ESP, and tunnel through.

IPsec route-based: VTI not assigned to an interface

A subtler failure mode: the Phase 2 entry has “Install Virtual Tunnel Interface” enabled, but the VTI has not been assigned to an interface under Interfaces → Assignments. The VTI exists in the kernel (ifconfig ipsec0 shows it) but it has no IP configuration and is not a routeable interface as far as PF is concerned.

The diagnostic:

ifconfig ipsec0
> ipsec0: flags=8010<POINTOPOINT,MULTICAST> metric 0 mtu 1400

The UP flag is missing; the interface is administratively down. Either Phase 2 is not ESTABLISHED (Layer 1 problem — go back to negotiation), or the VTI was enabled but not brought up. The fix: assign the VTI under Interfaces → Assignments, configure an IP, and ensure the corresponding ifconfig ipsec0 shows UP,RUNNING.

IPsec route-based: traffic leaves but doesn’t return

A VTI route exists on the local side. Packets from the LAN leave, get encapsulated, arrive at the remote side. But the remote side’s response never arrives back on the local side. The symmetric-routing signature:

  • swanctl --list-sas --no-headers shows byte counters increasing on the local outbound side and at zero on the local inbound side.
  • tcpdump -ni wan0 shows ESP packets leaving the local firewall (matching the outbound byte counter).
  • tcpdump -ni wan0 shows no ESP packets arriving at the local firewall.

The cause: the remote side does not know to send traffic back through the tunnel. The remote’s routing table does not include a route to the local LAN subnet via the VTI on the remote. Packets leaving the remote have a destination address in the local subnet, but the remote’s routing table routes them through its WAN (unencrypted, sent to the local firewall’s WAN IP), the local firewall’s IPsec daemon does not know what to do with them, PF drops them as no-state.

The fix is on the remote side: add a static route for the local subnet (10.0.0.0/24) with the VTI as gateway.

IPsec policy-based: Phase 2 selector misses

A policy-based tunnel does not use routes — it uses Phase 2 traffic selectors. A common failure pattern: traffic from 10.0.50.0/24 (a LAN subnet) should cross a policy-based tunnel to 10.1.0.0/24, but the Phase 2 selector only covers 10.0.0.0/24 (the LAN). The packets do not match any Phase 2 SA, and they fall through to whatever the firewall does with non-matching traffic (typically send through the WAN, where the remote does not understand them).

The diagnostic:

swanctl --list-sas --list-conns
> home-edge: ...
>   child home-edge-1, rekey_time: ...
>     local-ts: 10.0.0.0/24
>     remote-ts: 10.1.0.0/24

The local-ts is 10.0.0.0/24. Traffic from 10.0.50.10 does not match (the source 10.0.50.10 is in 10.0.50.0/24, not 10.0.0.0/24). The selector has to be widened to 10.0.0.0/16, or a second Phase 2 entry has to be added for 10.0.50.0/24.

The fix: edit the Phase 2 entry’s Local subnet, or add an additional Phase 2 entry for the missing subnet. Either way, re-trigger the negotiation (configctl ipsec reload) and confirm the SA’s traffic selector covers the new subnet.

WireGuard: AllowedIPs is the routing

WireGuard’s AllowedIPs is the routing table. A peer with allowed ips: 10.1.0.0/24 only carries traffic to 10.1.0.0/24. An operator who adds a new subnet 10.2.0.0/24 and expects it to flow through the existing tunnel gets zero transfer bytes and zero routing.

Read-only / Safewg show missing subnet
$ wg show wg0
interface: wg0
public key: <local-server-public-key>
listening port: 51820

peer: <remote-peer-public-key>
endpoint: 198.51.100.2:51820
allowed ips: 10.1.0.0/24
latest handshake: 1 minute, 23 seconds ago
transfer: 1.2 MiB received, 4.8 MiB sent
persistent keepalive: every 25 seconds

Illustrative output

The fix: update AllowedIPs on both ends. WireGuard’s AllowedIPs is a routing-table-like structure; both ends have to include the subnet for the routing to be symmetric.

Multi-WAN: route order and gateway groups

A multi-WAN deployment adds a routing twist: the firewall has a default route through one WAN and policy-based rules that send IPsec traffic through another. The IPsec tunnel may be bound to the wrong WAN, or the return traffic may not match the policy.

The diagnostic:

  • route -n get 10.1.0.50 returns the wrong interface.
  • pfctl -s rules | grep rtable shows the policy-routing assignments.

The fix:

  • For route-based IPsec: ensure the route to 10.1.0.0/24 has the VTI as next hop, regardless of WAN. Add the static route with the VTI as gateway; the WAN-specific routing is irrelevant for traffic that traverses the VTI.
  • For policy-based IPsec: the Phase 2 selectors do not interact with policy routing directly; the SA is invisible to the routing table. The operator who needs policy-routed policy-based IPsec has to convert to route-based first.

Asymmetric routing across the tunnel

A subtle failure: traffic from A to B crosses the tunnel; traffic from B to A takes a different path. The state is broken because the firewall expects a return packet through the tunnel and gets nothing.

The diagnostic:

tcpdump -ni ipsec0 -c 4 host 10.1.0.50
> 12:34:56.789012 10.0.0.50 > 10.1.0.50: ICMP echo request
> (no response)

tcpdump -ni igb1 -c 4 host 10.1.0.50
> 12:34:56.789013 10.1.0.50 > 10.0.0.50: ICMP echo reply

The echo reply arrives on the WAN (igb1), not the VTI. The remote side is routing the reply through its WAN to the operator’s WAN, where it arrives un-ESP-wrapped. The local firewall has no state for an ESP packet from the WAN to that destination, so it drops.

The cause: the remote side’s return route is not through the tunnel. The fix is on the remote side’s routing table.

The routing diagnostic workflow

For a tunnel up but no traffic flowing:

1. swanctl --list-sas
   → ESTABLISHED with byte counters rising: Layer 3 / Layer 4 problem
   → ESTABLISHED with byte counters at zero: routing problem on local or remote

2. route -n get <remote-host>
   → Egress interface is VTI (ipsec0 or wg0): routing is correct on local
   → Egress interface is WAN (igb1): local routing is missing the remote subnet

3. tcpdump -ni <vti_or_wg0> -c 4
   → Packets leave: routing local is correct; remote side is failing
   → No packets: local routing is the problem

4. tcpdump -ni <wan> 'esp or udp port 4500'
   → ESP packets leaving: encapsulation is happening
   → No ESP packets: encapsulation is failing (check Phase 2 entry, VTI binding)

5. Confirm remote side's routing table
   → The remote operator must check their route to <local-subnet> through their VTI

Summary

  • For route-based IPsec, route -n get <remote> must show the VTI as egress.
  • For policy-based IPsec, Phase 2 selectors must cover the protected subnets on both sides.
  • For WireGuard, AllowedIPs is the routing table; both ends have to include the new subnet.
  • Asymmetric routing (traffic takes one path there, a different path back) produces state-table misses and silent failures.
  • When traffic leaves but does not return, the cause is the remote side’s routing, not the local side’s.
  • The diagnostic workflow: confirm SAs up, check route lookup, capture on tunnel interface, capture on WAN for ESP, ask the remote operator to confirm their routing.

Knowledge check · 4 questions

  1. Q1. A route-based IPsec tunnel has Phase 1 and Phase 2 ESTABLISHED, but byte counters are zero and packets from the LAN do not cross the tunnel. `route -n get 10.1.0.50` returns interface igb1 (the WAN). What is the fix?

  2. Q2. WireGuard AllowedIPs is a routing-table-like setting that controls both what subnets the peer can send traffic from and what subnets the peer will route through this interface.

  3. Q3. Which of the following are valid routing failure modes for IPsec route-based VPN with a VTI? Select all that apply.

  4. Q4. A site-to-site tunnel has Phase 1 and Phase 2 ESTABLISHED, byte counters are zero, the local route lookup uses the VTI, the remote operator confirms their route is correct, tcpdump on the local VTI shows outgoing packets but no incoming packets. Where is the failure?

Passing score: 75%. Answers are checked in this browser.