Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# clang-tidy configuration for shadowsocks-libev project sources (src/ only).
# clang-tidy configuration for shadowsocks-c project sources (src/ only).
# Bundled sources under third_party/ and src/blake3/ are third-party code and
# are excluded by the file regex used in CI:
# run-clang-tidy -p build '/src/[^/]+\.c$'
Expand All @@ -8,7 +8,7 @@
# Checks disabled below are either stylistic churn (macro-parentheses,
# reserved-identifier: the codebase uses _prefixed names and vendored
# uthash.h/generated config.h trip them ~600 times) or produce false
# positives with the libev callback style (casting-through-void,
# positives with the event callback style (casting-through-void,
# multi-level-implicit-pointer-conversion).
Checks: >
clang-analyzer-*,
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ jobs:
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev

- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: brew install mbedtls@3 libsodium libev c-ares pcre2
run: brew install mbedtls@3 libsodium libuv c-ares pcre2

- name: Build
run: |
Expand All @@ -41,7 +41,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev
sudo apt-get install -y --no-install-recommends \
build-essential cmake debhelper dpkg-dev fakeroot asciidoc-base xmlto pkg-config

Expand Down
23 changes: 20 additions & 3 deletions .github/workflows/portability.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
ctest --test-dir build -L 'unit|vendor' --output-on-failure --no-tests=error
- name: Real TCP and UDP relay
run: python3 tests/interop.py --self --bin build/bin
- name: Asynchronous hostname ACL bypass
run: python3 tests/async_dns_interop.py --bin build/bin
- name: SIP003 transport and child cleanup
if: matrix.minimal == 'OFF'
run: python3 tests/interop.py --self --bin build/bin --plugin tests/sip003_fixture.py
Expand All @@ -35,6 +37,10 @@ jobs:
cmake --build consumer
./consumer/consumer_static
./consumer/consumer_shared
cmake -S tests/consumer -B consumer-legacy -DSS_PACKAGE_NAME=shadowsocks-libev -DCMAKE_PREFIX_PATH="$PWD/relocated"
cmake --build consumer-legacy
./consumer-legacy/consumer_static
./consumer-legacy/consumer_shared

windows:
runs-on: windows-latest
Expand All @@ -59,11 +65,14 @@ jobs:
ctest --test-dir build -L 'unit|vendor' --output-on-failure --no-tests=error
objdump -p build/bin/ss-server.exe | sed -n '/DLL Name/p'
python tests/interop.py --self --bin build/bin --isolate-windows-runtime
python tests/async_dns_interop.py --bin build/bin --isolate-windows-runtime
- name: Installed consumers
run: |
cmake --install build --prefix "$PWD/install"
cmake -S tests/consumer -B consumer -G Ninja -DCMAKE_PREFIX_PATH="$PWD/install"
cmake --build consumer
cmake -S tests/consumer -B consumer-legacy -G Ninja -DSS_PACKAGE_NAME=shadowsocks-libev -DCMAKE_PREFIX_PATH="$PWD/install"
cmake --build consumer-legacy
- name: Run installed consumers without toolchain DLLs
shell: pwsh
run: |
Expand All @@ -72,6 +81,10 @@ jobs:
if ($LASTEXITCODE -ne 0) { throw "Static consumer failed: $LASTEXITCODE" }
& ./consumer/consumer_shared.exe
if ($LASTEXITCODE -ne 0) { throw "Shared consumer failed: $LASTEXITCODE" }
& ./consumer-legacy/consumer_static.exe
if ($LASTEXITCODE -ne 0) { throw "Legacy static consumer failed: $LASTEXITCODE" }
& ./consumer-legacy/consumer_shared.exe
if ($LASTEXITCODE -ne 0) { throw "Legacy shared consumer failed: $LASTEXITCODE" }

