mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-28 10:44:43 +08:00
Merge pull request #3059 from shadowsocks/feature/publish-doxygen-pages
Publish native Doxygen documentation with GitHub Pages
This commit is contained in:
41 files changed
+1478
-1939
No files matched your search
@@ -43,7 +43,7 @@ jobs:
|
||||
sudo apt-get update
|
||||
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
|
||||
build-essential cmake debhelper dpkg-dev fakeroot doxygen pkg-config
|
||||
|
||||
- name: Debian package build test
|
||||
run: bash tests/test_deb_build.sh
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
name: documentation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
push:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: documentation-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Install Doxygen
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends doxygen
|
||||
- name: Build and validate documentation
|
||||
run: |
|
||||
python3 scripts/check_cli_docs.py
|
||||
python3 -m unittest discover -s tests -p test_cli_docs.py
|
||||
cmake -S . -B build-docs -DWITH_DOC_MAN=ON -DWITH_DOC_HTML=ON
|
||||
cmake --build build-docs --target doc-man doc-html --parallel 2
|
||||
python3 scripts/check_cli_docs.py --rendered build-docs
|
||||
test -s build-docs/html/index.html
|
||||
- name: Package downloadable man pages
|
||||
run: |
|
||||
tar -czf build-docs/html/man-pages.tar.gz -C build-docs \
|
||||
man/ss-local.1 man/ss-server.1 man/ss-tunnel.1 man/ss-redir.1 \
|
||||
man/ss-manager.1 man/ss-nat.1 man/shadowsocks-c.8 man/shadowsocks-libev.8
|
||||
tar -tzf build-docs/html/man-pages.tar.gz
|
||||
- name: Upload GitHub Pages site
|
||||
if: github.repository == 'shadowsocks/shadowsocks-c' && github.ref == 'refs/heads/master' && github.event_name != 'pull_request'
|
||||
uses: actions/upload-pages-artifact@v5
|
||||
with:
|
||||
path: build-docs/html
|
||||
|
||||
deploy:
|
||||
needs: docs
|
||||
if: github.repository == 'shadowsocks/shadowsocks-c' && github.ref == 'refs/heads/master' && github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
pages: write
|
||||
id-token: write
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Configure GitHub Pages
|
||||
uses: actions/configure-pages@v6
|
||||
- name: Deploy documentation
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v5
|
||||
@@ -26,27 +26,10 @@ jobs:
|
||||
run: actionlint -shellcheck= -pyflakes=
|
||||
- name: Lint Python scripts and tests
|
||||
run: ruff check --select E9,F63,F7,F82 tests scripts
|
||||
- name: Check generated CLI documentation
|
||||
- name: Check Doxygen CLI documentation
|
||||
run: |
|
||||
python3 scripts/gen_cli_docs.py --check
|
||||
python3 -m unittest discover -s tests -p test_gen_cli_docs.py
|
||||
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Install documentation tools
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends asciidoc xmlto docbook-xml docbook-xsl
|
||||
- name: Build man pages and HTML from source
|
||||
run: |
|
||||
cmake -S . -B build-docs -DWITH_DOC_MAN=ON -DWITH_DOC_HTML=ON
|
||||
cmake --build build-docs --target doc-man doc-html --parallel 2
|
||||
test -s build-docs/man/ss-local.1
|
||||
test -s build-docs/man/ss-nat.1
|
||||
test -s build-docs/man/shadowsocks-c.8
|
||||
test -s build-docs/html/ss-local.html
|
||||
python3 scripts/check_cli_docs.py
|
||||
python3 -m unittest discover -s tests -p test_cli_docs.py
|
||||
|
||||
tests:
|
||||
strategy:
|
||||
|
||||
+32
-18
@@ -75,35 +75,39 @@ notices.
|
||||
|
||||
## CLI and manual documentation
|
||||
|
||||
The SYNOPSIS and OPTIONS sections of the manual pages are generated from the
|
||||
literal `getopt_long` declarations in `src/{local,server,tunnel,redir,manager}.c`
|
||||
and the `getopts` declaration in `src/ss-nat`. Descriptions and argument names live
|
||||
in `CLI_DOC` source comments: common C options in `src/utils.c`, program-specific
|
||||
overrides in the corresponding C file, and shell options in `src/ss-nat`.
|
||||
Each entry has an AsciiDoc term such as `--mtu <MTU>::` followed by its description.
|
||||
The generator checks option coverage and argument arity across platform variants;
|
||||
describe platform or feature restrictions in the comment. Cipher lists come from
|
||||
the C cipher tables. Keep explanatory sections and examples in `doc/*.asciidoc`.
|
||||
Doxygen 1.9.4 or newer renders HTML and man pages directly from native source
|
||||
snippets. Each CLI parser has a `cli-options` snippet containing Doxygen
|
||||
`\snippet{doc}` references to its option descriptions. Shared descriptions live
|
||||
in `src/utils.c`; command-specific descriptions live beside the parser. The
|
||||
`ss-nat` script keeps its snippets in a quoted no-op heredoc so documentation
|
||||
cannot execute shell substitutions. Cipher tables are included directly with
|
||||
Doxygen code snippets.
|
||||
|
||||
After changing a parser or its documentation comments, regenerate the checked-in
|
||||
pages and run the generator tests:
|
||||
When adding or changing an option, update its parser, source snippet, and the
|
||||
parser's `cli-options` list. Keep argument names and platform restrictions in the
|
||||
source description. Edit narrative sections and examples in `doc/*.md`. There
|
||||
are no generated documentation files to commit.
|
||||
|
||||
Check that documented flags and argument arity match every platform variant:
|
||||
|
||||
```sh
|
||||
python3 scripts/gen_cli_docs.py
|
||||
python3 scripts/gen_cli_docs.py --check
|
||||
python3 -m unittest discover -s tests -p test_gen_cli_docs.py
|
||||
python3 scripts/check_cli_docs.py
|
||||
python3 -m unittest discover -s tests -p test_cli_docs.py
|
||||
```
|
||||
|
||||
To render the manuals, install Python 3, AsciiDoc, and xmlto, then run:
|
||||
Install Doxygen, then render both formats:
|
||||
|
||||
```sh
|
||||
cmake -S . -B build-docs -DWITH_DOC_MAN=ON -DWITH_DOC_HTML=ON
|
||||
cmake --build build-docs --target doc-man doc-html --parallel
|
||||
python3 scripts/check_cli_docs.py --rendered build-docs
|
||||
```
|
||||
|
||||
The build generates pages in the build directory without modifying source files
|
||||
or executing target binaries, so it also works when cross-compiling. CI checks
|
||||
that committed pages are current and renders both man and HTML output.
|
||||
Open `build-docs/html/index.html` for the CLI reference. Man pages are written to
|
||||
`build-docs/man/`, retaining the six command names and the `shadowsocks-c(8)` and
|
||||
`shadowsocks-libev(8)` overview lookups. Builds read source snippets without
|
||||
executing target binaries, including when cross-compiling. Python is needed only
|
||||
for validation; Doxygen alone renders the documentation.
|
||||
|
||||
## Pull requests
|
||||
|
||||
@@ -114,3 +118,13 @@ requests and exclude generated build output, credentials, and local configuratio
|
||||
|
||||
Respond to review feedback and keep the branch current with `master`. Maintainers
|
||||
will review the implementation and relevant CI results before merging.
|
||||
|
||||
## Published documentation
|
||||
|
||||
The `documentation` workflow builds and validates Doxygen output on pull requests.
|
||||
After a push to `master`, it publishes `build-docs/html` through GitHub Pages using
|
||||
GitHub Actions, including a downloadable `man-pages.tar.gz` archive. You can also
|
||||
run the workflow manually on `master` to redeploy.
|
||||
Deployment is limited to the canonical repository's `master` branch; pull requests
|
||||
and forks only validate the documentation. The `github-pages` environment records
|
||||
the deployed site URL and deployment history.
|
||||
@@ -13,6 +13,9 @@ created by [@clowwindy](https://github.com/clowwindy), and maintained by
|
||||
|
||||
Current version: 3.3.6 | [Changelog](debian/changelog)
|
||||
|
||||
[CLI reference and configuration guide](https://shadowsocks.github.io/shadowsocks-c/)
|
||||
are generated from the source with Doxygen and published after updates to `master`.
|
||||
|
||||
## Community
|
||||
|
||||
See the [contribution guide](CONTRIBUTION.md) for development setup, testing,
|
||||
@@ -145,7 +148,7 @@ client mode and build options. Existing Snap packages still use the
|
||||
The default build uses pinned sources included in this repository. It needs a
|
||||
C11 compiler, CMake 3.20+, and Make or Ninja. No Git submodules, dependency
|
||||
package installations, or network access are needed for configuration/build.
|
||||
Python is used by integration tests and optional documentation generation.
|
||||
Python is used by tests; optional documentation builds require Doxygen 1.9.4+.
|
||||
|
||||
```sh
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
||||
@@ -157,9 +160,8 @@ cmake --install build --prefix /your/install/prefix
|
||||
Programs are in `build/bin/`. Bundled binaries link to platform runtime
|
||||
libraries; they do not require separately installed third-party libraries.
|
||||
|
||||
Man pages and HTML documentation derive their CLI sections from the source
|
||||
option parsers. See [the documentation workflow](CONTRIBUTION.md#cli-and-manual-documentation)
|
||||
for regeneration and rendering commands.
|
||||
Doxygen renders man pages and HTML documentation from CLI source comments. See [the documentation workflow](CONTRIBUTION.md#cli-and-manual-documentation)
|
||||
for validation and rendering commands.
|
||||
|
||||
For a smaller build, use `-DSS_MINIMAL=ON`. It excludes PCRE2 regex, plugin
|
||||
subprocesses, the manager, and legacy stream ciphers. Minimal ACLs support
|
||||
@@ -180,7 +182,7 @@ Use `-DCMAKE_PREFIX_PATH=/opt/homebrew/opt/mbedtls@3` when needed on macOS.
|
||||
| `SS_BUILD_SHARED_LIBRARY` | `ON` | Shared embedding library |
|
||||
| `SS_MINIMAL` | `OFF` | Disable regex, plugins, manager, and legacy stream ciphers |
|
||||
| `SS_ENABLE_REGEX` / `SS_ENABLE_PLUGINS` / `SS_ENABLE_LEGACY` | `ON` | Individual compatibility features |
|
||||
| `WITH_DOC_MAN` / `WITH_DOC_HTML` | `OFF` | Generate documentation (requires asciidoc; man pages also need xmlto) |
|
||||
| `WITH_DOC_MAN` / `WITH_DOC_HTML` | `OFF` | Generate documentation (requires Doxygen 1.9.4+) |
|
||||
| `SS_INSTALL_TOOLS` | `OFF` | Install platform shell helpers |
|
||||
| `ENABLE_SANITIZERS` | `OFF` | AddressSanitizer and UndefinedBehaviorSanitizer |
|
||||
| `ENABLE_CONNMARKTOS` / `ENABLE_NFTABLES` | `OFF` | Optional Linux firewall integrations |
|
||||
@@ -273,7 +275,7 @@ sudo cmake --install build
|
||||
|
||||
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.
|
||||
-DWITH_STATIC=OFF`. Documentation additionally needs Doxygen 1.9.4 or newer.
|
||||
|
||||
### FreeBSD
|
||||
#### Install
|
||||
|
||||
+5
-6
@@ -173,7 +173,7 @@ Se você estiver usando o CentOS 7, precisará instalar estes pré-requisitos pa
|
||||
|
||||
```bash
|
||||
yum install epel-release -y
|
||||
yum install gcc gettext autoconf libtool automake make pcre-devel asciidoc xmlto c-ares-devel libev-devel libsodium-devel mbedtls-devel -y
|
||||
yum install gcc gettext autoconf libtool automake make pcre-devel doxygen c-ares-devel libev-devel libsodium-devel mbedtls-devel -y
|
||||
```
|
||||
|
||||
### Archlinux & Manjaro
|
||||
@@ -208,8 +208,7 @@ Em geral, você precisa das seguintes dependências de compilação:
|
||||
* libpcre3 (antiga biblioteca pcre)
|
||||
* libev
|
||||
* libc-ares
|
||||
* asciidoc (somente para documentação)
|
||||
* xmlto (apenas para documentação)
|
||||
* Doxygen 1.9.4+ (somente para documentação)
|
||||
|
||||
Notas: Fedora 26 libsodium versão >= 1.0.12, então você pode instalar via dnf install libsodium em vez de compilar a partir da fonte.
|
||||
|
||||
@@ -222,11 +221,11 @@ Para algumas das distribuições, você pode instalar dependências de compilaç
|
||||
```bash
|
||||
# Instalação de dependências básicas de compilação
|
||||
## Debian / Ubuntu
|
||||
sudo apt-get install --no-install-recommends gettext build-essential autoconf libtool libpcre3-dev asciidoc xmlto libev-dev libc-ares-dev automake libmbedtls-dev libsodium-dev pkg-config
|
||||
sudo apt-get install --no-install-recommends gettext build-essential autoconf libtool libpcre3-dev doxygen libev-dev libc-ares-dev automake libmbedtls-dev libsodium-dev pkg-config
|
||||
## CentOS / Fedora / RHEL
|
||||
sudo yum install gettext gcc autoconf libtool automake make asciidoc xmlto c-ares-devel libev-devel
|
||||
sudo yum install gettext gcc autoconf libtool automake make doxygen c-ares-devel libev-devel
|
||||
## Arch
|
||||
sudo pacman -S gettext gcc autoconf libtool automake make asciidoc xmlto c-ares libev
|
||||
sudo pacman -S gettext gcc autoconf libtool automake make doxygen c-ares libev
|
||||
|
||||
# Instalação do libsodium
|
||||
export LIBSODIUM_VER=1.0.16
|
||||
|
||||
Vendored
+2
-3
@@ -8,15 +8,14 @@ Uploaders:
|
||||
Roger Shimizu <rosh@debian.org>
|
||||
Build-Depends:
|
||||
cmake (>= 3.20),
|
||||
asciidoc-base | asciidoc,
|
||||
doxygen (>= 1.9.4),
|
||||
debhelper (>= 10),
|
||||
libc-ares-dev,
|
||||
libuv1-dev,
|
||||
libmbedtls-dev,
|
||||
libpcre2-dev,
|
||||
libsodium-dev (>= 1.0.12),
|
||||
pkg-config,
|
||||
xmlto
|
||||
pkg-config
|
||||
Standards-Version: 4.1.1
|
||||
Rules-Requires-Root: no
|
||||
Homepage: https://www.shadowsocks.org
|
||||
|
||||
+75
-121
@@ -1,131 +1,85 @@
|
||||
find_program(XMLTO_EXECUTABLE NAMES xmlto)
|
||||
find_program(ASCIIDOC_EXECUTABLE NAMES asciidoc asciidoc.py)
|
||||
option(WITH_DOC_MAN "Build manpage documentation with Doxygen" OFF)
|
||||
option(WITH_DOC_HTML "Build HTML documentation with Doxygen" OFF)
|
||||
|
||||
option(WITH_DOC_MAN "Build manpage documentation" OFF)
|
||||
option(WITH_DOC_HTML "Build HTML documentation" OFF)
|
||||
if((WITH_DOC_MAN OR WITH_DOC_HTML) AND NOT ASCIIDOC_EXECUTABLE)
|
||||
message(FATAL_ERROR "Documentation generation requires asciidoc")
|
||||
endif()
|
||||
if(WITH_DOC_MAN AND NOT XMLTO_EXECUTABLE)
|
||||
message(FATAL_ERROR "Manpage generation requires xmlto")
|
||||
find_package(Doxygen 1.9.4 QUIET)
|
||||
if(NOT DOXYGEN_FOUND)
|
||||
if(WITH_DOC_MAN OR WITH_DOC_HTML)
|
||||
message(FATAL_ERROR "Documentation generation requires Doxygen 1.9.4 or newer")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Homebrew catalogs are outside libxml's default search path. Respect an
|
||||
# explicitly configured catalog and support both Apple Silicon and Intel Macs.
|
||||
set(XMLTO_ENV)
|
||||
if(APPLE AND "$ENV{XML_CATALOG_FILES}" STREQUAL "")
|
||||
foreach(catalog /opt/homebrew/etc/xml/catalog /usr/local/etc/xml/catalog)
|
||||
if(EXISTS ${catalog})
|
||||
set(XMLTO_ENV XML_CATALOG_FILES=${catalog})
|
||||
break()
|
||||
endif()
|
||||
set(DOC_NAMES ss-local ss-server ss-tunnel ss-redir ss-manager ss-nat shadowsocks-c)
|
||||
set(DOC_INPUTS)
|
||||
foreach(name IN LISTS DOC_NAMES)
|
||||
list(APPEND DOC_INPUTS "${CMAKE_CURRENT_SOURCE_DIR}/${name}.md")
|
||||
endforeach()
|
||||
set(DOC_SOURCES)
|
||||
foreach(name local server tunnel redir manager utils aead stream)
|
||||
list(APPEND DOC_SOURCES "${PROJECT_SOURCE_DIR}/src/${name}.c")
|
||||
endforeach()
|
||||
list(APPEND DOC_SOURCES "${PROJECT_SOURCE_DIR}/src/ss-nat")
|
||||
|
||||
# Doxygen reads native documentation snippets directly from source. No target
|
||||
# binary or Python/AsciiDoc conversion step is needed, including in cross builds.
|
||||
foreach(format html man1 man8)
|
||||
set(DOXYGEN_HTML NO)
|
||||
set(DOXYGEN_MAN NO)
|
||||
set(DOXYGEN_MAN_EXTENSION .1)
|
||||
set(format_inputs ${DOC_INPUTS})
|
||||
set(outputs)
|
||||
if(format STREQUAL "html")
|
||||
set(DOXYGEN_HTML YES)
|
||||
list(APPEND format_inputs "${CMAKE_CURRENT_SOURCE_DIR}/index.md")
|
||||
list(APPEND outputs "${PROJECT_BINARY_DIR}/html/index.html")
|
||||
foreach(name IN LISTS DOC_NAMES)
|
||||
list(APPEND outputs "${PROJECT_BINARY_DIR}/html/${name}.html")
|
||||
endforeach()
|
||||
elseif(format STREQUAL "man1")
|
||||
set(DOXYGEN_MAN YES)
|
||||
list(REMOVE_ITEM format_inputs "${CMAKE_CURRENT_SOURCE_DIR}/shadowsocks-c.md")
|
||||
foreach(name ss-local ss-server ss-tunnel ss-redir ss-manager ss-nat)
|
||||
list(APPEND outputs "${PROJECT_BINARY_DIR}/man/${name}.1")
|
||||
endforeach()
|
||||
else()
|
||||
set(DOXYGEN_MAN YES)
|
||||
set(DOXYGEN_MAN_EXTENSION .8)
|
||||
set(format_inputs "${CMAKE_CURRENT_SOURCE_DIR}/shadowsocks-c.md")
|
||||
list(APPEND outputs "${PROJECT_BINARY_DIR}/man/shadowsocks-c.8")
|
||||
endif()
|
||||
set(DOXYGEN_INPUT)
|
||||
foreach(path IN LISTS format_inputs)
|
||||
string(APPEND DOXYGEN_INPUT " \"${path}\"")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(CMAKE_MANPAGE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/man)
|
||||
set(CMAKE_HTML_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/html)
|
||||
|
||||
set(DOC_DIR ${PROJECT_SOURCE_DIR}/doc)
|
||||
find_package(Python3 COMPONENTS Interpreter QUIET)
|
||||
if((WITH_DOC_MAN OR WITH_DOC_HTML) AND NOT Python3_Interpreter_FOUND)
|
||||
message(FATAL_ERROR "Documentation generation requires Python 3")
|
||||
endif()
|
||||
|
||||
# Read source declarations, never execute target binaries (including cross builds).
|
||||
# Keep checked-in pages for readers and for builds with documentation disabled.
|
||||
set(CLI_DOC_DIR ${DOC_DIR})
|
||||
set(CLI_DOC_FILES)
|
||||
if(Python3_Interpreter_FOUND)
|
||||
set(CLI_DOC_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated)
|
||||
set(CLI_DOC_INPUTS ${PROJECT_SOURCE_DIR}/src/utils.c
|
||||
${PROJECT_SOURCE_DIR}/src/aead.c ${PROJECT_SOURCE_DIR}/src/stream.c
|
||||
${PROJECT_SOURCE_DIR}/src/ss-nat)
|
||||
foreach(module local server tunnel redir manager)
|
||||
list(APPEND CLI_DOC_INPUTS ${PROJECT_SOURCE_DIR}/src/${module}.c)
|
||||
endforeach()
|
||||
foreach(name ss-local ss-server ss-tunnel ss-redir ss-manager ss-nat shadowsocks-c)
|
||||
list(APPEND CLI_DOC_INPUTS ${DOC_DIR}/${name}.asciidoc)
|
||||
list(APPEND CLI_DOC_FILES ${CLI_DOC_DIR}/${name}.asciidoc)
|
||||
endforeach()
|
||||
add_custom_command(OUTPUT ${CLI_DOC_FILES}
|
||||
COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/gen_cli_docs.py
|
||||
--output-dir ${CLI_DOC_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${CLI_DOC_FILES}
|
||||
DEPENDS ${CLI_DOC_INPUTS} ${PROJECT_SOURCE_DIR}/scripts/gen_cli_docs.py
|
||||
COMMENT "Generating CLI documentation from source"
|
||||
set(config "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile-${format}")
|
||||
configure_file(Doxyfile.in "${config}" @ONLY)
|
||||
set(stamp "${CMAKE_CURRENT_BINARY_DIR}/${format}.stamp")
|
||||
add_custom_command(OUTPUT "${stamp}" ${outputs}
|
||||
COMMAND "${DOXYGEN_EXECUTABLE}" "${config}"
|
||||
COMMAND ${CMAKE_COMMAND} -E touch "${stamp}"
|
||||
DEPENDS "${config}" ${format_inputs} ${DOC_SOURCES}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMENT "Generating ${format} documentation with Doxygen"
|
||||
VERBATIM)
|
||||
add_custom_target(doc-cli DEPENDS ${CLI_DOC_FILES})
|
||||
endif()
|
||||
set(DOC_${format}_OUTPUTS "${stamp}" ${outputs})
|
||||
endforeach()
|
||||
|
||||
set(XMLTO_OPTS -m ${DOC_DIR}/manpage-normal.xsl -m ${DOC_DIR}/manpage-bold-literal.xsl man)
|
||||
set(ASCIIDOC_XML_OPTS -b docbook -d manpage -f ${DOC_DIR}/asciidoc.conf -aversion=${PROJECT_VERSION})
|
||||
set(ASCIIDOC_HTML_OPTS -b html4 -d article -f ${DOC_DIR}/asciidoc.conf -aversion=${PROJECT_VERSION})
|
||||
|
||||
|
||||
set(MAN_NAMES ss-local.1 ss-manager.1 ss-nat.1 ss-redir.1 ss-server.1 ss-tunnel.1 shadowsocks-c.8)
|
||||
set(MAN_FILES)
|
||||
set(HTML_FILES)
|
||||
|
||||
foreach (manfile IN LISTS MAN_NAMES)
|
||||
string(REGEX REPLACE \\.. .xml xmlfile ${manfile})
|
||||
string(REGEX REPLACE \\.. .asciidoc docfile ${manfile})
|
||||
string(REGEX REPLACE \\.. .html htmlfile ${manfile})
|
||||
|
||||
set(manfile ${CMAKE_MANPAGE_OUTPUT_DIRECTORY}/${manfile})
|
||||
set(htmlfile ${CMAKE_HTML_OUTPUT_DIRECTORY}/${htmlfile})
|
||||
set(docfile ${CLI_DOC_DIR}/${docfile})
|
||||
|
||||
add_custom_command(OUTPUT ${manfile}
|
||||
COMMAND ${ASCIIDOC_EXECUTABLE} ${ASCIIDOC_XML_OPTS} -o ${xmlfile} ${docfile}
|
||||
COMMAND ${CMAKE_COMMAND} -E env ${XMLTO_ENV} ${XMLTO_EXECUTABLE} ${XMLTO_OPTS} ${xmlfile}
|
||||
# After we built the manpage, the xmlfile is nolongger needed
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${xmlfile}
|
||||
DEPENDS ${docfile} ${DOC_DIR}/asciidoc.conf
|
||||
${DOC_DIR}/manpage-normal.xsl ${DOC_DIR}/manpage-bold-literal.xsl
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/man
|
||||
COMMENT "Building manpage ${manfile}"
|
||||
VERBATIM)
|
||||
list(APPEND MAN_FILES ${manfile})
|
||||
|
||||
add_custom_command(OUTPUT ${htmlfile}
|
||||
COMMAND ${ASCIIDOC_EXECUTABLE} ${ASCIIDOC_HTML_OPTS} -o ${htmlfile} ${docfile}
|
||||
DEPENDS ${docfile} ${DOC_DIR}/asciidoc.conf
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/html
|
||||
COMMENT "Building htmlfile ${htmlfile}"
|
||||
VERBATIM)
|
||||
list(APPEND HTML_FILES ${htmlfile})
|
||||
endforeach ()
|
||||
|
||||
add_custom_target(doc-man ALL DEPENDS ${MAN_FILES})
|
||||
add_custom_target(doc-html ALL DEPENDS ${HTML_FILES})
|
||||
if(TARGET doc-cli)
|
||||
add_dependencies(doc-man doc-cli)
|
||||
add_dependencies(doc-html doc-cli)
|
||||
endif()
|
||||
|
||||
|
||||
if (NOT WITH_DOC_MAN)
|
||||
add_custom_target(doc-man ALL DEPENDS ${DOC_man1_OUTPUTS} ${DOC_man8_OUTPUTS})
|
||||
add_custom_target(doc-html ALL DEPENDS ${DOC_html_OUTPUTS})
|
||||
if(NOT WITH_DOC_MAN)
|
||||
set_target_properties(doc-man PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
else ()
|
||||
install(DIRECTORY ${PROJECT_BINARY_DIR}/man/
|
||||
DESTINATION share/man/man1
|
||||
FILES_MATCHING PATTERN "*.1"
|
||||
)
|
||||
install(DIRECTORY ${PROJECT_BINARY_DIR}/man/
|
||||
DESTINATION share/man/man8
|
||||
FILES_MATCHING PATTERN "*.8"
|
||||
)
|
||||
endif ()
|
||||
if (NOT WITH_DOC_HTML)
|
||||
else()
|
||||
foreach(name ss-local ss-server ss-tunnel ss-redir ss-manager ss-nat)
|
||||
install(FILES "${PROJECT_BINARY_DIR}/man/${name}.1" DESTINATION share/man/man1)
|
||||
endforeach()
|
||||
install(FILES "${PROJECT_BINARY_DIR}/man/shadowsocks-c.8"
|
||||
"${PROJECT_BINARY_DIR}/man/shadowsocks-libev.8" DESTINATION share/man/man8)
|
||||
endif()
|
||||
if(NOT WITH_DOC_HTML)
|
||||
set_target_properties(doc-html PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
else ()
|
||||
install(DIRECTORY ${PROJECT_BINARY_DIR}/html/
|
||||
DESTINATION share/doc/${PROJECT_NAME})
|
||||
endif ()
|
||||
else()
|
||||
install(DIRECTORY "${PROJECT_BINARY_DIR}/html/" DESTINATION share/doc/${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
# This is required for custom command
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/man)
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/html)
|
||||
|
||||
# Retain the former manual lookup name.
|
||||
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/man")
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/man/shadowsocks-libev.8" ".so man8/shadowsocks-c.8\n")
|
||||
@@ -0,0 +1,26 @@
|
||||
PROJECT_NAME = "shadowsocks-c"
|
||||
PROJECT_NUMBER = "@PROJECT_VERSION@"
|
||||
OUTPUT_DIRECTORY = "@PROJECT_BINARY_DIR@"
|
||||
INPUT = @DOXYGEN_INPUT@
|
||||
INPUT_ENCODING = UTF-8
|
||||
EXAMPLE_PATH = "@PROJECT_SOURCE_DIR@/src"
|
||||
EXAMPLE_PATTERNS = *.c ss-nat
|
||||
RECURSIVE = NO
|
||||
MARKDOWN_SUPPORT = YES
|
||||
AUTOLINK_SUPPORT = NO
|
||||
EXTRACT_ALL = NO
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
WARN_AS_ERROR = YES
|
||||
GENERATE_HTML = @DOXYGEN_HTML@
|
||||
HTML_OUTPUT = html
|
||||
GENERATE_TREEVIEW = YES
|
||||
GENERATE_MAN = @DOXYGEN_MAN@
|
||||
MAN_OUTPUT = man
|
||||
MAN_SUBDIR = .
|
||||
MAN_EXTENSION = @DOXYGEN_MAN_EXTENSION@
|
||||
MAN_LINKS = NO
|
||||
GENERATE_LATEX = NO
|
||||
HAVE_DOT = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
@@ -1,36 +0,0 @@
|
||||
[tags]
|
||||
bracket-emphasis={1?[{1}]}<emphasis><|></emphasis>
|
||||
|
||||
[quotes]
|
||||
<|>=#bracket-emphasis
|
||||
|
||||
[attributes]
|
||||
asterisk=*
|
||||
plus=+
|
||||
caret=^
|
||||
startsb=[
|
||||
endsb=]
|
||||
backslash=\
|
||||
tilde=~
|
||||
apostrophe='
|
||||
backtick=`
|
||||
litdd=--
|
||||
|
||||
ifdef::doctype-manpage[]
|
||||
ifdef::backend-docbook[]
|
||||
[header]
|
||||
template::[header-declarations]
|
||||
<refentry>
|
||||
<refmeta>
|
||||
<refentrytitle>{mantitle}</refentrytitle>
|
||||
<manvolnum>{manvolnum}</manvolnum>
|
||||
<refmiscinfo class="source">shadowsocks-c</refmiscinfo>
|
||||
<refmiscinfo class="version">{version}</refmiscinfo>
|
||||
<refmiscinfo class="manual">shadowsocks-c Manual</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname>{manname}</refname>
|
||||
<refpurpose>{manpurpose}</refpurpose>
|
||||
</refnamediv>
|
||||
endif::backend-docbook[]
|
||||
endif::doctype-manpage[]
|
||||
@@ -0,0 +1,16 @@
|
||||
\mainpage shadowsocks-c CLI reference
|
||||
|
||||
Command-line reference and configuration guide, generated by Doxygen from the
|
||||
source documentation.
|
||||
|
||||
- \ref ss-local "ss-local: SOCKS5 client"
|
||||
- \ref ss-server "ss-server: proxy server"
|
||||
- \ref ss-tunnel "ss-tunnel: local port forwarding"
|
||||
- \ref ss-redir "ss-redir: transparent proxy"
|
||||
- \ref ss-manager "ss-manager: multi-user management"
|
||||
- \ref ss-nat "ss-nat: NAT setup helper"
|
||||
- \ref shadowsocks-c "Configuration, examples, and management protocol"
|
||||
|
||||
[Download the generated man pages](https://shadowsocks.github.io/shadowsocks-c/man-pages.tar.gz)
|
||||
from the published site. The archive includes the six CLI manuals and both
|
||||
overview lookup names.
|
||||
@@ -1,35 +0,0 @@
|
||||
<!-- manpage-base.xsl:
|
||||
special formatting for manpages rendered from asciidoc+docbook -->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<!-- these params silence some output from xmlto -->
|
||||
<xsl:param name="man.output.quietly" select="1"/>
|
||||
<xsl:param name="refentry.meta.get.quietly" select="1"/>
|
||||
|
||||
<!-- convert asciidoc callouts to man page format;
|
||||
git.docbook.backslash and git.docbook.dot params
|
||||
must be supplied by another XSL file or other means -->
|
||||
<xsl:template match="co">
|
||||
<xsl:value-of select="concat(
|
||||
$git.docbook.backslash,'fB(',
|
||||
substring-after(@id,'-'),')',
|
||||
$git.docbook.backslash,'fR')"/>
|
||||
</xsl:template>
|
||||
<xsl:template match="calloutlist">
|
||||
<xsl:value-of select="$git.docbook.dot"/>
|
||||
<xsl:text>sp </xsl:text>
|
||||
<xsl:apply-templates/>
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:template>
|
||||
<xsl:template match="callout">
|
||||
<xsl:value-of select="concat(
|
||||
$git.docbook.backslash,'fB',
|
||||
substring-after(@arearefs,'-'),
|
||||
'. ',$git.docbook.backslash,'fR')"/>
|
||||
<xsl:apply-templates/>
|
||||
<xsl:value-of select="$git.docbook.dot"/>
|
||||
<xsl:text>br </xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
@@ -1,17 +0,0 @@
|
||||
<!-- manpage-bold-literal.xsl:
|
||||
special formatting for manpages rendered from asciidoc+docbook -->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<!-- render literal text as bold (instead of plain or monospace);
|
||||
this makes literal text easier to distinguish in manpages
|
||||
viewed on a tty -->
|
||||
<xsl:template match="literal">
|
||||
<xsl:value-of select="$git.docbook.backslash"/>
|
||||
<xsl:text>fB</xsl:text>
|
||||
<xsl:apply-templates/>
|
||||
<xsl:value-of select="$git.docbook.backslash"/>
|
||||
<xsl:text>fR</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
@@ -1,13 +0,0 @@
|
||||
<!-- manpage-normal.xsl:
|
||||
special settings for manpages rendered from asciidoc+docbook
|
||||
handles anything we want to keep away from docbook-xsl 1.72.0 -->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<xsl:import href="manpage-base.xsl"/>
|
||||
|
||||
<!-- these are the normal values for the roff control characters -->
|
||||
<xsl:param name="git.docbook.backslash">\</xsl:param>
|
||||
<xsl:param name="git.docbook.dot" >.</xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|
||||
@@ -1,172 +0,0 @@
|
||||
shadowsocks-c(8)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
shadowsocks-c - a lightweight and secure socks5 proxy
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
// Generated by scripts/gen_cli_docs.py; do not edit this section.
|
||||
|
||||
*ss-local* [options]
|
||||
|
||||
*ss-server* [options]
|
||||
|
||||
*ss-tunnel* [options]
|
||||
|
||||
*ss-redir* [options]
|
||||
|
||||
*ss-manager* [options]
|
||||
|
||||
*ss-nat* [options]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of *libuv*
|
||||
to achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components. One is `ss-server`(1)
|
||||
that runs on a remote server to provide secured tunnel service.
|
||||
`ss-local`(1) and `ss-redir`(1) are clients on your local machines to proxy
|
||||
traffic(TCP/UDP or both).
|
||||
`ss-tunnel`(1) is a tool for local port forwarding.
|
||||
|
||||
While `ss-local`(1) works as a standard socks5 proxy, `ss-redir`(1) works
|
||||
as a transparent proxy and requires netfilter's NAT module. For more
|
||||
information, check out the 'EXAMPLE' section.
|
||||
|
||||
`ss-manager`(1) is a controller for multi-user management and traffic
|
||||
statistics, using UNIX domain socket to talk with `ss-server`(1).
|
||||
Also, it provides a UNIX domain socket or IP based API for other software.
|
||||
About the details of this API, please refer to the 'PROTOCOL' section.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
// Generated by scripts/gen_cli_docs.py; do not edit this section.
|
||||
|
||||
`ss-local`(1)::
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
`ss-server`(1)::
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
`ss-tunnel`(1)::
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
`ss-redir`(1)::
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
`ss-manager`(1)::
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
`ss-nat`(1)::
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
CONFIG FILE
|
||||
-----------
|
||||
The config file is written in JSON and easy to edit.
|
||||
|
||||
The config file equivalent of command line options is listed as example below.
|
||||
[frame="topbot",options="header"]
|
||||
|==========================================================================
|
||||
| Command line | JSON
|
||||
| -s some.server.net | "server": "some.server.net"
|
||||
| -s some.server.net -p 1234 (client) | "server": "some.server.net:1234"
|
||||
| -p 1234 | "server_port": "1234"
|
||||
| -b 0.0.0.0 | "local_address": "0.0.0.0"
|
||||
| -b 10.0.0.2 | "local_ipv4_address": "10.0.0.2"
|
||||
| -b 2620:129:35::33 | "local_ipv6_address": "2620:129:35::33"
|
||||
| -l 4321 | "local_port": "4321"
|
||||
| -k "PasSworD" | "password": "PasSworD"
|
||||
| -m "aes-256-cfb" | "method": "aes-256-cfb"
|
||||
| -t 60 | "timeout": 60
|
||||
| -a nobody | "user": "nobody"
|
||||
| --acl "/path/to/acl" | "acl": "/path/to/acl"
|
||||
| --fast-open | "fast_open": true
|
||||
| --reuse-port | "reuse_port": true
|
||||
| --no-delay | "no_delay": true
|
||||
| --plugin "obfs-server" | "plugin": "obfs-server"
|
||||
| --plugin-opts "obfs=http" | "plugin_opts": "obfs=http"
|
||||
| -6 | "ipv6_first": true
|
||||
| -n "/etc/nofile" | "nofile": "/etc/nofile"
|
||||
| -d "8.8.8.8" | "nameserver": "8.8.8.8"
|
||||
| -L "somedns.net:53" | "tunnel_address": "somedns.net:53"
|
||||
| -u | "mode": "tcp_and_udp"
|
||||
| -U | "mode": "udp_only"
|
||||
| no "-u" nor "-U" options (default) | "mode": "tcp_only"
|
||||
| -T | "tcp_tproxy": true
|
||||
| (only in ss-manager's config) | "port_password": {"1234":"PasSworD"}
|
||||
|============================================================================
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
`ss-redir` requires netfilter's NAT function. Here is an example:
|
||||
|
||||
....
|
||||
# Create new chain
|
||||
iptables -t nat -N SHADOWSOCKS
|
||||
iptables -t mangle -N SHADOWSOCKS
|
||||
|
||||
# Ignore your shadowsocks server's addresses
|
||||
# It's very IMPORTANT, just be careful.
|
||||
iptables -t nat -A SHADOWSOCKS -d 123.123.123.123 -j RETURN
|
||||
|
||||
# Ignore LANs and any other addresses you'd like to bypass the proxy
|
||||
# See Wikipedia and RFC5735 for full list of reserved networks.
|
||||
# See ashi009/bestroutetb for a highly optimized CHN route list.
|
||||
iptables -t nat -A SHADOWSOCKS -d 0.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 10.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 169.254.0.0/16 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 172.16.0.0/12 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 192.168.0.0/16 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 224.0.0.0/4 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 240.0.0.0/4 -j RETURN
|
||||
|
||||
# Anything else should be redirected to shadowsocks's local port
|
||||
iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 12345
|
||||
|
||||
# Add any UDP rules
|
||||
ip rule add fwmark 0x01/0x01 table 100
|
||||
ip route add local 0.0.0.0/0 dev lo table 100
|
||||
iptables -t mangle -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 12345 --tproxy-mark 0x01/0x01
|
||||
|
||||
# Apply the rules
|
||||
iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS
|
||||
iptables -t mangle -A PREROUTING -j SHADOWSOCKS
|
||||
|
||||
# Start the shadowsocks-redir
|
||||
ss-redir -u -c /etc/config/shadowsocks.json -f /var/run/shadowsocks.pid
|
||||
....
|
||||
|
||||
PROTOCOL
|
||||
--------
|
||||
`ss-manager`(1) provides several APIs through UDP protocol::
|
||||
|
||||
Send UDP commands in the following format to the manager-address provided to ss-manager(1): ::::
|
||||
command: [JSON data]
|
||||
|
||||
To add a port: ::::
|
||||
add: {"server_port": 8001, "password":"7cd308cc059"}
|
||||
|
||||
To remove a port: ::::
|
||||
remove: {"server_port": 8001}
|
||||
|
||||
To receive a pong: ::::
|
||||
ping
|
||||
|
||||
Then `ss-manager`(1) will send back the traffic statistics: ::::
|
||||
stat: {"8001":11370}
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
`ss-local`(1),
|
||||
`ss-server`(1),
|
||||
`ss-tunnel`(1),
|
||||
`ss-redir`(1),
|
||||
`ss-manager`(1),
|
||||
`iptables`(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -0,0 +1,177 @@
|
||||
\page shadowsocks-c shadowsocks-c
|
||||
|
||||
\brief a lightweight and secure socks5 proxy
|
||||
|
||||
\section overview_synopsis SYNOPSIS
|
||||
|
||||
*ss-local* [options]
|
||||
|
||||
*ss-server* [options]
|
||||
|
||||
*ss-tunnel* [options]
|
||||
|
||||
*ss-redir* [options]
|
||||
|
||||
*ss-manager* [options]
|
||||
|
||||
*ss-nat* [options]
|
||||
|
||||
\section overview_description DESCRIPTION
|
||||
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of *libuv*
|
||||
to achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components. One is ss-server(1)
|
||||
that runs on a remote server to provide secured tunnel service.
|
||||
ss-local(1) and ss-redir(1) are clients on your local machines to proxy
|
||||
traffic(TCP/UDP or both).
|
||||
ss-tunnel(1) is a tool for local port forwarding.
|
||||
|
||||
While ss-local(1) works as a standard socks5 proxy, ss-redir(1) works
|
||||
as a transparent proxy and requires netfilter's NAT module. For more
|
||||
information, check out the `EXAMPLE` section.
|
||||
|
||||
ss-manager(1) is a controller for multi-user management and traffic
|
||||
statistics, using UNIX domain socket to talk with ss-server(1).
|
||||
Also, it provides a UNIX domain socket or IP based API for other software.
|
||||
About the details of this API, please refer to the `PROTOCOL` section.
|
||||
|
||||
\section overview_options OPTIONS
|
||||
|
||||
**ss-local(1)**
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
**ss-server(1)**
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
**ss-tunnel(1)**
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
**ss-redir(1)**
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
**ss-manager(1)**
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
**ss-nat(1)**
|
||||
See this command's generated SYNOPSIS and OPTIONS for its accepted arguments.
|
||||
|
||||
\section overview_config_file CONFIG FILE
|
||||
|
||||
The config file is written in JSON and easy to edit.
|
||||
|
||||
The config file equivalent of command line options is listed as examples below.
|
||||
|
||||
- `-s some.server.net`: `"server": "some.server.net"`
|
||||
- `-s some.server.net -p 1234 (client)`: `"server": "some.server.net:1234"`
|
||||
- `-p 1234`: `"server_port": "1234"`
|
||||
- `-b 0.0.0.0`: `"local_address": "0.0.0.0"`
|
||||
- `-b 10.0.0.2`: `"local_ipv4_address": "10.0.0.2"`
|
||||
- `-b 2620:129:35::33`: `"local_ipv6_address": "2620:129:35::33"`
|
||||
- `-l 4321`: `"local_port": "4321"`
|
||||
- `-k "PasSworD"`: `"password": "PasSworD"`
|
||||
- `-m "aes-256-cfb"`: `"method": "aes-256-cfb"`
|
||||
- `-t 60`: `"timeout": 60`
|
||||
- `-a nobody`: `"user": "nobody"`
|
||||
- `--acl "/path/to/acl"`: `"acl": "/path/to/acl"`
|
||||
- `--fast-open`: `"fast_open": true`
|
||||
- `--reuse-port`: `"reuse_port": true`
|
||||
- `--no-delay`: `"no_delay": true`
|
||||
- `--plugin "obfs-server"`: `"plugin": "obfs-server"`
|
||||
- `--plugin-opts "obfs=http"`: `"plugin_opts": "obfs=http"`
|
||||
- `-6`: `"ipv6_first": true`
|
||||
- `-n 1024`: `"nofile": 1024`
|
||||
- `-d "8.8.8.8"`: `"nameserver": "8.8.8.8"`
|
||||
- `-L "somedns.net:53"`: `"tunnel_address": "somedns.net:53"`
|
||||
- `-u`: `"mode": "tcp_and_udp"`
|
||||
- `-U`: `"mode": "udp_only"`
|
||||
- `no "-u" nor "-U" options (default)`: `"mode": "tcp_only"`
|
||||
- `-T`: `"tcp_tproxy": true`
|
||||
- `(only in ss-manager's config)`: `"port_password": {"1234":"PasSworD"}`
|
||||
|
|
||||
\section overview_example EXAMPLE
|
||||
|
||||
`ss-redir` requires netfilter's NAT function. Here is an example:
|
||||
|
||||
```
|
||||
# Create new chain
|
||||
iptables -t nat -N SHADOWSOCKS
|
||||
iptables -t mangle -N SHADOWSOCKS
|
||||
|
||||
# Ignore your shadowsocks server's addresses
|
||||
# It's very IMPORTANT, just be careful.
|
||||
iptables -t nat -A SHADOWSOCKS -d 123.123.123.123 -j RETURN
|
||||
|
||||
# Ignore LANs and any other addresses you'd like to bypass the proxy
|
||||
# See Wikipedia and RFC5735 for full list of reserved networks.
|
||||
# See ashi009/bestroutetb for a highly optimized CHN route list.
|
||||
iptables -t nat -A SHADOWSOCKS -d 0.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 10.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 169.254.0.0/16 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 172.16.0.0/12 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 192.168.0.0/16 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 224.0.0.0/4 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 240.0.0.0/4 -j RETURN
|
||||
|
||||
# Anything else should be redirected to shadowsocks's local port
|
||||
iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 12345
|
||||
|
||||
# Add any UDP rules
|
||||
ip rule add fwmark 0x01/0x01 table 100
|
||||
ip route add local 0.0.0.0/0 dev lo table 100
|
||||
iptables -t mangle -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 12345 --tproxy-mark 0x01/0x01
|
||||
|
||||
# Apply the rules
|
||||
iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS
|
||||
iptables -t mangle -A PREROUTING -j SHADOWSOCKS
|
||||
|
||||
# Start the shadowsocks-redir
|
||||
ss-redir -u -c /etc/config/shadowsocks.json -f /var/run/shadowsocks.pid
|
||||
```
|
||||
|
||||
\section overview_protocol PROTOCOL
|
||||
|
||||
**ss-manager(1) provides several APIs through UDP protocol**
|
||||
|
||||
**Send UDP commands in the following format to the manager-address provided to ss-manager(1):**
|
||||
|
||||
```text
|
||||
command: [JSON data]
|
||||
```
|
||||
|
||||
**To add a port:**
|
||||
|
||||
```text
|
||||
add: {"server_port": 8001, "password":"7cd308cc059"}
|
||||
```
|
||||
|
||||
**To remove a port:**
|
||||
|
||||
```text
|
||||
remove: {"server_port": 8001}
|
||||
```
|
||||
|
||||
**To receive a pong:**
|
||||
|
||||
```text
|
||||
ping
|
||||
```
|
||||
|
||||
**Then ss-manager(1) will send back the traffic statistics:**
|
||||
|
||||
```text
|
||||
stat: {"8001":11370}
|
||||
```
|
||||
|
||||
\section overview_see_also SEE ALSO
|
||||
|
||||
ss-local(1),
|
||||
ss-server(1),
|
||||
ss-tunnel(1),
|
||||
ss-redir(1),
|
||||
ss-manager(1),
|
||||
iptables(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -1,188 +0,0 @@
|
||||
ss-local(1)
|
||||
===========
|
||||
|
||||
NAME
|
||||
----
|
||||
ss-local - shadowsocks client as socks5 proxy, C implementation
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
// Generated by scripts/gen_cli_docs.py from src/local.c; do not edit this section.
|
||||
|
||||
*ss-local* [-f <pid_file>] [-s <server_host>] [-p <server_port>] [-l
|
||||
<local_port>] [-k <password>] [-t <timeout>] [-m <encrypt_method>] [-i
|
||||
<interface>] [-c <config_file>] [-b <local_address>] [-a <user_name>] [-n
|
||||
<number>] [-S <path>] [-h] [-u] [-U] [-v] [-V] [-6] [-A] [--reuse-port]
|
||||
[--tcp-incoming-sndbuf <size>] [--tcp-incoming-rcvbuf <size>]
|
||||
[--tcp-outgoing-sndbuf <size>] [--tcp-outgoing-rcvbuf <size>] [--fast-open]
|
||||
[--no-delay] [--acl <acl_config>] [--mtu <MTU>] [--mptcp] [--plugin
|
||||
<plugin_name>] [--plugin-opts <plugin_options>] [--password <password>]
|
||||
[--key <key_in_base64>] [--server-url <ss_url>] [--help]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components. `ss-local`(1) works as a standard
|
||||
socks5 proxy on local machines to proxy TCP traffic.
|
||||
For more information, check out `shadowsocks-libev`(8).
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
// Generated by scripts/gen_cli_docs.py from src/local.c; do not edit this section.
|
||||
|
||||
This section lists options across supported builds. Platform and feature
|
||||
restrictions are noted below; not every option is effective on every platform.
|
||||
|
||||
-f <pid_file>::
|
||||
Start shadowsocks as a daemon with specific pid file.
|
||||
|
||||
-s <server_host>::
|
||||
Set the server's hostname or IP.
|
||||
|
||||
-p <server_port>::
|
||||
Set the server's port number.
|
||||
|
||||
-l <local_port>::
|
||||
Set the local port number.
|
||||
|
||||
-k <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
-t <timeout>::
|
||||
Set the socket timeout in seconds. The default value is 60.
|
||||
|
||||
-m <encrypt_method>::
|
||||
Set the cipher. The default is 'chacha20-ietf-poly1305'.
|
||||
+
|
||||
AEAD cipher names from the source (availability depends on the build):
|
||||
aes-128-gcm, aes-192-gcm, aes-256-gcm, 2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm, chacha20-ietf-poly1305, 2022-blake3-chacha20-poly1305, xchacha20-ietf-poly1305.
|
||||
+
|
||||
Legacy stream cipher names recognized by the source (disabled in minimal builds;
|
||||
some require backend support): table, rc4, rc4-md5, aes-128-cfb, aes-192-cfb, aes-256-cfb, aes-128-ctr, aes-192-ctr, aes-256-ctr, bf-cfb, camellia-128-cfb, camellia-192-cfb, camellia-256-cfb, cast5-cfb, des-cfb, idea-cfb, rc2-cfb, seed-cfb, salsa20, chacha20, chacha20-ietf.
|
||||
+
|
||||
The '2022-blake3-*' ciphers implement Shadowsocks 2022 (SIP022). They require
|
||||
a base64-encoded pre-shared key supplied with *-k*: 16 bytes for
|
||||
2022-blake3-aes-128-gcm and 32 bytes for the other 2022 ciphers.
|
||||
Generate a 32-byte key with `openssl rand -base64 32`.
|
||||
Passwords are not stretched into keys for these ciphers.
|
||||
|
||||
-i <interface>::
|
||||
Send outbound traffic through the specified network interface where supported by the platform.
|
||||
|
||||
-c <config_file>::
|
||||
Use a configuration file.
|
||||
+
|
||||
Refer to `shadowsocks-c`(8) 'CONFIG FILE' section for more details.
|
||||
|
||||
-b <local_address>::
|
||||
Specify the local address to use while this client is making outbound
|
||||
connections to the server.
|
||||
|
||||
-a <user_name>::
|
||||
Run as a specific user.
|
||||
|
||||
-n <number>::
|
||||
Specify the maximum number of open files. Requires a platform with setrlimit support.
|
||||
|
||||
-S <path>::
|
||||
Android only: UNIX socket path for traffic statistics.
|
||||
|
||||
-h::
|
||||
Print help message.
|
||||
|
||||
-u::
|
||||
Enable UDP relay.
|
||||
|
||||
-U::
|
||||
Enable UDP relay and disable TCP relay.
|
||||
|
||||
-v::
|
||||
Enable verbose mode.
|
||||
|
||||
-V::
|
||||
Android only: enable VPN socket protection.
|
||||
|
||||
-6::
|
||||
Resolve hostname to IPv6 address first.
|
||||
|
||||
-A::
|
||||
Deprecated one-time authentication option. Exits with an error; use AEAD ciphers instead.
|
||||
|
||||
--reuse-port::
|
||||
Enable port reuse where supported by the operating system.
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
Set TCP send buffer size for incoming connections.
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
|
||||
--fast-open::
|
||||
Enable TCP Fast Open where supported by the operating system.
|
||||
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--acl <acl_config>::
|
||||
Enable ACL (Access Control List) and specify config file.
|
||||
|
||||
--mtu <MTU>::
|
||||
Specify the MTU of your network interface.
|
||||
|
||||
--mptcp::
|
||||
Enable Multipath TCP.
|
||||
+
|
||||
Only available with MPTCP enabled Linux kernel.
|
||||
|
||||
--plugin <plugin_name>::
|
||||
Enable SIP003 plugin. (Experimental)
|
||||
|
||||
--plugin-opts <plugin_options>::
|
||||
Set SIP003 plugin options. (Experimental)
|
||||
|
||||
--password <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
--key <key_in_base64>::
|
||||
Set the key directly. The key should be encoded with URL-safe Base64.
|
||||
|
||||
--server-url <ss_url>::
|
||||
Take the server address, port, cipher, password and any SIP003 plugin
|
||||
from a single 'ss://' URL, as produced by most clients and by
|
||||
*shadowsocks-rust*'s `ssurl`. Both the SIP002 form
|
||||
('ss://base64(method:password)@host:port/?plugin=...#tag') and the older
|
||||
'ss://base64(method:password@host:port)' form are accepted. Options given
|
||||
later on the command line override the values taken from the URL.
|
||||
|
||||
--help::
|
||||
Print help message.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
`ss-local`(1) can be started from command line and run in foreground.
|
||||
Here is an example:
|
||||
....
|
||||
# Start ss-local with given parameters
|
||||
ss-local -s example.com -p 12345 -l 1080 -k foobar -m aes-256-cfb
|
||||
....
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
`ss-server`(1),
|
||||
`ss-tunnel`(1),
|
||||
`ss-redir`(1),
|
||||
`ss-manager`(1),
|
||||
`shadowsocks-libev`(8),
|
||||
`iptables`(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
\page ss-local ss-local
|
||||
|
||||
\brief shadowsocks client as socks5 proxy, C implementation
|
||||
|
||||
\section ss_local_synopsis SYNOPSIS
|
||||
|
||||
`ss-local [options]`
|
||||
|
||||
\section ss_local_description DESCRIPTION
|
||||
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components. ss-local(1) works as a standard
|
||||
socks5 proxy on local machines to proxy TCP traffic.
|
||||
For more information, check out shadowsocks-libev(8).
|
||||
|
||||
\section ss_local_options OPTIONS
|
||||
|
||||
Options include all supported platform variants; restrictions are noted below.
|
||||
|
||||
\snippet{doc} local.c cli-options
|
||||
|
||||
\section ss_local_example EXAMPLE
|
||||
|
||||
ss-local(1) can be started from command line and run in foreground.
|
||||
Here is an example:
|
||||
```
|
||||
# Start ss-local with given parameters
|
||||
ss-local -s example.com -p 12345 -l 1080 -k foobar -m aes-256-cfb
|
||||
```
|
||||
|
||||
\section ss_local_see_also SEE ALSO
|
||||
|
||||
ss-server(1),
|
||||
ss-tunnel(1),
|
||||
ss-redir(1),
|
||||
ss-manager(1),
|
||||
shadowsocks-libev(8),
|
||||
iptables(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -1,192 +0,0 @@
|
||||
ss-manager(1)
|
||||
=============
|
||||
|
||||
NAME
|
||||
----
|
||||
ss-manager - ss-server controller for multi-user management and traffic statistics
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
// Generated by scripts/gen_cli_docs.py from src/manager.c; do not edit this section.
|
||||
|
||||
*ss-manager* [-f <pid_file>] [-s <server_host>] [-l <local_port>] [-k
|
||||
<password>] [-t <timeout>] [-m <encrypt_method>] [-c <config_file>] [-i
|
||||
<interface>] [-d <addr>] [-a <user_name>] [-n <number>] [-D <path>] [-6] [-h]
|
||||
[-u] [-U] [-v] [-A] [--fast-open] [--no-delay] [--reuse-port] [--acl
|
||||
<acl_config>] [--manager-address <address>] [--executable <path>] [--mtu
|
||||
<MTU>] [--plugin <plugin_name>] [--plugin-opts <plugin_options>] [--password
|
||||
<password>] [--workdir <path>] [--help]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components.
|
||||
`ss-manager`(1) is a controller for multi-user management and
|
||||
traffic statistics, using UNIX domain socket to talk with `ss-server`(1).
|
||||
Also, it provides a UNIX domain socket or IP based API for other software.
|
||||
About the details of this API, please refer to the following 'PROTOCOL'
|
||||
section.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
// Generated by scripts/gen_cli_docs.py from src/manager.c; do not edit this section.
|
||||
|
||||
This section lists options across supported builds. Platform and feature
|
||||
restrictions are noted below; not every option is effective on every platform.
|
||||
|
||||
-f <pid_file>::
|
||||
Start shadowsocks as a daemon with specific pid file.
|
||||
|
||||
-s <server_host>::
|
||||
Set a server listening hostname or IP address. May be repeated.
|
||||
|
||||
-l <local_port>::
|
||||
Accepted for compatibility but ignored by this program; it does not configure a local listener.
|
||||
|
||||
-k <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
-t <timeout>::
|
||||
Set the socket timeout in seconds. The default value is 60.
|
||||
|
||||
-m <encrypt_method>::
|
||||
Set the cipher. The default is 'chacha20-ietf-poly1305'.
|
||||
+
|
||||
AEAD cipher names from the source (availability depends on the build):
|
||||
aes-128-gcm, aes-192-gcm, aes-256-gcm, 2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm, chacha20-ietf-poly1305, 2022-blake3-chacha20-poly1305, xchacha20-ietf-poly1305.
|
||||
+
|
||||
Legacy stream cipher names recognized by the source (disabled in minimal builds;
|
||||
some require backend support): table, rc4, rc4-md5, aes-128-cfb, aes-192-cfb, aes-256-cfb, aes-128-ctr, aes-192-ctr, aes-256-ctr, bf-cfb, camellia-128-cfb, camellia-192-cfb, camellia-256-cfb, cast5-cfb, des-cfb, idea-cfb, rc2-cfb, seed-cfb, salsa20, chacha20, chacha20-ietf.
|
||||
+
|
||||
The '2022-blake3-*' ciphers implement Shadowsocks 2022 (SIP022). They require
|
||||
a base64-encoded pre-shared key supplied with *-k*: 16 bytes for
|
||||
2022-blake3-aes-128-gcm and 32 bytes for the other 2022 ciphers.
|
||||
Generate a 32-byte key with `openssl rand -base64 32`.
|
||||
Passwords are not stretched into keys for these ciphers.
|
||||
|
||||
-c <config_file>::
|
||||
Use a JSON configuration file. The "port_password" field can start multiple ss-server instances.
|
||||
|
||||
-i <interface>::
|
||||
Send outbound traffic through the specified network interface where supported by the platform.
|
||||
|
||||
-d <addr>::
|
||||
Configure name servers for the internal c-ares DNS resolver. By default it uses the system resolver configuration.
|
||||
|
||||
-a <user_name>::
|
||||
Run as a specific user.
|
||||
|
||||
-n <number>::
|
||||
Specify the maximum number of open files. Requires a platform with setrlimit support.
|
||||
|
||||
-D <path>::
|
||||
Set the working directory of ss-manager.
|
||||
|
||||
-6::
|
||||
Resolve hostname to IPv6 address first.
|
||||
|
||||
-h::
|
||||
Print help message.
|
||||
|
||||
-u::
|
||||
Enable UDP relay.
|
||||
|
||||
-U::
|
||||
Enable UDP relay and disable TCP relay.
|
||||
|
||||
-v::
|
||||
Enable verbose mode.
|
||||
|
||||
-A::
|
||||
Deprecated one-time authentication option. Exits with an error; use AEAD ciphers instead.
|
||||
|
||||
--fast-open::
|
||||
Enable TCP Fast Open where supported by the operating system.
|
||||
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--reuse-port::
|
||||
Enable port reuse where supported by the operating system.
|
||||
|
||||
--acl <acl_config>::
|
||||
Enable ACL (Access Control List) and specify config file.
|
||||
|
||||
--manager-address <address>::
|
||||
Set the manager control address: a UNIX domain socket path or an IP address and port.
|
||||
|
||||
--executable <path>::
|
||||
Set the executable path of ss-server used by ss-manager.
|
||||
|
||||
--mtu <MTU>::
|
||||
Specify the MTU of your network interface.
|
||||
|
||||
--plugin <plugin_name>::
|
||||
Enable SIP003 plugin. (Experimental)
|
||||
|
||||
--plugin-opts <plugin_options>::
|
||||
Set SIP003 plugin options. (Experimental)
|
||||
|
||||
--password <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
--workdir <path>::
|
||||
Set the working directory of ss-manager (alias for *-D*).
|
||||
|
||||
--help::
|
||||
Print help message.
|
||||
|
||||
PROTOCOL
|
||||
--------
|
||||
`ss-manager`(1) provides several APIs through UDP protocol:
|
||||
|
||||
Send UDP commands in the following format to the manager-address provided to ss-manager(1): ::::
|
||||
command: [JSON data]
|
||||
|
||||
To add a port: ::::
|
||||
add: {"server_port": 8001, "password":"7cd308cc059"}
|
||||
|
||||
To remove a port: ::::
|
||||
remove: {"server_port": 8001}
|
||||
|
||||
To receive the traffic statistics: ::::
|
||||
ping
|
||||
|
||||
The format of the traffic statistics: ::::
|
||||
stat: {"8001":11370}
|
||||
|
||||
There is no way to reset the traffic statistics, unless you remove the port and add it again
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
To use `ss-manager`(1), First start it and specify necessary information.
|
||||
|
||||
Then communicate with `ss-manager`(1) through UNIX Domain Socket using UDP
|
||||
protocol:
|
||||
|
||||
....
|
||||
# Start the manager. Arguments for ss-server will be passed to generated
|
||||
# ss-server process(es) respectively.
|
||||
ss-manager --manager-address /tmp/manager.sock --executable $(which ss-server) -s example.com -m aes-256-cfb -c /path/to/config.json
|
||||
|
||||
# Connect to the socket. Using netcat-openbsd as an example.
|
||||
# You should use scripts or other programs for further management.
|
||||
nc -Uu /tmp/manager.sock
|
||||
....
|
||||
|
||||
After that, you may communicate with `ss-manager`(1) as described above in the
|
||||
'PROTOCOL' section.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
`ss-local`(1),
|
||||
`ss-server`(1),
|
||||
`ss-tunnel`(1),
|
||||
`ss-redir`(1),
|
||||
`shadowsocks-libev`(8),
|
||||
`iptables`(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -0,0 +1,93 @@
|
||||
\page ss-manager ss-manager
|
||||
|
||||
\brief ss-server controller for multi-user management and traffic statistics
|
||||
|
||||
\section ss_manager_synopsis SYNOPSIS
|
||||
|
||||
`ss-manager [options]`
|
||||
|
||||
\section ss_manager_description DESCRIPTION
|
||||
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components.
|
||||
ss-manager(1) is a controller for multi-user management and
|
||||
traffic statistics, using UNIX domain socket to talk with ss-server(1).
|
||||
Also, it provides a UNIX domain socket or IP based API for other software.
|
||||
About the details of this API, please refer to the following `PROTOCOL`
|
||||
section.
|
||||
|
||||
\section ss_manager_options OPTIONS
|
||||
|
||||
Options include all supported platform variants; restrictions are noted below.
|
||||
|
||||
\snippet{doc} manager.c cli-options
|
||||
|
||||
\section ss_manager_protocol PROTOCOL
|
||||
|
||||
ss-manager(1) provides several APIs through UDP protocol:
|
||||
|
||||
**Send UDP commands in the following format to the manager-address provided to ss-manager(1):**
|
||||
|
||||
```text
|
||||
command: [JSON data]
|
||||
```
|
||||
|
||||
**To add a port:**
|
||||
|
||||
```text
|
||||
add: {"server_port": 8001, "password":"7cd308cc059"}
|
||||
```
|
||||
|
||||
**To remove a port:**
|
||||
|
||||
```text
|
||||
remove: {"server_port": 8001}
|
||||
```
|
||||
|
||||
**To receive the traffic statistics:**
|
||||
|
||||
```text
|
||||
ping
|
||||
```
|
||||
|
||||
**The format of the traffic statistics:**
|
||||
|
||||
```text
|
||||
stat: {"8001":11370}
|
||||
```
|
||||
|
||||
There is no way to reset the traffic statistics, unless you remove the port and add it again
|
||||
|
||||
\section ss_manager_example EXAMPLE
|
||||
|
||||
To use ss-manager(1), First start it and specify necessary information.
|
||||
|
||||
Then communicate with ss-manager(1) through UNIX Domain Socket using UDP
|
||||
protocol:
|
||||
|
||||
```
|
||||
# Start the manager. Arguments for ss-server will be passed to generated
|
||||
# ss-server process(es) respectively.
|
||||
ss-manager --manager-address /tmp/manager.sock --executable $(which ss-server) -s example.com -m aes-256-cfb -c /path/to/config.json
|
||||
|
||||
# Connect to the socket. Using netcat-openbsd as an example.
|
||||
# You should use scripts or other programs for further management.
|
||||
nc -Uu /tmp/manager.sock
|
||||
```
|
||||
|
||||
After that, you may communicate with ss-manager(1) as described above in the
|
||||
`PROTOCOL` section.
|
||||
|
||||
\section ss_manager_see_also SEE ALSO
|
||||
|
||||
ss-local(1),
|
||||
ss-server(1),
|
||||
ss-tunnel(1),
|
||||
ss-redir(1),
|
||||
shadowsocks-libev(8),
|
||||
iptables(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -1,103 +0,0 @@
|
||||
ss-nat(1)
|
||||
=========
|
||||
|
||||
NAME
|
||||
----
|
||||
ss-nat - helper script to setup NAT rules for transparent proxy
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
// Generated by scripts/gen_cli_docs.py from src/ss-nat; do not edit this section.
|
||||
|
||||
*ss-nat* [-s <server_ip>] [-l <local_port>] [-S <server_ip>] [-L <local_port>]
|
||||
[-i <ip_list_file>] [-I <interface>] [-e <extra_options>] [-a <lan_ips>] [-b
|
||||
<wan_ips>] [-w <wan_ips>] [-o] [-u] [-U] [-f] [-h]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
`ss-nat`(1) sets up NAT rules for `ss-redir`(1) to provide traffic redirection.
|
||||
It requires netfilter's NAT module and `iptables`(8).
|
||||
For more information, check out `shadowsocks-libev`(8) and the following
|
||||
'EXAMPLE' section.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
// Generated by scripts/gen_cli_docs.py from src/ss-nat; do not edit this section.
|
||||
|
||||
This section lists options across supported builds. Platform and feature
|
||||
restrictions are noted below; not every option is effective on every platform.
|
||||
|
||||
-s <server_ip>::
|
||||
IP address of shadowsocks remote server
|
||||
|
||||
-l <local_port>::
|
||||
Port number of shadowsocks local server
|
||||
|
||||
-S <server_ip>::
|
||||
IP address of shadowsocks remote UDP server
|
||||
|
||||
-L <local_port>::
|
||||
Port number of shadowsocks local UDP server
|
||||
|
||||
-i <ip_list_file>::
|
||||
a file whose content is bypassed ip list
|
||||
|
||||
-I <interface>::
|
||||
Set the LAN interface for NAT rules. The default is eth0.
|
||||
|
||||
-e <extra_options>::
|
||||
Extra options for iptables
|
||||
|
||||
-a <lan_ips>::
|
||||
LAN IP of access control, need a prefix to define access control mode
|
||||
|
||||
-b <wan_ips>::
|
||||
WAN IP of will be bypassed
|
||||
|
||||
-w <wan_ips>::
|
||||
WAN IP of will be forwarded
|
||||
|
||||
-o::
|
||||
Apply the rules to the OUTPUT chain
|
||||
|
||||
-u::
|
||||
Enable udprelay mode, TPROXY is required
|
||||
|
||||
-U::
|
||||
Enable udprelay mode, using different IP and ports for TCP and UDP
|
||||
|
||||
-f::
|
||||
Flush the rules
|
||||
|
||||
-h::
|
||||
Show this help message and exit
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
`ss-nat` requires `iptables`(8). Here is an example:
|
||||
|
||||
....
|
||||
# Enable NAT rules for shadowsocks,
|
||||
# with both TCP and UDP redirection enabled,
|
||||
# and applied for both PREROUTING and OUTPUT chains
|
||||
root@Wrt:~# ss-nat -s 192.168.1.100 -l 1080 -u -o
|
||||
|
||||
# Disable and flush all NAT rules for shadowsocks
|
||||
root@Wrt:~# ss-nat -f
|
||||
....
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
`ss-local`(1),
|
||||
`ss-server`(1),
|
||||
`ss-tunnel`(1),
|
||||
`ss-manager`(1),
|
||||
`shadowsocks-libev`(8),
|
||||
`iptables`(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
\page ss-nat ss-nat
|
||||
|
||||
\brief helper script to setup NAT rules for transparent proxy
|
||||
|
||||
\section ss_nat_synopsis SYNOPSIS
|
||||
|
||||
`ss-nat [options]`
|
||||
|
||||
\section ss_nat_description DESCRIPTION
|
||||
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
ss-nat(1) sets up NAT rules for ss-redir(1) to provide traffic redirection.
|
||||
It requires netfilter's NAT module and iptables(8).
|
||||
For more information, check out shadowsocks-libev(8) and the following
|
||||
`EXAMPLE` section.
|
||||
|
||||
\section ss_nat_options OPTIONS
|
||||
|
||||
Options include all supported platform variants; restrictions are noted below.
|
||||
|
||||
\snippet{doc} ss-nat cli-options
|
||||
|
||||
\section ss_nat_example EXAMPLE
|
||||
|
||||
`ss-nat` requires iptables(8). Here is an example:
|
||||
|
||||
```
|
||||
# Enable NAT rules for shadowsocks,
|
||||
# with both TCP and UDP redirection enabled,
|
||||
# and applied for both PREROUTING and OUTPUT chains
|
||||
root@Wrt:~# ss-nat -s 192.168.1.100 -l 1080 -u -o
|
||||
|
||||
# Disable and flush all NAT rules for shadowsocks
|
||||
root@Wrt:~# ss-nat -f
|
||||
```
|
||||
|
||||
\section ss_nat_see_also SEE ALSO
|
||||
|
||||
ss-local(1),
|
||||
ss-server(1),
|
||||
ss-tunnel(1),
|
||||
ss-manager(1),
|
||||
shadowsocks-libev(8),
|
||||
iptables(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -1,203 +0,0 @@
|
||||
ss-redir(1)
|
||||
===========
|
||||
|
||||
NAME
|
||||
----
|
||||
ss-redir - shadowsocks client as transparent proxy, C implementation
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
// Generated by scripts/gen_cli_docs.py from src/redir.c; do not edit this section.
|
||||
|
||||
*ss-redir* [-f <pid_file>] [-s <server_host>] [-p <server_port>] [-l
|
||||
<local_port>] [-k <password>] [-t <timeout>] [-m <encrypt_method>] [-c
|
||||
<config_file>] [-b <local_address>] [-a <user_name>] [-n <number>] [-h] [-u]
|
||||
[-U] [-T] [-v] [-6] [-A] [--fast-open] [--mtu <MTU>] [--mptcp] [--plugin
|
||||
<plugin_name>] [--plugin-opts <plugin_options>] [--reuse-port]
|
||||
[--tcp-incoming-sndbuf <size>] [--tcp-incoming-rcvbuf <size>]
|
||||
[--tcp-outgoing-sndbuf <size>] [--tcp-outgoing-rcvbuf <size>] [--no-delay]
|
||||
[--password <password>] [--key <key_in_base64>] [--help]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components.
|
||||
`ss-redir`(1) works as a transparent proxy on local machines to proxy TCP
|
||||
traffic and requires netfilter's NAT module.
|
||||
For more information, check out `shadowsocks-libev`(8) and the following
|
||||
'EXAMPLE' section.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
// Generated by scripts/gen_cli_docs.py from src/redir.c; do not edit this section.
|
||||
|
||||
This section lists options across supported builds. Platform and feature
|
||||
restrictions are noted below; not every option is effective on every platform.
|
||||
|
||||
-f <pid_file>::
|
||||
Start shadowsocks as a daemon with specific pid file.
|
||||
|
||||
-s <server_host>::
|
||||
Set the server's hostname or IP.
|
||||
|
||||
-p <server_port>::
|
||||
Set the server's port number.
|
||||
|
||||
-l <local_port>::
|
||||
Set the local port number.
|
||||
|
||||
-k <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
-t <timeout>::
|
||||
Set the socket timeout in seconds. The default value is 60.
|
||||
|
||||
-m <encrypt_method>::
|
||||
Set the cipher. The default is 'chacha20-ietf-poly1305'.
|
||||
+
|
||||
AEAD cipher names from the source (availability depends on the build):
|
||||
aes-128-gcm, aes-192-gcm, aes-256-gcm, 2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm, chacha20-ietf-poly1305, 2022-blake3-chacha20-poly1305, xchacha20-ietf-poly1305.
|
||||
+
|
||||
Legacy stream cipher names recognized by the source (disabled in minimal builds;
|
||||
some require backend support): table, rc4, rc4-md5, aes-128-cfb, aes-192-cfb, aes-256-cfb, aes-128-ctr, aes-192-ctr, aes-256-ctr, bf-cfb, camellia-128-cfb, camellia-192-cfb, camellia-256-cfb, cast5-cfb, des-cfb, idea-cfb, rc2-cfb, seed-cfb, salsa20, chacha20, chacha20-ietf.
|
||||
+
|
||||
The '2022-blake3-*' ciphers implement Shadowsocks 2022 (SIP022). They require
|
||||
a base64-encoded pre-shared key supplied with *-k*: 16 bytes for
|
||||
2022-blake3-aes-128-gcm and 32 bytes for the other 2022 ciphers.
|
||||
Generate a 32-byte key with `openssl rand -base64 32`.
|
||||
Passwords are not stretched into keys for these ciphers.
|
||||
|
||||
-c <config_file>::
|
||||
Use a configuration file.
|
||||
+
|
||||
Refer to `shadowsocks-c`(8) 'CONFIG FILE' section for more details.
|
||||
|
||||
-b <local_address>::
|
||||
Specify the local address to use while this client is making outbound
|
||||
connections to the server.
|
||||
|
||||
-a <user_name>::
|
||||
Run as a specific user.
|
||||
|
||||
-n <number>::
|
||||
Specify the maximum number of open files. Requires a platform with setrlimit support.
|
||||
|
||||
-h::
|
||||
Print help message.
|
||||
|
||||
-u::
|
||||
Enable UDP relay. Requires Linux TPROXY support and permission to configure transparent proxying.
|
||||
|
||||
-U::
|
||||
Enable UDP relay and disable TCP relay.
|
||||
|
||||
-T::
|
||||
Use TPROXY instead of REDIRECT for TCP traffic. Requires Linux TPROXY support.
|
||||
|
||||
-v::
|
||||
Enable verbose mode.
|
||||
|
||||
-6::
|
||||
Resolve hostname to IPv6 address first.
|
||||
|
||||
-A::
|
||||
Deprecated one-time authentication option. Exits with an error; use AEAD ciphers instead.
|
||||
|
||||
--fast-open::
|
||||
Enable TCP Fast Open where supported by the operating system.
|
||||
|
||||
--mtu <MTU>::
|
||||
Specify the MTU of your network interface.
|
||||
|
||||
--mptcp::
|
||||
Enable Multipath TCP.
|
||||
+
|
||||
Only available with MPTCP enabled Linux kernel.
|
||||
|
||||
--plugin <plugin_name>::
|
||||
Enable SIP003 plugin. (Experimental)
|
||||
|
||||
--plugin-opts <plugin_options>::
|
||||
Set SIP003 plugin options. (Experimental)
|
||||
|
||||
--reuse-port::
|
||||
Enable port reuse where supported by the operating system.
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
Set TCP send buffer size for incoming connections.
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--password <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
--key <key_in_base64>::
|
||||
Set the key directly. The key should be encoded with URL-safe Base64.
|
||||
|
||||
--help::
|
||||
Print help message.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
ss-redir requires netfilter's NAT function. Here is an example:
|
||||
|
||||
....
|
||||
# Create new chain
|
||||
iptables -t nat -N SHADOWSOCKS
|
||||
iptables -t mangle -N SHADOWSOCKS
|
||||
|
||||
# Ignore your shadowsocks server's addresses
|
||||
# It's very IMPORTANT, just be careful.
|
||||
iptables -t nat -A SHADOWSOCKS -d 123.123.123.123 -j RETURN
|
||||
|
||||
# Ignore LANs and any other addresses you'd like to bypass the proxy
|
||||
# See Wikipedia and RFC5735 for full list of reserved networks.
|
||||
# See ashi009/bestroutetb for a highly optimized CHN route list.
|
||||
iptables -t nat -A SHADOWSOCKS -d 0.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 10.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 169.254.0.0/16 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 172.16.0.0/12 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 192.168.0.0/16 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 224.0.0.0/4 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 240.0.0.0/4 -j RETURN
|
||||
|
||||
# Anything else should be redirected to shadowsocks's local port
|
||||
iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 12345
|
||||
|
||||
# Add any UDP rules
|
||||
ip route add local default dev lo table 100
|
||||
ip rule add fwmark 1 lookup 100
|
||||
iptables -t mangle -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 12345 --tproxy-mark 0x01/0x01
|
||||
|
||||
# Apply the rules
|
||||
iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS
|
||||
iptables -t mangle -A PREROUTING -j SHADOWSOCKS
|
||||
|
||||
# Start the shadowsocks-redir
|
||||
ss-redir -u -c /etc/config/shadowsocks.json -f /var/run/shadowsocks.pid
|
||||
....
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
`ss-local`(1),
|
||||
`ss-server`(1),
|
||||
`ss-tunnel`(1),
|
||||
`ss-manager`(1),
|
||||
`shadowsocks-libev`(8),
|
||||
`iptables`(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -0,0 +1,77 @@
|
||||
\page ss-redir ss-redir
|
||||
|
||||
\brief shadowsocks client as transparent proxy, C implementation
|
||||
|
||||
\section ss_redir_synopsis SYNOPSIS
|
||||
|
||||
`ss-redir [options]`
|
||||
|
||||
\section ss_redir_description DESCRIPTION
|
||||
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components.
|
||||
ss-redir(1) works as a transparent proxy on local machines to proxy TCP
|
||||
traffic and requires netfilter's NAT module.
|
||||
For more information, check out shadowsocks-libev(8) and the following
|
||||
`EXAMPLE` section.
|
||||
|
||||
\section ss_redir_options OPTIONS
|
||||
|
||||
Options include all supported platform variants; restrictions are noted below.
|
||||
|
||||
\snippet{doc} redir.c cli-options
|
||||
|
||||
\section ss_redir_example EXAMPLE
|
||||
|
||||
ss-redir requires netfilter's NAT function. Here is an example:
|
||||
|
||||
```
|
||||
# Create new chain
|
||||
iptables -t nat -N SHADOWSOCKS
|
||||
iptables -t mangle -N SHADOWSOCKS
|
||||
|
||||
# Ignore your shadowsocks server's addresses
|
||||
# It's very IMPORTANT, just be careful.
|
||||
iptables -t nat -A SHADOWSOCKS -d 123.123.123.123 -j RETURN
|
||||
|
||||
# Ignore LANs and any other addresses you'd like to bypass the proxy
|
||||
# See Wikipedia and RFC5735 for full list of reserved networks.
|
||||
# See ashi009/bestroutetb for a highly optimized CHN route list.
|
||||
iptables -t nat -A SHADOWSOCKS -d 0.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 10.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 127.0.0.0/8 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 169.254.0.0/16 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 172.16.0.0/12 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 192.168.0.0/16 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 224.0.0.0/4 -j RETURN
|
||||
iptables -t nat -A SHADOWSOCKS -d 240.0.0.0/4 -j RETURN
|
||||
|
||||
# Anything else should be redirected to shadowsocks's local port
|
||||
iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 12345
|
||||
|
||||
# Add any UDP rules
|
||||
ip route add local default dev lo table 100
|
||||
ip rule add fwmark 1 lookup 100
|
||||
iptables -t mangle -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 12345 --tproxy-mark 0x01/0x01
|
||||
|
||||
# Apply the rules
|
||||
iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS
|
||||
iptables -t mangle -A PREROUTING -j SHADOWSOCKS
|
||||
|
||||
# Start the shadowsocks-redir
|
||||
ss-redir -u -c /etc/config/shadowsocks.json -f /var/run/shadowsocks.pid
|
||||
```
|
||||
|
||||
\section ss_redir_see_also SEE ALSO
|
||||
|
||||
ss-local(1),
|
||||
ss-server(1),
|
||||
ss-tunnel(1),
|
||||
ss-manager(1),
|
||||
shadowsocks-libev(8),
|
||||
iptables(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -1,202 +0,0 @@
|
||||
ss-server(1)
|
||||
============
|
||||
|
||||
NAME
|
||||
----
|
||||
ss-server - shadowsocks server, C implementation
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
// Generated by scripts/gen_cli_docs.py from src/server.c; do not edit this section.
|
||||
|
||||
*ss-server* [-f <pid_file>] [-s <server_host>] [-p <server_port>] [-l
|
||||
<local_port>] [-k <password>] [-t <timeout>] [-m <encrypt_method>] [-b
|
||||
<local_address>] [-c <config_file>] [-i <interface>] [-d <addr>] [-a
|
||||
<user_name>] [-n <number>] [-h] [-u] [-U] [-v] [-6] [-A] [--fast-open]
|
||||
[--reuse-port] [--tcp-incoming-sndbuf <size>] [--tcp-incoming-rcvbuf <size>]
|
||||
[--tcp-outgoing-sndbuf <size>] [--tcp-outgoing-rcvbuf <size>] [--no-delay]
|
||||
[--acl <acl_config>] [--manager-address <address>] [--mtu <MTU>] [--help]
|
||||
[--plugin <plugin_name>] [--plugin-opts <plugin_options>] [--password
|
||||
<password>] [--key <key_in_base64>] [--mptcp] [--nftables-sets <sets>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components.
|
||||
`ss-server`(1) runs on a remote server to provide secured tunnel service.
|
||||
For more information, check out `shadowsocks-libev`(8).
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
// Generated by scripts/gen_cli_docs.py from src/server.c; do not edit this section.
|
||||
|
||||
This section lists options across supported builds. Platform and feature
|
||||
restrictions are noted below; not every option is effective on every platform.
|
||||
|
||||
-f <pid_file>::
|
||||
Start shadowsocks as a daemon with specific pid file.
|
||||
|
||||
-s <server_host>::
|
||||
Set a server listening hostname or IP address. May be repeated.
|
||||
|
||||
-p <server_port>::
|
||||
Set the server listening port.
|
||||
|
||||
-l <local_port>::
|
||||
Accepted for compatibility but ignored by this program; it does not configure a local listener.
|
||||
|
||||
-k <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
-t <timeout>::
|
||||
Set the socket timeout in seconds. The default value is 60.
|
||||
|
||||
-m <encrypt_method>::
|
||||
Set the cipher. The default is 'chacha20-ietf-poly1305'.
|
||||
+
|
||||
AEAD cipher names from the source (availability depends on the build):
|
||||
aes-128-gcm, aes-192-gcm, aes-256-gcm, 2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm, chacha20-ietf-poly1305, 2022-blake3-chacha20-poly1305, xchacha20-ietf-poly1305.
|
||||
+
|
||||
Legacy stream cipher names recognized by the source (disabled in minimal builds;
|
||||
some require backend support): table, rc4, rc4-md5, aes-128-cfb, aes-192-cfb, aes-256-cfb, aes-128-ctr, aes-192-ctr, aes-256-ctr, bf-cfb, camellia-128-cfb, camellia-192-cfb, camellia-256-cfb, cast5-cfb, des-cfb, idea-cfb, rc2-cfb, seed-cfb, salsa20, chacha20, chacha20-ietf.
|
||||
+
|
||||
The '2022-blake3-*' ciphers implement Shadowsocks 2022 (SIP022). They require
|
||||
a base64-encoded pre-shared key supplied with *-k*: 16 bytes for
|
||||
2022-blake3-aes-128-gcm and 32 bytes for the other 2022 ciphers.
|
||||
Generate a 32-byte key with `openssl rand -base64 32`.
|
||||
Passwords are not stretched into keys for these ciphers.
|
||||
|
||||
-b <local_address>::
|
||||
Set the local address for outbound connections to destination servers.
|
||||
|
||||
-c <config_file>::
|
||||
Use a configuration file.
|
||||
+
|
||||
Refer to `shadowsocks-c`(8) 'CONFIG FILE' section for more details.
|
||||
|
||||
-i <interface>::
|
||||
Send outbound traffic through the specified network interface where supported by the platform.
|
||||
|
||||
-d <addr>::
|
||||
Configure name servers for the internal c-ares DNS resolver. By default it uses the system resolver configuration.
|
||||
|
||||
-a <user_name>::
|
||||
Run as a specific user.
|
||||
|
||||
-n <number>::
|
||||
Specify the maximum number of open files. Requires a platform with setrlimit support.
|
||||
|
||||
-h::
|
||||
Print help message.
|
||||
|
||||
-u::
|
||||
Enable UDP relay.
|
||||
|
||||
-U::
|
||||
Enable UDP relay and disable TCP relay.
|
||||
|
||||
-v::
|
||||
Enable verbose mode.
|
||||
|
||||
-6::
|
||||
Resolve hostname to IPv6 address first.
|
||||
|
||||
-A::
|
||||
Deprecated one-time authentication option. Exits with an error; use AEAD ciphers instead.
|
||||
|
||||
--fast-open::
|
||||
Enable TCP Fast Open where supported by the operating system.
|
||||
|
||||
--reuse-port::
|
||||
Enable port reuse where supported by the operating system.
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
Set TCP send buffer size for incoming connections.
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--acl <acl_config>::
|
||||
Enable ACL (Access Control List) and specify config file.
|
||||
|
||||
--manager-address <address>::
|
||||
Set the manager control address: a UNIX domain socket path or an IP address and port.
|
||||
|
||||
--mtu <MTU>::
|
||||
Specify the MTU of your network interface.
|
||||
|
||||
--help::
|
||||
Print help message.
|
||||
|
||||
--plugin <plugin_name>::
|
||||
Enable SIP003 plugin. (Experimental)
|
||||
|
||||
--plugin-opts <plugin_options>::
|
||||
Set SIP003 plugin options. (Experimental)
|
||||
|
||||
--password <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
--key <key_in_base64>::
|
||||
Set the key directly. The key should be encoded with URL-safe Base64.
|
||||
|
||||
--mptcp::
|
||||
Enable Multipath TCP.
|
||||
+
|
||||
Only available with MPTCP enabled Linux kernel.
|
||||
|
||||
--nftables-sets <sets>::
|
||||
Linux builds with USE_NFTABLES only: add malicious IP addresses to nftables sets. Format: `[<table1>:]<set1>[,[<table2>:]<set2>...]`.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
It is recommended to use a config file when starting `ss-server`(1).
|
||||
|
||||
The config file is written in JSON and is easy to edit.
|
||||
Check out the 'SEE ALSO' section for the default path of config file.
|
||||
|
||||
....
|
||||
# Start the ss-server
|
||||
ss-server -c /etc/shadowsocks-libev/config.json
|
||||
....
|
||||
|
||||
INCOMPATIBILITY
|
||||
---------------
|
||||
The config file of `shadowsocks-libev`(8) is slightly different from original
|
||||
shadowsocks.
|
||||
|
||||
In order to listen to both IPv4/IPv6 address, use the following grammar in
|
||||
your config json file:
|
||||
....
|
||||
{
|
||||
"server":["::0","0.0.0.0"],
|
||||
...
|
||||
}
|
||||
....
|
||||
|
||||
`ss-server`(1) also does not understand "port_password" field in config file.
|
||||
If you want to start up multiple server instances with a single config file,
|
||||
please try ss-manager tool. See `ss-manager`(8) for details.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
`ss-local`(1),
|
||||
`ss-tunnel`(1),
|
||||
`ss-redir`(1),
|
||||
`ss-manager`(1),
|
||||
`shadowsocks-libev`(8),
|
||||
`iptables`(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -0,0 +1,64 @@
|
||||
\page ss-server ss-server
|
||||
|
||||
\brief shadowsocks server, C implementation
|
||||
|
||||
\section ss_server_synopsis SYNOPSIS
|
||||
|
||||
`ss-server [options]`
|
||||
|
||||
\section ss_server_description DESCRIPTION
|
||||
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components.
|
||||
ss-server(1) runs on a remote server to provide secured tunnel service.
|
||||
For more information, check out shadowsocks-libev(8).
|
||||
|
||||
\section ss_server_options OPTIONS
|
||||
|
||||
Options include all supported platform variants; restrictions are noted below.
|
||||
|
||||
\snippet{doc} server.c cli-options
|
||||
|
||||
\section ss_server_example EXAMPLE
|
||||
|
||||
It is recommended to use a config file when starting ss-server(1).
|
||||
|
||||
The config file is written in JSON and is easy to edit.
|
||||
Check out the `SEE ALSO` section for the default path of config file.
|
||||
|
||||
```
|
||||
# Start the ss-server
|
||||
ss-server -c /etc/shadowsocks-libev/config.json
|
||||
```
|
||||
|
||||
\section ss_server_incompatibility INCOMPATIBILITY
|
||||
|
||||
The config file of shadowsocks-libev(8) is slightly different from original
|
||||
shadowsocks.
|
||||
|
||||
In order to listen to both IPv4/IPv6 address, use the following grammar in
|
||||
your config json file:
|
||||
```
|
||||
{
|
||||
"server":["::0","0.0.0.0"],
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
ss-server(1) also does not understand "port_password" field in config file.
|
||||
If you want to start up multiple server instances with a single config file,
|
||||
please try ss-manager tool. See ss-manager(8) for details.
|
||||
|
||||
\section ss_server_see_also SEE ALSO
|
||||
|
||||
ss-local(1),
|
||||
ss-tunnel(1),
|
||||
ss-redir(1),
|
||||
ss-manager(1),
|
||||
shadowsocks-libev(8),
|
||||
iptables(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -1,181 +0,0 @@
|
||||
ss-tunnel(1)
|
||||
============
|
||||
|
||||
NAME
|
||||
----
|
||||
ss-tunnel - shadowsocks tools for local port forwarding, C implementation
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
// Generated by scripts/gen_cli_docs.py from src/tunnel.c; do not edit this section.
|
||||
|
||||
*ss-tunnel* [-f <pid_file>] [-s <server_host>] [-p <server_port>] [-l
|
||||
<local_port>] [-k <password>] [-t <timeout>] [-m <encrypt_method>] [-i
|
||||
<interface>] [-c <config_file>] [-b <local_address>] [-L <addr:port>] [-a
|
||||
<user_name>] [-n <number>] [-h] [-u] [-U] [-v] [-V] [-6] [-A] [--fast-open]
|
||||
[--mtu <MTU>] [--no-delay] [--mptcp] [--plugin <plugin_name>] [--plugin-opts
|
||||
<plugin_options>] [--reuse-port] [--tcp-incoming-sndbuf <size>]
|
||||
[--tcp-incoming-rcvbuf <size>] [--tcp-outgoing-sndbuf <size>]
|
||||
[--tcp-outgoing-rcvbuf <size>] [--password <password>] [--key
|
||||
<key_in_base64>] [--help]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components.
|
||||
`ss-tunnel`(1) is a tool for local port forwarding.
|
||||
See 'OPTIONS' section for special option needed by `ss-tunnel`(1).
|
||||
For more information, check out `shadowsocks-libev`(8).
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
// Generated by scripts/gen_cli_docs.py from src/tunnel.c; do not edit this section.
|
||||
|
||||
This section lists options across supported builds. Platform and feature
|
||||
restrictions are noted below; not every option is effective on every platform.
|
||||
|
||||
-f <pid_file>::
|
||||
Start shadowsocks as a daemon with specific pid file.
|
||||
|
||||
-s <server_host>::
|
||||
Set the server's hostname or IP.
|
||||
|
||||
-p <server_port>::
|
||||
Set the server's port number.
|
||||
|
||||
-l <local_port>::
|
||||
Set the local port number.
|
||||
|
||||
-k <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
-t <timeout>::
|
||||
Set the socket timeout in seconds. The default value is 60.
|
||||
|
||||
-m <encrypt_method>::
|
||||
Set the cipher. The default is 'chacha20-ietf-poly1305'.
|
||||
+
|
||||
AEAD cipher names from the source (availability depends on the build):
|
||||
aes-128-gcm, aes-192-gcm, aes-256-gcm, 2022-blake3-aes-128-gcm, 2022-blake3-aes-256-gcm, chacha20-ietf-poly1305, 2022-blake3-chacha20-poly1305, xchacha20-ietf-poly1305.
|
||||
+
|
||||
Legacy stream cipher names recognized by the source (disabled in minimal builds;
|
||||
some require backend support): table, rc4, rc4-md5, aes-128-cfb, aes-192-cfb, aes-256-cfb, aes-128-ctr, aes-192-ctr, aes-256-ctr, bf-cfb, camellia-128-cfb, camellia-192-cfb, camellia-256-cfb, cast5-cfb, des-cfb, idea-cfb, rc2-cfb, seed-cfb, salsa20, chacha20, chacha20-ietf.
|
||||
+
|
||||
The '2022-blake3-*' ciphers implement Shadowsocks 2022 (SIP022). They require
|
||||
a base64-encoded pre-shared key supplied with *-k*: 16 bytes for
|
||||
2022-blake3-aes-128-gcm and 32 bytes for the other 2022 ciphers.
|
||||
Generate a 32-byte key with `openssl rand -base64 32`.
|
||||
Passwords are not stretched into keys for these ciphers.
|
||||
|
||||
-i <interface>::
|
||||
Send outbound traffic through the specified network interface where supported by the platform.
|
||||
|
||||
-c <config_file>::
|
||||
Use a configuration file.
|
||||
+
|
||||
Refer to `shadowsocks-c`(8) 'CONFIG FILE' section for more details.
|
||||
|
||||
-b <local_address>::
|
||||
Specify the local address to use while this client is making outbound
|
||||
connections to the server.
|
||||
|
||||
-L <addr:port>::
|
||||
Destination server address and port for local port forwarding.
|
||||
|
||||
-a <user_name>::
|
||||
Run as a specific user.
|
||||
|
||||
-n <number>::
|
||||
Specify the maximum number of open files. Requires a platform with setrlimit support.
|
||||
|
||||
-h::
|
||||
Print help message.
|
||||
|
||||
-u::
|
||||
Enable UDP relay.
|
||||
|
||||
-U::
|
||||
Enable UDP relay and disable TCP relay.
|
||||
|
||||
-v::
|
||||
Enable verbose mode.
|
||||
|
||||
-V::
|
||||
Android only: enable VPN socket protection.
|
||||
|
||||
-6::
|
||||
Resolve hostname to IPv6 address first.
|
||||
|
||||
-A::
|
||||
Deprecated one-time authentication option. Exits with an error; use AEAD ciphers instead.
|
||||
|
||||
--fast-open::
|
||||
Enable TCP Fast Open where supported by the operating system.
|
||||
|
||||
--mtu <MTU>::
|
||||
Specify the MTU of your network interface.
|
||||
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--mptcp::
|
||||
Enable Multipath TCP.
|
||||
+
|
||||
Only available with MPTCP enabled Linux kernel.
|
||||
|
||||
--plugin <plugin_name>::
|
||||
Enable SIP003 plugin. (Experimental)
|
||||
|
||||
--plugin-opts <plugin_options>::
|
||||
Set SIP003 plugin options. (Experimental)
|
||||
|
||||
--reuse-port::
|
||||
Enable port reuse where supported by the operating system.
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
Set TCP send buffer size for incoming connections.
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
|
||||
--password <password>::
|
||||
Set the password. The server and the client should use the same password.
|
||||
|
||||
--key <key_in_base64>::
|
||||
Set the key directly. The key should be encoded with URL-safe Base64.
|
||||
|
||||
--help::
|
||||
Print help message.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
`ss-tunnel`(1) can be used to forward DNS queries to a remote DNS server
|
||||
through the shadowsocks tunnel. Here is an example:
|
||||
|
||||
....
|
||||
# Forward local UDP port 5353 to 8.8.8.8:53 through the ss-server
|
||||
ss-tunnel -s example.com -p 12345 -l 5353 -k foobar -m aes-256-cfb -L 8.8.8.8:53 -u
|
||||
|
||||
# Then configure your system to use 127.0.0.1:5353 as the DNS server
|
||||
dig @127.0.0.1 -p 5353 www.google.com
|
||||
....
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
`ss-local`(1),
|
||||
`ss-server`(1),
|
||||
`ss-redir`(1),
|
||||
`ss-manager`(1),
|
||||
`shadowsocks-libev`(8),
|
||||
`iptables`(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -0,0 +1,48 @@
|
||||
\page ss-tunnel ss-tunnel
|
||||
|
||||
\brief shadowsocks tools for local port forwarding, C implementation
|
||||
|
||||
\section ss_tunnel_synopsis SYNOPSIS
|
||||
|
||||
`ss-tunnel [options]`
|
||||
|
||||
\section ss_tunnel_description DESCRIPTION
|
||||
|
||||
*shadowsocks-c* is a lightweight and secure socks5 proxy.
|
||||
It is a port of the original shadowsocks created by clowwindy.
|
||||
*shadowsocks-c* is written in pure C and takes advantage of libuv to
|
||||
achieve both high performance and low resource consumption.
|
||||
|
||||
*shadowsocks-c* consists of five components.
|
||||
ss-tunnel(1) is a tool for local port forwarding.
|
||||
See `OPTIONS` section for special option needed by ss-tunnel(1).
|
||||
For more information, check out shadowsocks-libev(8).
|
||||
|
||||
\section ss_tunnel_options OPTIONS
|
||||
|
||||
Options include all supported platform variants; restrictions are noted below.
|
||||
|
||||
\snippet{doc} tunnel.c cli-options
|
||||
|
||||
\section ss_tunnel_example EXAMPLE
|
||||
|
||||
ss-tunnel(1) can be used to forward DNS queries to a remote DNS server
|
||||
through the shadowsocks tunnel. Here is an example:
|
||||
|
||||
```
|
||||
# Forward local UDP port 5353 to 8.8.8.8:53 through the ss-server
|
||||
ss-tunnel -s example.com -p 12345 -l 5353 -k foobar -m aes-256-cfb -L 8.8.8.8:53 -u
|
||||
|
||||
# Then configure your system to use 127.0.0.1:5353 as the DNS server
|
||||
dig @127.0.0.1 -p 5353 www.google.com
|
||||
```
|
||||
|
||||
\section ss_tunnel_see_also SEE ALSO
|
||||
|
||||
ss-local(1),
|
||||
ss-server(1),
|
||||
ss-redir(1),
|
||||
ss-manager(1),
|
||||
shadowsocks-libev(8),
|
||||
iptables(8),
|
||||
/etc/shadowsocks-libev/config.json
|
||||
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Check native Doxygen CLI snippets against source getopt declarations.
|
||||
|
||||
This is validation only. Doxygen reads source snippets and renders the manuals;
|
||||
no generated documentation or intermediate markup is written by this script.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
PROGRAMS = ("local", "server", "tunnel", "redir", "manager", "nat")
|
||||
C_COMMENT = re.compile(r'/\*.*?\*/|//[^\n]*', re.S)
|
||||
|
||||
|
||||
def short_options(spec):
|
||||
result = {}
|
||||
spec = spec.lstrip(':+-')
|
||||
while spec:
|
||||
match = re.match(r'([A-Za-z0-9])(:?)', spec)
|
||||
if not match:
|
||||
raise ValueError(f"Unsupported getopt string: {spec}")
|
||||
flag, argument = match.groups()
|
||||
if '-' + flag in result:
|
||||
raise ValueError(f"Duplicate short option: {flag}")
|
||||
result['-' + flag] = bool(argument)
|
||||
spec = spec[match.end():]
|
||||
return result
|
||||
|
||||
|
||||
def options(source, shell=False):
|
||||
result = {}
|
||||
if shell:
|
||||
specs = re.findall(r'^while getopts "([^"]+)" \w+; do$', source, re.M)
|
||||
if len(specs) != 1:
|
||||
raise ValueError("Expected one literal shell getopts declaration")
|
||||
else:
|
||||
source = C_COMMENT.sub('', source)
|
||||
specs = re.findall(r'getopt_long\(argc,\s*argv,\s*"([^"]+)"\s*,\s*long_options,\s*NULL\)', source)
|
||||
if not specs or len(specs) != len(re.findall(r'\bgetopt_long\s*\(', source)):
|
||||
raise ValueError("Expected literal getopt_long declarations")
|
||||
for spec in specs:
|
||||
for flag, argument in short_options(spec).items():
|
||||
if flag in result and result[flag] != argument:
|
||||
raise ValueError(f"Inconsistent argument across platform variants: {flag}")
|
||||
result[flag] = argument
|
||||
if shell:
|
||||
return result
|
||||
tables = re.findall(r'static struct option long_options\[\]\s*=\s*\{(.*?)\};', source, re.S)
|
||||
if len(tables) != 1:
|
||||
raise ValueError("Expected one long_options table")
|
||||
table = re.sub(r'^\s*#.*$', '', tables[0], flags=re.M)
|
||||
entry = re.compile(r'\{\s*"([a-z0-9-]+)"\s*,\s*(no_argument|required_argument)\s*,\s*NULL\s*,\s*GETOPT_VAL_[A-Z0-9_]+\s*\}\s*,', re.S)
|
||||
for match in entry.finditer(table):
|
||||
flag, argument = match.groups()
|
||||
if '--' + flag in result:
|
||||
raise ValueError(f"Duplicate long option: {flag}")
|
||||
result['--' + flag] = argument == 'required_argument'
|
||||
remainder = entry.sub('', table)
|
||||
if not re.fullmatch(r'\s*\{\s*NULL\s*,\s*0\s*,\s*NULL\s*,\s*0\s*\}\s*', remainder):
|
||||
raise ValueError(f"Unsupported long_options entry: {remainder.strip()}")
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def snippets(source):
|
||||
result = {}
|
||||
for match in re.finditer(r'(?:/\*|//) \[([\w-]+)\]\n(.*?)\n\[\1\](?: \*/)?', source, re.S):
|
||||
name, body = match.groups()
|
||||
if name in result:
|
||||
raise ValueError(f"Duplicate snippet: {name}")
|
||||
result[name] = body
|
||||
return result
|
||||
|
||||
|
||||
def documented_options(source_name, sources):
|
||||
inventory = snippets(sources[source_name]).get('cli-options')
|
||||
if not inventory:
|
||||
raise ValueError(f"{source_name}: missing cli-options snippet")
|
||||
result = {}
|
||||
for line in inventory.splitlines():
|
||||
match = re.fullmatch(r'\\snippet\{doc\} ([\w.-]+) ([\w-]+)', line)
|
||||
if not match:
|
||||
raise ValueError(f"Invalid option snippet inclusion: {line}")
|
||||
filename, identifier = match.groups()
|
||||
body = snippets(sources.get(filename, '')).get(identifier)
|
||||
if not body:
|
||||
raise ValueError(f"Missing snippet: {filename} {identifier}")
|
||||
heading, _, description = body.partition('\n')
|
||||
term = re.fullmatch(r'\\par `(-{1,2}[A-Za-z0-9][A-Za-z0-9-]*)(?: (<[^>]+>))?`', heading)
|
||||
if not term or not description.strip():
|
||||
raise ValueError(f"Invalid option documentation: {filename} {identifier}")
|
||||
flag, argument = term.groups()
|
||||
if flag in result:
|
||||
raise ValueError(f"Duplicate documented option: {flag}")
|
||||
result[flag] = bool(argument)
|
||||
return result
|
||||
|
||||
|
||||
def check(root=ROOT, rendered=None):
|
||||
sources = {path.name: path.read_text(encoding='utf-8')
|
||||
for path in (root / 'src').glob('*.c')}
|
||||
sources['ss-nat'] = (root / 'src/ss-nat').read_text(encoding='utf-8')
|
||||
for module in PROGRAMS:
|
||||
program = 'ss-' + module
|
||||
filename = 'ss-nat' if module == 'nat' else module + '.c'
|
||||
declared = options(sources[filename], shell=module == 'nat')
|
||||
documented = documented_options(filename, sources)
|
||||
missing = declared.keys() - documented.keys()
|
||||
extra = documented.keys() - declared.keys()
|
||||
if missing or extra:
|
||||
raise ValueError(f"{program}: missing documentation {sorted(missing)}; stale documentation {sorted(extra)}")
|
||||
for flag in declared:
|
||||
if declared[flag] != documented[flag]:
|
||||
raise ValueError(f"{program}: argument mismatch for {flag}")
|
||||
page = (root / f'doc/{program}.md').read_text(encoding='utf-8')
|
||||
if page.count(f'\\snippet{{doc}} {filename} cli-options') != 1:
|
||||
raise ValueError(f"{program}: manual must include its source cli-options exactly once")
|
||||
if rendered:
|
||||
man = (rendered / 'man' / (program + '.1')).read_text(encoding='utf-8')
|
||||
man = re.sub(r'\\f[A-Z]', '', man).replace('\\-', '-')
|
||||
for flag in declared:
|
||||
if not re.search(r'(?<![\w-])' + re.escape(flag) + r'(?![\w-])', man):
|
||||
raise ValueError(f"{program}: missing rendered flag {flag}")
|
||||
html = (rendered / 'html' / (program + '.html')).read_text(encoding='utf-8')
|
||||
if 'OPTIONS' not in html or 'SYNOPSIS' not in html:
|
||||
raise ValueError(f"{program}: incomplete HTML output")
|
||||
if rendered:
|
||||
man = (rendered / 'man/shadowsocks-c.8').read_text(encoding='utf-8')
|
||||
if not re.search(r'^\.TH .* 8 ', man, re.M):
|
||||
raise ValueError('Overview manual must use section 8')
|
||||
alias = (rendered / 'man/shadowsocks-libev.8').read_text(encoding='utf-8')
|
||||
if alias != '.so man8/shadowsocks-c.8\n':
|
||||
raise ValueError('Missing legacy manual alias')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--root', type=Path, default=ROOT)
|
||||
parser.add_argument('--rendered', type=Path, help='also check a Doxygen build directory')
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
check(args.root, args.rendered)
|
||||
except (ValueError, OSError) as error:
|
||||
parser.exit(1, f'{error}\n')
|
||||
print('Doxygen CLI documentation matches the source parsers.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,194 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate man-page CLI sections from getopt declarations and CLI_DOC comments.
|
||||
|
||||
This intentionally parses a small, checked subset of C, not arbitrary expressions.
|
||||
Unsupported parser declarations fail instead of silently dropping options. Source
|
||||
is read without preprocessing so cross-builds document all platform variants.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
PROGRAMS = ("local", "server", "tunnel", "redir", "manager", "nat")
|
||||
C_COMMENT = re.compile(r'/\*.*?\*/|//[^\n]*', re.S)
|
||||
TERM = re.compile(r'(-{1,2}[A-Za-z0-9][A-Za-z0-9-]*)(?: (<[^>]+>))?::')
|
||||
|
||||
|
||||
def descriptions(source):
|
||||
blocks = re.findall(r'/\* CLI_DOC\n(.*?)\*/', source, re.S)
|
||||
for block in re.findall(r'^# CLI_DOC\n(.*?)^# END_CLI_DOC$', source, re.M | re.S):
|
||||
blocks.append(re.sub(r'^# ?', '', block, flags=re.M))
|
||||
result = {}
|
||||
for block in blocks:
|
||||
for entry in re.split(r'\n\s*\n(?=-)', block.strip()):
|
||||
term, separator, body = entry.partition('\n')
|
||||
match = TERM.fullmatch(term)
|
||||
if not match or not separator or not body.strip():
|
||||
raise ValueError(f"Invalid CLI_DOC entry: {term}")
|
||||
flag, argument = match.groups()
|
||||
if flag in result:
|
||||
raise ValueError(f"Duplicate CLI_DOC entry: {flag}")
|
||||
result[flag] = (argument, body.strip())
|
||||
return result
|
||||
|
||||
|
||||
def short_options(spec):
|
||||
result = {}
|
||||
spec = spec.lstrip(':+-')
|
||||
while spec:
|
||||
match = re.match(r'([A-Za-z0-9])(:?)', spec)
|
||||
if not match:
|
||||
raise ValueError(f"Unsupported getopt string: {spec}")
|
||||
flag, argument = match.groups()
|
||||
if '-' + flag in result:
|
||||
raise ValueError(f"Duplicate short option: {flag}")
|
||||
result['-' + flag] = bool(argument)
|
||||
spec = spec[match.end():]
|
||||
return result
|
||||
|
||||
|
||||
def options(source, shell=False):
|
||||
result = {}
|
||||
if shell:
|
||||
specs = re.findall(r'^while getopts "([^"]+)" \w+; do$', source, re.M)
|
||||
if len(specs) != 1:
|
||||
raise ValueError("Expected one literal shell getopts declaration")
|
||||
else:
|
||||
source = C_COMMENT.sub('', source)
|
||||
specs = re.findall(r'getopt_long\(argc,\s*argv,\s*"([^"]+)"\s*,\s*long_options,\s*NULL\)', source)
|
||||
if not specs or len(specs) != len(re.findall(r'\bgetopt_long\s*\(', source)):
|
||||
raise ValueError("Expected literal getopt_long declarations")
|
||||
for spec in specs:
|
||||
for flag, argument in short_options(spec).items():
|
||||
if flag in result and result[flag] != argument:
|
||||
raise ValueError(f"Inconsistent argument across platform variants: {flag}")
|
||||
result[flag] = argument
|
||||
if shell:
|
||||
return result
|
||||
tables = re.findall(r'static struct option long_options\[\]\s*=\s*\{(.*?)\};', source, re.S)
|
||||
if len(tables) != 1:
|
||||
raise ValueError("Expected one long_options table")
|
||||
table = re.sub(r'^\s*#.*$', '', tables[0], flags=re.M)
|
||||
entry = re.compile(r'\{\s*"([a-z0-9-]+)"\s*,\s*(no_argument|required_argument)\s*,\s*NULL\s*,\s*GETOPT_VAL_[A-Z0-9_]+\s*\}\s*,', re.S)
|
||||
for match in entry.finditer(table):
|
||||
flag, argument = match.groups()
|
||||
if '--' + flag in result:
|
||||
raise ValueError(f"Duplicate long option: {flag}")
|
||||
result['--' + flag] = argument == 'required_argument'
|
||||
remainder = entry.sub('', table)
|
||||
if not re.fullmatch(r'\s*\{\s*NULL\s*,\s*0\s*,\s*NULL\s*,\s*0\s*\}\s*', remainder):
|
||||
raise ValueError(f"Unsupported long_options entry: {remainder.strip()}")
|
||||
return result
|
||||
|
||||
|
||||
def cipher_names(root, kind):
|
||||
source = C_COMMENT.sub('', (root / f'src/{kind}.c').read_text())
|
||||
match = re.search(r'const char \*supported_' + kind + r'_ciphers\[[^]]+\]\s*=\s*\{(.*?)\};', source, re.S)
|
||||
if not match:
|
||||
raise ValueError(f"Missing {kind} cipher table")
|
||||
table = re.sub(r'^\s*#.*$', '', match[1], flags=re.M)
|
||||
names = re.findall(r'"([a-z0-9-]+)"', table)
|
||||
if not names or re.sub(r'"[a-z0-9-]+"|[\s,]', '', table):
|
||||
raise ValueError(f"Unsupported {kind} cipher table")
|
||||
return ', '.join(names)
|
||||
|
||||
|
||||
def sections(program, declared, docs):
|
||||
missing = declared.keys() - docs.keys()
|
||||
if missing:
|
||||
raise ValueError(f"{program}: missing CLI_DOC descriptions: {', '.join(sorted(missing))}")
|
||||
synopsis = [f'*{program}*']
|
||||
entries = []
|
||||
for flag, takes_argument in declared.items():
|
||||
argument, body = docs[flag]
|
||||
if bool(argument) != takes_argument:
|
||||
raise ValueError(f"{program}: argument mismatch for {flag}")
|
||||
term = flag + (' ' + argument if argument else '')
|
||||
synopsis.append(f'[{term}]')
|
||||
entries.append(f'{term}::\n{body}')
|
||||
return (textwrap.fill(' '.join(synopsis), width=78, subsequent_indent=' ',
|
||||
break_long_words=False, break_on_hyphens=False),
|
||||
'\n\n'.join(entries))
|
||||
|
||||
|
||||
def replace_section(document, heading, body):
|
||||
pattern = re.compile(r'(^' + heading + r'\n-+\n).*?(?=^[A-Z][A-Z /-]*\n-+\n|\Z)', re.M | re.S)
|
||||
document, count = pattern.subn(lambda m: m[1] + body + '\n\n', document)
|
||||
if count != 1:
|
||||
raise ValueError(f"Expected one {heading} section")
|
||||
return document
|
||||
|
||||
|
||||
def generate(root):
|
||||
shared = descriptions((root / 'src/utils.c').read_text())
|
||||
replacements = {f'{{cli-{kind}-ciphers}}': cipher_names(root, kind)
|
||||
for kind in ('aead', 'stream')}
|
||||
result = {}
|
||||
all_options = set()
|
||||
summary = []
|
||||
for module in PROGRAMS:
|
||||
program = 'ss-' + module
|
||||
path = 'src/ss-nat' if module == 'nat' else f'src/{module}.c'
|
||||
source = (root / path).read_text()
|
||||
declared = options(source, shell=module == 'nat')
|
||||
local = descriptions(source)
|
||||
if local.keys() - declared.keys():
|
||||
raise ValueError(f"{program}: stale CLI_DOC descriptions: {local.keys() - declared.keys()}")
|
||||
docs = local if module == 'nat' else {**shared, **local}
|
||||
if module != 'nat':
|
||||
all_options.update(declared)
|
||||
synopsis, body = sections(program, declared, docs)
|
||||
note = (f'// Generated by scripts/gen_cli_docs.py from {path}; do not edit this section.\n\n')
|
||||
document = (root / f'doc/{program}.asciidoc').read_text()
|
||||
document = replace_section(document, 'SYNOPSIS', note + synopsis)
|
||||
body = ('This section lists options across supported builds. Platform and feature\n'
|
||||
'restrictions are noted below; not every option is effective on every platform.\n\n' + body)
|
||||
document = replace_section(document, 'OPTIONS', note + body)
|
||||
for key, value in replacements.items():
|
||||
document = document.replace(key, value)
|
||||
result[f'{program}.asciidoc'] = document
|
||||
summary.append(f'`{program}`(1)::\nSee this command\'s generated SYNOPSIS and OPTIONS for its accepted arguments.')
|
||||
if shared.keys() - all_options:
|
||||
raise ValueError(f"Stale shared CLI_DOC descriptions: {shared.keys() - all_options}")
|
||||
document = (root / 'doc/shadowsocks-c.asciidoc').read_text()
|
||||
note = '// Generated by scripts/gen_cli_docs.py; do not edit this section.\n\n'
|
||||
document = replace_section(document, 'SYNOPSIS', note + '\n\n'.join(f'*ss-{p}* [options]' for p in PROGRAMS))
|
||||
document = replace_section(document, 'OPTIONS', note + '\n\n'.join(summary))
|
||||
result['shadowsocks-c.asciidoc'] = document
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--root', type=Path, default=ROOT)
|
||||
mode = parser.add_mutually_exclusive_group()
|
||||
mode.add_argument('--check', action='store_true', help='fail if checked-in pages are stale')
|
||||
mode.add_argument('--output-dir', type=Path, help='write assembled pages here instead of doc/')
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
generated = generate(args.root)
|
||||
if args.check:
|
||||
stale = [name for name, text in generated.items()
|
||||
if (args.root / 'doc' / name).read_text() != text]
|
||||
if stale:
|
||||
raise ValueError('Stale CLI docs: ' + ', '.join(stale) +
|
||||
'; run python3 scripts/gen_cli_docs.py')
|
||||
else:
|
||||
output = args.output_dir or args.root / 'doc'
|
||||
output.mkdir(parents=True, exist_ok=True)
|
||||
for name, text in generated.items():
|
||||
path = output / name
|
||||
if not path.exists() or path.read_text() != text:
|
||||
path.write_text(text)
|
||||
except (ValueError, OSError) as error:
|
||||
parser.exit(1, f'{error}\n')
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -93,6 +93,7 @@
|
||||
*/
|
||||
|
||||
const char *supported_aead_ciphers[AEAD_CIPHER_NUM] = {
|
||||
// [cli-aead-ciphers]
|
||||
"aes-128-gcm",
|
||||
"aes-192-gcm",
|
||||
"aes-256-gcm",
|
||||
@@ -103,6 +104,7 @@ const char *supported_aead_ciphers[AEAD_CIPHER_NUM] = {
|
||||
#ifdef FS_HAVE_XCHACHA20IETF
|
||||
"xchacha20-ietf-poly1305"
|
||||
#endif
|
||||
// [cli-aead-ciphers]
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+38
@@ -1512,6 +1512,44 @@ main(int argc, char **argv)
|
||||
|
||||
memset(remote_addr, 0, sizeof(ss_addr_t) * MAX_REMOTE_NUM);
|
||||
|
||||
/* [cli-options]
|
||||
\snippet{doc} utils.c cli_short_f
|
||||
\snippet{doc} utils.c cli_short_s
|
||||
\snippet{doc} utils.c cli_short_p
|
||||
\snippet{doc} utils.c cli_short_l
|
||||
\snippet{doc} utils.c cli_short_k
|
||||
\snippet{doc} utils.c cli_short_t
|
||||
\snippet{doc} utils.c cli_short_m
|
||||
\snippet{doc} utils.c cli_short_i
|
||||
\snippet{doc} utils.c cli_short_c
|
||||
\snippet{doc} utils.c cli_short_b
|
||||
\snippet{doc} utils.c cli_short_a
|
||||
\snippet{doc} utils.c cli_short_n
|
||||
\snippet{doc} utils.c cli_short_S
|
||||
\snippet{doc} utils.c cli_short_h
|
||||
\snippet{doc} utils.c cli_short_u
|
||||
\snippet{doc} utils.c cli_short_U
|
||||
\snippet{doc} utils.c cli_short_v
|
||||
\snippet{doc} utils.c cli_short_V
|
||||
\snippet{doc} utils.c cli_short_6
|
||||
\snippet{doc} utils.c cli_short_A
|
||||
\snippet{doc} utils.c cli_long_reuse_port
|
||||
\snippet{doc} utils.c cli_long_tcp_incoming_sndbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_incoming_rcvbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_outgoing_sndbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_outgoing_rcvbuf
|
||||
\snippet{doc} utils.c cli_long_fast_open
|
||||
\snippet{doc} utils.c cli_long_no_delay
|
||||
\snippet{doc} utils.c cli_long_acl
|
||||
\snippet{doc} utils.c cli_long_mtu
|
||||
\snippet{doc} utils.c cli_long_mptcp
|
||||
\snippet{doc} utils.c cli_long_plugin
|
||||
\snippet{doc} utils.c cli_long_plugin_opts
|
||||
\snippet{doc} utils.c cli_long_password
|
||||
\snippet{doc} utils.c cli_long_key
|
||||
\snippet{doc} utils.c cli_long_server_url
|
||||
\snippet{doc} utils.c cli_long_help
|
||||
[cli-options] */
|
||||
static struct option long_options[] = {
|
||||
{ "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT },
|
||||
{ "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF },
|
||||
|
||||
+42
-5
@@ -1271,16 +1271,53 @@ main(int argc, char **argv)
|
||||
|
||||
jconf_t *conf = NULL;
|
||||
|
||||
/* CLI_DOC
|
||||
-s <server_host>::
|
||||
/* [cli_short_s]
|
||||
\par `-s <server_host>`
|
||||
Set a server listening hostname or IP address. May be repeated.
|
||||
[cli_short_s] */
|
||||
|
||||
-l <local_port>::
|
||||
/* [cli_short_l]
|
||||
\par `-l <local_port>`
|
||||
Accepted for compatibility but ignored by this program; it does not configure a local listener.
|
||||
[cli_short_l] */
|
||||
|
||||
-c <config_file>::
|
||||
/* [cli_short_c]
|
||||
\par `-c <config_file>`
|
||||
Use a JSON configuration file. The "port_password" field can start multiple ss-server instances.
|
||||
*/
|
||||
[cli_short_c] */
|
||||
|
||||
/* [cli-options]
|
||||
\snippet{doc} utils.c cli_short_f
|
||||
\snippet{doc} manager.c cli_short_s
|
||||
\snippet{doc} manager.c cli_short_l
|
||||
\snippet{doc} utils.c cli_short_k
|
||||
\snippet{doc} utils.c cli_short_t
|
||||
\snippet{doc} utils.c cli_short_m
|
||||
\snippet{doc} manager.c cli_short_c
|
||||
\snippet{doc} utils.c cli_short_i
|
||||
\snippet{doc} utils.c cli_short_d
|
||||
\snippet{doc} utils.c cli_short_a
|
||||
\snippet{doc} utils.c cli_short_n
|
||||
\snippet{doc} utils.c cli_short_D
|
||||
\snippet{doc} utils.c cli_short_6
|
||||
\snippet{doc} utils.c cli_short_h
|
||||
\snippet{doc} utils.c cli_short_u
|
||||
\snippet{doc} utils.c cli_short_U
|
||||
\snippet{doc} utils.c cli_short_v
|
||||
\snippet{doc} utils.c cli_short_A
|
||||
\snippet{doc} utils.c cli_long_fast_open
|
||||
\snippet{doc} utils.c cli_long_no_delay
|
||||
\snippet{doc} utils.c cli_long_reuse_port
|
||||
\snippet{doc} utils.c cli_long_acl
|
||||
\snippet{doc} utils.c cli_long_manager_address
|
||||
\snippet{doc} utils.c cli_long_executable
|
||||
\snippet{doc} utils.c cli_long_mtu
|
||||
\snippet{doc} utils.c cli_long_plugin
|
||||
\snippet{doc} utils.c cli_long_plugin_opts
|
||||
\snippet{doc} utils.c cli_long_password
|
||||
\snippet{doc} utils.c cli_long_workdir
|
||||
\snippet{doc} utils.c cli_long_help
|
||||
[cli-options] */
|
||||
static struct option long_options[] = {
|
||||
{ "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN },
|
||||
{ "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY },
|
||||
|
||||
+38
-3
@@ -922,10 +922,45 @@ main(int argc, char **argv)
|
||||
|
||||
memset(remote_addr, 0, sizeof(ss_addr_t) * MAX_REMOTE_NUM);
|
||||
|
||||
/* CLI_DOC
|
||||
-u::
|
||||
/* [cli_short_u]
|
||||
\par `-u`
|
||||
Enable UDP relay. Requires Linux TPROXY support and permission to configure transparent proxying.
|
||||
*/
|
||||
[cli_short_u] */
|
||||
|
||||
/* [cli-options]
|
||||
\snippet{doc} utils.c cli_short_f
|
||||
\snippet{doc} utils.c cli_short_s
|
||||
\snippet{doc} utils.c cli_short_p
|
||||
\snippet{doc} utils.c cli_short_l
|
||||
\snippet{doc} utils.c cli_short_k
|
||||
\snippet{doc} utils.c cli_short_t
|
||||
\snippet{doc} utils.c cli_short_m
|
||||
\snippet{doc} utils.c cli_short_c
|
||||
\snippet{doc} utils.c cli_short_b
|
||||
\snippet{doc} utils.c cli_short_a
|
||||
\snippet{doc} utils.c cli_short_n
|
||||
\snippet{doc} utils.c cli_short_h
|
||||
\snippet{doc} redir.c cli_short_u
|
||||
\snippet{doc} utils.c cli_short_U
|
||||
\snippet{doc} utils.c cli_short_T
|
||||
\snippet{doc} utils.c cli_short_v
|
||||
\snippet{doc} utils.c cli_short_6
|
||||
\snippet{doc} utils.c cli_short_A
|
||||
\snippet{doc} utils.c cli_long_fast_open
|
||||
\snippet{doc} utils.c cli_long_mtu
|
||||
\snippet{doc} utils.c cli_long_mptcp
|
||||
\snippet{doc} utils.c cli_long_plugin
|
||||
\snippet{doc} utils.c cli_long_plugin_opts
|
||||
\snippet{doc} utils.c cli_long_reuse_port
|
||||
\snippet{doc} utils.c cli_long_tcp_incoming_sndbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_incoming_rcvbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_outgoing_sndbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_outgoing_rcvbuf
|
||||
\snippet{doc} utils.c cli_long_no_delay
|
||||
\snippet{doc} utils.c cli_long_password
|
||||
\snippet{doc} utils.c cli_long_key
|
||||
\snippet{doc} utils.c cli_long_help
|
||||
[cli-options] */
|
||||
static struct option long_options[] = {
|
||||
{ "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN },
|
||||
{ "mtu", required_argument, NULL, GETOPT_VAL_MTU },
|
||||
|
||||
+53
-8
@@ -1838,19 +1838,64 @@ main(int argc, char **argv)
|
||||
memset(&local_addr_v4, 0, sizeof(struct sockaddr_storage));
|
||||
memset(&local_addr_v6, 0, sizeof(struct sockaddr_storage));
|
||||
|
||||
/* CLI_DOC
|
||||
-s <server_host>::
|
||||
/* [cli_short_s]
|
||||
\par `-s <server_host>`
|
||||
Set a server listening hostname or IP address. May be repeated.
|
||||
[cli_short_s] */
|
||||
|
||||
-l <local_port>::
|
||||
Accepted for compatibility but ignored by this program; it does not configure a local listener.
|
||||
|
||||
-p <server_port>::
|
||||
/* [cli_short_p]
|
||||
\par `-p <server_port>`
|
||||
Set the server listening port.
|
||||
[cli_short_p] */
|
||||
|
||||
-b <local_address>::
|
||||
/* [cli_short_l]
|
||||
\par `-l <local_port>`
|
||||
Accepted for compatibility but ignored by this program; it does not configure a local listener.
|
||||
[cli_short_l] */
|
||||
|
||||
/* [cli_short_b]
|
||||
\par `-b <local_address>`
|
||||
Set the local address for outbound connections to destination servers.
|
||||
*/
|
||||
[cli_short_b] */
|
||||
|
||||
/* [cli-options]
|
||||
\snippet{doc} utils.c cli_short_f
|
||||
\snippet{doc} server.c cli_short_s
|
||||
\snippet{doc} server.c cli_short_p
|
||||
\snippet{doc} server.c cli_short_l
|
||||
\snippet{doc} utils.c cli_short_k
|
||||
\snippet{doc} utils.c cli_short_t
|
||||
\snippet{doc} utils.c cli_short_m
|
||||
\snippet{doc} server.c cli_short_b
|
||||
\snippet{doc} utils.c cli_short_c
|
||||
\snippet{doc} utils.c cli_short_i
|
||||
\snippet{doc} utils.c cli_short_d
|
||||
\snippet{doc} utils.c cli_short_a
|
||||
\snippet{doc} utils.c cli_short_n
|
||||
\snippet{doc} utils.c cli_short_h
|
||||
\snippet{doc} utils.c cli_short_u
|
||||
\snippet{doc} utils.c cli_short_U
|
||||
\snippet{doc} utils.c cli_short_v
|
||||
\snippet{doc} utils.c cli_short_6
|
||||
\snippet{doc} utils.c cli_short_A
|
||||
\snippet{doc} utils.c cli_long_fast_open
|
||||
\snippet{doc} utils.c cli_long_reuse_port
|
||||
\snippet{doc} utils.c cli_long_tcp_incoming_sndbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_incoming_rcvbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_outgoing_sndbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_outgoing_rcvbuf
|
||||
\snippet{doc} utils.c cli_long_no_delay
|
||||
\snippet{doc} utils.c cli_long_acl
|
||||
\snippet{doc} utils.c cli_long_manager_address
|
||||
\snippet{doc} utils.c cli_long_mtu
|
||||
\snippet{doc} utils.c cli_long_help
|
||||
\snippet{doc} utils.c cli_long_plugin
|
||||
\snippet{doc} utils.c cli_long_plugin_opts
|
||||
\snippet{doc} utils.c cli_long_password
|
||||
\snippet{doc} utils.c cli_long_key
|
||||
\snippet{doc} utils.c cli_long_mptcp
|
||||
\snippet{doc} utils.c cli_long_nftables_sets
|
||||
[cli-options] */
|
||||
static struct option long_options[] = {
|
||||
{ "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN },
|
||||
{ "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT },
|
||||
|
||||
+94
-46
@@ -168,52 +168,100 @@ EOF
|
||||
return $?
|
||||
}
|
||||
|
||||
# CLI_DOC
|
||||
# -s <server_ip>::
|
||||
# IP address of shadowsocks remote server
|
||||
#
|
||||
# -l <local_port>::
|
||||
# Port number of shadowsocks local server
|
||||
#
|
||||
# -S <server_ip>::
|
||||
# IP address of shadowsocks remote UDP server
|
||||
#
|
||||
# -L <local_port>::
|
||||
# Port number of shadowsocks local UDP server
|
||||
#
|
||||
# -i <ip_list_file>::
|
||||
# a file whose content is bypassed ip list
|
||||
#
|
||||
# -a <lan_ips>::
|
||||
# LAN IP of access control, need a prefix to define access control mode
|
||||
#
|
||||
# -b <wan_ips>::
|
||||
# WAN IP of will be bypassed
|
||||
#
|
||||
# -w <wan_ips>::
|
||||
# WAN IP of will be forwarded
|
||||
#
|
||||
# -e <extra_options>::
|
||||
# Extra options for iptables
|
||||
#
|
||||
# -o::
|
||||
# Apply the rules to the OUTPUT chain
|
||||
#
|
||||
# -u::
|
||||
# Enable udprelay mode, TPROXY is required
|
||||
#
|
||||
# -U::
|
||||
# Enable udprelay mode, using different IP and ports for TCP and UDP
|
||||
#
|
||||
# -f::
|
||||
# Flush the rules
|
||||
#
|
||||
# -h::
|
||||
# Show this help message and exit
|
||||
#
|
||||
# -I <interface>::
|
||||
# Set the LAN interface for NAT rules. The default is eth0.
|
||||
# END_CLI_DOC
|
||||
: <<'DOXYGEN_CLI_DOCS'
|
||||
// [cli_short_s]
|
||||
\par `-s <server_ip>`
|
||||
IP address of shadowsocks remote server
|
||||
[cli_short_s]
|
||||
|
||||
// [cli_short_l]
|
||||
\par `-l <local_port>`
|
||||
Port number of shadowsocks local server
|
||||
[cli_short_l]
|
||||
|
||||
// [cli_short_S]
|
||||
\par `-S <server_ip>`
|
||||
IP address of shadowsocks remote UDP server
|
||||
[cli_short_S]
|
||||
|
||||
// [cli_short_L]
|
||||
\par `-L <local_port>`
|
||||
Port number of shadowsocks local UDP server
|
||||
[cli_short_L]
|
||||
|
||||
// [cli_short_i]
|
||||
\par `-i <ip_list_file>`
|
||||
a file whose content is bypassed ip list
|
||||
[cli_short_i]
|
||||
|
||||
// [cli_short_I]
|
||||
\par `-I <interface>`
|
||||
Set the LAN interface for NAT rules. The default is eth0.
|
||||
[cli_short_I]
|
||||
|
||||
// [cli_short_e]
|
||||
\par `-e <extra_options>`
|
||||
Extra options for iptables
|
||||
[cli_short_e]
|
||||
|
||||
// [cli_short_a]
|
||||
\par `-a <lan_ips>`
|
||||
LAN IP of access control, need a prefix to define access control mode
|
||||
[cli_short_a]
|
||||
|
||||
// [cli_short_b]
|
||||
\par `-b <wan_ips>`
|
||||
WAN IP of will be bypassed
|
||||
[cli_short_b]
|
||||
|
||||
// [cli_short_w]
|
||||
\par `-w <wan_ips>`
|
||||
WAN IP of will be forwarded
|
||||
[cli_short_w]
|
||||
|
||||
// [cli_short_o]
|
||||
\par `-o`
|
||||
Apply the rules to the OUTPUT chain
|
||||
[cli_short_o]
|
||||
|
||||
// [cli_short_u]
|
||||
\par `-u`
|
||||
Enable udprelay mode, TPROXY is required
|
||||
[cli_short_u]
|
||||
|
||||
// [cli_short_U]
|
||||
\par `-U`
|
||||
Enable udprelay mode, using different IP and ports for TCP and UDP
|
||||
[cli_short_U]
|
||||
|
||||
// [cli_short_f]
|
||||
\par `-f`
|
||||
Flush the rules
|
||||
[cli_short_f]
|
||||
|
||||
// [cli_short_h]
|
||||
\par `-h`
|
||||
Show this help message and exit
|
||||
[cli_short_h]
|
||||
|
||||
// [cli-options]
|
||||
\snippet{doc} ss-nat cli_short_s
|
||||
\snippet{doc} ss-nat cli_short_l
|
||||
\snippet{doc} ss-nat cli_short_S
|
||||
\snippet{doc} ss-nat cli_short_L
|
||||
\snippet{doc} ss-nat cli_short_i
|
||||
\snippet{doc} ss-nat cli_short_I
|
||||
\snippet{doc} ss-nat cli_short_e
|
||||
\snippet{doc} ss-nat cli_short_a
|
||||
\snippet{doc} ss-nat cli_short_b
|
||||
\snippet{doc} ss-nat cli_short_w
|
||||
\snippet{doc} ss-nat cli_short_o
|
||||
\snippet{doc} ss-nat cli_short_u
|
||||
\snippet{doc} ss-nat cli_short_U
|
||||
\snippet{doc} ss-nat cli_short_f
|
||||
\snippet{doc} ss-nat cli_short_h
|
||||
[cli-options]
|
||||
DOXYGEN_CLI_DOCS
|
||||
while getopts ":s:l:S:L:i:I:e:a:b:w:ouUfh" arg; do
|
||||
case "$arg" in
|
||||
s)
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
#define CHACHA20IETF 20
|
||||
|
||||
const char *supported_stream_ciphers[STREAM_CIPHER_NUM] = {
|
||||
// [cli-stream-ciphers]
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5",
|
||||
@@ -117,6 +118,7 @@ const char *supported_stream_ciphers[STREAM_CIPHER_NUM] = {
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
// [cli-stream-ciphers]
|
||||
};
|
||||
|
||||
static const char *supported_stream_ciphers_mbedtls[STREAM_CIPHER_NUM] = {
|
||||
|
||||
@@ -957,6 +957,42 @@ main(int argc, char **argv)
|
||||
|
||||
memset(remote_addr, 0, sizeof(ss_addr_t) * MAX_REMOTE_NUM);
|
||||
|
||||
/* [cli-options]
|
||||
\snippet{doc} utils.c cli_short_f
|
||||
\snippet{doc} utils.c cli_short_s
|
||||
\snippet{doc} utils.c cli_short_p
|
||||
\snippet{doc} utils.c cli_short_l
|
||||
\snippet{doc} utils.c cli_short_k
|
||||
\snippet{doc} utils.c cli_short_t
|
||||
\snippet{doc} utils.c cli_short_m
|
||||
\snippet{doc} utils.c cli_short_i
|
||||
\snippet{doc} utils.c cli_short_c
|
||||
\snippet{doc} utils.c cli_short_b
|
||||
\snippet{doc} utils.c cli_short_L
|
||||
\snippet{doc} utils.c cli_short_a
|
||||
\snippet{doc} utils.c cli_short_n
|
||||
\snippet{doc} utils.c cli_short_h
|
||||
\snippet{doc} utils.c cli_short_u
|
||||
\snippet{doc} utils.c cli_short_U
|
||||
\snippet{doc} utils.c cli_short_v
|
||||
\snippet{doc} utils.c cli_short_V
|
||||
\snippet{doc} utils.c cli_short_6
|
||||
\snippet{doc} utils.c cli_short_A
|
||||
\snippet{doc} utils.c cli_long_fast_open
|
||||
\snippet{doc} utils.c cli_long_mtu
|
||||
\snippet{doc} utils.c cli_long_no_delay
|
||||
\snippet{doc} utils.c cli_long_mptcp
|
||||
\snippet{doc} utils.c cli_long_plugin
|
||||
\snippet{doc} utils.c cli_long_plugin_opts
|
||||
\snippet{doc} utils.c cli_long_reuse_port
|
||||
\snippet{doc} utils.c cli_long_tcp_incoming_sndbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_incoming_rcvbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_outgoing_sndbuf
|
||||
\snippet{doc} utils.c cli_long_tcp_outgoing_rcvbuf
|
||||
\snippet{doc} utils.c cli_long_password
|
||||
\snippet{doc} utils.c cli_long_key
|
||||
\snippet{doc} utils.c cli_long_help
|
||||
[cli-options] */
|
||||
static struct option long_options[] = {
|
||||
{ "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN },
|
||||
{ "mtu", required_argument, NULL, GETOPT_VAL_MTU },
|
||||
|
||||
+146
-59
@@ -317,161 +317,248 @@ ss_is_ipv6addr(const char *addr)
|
||||
return strcmp(addr, ":") > 0;
|
||||
}
|
||||
|
||||
/* CLI_DOC
|
||||
-s <server_host>::
|
||||
/* [cli_short_s]
|
||||
\par `-s <server_host>`
|
||||
Set the server's hostname or IP.
|
||||
[cli_short_s] */
|
||||
|
||||
-p <server_port>::
|
||||
/* [cli_short_p]
|
||||
\par `-p <server_port>`
|
||||
Set the server's port number.
|
||||
[cli_short_p] */
|
||||
|
||||
-l <local_port>::
|
||||
/* [cli_short_l]
|
||||
\par `-l <local_port>`
|
||||
Set the local port number.
|
||||
[cli_short_l] */
|
||||
|
||||
-k <password>::
|
||||
/* [cli_short_k]
|
||||
\par `-k <password>`
|
||||
Set the password. The server and the client should use the same password.
|
||||
[cli_short_k] */
|
||||
|
||||
--password <password>::
|
||||
/* [cli_long_password]
|
||||
\par `--password <password>`
|
||||
Set the password. The server and the client should use the same password.
|
||||
[cli_long_password] */
|
||||
|
||||
--key <key_in_base64>::
|
||||
/* [cli_long_key]
|
||||
\par `--key <key_in_base64>`
|
||||
Set the key directly. The key should be encoded with URL-safe Base64.
|
||||
[cli_long_key] */
|
||||
|
||||
--server-url <ss_url>::
|
||||
/* [cli_long_server_url]
|
||||
\par `--server-url <ss_url>`
|
||||
Take the server address, port, cipher, password and any SIP003 plugin
|
||||
from a single 'ss://' URL, as produced by most clients and by
|
||||
from a single `ss://` URL, as produced by most clients and by
|
||||
*shadowsocks-rust*'s `ssurl`. Both the SIP002 form
|
||||
('ss://base64(method:password)@host:port/?plugin=...#tag') and the older
|
||||
'ss://base64(method:password@host:port)' form are accepted. Options given
|
||||
(`ss://base64(method:password)@host:port/?plugin=...#tag`) and the older
|
||||
`ss://base64(method:password@host:port)` form are accepted. Options given
|
||||
later on the command line override the values taken from the URL.
|
||||
[cli_long_server_url] */
|
||||
|
||||
/* [cli_short_m]
|
||||
\par `-m <encrypt_method>`
|
||||
Set the cipher. The default is `chacha20-ietf-poly1305`.
|
||||
|
||||
-m <encrypt_method>::
|
||||
Set the cipher. The default is 'chacha20-ietf-poly1305'.
|
||||
+
|
||||
AEAD cipher names from the source (availability depends on the build):
|
||||
{cli-aead-ciphers}.
|
||||
+
|
||||
\snippet aead.c cli-aead-ciphers
|
||||
|
||||
Legacy stream cipher names recognized by the source (disabled in minimal builds;
|
||||
some require backend support): {cli-stream-ciphers}.
|
||||
+
|
||||
The '2022-blake3-*' ciphers implement Shadowsocks 2022 (SIP022). They require
|
||||
some require backend support):
|
||||
\snippet stream.c cli-stream-ciphers
|
||||
|
||||
The `2022-blake3-*` ciphers implement Shadowsocks 2022 (SIP022). They require
|
||||
a base64-encoded pre-shared key supplied with *-k*: 16 bytes for
|
||||
2022-blake3-aes-128-gcm and 32 bytes for the other 2022 ciphers.
|
||||
Generate a 32-byte key with `openssl rand -base64 32`.
|
||||
Passwords are not stretched into keys for these ciphers.
|
||||
[cli_short_m] */
|
||||
|
||||
-a <user_name>::
|
||||
/* [cli_short_a]
|
||||
\par `-a <user_name>`
|
||||
Run as a specific user.
|
||||
[cli_short_a] */
|
||||
|
||||
-f <pid_file>::
|
||||
/* [cli_short_f]
|
||||
\par `-f <pid_file>`
|
||||
Start shadowsocks as a daemon with specific pid file.
|
||||
[cli_short_f] */
|
||||
|
||||
-t <timeout>::
|
||||
/* [cli_short_t]
|
||||
\par `-t <timeout>`
|
||||
Set the socket timeout in seconds. The default value is 60.
|
||||
[cli_short_t] */
|
||||
|
||||
-c <config_file>::
|
||||
/* [cli_short_c]
|
||||
\par `-c <config_file>`
|
||||
Use a configuration file.
|
||||
+
|
||||
Refer to `shadowsocks-c`(8) 'CONFIG FILE' section for more details.
|
||||
|
||||
-n <number>::
|
||||
Refer to `shadowsocks-c`(8) `CONFIG FILE` section for more details.
|
||||
[cli_short_c] */
|
||||
|
||||
/* [cli_short_n]
|
||||
\par `-n <number>`
|
||||
Specify the maximum number of open files. Requires a platform with setrlimit support.
|
||||
[cli_short_n] */
|
||||
|
||||
-i <interface>::
|
||||
/* [cli_short_i]
|
||||
\par `-i <interface>`
|
||||
Send outbound traffic through the specified network interface where supported by the platform.
|
||||
[cli_short_i] */
|
||||
|
||||
-b <local_address>::
|
||||
/* [cli_short_b]
|
||||
\par `-b <local_address>`
|
||||
Specify the local address to use while this client is making outbound
|
||||
connections to the server.
|
||||
[cli_short_b] */
|
||||
|
||||
-u::
|
||||
/* [cli_short_u]
|
||||
\par `-u`
|
||||
Enable UDP relay.
|
||||
[cli_short_u] */
|
||||
|
||||
-U::
|
||||
/* [cli_short_U]
|
||||
\par `-U`
|
||||
Enable UDP relay and disable TCP relay.
|
||||
[cli_short_U] */
|
||||
|
||||
-6::
|
||||
/* [cli_short_6]
|
||||
\par `-6`
|
||||
Resolve hostname to IPv6 address first.
|
||||
[cli_short_6] */
|
||||
|
||||
--fast-open::
|
||||
/* [cli_long_fast_open]
|
||||
\par `--fast-open`
|
||||
Enable TCP Fast Open where supported by the operating system.
|
||||
[cli_long_fast_open] */
|
||||
|
||||
--reuse-port::
|
||||
/* [cli_long_reuse_port]
|
||||
\par `--reuse-port`
|
||||
Enable port reuse where supported by the operating system.
|
||||
[cli_long_reuse_port] */
|
||||
|
||||
--acl <acl_config>::
|
||||
/* [cli_long_acl]
|
||||
\par `--acl <acl_config>`
|
||||
Enable ACL (Access Control List) and specify config file.
|
||||
[cli_long_acl] */
|
||||
|
||||
--mtu <MTU>::
|
||||
/* [cli_long_mtu]
|
||||
\par `--mtu <MTU>`
|
||||
Specify the MTU of your network interface.
|
||||
[cli_long_mtu] */
|
||||
|
||||
--mptcp::
|
||||
/* [cli_long_mptcp]
|
||||
\par `--mptcp`
|
||||
Enable Multipath TCP.
|
||||
+
|
||||
|
||||
Only available with MPTCP enabled Linux kernel.
|
||||
[cli_long_mptcp] */
|
||||
|
||||
--no-delay::
|
||||
/* [cli_long_no_delay]
|
||||
\par `--no-delay`
|
||||
Enable TCP_NODELAY.
|
||||
[cli_long_no_delay] */
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
/* [cli_long_tcp_incoming_sndbuf]
|
||||
\par `--tcp-incoming-sndbuf <size>`
|
||||
Set TCP send buffer size for incoming connections.
|
||||
[cli_long_tcp_incoming_sndbuf] */
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
/* [cli_long_tcp_incoming_rcvbuf]
|
||||
\par `--tcp-incoming-rcvbuf <size>`
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
[cli_long_tcp_incoming_rcvbuf] */
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
/* [cli_long_tcp_outgoing_sndbuf]
|
||||
\par `--tcp-outgoing-sndbuf <size>`
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
[cli_long_tcp_outgoing_sndbuf] */
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
/* [cli_long_tcp_outgoing_rcvbuf]
|
||||
\par `--tcp-outgoing-rcvbuf <size>`
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
[cli_long_tcp_outgoing_rcvbuf] */
|
||||
|
||||
--plugin <plugin_name>::
|
||||
/* [cli_long_plugin]
|
||||
\par `--plugin <plugin_name>`
|
||||
Enable SIP003 plugin. (Experimental)
|
||||
[cli_long_plugin] */
|
||||
|
||||
--plugin-opts <plugin_options>::
|
||||
/* [cli_long_plugin_opts]
|
||||
\par `--plugin-opts <plugin_options>`
|
||||
Set SIP003 plugin options. (Experimental)
|
||||
[cli_long_plugin_opts] */
|
||||
|
||||
-v::
|
||||
/* [cli_short_v]
|
||||
\par `-v`
|
||||
Enable verbose mode.
|
||||
[cli_short_v] */
|
||||
|
||||
-h::
|
||||
/* [cli_short_h]
|
||||
\par `-h`
|
||||
Print help message.
|
||||
[cli_short_h] */
|
||||
|
||||
--help::
|
||||
/* [cli_long_help]
|
||||
\par `--help`
|
||||
Print help message.
|
||||
[cli_long_help] */
|
||||
|
||||
-A::
|
||||
/* [cli_short_A]
|
||||
\par `-A`
|
||||
Deprecated one-time authentication option. Exits with an error; use AEAD ciphers instead.
|
||||
[cli_short_A] */
|
||||
|
||||
-S <path>::
|
||||
/* [cli_short_S]
|
||||
\par `-S <path>`
|
||||
Android only: UNIX socket path for traffic statistics.
|
||||
[cli_short_S] */
|
||||
|
||||
-V::
|
||||
/* [cli_short_V]
|
||||
\par `-V`
|
||||
Android only: enable VPN socket protection.
|
||||
[cli_short_V] */
|
||||
|
||||
-L <addr:port>::
|
||||
/* [cli_short_L]
|
||||
\par `-L <addr:port>`
|
||||
Destination server address and port for local port forwarding.
|
||||
[cli_short_L] */
|
||||
|
||||
-T::
|
||||
/* [cli_short_T]
|
||||
\par `-T`
|
||||
Use TPROXY instead of REDIRECT for TCP traffic. Requires Linux TPROXY support.
|
||||
[cli_short_T] */
|
||||
|
||||
-d <addr>::
|
||||
/* [cli_short_d]
|
||||
\par `-d <addr>`
|
||||
Configure name servers for the internal c-ares DNS resolver. By default it uses the system resolver configuration.
|
||||
[cli_short_d] */
|
||||
|
||||
-D <path>::
|
||||
/* [cli_short_D]
|
||||
\par `-D <path>`
|
||||
Set the working directory of ss-manager.
|
||||
[cli_short_D] */
|
||||
|
||||
--workdir <path>::
|
||||
/* [cli_long_workdir]
|
||||
\par `--workdir <path>`
|
||||
Set the working directory of ss-manager (alias for *-D*).
|
||||
[cli_long_workdir] */
|
||||
|
||||
--manager-address <address>::
|
||||
/* [cli_long_manager_address]
|
||||
\par `--manager-address <address>`
|
||||
Set the manager control address: a UNIX domain socket path or an IP address and port.
|
||||
[cli_long_manager_address] */
|
||||
|
||||
--executable <path>::
|
||||
/* [cli_long_executable]
|
||||
\par `--executable <path>`
|
||||
Set the executable path of ss-server used by ss-manager.
|
||||
[cli_long_executable] */
|
||||
|
||||
--nftables-sets <sets>::
|
||||
/* [cli_long_nftables_sets]
|
||||
\par `--nftables-sets <sets>`
|
||||
Linux builds with USE_NFTABLES only: add malicious IP addresses to nftables sets. Format: `[<table1>:]<set1>[,[<table2>:]<set2>...]`.
|
||||
*/
|
||||
[cli_long_nftables_sets] */
|
||||
|
||||
void
|
||||
usage()
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
"""Regression checks for drift between getopt and native Doxygen snippets."""
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SPEC = importlib.util.spec_from_file_location('check_cli_docs', ROOT / 'scripts/check_cli_docs.py')
|
||||
DOCS = importlib.util.module_from_spec(SPEC)
|
||||
SPEC.loader.exec_module(DOCS)
|
||||
|
||||
|
||||
class CliDocsTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.root = Path(self.temp.name)
|
||||
(self.root / 'src').mkdir()
|
||||
(self.root / 'doc').mkdir()
|
||||
for name in ('local.c', 'server.c', 'tunnel.c', 'redir.c', 'manager.c', 'utils.c', 'ss-nat'):
|
||||
shutil.copyfile(ROOT / 'src' / name, self.root / 'src' / name)
|
||||
for path in (ROOT / 'doc').glob('*.md'):
|
||||
shutil.copyfile(path, self.root / 'doc' / path.name)
|
||||
|
||||
def change(self, filename, old, new):
|
||||
path = self.root / filename
|
||||
source = path.read_text(encoding='utf-8')
|
||||
self.assertIn(old, source)
|
||||
path.write_text(source.replace(old, new), encoding='utf-8')
|
||||
|
||||
def test_current_documentation_matches_all_variants(self):
|
||||
DOCS.check(self.root)
|
||||
sources = {p.name: p.read_text(encoding='utf-8') for p in (self.root / 'src').iterdir()}
|
||||
local = DOCS.documented_options('local.c', sources)
|
||||
self.assertIn('-S', local)
|
||||
self.assertIn('-V', local)
|
||||
self.assertIn('--nftables-sets', DOCS.documented_options('server.c', sources))
|
||||
self.assertIn('-I', DOCS.documented_options('ss-nat', sources))
|
||||
self.assertNotIn('-p', DOCS.documented_options('manager.c', sources))
|
||||
|
||||
def test_new_option_requires_documentation(self):
|
||||
self.change('src/local.c', '"reuse-port",', '"new-option",')
|
||||
with self.assertRaisesRegex(ValueError, 'missing documentation.*new-option'):
|
||||
DOCS.check(self.root)
|
||||
|
||||
def test_argument_arity_is_checked(self):
|
||||
self.change('src/local.c', '"reuse-port", no_argument',
|
||||
'"reuse-port", required_argument')
|
||||
with self.assertRaisesRegex(ValueError, 'argument mismatch.*reuse-port'):
|
||||
DOCS.check(self.root)
|
||||
|
||||
def test_unknown_parser_syntax_fails_closed(self):
|
||||
self.change('src/local.c', '"reuse-port", no_argument',
|
||||
'"reuse-port", optional_argument')
|
||||
with self.assertRaisesRegex(ValueError, 'Unsupported long_options'):
|
||||
DOCS.check(self.root)
|
||||
|
||||
def test_nonliteral_short_options_fail_closed(self):
|
||||
self.change('src/local.c', '"f:s:p:l:k:t:m:i:c:b:a:n:huUv6A"', 'SHORT_OPTIONS')
|
||||
with self.assertRaisesRegex(ValueError, 'literal getopt_long'):
|
||||
DOCS.check(self.root)
|
||||
|
||||
def test_shell_options_require_documentation(self):
|
||||
self.change('src/ss-nat', ':s:l:S:L:i:I:e:a:b:w:ouUfh', ':s:l:S:L:i:I:e:a:b:w:ouUfhz')
|
||||
with self.assertRaisesRegex(ValueError, 'missing documentation.*-z'):
|
||||
DOCS.check(self.root)
|
||||
|
||||
def test_missing_snippet_is_rejected(self):
|
||||
self.change('src/local.c', 'utils.c cli_long_reuse_port', 'utils.c missing_snippet')
|
||||
with self.assertRaisesRegex(ValueError, 'Missing snippet'):
|
||||
DOCS.check(self.root)
|
||||
|
||||
def test_duplicate_option_is_rejected(self):
|
||||
self.change('src/local.c', 'utils.c cli_long_reuse_port', 'utils.c cli_short_f')
|
||||
with self.assertRaisesRegex(ValueError, 'Duplicate documented option'):
|
||||
DOCS.check(self.root)
|
||||
|
||||
def test_manual_must_include_parser_options(self):
|
||||
self.change('doc/ss-local.md', 'local.c cli-options', 'local.c missing-options')
|
||||
with self.assertRaisesRegex(ValueError, 'manual must include'):
|
||||
DOCS.check(self.root)
|
||||
|
||||
def test_missing_rendered_flag_is_rejected(self):
|
||||
output = self.root / 'rendered'
|
||||
(output / 'man').mkdir(parents=True)
|
||||
(output / 'man/ss-local.1').write_text('.TH ss-local 1\n', encoding='utf-8')
|
||||
with self.assertRaisesRegex(ValueError, 'missing rendered flag'):
|
||||
DOCS.check(self.root, output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,107 +0,0 @@
|
||||
"""Regression checks for parser/documentation drift and cross-platform extraction."""
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SPEC = importlib.util.spec_from_file_location('gen_cli_docs', ROOT / 'scripts/gen_cli_docs.py')
|
||||
GEN = importlib.util.module_from_spec(SPEC)
|
||||
SPEC.loader.exec_module(GEN)
|
||||
|
||||
|
||||
class CliDocsTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.root = Path(self.temp.name)
|
||||
for directory in ('src', 'doc'):
|
||||
(self.root / directory).mkdir()
|
||||
for name in ('utils.c', 'local.c', 'server.c', 'tunnel.c', 'redir.c',
|
||||
'manager.c', 'ss-nat', 'aead.c', 'stream.c'):
|
||||
shutil.copyfile(ROOT / 'src' / name, self.root / 'src' / name)
|
||||
for path in (ROOT / 'doc').glob('*.asciidoc'):
|
||||
shutil.copyfile(path, self.root / 'doc' / path.name)
|
||||
|
||||
def change(self, filename, old, new):
|
||||
path = self.root / filename
|
||||
source = path.read_text()
|
||||
self.assertIn(old, source)
|
||||
path.write_text(source.replace(old, new))
|
||||
|
||||
def test_checked_in_pages_and_idempotence(self):
|
||||
generated = GEN.generate(self.root)
|
||||
self.assertEqual(len(generated), 7)
|
||||
for name, text in generated.items():
|
||||
self.assertEqual(text, (self.root / 'doc' / name).read_text())
|
||||
(self.root / 'doc' / name).write_text(text)
|
||||
self.assertEqual(generated, GEN.generate(self.root))
|
||||
|
||||
def test_platform_options_aliases_and_program_specific_flags(self):
|
||||
pages = GEN.generate(self.root)
|
||||
self.assertIn('-S <path>::\nAndroid only', pages['ss-local.asciidoc'])
|
||||
self.assertIn('-V::\nAndroid only', pages['ss-tunnel.asciidoc'])
|
||||
self.assertIn('--nftables-sets <sets>::\nLinux builds', pages['ss-server.asciidoc'])
|
||||
self.assertIn('-I <interface>::', pages['ss-nat.asciidoc'])
|
||||
self.assertIn('--password <password>::', pages['ss-tunnel.asciidoc'])
|
||||
self.assertIn('--workdir <path>::', pages['ss-manager.asciidoc'])
|
||||
self.assertNotIn('[-p ', pages['ss-manager.asciidoc'])
|
||||
self.assertNotIn('--tcp-incoming-sndbuf', pages['ss-manager.asciidoc'])
|
||||
self.assertIn('-A::\nDeprecated', pages['ss-manager.asciidoc'])
|
||||
|
||||
def test_new_option_requires_description(self):
|
||||
self.change('src/local.c', '"reuse-port",', '"new-option",')
|
||||
with self.assertRaisesRegex(ValueError, 'missing CLI_DOC.*new-option'):
|
||||
GEN.generate(self.root)
|
||||
|
||||
def test_argument_arity_is_checked(self):
|
||||
self.change('src/local.c', '"reuse-port", no_argument',
|
||||
'"reuse-port", required_argument')
|
||||
with self.assertRaisesRegex(ValueError, 'argument mismatch.*reuse-port'):
|
||||
GEN.generate(self.root)
|
||||
|
||||
def test_unknown_table_syntax_fails_closed(self):
|
||||
self.change('src/local.c', '"reuse-port", no_argument',
|
||||
'"reuse-port", optional_argument')
|
||||
with self.assertRaisesRegex(ValueError, 'Unsupported long_options'):
|
||||
GEN.generate(self.root)
|
||||
|
||||
def test_nonliteral_short_options_fail_closed(self):
|
||||
self.change('src/local.c', '"f:s:p:l:k:t:m:i:c:b:a:n:huUv6A"', 'SHORT_OPTIONS')
|
||||
with self.assertRaisesRegex(ValueError, 'literal getopt_long'):
|
||||
GEN.generate(self.root)
|
||||
|
||||
def test_shell_arity_and_new_flags(self):
|
||||
self.change('src/ss-nat', ':s:l:S:L:i:I:e:a:b:w:ouUfh', ':s:l:S:L:i:I:e:a:b:w:ouUfhz')
|
||||
with self.assertRaisesRegex(ValueError, 'missing CLI_DOC.*-z'):
|
||||
GEN.generate(self.root)
|
||||
|
||||
def test_stale_override_is_rejected(self):
|
||||
self.change('src/server.c', '-p <server_port>::', '--unused <server_port>::')
|
||||
with self.assertRaisesRegex(ValueError, 'stale CLI_DOC'):
|
||||
GEN.generate(self.root)
|
||||
|
||||
def test_cipher_table_changes_propagate(self):
|
||||
self.change('src/aead.c', '"aes-128-gcm",', '"new-aead-cipher",')
|
||||
self.assertIn('new-aead-cipher', GEN.generate(self.root)['ss-local.asciidoc'])
|
||||
|
||||
def test_check_detects_stale_docs_and_build_output_preserves_source(self):
|
||||
self.change('doc/ss-local.asciidoc', '--mtu <MTU>::', '--mtu <WRONG>::')
|
||||
command = [sys.executable, str(ROOT / 'scripts/gen_cli_docs.py'),
|
||||
'--root', str(self.root)]
|
||||
checked = subprocess.run(command + ['--check'], capture_output=True, text=True)
|
||||
self.assertNotEqual(checked.returncode, 0)
|
||||
self.assertIn('Stale CLI docs', checked.stderr)
|
||||
output = self.root / 'generated'
|
||||
subprocess.run(command + ['--output-dir', str(output)], check=True)
|
||||
self.assertIn('--mtu <MTU>::', (output / 'ss-local.asciidoc').read_text())
|
||||
self.assertIn('--mtu <WRONG>::', (self.root / 'doc/ss-local.asciidoc').read_text())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user