mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-20 04:23:49 +00:00
Add an interoperability test against shadowsocks-rust
A cipher can round-trip perfectly against our own implementation and still be wrong: header layout, padding rules, and nonce ordering are only pinned down by talking to another implementation. This drives ss-local against rust's ssserver and rust's sslocal against ss-server, over a local origin server so it needs no network access. Covers the three SIP022 methods plus aes-256-gcm, so a regression in the legacy path shows up here too. Skips itself when shadowsocks-rust or the built binaries are absent, so it is safe to run anywhere.
This commit is contained in:
@@ -174,6 +174,16 @@ ss_add_test(test_aead2022
|
||||
"test_aead2022.c;${SS_CRYPTO_TEST_SOURCES}"
|
||||
"${TEST_CRYPTO_LIBS};m")
|
||||
|
||||
# test_interop_rust - interoperability against shadowsocks-rust.
|
||||
# Skips itself when shadowsocks-rust or the built binaries are absent.
|
||||
add_test(NAME test_interop_rust
|
||||
COMMAND bash "${PROJECT_SOURCE_DIR}/tests/test_interop_rust.sh"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}")
|
||||
set_tests_properties(test_interop_rust PROPERTIES
|
||||
LABELS "integration"
|
||||
TIMEOUT 300
|
||||
ENVIRONMENT "SS_BIN_DIR=${RUNTIME_SHARED_OUTPUT_DIRECTORY}")
|
||||
|
||||
# test_ss_setup - bash unit tests for the ss-setup TUI tool
|
||||
add_test(NAME test_ss_setup
|
||||
COMMAND bash "${PROJECT_SOURCE_DIR}/tests/test_ss_setup.sh"
|
||||
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Interoperability tests against shadowsocks-rust.
|
||||
#
|
||||
# The 2022 (SIP022) ciphers are only useful if they interoperate with other
|
||||
# implementations, and a spec detail can be got wrong in a way that still
|
||||
# round-trips against ourselves. This drives our binaries against
|
||||
# shadowsocks-rust's in both directions.
|
||||
#
|
||||
# Skips (exit 0) when shadowsocks-rust is not installed, so it is safe to
|
||||
# run everywhere. Install it with `brew install shadowsocks-rust` or
|
||||
# `cargo install shadowsocks-rust`.
|
||||
|
||||
set -u
|
||||
|
||||
BIN_DIR="${SS_BIN_DIR:-build/shared/bin}"
|
||||
ORIGIN_PORT=${ORIGIN_PORT:-18999}
|
||||
SERVER_PORT=${SERVER_PORT:-18388}
|
||||
LOCAL_PORT=${LOCAL_PORT:-18081}
|
||||
|
||||
result=0
|
||||
SPID=""
|
||||
LPID=""
|
||||
HPID=""
|
||||
|
||||
cleanup() {
|
||||
[ -n "$SPID" ] && kill -9 "$SPID" 2>/dev/null
|
||||
[ -n "$LPID" ] && kill -9 "$LPID" 2>/dev/null
|
||||
[ -n "$HPID" ] && kill -9 "$HPID" 2>/dev/null
|
||||
wait 2>/dev/null
|
||||
return 0
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
for tool in sslocal ssserver; do
|
||||
if ! command -v "$tool" > /dev/null 2>&1; then
|
||||
echo "SKIP: shadowsocks-rust ($tool) not installed"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
for tool in curl python3 openssl; do
|
||||
if ! command -v "$tool" > /dev/null 2>&1; then
|
||||
echo "SKIP: $tool not available"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -x "$BIN_DIR/ss-local" ] || [ ! -x "$BIN_DIR/ss-server" ]; then
|
||||
echo "SKIP: shadowsocks-libev binaries not found in $BIN_DIR"
|
||||
echo " (set SS_BIN_DIR to override)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# A local origin server keeps the test off the network.
|
||||
WWW_DIR="$(mktemp -d)"
|
||||
echo "interop-ok" > "$WWW_DIR/index.html"
|
||||
(cd "$WWW_DIR" && python3 -m http.server "$ORIGIN_PORT" --bind 127.0.0.1) \
|
||||
> /dev/null 2>&1 &
|
||||
HPID=$!
|
||||
sleep 1
|
||||
|
||||
# Fetch through the SOCKS5 proxy and check we got the origin's content back.
|
||||
fetch_through_proxy() {
|
||||
curl -s --max-time 15 --socks5-hostname "127.0.0.1:$LOCAL_PORT" \
|
||||
"http://127.0.0.1:$ORIGIN_PORT/" 2>/dev/null | grep -q "interop-ok"
|
||||
}
|
||||
|
||||
run_case() {
|
||||
local desc="$1" server_cmd="$2" client_cmd="$3"
|
||||
|
||||
printf '\e[0;36mrunning: %s\e[0m\n' "$desc"
|
||||
|
||||
$server_cmd > /dev/null 2>&1 &
|
||||
SPID=$!
|
||||
sleep 1
|
||||
$client_cmd > /dev/null 2>&1 &
|
||||
LPID=$!
|
||||
sleep 2
|
||||
|
||||
if fetch_through_proxy; then
|
||||
printf '\e[0;32mOK: %s\e[0m\n' "$desc"
|
||||
else
|
||||
printf '\e[0;31mFAILED: %s\e[0m\n' "$desc"
|
||||
result=1
|
||||
fi
|
||||
|
||||
kill -9 "$SPID" "$LPID" 2>/dev/null
|
||||
wait "$SPID" "$LPID" 2>/dev/null
|
||||
SPID=""
|
||||
LPID=""
|
||||
# let the listening sockets go away before the next case binds them
|
||||
sleep 2
|
||||
}
|
||||
|
||||
test_method() {
|
||||
local method="$1" key_size="$2"
|
||||
local psk
|
||||
|
||||
psk="$(openssl rand -base64 "$key_size")"
|
||||
|
||||
run_case "$method: libev client -> rust server" \
|
||||
"ssserver -s 127.0.0.1:$SERVER_PORT -k $psk -m $method" \
|
||||
"$BIN_DIR/ss-local -s 127.0.0.1 -p $SERVER_PORT -l $LOCAL_PORT -k $psk -m $method"
|
||||
|
||||
run_case "$method: rust client -> libev server" \
|
||||
"$BIN_DIR/ss-server -s 127.0.0.1 -p $SERVER_PORT -k $psk -m $method" \
|
||||
"sslocal -b 127.0.0.1:$LOCAL_PORT -s 127.0.0.1:$SERVER_PORT -k $psk -m $method"
|
||||
}
|
||||
|
||||
# SIP022. The key sizes are fixed by the spec.
|
||||
test_method 2022-blake3-aes-128-gcm 16
|
||||
test_method 2022-blake3-aes-256-gcm 32
|
||||
test_method 2022-blake3-chacha20-poly1305 32
|
||||
|
||||
# A legacy AEAD cipher, to catch a regression that only affects the old path.
|
||||
test_method aes-256-gcm 32
|
||||
|
||||
rm -rf "$WWW_DIR"
|
||||
|
||||
exit $result
|
||||
Reference in New Issue
Block a user