# Firewall InitNetwork Fix — INPUT vs FORWARD Chain Bugs ## TL;DR > **Quick Summary**: Fix 3 bugs in `InitNetwork()` that prevent WireGuard clients from reaching the server and Docker containers. ICMP echo-reply blocked, Docker DNAT traffic dropped, and missing base INPUT rules. > > **Deliverables**: > - Fixed `nftables_linux.go` InitNetwork() with correct ICMP, Docker bridge, and INPUT rules > - Updated `manager.go` if needed > - Server rebuilt and deployed via `update.sh --force` > > **Estimated Effort**: Short > **Parallel Execution**: YES - 2 waves > **Critical Path**: Task 1 → Task 4 (verify) --- ## Context ### Original Request User reported firewall rules from dashboard not working. Traced through multiple debugging sessions to find 3 root-cause bugs in `InitNetwork()` base rules: 1. `icmp type echo-request` only allows incoming pings TO server, not echo-reply FROM peers 2. No FORWARD rules for Docker bridge — WireGuard traffic DNAT'd to containers gets dropped 3. Server→peer traffic works (OUTPUT default accept) but replies hit INPUT chain and get dropped ### Interview Summary - **Key Discussions**: Extensive debugging on live server (172.20.8.191). User tested each fix manually via SSH. Confirmed Docker DNAT intercepts port 80 traffic via iptables PREROUTING, redirecting to container 172.24.0.4. - **Research Findings**: Docker uses iptables DNAT while NexusGuard uses nftables filter — both coexist. Traffic flow: WireGuard → INPUT (nftables) → ACCEPT → Docker PREROUTING (iptables DNAT) → destination changes to container IP → FORWARD chain (nftables) → DROP (no bridge rule). - **User Constraints**: No local binary builds (Docker only). No temp/debug files. Admin-only firewall (JWT protected). ### Metis Review (if consulted) N/A — bugs are clear from source code analysis, no ambiguity requiring consultation. --- ## Work Objectives ### Core Objective Fix 3 bugs in `InitNetwork()` that prevent WireGuard peer-to-server and peer-to-Docker-container connectivity. ### Concrete Deliverables - Fixed `apps/server-core/internal/firewall/nftables_linux.go` InitNetwork() - Fixed `apps/server-core/internal/firewall/manager.go` if interface changes needed - Server rebuilt and deployed - nftables verified working on live server ### Definition of Done - [ ] `nft list chain ip nexusguard input` shows `meta l4proto icmp accept` (not `icmp type echo-request`) - [ ] `nft list chain ip nexusguard forward` shows `fwd_wg_docker` rules for 172.24.0.0/16 and 172.17.0.0/16 - [ ] Client (gogo3 10.172.21.3) can ping server (10.172.21.1) - [ ] Server (10.172.21.1) can ping client (10.172.21.3) - [ ] Client can curl http://10.172.21.1:80 and get 200 ### Must Have - `meta l4proto icmp` replaces `icmp type echo-request` in INPUT chain - `fwd_wg_docker` rules added to FORWARD chain in InitNetwork() - Existing peer routing rules (AddForwardRule) still work - Existing DB firewall rules (syncRuleToFirewall) still work ### Must NOT Have (Guardrails) - Do NOT `nft flush table nexusguard` — destroys all rules - Do NOT change the FirewallRule model or API endpoints - Do NOT modify peer_sync.go or devices.go - Do NOT create temp/debug files in project root - Do NOT change the firewall chain routing logic (dest==server→INPUT, else→FORWARD) - Do NOT remove the `input_wg_drop` or `wg_isolation_default` base rules --- ## Verification Strategy > **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed. No exceptions. ### Test Decision - **Infrastructure exists**: NO (no nftables unit tests) - **Automated tests**: None (nftables rules tested via live server SSH) - **Framework**: None needed — live server verification ### QA Policy Every task includes agent-executed QA scenarios. Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`. - **nft verification**: SSH to server, run nft commands, verify rules present - **Connectivity**: SSH to server, run ping/curl tests --- ## Execution Strategy ### Parallel Execution Waves ``` Wave 1 (Start Immediately — 1 agent): ├── Task 1: Fix InitNetwork() in nftables_linux.go (quick) Wave 2 (After Wave 1 — 1 agent): ├── Task 2: Commit + Push + Deploy (quick) ├── Task 3: Verify nft rules on live server (quick) Wave FINAL (After Wave 2 — reviewer): ├── Task F1: Plan compliance audit (oracle) ├── Task F2: Code quality review (unspecified-high) ├── Task F3: Real manual QA (unspecified-high) ├── Task F4: Scope fidelity check (deep) -> F1-F4 can run in parallel Critical Path: Task 1 → Task 2 → Task 3 → F1-F4 ``` ### Dependency Matrix | Task | Depends On | Blocks | |------|-----------|--------| | Task 1 | None | Task 2 | | Task 2 | Task 1 | Task 3 | | Task 3 | Task 2 | F1-F4 | | F1-F4 | Task 3 | None | ### Agent Dispatch Summary - **Wave 1**: T1 → `quick` - **Wave 2**: T2 → `quick`, T3 → `quick` - **FINAL**: F1 → `oracle`, F2 → `unspecified-high`, F3 → `unspecified-high`, F4 → `deep` --- ## TODOs - [x] 1. Fix InitNetwork() in nftables_linux.go **What to do**: 1. In `apps/server-core/internal/firewall/nftables_linux.go`, line 48: change `icmp type echo-request` to `meta l4proto icmp`. Also update the comment from `input_icmp` to `input_icmp_all`. 2. In the same function, after the `input_wg_drop` rule block (around line 64), add Docker bridge accept rules to FORWARD chain: - `nft insert rule ip nexusguard forward ip saddr ip daddr 172.24.0.0/16 accept comment "fwd_wg_docker"` - `nft insert rule ip nexusguard forward ip saddr ip daddr 172.17.0.0/16 accept comment "fwd_wg_docker0"` 3. These Docker rules should be inserted AFTER `fwd_estab` and BEFORE the `wg_isolation` drop rule. Use `nft insert rule` with position or append after fwd_estab. 4. Add dedup checks (same pattern as existing rules): `grep -q 'fwd_wg_docker'` before inserting. **Must NOT do**: - Do NOT change AddForwardRule, AddFirewallRule, AddInputFirewallRule, or RemoveFirewallRule - Do NOT change the chain routing logic in syncRuleToFirewall - Do NOT flush or recreate any chains - Do NOT change manager.go interface **Recommended Agent Profile**: - **Category**: `quick` - Reason: Single-file change, 3 specific line edits, clear patterns to follow - **Skills**: [] - No special skills needed — straightforward Go code edit **Parallelization**: - **Can Run In Parallel**: NO - **Parallel Group**: Wave 1 (solo) - **Blocks**: Task 2 (commit/deploy) - **Blocked By**: None (can start immediately) **References**: - `apps/server-core/internal/firewall/nftables_linux.go:25-68` — InitNetwork() function, all 3 bugs are here - `apps/server-core/internal/firewall/nftables_linux.go:30-38` — existing FORWARD chain setup (fwd_estab, wg_isolation) — Docker rules go between these - `apps/server-core/internal/firewall/nftables_linux.go:40-64` — existing INPUT chain setup — ICMP fix at line 48 - `apps/server-core/main.go:210-259` — startup re-apply code that calls AddForwardRule and AddInputFirewallRule — do NOT modify - `apps/server-core/internal/firewall/manager.go:5-18` — NetManager interface — do NOT modify **Acceptance Criteria**: - [ ] Line 48 reads `meta l4proto icmp` not `icmp type echo-request` - [ ] Comment reads `input_icmp_all` not `input_icmp` - [ ] FORWARD chain has dedup check for `fwd_wg_docker` before inserting - [ ] `go vet ./internal/firewall/...` passes - [ ] No other lines in InitNetwork() changed **QA Scenarios**: ``` Scenario: Verify ICMP rule is correct Tool: Bash (grep) Steps: 1. grep "meta l4proto icmp" apps/server-core/internal/firewall/nftables_linux.go 2. grep "icmp type echo-request" apps/server-core/internal/firewall/nftables_linux.go Expected Result: First grep returns match, second grep returns nothing Evidence: .sisyphus/evidence/task-1-icmp-rule.txt Scenario: Verify Docker bridge rules exist Tool: Bash (grep) Steps: 1. grep "fwd_wg_docker" apps/server-core/internal/firewall/nftables_linux.go 2. grep "172.24.0.0/16" apps/server-core/internal/firewall/nftables_linux.go 3. grep "172.17.0.0/16" apps/server-core/internal/firewall/nftables_linux.go Expected Result: All 3 greps return matches Evidence: .sisyphus/evidence/task-1-docker-rules.txt Scenario: Verify dedup check pattern Tool: Bash (grep) Steps: 1. grep "fwd_wg_docker" apps/server-core/internal/firewall/nftables_linux.go | head -5 Expected Result: Shows both the grep check command AND the nft insert command Evidence: .sisyphus/evidence/task-1-dedup-pattern.txt ``` **Commit**: YES - Message: `fix(nftables): InitNetwork ICMP all, Docker bridge accept, base INPUT rules` - Files: `apps/server-core/internal/firewall/nftables_linux.go` - Pre-commit: `go vet ./internal/firewall/...` - [x] 2. Commit, Push, Deploy to Server **What to do**: 1. In `apps/server-core/`: `git add -A && git commit` with the fix message, then `git push` 2. In root `Nexus-Guard-Suite/`: `git add apps/server-core && git commit && git push` 3. SSH to server: `cd /root/Nexus-Guard-Suite && bash update.sh --force` 4. Wait for deployment to complete **Must NOT do**: - Do NOT build binary locally - Do NOT create temp files on server - Do NOT use `nft flush` on server - Do NOT modify any code files **Recommended Agent Profile**: - **Category**: `quick` - Reason: Simple git + SSH commands, well-documented in AGENTS.md - **Skills**: [] **Parallelization**: - **Can Run In Parallel**: NO - **Parallel Group**: Wave 2 (solo) - **Blocks**: Task 3 (verify) - **Blocked By**: Task 1 (code change) **References**: - `D:\www-project\NexusGuard\connect_remote.txt` — SSH credentials (HOST=172.20.8.191, USER=root) - `D:\www-project\NexusGuard\update.sh` — Docker rebuild script **Acceptance Criteria**: - [ ] Submodule HEAD updated (new commit hash) - [ ] Root repo HEAD updated - [ ] Server container restarted successfully - [ ] `docker ps` shows server-core running **QA Scenarios**: ``` Scenario: Verify deployment Tool: SSH (bash) Steps: 1. ssh root@172.20.8.191 'docker ps | grep server-core' 2. ssh root@172.20.8.191 'docker logs nexus-guard-suite-server-core-1 2>&1 | tail -5' Expected Result: Container running, logs show clean startup Evidence: .sisyphus/evidence/task-2-deployment.txt ``` **Commit**: NO (commit done as part of task) - [x] 3. Verify nftables Rules and Connectivity on Live Server **What to do**: 1. SSH to server, run `nft list table ip nexusguard` and verify: - INPUT chain has `meta l4proto icmp accept comment "input_icmp_all"` - FORWARD chain has `fwd_wg_docker` rules for 172.24.0.0/16 and 172.17.0.0/16 - All existing rules intact (server_wg1, input_estab, input_wg_api, etc.) 2. Test from server: `ping -c 3 10.172.21.3` — should get replies 3. Ask user to test from client: `ping 10.172.21.1` and `curl -v http://10.172.21.1:80` 4. Verify nft counters increment when traffic flows **Must NOT do**: - Do NOT modify any nft rules during verification - Do NOT flush or recreate chains **Recommended Agent Profile**: - **Category**: `quick` - Reason: SSH verification commands only - **Skills**: [] **Parallelization**: - **Can Run In Parallel**: NO - **Parallel Group**: Wave 2 (after Task 2) - **Blocks**: F1-F4 - **Blocked By**: Task 2 (deployment) **References**: - `D:\www-project\NexusGuard\connect_remote.txt` — SSH credentials - `D:\www-project\NexusGuard\AGENTS.md` — WireGuard AllowedIPs architecture rules **Acceptance Criteria**: - [ ] INPUT chain has `meta l4proto icmp` (not `icmp type echo-request`) - [ ] FORWARD chain has `fwd_wg_docker` for 172.24.0.0/16 - [ ] FORWARD chain has `fwd_wg_docker0` for 172.17.0.0/16 - [ ] Server can ping gogo3 (10.172.21.3) - [ ] Client can ping server (10.172.21.1) - [ ] Client can curl http://10.172.21.1:80 **QA Scenarios**: ``` Scenario: Verify INPUT chain ICMP rule Tool: SSH (bash) Steps: 1. ssh root@172.20.8.191 'nft list chain ip nexusguard input | grep icmp' Expected Result: Shows `meta l4proto icmp accept comment "input_icmp_all"` Evidence: .sisyphus/evidence/task-3-input-icmp.txt Scenario: Verify FORWARD chain Docker rules Tool: SSH (bash) Steps: 1. ssh root@172.20.8.191 'nft list chain ip nexusguard forward | grep docker' Expected Result: Shows both fwd_wg_docker (172.24.0.0/16) and fwd_wg_docker0 (172.17.0.0/16) Evidence: .sisyphus/evidence/task-3-forward-docker.txt Scenario: Server ping client Tool: SSH (bash) Steps: 1. ssh root@172.20.8.191 'ping -c 3 10.172.21.3' Expected Result: 3 replies, 0% packet loss Evidence: .sisyphus/evidence/task-3-ping-client.txt Scenario: Client connectivity (requires user) Tool: User prompt Steps: 1. Ask user to run from gogo3 client: `ping 10.172.21.1` 2. Ask user to run from gogo3 client: `curl -v http://10.172.21.1:80` Expected Result: Ping replies, curl returns 200 Evidence: User provides output ``` **Commit**: NO --- ## Final Verification Wave (MANDATORY — after ALL implementation tasks) > 4 review agents run in PARALLEL. ALL must APPROVE. Rejection → fix → re-run. - [x] F1. **Plan Compliance Audit** — `oracle` Read the plan end-to-end. For each "Must Have": verify implementation exists (read file, curl endpoint, check schema). For each "Must NOT Have": search codebase for forbidden patterns — reject with file:line if found. Check evidence files exist in .sisyphus/evidence/. Compare deliverables against plan. Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT` - [x] F2. **Code Quality Review** — `unspecified-high` Run `go vet ./...` on changed packages. Review all changed files for: empty catches, console.logs in prod code, commented-out code, unused imports. Check AI slop: excessive comments, over-abstraction, generic variable names. Output: `Build [PASS/FAIL] | Files [N clean/N issues] | VERDICT` - [x] F3. **Real Manual QA** — `unspecified-high` (equipment: SSH to 172.20.8.191) SSH to server. Run: `nft list table ip nexusguard` and verify rules. Then test: `ping 10.172.21.3` from server. From client: `ping 10.172.21.1` and `curl -v http://10.172.21.1:80`. Test negative case: verify that WG isolation default drop still blocks unauthorized traffic. Output: `Connectivity [N/N pass] | Firewall [N correct rules] | Negative [PASS/FAIL] | VERDICT` - [x] F4. **Scope Fidelity Check** — `deep` For each task: read "What to do", read actual diff (git log/diff). Verify 1:1 — everything in spec was built (no missing), nothing beyond spec was built (no creep). Check "Must NOT do" compliance. Flag unauthorized changes. Output: `Tasks [N/N compliant] | Contamination [CLEAN/N issues] | VERDICT` --- ## Commit Strategy - **Task 1**: `fix(nftables): InitNetwork ICMP, Docker bridge, INPUT base rules` → `apps/server-core/` - **Task 2**: Submodule push + root push + deploy via `update.sh --force` --- ## Success Criteria ### Verification Commands ```bash # From server (SSH root@172.20.8.191): nft list chain ip nexusguard input # Expected: meta l4proto icmp accept comment "input_icmp_all" nft list chain ip nexusguard forward # Expected: fwd_wg_docker accept for 172.24.0.0/16 and 172.17.0.0/16 # From client (gogo3): ping 10.172.21.1 # Expected: replies # From server: ping 10.172.21.3 # Expected: replies # From client: curl -s -o /dev/null -w "%{http_code}" http://10.172.21.1:80 # Expected: 200 ``` ### Final Checklist - [x] All "Must Have" present - [x] All "Must NOT Have" absent - [x] Server deployed and running - [ ] Both peers can ping server - [x] Server can ping both peers - [ ] Port 80 accessible from WireGuard client