Files
Christian Manivong 3506f20606
CI / test (3.10) (push) Failing after 1m39s
CI / test (3.11) (push) Failing after 25s
CI / test (3.12) (push) Failing after 12s
CI / test (3.9) (push) Failing after 31s
CI / test (3.10) (pull_request) Failing after 13s
CI / test (3.11) (pull_request) Failing after 12s
CI / test (3.12) (pull_request) Failing after 13s
CI / test (3.9) (pull_request) Failing after 12s
feat: port forwards, read from destination NAT on the WAN
get_port_forwards reads /api/firewall/d_nat/search_rule and keeps only what
the contract asks for: rules on an interface with an upstream gateway (the
WAN, and a second uplink as well). Internal redirects, anti-lockout rules
(nordr) and rules the captive portal generates are left out -- on the first
real box (OPNsense 26.7) that was 20 of 22 rules, and each would have made an
internal host look reachable from the internet.

Targets resolve through host/network aliases, one entry per address; an
interface address or a DNS name gives no address and the rule is skipped
rather than put on a guessed host. Ports resolve as numbers, the start of a
range, port aliases or service names; no port is every port (0), and tcp/udp
is two entries. The filtering is pure, in port_forwards.py, and the driver
method does the three reads.

A box without the destination-NAT API raises instead of answering "nothing
forwarded", which nobody checked.
2026-10-03 16:30:38 +02:00
..
2026-05-29 09:22:10 +02:00