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.
7.2 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
shadowsocks-c (formerly shadowsocks-libev) is a lightweight SOCKS5 proxy. Version 3.3.6, licensed under GPLv3.
The sources are C++20 (no exceptions, no RTTI, no heap allocation after startup; see docs/cpp-core.md).
The public src/shadowsocks.h stays a C header with a stable ABI.
Build Commands
CMake (sole build system)
cmake --preset bundled # or: cmake -S . -B build -G Ninja
cmake --build --preset bundled
ctest --preset bundled
Bundled mode (the default, SS_DEPENDENCY_MODE=bundled) builds every dependency from the pinned archives in
third_party/dist with no network access. SS_DEPENDENCY_MODE=system uses distro libraries instead.
There are no git submodules.
Binaries land in <build>/bin/, libraries in <build>/lib/.
Build Dependencies
- CMake >= 3.20, C11 and C++20 compilers (GCC >= 11, Clang >= 14, Apple Clang >= 15), Ninja for the presets
- System mode only: Mbed TLS 2.x/3.x, libsodium >= 1.0.4, PCRE2 (8-bit), libuv, c-ares
- Doxygen (documentation only)
CMake Options
-DSS_MINIMAL=ON: no regex, plugins or manager-DWITH_STATIC=OFF: link third-party dependencies dynamically-DSS_BUILD_EXECUTABLES / SS_BUILD_STATIC_LIBRARY / SS_BUILD_SHARED_LIBRARY: choose outputs-DWITH_DOC_MAN=ON/-DWITH_DOC_HTML=ON: build documentation-DENABLE_CONNMARKTOS=ON,-DENABLE_NFTABLES=ON: Linux netfilter features-DENABLE_SANITIZERS=ON,-DENABLE_COVERAGE=ON,-DDISABLE_SSP=ON,-DBUILD_TESTING=OFF
Testing
Unit Tests (CTest)
ctest --test-dir build -LE memcheck --output-on-failure
Unit tests compile the specific src/*.cpp files they need (see ss_add_test in tests/CMakeLists.txt).
New tests are C++ (tests/test_*_cpp.cpp, tests/test_core_*.cpp) using tests/test_helpers.hpp; older
ones are C (tests/test_*.c). Codec tests compare against the C oracle in tests/reference/. The
alloc_steady_* tests fail on any heap allocation in steady state.
Labels: unit, vendor, integration, memcheck (Linux + valgrind).
Integration Tests
python3 tests/interop.py --self --bin build/bin # TCP/UDP relay, all AEAD/2022 methods
python3 tests/tunnel_interop.py --bin build/bin # ss-tunnel, every method
python3 tests/test_manager.py --bin build/bin # ss-manager (needs -DWITH_SS_MANAGER=ON on macOS)
python3 tests/test.py --bin build/bin/ -c tests/aes-gcm.json # one cipher via curl/dig (needs network)
python3 tests/test_cli.py --bin-dir build/bin # CLI contract: help/version/exit codes
python3 tests/stress_test.py --bin build/bin/ --size 10
Allocation audit
python3 tests/alloc_audit/measure_alloc.py --bin build/bin --shim build/lib/libss_alloc_audit.dylib
Reports heap allocations per relayed connection (C baseline numbers are in docs/cpp-core.md).
Code Formatting
Uses uncrustify with the config at .uncrustify.cfg. Key settings: 4-space indent, no tabs, 120-column width, K&R brace style (braces on same line).
Code Quality Tooling
- clang-tidy: config in
.clang-tidy. The build exportscompile_commands.jsonautomatically. Run locally:On macOS with Homebrew LLVM, addrun-clang-tidy -quiet -p build '/(src/(core/|event/|relay/|crypto/|api/)?[^/]+\.(c|cpp)|tests/test_(core_[^/]+|[a-z_]+_cpp)\.cpp)$'-extra-arg="-isysroot$(xcrun --show-sdk-path)". CI (clang-tidyjob intests.yml) enforces a warning-count ratchet viaMAX_WARNINGS— lower it when fixing findings; never raise it without justification. - No-heap lint:
scripts/check_no_heap.py --self-test(also a ctest) rejects heap allocation in C++ sources undersrc/. - Sanitizers:
cmake .. -DENABLE_SANITIZERS=ONbuilds with ASan + UBSan. CI runs ctest and the stress test under sanitizers on every PR. - Coverage:
cmake .. -DENABLE_COVERAGE=ON, run tests, thenmake coverage(needs lcov). HTML report lands inbuild/coverage-html/. CI uploads it as thecoverage-htmlartifact.
Architecture
Binaries (all in src/)
Each binary is compiled with a module define that controls conditional compilation:
| Binary | Define | Purpose |
|---|---|---|
ss-local |
MODULE_LOCAL |
SOCKS5 client proxy |
ss-server |
MODULE_REMOTE |
Server-side proxy |
ss-tunnel |
MODULE_TUNNEL |
Port forwarding tunnel (implies MODULE_LOCAL) |
ss-redir |
MODULE_REDIR |
Transparent proxy via iptables (Linux only, implies MODULE_LOCAL) |
ss-manager |
MODULE_MANAGER |
Multi-server manager daemon (Linux only by default) |
A library libshadowsocks-c (legacy names libshadowsocks-libev.* are kept) is built from the ss-local sources with -DLIB_ONLY. Its public API is in src/shadowsocks.h.
Source Organization (src/)
Shared by all binaries:
utils.cpp- logging, system utilities,ss_malloc/ss_free(startup only), CLI help snippetsjconf.cpp/json.cpp- JSON config file parsingnetutils.cpp- network address utilitiesppbloom.cpp- ping-pong bloom filter for salt replay detection (third_party/bloom)
Relay engines (src/relay/): tcp.cpp (one TCP engine for all four programs, Kind selects the
handshake), udp.cpp (UDP relay), codec.cpp (per-connection encoder/decoder variants), resolver.cpp
(pooled c-ares queries), socket.cpp (upstream sockets, TFO). Each program's main() builds a config and
runs them.
Crypto (src/crypto/): value-type codecs aead.cpp (AES-GCM, ChaCha20-Poly1305), aead2022.cpp
(Shadowsocks 2022, BLAKE3 from src/blake3), keys.cpp
(key derivation, method tables). The old C implementation lives in tests/reference/ as a test oracle.
ACL: acl.cpp / rule.cpp / ipset.cpp - IP prefix sets and PCRE2/literal domain rules.
Plugins: plugin.cpp / process.cpp - SIP003 plugin subprocess management.
C++ core: src/core/*.hpp - ownership and allocation primitives (pools, handles, fixed buffers, arena,
fixed hash map/LRU, intrusive list, bounded heap, heap_guard for third-party allocators).
Embedding API: src/shadowsocks.h (unchanged C ABI), src/shadowsocks/control.h
(ss_local_start/stop/wait/destroy) and src/shadowsocks/shadowsocks.hpp (RAII wrapper).
Event Loop
src/event/loop.hpp wraps libuv (kqueue/epoll/IOCP) handles embedded by value in their owners;
src/event/program.hpp is the per-process loop, signals and timers. Connections come from fixed pools sized by
--max-connections, --max-udp-sessions and --max-dns-queries; a full TCP pool pauses accepting.
Non-owning references (DNS answers, timers) are generation-checked handles. Each binary still defines its
own main() and option parsing in local.cpp, tunnel.cpp, redir.cpp, server.cpp, manager.cpp.
Compiler Flags
From cmake/ProjectOptions.cmake: -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -fstack-protector-strong, plus _GNU_SOURCE on Linux. C is C11 with GNU extensions. C++ is C++20 without extensions and adds -Wextra -fno-exceptions -fno-rtti -fno-threadsafe-statics.
-Werror means all warnings are errors — new code must compile warning-free.