Import: keep what rulesets mean, name zones as asked

Fixes from an audit of the importer, each of which could change what an
imported ruleset does: two base chains on one hook imported their rules
twice (and hoisted the second's built-ins), now in priority order with
the stricter policy; raw rules from a jumped-to chain lost the jump's
condition, now put in front; a jump and a rule matching one field are
combined only when one's addresses lie within the other's; a second
match on a field replaced the first, and != on hop limit and TCP flags
read as ==, now kept raw; a forward accept without ct status dnat no
longer folds into the port forward, nor an interface-limited IPv6
accept into an open pinhole; raw rules' set references are renamed
(NAME_v4/_v6) or written out, so nftables takes them; DNATs with
matches a forward can't hold are left out with a note.

Sets with flags timeout become dynamic sets; a DNAT of several ports one
forward per port. Zone names: --zone IFACE=NAME (and on the Import
page), VLAN defines, more suffixes, and a note on where each name came
from. testdata/audit.nft covers the cases, checked with nft 1.1.3.

make test and make e2e (246 checks) pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-20 08:43:42 +01:00
1 parent c17f5cd9f0
commit 47bae07d42
15 files changed
+823 -117

No files matched your search

+39
View File
@@ -6,6 +6,45 @@ All notable changes to Housecarl are documented here. The format follows
## [Unreleased]
### Added
- **Zone names at import:** `hc import --zone enp2s0=lan` (repeat;
interfaces given one name share a zone; Zone names on the Import
page), and a note listing each zone and where its name came from.
Defines holding a VLAN sub-interface (`enp2s0.20`) name their zone,
and `_ifname`, `_device` and `_nic` are taken off define names too
(docs/import.md, "How things are named").
- Import: sets with `flags timeout` become dynamic sets; a DNAT of
several ports becomes one port forward per port.
### Fixed
- Import: two base chains on one hook had their rules imported twice,
and the second chain's leading built-ins were moved above the first
chain's rules; they now follow each other by priority (read in a
fixed order), with the stricter policy, and a note.
- Import: a rule inside a jumped-to chain that stays raw kept only its
own text and so applied to everything; the jump's condition now goes
in front. A jump and a rule matching the same field are combined only
when one's addresses lie within the other's; else the rule stays raw.
A jump's ports, ICMP types, connection status and hop limit were
dropped; a limit or log on the jump is no longer silently lost.
- Import: a second match on the same field (`ip saddr A ip saddr != B`)
replaced the first; `!=` on the hop limit and TCP flags was read as
`==`. Such rules now stay raw, as written.
- Import: a forward-chain accept to a forwarded host and port without
`ct status dnat` was folded into the port forward, which only lets
forwarded connections through; it stays a rule now. An IPv6 accept
limited to an interface no longer becomes a pinhole open to all.
- Import: raw rules naming a set of the old table made nftables refuse
the ruleset; address sets are now renamed `NAME_v4`/`NAME_v6`, other
sets written out with their elements, and what can't be is left out
with a note. Rules naming a set that isn't imported stay raw instead
of failing validation.
- Import: a DNAT to an IPv6 address, or with matches a port forward
can't hold (an interface excluded, a limit, a log), is left out with a
note instead of being imported without them.
## [0.1.0] - 2026-10-19
The first version of Housecarl, a firewall manager for nftables, built