From 68b9652aa9fc47b19f230ac07db1d4946d3a7782 Mon Sep 17 00:00:00 2001 From: Origami74 Date: Wed, 18 Feb 2026 00:50:35 +0000 Subject: [PATCH] feat(docker): Add iperf3 testing, config templating, and test improvements Docker testing infrastructure: - Add iperf3 bandwidth testing (10s duration, 8 parallel streams) - Install iperf3 in container, auto-start as daemon alongside FIPS - Support --live flag for real-time iperf3 output during tests - Aggregate [SUM] bandwidth reporting with correct units Configuration templating system: - Single node.template.yaml replacing per-node hand-written configs - Topology definitions in configs/topologies/ (mesh.yaml, chain.yaml) - generate-configs.sh script for automatic config generation - Integrated into build.sh for regeneration on build - Generated configs in generated-configs/ (gitignored) Ping test improvements: - Reduce to 1 ping per test for faster execution (~10s vs ~30s) - Show response times (RTT) for each test - Add Ctrl+C trap for clean exit - Reduce convergence wait from 5s to 3s --- examples/docker-network/.gitignore | 1 + examples/docker-network/Dockerfile | 6 +- examples/docker-network/README.md | 68 +++++++- .../docker-network/configs/chain/node-a.yaml | 31 ---- .../docker-network/configs/chain/node-b.yaml | 37 ----- .../docker-network/configs/chain/node-c.yaml | 37 ----- .../docker-network/configs/chain/node-d.yaml | 37 ----- .../docker-network/configs/chain/node-e.yaml | 31 ---- .../docker-network/configs/mesh/node-a.yaml | 37 ----- .../docker-network/configs/mesh/node-b.yaml | 31 ---- .../docker-network/configs/mesh/node-c.yaml | 43 ----- .../docker-network/configs/mesh/node-d.yaml | 43 ----- .../docker-network/configs/mesh/node-e.yaml | 43 ----- .../docker-network/configs/node.template.yaml | 25 +++ .../configs/topologies/chain.yaml | 42 +++++ .../configs/topologies/mesh.yaml | 44 +++++ examples/docker-network/docker-compose.yml | 20 +-- examples/docker-network/scripts/build.sh | 3 + .../scripts/generate-configs.sh | 155 ++++++++++++++++++ examples/docker-network/scripts/iperf-test.sh | 127 ++++++++++++++ examples/docker-network/scripts/ping-test.sh | 22 ++- 21 files changed, 492 insertions(+), 391 deletions(-) delete mode 100644 examples/docker-network/configs/chain/node-a.yaml delete mode 100644 examples/docker-network/configs/chain/node-b.yaml delete mode 100644 examples/docker-network/configs/chain/node-c.yaml delete mode 100644 examples/docker-network/configs/chain/node-d.yaml delete mode 100644 examples/docker-network/configs/chain/node-e.yaml delete mode 100644 examples/docker-network/configs/mesh/node-a.yaml delete mode 100644 examples/docker-network/configs/mesh/node-b.yaml delete mode 100644 examples/docker-network/configs/mesh/node-c.yaml delete mode 100644 examples/docker-network/configs/mesh/node-d.yaml delete mode 100644 examples/docker-network/configs/mesh/node-e.yaml create mode 100644 examples/docker-network/configs/node.template.yaml create mode 100644 examples/docker-network/configs/topologies/chain.yaml create mode 100644 examples/docker-network/configs/topologies/mesh.yaml create mode 100755 examples/docker-network/scripts/generate-configs.sh create mode 100755 examples/docker-network/scripts/iperf-test.sh diff --git a/examples/docker-network/.gitignore b/examples/docker-network/.gitignore index 52be687..0a254e6 100644 --- a/examples/docker-network/.gitignore +++ b/examples/docker-network/.gitignore @@ -1 +1,2 @@ fips +generated-configs \ No newline at end of file diff --git a/examples/docker-network/Dockerfile b/examples/docker-network/Dockerfile index e7cf8d3..6145f2a 100644 --- a/examples/docker-network/Dockerfile +++ b/examples/docker-network/Dockerfile @@ -2,7 +2,7 @@ FROM debian:bookworm-slim RUN apt-get update && \ apt-get install -y --no-install-recommends \ - iproute2 iputils-ping dnsutils openssh-client openssh-server && \ + iproute2 iputils-ping dnsutils openssh-client openssh-server iperf3 && \ rm -rf /var/lib/apt/lists/* # Setup SSH server with no authentication (test only!) @@ -16,5 +16,5 @@ RUN mkdir -p /var/run/sshd && \ COPY fips /usr/local/bin/ RUN chmod +x /usr/local/bin/fips -# Start SSH server in background, then run FIPS -ENTRYPOINT ["/bin/bash", "-c", "/usr/sbin/sshd && exec fips --config /etc/fips/fips.yaml"] +# Start SSH server and iperf3 server in background, then run FIPS +ENTRYPOINT ["/bin/bash", "-c", "/usr/sbin/sshd && iperf3 -s -D && exec fips --config /etc/fips/fips.yaml"] diff --git a/examples/docker-network/README.md b/examples/docker-network/README.md index 3f17d06..b2b6a45 100644 --- a/examples/docker-network/README.md +++ b/examples/docker-network/README.md @@ -24,7 +24,8 @@ Build the binary and copy it to the docker context: ```bash docker compose --profile mesh build docker compose --profile mesh up -d -./scripts/ping-test.sh mesh # 20/20 expected +./scripts/ping-test.sh mesh # 20/20 expected (with response times) +./scripts/iperf-test.sh mesh # bandwidth test docker compose --profile mesh down ``` @@ -33,7 +34,8 @@ docker compose --profile mesh down ```bash docker compose --profile chain build docker compose --profile chain up -d -./scripts/ping-test.sh chain # 6/6 expected +./scripts/ping-test.sh chain # 6/6 expected (with response times) +./scripts/iperf-test.sh chain # bandwidth test docker compose --profile chain down ``` @@ -75,6 +77,68 @@ The ping test covers: - Multi-hop: A→C (2 hops), A→D (3 hops), A→E (4 hops) - Reverse: E→A (4 hops) +## Performance Testing + +The `iperf-test.sh` script measures bandwidth between nodes using iperf3: + +```bash +./scripts/iperf-test.sh [mesh|chain] +``` + +The test runs iperf3 with the following parameters: +- Duration: 10 seconds (`-t 10`) +- Parallel streams: 8 (`-P 8`) +- Protocol: TCP over IPv6 + +This exercises the full FIPS stack including encryption, routing, and TUN device performance. + +## Configuration Management + +Node configurations are generated from templates to ensure consistency across all nodes: + +### File Structure + +``` +configs/ +├── node.template.yaml # Single template for all node configs +├── topologies/ +│ ├── mesh.yaml # Mesh topology definition (reference) +│ └── chain.yaml # Chain topology definition (reference) +└── [mesh|chain]/ # Original hand-written configs (deprecated) + +generated-configs/ # Auto-generated configs (gitignored) +├── mesh/ +│ ├── node-a.yaml +│ ├── node-b.yaml +│ └── ... +└── chain/ + ├── node-a.yaml + └── ... +``` + +### Topology Files + +The `configs/topologies/` directory contains YAML files documenting each network topology: +- Node identities (nsec, npub) +- Docker IP addresses +- Peer connections for each node + +These files serve as reference documentation and make it easy to understand and modify network topologies. + +### Generating Configs + +The `scripts/generate-configs.sh` script reads the topology definitions (embedded in the script) and generates node configs into `generated-configs/`: + +```bash +./scripts/generate-configs.sh [mesh|chain|all] +``` + +The build script (`scripts/build.sh`) automatically regenerates configs before building Docker images. + +### Modifying Topologies + +To change network topologies, edit the `get_mesh_peers()` or `get_chain_peers()` functions in `generate-configs.sh`, then update the corresponding YAML file in `configs/topologies/` for documentation. + ## Node Identities All nodes use deterministic test keys (not for production use). diff --git a/examples/docker-network/configs/chain/node-a.yaml b/examples/docker-network/configs/chain/node-a.yaml deleted file mode 100644 index b76290e..0000000 --- a/examples/docker-network/configs/chain/node-a.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# FIPS Node A configuration (chain topology: A-B-C-D-E) -# -# Identity: npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m -# FIPS address: fd69:e08d:65cc:3a6b:9c2c:2ac4:bd40:5e4b - -node: - identity: - nsec: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le" - alias: "node-b" - addresses: - - transport: udp - addr: "172.20.0.11:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/chain/node-b.yaml b/examples/docker-network/configs/chain/node-b.yaml deleted file mode 100644 index d6f6646..0000000 --- a/examples/docker-network/configs/chain/node-b.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# FIPS Node B configuration (chain topology: A-B-C-D-E) -# -# Identity: npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le -# FIPS address: fd8e:302c:287e:b48d:6268:122f:da76:b77 - -node: - identity: - nsec: "b102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fb0" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m" - alias: "node-a" - addresses: - - transport: udp - addr: "172.20.0.10:4000" - connect_policy: auto_connect - - npub: "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6" - alias: "node-c" - addresses: - - transport: udp - addr: "172.20.0.12:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/chain/node-c.yaml b/examples/docker-network/configs/chain/node-c.yaml deleted file mode 100644 index ca1457a..0000000 --- a/examples/docker-network/configs/chain/node-c.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# FIPS Node C configuration (chain topology: A-B-C-D-E) -# -# Identity: npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6 -# FIPS address: fdac:a221:4069:5044:c41:d550:280e:d15a - -node: - identity: - nsec: "c102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fc0" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le" - alias: "node-b" - addresses: - - transport: udp - addr: "172.20.0.11:4000" - connect_policy: auto_connect - - npub: "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl" - alias: "node-d" - addresses: - - transport: udp - addr: "172.20.0.13:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/chain/node-d.yaml b/examples/docker-network/configs/chain/node-d.yaml deleted file mode 100644 index aba5b89..0000000 --- a/examples/docker-network/configs/chain/node-d.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# FIPS Node D configuration (chain topology: A-B-C-D-E) -# -# Identity: npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl -# FIPS address: fdb6:8411:a191:6d48:efc6:b8bd:63bb:1cd7 - -node: - identity: - nsec: "d102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fd0" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6" - alias: "node-c" - addresses: - - transport: udp - addr: "172.20.0.12:4000" - connect_policy: auto_connect - - npub: "npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4" - alias: "node-e" - addresses: - - transport: udp - addr: "172.20.0.14:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/chain/node-e.yaml b/examples/docker-network/configs/chain/node-e.yaml deleted file mode 100644 index 3fdb7ab..0000000 --- a/examples/docker-network/configs/chain/node-e.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# FIPS Node E configuration (chain topology: A-B-C-D-E) -# -# Identity: npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4 -# FIPS address: fded:7dee:d386:a546:2a43:5103:16d8:4f3c - -node: - identity: - nsec: "e102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe0" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl" - alias: "node-d" - addresses: - - transport: udp - addr: "172.20.0.13:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/mesh/node-a.yaml b/examples/docker-network/configs/mesh/node-a.yaml deleted file mode 100644 index 1433d8e..0000000 --- a/examples/docker-network/configs/mesh/node-a.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# FIPS Node A configuration (mesh topology) -# -# Identity: npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m -# FIPS address: fd69:e08d:65cc:3a6b:9c2c:2ac4:bd40:5e4b - -node: - identity: - nsec: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl" - alias: "node-d" - addresses: - - transport: udp - addr: "172.20.0.13:4000" - connect_policy: auto_connect - - npub: "npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4" - alias: "node-e" - addresses: - - transport: udp - addr: "172.20.0.14:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/mesh/node-b.yaml b/examples/docker-network/configs/mesh/node-b.yaml deleted file mode 100644 index 13150d1..0000000 --- a/examples/docker-network/configs/mesh/node-b.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# FIPS Node B configuration (mesh topology) -# -# Identity: npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le -# FIPS address: fd8e:302c:287e:b48d:6268:122f:da76:b77 - -node: - identity: - nsec: "b102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fb0" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6" - alias: "node-c" - addresses: - - transport: udp - addr: "172.20.0.12:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/mesh/node-c.yaml b/examples/docker-network/configs/mesh/node-c.yaml deleted file mode 100644 index 98c4c2c..0000000 --- a/examples/docker-network/configs/mesh/node-c.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# FIPS Node C configuration (mesh topology) -# -# Identity: npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6 -# FIPS address: fdac:a221:4069:5044:c41:d550:280e:d15a - -node: - identity: - nsec: "c102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fc0" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le" - alias: "node-b" - addresses: - - transport: udp - addr: "172.20.0.11:4000" - connect_policy: auto_connect - - npub: "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl" - alias: "node-d" - addresses: - - transport: udp - addr: "172.20.0.13:4000" - connect_policy: auto_connect - - npub: "npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4" - alias: "node-e" - addresses: - - transport: udp - addr: "172.20.0.14:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/mesh/node-d.yaml b/examples/docker-network/configs/mesh/node-d.yaml deleted file mode 100644 index d564d1d..0000000 --- a/examples/docker-network/configs/mesh/node-d.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# FIPS Node D configuration (mesh topology) -# -# Identity: npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl -# FIPS address: fdb6:8411:a191:6d48:efc6:b8bd:63bb:1cd7 - -node: - identity: - nsec: "d102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fd0" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m" - alias: "node-a" - addresses: - - transport: udp - addr: "172.20.0.10:4000" - connect_policy: auto_connect - - npub: "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6" - alias: "node-c" - addresses: - - transport: udp - addr: "172.20.0.12:4000" - connect_policy: auto_connect - - npub: "npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4" - alias: "node-e" - addresses: - - transport: udp - addr: "172.20.0.14:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/mesh/node-e.yaml b/examples/docker-network/configs/mesh/node-e.yaml deleted file mode 100644 index 3c1dea5..0000000 --- a/examples/docker-network/configs/mesh/node-e.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# FIPS Node E configuration (mesh topology) -# -# Identity: npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4 -# FIPS address: fded:7dee:d386:a546:2a43:5103:16d8:4f3c - -node: - identity: - nsec: "e102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe0" - -tun: - enabled: true - name: fips0 - mtu: 1280 - -dns: - enabled: true - bind_addr: "127.0.0.1" - port: 53 - -transports: - udp: - bind_addr: "0.0.0.0:4000" - mtu: 1472 - -peers: - - npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m" - alias: "node-a" - addresses: - - transport: udp - addr: "172.20.0.10:4000" - connect_policy: auto_connect - - npub: "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6" - alias: "node-c" - addresses: - - transport: udp - addr: "172.20.0.12:4000" - connect_policy: auto_connect - - npub: "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl" - alias: "node-d" - addresses: - - transport: udp - addr: "172.20.0.13:4000" - connect_policy: auto_connect diff --git a/examples/docker-network/configs/node.template.yaml b/examples/docker-network/configs/node.template.yaml new file mode 100644 index 0000000..27a64c6 --- /dev/null +++ b/examples/docker-network/configs/node.template.yaml @@ -0,0 +1,25 @@ +# FIPS Node {{NODE_NAME}} configuration ({{TOPOLOGY}} topology) +# +# Identity: {{NPUB}} + +node: + identity: + nsec: "{{NSEC}}" + +tun: + enabled: true + name: fips0 + mtu: 1280 + +dns: + enabled: true + bind_addr: "127.0.0.1" + port: 53 + +transports: + udp: + bind_addr: "0.0.0.0:4000" + mtu: 1472 + +peers: +{{PEERS}} \ No newline at end of file diff --git a/examples/docker-network/configs/topologies/chain.yaml b/examples/docker-network/configs/topologies/chain.yaml new file mode 100644 index 0000000..f0b8754 --- /dev/null +++ b/examples/docker-network/configs/topologies/chain.yaml @@ -0,0 +1,42 @@ +# Chain Topology Definition +# +# Five nodes in a linear chain: A — B — C — D — E +# Each node peers only with its immediate neighbors. Multi-hop communication +# (e.g., A to E) requires the discovery protocol to find routes through +# intermediate nodes. + +nodes: + a: + nsec: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" + npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m" + docker_ip: "172.20.0.10" + peers: [b] + + b: + nsec: "b102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fb0" + npub: "npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le" + docker_ip: "172.20.0.11" + peers: [a, c] + + c: + nsec: "c102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fc0" + npub: "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6" + docker_ip: "172.20.0.12" + peers: [b, d] + + d: + nsec: "d102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fd0" + npub: "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl" + docker_ip: "172.20.0.13" + peers: [c, e] + + e: + nsec: "e102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe0" + npub: "npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4" + docker_ip: "172.20.0.14" + peers: [d] + +# Test Coverage: +# - Adjacent hops: A→B, B→C (1 hop each) +# - Multi-hop: A→C (2 hops), A→D (3 hops), A→E (4 hops) +# - Reverse: E→A (4 hops) \ No newline at end of file diff --git a/examples/docker-network/configs/topologies/mesh.yaml b/examples/docker-network/configs/topologies/mesh.yaml new file mode 100644 index 0000000..35f7e7e --- /dev/null +++ b/examples/docker-network/configs/topologies/mesh.yaml @@ -0,0 +1,44 @@ +# Mesh Topology Definition +# +# Five nodes with 6 bidirectional UDP links forming a sparse, fully connected +# graph. Not all nodes are direct peers — non-adjacent pairs require +# discovery-driven multi-hop routing to establish end-to-end sessions. + +nodes: + a: + nsec: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" + npub: "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m" + docker_ip: "172.20.0.10" + peers: [d, e] + + b: + nsec: "b102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fb0" + npub: "npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le" + docker_ip: "172.20.0.11" + peers: [c] + + c: + nsec: "c102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fc0" + npub: "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6" + docker_ip: "172.20.0.12" + peers: [b, d, e] + + d: + nsec: "d102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fd0" + npub: "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl" + docker_ip: "172.20.0.13" + peers: [a, c, e] + + e: + nsec: "e102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe0" + npub: "npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4" + docker_ip: "172.20.0.14" + peers: [a, c, d] + +# Spanning Tree Structure (rooted at node A): +# - A — D (tree edge, D's parent is A) +# - A — E (tree edge, E's parent is A) +# - C — D (tree edge, C's parent is D) +# - B — C (tree edge, B's parent is C) +# - D — E (non-tree link) +# - C — E (non-tree link) \ No newline at end of file diff --git a/examples/docker-network/docker-compose.yml b/examples/docker-network/docker-compose.yml index 3038153..61e0146 100644 --- a/examples/docker-network/docker-compose.yml +++ b/examples/docker-network/docker-compose.yml @@ -27,7 +27,7 @@ services: hostname: node-a volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/mesh/node-a.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/mesh/node-a.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.10 @@ -39,7 +39,7 @@ services: hostname: node-b volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/mesh/node-b.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/mesh/node-b.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.11 @@ -51,7 +51,7 @@ services: hostname: node-c volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/mesh/node-c.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/mesh/node-c.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.12 @@ -63,7 +63,7 @@ services: hostname: node-d volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/mesh/node-d.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/mesh/node-d.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.13 @@ -75,7 +75,7 @@ services: hostname: node-e volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/mesh/node-e.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/mesh/node-e.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.14 @@ -88,7 +88,7 @@ services: hostname: node-a volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/chain/node-a.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/chain/node-a.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.10 @@ -100,7 +100,7 @@ services: hostname: node-b volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/chain/node-b.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/chain/node-b.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.11 @@ -112,7 +112,7 @@ services: hostname: node-c volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/chain/node-c.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/chain/node-c.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.12 @@ -124,7 +124,7 @@ services: hostname: node-d volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/chain/node-d.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/chain/node-d.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.13 @@ -136,7 +136,7 @@ services: hostname: node-e volumes: - ./resolv.conf:/etc/resolv.conf:ro - - ./configs/chain/node-e.yaml:/etc/fips/fips.yaml:ro + - ./generated-configs/chain/node-e.yaml:/etc/fips/fips.yaml:ro networks: fips-net: ipv4_address: 172.20.0.14 diff --git a/examples/docker-network/scripts/build.sh b/examples/docker-network/scripts/build.sh index fc6d8a6..a2680f4 100755 --- a/examples/docker-network/scripts/build.sh +++ b/examples/docker-network/scripts/build.sh @@ -53,4 +53,7 @@ fi echo "Done. Binary at $DOCKER_DIR/fips" echo "" +echo "Generating node configurations from templates..." +"$SCRIPT_DIR/generate-configs.sh" all +echo "" echo "Next: cd $DOCKER_DIR && docker compose --profile mesh build" diff --git a/examples/docker-network/scripts/generate-configs.sh b/examples/docker-network/scripts/generate-configs.sh new file mode 100755 index 0000000..aea6570 --- /dev/null +++ b/examples/docker-network/scripts/generate-configs.sh @@ -0,0 +1,155 @@ +#!/bin/bash +# Generate FIPS node configuration files from template and topology definition. +# +# Usage: ./generate-configs.sh [mesh|chain|all] + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_DIR="$SCRIPT_DIR/../configs" +GENERATED_DIR="$SCRIPT_DIR/../generated-configs" +TEMPLATE_FILE="$CONFIG_DIR/node.template.yaml" + +# Node data lookup functions +get_nsec() { + case "$1" in + a) echo "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" ;; + b) echo "b102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fb0" ;; + c) echo "c102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fc0" ;; + d) echo "d102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fd0" ;; + e) echo "e102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fe0" ;; + esac +} + +get_npub() { + case "$1" in + a) echo "npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m" ;; + b) echo "npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le" ;; + c) echo "npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6" ;; + d) echo "npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl" ;; + e) echo "npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4" ;; + esac +} + +get_docker_ip() { + case "$1" in + a) echo "172.20.0.10" ;; + b) echo "172.20.0.11" ;; + c) echo "172.20.0.12" ;; + d) echo "172.20.0.13" ;; + e) echo "172.20.0.14" ;; + esac +} + +get_mesh_peers() { + case "$1" in + a) echo "d e" ;; + b) echo "c" ;; + c) echo "b d e" ;; + d) echo "a c e" ;; + e) echo "a c d" ;; + esac +} + +get_chain_peers() { + case "$1" in + a) echo "b" ;; + b) echo "a c" ;; + c) echo "b d" ;; + d) echo "c e" ;; + e) echo "d" ;; + esac +} + +generate_peer_block() { + local peer_id="$1" + cat < "$output_file" + echo " ✓ Generated $output_file" + done +} + +main() { + local requested="${1:-all}" + + case "$requested" in + mesh) + generate_topology "mesh" + ;; + chain) + generate_topology "chain" + ;; + all) + generate_topology "mesh" + generate_topology "chain" + ;; + *) + echo "Error: Unknown topology '$requested'" + echo "Usage: $0 [mesh|chain|all]" + exit 1 + ;; + esac + + echo "" + echo "✓ All configurations generated successfully!" +} + +main "$@" \ No newline at end of file diff --git a/examples/docker-network/scripts/iperf-test.sh b/examples/docker-network/scripts/iperf-test.sh new file mode 100755 index 0000000..4babbd2 --- /dev/null +++ b/examples/docker-network/scripts/iperf-test.sh @@ -0,0 +1,127 @@ +#!/bin/bash +# End-to-end iperf3 bandwidth test between FIPS nodes via DNS resolution. +# Usage: ./iperf-test.sh [mesh|chain] [--live] +# +# Requires containers to be running: +# docker compose --profile mesh up -d +# ./scripts/iperf-test.sh mesh +# ./scripts/iperf-test.sh mesh --live # Show live iperf3 output +set -e + +# Exit entire script on Ctrl+C +trap 'echo ""; echo "Test interrupted"; exit 130' INT + +PROFILE="${1:-mesh}" +LIVE_OUTPUT=false +if [ "$2" = "--live" ] || [ "$1" = "--live" ]; then + LIVE_OUTPUT=true + [ "$1" = "--live" ] && PROFILE="mesh" +fi + +DURATION=10 +PARALLEL=8 +PASSED=0 +FAILED=0 + +# Node identities +NPUB_A="npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m" +NPUB_B="npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le" +NPUB_C="npub1cld9yay0u24davpu6c35l4vldrhzvaq66pcqtg9a0j2cnjrn9rtsxx2pe6" +NPUB_D="npub1n9lpnv0592cc2ps6nm0ca3qls642vx7yjsv35rkxqzj2vgds52sqgpverl" +NPUB_E="npub1wf8akf8lu2zdkjkmwhl75pqvven654mpv4sz2x2tprl5265mgrzq8nhak4" + +# FIPS IPv6 addresses (derived from npubs) +ADDR_A="fd69:e08d:65cc:3a6b:9c2c:2ac4:bd40:5e4b" +ADDR_B="fd8e:302c:287e:b48d:e5b7:6eee:e8a7:4f1e" +ADDR_C="fdac:a221:4069:5044:e0e5:7a5f:5a0f:4d43" +ADDR_D="fdb6:8411:a191:6d48:c5f7:e5f5:e5a5:2a50" +ADDR_E="fded:7dee:d386:a546:e5f7:e5f5:e5a5:2a50" + +iperf_test() { + local server_node="$1" + local client_node="$2" + local dest_npub="$3" + local label="$4" + + echo "" + echo "=== $label ===" + + # iperf3 server is already running in daemon mode in each container + + if [ "$LIVE_OUTPUT" = true ]; then + # Show live output + echo "Running iperf3 test (live output):" + if docker exec "fips-$client_node" iperf3 -c "${dest_npub}.fips" -t "$DURATION" -P "$PARALLEL"; then + PASSED=$((PASSED + 1)) + else + echo "FAIL" + FAILED=$((FAILED + 1)) + fi + else + # Capture and summarize output + echo -n "Running iperf3 test... " + local output + if output=$(docker exec "fips-$client_node" iperf3 -c "${dest_npub}.fips" -t "$DURATION" -P "$PARALLEL" 2>&1); then + # Check if we got valid results + if echo "$output" | grep -q "sender"; then + # Extract and display results (get SUM line for aggregate bandwidth) + local bandwidth=$(echo "$output" | grep "\[SUM\].*sender" | tail -1 | awk '{print $(NF-2), $(NF-1)}') + echo "OK" + echo "Bandwidth: $bandwidth" + PASSED=$((PASSED + 1)) + else + echo "FAIL (no bandwidth data)" + echo "Output: $output" + FAILED=$((FAILED + 1)) + fi + else + echo "FAIL" + echo "Error output:" + echo "$output" | head -10 + FAILED=$((FAILED + 1)) + fi + fi +} + +echo "=== FIPS iperf3 Bandwidth Test ($PROFILE topology) ===" +echo "" + +# Wait for nodes to converge +echo "Waiting 3s for mesh convergence..." +sleep 3 + +if [ "$PROFILE" = "mesh" ]; then + # Test key paths in mesh topology + echo "" + echo "Testing mesh topology paths:" + + # Direct peer links + iperf_test node-a node-d "$NPUB_D" "A → D (direct peer)" + iperf_test node-a node-e "$NPUB_E" "A → E (direct peer)" + + # Multi-hop paths + iperf_test node-a node-b "$NPUB_B" "A → B (multi-hop)" + iperf_test node-a node-c "$NPUB_C" "A → C (multi-hop)" + + # Reverse test + iperf_test node-e node-a "$NPUB_A" "E → A (direct peer)" + +elif [ "$PROFILE" = "chain" ]; then + echo "" + echo "Testing chain topology paths:" + + # Adjacent hop + iperf_test node-a node-b "$NPUB_B" "A → B (1 hop)" + + # Multi-hop tests + iperf_test node-a node-c "$NPUB_C" "A → C (2 hops)" + iperf_test node-a node-d "$NPUB_D" "A → D (3 hops)" + iperf_test node-a node-e "$NPUB_E" "A → E (4 hops)" + + # Reverse multi-hop + iperf_test node-e node-a "$NPUB_A" "E → A (4 hops)" +fi + +echo "" +echo "=== Results: $PASSED passed, $FAILED failed ===" +[ "$FAILED" -eq 0 ] && exit 0 || exit 1 \ No newline at end of file diff --git a/examples/docker-network/scripts/ping-test.sh b/examples/docker-network/scripts/ping-test.sh index a81a309..2097921 100755 --- a/examples/docker-network/scripts/ping-test.sh +++ b/examples/docker-network/scripts/ping-test.sh @@ -7,9 +7,12 @@ # ./scripts/ping-test.sh mesh set -e +# Exit entire script on Ctrl+C +trap 'echo ""; echo "Test interrupted"; exit 130' INT + PROFILE="${1:-mesh}" -COUNT=3 -TIMEOUT=10 +COUNT=1 +TIMEOUT=5 PASSED=0 FAILED=0 @@ -26,8 +29,15 @@ ping_test() { local label="$3" echo -n " $label ... " - if docker exec "fips-$from" ping6 -c "$COUNT" -W "$TIMEOUT" "${to_npub}.fips" > /dev/null 2>&1; then - echo "OK" + local output + if output=$(docker exec "fips-$from" ping6 -c "$COUNT" -W "$TIMEOUT" "${to_npub}.fips" 2>&1); then + # Extract round-trip time from ping output + local rtt=$(echo "$output" | grep -oE 'time=[0-9.]+' | cut -d= -f2) + if [ -n "$rtt" ]; then + echo "OK (${rtt}ms)" + else + echo "OK" + fi PASSED=$((PASSED + 1)) else echo "FAIL" @@ -39,8 +49,8 @@ echo "=== FIPS Ping Test ($PROFILE topology) ===" echo "" # Wait for nodes to converge -echo "Waiting 5s for mesh convergence..." -sleep 5 +echo "Waiting 3s for mesh convergence..." +sleep 3 if [ "$PROFILE" = "mesh" ]; then # Sparse mesh topology: A-B, B-C, C-D, D-E, E-A, A-D