Files
Nexus-Guard-Suite/.omo/plans/archive/firewall-initnetwork-fix.md
datadunia cbacfea7f2
NexusGuard CI / server-core-test (push) Failing after 3m6s
NexusGuard CI / server-core-build (push) Has been skipped
NexusGuard CI / device-agent-test (push) Failing after 4s
NexusGuard CI / device-agent-cross-build (amd64, linux) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (amd64, windows) (push) Has been skipped
NexusGuard CI / device-agent-cross-build (arm64, linux) (push) Has been skipped
NexusGuard CI / dashboard-test (push) Failing after 4s
NexusGuard CI / dashboard-dist (push) Has been skipped
chore: update submodule refs, clean up plans/evidence, update .gitignore
2026-06-07 23:53:15 +07:00

16 KiB

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

  • 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 <wgSubnet> ip daddr 172.24.0.0/16 accept comment "fwd_wg_docker"
      • nft insert rule ip nexusguard forward ip saddr <wgSubnet> 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/...
  • 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)

  • 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.

  • F1. Plan Compliance Auditoracle 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

  • F2. Code Quality Reviewunspecified-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

  • F3. Real Manual QAunspecified-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

  • F4. Scope Fidelity Checkdeep 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 rulesapps/server-core/
  • Task 2: Submodule push + root push + deploy via update.sh --force

Success Criteria

Verification Commands

# 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

  • All "Must Have" present
  • All "Must NOT Have" absent
  • Server deployed and running
  • Both peers can ping server
  • Server can ping both peers
  • Port 80 accessible from WireGuard client