Skip to main content
RunBook Academy

OPNsenseXX · VPN FundamentalsVPN fundamentals

VPN routing and tunnel interfaces — putting the tunnel inside the routing table

Intermediate⏱ ~14 minifconfignetstatroutetcpdumppfctl

What you'll learn

  • Explain how a VPN tunnel becomes a routing interface with its own subnet
  • Read the routing table after a tunnel comes up and identify the tunnel routes
  • Distinguish split-tunnel and full-tunnel routing for remote access
  • Recognise the routing failures that break VPN traffic — wrong routes, MTU, asymmetric routing
  • Configure tunnel routing deliberately on OPNsense

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-14

Not yet marked complete on this device.

A VPN tunnel is not just a secure pipe. To the routing table, it is a virtual interface with its own subnet — a point-to-point link that carries traffic to and from the inside network. The moment a tunnel comes up, OPNsense installs routes that send traffic destined for the remote subnet through the tunnel interface. The moment those routes are wrong, the tunnel is up, the encryption works, the authentication succeeds, and traffic still does not flow.

This lesson covers how a tunnel becomes a routing interface, how OPNsense installs routes for the tunnel subnet, how policy routing interacts with VPN traffic, and the production routing failures that break otherwise-valid tunnels.

The tunnel as a virtual interface

Every VPN implementation on OPNsense produces a virtual interface. WireGuard creates a wgN interface (e.g. wg0). IPsec creates an encN interface for route-based configurations (sometimes called VTI — Virtual Tunnel Interface) or installs the routes implicitly for policy-based configurations. OpenVPN creates a ovpnN interface.

Each interface has an IP address (the local tunnel endpoint), a peer IP (the remote tunnel endpoint), and behaves like any other point-to-point link from the routing table’s perspective:

Read-only / Safeifconfig wg0
$ ifconfig wg0
wg0: flags=80d1<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1420
  options=80000<LINKSTATE>
  inet 10.99.0.1 --> 10.99.0.2 netmask 0xffffff00
  inet6 fe80::1%wg0 prefixlen 64 scopeid 0x9
  groups: wg

Illustrative output

The MTU is the most important operational detail. A tunnel interface has overhead — WireGuard adds 32 bytes (UDP header + WireGuard header + Poly1305 authentication tag), IPsec ESP in tunnel mode adds 50-70 bytes depending on the cipher. The effective MTU on the tunnel interface is the underlying MTU minus the overhead. With a 1500-byte underlying path, a WireGuard tunnel has an MTU of 1420; an IPsec ESP-AES-GCM tunnel has an MTU of approximately 1440.

The MTU matters because traffic that exceeds it is fragmented or dropped. Most operating systems handle fragmentation gracefully for IPv4, but IPv6 does not fragment at all — and ICMP “packet too big” messages that drive path MTU discovery are sometimes blocked by intermediate firewalls. The result: a tunnel that carries small packets fine and hangs at sizes above the effective MTU.

Routes the firewall installs

When the tunnel comes up, OPNsense adds routes to the routing table. For a site-to-site tunnel between 10.0.0.0/24 (local) and 10.1.0.0/24 (remote), the firewall installs a route that sends traffic for 10.1.0.0/24 through the tunnel interface.

Read-only / Safetunnel routes
$ netstat -rn | grep -E 'wg0|10.1.0'
Destination        Gateway            Flags     Netif
10.1.0.0/24         10.99.0.2          UGS       wg0
10.99.0.0/24        link#9             U         wg0

Illustrative output

The route has three flags that matter:

  • U (Up): the route is active and the interface is up.
  • G (Gateway): the route goes through a gateway (the remote tunnel endpoint), not a directly-attached network.
  • S (Static): the route was added by configuration, not learned dynamically.

A static route is the right answer for site-to-site tunnels — the remote subnet does not move, the operator does not want a routing protocol to make the decision, and the configuration should be deliberate. For remote access with many peers, the routes are still static (the peer’s AllowedIPs becomes the route), but they are added per-peer rather than per-tunnel.

Split-tunnel vs full-tunnel

Remote-access VPNs have a routing choice the operator has to make deliberately:

Split-tunnel. The VPN only carries traffic destined for the corporate network. Traffic to the Internet goes directly from the client to the Internet, bypassing the VPN. The client’s AllowedIPs on WireGuard (or the route push on OpenVPN) lists only the corporate subnets.