static-macos:
runs-on: macos-latest
Expand All @@ -95,6 +108,7 @@ jobs:
- name: Exercise installed static programs
run: |
python3 tests/interop.py --self --bin relocated-static/bin
python3 tests/async_dns_interop.py --bin relocated-static/bin
python3 tests/interop.py --self --bin relocated-static/bin --plugin tests/sip003_fixture.py
- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -132,7 +146,9 @@ jobs:
- name: Reject third-party DLL imports, including delay imports
run: python tests/check_static_runtime.py relocated-static/bin/ss-*.exe consumer-static/consumer_static.exe
- name: Exercise installed programs without toolchain DLLs
run: python tests/interop.py --self --bin relocated-static/bin --isolate-windows-runtime
run: |
python tests/interop.py --self --bin relocated-static/bin --isolate-windows-runtime
python tests/async_dns_interop.py --bin relocated-static/bin --isolate-windows-runtime
- name: Run static consumer with only Windows system directories on PATH
shell: pwsh
run: |
Expand Down Expand Up @@ -171,6 +187,7 @@ jobs:
cmake --build build --parallel 4
ctest --test-dir build -L 'unit|vendor' --output-on-failure --no-tests=error
python3 tests/interop.py --self --bin build/bin
python3 tests/async_dns_interop.py --bin build/bin
cmake --install build --prefix "$PWD/install"
cmake -S tests/consumer -B consumer -G Ninja -DCMAKE_PREFIX_PATH="$PWD/install"
cmake --build consumer
Expand All @@ -182,7 +199,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Source archive
run: python3 scripts/source_archive.py release/shadowsocks-libev.tar.gz
run: python3 scripts/source_archive.py release/shadowsocks-c.tar.gz
- name: Prepare compiler image
run: |
printf 'FROM alpine:3.24\nRUN apk add --no-cache build-base cmake python3 linux-headers\n' > /tmp/ss-toolchain.Dockerfile
Expand All @@ -191,7 +208,7 @@ jobs:
run: |
docker run --rm --network none -v "$PWD/release:/release:ro" ss-toolchain sh -ec '
mkdir /src
tar xzf /release/shadowsocks-libev.tar.gz -C /src --strip-components=1
tar xzf /release/shadowsocks-c.tar.gz -C /src --strip-components=1
cmake -S /src -B /build -DCMAKE_DISABLE_FIND_PACKAGE_Python3=TRUE
cmake --build /build --parallel 4
ctest --test-dir /build -L "unit|vendor" --output-on-failure --no-tests=error
Expand Down
50 changes: 41 additions & 9 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ on:
branches: [master]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: '1.25'
cache: false
- uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install pinned linters
run: |
go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.12
python -m pip install ruff==0.15.6
- name: Lint GitHub Actions workflows
run: actionlint -shellcheck= -pyflakes=
- name: Lint Python scripts and tests
run: ruff check --select E9,F63,F7,F82 tests scripts

tests:
strategy:
fail-fast: false
Expand All @@ -20,11 +40,11 @@ jobs:
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev valgrind
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev valgrind

- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: brew install mbedtls@3 libsodium libev c-ares pcre2
run: brew install mbedtls@3 libsodium libuv c-ares pcre2

- name: Build test binaries
run: |
Expand Down Expand Up @@ -62,7 +82,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev

- name: Build with ASan + UBSan
run: |
Expand Down Expand Up @@ -91,14 +111,16 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang-tidy-18 clang-tools-18 libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev
sudo apt-get install -y clang-tidy-18 clang-tools-18 libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev

- name: Configure (compile_commands.json)
run: cmake -S . -B build

- name: Run clang-tidy on project sources
run: |
run-clang-tidy-18 -quiet -p build "$PWD/src/[^/]+\.c$" 2>/dev/null | tee tidy.log || true
set -o pipefail
tidy_status=0
run-clang-tidy-18 -quiet -p build "$PWD/src/[^/]+\.c$" 2>&1 | tee tidy.log || tidy_status=$?
grep 'warning:' tidy.log | sort -u > warnings.txt || true
count="$(wc -l < warnings.txt)"
echo "clang-tidy warnings: $count (max allowed: $MAX_WARNINGS)"
Expand All @@ -108,8 +130,8 @@ jobs:
cat warnings.txt
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
if ! grep -q . warnings.txt && grep -qE 'error:' tidy.log; then
echo "clang-tidy produced errors:"; grep -E 'error:' tidy.log | sort -u
if [ "$tidy_status" -ne 0 ] || grep -qE 'error:' tidy.log; then
echo "clang-tidy failed (exit status: $tidy_status). See tidy.log for diagnostics."
exit 1
fi
if [ "$count" -gt "$MAX_WARNINGS" ]; then
Expand All @@ -118,6 +140,16 @@ jobs:
exit 1
fi

