NAT Testing - Quick Reference
Overview
Tests P2P connectivity through Network Address Translation (NAT) using Incus container-based NAT routers to verify DMS nodes can traverse NAT via libp2p relay and AutoNAT mechanisms.
NAT Simulation Design
Architecture
┌─────────────────── Incus Host ───────────────────┐
│ │
│ NAT Router 1 (Container) Relay (Container) │
│ ┌──────────────┐ ┌──────────┐ │
│ │ eth0: public │ │ public │ │
│ │ eth1: private├─────┐ │ address │ │
│ └──────────────┘ │ └──────────┘ │
│ │ │ │ │
│ iptables NAT Alice (VM) │ │
│ │ 172.16.1.10 │ │
│ │ │ │ │
│ NAT Router 2 │ Bob (VM) │
│ ┌──────────────┐ │ 172.16.2.10 │
│ │ eth0: public │ │ │ │
│ │ eth1: private├─────┴──────────────┘ │
│ └──────────────┘ │
│ │ │
│ iptables NAT │
└───────────────────────────────────────────────────┘
Design Rationale
Why Container-Based NAT Routers?
- True NAT behavior: Actual iptables NAT, not simulated
- Isolation: Each node has its own private network (172.16.x.0/24)
- No host pollution: All configuration inside containers
- AutoNAT compatibility: Private IPs trigger proper NAT detection
Two-Layer Firewall Approach:
Layer 1 - Host-level iptables (blocks cross-NAT traffic):
iptables -I FORWARD -s 172.16.1.0/24 -d 172.16.2.0/24 -j DROP
Prevents Incus host kernel from routing between private networks.
Layer 2 - NAT Router container iptables (provides NAT + AutoNAT detection):
# Block inbound NEW (AutoNAT probes fail → NAT detected)
iptables -A FORWARD -i eth0 -o eth1 --ctstate NEW -j DROP
# Allow outbound (Alice/Bob can reach Relay)
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
# Symmetrical NAT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE --random-fully
Symmetrical NAT:
- Each unique connection gets random external port (
--random-fully) - Most restrictive NAT type
- Forces relay usage (hole punching won't work)
File Structure
tests/acceptance/
├── nat_test.go # Test entry point
├── features/nat.feature # BDD scenario
├── steps/nat.go # Step implementations
├── utils/
│ ├── nat_router.go # NAT router management
│ ├── incus.go # Incus utilities
│ └── cli.go # DMS CLI helpers
└── NAT_TESTING_README.md # This file
Key Configuration
NAT Router Setup (utils/nat_router.go)
CreateNATRouterContainer:
- Creates Ubuntu container with dual NICs (external + internal)
- Configures iptables for symmetrical NAT
- Blocks cross-NAT traffic and inbound NEW connections
Host Firewall Rules:
AddHostCrossNATBlocking(): Adds temporary iptables rulesRemoveHostCrossNATBlocking(): Cleans up on test completion
Test Flow (features/nat.feature)
- Setup: Create Alice & Bob behind isolated NAT networks
- Direct Test: Alice → Bob (should FAIL due to NAT)
- Relay Setup: Create public relay, connect Alice & Bob
- Wait: 90 seconds for AutoNAT detection + relay circuits
- Verify: Alice & Bob advertise
/p2p-circuitaddresses - Relay Test: Alice → Relay → Bob (should SUCCEED)
Running the Test
Prerequisites
# 1. Build DMS binary
go build -o tests/acceptance/builds/dms_linux_amd64 .
# 2. Verify Incus running
incus list
Run Test
# Requires sudo for host-level iptables
sudo make run-acceptance-TestNAT INSTANCE_TYPE=vm
Test Duration: ~4-5 minutes
Expected Output
[SETUP] Creating 2 DMS nodes behind container-based NAT routers...
[HOST-FIREWALL] Adding rules to block traffic from 172.16.1.1/24...
[NAT-ROUTER] NAT router configured with symmetrical NAT (--random-fully)
...
[CONNECTION] Alice → Bob FAILED ✅ (NAT isolation working)
...
[RELAY] Alice successfully connected to relay
[RELAY] Bob successfully connected to relay
...
[RELAY ADDRESS] ✓ Relay addresses found
...
[CONNECTION] Alice → Bob via relay SUCCEEDED ✅
Key Commands
Makefile Targets
# Run NAT test (recommended)
sudo make run-acceptance-TestNAT INSTANCE_TYPE=vm
# Build test binary with capabilities (experimental)
make build-acceptance-tests
make setcap-acceptance
Manual Test Execution
cd tests/acceptance
sudo INSTANCE_TYPE=vm go test -test.v -tags=acceptance -test.run "^TestNAT/"
Network Configuration
Private Networks
nat-net-1: 172.16.1.0/24 (Alice)nat-net-2: 172.16.2.0/24 (Bob)- Each network:
ipv4.nat=false(router handles NAT)
NAT Routers
- External: incusbr0 (10.x.x.x)
- Internal: 172.16.x.1 (gateway for clients)
- Type: Ubuntu container (not VM)
DMS Nodes
- Type: VM or Container (set via
INSTANCE_TYPE) - Network: Single NIC on private network
- Gateway: NAT router IP (172.16.x.1)
Cleanup
Automatic:
- Host iptables rules removed on test completion
- Incus instances and networks deleted
- No persistent changes to host
Manual (if test interrupted):
# Remove host firewall rules
sudo iptables -L FORWARD -n --line-numbers | grep NUNET-NAT-TEST
sudo iptables -D FORWARD <line-number>
# Delete Incus resources
incus list | grep acc-test | awk '{print $2}' | xargs -I {} incus delete {} --force
incus network list | grep nat-net | awk '{print $2}' | xargs -I {} incus network delete {}
Why Sudo is Required
Modern iptables (nf_tables backend) requires root privileges for:
- Modifying FORWARD chain
- Accessing
/run/xtables.lock - Interacting with netfilter kernel modules
The test uses temporary iptables rules that are automatically cleaned up.
Troubleshooting
Direct Connection Still Works
Check host firewall:
sudo iptables -L FORWARD -n | grep NUNET-NAT-TEST
# Should see DROP rules for cross-NAT traffic
Check NAT router:
incus exec acc-test-nat-router-1 -- iptables -L FORWARD -n
# Should see NEW connection blocking
No Relay Addresses Advertised
Check AutoNAT detection:
- Relay must be on different network (incusbr0) than Alice/Bob
- Wait full 90 seconds (60s boot delay + 30s for circuits)
- Verify relay is running:
incus exec acc-test-relay -- pgrep nunet
Test Hangs or Times Out
Check VM networking:
incus exec acc-test-alice -- ip route
# Should show: default via 172.16.1.1
Reference
- Full Documentation:
NAT_TESTING_GUIDE.md(detailed troubleshooting) - Test Scenario:
features/nat.feature(BDD specification) - Implementation:
steps/nat.go(step definitions) - NAT Router Code:
utils/nat_router.go(container management)