Skip to content

nftables: per-rule logging and a live firewall-log view - #14

Merged
edimarlnx merged 1 commit into
mainfrom
nftables-log
Aug 31, 2026
Merged

edimarlnx merged 1 commit into
mainfrom
nftables-log

Conversation

@edimarlnx

Copy link
Copy Markdown
Contributor

Adds the OPNsense-style logging model to the nftables backend: mark a rule to be logged, and watch the logged rules fire in a live view.

Per-rule logging (l)

  • A rule the tool owns is replaced in place with nft replace rule … log prefix "tui:<chain> <verdict> " …, keeping its handle and position. nft rules are immutable, so a log statement can only be added or removed by replacing the whole rule.
  • The replacement is rebuilt from the rule's own modelled match and previewed like every other mutation. A rule the model does not hold in full (an unmodeled match, a NAT translation, an unsupported verdict) is refused rather than rewritten from a display rendering.
  • The log/nflog statement (prefix, level, group) now round-trips through the reader; the prefix keeps its own trailing space so it round-trips to nft. A reject rule keeps the answer it sends.
  • A logged rule carries a LOG marker in its row and a LOG column.

Live log (w)

  • A read-only stream of the kernel firewall log, filtered to the tool's own tui: prefix, read with journalctl --kernel --follow --output=short-iso. A machine without journald is told so plainly.
  • Each event parses into time, direction (from the chain, falling back to the interfaces), action, source, destination, port and prefix; shown newest-last, pausable, with the retained lines capped.
  • --demo plays a synthetic feed so the view animates with no journald and no root.
  • --check/--report note how many owned rules log and whether the live source is readable.

Boundary

Exec for the stream stays inside internal/nftables/ (the backend package), so check-exec.sh is unchanged. Every mutation is still a previewed runner.Command.

Validation (no lab)

  • make check green: fmt, vet, golangci (incl. gosec), exec boundary, tests, tidy.
  • Against real nft v1.1.1 in unshare -rn: the replace … log prefix … and its reverse are accepted, reject with tcp reset + log is accepted, and the log statement round-trips through nft -j. A logging drop rule fires (counter increments) but the rootless netns does not deliver its kernel-log line, so the parser is proven on the documented nf_log line format as labelled fixtures.
  • Fuzz: new FuzzParseKernelLogLine (45s) plus FuzzDecodeExprs (35s) and FuzzParseRuleset (30s) with new log/nflog/reject seeds — no crashes.

Lab acceptance still owed (item 10's lab twin, for later)

Mark a drop-with-log rule through the real TUI, generate blocked traffic against the router, and see the live view show the event with the correct direction and source — on the multi-VM lab where the init-namespace kernel log and journald deliver the line.

🤖 Generated with Claude Code

Add the OPNsense-style logging model to the nftables backend: mark a
rule to be logged, and watch the logged rules fire in a live view.

Per-rule logging (l): a rule the tool owns is replaced in place with
`nft replace rule … log prefix "tui:<chain> <verdict> " …`, keeping its
handle and position. The replacement is rebuilt from the rule's own
modelled match and previewed like every other mutation; a rule the model
does not hold in full — an unmodeled match, a NAT translation, an
unsupported verdict — is refused rather than rewritten from a rendering.
The log statement (prefix, level, group) now round-trips through the
reader, and a logged rule carries a LOG marker in its row.

Live log (w): a read-only stream of the kernel firewall log, filtered to
the tool's own `tui:` prefix, read with `journalctl --kernel --follow`.
Each event is parsed into time, direction, action, source, destination,
port and prefix and shown newest-last; the feed pauses and the retained
lines are capped. --demo plays a synthetic feed so the view animates with
no journald and no root. --check and --report note how many owned rules
log and whether the live source is readable.

Exec for the stream stays inside internal/nftables (the backend package),
so the exec boundary is unchanged. Validated against nft v1.1.1 in a
rootless netns (the replace and reject-with syntax, and the JSON
round-trip); the kernel-log parser is proven on the documented nf_log
line format, since a rootless netns fires the rule but does not deliver
its kernel log line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MCypLQF5AD8JD831Ea9S9q
@edimarlnx
edimarlnx merged commit a6028a9 into main Aug 31, 2026
8 checks passed
@edimarlnx
edimarlnx deleted the nftables-log branch August 31, 2026 01:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant