ITADN

Far Gateway host route not created for WireGuard-assigned gateway (monitor traffic silently falls back to WAN)

#10706Openlonaman 创建于 18 天前
support
L
lonamancommented
**Important notices** Before you add a new report, we ask you kindly to acknowledge the following: - [x] I have read the contributing guidelines at https://github.com/opnsense/core/blob/master/CONTRIBUTING.md - [x] I am convinced that my issue is new after having checked both open and closed issues at https://github.com/opnsense/core/issues?q=is%3Aissue - [x] AI tools were used to create at least part of the text submitted herewith. If AI was used, please disclose: - Model used: Claude - Extent of AI involvement: Drafting post with input ## Describe the bug When a WireGuard client interface is assigned as a gateway with **Far Gateway** checked and an arbitrary (intentionally unassigned) placeholder IP address, OPNsense does not create the static host route needed to actually route monitor traffic through the tunnel — despite the config being valid and `dpinger_status()` correctly reporting the configured gateway IP. The result is that gateway monitoring traffic silently falls through to the default WAN route instead of traversing the VPN tunnel, and the dpinger-reported status (loss/latency) reflects the WAN path, not the tunnel. This makes gateway monitoring on a WireGuard-based gateway meaningless — the tunnel can be completely down while monitoring reports it healthy. ## Environment - OPNsense 26.7.1_1-amd64 - FreeBSD 15.1-RELEASE-p1 - Native WireGuard (VPN > WireGuard), client instance assigned as an interface - Gateway configured with **Far Gateway** enabled, arbitrary placeholder IP address, and a Monitor IP ## Setup 1. WireGuard client instance assigned as an interface (e.g. `wg2`), tunnel address `10.x.x.x/32`. 2. Gateway created for this interface: - Far Gateway: checked - IP Address (gateway field): an arbitrary unused placeholder, e.g. `10.x.x.1` (not a real, routable address — this is the documented/expected pattern for WireGuard gateways in OPNsense, since a WG tunnel has no real on-link next-hop) - Monitor IP: a real internet host (e.g. a public DNS resolver) ## Expected behavior OPNsense creates a static host route anchoring the placeholder gateway IP to the WireGuard interface (this is the whole purpose of the Far Gateway flag), and a derived host route for the Monitor IP via that gateway — so dpinger's probe traffic actually traverses the tunnel. ## Actual behavior No such route is created, at any point — not after initial gateway creation, not after Save + Apply on the gateway config, and not after a full "Reload all services." `route get <monitor IP>` continues to resolve via the WAN default route indefinitely. ## Reproduction / evidence **Config confirmed correct** — `dpinger_status()` shows the intended gateway IP: ``` [WAN_ProtonVPN] => Array ( [status] => none [monitor] => 8.8.8.8 [gateway] => 10.x.x.1 ... [loss] => 0.0 % ) ``` **But the kernel route table disagrees** — no route exists for the gateway IP or monitor IP via the tunnel interface, at all: ``` # netstat -rn -f inet | grep "10.x.x.1" (no output) # route get 8.8.8.8 route to: dns.google destination: default gateway: <WAN gateway> interface: em1 flags: <UP,GATEWAY,DONE,STATIC> ``` **Confirmed via packet capture that monitor traffic is actually leaking out WAN, not the tunnel:** ``` # tcpdump -ni wg2 icmp listening on wg2, link-type NULL (BSD loopback) 0 packets captured <-- nothing, despite ping succeeding # tcpdump -ni em1 icmp and host 8.8.8.8 09:38:55 IP <WAN IP> > 8.8.8.8: ICMP echo request 09:38:55 IP 8.8.8.8 > <WAN IP>: ICMP echo reply ``` The source address of the ICMP echo (the tunnel's `-S 10.x.x.2`) was rewritten by outbound NAT on the way out `em1` — proof the packet never touched the tunnel despite dpinger and manual pings both reporting clean, low-latency success. **System log during a full service reload shows the likely proximate cause** — the route-resolution logic explicitly fails to match the placeholder gateway IP against any known interface subnet (expected, since it's intentionally unassigned) and falls back to a default bind instead of applying the Far Gateway pinning: ``` /usr/local/sbin/pluginctl: Chose to bind WAN_ProtonVPN on 10.x.x.2 since we could not find a proper match. ``` ## Workaround Manually add the missing route as a **static route** (System > Routes > Configuration), not relying on the dynamic Far-Gateway route builder: - Network: `<monitor IP>/32` - Gateway: the WireGuard gateway object This is a declarative config entry (persists across reboot, unlike a manual `route add` at the shell) and correctly anchors monitor traffic to the tunnel. Confirmed via repeat of the above tcpdump test that ICMP now correctly traverses `wg2` after adding this route, and that `dpinger_status()` correctly reports `down`/100% loss on a real tunnel outage once this is in place (previously it never did, regardless of actual tunnel state). ## Impact Anyone using a WireGuard client gateway with Far Gateway + Monitor IP for health checking, multi-WAN/VPN failover via Gateway Groups, or any alerting built on gateway status, gets **silently incorrect monitoring** — the gateway will report healthy even when the tunnel is completely down, because the probe traffic never actually uses the tunnel. This directly undermines gateway-group-based VPN failover, since the failover trigger never fires.
1 条评论