TL;DR

Firewall → Settings → Advanced → Disable reply-to on WAN rules → check → Save → Apply.

Symptom: a port-forward or WAN rule answers from any internet IP, but from a host that lives in the same subnet as the firewall’s WAN everything times out (SSH, HTTPS, even ping), even though the rule says from any.

With a single WAN this is safe: the firewall stops forcing replies through the gateway and goes back to its routing table.

The setup

1
2
3
4
5
6
7
8
                203.0.113.0/24  (same L2 segment)
   ┌────────────────────┬────────────────────┬────────────────────┐
   │                    │                    │                    │
 gateway             fw01 (OPNsense)      neighbor             internet
 203.0.113.1         WAN 203.0.113.40     203.0.113.50         (via gateway)
                        │ rdr :22 → 192.168.1.10
                        ▼
                     LAN server
  • From the internet: ssh -p 22 203.0.113.40 reaches the LAN server. Fine.
  • From neighbor (203.0.113.50): every port times out.

What reply-to does

OPNsense generates the rules on WAN-type interfaces (those with a gateway) with reply-to pointing at that gateway:

1
pfctl -sr | grep reply-to
1
pass in quick on vtnet0 reply-to (vtnet0 203.0.113.1) inet proto tcp from any to 192.168.1.10 port = ssh flags S/SA keep state

reply-to is a pf option. When a packet comes in and creates a state, pf records in that state that every reply must leave through vtnet0 toward 203.0.113.1. Those replies skip the routing table: pf picks the next hop on its own.

It exists for multi-WAN. If you have two providers and a client comes in on WAN2, the reply must leave through WAN2. If it leaves through the default route (WAN1), it carries a source IP that provider 1 does not recognize and gets lost. reply-to guarantees a symmetric return path without thinking about routes.

Why it breaks neighbors

For an internet client, “reply to the gateway” is exactly what the routing table would do anyway, so nothing looks wrong.

For the neighbor it is different. Its IP (203.0.113.50) is on a connected network of the firewall. Without reply-to, the firewall would ARP for its MAC and answer directly. With reply-to, the SYN-ACK leaves with the gateway’s MAC as destination:

1
2
# on the OPNsense box (csh shell: wrap in sh -c)
sh -c "tcpdump -lnei vtnet0 host 203.0.113.50 and tcp port 22"
1
2
<neighbor-mac> > <fw01-mac>          203.0.113.50.49612 > 203.0.113.40.22: Flags [S]    ← arrives directly
<fw01-mac>     > 00:00:5e:00:01:<vrid> 203.0.113.40.22 > 203.0.113.50.49612: Flags [S.]   ← leaves to the gateway

(00:00:5e:00:01:xx is the VRRP virtual MAC: the gateway was a redundant pair.)

From there it depends on the gateway. To it, the packet arrives on the same interface it would have to leave through, and if it runs a stateful filter it sees a SYN-ACK for a connection whose SYN it never saw. In the lab, the gateway simply did not send it back onto the segment. On the neighbor you only see retried SYNs and no [S.].

The fingerprint on the firewall is a half-open state:

1
pfctl -ss | grep 203.0.113.50
1
all tcp 192.168.1.10:22 (203.0.113.40:22) <- 203.0.113.50:57792   SYN_SENT:ESTABLISHED

The server already answered (ESTABLISHED) and the client is still waiting (SYN_SENT): the reply is lost on the way back, not on the way in. The filter is not blocking anything.

What the fix changes

With Disable reply-to on WAN rules checked, OPNsense regenerates the rules without reply-to:

1
pass in quick on vtnet0 inet proto tcp from any to 192.168.1.10 port = ssh flags S/SA keep state

The state no longer pins the next hop, so replies go through the normal routing table:

Reply destinationWith reply-toWithout reply-to
Internet clientgatewaygateway (default route)
Neighbor in 203.0.113.0/24gateway ✗direct via ARP ✓
Client that came in on another WAN (multi-WAN)its gateway ✓default route ✗

The last row is the cost. With multi-WAN, do not disable it globally. Instead, drop reply-to only on the affected port-forward’s rule: in the rule, Advanced → reply-to. Check which options your version offers.

Verify

1
2
3
# on the OPNsense box
sh -c "pfctl -sr | grep -c reply-to; grep -n disablereplyto /conf/config.xml"
# expected: 0  and  <disablereplyto>yes</disablereplyto>
1
2
# from the neighbor
nc -z -w5 203.0.113.40 22 && echo open

Traps

  • “Disable force gateway” is not this. It sits on the same page with a similar name, but it only affects traffic originated by the firewall itself (DNS, NTP, updates). It does not touch replies to inbound traffic.
  • A static route on the gateway does not help. The gateway already has the subnet as connected; the problem is that it will not send the packet back onto the same segment, not that it does not know the way.
  • csh shell. Over SSH, OPNsense drops you into csh, and things like 2>/dev/null fail with Ambiguous output redirect. Use sh -c "..." or ssh root@fw01 sh <<'EOF'.
  • Test every port, not one. If only one port fails it is a different problem (rule, NAT, service). If they all fail, ping included, and only from the same subnet, suspect reply-to.

See also