docs: add WireGuard AllowedIPs server vs client architecture rule
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 4s
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 4s
NexusGuard CI / dashboard-dist (push) Has been skipped
Documents the critical distinction between server-side (kernel routing table) and client-side (conf file) AllowedIPs to prevent the same bug from recurring. Server-side: always InternalIP/32 per peer. Client-side: use EndpointAllowedIPs from DB.
This commit is contained in:
@@ -83,6 +83,43 @@ NexusGuard SD-WAN Suite — Enterprise Zero-Trust SD-WAN with WireGuard tunnelin
|
||||
- **NEVER** force push
|
||||
- **NEVER** create cross-phase workarounds
|
||||
|
||||
## WIREGUARD AllowedIPs — SERVER vs CLIENT (CRITICAL)
|
||||
|
||||
WireGuard `AllowedIPs` has **two different meanings** depending on context. Mixing them causes only 1 peer to work.
|
||||
|
||||
### Rule
|
||||
| Context | Where | Value | Purpose |
|
||||
|---------|-------|-------|---------|
|
||||
| **Server-side** (kernel `wg set`) | `SyncLocalPeers()` → `peer_sync.go` | `InternalIP/32` per peer | WireGuard routing table — each IP must belong to exactly ONE peer |
|
||||
| **Client-side** (`.conf` file) | `getDeviceConfig()` → `peers.go` | `EndpointAllowedIPs` from DB (e.g. `/24`, `0.0.0.0/0`) | Tells client which traffic routes through VPN tunnel |
|
||||
| **Firewall** (nftables) | `AddForwardRule()` → `nftables_linux.go` | `EndpointAllowedIPs` from DB | Controls which IPs peer can reach via forwarding |
|
||||
|
||||
### Why
|
||||
WireGuard uses `AllowedIPs` as an **internal routing table**. When two peers share the same `/24`, WireGuard assigns the AllowedIPs to the **last peer configured only** — the first peer gets `(none)`. This is not a bug; it's how WireGuard routing works.
|
||||
|
||||
### Anti-pattern
|
||||
```go
|
||||
// WRONG — uses client config for server-side routing
|
||||
if d.EndpointAllowedIPs != "" {
|
||||
allowedIPs = d.EndpointAllowedIPs // "10.172.21.0/24" ← SAME for both peers!
|
||||
}
|
||||
```
|
||||
|
||||
### Correct pattern
|
||||
```go
|
||||
// CORRECT — server-side always /32 per peer
|
||||
allowedIPs := *d.InternalIP + "/32" // "10.172.21.2/32" for gogo2
|
||||
if d.AllowInternet {
|
||||
allowedIPs = "0.0.0.0/0"
|
||||
}
|
||||
// Do NOT override with EndpointAllowedIPs here
|
||||
```
|
||||
|
||||
### Database field: `endpoint_allowed_ips`
|
||||
- Used for **client config** and **firewall rules**
|
||||
- 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
|
||||
|
||||
## 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