- name: Upload clang-tidy diagnostics
if: always()
uses: actions/upload-artifact@v4
with:
name: clang-tidy-diagnostics
path: |
tidy.log
warnings.txt
if-no-files-found: ignore

coverage:
runs-on: ubuntu-latest
steps:
Expand All @@ -126,7 +158,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y lcov libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev
sudo apt-get install -y lcov libpcre2-dev libmbedtls-dev libsodium-dev libuv1-dev libc-ares-dev

- name: Build with coverage instrumentation
run: |
Expand Down Expand Up @@ -160,7 +192,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Install dependencies and independent peer
run: brew install mbedtls@3 libsodium libev c-ares pcre2 shadowsocks-rust
run: brew install mbedtls@3 libsodium libuv c-ares pcre2 shadowsocks-rust
- name: Build
run: |
cmake -S . -B build -DSS_DEPENDENCY_MODE=system -DWITH_STATIC=OFF
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)

set(PROJECT_NAME shadowsocks-libev)
set(PROJECT_NAME shadowsocks-c)
set(RELEASE_DATE 2026-02-09)
set(PROJECT_VERSION "3.3.6")
set(PROJECT_DESC "a lightweight secured socks5 proxy")
Expand Down Expand Up @@ -98,6 +98,7 @@ endif()
include(${PROJECT_SOURCE_DIR}/cmake/configure.cmake)
configure_file(${PROJECT_SOURCE_DIR}/cmake/config.h.cmake ${PROJECT_BINARY_DIR}/src/config.h)
include(cmake/ProjectOptions.cmake)
ss_project_options(ss_ev)
include_directories(${PROJECT_BINARY_DIR}/src)
add_compile_definitions(HAVE_CONFIG_H)

Expand Down
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# shadowsocks-libev
# shadowsocks-c

