diff --git a/tests/integration/nat/Dockerfile b/tests/integration/nat/Dockerfile index 503e86cc..56c29ea9 100644 --- a/tests/integration/nat/Dockerfile +++ b/tests/integration/nat/Dockerfile @@ -8,8 +8,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ iproute2 \ && rm -rf /var/lib/apt/lists/* -# Build miniupnpd with stub redirector: no iptables/nftables needed, always -# returns success for port mapping requests. +# Build miniupnpd with a stub redirector. miniupnpd normally calls iptables/nftables +# to install the actual port forwarding rules when it receives a mapping request. +# In Docker, those calls fail because the container lacks the required kernel +# capabilities, causing every mapping request to return an error to the client. +# The stub replaces the firewall backend with no-ops that always return success, +# so mapping requests complete normally without touching the kernel. COPY tests/integration/nat/miniupnpd_stub_rdr.c /tmp/stub_rdr.c RUN git clone --depth=1 --branch miniupnpd_2_3_9 \ https://github.com/miniupnp/miniupnp.git /tmp/miniupnp \ diff --git a/tests/integration/nat/docker-entrypoint.sh b/tests/integration/nat/docker-entrypoint.sh index b71e64d3..1d5b9df9 100644 --- a/tests/integration/nat/docker-entrypoint.sh +++ b/tests/integration/nat/docker-entrypoint.sh @@ -4,9 +4,24 @@ set -euo pipefail RUNDIR=/tmp/miniupnpd mkdir -p "$RUNDIR" +# miniupnpd must listen on the same interface as the test node. +# We get the default route interface (e.g. eth0) and its IP. LAN_IF=$(ip route show default | awk '/default/{print $5; exit}') LAN_IP=$(ip -4 addr show "$LAN_IF" | awk '/inet /{print $2; exit}' | cut -d/ -f1) +if [[ -z "$LAN_IF" ]]; then + echo "ERROR: could not determine LAN interface" >&2 + exit 1 +fi + +if [[ -z "$LAN_IP" ]]; then + echo "ERROR: could not determine LAN IP on $LAN_IF" >&2 + exit 1 +fi + +# We use a public WAN IP (1.2.3.4) on a dummy interface because miniupnpd +# disables port forwarding when the external interface has a private/RFC1918 +# address (treats it as double-NAT). ip link add plum-wan type dummy ip addr add 1.2.3.4/24 dev plum-wan ip link set plum-wan up @@ -17,11 +32,17 @@ start_miniupnpd() { ext_ifname=plum-wan listening_ip=$LAN_IF enable_pcp_pmp=$enable_pcp_pmp +# port=0: pick a random HTTP port to avoid conflicts with host services. port=0 +# Without an allow rule miniupnpd denies all mapping requests by default. allow 1024-65535 0.0.0.0/0 1024-65535 EOF miniupnpd -d -f "$RUNDIR/miniupnpd.conf" > "$RUNDIR/miniupnpd.log" 2>&1 & + MINIUPNPD_PID=$! sleep 1 + kill -0 "$MINIUPNPD_PID" 2>/dev/null \ + || { echo "ERROR: miniupnpd failed to start" >&2; cat "$RUNDIR/miniupnpd.log" >&2; exit 1; } + echo "miniupnpd started (pid $MINIUPNPD_PID)" } if [[ "${TEST_PCP:-0}" == "1" ]]; then diff --git a/tests/integration/nat/miniupnpd_stub_rdr.c b/tests/integration/nat/miniupnpd_stub_rdr.c index 15e45b0a..9caf44b8 100644 --- a/tests/integration/nat/miniupnpd_stub_rdr.c +++ b/tests/integration/nat/miniupnpd_stub_rdr.c @@ -1,6 +1,13 @@ -/* Stub firewall backend for miniupnpd. - * Replaces iptcrdr.o + iptpinhole.o + nfct_get.o. - * All mapping operations succeed without touching the kernel. */ +/* Stub firewall backend for miniupnpd used in Docker-based tests. + * + * miniupnpd normally calls iptables/nftables to install port forwarding rules + * when it processes a UPnP/PCP/NAT-PMP mapping request. In a Docker container + * those calls fail because the container lacks the required kernel capabilities, + * causing every mapping request to return an error to the client. + * + * This file replaces iptcrdr.o + iptpinhole.o + nfct_get.o with no-ops that + * always return success, so miniupnpd responds correctly to mapping requests + * without touching the kernel. */ #include #include