Compile conntrack rules into raw-priority chains #22

Merged
benvin merged 12 commits from benvin/notrack-raw into main 2026-10-04 13:55:37 +11:00
Member

Conntrack (NOTRACK/drop/helper) entries were parsed but never compiled, and zone specs could fail open on typos or exclusions.

  • Compile conntrack rules into raw-priority raw_prerouting/raw_output chains
  • Match SOURCE zone iif (prerouting) / DEST zone oif (output) plus addresses; fw sources go to raw_output
  • Omitted SOURCE/DEST is global (shorewall NOTRACK - - udp 53 loads)
  • Reject zone exclusion/plus forms (all!x, all+, any!x) in conntrack entries
  • Expand all!zone exclusions per zone for filter rules
  • Reject unknown zone names in rule/blrule/conntrack validation; compiler fails closed on unknown zones
Conntrack (NOTRACK/drop/helper) entries were parsed but never compiled, and zone specs could fail open on typos or exclusions. - Compile conntrack rules into raw-priority `raw_prerouting`/`raw_output` chains - Match SOURCE zone iif (prerouting) / DEST zone oif (output) plus addresses; fw sources go to raw_output - Omitted SOURCE/DEST is global (shorewall `NOTRACK - - udp 53` loads) - Reject zone exclusion/plus forms (`all!x`, `all+`, `any!x`) in conntrack entries - Expand `all!zone` exclusions per zone for filter rules - Reject unknown zone names in rule/blrule/conntrack validation; compiler fails closed on unknown zones
unkin-agent added 1 commit 2026-10-03 22:54:35 +10:00
Compile conntrack rules into raw-priority chains
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
c9adff32f6
Author
Member

No findings.

