Merge branch 'master' into next

# Conflicts:
#	testing/ci-local.sh
This commit is contained in:
Johnathan Corgan
2026-04-15 06:35:32 +00:00
13 changed files with 374 additions and 50 deletions
+14 -6
View File
@@ -145,16 +145,24 @@ record() {
run_build() {
stage "Stage 1: Build"
info "cargo build --release"
if cargo build --release 2>&1; then
info "cargo build --release --features gateway"
if cargo build --release --features gateway 2>&1; then
record "build" 0
else
record "build" 1
return 1
fi
info "cargo clippy --all -- -D warnings"
if cargo clippy --all -- -D warnings 2>&1; then
info "cargo fmt --check"
if cargo fmt --check 2>&1; then
record "fmt" 0
else
record "fmt" 1
return 1
fi
info "cargo clippy --all --features gateway -- -D warnings"
if cargo clippy --all --features gateway -- -D warnings 2>&1; then
record "clippy" 0
else
record "clippy" 1
@@ -169,7 +177,7 @@ run_tests() {
local cmd
if command -v cargo-nextest &>/dev/null; then
cmd="cargo nextest run --all"
cmd="cargo nextest run --all --features gateway"
info "$cmd"
if $cmd 2>&1; then
record "unit-tests" 0
@@ -177,7 +185,7 @@ run_tests() {
record "unit-tests" 1
fi
else
cmd="cargo test --all"
cmd="cargo test --all --features gateway"
info "$cmd (nextest not found, using cargo test)"
if $cmd 2>&1; then
record "unit-tests" 0
+5 -2
View File
@@ -46,11 +46,13 @@ if [ "$UNAME_S" = "Darwin" ]; then
echo "Building FIPS for Linux (release) using cargo-zigbuild..."
cargo zigbuild --release --target "$CARGO_TARGET" --manifest-path="$PROJECT_ROOT/Cargo.toml"
cargo zigbuild --release --target "$CARGO_TARGET" --manifest-path="$PROJECT_ROOT/Cargo.toml" --features gateway --bin fips-gateway
TARGET_DIR="$PROJECT_ROOT/target/$CARGO_TARGET/release"
else
echo "Building FIPS (release)..."
cargo build --release --manifest-path="$PROJECT_ROOT/Cargo.toml"
cargo build --release --manifest-path="$PROJECT_ROOT/Cargo.toml" --features gateway --bin fips-gateway
TARGET_DIR="$PROJECT_ROOT/target/release"
fi
@@ -58,11 +60,12 @@ fi
echo "Copying binaries to $DOCKER_DIR/"
cp "$TARGET_DIR/fips" "$DOCKER_DIR/fips"
cp "$TARGET_DIR/fipsctl" "$DOCKER_DIR/fipsctl"
cp "$TARGET_DIR/fips-gateway" "$DOCKER_DIR/fips-gateway"
[ -f "$TARGET_DIR/fipstop" ] && cp "$TARGET_DIR/fipstop" "$DOCKER_DIR/fipstop" || true
chmod +x "$DOCKER_DIR/fips" "$DOCKER_DIR/fipsctl"
chmod +x "$DOCKER_DIR/fips" "$DOCKER_DIR/fipsctl" "$DOCKER_DIR/fips-gateway"
[ -f "$DOCKER_DIR/fipstop" ] && chmod +x "$DOCKER_DIR/fipstop" || true
echo "Done. Binaries at $DOCKER_DIR/{fips,fipsctl,fipstop}"
echo "Done. Binaries at $DOCKER_DIR/{fips,fipsctl,fipstop,fips-gateway}"
if [ "$BUILD_DOCKER" = true ]; then
echo ""
+69 -7
View File
@@ -44,12 +44,21 @@ with open('$config_file') as f:
cfg['gateway'] = {
'enabled': True,
'pool': 'fd01::/112',
'lan_interface': 'eth0',
# Docker assigns gateway-lan to eth1 (fips-net is eth0). The
# LAN-side masquerade for inbound port forwards gates on this.
'lan_interface': 'eth1',
'dns': {
'listen': '[::]:53',
'ttl': 5,
},
'pool_grace_period': 5,
'port_forwards': [
{
'listen_port': 18080,
'proto': 'tcp',
'target': '[fd02::20]:8080',
},
],
}
with open('$config_file', 'w') as f:
@@ -163,9 +172,62 @@ else
check "nftables DNAT rules" 1
fi
# Phase 7: TTL expiration and pool reclamation
# Phase 7: Inbound port forwarding (TASK-2026-0061)
#
# Mesh peer (gw-server) → gw-gateway fips0:18080 → DNAT → [fd02::20]:8080
# (gw-client LAN HTTP server). Exercises the DNAT rule + LAN-side
# masquerade installed by set_port_forwards().
echo ""
echo "Phase 7: TTL expiration and pool reclamation"
echo "Phase 7: Inbound port forward"
# Confirm the port-forward DNAT rule is present on the gateway. The
# distinctive listen port (18080) identifies our rule regardless of how
# nft renders the l4proto/dport predicates.
if echo "$NFT_RULES" | grep -q "18080"; then
check "nftables port-forward DNAT rule (tcp 18080)" 0
else
check "nftables port-forward DNAT rule (tcp 18080)" 1
fi
# Start a marker HTTP server on the LAN-side client (fd02::20:8080).
# `docker exec -d` is required; `docker exec bash -c 'cmd &'` doesn't
# keep the child alive past the exec session, even with nohup.
docker exec "$CLIENT" sh -c \
'mkdir -p /tmp/inbound && echo "inbound-forward-ok" > /tmp/inbound/index.html && pkill -f "http.server 8080" 2>/dev/null || true' \
>/dev/null 2>&1 || true
docker exec -d "$CLIENT" python3 -m http.server 8080 --bind :: --directory /tmp/inbound \
>/dev/null 2>&1 || true
# Give the server a moment to bind.
for _ in 1 2 3 4 5; do
if docker exec "$CLIENT" ss -6lnt 2>/dev/null | grep -q ':8080'; then
break
fi
sleep 1
done
# Derive the gateway's mesh IPv6 (fd00::/8 address assigned to fips0).
GW_MESH_IP=$(docker exec "$GATEWAY" bash -c \
"ip -6 -o addr show fips0 | awk '/inet6 fd/ {print \$4}' | cut -d/ -f1 | head -1" \
2>/dev/null || echo "")
if [ -z "$GW_MESH_IP" ]; then
check "Gateway fips0 IPv6 address" 1
else
echo " Gateway mesh IPv6: $GW_MESH_IP"
# From the mesh side (gw-server), fetch through the forward rule.
FWD_RESPONSE=$(docker exec "$SERVER" curl -6 -s --max-time 10 \
"http://[${GW_MESH_IP}]:18080/" 2>&1) || true
if echo "$FWD_RESPONSE" | grep -q "inbound-forward-ok"; then
check "Inbound HTTP via port forward 18080 → [fd02::20]:8080" 0
else
check "Inbound HTTP via port forward (response: '${FWD_RESPONSE:0:80}')" 1
fi
fi
# Phase 8: TTL expiration and pool reclamation
echo ""
echo "Phase 8: TTL expiration and pool reclamation"
# Flush conntrack so stale sessions from Phase 5 don't keep the mapping alive.
docker exec "$GATEWAY" conntrack -F 2>/dev/null || true
# Config uses ttl=5, pool_grace_period=5. Pool tick interval is 10s, so:
@@ -185,9 +247,9 @@ else
check "Mapping reclaimed (count: $MAPPING_COUNT)" 1
fi
# Phase 8: SERVFAIL when daemon DNS is down
# Phase 9: SERVFAIL when daemon DNS is down
echo ""
echo "Phase 8: SERVFAIL when daemon DNS is down"
echo "Phase 9: SERVFAIL when daemon DNS is down"
# Kill the fips daemon inside the gateway container (gateway stays running)
docker exec "$GATEWAY" pkill -f "^fips --config" 2>/dev/null || true
sleep 2
@@ -201,9 +263,9 @@ else
check "SERVFAIL when daemon DNS down (got: '${SERVFAIL_RESULT:0:80}')" 1
fi
# Phase 9: Cleanup verification (nftables removed on shutdown)
# Phase 10: Cleanup verification (nftables removed on shutdown)
echo ""
echo "Phase 9: Cleanup on shutdown"
echo "Phase 10: Cleanup on shutdown"
# fips-gateway is PID 1 (exec in entrypoint), so SIGTERM stops the container.
# Verify cleanup by checking container logs for the shutdown sequence.
docker stop --time=10 "$GATEWAY" >/dev/null 2>&1 || true