Full-tunnel. The VPN carries all the client’s traffic. Traffic to the Internet goes from the client to the firewall, through the VPN, and out the firewall’s WAN. The client’s AllowedIPs is 0.0.0.0/0 (or the equivalent catch-all).

PatternProsCons
Split-tunnelLower VPN bandwidth; faster client Internet; less firewall loadSplits the trust model — corporate traffic is filtered, Internet traffic is not
Full-tunnelAll client traffic is filtered by the firewall; consistent logging; DLP and IDS see everythingHigher VPN bandwidth; firewall becomes the bottleneck; client Internet depends on firewall WAN

The right answer depends on the threat model. Split-tunnel is the common production choice for technical staff whose endpoint is itself trusted (managed laptop with corporate antivirus and EDR); the firewall filters corporate traffic, and the client’s own protections handle Internet traffic. Full-tunnel is the right choice for untrusted endpoints or compliance regimes that require all traffic to be inspected.

Policy routing and VPN traffic

VPN traffic interacts with policy routing in two ways that produce recurring production incidents.

VPN traffic must not be policy-routed through the WAN. When a multi-WAN firewall has a policy-routing rule that says “LAN to any → WAN gateway group”, the rule matches VPN-destined traffic too — and tries to send it through the WAN gateway. The packet leaves the firewall’s WAN interface, never reaches the VPN peer, and is lost.

The fix is a before-rule that matches the VPN subnet with gateway = default. The before-rule fires first, the traffic is routed through the tunnel interface, and the policy-routing rule never matches.

Asymmetric routing with split-tunnel. A client with split-tunnel reaches 10.0.0.50 (server) via the VPN. The server responds to 10.0.0.50; the response goes to the client’s tunnel address (10.99.0.5). If the server has a route back through the VPN for the tunnel subnet, the response works. If the server has a default route that goes somewhere else, the response is misrouted.

Split-tunnel deployments must ensure the server-side routing matches the client-side. The operator who adds a VPN without verifying the return path finds that “the VPN works for some hosts and not others” — the diagnostic that resolves it is the routing table on the server, not the VPN.

MTU and the silent failure

MTU on a tunnel interface is set automatically (the VPN implementation picks a value based on the underlying interface MTU and the overhead), but the operator can override it. The common production failure: a tunnel that carries small packets and 1,500-byte packets fine but fails at 1,400 bytes, or hangs at the IPv6 minimum MTU of 1,280.

The diagnostic is a packet capture with packet sizes:

Read-only / Safeping with DF
$ ping -c 3 -s 1400 -M do 10.1.0.50
PING 10.1.0.50 (10.1.0.50): 1400 data bytes
1480 bytes from 10.1.0.50: icmp_seq=0 ttl=64 time=12.4 ms
1480 bytes from 10.1.0.50: icmp_seq=1 ttl=64 time=11.8 ms
1480 bytes from 10.1.0.50: icmp_seq=2 ttl=64 time=12.1 ms
--- 10.1.0.50 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 11.800/12.100/12.400/0.245 ms

Illustrative output

The -M do flag tells the ping not to fragment. If the path cannot carry the packet, the ping fails with “message too long, mtu=N”. That MTU value is the path MTU; configuring the tunnel MTU and the source host’s MTU to match eliminates the failure.

Summary

  • A VPN tunnel is a virtual interface with its own IP address, its own MTU, and its own subnet.
  • OPNsense installs routes for the remote subnet when the tunnel comes up; the routes are withdrawn when the tunnel goes down.
  • Split-tunnel routes only corporate subnets through the VPN; full-tunnel routes all client traffic. The choice is policy, not technical.
  • Policy-routing rules on a multi-WAN firewall must include a before-rule for VPN traffic, or they will mis-route the VPN through the WAN.
  • Tunnel MTU is lower than the underlying path MTU; mismatch produces silent failures for large packets.

Knowledge check · 4 questions

  1. Q1. A WireGuard tunnel interface shows mtu 1420. An HTTP GET over the tunnel hangs at 1300 bytes of payload but works at 800 bytes. What is the most likely cause?

  2. Q2. A multi-WAN firewall has a policy-routing rule that matches LAN to any and uses a gateway group. Without a before-rule for the VPN subnet, the VPN traffic will be policy-routed through the WAN gateway.

  3. Q3. Which of the following are correct statements about VPN routing? Select all that apply.

  4. Q4. A WireGuard tunnel is up, the handshake is successful, the firewall rules allow the traffic, but hosts behind the firewall cannot reach hosts behind the remote peer. What is the most likely cause?

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