docs: add INPUT vs FORWARD chain architecture to AGENTS.md
NexusGuard CI / server-core-test (push) Failing after 4s
NexusGuard CI / server-core-build (push) Has been skipped
NexusGuard CI / device-agent-test (push) Failing after 3s
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 5s
NexusGuard CI / dashboard-dist (push) Has been skipped
NexusGuard CI / server-core-test (push) Failing after 4s
NexusGuard CI / server-core-build (push) Has been skipped
NexusGuard CI / device-agent-test (push) Failing after 3s
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 5s
NexusGuard CI / dashboard-dist (push) Has been skipped
This commit is contained in:
@@ -120,6 +120,48 @@ if d.AllowInternet {
|
||||
- NOT used for server-side WireGuard kernel config
|
||||
- Example: `10.172.21.0/24` allows peer to reach full subnet via firewall + routes full subnet through VPN on client
|
||||
|
||||
## FIREWALL CHAINS — INPUT vs FORWARD (CRITICAL)
|
||||
|
||||
nftables traffic enters different chains depending on destination:
|
||||
- **Traffic TO server's own IP** (e.g. 10.172.21.1) → **INPUT chain**
|
||||
- **Traffic THROUGH server** (peer-to-peer, e.g. 10.172.21.2 → 10.172.21.3) → **FORWARD chain**
|
||||
|
||||
### Rule routing in code
|
||||
| Destination | Chain | Method |
|
||||
|-------------|-------|--------|
|
||||
| Server's own `interface_address` | INPUT | `AddInputFirewallRule()` |
|
||||
| Other peer IPs / subnets | FORWARD | `AddFirewallRule()` |
|
||||
|
||||
### Detection logic (syncRuleToFirewall)
|
||||
```go
|
||||
serverIP = strings.Split(localServer.InterfaceAddress, "/")[0]
|
||||
destBase = strings.Split(destCIDR, "/")[0]
|
||||
if destBase == serverIP {
|
||||
fw.AddInputFirewallRule(...) // → INPUT chain
|
||||
} else {
|
||||
fw.AddFirewallRule(...) // → FORWARD chain
|
||||
}
|
||||
```
|
||||
|
||||
### Anti-pattern
|
||||
```go
|
||||
// WRONG — all rules go to FORWARD, server IP rules are dead
|
||||
fw.AddFirewallRule(...) // for dest=10.172.21.1 → enters FORWARD chain → never matched
|
||||
```
|
||||
|
||||
### Correct pattern
|
||||
```go
|
||||
// CORRECT — detect server IP, route to correct chain
|
||||
if destBase == serverIP {
|
||||
fw.AddInputFirewallRule(...) // → INPUT chain (matches traffic TO server)
|
||||
} else {
|
||||
fw.AddFirewallRule(...) // → FORWARD chain (matches traffic THROUGH server)
|
||||
}
|
||||
```
|
||||
|
||||
### Why
|
||||
Traffic to server's own IP is processed by INPUT chain, not FORWARD chain. Placing rules in FORWARD chain for server-bound traffic makes them dead rules that never match.
|
||||
|
||||
## UNIQUE STYLES
|
||||
- **Zero-Attack Surface**: `/auth/register` locked; admin via `-create-admin` CLI only
|
||||
- **Stealth Agent**: No `/etc/wireguard/` — config in memory only
|
||||
|
||||
Reference in New Issue
Block a user