test(iperf): install iptables rule inside of container (#9880)

In Docker environments, applying iptables rules to filter
container-container traffic on the Docker bridged network is not
reliable, leading to direct connections being established in our relayed
tests. To fix this, we insert the rules directly from the client
container itself.

---------

Co-authored-by: Jamil Bou Kheir <jamilbk@users.noreply.github.com>
This commit is contained in:
Thomas Eizinger
2025-07-16 18:29:33 +08:00
committed by GitHub
parent 2fd56fb7ae
commit cf2470ba1e
5 changed files with 31 additions and 10 deletions

View File

@@ -147,7 +147,11 @@ jobs:
- name: Ensure Client emitted no warnings
if: "!cancelled()"
run: docker compose logs client | grep "WARN" && exit 1 || exit 0
# Remove the error filter once headless-client 1.5.2 is released.
run: |
docker compose logs client | \
grep "Operation not permitted (os error 1)" --invert | \
grep "WARN" && exit 1 || exit 0
- name: Show Client logs
if: "!cancelled()"
run: docker compose logs client

View File

@@ -107,6 +107,9 @@ jobs:
if grep -q '^website/' changed_files.txt; then
jobs="${jobs},codeql"
fi
if grep -q '^scripts/tests/' changed_files.txt; then
jobs="${jobs},build-artifacts,build-perf-artifacts"
fi
echo "jobs_to_run=$jobs" >> "$GITHUB_OUTPUT"
@@ -311,7 +314,7 @@ jobs:
run: |
# We need to increase the log level to make sure that they don't hold off storm of packets
# generated by UDP tests. Wire is especially chatty.
sed -i 's/^\(\s*\)RUST_LOG:.*$/\1RUST_LOG: wire=error,info/' docker-compose.yml
sed -i 's/^\(\s*\)RUST_LOG:.*$/\1RUST_LOG: wire=error,opentelemetry_sdk=error,info/' docker-compose.yml
grep RUST_LOG docker-compose.yml
# Start services in the same order each time for the tests

View File

@@ -46,7 +46,7 @@ CMD ${PACKAGE}
# Build an image for GitHub Actions which includes debug asserts and more test utilities
FROM runtime AS debug
RUN apk add --no-cache iperf3 bind-tools iproute2 jq procps
RUN apk add --no-cache iperf3 bind-tools iproute2 jq procps iptables
## Build first with `cargo build --target ${TARGET} -p ${PACKAGE} && mv /target/${TARGET}/debug/${PACKAGE} .`
ARG PACKAGE

View File

@@ -10,6 +10,7 @@ use firezone_tunnel::messages::client::{
use firezone_tunnel::{ClientTunnel, IpConfig};
use ip_network::{Ipv4Network, Ipv6Network};
use phoenix_channel::{ErrorReply, OutboundRequestId, PhoenixChannel, PublicKeyParam};
use std::mem;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::time::Instant;
use std::{
@@ -27,6 +28,8 @@ pub struct Eventloop {
portal: PhoenixChannel<(), IngressMessages, (), PublicKeyParam>,
cmd_rx: tokio::sync::mpsc::UnboundedReceiver<Command>,
event_tx: tokio::sync::mpsc::Sender<Event>,
logged_permission_denied: bool,
}
/// Commands that can be sent to the [`Eventloop`].
@@ -86,6 +89,7 @@ impl Eventloop {
portal,
cmd_rx,
event_tx,
logged_permission_denied: false,
}
}
}
@@ -154,6 +158,19 @@ impl Eventloop {
return Poll::Ready(Err(e));
}
if e.root_cause()
.downcast_ref::<io::Error>()
.is_some_and(|e| e.kind() == io::ErrorKind::PermissionDenied)
{
if !mem::replace(&mut self.logged_permission_denied, true) {
tracing::info!(
"Encountered `PermissionDenied` IO error. Check your local firewall rules to allow outbound STUN/TURN/WireGuard and general UDP traffic."
)
}
continue;
}
tracing::warn!("Tunnel error: {e:#}");
continue;
}

View File

@@ -19,14 +19,11 @@ function relay2() {
}
function install_iptables_drop_rules() {
sudo iptables -I FORWARD 1 -s 172.28.0.100 -d 172.28.0.105 -j DROP
sudo iptables -I FORWARD 1 -s 172.28.0.105 -d 172.28.0.100 -j DROP
trap remove_iptables_drop_rules EXIT # Cleanup after us
}
# Install `iptables` to have it available in the compatibility tests
docker compose exec -it client /bin/sh -c 'apk add iptables'
function remove_iptables_drop_rules() {
sudo iptables -D FORWARD -s 172.28.0.100 -d 172.28.0.105 -j DROP
sudo iptables -D FORWARD -s 172.28.0.105 -d 172.28.0.100 -j DROP
# Execute within the client container because doing so from the host is not reliable in CI.
docker compose exec -it client /bin/sh -c 'iptables -A OUTPUT -d 172.28.0.105 -j DROP'
}
function client_curl_resource() {