mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 00:04:54 +00:00
Merge branch 'master' into next
This commit is contained in:
@@ -120,6 +120,7 @@ ping_path() {
|
||||
return
|
||||
fi
|
||||
echo "${rtt//\// } ${loss:-N/A}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── Path definitions ───────────────────────────────────────────────────────
|
||||
|
||||
@@ -26,6 +26,16 @@ SERVER2="fips-gw-server-2${FIPS_CI_NAME_SUFFIX:-}"
|
||||
CLIENT="fips-gw-client${FIPS_CI_NAME_SUFFIX:-}"
|
||||
CLIENT2="fips-gw-client-2${FIPS_CI_NAME_SUFFIX:-}"
|
||||
|
||||
# LAN-side IPv6 addressing. run_gateway claims a per-run /64 and exports
|
||||
# FIPS_GW_LAN6_PREFIX; unset (standalone / GitHub) these render the base
|
||||
# compose's fd02:: addresses, byte-identical to before. GW_DNS is the gateway's
|
||||
# LAN address (nameserver + route next-hop); GW_CLIENT_LAN is gw-client's LAN
|
||||
# address (inbound port-forward target). fd01::/112 (the virtual pool) is NOT
|
||||
# claimed and stays literal below.
|
||||
GW_LAN6_PREFIX="${FIPS_GW_LAN6_PREFIX:-fd02}"
|
||||
GW_DNS="${GW_LAN6_PREFIX}::10"
|
||||
GW_CLIENT_LAN="${GW_LAN6_PREFIX}::20"
|
||||
|
||||
# ── inject-config subcommand ─────────────────────────────────────────────
|
||||
|
||||
inject_gateway_config() {
|
||||
@@ -58,21 +68,21 @@ cfg['gateway'] = {
|
||||
{
|
||||
'listen_port': 18080,
|
||||
'proto': 'tcp',
|
||||
'target': '[fd02::20]:8080',
|
||||
'target': '[${GW_CLIENT_LAN}]:8080',
|
||||
},
|
||||
# 6B: second TCP forward — exercises multiple simultaneous TCP
|
||||
# rules sharing the same LAN backend on a different listen port.
|
||||
{
|
||||
'listen_port': 18082,
|
||||
'proto': 'tcp',
|
||||
'target': '[fd02::20]:8081',
|
||||
'target': '[${GW_CLIENT_LAN}]:8081',
|
||||
},
|
||||
# 6A: UDP forward — exercises the runtime UDP DNAT path (rule
|
||||
# shape + conntrack handling) end-to-end.
|
||||
{
|
||||
'listen_port': 18081,
|
||||
'proto': 'udp',
|
||||
'target': '[fd02::20]:8081',
|
||||
'target': '[${GW_CLIENT_LAN}]:8081',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -130,7 +140,7 @@ for i in $(seq 1 30); do
|
||||
# Try resolving the server's npub via the gateway DNS from the client.
|
||||
# Match fd01:: specifically (the pool prefix) to avoid false-positive
|
||||
# matches on error messages containing fd02::10.
|
||||
local_result=$(docker exec "$CLIENT" dig +short AAAA "${NPUB_B}.fips" @fd02::10 2>/dev/null || true)
|
||||
local_result=$(docker exec "$CLIENT" dig +short AAAA "${NPUB_B}.fips" @${GW_DNS} 2>/dev/null || true)
|
||||
if echo "$local_result" | grep -q "^fd01::"; then
|
||||
echo " Gateway DNS responding after ${i}s"
|
||||
DNS_READY=true
|
||||
@@ -146,23 +156,23 @@ fi
|
||||
# Phase 3: Client network setup — route virtual IP pool via gateway
|
||||
echo ""
|
||||
echo "Phase 3: Client network setup"
|
||||
docker exec "$CLIENT" ip -6 route add fd01::/112 via fd02::10 2>/dev/null || true
|
||||
echo " Added route fd01::/112 via fd02::10 on $CLIENT"
|
||||
docker exec "$CLIENT2" ip -6 route add fd01::/112 via fd02::10 2>/dev/null || true
|
||||
echo " Added route fd01::/112 via fd02::10 on $CLIENT2"
|
||||
docker exec "$CLIENT" ip -6 route add fd01::/112 via ${GW_DNS} 2>/dev/null || true
|
||||
echo " Added route fd01::/112 via ${GW_DNS} on $CLIENT"
|
||||
docker exec "$CLIENT2" ip -6 route add fd01::/112 via ${GW_DNS} 2>/dev/null || true
|
||||
echo " Added route fd01::/112 via ${GW_DNS} on $CLIENT2"
|
||||
|
||||
# Phase 4: DNS resolution test — resolve server npub from both clients,
|
||||
# exercising concurrent multi-client mappings.
|
||||
echo ""
|
||||
echo "Phase 4: DNS resolution"
|
||||
VIRTUAL_IP=$(docker exec "$CLIENT" dig +short AAAA "${NPUB_B}.fips" @fd02::10 2>/dev/null | head -1)
|
||||
VIRTUAL_IP=$(docker exec "$CLIENT" dig +short AAAA "${NPUB_B}.fips" @${GW_DNS} 2>/dev/null | head -1)
|
||||
if [ -n "$VIRTUAL_IP" ] && echo "$VIRTUAL_IP" | grep -q "fd01"; then
|
||||
check "Resolve ${NPUB_B:0:20}...fips on $CLIENT → $VIRTUAL_IP" 0
|
||||
else
|
||||
check "Resolve ${NPUB_B:0:20}...fips on $CLIENT (got: '$VIRTUAL_IP')" 1
|
||||
fi
|
||||
|
||||
VIRTUAL_IP_2=$(docker exec "$CLIENT2" dig +short AAAA "${NPUB_C}.fips" @fd02::10 2>/dev/null | head -1)
|
||||
VIRTUAL_IP_2=$(docker exec "$CLIENT2" dig +short AAAA "${NPUB_C}.fips" @${GW_DNS} 2>/dev/null | head -1)
|
||||
if [ -n "$VIRTUAL_IP_2" ] && echo "$VIRTUAL_IP_2" | grep -q "fd01"; then
|
||||
check "Resolve ${NPUB_C:0:20}...fips on $CLIENT2 → $VIRTUAL_IP_2" 0
|
||||
else
|
||||
@@ -357,7 +367,7 @@ else
|
||||
# 8080 backend serves "inbound-forward-ok" (no -2 suffix) — distinct
|
||||
# from the 8081 backend so a misrouted response would be detectable.
|
||||
if echo "$FWD_RESPONSE" | grep -qE '^inbound-forward-ok$'; then
|
||||
check "Inbound HTTP via TCP forward 18080 → [fd02::20]:8080" 0
|
||||
check "Inbound HTTP via TCP forward 18080 → [${GW_CLIENT_LAN}]:8080" 0
|
||||
else
|
||||
check "Inbound HTTP via TCP forward 18080 (response: '${FWD_RESPONSE:0:80}')" 1
|
||||
fi
|
||||
@@ -365,7 +375,7 @@ else
|
||||
FWD_RESPONSE_2=$(docker exec "$SERVER" curl -6 -s --max-time 10 \
|
||||
"http://[${GW_MESH_IP}]:18082/" 2>&1) || true
|
||||
if echo "$FWD_RESPONSE_2" | grep -q "inbound-forward-ok-2"; then
|
||||
check "Inbound HTTP via TCP forward 18082 → [fd02::20]:8081 (6B)" 0
|
||||
check "Inbound HTTP via TCP forward 18082 → [${GW_CLIENT_LAN}]:8081 (6B)" 0
|
||||
else
|
||||
check "Inbound HTTP via TCP forward 18082 (response: '${FWD_RESPONSE_2:0:80}')" 1
|
||||
fi
|
||||
@@ -384,7 +394,7 @@ except Exception as e:
|
||||
sys.stdout.write('ERR: ' + str(e))
|
||||
" 2>&1) || true
|
||||
if echo "$UDP_RESPONSE" | grep -q "udp-forward-ok:ping-via-udp-fwd"; then
|
||||
check "Inbound UDP via forward 18081 → [fd02::20]:8081 (6A)" 0
|
||||
check "Inbound UDP via forward 18081 → [${GW_CLIENT_LAN}]:8081 (6A)" 0
|
||||
else
|
||||
check "Inbound UDP via forward 18081 (response: '${UDP_RESPONSE:0:80}')" 1
|
||||
fi
|
||||
@@ -444,8 +454,8 @@ docker exec "$GATEWAY" pkill -f "^fips --config" 2>/dev/null || true
|
||||
sleep 2
|
||||
|
||||
# Gateway upstream timeout is 5s, so dig must wait longer than that.
|
||||
SERVFAIL_RESULT=$(docker exec "$CLIENT" dig +short +tries=1 +time=8 AAAA "test-servfail.fips" @fd02::10 2>&1 || true)
|
||||
SERVFAIL_STATUS=$(docker exec "$CLIENT" dig +tries=1 +time=8 AAAA "test-servfail.fips" @fd02::10 2>&1 | grep -c "SERVFAIL" || true)
|
||||
SERVFAIL_RESULT=$(docker exec "$CLIENT" dig +short +tries=1 +time=8 AAAA "test-servfail.fips" @${GW_DNS} 2>&1 || true)
|
||||
SERVFAIL_STATUS=$(docker exec "$CLIENT" dig +tries=1 +time=8 AAAA "test-servfail.fips" @${GW_DNS} 2>&1 | grep -c "SERVFAIL" || true)
|
||||
if [ "$SERVFAIL_STATUS" -ge 1 ]; then
|
||||
check "SERVFAIL when daemon DNS is down" 0
|
||||
else
|
||||
|
||||
@@ -74,6 +74,7 @@ docker_host_name() {
|
||||
local host
|
||||
host=$(get_node_attr "$topology_file" "$node_id" "docker_host")
|
||||
echo "${host:-node-$node_id}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Get peers list from topology
|
||||
@@ -118,6 +119,7 @@ get_default_transport() {
|
||||
local topology_file="$1"
|
||||
local transport=$(grep "^default_transport:" "$topology_file" | head -1 | sed 's/.*: *\([a-z]*\).*/\1/')
|
||||
echo "${transport:-udp}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Get the port for a given transport type
|
||||
@@ -272,6 +274,16 @@ generate_topology() {
|
||||
echo "${var_name}=$(get_key RESOLVED_NPUB "$node_id")" >> "$env_file"
|
||||
done
|
||||
echo " ✓ Generated $env_file"
|
||||
|
||||
# Phase 4 (gateway only): write the LAN-client resolv.conf. Its nameserver
|
||||
# is the gateway's LAN address, which must be a literal known before the
|
||||
# client starts. run_gateway claims a per-run /64 and exports
|
||||
# FIPS_GW_LAN6_PREFIX before calling this; unset (standalone / GitHub) it
|
||||
# renders the base compose's fd02::10.
|
||||
if [ "$topology_name" = "gateway" ]; then
|
||||
echo "nameserver ${FIPS_GW_LAN6_PREFIX:-fd02}::10" > "$output_dir/resolv.conf"
|
||||
echo " ✓ Generated $output_dir/resolv.conf"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
|
||||
@@ -159,6 +159,7 @@ build_netem_params() {
|
||||
fi
|
||||
|
||||
echo "$params"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check if a container is running
|
||||
|
||||
@@ -285,15 +285,31 @@ phase_result() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Count occurrences of a pattern across all node logs
|
||||
# Count occurrences of a pattern across all node logs.
|
||||
#
|
||||
# A node whose logs cannot be read makes the whole count unusable rather than
|
||||
# contributing 0. The previous form ended each read `| grep -c "$pat" || true`,
|
||||
# so a failed `docker logs` yielded 0 for that node and the six assert_zero_count
|
||||
# callers below read a clean result from a node that was never consulted — one
|
||||
# unreadable node silently weakened the assertion instead of voiding it.
|
||||
#
|
||||
# Returns non-zero and prints a sentinel naming the container. Every caller must
|
||||
# split the declaration from the assignment (`local c` then `c=$(...)`), because
|
||||
# `local c=$(...)` takes `local`'s exit status and discards this one.
|
||||
count_log_pattern() {
|
||||
local pattern="$1"
|
||||
local total=0
|
||||
local node logs count
|
||||
for node in $NODES; do
|
||||
local count=$(docker logs "fips-node-${node}${FIPS_CI_NAME_SUFFIX:-}" 2>&1 | grep -c "$pattern" || true)
|
||||
if ! logs=$(docker logs "fips-node-${node}${FIPS_CI_NAME_SUFFIX:-}" 2>&1); then
|
||||
echo "unreadable:fips-node-${node}${FIPS_CI_NAME_SUFFIX:-}"
|
||||
return 1
|
||||
fi
|
||||
count=$(grep -c "$pattern" <<<"$logs" || true)
|
||||
total=$((total + count))
|
||||
done
|
||||
echo "$total"
|
||||
return 0
|
||||
}
|
||||
|
||||
wait_for_log_pattern_count() {
|
||||
@@ -325,7 +341,12 @@ assert_min_count() {
|
||||
local pattern="$1"
|
||||
local min_count="$2"
|
||||
local description="$3"
|
||||
local count=$(count_log_pattern "$pattern")
|
||||
local count
|
||||
count=$(count_log_pattern "$pattern") || {
|
||||
echo " ✗ $description: node logs unreadable ($count), count not established"
|
||||
FAILED=$((FAILED + 1))
|
||||
return
|
||||
}
|
||||
if [ "$count" -ge "$min_count" ]; then
|
||||
echo " ✓ $description: $count (>= $min_count)"
|
||||
PASSED=$((PASSED + 1))
|
||||
@@ -339,7 +360,12 @@ assert_min_count() {
|
||||
assert_zero_count() {
|
||||
local pattern="$1"
|
||||
local description="$2"
|
||||
local count=$(count_log_pattern "$pattern")
|
||||
local count
|
||||
count=$(count_log_pattern "$pattern") || {
|
||||
echo " ✗ $description: node logs unreadable ($count), zero not established"
|
||||
FAILED=$((FAILED + 1))
|
||||
return
|
||||
}
|
||||
if [ "$count" -eq 0 ]; then
|
||||
echo " ✓ $description: 0"
|
||||
PASSED=$((PASSED + 1))
|
||||
|
||||
Reference in New Issue
Block a user