Skip to content

Commit f4fdf81

Browse files
committed
ci: detect outbound internet traffic generated while running tests
Resolves bitcoin#31339
1 parent bd058f1 commit f4fdf81

File tree

6 files changed

+60
-3
lines changed

6 files changed

+60
-3
lines changed

ci/test/00_setup_env.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out}
6464
# The folder for previous release binaries.
6565
# This folder exists only on the ci guest, and on the ci host as a volume.
6666
export PREVIOUS_RELEASES_DIR=${PREVIOUS_RELEASES_DIR:-$BASE_ROOT_DIR/prev_releases}
67-
export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential pkgconf curl ca-certificates ccache python3 rsync git procps bison e2fsprogs cmake ninja-build}
67+
export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential pkgconf curl ca-certificates ccache python3 rsync git procps bison e2fsprogs cmake ninja-build net-tools tcpdump}
6868
export GOAL=${GOAL:-install}
6969
export DIR_QA_ASSETS=${DIR_QA_ASSETS:-${BASE_SCRATCH_DIR}/qa-assets}
7070
export CI_RETRY_EXE=${CI_RETRY_EXE:-"retry --"}

ci/test/00_setup_env_mac_native.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ export CI_OS_NAME="macos"
1717
export NO_DEPENDS=1
1818
export OSX_SDK=""
1919
export BITCOIN_CMD="bitcoin -m" # Used in functional tests
20+
# Can't run tcpdump: tcpdump: en0: You don't have permission to capture on that device
21+
export CI_TCPDUMP_OK_TO_FAIL=1

ci/test/00_setup_env_mac_native_fuzz.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ export RUN_UNIT_TESTS=false
1616
export RUN_FUNCTIONAL_TESTS=false
1717
export RUN_FUZZ_TESTS=true
1818
export GOAL="all"
19+
# Can't run tcpdump: tcpdump: en0: You don't have permission to capture on that device
20+
export CI_TCPDUMP_OK_TO_FAIL=1

ci/test/00_setup_env_native_centos.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
88

99
export CONTAINER_NAME=ci_native_centos
1010
export CI_IMAGE_NAME_TAG="quay.io/centos/centos:stream10"
11-
export CI_BASE_PACKAGES="gcc-c++ glibc-devel libstdc++-devel ccache make ninja-build git python3 python3-pip which patch xz procps-ng rsync coreutils bison e2fsprogs cmake dash"
11+
export CI_BASE_PACKAGES="gcc-c++ glibc-devel libstdc++-devel ccache make ninja-build git python3 python3-pip which patch xz procps-ng rsync coreutils bison e2fsprogs cmake dash net-tools tcpdump"
1212
export PIP_PACKAGES="pyzmq pycapnp"
1313
export DEP_OPTS="DEBUG=1"
1414
export GOAL="install"

ci/test/02_run_container.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
8686
docker image prune --force --filter "label=$CI_IMAGE_LABEL"
8787