[![Build Status](https://travis-ci.com/shadowsocks/shadowsocks-libev.svg?branch=master)](https://travis-ci.com/shadowsocks/shadowsocks-libev) [![Snap Status](https://snapcraft.io/shadowsocks-libev/badge.svg)](https://snapcraft.io/shadowsocks-libev)

## Intro

[Shadowsocks-libev](https://shadowsocks.org) is a lightweight secured SOCKS5
[shadowsocks-c](https://shadowsocks.org) is a lightweight secured SOCKS5
proxy for embedded devices and low-end boxes.

It is a port of [Shadowsocks](https://github.com/shadowsocks/shadowsocks)
Expand All @@ -15,12 +15,19 @@ Current version: 3.3.6 | [Changelog](debian/changelog)

## Features

Shadowsocks-libev is written in pure C and depends on [libev](http://software.schmorp.de/pkg/libev.html). It's designed
shadowsocks-c is written in pure C and depends on [libuv](https://libuv.org/). It's designed
to be a lightweight implementation of shadowsocks protocol, in order to keep the resource usage as low as possible.

For a full list of feature comparison between different versions of shadowsocks,
refer to the [Wiki page](https://github.com/shadowsocks/shadowsocks/wiki/Feature-Comparison-across-Different-Versions).

The project is now **shadowsocks-c**. Commands (`ss-local`, `ss-server`, etc.)
and the `shadowsocks.h` API remain compatible. New builds produce
`libshadowsocks-c` with CMake/pkg-config package `shadowsocks-c`; legacy library
filenames and package lookup names remain available as compatibility aliases.
Existing configuration paths, distro package names and service names are retained.
Repository links below still point to the current GitHub repository.

## Quick Start

Snap is the recommended way to install the latest binaries.
Expand Down Expand Up @@ -93,7 +100,7 @@ IPv4/IPv6 CIDRs, `full:example.com` for exact domains, and
case and respect label boundaries. Unsupported regex rules are rejected.

Distribution packages can use `-DSS_DEPENDENCY_MODE=system -DWITH_STATIC=OFF`
with libev, c-ares, libsodium, Mbed TLS 3.x, and PCRE2 development packages.
with libuv, c-ares, libsodium, Mbed TLS 3.x, and PCRE2 development packages.
Use `-DCMAKE_PREFIX_PATH=/opt/homebrew/opt/mbedtls@3` when needed on macOS.

| Option | Default | Purpose |
Expand All @@ -110,7 +117,7 @@ Use `-DCMAKE_PREFIX_PATH=/opt/homebrew/opt/mbedtls@3` when needed on macOS.
| `ENABLE_SANITIZERS` | `OFF` | AddressSanitizer and UndefinedBehaviorSanitizer |
| `ENABLE_CONNMARKTOS` / `ENABLE_NFTABLES` | `OFF` | Optional Linux firewall integrations |

CMake consumers can use `find_package(shadowsocks-libev CONFIG REQUIRED)` and
CMake consumers can use `find_package(shadowsocks-c CONFIG REQUIRED)` and
link `shadowsocks::static`, `shadowsocks::shared`, or `shadowsocks::shadowsocks`
(which prefers the shared library when installed). A pkg-config file is also
installed. Dependency provenance and update instructions are in
Expand Down Expand Up @@ -196,7 +203,7 @@ ctest --test-dir build -L 'unit|vendor' --output-on-failure
sudo cmake --install build
```

Distribution packagers can install `libpcre2-dev libev-dev libc-ares-dev
Distribution packagers can install `libpcre2-dev libuv1-dev libc-ares-dev
libmbedtls-dev libsodium-dev` and select `-DSS_DEPENDENCY_MODE=system
-DWITH_STATIC=OFF`. Documentation additionally needs asciidoc and xmlto.

Expand Down Expand Up @@ -275,7 +282,7 @@ cmake --build build-windows --parallel

Cross-compilation does not run Windows tests. The portability workflow runs
native UCRT64 tests and TCP/UDP relay checks on Windows. Bundled mode is required
because libev must use the project's Winsock handle adapter. MSVC remains a
with a bundled libuv IOCP backend. MSVC remains a
separate, unsupported milestone; configuration reports this explicitly.
The historical Autotools scripts in `docker/mingw` are superseded by this build.

Expand Down
11 changes: 5 additions & 6 deletions cmake/Dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ elseif(NOT SS_DEPENDENCY_MODE STREQUAL "system")
message(FATAL_ERROR "SS_DEPENDENCY_MODE must be bundled or system")
endif()
if(WIN32)
message(FATAL_ERROR "Windows requires bundled dependencies: libev must use this project's Winsock handle adapter")
message(FATAL_ERROR "Windows requires bundled dependencies: the bundled libuv configuration is the validated Windows build")
endif()

# Select one linkage mode consistently for programs, libraries, and tests.
Expand All @@ -30,10 +30,8 @@ endif()
find_package(MbedTLS REQUIRED)
find_package(Sodium REQUIRED)
find_package(Cares REQUIRED)
find_path(LIBEV_INCLUDE_DIR ev.h)
find_library(LIBEV_LIBRARY NAMES ev)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libev REQUIRED_VARS LIBEV_LIBRARY LIBEV_INCLUDE_DIR)
find_path(LIBUV_INCLUDE_DIR uv.h REQUIRED)
find_library(LIBUV_LIBRARY NAMES uv REQUIRED)
find_package(Threads REQUIRED)
if(WITH_STATIC)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_ss_saved_suffixes})
Expand All @@ -51,7 +49,8 @@ ss_import_dependency(ss_cares "${CARES_LIBRARY}" "${CARES_INCLUDE_DIRS}")
if(SS_ENABLE_REGEX)
ss_import_dependency(ss_pcre2 "${PCRE2_LIBRARY}" "${PCRE2_INCLUDE_DIRS}")
endif()
ss_import_dependency(ss_ev "${LIBEV_LIBRARY}" "${LIBEV_INCLUDE_DIR}")
ss_import_dependency(ss_uv "${LIBUV_LIBRARY}" "${LIBUV_INCLUDE_DIR}")
include(${PROJECT_SOURCE_DIR}/cmake/EventLoop.cmake)
if(WIN32)
set_property(TARGET ss_cares APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2_32 iphlpapi)
set_property(TARGET ss_ev APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2_32)
Expand Down
6 changes: 6 additions & 0 deletions cmake/EventLoop.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_library(ss_ev STATIC ${PROJECT_SOURCE_DIR}/src/ss_event.c)
target_include_directories(ss_ev PUBLIC ${PROJECT_SOURCE_DIR}/src)
target_link_libraries(ss_ev PUBLIC ss_uv Threads::Threads ${SS_MATH_LIBRARY} ${CMAKE_DL_LIBS})
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(ss_ev PUBLIC rt)
endif()
Loading
Loading