Files
shadowsocks-libev/tests/tunnel_interop.py
Max Lv 5f264333a0 Remove the stream ciphers
The unauthenticated stream ciphers (aes-*-cfb, aes-*-ctr, camellia-*-cfb,
chacha20, chacha20-ietf, salsa20) are gone from every build, together
with the SS_ENABLE_LEGACY option, the C++ stream codecs, their C test
oracle and the stream-only tests and configurations. A configuration
naming one of them, or RC4/table, now fails at startup with a message
pointing to an AEAD method, and test_cli checks that.

Shell completions list only the supported methods (and now include the
2022 ones), and the docs and the compatibility contract say the stream
ciphers were removed.
2026-10-15 00:34:33 +08:00

99 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""ss-tunnel against ss-server (and shadowsocks-rust when present): concurrent TCP
transfers and a UDP round trip through a fixed tunnel target, for every method."""
import argparse
import base64
import concurrent.futures
import os
from pathlib import Path
import shutil
import socket
import subprocess
import threading
from interop import TCPHandler, TCPOrigin, UDPHandler, UDPOrigin, free_port, peers, receive
METHODS = ["2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305",
"aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305"]
def tcp_case(port, size):
payload = os.urandom(size)
with socket.create_connection(("127.0.0.1", port), timeout=15) as sock, \
concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
upload = pool.submit(sock.sendall, payload)
assert receive(sock, size) == payload, "TCP payload mismatch"
upload.result(timeout=15)
def udp_case(port):
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.settimeout(.5)
for size in (1, 1200):
payload = os.urandom(size)
# The UDP-only tunnel has no TCP port to wait on: retry until up.
for attempt in range(20):
sock.sendto(payload, ("127.0.0.1", port))
try:
reply, _ = sock.recvfrom(65535)
break
except TimeoutError:
if attempt == 19:
raise
assert reply == payload, "UDP payload mismatch"
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--bin", required=True, type=Path)
parser.add_argument("--fast-open", action="store_true")
args = parser.parse_args()
bins = args.bin.resolve()
server, tunnel = str(bins / "ss-server"), str(bins / "ss-tunnel")
rust_server = shutil.which("ssserver")
failures = 0
with TCPOrigin(("127.0.0.1", 0), TCPHandler) as tcp, UDPOrigin(("127.0.0.1", 0), UDPHandler) as udp:
for origin in (tcp, udp):
threading.Thread(target=origin.serve_forever, daemon=True).start()
try:
for method in METHODS:
for peer in ("C server",) + (("Rust server",) if rust_server else ()):
key = base64.b64encode(os.urandom(16 if "aes-128" in method else 32)).decode()
secret = ["-k", key]
sport, tport, uport = free_port(), free_port(), free_port()
if peer == "C server":
srv = [server, "-s", "127.0.0.1", "-p", str(sport), "-m", method, "-u"] + secret
else:
srv = [rust_server, "-s", f"127.0.0.1:{sport}", "-m", method, "-U"] + secret
extra = ["--fast-open"] if args.fast_open else []
tcp_tunnel = [tunnel, "-s", "127.0.0.1", "-p", str(sport), "-l", str(tport), "-m", method,
"-L", f"127.0.0.1:{tcp.server_address[1]}"] + secret + extra
udp_tunnel = [tunnel, "-s", "127.0.0.1", "-p", str(sport), "-l", str(uport), "-m", method,
"-U", "-L", f"127.0.0.1:{udp.server_address[1]}"] + secret
label = f"{method}: tunnel -> {peer}"
try:
with peers([srv, tcp_tunnel], [sport, tport]):
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
cases = [pool.submit(tcp_case, tport, size) for size in (1, 4096, 65536, 1048576)]
for case in cases:
case.result(timeout=60)
udp_proc = subprocess.Popen(udp_tunnel, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
try:
udp_case(uport)
finally:
udp_proc.terminate()
udp_proc.wait(timeout=5)
print("PASS " + label, flush=True)
except (OSError, AssertionError, TimeoutError) as error:
failures += 1
print(f"FAIL {label}: {error!r}", flush=True)
finally:
tcp.shutdown()
udp.shutdown()
return int(failures != 0)
if __name__ == "__main__":
raise SystemExit(main())