8888
# shellcheck disable=SC2086
89-
CI_CONTAINER_ID=$(docker run --cap-add LINUX_IMMUTABLE $CI_CONTAINER_CAP --rm --interactive --detach --tty \
89+
CI_CONTAINER_ID=$(docker run --cap-add LINUX_IMMUTABLE --cap-add NET_RAW $CI_CONTAINER_CAP --rm --interactive --detach --tty \
9090
--mount "type=bind,src=$BASE_READ_ONLY_DIR,dst=$BASE_READ_ONLY_DIR,readonly" \
9191
--mount "${CI_CCACHE_MOUNT}" \
9292
--mount "${CI_DEPENDS_MOUNT}" \

ci/test/03_test_script.sh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,17 +167,65 @@ if [ "$RUN_CHECK_DEPS" = "true" ]; then
167167
"${BASE_ROOT_DIR}/contrib/devtools/check-deps.sh" "${BASE_BUILD_DIR}"
168168
fi
169169

170+
function get_interfaces()
171+
{
172+
set -o pipefail
173+
ifconfig | awk -F ':| ' '/^[^[:space:]]/ { if (!match($1, /^lo/)) { print $1 } }'
174+
set +o pipefail
175+
}
176+
177+
function tcpdump_file()
178+
{
179+
echo "/tmp/tcpdump_$1_$2"
180+
}
181+
182+
function traffic_monitor_begin()
183+
{
184+
test_name="$1"
185+
for ifname in $(get_interfaces) ; do
186+
tcpdump -nU -i "$ifname" -w "$(tcpdump_file "$test_name" "$ifname")" &
187+
done
188+
}
189+
190+
function traffic_monitor_end()
191+
{
192+
test_name="$1"
193+
194+
for ifname in $(get_interfaces) ; do
195+
f=$(tcpdump_file "$test_name" "$ifname")
196+
if [ ! -e "$f" ] && [ "$CI_TCPDUMP_OK_TO_FAIL" = "1" ] ; then
197+
# In some CI environments this script is not running as root and so the
198+
# tcpdump errors and does not create $f. Skip silently those, but we
199+
# need at least one where tcpdump can run and this is the ASAN one. So
200+
# treat the absence of $f as an error only on the ASAN task.
201+
continue
202+
fi
203+
# We are running as root and those files are created with owner:group =
204+
# tcpdump:tcpdump and then `tcpdump -r` refuses to read them with an error
205+
# "permission denied" if they are not owned by root:root.
206+
chown root:root "$f"
207+
out="$(tcpdump -n -r "$f" --direction=out tcp or udp)"
208+
if [ -n "$out" ] ; then
209+
echo "Error: outbound TCP or UDP packets on the non loopback interface generated during $test_name tests:" >&2
210+
tcpdump -n -r "$f" tcp or udp
211+
fi
212+
done
213+
}
214+
170215
if [ "$RUN_UNIT_TESTS" = "true" ]; then
216+
traffic_monitor_begin "unit"
171217
DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" \
172218
LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" \
173219
CTEST_OUTPUT_ON_FAILURE=ON \
174220
ctest --test-dir "${BASE_BUILD_DIR}" \
175221
--stop-on-failure \
176222
"${MAKEJOBS}" \
177223
--timeout $(( TEST_RUNNER_TIMEOUT_FACTOR * 60 ))
224+
traffic_monitor_end "unit"
178225
fi
179226

180227
if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
228+
traffic_monitor_begin "functional"
181229
# parses TEST_RUNNER_EXTRA as an array which allows for multiple arguments such as TEST_RUNNER_EXTRA='--exclude "rpc_bind.py --ipv6"'
182230
eval "TEST_RUNNER_EXTRA=($TEST_RUNNER_EXTRA)"
183231
LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" \
@@ -190,9 +238,11 @@ if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
190238
"${TEST_RUNNER_EXTRA[@]}" \
191239
--quiet \
192240
--failfast
241+
traffic_monitor_end "functional"
193242
fi
194243

195244
if [ "${RUN_TIDY}" = "true" ]; then
245+
traffic_monitor_begin "tidy"
196246
cmake -B /tidy-build -DLLVM_DIR=/usr/lib/llvm-"${TIDY_LLVM_V}"/cmake -DCMAKE_BUILD_TYPE=Release -S "${BASE_ROOT_DIR}"/contrib/devtools/bitcoin-tidy
197247
cmake --build /tidy-build "$MAKEJOBS"
198248
cmake --build /tidy-build --target bitcoin-tidy-tests "$MAKEJOBS"
@@ -219,9 +269,11 @@ if [ "${RUN_TIDY}" = "true" ]; then
219269
cd "${BASE_ROOT_DIR}/src"
220270
python3 "/include-what-you-use/fix_includes.py" --nosafe_headers < /tmp/iwyu_ci.out
221271
git --no-pager diff
272+
traffic_monitor_end "tidy"
222273
fi
223274

224275
if [ "$RUN_FUZZ_TESTS" = "true" ]; then
276+
traffic_monitor_begin "fuzz"
225277
# shellcheck disable=SC2086
226278
LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" \
227279
"${BASE_BUILD_DIR}/test/fuzz/test_runner.py" \
@@ -230,4 +282,5 @@ if [ "$RUN_FUZZ_TESTS" = "true" ]; then
230282
-l DEBUG \
231283
"${DIR_FUZZ_IN}" \
232284
--empty_min_time=60
285+
traffic_monitor_end "fuzz"
233286
fi

0 commit comments

Comments
 (0)