feat(status): report where ZFW-IN sits in INPUT, and what runs ahead of it - #26
Open
chicohaager wants to merge 1 commit into
Open
feat(status): report where ZFW-IN sits in INPUT, and what runs ahead of it#26chicohaager wants to merge 1 commit into
chicohaager wants to merge 1 commit into
Conversation
…of it ZFW hooks its chain with `-C INPUT -j ZFW-IN || -I INPUT 1 -j ZFW-IN`: it takes position 1 once and never re-asserts it. Anything a later tool inserts ahead of it — a blocklist module's own chain, Tailscale's ts-input, an ACCEPT-all from a VPN installer — is evaluated before ZFW. A stricter chain there is harmless; a permissive one bypasses ZFW without any tab saying so. Seen on a real host: ZFW-IN at INPUT rule #3 behind two foreign chains, while Status reported hooked=true and the dashboard read "active". Status already fetched `iptables -S INPUT` and reduced it to a boolean (`strings.Contains(out, "-j ZFW-IN")`). It now keeps the information: - Status.InputPosition (1-based rule index, 0 = not hooked) and Status.InputBefore (the specs ahead of it, capped at 32), plus the same pair for ZFW-IN6 in the IPv6 INPUT chain. Parsing is a pure function (inputOrder) over the dump: only `-A INPUT` lines count, the policy line and foreign chains are ignored, a v4 dump never matches the v6 target. - Audit finding M9 "Rules ahead of ZFW-IN in INPUT": fixed only when ZFW-IN is first; open otherwise, with the predecessors named in the detail so the operator can judge them — ZFW cannot. - Firewall tab: "INPUT position #n" (green at 1, amber otherwise) with the rules ahead listed under the label; same item for IPv6. - OpenAPI: the four new Status fields. Deliberately not: re-inserting ZFW-IN at position 1 on a timer. Two tools that both insist on being first shove each other in a loop. ZFW reports and leaves the decision to the operator. Tests: four inputOrder cases (real-world dump with ZFW-IN at #3, first / absent / empty dump, match rules kept verbatim and foreign chains ignored, predecessor cap does not alter the count) and the M9 handler test (open at #3 with predecessors named, fixed at #1, open when unhooked). Each was run against a sabotaged implementation once: three of the four inputOrder tests and the M9 test go red under the old contains-only semantics. Firewall tab rendered headless with stubbed status for both states; the grid shows "#3 · 2 rules ahead: IPBLOCKLIST, ts-input" and "#1" respectively. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRUX9ZKesnvfMooL7UFPtX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 0 of the blocklist plan — and useful on its own.
ZFW takes INPUT position 1 once and never re-asserts it. A tool installed later can end up ahead of it; a permissive rule there bypasses ZFW silently while the dashboard still says "active". Seen on a real host: ZFW-IN at rule #3 behind two foreign chains.
Statusgainsinput_position/input_before(and the IPv6 pair). The-S INPUTdump was already fetched; it is now parsed instead of reduced to a boolean.Tests sabotage-checked (three of four parser tests and the M9 test go red under the old semantics). Firewall tab rendered headless for both states.
🤖 Generated with Claude Code
https://claude.ai/code/session_01GRUX9ZKesnvfMooL7UFPtX