Merge pull request #3059 from shadowsocks/feature/publish-doxygen-pages

Publish native Doxygen documentation with GitHub Pages
This commit is contained in:
Max Lv authored and GitHub committed 2026-09-12 15:01:38 +08:00
commit 36a5cc6b8d
41 files changed
+1478 -1939

No files matched your search

+1 -1
View File
@@ -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
+63
View File
@@ -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
+3 -20
View File
@@ -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
View File
@@ -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.
+8 -6
View File
@@ -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
View File
@@ -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
+2 -3
View File
@@ -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
View File
@@ -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")
+26
View File
@@ -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
-36
View File
@@ -1,36 +0,0 @@
[tags]
bracket-emphasis={1?[{1}]}<emphasis>&lt;|&gt;</emphasis>
[quotes]
&lt;|&gt;=#bracket-emphasis
[attributes]
asterisk=&#42;
plus=&#43;
caret=&#94;
startsb=&#91;
endsb=&#93;
backslash=&#92;
tilde=&#126;
apostrophe=&#39;
backtick=&#96;
litdd=&#45;&#45;
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[]
+16
View File
@@ -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.
-35
View File
@@ -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&#10;</xsl:text>
<xsl:apply-templates/>
<xsl:text>&#10;</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&#10;</xsl:text>
</xsl:template>
</xsl:stylesheet>
-17
View File
@@ -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>
-13
View File
@@ -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>
-172
View File
@@ -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
+177
View File
@@ -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
-188
View File
@@ -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
+43
View File
@@ -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
-192
View File
@@ -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
+93
View File
@@ -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
-103
View File
@@ -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
+49
View File
@@ -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
-203
View File
@@ -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
+77
View File
@@ -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
-202
View File
@@ -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
+64
View File
@@ -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
-181
View File
@@ -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
+48
View File
@@ -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
+151
View File
@@ -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()
-194
View File
@@ -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())
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+2
View File
@@ -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] = {
+36
View File
@@ -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
View File
@@ -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()
+94
View File
@@ -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()
-107
View File
@@ -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()