No findings.
benvin added 4 commits 2026-10-03 23:44:12 +10:00
Match source/dest zones and addresses on conntrack rules
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
3c5f1cacd4
Restrict raw_output to fw sources and reject unmatched prerouting dest zones
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
6af17a4c02
Reject fw source on prerouting conntrack and pin global omitted-zone entries
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
337490d995
Merge pull request 'Match source/dest zones on conntrack rules' (#24) from benvin/conntrack-zones into benvin/notrack-raw
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
3c5d23a811
Reviewed-on: #24
unkin-agent added 2 commits 2026-10-03 23:48:10 +10:00
Expand all!zone exclusions and fail closed on unknown zones
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
b6d67897de
Author
Member
  • internal/nftables/compiler.go:266-272 — in raw_prerouting the DEST zone is never resolved: an unknown zone or none (valid at validation) gives dstIfaces=[""] with no addr check (the ok && guard skips it), so SOURCE net DEST none compiles to iif=eth0 notrack, a widened match → in raw_prerouting resolve dstZone (skip when unknown/none) and apply the unknown-zone skip to dest, not only src.
  • internal/nftables/compiler.go:419-420 — the same-zone pairing check tests only srcSpec for +!, so SOURCE lan DEST all+!net drops lan→lan (forward) while SOURCE all+!net DEST lan keeps it → check whichever spec is the exclusion (+! in srcSpec or dstSpec) per side.
  • internal/nftables/compiler_test.go:2423 — no case for conntrack DEST none/unknown in prerouting, nor for lan → all+!x same-zone pairing → add both.
- internal/nftables/compiler.go:266-272 — in raw_prerouting the DEST zone is never resolved: an unknown zone or `none` (valid at validation) gives dstIfaces=[""] with no addr check (the `ok &&` guard skips it), so `SOURCE net DEST none` compiles to `iif=eth0 notrack`, a widened match → in raw_prerouting resolve dstZone (skip when unknown/none) and apply the unknown-zone skip to dest, not only src. - internal/nftables/compiler.go:419-420 — the same-zone pairing check tests only `srcSpec` for `+!`, so `SOURCE lan DEST all+!net` drops lan→lan (forward) while `SOURCE all+!net DEST lan` keeps it → check whichever spec is the exclusion (`+!` in srcSpec or dstSpec) per side. - internal/nftables/compiler_test.go:2423 — no case for conntrack DEST `none`/unknown in prerouting, nor for `lan → all+!x` same-zone pairing → add both.
unkin-agent added 2 commits 2026-10-03 23:50:20 +10:00
Fail closed on unknown/none conntrack DEST and pair all+ symmetrically
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
bf235291d0
Author
Member
  • internal/nftables/compiler.go:245 — conntrack DEST all!net fails open: Source fw, Dest all!net emits an oif-less raw_output rule (from the expanded fw dest) that matches egress via net too; also all!net:addr in raw_prerouting emits duplicate identical rules per dest zone (dest iface is never matched there) → in raw_output a dest zone with no iface (fw) must not produce an unconditional rule when the dest spec is an exclusion; dedupe prerouting pairs.
  • internal/nftables/compiler.go:245 — conntrack exclusions never apply the intra-zone rule that compileOneRule applies: lan → all!net:192.0.2.1 and all!net → lan:192.0.2.1 both emit lan→lan (iif=eth1 daddr=...) → reuse the src==dst skip (all!x skips, all+/all+!x pairs) in compileConntrack, and add tests for dest-side exclusion and intra-zone.
- internal/nftables/compiler.go:245 — conntrack DEST `all!net` fails open: Source `fw`, Dest `all!net` emits an oif-less `raw_output` rule (from the expanded `fw` dest) that matches egress via `net` too; also `all!net:addr` in raw_prerouting emits duplicate identical rules per dest zone (dest iface is never matched there) → in raw_output a dest zone with no iface (fw) must not produce an unconditional rule when the dest spec is an exclusion; dedupe prerouting pairs. - internal/nftables/compiler.go:245 — conntrack exclusions never apply the intra-zone rule that compileOneRule applies: `lan` → `all!net:192.0.2.1` and `all!net` → `lan:192.0.2.1` both emit lan→lan (`iif=eth1 daddr=...`) → reuse the src==dst skip (`all!x` skips, `all+`/`all+!x` pairs) in compileConntrack, and add tests for dest-side exclusion and intra-zone.
unkin-agent added 1 commit 2026-10-03 23:53:12 +10:00
Reject zone exclusions in conntrack entries
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
90d2875301
Author
Member
  • internal/nftables/compiler.go:236 — SOURCE all/any/all+/any+ is treated as a named non-fw zone in the chain switch: chain: both compiles raw_prerouting only (raw_output silently dropped, so locally-originated traffic is not NOTRACKed/dropped), and chain: output errors. Omitted SOURCE gets both chains → normalize all/any(+) to the global case (src.Zone == "") in the switch, and add a test for Source: "all", Chain: both|output.
- internal/nftables/compiler.go:236 — SOURCE `all`/`any`/`all+`/`any+` is treated as a named non-fw zone in the chain switch: `chain: both` compiles raw_prerouting only (raw_output silently dropped, so locally-originated traffic is not NOTRACKed/dropped), and `chain: output` errors. Omitted SOURCE gets both chains → normalize all/any(+) to the global case (`src.Zone == ""`) in the switch, and add a test for `Source: "all", Chain: both|output`.
unkin-agent added 1 commit 2026-10-03 23:54:39 +10:00
Treat conntrack SOURCE all/any as global like an omitted source
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
da65c5d0a8
Author
Member
  • internal/nftables/compiler.go:~269 (compileConntrackPair) — DEST fw zone in raw_prerouting is exempt from the "needs an address" error and its dest match is dropped, so DROP net $FW / NOTRACK net $FW match all inbound traffic from net including forwarded → reject fw DEST in prerouting like other non-address dests (or restrict to raw_output/input-equivalent).
  • nit: go.mod/go.sum (nftables 0.2.0→0.3.0, netlink, x/sys, x/net) and the DNAT Specified = true change in compileDNATRule are unrelated to conntrack → split into separate PRs (dependency bump; DNAT readback fix).
- internal/nftables/compiler.go:~269 (compileConntrackPair) — DEST fw zone in raw_prerouting is exempt from the "needs an address" error and its dest match is dropped, so `DROP net $FW` / `NOTRACK net $FW` match all inbound traffic from net including forwarded → reject fw DEST in prerouting like other non-address dests (or restrict to raw_output/input-equivalent). - nit: go.mod/go.sum (nftables 0.2.0→0.3.0, netlink, x/sys, x/net) and the DNAT `Specified = true` change in compileDNATRule are unrelated to conntrack → split into separate PRs (dependency bump; DNAT readback fix).
unkin-agent added 1 commit 2026-10-03 23:56:31 +10:00
Reject conntrack fw DEST without an address in prerouting
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
9078f410ee
Author
Member

No findings.

No findings.
benvin merged commit 9abaa85d6a into main 2026-10-04 13:55:37 +11:00
benvin deleted branch benvin/notrack-raw 2026-10-04 13:55:37 +11:00
Sign in to join this conversation.