Project

General

Profile

Actions

Bug #17044

open

Firewall-originated IKEv2 traffic (charon) egresses via wrong WAN interface despite correct static route and Manual Outbound NAT rules, in multi-WAN + VTI IPsec configuration

Added by Samuel GARÇON 1 day ago.

Status:
New
Priority:
Very High
Assignee:
-
Category:
IPsec
Target version:
-
Start date:
Due date:
% Done:

0%

Estimated time:
Release Notes:
Default
Affected Plus Version:
26.07
Affected Architecture:
8200

Description

Summary

On a multi-WAN system with an IPsec (IKEv2, VTI/routed mode, BGP) tunnel to an Azure VPN Gateway explicitly bound to a non-default WAN interface, locally-generated IKE_SA_INIT packets (both charon's responses to peer-initiated exchanges, and charon's own initiated IKE_SA_INIT requests) intermittently egress via the default (primary) WAN interface instead of the WAN interface the Phase 1 connection is explicitly bound to — despite:

A correct, present, and actively-used static host route for the peer IP via the intended WAN's gateway
Explicit Phase 1 interface binding to the non-default WAN
Correct, verified Manual Outbound NAT catch-all rules per interface
No floating firewall rules present
Strict Interface Binding disabled

This causes the peer (Azure) to never acknowledge IKE_SA_INIT responses/requests, since they arrive from an unexpected source IP (the primary WAN's public IP rather than the configured/expected secondary WAN IP), resulting in permanent IKE_SA_INIT retry loops and total inability to establish the tunnel.

Environment

pfSense Plus 26.07-RELEASE (also reproduced pre-upgrade on 26.03.1-RELEASE)
2x WAN interfaces, both DHCP (GPON/fibre), different ISPs/subnets:
WAN_NET_GPON_832_FIBRE_PRINCIPALE_DHCP — default gateway (Tier 1)
WAN_NET_GPON_832_FIBRE_SECONDAIRE_DHCP — non-default WAN, statically-addressed lease, hosts the IPsec Phase 1
Manual Outbound NAT mode, with per-interface catch-all rules present for both WANs
IPsec: IKEv2, VTI (routed) mode, BGP peering over the tunnel to Azure VPN Gateway (custom IPsec/IKE policy: AES256-GCM / SHA256 / DH14, matched on both sides)
Strict Interface Binding: disabled (tested both enabled and disabled — no behavioral difference)
No floating firewall rules configured
Static route present: 4.211.176.201/32 via 90.63.242.1 (WAN_NET_GPON_832_FIBRE_SECONDAIRE_DHCP), confirmed active via netstat -rn

Steps to Reproduce

Configure two WAN interfaces on different upstream ISPs, one as default/Tier 1, one as non-default.
Configure an IPsec Phase 1 (IKEv2, VTI mode) explicitly bound to the non-default WAN interface, peering with a remote gateway that both initiates and responds to IKE (e.g., Azure VPN Gateway with BGP, "Default" Connection Mode).
Add a static host route for the peer IP via the non-default WAN's gateway.
Allow the tunnel to attempt negotiation over time, particularly across any event that touches routing/interface state (WAN interface reload, gateway monitor blip, static route edit, IPsec service reload).
Capture traffic on the non-default WAN interface (tcpdump -i <secondary_wan_if> host <peer_ip> and udp port 500 -vv) during a negotiation attempt.

Expected Behavior

All IKE traffic (both charon-initiated requests and charon's responses to peer-initiated exchanges) for a Phase 1 explicitly bound to a specific WAN interface should consistently egress via that interface, with the source IP matching that interface's address, matching the currently active routing table.

Actual Behavior

Packet captures taken on the non-default WAN interface (ix2.832) show IKE_SA_INIT response/request packets with a source IP belonging to the default/primary WAN (86.228.220.101), despite:

Being captured on the secondary WAN's own interface
A confirmed-correct, confirmed-active static route for the peer IP via the secondary WAN's gateway
No floating rules or policy routing rules matching this traffic

This occurs both for:
(a) charon's responses to peer-initiated IKE_SA_INIT requests, and
(b) charon's own freshly-initiated IKE_SA_INIT requests (new cookie, no prior pf state) — ruling out stale pf state as the sole cause in at least this instance.

Evidence

pfctl -ss showed a state with an incorrect NAT binding at one point in the investigation:

ix2.832 udp 86.228.220.101:30378 (90.63.242.158:500) -> 4.211.176.201:500 SINGLE:NO_TRAFFIC

Killing this state (pfctl -k <peer_ip>) plus a full IPsec service restart (not just a config/vici reload) and a full pfctl -F state flush temporarily resolved the issue. However, the problem recurred after this remediation, including for a fresh IKE_SA_INIT with a new cookie and no prior associated state — indicating the fix was not durable and the underlying cause was not fully addressed by clearing pf state alone.

pfctl -s nat showed correctly-scoped catch-all rules per interface:

nat on ix2.832 inet all -> 90.63.242.158 port 1024:65535
nat on ix3.832 inet all -> 86.228.220.101 port 1024:65535

Since NAT rule matching occurs after interface/route selection, this confirms the packet's egress interface selection itself (not NAT rule matching) is the point of failure.

Sample capture (sanitized), showing the reply on ix2.832 incorrectly sourced from the primary WAN:

[peer]:500 > 90.63.242.158:500 (peer's request, correctly received on secondary WAN)
86.228.220.101:6947 > [peer]:500 (pfSense's response, captured on ix2.832, but sourced from PRIMARY WAN IP)

Troubleshooting already performed (all ruled out as root cause)

Verified Phase 1/2 crypto proposals match on both sides
Verified DPD timers match peer
Verified unique = UNIQUE_REPLACE
Verified My/Peer identifier configuration (IP-based, standard)
Disabled Strict Interface Binding — no change
Verified no Floating rules exist
Verified Manual Outbound NAT has correct catch-all + dedicated UDP/500+4500 rules per interface, correctly ordered
Verified static route present and actively used (netstat -rn, Uses counter incrementing)
pfctl -k targeted state kill — temporary fix, not durable
pfctl -F state full flush + IPsec service restart — temporary fix, not durable
Confirmed this persisted across upgrade from 26.03.1 to 26.07

No data to display

Actions

Also available in: Atom