Skip to content

Destination NAT rule with IPv4+IPv6 breaks entire ruleset load at boot (silent total loss of filter and NAT) #10755

Description

@am312

Important notices

Before you add a new report, we ask you kindly to acknowledge the following:

If AI was used, please disclose:

  • Model used: Claude Opus 5
  • Extent of AI involvement: formatted the bug report

Describe the bug:

A Destination NAT rule with TCP/IP Version set to IPv4+IPv6 on a WAN interface that has no usable IPv6 address causes /tmp/rules.debug to contain a rule pf cannot load:

/tmp/rules.debug:52: no translation address with matching address family found
/tmp/rules.debug:160: rule expands to no valid combination

Because pf loads rulesets atomically, this single error aborts the load of the entire ruleset. After boot the firewall is left in this state:

pfctl -si reports Status: Enabled
pfctl -sr returns nothing (zero filter rules)
pfctl -s nat returns nothing (zero NAT rules)

With no source NAT, LAN clients emit packets with their private source address and lose all internet connectivity. The firewall itself remains fully functional (its own traffic already sources from the WAN address), so the web GUI and SSH stay reachable and DNS served from the firewall continues to answer — which makes the failure very hard to attribute.

The failure is silent. configctl filter reload returns OK, and the GUI reports the apply as successful. Nothing surfaces the fact that pf holds no rules at all.

There are arguably two separate issues here:

Boot-time ruleset generation emits an unloadable rule for an IPv4+IPv6 NAT rule when the interface has no IPv6 address.
A failed ruleset load is not reported anywhere the user can see, leaving the system with no filtering and no NAT while reporting success. To reproduce:

  1. Configure a WAN interface with IPv4 only (no usable IPv6 address).
  2. Create a Destination NAT rule under Firewall -> NAT -> Destination with TCP/IP Version set to IPv4+IPv6.
  3. Run configctl filter reload — the ruleset loads correctly, and pfctl -s nat shows the expected automatic source NAT rules. No failure at this point.
  4. Reboot the firewall.
  5. After boot, LAN clients can no longer reach the internet. pfctl -sr and pfctl -s nat both return nothing.
  6. Change the same rule to IPv4 only and apply. Connectivity is restored immediately, with no reboot required.

The reload/reboot asymmetry is reproducible in both directions.

Expected behavior:

One of the following:

An IPv4+IPv6 rule should expand only to the address families actually available on the interface, rather than producing a rule that cannot be loaded;

or

The rule should be rejected at save time in the GUI with a clear validation error; and in any case
A failed ruleset load must be reported loudly — in the GUI, in the configctl filter reload return value, and in the system log — rather than silently leaving pf with an empty ruleset.

Relevant log files:

root@OPNsense:~ # opnsense-version -v
26.7.2_2
root@OPNsense:~ # pfctl -si |head -1
Status: Enabled for 0 days 00:02:31 Debug: Urgent
root@OPNsense:~ # pfctl -sr |wc -l
0
root@OPNsense:~ # configctl filter reload
OK
root@OPNsense:~ # pfctl -sr
root@OPNsense:~ # pfctl -s nat
root@OPNsense:/tmp # pfctl -n -f /tmp/rules.debug
/tmp/rules.debug:52: no translation address with matching address family found.
/tmp/rules.debug:160: rule expands to no valid combination

Environment:

OPNsense version: 26.7.2_2
Hardware: x86-64 laptop, two interfaces (one onboard Intel NIC, one USB Ethernet adapter)
WAN: IPv4 only, DHCP, with a spoofed/cloned MAC address
Outbound/Source NAT mode: Automatic source NAT rule generation
No CARP/HA — single firewall
Plugins in use: AdGuard Home, dnsmasq (DHCP), Unbound (resolver)

Related issues:

#4493 — "Adding a dual stack rule with IPv6-only L4 protocol prevent the firewall from starting" (closed, milestone 21.1). Same failure shape and same requested fix, but on the filter rule path. This report covers the Destination NAT path, which appears not to have received the equivalent validation. It also differs in that the failure here is silent: #4493 produced a visible boot alert, whereas this leaves no user-visible indication that pf holds no rules.
#3978 — Same no translation address with matching address family found error when an interface lacks an address during multi-WAN failover. Same underlying mechanism (missing address at generation time), different trigger.
#6909 — WireGuard endpoints lost internet after boot because NAT was not applied; a manual filter restart fixed it, and it was resolved as a boot-ordering race. Structurally the same reload-works/boot-fails asymmetry seen here.
#2841 — Earliest report of the same error string (2018), for context on how long-lived this failure mode is.

Additional context:

The problem first appeared after disabling an unrelated Destination NAT entry in the GUI, which triggered a ruleset regeneration. The IPv4+IPv6 rule had presumably been latent until that regeneration.

Because the symptoms are "firewall reaches the internet, LAN does not, DNS still works, GUI and SSH still reachable," this presents as a routing or NAT misconfiguration rather than a ruleset load failure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    supportCommunity support or awaiting triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions