Repository: shadowsocks/shadowsocks-libev Branch: master Commit: 8ad3036f29c7 Files: 187 Total size: 1.4 MB Directory structure: gitextract_w3iy52_5/ ├── .copr/ │ └── Makefile ├── .dockerignore ├── .github/ │ ├── FUNDING.yml │ ├── dependabot.yml │ ├── issue_template.md │ └── workflows/ │ └── build.yml ├── .gitignore ├── .gitmodules ├── .travis.yml ├── .uncrustify.cfg ├── AUTHORS ├── CLAUDE.md ├── CMakeLists.txt ├── COPYING ├── Changes ├── LICENSE ├── README.md ├── README_pt_BR.md ├── acl/ │ ├── chn.acl │ ├── gfwlist.acl │ ├── local.acl │ ├── server_block_chn.acl │ └── server_block_local.acl ├── cmake/ │ ├── FindCares.cmake │ ├── FindMbedTLS.cmake │ ├── FindPCRE2.cmake │ ├── FindSodium.cmake │ ├── config.h.cmake │ ├── configure.cmake │ └── shadowsocks-libev.pc.cmake ├── completions/ │ ├── bash/ │ │ ├── ss-local │ │ ├── ss-manager │ │ ├── ss-redir │ │ ├── ss-server │ │ └── ss-tunnel │ └── zsh/ │ ├── _ss-local │ ├── _ss-manager │ ├── _ss-redir │ ├── _ss-server │ └── _ss-tunnel ├── debian/ │ ├── .gitignore │ ├── README.Debian │ ├── changelog │ ├── compat │ ├── config.json │ ├── control │ ├── copyright │ ├── copyright.original │ ├── libshadowsocks-libev-dev.install │ ├── libshadowsocks-libev2.install │ ├── rules │ ├── shadowsocks-libev-local@.service │ ├── shadowsocks-libev-redir@.service │ ├── shadowsocks-libev-server@.service │ ├── shadowsocks-libev-tunnel@.service │ ├── shadowsocks-libev.NEWS │ ├── shadowsocks-libev.default │ ├── shadowsocks-libev.doc-base │ ├── shadowsocks-libev.docs │ ├── shadowsocks-libev.init │ ├── shadowsocks-libev.install │ ├── shadowsocks-libev.lintian-overrides │ ├── shadowsocks-libev.postinst │ ├── shadowsocks-libev.postrm │ ├── shadowsocks-libev.service │ ├── source/ │ │ └── format │ ├── tests/ │ │ └── control │ ├── upstream/ │ │ └── metadata │ └── watch ├── doc/ │ ├── CMakeLists.txt │ ├── asciidoc.conf │ ├── manpage-base.xsl │ ├── manpage-bold-literal.xsl │ ├── manpage-normal.xsl │ ├── shadowsocks-libev.asciidoc │ ├── ss-local.asciidoc │ ├── ss-manager.asciidoc │ ├── ss-nat.asciidoc │ ├── ss-redir.asciidoc │ ├── ss-server.asciidoc │ └── ss-tunnel.asciidoc ├── docker/ │ ├── alpine/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── docker-compose.yml │ │ └── entrypoint.sh │ └── mingw/ │ ├── Dockerfile │ ├── Makefile │ ├── apt.sh │ ├── build.sh │ ├── deps.sh │ ├── make.bat │ └── prepare.sh ├── rpm/ │ ├── SOURCES/ │ │ ├── etc/ │ │ │ └── init.d/ │ │ │ └── shadowsocks-libev │ │ └── systemd/ │ │ ├── shadowsocks-libev-local.service │ │ ├── shadowsocks-libev-local@.service │ │ ├── shadowsocks-libev-redir@.service │ │ ├── shadowsocks-libev-server@.service │ │ ├── shadowsocks-libev-tunnel@.service │ │ ├── shadowsocks-libev.default │ │ └── shadowsocks-libev.service │ ├── SPECS/ │ │ └── shadowsocks-libev.spec.in │ └── genrpm.sh ├── scripts/ │ ├── build_deb.sh │ ├── chroot_build.sh │ ├── code-format.bat │ ├── code-format.sh │ ├── git_archive.sh │ ├── git_version.sh │ ├── iperf.sh │ └── ss-setup.sh ├── snap/ │ └── snapcraft.yaml ├── src/ │ ├── CMakeLists.txt │ ├── acl.c │ ├── acl.h │ ├── aead.c │ ├── aead.h │ ├── android.c │ ├── base64.c │ ├── base64.h │ ├── cache.c │ ├── cache.h │ ├── common.h │ ├── crypto.c │ ├── crypto.h │ ├── jconf.c │ ├── jconf.h │ ├── json.c │ ├── json.h │ ├── local.c │ ├── local.h │ ├── manager.c │ ├── manager.h │ ├── netutils.c │ ├── netutils.h │ ├── plugin.c │ ├── plugin.h │ ├── ppbloom.c │ ├── ppbloom.h │ ├── redir.c │ ├── redir.h │ ├── resolv.c │ ├── resolv.h │ ├── rule.c │ ├── rule.h │ ├── server.c │ ├── server.h │ ├── shadowsocks.h │ ├── socks5.h │ ├── ss-nat │ ├── stream.c │ ├── stream.h │ ├── tunnel.c │ ├── tunnel.h │ ├── udprelay.c │ ├── udprelay.h │ ├── uthash.h │ ├── utils.c │ ├── utils.h │ ├── winsock.c │ └── winsock.h └── tests/ ├── CMakeLists.txt ├── aes-ctr.json ├── aes-gcm.json ├── aes.json ├── chacha20-ietf-poly1305.json ├── chacha20-ietf.json ├── chacha20.json ├── qemu/ │ └── guest-init.sh ├── rc4-md5.json ├── redir.json ├── salsa20.json ├── stress_test.py ├── test.py ├── test.sh ├── test_base64.c ├── test_buffer.c ├── test_cache.c ├── test_crypto.c ├── test_deb_build.sh ├── test_jconf.c ├── test_json.c ├── test_netutils.c ├── test_ppbloom.c ├── test_redir_qemu.sh ├── test_rule.c ├── test_ss_setup.sh └── test_utils.c ================================================ FILE CONTENTS ================================================ ================================================ FILE: .copr/Makefile ================================================ .PHONY: deps srpm .DEFAULT_GOAL := srpm DOT_COPR := $(dir $(firstword $(MAKEFILE_LIST))) TOP_DIR := $(realpath $(DOT_COPR)/../) RPM_DIR := $(TOP_DIR)/rpm outdir ?= $(RPM_DIR)/SRPMS HAS_GIT := $(shell command -v git 2> /dev/null) ifndef HAS_GIT deps: dnf -y install git else deps: endif srpm: deps git config --global --add safe.directory $(TOP_DIR) git config --global --add safe.directory $(TOP_DIR)/libbloom git config --global --add safe.directory $(TOP_DIR)/libcork git config --global --add safe.directory $(TOP_DIR)/libipset $(RPM_DIR)/genrpm.sh -o $(outdir) ================================================ FILE: .dockerignore ================================================ # General .dockerignore .git .gitmodules .gitignore .github AUTHORS Changes COPYING INSTALL LICENSE README.md # Code formatting .uncrustify.cfg code-format.bat code-format.sh # CI & CD .travis.yml tests # OS-specific packaging, etc. debian scripts/build_deb.sh rpm completions ================================================ FILE: .github/FUNDING.yml ================================================ custom: ['https://crowdfunding.lfx.linuxfoundation.org/projects/shadowsocks'] ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" ================================================ FILE: .github/issue_template.md ================================================ Please answer these questions before submitting your issue. Thanks! (Please mention that if the issue you filed is solved, you may wish to close it by yourself. Thanks again.) (PS, you can remove 3 lines above, including this one, before post your issue.) ### What version of shadowsocks-libev are you using? ### What operating system are you using? ### What did you do? ### What did you expect to see? ### What did you see instead? ### What is your config in detail (with all sensitive info masked)? ================================================ FILE: .github/workflows/build.yml ================================================ name: build on: push: branches: [master] pull_request: branches: [master] jobs: build: strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Install dependencies (Linux) if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev - name: Install dependencies (macOS) if: runner.os == 'macOS' run: brew install mbedtls@3 libsodium libev c-ares pcre2 - name: Build run: | mkdir -p build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release -DWITH_STATIC=OFF make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu) - name: Unit tests run: | cd build ctest --output-on-failure - name: ss-setup TUI tests run: bash tests/test_ss_setup.sh - name: Stress test run: | python3 tests/stress_test.py --bin build/shared/bin/ --size 10 - name: ss-redir transparent proxy test (QEMU) if: runner.os == 'Linux' run: | sudo apt-get install -y qemu-system-x86 bash tests/test_redir_qemu.sh build/shared/bin/ timeout-minutes: 8 - name: Debian package build test if: runner.os == 'Linux' run: | sudo apt-get install -y --no-install-recommends \ build-essential debhelper dpkg-dev fakeroot asciidoc-base xmlto pkg-config bash tests/test_deb_build.sh timeout-minutes: 10 ================================================ FILE: .gitignore ================================================ # Ignore files generated by autoconf /Makefile.in /aclocal.m4 /auto/ /config.h.in /configure /doc/Makefile.in /m4/libtool.m4 /m4/ltoptions.m4 /m4/ltsugar.m4 /m4/ltversion.m4 /m4/lt~obsolete.m4 /src/Makefile.in /src/config.h # Ignore files generated by configure build/ .deps/ /Makefile src/Makefile libev/Makefile libudns/Makefile libcork/Makefile libipset/Makefile doc/Makefile autom4te.cache/ /config.h config.log config.status libtool pid src/ss-* !src/ss-nat stamp-h1 .libs .pc debian/shadowsocks-libev/ debian/patches/ debian/files debian/shadowsocks-libev.substvars debian/*.debhelper* .dirstamp shadowsocks-libev.pc debian/libshadowsocks-libev*.symbols libsodium/src/libsodium/include/sodium/version.h rpm/SPECS/shadowsocks-libev.spec rpm/SRPMS/ rpm/RPMS/ rpm/BUILD/ rpm/BUILDROOT/ *.rpm *.deb # Ignore per-project vim config .vimrc # Ignore garbage of OS X *.DS_Store # Ignore vim cache *.swp # Documentation files doc/*.1 doc/*.8 doc/*.gz doc/*.xml doc/*.html # Do not edit the following section # Edit Compile Debug Document Distribute *~ *.bak *.bin *.dll *.exe *-ISO*.bdf *-JIS*.bdf *-KOI8*.bdf *.kld *.ko *.ko.cmd *.lai *.l[oa] *.[oa] *.obj *.patch *.so *.pcf.gz *.pdb *.tar *.tar.bz2 *.tar.gz *.tgz *.snap # # Visual Studio Code .vscode/* .devcontainer/* # CMake objection obj-* ================================================ FILE: .gitmodules ================================================ [submodule "libcork"] path = libcork url = https://github.com/shadowsocks/libcork.git ignore = dirty [submodule "libipset"] path = libipset url = https://github.com/shadowsocks/ipset.git ignore = dirty [submodule "libbloom"] path = libbloom url = https://github.com/shadowsocks/libbloom.git ignore = dirty ================================================ FILE: .travis.yml ================================================ sudo: required language: c dist : trusty compiler: - clang - gcc os: - linux - osx env: global: - LIBSODIUM_VER=1.0.12 - MBEDTLS_VER=2.4.0 before_install: - | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then # All dependencies for macOS build. Some packages has been installed by travis so use reinstall. brew reinstall cmake xmlto c-ares libev mbedtls libsodium asciidoc >> /dev/null 2>&1; else wget https://github.com/jedisct1/libsodium/releases/download/$LIBSODIUM_VER/libsodium-$LIBSODIUM_VER.tar.gz; tar xvf libsodium-$LIBSODIUM_VER.tar.gz; pushd libsodium-$LIBSODIUM_VER; ./configure --prefix=/usr && make; sudo make install; popd; wget https://tls.mbed.org/download/mbedtls-$MBEDTLS_VER-gpl.tgz; tar xvf mbedtls-$MBEDTLS_VER-gpl.tgz; pushd mbedtls-$MBEDTLS_VER; make SHARED=1; sudo make install; popd; # Load cached docker images if [[ -d $HOME/docker ]]; then ls $HOME/docker/*.tar.gz | xargs -I {file} sh -c "zcat {file} | docker load"; fi fi addons: apt: sources: - george-edison55-precise-backports # cmake 3.2.3 / doxygen 1.8.3 packages: - cmake - libc-ares-dev - libev-dev - asciidoc - xmlto script: - git submodule update --init --recursive - mkdir -p build && cd build - cmake .. - make - ctest --output-on-failure branches: only: - master notifications: recipients: - max.c.lv@gmail.com email: on_success: change on_failure: always ================================================ FILE: .uncrustify.cfg ================================================ # # General options # # The type of line endings newlines = lf # auto/lf/crlf/cr # The original size of tabs in the input input_tab_size = 8 # number # The size of tabs in the output (only used if align_with_tabs=true) output_tab_size = 8 # number # The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn) string_escape_char = 92 # number # Alternate string escape char for Pawn. Only works right before the quote char. string_escape_char2 = 0 # number # # Indenting # # The number of columns to indent per level. # Usually 2, 3, 4, or 8. indent_columns = 4 # number # The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents. # For FreeBSD, this is set to 4. indent_continue = 0 # number # How to use tabs when indenting code # 0=spaces only # 1=indent with tabs to brace level, align with spaces # 2=indent and align with tabs, using spaces when not on a tabstop indent_with_tabs = 0 # number # Comments that are not a brace level are indented with tabs on a tabstop. # Requires indent_with_tabs=2. If false, will use spaces. indent_cmt_with_tabs = false # false/true # Whether to indent strings broken by '\' so that they line up indent_align_string = true # false/true # The number of spaces to indent multi-line XML strings. # Requires indent_align_string=True indent_xml_string = 0 # number # Spaces to indent '{' from level indent_brace = 0 # number # Whether braces are indented to the body level indent_braces = false # false/true # Disabled indenting function braces if indent_braces is true indent_braces_no_func = false # false/true # Disabled indenting class braces if indent_braces is true indent_braces_no_class = false # false/true # Disabled indenting struct braces if indent_braces is true indent_braces_no_struct = false # false/true # Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. indent_brace_parent = false # false/true # Whether the 'namespace' body is indented indent_namespace = false # false/true # The number of spaces to indent a namespace block indent_namespace_level = 0 # number # If the body of the namespace is longer than this number, it won't be indented. # Requires indent_namespace=true. Default=0 (no limit) indent_namespace_limit = 0 # number # Whether the 'extern "C"' body is indented indent_extern = false # false/true # Whether the 'class' body is indented indent_class = false # false/true # Whether to indent the stuff after a leading class colon indent_class_colon = false # false/true # False=treat 'else\nif' as 'else if' for indenting purposes # True=indent the 'if' one level indent_else_if = false # false/true # Amount to indent variable declarations after a open brace. neg=relative, pos=absolute indent_var_def_blk = 0 # number # Indent continued variable declarations instead of aligning. indent_var_def_cont = false # false/true # True: indent continued function call parameters one indent level # False: align parameters under the open paren indent_func_call_param = false # false/true # Same as indent_func_call_param, but for function defs indent_func_def_param = false # false/true # Same as indent_func_call_param, but for function protos indent_func_proto_param = false # false/true # Same as indent_func_call_param, but for class declarations indent_func_class_param = false # false/true # Same as indent_func_call_param, but for class variable constructors indent_func_ctor_var_param = false # false/true # Same as indent_func_call_param, but for templates indent_template_param = false # false/true # Double the indent for indent_func_xxx_param options indent_func_param_double = false # false/true # Indentation column for standalone 'const' function decl/proto qualifier indent_func_const = 0 # number # Indentation column for standalone 'throw' function decl/proto qualifier indent_func_throw = 0 # number # The number of spaces to indent a continued '->' or '.' # Usually set to 0, 1, or indent_columns. indent_member = 0 # number # Spaces to indent single line ('//') comments on lines before code indent_sing_line_comments = 0 # number # If set, will indent trailing single line ('//') comments relative # to the code instead of trying to keep the same absolute column indent_relative_single_line_comments = false # false/true # Spaces to indent 'case' from 'switch' # Usually 0 or indent_columns. indent_switch_case = 0 # number # Spaces to shift the 'case' line, without affecting any other lines # Usually 0. indent_case_shift = 0 # number # Spaces to indent '{' from 'case'. # By default, the brace will appear under the 'c' in case. # Usually set to 0 or indent_columns. indent_case_brace = 0 # number # Whether to indent comments found in first column indent_col1_comment = false # false/true # How to indent goto labels # >0 : absolute column where 1 is the leftmost column # <=0 : subtract from brace indent indent_label = 1 # number # Same as indent_label, but for access specifiers that are followed by a colon indent_access_spec = 1 # number # Indent the code after an access specifier by one level. # If set, this option forces 'indent_access_spec=0' indent_access_spec_body = false # false/true # If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended) indent_paren_nl = false # false/true # Controls the indent of a close paren after a newline. # 0: Indent to body level # 1: Align under the open paren # 2: Indent to the brace level indent_paren_close = 0 # number # Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren indent_comma_paren = false # false/true # Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren indent_bool_paren = false # false/true # If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones indent_first_bool_expr = false # false/true # If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended) indent_square_nl = false # false/true # Don't change the relative indent of ESQL/C 'EXEC SQL' bodies indent_preserve_sql = false # false/true # Align continued statements at the '='. Default=True # If FALSE or the '=' is followed by a newline, the next line is indent one tab. indent_align_assign = true # false/true # # Spacing options # # Add or remove space around arithmetic operator '+', '-', '/', '*', etc sp_arith = force # ignore/add/remove/force # Add or remove space around assignment operator '=', '+=', etc sp_assign = force # ignore/add/remove/force # Add or remove space around assignment operator '=' in a prototype sp_assign_default = ignore # ignore/add/remove/force # Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign. sp_before_assign = ignore # ignore/add/remove/force # Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign. sp_after_assign = ignore # ignore/add/remove/force # Add or remove space around assignment '=' in enum sp_enum_assign = force # ignore/add/remove/force # Add or remove space before assignment '=' in enum. Overrides sp_enum_assign. sp_enum_before_assign = ignore # ignore/add/remove/force # Add or remove space after assignment '=' in enum. Overrides sp_enum_assign. sp_enum_after_assign = ignore # ignore/add/remove/force # Add or remove space around preprocessor '##' concatenation operator. Default=Add sp_pp_concat = add # ignore/add/remove/force # Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator. Default=Add sp_pp_stringify = add # ignore/add/remove/force # Add or remove space around boolean operators '&&' and '||' sp_bool = force # ignore/add/remove/force # Add or remove space around compare operator '<', '>', '==', etc sp_compare = force # ignore/add/remove/force # Add or remove space inside '(' and ')' sp_inside_paren = remove # ignore/add/remove/force # Add or remove space between nested parens sp_paren_paren = remove # ignore/add/remove/force # Whether to balance spaces inside nested parens sp_balance_nested_parens = false # false/true # Add or remove space between ')' and '{' sp_paren_brace = force # ignore/add/remove/force # Add or remove space before pointer star '*' sp_before_ptr_star = add # ignore/add/remove/force # Add or remove space before pointer star '*' that isn't followed by a variable name # If set to 'ignore', sp_before_ptr_star is used instead. sp_before_unnamed_ptr_star = add # ignore/add/remove/force # Add or remove space between pointer stars '*' sp_between_ptr_star = remove # ignore/add/remove/force # Add or remove space after pointer star '*', if followed by a word. sp_after_ptr_star = remove # ignore/add/remove/force # Add or remove space after a pointer star '*', if followed by a func proto/def. sp_after_ptr_star_func = remove # ignore/add/remove/force # Add or remove space before a pointer star '*', if followed by a func proto/def. sp_before_ptr_star_func = ignore # ignore/add/remove/force # Add or remove space before a reference sign '&' sp_before_byref = force # ignore/add/remove/force # Add or remove space before a reference sign '&' that isn't followed by a variable name # If set to 'ignore', sp_before_byref is used instead. sp_before_unnamed_byref = force # ignore/add/remove/force # Add or remove space after reference sign '&', if followed by a word. sp_after_byref = ignore # ignore/add/remove/force # Add or remove space after a reference sign '&', if followed by a func proto/def. sp_after_byref_func = ignore # ignore/add/remove/force # Add or remove space before a reference sign '&', if followed by a func proto/def. sp_before_byref_func = ignore # ignore/add/remove/force # Add or remove space between type and word. Default=Force sp_after_type = force # ignore/add/remove/force # Add or remove space in 'template <' vs 'template<'. # If set to ignore, sp_before_angle is used. sp_template_angle = ignore # ignore/add/remove/force # Add or remove space before '<>' sp_before_angle = ignore # ignore/add/remove/force # Add or remove space inside '<' and '>' sp_inside_angle = ignore # ignore/add/remove/force # Add or remove space after '<>' sp_after_angle = ignore # ignore/add/remove/force # Add or remove space between '<>' and '(' as found in 'new List();' sp_angle_paren = ignore # ignore/add/remove/force # Add or remove space between '<>' and a word as in 'List m;' sp_angle_word = ignore # ignore/add/remove/force # Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add sp_angle_shift = add # ignore/add/remove/force # Add or remove space before '(' of 'if', 'for', 'switch', and 'while' sp_before_sparen = force # ignore/add/remove/force # Add or remove space inside if-condition '(' and ')' sp_inside_sparen = remove # ignore/add/remove/force # Add or remove space before if-condition ')'. Overrides sp_inside_sparen. sp_inside_sparen_close = ignore # ignore/add/remove/force # Add or remove space after ')' of 'if', 'for', 'switch', and 'while' sp_after_sparen = ignore # ignore/add/remove/force # Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while' sp_sparen_brace = force # ignore/add/remove/force # Add or remove space between 'invariant' and '(' in the D language. sp_invariant_paren = ignore # ignore/add/remove/force # Add or remove space after the ')' in 'invariant (C) c' in the D language. sp_after_invariant_paren = ignore # ignore/add/remove/force # Add or remove space before empty statement ';' on 'if', 'for' and 'while' sp_special_semi = ignore # ignore/add/remove/force # Add or remove space before ';'. Default=Remove sp_before_semi = remove # ignore/add/remove/force # Add or remove space before ';' in non-empty 'for' statements sp_before_semi_for = ignore # ignore/add/remove/force # Add or remove space before a semicolon of an empty part of a for statement. sp_before_semi_for_empty = ignore # ignore/add/remove/force # Add or remove space after ';', except when followed by a comment. Default=Add sp_after_semi = force # ignore/add/remove/force # Add or remove space after ';' in non-empty 'for' statements. Default=Force sp_after_semi_for = force # ignore/add/remove/force # Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; ). sp_after_semi_for_empty = remove # ignore/add/remove/force # Add or remove space before '[' (except '[]') sp_before_square = remove # ignore/add/remove/force # Add or remove space before '[]' sp_before_squares = ignore # ignore/add/remove/force # Add or remove space inside '[' and ']' sp_inside_square = remove # ignore/add/remove/force # Add or remove space after ',' sp_after_comma = force # ignore/add/remove/force # Add or remove space before ',' sp_before_comma = remove # ignore/add/remove/force # Add or remove space between an open paren and comma: '(,' vs '( ,' sp_paren_comma = force # ignore/add/remove/force # Add or remove space before the variadic '...' when preceded by a non-punctuator sp_before_ellipsis = ignore # ignore/add/remove/force # Add or remove space after class ':' sp_after_class_colon = ignore # ignore/add/remove/force # Add or remove space before class ':' sp_before_class_colon = ignore # ignore/add/remove/force # Add or remove space before case ':'. Default=Remove sp_before_case_colon = remove # ignore/add/remove/force # Add or remove space between 'operator' and operator sign sp_after_operator = ignore # ignore/add/remove/force # Add or remove space between the operator symbol and the open paren, as in 'operator ++(' sp_after_operator_sym = ignore # ignore/add/remove/force # Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a' sp_after_cast = remove # ignore/add/remove/force # Add or remove spaces inside cast parens sp_inside_paren_cast = remove # ignore/add/remove/force # Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)' sp_cpp_cast_paren = ignore # ignore/add/remove/force # Add or remove space between 'sizeof' and '(' sp_sizeof_paren = remove # ignore/add/remove/force # Add or remove space after the tag keyword (Pawn) sp_after_tag = ignore # ignore/add/remove/force # Add or remove space inside enum '{' and '}' sp_inside_braces_enum = remove # ignore/add/remove/force # Add or remove space inside struct/union '{' and '}' sp_inside_braces_struct = force # ignore/add/remove/force # Add or remove space inside '{' and '}' sp_inside_braces = force # ignore/add/remove/force # Add or remove space inside '{}' sp_inside_braces_empty = remove # ignore/add/remove/force # Add or remove space between return type and function name # A minimum of 1 is forced except for pointer return types. sp_type_func = remove # ignore/add/remove/force # Add or remove space between function name and '(' on function declaration sp_func_proto_paren = remove # ignore/add/remove/force # Add or remove space between function name and '(' on function definition sp_func_def_paren = remove # ignore/add/remove/force # Add or remove space inside empty function '()' sp_inside_fparens = remove # ignore/add/remove/force # Add or remove space inside function '(' and ')' sp_inside_fparen = remove # ignore/add/remove/force # Add or remove space between ']' and '(' when part of a function call. sp_square_fparen = ignore # ignore/add/remove/force # Add or remove space between ')' and '{' of function sp_fparen_brace = ignore # ignore/add/remove/force # Add or remove space between function name and '(' on function calls sp_func_call_paren = remove # ignore/add/remove/force # Add or remove space between function name and '()' on function calls without parameters. # If set to 'ignore' (the default), sp_func_call_paren is used. sp_func_call_paren_empty = ignore # ignore/add/remove/force # Add or remove space between the user function name and '(' on function calls # You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file. sp_func_call_user_paren = ignore # ignore/add/remove/force # Add or remove space between a constructor/destructor and the open paren sp_func_class_paren = ignore # ignore/add/remove/force # Add or remove space between 'return' and '(' sp_return_paren = ignore # ignore/add/remove/force # Add or remove space between '__attribute__' and '(' sp_attribute_paren = remove # ignore/add/remove/force # Add or remove space between 'defined' and '(' in '#if defined (FOO)' sp_defined_paren = ignore # ignore/add/remove/force # Add or remove space between 'throw' and '(' in 'throw (something)' sp_throw_paren = ignore # ignore/add/remove/force # Add or remove space between macro and value sp_macro = ignore # ignore/add/remove/force # Add or remove space between macro function ')' and value sp_macro_func = ignore # ignore/add/remove/force # Add or remove space between 'else' and '{' if on the same line sp_else_brace = force # ignore/add/remove/force # Add or remove space between '}' and 'else' if on the same line sp_brace_else = force # ignore/add/remove/force # Add or remove space between '}' and the name of a typedef on the same line sp_brace_typedef = force # ignore/add/remove/force # Add or remove space between 'catch' and '{' if on the same line sp_catch_brace = ignore # ignore/add/remove/force # Add or remove space between '}' and 'catch' if on the same line sp_brace_catch = ignore # ignore/add/remove/force # Add or remove space between 'finally' and '{' if on the same line sp_finally_brace = ignore # ignore/add/remove/force # Add or remove space between '}' and 'finally' if on the same line sp_brace_finally = ignore # ignore/add/remove/force # Add or remove space between 'try' and '{' if on the same line sp_try_brace = ignore # ignore/add/remove/force # Add or remove space between get/set and '{' if on the same line sp_getset_brace = ignore # ignore/add/remove/force # Add or remove space before the '::' operator sp_before_dc = ignore # ignore/add/remove/force # Add or remove space after the '::' operator sp_after_dc = ignore # ignore/add/remove/force # Add or remove around the D named array initializer ':' operator sp_d_array_colon = ignore # ignore/add/remove/force # Add or remove space after the '!' (not) operator. Default=Remove sp_not = remove # ignore/add/remove/force # Add or remove space after the '~' (invert) operator. Default=Remove sp_inv = remove # ignore/add/remove/force # Add or remove space after the '&' (address-of) operator. Default=Remove # This does not affect the spacing after a '&' that is part of a type. sp_addr = remove # ignore/add/remove/force # Add or remove space around the '.' or '->' operators. Default=Remove sp_member = remove # ignore/add/remove/force # Add or remove space after the '*' (dereference) operator. Default=Remove # This does not affect the spacing after a '*' that is part of a type. sp_deref = remove # ignore/add/remove/force # Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove sp_sign = remove # ignore/add/remove/force # Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove sp_incdec = remove # ignore/add/remove/force # Add or remove space before a backslash-newline at the end of a line. Default=Add sp_before_nl_cont = add # ignore/add/remove/force # Add or remove space after the scope '+' or '-', as in '-(void) foo;' or '+(int) bar;' sp_after_oc_scope = ignore # ignore/add/remove/force # Add or remove space after the colon in message specs # '-(int) f:(int) x;' vs '-(int) f: (int) x;' sp_after_oc_colon = ignore # ignore/add/remove/force # Add or remove space before the colon in message specs # '-(int) f: (int) x;' vs '-(int) f : (int) x;' sp_before_oc_colon = ignore # ignore/add/remove/force # Add or remove space after the colon in message specs # '[object setValue:1];' vs '[object setValue: 1];' sp_after_send_oc_colon = ignore # ignore/add/remove/force # Add or remove space before the colon in message specs # '[object setValue:1];' vs '[object setValue :1];' sp_before_send_oc_colon = ignore # ignore/add/remove/force # Add or remove space after the (type) in message specs # '-(int)f: (int) x;' vs '-(int)f: (int)x;' sp_after_oc_type = ignore # ignore/add/remove/force # Add or remove space after the first (type) in message specs # '-(int) f:(int)x;' vs '-(int)f:(int)x;' sp_after_oc_return_type = ignore # ignore/add/remove/force # Add or remove space between '@selector' and '(' # '@selector(msgName)' vs '@selector (msgName)' # Also applies to @protocol() constructs sp_after_oc_at_sel = ignore # ignore/add/remove/force # Add or remove space between '@selector(x)' and the following word # '@selector(foo) a:' vs '@selector(foo)a:' sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force # Add or remove space inside '@selector' parens # '@selector(foo)' vs '@selector( foo )' # Also applies to @protocol() constructs sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force # Add or remove space before a block pointer caret # '^int (int arg){...}' vs. ' ^int (int arg){...}' sp_before_oc_block_caret = ignore # ignore/add/remove/force # Add or remove space after a block pointer caret # '^int (int arg){...}' vs. '^ int (int arg){...}' sp_after_oc_block_caret = ignore # ignore/add/remove/force # Add or remove space around the ':' in 'b ? t : f' sp_cond_colon = force # ignore/add/remove/force # Add or remove space around the '?' in 'b ? t : f' sp_cond_question = force # ignore/add/remove/force # Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here. sp_case_label = ignore # ignore/add/remove/force # Control the space around the D '..' operator. sp_range = ignore # ignore/add/remove/force # Control the space after the opening of a C++ comment '// A' vs '//A' # MPlayer devs note: we ignore the following setting because it breaks Doxygen comments #sp_cmt_cpp_start = ignore # ignore/add/remove/force sp_cmt_cpp_start = add # ignore/add/remove/force # Controls the spaces between #else or #endif and a trailing comment sp_endif_cmt = ignore # ignore/add/remove/force # # Code alignment (not left column spaces/tabs) # # Whether to keep non-indenting tabs align_keep_tabs = false # false/true # Whether to use tabs for aligning align_with_tabs = false # false/true # Whether to bump out to the next tab when aligning align_on_tabstop = false # false/true # Whether to left-align numbers align_number_left = true # false/true # Align variable definitions in prototypes and functions align_func_params = false # false/true # Align parameters in single-line functions that have the same name. # The function names must already be aligned with each other. align_same_func_call_params = false # false/true # The span for aligning variable definitions (0=don't align) align_var_def_span = 0 # number # How to align the star in variable definitions. # 0=Part of the type 'void * foo;' # 1=Part of the variable 'void *foo;' # 2=Dangling 'void *foo;' align_var_def_star_style = 2 # number # How to align the '&' in variable definitions. # 0=Part of the type # 1=Part of the variable # 2=Dangling align_var_def_amp_style = 0 # number # The threshold for aligning variable definitions (0=no limit) align_var_def_thresh = 0 # number # The gap for aligning variable definitions align_var_def_gap = 0 # number # Whether to align the colon in struct bit fields align_var_def_colon = false # false/true # Whether to align any attribute after the variable name align_var_def_attribute = false # false/true # Whether to align inline struct/enum/union variable definitions align_var_def_inline = false # false/true # The span for aligning on '=' in assignments (0=don't align) align_assign_span = 1 # number # The threshold for aligning on '=' in assignments (0=no limit) align_assign_thresh = 0 # number # The span for aligning on '=' in enums (0=don't align) align_enum_equ_span = 1 # number # The threshold for aligning on '=' in enums (0=no limit) align_enum_equ_thresh = 0 # number # The span for aligning struct/union (0=don't align) align_var_struct_span = 0 # number # The threshold for aligning struct/union member definitions (0=no limit) align_var_struct_thresh = 0 # number # The gap for aligning struct/union member definitions align_var_struct_gap = 0 # number # The span for aligning struct initializer values (0=don't align) align_struct_init_span = 1 # number # The minimum space between the type and the synonym of a typedef align_typedef_gap = 0 # number # The span for aligning single-line typedefs (0=don't align) align_typedef_span = 0 # number # How to align typedef'd functions with other typedefs # 0: Don't mix them at all # 1: align the open paren with the types # 2: align the function type name with the other type names align_typedef_func = 0 # number # Controls the positioning of the '*' in typedefs. Just try it. # 0: Align on typedef type, ignore '*' # 1: The '*' is part of type name: typedef int *pint; # 2: The '*' is part of the type, but dangling: typedef int *pint; align_typedef_star_style = 0 # number # Controls the positioning of the '&' in typedefs. Just try it. # 0: Align on typedef type, ignore '&' # 1: The '&' is part of type name: typedef int &pint; # 2: The '&' is part of the type, but dangling: typedef int &pint; align_typedef_amp_style = 0 # number # The span for aligning comments that end lines (0=don't align) align_right_cmt_span = 0 # number # If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment align_right_cmt_mix = false # false/true # If a trailing comment is more than this number of columns away from the text it follows, # it will qualify for being aligned. This has to be > 0 to do anything. align_right_cmt_gap = 0 # number # Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore) align_right_cmt_at_col = 0 # number # The span for aligning function prototypes (0=don't align) align_func_proto_span = 0 # number # Minimum gap between the return type and the function name. align_func_proto_gap = 0 # number # Align function protos on the 'operator' keyword instead of what follows align_on_operator = false # false/true # Whether to mix aligning prototype and variable declarations. # If true, align_var_def_XXX options are used instead of align_func_proto_XXX options. align_mix_var_proto = false # false/true # Align single-line functions with function prototypes, uses align_func_proto_span align_single_line_func = false # false/true # Aligning the open brace of single-line functions. # Requires align_single_line_func=true, uses align_func_proto_span align_single_line_brace = false # false/true # Gap for align_single_line_brace. align_single_line_brace_gap = 0 # number # The span for aligning ObjC msg spec (0=don't align) align_oc_msg_spec_span = 0 # number # Whether to align macros wrapped with a backslash and a newline. # This will not work right if the macro contains a multi-line comment. align_nl_cont = false # false/true # The minimum space between label and value of a preprocessor define align_pp_define_gap = 0 # number # The span for aligning on '#define' bodies (0=don't align) align_pp_define_span = 0 # number # Align lines that start with '<<' with previous '<<'. Default=true align_left_shift = true # false/true # Span for aligning parameters in an Obj-C message call on the ':' (0=don't align) align_oc_msg_colon_span = 0 # number # Aligning parameters in an Obj-C '+' or '-' declaration on the ':' align_oc_decl_colon = false # false/true # # Newline adding and removing options # # Whether to collapse empty blocks between '{' and '}' nl_collapse_empty_body = false # false/true # Don't split one-line braced assignments - 'foo_t f = { 1, 2 };' nl_assign_leave_one_liners = false # false/true # Don't split one-line braced statements inside a class xx { } body nl_class_leave_one_liners = false # false/true # Don't split one-line enums: 'enum foo { BAR = 15 };' nl_enum_leave_one_liners = false # false/true # Don't split one-line get or set functions nl_getset_leave_one_liners = false # false/true # Don't split one-line function definitions - 'int foo() { return 0; }' nl_func_leave_one_liners = false # false/true # Don't split one-line if/else statements - 'if(a) b++;' nl_if_leave_one_liners = false # false/true # Add or remove newlines at the start of the file nl_start_of_file = remove # ignore/add/remove/force # The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force' nl_start_of_file_min = 0 # number # Add or remove newline at the end of the file nl_end_of_file = force # ignore/add/remove/force # The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force') nl_end_of_file_min = 1 # number # Add or remove newline between '=' and '{' nl_assign_brace = remove # ignore/add/remove/force # Add or remove newline between '=' and '[' (D only) nl_assign_square = ignore # ignore/add/remove/force # Add or remove newline after '= [' (D only). Will also affect the newline before the ']' nl_after_square_assign = ignore # ignore/add/remove/force # The number of blank lines after a block of variable definitions nl_func_var_def_blk = 0 # number # Add or remove newline between a function call's ')' and '{', as in: # list_for_each(item, &list) { } nl_fcall_brace = ignore # ignore/add/remove/force # Add or remove newline between 'enum' and '{' nl_enum_brace = remove # ignore/add/remove/force # Add or remove newline between 'struct and '{' nl_struct_brace = remove # ignore/add/remove/force # Add or remove newline between 'union' and '{' nl_union_brace = remove # ignore/add/remove/force # Add or remove newline between 'if' and '{' nl_if_brace = remove # ignore/add/remove/force # Add or remove newline between '}' and 'else' nl_brace_else = remove # ignore/add/remove/force # Add or remove newline between 'else if' and '{' # If set to ignore, nl_if_brace is used instead nl_elseif_brace = ignore # ignore/add/remove/force # Add or remove newline between 'else' and '{' nl_else_brace = remove # ignore/add/remove/force # Add or remove newline between 'else' and 'if' nl_else_if = remove # ignore/add/remove/force # Add or remove newline between '}' and 'finally' nl_brace_finally = ignore # ignore/add/remove/force # Add or remove newline between 'finally' and '{' nl_finally_brace = ignore # ignore/add/remove/force # Add or remove newline between 'try' and '{' nl_try_brace = ignore # ignore/add/remove/force # Add or remove newline between get/set and '{' nl_getset_brace = ignore # ignore/add/remove/force # Add or remove newline between 'for' and '{' nl_for_brace = remove # ignore/add/remove/force # Add or remove newline between 'catch' and '{' nl_catch_brace = ignore # ignore/add/remove/force # Add or remove newline between '}' and 'catch' nl_brace_catch = ignore # ignore/add/remove/force # Add or remove newline between 'while' and '{' nl_while_brace = remove # ignore/add/remove/force # Add or remove newline between 'using' and '{' nl_using_brace = ignore # ignore/add/remove/force # Add or remove newline between two open or close braces. # Due to general newline/brace handling, REMOVE may not work. nl_brace_brace = ignore # ignore/add/remove/force # Add or remove newline between 'do' and '{' nl_do_brace = remove # ignore/add/remove/force # Add or remove newline between '}' and 'while' of 'do' statement nl_brace_while = remove # ignore/add/remove/force # Add or remove newline between 'switch' and '{' nl_switch_brace = remove # ignore/add/remove/force # Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc. # Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch, and nl_catch_brace. nl_multi_line_cond = false # false/true # Force a newline in a define after the macro name for multi-line defines. nl_multi_line_define = false # false/true # Whether to put a newline before 'case' statement nl_before_case = false # false/true # Add or remove newline between ')' and 'throw' nl_before_throw = ignore # ignore/add/remove/force # Whether to put a newline after 'case' statement nl_after_case = true # false/true # Newline between namespace and { nl_namespace_brace = ignore # ignore/add/remove/force # Add or remove newline between 'template<>' and whatever follows. nl_template_class = ignore # ignore/add/remove/force # Add or remove newline between 'class' and '{' nl_class_brace = ignore # ignore/add/remove/force # Add or remove newline after each ',' in the constructor member initialization nl_class_init_args = ignore # ignore/add/remove/force # Add or remove newline between return type and function name in a function definition nl_func_type_name = force # ignore/add/remove/force # Add or remove newline between return type and function name inside a class {} # Uses nl_func_type_name or nl_func_proto_type_name if set to ignore. nl_func_type_name_class = ignore # ignore/add/remove/force # Add or remove newline between function scope and name in a definition # Controls the newline after '::' in 'void A::f() { }' nl_func_scope_name = ignore # ignore/add/remove/force # Add or remove newline between return type and function name in a prototype nl_func_proto_type_name = remove # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' nl_func_paren = remove # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' in the definition nl_func_def_paren = remove # ignore/add/remove/force # Add or remove newline after '(' in a function declaration nl_func_decl_start = remove # ignore/add/remove/force # Add or remove newline after '(' in a function definition nl_func_def_start = ignore # ignore/add/remove/force # Overrides nl_func_decl_start when there is only one parameter. nl_func_decl_start_single = ignore # ignore/add/remove/force # Overrides nl_func_def_start when there is only one parameter. nl_func_def_start_single = ignore # ignore/add/remove/force # Add or remove newline after each ',' in a function declaration nl_func_decl_args = ignore # ignore/add/remove/force # Add or remove newline after each ',' in a function definition nl_func_def_args = ignore # ignore/add/remove/force # Add or remove newline before the ')' in a function declaration nl_func_decl_end = remove # ignore/add/remove/force # Add or remove newline before the ')' in a function definition nl_func_def_end = ignore # ignore/add/remove/force # Overrides nl_func_decl_end when there is only one parameter. nl_func_decl_end_single = ignore # ignore/add/remove/force # Overrides nl_func_def_end when there is only one parameter. nl_func_def_end_single = ignore # ignore/add/remove/force # Add or remove newline between '()' in a function declaration. nl_func_decl_empty = ignore # ignore/add/remove/force # Add or remove newline between '()' in a function definition. nl_func_def_empty = ignore # ignore/add/remove/force # Add or remove newline between function signature and '{' nl_fdef_brace = force # ignore/add/remove/force # Whether to put a newline after 'return' statement nl_after_return = false # false/true # Add or remove a newline between the return keyword and return expression. nl_return_expr = ignore # ignore/add/remove/force # Whether to put a newline after semicolons, except in 'for' statements nl_after_semicolon = true # false/true # Whether to put a newline after brace open. # This also adds a newline before the matching brace close. nl_after_brace_open = false # false/true # If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is # placed between the open brace and a trailing single-line comment. nl_after_brace_open_cmt = false # false/true # Whether to put a newline after a virtual brace open with a non-empty body. # These occur in un-braced if/while/do/for statement bodies. nl_after_vbrace_open = true # false/true # Whether to put a newline after a virtual brace open with an empty body. # These occur in un-braced if/while/do/for statement bodies. nl_after_vbrace_open_empty = false # false/true # Whether to put a newline after a brace close. # Does not apply if followed by a necessary ';'. nl_after_brace_close = false # false/true # Whether to put a newline after a virtual brace close. # Would add a newline before return in: 'if (foo) a++; return;' nl_after_vbrace_close = false # false/true # Whether to alter newlines in '#define' macros nl_define_macro = false # false/true # Whether to not put blanks after '#ifxx', '#elxx', or before '#endif' nl_squeeze_ifdef = false # false/true # Add or remove blank line before 'if' nl_before_if = ignore # ignore/add/remove/force # Add or remove blank line after 'if' statement nl_after_if = ignore # ignore/add/remove/force # Add or remove blank line before 'for' nl_before_for = ignore # ignore/add/remove/force # Add or remove blank line after 'for' statement nl_after_for = ignore # ignore/add/remove/force # Add or remove blank line before 'while' nl_before_while = ignore # ignore/add/remove/force # Add or remove blank line after 'while' statement nl_after_while = ignore # ignore/add/remove/force # Add or remove blank line before 'switch' nl_before_switch = ignore # ignore/add/remove/force # Add or remove blank line after 'switch' statement nl_after_switch = ignore # ignore/add/remove/force # Add or remove blank line before 'do' nl_before_do = ignore # ignore/add/remove/force # Add or remove blank line after 'do/while' statement nl_after_do = ignore # ignore/add/remove/force # Whether to double-space commented-entries in struct/enum nl_ds_struct_enum_cmt = false # false/true # Whether to double-space before the close brace of a struct/union/enum # (lower priority than 'eat_blanks_before_close_brace') nl_ds_struct_enum_close_brace = false # false/true # Add or remove a newline around a class colon. # Related to pos_class_colon, nl_class_init_args, and pos_comma. nl_class_colon = ignore # ignore/add/remove/force # Change simple unbraced if statements into a one-liner # 'if(b)\n i++;' => 'if(b) i++;' nl_create_if_one_liner = false # false/true # Change simple unbraced for statements into a one-liner # 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);' nl_create_for_one_liner = false # false/true # Change simple unbraced while statements into a one-liner # 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' nl_create_while_one_liner = false # false/true # # Positioning options # # The position of arithmetic operators in wrapped expressions pos_arith = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of assignment in wrapped expressions. # Do not affect '=' followed by '{' pos_assign = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of boolean operators in wrapped expressions pos_bool = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of comparison operators in wrapped expressions pos_compare = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of conditional (b ? t : f) operators in wrapped expressions pos_conditional = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of the comma in wrapped expressions pos_comma = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of the comma in the constructor initialization list pos_class_comma = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force # The position of colons between constructor and member initialization pos_class_colon = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force # # Line Splitting options # # Try to limit code width to N number of columns code_width = 120 # number # Whether to fully split long 'for' statements at semi-colons ls_for_split_full = false # false/true # Whether to fully split long function protos/calls at commas ls_func_split_full = false # false/true # # Blank line options # # The maximum consecutive newlines nl_max = 2 # number # The number of newlines after a function prototype, if followed by another function prototype nl_after_func_proto = 0 # number # The number of newlines after a function prototype, if not followed by another function prototype nl_after_func_proto_group = 0 # number # The number of newlines after '}' of a multi-line function body nl_after_func_body = 2 # number # The number of newlines after '}' of a single line function body nl_after_func_body_one_liner = 2 # number # The minimum number of newlines before a multi-line comment. # Doesn't apply if after a brace open or another multi-line comment. nl_before_block_comment = 0 # number # The minimum number of newlines before a single-line C comment. # Doesn't apply if after a brace open or other single-line C comments. nl_before_c_comment = 0 # number # The minimum number of newlines before a CPP comment. # Doesn't apply if after a brace open or other CPP comments. nl_before_cpp_comment = 0 # number # Whether to force a newline after a multi-line comment. nl_after_multiline_comment = false # false/true # The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. # Will not change the newline count if after a brace open. # 0 = No change. nl_before_access_spec = 0 # number # The number of newlines after a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. # 0 = No change. nl_after_access_spec = 0 # number # The number of newlines between a function def and the function comment. # 0 = No change. nl_comment_func_def = 0 # number # The number of newlines after a try-catch-finally block that isn't followed by a brace close. # 0 = No change. nl_after_try_catch_finally = 0 # number # The number of newlines before and after a property, indexer or event decl. # 0 = No change. nl_around_cs_property = 0 # number # The number of newlines between the get/set/add/remove handlers in C#. # 0 = No change. nl_between_get_set = 0 # number # Whether to remove blank lines after '{' eat_blanks_after_open_brace = true # false/true # Whether to remove blank lines before '}' eat_blanks_before_close_brace = true # false/true # # Code modifying options (non-whitespace) # # Add or remove braces on single-line 'do' statement mod_full_brace_do = remove # ignore/add/remove/force # Add or remove braces on single-line 'for' statement mod_full_brace_for = remove # ignore/add/remove/force # Add or remove braces on single-line function definitions. (Pawn) mod_full_brace_function = ignore # ignore/add/remove/force # Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'. mod_full_brace_if = ignore # ignore/add/remove/force # Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. # If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. mod_full_brace_if_chain = false # false/true # Don't remove braces around statements that span N newlines mod_full_brace_nl = 0 # number # Add or remove braces on single-line 'while' statement mod_full_brace_while = remove # ignore/add/remove/force # Add or remove braces on single-line 'using ()' statement mod_full_brace_using = remove # ignore/add/remove/force # Add or remove unnecessary paren on 'return' statement mod_paren_on_return = remove # ignore/add/remove/force # Whether to change optional semicolons to real semicolons mod_pawn_semicolon = false # false/true # Add parens on 'while' and 'if' statement around bools mod_full_paren_if_bool = false # false/true # Whether to remove superfluous semicolons mod_remove_extra_semicolon = true # false/true # If a function body exceeds the specified number of newlines and doesn't have a comment after # the close brace, a comment will be added. mod_add_long_function_closebrace_comment = 0 # number # If a switch body exceeds the specified number of newlines and doesn't have a comment after # the close brace, a comment will be added. mod_add_long_switch_closebrace_comment = 0 # number # If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after # the #else, a comment will be added. mod_add_long_ifdef_endif_comment = 0 # number # If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after # the #endif, a comment will be added. mod_add_long_ifdef_else_comment = 0 # number # If TRUE, will sort consecutive single-line 'import' statements [Java, D] mod_sort_import = false # false/true # If TRUE, will sort consecutive single-line 'using' statements [C#] mod_sort_using = false # false/true # If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] # This is generally a bad idea, as it may break your code. mod_sort_include = false # false/true # If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace. mod_move_case_break = false # false/true # Will add or remove the braces around a fully braced case statement. # Will only remove the braces if there are no variable declarations in the block. mod_case_brace = ignore # ignore/add/remove/force # If TRUE, it will remove a void 'return;' that appears as the last statement in a function. mod_remove_empty_return = false # false/true # # Comment modifications # # Try to wrap comments at cmt_width columns cmt_width = 0 # number # Set the comment reflow mode (default: 0) # 0: no reflowing (apart from the line wrapping due to cmt_width) # 1: no touching at all # 2: full reflow cmt_reflow_mode = 0 # number # If false, disable all multi-line comment changes, including cmt_width. keyword substitution, and leading chars. # Default is true. cmt_indent_multi = true # false/true # Whether to group c-comments that look like they are in a block cmt_c_group = false # false/true # Whether to put an empty '/*' on the first line of the combined c-comment cmt_c_nl_start = false # false/true # Whether to put a newline before the closing '*/' of the combined c-comment cmt_c_nl_end = false # false/true # Whether to group cpp-comments that look like they are in a block cmt_cpp_group = false # false/true # Whether to put an empty '/*' on the first line of the combined cpp-comment cmt_cpp_nl_start = false # false/true # Whether to put a newline before the closing '*/' of the combined cpp-comment cmt_cpp_nl_end = false # false/true # Whether to change cpp-comments into c-comments cmt_cpp_to_c = false # false/true # Whether to put a star on subsequent comment lines cmt_star_cont = true # false/true # The number of spaces to insert at the start of subsequent comment lines cmt_sp_before_star_cont = 0 # number # The number of spaces to insert after the star on subsequent comment lines cmt_sp_after_star_cont = 0 # number # For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of # the comment are the same length. Default=True cmt_multi_check_last = false # false/true # The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment. # Will substitute $(filename) with the current file's name. cmt_insert_file_header = "" # string # The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment. # Will substitute $(filename) with the current file's name. cmt_insert_file_footer = "" # string # The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment. # Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff. # Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... } cmt_insert_func_header = "" # string # The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment. # Will substitute $(class) with the class name. cmt_insert_class_header = "" # string # If a preprocessor is encountered when stepping backwards from a function name, then # this option decides whether the comment should be inserted. # Affects cmt_insert_func_header and cmt_insert_class_header. cmt_insert_before_preproc = false # false/true # # Preprocessor options # # Control indent of preprocessors inside #if blocks at brace level 0 pp_indent = remove # ignore/add/remove/force # Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false) pp_indent_at_level = false # false/true # If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1. pp_indent_count = 1 # number # Add or remove space after # based on pp_level of #if blocks pp_space = remove # ignore/add/remove/force # Sets the number of spaces added with pp_space pp_space_count = 0 # number # The indent for #region and #endregion in C# and '#pragma region' in C/C++ pp_indent_region = 0 # number # Whether to indent the code between #region and #endregion pp_region_indent_code = false # false/true # If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level pp_indent_if = 0 # number # Control whether to indent the code between #if, #else and #endif when not at file-level pp_if_indent_code = false # false/true # Whether to indent '#define' at the brace level (true) or from column 1 (false) pp_define_at_level = false # false/true # You can force a token to be a type with the 'type' option. # Example: # type myfoo1 myfoo2 # # You can create custom macro-based indentation using macro-open, # macro-else and macro-close. # Example: # macro-open BEGIN_TEMPLATE_MESSAGE_MAP # macro-open BEGIN_MESSAGE_MAP # macro-close END_MESSAGE_MAP # # You can assign any keyword to any type with the set option. # set func_call_user _ N_ # # The full syntax description of all custom definition config entries # is shown below: # # define custom tokens as: # - embed whitespace in token using '' escape character, or # put token in quotes # - these: ' " and ` are recognized as quote delimiters # # type token1 token2 token3 ... # ^ optionally specify multiple tokens on a single line # define def_token output_token # ^ output_token is optional, then NULL is assumed # macro-open token # macro-close token # macro-else token # set id token1 token2 ... # ^ optionally specify multiple tokens on a single line # ^ id is one of the names in token_enum.h sans the CT_ prefix, # e.g. PP_PRAGMA # # all tokens are separated by any mix of ',' commas, '=' equal signs # and whitespace (space, tab) # ================================================ FILE: AUTHORS ================================================ Shadowsocks-libev was originally created in late 2013, by Clowwindy , then rewritten and maintained by Max Lv . Here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS -- people who have submitted patches, fixed bugs, added translations, and generally made shadowsocks-libev that much better: https://github.com/shadowsocks/shadowsocks-libev/graphs/contributors ================================================ FILE: CLAUDE.md ================================================ # CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview shadowsocks-libev is a lightweight SOCKS5 proxy written in pure C. Version 3.3.6, licensed under GPLv3. ## Build Commands ### CMake (sole build system) ```bash git submodule update --init --recursive mkdir -p build && cd build cmake .. make sudo make install ``` On macOS, CMake should auto-detect library paths. If needed, specify paths: ```bash cmake .. -DCMAKE_PREFIX_PATH="/usr/local/opt/mbedtls;/usr/local/opt/libsodium" ``` CMake outputs binaries to `build/bin/` (static) and `build/shared/bin/` (shared). ### Build Dependencies - cmake (>= 3.2), a C compiler (gcc or clang), pkg-config - libmbedtls, libsodium (>= 1.0.4), libpcre3, libev, libc-ares - asciidoc + xmlto (documentation only) ### CMake Options - `-DWITH_EMBEDDED_SRC=OFF`: use system libcork/libipset/libbloom instead of bundled submodules - `-DWITH_DOC_MAN=OFF`: skip man page generation - `-DENABLE_CONNMARKTOS=ON`: Linux netfilter conntrack QoS support - `-DENABLE_NFTABLES=ON`: nftables firewall integration - `-DDISABLE_SSP=ON`: disable stack protector - `-DBUILD_TESTING=OFF`: disable unit tests ## Testing ### Unit Tests (CTest) ```bash cd build ctest --output-on-failure ``` 10 unit test modules cover: base64, buffer, crypto, json, jconf, cache, ppbloom, rule, netutils, utils. ### Integration Tests Integration tests use Python and require `curl` and `dig` to be available: ```bash bash tests/test.sh ``` The test harness (`tests/test.py`) starts ss-server, ss-local, and ss-tunnel locally, then runs curl through the SOCKS5 proxy and dig through the tunnel. Each test config in `tests/*.json` exercises a different cipher. Run a single cipher test: ```bash python tests/test.py --bin build/bin/ -c tests/aes-gcm.json ``` ## Code Formatting Uses **uncrustify** with the config at `.uncrustify.cfg`. Key settings: 4-space indent, no tabs, 120-column width, K&R brace style (braces on same line). ## Architecture ### Binaries (all in `src/`) Each binary is compiled with a module define that controls conditional compilation: | Binary | Define | Purpose | |---|---|---| | `ss-local` | `MODULE_LOCAL` | SOCKS5 client proxy | | `ss-server` | `MODULE_REMOTE` | Server-side proxy | | `ss-tunnel` | `MODULE_TUNNEL` | Port forwarding tunnel (implies `MODULE_LOCAL`) | | `ss-redir` | `MODULE_REDIR` | Transparent proxy via iptables (Linux only, implies `MODULE_LOCAL`) | | `ss-manager` | `MODULE_MANAGER` | Multi-server manager daemon | A shared library `libshadowsocks-libev` is also built from the ss-local sources with `-DLIB_ONLY`. Its public API is in `src/shadowsocks.h`. ### Source Organization (`src/`) **Shared by all binaries:** - `utils.c` - logging, system utilities - `jconf.c` / `json.c` - JSON config file parsing - `netutils.c` - network address utilities - `cache.c` - hash-based LRU connection cache - `udprelay.c` - UDP relay implementation (shared, but uses `#ifdef MODULE_*` for per-binary behavior) **Crypto layer** (two parallel implementations behind a common `crypto_t` interface): - `crypto.c` / `crypto.h` - crypto initialization, key derivation (HKDF), buffer management. Defines `crypto_t` with function pointers for encrypt/decrypt. - `stream.c` - stream cipher implementation (CFB mode via mbedTLS) - `aead.c` - AEAD cipher implementation (AES-GCM via mbedTLS, ChaCha20-Poly1305 via libsodium) - `ppbloom.c` - ping-pong bloom filter for nonce replay detection **ACL (Access Control Lists):** - `acl.c` / `rule.c` - IP/domain-based routing rules using libipset **Plugin support:** - `plugin.c` - SIP003 plugin subprocess management ### Bundled Submodules Three git submodules in the repo root (can be replaced with system libs via `-DWITH_EMBEDDED_SRC=OFF`): - `libcork/` - data structures (dllist, hash-table, buffers) - `libipset/` - IP set operations for ACL - `libbloom/` - bloom filter implementation ### Event Loop All binaries use **libev** for async I/O. The connection lifecycle follows stages defined in `src/common.h`: `STAGE_INIT` -> `STAGE_HANDSHAKE` -> `STAGE_RESOLVE` -> `STAGE_STREAM` -> `STAGE_STOP`. Each binary defines its own `listen_ctx_t`, `server_t`, and `remote_t` structs (note: "server" in `local.h` means the local-side connection, "remote" means the ss-server side). ### Compiler Flags Default flags from `CMakeLists.txt`: `-g -O2 -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -std=gnu99 -D_GNU_SOURCE` The `-Werror` flag means all warnings are errors - new code must compile warning-free. ================================================ FILE: CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.5) set(PROJECT_NAME shadowsocks-libev) set(RELEASE_DATE 2026-02-09) set(PROJECT_VERSION "3.3.6") set(PROJECT_DESC "a lightweight secured socks5 proxy") set(PROJECT_URL "https://shadowsocks.org") set(PROJECT_ISSUES_URL "https://github.com/shadowsocks/shadowsocks-libev") project(${PROJECT_NAME} VERSION ${PROJECT_VERSION}) include(GNUInstallDirs) # Compiler flags matching autotools # Note: -Werror is applied per-target in src/CMakeLists.txt to avoid # breaking bundled submodules (libcork, libipset, libbloom) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -D_GNU_SOURCE") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -Wno-deprecated-declarations -fno-strict-aliasing") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) set(RUNTIME_SHARED_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/shared/bin) set(CMAKE_MACOSX_RPATH TRUE) set(CMAKE_POSITION_INDEPENDENT_CODE ON) if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug) endif () # Detect linux if (UNIX AND NOT APPLE) set(LINUX TRUE) endif () message(STATUS "Running cmake version ${CMAKE_VERSION}") option(WITH_STATIC "build with static libraries." ON) option(WITH_EMBEDDED_SRC "build with embedded libcork, libipset, and libbloom source." ON) option(ENABLE_CONNMARKTOS "Enable saved connmark to IP TOS QoS feature" OFF) option(ENABLE_NFTABLES "Report malicious IP to nftables" OFF) # When choose to not use embedded libcork, libipset and libbloom, use libs shipped by system if (NOT WITH_EMBEDDED_SRC) set(USE_SYSTEM_SHARED_LIB TRUE) endif () # Find dependencies via Find modules find_package(PCRE2 REQUIRED) find_package(MbedTLS REQUIRED) find_package(Sodium REQUIRED) find_package(Cares REQUIRED) # Connmarktos support if(ENABLE_CONNMARKTOS) if(NOT LINUX) message(FATAL_ERROR "connmarktos is only supported on Linux") endif() find_library(NETFILTER_CONNTRACK_LIB netfilter_conntrack) find_library(NFNETLINK_LIB nfnetlink) if(NOT NETFILTER_CONNTRACK_LIB) message(FATAL_ERROR "--enable-connmarktos specified but libnetfilter_conntrack not found") endif() set(USE_NFCONNTRACK_TOS 1) message(STATUS "Connmarktos enabled") endif() # Nftables support if(ENABLE_NFTABLES) if(NOT LINUX) message(FATAL_ERROR "nftables is only supported on Linux") endif() find_library(MNL_LIB mnl) find_library(NFTNL_LIB nftnl) if(NOT MNL_LIB OR NOT NFTNL_LIB) message(FATAL_ERROR "--enable-nftables specified but libmnl or libnftnl not found") endif() set(USE_NFTABLES 1) message(STATUS "Nftables enabled") endif() # Run platform tests include(${PROJECT_SOURCE_DIR}/cmake/configure.cmake) configure_file(${PROJECT_SOURCE_DIR}/cmake/config.h.cmake ${PROJECT_BINARY_DIR}/src/config.h) add_definitions(-I${PROJECT_BINARY_DIR}/src) add_definitions(-DHAVE_CONFIG_H) # pkg-config configure_file( ${PROJECT_SOURCE_DIR}/cmake/shadowsocks-libev.pc.cmake ${PROJECT_BINARY_DIR}/pkgconfig/shadowsocks-libev.pc @ONLY ) install(FILES ${PROJECT_BINARY_DIR}/pkgconfig/shadowsocks-libev.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) if (WITH_EMBEDDED_SRC) # We need libcork,libipset headers include_directories(libcork/include) include_directories(libipset/include) include_directories(libbloom/murmur2) include_directories(libbloom) set(LIBCORK_SOURCE libcork/src/libcork/cli/commands.c libcork/src/libcork/core/allocator.c libcork/src/libcork/core/error.c libcork/src/libcork/core/gc.c libcork/src/libcork/core/hash.c libcork/src/libcork/core/ip-address.c libcork/src/libcork/core/mempool.c libcork/src/libcork/core/timestamp.c libcork/src/libcork/core/u128.c libcork/src/libcork/core/version.c libcork/src/libcork/ds/array.c libcork/src/libcork/ds/bitset.c libcork/src/libcork/ds/buffer.c libcork/src/libcork/ds/dllist.c libcork/src/libcork/ds/file-stream.c libcork/src/libcork/ds/hash-table.c libcork/src/libcork/ds/managed-buffer.c libcork/src/libcork/ds/ring-buffer.c libcork/src/libcork/ds/slice.c libcork/src/libcork/posix/directory-walker.c libcork/src/libcork/posix/env.c libcork/src/libcork/posix/exec.c libcork/src/libcork/posix/files.c libcork/src/libcork/posix/process.c libcork/src/libcork/pthreads/thread.c ) if (NOT MINGW) set(LIBCORK_SOURCE ${LIBCORK_SOURCE} libcork/src/libcork/posix/subprocess.c) else () set(LIBCORK_SOURCE ${LIBCORK_SOURCE} libcork/src/libcork/posix/mingw.c) endif () add_library(cork STATIC ${LIBCORK_SOURCE}) target_compile_definitions(cork PUBLIC -DCORK_API=CORK_LOCAL) if (MINGW) target_link_libraries(cork ws2_32) endif () set(LIBIPSET_SOURCE libipset/src/libipset/general.c libipset/src/libipset/bdd/assignments.c libipset/src/libipset/bdd/basics.c libipset/src/libipset/bdd/bdd-iterator.c libipset/src/libipset/bdd/expanded.c libipset/src/libipset/bdd/reachable.c libipset/src/libipset/bdd/read.c libipset/src/libipset/bdd/write.c libipset/src/libipset/map/allocation.c libipset/src/libipset/map/inspection.c libipset/src/libipset/map/ipv4_map.c libipset/src/libipset/map/ipv6_map.c libipset/src/libipset/map/storage.c libipset/src/libipset/set/allocation.c libipset/src/libipset/set/inspection.c libipset/src/libipset/set/ipv4_set.c libipset/src/libipset/set/ipv6_set.c libipset/src/libipset/set/iterator.c libipset/src/libipset/set/storage.c ) add_library(ipset STATIC ${LIBIPSET_SOURCE}) set(LIBBLOOM_SOURCE libbloom/bloom.c libbloom/murmur2/MurmurHash2.c ) add_library(bloom STATIC ${LIBBLOOM_SOURCE}) target_link_libraries(ipset cork bloom) endif () add_subdirectory(src) add_subdirectory(doc) # Testing include(CTest) if(BUILD_TESTING) add_subdirectory(tests) endif() # Install ss-nat on Linux if(LINUX) install(PROGRAMS src/ss-nat DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() # Install ss-setup TUI tool install(PROGRAMS scripts/ss-setup.sh DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME ss-setup) ================================================ FILE: COPYING ================================================ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ================================================ FILE: Changes ================================================ shadowsocks-libev (3.3.5-1) unstable; urgency=medium * Remove the SNI proxy function. * Minor bug fixes. (#2581, #2582, #2590, #2595, #2599, #2600, #2620, #2687, #2692) -- Max Lv Tue, 15 Sep 2020 10:24:43 +0800 shadowsocks-libev (3.3.4-1) unstable; urgency=medium * Minor bug fixes. (#2539, #2565, #2566, #2577) * Security bug fixes. (CVE-2019-5163, CVE-2019-5164) -- Max Lv Fri, 10 Jan 2020 09:28:25 +0800 shadowsocks-libev (3.3.3-1) unstable; urgency=medium * Refine the handling of suspicious connections. -- Max Lv Thu, 31 Oct 2019 15:06:04 +0800 shadowsocks-libev (3.3.2-1) unstable; urgency=medium * Refine the handling of fragment request. * Minor bug fixes. (#2463, #2481, #2508) -- Max Lv Sat, 12 Oct 2019 08:42:24 +0800 shadowsocks-libev (3.3.1-1) unstable; urgency=high * Fix a high CPU bug introduced in 3.3.0. (#2449) * Fix MinGW build. (#2438) * Minor bug fixes. (#2402, #2412, #2427, #2443) -- Max Lv Fri, 09 Aug 2019 15:02:34 +0800 shadowsocks-libev (3.3.0-1) unstable; urgency=medium * Enlarge the socket buffer size to 16KB. * Fix the empty list bug in ss-manager. * Fix the IPv6 address parser. -- Max Lv Sat, 08 Jun 2019 07:53:20 +0800 shadowsocks-libev (3.2.5-1) unstable; urgency=medium * Fix a bug of port parser. -- Max Lv Sat, 09 Mar 2019 18:54:36 +0800 shadowsocks-libev (3.2.4-1) unstable; urgency=medium * Fix a crash with MinGW. * Refine SIP003 plugin interface. * Remove connection timeout from all clients. -- Max Lv Tue, 26 Feb 2019 09:40:18 +0800 shadowsocks-libev (3.2.3-1) unstable; urgency=medium * Fix the alignment issue again. -- Max Lv Wed, 28 Nov 2018 00:27:40 -0800 shadowsocks-libev (3.2.2-1) unstable; urgency=medium * Fix a bug on 32-bit arch. -- Max Lv Mon, 26 Nov 2018 20:07:21 -0800 shadowsocks-libev (3.2.1-1) unstable; urgency=medium * Add TCP fast open support to ss-tunnel by @PantherJohn. * Fix several security issues. -- Max Lv Wed, 07 Nov 2018 22:31:59 -0800 shadowsocks-libev (3.2.0-1) unstable; urgency=medium * Add MinGW support by @linusyang. * Refine c-ares integration by @xnoreq. * Fix building issues with GCC8 by @FlyingheartCN. * Minor bug fixes. -- Max Lv Mon, 28 May 2018 19:46:21 -0700 shadowsocks-libev (3.1.3-1) unstable; urgency=medium * Fix a bug in UDP relay. -- Max Lv Mon, 15 Jan 2018 17:19:31 -0800 shadowsocks-libev (3.1.2-1) unstable; urgency=medium * Fix a bug in DNS resolver. * Add new TFO API support. -- Max Lv Thu, 28 Dec 2017 21:01:56 -0800 shadowsocks-libev (3.1.1-1) unstable; urgency=high * Fix a security issue in ss-manager. (CVE-2017-15924) -- Max Lv Mon, 20 Nov 2017 12:13:04 +0800 shadowsocks-libev (3.1.0-1) unstable; urgency=low * Replace libudns with libc-ares. -- Max Lv Thu, 14 Sep 2017 19:27:51 -0700 shadowsocks-libev (3.0.8-1) unstable; urgency=medium * Refine the ping-pong bloom filter. * Minor bug fixes by @vfreex, @vlolteanu and @jackyyf. -- Max Lv Thu, 27 Jul 2017 11:01:37 +0800 shadowsocks-libev (3.0.7-1) unstable; urgency=medium * Refine manager mode by @mengxd. * Fix a potential memory leak by @vlolteanu. -- Max Lv Tue, 27 Jun 2017 14:08:27 +0800 shadowsocks-libev (3.0.6-1) unstable; urgency=medium * Fix a bug with AEAD ciphers. * Refine ACL support by @blackgear. -- Max Lv Wed, 26 Apr 2017 13:48:11 +0800 shadowsocks-libev (3.0.5-1) unstable; urgency=medium * Fix a bug of TCP Fast Open in ss-redir. -- Max Lv Tue, 21 Mar 2017 13:49:18 +0800 shadowsocks-libev (3.0.4-1) unstable; urgency=medium * Add CMake files by @wenerme. * Support TCP Fast Open in ss-redir by @lqs. * Support TOS/DESCP in ss-redir by @sduponch. * Refine MPTCP by @sduponch. -- Max Lv Thu, 16 Mar 2017 14:07:57 +0800 shadowsocks-libev (3.0.3-1) unstable; urgency=medium * Replace nonce cache with a ping-pong bloom filter. -- Max Lv Fri, 24 Feb 2017 12:08:31 +0800 shadowsocks-libev (3.0.2-1) unstable; urgency=high * Add session key for AEAD. (SIP007) -- Max Lv Mon, 13 Feb 2017 09:07:17 +0800 shadowsocks-libev (3.0.1-1) unstable; urgency=medium * Fix a crashe when using stream ciphers. * Fix a protocol bug in AEAD ciphers. (SIP004) * Allow setting keys directly. (SIP006) -- Max Lv Tue, 07 Feb 2017 13:18:02 +0800 shadowsocks-libev (3.0.0-1) unstable; urgency=medium * Drop dependencies of OpenSSL and PolarSSL. * Deprecate OTA (One-Time-Auth). * Add new ciphers for SIP004: aes-128-gcm, aes-192-gcm, aes-256-gcm, chacha20-poly1305 and chacha20-ietf-poly1305. * Refine SIP003 to support standalone mode of obfsproxy. -- Max Lv Wed, 01 Feb 2017 19:10:14 +0800 shadowsocks-libev (2.6.3-1) unstable; urgency=medium * Refine the project structure. -- Max Lv Tue, 24 Jan 2017 19:10:45 +0800 shadowsocks-libev (2.6.2-1) unstable; urgency=medium * Refine SIP003 plugin support. -- Max Lv Mon, 16 Jan 2017 10:16:12 +0800 shadowsocks-libev (2.6.1-1) unstable; urgency=medium * Deprecate HTTP/TLS obfuscating. * Add SIP003 plugin support. -- Max Lv Sun, 08 Jan 2017 15:14:19 +0800 shadowsocks-libev (2.6.0-1) unstable; urgency=medium * Add HTTP/TLS obfuscating. * Add support of aunch_activate_socket on macOS. -- Max Lv Tue, 27 Dec 2016 16:37:23 +0800 shadowsocks-libev (2.5.6-1) unstable; urgency=medium * Add outbound ACL for server. * Refine log format. -- Max Lv Tue, 01 Nov 2016 09:51:52 +0800 shadowsocks-libev (2.5.5-1) unstable; urgency=medium * Refine attack detection. -- Max Lv Tue, 11 Oct 2016 15:45:09 +0800 shadowsocks-libev (2.5.4-1) unstable; urgency=medium * Fix a bug of auto blocking mechanism. -- Max Lv Sun, 09 Oct 2016 19:36:37 +0800 shadowsocks-libev (2.5.3-1) unstable; urgency=medium * Fix TCP Fast Open on macOS. -- Max Lv Wed, 21 Sep 2016 19:31:57 +0800 shadowsocks-libev (2.5.2-1) unstable; urgency=medium * Fix a bug of UDP relay mode of ss-local. -- Max Lv Mon, 12 Sep 2016 12:54:33 +0800 shadowsocks-libev (2.5.1-1) unstable; urgency=medium * Refine ACL feature with hostname support. * Add HTTP/SNI parser for ss-local/ss-redir. -- Max Lv Sat, 10 Sep 2016 17:06:49 +0800 shadowsocks-libev (2.5.0-1) unstable; urgency=medium * Fix several bugs of the command line interface. * Add aes-128/192/256-ctr ciphers. * Add option MTU for UDP relay. * Add MultiPath TCP support. -- Max Lv Mon, 29 Aug 2016 13:07:51 +0800 shadowsocks-libev (2.4.8-1) unstable; urgency=low * Update manual pages with asciidoc. * Fix issues of bind_address option. -- Max Lv Wed, 20 Jul 2016 09:25:50 +0800 shadowsocks-libev (2.4.7-1) unstable; urgency=low * Add ss-nat, a helper script to set up NAT rules for ss-redir. * Fix several issues for debian package. -- Max Lv Wed, 1 Jun 2016 18:21:45 +0800 shadowsocks-libev (2.4.6-1) unstable; urgency=low * Update manual pages. -- Max Lv Thu, 21 Apr 2016 17:33:34 +0800 shadowsocks-libev (2.4.5-1) unstable; urgency=low * Fix build issues on OpenWRT. * Reduce the latency of redir mode. -- Max Lv Mon, 01 Feb 2016 13:22:50 +0800 shadowsocks-libev (2.4.4-1) unstable; urgency=low * Fix a potential memory leak. * Fix some compiler related issues. -- Max Lv Wed, 13 Jan 2016 11:50:12 +0800 shadowsocks-libev (2.4.3-1) unstable; urgency=high * Refine the buffer allocation. -- Max Lv Sat, 19 Dec 2015 12:30:21 +0900 shadowsocks-libev (2.4.1-1) unstable; urgency=high * Fix a security bug. -- Max Lv Thu, 29 Oct 2015 15:42:47 +0900 shadowsocks-libev (2.4.0-1) unstable; urgency=low * Update the one-time authentication -- Max Lv Thu, 24 Sep 2015 14:11:05 +0900 shadowsocks-libev (2.3.3-1) unstable; urgency=low * Refine the onetime authentication of header. * Enforce CRC16 on the payload. -- Max Lv Fri, 18 Sep 2015 10:38:21 +0900 shadowsocks-libev (2.3.2-1) unstable; urgency=low * Fix minor issues of build scripts. -- Max Lv Sun, 13 Sep 2015 15:22:28 +0900 shadowsocks-libev (2.3.1-1) unstable; urgency=low * Fix an issue of connection cache of UDP relay. * Add support of onetime authentication for header verification. -- Max Lv Fri, 04 Sep 2015 07:54:02 +0900 shadowsocks-libev (2.3.0-1) unstable; urgency=low * Add manager mode to support multi-user and traffic stat. * Fix a build issue on OS X El Capitan. -- Max Lv Thu, 30 Jul 2015 17:30:43 +0900 shadowsocks-libev (2.2.3-1) unstable; urgency=high * Fix the multiple UDP source port issue. * Allow working in UDP only mode. -- Max Lv Sat, 11 Jul 2015 08:31:02 +0900 shadowsocks-libev (2.2.2-1) unstable; urgency=low * Fix the timer of UDP relay. * Check name_len in the header. -- Max Lv Mon, 15 Jun 2015 10:26:40 +0900 shadowsocks-libev (2.2.1-1) unstable; urgency=low * Fix an issue of UDP relay. -- Max Lv Sun, 10 May 2015 21:23:44 +0900 shadowsocks-libev (2.2.0-1) unstable; urgency=low * Add TPROXY support in redir mode. -- Max Lv Mon, 04 May 2015 02:44:17 -0300 shadowsocks-libev (2.1.4-1) unstable; urgency=low * Fix a bug of server mode ACL. -- Max Lv Sun, 08 Feb 2015 20:24:43 +0900 shadowsocks-libev (2.1.3-1) unstable; urgency=low * Add ACL support to remote server. -- Max Lv Sun, 08 Feb 2015 10:59:44 +0900 shadowsocks-libev (2.1.2-1) unstable; urgency=low * Refine multiple port binding. -- Max Lv Sat, 31 Jan 2015 18:56:25 +0900 shadowsocks-libev (2.1.1-1) unstable; urgency=low * Fix a memory leak. -- Max Lv Wed, 21 Jan 2015 21:40:58 +0900 shadowsocks-libev (2.1.0-1) unstable; urgency=low * Fix a bug of tunnel mode. -- Max Lv Mon, 19 Jan 2015 09:59:52 +0900 shadowsocks-libev (2.0.8-1) unstable; urgency=low * Fix a bug of IPv6. -- Max Lv Fri, 16 Jan 2015 10:58:12 +0900 shadowsocks-libev (2.0.7-1) unstable; urgency=low * Fix some performance issue. -- Max Lv Tue, 13 Jan 2015 13:17:58 +0900 shadowsocks-libev (2.0.6-1) unstable; urgency=high * Fix a critical issue in redir mode. -- Max Lv Mon, 12 Jan 2015 21:51:19 +0900 shadowsocks-libev (2.0.5-1) unstable; urgency=low * Refine local, tunnel, and redir modes. -- Max Lv Mon, 12 Jan 2015 12:39:05 +0800 shadowsocks-libev (2.0.4-1) unstable; urgency=low * Fix building issues with MinGW32. -- Max Lv Sun, 11 Jan 2015 13:33:31 +0900 shadowsocks-libev (2.0.3-1) unstable; urgency=high * Fix some issues. -- Max Lv Sat, 10 Jan 2015 16:27:54 +0800 shadowsocks-libev (2.0.2-1) unstable; urgency=low * Fix issues with MinGW. -- Max Lv Sat, 10 Jan 2015 15:17:10 +0800 shadowsocks-libev (2.0.1-1) unstable; urgency=low * Implement a real asynchronous DNS resolver. -- Max Lv Sat, 10 Jan 2015 10:04:28 +0800 shadowsocks-libev (1.6.4-1) unstable; urgency=low * Update documents. -- Max Lv Wed, 07 Jan 2015 21:48:58 +0900 shadowsocks-libev (1.6.3-1) unstable; urgency=low * Refine ss-redir. -- Max Lv Sun, 04 Jan 2015 19:23:52 +0900 shadowsocks-libev (1.6.2-1) unstable; urgency=low * Fix some build issues. -- Max Lv Tue, 30 Dec 2014 10:30:28 +0800 shadowsocks-libev (1.6.1-1) unstable; urgency=high * Add salsa20 and chacha20 support. -- Max Lv Sat, 13 Dec 2014 15:11:34 +0800 shadowsocks-libev (1.6.0-1) unstable; urgency=low * Solve conflicts with other shadowsocks portings. -- Max Lv Mon, 17 Nov 2014 14:10:21 +0800 shadowsocks-libev (1.5.3-2) unstable; urgency=low * rename as shadowsocks-libev. -- Symeon Huang Sat, 15 Nov 2014 14:55:28 +0000 shadowsocks (1.5.3-1) unstable; urgency=low * Fix log on Win32. -- Max Lv Fri, 14 Nov 2014 09:10:06 +0800 shadowsocks (1.5.2-1) unstable; urgency=low * Handle SIGTERM and SIGKILL nicely. -- Max Lv Tue, 12 Nov 2014 13:11:29 +0800 shadowsocks (1.5.1-1) unstable; urgency=low * Fix a bug of tcp fast open. -- Max Lv Sat, 08 Nov 2014 19:45:37 +0900 shadowsocks (1.5.0-1) unstable; urgency=low * Support to build static or shared library. * Supprot IPv6 NAT in redirect mode. * Refine the cache size of UDPRelay. -- Max Lv Fri, 07 Nov 2014 09:33:19 +0800 shadowsocks (1.4.8-1) unstable; urgency=low * Fix a bug of tcp fast open. -- Max Lv Wed, 08 Oct 2014 18:02:02 +0800 shadowsocks (1.4.7-1) unstable; urgency=low * Add a new encryptor rc4-md5. -- Max Lv Tue, 09 Sep 2014 07:50:10 +0800 shadowsocks (1.4.6-1) unstable; urgency=low * Add ACL support. -- Max Lv Sat, 03 May 2014 04:37:10 -0400 shadowsocks (1.4.5-1) unstable; urgency=high * Fix the compatibility issue of udprelay. * Enhance asyncns to reduce the latency. * Add TCP_FASTOPEN support. -- Max Lv Sun, 20 Apr 2014 08:12:45 +0800 shadowsocks (1.4.4-1) unstable; urgency=low * Add CommonCrypto support for darwin. * Fix some config related issues. -- Max Lv Wed, 26 Mar 2014 13:29:03 +0800 shadowsocks (1.4.3-1) unstable; urgency=low * Add tunnel mode with local port forwarding feature. -- Max Lv Fri, 21 Feb 2014 11:52:13 +0900 shadowsocks (1.4.2-1) unstable; urgency=high * Fix the UDP relay issues. * Add syslog support. -- Max Lv Sun, 05 Jan 2014 10:05:29 +0900 shadowsocks (1.4.1-1) unstable; urgency=low * Add multi-port support. * Add PolarSSL support by @linusyang. -- Max Lv Tue, 12 Nov 2013 03:57:21 +0000 shadowsocks (1.4.0-1) unstable; urgency=low * Add standard socks5 udp support. -- Max Lv Sun, 08 Sep 2013 02:20:40 +0000 shadowsocks (1.3.3-1) unstable; urgency=high * Provide more info in verbose mode. -- Max Lv Fri, 21 Jun 2013 09:59:20 +0800 shadowsocks (1.3.2-1) unstable; urgency=high * Fix some ciphers by @linusyang. -- Max Lv Sun, 09 Jun 2013 09:52:31 +0000 shadowsocks (1.3.1-1) unstable; urgency=low * Support more cihpers: camellia, idea, rc2 and seed. -- Max Lv Tue, 04 Jun 2013 00:56:17 +0000 shadowsocks (1.3-1) unstable; urgency=low * Able to bind connections to specific interface. * Support more ciphers: aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb. -- Max Lv Thu, 16 May 2013 10:51:15 +0800 shadowsocks (1.2-2) unstable; urgency=low * Close timeouted TCP connections. -- Max Lv Tue, 07 May 2013 14:10:33 +0800 shadowsocks (1.2-1) unstable; urgency=low * Fix a high load issue. -- Max Lv Thu, 18 Apr 2013 10:52:34 +0800 shadowsocks (1.1-1) unstable; urgency=low * Fix a IPV6 resolve issue. -- Max Lv Wed, 10 Apr 2013 12:11:36 +0800 shadowsocks (1.0-2) unstable; urgency=low * Initial release. -- Max Lv Sat, 06 Apr 2013 16:59:15 +0800 ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS ================================================ FILE: README.md ================================================ # shadowsocks-libev [![Build Status](https://travis-ci.com/shadowsocks/shadowsocks-libev.svg?branch=master)](https://travis-ci.com/shadowsocks/shadowsocks-libev) [![Snap Status](https://snapcraft.io/shadowsocks-libev/badge.svg)](https://snapcraft.io/shadowsocks-libev) ## Intro [Shadowsocks-libev](https://shadowsocks.org) is a lightweight secured SOCKS5 proxy for embedded devices and low-end boxes. It is a port of [Shadowsocks](https://github.com/shadowsocks/shadowsocks) created by [@clowwindy](https://github.com/clowwindy), and maintained by [@madeye](https://github.com/madeye) and [@linusyang](https://github.com/linusyang). Current version: 3.3.6 | [Changelog](debian/changelog) ## Features Shadowsocks-libev is written in pure C and depends on [libev](http://software.schmorp.de/pkg/libev.html). It's designed to be a lightweight implementation of shadowsocks protocol, in order to keep the resource usage as low as possible. For a full list of feature comparison between different versions of shadowsocks, refer to the [Wiki page](https://github.com/shadowsocks/shadowsocks/wiki/Feature-Comparison-across-Different-Versions). ## Quick Start Snap is the recommended way to install the latest binaries. ### Install snap core https://snapcraft.io/core ### Install from snapcraft.io Stable channel: ```bash sudo snap install shadowsocks-libev ``` Edge channel: ```bash sudo snap install shadowsocks-libev --edge ``` ## Installation ### Distribution-specific guide - [Debian & Ubuntu](#debian--ubuntu) + [Install from repository](#install-from-repository-not-recommended) + [Build deb package from source](#build-deb-package-from-source) + [Configure and start the service](#configure-and-start-the-service) - [Fedora & RHEL](#fedora--rhel) + [Build from source with centos](#build-from-source-with-centos) - [Archlinux & Manjaro](#archlinux--manjaro) - [NixOS](#nixos) - [Nix](#nix) - [Directly build and install on UNIX-like system](#linux) - [FreeBSD](#freebsd) + [Install](#install) + [Configuration](#configuration) + [Run](#run) + [Run as client](#run-as-client) - [OpenWRT](#openwrt) - [OS X](#os-x) - [Windows (MinGW)](#windows-mingw) - [Docker](#docker) * * * ### Build from source (CMake) shadowsocks-libev uses CMake as its sole build system. Start by pulling submodules: ```bash git submodule update --init --recursive ``` Then build: ```bash mkdir -p build && cd build cmake .. make sudo make install ``` To run unit tests: ```bash cd build ctest --output-on-failure ``` #### CMake options For a complete list of available options, run `cmake -LH` from a build directory. Commonly used options: | Option | Default | Description | |---|---|---| | `-DWITH_EMBEDDED_SRC=OFF` | `ON` | Use system libcork/libipset/libbloom instead of bundled submodules | | `-DWITH_DOC_MAN=OFF` | `ON` | Skip man page generation (removes asciidoc/xmlto dependency) | | `-DBUILD_TESTING=OFF` | `ON` | Disable unit tests | | `-DENABLE_CONNMARKTOS=ON` | `OFF` | Linux netfilter conntrack QoS support | | `-DENABLE_NFTABLES=ON` | `OFF` | nftables firewall integration | On macOS, if libraries are installed via Homebrew, specify paths: ```bash cmake .. -DCMAKE_PREFIX_PATH="/usr/local/opt/mbedtls;/usr/local/opt/libsodium" ``` ### Debian & Ubuntu #### Install from repository (not recommended) Shadowsocks-libev is available in the official repository for following distributions: * Debian 8 or higher, including oldoldstable (jessie), old stable (stretch), stable (buster), testing (bullseye) and unstable (sid) * Ubuntu 16.10 or higher ```bash sudo apt update sudo apt install shadowsocks-libev ``` #### Build deb package from source You can build shadowsocks-libev and all its dependencies by script: ```bash mkdir -p ~/build-area/ cp ./scripts/build_deb.sh ~/build-area/ cd ~/build-area ./build_deb.sh ``` For older systems, building `.deb` packages is not supported. Please try to build and install directly from source. See the [Linux](#linux) section below. #### Configure and start the service ``` # Edit the configuration file sudo vim /etc/shadowsocks-libev/config.json # Edit the default configuration for debian sudo vim /etc/default/shadowsocks-libev # Start the service sudo /etc/init.d/shadowsocks-libev start # for sysvinit, or sudo systemctl start shadowsocks-libev # for systemd ``` ### Fedora & RHEL Supported distributions: * Recent Fedora versions (until EOL) * RHEL 6, 7 and derivatives (including CentOS, Scientific Linux) #### Build from source with centos If you are using CentOS 7, you need to install these prerequirements to build from source code: ```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 ``` ### Archlinux & Manjaro ```bash sudo pacman -S shadowsocks-libev ``` Please refer to downstream [PKGBUILD](https://github.com/archlinux/svntogit-community/blob/packages/shadowsocks-libev/trunk/PKGBUILD) script for extra modifications and distribution-specific bugs. ### NixOS ```bash nix-env -iA nixos.shadowsocks-libev ``` ### Nix ```bash nix-env -iA nixpkgs.shadowsocks-libev ``` ### Linux In general, you need the following build dependencies: * cmake (>= 3.2) * a C compiler (gcc or clang) * pkg-config * libmbedtls * libsodium (>= 1.0.4) * libpcre2 * libev * libc-ares * asciidoc (for documentation only) * xmlto (for documentation only) If your system is too old to provide libmbedtls and libsodium (>= 1.0.4), you will need to either install those libraries manually or upgrade your system. Install build dependencies for your distribution: ```bash # Debian / Ubuntu sudo apt-get install --no-install-recommends build-essential cmake pkg-config \ libpcre2-dev libev-dev libc-ares-dev libmbedtls-dev libsodium-dev \ asciidoc xmlto # CentOS / Fedora / RHEL sudo yum install gcc cmake make pkg-config pcre2-devel c-ares-devel \ libev-devel libsodium-devel mbedtls-devel asciidoc xmlto # Arch sudo pacman -S gcc cmake make pkg-config pcre2 c-ares libev libsodium mbedtls \ asciidoc xmlto ``` Then build and install: ```bash git submodule update --init --recursive mkdir -p build && cd build cmake .. make sudo make install ``` ### FreeBSD #### Install Shadowsocks-libev is available in FreeBSD Ports Collection. You can install it in either way, `pkg` or `ports`. **pkg (recommended)** ```bash pkg install shadowsocks-libev ``` **ports** ```bash cd /usr/ports/net/shadowsocks-libev make install ``` #### Configuration Edit your `config.json` file. By default, it's located in `/usr/local/etc/shadowsocks-libev`. To enable shadowsocks-libev, add the following rc variable to your `/etc/rc.conf` file: ``` shadowsocks_libev_enable="YES" ``` #### Run Start the Shadowsocks server: ```bash service shadowsocks_libev start ``` #### Run as client By default, shadowsocks-libev is running as a server in FreeBSD. If you would like to start shadowsocks-libev in client mode, you can modify the rc script (`/usr/local/etc/rc.d/shadowsocks_libev`) manually. ``` # modify the following line from "ss-server" to "ss-local" command="/usr/local/bin/ss-local" ``` Note that is simply a workaround, each time you upgrade the port your changes will be overwritten by the new version. ### OpenWRT The OpenWRT project is maintained here: [openwrt-shadowsocks](https://github.com/shadowsocks/openwrt-shadowsocks). ### OS X For OS X, use [Homebrew](http://brew.sh) to install or build. Install Homebrew: ```bash ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" ``` Install shadowsocks-libev: ```bash brew install shadowsocks-libev ``` ### Windows (MinGW) To build Windows native binaries, the recommended method is to use Docker: * On Windows: double-click `make.bat` in `docker\mingw` * On Unix-like system: cd shadowsocks-libev/docker/mingw make A tarball with 32-bit and 64-bit binaries will be generated in the same directory. You could also manually use MinGW-w64 compilers to build in Unix-like shell (MSYS2/Cygwin), or cross-compile on Unix-like systems (Linux/MacOS). Please refer to build scripts in `docker/mingw`. Currently you need to use a patched libev library for MinGW: * https://github.com/shadowsocks/libev/archive/mingw.zip Notice that TCP Fast Open (TFO) is only available on **Windows 10**, **1607** or later version (precisely, build >= 14393). If you are using **1709** (build 16299) or later version, you also need to run the following command in PowerShell/Command Prompt **as Administrator** and **reboot** to use TFO properly: netsh int tcp set global fastopenfallback=disabled ### Docker As you expect, simply pull the image and run. ``` docker pull shadowsocks/shadowsocks-libev docker run -e PASSWORD= -p:8388 -p:8388/udp -d shadowsocks/shadowsocks-libev ``` More information about the image can be found [here](docker/alpine/README.md). ## Usage For a detailed and complete list of all supported arguments, you may refer to the man pages of the applications, respectively. ss-[local|redir|server|tunnel|manager] -s Host name or IP address of your remote server. -p Port number of your remote server. -l Port number of your local server. -k Password of your remote server. -m Encrypt method: rc4-md5, aes-128-gcm, aes-192-gcm, aes-256-gcm, aes-128-cfb, aes-192-cfb, aes-256-cfb, aes-128-ctr, aes-192-ctr, aes-256-ctr, camellia-128-cfb, camellia-192-cfb, camellia-256-cfb, bf-cfb, chacha20-ietf-poly1305, xchacha20-ietf-poly1305, salsa20, chacha20 and chacha20-ietf. The default cipher is chacha20-ietf-poly1305. [-a ] Run as another user. [-f ] The file path to store pid. [-t ] Socket timeout in seconds. [-c ] The path to config file. [-n ] Max number of open files. [-i ] Network interface to bind. (not available in redir mode) [-b ] Local address to bind. For servers: Specify the local address to use while this server is making outbound connections to remote servers on behalf of the clients. For clients: Specify the local address to use while this client is making outbound connections to the server. [-u] Enable UDP relay. (TPROXY is required in redir mode) [-U] Enable UDP relay and disable TCP relay. (not available in local mode) [-T] Use tproxy instead of redirect. (for tcp) (only available in redir mode) [-L :] Destination server address and port for local port forwarding. (only available in tunnel mode) [-6] Resolve hostname to IPv6 address first. [-d ] Name servers for internal DNS resolver. (only available in server mode) [--reuse-port] Enable port reuse. [--fast-open] Enable TCP fast open. with Linux kernel > 3.7.0. (only available in local and server mode) [--acl ] Path to ACL (Access Control List). (only available in local and server mode) [--manager-address ] UNIX domain socket address. (only available in server and manager mode) [--mtu ] MTU of your network interface. [--mptcp] Enable Multipath TCP on MPTCP Kernel. [--no-delay] Enable TCP_NODELAY. [--executable ] Path to the executable of ss-server. (only available in manager mode) [-D ] Path to the working directory of ss-manager. (only available in manager mode) [--key ] Key of your remote server. [--plugin ] Enable SIP003 plugin. (Experimental) [--plugin-opts ] Set SIP003 plugin options. (Experimental) [-v] Verbose mode. ## Helper Scripts ### ss-setup `ss-setup` is an interactive TUI (text user interface) tool for setting up shadowsocks-libev server and client configurations. It uses `whiptail` or `dialog` for the menu interface. It is installed automatically by `make install` and can also be run directly from `scripts/ss-setup.sh`. **Prerequisites:** `whiptail` or `dialog`, `openssl` (optional, for password generation) #### Server setup (with systemd service) Run as root for full functionality (config + systemd service installation): ```bash sudo ss-setup ``` This launches an interactive menu that walks you through: 1. Choosing a config instance name 2. Setting the listen address and port (manual or random high port) 3. Selecting an AEAD cipher (chacha20-ietf-poly1305, aes-256-gcm, etc.) 4. Generating or entering a password 5. Configuring timeout, network mode (TCP/UDP), and TCP Fast Open 6. Optionally selecting a SIP003 plugin 7. Installing and starting a systemd service The config is saved to `/etc/shadowsocks-libev/.json` and a systemd template service `shadowsocks-libev-server@.service` is created. At the end, it displays a `ss://` URI you can import into clients. #### Client config generation Select "Generate ss-local client config" from the main menu. The wizard prompts for the remote server address, port, cipher, password, and local SOCKS5 port, then writes a JSON config: ```bash # Run without root to generate config in the current directory ss-setup # Select: client -> fill in server details -> save # Then start the client ss-local -c ~/ss-client.json ``` #### Config-only mode (non-root) When run without root, `ss-setup` skips service installation and plugin management, but still generates config files in the current directory: ```bash ss-setup # Config saved to ./config.json (in current directory) # Start manually: ss-server -c ./config.json ``` #### Service management From the main menu, select "Manage running services" to start, stop, restart, enable/disable, or view logs for any configured instance: ``` sudo ss-setup # Select: service -> pick instance -> start/stop/restart/logs ``` #### Plugin installation Select "Install a SIP003 plugin" from the main menu (requires root). Supports automatic download of: - simple-obfs (build from source or package manager) - v2ray-plugin (GitHub release) - xray-plugin (GitHub release) - kcptun (GitHub release) - Custom plugin binary ### ss-nat `ss-nat` is a helper script that sets up iptables NAT rules for `ss-redir` to provide transparent TCP/UDP redirection. It is installed on Linux systems by `make install`. **Prerequisites:** Linux with `iptables`, `ipset`, and optionally TPROXY kernel module for UDP #### Basic usage (TCP redirect) ```bash # Start ss-redir first ss-redir -s YOUR_SERVER_IP -p 8388 -l 1080 -k PASSWORD -m chacha20-ietf-poly1305 -u # Set up NAT rules to redirect TCP traffic through ss-redir sudo ss-nat -s YOUR_SERVER_IP -l 1080 ``` #### Enable UDP relay with TPROXY ```bash sudo ss-nat -s YOUR_SERVER_IP -l 1080 -u ``` #### Apply rules to OUTPUT chain (proxy the local machine itself) ```bash sudo ss-nat -s YOUR_SERVER_IP -l 1080 -u -o ``` #### Use separate TCP/UDP servers ```bash sudo ss-nat -s TCP_SERVER_IP -l 1080 -S UDP_SERVER_IP -L 1080 -U ``` #### Bypass specific WAN IPs ```bash sudo ss-nat -s YOUR_SERVER_IP -l 1080 -b "1.2.3.4 5.6.7.8" ``` #### Use a bypass IP list file ```bash # Create a file with one IP/CIDR per line echo "1.2.3.0/24" > /etc/ss-bypass.list echo "5.6.7.0/24" >> /etc/ss-bypass.list sudo ss-nat -s YOUR_SERVER_IP -l 1080 -i /etc/ss-bypass.list ``` #### LAN access control ```bash # Whitelist mode: only proxy traffic from these LAN IPs sudo ss-nat -s YOUR_SERVER_IP -l 1080 -a "w192.168.1.10 192.168.1.20" # Blacklist mode: proxy all LAN traffic except these IPs sudo ss-nat -s YOUR_SERVER_IP -l 1080 -a "b192.168.1.100" ``` #### Flush all rules ```bash sudo ss-nat -f ``` #### Complete example: transparent proxy gateway Set up a Linux box as a transparent proxy gateway for the entire LAN: ```bash # 1. Start ss-redir with UDP relay ss-redir -s YOUR_SERVER_IP -p 8388 -l 1080 -k PASSWORD \ -m chacha20-ietf-poly1305 -u -f /var/run/ss-redir.pid # 2. Set up NAT rules (TCP + UDP, apply to local OUTPUT too) sudo ss-nat -s YOUR_SERVER_IP -l 1080 -u -o -I eth0 # 3. Point other devices' default gateway to this machine's LAN IP # and set their DNS to a public resolver (e.g., 1.1.1.1 or 8.8.8.8) # To tear down: sudo ss-nat -f ``` ## Transparent proxy (manual iptables) The latest shadowsocks-libev has provided a *redir* mode. You can configure your Linux-based box or router to proxy all TCP traffic transparently, which is handy if you use an OpenWRT-powered router. Note: For most use cases, [`ss-nat`](#ss-nat) above is simpler than writing iptables rules manually. # 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 ## Transparent proxy (pure tproxy) Executing this script on the linux host can proxy all outgoing traffic of this machine (except the traffic sent to the reserved address). Other hosts under the same LAN can also change their default gateway to the ip of this linux host (at the same time change the dns server to 1.1.1.1 or 8.8.8.8, etc.) to proxy their outgoing traffic. > Of course, the ipv6 proxy is similar, just change `iptables` to `ip6tables`, `ip` to `ip -6`, `127.0.0.1` to `::1`, and other details. ```shell #!/bin/bash start_ssredir() { # please modify MyIP, MyPort, etc. (ss-redir -s MyIP -p MyPort -m MyMethod -k MyPasswd -b 127.0.0.1 -l 60080 --no-delay -u -T -v >/var/log/ss-redir.log &) } stop_ssredir() { kill -9 $(pidof ss-redir) &>/dev/null } start_iptables() { ##################### SSREDIR ##################### iptables -t mangle -N SSREDIR # connection-mark -> packet-mark iptables -t mangle -A SSREDIR -j CONNMARK --restore-mark iptables -t mangle -A SSREDIR -m mark --mark 0x2333 -j RETURN # please modify MyIP, MyPort, etc. # ignore traffic sent to ss-server iptables -t mangle -A SSREDIR -p tcp -d MyIP --dport MyPort -j RETURN iptables -t mangle -A SSREDIR -p udp -d MyIP --dport MyPort -j RETURN # ignore traffic sent to reserved addresses iptables -t mangle -A SSREDIR -d 0.0.0.0/8 -j RETURN iptables -t mangle -A SSREDIR -d 10.0.0.0/8 -j RETURN iptables -t mangle -A SSREDIR -d 100.64.0.0/10 -j RETURN iptables -t mangle -A SSREDIR -d 127.0.0.0/8 -j RETURN iptables -t mangle -A SSREDIR -d 169.254.0.0/16 -j RETURN iptables -t mangle -A SSREDIR -d 172.16.0.0/12 -j RETURN iptables -t mangle -A SSREDIR -d 192.0.0.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 192.0.2.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 192.88.99.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 192.168.0.0/16 -j RETURN iptables -t mangle -A SSREDIR -d 198.18.0.0/15 -j RETURN iptables -t mangle -A SSREDIR -d 198.51.100.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 203.0.113.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 224.0.0.0/4 -j RETURN iptables -t mangle -A SSREDIR -d 240.0.0.0/4 -j RETURN iptables -t mangle -A SSREDIR -d 255.255.255.255/32 -j RETURN # mark the first packet of the connection iptables -t mangle -A SSREDIR -p tcp --syn -j MARK --set-mark 0x2333 iptables -t mangle -A SSREDIR -p udp -m conntrack --ctstate NEW -j MARK --set-mark 0x2333 # packet-mark -> connection-mark iptables -t mangle -A SSREDIR -j CONNMARK --save-mark ##################### OUTPUT ##################### # proxy the outgoing traffic from this machine iptables -t mangle -A OUTPUT -p tcp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j SSREDIR iptables -t mangle -A OUTPUT -p udp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j SSREDIR ##################### PREROUTING ##################### # proxy traffic passing through this machine (other->other) iptables -t mangle -A PREROUTING -p tcp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j SSREDIR iptables -t mangle -A PREROUTING -p udp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j SSREDIR # hand over the marked package to TPROXY for processing iptables -t mangle -A PREROUTING -p tcp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port 60080 iptables -t mangle -A PREROUTING -p udp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port 60080 } stop_iptables() { ##################### PREROUTING ##################### iptables -t mangle -D PREROUTING -p tcp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port 60080 &>/dev/null iptables -t mangle -D PREROUTING -p udp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port 60080 &>/dev/null iptables -t mangle -D PREROUTING -p tcp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j SSREDIR &>/dev/null iptables -t mangle -D PREROUTING -p udp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j SSREDIR &>/dev/null ##################### OUTPUT ##################### iptables -t mangle -D OUTPUT -p tcp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j SSREDIR &>/dev/null iptables -t mangle -D OUTPUT -p udp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j SSREDIR &>/dev/null ##################### SSREDIR ##################### iptables -t mangle -F SSREDIR &>/dev/null iptables -t mangle -X SSREDIR &>/dev/null } start_iproute2() { ip route add local default dev lo table 100 ip rule add fwmark 0x2333 table 100 } stop_iproute2() { ip rule del table 100 &>/dev/null ip route flush table 100 &>/dev/null } start_resolvconf() { # or nameserver 8.8.8.8, etc. echo "nameserver 1.1.1.1" >/etc/resolv.conf } stop_resolvconf() { echo "nameserver 114.114.114.114" >/etc/resolv.conf } start() { echo "start ..." start_ssredir start_iptables start_iproute2 start_resolvconf echo "start end" } stop() { echo "stop ..." stop_resolvconf stop_iproute2 stop_iptables stop_ssredir echo "stop end" } restart() { stop sleep 1 start } main() { if [ $# -eq 0 ]; then echo "usage: $0 start|stop|restart ..." return 1 fi for funcname in "$@"; do if [ "$(type -t $funcname)" != 'function' ]; then echo "'$funcname' not a shell function" return 1 fi done for funcname in "$@"; do $funcname done return 0 } main "$@" ``` ## Security Tips For any public server, to avoid users accessing localhost of your server, please add `--acl acl/server_block_local.acl` to the command line. Although shadowsocks-libev can handle thousands of concurrent connections nicely, we still recommend setting up your server's firewall rules to limit connections from each user: # Up to 32 connections are enough for normal usage iptables -A INPUT -p tcp --syn --dport ${SHADOWSOCKS_PORT} -m connlimit --connlimit-above 32 -j REJECT --reject-with tcp-reset ## License ``` Copyright: 2013-2015, Clow Windy 2013-2018, Max Lv 2014, Linus Yang This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ``` ================================================ FILE: README_pt_BR.md ================================================ # shadowsocks-libev [![Build Status](https://travis-ci.com/shadowsocks/shadowsocks-libev.svg?branch=master)](https://travis-ci.com/shadowsocks/shadowsocks-libev) [![Snap Status](https://build.snapcraft.io/badge/shadowsocks/shadowsocks-libev.svg)](https://build.snapcraft.io/user/shadowsocks/shadowsocks-libev) ## Introdução [Shadowsocks-libev](https://shadowsocks.org) é um SOCKS5 leve e seguro proxy para dispositivos embutidos e caixas de baixo custo. É uma porta de [Shadowsocks](https://github.com/shadowsocks/shadowsocks) criado por [@clowwindy](https://github.com/clowwindy) e mantido por [@madeye](https://github.com/madeye) e [@linusyang](https://github.com/linusyang). Versão atual: 3.3.6 | [Changelog](debian/changelog) ## Características Shadowsocks-libev é escrito em C puro e depende de [libev](http://software.schmorp.de/pkg/libev.html). Ele foi projetado para ser uma implementação leve do protocolo shadowsocks, a fim de manter o uso de recursos o mais baixo possível. Para obter uma lista completa de comparação de recursos entre diferentes versões de shadowsocks, consulte a [página da Wiki (https://github.com/shadowsocks/shadowsocks/wiki/Feature-Comparison-across-Different-Versions). ## Começo rápido Snap é a maneira recomendada de instalar os binários mais recentes. ### Instale o snap core https://snapcraft.io/core ### Instalar a partir do snapcraft.io Stable channel: ```bash sudo snap install shadowsocks-libev ``` Edge channel: ```bash sudo snap install shadowsocks-libev --edge ``` ## Instalação ### Guia específico de distribuição - [Debian & Ubuntu](#debian--ubuntu) + [Instalar do repositório](#instale-a-partir-do-repositório-não-recomendado) + [Construa o pacote deb a partir da fonte](#compile-o-pacote-deb-a-partir-da-fonte) + [Configurar e iniciar o serviço](#configurar-e-iniciar-o-serviço) - [Fedora & RHEL](#fedora--rhel) + [Construir a partir da fonte com centos](#construa-a-partir-da-fonte-com-centos) - [Archlinux & Manjaro](#archlinux--manjaro) - [NixOS](#nixos) - [Nix](#nix) - [Compile e instale diretamente no sistema semelhante ao UNIX](#linux) - [FreeBSD](#freebsd) + [Instalar](#instalar) + [Configuração](#configuração) + [Executar](#executar) + [Executar como cliente](#executar-como-cliente) - [OpenWRT](#openwrt) - [OS X](#os-x) - [Windows (MinGW)](#windows-mingw) - [Docker](#docker) * * * ### Inicialize o ambiente de compilação Este repositório usa submódulos, então você deve puxá-los antes de começar, usando: ```bash git submodule update --init --recursive ``` ### Guia de configuração de pré-compilação Para obter uma lista completa das opções de tempo de configuração disponíveis, tentar `configure --help`. ### Debian & Ubuntu #### Instale a partir do repositório (não recomendado) Shadowsocks-libev está disponível no repositório oficial para as seguintes distribuições: * Debian 8 ou superior, incluindo oldoldstable (jessie), old stable (stretch), stable (buster), testing (bullseye) e unstable (sid) * Ubuntu 16.10 ou superior ```bash sudo apt update sudo apt install shadowsocks-libev ``` #### Compile o pacote deb a partir da fonte. Distribuições suportadas: * Debian 8, 9 ou superior * Ubuntu 14.04 LTS, 16.04 LTS, 16.10 ou superior Você pode construir shadowsocks-libev e todas as suas dependências por script: ```bash mkdir -p ~/build-area/ cp ./scripts/build_deb.sh ~/build-area/ cd ~/build-area ./build_deb.sh ``` Para sistemas mais antigos, a construção de pacotes `.deb` não é suportada. Por favor, tente construir e instalar diretamente da fonte. Veja a seção [Linux](#linux) abaixo. **Nota para usuários do Debian 8 (Jessie) para construir seus próprios pacotes deb**: Nós encorajamos você a instalar shadowsocks-libev de `jessie-backports-sloppy`. Se você insistir em compilar a partir da fonte, você precisará instalar manualmente o libsodium de `jessie-backports-sloppy`, **NÃO** libsodium no repositório principal. Para mais informações sobre backports, você pode consultar [Debian Backports](https://backports.debian.org). ``` bash cd shadowsocks-libev sudo sh -c 'printf "deb http://deb.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/jessie-backports.list' sudo sh -c 'printf "deb http://deb.debian.org/debian jessie-backports-sloppy main" >> /etc/apt/sources.list.d/jessie-backports.list' sudo apt-get install --no-install-recommends devscripts equivs mk-build-deps --root-cmd sudo --install --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y" ./autogen.sh && dpkg-buildpackage -b -us -uc cd .. sudo dpkg -i shadowsocks-libev*.deb ``` **Nota para usuários do Debian 9 (Stretch) para construir seus próprios pacotes deb**: Nós encorajamos você a instalar shadowsocks-libev de `stretch-backports`. Se você insistir em compilar a partir do código-fonte, precisará instalar manualmente o libsodium de `stretch-backports`, **NÃO** libsodium no repositório principal. Para mais informações sobre backports, você pode consultar [Debian Backports](https://backports.debian.org). ``` bash cd shadowsocks-libev sudo sh -c 'printf "deb http://deb.debian.org/debian stretch-backports main" > /etc/apt/sources.list.d/stretch-backports.list' sudo apt-get install --no-install-recommends devscripts equivs mk-build-deps --root-cmd sudo --install --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y" ./autogen.sh && dpkg-buildpackage -b -us -uc cd .. sudo dpkg -i shadowsocks-libev*.deb ``` #### Configurar e iniciar o serviço ``` # Edite o arquivo de configuração sudo vim /etc/shadowsocks-libev/config.json # Edite a configuração padrão do debian sudo vim /etc/default/shadowsocks-libev # Inicia o serviço sudo /etc/init.d/shadowsocks-libev start # para sysvinit, ou sudo systemctl start shadowsocks-libev # para systemd ``` ### Fedora & RHEL Distribuições suportadas: * Versões recentes do Fedora (até EOL) * RHEL 6, 7 e derivados (incluindo CentOS, Scientific Linux) #### Construa a partir da fonte com centos Se você estiver usando o CentOS 7, precisará instalar estes pré-requisitos para compilar a partir do código-fonte: ```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 ``` ### Archlinux & Manjaro ```bash sudo pacman -S shadowsocks-libev ``` Consulte o script downstream [PKGBUILD](https://github.com/archlinux/svntogit-community/blob/packages/shadowsocks-libev/trunk/PKGBUILD) para modificações extras e bugs específicos da distribuição. ### NixOS ```bash nix-env -iA nixos.shadowsocks-libev ``` ### Nix ```bash nix-env -iA nixpkgs.shadowsocks-libev ``` ### Linux Em geral, você precisa das seguintes dependências de compilação: * autotools (autoconf, automake, libtool) * gettext * pkg-config * libmbedtls * libsodium * libpcre3 (antiga biblioteca pcre) * libev * libc-ares * asciidoc (somente para documentação) * xmlto (apenas 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. Se seu sistema for muito antigo para fornecer libmbedtls e libsodium (posterior a **v1.0.8**), você precisará instalar essas bibliotecas manualmente ou atualizar seu sistema. Se o seu sistema fornece essas bibliotecas, você **não deve** instalá-las a partir do código-fonte. Você deve ir para esta seção e instalá-las a partir do repositório de distribuição. Para algumas das distribuições, você pode instalar dependências de compilação como esta: ```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 ## CentOS / Fedora / RHEL sudo yum install gettext gcc autoconf libtool automake make asciidoc xmlto c-ares-devel libev-devel ## Arch sudo pacman -S gettext gcc autoconf libtool automake make asciidoc xmlto c-ares libev # Instalação do libsodium export LIBSODIUM_VER=1.0.16 wget https://download.libsodium.org/libsodium/releases/old/libsodium-$LIBSODIUM_VER.tar.gz tar xvf libsodium-$LIBSODIUM_VER.tar.gz pushd libsodium-$LIBSODIUM_VER ./configure --prefix=/usr && make sudo make install popd sudo ldconfig # Instalação do MbedTLS export MBEDTLS_VER=2.6.0 wget https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/mbedtls-$MBEDTLS_VER.tar.gz tar xvf mbedtls-$MBEDTLS_VER.tar.gz pushd mbedtls-$MBEDTLS_VER make SHARED=1 CFLAGS="-O2 -fPIC" sudo make DESTDIR=/usr install popd sudo ldconfig # Comece a construir ./autogen.sh && ./configure && make sudo make install ``` Pode ser necessário instalar manualmente os softwares ausentes. ### FreeBSD #### Instalar Shadowsocks-libev está disponível na Coleção de Ports do FreeBSD. Você pode instalá-lo de qualquer maneira, `pkg` ou `ports`. **pkg (recomendado)** ```bash pkg install shadowsocks-libev ``` **portas** ```bash cd /usr/ports/net/shadowsocks-libev make install ``` #### Configuração Edite seu arquivo `config.json`. Por padrão, está localizado em `/usr/local/etc/shadowsocks-libev`. Para habilitar shadowsocks-libev, adicione a seguinte variável rc ao seu arquivo `/etc/rc.conf`: ``` shadowsocks_libev_enable="YES" ``` #### Executar Inicie o servidor Shadowsocks: ```bash service shadowsocks_libev start ``` #### Executar como cliente Por padrão, shadowsocks-libev está rodando como um servidor no FreeBSD. Se você quiser iniciar o shadowsocks-libev no modo cliente, você pode modificar o script rc (`/usr/local/etc/rc.d/shadowsocks_libev`) manualmente. ``` # modifique a seguinte linha de "ss-server" para "ss-local" command="/usr/local/bin/ss-local" ``` Observe que é simplesmente uma solução alternativa, cada vez que você atualizar a porta, suas alterações serão substituídas pela nova versão. ### OpenWRT O projeto OpenWRT é mantido aqui: [openwrt-shadowsocks](https://github.com/shadowsocks/openwrt-shadowsocks). ### OS X Para OS X, use [Homebrew](http://brew.sh) para instalar ou compilar. Instale o Homebrew: ```bash ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" ``` Instale shadowsocks-libev: ```bash brew install shadowsocks-libev ``` ### Windows (MinGW) Para compilar binários nativos do Windows, o método recomendado é usar o Docker: * No Windows: clique duas vezes em `make.bat` em `docker\mingw` * No sistema do tipo Unix: cd shadowsocks-libev/docker/mingw make Um tarball com binários de 32 bits e 64 bits será gerado no mesmo diretório. Você também pode usar compiladores MinGW-w64 manualmente para compilar em shell do tipo Unix (MSYS2/Cygwin) ou compilar em sistemas semelhantes ao Unix (Linux/MacOS). Por favor, consulte os scripts de compilação em `docker/mingw`. Atualmente você precisa usar uma biblioteca libev corrigida para MinGW: * https://github.com/shadowsocks/libev/archive/mingw.zip Observe que o TCP Fast Open (TFO) está disponível apenas no **Windows 10**, **1607** ou versão posterior (precisamente, build >= 14393). Se você estiver usando **1709** (compilação 16299) ou versão posterior, também precisará executar o seguinte comando no PowerShell/Prompt de comando **como administrador** e **reinicializar** para usar o TFO corretamente: netsh int tcp set global fastopenfallback=disabled ### Docker Como você espera, basta puxar a imagem e executar. ``` docker pull shadowsocks/shadowsocks-libev docker run -e PASSWORD= -p:8388 -p:8388/udp -d shadowsocks/shadowsocks-libev ``` Mais informações sobre a imagem podem ser encontradas [aqui](docker/alpine/README.md). ## Utilização Para obter uma lista detalhada e completa de todos os argumentos suportados, você pode consultar as páginas de manual dos aplicativos, respectivamente. ss-[local|redir|server|tunnel|manager] -s Nome do host ou endereço IP de seu servidor remoto. -p Número da porta do seu servidor remoto. -l Número da porta do seu servidor local. -k Senha do seu servidor remoto. -m Método de criptografia: rc4-md5, aes-128-gcm, aes-192-gcm, aes-256-gcm, aes-128-cfb, aes-192-cfb, aes-256-cfb, aes-128-ctr, aes-192-ctr, aes-256-ctr, camellia-128-cfb, camellia-192-cfb, camellia-256-cfb, bf-cfb, chacha20-ietf-poly1305, xchacha20-ietf-poly1305, salsa20, chacha20 e chacha20-ietf. A cifra padrão é chacha20-ietf-poly1305. [-a ] Executar como outro usuário. [-f ] O caminho do arquivo para armazenar pid. [-t ] Tempo limite do soquete em segundos. [-c ] O caminho para o arquivo de configuração. [-n ] Número máximo de arquivos abertos. [-i ] Interface de rede a ser vinculada. (não disponível no modo redir) [-b ] Endereço local para ligar. Para servidores: Especifique o endereço local a ser usado enquanto este servidor está fazendo saída conexões a servidores remotos em nome do clientes. Para clientes: Especifique o endereço local a ser usado enquanto este cliente está fazendo saída conexões com o servidor. [-u] Habilita retransmissão UDP. (TPROXY é necessário no modo redir) [-U] Ativa a retransmissão UDP e desativa a retransmissão TCP. (não disponível no modo local) [-T] Use tproxy em vez de redirecionar. (para tcp) (disponível apenas no modo redir) [-L :] Endereço e porta do servidor de destino para encaminhamento de porta local. (disponível apenas no modo túnel) [-6] Primeiro, resolva o nome do host para o endereço IPv6. [-d ] Servidores de nome para resolvedor de DNS interno. (disponível apenas no modo servidor) [--reuse-port] Habilita a reutilização de porta. [--fast-open] Habilita a abertura rápida do TCP. com kernel do Linux > 3.7.0. (disponível apenas no modo local e servidor) [--acl ] Caminho para ACL (lista de controle de acesso). (disponível apenas no modo local e servidor) [--manager-address ] endereço de soquete do domínio UNIX. (disponível apenas no modo servidor e gerenciador) [--mtu ] MTU de sua interface de rede. [--mptcp] Habilita o Multipath TCP no Kernel MPTCP. [--no-delay] Habilita TCP_NODELAY. [--executable ] Caminho para o executável do ss-server. (disponível apenas no modo gerenciador) [-D ] Caminho para o diretório de trabalho do ss-manager. (disponível apenas no modo gerenciador) [--key ] Chave do seu servidor remoto. ## proxy transparente O mais recente shadowsocks-libev forneceu um modo *redir*. Você pode configurar sua caixa ou roteador baseado em Linux para fazer proxy de todo o tráfego TCP de forma transparente, o que é útil se você usar um roteador com OpenWRT. # Criar nova cadeia iptables -t nat -N SHADOWSOCKS iptables -t mangle -N SHADOWSOCKS # Ignore os endereços do seu servidor shadowsocks # É muito IMPORTANTE, apenas tome cuidado. iptables -t nat -A SHADOWSOCKS -d 123.123.123.123 -j RETURN # Ignore LANs e quaisquer outros endereços que você gostaria de ignorar o proxy # Veja Wikipedia e RFC5735 para lista completa de redes reservadas. # Consulte ashi009/bestroutetb para obter uma lista de rotas CHN altamente otimizada. 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 # Qualquer outra coisa deve ser redirecionada para a porta local do shadowsocks iptables -t nat -A SHADOWSOCKS -p tcp -j REDIRECT --to-ports 12345 # Adicione quaisquer regras UDP 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 # Aplicar as regras iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS iptables -t mangle -A PREROUTING -j SHADOWSOCKS # Iniciar o shadowsocks-redir ss-redir -u -c /etc/config/shadowsocks.json -f /var/run/shadowsocks.pid ## Proxy transparente (tproxy puro) A execução deste script no host linux pode fazer proxy de todo o tráfego de saída desta máquina (exceto o tráfego enviado para o endereço reservado). Outros hosts na mesma LAN também podem alterar seu gateway padrão para o ip deste host linux (ao mesmo tempo, alterar o servidor dns para 1.1.1.1 ou 8.8.8.8, etc.) para fazer proxy de seu tráfego de saída. > Claro, o proxy ipv6 é semelhante, basta alterar `iptables` para `ip6tables`, `ip` para `ip -6`, `127.0.0.1` para `::1`, e outros detalhes. ```shell #!/bin/bash start_ssredir() { # modifique MyIP, MyPort, etc. (ss-redir -s MyIP -p MyPort -m MyMethod -k MyPasswd -b 127.0.0.1 -l 60080 --no-delay -u -T -v >/var/log/ss-redir.log &) } stop_ssredir() { kill -9 $(pidof ss-redir) &>/dev/null } start_iptables() { ##################### SSREDIR ##################### iptables -t mangle -N SSREDIR # connection-mark -> packet-mark iptables -t mangle -A SSREDIR -j CONNMARK --restore-mark iptables -t mangle -A SSREDIR -m mark --mark 0x2333 -j RETURN # modifique MyIP, MyPort, etc. # ignorar o tráfego enviado para o servidor ss iptables -t mangle -A SSREDIR -p tcp -d MyIP --dport MyPort -j RETURN iptables -t mangle -A SSREDIR -p udp -d MyIP --dport MyPort -j RETURN # ignorar o tráfego enviado para endereços reservados iptables -t mangle -A SSREDIR -d 0.0.0.0/8 -j RETURN iptables -t mangle -A SSREDIR -d 10.0.0.0/8 -j RETURN iptables -t mangle -A SSREDIR -d 100.64.0.0/10 -j RETURN iptables -t mangle -A SSREDIR -d 127.0.0.0/8 -j RETURN iptables -t mangle -A SSREDIR -d 169.254.0.0/16 -j RETURN iptables -t mangle -A SSREDIR -d 172.16.0.0/12 -j RETURN iptables -t mangle -A SSREDIR -d 192.0.0.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 192.0.2.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 192.88.99.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 192.168.0.0/16 -j RETURN iptables -t mangle -A SSREDIR -d 198.18.0.0/15 -j RETURN iptables -t mangle -A SSREDIR -d 198.51.100.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 203.0.113.0/24 -j RETURN iptables -t mangle -A SSREDIR -d 224.0.0.0/4 -j RETURN iptables -t mangle -A SSREDIR -d 240.0.0.0/4 -j RETURN iptables -t mangle -A SSREDIR -d 255.255.255.255/32 -j RETURN # marca o primeiro pacote da conexão iptables -t mangle -A SSREDIR -p tcp --syn -j MARK --set-mark 0x2333 iptables -t mangle -A SSREDIR -p udp -m conntrack --ctstate NEW -j MARK --set-mark 0x2333 # packet-mark -> connection-mark iptables -t mangle -A SSREDIR -j CONNMARK --save-mark ##################### OUTPUT ##################### # proxy the outgoing traffic from this machine iptables -t mangle -A OUTPUT -p tcp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j SSREDIR iptables -t mangle -A OUTPUT -p udp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j SSREDIR ##################### PREROUTING ##################### # proxy traffic passing through this machine (other->other) iptables -t mangle -A PREROUTING -p tcp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j SSREDIR iptables -t mangle -A PREROUTING -p udp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j SSREDIR # hand over the marked package to TPROXY for processing iptables -t mangle -A PREROUTING -p tcp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port 60080 iptables -t mangle -A PREROUTING -p udp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port 60080 } stop_iptables() { ##################### PREROUTING ##################### iptables -t mangle -D PREROUTING -p tcp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port 60080 &>/dev/null iptables -t mangle -D PREROUTING -p udp -m mark --mark 0x2333 -j TPROXY --on-ip 127.0.0.1 --on-port 60080 &>/dev/null iptables -t mangle -D PREROUTING -p tcp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j SSREDIR &>/dev/null iptables -t mangle -D PREROUTING -p udp -m addrtype ! --src-type LOCAL ! --dst-type LOCAL -j SSREDIR &>/dev/null ##################### OUTPUT ##################### iptables -t mangle -D OUTPUT -p tcp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j SSREDIR &>/dev/null iptables -t mangle -D OUTPUT -p udp -m addrtype --src-type LOCAL ! --dst-type LOCAL -j SSREDIR &>/dev/null ##################### SSREDIR ##################### iptables -t mangle -F SSREDIR &>/dev/null iptables -t mangle -X SSREDIR &>/dev/null } start_iproute2() { ip route add local default dev lo table 100 ip rule add fwmark 0x2333 table 100 } stop_iproute2() { ip rule del table 100 &>/dev/null ip route flush table 100 &>/dev/null } start_resolvconf() { # or nameserver 8.8.8.8, etc. echo "nameserver 1.1.1.1" >/etc/resolv.conf } stop_resolvconf() { echo "nameserver 114.114.114.114" >/etc/resolv.conf } start() { echo "start ..." start_ssredir start_iptables start_iproute2 start_resolvconf echo "start end" } stop() { echo "stop ..." stop_resolvconf stop_iproute2 stop_iptables stop_ssredir echo "stop end" } restart() { stop sleep 1 start } main() { if [ $# -eq 0 ]; then echo "usage: $0 start|stop|restart ..." return 1 fi for funcname in "$@"; do if [ "$(type -t $funcname)" != 'function' ]; then echo "'$funcname' not a shell function" return 1 fi done for funcname in "$@"; do $funcname done return 0 } main "$@" ``` ## Dicas de segurança Para qualquer servidor público, para evitar que os usuários acessem o localhost do seu servidor, adicione `--acl acl/server_block_local.acl` à linha de comando. Embora shadowsocks-libev possa lidar bem com milhares de conexões simultâneas, ainda recomendamos configurando as regras de firewall do seu servidor para limitar as conexões de cada usuário: # Até 32 conexões são suficientes para uso normal iptables -A INPUT -p tcp --syn --dport ${SHADOWSOCKS_PORT} -m connlimit --connlimit-above 32 -j REJECT --reject-with tcp-reset ## Licença ``` Copyright: 2013-2015, Clow Windy 2013-2018, Max Lv 2014, Linus Yang Este programa é um software livre: você pode redistribuí-lo e/ou modificá-lo sob os termos da GNU General Public License conforme publicada pela Free Software Foundation, a versão 3 da Licença ou (a seu critério) qualquer versão posterior. Este programa é distribuído na esperança de que seja útil, mas SEM QUALQUER GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou ADEQUAÇÃO A UM DETERMINADO FIM.Veja a Licença Pública Geral GNU para mais detalhes. Você deve ter recebido uma cópia da GNU General Public License juntamente com este programa. Caso contrário, consulte . ``` ================================================ FILE: acl/chn.acl ================================================ [proxy_all] [bypass_list] 1.0.1.0/24 1.0.2.0/23 1.0.8.0/21 1.0.32.0/19 1.1.0.0/24 1.1.2.0/23 1.1.4.0/22 1.1.8.0/21 1.1.16.0/20 1.1.32.0/19 1.2.0.0/23 1.2.2.0/24 1.2.5.0/24 1.2.6.0/23 1.2.8.0/21 1.2.16.0/20 1.2.32.0/19 1.2.64.0/18 1.3.0.0/16 1.4.1.0/24 1.4.2.0/23 1.4.4.0/22 1.4.8.0/21 1.4.16.0/20 1.4.32.0/19 1.4.64.0/18 1.8.0.0/18 1.8.64.0/19 1.8.96.0/22 1.8.100.0/23 1.8.112.0/20 1.8.128.0/20 1.8.144.0/22 1.8.148.0/23 1.8.154.0/23 1.8.156.0/22 1.8.160.0/19 1.8.192.0/19 1.8.224.0/20 1.8.244.0/22 1.8.248.0/21 1.10.0.0/21 1.10.8.0/23 1.10.11.0/24 1.10.12.0/22 1.10.16.0/20 1.10.32.0/19 1.10.64.0/18 1.12.0.0/14 1.18.128.0/24 1.24.0.0/13 1.45.0.0/16 1.48.0.0/14 1.56.0.0/13 1.68.0.0/14 1.80.0.0/12 1.116.0.0/15 1.118.1.0/24 1.118.2.0/23 1.118.4.0/22 1.118.8.0/21 1.118.16.0/20 1.118.32.0/19 1.118.64.0/18 1.118.128.0/17 1.119.0.0/16 1.180.0.0/14 1.184.0.0/15 1.188.0.0/14 1.192.0.0/13 1.202.0.0/15 1.204.0.0/14 2.20.54.23/32 8.128.0.0/10 8.209.36.0/22 8.209.40.0/21 8.209.48.0/20 8.209.192.0/18 8.210.0.0/15 8.212.0.0/14 8.216.0.0/13 14.0.0.0/21 14.0.12.0/22 14.1.0.0/22 14.1.24.0/22 14.1.108.0/22 14.16.0.0/12 14.102.128.0/22 14.102.180.0/22 14.103.0.0/16 14.104.0.0/13 14.112.0.0/12 14.130.0.0/15 14.134.0.0/15 14.144.0.0/12 14.192.60.0/22 14.192.76.0/22 14.196.0.0/15 14.204.0.0/15 14.208.0.0/12 20.81.0.0/24 20.134.160.0/20 20.139.160.0/20 20.249.255.0/24 20.251.0.0/22 23.236.64.0/25 23.236.64.128/26 23.236.64.192/27 27.0.128.0/21 27.0.160.0/21 27.0.188.0/22 27.0.204.0/22 27.0.208.0/21 27.8.0.0/13 27.16.0.0/12 27.34.232.0/21 27.36.0.0/14 27.40.0.0/13 27.50.40.0/21 27.50.128.0/17 27.54.72.0/21 27.54.152.0/21 27.54.192.0/18 27.98.208.0/20 27.98.224.0/19 27.99.128.0/17 27.103.0.0/16 27.106.128.0/18 27.106.204.0/22 27.109.32.0/19 27.109.124.0/22 27.112.0.0/18 27.112.80.0/20 27.112.112.0/21 27.113.128.0/18 27.115.0.0/17 27.116.44.0/22 27.121.72.0/21 27.121.120.0/21 27.128.0.0/15 27.131.220.0/22 27.144.0.0/16 27.148.0.0/14 27.152.0.0/13 27.184.0.0/13 27.192.0.0/11 27.224.0.0/14 36.0.0.0/22 36.0.16.0/20 36.0.32.0/19 36.0.64.0/18 36.0.128.0/17 36.1.0.0/16 36.4.0.0/14 36.16.0.0/12 36.32.0.0/14 36.36.0.0/16 36.37.0.0/19 36.37.36.0/23 36.37.39.0/24 36.37.40.0/21 36.37.48.0/20 36.40.0.0/13 36.48.0.0/15 36.51.0.0/17 36.51.128.0/18 36.51.192.0/19 36.51.224.0/20 36.51.240.0/21 36.51.248.0/22 36.51.252.0/23 36.56.0.0/13 36.96.0.0/11 36.128.0.0/10 36.192.0.0/11 36.248.0.0/14 36.254.0.0/16 36.255.116.0/22 36.255.128.0/22 36.255.164.0/22 36.255.172.0/22 36.255.176.0/22 38.142.239.114/32 39.0.0.0/24 39.0.2.0/23 39.0.4.0/22 39.0.8.0/21 39.0.16.0/20 39.0.32.0/19 39.0.64.0/18 39.0.128.0/17 39.64.0.0/11 39.96.0.0/13 39.104.0.0/14 39.108.0.0/16 39.109.120.0/23 39.128.0.0/10 40.0.176.0/20 40.0.247.0/24 40.0.248.0/22 40.0.252.0/23 40.0.255.0/24 40.72.0.0/15 40.77.136.112/28 40.77.236.224/27 40.77.254.64/27 40.125.128.0/17 40.126.64.0/18 40.198.10.0/24 40.198.16.0/21 40.198.24.0/23 40.251.225.0/24 40.251.227.0/24 42.0.0.0/22 42.0.8.0/21 42.0.16.0/21 42.0.24.0/22 42.0.32.0/19 42.0.128.0/17 42.1.0.0/19 42.1.32.0/20 42.1.48.0/21 42.1.56.0/22 42.4.0.0/14 42.48.0.0/13 42.56.0.0/14 42.62.0.0/17 42.62.128.0/19 42.62.160.0/20 42.62.180.0/22 42.62.184.0/21 42.63.0.0/16 42.80.0.0/15 42.83.64.0/20 42.83.80.0/22 42.83.88.0/21 42.83.96.0/19 42.83.128.0/23 42.83.134.0/24 42.83.139.0/24 42.83.140.0/22 42.83.144.0/20 42.83.160.0/19 42.83.192.0/18 42.84.0.0/14 42.88.0.0/13 42.96.64.0/19 42.96.96.0/21 42.96.108.0/22 42.96.112.0/20 42.96.128.0/17 42.97.0.0/16 42.99.0.0/18 42.99.64.0/19 42.99.96.0/20 42.99.112.0/22 42.99.120.0/21 42.100.0.0/14 42.120.0.0/15 42.122.0.0/16 42.123.0.0/19 42.123.36.0/22 42.123.40.0/21 42.123.48.0/20 42.123.64.0/18 42.123.128.0/17 42.128.0.0/12 42.156.0.0/19 42.156.36.0/22 42.156.40.0/21 42.156.48.0/20 42.156.64.0/18 42.156.128.0/17 42.157.0.0/21 42.157.8.0/22 42.157.14.0/23 42.157.16.0/20 42.157.32.0/19 42.157.64.0/18 42.157.128.0/17 42.158.0.0/15 42.160.0.0/12 42.176.0.0/13 42.184.0.0/15 42.186.0.0/16 42.187.0.0/18 42.187.64.0/19 42.187.96.0/20 42.187.112.0/21 42.187.120.0/22 42.187.128.0/17 42.192.0.0/13 42.201.0.0/17 42.202.0.0/15 42.204.0.0/14 42.208.0.0/12 42.224.0.0/12 42.240.0.0/16 42.242.0.0/15 42.244.0.0/15 42.246.0.0/16 42.247.0.0/22 42.247.4.0/24 42.247.5.0/25 42.247.5.128/26 42.247.5.204/30 42.247.5.208/28 42.247.5.224/27 42.247.6.0/23 42.247.8.0/21 42.247.16.0/20 42.247.32.0/19 42.247.64.0/18 42.247.128.0/17 42.248.0.0/13 43.224.12.0/22 43.224.24.0/22 43.224.44.0/22 43.224.52.0/22 43.224.56.0/22 43.224.68.0/22 43.224.72.0/22 43.224.80.0/22 43.224.100.0/22 43.224.144.0/22 43.224.160.0/22 43.224.176.0/22 43.224.184.0/22 43.224.200.0/21 43.224.208.0/21 43.224.216.0/22 43.224.240.0/22 43.225.76.0/22 43.225.86.0/24 43.225.120.0/22 43.225.180.0/22 43.225.208.0/22 43.225.216.0/21 43.225.224.0/20 43.225.240.0/21 43.225.252.0/22 43.226.32.0/19 43.226.64.0/19 43.226.96.0/20 43.226.112.0/21 43.226.120.0/22 43.226.128.0/19 43.226.160.0/21 43.226.236.0/22 43.226.240.0/20 43.227.0.0/21 43.227.8.0/22 43.227.32.0/19 43.227.64.0/19 43.227.104.0/22 43.227.136.0/21 43.227.144.0/22 43.227.152.0/21 43.227.160.0/20 43.227.176.0/21 43.227.188.0/22 43.227.192.0/19 43.227.232.0/22 43.227.248.0/21 43.228.0.0/18 43.228.64.0/21 43.228.76.0/22 43.228.100.0/22 43.228.116.0/24 43.228.118.0/23 43.228.132.0/22 43.228.136.0/22 43.228.148.0/22 43.228.152.0/22 43.228.188.0/22 43.229.40.0/22 43.229.48.0/22 43.229.56.0/22 43.229.96.0/22 43.229.136.0/21 43.229.168.0/21 43.229.176.0/20 43.229.192.0/21 43.229.216.0/21 43.229.232.0/21 43.230.20.0/22 43.230.32.0/22 43.230.68.0/22 43.230.72.0/22 43.230.84.0/22 43.230.124.0/22 43.230.220.0/22 43.230.224.0/19 43.231.12.0/22 43.231.32.0/20 43.231.80.0/20 43.231.96.0/20 43.231.136.0/21 43.231.144.0/20 43.231.160.0/20 43.231.176.0/21 43.236.0.0/15 43.238.0.0/16 43.239.0.0/19 43.239.32.0/20 43.239.48.0/22 43.239.116.0/22 43.239.120.0/22 43.239.172.0/22 43.240.0.0/22 43.240.56.0/21 43.240.68.0/22 43.240.72.0/21 43.240.84.0/22 43.240.124.0/22 43.240.128.0/21 43.240.136.0/22 43.240.156.0/22 43.240.160.0/19 43.240.192.0/19 43.240.240.0/20 43.241.0.0/20 43.241.16.0/21 43.241.48.0/22 43.241.76.0/22 43.241.80.0/20 43.241.112.0/22 43.241.168.0/21 43.241.176.0/21 43.241.184.0/22 43.241.208.0/20 43.241.224.0/20 43.241.240.0/22 43.241.248.0/22 43.242.8.0/21 43.242.16.0/20 43.242.48.0/22 43.242.53.0/24 43.242.54.0/23 43.242.56.0/21 43.242.64.0/22 43.242.72.0/21 43.242.80.0/20 43.242.96.0/22 43.242.144.0/20 43.242.160.0/21 43.242.180.0/22 43.242.188.0/22 43.242.192.0/21 43.242.204.0/22 43.242.216.0/21 43.242.252.0/22 43.243.4.0/22 43.243.8.0/21 43.243.16.0/22 43.243.88.0/22 43.243.128.0/22 43.243.136.0/22 43.243.144.0/21 43.243.156.0/22 43.243.180.0/22 43.243.228.0/22 43.243.232.0/22 43.243.244.0/22 43.246.0.0/18 43.246.64.0/19 43.246.96.0/22 43.246.228.0/22 43.247.4.0/22 43.247.8.0/22 43.247.44.0/22 43.247.48.0/22 43.247.68.0/22 43.247.76.0/22 43.247.84.0/22 43.247.88.0/21 43.247.96.0/21 43.247.108.0/22 43.247.112.0/22 43.247.148.0/22 43.247.152.0/22 43.247.176.0/20 43.247.196.0/22 43.247.200.0/21 43.247.208.0/20 43.247.224.0/19 43.248.0.0/21 43.248.20.0/22 43.248.28.0/22 43.248.48.0/22 43.248.76.0/22 43.248.80.0/20 43.248.96.0/19 43.248.128.0/20 43.248.144.0/21 43.248.176.0/20 43.248.192.0/20 43.248.208.0/22 43.248.228.0/22 43.248.232.0/22 43.248.244.0/22 43.249.4.0/22 43.249.120.0/22 43.249.132.0/22 43.249.136.0/22 43.249.144.0/20 43.249.160.0/21 43.249.168.0/22 43.249.192.0/22 43.249.236.0/22 43.250.4.0/22 43.250.12.0/22 43.250.16.0/21 43.250.28.0/22 43.250.32.0/22 43.250.96.0/21 43.250.108.0/22 43.250.112.0/21 43.250.128.0/22 43.250.144.0/21 43.250.160.0/22 43.250.168.0/22 43.250.176.0/22 43.250.200.0/22 43.250.212.0/22 43.250.216.0/21 43.250.236.0/22 43.250.244.0/22 43.251.4.0/22 43.251.36.0/22 43.251.192.0/22 43.251.232.0/22 43.251.244.0/22 43.252.48.0/22 43.252.56.0/22 43.252.224.0/22 43.254.0.0/21 43.254.8.0/22 43.254.24.0/22 43.254.36.0/22 43.254.44.0/22 43.254.52.0/22 43.254.64.0/22 43.254.72.0/22 43.254.84.0/22 43.254.88.0/21 43.254.100.0/22 43.254.104.0/22 43.254.112.0/21 43.254.128.0/22 43.254.136.0/21 43.254.144.0/20 43.254.168.0/21 43.254.180.0/22 43.254.184.0/21 43.254.192.0/22 43.254.200.0/22 43.254.208.0/22 43.254.220.0/22 43.254.224.0/20 43.254.240.0/22 43.254.248.0/21 43.255.0.0/21 43.255.8.0/22 43.255.16.0/22 43.255.48.0/22 43.255.64.0/20 43.255.84.0/22 43.255.96.0/22 43.255.144.0/22 43.255.176.0/22 43.255.184.0/22 43.255.192.0/22 43.255.200.0/21 43.255.208.0/21 43.255.224.0/21 43.255.232.0/22 43.255.244.0/22 45.40.192.0/20 45.40.208.0/21 45.40.224.0/19 45.65.16.0/20 45.112.132.0/22 45.112.188.0/22 45.112.208.0/22 45.112.216.0/21 45.112.228.0/22 45.112.232.0/21 45.113.12.0/22 45.113.16.0/20 45.113.40.0/22 45.113.52.0/22 45.113.72.0/22 45.113.144.0/21 45.113.168.0/22 45.113.184.0/22 45.113.200.0/21 45.113.208.0/20 45.113.240.0/22 45.113.252.0/22 45.114.0.0/22 45.114.32.0/22 45.114.52.0/22 45.114.96.0/22 45.114.136.0/22 45.114.196.0/22 45.114.200.0/22 45.114.228.0/22 45.114.237.0/24 45.114.238.0/23 45.114.252.0/22 45.115.44.0/22 45.115.100.0/22 45.115.120.0/22 45.115.132.0/22 45.115.144.0/22 45.115.156.0/22 45.115.164.0/22 45.115.200.0/22 45.115.212.0/22 45.115.244.0/22 45.115.248.0/22 45.116.16.0/22 45.116.24.0/22 45.116.32.0/21 45.116.52.0/22 45.116.96.0/21 45.116.140.0/22 45.116.152.0/22 45.116.208.0/22 45.117.8.0/22 45.117.20.0/22 45.117.68.0/22 45.117.124.0/22 45.117.252.0/22 45.119.60.0/22 45.119.64.0/21 45.119.72.0/22 45.119.104.0/22 45.119.232.0/22 45.120.100.0/22 45.120.140.0/22 45.120.164.0/22 45.120.180.128/27 45.120.240.0/22 45.121.52.0/22 45.121.64.0/21 45.121.72.0/22 45.121.92.0/22 45.121.96.0/22 45.121.172.0/22 45.121.176.0/22 45.121.240.0/20 45.122.0.0/19 45.122.32.0/21 45.122.40.0/22 45.122.60.0/22 45.122.64.0/19 45.122.96.0/20 45.122.112.0/21 45.122.160.0/19 45.122.192.0/20 45.122.208.0/21 45.122.216.0/22 45.123.28.0/22 45.123.32.0/21 45.123.44.0/22 45.123.48.0/20 45.123.64.0/20 45.123.80.0/21 45.123.120.0/22 45.123.128.0/21 45.123.136.0/22 45.123.148.0/22 45.123.152.0/21 45.123.164.0/22 45.123.168.0/21 45.123.176.0/21 45.123.184.0/22 45.123.204.0/22 45.123.212.0/22 45.123.224.0/19 45.124.0.0/22 45.124.20.0/22 45.124.28.0/22 45.124.32.0/21 45.124.44.0/22 45.124.68.0/22 45.124.76.0/22 45.124.80.0/22 45.124.100.0/22 45.124.124.0/22 45.124.172.0/22 45.124.176.0/22 45.124.208.0/22 45.124.248.0/22 45.125.24.0/22 45.125.44.0/22 45.125.52.0/22 45.125.56.0/22 45.125.76.0/22 45.125.80.0/20 45.125.96.0/21 45.125.136.0/22 45.126.48.0/21 45.126.108.0/22 45.126.112.0/21 45.126.120.0/22 45.126.220.0/22 45.127.8.0/21 45.127.128.0/22 45.127.144.0/21 45.127.156.0/22 45.248.8.0/22 45.248.80.0/22 45.248.88.0/22 45.248.96.0/20 45.248.128.0/21 45.248.204.0/22 45.248.208.0/20 45.248.224.0/19 45.249.0.0/21 45.249.12.0/22 45.249.16.0/20 45.249.32.0/21 45.249.112.0/22 45.249.188.0/22 45.249.192.0/20 45.249.208.0/21 45.250.12.0/22 45.250.16.0/22 45.250.28.0/22 45.250.32.0/21 45.250.40.0/22 45.250.76.0/22 45.250.80.0/20 45.250.96.0/22 45.250.104.0/21 45.250.112.0/20 45.250.128.0/20 45.250.144.0/21 45.250.152.0/22 45.250.164.0/22 45.250.180.0/22 45.250.184.0/21 45.250.192.0/22 45.251.0.0/22 45.251.8.0/22 45.251.16.0/21 45.251.52.0/22 45.251.84.0/22 45.251.88.0/21 45.251.96.0/21 45.251.120.0/21 45.251.137.0/24 45.251.138.0/23 45.251.140.0/22 45.251.144.0/20 45.251.160.0/19 45.251.192.0/19 45.251.224.0/22 45.252.0.0/19 45.252.32.0/20 45.252.48.0/22 45.252.84.0/22 45.252.88.0/21 45.252.96.0/19 45.252.128.0/19 45.252.160.0/20 45.252.176.0/22 45.252.192.0/19 45.252.224.0/21 45.252.232.0/22 45.253.0.0/18 45.253.64.0/20 45.253.80.0/21 45.253.92.0/22 45.253.96.0/20 45.253.112.0/21 45.253.120.0/22 45.253.130.0/23 45.253.132.0/22 45.253.136.0/21 45.253.144.0/20 45.253.160.0/19 45.253.192.0/19 45.253.224.0/20 45.253.240.0/22 45.254.0.0/20 45.254.16.0/21 45.254.28.0/22 45.254.40.0/22 45.254.48.0/20 45.254.64.0/18 45.254.128.0/18 45.254.192.0/19 45.254.224.0/21 45.254.236.0/22 45.254.240.0/22 45.254.248.0/22 45.255.0.0/18 45.255.64.0/19 45.255.96.0/20 45.255.112.0/21 45.255.120.0/22 45.255.136.0/21 45.255.144.0/20 45.255.160.0/19 45.255.192.0/19 45.255.224.0/20 45.255.240.0/21 45.255.248.0/22 46.248.24.0/23 47.92.0.0/14 47.96.0.0/11 49.4.0.0/14 49.51.56.0/22 49.51.60.0/23 49.51.110.0/23 49.51.112.0/20 49.52.0.0/14 49.64.0.0/11 49.112.0.0/13 49.120.0.0/14 49.128.0.0/24 49.128.2.0/23 49.128.4.0/22 49.140.0.0/15 49.152.0.0/14 49.208.0.0/14 49.220.0.0/14 49.232.0.0/14 49.239.0.0/18 49.239.192.0/18 52.80.0.0/14 52.94.249.0/27 52.130.0.0/15 54.222.0.0/15 54.231.208.0/20 54.240.224.0/24 57.92.96.0/20 58.14.0.0/15 58.16.0.0/13 58.24.0.0/15 58.30.0.0/15 58.32.0.0/11 58.65.232.0/21 58.66.0.0/15 58.68.128.0/19 58.68.160.0/23 58.68.163.0/24 58.68.164.0/22 58.68.179.0/24 58.68.180.0/24 58.68.200.0/21 58.68.208.0/20 58.68.224.0/19 58.82.0.0/17 58.83.0.0/16 58.87.64.0/18 58.99.128.0/17 58.100.0.0/15 58.116.0.0/14 58.128.0.0/13 58.144.0.0/16 58.154.0.0/15 58.192.0.0/11 58.240.0.0/12 59.32.0.0/11 59.64.0.0/12 59.80.0.0/15 59.82.0.0/16 59.83.0.0/18 59.83.132.0/22 59.83.136.0/21 59.83.144.0/20 59.83.160.0/19 59.83.192.0/19 59.83.224.0/20 59.83.240.0/21 59.83.248.0/22 59.83.252.0/23 59.83.254.0/24 59.107.0.0/16 59.108.0.0/14 59.151.0.0/17 59.152.16.0/20 59.152.36.0/22 59.152.64.0/20 59.152.112.0/21 59.153.4.0/22 59.153.32.0/22 59.153.64.0/21 59.153.72.0/22 59.153.92.0/22 59.153.136.0/22 59.153.152.0/21 59.153.164.0/22 59.153.168.0/21 59.153.176.0/20 59.153.192.0/22 59.155.0.0/16 59.172.0.0/14 59.191.0.0/17 59.192.0.0/10 60.0.0.0/11 60.55.0.0/16 60.63.0.0/16 60.160.0.0/11 60.194.0.0/15 60.200.0.0/13 60.208.0.0/12 60.232.0.0/15 60.235.0.0/16 60.245.128.0/17 60.247.0.0/16 60.252.0.0/16 60.253.128.0/17 60.255.0.0/16 61.4.81.0/24 61.4.82.0/23 61.4.84.0/22 61.4.88.0/21 61.4.176.0/20 61.8.160.0/20 61.14.212.0/22 61.14.216.0/21 61.14.240.0/21 61.28.0.0/17 61.29.128.0/18 61.29.192.0/19 61.29.224.0/20 61.45.128.0/18 61.45.224.0/20 61.47.128.0/18 61.48.0.0/13 61.87.192.0/18 61.128.0.0/10 61.232.0.0/14 61.236.0.0/15 61.240.0.0/14 62.234.0.0/16 68.79.0.0/18 69.230.192.0/18 69.231.128.0/18 69.234.192.0/18 69.235.128.0/18 71.131.192.0/18 71.132.0.0/18 71.136.64.0/18 71.137.0.0/18 72.163.240.0/23 72.163.248.0/22 81.68.0.0/14 81.161.63.0/24 82.156.0.0/15 87.254.207.0/24 91.223.53.0/24 91.239.190.0/24 93.183.14.0/24 93.183.18.0/24 94.191.0.0/17 101.0.0.0/22 101.1.0.0/22 101.2.172.0/22 101.4.0.0/14 101.16.0.0/12 101.32.0.0/14 101.36.0.0/18 101.36.64.0/20 101.36.88.0/21 101.36.96.0/19 101.36.128.0/17 101.37.0.0/16 101.38.0.0/15 101.40.0.0/13 101.48.0.0/15 101.50.8.0/21 101.50.56.0/22 101.52.0.0/16 101.53.100.0/22 101.54.0.0/16 101.55.224.0/21 101.64.0.0/13 101.72.0.0/14 101.76.0.0/15 101.78.0.0/22 101.78.32.0/19 101.80.0.0/12 101.96.0.0/21 101.96.8.0/22 101.96.16.0/20 101.96.128.0/17 101.99.96.0/19 101.101.64.0/19 101.101.100.0/24 101.101.102.0/23 101.101.104.0/21 101.101.112.0/20 101.102.64.0/19 101.102.100.0/23 101.102.102.0/24 101.102.104.0/21 101.102.112.0/20 101.104.0.0/14 101.110.64.0/19 101.110.96.0/20 101.110.116.0/22 101.110.120.0/21 101.120.0.0/14 101.124.0.0/15 101.126.0.0/16 101.128.0.0/22 101.128.8.0/21 101.128.16.0/20 101.128.32.0/19 101.129.0.0/16 101.130.0.0/15 101.132.0.0/15 101.134.0.0/17 101.134.128.0/19 101.134.160.0/20 101.134.176.0/21 101.134.184.0/22 101.134.189.0/24 101.134.190.0/23 101.134.192.0/18 101.135.0.0/16 101.144.0.0/12 101.192.0.0/14 101.196.0.0/16 101.198.128.0/18 101.198.194.0/24 101.198.196.0/23 101.198.200.0/22 101.198.224.0/19 101.199.0.0/19 101.199.48.0/20 101.199.64.0/18 101.199.128.0/17 101.200.0.0/15 101.203.128.0/19 101.203.160.0/21 101.203.172.0/22 101.203.176.0/20 101.204.0.0/14 101.224.0.0/13 101.232.0.0/15 101.234.64.0/21 101.234.76.0/22 101.234.80.0/20 101.234.96.0/19 101.236.0.0/14 101.240.0.0/13 101.248.0.0/15 101.251.0.0/22 101.251.8.0/21 101.251.16.0/20 101.251.32.0/19 101.251.64.0/18 101.251.128.0/17 101.252.0.0/15 101.254.0.0/16 102.176.130.0/24 103.1.8.0/22 103.1.20.0/22 103.1.24.0/22 103.1.88.0/22 103.1.168.0/22 103.2.108.0/22 103.2.156.0/22 103.2.164.0/22 103.2.200.0/21 103.2.208.0/21 103.3.84.0/22 103.3.88.0/21 103.3.96.0/19 103.3.128.0/20 103.3.148.0/22 103.3.152.0/21 103.4.56.0/22 103.4.168.0/22 103.4.184.0/22 103.5.36.0/22 103.5.52.0/23 103.5.56.0/22 103.5.152.0/22 103.5.168.0/22 103.5.192.0/22 103.5.252.0/22 103.6.76.0/22 103.6.108.0/22 103.6.120.0/22 103.6.220.0/22 103.6.228.0/22 103.7.140.0/22 103.7.212.0/22 103.7.216.0/21 103.8.0.0/21 103.8.8.0/22 103.8.32.0/22 103.8.52.0/22 103.8.68.0/22 103.8.108.0/22 103.8.156.0/22 103.8.200.0/21 103.8.220.0/22 103.9.8.0/22 103.9.24.0/22 103.9.108.0/22 103.9.152.0/22 103.9.248.0/21 103.10.0.0/22 103.10.16.0/22 103.10.84.0/22 103.10.111.0/24 103.10.140.0/22 103.11.16.0/22 103.11.168.0/22 103.11.180.0/22 103.12.32.0/22 103.12.136.0/22 103.12.184.0/22 103.12.232.0/22 103.13.12.0/22 103.13.124.0/22 103.13.144.0/22 103.13.196.0/22 103.13.244.0/22 103.14.84.0/22 103.14.132.0/22 103.14.136.0/22 103.14.156.0/22 103.14.240.0/22 103.15.4.0/22 103.15.8.0/22 103.15.16.0/22 103.15.96.0/22 103.15.200.0/22 103.16.52.0/22 103.16.80.0/21 103.16.88.0/22 103.16.108.0/22 103.16.124.0/22 103.17.40.0/22 103.17.64.0/22 103.17.120.0/23 103.17.136.0/22 103.17.160.0/22 103.17.204.0/22 103.17.228.0/22 103.18.192.0/22 103.18.208.0/21 103.18.224.0/22 103.19.12.0/22 103.19.40.0/21 103.19.64.0/21 103.19.72.0/22 103.19.232.0/22 103.20.12.0/22 103.20.32.0/23 103.20.34.0/24 103.20.68.0/22 103.20.112.0/22 103.20.128.0/22 103.20.160.0/22 103.20.248.0/22 103.21.112.0/21 103.21.140.0/22 103.21.176.0/22 103.21.240.0/22 103.22.0.0/18 103.22.64.0/19 103.22.100.0/22 103.22.104.0/21 103.22.112.0/20 103.22.188.0/22 103.22.228.0/22 103.22.252.0/22 103.23.8.0/22 103.23.56.0/22 103.23.160.0/21 103.23.176.0/22 103.23.228.0/22 103.24.24.0/22 103.24.116.0/22 103.24.128.0/22 103.24.144.0/22 103.24.176.0/22 103.24.184.0/22 103.24.228.0/22 103.24.252.0/22 103.25.20.0/22 103.25.24.0/21 103.25.32.0/21 103.25.40.0/22 103.25.48.0/22 103.25.64.0/21 103.25.148.0/22 103.25.156.0/22 103.25.216.0/22 103.26.0.0/22 103.26.64.0/22 103.26.76.0/22 103.26.116.0/22 103.26.156.0/22 103.26.160.0/22 103.26.228.0/22 103.26.240.0/22 103.27.4.0/22 103.27.12.0/22 103.27.24.0/22 103.27.56.0/22 103.27.96.0/22 103.27.240.0/22 103.28.4.0/22 103.28.8.0/22 103.28.184.0/22 103.28.204.0/22 103.28.212.0/22 103.29.16.0/22 103.29.128.0/21 103.29.136.0/22 103.30.20.0/22 103.30.96.0/22 103.30.148.0/22 103.30.202.0/23 103.30.228.0/22 103.30.236.0/22 103.31.0.0/22 103.31.48.0/21 103.31.60.0/22 103.31.64.0/21 103.31.72.0/24 103.31.148.0/22 103.31.160.0/22 103.31.168.0/22 103.31.200.0/22 103.31.236.0/22 103.32.0.0/15 103.34.0.0/16 103.35.0.0/19 103.35.32.0/20 103.35.48.0/22 103.35.104.0/22 103.35.220.0/22 103.36.28.0/22 103.36.36.0/22 103.36.56.0/21 103.36.64.0/22 103.36.72.0/22 103.36.96.0/22 103.36.132.0/22 103.36.136.0/22 103.36.160.0/19 103.36.192.0/19 103.36.224.0/20 103.36.240.0/21 103.37.12.0/22 103.37.16.0/22 103.37.24.0/22 103.37.44.0/22 103.37.52.0/22 103.37.56.0/22 103.37.72.0/22 103.37.100.0/22 103.37.104.0/22 103.37.136.0/21 103.37.144.0/20 103.37.160.0/21 103.37.172.0/22 103.37.176.0/22 103.37.188.0/22 103.37.208.0/20 103.37.252.0/22 103.38.0.0/22 103.38.32.0/22 103.38.40.0/21 103.38.76.0/22 103.38.84.0/22 103.38.92.0/22 103.38.96.0/22 103.38.116.0/22 103.38.132.0/22 103.38.140.0/22 103.38.220.0/22 103.38.224.0/21 103.38.232.0/22 103.38.252.0/23 103.39.64.0/22 103.39.88.0/22 103.39.100.0/22 103.39.104.0/22 103.39.160.0/19 103.39.200.0/21 103.39.208.0/20 103.39.224.0/21 103.39.232.0/22 103.40.12.0/22 103.40.16.0/20 103.40.32.0/20 103.40.88.0/22 103.40.192.0/22 103.40.212.0/22 103.40.220.0/22 103.40.228.0/22 103.40.232.0/21 103.40.240.0/20 103.41.0.0/22 103.41.52.0/22 103.41.140.0/22 103.41.148.0/22 103.41.152.0/22 103.41.160.0/21 103.41.220.0/22 103.41.224.0/21 103.41.232.0/22 103.42.8.0/22 103.42.24.0/22 103.42.32.0/22 103.42.64.0/21 103.42.76.0/22 103.42.232.0/22 103.43.26.0/23 103.43.96.0/21 103.43.104.0/22 103.43.124.0/22 103.43.184.0/22 103.43.192.0/21 103.43.208.0/22 103.43.220.0/22 103.43.224.0/22 103.43.240.0/22 103.44.58.0/23 103.44.80.0/22 103.44.120.0/21 103.44.144.0/22 103.44.152.0/22 103.44.168.0/22 103.44.176.0/20 103.44.192.0/20 103.44.224.0/22 103.44.236.0/22 103.44.240.0/20 103.45.0.0/18 103.45.72.0/21 103.45.80.0/20 103.45.96.0/19 103.45.128.0/18 103.45.192.0/19 103.45.224.0/22 103.45.248.0/22 103.46.0.0/22 103.46.12.0/22 103.46.16.0/20 103.46.32.0/19 103.46.64.0/18 103.46.128.0/21 103.46.136.0/22 103.46.152.0/21 103.46.160.0/20 103.46.176.0/21 103.46.244.0/22 103.46.248.0/22 103.47.4.0/22 103.47.20.0/22 103.47.36.0/22 103.47.40.0/22 103.47.48.0/22 103.47.80.0/22 103.47.96.0/22 103.47.116.0/22 103.47.120.0/22 103.47.136.0/21 103.47.212.0/22 103.48.52.0/22 103.48.92.0/22 103.48.148.0/22 103.48.152.0/22 103.48.202.0/23 103.48.216.0/21 103.48.224.0/20 103.48.240.0/21 103.49.12.0/22 103.49.20.0/22 103.49.72.0/21 103.49.96.0/22 103.49.108.0/22 103.49.128.0/22 103.49.176.0/21 103.50.36.0/22 103.50.44.0/22 103.50.48.0/20 103.50.64.0/21 103.50.72.0/22 103.50.92.0/22 103.50.108.0/22 103.50.112.0/20 103.50.132.0/22 103.50.136.0/21 103.50.172.0/22 103.50.176.0/20 103.50.192.0/21 103.50.200.0/22 103.50.220.0/22 103.50.224.0/20 103.50.240.0/21 103.50.248.0/22 103.52.40.0/22 103.52.72.0/21 103.52.80.0/21 103.52.96.0/21 103.52.104.0/22 103.52.160.0/21 103.52.172.0/22 103.52.176.0/22 103.52.184.0/22 103.52.196.0/22 103.53.64.0/21 103.53.92.0/22 103.53.124.0/22 103.53.128.0/20 103.53.144.0/22 103.53.160.0/22 103.53.180.0/22 103.53.204.0/22 103.53.208.0/21 103.53.236.0/22 103.53.248.0/22 103.54.8.0/22 103.54.48.0/22 103.54.160.0/21 103.54.212.0/22 103.54.228.0/22 103.54.240.0/22 103.55.80.0/22 103.55.120.0/22 103.55.152.0/22 103.55.172.0/22 103.55.204.0/22 103.55.208.0/22 103.55.228.0/22 103.55.236.0/22 103.55.240.0/22 103.56.20.0/22 103.56.32.0/22 103.56.56.0/21 103.56.72.0/21 103.56.140.0/22 103.56.152.0/22 103.56.184.0/22 103.56.200.0/22 103.57.12.0/22 103.57.52.0/22 103.57.56.0/22 103.57.76.0/22 103.57.136.0/22 103.57.196.0/22 103.58.24.0/22 103.59.76.0/22 103.59.112.0/21 103.59.120.0/24 103.59.123.0/24 103.59.124.0/22 103.59.128.0/22 103.59.148.0/22 103.60.32.0/22 103.60.44.0/22 103.60.164.0/22 103.60.228.0/22 103.60.236.0/22 103.61.60.0/24 103.61.104.0/22 103.61.140.0/22 103.61.152.0/21 103.61.160.0/22 103.61.172.0/22 103.61.176.0/22 103.62.24.0/22 103.62.72.0/21 103.62.80.0/21 103.62.88.0/22 103.62.96.0/19 103.62.128.0/21 103.62.156.0/22 103.62.160.0/19 103.62.192.0/22 103.62.204.0/22 103.62.208.0/20 103.62.224.0/22 103.63.32.0/19 103.63.64.0/20 103.63.80.0/21 103.63.88.0/22 103.63.140.0/22 103.63.144.0/22 103.63.152.0/22 103.63.160.0/20 103.63.176.0/21 103.63.184.0/22 103.63.192.0/20 103.63.208.0/22 103.63.240.0/20 103.64.0.0/21 103.64.24.0/21 103.64.32.0/19 103.64.64.0/18 103.64.140.0/22 103.64.144.0/22 103.64.152.0/21 103.64.160.0/19 103.64.192.0/18 103.65.0.0/21 103.65.12.0/22 103.65.16.0/22 103.65.48.0/20 103.65.64.0/19 103.65.100.0/22 103.65.104.0/21 103.65.112.0/20 103.65.128.0/21 103.65.136.0/22 103.65.144.0/20 103.65.160.0/20 103.66.32.0/22 103.66.40.0/22 103.66.108.0/22 103.66.200.0/22 103.66.240.0/20 103.67.0.0/21 103.67.8.0/22 103.67.40.0/21 103.67.48.0/20 103.67.64.0/18 103.67.128.0/20 103.67.144.0/21 103.67.172.0/24 103.67.175.0/24 103.67.192.0/22 103.67.212.0/22 103.68.88.0/22 103.68.100.0/22 103.68.128.0/22 103.69.16.0/22 103.69.212.0/23 103.70.8.0/22 103.70.148.0/22 103.70.236.0/22 103.70.252.0/22 103.71.0.0/22 103.71.68.0/22 103.71.72.0/22 103.71.80.0/21 103.71.88.0/22 103.71.120.0/21 103.71.128.0/22 103.71.196.0/22 103.71.200.0/22 103.71.232.0/22 103.72.12.0/22 103.72.16.0/20 103.72.32.0/20 103.72.48.0/21 103.72.112.0/21 103.72.124.0/22 103.72.128.0/21 103.72.149.0/24 103.72.150.0/23 103.72.172.0/22 103.72.180.0/22 103.72.224.0/19 103.73.0.0/19 103.73.48.0/22 103.73.116.0/22 103.73.120.0/22 103.73.128.0/20 103.73.168.0/22 103.73.176.0/22 103.73.204.0/22 103.73.208.0/22 103.73.240.0/23 103.73.244.0/22 103.73.248.0/22 103.74.24.0/21 103.74.32.0/20 103.74.48.0/22 103.74.56.0/21 103.74.80.0/22 103.74.124.0/22 103.74.148.0/22 103.74.152.0/21 103.74.204.0/22 103.74.232.0/22 103.75.87.0/24 103.75.88.0/21 103.75.104.0/21 103.75.112.0/22 103.75.120.0/22 103.75.128.0/22 103.75.144.0/22 103.75.152.0/22 103.76.60.0/22 103.76.64.0/21 103.76.72.0/22 103.76.92.0/22 103.76.216.0/21 103.76.224.0/22 103.77.28.0/22 103.77.52.0/22 103.77.56.0/22 103.77.88.0/22 103.77.132.0/22 103.77.148.0/22 103.77.220.0/22 103.78.56.0/21 103.78.64.0/22 103.78.124.0/22 103.78.172.0/22 103.78.176.0/22 103.78.196.0/22 103.78.228.0/22 103.79.24.0/21 103.79.36.0/22 103.79.40.0/21 103.79.56.0/21 103.79.64.0/21 103.79.80.0/21 103.79.136.0/22 103.79.188.0/22 103.79.192.0/20 103.79.208.0/21 103.79.243.0/24 103.80.44.0/22 103.80.72.0/22 103.80.176.0/21 103.80.184.0/22 103.80.192.0/22 103.80.200.0/22 103.80.232.0/22 103.81.4.0/22 103.81.44.0/22 103.81.48.0/22 103.81.96.0/22 103.81.120.0/22 103.81.148.0/22 103.81.164.0/22 103.81.200.0/22 103.81.232.0/22 103.82.60.0/22 103.82.68.0/22 103.82.84.0/22 103.82.104.0/22 103.82.224.0/22 103.82.236.0/22 103.83.44.0/22 103.83.52.0/22 103.83.60.0/22 103.83.72.0/22 103.83.112.0/22 103.83.132.0/22 103.83.180.0/22 103.84.0.0/22 103.84.12.0/22 103.84.20.0/22 103.84.24.0/21 103.84.48.0/22 103.84.56.0/22 103.84.64.0/22 103.84.72.0/22 103.85.44.0/22 103.85.48.0/21 103.85.56.0/22 103.85.84.0/22 103.85.136.0/22 103.85.144.0/22 103.85.164.0/22 103.85.168.0/21 103.85.176.0/22 103.86.28.0/22 103.86.32.0/22 103.86.60.0/22 103.86.129.0/24 103.86.204.0/22 103.86.208.0/20 103.86.224.0/19 103.87.0.0/21 103.87.20.0/22 103.87.32.0/22 103.87.96.0/22 103.87.132.0/22 103.87.180.0/22 103.87.224.0/22 103.88.4.0/22 103.88.8.0/21 103.88.16.0/21 103.88.32.0/21 103.88.60.0/22 103.88.64.0/22 103.88.72.0/22 103.88.96.0/21 103.88.152.0/23 103.88.164.0/22 103.88.212.0/22 103.89.28.0/22 103.89.96.0/20 103.89.112.0/22 103.89.148.0/22 103.89.172.0/22 103.89.184.0/21 103.89.192.0/19 103.89.224.0/21 103.90.52.0/22 103.90.92.0/22 103.90.100.0/22 103.90.104.0/21 103.90.112.0/20 103.90.128.0/21 103.90.152.0/22 103.90.168.0/22 103.90.173.0/24 103.90.176.0/22 103.90.188.0/22 103.90.192.0/22 103.91.36.0/22 103.91.40.0/22 103.91.108.0/22 103.91.152.0/22 103.91.176.0/22 103.91.200.0/22 103.91.208.0/21 103.91.236.0/22 103.92.48.0/20 103.92.64.0/20 103.92.80.0/22 103.92.88.0/22 103.92.108.0/22 103.92.124.0/22 103.92.132.0/22 103.92.156.0/22 103.92.164.0/22 103.92.168.0/21 103.92.176.0/20 103.92.192.0/22 103.92.236.0/22 103.92.240.0/20 103.93.0.0/21 103.93.28.0/22 103.93.84.0/22 103.93.152.0/22 103.93.180.0/22 103.93.204.0/22 103.94.12.0/22 103.94.20.0/22 103.94.28.0/22 103.94.32.0/20 103.94.72.0/22 103.94.88.0/22 103.94.116.0/22 103.94.160.0/22 103.94.182.0/24 103.94.200.0/22 103.95.31.0/24 103.95.52.0/22 103.95.70.0/23 103.95.88.0/21 103.95.136.0/21 103.95.144.0/22 103.95.152.0/22 103.95.216.0/21 103.95.224.0/22 103.95.236.0/22 103.95.240.0/20 103.96.8.0/22 103.96.124.0/22 103.96.136.0/22 103.96.152.0/21 103.96.160.0/19 103.96.192.0/20 103.96.208.0/21 103.96.216.0/22 103.97.40.0/22 103.97.60.0/23 103.97.112.0/21 103.97.148.0/22 103.97.188.0/22 103.97.192.0/22 103.98.40.0/21 103.98.48.0/22 103.98.56.0/22 103.98.80.0/22 103.98.88.0/22 103.98.100.0/22 103.98.124.0/24 103.98.126.0/23 103.98.136.0/21 103.98.144.0/22 103.98.164.0/22 103.98.168.0/22 103.98.180.0/22 103.98.196.0/22 103.98.216.0/21 103.98.224.0/21 103.98.232.0/22 103.98.240.0/21 103.98.248.0/23 103.98.250.0/24 103.98.252.0/22 103.99.56.0/22 103.99.104.0/22 103.99.116.0/22 103.99.120.0/22 103.99.132.0/22 103.99.136.0/21 103.99.144.0/22 103.99.152.0/22 103.99.220.0/22 103.99.232.0/21 103.100.0.0/22 103.100.32.0/22 103.100.40.0/22 103.100.48.0/22 103.100.56.0/22 103.100.64.0/22 103.100.88.0/22 103.100.116.0/22 103.100.144.0/22 103.100.240.0/22 103.100.248.0/21 103.101.4.0/22 103.101.8.0/21 103.101.60.0/22 103.101.121.0/24 103.101.122.0/23 103.101.124.0/24 103.101.126.0/23 103.101.144.0/21 103.101.180.0/22 103.101.184.0/22 103.102.76.0/22 103.102.80.0/22 103.102.168.0/21 103.102.180.0/22 103.102.184.0/21 103.102.192.0/22 103.102.196.0/24 103.102.200.0/22 103.102.208.0/21 103.103.12.0/22 103.103.16.0/22 103.103.36.0/22 103.103.72.0/22 103.103.188.0/22 103.103.204.0/22 103.104.36.0/22 103.104.40.0/22 103.104.64.0/22 103.104.152.0/22 103.104.252.0/22 103.105.0.0/21 103.105.12.0/22 103.105.16.0/22 103.105.60.0/22 103.105.116.0/22 103.105.180.0/22 103.105.184.0/22 103.105.200.0/21 103.105.220.0/22 103.106.36.0/22 103.106.40.0/21 103.106.60.0/22 103.106.68.0/22 103.106.96.0/22 103.106.120.0/22 103.106.128.0/21 103.106.190.0/23 103.106.196.0/22 103.106.212.0/22 103.106.252.0/22 103.107.0.0/22 103.107.28.0/22 103.107.32.0/22 103.107.44.0/22 103.107.72.0/22 103.107.164.0/22 103.107.168.0/22 103.107.188.0/22 103.107.192.0/22 103.107.208.0/20 103.108.52.0/22 103.108.160.0/21 103.108.194.0/24 103.108.196.0/22 103.108.208.0/21 103.108.224.0/22 103.108.244.0/22 103.108.251.0/24 103.109.20.0/22 103.109.48.0/22 103.109.88.0/22 103.109.106.0/23 103.109.248.0/22 103.110.32.0/22 103.110.92.0/22 103.110.119.0/24 103.110.127.0/24 103.110.128.0/23 103.110.131.0/24 103.110.132.0/22 103.110.136.0/22 103.110.156.0/22 103.110.188.0/22 103.110.204.0/22 103.111.64.0/22 103.111.172.0/22 103.111.252.0/22 103.112.72.0/22 103.112.88.0/21 103.112.108.0/22 103.112.112.0/22 103.112.140.0/22 103.113.4.0/22 103.113.144.0/22 103.113.220.0/22 103.113.232.0/21 103.114.4.0/22 103.114.68.0/22 103.114.100.0/22 103.114.148.0/22 103.114.156.0/23 103.114.159.0/24 103.114.212.0/22 103.114.236.0/22 103.114.240.0/22 103.115.52.0/22 103.115.68.0/22 103.115.92.0/22 103.115.120.0/22 103.115.148.0/22 103.115.248.0/22 103.116.76.0/22 103.116.92.0/22 103.116.120.0/22 103.116.128.0/22 103.116.150.0/23 103.116.184.0/22 103.116.220.0/22 103.116.224.0/21 103.117.16.0/22 103.117.88.0/22 103.117.188.0/22 103.117.220.0/22 103.118.19.0/24 103.118.52.0/22 103.118.56.0/21 103.118.64.0/21 103.118.72.0/22 103.118.88.0/22 103.118.173.0/24 103.119.115.0/24 103.119.156.0/22 103.119.180.0/22 103.119.200.0/22 103.119.224.0/22 103.120.52.0/22 103.120.72.0/22 103.120.76.0/24 103.120.88.0/22 103.120.96.0/22 103.120.140.0/22 103.120.196.0/22 103.120.224.0/22 103.121.52.0/22 103.121.160.0/21 103.121.250.0/24 103.121.252.0/22 103.122.48.0/22 103.122.178.0/23 103.122.192.0/22 103.122.240.0/23 103.122.242.0/24 103.123.4.0/22 103.123.56.0/22 103.123.88.0/21 103.123.116.0/22 103.123.176.0/22 103.123.200.0/21 103.123.208.0/21 103.124.24.0/22 103.124.48.0/22 103.124.64.0/22 103.124.212.0/22 103.124.216.0/22 103.125.20.0/22 103.125.44.0/22 103.125.132.0/22 103.125.164.0/22 103.125.196.0/22 103.125.236.0/22 103.126.0.0/22 103.126.16.0/23 103.126.44.0/22 103.126.124.0/22 103.126.128.0/22 103.129.53.0/24 103.129.54.0/23 103.129.148.0/22 103.130.132.0/22 103.130.160.0/22 103.130.228.0/22 103.131.20.0/22 103.131.36.0/22 103.131.152.0/22 103.131.168.0/22 103.131.224.0/21 103.131.240.0/22 103.132.60.0/22 103.132.64.0/20 103.132.80.0/22 103.132.104.0/21 103.132.112.0/21 103.132.120.0/22 103.132.188.0/22 103.132.208.0/21 103.133.12.0/22 103.133.40.0/22 103.133.128.0/22 103.133.232.0/22 103.134.196.0/22 103.135.80.0/22 103.135.124.0/22 103.135.148.0/22 103.135.156.0/22 103.135.160.0/21 103.135.176.0/22 103.135.184.0/22 103.135.192.0/21 103.135.236.0/22 103.136.128.0/22 103.136.232.0/22 103.137.58.0/23 103.137.60.0/24 103.137.136.0/23 103.137.149.0/24 103.137.180.0/22 103.137.236.0/22 103.138.2.0/23 103.138.134.0/23 103.138.208.0/23 103.138.220.0/23 103.138.248.0/23 103.139.22.0/23 103.139.134.0/23 103.139.136.0/23 103.139.172.0/23 103.139.204.0/23 103.139.212.0/23 103.140.14.0/23 103.140.46.0/23 103.140.140.0/23 103.140.144.0/23 103.140.192.0/23 103.141.10.0/23 103.141.58.0/23 103.141.128.0/23 103.141.186.0/23 103.141.242.0/23 103.142.0.0/23 103.142.28.0/23 103.142.58.0/23 103.142.82.0/23 103.142.96.0/23 103.142.122.0/23 103.142.128.0/23 103.142.154.0/23 103.142.156.0/23 103.142.180.0/23 103.142.186.0/23 103.142.220.0/23 103.142.230.0/24 103.142.234.0/23 103.142.238.0/23 103.143.16.0/22 103.143.31.0/24 103.143.74.0/23 103.143.124.0/23 103.143.132.0/22 103.143.174.0/23 103.143.228.0/23 103.144.66.0/23 103.144.70.0/23 103.144.72.0/23 103.144.136.0/23 103.144.158.0/23 103.145.40.0/22 103.145.73.0/24 103.145.80.0/23 103.145.90.0/23 103.145.92.0/22 103.145.98.0/23 103.145.107.0/24 103.145.188.0/23 103.146.6.0/23 103.146.72.0/23 103.146.90.0/23 103.146.126.0/23 103.146.138.0/23 103.146.236.0/23 103.146.252.0/23 103.147.124.0/23 103.147.198.0/23 103.147.206.0/23 103.148.174.0/23 103.192.0.0/19 103.192.48.0/21 103.192.56.0/22 103.192.84.0/22 103.192.88.0/21 103.192.96.0/20 103.192.112.0/22 103.192.128.0/20 103.192.144.0/22 103.192.164.0/22 103.192.188.0/22 103.192.208.0/21 103.192.216.0/22 103.192.252.0/22 103.193.40.0/21 103.193.120.0/22 103.193.140.0/22 103.193.160.0/22 103.193.188.0/22 103.193.192.0/22 103.193.212.0/22 103.193.216.0/21 103.193.224.0/20 103.194.16.0/22 103.194.230.0/23 103.195.112.0/22 103.195.152.0/22 103.195.160.0/22 103.196.64.0/22 103.196.72.0/22 103.196.88.0/21 103.196.96.0/22 103.196.168.0/22 103.196.185.0/24 103.196.186.0/23 103.197.181.0/24 103.197.183.0/24 103.197.228.0/22 103.197.253.0/24 103.197.254.0/23 103.198.20.0/22 103.198.60.0/22 103.198.64.0/22 103.198.72.0/22 103.198.124.0/22 103.198.156.0/22 103.198.180.0/22 103.198.196.0/22 103.198.200.0/22 103.198.216.0/21 103.198.224.0/20 103.198.240.0/21 103.199.164.0/22 103.199.196.0/22 103.199.228.0/22 103.199.252.0/22 103.200.52.0/22 103.200.64.0/21 103.200.136.0/21 103.200.144.0/20 103.200.160.0/19 103.200.192.0/22 103.200.220.0/22 103.200.224.0/19 103.201.0.0/20 103.201.16.0/21 103.201.28.0/22 103.201.32.0/19 103.201.64.0/22 103.201.76.0/22 103.201.80.0/20 103.201.96.0/20 103.201.112.0/21 103.201.120.0/22 103.201.152.0/21 103.201.160.0/19 103.201.192.0/18 103.202.0.0/19 103.202.32.0/20 103.202.56.0/21 103.202.64.0/18 103.202.128.0/20 103.202.144.0/22 103.202.152.0/21 103.202.160.0/19 103.202.192.0/20 103.202.212.0/22 103.202.228.0/22 103.202.236.0/22 103.202.240.0/20 103.203.0.0/19 103.203.32.0/22 103.203.96.0/19 103.203.128.0/22 103.203.140.0/22 103.203.164.0/22 103.203.168.0/22 103.203.192.0/22 103.203.200.0/22 103.203.212.0/22 103.203.216.0/22 103.204.24.0/22 103.204.88.0/22 103.204.112.0/22 103.204.136.0/21 103.204.144.0/21 103.204.152.0/22 103.204.196.0/22 103.204.232.0/21 103.205.4.0/22 103.205.40.0/21 103.205.52.0/22 103.205.108.0/22 103.205.116.0/22 103.205.120.0/24 103.205.136.0/22 103.205.162.0/24 103.205.188.0/22 103.205.192.0/21 103.205.200.0/22 103.205.236.0/22 103.205.248.0/21 103.206.0.0/22 103.206.44.0/22 103.206.148.0/22 103.207.104.0/22 103.207.184.0/21 103.207.192.0/20 103.207.208.0/21 103.207.220.0/22 103.207.228.0/22 103.207.232.0/22 103.208.12.0/22 103.208.16.0/22 103.208.28.0/22 103.208.48.0/22 103.208.148.0/22 103.209.112.0/22 103.209.136.0/22 103.209.200.0/22 103.209.208.0/22 103.209.216.0/22 103.210.0.0/22 103.210.96.0/22 103.210.156.0/22 103.210.160.0/19 103.210.217.0/24 103.210.218.0/23 103.211.44.0/22 103.211.96.0/23 103.211.98.0/24 103.211.100.0/22 103.211.156.0/22 103.211.165.0/24 103.211.168.0/22 103.211.220.0/22 103.211.248.0/22 103.212.0.0/20 103.212.44.0/22 103.212.48.0/22 103.212.84.0/22 103.212.100.0/22 103.212.148.0/22 103.212.164.0/22 103.212.196.0/22 103.212.200.0/22 103.212.252.0/22 103.213.40.0/21 103.213.48.0/20 103.213.64.0/19 103.213.96.0/22 103.213.132.0/22 103.213.136.0/21 103.213.144.0/20 103.213.160.0/19 103.213.252.0/22 103.214.48.0/22 103.214.84.0/22 103.214.212.0/22 103.214.240.0/21 103.215.28.0/22 103.215.32.0/21 103.215.44.0/22 103.215.100.0/23 103.215.108.0/22 103.215.116.0/22 103.215.120.0/22 103.215.140.0/22 103.216.4.0/22 103.216.8.0/21 103.216.16.0/20 103.216.32.0/20 103.216.64.0/22 103.216.108.0/22 103.216.136.0/22 103.216.152.0/22 103.216.224.0/21 103.216.240.0/20 103.217.0.0/18 103.217.168.0/22 103.217.180.0/22 103.217.184.0/21 103.217.192.0/20 103.218.8.0/21 103.218.16.0/21 103.218.29.0/24 103.218.30.0/23 103.218.32.0/19 103.218.64.0/19 103.218.192.0/20 103.218.208.0/21 103.218.216.0/22 103.219.24.0/21 103.219.32.0/21 103.219.64.0/22 103.219.84.0/22 103.219.88.0/21 103.219.96.0/21 103.219.176.0/22 103.219.184.0/22 103.220.48.0/20 103.220.64.0/22 103.220.92.0/22 103.220.96.0/22 103.220.104.0/21 103.220.116.0/22 103.220.120.0/21 103.220.128.0/20 103.220.144.0/21 103.220.152.0/22 103.220.160.0/19 103.220.192.0/21 103.220.200.0/22 103.220.240.0/20 103.221.0.0/19 103.221.32.0/21 103.221.88.0/21 103.221.96.0/19 103.221.128.0/18 103.221.192.0/20 103.222.0.0/20 103.222.16.0/22 103.222.24.0/21 103.222.33.0/24 103.222.34.0/23 103.222.36.0/22 103.222.40.0/21 103.222.48.0/20 103.222.64.0/18 103.222.128.0/18 103.222.192.0/19 103.222.224.0/21 103.222.232.0/22 103.222.240.0/21 103.223.16.0/20 103.223.32.0/19 103.223.64.0/19 103.223.96.0/20 103.223.112.0/21 103.223.124.0/22 103.223.128.0/21 103.223.140.0/22 103.223.144.0/20 103.223.160.0/20 103.223.176.0/21 103.223.188.0/22 103.223.192.0/18 103.224.0.0/22 103.224.40.0/21 103.224.60.0/22 103.224.220.0/22 103.224.224.0/21 103.224.232.0/22 103.226.40.0/22 103.226.56.0/21 103.226.80.0/22 103.226.116.0/22 103.226.132.0/22 103.226.156.0/22 103.226.180.0/22 103.226.196.0/22 103.227.48.0/22 103.227.72.0/21 103.227.80.0/22 103.227.100.0/22 103.227.120.0/22 103.227.132.0/22 103.227.136.0/22 103.227.196.0/22 103.227.204.0/23 103.227.206.0/24 103.227.212.0/22 103.227.228.0/22 103.228.12.0/22 103.228.88.0/22 103.228.136.0/22 103.228.160.0/22 103.228.176.0/22 103.228.204.0/22 103.228.208.0/22 103.228.228.0/22 103.228.232.0/22 103.229.20.0/22 103.229.136.0/22 103.229.148.0/22 103.229.172.0/22 103.229.212.0/22 103.229.216.0/21 103.229.228.0/22 103.229.236.0/22 103.229.240.0/22 103.230.0.0/22 103.230.28.0/22 103.230.40.0/21 103.230.96.0/22 103.230.196.0/22 103.230.200.0/21 103.230.212.0/22 103.230.236.0/22 103.231.16.0/21 103.231.64.0/21 103.231.144.0/22 103.231.180.0/22 103.231.244.0/22 103.232.4.0/22 103.232.17.168/29 103.232.144.0/22 103.233.4.0/22 103.233.44.0/22 103.233.52.0/22 103.233.104.0/22 103.233.128.0/22 103.233.136.0/22 103.233.228.0/22 103.234.0.0/22 103.234.20.0/22 103.234.56.0/22 103.234.124.0/22 103.234.128.0/22 103.234.172.0/22 103.234.180.0/22 103.235.56.0/21 103.235.80.0/22 103.235.85.0/24 103.235.86.0/23 103.235.128.0/20 103.235.144.0/21 103.235.184.0/22 103.235.192.0/22 103.235.200.0/22 103.235.220.0/22 103.235.224.0/19 103.236.0.0/18 103.236.64.0/19 103.236.96.0/22 103.236.120.0/22 103.236.184.0/22 103.236.240.0/20 103.237.0.0/20 103.237.24.0/21 103.237.68.0/22 103.237.88.0/22 103.237.152.0/22 103.237.176.0/20 103.237.192.0/18 103.238.0.0/21 103.238.18.0/23 103.238.20.0/22 103.238.24.0/21 103.238.32.0/20 103.238.48.0/21 103.238.56.0/22 103.238.88.0/21 103.238.96.0/22 103.238.132.0/22 103.238.140.0/22 103.238.144.0/22 103.238.160.0/22 103.238.165.0/24 103.238.166.0/23 103.238.168.0/21 103.238.176.0/20 103.238.196.0/22 103.238.204.0/22 103.238.252.0/22 103.239.0.0/22 103.239.44.0/22 103.239.68.0/22 103.239.152.0/21 103.239.180.0/22 103.239.184.0/22 103.239.192.0/21 103.239.204.0/22 103.239.208.0/22 103.239.224.0/22 103.239.244.0/22 103.240.16.0/22 103.240.36.0/22 103.240.72.0/22 103.240.84.0/22 103.240.124.0/22 103.240.172.0/22 103.240.188.0/22 103.240.244.0/22 103.241.12.0/22 103.241.92.0/22 103.241.96.0/22 103.241.160.0/22 103.241.184.0/21 103.241.220.0/22 103.242.64.0/23 103.242.128.0/23 103.242.160.0/22 103.242.168.0/21 103.242.176.0/22 103.242.200.0/22 103.242.212.0/22 103.242.220.0/22 103.242.240.0/22 103.243.136.0/22 103.243.252.0/22 103.244.16.0/22 103.244.58.0/23 103.244.60.0/22 103.244.64.0/20 103.244.80.0/21 103.244.116.0/22 103.244.164.0/22 103.244.232.0/22 103.244.252.0/22 103.245.23.0/24 103.245.52.0/22 103.245.60.0/22 103.245.80.0/22 103.245.124.0/22 103.245.128.0/22 103.246.8.0/21 103.246.120.0/21 103.246.132.0/22 103.246.152.0/22 103.247.168.0/21 103.247.176.0/22 103.247.200.0/22 103.247.212.0/22 103.248.64.0/23 103.248.100.0/22 103.248.124.0/22 103.248.152.0/22 103.248.168.0/22 103.248.192.0/22 103.248.212.0/22 103.248.224.0/21 103.249.8.0/21 103.249.52.0/22 103.249.128.0/22 103.249.136.0/22 103.249.144.0/22 103.249.164.0/22 103.249.168.0/21 103.249.176.0/22 103.249.188.0/22 103.249.192.0/22 103.249.244.0/22 103.249.252.0/22 103.250.32.0/22 103.250.104.0/22 103.250.124.0/22 103.250.180.0/22 103.250.192.0/22 103.250.216.0/22 103.250.224.0/22 103.250.236.0/22 103.250.248.0/21 103.251.32.0/22 103.251.84.0/22 103.251.96.0/22 103.251.124.0/22 103.251.160.0/22 103.251.192.0/22 103.251.204.0/22 103.251.240.0/22 103.252.28.0/22 103.252.36.0/22 103.252.64.0/22 103.252.96.0/22 103.252.104.0/22 103.252.172.0/22 103.252.204.0/22 103.252.208.0/22 103.252.232.0/22 103.252.248.0/22 103.253.4.0/22 103.253.60.0/22 103.253.204.0/22 103.253.220.0/22 103.253.224.0/22 103.253.232.0/22 103.254.8.0/22 103.254.20.0/22 103.254.64.0/21 103.254.76.0/22 103.254.112.0/22 103.254.176.0/22 103.254.188.0/22 103.255.68.0/22 103.255.88.0/21 103.255.136.0/21 103.255.184.0/22 103.255.200.0/22 103.255.208.0/22 103.255.228.0/22 104.222.196.0/24 106.0.0.0/24 106.0.2.0/23 106.0.4.0/22 106.0.8.0/21 106.0.16.0/20 106.0.44.0/22 106.0.64.0/18 106.2.0.0/23 106.2.3.0/24 106.2.4.0/22 106.2.8.0/21 106.2.16.0/20 106.2.32.0/19 106.2.64.0/18 106.2.128.0/17 106.3.16.0/20 106.3.32.0/19 106.3.64.0/20 106.3.80.0/22 106.3.88.0/21 106.3.96.0/19 106.3.128.0/19 106.3.164.0/22 106.3.168.0/21 106.3.176.0/20 106.3.192.0/18 106.4.0.0/14 106.8.0.0/15 106.11.0.0/16 106.12.0.0/14 106.16.0.0/12 106.32.0.0/12 106.48.0.0/21 106.48.8.0/22 106.48.16.0/20 106.48.32.0/20 106.48.57.0/24 106.48.60.0/24 106.48.63.0/24 106.48.64.0/18 106.48.128.0/17 106.49.1.0/24 106.49.2.0/23 106.49.4.0/22 106.49.8.0/21 106.49.16.0/20 106.49.32.0/19 106.49.64.0/19 106.49.96.0/24 106.49.98.0/23 106.49.100.0/22 106.49.104.0/21 106.49.112.0/20 106.49.128.0/17 106.50.0.0/16 106.52.0.0/14 106.56.0.0/13 106.74.0.0/16 106.75.0.0/17 106.75.128.0/18 106.75.201.0/24 106.75.204.0/22 106.75.208.0/20 106.75.224.0/19 106.80.0.0/12 106.108.0.0/14 106.112.0.0/12 106.224.0.0/12 109.71.4.0/24 109.244.0.0/16 110.6.0.0/15 110.16.0.0/14 110.34.40.0/21 110.40.0.0/15 110.42.0.0/16 110.43.0.0/18 110.43.64.0/21 110.43.72.0/22 110.43.76.0/23 110.43.80.0/20 110.43.96.0/19 110.43.128.0/17 110.44.12.0/22 110.44.144.0/20 110.48.0.0/16 110.51.0.0/16 110.52.0.0/15 110.56.0.0/13 110.64.0.0/15 110.72.0.0/15 110.75.0.0/16 110.76.0.0/20 110.76.16.0/22 110.76.20.0/24 110.76.22.0/24 110.76.24.0/21 110.76.32.0/19 110.76.132.0/22 110.76.156.0/22 110.76.184.0/22 110.76.192.0/18 110.77.0.0/17 110.80.0.0/13 110.88.0.0/14 110.92.68.0/22 110.93.32.0/19 110.94.0.0/15 110.96.0.0/11 110.152.0.0/14 110.156.0.0/15 110.166.0.0/15 110.172.192.0/18 110.173.0.0/19 110.173.32.0/20 110.173.64.0/19 110.173.192.0/19 110.176.0.0/12 110.192.0.0/11 110.228.0.0/14 110.232.32.0/19 110.236.0.0/15 110.240.0.0/12 111.0.0.0/10 111.66.0.0/16 111.67.192.0/20 111.68.64.0/19 111.72.0.0/13 111.85.0.0/16 111.91.192.0/19 111.92.248.0/21 111.112.0.0/14 111.116.0.0/15 111.118.200.0/21 111.119.64.0/18 111.119.128.0/19 111.120.0.0/14 111.124.0.0/16 111.126.0.0/15 111.128.0.0/11 111.160.0.0/13 111.170.0.0/16 111.172.0.0/14 111.176.0.0/13 111.186.0.0/15 111.192.0.0/12 111.208.0.0/13 111.221.28.0/24 111.221.128.0/17 111.222.0.0/16 111.223.4.0/22 111.223.8.0/21 111.223.16.0/22 111.223.240.0/22 111.223.249.0/24 111.223.250.0/23 111.224.0.0/13 111.235.96.0/19 111.235.156.0/22 111.235.160.0/21 111.235.170.0/23 111.235.172.0/22 111.235.176.0/20 112.0.0.0/10 112.64.0.0/14 112.73.64.0/18 112.74.0.0/16 112.80.0.0/12 112.96.0.0/13 112.109.128.0/17 112.111.0.0/16 112.112.0.0/14 112.116.0.0/15 112.122.0.0/15 112.124.0.0/14 112.128.0.0/14 112.132.0.0/16 112.137.48.0/21 112.192.0.0/14 112.224.0.0/11 113.0.0.0/13 113.8.0.0/15 113.11.192.0/19 113.12.0.0/14 113.16.0.0/15 113.18.0.0/16 113.21.232.0/21 113.24.0.0/14 113.31.0.0/16 113.44.0.0/14 113.48.0.0/14 113.52.160.0/19 113.52.228.0/22 113.54.0.0/15 113.56.0.0/15 113.58.0.0/16 113.59.0.0/17 113.59.224.0/22 113.62.0.0/15 113.64.0.0/10 113.128.0.0/15 113.130.96.0/20 113.130.112.0/21 113.132.0.0/14 113.136.0.0/13 113.194.0.0/15 113.197.100.0/23 113.197.102.0/24 113.197.104.0/22 113.200.0.0/15 113.202.0.0/16 113.204.0.0/14 113.208.96.0/19 113.208.128.0/17 113.209.0.0/16 113.212.0.0/18 113.212.100.0/22 113.212.184.0/21 113.213.0.0/17 113.214.0.0/15 113.218.0.0/15 113.220.0.0/14 113.224.0.0/12 113.240.0.0/13 113.248.0.0/14 114.28.0.0/17 114.28.128.0/18 114.28.192.0/19 114.28.232.0/22 114.28.236.0/23 114.28.240.0/20 114.31.64.0/21 114.54.0.0/15 114.60.0.0/14 114.64.0.0/14 114.68.0.0/16 114.79.64.0/18 114.80.0.0/12 114.96.0.0/13 114.104.0.0/14 114.110.0.0/20 114.110.64.0/18 114.111.0.0/19 114.111.160.0/19 114.112.4.0/22 114.112.8.0/22 114.112.24.0/21 114.112.32.0/19 114.112.64.0/19 114.112.96.0/20 114.112.116.0/22 114.112.120.0/21 114.112.136.0/21 114.112.144.0/20 114.112.160.0/19 114.112.192.0/19 114.113.0.0/17 114.113.128.0/21 114.113.140.0/22 114.113.144.0/20 114.113.160.0/19 114.113.196.0/22 114.113.200.0/21 114.113.208.0/20 114.113.224.0/20 114.114.0.0/15 114.116.0.0/15 114.118.0.0/16 114.119.0.0/17 114.119.192.0/18 114.132.0.0/16 114.135.0.0/16 114.138.0.0/15 114.141.64.0/21 114.141.80.0/21 114.141.128.0/18 114.196.0.0/15 114.198.248.0/21 114.208.0.0/12 114.224.0.0/11 115.24.0.0/14 115.28.0.0/15 115.31.64.0/20 115.32.0.0/14 115.42.56.0/22 115.44.0.0/14 115.48.0.0/12 115.69.64.0/20 115.84.0.0/18 115.84.192.0/19 115.85.192.0/18 115.100.0.0/14 115.104.0.0/14 115.120.0.0/14 115.124.16.0/20 115.148.0.0/14 115.152.0.0/13 115.166.64.0/19 115.168.0.0/16 115.169.0.0/23 115.169.3.0/24 115.169.6.0/24 115.169.9.0/24 115.169.14.0/23 115.169.16.0/20 115.169.39.0/24 115.169.42.0/23 115.169.44.0/22 115.169.48.0/20 115.169.64.0/18 115.169.128.0/17 115.170.0.0/15 115.172.0.0/14 115.180.0.0/14 115.187.0.0/20 115.190.0.0/15 115.192.0.0/11 115.224.0.0/12 116.0.8.0/21 116.0.24.0/21 116.1.0.0/16 116.2.0.0/15 116.4.0.0/14 116.8.0.0/14 116.13.0.0/16 116.16.0.0/12 116.50.0.0/20 116.52.0.0/14 116.56.0.0/15 116.58.128.0/20 116.58.208.0/20 116.60.0.0/14 116.66.0.0/18 116.66.64.0/19 116.66.96.0/20 116.66.120.0/22 116.68.136.0/21 116.68.176.0/21 116.69.0.0/16 116.70.0.0/17 116.76.0.0/14 116.85.0.0/17 116.85.128.0/18 116.85.192.0/19 116.85.224.0/20 116.85.240.0/21 116.85.248.0/23 116.85.250.0/24 116.85.252.0/22 116.89.144.0/20 116.90.80.0/20 116.90.184.0/21 116.95.0.0/16 116.112.0.0/14 116.116.0.0/15 116.128.0.0/10 116.192.0.0/16 116.193.16.0/20 116.193.32.0/19 116.193.176.0/21 116.194.0.0/15 116.196.0.0/21 116.196.8.0/22 116.196.12.0/23 116.196.16.0/20 116.196.32.0/19 116.196.64.0/18 116.196.128.0/18 116.196.192.0/21 116.196.200.0/23 116.196.203.0/24 116.196.204.0/22 116.196.208.0/20 116.196.224.0/19 116.197.160.0/21 116.197.180.0/23 116.198.0.0/16 116.199.0.0/17 116.199.128.0/19 116.204.0.0/17 116.204.232.0/22 116.205.0.0/16 116.207.0.0/16 116.208.0.0/14 116.212.160.0/20 116.213.64.0/18 116.213.128.0/17 116.214.32.0/19 116.214.64.0/20 116.214.128.0/17 116.215.0.0/16 116.216.0.0/14 116.224.0.0/12 116.242.0.0/15 116.244.0.0/14 116.248.0.0/15 116.252.0.0/15 116.254.104.0/21 116.254.129.0/24 116.254.130.0/23 116.254.132.0/22 116.254.136.0/21 116.254.144.0/20 116.254.160.0/19 116.254.192.0/18 116.255.128.0/17 117.8.0.0/13 117.21.0.0/16 117.22.0.0/15 117.24.0.0/13 117.32.0.0/13 117.40.0.0/14 117.44.0.0/15 117.48.0.0/15 117.50.0.0/16 117.51.128.0/23 117.51.131.0/24 117.51.132.0/22 117.51.136.0/21 117.51.144.0/20 117.51.160.0/19 117.51.192.0/18 117.53.48.0/20 117.53.176.0/20 117.57.0.0/16 117.58.0.0/18 117.59.0.0/16 117.60.0.0/14 117.64.0.0/13 117.72.0.0/15 117.74.64.0/19 117.74.128.0/17 117.75.0.0/16 117.76.0.0/14 117.80.0.0/12 117.100.0.0/15 117.103.16.0/20 117.103.40.0/21 117.103.72.0/21 117.103.128.0/20 117.104.168.0/21 117.106.0.0/15 117.112.0.0/13 117.120.64.0/18 117.120.128.0/17 117.121.0.0/19 117.121.32.0/21 117.121.40.0/22 117.121.44.0/23 117.121.46.0/24 117.121.48.0/20 117.121.64.0/18 117.121.128.0/20 117.121.148.0/22 117.121.152.0/21 117.121.160.0/19 117.121.192.0/21 117.122.128.0/17 117.124.0.0/14 117.128.0.0/10 118.24.0.0/15 118.26.0.0/19 118.26.36.0/22 118.26.40.0/21 118.26.48.0/20 118.26.64.0/19 118.26.104.0/21 118.26.112.0/20 118.26.128.0/17 118.28.0.0/15 118.30.0.0/20 118.30.16.0/21 118.30.24.0/22 118.30.32.0/19 118.30.64.0/18 118.30.128.0/17 118.31.0.0/16 118.64.0.0/15 118.66.0.0/16 118.67.112.0/20 118.72.0.0/13 118.80.0.0/15 118.84.0.0/15 118.88.32.0/19 118.88.64.0/18 118.88.128.0/17 118.89.0.0/16 118.102.16.0/20 118.102.32.0/21 118.103.164.0/22 118.103.168.0/21 118.103.176.0/22 118.103.245.0/24 118.103.246.0/23 118.112.0.0/13 118.120.0.0/14 118.124.0.0/15 118.126.1.0/24 118.126.2.0/23 118.126.4.0/22 118.126.8.0/21 118.126.16.0/23 118.126.18.0/24 118.126.32.0/19 118.126.64.0/18 118.126.128.0/17 118.127.128.0/19 118.132.0.0/14 118.144.0.0/14 118.178.0.0/16 118.180.0.0/14 118.184.5.0/24 118.184.10.0/24 118.184.115.0/24 118.184.116.0/22 118.184.120.0/23 118.184.122.0/24 118.184.128.0/18 118.184.192.0/19 118.184.240.0/20 118.186.0.0/15 118.188.0.0/16 118.190.0.0/16 118.191.0.0/20 118.191.24.0/21 118.191.32.0/19 118.191.64.0/18 118.191.144.0/21 118.191.153.0/24 118.191.154.0/23 118.191.156.0/22 118.191.160.0/19 118.191.192.0/20 118.191.209.0/24 118.191.210.0/23 118.191.212.0/22 118.191.248.0/21 118.192.0.0/16 118.193.0.0/22 118.193.32.0/20 118.193.56.0/21 118.193.68.0/22 118.193.72.0/24 118.193.77.0/24 118.193.96.0/19 118.194.0.0/17 118.194.128.0/18 118.194.192.0/19 118.194.232.0/21 118.194.240.0/20 118.195.0.0/16 118.196.0.0/14 118.202.0.0/15 118.204.0.0/14 118.212.0.0/15 118.215.192.0/18 118.224.0.0/14 118.228.0.0/17 118.228.128.0/20 118.228.144.0/21 118.228.156.0/22 118.228.160.0/19 118.228.192.0/18 118.229.0.0/16 118.230.0.0/16 118.239.0.0/16 118.242.0.0/16 118.244.0.0/14 118.248.0.0/13 119.0.0.0/15 119.2.0.0/19 119.2.128.0/17 119.3.0.0/16 119.4.0.0/14 119.10.0.0/17 119.15.136.0/21 119.16.0.0/16 119.18.192.0/20 119.18.208.0/21 119.18.224.0/19 119.19.0.0/16 119.20.0.0/14 119.27.64.0/18 119.27.128.0/17 119.28.28.0/24 119.29.0.0/16 119.30.48.0/20 119.31.192.0/19 119.32.0.0/14 119.36.0.0/15 119.38.0.0/17 119.38.128.0/18 119.38.192.0/20 119.38.208.0/22 119.38.212.0/23 119.38.214.0/27 119.38.214.56/29 119.38.214.64/26 119.38.214.128/25 119.38.215.0/24 119.38.216.0/21 119.39.0.0/16 119.40.0.0/18 119.40.64.0/20 119.40.128.0/17 119.41.0.0/16 119.42.0.0/19 119.42.52.0/22 119.42.128.0/20 119.42.224.0/19 119.44.0.0/15 119.48.0.0/13 119.57.0.0/16 119.58.0.0/16 119.59.128.0/17 119.60.0.0/15 119.62.0.0/16 119.63.32.0/19 119.75.208.0/20 119.78.0.0/15 119.80.0.0/16 119.82.208.0/20 119.84.0.0/14 119.88.0.0/16 119.89.0.0/17 119.89.128.0/21 119.89.136.0/23 119.89.139.0/24 119.89.140.0/22 119.89.144.0/20 119.89.160.0/20 119.89.176.0/22 119.89.180.0/23 119.89.183.0/24 119.89.184.0/21 119.89.192.0/23 119.89.194.0/24 119.89.196.0/22 119.89.200.0/21 119.89.208.0/21 119.89.217.0/24 119.89.218.0/23 119.89.220.0/22 119.89.224.0/19 119.90.0.0/15 119.96.0.0/13 119.108.0.0/15 119.112.0.0/12 119.128.0.0/12 119.144.0.0/14 119.148.160.0/19 119.151.192.0/18 119.160.200.0/21 119.161.120.0/21 119.161.128.0/21 119.161.160.0/19 119.161.192.0/18 119.162.0.0/15 119.164.0.0/14 119.176.0.0/12 119.232.0.0/15 119.235.128.0/19 119.235.160.0/20 119.235.184.0/22 119.248.0.0/14 119.252.96.0/21 119.252.240.0/21 119.252.249.0/24 119.252.252.0/23 119.253.0.0/16 119.254.0.0/15 120.0.0.0/12 120.24.0.0/14 120.30.0.0/15 120.32.0.0/12 120.48.0.0/15 120.52.0.0/14 120.64.0.0/13 120.72.32.0/19 120.72.128.0/17 120.76.0.0/14 120.80.0.0/13 120.88.8.0/21 120.90.0.0/15 120.92.0.0/17 120.92.128.0/18 120.92.192.0/22 120.92.198.0/23 120.92.200.0/21 120.92.208.0/20 120.92.224.0/19 120.94.0.0/15 120.128.0.0/13 120.136.16.0/21 120.136.128.0/18 120.137.0.0/17 120.143.128.0/19 120.192.0.0/10 121.0.8.0/21 121.0.16.0/20 121.4.0.0/15 121.8.0.0/13 121.16.0.0/12 121.32.0.0/13 121.40.0.0/14 121.46.0.0/18 121.46.76.0/22 121.46.128.0/17 121.47.0.0/16 121.48.0.0/15 121.50.8.0/21 121.51.0.0/16 121.52.160.0/19 121.52.208.0/20 121.52.224.0/19 121.54.176.0/21 121.55.0.0/18 121.56.0.0/15 121.58.0.0/17 121.58.136.0/21 121.58.144.0/20 121.58.160.0/21 121.59.0.0/16 121.60.0.0/14 121.68.0.0/14 121.76.0.0/15 121.79.128.0/18 121.89.0.0/16 121.100.128.0/17 121.101.0.0/18 121.101.208.0/20 121.192.0.0/13 121.200.192.0/21 121.201.0.0/16 121.204.0.0/14 121.224.0.0/12 121.248.0.0/14 121.255.0.0/16 122.0.64.0/18 122.0.128.0/17 122.4.0.0/14 122.10.132.0/23 122.10.136.0/23 122.10.196.0/23 122.10.216.0/22 122.10.228.0/22 122.10.232.0/21 122.10.240.0/21 122.10.248.0/22 122.11.0.0/17 122.12.0.0/15 122.14.0.0/17 122.14.192.0/18 122.48.0.0/16 122.49.0.0/18 122.51.0.0/16 122.64.0.0/11 122.96.0.0/15 122.98.144.0/20 122.98.160.0/21 122.98.172.0/22 122.98.176.0/20 122.98.192.0/21 122.98.232.0/21 122.98.240.0/20 122.102.0.0/20 122.102.64.0/19 122.112.0.0/18 122.112.64.0/19 122.112.96.0/22 122.112.107.0/24 122.112.118.0/24 122.112.122.0/24 122.112.125.0/24 122.112.128.0/17 122.113.0.0/16 122.114.0.0/16 122.115.0.0/18 122.115.80.0/20 122.115.96.0/19 122.115.128.0/17 122.119.0.0/16 122.128.100.0/22 122.128.120.0/21 122.136.0.0/13 122.144.128.0/17 122.152.192.0/18 122.156.0.0/14 122.188.0.0/14 122.192.0.0/14 122.198.0.0/16 122.200.40.0/21 122.200.64.0/18 122.201.48.0/20 122.204.0.0/14 122.224.0.0/12 122.240.0.0/13 122.248.24.0/21 122.248.48.0/20 122.255.64.0/21 123.0.128.0/21 123.0.136.0/23 123.0.139.0/24 123.0.140.0/22 123.0.144.0/20 123.0.160.0/19 123.4.0.0/14 123.8.0.0/13 123.49.130.0/23 123.49.132.0/22 123.49.136.0/22 123.49.152.0/21 123.49.160.0/19 123.49.192.0/18 123.50.160.0/19 123.52.0.0/14 123.56.0.0/15 123.58.0.0/18 123.58.64.0/20 123.58.80.0/21 123.58.88.0/22 123.58.96.0/19 123.58.128.0/17 123.59.0.0/16 123.61.0.0/16 123.62.0.0/16 123.64.0.0/11 123.96.0.0/15 123.98.0.0/17 123.99.128.0/17 123.100.0.0/19 123.100.232.0/24 123.101.0.0/16 123.103.0.0/20 123.103.16.0/21 123.103.24.0/22 123.103.28.0/23 123.103.30.0/24 123.103.32.0/19 123.103.64.0/18 123.108.134.0/24 123.108.138.0/23 123.108.140.0/24 123.108.142.0/24 123.108.208.0/20 123.112.0.0/12 123.128.0.0/13 123.137.0.0/16 123.138.0.0/15 123.144.0.0/12 123.160.0.0/12 123.176.60.0/22 123.176.80.0/20 123.177.0.0/16 123.178.0.0/15 123.180.0.0/14 123.184.0.0/13 123.196.0.0/15 123.199.128.0/17 123.206.0.0/15 123.232.0.0/14 123.242.0.0/17 123.242.192.0/21 123.244.0.0/14 123.249.0.0/16 123.253.109.0/24 123.253.110.0/24 123.253.240.0/22 123.254.96.0/21 124.6.64.0/18 124.14.0.0/15 124.16.0.0/15 124.20.0.0/14 124.28.192.0/18 124.29.0.0/17 124.31.0.0/16 124.40.112.0/20 124.40.128.0/18 124.40.192.0/19 124.40.240.0/22 124.42.0.0/16 124.47.0.0/18 124.64.0.0/15 124.66.0.0/17 124.67.0.0/16 124.68.0.0/17 124.68.128.0/18 124.68.192.0/19 124.68.224.0/20 124.68.240.0/23 124.68.242.0/24 124.68.244.0/23 124.68.254.0/23 124.69.0.0/16 124.70.0.0/15 124.72.0.0/13 124.88.0.0/13 124.108.8.0/21 124.108.40.0/21 124.109.96.0/21 124.112.0.0/14 124.116.0.0/15 124.118.0.0/16 124.119.0.0/17 124.119.128.0/18 124.119.192.0/19 124.119.224.0/20 124.119.240.0/22 124.119.244.0/23 124.119.246.0/25 124.119.246.128/26 124.119.246.192/27 124.119.246.224/28 124.119.246.240/29 124.119.246.248/30 124.119.246.254/31 124.119.247.0/24 124.119.248.0/21 124.126.0.0/15 124.128.0.0/13 124.147.128.0/17 124.150.137.0/24 124.151.0.0/16 124.152.0.0/16 124.160.0.0/13 124.172.0.0/14 124.192.0.0/15 124.196.0.0/16 124.200.0.0/13 124.220.0.0/14 124.224.0.0/12 124.240.0.0/17 124.240.128.0/18 124.242.0.0/16 124.243.192.0/18 124.248.0.0/17 124.249.0.0/16 124.250.0.0/15 124.254.0.0/18 125.31.192.0/18 125.32.0.0/12 125.58.128.0/17 125.61.128.0/17 125.62.0.0/18 125.64.0.0/11 125.96.0.0/15 125.98.0.0/16 125.104.0.0/13 125.112.0.0/12 125.169.0.0/16 125.171.0.0/16 125.208.0.0/19 125.208.37.0/24 125.208.40.0/24 125.208.45.0/24 125.208.46.0/23 125.208.48.0/20 125.210.0.0/15 125.213.0.0/17 125.214.96.0/19 125.215.0.0/18 125.216.0.0/13 125.254.128.0/17 128.108.0.0/16 129.28.0.0/16 129.204.0.0/16 129.211.0.0/16 129.223.254.0/24 129.227.99.0/24 130.36.146.0/23 130.214.218.0/23 131.228.96.0/24 131.253.12.0/29 131.253.12.80/28 131.253.12.240/29 132.232.0.0/16 132.237.134.0/24 132.237.150.0/24 134.175.0.0/16 135.159.208.0/20 135.244.80.0/20 137.59.59.0/24 137.59.88.0/22 138.32.244.0/22 139.5.56.0/21 139.5.80.0/22 139.5.92.0/22 139.5.128.0/22 139.5.160.0/22 139.5.192.0/22 139.5.204.0/22 139.5.244.0/22 139.9.0.0/16 139.129.0.0/16 139.138.238.0/28 139.148.0.0/16 139.155.0.0/16 139.159.0.0/19 139.159.32.0/21 139.159.40.0/22 139.159.52.0/22 139.159.56.0/21 139.159.64.0/19 139.159.96.0/20 139.159.112.0/22 139.159.116.0/23 139.159.120.0/21 139.159.128.0/17 139.170.0.0/16 139.176.0.0/16 139.183.0.0/16 139.186.0.0/16 139.189.0.0/16 139.196.0.0/15 139.198.0.0/21 139.198.8.0/23 139.198.11.0/24 139.198.12.0/22 139.198.16.0/20 139.198.32.0/19 139.198.66.0/23 139.198.68.0/22 139.198.72.0/21 139.198.80.0/20 139.198.96.0/20 139.198.113.0/24 139.198.114.0/23 139.198.116.0/22 139.198.122.0/23 139.198.124.0/22 139.198.128.0/17 139.199.0.0/16 139.200.0.0/13 139.208.0.0/13 139.217.0.0/16 139.219.0.0/16 139.220.0.0/17 139.220.128.0/18 139.220.192.0/22 139.220.196.0/23 139.220.200.0/21 139.220.208.0/23 139.220.212.0/22 139.220.216.0/21 139.220.224.0/19 139.221.0.0/16 139.224.0.0/16 139.226.0.0/15 140.75.0.0/16 140.101.208.0/24 140.143.0.0/16 140.179.0.0/16 140.205.0.0/18 140.205.64.0/19 140.205.96.0/20 140.205.112.0/21 140.205.120.0/23 140.205.123.0/24 140.205.124.0/22 140.205.128.0/17 140.206.0.0/15 140.210.0.0/16 140.224.0.0/16 140.237.0.0/16 140.240.0.0/16 140.242.223.0/24 140.242.224.0/24 140.243.0.0/16 140.246.0.0/16 140.249.0.0/16 140.250.0.0/16 140.255.0.0/16 144.0.0.0/16 144.7.0.0/16 144.12.0.0/16 144.36.146.0/23 144.48.64.0/22 144.48.88.0/22 144.48.156.0/22 144.48.180.0/22 144.48.184.0/22 144.48.204.0/22 144.48.208.0/21 144.52.0.0/16 144.123.0.0/16 144.211.80.0/24 144.211.138.0/24 144.255.0.0/16 146.56.192.0/18 146.196.56.0/22 146.196.68.0/22 146.196.92.0/22 146.196.112.0/21 146.196.124.0/22 146.217.137.0/24 146.222.79.0/24 146.222.81.0/24 146.222.94.0/24 147.243.13.32/27 147.243.13.64/27 147.243.14.32/27 148.70.0.0/16 150.0.0.0/16 150.115.0.0/16 150.121.0.0/16 150.122.0.0/16 150.129.136.0/22 150.129.192.0/22 150.129.252.0/22 150.138.0.0/15 150.158.0.0/16 150.222.88.0/23 150.223.0.0/16 150.242.0.0/21 150.242.8.0/22 150.242.28.0/22 150.242.44.0/22 150.242.48.0/21 150.242.56.0/22 150.242.76.0/22 150.242.80.0/22 150.242.92.0/22 150.242.96.0/22 150.242.112.0/21 150.242.120.0/22 150.242.152.0/22 150.242.158.0/24 150.242.160.0/21 150.242.168.0/22 150.242.184.0/21 150.242.192.0/22 150.242.224.0/22 150.242.232.0/21 150.242.240.0/21 150.242.248.0/22 150.255.0.0/16 152.32.178.0/23 152.104.128.0/17 152.136.0.0/16 153.0.0.0/16 153.3.0.0/16 153.34.0.0/15 153.36.0.0/15 153.99.0.0/16 153.101.0.0/16 153.118.0.0/15 154.8.128.0/17 155.126.176.0/23 156.107.160.0/24 156.107.170.0/24 156.107.179.0/24 156.107.181.0/24 156.154.62.0/23 157.0.0.0/16 157.18.0.0/16 157.61.0.0/16 157.119.8.0/21 157.119.16.0/22 157.119.28.0/22 157.119.132.0/22 157.119.136.0/21 157.119.144.0/20 157.119.160.0/21 157.119.172.0/22 157.119.192.0/21 157.119.240.0/22 157.119.252.0/22 157.122.0.0/16 157.133.186.0/23 157.133.192.0/21 157.133.212.0/24 157.133.236.0/24 157.148.0.0/16 157.156.0.0/16 157.255.0.0/16 159.75.0.0/16 159.221.232.0/22 159.226.0.0/16 160.19.208.0/21 160.19.216.0/22 160.20.48.0/22 160.62.10.0/24 160.83.109.0/24 160.83.110.0/23 160.202.60.0/23 160.202.62.0/24 160.202.148.0/22 160.202.152.0/22 160.202.212.0/22 160.202.216.0/21 160.202.224.0/19 160.238.64.0/22 161.163.0.0/21 161.163.28.0/23 161.163.176.0/24 161.163.178.0/23 161.163.180.0/22 161.189.0.0/16 161.207.0.0/16 162.14.0.0/16 162.105.0.0/16 163.0.0.0/16 163.47.4.0/22 163.53.0.0/20 163.53.36.0/22 163.53.40.0/22 163.53.48.0/20 163.53.64.0/22 163.53.88.0/21 163.53.96.0/19 163.53.128.0/21 163.53.136.0/22 163.53.160.0/20 163.53.188.0/22 163.53.220.0/22 163.53.236.0/22 163.53.240.0/22 163.116.202.0/23 163.125.0.0/16 163.142.0.0/16 163.177.0.0/16 163.179.0.0/16 163.204.0.0/16 163.244.246.0/24 164.52.80.0/24 165.156.30.0/24 166.111.0.0/16 167.139.0.0/16 167.189.0.0/16 167.220.244.0/22 168.159.144.0/21 168.159.152.0/22 168.159.156.0/23 168.159.158.0/24 168.160.0.0/16 168.230.0.0/24 170.179.0.0/16 170.225.224.0/23 170.252.152.0/21 171.8.0.0/13 171.22.147.0/24 171.34.0.0/15 171.36.0.0/14 171.40.0.0/13 171.80.0.0/12 171.104.0.0/13 171.112.0.0/12 171.208.0.0/12 172.60.2.0/24 172.81.192.0/18 173.39.200.0/23 175.0.0.0/12 175.16.0.0/13 175.24.0.0/14 175.30.0.0/15 175.42.0.0/15 175.44.0.0/16 175.46.0.0/15 175.48.0.0/12 175.64.0.0/11 175.102.0.0/16 175.106.128.0/17 175.111.144.0/20 175.111.160.0/20 175.111.184.0/22 175.146.0.0/15 175.148.0.0/14 175.152.0.0/14 175.158.96.0/22 175.160.0.0/12 175.176.156.0/22 175.176.188.0/22 175.178.0.0/16 175.184.128.0/18 175.185.0.0/16 175.186.0.0/15 175.188.0.0/14 180.76.16.0/20 180.76.32.0/19 180.76.64.0/18 180.76.128.0/18 180.76.192.0/19 180.76.224.0/20 180.76.240.0/24 180.76.242.0/23 180.76.244.0/22 180.76.248.0/22 180.76.252.0/23 180.76.255.0/24 180.77.0.0/16 180.78.0.0/15 180.84.0.0/15 180.86.0.0/16 180.88.0.0/14 180.94.56.0/21 180.94.96.0/20 180.94.120.0/21 180.95.128.0/17 180.96.0.0/11 180.129.128.0/17 180.130.0.0/16 180.136.0.0/13 180.148.16.0/21 180.148.152.0/21 180.148.216.0/21 180.148.224.0/19 180.149.128.0/19 180.150.160.0/21 180.150.176.0/20 180.152.0.0/13 180.160.0.0/12 180.178.112.0/21 180.178.192.0/18 180.184.0.0/14 180.188.0.0/17 180.189.148.0/22 180.200.252.0/22 180.201.0.0/16 180.202.0.0/15 180.208.0.0/15 180.210.212.0/22 180.210.233.0/24 180.210.236.0/22 180.212.0.0/15 180.222.224.0/19 180.223.0.0/19 180.223.32.0/20 180.223.48.0/21 180.223.57.0/24 180.223.58.0/23 180.223.60.0/22 180.223.80.0/20 180.223.96.0/19 180.223.128.0/17 180.233.0.0/18 180.233.64.0/19 180.233.144.0/22 180.235.64.0/19 180.235.112.0/22 182.16.144.0/21 182.16.192.0/19 182.18.0.0/17 182.23.184.0/21 182.23.200.0/21 182.32.0.0/12 182.48.96.0/19 182.49.0.0/16 182.50.0.0/22 182.50.8.0/21 182.50.112.0/20 182.51.0.0/16 182.54.0.0/17 182.61.0.0/18 182.61.128.0/19 182.61.192.0/18 182.80.0.0/13 182.88.0.0/14 182.92.0.0/16 182.96.0.0/11 182.128.0.0/12 182.144.0.0/13 182.157.0.0/16 182.160.64.0/19 182.174.0.0/15 182.200.0.0/13 182.236.128.0/17 182.237.24.0/21 182.238.0.0/16 182.239.0.0/19 182.240.0.0/13 182.254.0.0/17 182.254.128.0/18 182.254.192.0/19 182.254.224.0/20 182.254.240.0/21 182.254.248.0/23 182.254.251.0/24 182.254.252.0/22 183.0.0.0/10 183.64.0.0/13 183.78.160.0/21 183.78.180.0/22 183.81.180.0/22 183.84.0.0/15 183.91.128.0/22 183.91.136.0/21 183.91.144.0/20 183.92.0.0/14 183.128.0.0/11 183.160.0.0/13 183.168.0.0/15 183.170.0.0/16 183.172.0.0/14 183.184.0.0/13 183.192.0.0/10 185.109.236.0/24 185.216.118.0/24 188.131.128.0/17 192.11.23.0/24 192.11.26.0/24 192.11.39.0/24 192.11.236.0/24 192.23.191.0/24 192.55.10.0/23 192.55.40.0/24 192.55.46.0/24 192.55.68.0/22 192.102.204.0/22 192.124.154.0/24 192.137.31.0/24 192.139.136.0/24 192.140.128.0/21 192.140.136.0/22 192.140.156.0/22 192.140.160.0/19 192.140.192.0/20 192.140.208.0/21 192.144.128.0/17 192.163.11.0/24 192.232.97.0/24 193.9.22.0/24 193.17.120.0/22 193.20.64.0/22 193.112.0.0/16 193.200.196.0/24 193.200.222.160/28 194.138.136.0/24 194.138.202.0/23 194.138.245.0/24 198.175.100.0/22 198.208.17.0/24 198.208.19.0/24 199.7.72.0/24 199.65.192.0/21 199.244.144.0/24 202.0.100.0/23 202.0.122.0/23 202.1.105.0/24 202.1.106.0/24 202.3.128.0/23 202.4.128.0/19 202.4.252.0/22 202.5.208.0/21 202.5.216.0/22 202.6.6.0/23 202.6.66.0/23 202.6.72.0/23 202.6.87.0/24 202.6.88.0/23 202.6.92.0/23 202.6.103.0/24 202.6.108.0/24 202.6.110.0/23 202.6.114.0/24 202.6.176.0/20 202.8.0.0/24 202.8.2.0/23 202.8.4.0/23 202.8.12.0/24 202.8.24.0/24 202.8.77.0/24 202.8.128.0/19 202.8.192.0/20 202.9.32.0/24 202.9.34.0/23 202.9.48.0/23 202.9.51.0/24 202.9.52.0/23 202.9.54.0/24 202.9.57.0/24 202.9.58.0/23 202.10.64.0/21 202.10.74.0/23 202.10.76.0/22 202.10.112.0/20 202.12.1.0/24 202.12.2.0/24 202.12.17.0/24 202.12.18.0/23 202.12.72.0/24 202.12.84.0/23 202.12.96.0/24 202.12.98.0/23 202.12.106.0/24 202.12.111.0/24 202.12.116.0/24 202.14.64.0/23 202.14.69.0/24 202.14.73.0/24 202.14.74.0/23 202.14.76.0/24 202.14.78.0/23 202.14.88.0/24 202.14.97.0/24 202.14.104.0/23 202.14.108.0/23 202.14.111.0/24 202.14.114.0/23 202.14.118.0/23 202.14.124.0/23 202.14.127.0/24 202.14.129.0/24 202.14.135.0/24 202.14.136.0/24 202.14.149.0/24 202.14.151.0/24 202.14.157.0/24 202.14.158.0/23 202.14.169.0/24 202.14.170.0/23 202.14.172.0/22 202.14.176.0/24 202.14.184.0/23 202.14.208.0/23 202.14.213.0/24 202.14.219.0/24 202.14.220.0/24 202.14.222.0/23 202.14.225.0/24 202.14.226.0/23 202.14.231.0/24 202.14.235.0/24 202.14.236.0/22 202.14.246.0/24 202.14.251.0/24 202.20.66.0/24 202.20.79.0/24 202.20.87.0/24 202.20.88.0/23 202.20.90.0/24 202.20.94.0/23 202.20.114.0/24 202.20.117.0/24 202.20.120.0/24 202.20.125.0/24 202.20.126.0/23 202.21.48.0/20 202.21.131.0/24 202.21.132.0/24 202.21.141.0/24 202.21.142.0/24 202.21.147.0/24 202.21.148.0/24 202.21.150.0/23 202.21.152.0/23 202.21.154.0/24 202.21.156.0/24 202.21.208.0/24 202.22.248.0/21 202.27.12.0/24 202.27.14.0/24 202.27.136.0/23 202.36.226.0/24 202.38.0.0/22 202.38.8.0/21 202.38.48.0/20 202.38.64.0/18 202.38.128.0/21 202.38.136.0/23 202.38.138.0/24 202.38.140.0/22 202.38.146.0/23 202.38.149.0/24 202.38.150.0/23 202.38.152.0/22 202.38.156.0/24 202.38.158.0/23 202.38.160.0/23 202.38.164.0/22 202.38.168.0/22 202.38.176.0/23 202.38.184.0/21 202.38.192.0/18 202.40.4.0/23 202.40.7.0/24 202.40.15.0/24 202.40.135.0/24 202.40.136.0/24 202.40.140.0/24 202.40.143.0/24 202.40.144.0/23 202.40.150.0/24 202.40.155.0/24 202.40.156.0/24 202.40.158.0/23 202.40.162.0/24 202.41.8.0/23 202.41.11.0/24 202.41.12.0/23 202.41.128.0/24 202.41.130.0/23 202.41.142.0/24 202.41.152.0/21 202.41.192.0/24 202.41.196.0/22 202.41.200.0/22 202.41.240.0/20 202.43.76.0/22 202.43.144.0/20 202.44.16.0/20 202.44.48.0/22 202.44.67.0/24 202.44.74.0/24 202.44.97.0/24 202.44.129.0/24 202.44.132.0/23 202.44.146.0/23 202.45.0.0/23 202.45.2.0/24 202.45.15.0/24 202.45.16.0/20 202.46.16.0/23 202.46.18.0/24 202.46.20.0/23 202.46.128.0/24 202.46.224.0/20 202.47.82.0/23 202.47.96.0/20 202.47.126.0/24 202.47.128.0/24 202.47.130.0/23 202.52.34.0/24 202.52.143.0/24 202.53.140.0/24 202.53.143.0/24 202.53.202.0/24 202.57.212.0/22 202.57.216.0/22 202.57.240.0/20 202.58.0.0/24 202.58.112.0/22 202.59.0.0/23 202.59.212.0/22 202.59.236.0/24 202.59.240.0/24 202.60.48.0/21 202.60.96.0/21 202.60.112.0/20 202.60.132.0/22 202.60.136.0/21 202.60.144.0/20 202.61.68.0/22 202.61.76.0/22 202.61.88.0/22 202.61.123.0/24 202.61.127.0/24 202.62.112.0/22 202.62.248.0/22 202.62.252.0/24 202.62.255.0/24 202.63.80.0/20 202.63.160.0/19 202.63.248.0/22 202.63.253.0/24 202.65.0.0/21 202.65.8.0/23 202.67.0.0/22 202.69.4.0/23 202.69.16.0/20 202.70.0.0/19 202.70.96.0/20 202.70.192.0/20 202.71.32.0/20 202.72.40.0/21 202.72.80.0/20 202.72.112.0/20 202.73.128.0/22 202.73.240.0/20 202.74.8.0/21 202.74.36.0/24 202.74.42.0/24 202.74.52.0/24 202.74.80.0/20 202.74.254.0/23 202.75.208.0/20 202.75.252.0/22 202.76.247.0/24 202.76.252.0/22 202.77.80.0/21 202.77.92.0/22 202.78.8.0/21 202.79.224.0/21 202.79.248.0/22 202.80.192.0/20 202.81.0.0/22 202.81.176.0/20 202.83.252.0/22 202.84.0.0/20 202.84.16.0/23 202.84.22.0/24 202.84.24.0/21 202.85.208.0/20 202.86.249.0/24 202.87.80.0/20 202.88.32.0/22 202.89.8.0/21 202.89.96.0/22 202.89.108.0/22 202.89.119.0/24 202.89.232.0/21 202.90.0.0/22 202.90.16.0/20 202.90.37.0/24 202.90.96.0/19 202.90.193.0/24 202.90.196.0/24 202.90.205.0/24 202.90.224.0/20 202.91.0.0/22 202.91.96.0/20 202.91.128.0/22 202.91.176.0/20 202.91.224.0/19 202.92.0.0/22 202.92.8.0/21 202.92.48.0/20 202.92.252.0/22 202.93.0.0/22 202.93.252.0/22 202.94.0.0/19 202.94.74.0/24 202.94.81.0/24 202.94.92.0/22 202.95.240.0/21 202.95.252.0/22 202.96.0.0/12 202.112.0.0/13 202.120.0.0/15 202.122.0.0/21 202.122.32.0/21 202.122.64.0/19 202.122.112.0/20 202.122.128.0/24 202.122.132.0/24 202.123.96.0/20 202.123.116.0/22 202.123.120.0/22 202.124.16.0/21 202.124.24.0/22 202.125.107.0/24 202.125.109.0/24 202.125.112.0/20 202.125.176.0/20 202.127.0.0/21 202.127.12.0/22 202.127.16.0/20 202.127.40.0/21 202.127.48.0/20 202.127.112.0/20 202.127.128.0/19 202.127.160.0/21 202.127.192.0/20 202.127.208.0/23 202.127.212.0/22 202.127.216.0/21 202.127.224.0/19 202.129.208.0/24 202.130.0.0/19 202.130.39.0/24 202.130.224.0/19 202.131.16.0/21 202.131.59.0/24 202.131.208.0/20 202.133.32.0/20 202.134.58.0/24 202.134.128.0/20 202.134.208.0/20 202.136.48.0/20 202.136.208.0/20 202.136.224.0/20 202.136.248.0/22 202.136.254.0/23 202.137.231.0/24 202.140.140.0/22 202.140.144.0/20 202.141.160.0/19 202.142.16.0/20 202.143.4.0/22 202.143.16.0/20 202.143.32.0/20 202.143.56.0/21 202.143.100.0/22 202.143.104.0/22 202.146.160.0/20 202.146.186.0/24 202.146.188.0/22 202.146.196.0/22 202.146.200.0/21 202.147.144.0/20 202.148.32.0/20 202.148.64.0/18 202.149.32.0/19 202.149.160.0/19 202.149.224.0/19 202.150.16.0/20 202.150.32.0/20 202.150.56.0/22 202.150.192.0/20 202.150.224.0/19 202.151.0.0/22 202.151.128.0/19 202.152.176.0/20 202.153.0.0/22 202.153.7.0/24 202.153.48.0/20 202.157.192.0/19 202.158.160.0/19 202.158.242.0/24 202.160.140.0/22 202.160.156.0/22 202.160.176.0/20 202.162.67.0/24 202.162.75.0/24 202.164.0.0/20 202.164.96.0/19 202.165.176.0/20 202.165.208.0/20 202.165.239.0/24 202.165.240.0/23 202.165.243.0/24 202.165.245.0/24 202.165.251.0/24 202.165.252.0/22 202.166.224.0/19 202.168.80.0/22 202.168.128.0/20 202.168.160.0/19 202.170.128.0/19 202.170.216.0/21 202.170.224.0/19 202.171.216.0/21 202.171.232.0/24 202.171.235.0/24 202.172.0.0/22 202.172.7.0/24 202.173.0.0/22 202.173.6.0/24 202.173.8.0/21 202.173.112.0/22 202.173.224.0/19 202.174.64.0/20 202.174.124.0/22 202.176.224.0/19 202.179.160.0/20 202.179.240.0/20 202.180.128.0/19 202.180.208.0/21 202.181.8.0/22 202.181.28.0/22 202.181.112.0/20 202.182.32.0/20 202.182.192.0/19 202.189.0.0/18 202.189.80.0/20 202.189.184.0/21 202.191.0.0/24 202.191.68.0/22 202.191.72.0/21 202.191.80.0/20 202.192.0.0/12 203.0.4.0/22 203.0.10.0/23 203.0.18.0/24 203.0.24.0/24 203.0.42.0/23 203.0.45.0/24 203.0.46.0/23 203.0.81.0/24 203.0.82.0/23 203.0.90.0/23 203.0.96.0/23 203.0.104.0/21 203.0.114.0/23 203.0.122.0/24 203.0.128.0/24 203.0.130.0/23 203.0.132.0/22 203.0.137.0/24 203.0.142.0/24 203.0.144.0/24 203.0.146.0/24 203.0.148.0/24 203.0.150.0/23 203.0.152.0/24 203.0.177.0/24 203.0.224.0/24 203.1.4.0/22 203.1.18.0/24 203.1.26.0/23 203.1.65.0/24 203.1.66.0/23 203.1.70.0/23 203.1.76.0/23 203.1.90.0/24 203.1.97.0/24 203.1.98.0/23 203.1.100.0/22 203.1.108.0/24 203.1.253.0/24 203.1.254.0/24 203.2.64.0/21 203.2.73.0/24 203.2.112.0/21 203.2.126.0/23 203.2.140.0/24 203.2.150.0/24 203.2.152.0/22 203.2.156.0/23 203.2.160.0/21 203.2.180.0/23 203.2.196.0/23 203.2.209.0/24 203.2.214.0/23 203.2.226.0/23 203.2.229.0/24 203.2.236.0/23 203.3.68.0/24 203.3.72.0/23 203.3.75.0/24 203.3.80.0/21 203.3.96.0/22 203.3.105.0/24 203.3.112.0/21 203.3.120.0/24 203.3.123.0/24 203.3.135.0/24 203.3.139.0/24 203.3.143.0/24 203.4.132.0/23 203.4.134.0/24 203.4.151.0/24 203.4.152.0/22 203.4.174.0/23 203.4.180.0/24 203.4.186.0/24 203.4.205.0/24 203.4.208.0/22 203.4.227.0/24 203.4.230.0/23 203.5.4.0/23 203.5.7.0/24 203.5.8.0/23 203.5.11.0/24 203.5.21.0/24 203.5.22.0/24 203.5.44.0/24 203.5.46.0/23 203.5.52.0/22 203.5.56.0/23 203.5.60.0/23 203.5.114.0/23 203.5.118.0/24 203.5.120.0/24 203.5.172.0/24 203.5.180.0/23 203.5.182.0/24 203.5.185.0/24 203.5.186.0/24 203.5.188.0/23 203.5.190.0/24 203.5.195.0/24 203.5.214.0/23 203.5.218.0/23 203.6.131.0/24 203.6.136.0/24 203.6.138.0/23 203.6.142.0/24 203.6.150.0/23 203.6.157.0/24 203.6.159.0/24 203.6.224.0/20 203.6.248.0/23 203.7.129.0/24 203.7.138.0/23 203.7.147.0/24 203.7.150.0/23 203.7.158.0/24 203.7.192.0/23 203.7.200.0/24 203.8.0.0/24 203.8.8.0/24 203.8.23.0/24 203.8.70.0/24 203.8.82.0/24 203.8.86.0/23 203.8.91.0/24 203.8.110.0/23 203.8.115.0/24 203.8.166.0/23 203.8.169.0/24 203.8.173.0/24 203.8.184.0/24 203.8.186.0/23 203.8.190.0/23 203.8.192.0/24 203.8.197.0/24 203.8.198.0/23 203.8.203.0/24 203.8.209.0/24 203.8.210.0/23 203.8.212.0/22 203.8.217.0/24 203.8.220.0/24 203.9.32.0/24 203.9.36.0/23 203.9.57.0/24 203.9.63.0/24 203.9.65.0/24 203.9.70.0/23 203.9.72.0/24 203.9.75.0/24 203.9.76.0/23 203.9.96.0/22 203.9.100.0/23 203.9.108.0/24 203.9.158.0/24 203.10.34.0/24 203.10.56.0/24 203.10.74.0/23 203.10.84.0/22 203.10.88.0/24 203.10.95.0/24 203.10.125.0/24 203.11.70.0/24 203.11.76.0/22 203.11.82.0/24 203.11.84.0/22 203.11.100.0/22 203.11.109.0/24 203.11.117.0/24 203.11.122.0/24 203.11.126.0/24 203.11.136.0/22 203.11.141.0/24 203.11.142.0/23 203.11.180.0/22 203.11.208.0/22 203.12.16.0/24 203.12.19.0/24 203.12.24.0/24 203.12.57.0/24 203.12.65.0/24 203.12.66.0/24 203.12.70.0/23 203.12.87.0/24 203.12.90.0/24 203.12.92.0/22 203.12.100.0/23 203.12.103.0/24 203.12.114.0/24 203.12.118.0/24 203.12.130.0/24 203.12.137.0/24 203.12.196.0/22 203.12.211.0/24 203.12.219.0/24 203.12.226.0/24 203.12.240.0/22 203.13.18.0/24 203.13.24.0/24 203.13.44.0/23 203.13.88.0/23 203.13.92.0/22 203.13.173.0/24 203.13.224.0/23 203.13.227.0/24 203.13.233.0/24 203.14.24.0/22 203.14.33.0/24 203.14.56.0/24 203.14.61.0/24 203.14.62.0/24 203.14.104.0/24 203.14.114.0/23 203.14.118.0/24 203.14.162.0/24 203.14.184.0/21 203.14.192.0/24 203.14.194.0/23 203.14.214.0/24 203.14.231.0/24 203.14.246.0/24 203.15.0.0/20 203.15.20.0/23 203.15.22.0/24 203.15.87.0/24 203.15.88.0/23 203.15.105.0/24 203.15.112.0/21 203.15.130.0/23 203.15.149.0/24 203.15.151.0/24 203.15.156.0/22 203.15.174.0/24 203.15.227.0/24 203.15.232.0/22 203.15.238.0/23 203.15.240.0/23 203.15.246.0/24 203.16.10.0/24 203.16.12.0/23 203.16.16.0/21 203.16.27.0/24 203.16.38.0/24 203.16.49.0/24 203.16.50.0/23 203.16.58.0/24 203.16.63.0/24 203.16.133.0/24 203.16.161.0/24 203.16.162.0/24 203.16.186.0/23 203.16.228.0/24 203.16.238.0/24 203.16.240.0/24 203.16.245.0/24 203.17.2.0/24 203.17.18.0/24 203.17.28.0/24 203.17.39.0/24 203.17.56.0/24 203.17.74.0/23 203.17.88.0/23 203.17.136.0/24 203.17.164.0/24 203.17.187.0/24 203.17.190.0/23 203.17.231.0/24 203.17.233.0/24 203.17.248.0/23 203.17.255.0/24 203.18.2.0/23 203.18.4.0/24 203.18.7.0/24 203.18.31.0/24 203.18.37.0/24 203.18.48.0/23 203.18.52.0/24 203.18.72.0/22 203.18.80.0/23 203.18.87.0/24 203.18.100.0/23 203.18.105.0/24 203.18.107.0/24 203.18.110.0/24 203.18.129.0/24 203.18.131.0/24 203.18.132.0/23 203.18.144.0/24 203.18.153.0/24 203.18.199.0/24 203.18.208.0/24 203.18.211.0/24 203.18.215.0/24 203.19.1.0/24 203.19.18.0/24 203.19.24.0/24 203.19.30.0/24 203.19.41.0/24 203.19.44.0/23 203.19.46.0/24 203.19.58.0/24 203.19.60.0/23 203.19.64.0/24 203.19.68.0/24 203.19.72.0/24 203.19.101.0/24 203.19.111.0/24 203.19.131.0/24 203.19.133.0/24 203.19.144.0/24 203.19.147.0/24 203.19.149.0/24 203.19.156.0/24 203.19.176.0/24 203.19.178.0/23 203.19.208.0/24 203.19.228.0/22 203.19.233.0/24 203.19.242.0/24 203.19.248.0/23 203.19.255.0/24 203.20.17.0/24 203.20.40.0/23 203.20.44.0/24 203.20.48.0/24 203.20.61.0/24 203.20.65.0/24 203.20.84.0/23 203.20.89.0/24 203.20.106.0/23 203.20.115.0/24 203.20.117.0/24 203.20.118.0/23 203.20.122.0/24 203.20.126.0/23 203.20.135.0/24 203.20.140.0/22 203.20.150.0/24 203.20.230.0/24 203.20.232.0/24 203.20.236.0/24 203.21.0.0/23 203.21.2.0/24 203.21.8.0/24 203.21.10.0/24 203.21.18.0/24 203.21.33.0/24 203.21.34.0/24 203.21.41.0/24 203.21.44.0/24 203.21.68.0/24 203.21.82.0/24 203.21.96.0/22 203.21.124.0/24 203.21.136.0/23 203.21.145.0/24 203.21.206.0/24 203.22.24.0/24 203.22.28.0/23 203.22.31.0/24 203.22.68.0/24 203.22.76.0/24 203.22.84.0/24 203.22.87.0/24 203.22.92.0/22 203.22.99.0/24 203.22.106.0/24 203.22.122.0/23 203.22.131.0/24 203.22.163.0/24 203.22.166.0/24 203.22.170.0/24 203.22.176.0/21 203.22.194.0/24 203.22.242.0/23 203.22.245.0/24 203.22.246.0/24 203.22.252.0/23 203.23.0.0/24 203.23.47.0/24 203.23.61.0/24 203.23.62.0/23 203.23.73.0/24 203.23.85.0/24 203.23.92.0/22 203.23.98.0/24 203.23.107.0/24 203.23.112.0/24 203.23.130.0/24 203.23.140.0/23 203.23.172.0/24 203.23.182.0/24 203.23.186.0/23 203.23.192.0/24 203.23.197.0/24 203.23.198.0/24 203.23.204.0/22 203.23.224.0/24 203.23.226.0/23 203.23.228.0/22 203.23.249.0/24 203.23.251.0/24 203.24.13.0/24 203.24.18.0/24 203.24.27.0/24 203.24.43.0/24 203.24.56.0/24 203.24.58.0/24 203.24.67.0/24 203.24.74.0/24 203.24.79.0/24 203.24.80.0/23 203.24.84.0/23 203.24.86.0/24 203.24.90.0/24 203.24.111.0/24 203.24.112.0/24 203.24.116.0/24 203.24.122.0/23 203.24.145.0/24 203.24.152.0/23 203.24.157.0/24 203.24.161.0/24 203.24.167.0/24 203.24.186.0/23 203.24.199.0/24 203.24.202.0/24 203.24.212.0/23 203.24.217.0/24 203.24.219.0/24 203.24.244.0/24 203.25.19.0/24 203.25.20.0/23 203.25.46.0/24 203.25.64.0/23 203.25.91.0/24 203.25.99.0/24 203.25.100.0/24 203.25.106.0/24 203.25.131.0/24 203.25.135.0/24 203.25.138.0/24 203.25.147.0/24 203.25.153.0/24 203.25.154.0/23 203.25.164.0/24 203.25.166.0/24 203.25.174.0/23 203.25.180.0/24 203.25.182.0/24 203.25.191.0/24 203.25.199.0/24 203.25.200.0/24 203.25.202.0/23 203.25.208.0/20 203.25.229.0/24 203.25.235.0/24 203.25.236.0/24 203.25.242.0/24 203.26.12.0/24 203.26.34.0/24 203.26.49.0/24 203.26.50.0/24 203.26.55.0/24 203.26.56.0/23 203.26.60.0/24 203.26.65.0/24 203.26.68.0/24 203.26.76.0/24 203.26.80.0/24 203.26.84.0/24 203.26.97.0/24 203.26.102.0/23 203.26.115.0/24 203.26.116.0/24 203.26.129.0/24 203.26.143.0/24 203.26.144.0/24 203.26.148.0/23 203.26.154.0/24 203.26.158.0/23 203.26.161.0/24 203.26.170.0/24 203.26.173.0/24 203.26.176.0/24 203.26.185.0/24 203.26.202.0/23 203.26.210.0/24 203.26.214.0/24 203.26.222.0/24 203.26.224.0/24 203.26.228.0/24 203.26.232.0/24 203.27.0.0/24 203.27.10.0/24 203.27.15.0/24 203.27.16.0/24 203.27.20.0/24 203.27.22.0/23 203.27.40.0/24 203.27.45.0/24 203.27.53.0/24 203.27.65.0/24 203.27.66.0/24 203.27.81.0/24 203.27.88.0/24 203.27.102.0/24 203.27.109.0/24 203.27.117.0/24 203.27.121.0/24 203.27.122.0/23 203.27.125.0/24 203.27.200.0/24 203.27.202.0/24 203.27.233.0/24 203.27.241.0/24 203.27.250.0/24 203.28.10.0/24 203.28.12.0/24 203.28.33.0/24 203.28.34.0/23 203.28.43.0/24 203.28.44.0/24 203.28.54.0/24 203.28.56.0/24 203.28.73.0/24 203.28.74.0/24 203.28.76.0/24 203.28.86.0/24 203.28.88.0/24 203.28.112.0/24 203.28.131.0/24 203.28.136.0/24 203.28.140.0/24 203.28.145.0/24 203.28.165.0/24 203.28.169.0/24 203.28.170.0/24 203.28.178.0/23 203.28.185.0/24 203.28.187.0/24 203.28.196.0/24 203.28.226.0/23 203.28.239.0/24 203.29.2.0/24 203.29.8.0/23 203.29.13.0/24 203.29.14.0/24 203.29.28.0/24 203.29.46.0/24 203.29.57.0/24 203.29.61.0/24 203.29.63.0/24 203.29.69.0/24 203.29.73.0/24 203.29.81.0/24 203.29.90.0/24 203.29.95.0/24 203.29.100.0/24 203.29.103.0/24 203.29.112.0/24 203.29.120.0/22 203.29.182.0/23 203.29.187.0/24 203.29.189.0/24 203.29.190.0/24 203.29.205.0/24 203.29.210.0/24 203.29.217.0/24 203.29.227.0/24 203.29.231.0/24 203.29.233.0/24 203.29.234.0/24 203.29.248.0/24 203.29.254.0/23 203.30.16.0/23 203.30.25.0/24 203.30.29.0/24 203.30.66.0/24 203.30.81.0/24 203.30.87.0/24 203.30.111.0/24 203.30.121.0/24 203.30.123.0/24 203.30.152.0/24 203.30.156.0/24 203.30.162.0/24 203.30.173.0/24 203.30.175.0/24 203.30.187.0/24 203.30.194.0/24 203.30.217.0/24 203.30.220.0/24 203.30.222.0/24 203.30.232.0/23 203.30.235.0/24 203.30.240.0/23 203.30.246.0/24 203.30.250.0/23 203.31.45.0/24 203.31.46.0/24 203.31.49.0/24 203.31.51.0/24 203.31.54.0/23 203.31.69.0/24 203.31.72.0/24 203.31.80.0/24 203.31.85.0/24 203.31.97.0/24 203.31.105.0/24 203.31.106.0/24 203.31.108.0/23 203.31.124.0/24 203.31.162.0/24 203.31.174.0/24 203.31.177.0/24 203.31.181.0/24 203.31.187.0/24 203.31.189.0/24 203.31.204.0/24 203.31.220.0/24 203.31.222.0/23 203.31.225.0/24 203.31.229.0/24 203.31.248.0/23 203.31.253.0/24 203.32.20.0/24 203.32.48.0/23 203.32.56.0/24 203.32.60.0/24 203.32.62.0/24 203.32.68.0/23 203.32.76.0/24 203.32.81.0/24 203.32.84.0/23 203.32.95.0/24 203.32.102.0/24 203.32.105.0/24 203.32.130.0/24 203.32.133.0/24 203.32.140.0/24 203.32.152.0/24 203.32.186.0/23 203.32.192.0/24 203.32.196.0/24 203.32.203.0/24 203.32.204.0/23 203.32.212.0/24 203.33.4.0/24 203.33.7.0/24 203.33.12.0/23 203.33.21.0/24 203.33.26.0/24 203.33.32.0/24 203.33.63.0/24 203.33.64.0/24 203.33.67.0/24 203.33.68.0/24 203.33.73.0/24 203.33.79.0/24 203.33.100.0/24 203.33.122.0/24 203.33.129.0/24 203.33.131.0/24 203.33.145.0/24 203.33.156.0/24 203.33.158.0/23 203.33.174.0/24 203.33.185.0/24 203.33.200.0/24 203.33.202.0/23 203.33.204.0/24 203.33.206.0/23 203.33.214.0/23 203.33.224.0/23 203.33.226.0/24 203.33.233.0/24 203.33.243.0/24 203.33.250.0/24 203.34.4.0/24 203.34.21.0/24 203.34.27.0/24 203.34.39.0/24 203.34.48.0/23 203.34.54.0/24 203.34.56.0/23 203.34.67.0/24 203.34.69.0/24 203.34.76.0/24 203.34.92.0/24 203.34.106.0/24 203.34.113.0/24 203.34.147.0/24 203.34.150.0/24 203.34.152.0/23 203.34.161.0/24 203.34.162.0/24 203.34.187.0/24 203.34.192.0/21 203.34.204.0/22 203.34.232.0/24 203.34.240.0/24 203.34.242.0/24 203.34.245.0/24 203.34.251.0/24 203.55.2.0/23 203.55.4.0/24 203.55.10.0/24 203.55.13.0/24 203.55.22.0/24 203.55.30.0/24 203.55.93.0/24 203.55.101.0/24 203.55.109.0/24 203.55.110.0/24 203.55.116.0/23 203.55.119.0/24 203.55.128.0/23 203.55.146.0/23 203.55.192.0/24 203.55.196.0/24 203.55.218.0/23 203.55.221.0/24 203.55.224.0/24 203.56.1.0/24 203.56.4.0/24 203.56.12.0/24 203.56.24.0/24 203.56.38.0/24 203.56.40.0/24 203.56.46.0/24 203.56.50.0/23 203.56.52.0/22 203.56.68.0/23 203.56.82.0/23 203.56.84.0/23 203.56.95.0/24 203.56.110.0/24 203.56.121.0/24 203.56.161.0/24 203.56.169.0/24 203.56.172.0/23 203.56.175.0/24 203.56.183.0/24 203.56.185.0/24 203.56.187.0/24 203.56.192.0/24 203.56.198.0/24 203.56.201.0/24 203.56.208.0/23 203.56.210.0/24 203.56.214.0/24 203.56.216.0/24 203.56.227.0/24 203.56.228.0/24 203.56.232.0/24 203.56.240.0/24 203.56.252.0/24 203.56.254.0/24 203.57.5.0/24 203.57.6.0/24 203.57.12.0/23 203.57.28.0/24 203.57.39.0/24 203.57.46.0/24 203.57.58.0/24 203.57.61.0/24 203.57.66.0/24 203.57.69.0/24 203.57.70.0/23 203.57.73.0/24 203.57.90.0/24 203.57.101.0/24 203.57.109.0/24 203.57.123.0/24 203.57.157.0/24 203.57.200.0/24 203.57.202.0/24 203.57.206.0/24 203.57.222.0/24 203.57.224.0/20 203.57.246.0/23 203.57.249.0/24 203.57.253.0/24 203.57.254.0/23 203.62.2.0/24 203.62.131.0/24 203.62.139.0/24 203.62.161.0/24 203.62.197.0/24 203.62.228.0/22 203.62.234.0/24 203.62.246.0/24 203.65.240.0/22 203.76.160.0/22 203.76.168.0/22 203.76.208.0/21 203.76.216.0/22 203.76.240.0/22 203.77.180.0/22 203.78.48.0/20 203.78.156.0/22 203.79.0.0/20 203.80.4.0/23 203.80.32.0/20 203.80.57.0/24 203.80.129.0/24 203.80.132.0/22 203.80.140.0/22 203.80.144.0/20 203.81.0.0/21 203.81.16.0/20 203.81.244.0/22 203.82.0.0/23 203.82.16.0/21 203.82.112.0/20 203.82.224.0/20 203.83.0.0/22 203.83.12.0/22 203.83.56.0/21 203.83.224.0/20 203.86.0.0/18 203.86.64.0/19 203.86.250.0/24 203.86.254.0/23 203.88.32.0/19 203.88.100.0/22 203.88.192.0/19 203.89.0.0/22 203.89.100.0/22 203.89.136.0/22 203.89.144.0/24 203.90.0.0/22 203.90.8.0/21 203.90.128.0/18 203.90.192.0/19 203.91.32.0/19 203.91.96.0/20 203.91.120.0/21 203.92.0.0/22 203.92.6.0/24 203.92.160.0/19 203.93.0.0/16 203.94.0.0/19 203.95.0.0/21 203.95.96.0/19 203.95.128.0/18 203.95.200.0/21 203.95.208.0/22 203.95.224.0/19 203.99.8.0/21 203.99.16.0/22 203.99.30.0/23 203.99.80.0/20 203.100.32.0/20 203.100.58.0/24 203.100.60.0/24 203.100.63.0/24 203.100.80.0/20 203.100.96.0/19 203.100.192.0/20 203.104.32.0/20 203.105.96.0/19 203.105.128.0/19 203.107.0.0/19 203.107.32.0/20 203.107.52.0/22 203.107.56.0/21 203.107.69.0/24 203.107.70.0/23 203.107.72.0/21 203.107.80.0/20 203.107.96.0/19 203.110.160.0/19 203.110.208.0/20 203.110.232.0/23 203.110.234.0/24 203.114.80.0/20 203.114.244.0/22 203.118.192.0/19 203.118.241.0/24 203.118.248.0/22 203.119.24.0/23 203.119.32.0/24 203.119.34.0/23 203.119.80.0/22 203.119.85.0/24 203.119.113.0/24 203.119.114.0/23 203.119.116.0/22 203.119.120.0/21 203.119.128.0/17 203.123.58.0/24 203.128.32.0/19 203.128.96.0/19 203.128.128.0/24 203.128.224.0/21 203.130.32.0/20 203.132.32.0/19 203.134.240.0/22 203.134.246.0/23 203.135.96.0/19 203.135.160.0/20 203.142.12.0/23 203.142.219.0/24 203.142.224.0/19 203.145.0.0/19 203.148.0.0/18 203.148.64.0/20 203.148.80.0/22 203.148.86.0/23 203.149.92.0/22 203.152.64.0/19 203.152.128.0/19 203.153.0.0/22 203.156.192.0/18 203.158.16.0/21 203.160.129.0/24 203.160.192.0/19 203.161.0.0/22 203.161.180.0/24 203.161.183.0/24 203.161.192.0/19 203.166.160.0/19 203.167.28.0/22 203.168.0.0/19 203.170.58.0/23 203.171.0.0/22 203.171.208.0/24 203.171.224.0/20 203.174.4.0/24 203.174.6.0/24 203.174.96.0/20 203.175.128.0/19 203.175.192.0/18 203.176.0.0/18 203.176.64.0/19 203.176.168.0/21 203.184.80.0/20 203.187.160.0/19 203.189.0.0/23 203.189.6.0/23 203.189.112.0/22 203.189.192.0/19 203.189.240.0/22 203.190.96.0/20 203.190.249.0/24 203.191.0.0/23 203.191.2.0/24 203.191.5.0/24 203.191.7.0/24 203.191.29.0/24 203.191.31.0/24 203.191.64.0/18 203.191.133.0/24 203.191.144.0/20 203.192.0.0/19 203.193.224.0/19 203.195.64.0/19 203.195.128.0/17 203.196.0.0/20 203.196.28.0/22 203.201.181.0/24 203.201.182.0/24 203.202.236.0/22 203.205.64.0/19 203.207.64.0/18 203.207.128.0/17 203.208.0.0/20 203.208.16.0/22 203.208.32.0/19 203.209.224.0/19 203.212.0.0/20 203.212.80.0/20 203.217.164.0/22 203.223.0.0/20 203.223.16.0/24 203.223.22.0/24 204.55.160.0/24 204.74.96.0/24 204.114.176.0/23 206.219.44.0/23 206.219.50.0/23 206.219.52.0/23 207.89.20.0/24 210.2.0.0/23 210.2.2.0/24 210.2.5.0/24 210.2.6.0/23 210.2.8.0/21 210.2.24.0/21 210.5.0.0/19 210.5.56.0/24 210.5.60.0/24 210.5.128.0/19 210.7.56.0/21 210.12.0.0/15 210.14.64.0/19 210.14.112.0/20 210.14.128.0/17 210.15.0.0/17 210.15.128.0/18 210.16.128.0/21 210.16.136.0/22 210.16.156.0/22 210.16.160.0/19 210.21.0.0/16 210.22.0.0/16 210.23.32.0/19 210.25.0.0/16 210.26.0.0/15 210.28.0.0/14 210.32.0.0/12 210.51.0.0/16 210.52.0.0/18 210.52.64.0/23 210.52.66.0/24 210.52.68.0/22 210.52.72.0/21 210.52.80.0/20 210.52.96.0/21 210.52.104.0/22 210.52.108.0/24 210.52.110.0/23 210.52.112.0/20 210.52.128.0/17 210.53.0.0/16 210.56.192.0/19 210.72.0.0/14 210.76.0.0/15 210.78.0.0/16 210.79.64.0/18 210.79.224.0/19 210.82.0.0/15 210.87.128.0/18 210.185.192.0/18 210.192.96.0/19 211.64.0.0/13 211.80.0.0/12 211.96.0.0/14 211.100.0.0/17 211.100.128.0/19 211.100.160.0/20 211.100.184.0/21 211.100.192.0/18 211.101.0.0/16 211.102.0.0/15 211.136.0.0/13 211.144.0.0/13 211.152.0.0/17 211.152.134.0/23 211.152.138.0/23 211.152.140.0/22 211.152.150.0/23 211.152.157.0/24 211.152.158.0/23 211.152.160.0/19 211.152.192.0/18 211.153.0.0/16 211.154.0.0/19 211.154.32.0/20 211.154.48.0/21 211.154.64.0/18 211.154.128.0/17 211.155.0.0/18 211.155.67.0/24 211.155.68.0/24 211.155.72.0/21 211.155.80.0/20 211.155.97.0/24 211.155.98.0/23 211.155.100.0/22 211.155.104.0/21 211.155.113.0/24 211.155.117.0/24 211.155.118.0/23 211.155.120.0/21 211.155.128.0/17 211.156.0.0/18 211.156.64.0/19 211.156.96.0/21 211.156.104.0/22 211.156.108.0/23 211.156.112.0/20 211.156.128.0/17 211.157.0.0/16 211.158.0.0/15 211.160.0.0/13 212.64.0.0/17 212.129.128.0/17 218.0.0.0/12 218.16.0.0/13 218.24.0.0/14 218.28.0.0/15 218.30.0.0/19 218.30.64.0/18 218.30.128.0/18 218.30.192.0/19 218.30.224.0/20 218.30.240.0/21 218.30.248.0/22 218.30.252.0/25 218.30.252.128/26 218.30.252.194/31 218.30.252.196/30 218.30.252.200/29 218.30.252.208/28 218.30.252.224/27 218.30.253.0/24 218.30.254.0/23 218.31.0.0/16 218.56.0.0/13 218.64.0.0/11 218.96.0.0/15 218.98.0.0/18 218.98.96.0/21 218.98.104.0/22 218.98.108.0/23 218.98.110.0/24 218.98.112.0/20 218.98.128.0/19 218.98.192.0/18 218.99.0.0/16 218.100.96.0/19 218.100.128.0/17 218.104.0.0/14 218.108.0.0/15 218.185.192.0/19 218.192.0.0/12 218.240.0.0/14 218.244.0.0/15 218.246.0.0/17 218.246.129.0/24 218.246.131.0/24 218.246.132.0/23 218.246.134.0/24 218.246.139.0/24 218.246.144.0/20 218.246.160.0/19 218.246.192.0/18 218.247.0.0/18 218.247.96.0/19 218.247.128.0/17 218.249.0.0/16 219.72.0.0/16 219.82.0.0/16 219.83.128.0/17 219.90.68.0/22 219.90.72.0/21 219.128.0.0/11 219.216.0.0/13 219.224.0.0/13 219.232.0.0/15 219.234.0.0/21 219.234.9.0/24 219.234.10.0/23 219.234.12.0/22 219.234.32.0/19 219.234.64.0/18 219.234.128.0/17 219.235.0.0/16 219.236.0.0/14 219.242.0.0/15 219.244.0.0/14 220.101.192.0/18 220.112.0.0/14 220.152.128.0/17 220.154.0.0/16 220.155.0.0/21 220.155.9.0/24 220.155.10.0/23 220.155.12.0/22 220.155.16.0/21 220.155.24.0/22 220.155.28.0/23 220.155.31.0/24 220.155.32.0/19 220.155.64.0/18 220.155.128.0/17 220.158.241.0/24 220.158.243.0/24 220.160.0.0/11 220.192.0.0/12 220.231.0.0/18 220.231.128.0/17 220.232.64.0/18 220.234.0.0/16 220.242.0.0/24 220.242.12.0/23 220.242.14.0/24 220.242.17.0/24 220.242.18.0/23 220.242.20.0/24 220.242.32.0/20 220.242.48.0/23 220.242.53.0/24 220.242.55.0/24 220.242.56.0/22 220.242.60.0/23 220.242.62.0/24 220.242.64.0/19 220.242.96.0/20 220.242.112.0/21 220.242.120.0/22 220.242.124.0/23 220.242.126.0/24 220.242.173.0/24 220.242.197.0/24 220.242.205.0/24 220.242.207.0/24 220.242.215.0/24 220.242.216.0/21 220.242.224.0/19 220.243.0.0/17 220.243.128.0/18 220.243.204.0/24 220.243.214.0/24 220.243.217.0/24 220.243.218.0/24 220.243.238.0/24 220.247.136.0/21 220.248.0.0/14 220.252.0.0/16 221.0.0.0/13 221.8.0.0/14 221.12.0.0/17 221.12.128.0/18 221.13.0.0/16 221.14.0.0/15 221.122.0.0/15 221.128.128.0/17 221.129.0.0/16 221.130.0.0/15 221.133.224.0/19 221.136.0.0/15 221.172.0.0/14 221.176.0.0/19 221.176.32.0/20 221.176.48.0/21 221.176.56.0/24 221.176.58.0/23 221.176.60.0/22 221.176.64.0/18 221.176.128.0/17 221.177.0.0/16 221.178.0.0/15 221.180.0.0/14 221.192.0.0/14 221.196.0.0/15 221.198.0.0/16 221.199.0.0/17 221.199.128.0/18 221.199.192.0/20 221.199.224.0/19 221.200.0.0/13 221.208.0.0/12 221.224.0.0/12 222.16.0.0/12 222.32.0.0/11 222.64.0.0/11 222.125.0.0/16 222.126.128.0/19 222.126.160.0/21 222.126.168.0/22 222.126.172.0/23 222.126.174.40/29 222.126.174.76/30 222.126.174.88/29 222.126.174.144/28 222.126.178.0/23 222.126.180.0/22 222.126.184.0/21 222.126.192.0/21 222.126.200.104/29 222.126.206.0/23 222.126.208.0/22 222.126.212.0/26 222.126.212.64/27 222.126.212.96/28 222.126.212.112/29 222.126.212.128/25 222.126.213.0/24 222.126.214.0/23 222.126.216.0/21 222.126.224.0/19 222.128.0.0/12 222.160.0.0/14 222.168.0.0/13 222.176.0.0/12 222.192.0.0/11 222.240.0.0/13 222.248.0.0/15 223.0.0.0/12 223.20.0.0/15 223.27.184.0/22 223.29.208.0/22 223.29.252.0/22 223.64.0.0/11 223.96.0.0/12 223.112.0.0/14 223.116.0.0/15 223.120.0.0/13 223.128.0.0/15 223.144.0.0/12 223.160.0.0/14 223.166.0.0/15 223.192.0.0/15 223.198.0.0/15 223.201.4.0/22 223.201.8.0/21 223.201.16.0/20 223.201.32.0/19 223.201.64.0/18 223.201.128.0/17 223.202.0.0/15 223.208.0.0/13 223.220.0.0/15 223.223.176.0/20 223.223.192.0/20 223.240.0.0/13 223.248.0.0/14 223.252.128.0/19 223.252.192.0/18 223.254.0.0/16 223.255.0.0/17 223.255.236.0/22 223.255.252.0/23 ================================================ FILE: acl/gfwlist.acl ================================================ # gfw list rules for shadowsocks-libev $ # updated on 2020-04-18 01:30:05$ [bypass_all] [proxy_list] # Telegram IPs$ 149.154.167.99/32 149.154.175.10/32 149.154.167.40/32 149.154.167.42/32 149.154.175.117/32 149.154.175.50/32 149.154.167.50/32 149.154.167.51/32 149.154.175.100/32 149.154.167.91/32 149.154.167.90/32 149.154.165.120/32 149.154.166.120/32 149.154.164.250/32 149.154.167.117/32 149.154.167.118/32 149.154.167.192/27 149.154.164.8/29 91.108.8.0/27 91.108.12.0/27 91.108.16.0/27 91.108.56.0/24 91.108.4.0/24 149.154.160.0/22 149.154.164.0/22 149.154.168.0/22 149.154.172.0/22 91.108.56.0/22 91.108.4.0/22 91.108.8.0/22 91.108.16.0/22 91.108.12.0/22 149.154.160.0/20 2001:b28:f23d:f001::e/128 2001:67c:4e8:f002::e/128 2001:b28:f23d:f003::e/128 2001:b28:f23d:f001::a/128 2001:67c:4e8:f002::a/128 2001:b28:f23d:f003::a/128 2001:67c:4e8:f004::a/128 2001:b28:f23f:f005::a/128 2001:67c:4e8:fa60::/64 2001:b28:f23d::/48 2001:b28:f23f::/48 2001:67c:4e8::/48 (^|\.)030buy\.com$ (^|\.)0rz\.tw$ (^|\.)1000giri\.net$ (^|\.)100ke\.org$ (^|\.)10conditionsoflove\.com$ (^|\.)10musume\.com$ (^|\.)10\.tt$ (^|\.)123rf\.com$ (^|\.)12bet\.com$ (^|\.)12vpn\.com$ (^|\.)12vpn\.net$ (^|\.)138\.com$ (^|\.)141hongkong\.com$ (^|\.)141jj\.com$ (^|\.)141tube\.com$ (^|\.)1688\.com\.au$ (^|\.)173ng\.com$ (^|\.)177pic\.info$ (^|\.)17t17p\.com$ (^|\.)18board\.com$ (^|\.)18board\.info$ (^|\.)18onlygirls\.com$ (^|\.)18p2p\.com$ (^|\.)18virginsex\.com$ (^|\.)1949er\.org$ (^|\.)1984bbs\.com$ (^|\.)1984bbs\.org$ (^|\.)1989report\.hkja\.org\.hk$ (^|\.)1991way\.com$ (^|\.)1998cdp\.org$ (^|\.)1-apple\.com\.tw$ (^|\.)1bao\.org$ (^|\.)1dumb\.com$ (^|\.)1e100\.net$ (^|\.)1eew\.com$ (^|\.)1mobile\.com$ (^|\.)1mobile\.tw$ (^|\.)1pondo\.tv$ (^|\.)2000fun\.com$ (^|\.)2008xianzhang\.info$ (^|\.)2017\.hk$ (^|\.)21andy\.com$ (^|\.)21join\.com$ (^|\.)21pron\.com$ (^|\.)21sextury\.com$ (^|\.)228\.net\.tw$ (^|\.)233abc\.com$ (^|\.)24hrs\.ca$ (^|\.)24smile\.org$ (^|\.)25u\.com$ (^|\.)2-hand\.info$ (^|\.)2lipstube\.com$ (^|\.)2shared\.com$ (^|\.)2waky\.com$ (^|\.)30boxes\.com$ (^|\.)315lz\.com$ (^|\.)32red\.com$ (^|\.)36rain\.com$ (^|\.)3a5a\.com$ (^|\.)3-a\.net$ (^|\.)3arabtv\.com$ (^|\.)3boys2girls\.com$ (^|\.)3d-game\.com$ (^|\.)3proxy\.ru$ (^|\.)3ren\.ca$ (^|\.)3tui\.net$ (^|\.)43110\.cf$ (^|\.)466453\.com$ (^|\.)4bluestones\.biz$ (^|\.)4chan\.com$ (^|\.)4dq\.com$ (^|\.)4everproxy\.com$ (^|\.)4irc\.com$ (^|\.)4mydomain\.com$ (^|\.)4pu\.com$ (^|\.)4rbtv\.com$ (^|\.)4shared\.com$ (^|\.)4sqi\.net$ (^|\.)51\.ca$ (^|\.)51jav\.org$ (^|\.)51luoben\.com$ (^|\.)5278\.cc$ (^|\.)5299\.tv$ (^|\.)56cun04\.jigsy\.com$ (^|\.)5aimiku\.com$ (^|\.)5i01\.com$ (^|\.)5isotoi5\.org$ (^|\.)5maodang\.com$ (^|\.)63i\.com$ (^|\.)64museum\.org$ (^|\.)64tianwang\.com$ (^|\.)64wiki\.com$ (^|\.)666kb\.com$ (^|\.)66\.ca$ (^|\.)6park\.com$ (^|\.)6parker\.com$ (^|\.)6parknews\.com$ (^|\.)7capture\.com$ (^|\.)7cow\.com$ (^|\.)85cc\.net$ (^|\.)85cc\.us$ (^|\.)85st\.com$ (^|\.)881903\.com$ (^|\.)888\.com$ (^|\.)888poker\.com$ (^|\.)89\.64\.charter\.constitutionalism\.solutions$ (^|\.)89-64\.org$ (^|\.)8-d\.com$ (^|\.)8news\.com\.tw$ (^|\.)8z1\.net$ (^|\.)9001700\.com$ (^|\.)908taiwan\.org$ (^|\.)91porn\.com$ (^|\.)91vps\.club$ (^|\.)92ccav\.com$ (^|\.)991\.com$ (^|\.)99btgc01\.com$ (^|\.)99cn\.info$ (^|\.)9bis\.com$ (^|\.)9bis\.net$ (^|\.)9gag\.com$ (^|\.)a248\.e\.akamai\.net$ (^|\.)a5\.com\.ru$ (^|\.)aamacau\.com$ (^|\.)abc\.com$ (^|\.)abchinese\.com$ (^|\.)abclite\.net$ (^|\.)abc\.net\.au$ (^|\.)abc\.pp\.ru$ (^|\.)abc\.xyz$ (^|\.)abebooks\.com$ (^|\.)abematv\.akamaized\.net$ (^|\.)abitno\.linpie\.com$ (^|\.)ablwang\.com$ (^|\.)aboluowang\.com$ (^|\.)aboutgfw\.com$ (^|\.)about\.google$ (^|\.)abs\.edu$ (^|\.)accim\.org$ (^|\.)aceros-de-hispania\.com$ (^|\.)acevpn\.com$ (^|\.)acg18\.me$ (^|\.)acgkj\.com$ (^|\.)ac\.jiruan\.net$ (^|\.)acmedia365\.com$ (^|\.)acmetoy\.com$ (^|\.)acnw\.com\.au$ (^|\.)actfortibet\.org$ (^|\.)actimes\.com\.au$ (^|\.)activpn\.com$ (^|\.)aculo\.us$ (^|\.)adcex\.com$ (^|\.)addictedtocoffee\.de$ (^|\.)adelaidebbs\.com$ (^|\.)admin\.recaptcha\.net$ (^|\.)admob\.com$ (^|\.)adpl\.org\.hk$ (^|\.)adsense\.com$ (^|\.)ads-twitter\.com$ (^|\.)adult\.friendfinder\.com$ (^|\.)adultfriendfinder\.com$ (^|\.)adultkeep\.net$ (^|\.)adult-sex-games\.com$ (^|\.)advanscene\.com$ (^|\.)advertfan\.com$ (^|\.)ae\.hao123\.com$ (^|\.)aenhancers\.com$ (^|\.)ae\.org$ (^|\.)aex\.com$ (^|\.)afantibbs\.com$ (^|\.)af\.mil$ (^|\.)agnesb\.fr$ (^|\.)agoogleaday\.com$ (^|\.)agro\.hk$ (^|\.)ai\.binwang\.me$ (^|\.)ai\.google$ (^|\.)ai-kan\.net$ (^|\.)aiph\.net$ (^|\.)airasia\.com$ (^|\.)airconsole\.com$ (^|\.)airvpn\.org$ (^|\.)aisex\.com$ (^|\.)aiss\.anws\.gov\.tw$ (^|\.)ait\.org\.tw$ (^|\.)aiweiweiblog\.com$ (^|\.)aiweiwei\.com$ (^|\.)ai-wen\.net$ (^|\.)akademiye\.org$ (^|\.)akamaihd\.net$ (^|\.)akiba-online\.com$ (^|\.)akiba-web\.com$ (^|\.)akow\.org$ (^|\.)alabout\.com$ (^|\.)alanhou\.com$ (^|\.)alarab\.qa$ (^|\.)alasbarricadas\.org$ (^|\.)alexlur\.org$ (^|\.)alforattv\.net$ (^|\.)alhayat\.com$ (^|\.)alicejapan\.co\.jp$ (^|\.)aliengu\.com$ (^|\.)al-islam\.com$ (^|\.)alkasir\.com$ (^|\.)allcoin\.com$ (^|\.)allconnected\.co$ (^|\.)alldrawnsex\.com$ (^|\.)allervpn\.com$ (^|\.)allfinegirls\.com$ (^|\.)allgirlmassage\.com$ (^|\.)allgirlsallowed\.org$ (^|\.)allgravure\.com$ (^|\.)alliance\.org\.hk$ (^|\.)allinfa\.com$ (^|\.)alljackpotscasino\.com$ (^|\.)allmovie\.com$ (^|\.)allowed\.org$ (^|\.)almasdarnews\.com$ (^|\.)almostmy\.com$ (^|\.)alphaporno\.com$ (^|\.)al-qimmah\.net$ (^|\.)alternate-tools\.com$ (^|\.)alternativeto\.net$ (^|\.)altrec\.com$ (^|\.)alvinalexander\.com$ (^|\.)alwaysdata\.com$ (^|\.)alwaysdata\.net$ (^|\.)alwaysvpn\.com$ (^|\.)am730\.com\.hk$ (^|\.)amazon\.co\.jp$ (^|\.)amazon\.com$ (^|\.)ameblo\.jp$ (^|\.)americangreencard\.com$ (^|\.)americanunfinished\.com$ (^|\.)amiblockedornot\.com$ (^|\.)amigobbs\.net$ (^|\.)amitabhafoundation\.us$ (^|\.)amnesty\.org$ (^|\.)amnesty\.org\.hk$ (^|\.)amnesty\.tw$ (^|\.)amnestyusa\.org$ (^|\.)amnyemachen\.org$ (^|\.)amoiist\.com$ (^|\.)ampproject\.org$ (^|\.)amtb-taipei\.org$ (^|\.)anchorfree\.com$ (^|\.)ancsconf\.org$ (^|\.)andfaraway\.net$ (^|\.)android\.com$ (^|\.)androidify\.com$ (^|\.)androidplus\.co$ (^|\.)androidtv\.com$ (^|\.)android-x86\.org$ (^|\.)andygod\.com$ (^|\.)angela-merkel\.de$ (^|\.)angelfire\.com$ (^|\.)angola\.org$ (^|\.)angularjs\.org$ (^|\.)animecrazy\.net$ (^|\.)animeshippuuden\.com$ (^|\.)aniscartujo\.com$ (^|\.)annatam\.com$ (^|\.)anobii\.com$ (^|\.)anontext\.com$ (^|\.)anonymise\.us$ (^|\.)anonymitynetwork\.com$ (^|\.)anonymizer\.com$ (^|\.)anonymouse\.org$ (^|\.)a-normal-day\.com$ (^|\.)anpopo\.com$ (^|\.)answering-islam\.org$ (^|\.)anthonycalzadilla\.com$ (^|\.)anti1984\.com$ (^|\.)antichristendom\.com$ (^|\.)antiwave\.net$ (^|\.)anyporn\.com$ (^|\.)anysex\.com$ (^|\.)aobo\.com\.au$ (^|\.)aofriend\.com$ (^|\.)aofriend\.com\.au$ (^|\.)aojiao\.org$ (^|\.)aolchannels\.aol\.com$ (^|\.)aomiwang\.com$ (^|\.)apartmentratings\.com$ (^|\.)apartments\.com$ (^|\.)apetube\.com$ (^|\.)api\.ai$ (^|\.)apiary\.io$ (^|\.)apidocs\.linksalpha\.com$ (^|\.)api\.dropboxapi\.com$ (^|\.)apigee\.com$ (^|\.)api\.linksalpha\.com$ (^|\.)api\.proxlet\.com$ (^|\.)api\.pureapk\.com$ (^|\.)api\.recaptcha\.net$ (^|\.)api-secure\.recaptcha\.net$ (^|\.)api-verify\.recaptcha\.net$ (^|\.)apk-dl\.com$ (^|\.)apkdler\.com$ (^|\.)apkmirror\.com$ (^|\.)apkmonk\.com$ (^|\.)apkplz\.com$ (^|\.)apkpure\.com$ (^|\.)aplusvpn\.com$ (^|\.)app\.box\.com$ (^|\.)appdownloader\.net$ (^|\.)app\.heywire\.com$ (^|\.)appledaily\.com$ (^|\.)appledaily\.com\.hk$ (^|\.)appledaily\.com\.tw$ (^|\.)appshopper\.com$ (^|\.)app\.smartmailcloud\.com$ (^|\.)appsocks\.net$ (^|\.)appspot\.com$ (^|\.)appsto\.re$ (^|\.)app\.tutanota\.com$ (^|\.)aptoide\.com$ (^|\.)archive\.fo$ (^|\.)archive\.is$ (^|\.)archive\.li$ (^|\.)archive\.org$ (^|\.)archives\.gov$ (^|\.)archives\.gov\.tw$ (^|\.)archive\.today$ (^|\.)arctosia\.com$ (^|\.)areca-backup\.org$ (^|\.)arena\.taipei$ (^|\.)arethusa\.su$ (^|\.)ar\.hao123\.com$ (^|\.)arlingtoncemetery\.mil$ (^|\.)army\.mil$ (^|\.)art4tibet1998\.org$ (^|\.)arte\.tv$ (^|\.)artofpeacefoundation\.org$ (^|\.)artstation\.com$ (^|\.)artsy\.net$ (^|\.)asacp\.org$ (^|\.)asdfg\.jp$ (^|\.)asg\.to$ (^|\.)asia-gaming\.com$ (^|\.)asiaharvest\.org$ (^|\.)asianews\.it$ (^|\.)asiansexdiary\.com$ (^|\.)asianspiss\.com$ (^|\.)asianwomensfilm\.de$ (^|\.)asiatgp\.com$ (^|\.)asiatoday\.us$ (^|\.)askstudent\.com$ (^|\.)askynz\.net$ (^|\.)assembla\.com$ (^|\.)assets\.bwbx\.io$ (^|\.)assimp\.org$ (^|\.)astrill\.com$ (^|\.)atchinese\.com$ (^|\.)atc\.org\.au$ (^|\.)atdmt\.com$ (^|\.)atgfw\.org$ (^|\.)athenaeizou\.com$ (^|\.)atlanta168\.com$ (^|\.)atlaspost\.com$ (^|\.)atnext\.com$ (^|\.)authorizeddns\.net$ (^|\.)authorizeddns\.org$ (^|\.)authorizeddns\.us$ (^|\.)autodraw\.com$ (^|\.)avaaz\.org$ (^|\.)avbody\.tv$ (^|\.)avcity\.tv$ (^|\.)av\.com$ (^|\.)avcool\.com$ (^|\.)avdb\.in$ (^|\.)avdb\.tv$ (^|\.)av-e-body\.com$ (^|\.)avfantasy\.com$ (^|\.)avg\.com$ (^|\.)avgle\.com$ (^|\.)avidemux\.org$ (^|\.)avmoo\.com$ (^|\.)avmoo\.net$ (^|\.)avmoo\.pw$ (^|\.)avmo\.pw$ (^|\.)av\.movie$ (^|\.)av\.nightlife141\.com$ (^|\.)avoision\.com$ (^|\.)avyahoo\.com$ (^|\.)axureformac\.com$ (^|\.)azerbaycan\.tv$ (^|\.)azerimix\.com$ (^|\.)azubu\.tv$ (^|\.)azurewebsites\.net$ (^|\.)b0ne\.com$ (^|\.)babynet\.com\.hk$ (^|\.)backchina\.com$ (^|\.)backpackers\.com\.tw$ (^|\.)backtotiananmen\.com$ (^|\.)badiucao\.com$ (^|\.)badjojo\.com$ (^|\.)badoo\.com$ (^|\.)bahamut\.com\.tw$ (^|\.)baidu\.jp$ (^|\.)baijie\.org$ (^|\.)bailandaily\.com$ (^|\.)baixing\.me$ (^|\.)bakgeekhome\.tk$ (^|\.)banana-vpn\.com$ (^|\.)band\.us$ (^|\.)bandwagonhost\.com$ (^|\.)bangbrosnetwork\.com$ (^|\.)bangchen\.net$ (^|\.)bangdream\.space$ (^|\.)bangyoulater\.com$ (^|\.)bankmobilevibe\.com$ (^|\.)bannedbook\.org$ (^|\.)bannednews\.org$ (^|\.)banorte\.com$ (^|\.)baramangaonline\.com$ (^|\.)barenakedislam\.com$ (^|\.)barnabu\.co\.uk$ (^|\.)barton\.de$ (^|\.)bartvpn\.com$ (^|\.)bash-hackers\.org$ (^|\.)bastillepost\.com$ (^|\.)bayvoice\.net$ (^|\.)bbcchinese\.com$ (^|\.)bbc\.com$ (^|\.)bbc\.co\.uk$ (^|\.)bb-chat\.tv$ (^|\.)bbchat\.tv$ (^|\.)bbci\.co\.uk$ (^|\.)bbc\.in$ (^|\.)bbg\.gov$ (^|\.)bbkz\.com$ (^|\.)bbnradio\.org$ (^|\.)bbs\.brockbbs\.com$ (^|\.)bbs\.cantonese\.asia$ (^|\.)bbsdigest\.com$ (^|\.)bbs\.ecstart\.com$ (^|\.)bbsfeed\.com$ (^|\.)bbs\.hanminzu\.org$ (^|\.)bbs\.hasi\.wang$ (^|\.)bbs\.huasing\.org$ (^|\.)bbs\.junglobal\.net$ (^|\.)bbs\.kimy\.com\.tw$ (^|\.)bbsland\.com$ (^|\.)bbs\.mikocon\.com$ (^|\.)bbsmo\.com$ (^|\.)bbs\.morbell\.com$ (^|\.)bbs\.mychat\.to$ (^|\.)bbs\.netbig\.com$ (^|\.)bbsone\.com$ (^|\.)bbs\.ozchinese\.com$ (^|\.)bbs\.qmzdd\.com$ (^|\.)bbs\.sina\.com$ (^|\.)bbs\.skykiwi\.com$ (^|\.)bbs\.sou-tong\.org$ (^|\.)bbs\.tuitui\.info$ (^|\.)bbs-tw\.com$ (^|\.)bbtoystore\.com$ (^|\.)bb\.ttv\.com\.tw$ (^|\.)bcast\.co\.nz$ (^|\.)bcc\.com\.tw$ (^|\.)bcchinese\.net$ (^|\.)bcex\.ca$ (^|\.)bcmorning\.com$ (^|\.)bdsmvideos\.net$ (^|\.)beaconevents\.com$ (^|\.)bebo\.com$ (^|\.)beeg\.com$ (^|\.)beevpn\.com$ (^|\.)behance\.net$ (^|\.)behindkink\.com$ (^|\.)beijing1989\.com$ (^|\.)beijingspring\.com$ (^|\.)beijingzx\.org$ (^|\.)belamionline\.com$ (^|\.)bell\.wiki$ (^|\.)bemywife\.cc$ (^|\.)beric\.me$ (^|\.)berlintwitterwall\.com$ (^|\.)berm\.co\.nz$ (^|\.)bestforchina\.org$ (^|\.)bestgore\.com$ (^|\.)bestpornstardb\.com$ (^|\.)bestvpnanalysis\.com$ (^|\.)bestvpn\.com$ (^|\.)bestvpnserver\.com$ (^|\.)bestvpnservice\.com$ (^|\.)bestvpnusa\.com$ (^|\.)bet365\.com$ (^|\.)betfair\.com$ (^|\.)betternet\.co$ (^|\.)bettervpn\.com$ (^|\.)bettween\.com$ (^|\.)betvictor\.com$ (^|\.)bewww\.net$ (^|\.)beyondfirewall\.com$ (^|\.)bfnn\.org$ (^|\.)bfsh\.hk$ (^|\.)bgvpn\.com$ (^|\.)bianlei\.com$ (^|\.)biantailajiao\.com$ (^|\.)biantailajiao\.in$ (^|\.)biblesforamerica\.org$ (^|\.)bibox\.com$ (^|\.)bic2011\.org$ (^|\.)bigfools\.com$ (^|\.)bigjapanesesex\.com$ (^|\.)bigmoney\.biz$ (^|\.)bignews\.org$ (^|\.)big\.one$ (^|\.)bigsound\.org$ (^|\.)biliworld\.com$ (^|\.)billypan\.com$ (^|\.)binance\.com$ (^|\.)binux\.me$ (^|\.)bipic\.net$ (^|\.)bird\.so$ (^|\.)bitc\.bme\.emory\.edu$ (^|\.)bitcointalk\.org$ (^|\.)bitcoinworld\.com$ (^|\.)bit\.do$ (^|\.)bitfinex\.com$ (^|\.)bithumb\.com$ (^|\.)bitinka\.com\.ar$ (^|\.)bit\.ly$ (^|\.)bitmex\.com$ (^|\.)bitshare\.com$ (^|\.)bitsnoop\.com$ (^|\.)bitvise\.com$ (^|\.)bit-z\.com$ (^|\.)bizhat\.com$ (^|\.)bjnewlife\.org$ (^|\.)bjs\.org$ (^|\.)bjzc\.org$ (^|\.)blacklogic\.com$ (^|\.)blackvpn\.com$ (^|\.)bl-doujinsouko\.com$ (^|\.)blewpass\.com$ (^|\.)blinkx\.com$ (^|\.)blinw\.com$ (^|\.)blip\.tv$ (^|\.)blockcn\.com$ (^|\.)blockless\.com$ (^|\.)blogblog\.com$ (^|\.)blog\.calibre-ebook\.com$ (^|\.)blogcatalog\.com$ (^|\.)blogcity\.me$ (^|\.)blog\.cnyes\.com$ (^|\.)blog\.daum\.net$ (^|\.)blog\.de$ (^|\.)blogdns\.org$ (^|\.)blog\.exblog\.co\.jp$ (^|\.)blog\.excite\.co\.jp$ (^|\.)blog\.expofutures\.com$ (^|\.)blog\.fizzik\.com$ (^|\.)blog\.foolsmountain\.com$ (^|\.)blog\.fuckgfw233\.org$ (^|\.)blogger\.com$ (^|\.)blog\.google$ (^|\.)blog\.goo\.ne\.jp$ (^|\.)blogimg\.jp$ (^|\.)blog\.inoreader\.com$ (^|\.)blog\.istef\.info$ (^|\.)blog\.jackjia\.com$ (^|\.)blog\.jp$ (^|\.)blog\.kangye\.org$ (^|\.)blog\.lester850\.info$ (^|\.)bloglines\.com$ (^|\.)bloglovin\.com$ (^|\.)blog\.martinoei\.com$ (^|\.)blog\.pathtosharepoint\.com$ (^|\.)blog\.pentalogic\.net$ (^|\.)blog\.qooza\.hk$ (^|\.)blog\.ranxiang\.com$ (^|\.)blogs\.icerocket\.com$ (^|\.)blog\.sina\.com\.tw$ (^|\.)blogs\.libraryinformationtechnology\.com$ (^|\.)blog\.sogoo\.org$ (^|\.)blog\.soylent\.com$ (^|\.)blogspot\.ae$ (^|\.)blogspot\.al$ (^|\.)blogspot\.am$ (^|\.)blogspot\.ba$ (^|\.)blogspot\.be$ (^|\.)blogspot\.bg$ (^|\.)blogspot\.ca$ (^|\.)blogspot\.cat$ (^|\.)blogspot\.ch$ (^|\.)blogspot\.cl$ (^|\.)blogspot\.com$ (^|\.)blogspot\.com\.ar$ (^|\.)blogspot\.com\.au$ (^|\.)blogspot\.com\.br$ (^|\.)blogspot\.com\.by$ (^|\.)blogspot\.com\.co$ (^|\.)blogspot\.com\.cy$ (^|\.)blogspot\.com\.ee$ (^|\.)blogspot\.com\.eg$ (^|\.)blogspot\.com\.es$ (^|\.)blogspot\.com\.mt$ (^|\.)blogspot\.com\.ng$ (^|\.)blogspot\.com\.tr$ (^|\.)blogspot\.com\.uy$ (^|\.)blogspot\.co\.uk$ (^|\.)blogspot\.cz$ (^|\.)blogspot\.de$ (^|\.)blogspot\.dk$ (^|\.)blogspot\.fi$ (^|\.)blogspot\.fr$ (^|\.)blogspot\.gr$ (^|\.)blogspot\.hk$ (^|\.)blogspot\.hr$ (^|\.)blogspot\.hu$ (^|\.)blogspot\.ie$ (^|\.)blogspot\.in$ (^|\.)blogspot\.is$ (^|\.)blogspot\.it$ (^|\.)blogspot\.jp$ (^|\.)blogspot\.kr$ (^|\.)blogspot\.li$ (^|\.)blogspot\.lt$ (^|\.)blogspot\.lu$ (^|\.)blogspot\.md$ (^|\.)blogspot\.mk$ (^|\.)blogspot\.mx$ (^|\.)blogspot\.my$ (^|\.)blogspot\.nl$ (^|\.)blogspot\.no$ (^|\.)blogspot\.pe$ (^|\.)blogspot\.pt$ (^|\.)blogspot\.qa$ (^|\.)blogspot\.ro$ (^|\.)blogspot\.ru$ (^|\.)blogspot\.se$ (^|\.)blogspot\.sg$ (^|\.)blogspot\.si$ (^|\.)blogspot\.sk$ (^|\.)blogspot\.sn$ (^|\.)blogspot\.tw$ (^|\.)blogspot\.ug$ (^|\.)blogs\.tampabay\.com$ (^|\.)blogs\.yahoo\.co\.jp$ (^|\.)blog\.syx86\.cn$ (^|\.)blog\.syx86\.com$ (^|\.)blog\.taragana\.com$ (^|\.)blogtd\.net$ (^|\.)blogtd\.org$ (^|\.)blog\.tiney\.com$ (^|\.)blog\.workflow\.is$ (^|\.)blog\.xuite\.net$ (^|\.)blog\.youthwant\.com\.tw$ (^|\.)blog\.youxu\.info$ (^|\.)bloodshed\.net$ (^|\.)bloomberg\.cn$ (^|\.)bloomberg\.com$ (^|\.)bloomberg\.de$ (^|\.)bloombergview\.com$ (^|\.)bloomfortune\.com$ (^|\.)blueangellive\.com$ (^|\.)bmfinn\.com$ (^|\.)bnews\.co$ (^|\.)bnn\.co$ (^|\.)bnrmetal\.com$ (^|\.)boardreader\.com$ (^|\.)bod\.asia$ (^|\.)bodog88\.com$ (^|\.)bolehvpn\.net$ (^|\.)bolin\.netfirms\.com$ (^|\.)bonbonme\.com$ (^|\.)bonbonsex\.com$ (^|\.)bonfoundation\.org$ (^|\.)bongacams\.com$ (^|\.)boobstagram\.com$ (^|\.)book\.com\.tw$ (^|\.)bookepub\.com$ (^|\.)books\.com\.tw$ (^|\.)booktopia\.com\.au$ (^|\.)book\.zi5\.me$ (^|\.)boomssr\.com$ (^|\.)botanwang\.com$ (^|\.)bot\.nu$ (^|\.)bowenpress\.com$ (^|\.)boxpn\.com$ (^|\.)boxunblog\.com$ (^|\.)boxunclub\.com$ (^|\.)boxun\.com$ (^|\.)boxun\.tv$ (^|\.)boyangu\.com$ (^|\.)boyfriendtv\.com$ (^|\.)boysfood\.com$ (^|\.)boysmaster\.com$ (^|\.)brainyquote\.com$ (^|\.)brandonhutchinson\.com$ (^|\.)braumeister\.org$ (^|\.)bravotube\.net$ (^|\.)brazzers\.com$ (^|\.)break\.com$ (^|\.)breakgfw\.com$ (^|\.)breaking911\.com$ (^|\.)breakingtweets\.com$ (^|\.)breakwall\.net$ (^|\.)br\.hao123\.com$ (^|\.)briefdream\.com$ (^|\.)briian\.com$ (^|\.)brizzly\.com$ (^|\.)brkmd\.com$ (^|\.)broadbook\.com$ (^|\.)broadpressinc\.com$ (^|\.)br\.st$ (^|\.)brucewang\.net$ (^|\.)brutaltgp\.com$ (^|\.)bt2mag\.com$ (^|\.)bt95\.com$ (^|\.)btaia\.com$ (^|\.)btbtav\.com$ (^|\.)btc98\.com$ (^|\.)btcbank\.bank$ (^|\.)btctrade\.im$ (^|\.)btdigg\.org$ (^|\.)btku\.me$ (^|\.)btku\.org$ (^|\.)btspread\.com$ (^|\.)btsynckeys\.com$ (^|\.)budaedu\.org$ (^|\.)buddhanet\.com\.tw$ (^|\.)buddhistchannel\.tv$ (^|\.)buffered\.com$ (^|\.)bullogger\.com$ (^|\.)bullog\.org$ (^|\.)bunbunhk\.com$ (^|\.)busayari\.com$ (^|\.)businessinsider\.com$ (^|\.)businesstoday\.com\.tw$ (^|\.)businessweek\.com$ (^|\.)busu\.org$ (^|\.)busytrade\.com$ (^|\.)buugaa\.com$ (^|\.)buy\.yahoo\.com\.tw$ (^|\.)buzzhand\.com$ (^|\.)buzzhand\.net$ (^|\.)buzzorange\.com$ (^|\.)bvpn\.com$ (^|\.)bwgyhw\.com$ (^|\.)bwh1\.net$ (^|\.)bwsj\.hk$ (^|\.)bx\.in\.th$ (^|\.)bx\.tl$ (^|\.)bynet\.co\.il$ (^|\.)c100tibet\.org$ (^|\.)c1522\.mooo\.com$ (^|\.)c2cx\.com$ (^|\.)cablegatesearch\.net$ (^|\.)cachinese\.com$ (^|\.)cacnw\.com$ (^|\.)cactusvpn\.com$ (^|\.)cafepress\.com$ (^|\.)cahr\.org\.tw$ (^|\.)calameo\.com$ (^|\.)calebelston\.com$ (^|\.)calgarychinese\.ca$ (^|\.)calgarychinese\.com$ (^|\.)calgarychinese\.net$ (^|\.)cam4\.com$ (^|\.)cam4\.jp$ (^|\.)cam4\.sg$ (^|\.)camfrog\.com$ (^|\.)cams\.com$ (^|\.)cams\.org\.sg$ (^|\.)canadameet\.com$ (^|\.)canalporno\.com$ (^|\.)canyu\.org$ (^|\.)caobian\.info$ (^|\.)caochangqing\.com$ (^|\.)cao\.im$ (^|\.)cap\.org\.hk$ (^|\.)carabinasypistolas\.com$ (^|\.)cardinalkungfoundation\.org$ (^|\.)carfax\.com$ (^|\.)caribbeancom\.com$ (^|\.)cari\.com\.my$ (^|\.)carmotorshow\.com$ (^|\.)cartoonmovement\.com$ (^|\.)casadeltibetbcn\.org$ (^|\.)casatibet\.org\.mx$ (^|\.)casinobellini\.com$ (^|\.)casinoking\.com$ (^|\.)casinoriva\.com$ (^|\.)casino\.williamhill\.com$ (^|\.)castbox\.fm$ (^|\.)catch22\.net$ (^|\.)catchgod\.com$ (^|\.)catfightpayperview\.xxx$ (^|\.)catholic\.org\.hk$ (^|\.)catholic\.org\.tw$ (^|\.)cathvoice\.org\.tw$ (^|\.)cattt\.com$ (^|\.)cbc\.ca$ (^|\.)cbsnews\.com$ (^|\.)cbs\.ntu\.edu\.tw$ (^|\.)cbtc\.org\.hk$ (^|\.)cccat\.cc$ (^|\.)cccat\.co$ (^|\.)ccdtr\.org$ (^|\.)cchere\.com$ (^|\.)ccim\.org$ (^|\.)cclife\.ca$ (^|\.)cclifefl\.org$ (^|\.)cclife\.org$ (^|\.)ccthere\.com$ (^|\.)ccthere\.net$ (^|\.)cctmweb\.net$ (^|\.)cctongbao\.com$ (^|\.)ccue\.ca$ (^|\.)ccue\.com$ (^|\.)ccvoice\.ca$ (^|\.)ccw\.org\.tw$ (^|\.)cdbook\.org$ (^|\.)cdcparty\.com$ (^|\.)cdef\.org$ (^|\.)cdig\.info$ (^|\.)cdjp\.org$ (^|\.)cdn1\.lp\.saboom\.com$ (^|\.)cdn-apple\.com$ (^|\.)cdn\.assets\.lfpcontent\.com$ (^|\.)cdnews\.com\.tw$ (^|\.)cdn\.helixstudios\.net$ (^|\.)cdn-images\.mailchimp\.com$ (^|\.)cdninstagram\.com$ (^|\.)cdn\.printfriendly\.com$ (^|\.)cdn\.seatguru\.com$ (^|\.)cdn\.softlayer\.net$ (^|\.)cdp1989\.org$ (^|\.)cdp1998\.org$ (^|\.)cdp2006\.org$ (^|\.)cdpa\.url\.tw$ (^|\.)cdpeu\.org$ (^|\.)cdpusa\.org$ (^|\.)cdpweb\.org$ (^|\.)cdpwu\.org$ (^|\.)cdw\.com$ (^|\.)cecc\.gov$ (^|\.)cellulo\.info$ (^|\.)cenews\.eu$ (^|\.)centauro\.com\.br$ (^|\.)centerforhumanreprod\.com$ (^|\.)centralnation\.com$ (^|\.)centurys\.net$ (^|\.)certificate\.revocationcheck\.com$ (^|\.)certificate-transparency\.org$ (^|\.)c-est-simple\.com$ (^|\.)cfhks\.org\.hk$ (^|\.)cfos\.de$ (^|\.)cftfc\.com$ (^|\.)cgdepot\.org$ (^|\.)cgst\.edu$ (^|\.)changeip\.name$ (^|\.)changeip\.net$ (^|\.)changeip\.org$ (^|\.)change\.org$ (^|\.)changp\.com$ (^|\.)changsa\.net$ (^|\.)channel8news\.sg$ (^|\.)chaoex\.com$ (^|\.)chapm25\.com$ (^|\.)chatnook\.com$ (^|\.)chaturbate\.com$ (^|\.)chengmingmag\.com$ (^|\.)chenguangcheng\.com$ (^|\.)chenpokong\.com$ (^|\.)chenpokong\.net$ (^|\.)chenshan20042005\.wordpress\.com$ (^|\.)cherrysave\.com$ (^|\.)chhongbi\.org$ (^|\.)chicagoncmtv\.com$ (^|\.)china101\.com$ (^|\.)china18\.org$ (^|\.)china21\.com$ (^|\.)china21\.org$ (^|\.)china5000\.us$ (^|\.)chinaaffairs\.org$ (^|\.)chinaaid\.me$ (^|\.)chinaaid\.net$ (^|\.)chinaaid\.org$ (^|\.)chinaaid\.us$ (^|\.)chinachange\.org$ (^|\.)chinachannel\.hk$ (^|\.)chinacitynews\.be$ (^|\.)chinacomments\.org$ (^|\.)chinadialogue\.net$ (^|\.)chinadigitaltimes\.net$ (^|\.)chinaelections\.org$ (^|\.)chinaeweekly\.com$ (^|\.)chinafreepress\.org$ (^|\.)chinagate\.com$ (^|\.)chinageeks\.org$ (^|\.)chinagfw\.org$ (^|\.)chinagonet\.com$ (^|\.)chinagreenparty\.org$ (^|\.)china\.hket\.com$ (^|\.)chinahorizon\.org$ (^|\.)chinahush\.com$ (^|\.)chinainperspective\.com$ (^|\.)chinainterimgov\.org$ (^|\.)chinalaborwatch\.org$ (^|\.)chinalawandpolicy\.com$ (^|\.)chinalawtranslate\.com$ (^|\.)china-mmm\.jp\.net$ (^|\.)china-mmm\.net$ (^|\.)china-mmm\.sa\.com$ (^|\.)chinamule\.com$ (^|\.)chinamz\.org$ (^|\.)chinanewscenter\.com$ (^|\.)chinapost\.com\.tw$ (^|\.)chinapress\.com\.my$ (^|\.)china-review\.com\.ua$ (^|\.)chinarightsia\.org$ (^|\.)chinasmile\.net$ (^|\.)chinasocialdemocraticparty\.com$ (^|\.)chinasoul\.org$ (^|\.)chinasucks\.net$ (^|\.)chinatimes\.com$ (^|\.)chinatopsex\.com$ (^|\.)chinatown\.com\.au$ (^|\.)chinatweeps\.com$ (^|\.)china\.ucanews\.com$ (^|\.)chinaview\.wordpress\.com$ (^|\.)chinaway\.org$ (^|\.)china-week\.com$ (^|\.)chinaworker\.info$ (^|\.)chinaxchina\.com$ (^|\.)chinayouth\.org\.hk$ (^|\.)chinayuanmin\.org$ (^|\.)chinesedaily\.com$ (^|\.)chinesedailynews\.com$ (^|\.)chinesedemocracy\.com$ (^|\.)chinese\.donga\.com$ (^|\.)chinese\.engadget\.com$ (^|\.)chinesegay\.org$ (^|\.)chinese-hermit\.net$ (^|\.)chinese\.irib\.ir$ (^|\.)chinese-leaders\.org$ (^|\.)chinese-memorial\.org$ (^|\.)chinesen\.de$ (^|\.)chinesenews\.net\.au$ (^|\.)chinesepen\.org$ (^|\.)chinese\.soifind\.com$ (^|\.)chinesetalks\.net$ (^|\.)chineseupress\.com$ (^|\.)chingcheong\.com$ (^|\.)chinman\.net$ (^|\.)chithu\.org$ (^|\.)chn\.chosun\.com$ (^|\.)chobit\.cc$ (^|\.)chrdnet\.com$ (^|\.)christianfreedom\.org$ (^|\.)christianstudy\.com$ (^|\.)christiantimes\.org\.hk$ (^|\.)christusrex\.org$ (^|\.)chrlawyers\.hk$ (^|\.)chromecast\.com$ (^|\.)chrome\.com$ (^|\.)chromeexperiments\.com$ (^|\.)chromercise\.com$ (^|\.)chromestatus\.com$ (^|\.)chromium\.org$ (^|\.)ch\.shvoong\.com$ (^|\.)chuang-yen\.org$ (^|\.)chubold\.com$ (^|\.)chubun\.com$ (^|\.)chuizi\.net$ (^|\.)churchinhongkong\.org$ (^|\.)chushigangdrug\.ch$ (^|\.)cienen\.com$ (^|\.)cineastentreff\.de$ (^|\.)cipfg\.org$ (^|\.)circlethebayfortibet\.org$ (^|\.)cirosantilli\.com$ (^|\.)citizencn\.com$ (^|\.)citizenlab\.org$ (^|\.)citizenscommission\.hk$ (^|\.)citizensradio\.org$ (^|\.)city365\.ca$ (^|\.)city9x\.com$ (^|\.)citypopulation\.de$ (^|\.)citytalk\.tw$ (^|\.)civicparty\.hk$ (^|\.)civildisobediencemovement\.org$ (^|\.)civilhrfront\.org$ (^|\.)civiliangunner\.com$ (^|\.)civilmedia\.tw$ (^|\.)ck101\.com$ (^|\.)clarionproject\.org$ (^|\.)classicalguitarblog\.net$ (^|\.)clb\.org\.hk$ (^|\.)cl\.d0z\.net$ (^|\.)cldr\.unicode\.org$ (^|\.)cleansite\.biz$ (^|\.)cleansite\.info$ (^|\.)cleansite\.us$ (^|\.)clearharmony\.net$ (^|\.)clearsurance\.com$ (^|\.)clearwisdom\.net$ (^|\.)clementine-player\.org$ (^|\.)cling\.omy\.sg$ (^|\.)clinica-tibet\.ru$ (^|\.)clipfish\.de$ (^|\.)cloakpoint\.com$ (^|\.)cloud\.feedly\.com$ (^|\.)cloud\.mail\.ru$ (^|\.)club1069\.com$ (^|\.)clyp\.it$ (^|\.)cmcn\.org$ (^|\.)cmi\.org\.tw$ (^|\.)cmp\.hku\.hk$ (^|\.)cms\.gov$ (^|\.)cmule\.com$ (^|\.)cmule\.org$ (^|\.)cmx\.im$ (^|\.)cn2\.streetvoice\.com$ (^|\.)cn6\.eu$ (^|\.)cnabc\.com$ (^|\.)cna\.com\.tw$ (^|\.)cnbbnews\.wordpress\.com$ (^|\.)cn\.calameo\.com$ (^|\.)cn\.dayabook\.com$ (^|\.)cnd\.org$ (^|\.)cnex\.org\.cn$ (^|\.)cn\.fmnnow\.com$ (^|\.)cn\.freeones\.com$ (^|\.)cn\.giganews\.com$ (^|\.)cn\.ibtimes\.com$ (^|\.)cnineu\.com$ (^|\.)cnn\.com$ (^|\.)cnnews\.chosun\.com$ (^|\.)cn\.nytstyle\.com$ (^|\.)cnpolitics\.org$ (^|\.)cn-proxy\.com$ (^|\.)cnproxy\.com$ (^|\.)cn\.sandscotaicentral\.com$ (^|\.)cn\.shafaqna\.com$ (^|\.)cn\.streetvoice\.com$ (^|\.)cn\.thegay\.com$ (^|\.)cn\.uncyclopedia\.wikia\.com$ (^|\.)cn\.uptodown\.com$ (^|\.)cn\.voa\.mobi$ (^|\.)coat\.co\.jp$ (^|\.)cobinhood\.com$ (^|\.)cochina\.co$ (^|\.)cochina\.org$ (^|\.)code1984\.com$ (^|\.)codeshare\.io$ (^|\.)codeskulptor\.org$ (^|\.)coin2co\.in$ (^|\.)coinbene\.com$ (^|\.)coinegg\.com$ (^|\.)coinex\.com$ (^|\.)coingi\.com$ (^|\.)coinrail\.co\.kr$ (^|\.)cointiger\.com$ (^|\.)cointobe\.com$ (^|\.)coinut\.com$ (^|\.)collateralmurder\.com$ (^|\.)collateralmurder\.org$ (^|\.)comefromchina\.com$ (^|\.)com\.google$ (^|\.)comic-mega\.me$ (^|\.)commandarms\.com$ (^|\.)commentshk\.com$ (^|\.)communistcrimes\.org$ (^|\.)communitychoicecu\.com$ (^|\.)community\.windy\.com$ (^|\.)compileheart\.com$ (^|\.)compress\.to$ (^|\.)co\.ng\.mil$ (^|\.)connect\.facebook\.net$ (^|\.)conoha\.jp$ (^|\.)contactmagazine\.net$ (^|\.)contests\.twilio\.com$ (^|\.)convio\.net$ (^|\.)coobay\.com$ (^|\.)coolaler\.com$ (^|\.)coolder\.com$ (^|\.)coolloud\.org\.tw$ (^|\.)coolncute\.com$ (^|\.)coolstuffinc\.com$ (^|\.)corumcollege\.com$ (^|\.)cosmic\.monar\.ch$ (^|\.)cos-moe\.com$ (^|\.)cosplayjav\.pl$ (^|\.)costco\.com$ (^|\.)cotweet\.com$ (^|\.)counter\.social$ (^|\.)coursehero\.com$ (^|\.)cpj\.org$ (^|\.)cq99\.us$ (^|\.)crackle\.com$ (^|\.)crazys\.cc$ (^|\.)crazyshit\.com$ (^|\.)crbug\.com$ (^|\.)crchina\.org$ (^|\.)crd-net\.org$ (^|\.)creaders\.net$ (^|\.)creadersnet\.com$ (^|\.)creativelab5\.com$ (^|\.)crisisresponse\.google$ (^|\.)cristyli\.com$ (^|\.)crocotube\.com$ (^|\.)crossfire\.co\.kr$ (^|\.)crossthewall\.net$ (^|\.)crossvpn\.net$ (^|\.)crrev\.com$ (^|\.)crucial\.com$ (^|\.)csdparty\.com$ (^|\.)c-spanvideo\.org$ (^|\.)css\.pixnet\.in$ (^|\.)csuchen\.de$ (^|\.)csw\.org\.uk$ (^|\.)ctao\.org$ (^|\.)ctfriend\.net$ (^|\.)cthlo\.github\.io$ (^|\.)ctitv\.com\.tw$ (^|\.)ct\.org\.tw$ (^|\.)cts\.com\.tw$ (^|\.)cuhkacs\.org$ (^|\.)cuihua\.org$ (^|\.)cuiweiping\.net$ (^|\.)culture\.tw$ (^|\.)cumlouder\.com$ (^|\.)curvefish\.com$ (^|\.)cusu\.hk$ (^|\.)cutscenes\.net$ (^|\.)cw\.com\.tw$ (^|\.)cyberghost\.natado\.com$ (^|\.)cyberghostvpn\.com$ (^|\.)cynscribe\.com$ (^|\.)cytode\.us$ (^|\.)d100\.net$ (^|\.)d1b183sg0nvnuh\.cloudfront\.net$ (^|\.)d1c37gjwa26taa\.cloudfront\.net$ (^|\.)d2bay\.com$ (^|\.)d2pass\.com$ (^|\.)d3c33hcgiwev3\.cloudfront\.net$ (^|\.)d3rhr7kgmtrq1v\.cloudfront\.net$ (^|\.)dabr\.co\.uk$ (^|\.)dabr\.eu$ (^|\.)dabr\.me$ (^|\.)dabr\.mobi$ (^|\.)dadazim\.com$ (^|\.)dadi360\.com$ (^|\.)dafabet\.com$ (^|\.)dafagood\.com$ (^|\.)dafahao\.com$ (^|\.)dafoh\.org$ (^|\.)daftporn\.com$ (^|\.)dagelijksestandaard\.nl$ (^|\.)daidostup\.ru$ (^|\.)dailidaili\.com$ (^|\.)dailymotion\.com$ (^|\.)dailynews\.sina\.com$ (^|\.)dailyview\.tw$ (^|\.)daiphapinfo\.net$ (^|\.)dajiyuan\.com$ (^|\.)dajiyuan\.de$ (^|\.)dajiyuan\.eu$ (^|\.)dajusha\.baywords\.com$ (^|\.)dalailama80\.org$ (^|\.)dalailama-archives\.org$ (^|\.)dalailamacenter\.org$ (^|\.)dalailama\.com$ (^|\.)dalailamafellows\.org$ (^|\.)dalailamafilm\.com$ (^|\.)dalailamafoundation\.org$ (^|\.)dalailamahindi\.com$ (^|\.)dalailamainaustralia\.org$ (^|\.)dalailamajapanese\.com$ (^|\.)dalailama\.mn$ (^|\.)dalailamaprotesters\.info$ (^|\.)dalailamaquotes\.org$ (^|\.)dalailama\.ru$ (^|\.)dalailamatrust\.org$ (^|\.)dalailama\.usc\.edu$ (^|\.)dalailamavisit\.org\.nz$ (^|\.)dalailamaworld\.com$ (^|\.)dalianmeng\.org$ (^|\.)daliulian\.org$ (^|\.)danbooru\.donmai\.us$ (^|\.)danke4china\.net$ (^|\.)danwei\.org$ (^|\.)daodu14\.jigsy\.com$ (^|\.)daolan\.net$ (^|\.)daozhongxing\.org$ (^|\.)darktech\.org$ (^|\.)darktoy\.net$ (^|\.)darpa\.mil$ (^|\.)dastrassi\.org$ (^|\.)data\.flurry\.com$ (^|\.)data\.gov\.tw$ (^|\.)data-vocabulary\.org$ (^|\.)daum\.net$ (^|\.)david-kilgour\.com$ (^|\.)dawangidc\.com$ (^|\.)daxa\.cn$ (^|\.)daylife\.com$ (^|\.)dbc\.hk$ (^|\.)db\.tt$ (^|\.)dcard\.tw$ (^|\.)dcmilitary\.com$ (^|\.)ddc\.com\.tw$ (^|\.)ddhw\.info$ (^|\.)ddns\.info$ (^|\.)ddns\.me\.uk$ (^|\.)ddns\.mobi$ (^|\.)ddns\.ms$ (^|\.)ddns\.name$ (^|\.)ddns\.net$ (^|\.)ddns\.us$ (^|\.)deaftone\.com$ (^|\.)debug\.com$ (^|\.)deck\.ly$ (^|\.)decodet\.co$ (^|\.)deepmind\.com$ (^|\.)deezer\.com$ (^|\.)definebabe\.com$ (^|\.)deja\.com$ (^|\.)delcamp\.net$ (^|\.)delicious\.com$ (^|\.)democrats\.org$ (^|\.)demo\.opera-mini\.net$ (^|\.)demosisto\.hk$ (^|\.)depositphotos\.com$ (^|\.)derekhsu\.homeip\.net$ (^|\.)de-sci\.org$ (^|\.)desc\.se$ (^|\.)design\.google$ (^|\.)desipro\.de$ (^|\.)dessci\.com$ (^|\.)destiny\.xfiles\.to$ (^|\.)destroy-china\.jp$ (^|\.)deutsche-welle\.de$ (^|\.)developers\.box\.net$ (^|\.)devio\.us$ (^|\.)devpn\.com$ (^|\.)dfas\.mil$ (^|\.)dfn\.org$ (^|\.)d-fukyu\.com$ (^|\.)dharamsalanet\.com$ (^|\.)dharmakara\.net$ (^|\.)dhcp\.biz$ (^|\.)diaoyuislands\.org$ (^|\.)dictionary\.goo\.ne\.jp$ (^|\.)difangwenge\.org$ (^|\.)digiland\.tw$ (^|\.)digisfera\.com$ (^|\.)digitalnomadsproject\.org$ (^|\.)diigo\.com$ (^|\.)dilber\.se$ (^|\.)dingchin\.com\.tw$ (^|\.)dipity\.com$ (^|\.)directcreative\.com$ (^|\.)discoins\.com$ (^|\.)disconnect\.me$ (^|\.)discordapp\.com$ (^|\.)discordapp\.net$ (^|\.)discuss4u\.com$ (^|\.)discuss\.com\.hk$ (^|\.)dish\.com$ (^|\.)disp\.cc$ (^|\.)disqus\.com$ (^|\.)dit-inc\.us$ (^|\.)dizhidizhi\.com$ (^|\.)dizhuzhishang\.com$ (^|\.)djangosnippets\.org$ (^|\.)djorz\.com$ (^|\.)dl\.box\.net$ (^|\.)dl-laby\.jp$ (^|\.)dlsite\.com$ (^|\.)dlyoutube\.com$ (^|\.)dm530\.net$ (^|\.)dmcdn\.net$ (^|\.)dmhy\.org$ (^|\.)dmm\.co\.jp$ (^|\.)dns04\.com$ (^|\.)dns05\.com$ (^|\.)dns1\.us$ (^|\.)dns2go\.com$ (^|\.)dns2\.us$ (^|\.)dnscrypt\.org$ (^|\.)dns-dns\.com$ (^|\.)dnset\.com$ (^|\.)dns\.google$ (^|\.)dnsrd\.com$ (^|\.)dnssec\.net$ (^|\.)dns-stuff\.com$ (^|\.)dnvod\.tv$ (^|\.)doctorvoice\.org$ (^|\.)documentingreality\.com$ (^|\.)dogfartnetwork\.com$ (^|\.)dojin\.com$ (^|\.)dok-forum\.net$ (^|\.)dolc\.de$ (^|\.)dolf\.org\.hk$ (^|\.)dollf\.com$ (^|\.)domain\.club\.tw$ (^|\.)domainhelp\.search\.com$ (^|\.)domains\.google$ (^|\.)domaintoday\.com\.au$ (^|\.)dongtaiwang\.com$ (^|\.)dongtaiwang\.net$ (^|\.)dongyangjing\.com$ (^|\.)dontfilter\.us$ (^|\.)dontmovetochina\.com$ (^|\.)dorjeshugden\.com$ (^|\.)dotplane\.com$ (^|\.)dotsub\.com$ (^|\.)dotvpn\.com$ (^|\.)doubibackup\.com$ (^|\.)doub\.io$ (^|\.)doubmirror\.cf$ (^|\.)dougscripts\.com$ (^|\.)douhokanko\.net$ (^|\.)doujincafe\.com$ (^|\.)dowei\.org$ (^|\.)download\.aircrack-ng\.org$ (^|\.)download\.cnet\.com$ (^|\.)download\.ithome\.com\.tw$ (^|\.)dphk\.org$ (^|\.)dpp\.org\.tw$ (^|\.)dpr\.info$ (^|\.)dragonex\.io$ (^|\.)dragonsprings\.org$ (^|\.)dreamamateurs\.com$ (^|\.)drepung\.org$ (^|\.)drgan\.net$ (^|\.)drmingxia\.org$ (^|\.)dropbooks\.tv$ (^|\.)dropbox\.com$ (^|\.)dropboxusercontent\.com$ (^|\.)drsunacademy\.com$ (^|\.)drtuber\.com$ (^|\.)dscn\.info$ (^|\.)dsmtp\.com$ (^|\.)dstk\.dk$ (^|\.)dtdns\.net$ (^|\.)dtiblog\.com$ (^|\.)dtic\.mil$ (^|\.)dtwang\.org$ (^|\.)duanzhihu\.com$ (^|\.)duck\.com$ (^|\.)duckdns\.org$ (^|\.)duckduckgo\.com$ (^|\.)duckduckgo-owned-server\.yahoo\.net$ (^|\.)duckload\.com$ (^|\.)duckmylife\.com$ (^|\.)duga\.jp$ (^|\.)duihuahrjournal\.org$ (^|\.)duihua\.org$ (^|\.)dumb1\.com$ (^|\.)dunyabulteni\.net$ (^|\.)duoweitimes\.com$ (^|\.)duping\.net$ (^|\.)duplicati\.com$ (^|\.)dupola\.com$ (^|\.)dupola\.net$ (^|\.)dushi\.ca$ (^|\.)dvdpac\.com$ (^|\.)dvorak\.org$ (^|\.)dw\.com$ (^|\.)dw\.de$ (^|\.)dwnews\.com$ (^|\.)dwnews\.net$ (^|\.)dw-world\.com$ (^|\.)dw-world\.de$ (^|\.)dynamicdns\.biz$ (^|\.)dynamicdns\.co\.uk$ (^|\.)dynamicdns\.me\.uk$ (^|\.)dynamic-dns\.net$ (^|\.)dynamicdns\.org\.uk$ (^|\.)dynawebinc\.com$ (^|\.)dyndns-ip\.com$ (^|\.)dyndns\.org$ (^|\.)dyndns-pics\.com$ (^|\.)dyndns\.pro$ (^|\.)dynssl\.com$ (^|\.)dynu\.com$ (^|\.)dynu\.net$ (^|\.)dynupdate\.no-ip\.com$ (^|\.)dysfz\.cc$ (^|\.)dzze\.com$ (^|\.)e123\.hk$ (^|\.)earlytibet\.com$ (^|\.)earthcam\.com$ (^|\.)earthvpn\.com$ (^|\.)eastern-ark\.com$ (^|\.)easternlightning\.org$ (^|\.)eastturkestan\.com$ (^|\.)eastturkistancc\.org$ (^|\.)eastturkistangovernmentinexile\.us$ (^|\.)eastturkistan-gov\.org$ (^|\.)easyca\.ca$ (^|\.)easypic\.com$ (^|\.)ebony-beauty\.com$ (^|\.)ebookbrowse\.com$ (^|\.)ebookee\.com$ (^|\.)ebook\.hyread\.com\.tw$ (^|\.)ebtcbank\.com$ (^|\.)ecfa\.org\.tw$ (^|\.)echofon\.com$ (^|\.)ecimg\.tw$ (^|\.)e-classical\.com\.tw$ (^|\.)ecministry\.net$ (^|\.)economist\.com$ (^|\.)ecsm\.vs\.com$ (^|\.)edgecastcdn\.net$ (^|\.)edicypages\.com$ (^|\.)edmontonchina\.cn$ (^|\.)edmontonservice\.com$ (^|\.)edns\.biz$ (^|\.)edoors\.com$ (^|\.)edubridge\.com$ (^|\.)edupro\.org$ (^|\.)eeas\.europa\.eu$ (^|\.)eesti\.ee$ (^|\.)eevpn\.com$ (^|\.)efcc\.org\.hk$ (^|\.)effers\.com$ (^|\.)efksoft\.com$ (^|\.)efukt\.com$ (^|\.)e-gold\.com$ (^|\.)e-hentaidb\.com$ (^|\.)e-hentai\.org$ (^|\.)eic-av\.com$ (^|\.)e-info\.org\.tw$ (^|\.)eireinikotaerukai\.com$ (^|\.)eisbb\.com$ (^|\.)eksisozluk\.com$ (^|\.)electionsmeter\.com$ (^|\.)elgoog\.im$ (^|\.)ellawine\.org$ (^|\.)elpais\.com$ (^|\.)eltondisney\.com$ (^|\.)emaga\.com$ (^|\.)emanna\.com$ (^|\.)embr\.in$ (^|\.)emilylau\.org\.hk$ (^|\.)empfil\.com$ (^|\.)emule-ed2k\.com$ (^|\.)emulefans\.com$ (^|\.)emuparadise\.me$ (^|\.)enanyang\.my$ (^|\.)encyclopedia\.com$ (^|\.)enewstree\.com$ (^|\.)enfal\.de$ (^|\.)en\.favotter\.net$ (^|\.)engagedaily\.org$ (^|\.)englishforeveryone\.org$ (^|\.)englishfromengland\.co\.uk$ (^|\.)englishpen\.org$ (^|\.)en\.hao123\.com$ (^|\.)enlighten\.org\.tw$ (^|\.)entermap\.com$ (^|\.)entnt\.com$ (^|\.)environment\.google$ (^|\.)epac\.to$ (^|\.)epa\.gov\.tw$ (^|\.)episcopalchurch\.org$ (^|\.)epochhk\.com$ (^|\.)epochtimes-bg\.com$ (^|\.)epochtimes\.co\.il$ (^|\.)epochtimes\.co\.kr$ (^|\.)epochtimes\.com$ (^|\.)epochtimes\.cz$ (^|\.)epochtimes\.de$ (^|\.)epochtimes\.fr$ (^|\.)epochtimes\.ie$ (^|\.)epochtimes\.it$ (^|\.)epochtimes\.jp$ (^|\.)epochtimes-romania\.com$ (^|\.)epochtimes\.ru$ (^|\.)epochtimes\.se$ (^|\.)epochtimestr\.com$ (^|\.)epochweek\.com$ (^|\.)epochweekly\.com$ (^|\.)eporner\.com$ (^|\.)equinenow\.com$ (^|\.)erabaru\.net$ (^|\.)eracom\.com\.tw$ (^|\.)eraysoft\.com\.tr$ (^|\.)erepublik\.com$ (^|\.)erights\.net$ (^|\.)eriversoft\.com$ (^|\.)erktv\.com$ (^|\.)ernestmandel\.org$ (^|\.)erodaizensyu\.com$ (^|\.)erodoujinlog\.com$ (^|\.)erodoujinworld\.com$ (^|\.)eromangadouzin\.com$ (^|\.)eromanga-kingdom\.com$ (^|\.)eromon\.net$ (^|\.)eroprofile\.com$ (^|\.)eroticsaloon\.net$ (^|\.)eslite\.com$ (^|\.)esmtp\.biz$ (^|\.)esurance\.com$ (^|\.)etaa\.org\.au$ (^|\.)etadult\.com$ (^|\.)etaiwannews\.com$ (^|\.)etherdelta\.com$ (^|\.)etizer\.org$ (^|\.)etokki\.com$ (^|\.)etools\.ncol\.com$ (^|\.)etowns\.net$ (^|\.)etowns\.org$ (^|\.)e-traderland\.net$ (^|\.)ettoday\.net$ (^|\.)etvonline\.hk$ (^|\.)eucasino\.com$ (^|\.)eulam\.com$ (^|\.)eu\.org$ (^|\.)eurekavpt\.com$ (^|\.)euronews\.com$ (^|\.)evchk\.wikia\.com$ (^|\.)evschool\.net$ (^|\.)exblog\.jp$ (^|\.)exchristian\.hk$ (^|\.)exmo\.com$ (^|\.)exmormon\.org$ (^|\.)expatshield\.com$ (^|\.)expecthim\.com$ (^|\.)expekt\.com$ (^|\.)experts-univers\.com$ (^|\.)exploader\.net$ (^|\.)expressvpn\.com$ (^|\.)exrates\.me$ (^|\.)extmatrix\.com$ (^|\.)extremetube\.com$ (^|\.)exx\.com$ (^|\.)eyevio\.jp$ (^|\.)eyny\.com$ (^|\.)e-zone\.com\.hk$ (^|\.)ezpc\.tk$ (^|\.)ezpeer\.com$ (^|\.)ezua\.com$ (^|\.)facebook\.br$ (^|\.)facebook\.com$ (^|\.)facebook\.design$ (^|\.)facebook\.hu$ (^|\.)facebook\.in$ (^|\.)facebookmail\.com$ (^|\.)facebook\.nl$ (^|\.)facebookquotes4u\.com$ (^|\.)facebook\.se$ (^|\.)faceless\.me$ (^|\.)facesofnyfw\.com$ (^|\.)facesoftibetanselfimmolators\.info$ (^|\.)fa\.gov\.tw$ (^|\.)fail\.hk$ (^|\.)faith100\.org$ (^|\.)faithfuleye\.com$ (^|\.)faiththedog\.info$ (^|\.)fakku\.net$ (^|\.)falsefire\.com$ (^|\.)falunart\.org$ (^|\.)falunasia\.info$ (^|\.)falunau\.org$ (^|\.)falunaz\.net$ (^|\.)falun\.caltech\.edu$ (^|\.)falun-co\.org$ (^|\.)falundafa-dc\.org$ (^|\.)falundafa-florida\.org$ (^|\.)falundafaindia\.org$ (^|\.)falundafamuseum\.org$ (^|\.)falundafa-nc\.org$ (^|\.)falundafa\.org$ (^|\.)falundafa-pa\.net$ (^|\.)falundafa-sacramento\.org$ (^|\.)falungong\.club$ (^|\.)falungong\.de$ (^|\.)falungong\.org\.uk$ (^|\.)falunhr\.org$ (^|\.)faluninfo\.de$ (^|\.)faluninfo\.net$ (^|\.)falun-ny\.net$ (^|\.)falunpilipinas\.net$ (^|\.)falunworld\.net$ (^|\.)familyfed\.org$ (^|\.)famunion\.com$ (^|\.)fangbinxing\.com$ (^|\.)fangeming\.com$ (^|\.)fangeqiang\.com$ (^|\.)fanglizhi\.info$ (^|\.)fangmincn\.org$ (^|\.)fangong\.forums-free\.com$ (^|\.)fangongheike\.com$ (^|\.)fangong\.org$ (^|\.)fanhaodang\.com$ (^|\.)fan-qiang\.com$ (^|\.)fanqiangdang\.com$ (^|\.)fanqianghou\.com$ (^|\.)fanqiang\.tk$ (^|\.)fanqiangyakexi\.net$ (^|\.)fanqiangzhe\.com$ (^|\.)fanswong\.com$ (^|\.)fanyue\.info$ (^|\.)fapdu\.com$ (^|\.)faproxy\.com$ (^|\.)faqserv\.com$ (^|\.)fartit\.com$ (^|\.)farwestchina\.com$ (^|\.)fastpic\.ru$ (^|\.)fastssh\.com$ (^|\.)faststone\.org$ (^|\.)fast\.wistia\.com$ (^|\.)fatbtc\.com$ (^|\.)favstar\.fm$ (^|\.)fawanghuihui\.org$ (^|\.)faydao\.com$ (^|\.)fbaddins\.com$ (^|\.)fbcdn\.net$ (^|\.)fb\.com$ (^|\.)fb\.me$ (^|\.)fbsbx\.com$ (^|\.)fbworkmail\.com$ (^|\.)fc2blog\.net$ (^|\.)fc2china\.com$ (^|\.)fc2cn\.com$ (^|\.)fc2\.com$ (^|\.)fda\.gov\.tw$ (^|\.)fdc64\.de$ (^|\.)fdc64\.org$ (^|\.)fdc89\.jp$ (^|\.)feedburner\.com$ (^|\.)feeds\.fileforum\.com$ (^|\.)feedx\.net$ (^|\.)feelssh\.com$ (^|\.)feer\.com$ (^|\.)feifeiss\.com$ (^|\.)feitianacademy\.org$ (^|\.)feitian-california\.org$ (^|\.)feministteacher\.com$ (^|\.)fengzhenghu\.com$ (^|\.)fengzhenghu\.net$ (^|\.)fevernet\.com$ (^|\.)fffff\.at$ (^|\.)ff\.im$ (^|\.)fflick\.com$ (^|\.)ffvpn\.com$ (^|\.)fgmtv\.net$ (^|\.)fgmtv\.org$ (^|\.)fhreports\.net$ (^|\.)fiddle\.jshell\.net$ (^|\.)figprayer\.com$ (^|\.)fileflyer\.com$ (^|\.)files2me\.com$ (^|\.)fileserve\.com$ (^|\.)filesor\.com$ (^|\.)fillthesquare\.org$ (^|\.)filmingfortibet\.org$ (^|\.)filmy\.olabloga\.pl$ (^|\.)filthdump\.com$ (^|\.)financetwitter\.com$ (^|\.)finchvpn\.com$ (^|\.)findmespot\.com$ (^|\.)findyoutube\.com$ (^|\.)findyoutube\.net$ (^|\.)fingerdaily\.com$ (^|\.)finler\.net$ (^|\.)firearmsworld\.net$ (^|\.)firebaseio\.com$ (^|\.)fireofliberty\.org$ (^|\.)firetweet\.io$ (^|\.)firstfivefollowers\.com$ (^|\.)flagsonline\.it$ (^|\.)flecheinthepeche\.fr$ (^|\.)fleshbot\.com$ (^|\.)fleursdeslettres\.com$ (^|\.)flgg\.us$ (^|\.)flgjustice\.org$ (^|\.)flickr\.com$ (^|\.)flickrhivemind\.net$ (^|\.)flickriver\.com$ (^|\.)fling\.com$ (^|\.)flipboard\.com$ (^|\.)flipkart\.com$ (^|\.)flitto\.com$ (^|\.)flnet\.org$ (^|\.)flog\.tw$ (^|\.)flyvpn\.com$ (^|\.)flyzy2005\.com$ (^|\.)fnac\.be$ (^|\.)fnac\.com$ (^|\.)fochk\.org$ (^|\.)focustaiwan\.tw$ (^|\.)focusvpn\.com$ (^|\.)fofg-europe\.net$ (^|\.)fofg\.org$ (^|\.)fofldfradio\.org$ (^|\.)fooooo\.com$ (^|\.)footwiball\.com$ (^|\.)foreignpolicy\.com$ (^|\.)forum4hk\.com$ (^|\.)forum\.baby-kingdom\.com$ (^|\.)forum\.cyberctm\.com$ (^|\.)forum\.idsam\.com$ (^|\.)forum\.my903\.com$ (^|\.)forum\.mymaji\.com$ (^|\.)forum\.omy\.sg$ (^|\.)forum\.palmislife\.com$ (^|\.)forum\.setty\.com\.tw$ (^|\.)forum\.sina\.com\.hk$ (^|\.)forum\.slime\.com\.tw$ (^|\.)forum\.tvb\.com$ (^|\.)forum\.xinbao\.de$ (^|\.)fotile\.me$ (^|\.)fourface\.nodesnoop\.com$ (^|\.)fourthinternational\.org$ (^|\.)foxdie\.us$ (^|\.)foxgay\.com$ (^|\.)foxsub\.com$ (^|\.)foxtang\.com$ (^|\.)fpmtmexico\.org$ (^|\.)fpmt\.org$ (^|\.)fpmt-osel\.org$ (^|\.)fpmt\.tw$ (^|\.)fqok\.org$ (^|\.)fqrouter\.com$ (^|\.)fq\.wikia\.com$ (^|\.)franklc\.com$ (^|\.)freakshare\.com$ (^|\.)free4u\.com\.ar$ (^|\.)freealim\.com$ (^|\.)freebrowser\.org$ (^|\.)freechal\.com$ (^|\.)freechinaforum\.org$ (^|\.)freechina\.net$ (^|\.)freechina\.news$ (^|\.)freechinaweibo\.com$ (^|\.)freeddns\.com$ (^|\.)freeddns\.org$ (^|\.)freedomchina\.info$ (^|\.)freedomcollection\.org$ (^|\.)freedomhouse\.org$ (^|\.)freedominfonetweb\.wordpress\.com$ (^|\.)freedomsherald\.org$ (^|\.)freeforums\.org$ (^|\.)freefq\.com$ (^|\.)free\.fr$ (^|\.)freefuckvids\.com$ (^|\.)freegao\.com$ (^|\.)free-gate\.org$ (^|\.)free-hada-now\.org$ (^|\.)freehongkong\.org$ (^|\.)freeilhamtohti\.org$ (^|\.)freekwonpyong\.org$ (^|\.)freelotto\.com$ (^|\.)freeman2\.com$ (^|\.)freemoren\.com$ (^|\.)freemorenews\.com$ (^|\.)freemuse\.org$ (^|\.)freenet-china\.org$ (^|\.)freenetproject\.org$ (^|\.)freenewscn\.com$ (^|\.)freeopenvpn\.com$ (^|\.)freeoz\.org$ (^|\.)free-proxy\.cz$ (^|\.)free-ssh\.com$ (^|\.)freessh\.us$ (^|\.)free-ss\.site$ (^|\.)freetcp\.com$ (^|\.)freetibetanheroes\.org$ (^|\.)freetibet\.net$ (^|\.)freetibet\.org$ (^|\.)freeviewmovies\.com$ (^|\.)freevpn\.me$ (^|\.)freevpn\.nl$ (^|\.)freewallpaper4\.me$ (^|\.)freewebs\.com$ (^|\.)freewechat\.com$ (^|\.)freeweibo\.com$ (^|\.)freewww\.biz$ (^|\.)freewww\.info$ (^|\.)freexinwen\.com$ (^|\.)freeyellow\.com$ (^|\.)freeyoutubeproxy\.net$ (^|\.)friendfeed\.com$ (^|\.)friendfeed-media\.com$ (^|\.)friends-of-tibet\.org$ (^|\.)friendsoftibet\.org$ (^|\.)fring\.com$ (^|\.)fringenetwork\.com$ (^|\.)fromchinatousa\.net$ (^|\.)frommel\.net$ (^|\.)from-pr\.com$ (^|\.)from-sd\.com$ (^|\.)frontlinedefenders\.org$ (^|\.)frootvpn\.com$ (^|\.)fscked\.org$ (^|\.)fsurf\.com$ (^|\.)ftchinese\.com$ (^|\.)ftp1\.biz$ (^|\.)ftpserver\.biz$ (^|\.)ftv\.com\.tw$ (^|\.)fucd\.com$ (^|\.)fuckcnnic\.net$ (^|\.)fuckgfw\.org$ (^|\.)fulione\.com$ (^|\.)fullerconsideration\.com$ (^|\.)fulue\.com$ (^|\.)funf\.tw$ (^|\.)funkyimg\.com$ (^|\.)funp\.com$ (^|\.)fuq\.com$ (^|\.)furbo\.org$ (^|\.)furhhdl\.org$ (^|\.)furinkan\.com$ (^|\.)furl\.net$ (^|\.)futurechinaforum\.org$ (^|\.)futuremessage\.org$ (^|\.)fux\.com$ (^|\.)fuyindiantai\.org$ (^|\.)fuyin\.net$ (^|\.)fuyu\.org\.tw$ (^|\.)fw\.cm$ (^|\.)fxcm-chinese\.com$ (^|\.)fxnetworks\.com$ (^|\.)fzh999\.com$ (^|\.)fzh999\.net$ (^|\.)fzlm\.com$ (^|\.)g0v\.social$ (^|\.)g6hentai\.com$ (^|\.)gabocorp\.com$ (^|\.)gaeproxy\.com$ (^|\.)gaforum\.org$ (^|\.)galaxymacau\.com$ (^|\.)galenwu\.com$ (^|\.)galstars\.net$ (^|\.)game735\.com$ (^|\.)gamebase\.com\.tw$ (^|\.)gamejolt\.com$ (^|\.)gamer2-cds\.cdn\.hinet\.net$ (^|\.)gamer-cds\.cdn\.hinet\.net$ (^|\.)gamer\.com\.tw$ (^|\.)gamez\.com\.tw$ (^|\.)gamousa\.com$ (^|\.)ganges\.com$ (^|\.)gaoming\.net$ (^|\.)gaopi\.net$ (^|\.)gaozhisheng\.net$ (^|\.)gaozhisheng\.org$ (^|\.)gardennetworks\.com$ (^|\.)gardennetworks\.org$ (^|\.)g-area\.org$ (^|\.)gartlive\.com$ (^|\.)gatecoin\.com$ (^|\.)gate\.io$ (^|\.)gate-project\.com$ (^|\.)gather\.com$ (^|\.)gatherproxy\.com$ (^|\.)gati\.org\.tw$ (^|\.)gaybubble\.com$ (^|\.)gaycn\.net$ (^|\.)gayhub\.com$ (^|\.)gaymap\.cc$ (^|\.)gaymenring\.com$ (^|\.)gaytube\.com$ (^|\.)gaywatch\.com$ (^|\.)gazotube\.com$ (^|\.)gcc\.org\.hk$ (^|\.)gclooney\.com$ (^|\.)gcmasia\.com$ (^|\.)g\.co$ (^|\.)gcpnews\.com$ (^|\.)gcr\.io$ (^|\.)gdbt\.net$ (^|\.)gdzf\.org$ (^|\.)geek-art\.net$ (^|\.)geekerhome\.com$ (^|\.)geekheart\.info$ (^|\.)gekikame\.com$ (^|\.)gelbooru\.com$ (^|\.)geocities\.co\.jp$ (^|\.)geocities\.com$ (^|\.)geocities\.jp$ (^|\.)gerefoundation\.org$ (^|\.)get\.app$ (^|\.)getastrill\.com$ (^|\.)getchu\.com$ (^|\.)getcloak\.com$ (^|\.)get\.dev$ (^|\.)getfoxyproxy\.org$ (^|\.)getfreedur\.com$ (^|\.)getgom\.com$ (^|\.)get\.how$ (^|\.)geti2p\.net$ (^|\.)getiton\.com$ (^|\.)getjetso\.com$ (^|\.)getlantern\.org$ (^|\.)getmdl\.io$ (^|\.)getoutline\.org$ (^|\.)get\.page$ (^|\.)getsocialscope\.com$ (^|\.)getsync\.com$ (^|\.)gettrials\.com$ (^|\.)gettyimages\.com$ (^|\.)getuploader\.com$ (^|\.)gfbv\.de$ (^|\.)gfgold\.com\.hk$ (^|\.)gfsale\.com$ (^|\.)gfw\.org\.ua$ (^|\.)gfw\.press$ (^|\.)ggpht\.com$ (^|\.)ggssl\.com$ (^|\.)ghostpath\.com$ (^|\.)ghut\.org$ (^|\.)giantessnight\.com$ (^|\.)gifree\.com$ (^|\.)giga-web\.jp$ (^|\.)gigporno\.ru$ (^|\.)girlbanker\.com$ (^|\.)gist\.github\.com$ (^|\.)github\.com$ (^|\.)git\.io$ (^|\.)gizlen\.net$ (^|\.)gjczz\.com$ (^|\.)glass8\.eu$ (^|\.)global\.bing\.com$ (^|\.)globaljihad\.net$ (^|\.)globalmediaoutreach\.com$ (^|\.)globalmuseumoncommunism\.org$ (^|\.)globalrescue\.net$ (^|\.)globaltm\.org$ (^|\.)globalvoicesonline\.org$ (^|\.)globalvoices\.org$ (^|\.)globalvpn\.net$ (^|\.)glock\.com$ (^|\.)gloryhole\.com$ (^|\.)glorystar\.me$ (^|\.)gluckman\.com$ (^|\.)glype\.com$ (^|\.)gmail\.com$ (^|\.)gmbd\.cn$ (^|\.)gmhz\.org$ (^|\.)gmll\.org$ (^|\.)gmodules\.com$ (^|\.)gmozomg\.izihost\.org$ (^|\.)gnci\.org\.hk$ (^|\.)go141\.com$ (^|\.)goagent\.biz$ (^|\.)goagent\.codeplex\.com$ (^|\.)goagentplus\.com$ (^|\.)gobet\.cc$ (^|\.)godfootsteps\.org$ (^|\.)godns\.work$ (^|\.)godoc\.org$ (^|\.)godsdirectcontact\.co\.uk$ (^|\.)godsdirectcontact\.org$ (^|\.)godsdirectcontact\.org\.tw$ (^|\.)godsimmediatecontact\.com$ (^|\.)gogotunnel\.com$ (^|\.)gohappy\.com\.tw$ (^|\.)gojet\.krtco\.com\.tw$ (^|\.)gokbayrak\.com$ (^|\.)golang\.org$ (^|\.)goldbet\.com$ (^|\.)goldbetsports\.com$ (^|\.)goldeneyevault\.com$ (^|\.)goldenfrog\.com$ (^|\.)goldjizz\.com$ (^|\.)goldstep\.net$ (^|\.)goldwave\.com$ (^|\.)go\.nesnode\.com$ (^|\.)gongmeng\.info$ (^|\.)gongm\.in$ (^|\.)gongminliliang\.com$ (^|\.)gongwt\.com$ (^|\.)gooday\.xyz$ (^|\.)gooddns\.info$ (^|\.)goodreaders\.com$ (^|\.)goodreads\.com$ (^|\.)goodtv\.com\.tw$ (^|\.)goodtv\.tv$ (^|\.)goofind\.com$ (^|\.)goo\.gl$ (^|\.)google\.ad$ (^|\.)google\.ae$ (^|\.)google\.al$ (^|\.)google\.am$ (^|\.)googleapis\.cn$ (^|\.)googleapis\.com$ (^|\.)googleapps\.com$ (^|\.)googlearth\.com$ (^|\.)googleartproject\.com$ (^|\.)google\.as$ (^|\.)google\.at$ (^|\.)google\.az$ (^|\.)google\.ba$ (^|\.)google\.be$ (^|\.)google\.bf$ (^|\.)google\.bg$ (^|\.)google\.bi$ (^|\.)google\.bj$ (^|\.)googleblog\.com$ (^|\.)googlebot\.com$ (^|\.)google\.bs$ (^|\.)google\.bt$ (^|\.)google\.by$ (^|\.)google\.ca$ (^|\.)google\.calstate\.edu$ (^|\.)google\.cat$ (^|\.)google\.cd$ (^|\.)google\.cf$ (^|\.)google\.cg$ (^|\.)google\.ch$ (^|\.)googlechinawebmaster\.com$ (^|\.)google\.ci$ (^|\.)google\.cl$ (^|\.)google\.cm$ (^|\.)google\.cn$ (^|\.)google\.co\.ao$ (^|\.)google\.co\.bw$ (^|\.)google\.co\.ck$ (^|\.)google\.co\.cr$ (^|\.)googlecode\.com$ (^|\.)google\.co\.id$ (^|\.)google\.co\.il$ (^|\.)google\.co\.in$ (^|\.)google\.co\.jp$ (^|\.)google\.co\.ke$ (^|\.)google\.co\.kr$ (^|\.)google\.co\.ls$ (^|\.)google\.com$ (^|\.)google\.co\.ma$ (^|\.)google\.com\.af$ (^|\.)google\.com\.ag$ (^|\.)google\.com\.ai$ (^|\.)google\.com\.ar$ (^|\.)google\.com\.au$ (^|\.)google\.com\.bd$ (^|\.)google\.com\.bh$ (^|\.)google\.com\.bn$ (^|\.)google\.com\.bo$ (^|\.)google\.com\.br$ (^|\.)google\.com\.bz$ (^|\.)google\.com\.co$ (^|\.)google\.com\.cu$ (^|\.)google\.com\.cy$ (^|\.)google\.com\.do$ (^|\.)google\.com\.ec$ (^|\.)google\.com\.eg$ (^|\.)google\.com\.et$ (^|\.)google\.com\.fj$ (^|\.)google\.com\.gh$ (^|\.)google\.com\.gi$ (^|\.)google\.com\.gt$ (^|\.)google\.com\.hk$ (^|\.)google\.com\.jm$ (^|\.)google\.com\.kh$ (^|\.)google\.com\.kw$ (^|\.)google\.com\.lb$ (^|\.)google\.com\.ly$ (^|\.)googlecommerce\.com$ (^|\.)google\.com\.mm$ (^|\.)google\.com\.mt$ (^|\.)google\.com\.mx$ (^|\.)google\.com\.my$ (^|\.)google\.com\.na$ (^|\.)google\.com\.nf$ (^|\.)google\.com\.ng$ (^|\.)google\.com\.ni$ (^|\.)google\.com\.np$ (^|\.)google\.com\.om$ (^|\.)google\.com\.pa$ (^|\.)google\.com\.pe$ (^|\.)google\.com\.pg$ (^|\.)google\.com\.ph$ (^|\.)google\.com\.pk$ (^|\.)google\.com\.pr$ (^|\.)google\.com\.py$ (^|\.)google\.com\.qa$ (^|\.)google\.com\.sa$ (^|\.)google\.com\.sb$ (^|\.)google\.com\.sg$ (^|\.)google\.com\.sl$ (^|\.)google\.com\.sv$ (^|\.)google\.com\.tj$ (^|\.)google\.com\.tr$ (^|\.)google\.com\.tw$ (^|\.)google\.com\.ua$ (^|\.)google\.com\.uy$ (^|\.)google\.com\.vc$ (^|\.)google\.com\.vn$ (^|\.)google\.co\.mz$ (^|\.)google\.co\.nz$ (^|\.)google\.co\.th$ (^|\.)google\.co\.tz$ (^|\.)google\.co\.ug$ (^|\.)google\.co\.uk$ (^|\.)google\.co\.uz$ (^|\.)google\.co\.ve$ (^|\.)google\.co\.vi$ (^|\.)google\.co\.za$ (^|\.)google\.co\.zm$ (^|\.)google\.co\.zw$ (^|\.)google\.cv$ (^|\.)google\.cz$ (^|\.)google\.de$ (^|\.)google\.dev$ (^|\.)google\.dj$ (^|\.)google\.dk$ (^|\.)google\.dm$ (^|\.)googledomains\.com$ (^|\.)googledrive\.com$ (^|\.)google\.dz$ (^|\.)googleearth\.com$ (^|\.)google\.ee$ (^|\.)google\.es$ (^|\.)google\.fi$ (^|\.)google\.fm$ (^|\.)google\.fr$ (^|\.)google\.ga$ (^|\.)google\.ge$ (^|\.)google\.gg$ (^|\.)google\.gl$ (^|\.)google\.gm$ (^|\.)google\.gp$ (^|\.)google\.gr$ (^|\.)googlegroups\.com$ (^|\.)google\.gy$ (^|\.)google\.hn$ (^|\.)googlehosted\.com$ (^|\.)google\.hr$ (^|\.)google\.ht$ (^|\.)google\.hu$ (^|\.)googleideas\.com$ (^|\.)google\.ie$ (^|\.)google\.im$ (^|\.)googleinsidesearch\.com$ (^|\.)google\.iq$ (^|\.)google\.is$ (^|\.)google\.it$ (^|\.)google\.je$ (^|\.)google\.jo$ (^|\.)google\.kg$ (^|\.)google\.ki$ (^|\.)google\.kz$ (^|\.)google\.la$ (^|\.)googlelabs\.com$ (^|\.)google\.li$ (^|\.)google\.lk$ (^|\.)google\.lt$ (^|\.)google\.lu$ (^|\.)google\.lv$ (^|\.)googlemail\.com$ (^|\.)googlemashups\.com$ (^|\.)google\.md$ (^|\.)google\.me$ (^|\.)google\.mg$ (^|\.)google\.mk$ (^|\.)google\.ml$ (^|\.)google\.mn$ (^|\.)google\.ms$ (^|\.)google\.mu$ (^|\.)google\.mv$ (^|\.)google\.mw$ (^|\.)google\.ne$ (^|\.)google\.nl$ (^|\.)google\.no$ (^|\.)google\.nr$ (^|\.)google\.nu$ (^|\.)googlepagecreator\.com$ (^|\.)google\.pl$ (^|\.)googleplay\.com$ (^|\.)googleplus\.com$ (^|\.)google\.pn$ (^|\.)google\.ps$ (^|\.)google\.pt$ (^|\.)google\.ro$ (^|\.)google\.rs$ (^|\.)google\.ru$ (^|\.)google\.rw$ (^|\.)google\.sc$ (^|\.)googlescholar\.com$ (^|\.)google\.se$ (^|\.)google\.sh$ (^|\.)google\.si$ (^|\.)googlesile\.com$ (^|\.)google\.sk$ (^|\.)google\.sm$ (^|\.)google\.sn$ (^|\.)google\.so$ (^|\.)googlesource\.com$ (^|\.)google\.sr$ (^|\.)google\.st$ (^|\.)google\.td$ (^|\.)google\.tg$ (^|\.)google\.tk$ (^|\.)google\.tl$ (^|\.)google\.tm$ (^|\.)google\.tn$ (^|\.)google\.to$ (^|\.)google\.tt$ (^|\.)googleusercontent\.com$ (^|\.)google\.vg$ (^|\.)googlevideo\.com$ (^|\.)google\.vu$ (^|\.)googleweblight\.com$ (^|\.)google\.ws$ (^|\.)googlezip\.net$ (^|\.)gopetition\.com$ (^|\.)go-pki\.com$ (^|\.)goproxing\.net$ (^|\.)goregrish\.com$ (^|\.)gospelherald\.com$ (^|\.)gotdns\.ch$ (^|\.)got-game\.org$ (^|\.)gotgeeks\.com$ (^|\.)gotrusted\.com$ (^|\.)gotw\.ca$ (^|\.)gov\.taipei$ (^|\.)gov\.tw$ (^|\.)g-queen\.com$ (^|\.)gr8domain\.biz$ (^|\.)gr8name\.biz$ (^|\.)grammaly\.com$ (^|\.)grandtrial\.org$ (^|\.)grangorz\.org$ (^|\.)graphis\.ne\.jp$ (^|\.)graphql\.org$ (^|\.)greasespot\.net$ (^|\.)greatfire\.org$ (^|\.)greatfire\.us7\.list-manage\.com$ (^|\.)greatfirewall\.biz$ (^|\.)great-firewall\.com$ (^|\.)greatfirewallofchina\.net$ (^|\.)greatfirewallofchina\.org$ (^|\.)great-roc\.org$ (^|\.)greatroc\.org$ (^|\.)greatroc\.tw$ (^|\.)greatzhonghua\.org$ (^|\.)greenfieldbookstore\.com\.hk$ (^|\.)greenparty\.org\.tw$ (^|\.)greenpeace\.com\.tw$ (^|\.)greenpeace\.org$ (^|\.)greenreadings\.com$ (^|\.)greenvpn\.net$ (^|\.)greenvpn\.org$ (^|\.)grotty-monday\.com$ (^|\.)groups\.google\.cn$ (^|\.)grow\.google$ (^|\.)gs-discuss\.com$ (^|\.)gsp\.target\.com$ (^|\.)gstatic\.com$ (^|\.)gtricks\.com$ (^|\.)gts-vpn\.com$ (^|\.)guaguass\.com$ (^|\.)guaguass\.org$ (^|\.)guancha\.org$ (^|\.)guaneryu\.com$ (^|\.)guangming\.com\.my$ (^|\.)guangnianvpn\.com$ (^|\.)guardster\.com$ (^|\.)gu-chu-sum\.org$ (^|\.)guishan\.org$ (^|\.)gumroad\.com$ (^|\.)gunsamerica\.com$ (^|\.)gunsandammo\.com$ (^|\.)gun-world\.net$ (^|\.)guo\.media$ (^|\.)guruonline\.hk$ (^|\.)gutteruncensored\.com$ (^|\.)gvlib\.com$ (^|\.)gvm\.com\.tw$ (^|\.)gvt0\.com$ (^|\.)gvt1\.com$ (^|\.)gvt3\.com$ (^|\.)gwtproject\.org$ (^|\.)gyalwarinpoche\.com$ (^|\.)gyatsostudio\.com$ (^|\.)gzm\.tv$ (^|\.)gzone-anime\.info$ (^|\.)h1n1china\.org$ (^|\.)h528\.com$ (^|\.)h5dm\.com$ (^|\.)h5galgame\.me$ (^|\.)hacg\.club$ (^|\.)hacg\.in$ (^|\.)hacg\.li$ (^|\.)hacg\.me$ (^|\.)hacg\.red$ (^|\.)hacken\.cc$ (^|\.)hacker\.org$ (^|\.)hackthatphone\.net$ (^|\.)hahaxixi\.github\.io$ (^|\.)hahlo\.com$ (^|\.)hakkatv\.org\.tw$ (^|\.)handcraftedsoftware\.org$ (^|\.)hanime\.tv$ (^|\.)hanunyi\.com$ (^|\.)haoel\.github\.io$ (^|\.)hao\.news$ (^|\.)happy-vpn\.com$ (^|\.)haproxy\.org$ (^|\.)hardsextube\.com$ (^|\.)harunyahya\.com$ (^|\.)hautelookcdn\.com$ (^|\.)hautelook\.com$ (^|\.)have8\.com$ (^|\.)hbg\.com$ (^|\.)hbo\.com$ (^|\.)h-china\.org$ (^|\.)hclips\.com$ (^|\.)hdlt\.me$ (^|\.)hd\.stheadline\.com$ (^|\.)hdtvb\.net$ (^|\.)hdzog\.com$ (^|\.)heartyit\.com$ (^|\.)heavy-r\.com$ (^|\.)hecaitou\.net$ (^|\.)hechaji\.com$ (^|\.)hec\.su$ (^|\.)heeact\.edu\.tw$ (^|\.)hegre-art\.com$ (^|\.)heix\.pp\.ru$ (^|\.)helloandroid\.com$ (^|\.)helloqueer\.com$ (^|\.)helloss\.pw$ (^|\.)hellotxt\.com$ (^|\.)hellouk\.org$ (^|\.)helpeachpeople\.com$ (^|\.)helplinfen\.com$ (^|\.)help\.linksalpha\.com$ (^|\.)helpster\.de$ (^|\.)helpzhuling\.org$ (^|\.)hentai\.to$ (^|\.)hentaitube\.tv$ (^|\.)hentaivideoworld\.com$ (^|\.)heqinglian\.net$ (^|\.)heungkongdiscuss\.com$ (^|\.)hexieshe\.com$ (^|\.)hexieshe\.xyz$ (^|\.)hexxeh\.net$ (^|\.)heyzo\.com$ (^|\.)hgseav\.com$ (^|\.)hhdcb3office\.org$ (^|\.)hhthesakyatrizin\.org$ (^|\.)hidden-advent\.org$ (^|\.)hidecloud\.com$ (^|\.)hidein\.net$ (^|\.)hideipvpn\.com$ (^|\.)hideman\.net$ (^|\.)hide\.me$ (^|\.)hideme\.nl$ (^|\.)hidemyass\.com$ (^|\.)hidemycomp\.com$ (^|\.)hidemy\.name$ (^|\.)higfw\.com$ (^|\.)highpeakspureearth\.com$ (^|\.)highrockmedia\.com$ (^|\.)hihiforum\.com$ (^|\.)hihistory\.net$ (^|\.)hiitch\.com$ (^|\.)hikinggfw\.org$ (^|\.)hilive\.tv$ (^|\.)himalayan-foundation\.org$ (^|\.)himalayanglacier\.com$ (^|\.)himemix\.com$ (^|\.)himemix\.net$ (^|\.)hi-on\.org\.tw$ (^|\.)hitbtc\.com$ (^|\.)hitomi\.la$ (^|\.)hiwifi\.com$ (^|\.)hizb-ut-tahrir\.info$ (^|\.)hizb-ut-tahrir\.org$ (^|\.)hizbuttahrir\.org$ (^|\.)hjclub\.info$ (^|\.)hk01\.com$ (^|\.)hk32168\.com$ (^|\.)hka8964\.wordpress\.com$ (^|\.)hkacg\.com$ (^|\.)hkacg\.net$ (^|\.)hkanews\.wordpress\.com$ (^|\.)hkatvnews\.com$ (^|\.)hkbc\.net$ (^|\.)hkbf\.org$ (^|\.)hkbookcity\.com$ (^|\.)hkchurch\.org$ (^|\.)hkci\.org\.hk$ (^|\.)hkcmi\.edu$ (^|\.)hkcnews\.com$ (^|\.)hkcoc\.com$ (^|\.)hkcoc\.weather\.com\.hk$ (^|\.)hkdailynews\.com\.hk$ (^|\.)hkday\.net$ (^|\.)hkdf\.org$ (^|\.)hkej\.com$ (^|\.)hkepc\.com$ (^|\.)hkfaa\.com$ (^|\.)hkfreezone\.com$ (^|\.)hk\.frienddy\.com$ (^|\.)hkfront\.org$ (^|\.)hkgalden\.com$ (^|\.)hk\.geocities\.com$ (^|\.)hkgolden\.com$ (^|\.)hk\.gradconnection\.com$ (^|\.)hkgreenradio\.org$ (^|\.)hk\.hao123img\.com$ (^|\.)hkheadline\.com$ (^|\.)hkhkhk\.com$ (^|\.)hkhrc\.org\.hk$ (^|\.)hkhrm\.org\.hk$ (^|\.)hkip\.org\.uk$ (^|\.)hkjc\.com$ (^|\.)hk\.jiepang\.com$ (^|\.)hkjp\.org$ (^|\.)hk\.knowledge\.yahoo\.com$ (^|\.)hklft\.com$ (^|\.)hklts\.org\.hk$ (^|\.)hk\.myblog\.yahoo\.com$ (^|\.)hk\.news\.yahoo\.com$ (^|\.)hkptu\.org$ (^|\.)hk-pub\.com$ (^|\.)hk\.rd\.yahoo\.com$ (^|\.)hkreporter\.com$ (^|\.)hkreporter\.loved\.hk$ (^|\.)hk\.search\.yahoo\.com$ (^|\.)hkupop\.hku\.hk$ (^|\.)hkusu\.net$ (^|\.)hk\.video\.news\.yahoo\.com$ (^|\.)hkvwet\.com$ (^|\.)hkwcc\.org\.hk$ (^|\.)hk\.yahoo\.com$ (^|\.)hkzone\.org$ (^|\.)h-moe\.com$ (^|\.)hmonghot\.com$ (^|\.)hmv\.co\.jp$ (^|\.)hmvdigital\.ca$ (^|\.)hmvdigital\.com$ (^|\.)hnjhj\.com$ (^|\.)hnntube\.com$ (^|\.)hola\.com$ (^|\.)hola\.org$ (^|\.)holymountaincn\.com$ (^|\.)holyspiritspeaks\.org$ (^|\.)homedepot\.com$ (^|\.)homeperversion\.com$ (^|\.)homeservershow\.com$ (^|\.)home\.sina\.com$ (^|\.)home\.so-net\.net\.tw$ (^|\.)hongkongfp\.com$ (^|\.)hongmeimei\.com$ (^|\.)hongzhi\.li$ (^|\.)hootsuite\.com$ (^|\.)hoovers\.com$ (^|\.)hopedialogue\.org$ (^|\.)hopto\.org$ (^|\.)hornygamer\.com$ (^|\.)hornytrip\.com$ (^|\.)hotav\.tv$ (^|\.)hotels\.cn$ (^|\.)hotfrog\.com\.tw$ (^|\.)hotgoo\.com$ (^|\.)hotpornshow\.com$ (^|\.)hotpot\.hk$ (^|\.)hotshame\.com$ (^|\.)hotspotshield\.com$ (^|\.)hotvpn\.com$ (^|\.)hougaige\.com$ (^|\.)howtoforge\.com$ (^|\.)hoxx\.com$ (^|\.)hpa\.gov\.tw$ (^|\.)hqcdp\.org$ (^|\.)hqjapanesesex\.com$ (^|\.)hqmovies\.com$ (^|\.)hqsbnet\.wordpress\.com$ (^|\.)hqsbonline\.wordpress\.com$ (^|\.)hrcchina\.org$ (^|\.)hrcir\.com$ (^|\.)hrea\.org$ (^|\.)hrichina\.org$ (^|\.)hrtsea\.com$ (^|\.)hrweb\.org$ (^|\.)hrw\.org$ (^|\.)hsjp\.net$ (^|\.)hsselite\.com$ (^|\.)hstern\.net$ (^|\.)hst\.net\.tw$ (^|\.)hstt\.net$ (^|\.)htkou\.net$ (^|\.)htl\.li$ (^|\.)ht\.ly$ (^|\.)html5rocks\.com$ (^|\.)https443\.net$ (^|\.)https443\.org$ (^|\.)huaglad\.com$ (^|\.)huanghuagang\.org$ (^|\.)huangyiyu\.com$ (^|\.)huaren4us\.com$ (^|\.)huaren\.us$ (^|\.)huashangnews\.com$ (^|\.)huaxiabao\.org$ (^|\.)huaxia-news\.com$ (^|\.)huaxin\.ph$ (^|\.)hua-yue\.net$ (^|\.)huayuworld\.org$ (^|\.)hudatoriq\.web\.id$ (^|\.)hudson\.org$ (^|\.)huffingtonpost\.com$ (^|\.)hugoroy\.eu$ (^|\.)huhaitai\.com$ (^|\.)huhamhire\.com$ (^|\.)huiyi\.in$ (^|\.)hulkshare\.com$ (^|\.)hulu\.com$ (^|\.)huluim\.com$ (^|\.)humanrightsbriefing\.org$ (^|\.)hungerstrikeforaids\.org$ (^|\.)hung-ya\.com$ (^|\.)huobi\.com$ (^|\.)huobi\.pro$ (^|\.)huobipro\.com$ (^|\.)huping\.net$ (^|\.)hurgokbayrak\.com$ (^|\.)hurriyet\.com\.tr$ (^|\.)hustlercash\.com$ (^|\.)hut2\.ru$ (^|\.)hutianyi\.net$ (^|\.)hutong9\.net$ (^|\.)huyandex\.com$ (^|\.)hwadzan\.tw$ (^|\.)hwayue\.org\.tw$ (^|\.)hwinfo\.com$ (^|\.)hxwk\.org$ (^|\.)hxwq\.org$ (^|\.)hybrid-analysis\.com$ (^|\.)hyperrate\.com$ (^|\.)i1\.hk$ (^|\.)i2p2\.de$ (^|\.)i2runner\.com$ (^|\.)i818hk\.com$ (^|\.)iam\.soy$ (^|\.)iamtopone\.com$ (^|\.)iask\.bz$ (^|\.)iask\.ca$ (^|\.)iav19\.com$ (^|\.)ibiblio\.org$ (^|\.)iblist\.com$ (^|\.)iblogserv-f\.net$ (^|\.)ibros\.org$ (^|\.)ibvpn\.com$ (^|\.)i-cable\.com$ (^|\.)icams\.com$ (^|\.)ice\.audionow\.com$ (^|\.)icij\.org$ (^|\.)icl-fi\.org$ (^|\.)icoco\.com$ (^|\.)iconpaper\.org$ (^|\.)icu-project\.org$ (^|\.)iddddg\.com$ (^|\.)idemocracy\.asia$ (^|\.)identi\.ca$ (^|\.)id\.hao123\.com$ (^|\.)id\.heroku\.com$ (^|\.)idiomconnection\.com$ (^|\.)idouga\.com$ (^|\.)idreamx\.com$ (^|\.)idv\.tw$ (^|\.)ieasy5\.com$ (^|\.)ied2k\.net$ (^|\.)ienergy1\.com$ (^|\.)ifan\.cz\.cc$ (^|\.)ifanqiang\.com$ (^|\.)ifcss\.org$ (^|\.)ifjc\.org$ (^|\.)ifreewares\.com$ (^|\.)if\.ttt$ (^|\.)ift\.tt$ (^|\.)igcd\.net$ (^|\.)igfw\.net$ (^|\.)igfw\.tech$ (^|\.)igmg\.de$ (^|\.)ignitedetroit\.net$ (^|\.)igoogle\.com$ (^|\.)igotmail\.com\.tw$ (^|\.)igvita\.com$ (^|\.)ihakka\.net$ (^|\.)ihao\.org$ (^|\.)iicns\.com$ (^|\.)iipdigital\.usembassy\.gov$ (^|\.)ikstar\.com$ (^|\.)ikwb\.com$ (^|\.)i\.lithium\.com$ (^|\.)illusionfactory\.com$ (^|\.)ilove80\.be$ (^|\.)ilovelongtoes\.com$ (^|\.)im88\.tw$ (^|\.)imageab\.com$ (^|\.)imagefap\.com$ (^|\.)imageflea\.com$ (^|\.)images\.comico\.tw$ (^|\.)images-gaytube\.com$ (^|\.)imageshack\.us$ (^|\.)imagevenue\.com$ (^|\.)imagezilla\.net$ (^|\.)imb\.org$ (^|\.)imdb\.com$ (^|\.)imgchili\.net$ (^|\.)img\.dlsite\.jp$ (^|\.)img\.ly$ (^|\.)imgmega\.com$ (^|\.)imgur\.com$ (^|\.)imkev\.com$ (^|\.)imlive\.com$ (^|\.)immigration\.gov\.tw$ (^|\.)immoral\.jp$ (^|\.)impact\.org\.au$ (^|\.)impp\.mn$ (^|\.)im\.tv$ (^|\.)in99\.org$ (^|\.)incapdns\.net$ (^|\.)incloak\.com$ (^|\.)incredibox\.fr$ (^|\.)indiandefensenews\.in$ (^|\.)indiemerch\.com$ (^|\.)in-disguise\.com$ (^|\.)info-graf\.fr$ (^|\.)initiativesforchina\.org$ (^|\.)inkui\.com$ (^|\.)inmediahk\.net$ (^|\.)innermongolia\.org$ (^|\.)inote\.tw$ (^|\.)insecam\.org$ (^|\.)insidevoa\.com$ (^|\.)instagram\.com$ (^|\.)instanthq\.com$ (^|\.)institut-tibetain\.org$ (^|\.)international-news\.newsmagazine\.asia$ (^|\.)internetdefenseleague\.org$ (^|\.)internetfreedom\.org$ (^|\.)internet\.org$ (^|\.)internetpopculture\.com$ (^|\.)inthenameofconfuciusmovie\.com$ (^|\.)investigating\.wordpress\.com$ (^|\.)inxian\.com$ (^|\.)iownyour\.biz$ (^|\.)iownyour\.org$ (^|\.)ipalter\.com$ (^|\.)i-part\.com\.tw$ (^|\.)ipfire\.org$ (^|\.)ipfs\.io$ (^|\.)iphone4hongkong\.com$ (^|\.)iphonehacks\.com$ (^|\.)iphonetaiwan\.org$ (^|\.)iphonix\.fr$ (^|\.)ipicture\.ru$ (^|\.)ipjetable\.net$ (^|\.)ipobar\.com$ (^|\.)ipoock\.com$ (^|\.)iportal\.me$ (^|\.)ippotv\.com$ (^|\.)ipredator\.se$ (^|\.)iptvbin\.com$ (^|\.)iptv\.com\.tw$ (^|\.)ipvanish\.com$ (^|\.)iredmail\.org$ (^|\.)ironbigfools\.compython\.net$ (^|\.)ironpython\.net$ (^|\.)ironsocket\.com$ (^|\.)isaacmao\.com$ (^|\.)is-a-hunter\.com$ (^|\.)isasecret\.com$ (^|\.)i-scmp\.com$ (^|\.)isc\.sans\.edu$ (^|\.)is\.gd$ (^|\.)isgreat\.org$ (^|\.)islahhaber\.net$ (^|\.)islamawareness\.net$ (^|\.)islamhouse\.com$ (^|\.)islamicity\.com$ (^|\.)islamicpluralism\.org$ (^|\.)islam\.org\.hk$ (^|\.)islamtoday\.net$ (^|\.)ismaelan\.com$ (^|\.)ismalltits\.com$ (^|\.)ismprofessional\.net$ (^|\.)isohunt\.com$ (^|\.)israbox\.com$ (^|\.)issuu\.com$ (^|\.)istars\.co\.nz$ (^|\.)istiqlalhewer\.com$ (^|\.)istockphoto\.com$ (^|\.)isunaffairs\.com$ (^|\.)isuntv\.com$ (^|\.)itaboo\.info$ (^|\.)itaiwan\.gov\.tw$ (^|\.)italiatibet\.org$ (^|\.)itasoftware\.com$ (^|\.)itemdb\.com$ (^|\.)ithelp\.ithome\.com\.tw$ (^|\.)itsaol\.com$ (^|\.)its\.caltech\.edu$ (^|\.)itshidden\.com$ (^|\.)itsky\.it$ (^|\.)itweet\.net$ (^|\.)iu45\.com$ (^|\.)iuhrdf\.org$ (^|\.)iuksky\.com$ (^|\.)ivacy\.com$ (^|\.)iverycd\.com$ (^|\.)ivpn\.net$ (^|\.)ixquick\.com$ (^|\.)ixxx\.com$ (^|\.)iyouport\.com$ (^|\.)izaobao\.us$ (^|\.)izlesem\.org$ (^|\.)izles\.net$ (^|\.)jamaat\.org$ (^|\.)jamyangnorbu\.com$ (^|\.)jandyx\.com$ (^|\.)janwongphoto\.com$ (^|\.)japanfirst\.asianfreeforum\.com$ (^|\.)japantimes\.co\.jp$ (^|\.)japan-whores\.com$ (^|\.)jav101\.com$ (^|\.)jav2be\.com$ (^|\.)jav68\.tv$ (^|\.)javakiba\.org$ (^|\.)javbus\.com$ (^|\.)jav\.com$ (^|\.)javfor\.me$ (^|\.)javhd\.com$ (^|\.)javhip\.com$ (^|\.)javhub\.net$ (^|\.)javhuge\.com$ (^|\.)javlibrary\.com$ (^|\.)javmobile\.net$ (^|\.)javmoo\.com$ (^|\.)javmoo\.xyz$ (^|\.)javseen\.com$ (^|\.)javtag\.com$ (^|\.)javzoo\.com$ (^|\.)ja\.wikipedia\.org$ (^|\.)jbtalks\.cc$ (^|\.)jbtalks\.com$ (^|\.)jbtalks\.my$ (^|\.)jcpenney\.com$ (^|\.)jdwsy\.com$ (^|\.)jeanyim\.com$ (^|\.)jetos\.com$ (^|\.)jex\.com$ (^|\.)jfqu36\.club$ (^|\.)jfqu37\.xyz$ (^|\.)jgoodies\.com$ (^|\.)jiangweiping\.com$ (^|\.)jiaoyou8\.com$ (^|\.)jiehua\.cz$ (^|\.)jieshibaobao\.com$ (^|\.)jigglegifs\.com$ (^|\.)jigong1024\.com$ (^|\.)jihadintel\.meforum\.org$ (^|\.)jihadology\.net$ (^|\.)jiji\.com$ (^|\.)jims\.net$ (^|\.)jinbushe\.org$ (^|\.)jingpin\.org$ (^|\.)jingsim\.org$ (^|\.)jinpianwang\.com$ (^|\.)jinroukong\.com$ (^|\.)jintian\.net$ (^|\.)jinx\.com$ (^|\.)jitouch\.com$ (^|\.)jizzthis\.com$ (^|\.)jjgirls\.com$ (^|\.)jkb\.cc$ (^|\.)jkforum\.net$ (^|\.)jkub\.com$ (^|\.)jma\.go\.jp$ (^|\.)j\.mp$ (^|\.)jmscult\.com$ (^|\.)joachims\.org$ (^|\.)jobnewera\.wordpress\.com$ (^|\.)jobso\.tv$ (^|\.)joinmastodon\.org$ (^|\.)journalchretien\.net$ (^|\.)journalofdemocracy\.org$ (^|\.)joymiihub\.com$ (^|\.)joyourself\.com$ (^|\.)jp\.hao123\.com$ (^|\.)jpl\.nasa\.gov$ (^|\.)jpopforum\.net$ (^|\.)jtvnw\.net$ (^|\.)jubushoushen\.com$ (^|\.)juhuaren\.com$ (^|\.)jukujo-club\.com$ (^|\.)juliepost\.com$ (^|\.)juliereyc\.com$ (^|\.)junauza\.com$ (^|\.)june4commemoration\.org$ (^|\.)junefourth-20\.net$ (^|\.)jungleheart\.com$ (^|\.)juoaa\.com$ (^|\.)justdied\.com$ (^|\.)justfreevpn\.com$ (^|\.)justicefortenzin\.org$ (^|\.)justpaste\.it$ (^|\.)justtristan\.com$ (^|\.)juyuange\.org$ (^|\.)juziyue\.com$ (^|\.)jwmusic\.org$ (^|\.)jyxf\.net$ (^|\.)kagyumonlam\.org$ (^|\.)kagyunews\.com\.hk$ (^|\.)kagyuoffice\.org$ (^|\.)kagyuoffice\.org\.tw$ (^|\.)kagyu\.org$ (^|\.)kagyu\.org\.za$ (^|\.)kaiyuan\.de$ (^|\.)kakao\.com$ (^|\.)kalachakralugano\.org$ (^|\.)kankan\.today$ (^|\.)kannewyork\.com$ (^|\.)kanshifang\.com$ (^|\.)kantie\.org$ (^|\.)kanzhongguo\.com$ (^|\.)kanzhongguo\.eu$ (^|\.)kaotic\.com$ (^|\.)karayou\.com$ (^|\.)karkhung\.com$ (^|\.)karmapa\.org$ (^|\.)karmapa-teachings\.org$ (^|\.)ka-wai\.com$ (^|\.)kawaiikawaii\.jp$ (^|\.)kawase\.com$ (^|\.)kba-tx\.org$ (^|\.)kb\.monitorware\.com$ (^|\.)kcoolonline\.com$ (^|\.)k-doujin\.net$ (^|\.)kebrum\.com$ (^|\.)kechara\.com$ (^|\.)keepandshare\.com$ (^|\.)keezmovies\.com$ (^|\.)kendatire\.com$ (^|\.)kendincos\.net$ (^|\.)kenengba\.com$ (^|\.)keontech\.net$ (^|\.)kepard\.com$ (^|\.)kex\.com$ (^|\.)keycdn\.com$ (^|\.)khabdha\.org$ (^|\.)khatrimaza\.org$ (^|\.)khmusic\.com\.tw$ (^|\.)kichiku-doujinko\.com$ (^|\.)kik\.com$ (^|\.)killwall\.com$ (^|\.)kindleren\.com$ (^|\.)kineox\.free\.fr$ (^|\.)kingdomsalvation\.org$ (^|\.)kinghost\.com$ (^|\.)kingstone\.com\.tw$ (^|\.)kink\.com$ (^|\.)kinmen\.org\.tw$ (^|\.)kinmen\.travel$ (^|\.)kinokuniya\.com$ (^|\.)kir\.jp$ (^|\.)kissbbao\.cn$ (^|\.)kiwi\.kz$ (^|\.)kkbox\.com$ (^|\.)kknews\.cc$ (^|\.)kk-whys\.co\.jp$ (^|\.)kmuh\.org\.tw$ (^|\.)knowledgerush\.com$ (^|\.)kobobooks\.com$ (^|\.)kobo\.com$ (^|\.)kodingen\.com$ (^|\.)kompozer\.net$ (^|\.)konachan\.com$ (^|\.)kone\.com$ (^|\.)koolsolutions\.com$ (^|\.)koornk\.com$ (^|\.)koranmandarin\.com$ (^|\.)korenan2\.com$ (^|\.)ksdl\.org$ (^|\.)ksnews\.com\.tw$ (^|\.)kspcoin\.com$ (^|\.)ktzhk\.com$ (^|\.)kucoin\.com$ (^|\.)kui\.name$ (^|\.)kun\.im$ (^|\.)kurashsultan\.com$ (^|\.)kurtmunger\.com$ (^|\.)kusocity\.com$ (^|\.)kwcg\.ca$ (^|\.)kwongwah\.com\.my$ (^|\.)kxsw\.life$ (^|\.)kyofun\.com$ (^|\.)kyohk\.net$ (^|\.)kyoyue\.com$ (^|\.)kyzyhello\.com$ (^|\.)kzeng\.info$ (^|\.)labiennale\.org$ (^|\.)ladbrokes\.com$ (^|\.)la-forum\.org$ (^|\.)lagranepoca\.com$ (^|\.)lalulalu\.com$ (^|\.)lama\.com\.tw$ (^|\.)lamayeshe\.com$ (^|\.)lamnia\.co\.uk$ (^|\.)lamrim\.com$ (^|\.)lanterncn\.cn$ (^|\.)lantosfoundation\.org$ (^|\.)laod\.cn$ (^|\.)laogai\.org$ (^|\.)laomiu\.com$ (^|\.)laoyang\.info$ (^|\.)laptoplockdown\.com$ (^|\.)laqingdan\.net$ (^|\.)larsgeorge\.com$ (^|\.)lastcombat\.com$ (^|\.)lastfm\.es$ (^|\.)latelinenews\.com$ (^|\.)latibet\.org$ (^|\.)lbank\.info$ (^|\.)ld\.hao123img\.com$ (^|\.)leafyvpn\.net$ (^|\.)lecloud\.net$ (^|\.)leeao\.com\.cn$ (^|\.)lefora\.com$ (^|\.)left21\.hk$ (^|\.)legalporno\.com$ (^|\.)legaltech\.law\.com$ (^|\.)legsjapan\.com$ (^|\.)leirentv\.ca$ (^|\.)leisurecafe\.ca$ (^|\.)leisurepro\.com$ (^|\.)lematin\.ch$ (^|\.)lemonde\.fr$ (^|\.)lenwhite\.com$ (^|\.)lerosua\.org$ (^|\.)lers\.google$ (^|\.)lesoir\.be$ (^|\.)letou\.com$ (^|\.)letscorp\.net$ (^|\.)le-vpn\.com$ (^|\.)lflink\.com$ (^|\.)lflinkup\.com$ (^|\.)lflinkup\.net$ (^|\.)lflinkup\.org$ (^|\.)lhakar\.org$ (^|\.)lhasocialwork\.org$ (^|\.)liangyou\.net$ (^|\.)liangzhichuanmei\.com$ (^|\.)lianyue\.net$ (^|\.)liaowangxizang\.net$ (^|\.)liberal\.org\.hk$ (^|\.)libertytimes\.com\.tw$ (^|\.)library\.usc\.cuhk\.edu\.hk$ (^|\.)lidecheng\.com$ (^|\.)lifemiles\.com$ (^|\.)lighten\.org\.tw$ (^|\.)lighti\.me$ (^|\.)lightnovel\.cn$ (^|\.)lightyearvpn\.com$ (^|\.)lihkg\.com$ (^|\.)like\.com$ (^|\.)limiao\.net$ (^|\.)line-apps\.com$ (^|\.)linear-abematv\.akamaized\.net$ (^|\.)line\.me$ (^|\.)line\.naver\.jp$ (^|\.)line-scdn\.net$ (^|\.)linglingfa\.com$ (^|\.)lingvodics\.com$ (^|\.)linkideo\.com$ (^|\.)link-o-rama\.com$ (^|\.)linkuswell\.com$ (^|\.)linux\.org\.hk$ (^|\.)linuxtoy\.org$ (^|\.)lionsroar\.com$ (^|\.)lipuman\.com$ (^|\.)liquidvpn\.com$ (^|\.)listentoyoutube\.com$ (^|\.)listorious\.com$ (^|\.)lists\.w3\.org$ (^|\.)liudejun\.com$ (^|\.)liuhanyu\.com$ (^|\.)liujianshu\.com$ (^|\.)liuxiaobo\.net$ (^|\.)liu-xiaobo\.org$ (^|\.)liuxiaotong\.com$ (^|\.)livecoin\.net$ (^|\.)livedoor\.jp$ (^|\.)liveleak\.com$ (^|\.)livestation\.com$ (^|\.)livestream\.com$ (^|\.)livevideo\.com$ (^|\.)livingonline\.us$ (^|\.)livingstream\.com$ (^|\.)liwangyang\.com$ (^|\.)lizhizhuangbi\.com$ (^|\.)lkcn\.net$ (^|\.)llss\.me$ (^|\.)load\.to$ (^|\.)lobsangwangyal\.com$ (^|\.)localbitcoins\.com$ (^|\.)localdomain\.ws$ (^|\.)localpresshk\.com$ (^|\.)lockestek\.com$ (^|\.)logbot\.net$ (^|\.)login\.target\.com$ (^|\.)logiqx\.com$ (^|\.)londonchinese\.ca$ (^|\.)longhair\.hk$ (^|\.)longmusic\.com$ (^|\.)longtermly\.net$ (^|\.)longtoes\.com$ (^|\.)lookpic\.com$ (^|\.)looktoronto\.com$ (^|\.)lotsawahouse\.org$ (^|\.)lotuslight\.org\.hk$ (^|\.)lotuslight\.org\.tw$ (^|\.)lovetvshow\.com$ (^|\.)lpsg\.com$ (^|\.)lrfz\.com$ (^|\.)lrip\.org$ (^|\.)lsd\.org\.hk$ (^|\.)lsforum\.net$ (^|\.)lsmchinese\.org$ (^|\.)lsmkorean\.org$ (^|\.)lsm\.org$ (^|\.)lsmradio\.com$ (^|\.)lsmwebcast\.com$ (^|\.)lsxszzg\.com$ (^|\.)ltn\.com\.tw$ (^|\.)luke54\.com$ (^|\.)luke54\.org$ (^|\.)lupm\.org$ (^|\.)lushstories\.com$ (^|\.)luxebc\.com$ (^|\.)lvhai\.org$ (^|\.)lvv2\.com$ (^|\.)lyfhk\.net$ (^|\.)lzmtnews\.org$ (^|\.)macgamestore\.com$ (^|\.)macrovpn\.com$ (^|\.)macts\.com\.tw$ (^|\.)mad-ar\.ch$ (^|\.)madewithcode\.com$ (^|\.)madonna-av\.com$ (^|\.)madrau\.com$ (^|\.)madthumbs\.com$ (^|\.)magazines\.sina\.com\.tw$ (^|\.)magic-net\.info$ (^|\.)mahabodhi\.org$ (^|\.)ma\.hao123\.com$ (^|\.)maiio\.net$ (^|\.)mail-archive\.com$ (^|\.)maildns\.xyz$ (^|\.)maiplus\.com$ (^|\.)maizhong\.org$ (^|\.)makemymood\.com$ (^|\.)makkahnewspaper\.com$ (^|\.)makzhou\.warehouse333\.com$ (^|\.)malaysiakini\.com$ (^|\.)mamingzhe\.com$ (^|\.)manchukuo\.net$ (^|\.)mangafox\.com$ (^|\.)mangafox\.me$ (^|\.)maniash\.com$ (^|\.)manicur4ik\.ru$ (^|\.)mansion\.com$ (^|\.)mansionpoker\.com$ (^|\.)manta\.com$ (^|\.)maplew\.com$ (^|\.)marc\.info$ (^|\.)marguerite\.su$ (^|\.)martau\.com$ (^|\.)martincartoons\.com$ (^|\.)martsangkagyuofficial\.org$ (^|\.)maruta\.be$ (^|\.)marxist\.com$ (^|\.)marxist\.net$ (^|\.)marxists\.org$ (^|\.)mash\.to$ (^|\.)maskedip\.com$ (^|\.)mastodon\.cloud$ (^|\.)mastodon\.host$ (^|\.)mastodon\.social$ (^|\.)matainja\.com$ (^|\.)material\.io$ (^|\.)mathable\.io$ (^|\.)mathiew-badimon\.com$ (^|\.)matome-plus\.com$ (^|\.)matome-plus\.net$ (^|\.)matsushimakaede\.com$ (^|\.)matters\.news$ (^|\.)mattwilcox\.net$ (^|\.)maturejp\.com$ (^|\.)maxing\.jp$ (^|\.)mayimayi\.com$ (^|\.)mcadforums\.com$ (^|\.)mcaf\.ee$ (^|\.)mcfog\.com$ (^|\.)mcreasite\.com$ (^|\.)md-t\.org$ (^|\.)meansys\.com$ (^|\.)mediachinese\.com$ (^|\.)mediafire\.com$ (^|\.)mediafreakcity\.com$ (^|\.)media\.nu\.nl$ (^|\.)media\.org\.hk$ (^|\.)medium\.com$ (^|\.)meetav\.com$ (^|\.)meetup\.com$ (^|\.)mefeedia\.com$ (^|\.)mefound\.com$ (^|\.)mega\.nz$ (^|\.)megaproxy\.com$ (^|\.)megarotic\.com$ (^|\.)megavideo\.com$ (^|\.)megurineluka\.com$ (^|\.)meirixiaochao\.com$ (^|\.)meltoday\.com$ (^|\.)me\.me$ (^|\.)memehk\.com$ (^|\.)meme\.yahoo\.com$ (^|\.)memorybbs\.com$ (^|\.)memrijttm\.org$ (^|\.)memri\.org$ (^|\.)mercatox\.com$ (^|\.)mercyprophet\.org$ (^|\.)mergersandinquisitions\.org$ (^|\.)meridian-trust\.org$ (^|\.)meripet\.biz$ (^|\.)meripet\.com$ (^|\.)merit-times\.com\.tw$ (^|\.)meshrep\.com$ (^|\.)mesotw\.com$ (^|\.)messenger\.com$ (^|\.)metacafe\.com$ (^|\.)metart\.com$ (^|\.)metarthunter\.com$ (^|\.)meteorshowersonline\.com$ (^|\.)metrohk\.com\.hk$ (^|\.)metrolife\.ca$ (^|\.)metroradio\.com\.hk$ (^|\.)meyou\.jp$ (^|\.)me\.youthwant\.com\.tw$ (^|\.)meyul\.com$ (^|\.)mfxmedia\.com$ (^|\.)mgoon\.com$ (^|\.)mgstage\.com$ (^|\.)mh4u\.org$ (^|\.)m\.hkgalden\.com$ (^|\.)mhradio\.org$ (^|\.)michaelanti\.com$ (^|\.)michaelmarketl\.com$ (^|\.)microvpn\.com$ (^|\.)middle-way\.net$ (^|\.)mihk\.hk$ (^|\.)mihr\.com$ (^|\.)mihua\.org$ (^|\.)mike\.cz\.cc$ (^|\.)mikesoltys\.com$ (^|\.)milph\.net$ (^|\.)milsurps\.com$ (^|\.)mimiai\.net$ (^|\.)mimivip\.com$ (^|\.)mimivv\.com$ (^|\.)mindrolling\.org$ (^|\.)minghui-a\.org$ (^|\.)minghui-b\.org$ (^|\.)minghui\.org$ (^|\.)minghui\.or\.kr$ (^|\.)minghui-school\.org$ (^|\.)minghuiyw\.wordpress\.com$ (^|\.)mingjinglishi\.com$ (^|\.)mingjingnews\.com$ (^|\.)mingjingtimes\.com$ (^|\.)mingpaocanada\.com$ (^|\.)mingpao\.com$ (^|\.)mingpaomonthly\.com$ (^|\.)mingpaonews\.com$ (^|\.)mingpaony\.com$ (^|\.)mingpaosf\.com$ (^|\.)mingpaotor\.com$ (^|\.)mingpaovan\.com$ (^|\.)mingshengbao\.com$ (^|\.)minhhue\.net$ (^|\.)miniforum\.org$ (^|\.)ministrybooks\.org$ (^|\.)minzhuhua\.net$ (^|\.)minzhuzhanxian\.com$ (^|\.)minzhuzhongguo\.org$ (^|\.)miroguide\.com$ (^|\.)mirrorbooks\.com$ (^|\.)mist\.vip$ (^|\.)mitao\.com\.tw$ (^|\.)mitbbsau\.com$ (^|\.)mitbbs\.com$ (^|\.)mixero\.com$ (^|\.)mixpod\.com$ (^|\.)mixx\.com$ (^|\.)mizzmona\.com$ (^|\.)mjib\.gov\.tw$ (^|\.)mjlsh\.usc\.cuhk\.edu\.hk$ (^|\.)mk5000\.com$ (^|\.)mlcool\.com$ (^|\.)mlzs\.work$ (^|\.)mmaaxx\.com$ (^|\.)mm-cg\.com$ (^|\.)m\.me$ (^|\.)mmmca\.com$ (^|\.)mnewstv\.com$ (^|\.)mobatek\.net$ (^|\.)mobile01\.com$ (^|\.)mobileways\.de$ (^|\.)mobypicture\.com$ (^|\.)moby\.to$ (^|\.)moeaic\.gov\.tw$ (^|\.)moeerolibrary\.com$ (^|\.)mofa\.gov\.tw$ (^|\.)mofaxiehui\.com$ (^|\.)mofos\.com$ (^|\.)mog\.com$ (^|\.)mohu\.club$ (^|\.)mohu\.ml$ (^|\.)mojim\.com$ (^|\.)mol\.gov\.tw$ (^|\.)molihua\.org$ (^|\.)mondex\.org$ (^|\.)moneyhome\.biz$ (^|\.)money-link\.com\.tw$ (^|\.)mo\.nightlife141\.com$ (^|\.)monitorchina\.org$ (^|\.)monster\.com$ (^|\.)moodyz\.com$ (^|\.)moonbbs\.com$ (^|\.)moonbingo\.com$ (^|\.)morningsun\.org$ (^|\.)moroneta\.com$ (^|\.)mos\.ru$ (^|\.)motherless\.com$ (^|\.)motiyun\.com$ (^|\.)motor4ik\.ru$ (^|\.)mousebreaker\.com$ (^|\.)movements\.org$ (^|\.)moviefap\.com$ (^|\.)mp3buscador\.com$ (^|\.)mp3ye\.eu$ (^|\.)mpettis\.com$ (^|\.)mpfinance\.com$ (^|\.)mpinews\.com$ (^|\.)m\.plixi\.com$ (^|\.)mponline\.hk$ (^|\.)mqxd\.org$ (^|\.)mrbasic\.com$ (^|\.)mrbonus\.com$ (^|\.)mrface\.com$ (^|\.)mrslove\.com$ (^|\.)mrtweet\.com$ (^|\.)msa-it\.org$ (^|\.)msguancha\.com$ (^|\.)msha\.gov$ (^|\.)m\.slandr\.net$ (^|\.)mswe1\.org$ (^|\.)m-team\.cc$ (^|\.)mthruf\.com$ (^|\.)mtw\.tl$ (^|\.)muchosucko\.com$ (^|\.)mullvad\.net$ (^|\.)multiply\.com$ (^|\.)multiproxy\.org$ (^|\.)multiupload\.com$ (^|\.)mummysgold\.com$ (^|\.)murmur\.tw$ (^|\.)musicade\.net$ (^|\.)muslimvideo\.com$ (^|\.)muzi\.com$ (^|\.)muzi\.net$ (^|\.)muzu\.tv$ (^|\.)mvdis\.gov\.tw$ (^|\.)mvg\.jp$ (^|\.)mx981\.com$ (^|\.)mx\.hao123\.com$ (^|\.)my03\.com$ (^|\.)myactimes\.com$ (^|\.)myanniu\.com$ (^|\.)myaudiocast\.com$ (^|\.)myav\.com\.tw$ (^|\.)mybbs\.us$ (^|\.)mybet\.com$ (^|\.)myca168\.com$ (^|\.)mycanadanow\.com$ (^|\.)mychinamyhome\.com$ (^|\.)mychinanet\.com$ (^|\.)mychinanews\.com$ (^|\.)mychinese\.news$ (^|\.)mycnnews\.com$ (^|\.)mycould\.com$ (^|\.)mydad\.info$ (^|\.)myddns\.com$ (^|\.)myeasytv\.com$ (^|\.)myeclipseide\.com$ (^|\.)my-formosa\.com$ (^|\.)myforum\.com\.hk$ (^|\.)myforum\.com\.uk$ (^|\.)myfreecams\.com$ (^|\.)myfreepaysite\.com$ (^|\.)myfreshnet\.com$ (^|\.)myftp\.info$ (^|\.)myftp\.name$ (^|\.)myiphide\.com$ (^|\.)mykomica\.org$ (^|\.)mylftv\.com$ (^|\.)my\.mail\.ru$ (^|\.)mymediarom\.com$ (^|\.)mymoe\.moe$ (^|\.)mymom\.info$ (^|\.)mymusic\.net\.tw$ (^|\.)mynetav\.net$ (^|\.)mynetav\.org$ (^|\.)mynumber\.org$ (^|\.)my\.opera\.com$ (^|\.)myparagliding\.com$ (^|\.)my\.pcloud\.com$ (^|\.)mypicture\.info$ (^|\.)mypop3\.net$ (^|\.)mypop3\.org$ (^|\.)mypopescu\.com$ (^|\.)my-private-network\.co\.uk$ (^|\.)my-proxy\.com$ (^|\.)myradio\.hk$ (^|\.)myreadingmanga\.info$ (^|\.)mysecondarydns\.com$ (^|\.)myshare\.url\.com\.tw$ (^|\.)mysinablog\.com$ (^|\.)mysite\.verizon\.net$ (^|\.)myspacecdn\.com$ (^|\.)myspace\.com$ (^|\.)mytalkbox\.com$ (^|\.)mytizi\.com$ (^|\.)mywww\.biz$ (^|\.)myz\.info$ (^|\.)naacoalition\.org$ (^|\.)naitik\.net$ (^|\.)nakido\.com$ (^|\.)nakuz\.com$ (^|\.)nalandabodhi\.org$ (^|\.)nalandawest\.org$ (^|\.)namgyalmonastery\.org$ (^|\.)namgyal\.org$ (^|\.)namsisi\.com$ (^|\.)nanyang\.com$ (^|\.)nanyangpost\.com$ (^|\.)nanzao\.com$ (^|\.)naol\.ca$ (^|\.)naol\.cc$ (^|\.)nat\.gov\.tw$ (^|\.)national-lottery\.co\.uk$ (^|\.)nationsonline\.org$ (^|\.)nationwide\.com$ (^|\.)nat\.moe$ (^|\.)naughtyamerica\.com$ (^|\.)navyfamily\.navy\.mil$ (^|\.)navyreserve\.navy\.mil$ (^|\.)naweeklytimes\.com$ (^|\.)nbtvpn\.com$ (^|\.)nccwatch\.org\.tw$ (^|\.)nch\.com\.tw$ (^|\.)ncn\.org$ (^|\.)nde\.de$ (^|\.)ndr\.de$ (^|\.)ned\.org$ (^|\.)nekoslovakia\.net$ (^|\.)nemesis2\.qx\.net$ (^|\.)neo-miracle\.com$ (^|\.)nepusoku\.com$ (^|\.)netbirds\.com$ (^|\.)netcolony\.com$ (^|\.)net-fits\.pro$ (^|\.)netflix\.com$ (^|\.)netme\.cc$ (^|\.)netsneak\.com$ (^|\.)network54\.com$ (^|\.)networkedblogs\.com$ (^|\.)networktunnel\.net$ (^|\.)neverforget8964\.org$ (^|\.)new-3lunch\.net$ (^|\.)new96\.ca$ (^|\.)new-akiba\.com$ (^|\.)newcenturymc\.com$ (^|\.)newcenturynews\.com$ (^|\.)newchen\.com$ (^|\.)newgrounds\.com$ (^|\.)newipnow\.com$ (^|\.)newlandmagazine\.com\.au$ (^|\.)newnews\.ca$ (^|\.)news100\.com\.tw$ (^|\.)newsancai\.com$ (^|\.)newschinacomment\.org$ (^|\.)newscn\.org$ (^|\.)news\.cnyes\.com$ (^|\.)newsdetox\.ca$ (^|\.)newsdh\.com$ (^|\.)news\.hk\.msn\.com$ (^|\.)news\.hkpeanut\.com$ (^|\.)news\.msn\.com\.tw$ (^|\.)news\.nationalgeographic\.com$ (^|\.)news\.now\.com$ (^|\.)news\.omy\.sg$ (^|\.)newspeak\.cc$ (^|\.)news\.seehua\.com$ (^|\.)news\.sina\.com\.hk$ (^|\.)news\.sina\.com\.tw$ (^|\.)news\.sinchew\.com\.my$ (^|\.)news\.singtao\.ca$ (^|\.)newstamago\.com$ (^|\.)newstapa\.org$ (^|\.)newstarnet\.com$ (^|\.)news\.tvb\.com$ (^|\.)news\.tvbs\.com\.tw$ (^|\.)news\.yahoo\.com$ (^|\.)newtaiwan\.com\.tw$ (^|\.)newtalk\.tw$ (^|\.)newyorktimes\.com$ (^|\.)nexon\.com$ (^|\.)next11\.co\.jp$ (^|\.)nextmag\.com\.tw$ (^|\.)nextmedia\.com$ (^|\.)nexton-net\.jp$ (^|\.)nexttv\.com\.tw$ (^|\.)nf\.id\.au$ (^|\.)nfjtyd\.com$ (^|\.)nflxext\.com$ (^|\.)nflximg\.com$ (^|\.)nflximg\.net$ (^|\.)nflxso\.net$ (^|\.)nflxvideo\.net$ (^|\.)nga\.mil$ (^|\.)ngensis\.com$ (^|\.)nhentai\.net$ (^|\.)nhi\.gov\.tw$ (^|\.)nhk-ondemand\.jp$ (^|\.)nic\.cz\.cc$ (^|\.)nic\.google$ (^|\.)nic\.gov$ (^|\.)nicovideo\.jp$ (^|\.)nighost\.org$ (^|\.)nikkei\.com$ (^|\.)ninecommentaries\.com$ (^|\.)ninjacloak\.com$ (^|\.)ninjaproxy\.ninja$ (^|\.)nintendium\.com$ (^|\.)ninth\.biz$ (^|\.)niu\.moe$ (^|\.)niusnews\.com$ (^|\.)njactb\.org$ (^|\.)njuice\.com$ (^|\.)nko\.navy\.mil$ (^|\.)nlfreevpn\.com$ (^|\.)nobelprize\.org$ (^|\.)nobel\.se$ (^|\.)nobodycanstop\.us$ (^|\.)nofile\.io$ (^|\.)no-ip\.org$ (^|\.)nokogiri\.org$ (^|\.)nokola\.com$ (^|\.)noodlevpn\.com$ (^|\.)norbulingka\.org$ (^|\.)nordstrom\.com$ (^|\.)nordstromimage\.com$ (^|\.)nordstromrack\.com$ (^|\.)nordvpn\.com$ (^|\.)notify\.dropboxapi\.com$ (^|\.)nottinghampost\.com$ (^|\.)novelasia\.com$ (^|\.)now\.com$ (^|\.)now\.im$ (^|\.)nownews\.com$ (^|\.)nowtorrents\.com$ (^|\.)noypf\.com$ (^|\.)npa\.go\.jp$ (^|\.)npa\.gov\.tw$ (^|\.)npnt\.me$ (^|\.)npsboost\.com$ (^|\.)nps\.gov$ (^|\.)nradio\.me$ (^|\.)nrk\.no$ (^|\.)ns01\.biz$ (^|\.)ns01\.info$ (^|\.)ns01\.us$ (^|\.)ns02\.biz$ (^|\.)ns02\.info$ (^|\.)ns02\.us$ (^|\.)ns1\.name$ (^|\.)ns2\.name$ (^|\.)ns3\.name$ (^|\.)nsc\.gov\.tw$ (^|\.)ntbk\.gov\.tw$ (^|\.)ntbna\.gov\.tw$ (^|\.)ntbt\.gov\.tw$ (^|\.)ntd\.tv$ (^|\.)ntdtv\.ca$ (^|\.)ntdtv\.co\.kr$ (^|\.)ntdtv\.com$ (^|\.)ntdtv\.cz$ (^|\.)ntdtvla\.com$ (^|\.)ntdtv\.org$ (^|\.)ntdtv\.ru$ (^|\.)ntrfun\.com$ (^|\.)ntsna\.gov\.tw$ (^|\.)nubiles\.net$ (^|\.)nuexpo\.com$ (^|\.)nukistream\.com$ (^|\.)nurgo-software\.com$ (^|\.)nusatrip\.com$ (^|\.)nutaku\.net$ (^|\.)nuuvem\.com$ (^|\.)nuvid\.com$ (^|\.)nuzcom\.com$ (^|\.)nvdst\.com$ (^|\.)nvquan\.org$ (^|\.)nvtongzhisheng\.org$ (^|\.)nwtca\.org$ (^|\.)nyaa\.eu$ (^|\.)nyaa\.si$ (^|\.)nydus\.ca$ (^|\.)nylon-angel\.com$ (^|\.)nylonstockingsonline\.com$ (^|\.)ny\.stgloballink\.com$ (^|\.)nytchina\.com$ (^|\.)nytcn\.me$ (^|\.)nytco\.com$ (^|\.)nyt\.com$ (^|\.)nytimes\.com$ (^|\.)nytimes\.map\.fastly\.net$ (^|\.)nytimg\.com$ (^|\.)nyti\.ms$ (^|\.)nytstyle\.com$ (^|\.)ny\.visiontimes\.com$ (^|\.)nzchinese\.com$ (^|\.)nzchinese\.net\.nz$ (^|\.)observechina\.net$ (^|\.)obutu\.com$ (^|\.)ocaspro\.com$ (^|\.)occupytiananmen\.com$ (^|\.)oclp\.hk$ (^|\.)ocreampies\.com$ (^|\.)ocry\.com$ (^|\.)october-review\.org$ (^|\.)oculuscdn\.com$ (^|\.)oculus\.com$ (^|\.)oex\.com$ (^|\.)offbeatchina\.com$ (^|\.)officeoftibet\.com$ (^|\.)ofile\.org$ (^|\.)ogaoga\.org$ (^|\.)ogate\.org$ (^|\.)oikos\.com\.tw$ (^|\.)oiktv\.com$ (^|\.)oizoblog\.com$ (^|\.)okayfreedom\.com$ (^|\.)okex\.com$ (^|\.)okk\.tw$ (^|\.)ok\.ru$ (^|\.)old-cat\.net$ (^|\.)old\.honeynet\.org$ (^|\.)old\.nabble\.com$ (^|\.)olumpo\.com$ (^|\.)olympicwatch\.org$ (^|\.)omgili\.com$ (^|\.)omni7\.jp$ (^|\.)omnitalk\.com$ (^|\.)omnitalk\.org$ (^|\.)on2\.com$ (^|\.)onapp\.com$ (^|\.)on\.cc$ (^|\.)onedrive\.live\.com$ (^|\.)onedumb\.com$ (^|\.)onejav\.com$ (^|\.)onion\.city$ (^|\.)onlinecha\.com$ (^|\.)online\.recoveryversion\.org$ (^|\.)onlineyoutube\.com$ (^|\.)onlytweets\.com$ (^|\.)onmoon\.com$ (^|\.)onmoon\.net$ (^|\.)onmypc\.biz$ (^|\.)onmypc\.info$ (^|\.)onmypc\.net$ (^|\.)onmypc\.org$ (^|\.)onmypc\.us$ (^|\.)onthehunt\.com$ (^|\.)ontrac\.com$ (^|\.)oopsforum\.com$ (^|\.)openallweb\.com$ (^|\.)open\.com\.hk$ (^|\.)opendemocracy\.net$ (^|\.)opendn\.xyz$ (^|\.)openervpn\.in$ (^|\.)openid\.net$ (^|\.)openleaks\.org$ (^|\.)openvpn\.net$ (^|\.)openvpn\.org$ (^|\.)openwebster\.com$ (^|\.)openwrt\.org\.cn$ (^|\.)opml\.radiotime\.com$ (^|\.)opus-gaming\.com$ (^|\.)organcare\.org\.tw$ (^|\.)organharvestinvestigation\.net$ (^|\.)organiccrap\.com$ (^|\.)orgasm\.com$ (^|\.)orgfree\.com$ (^|\.)orientaldaily\.com\.my$ (^|\.)orient-doll\.com$ (^|\.)orn\.jp$ (^|\.)orzistic\.org$ (^|\.)osfoora\.com$ (^|\.)otcbtc\.com$ (^|\.)otnd\.org$ (^|\.)otto\.de$ (^|\.)otzo\.com$ (^|\.)ourdearamy\.com$ (^|\.)ourhobby\.com$ (^|\.)oursogo\.com$ (^|\.)oursteps\.com\.au$ (^|\.)oursweb\.net$ (^|\.)ourtv\.hk$ (^|\.)overplay\.net$ (^|\.)oversea\.istarshine\.com$ (^|\.)owl\.li$ (^|\.)ow\.ly$ (^|\.)oyax\.com$ (^|\.)oyghan\.com$ (^|\.)ozchinese\.com$ (^|\.)ozvoice\.org$ (^|\.)ozxw\.com$ (^|\.)ozyoyo\.com$ (^|\.)pachosting\.com$ (^|\.)pacificpoker\.com$ (^|\.)packages\.debian\.org$ (^|\.)packetix\.net$ (^|\.)pacopacomama\.com$ (^|\.)padmanet\.com$ (^|\.)page2rss\.com$ (^|\.)page\.bid\.yahoo\.com$ (^|\.)pagodabox\.com$ (^|\.)palacemoon\.com$ (^|\.)paldengyal\.com$ (^|\.)paljorpublications\.com$ (^|\.)paltalk\.com$ (^|\.)panamapapers\.sueddeutsche\.de$ (^|\.)pandapow\.co$ (^|\.)pandapow\.net$ (^|\.)pandavpn-jp\.com$ (^|\.)pandora\.com$ (^|\.)pandora\.tv$ (^|\.)panluan\.net$ (^|\.)panoramio\.com$ (^|\.)pao-pao\.net$ (^|\.)paperb\.us$ (^|\.)paper\.li$ (^|\.)paradisehill\.cc$ (^|\.)paradisepoker\.com$ (^|\.)parkansky\.com$ (^|\.)partycasino\.com$ (^|\.)partypoker\.com$ (^|\.)passion\.com$ (^|\.)passiontimes\.hk$ (^|\.)pastebin\.com$ (^|\.)paste\.ee$ (^|\.)pastie\.org$ (^|\.)pbs\.org$ (^|\.)pbwiki\.com$ (^|\.)pbworks\.com$ (^|\.)pbxes\.com$ (^|\.)pbxes\.org$ (^|\.)pcanywhere\.net$ (^|\.)pcc\.gov\.tw$ (^|\.)pcdvd\.com\.tw$ (^|\.)pchome\.com\.tw$ (^|\.)pcij\.org$ (^|\.)pcstore\.com\.tw$ (^|\.)pct\.org\.tw$ (^|\.)pdetails\.com$ (^|\.)pdproxy\.com$ (^|\.)pds\.nasa\.gov$ (^|\.)peace\.ca$ (^|\.)peacefire\.org$ (^|\.)peacehall\.com$ (^|\.)pearlher\.org$ (^|\.)peeasian\.com$ (^|\.)pekingduck\.org$ (^|\.)pemulihan\.or\.id$ (^|\.)penchinese\.com$ (^|\.)penchinese\.net$ (^|\.)pengyulong\.com$ (^|\.)pen\.io$ (^|\.)penisbot\.com$ (^|\.)penthouse\.com$ (^|\.)pentoy\.hk$ (^|\.)peoplebookcafe\.com$ (^|\.)peoplenews\.tw$ (^|\.)peopo\.org$ (^|\.)percy\.in$ (^|\.)perfectgirls\.net$ (^|\.)perfectvpn\.net$ (^|\.)periscope\.tv$ (^|\.)persecutionblog\.com$ (^|\.)persiankitty\.com$ (^|\.)pfd\.org\.hk$ (^|\.)phapluan\.org$ (^|\.)phayul\.com$ (^|\.)philborges\.com$ (^|\.)philly\.com$ (^|\.)phmsociety\.org$ (^|\.)phncdn\.com$ (^|\.)phobos\.apple\.com$ (^|\.)phosphation13\.rssing\.com$ (^|\.)photodharma\.net$ (^|\.)photofocus\.com$ (^|\.)phuquocservices\.com$ (^|\.)picacomiccn\.com$ (^|\.)picacomic\.com$ (^|\.)picasaweb\.com$ (^|\.)picidae\.net$ (^|\.)picturedip\.com$ (^|\.)picturesocial\.com$ (^|\.)pictures\.playboy\.com$ (^|\.)pimg\.tw$ (^|\.)pin6\.com$ (^|\.)pin-cong\.com$ (^|\.)pincong\.rocks$ (^|\.)ping\.fm$ (^|\.)pinimg\.com$ (^|\.)pinkrod\.com$ (^|\.)pinoy-n\.com$ (^|\.)pinterest\.at$ (^|\.)pinterest\.ca$ (^|\.)pinterest\.co\.kr$ (^|\.)pinterest\.com$ (^|\.)pinterest\.co\.uk$ (^|\.)pinterest\.de$ (^|\.)pinterest\.dk$ (^|\.)pinterest\.fr$ (^|\.)pinterest\.jp$ (^|\.)pinterest\.nl$ (^|\.)pinterest\.se$ (^|\.)pioneer-worker\.forums-free\.com$ (^|\.)pipii\.tv$ (^|\.)piposay\.com$ (^|\.)piraattilahti\.org$ (^|\.)piring\.com$ (^|\.)pixelqi\.com$ (^|\.)pixiv\.net$ (^|\.)pixnet\.net$ (^|\.)pk\.com$ (^|\.)pki\.goog$ (^|\.)placemix\.com$ (^|\.)playboy\.com$ (^|\.)playboyplus\.com$ (^|\.)player\.fm$ (^|\.)playno1\.com$ (^|\.)playpcesor\.com$ (^|\.)plays\.com\.tw$ (^|\.)plm\.org\.hk$ (^|\.)plunder\.com$ (^|\.)plurk\.com$ (^|\.)plus28\.com$ (^|\.)plusbb\.com$ (^|\.)plus\.codes$ (^|\.)pmatehunter\.com$ (^|\.)pmates\.com$ (^|\.)po2b\.com$ (^|\.)pobieramy\.top$ (^|\.)podictionary\.com$ (^|\.)pokerstars\.com$ (^|\.)pokerstars\.net$ (^|\.)politicalchina\.org$ (^|\.)politicalconsultation\.org$ (^|\.)politiscales\.net$ (^|\.)poloniex\.com$ (^|\.)polymerhk\.com$ (^|\.)polymer-project\.org$ (^|\.)popo\.tw$ (^|\.)popvote\.hk$ (^|\.)popyard\.com$ (^|\.)popyard\.org$ (^|\.)porn2\.com$ (^|\.)porn5\.com$ (^|\.)pornbase\.org$ (^|\.)porn\.com$ (^|\.)pornerbros\.com$ (^|\.)pornhd\.com$ (^|\.)pornhost\.com$ (^|\.)pornhub\.com$ (^|\.)pornhubdeutsch\.net$ (^|\.)pornmm\.net$ (^|\.)pornoxo\.com$ (^|\.)pornrapidshare\.com$ (^|\.)pornsharing\.com$ (^|\.)pornsocket\.com$ (^|\.)pornstarclub\.com$ (^|\.)porntube\.com$ (^|\.)porntubenews\.com$ (^|\.)porntvblog\.com$ (^|\.)pornvisit\.com$ (^|\.)port25\.biz$ (^|\.)portablevpn\.nl$ (^|\.)poskotanews\.com$ (^|\.)post01\.com$ (^|\.)post76\.com$ (^|\.)post852\.com$ (^|\.)postadult\.com$ (^|\.)postimg\.org$ (^|\.)potato\.im$ (^|\.)potvpn\.com$ (^|\.)powerapple\.com$ (^|\.)power\.com$ (^|\.)powercx\.com$ (^|\.)powerphoto\.org$ (^|\.)prayforchina\.net$ (^|\.)premeforwindows7\.com$ (^|\.)premproxy\.com$ (^|\.)presentationzen\.com$ (^|\.)presidentlee\.tw$ (^|\.)prestige-av\.com$ (^|\.)pride\.google$ (^|\.)prism-break\.org$ (^|\.)prisoneralert\.com$ (^|\.)pritunl\.com$ (^|\.)privacybox\.de$ (^|\.)private\.com$ (^|\.)privateinternetaccess\.com$ (^|\.)privatepaste\.com$ (^|\.)privatetunnel\.com$ (^|\.)privatevpn\.com$ (^|\.)procopytips\.com$ (^|\.)prosiben\.de$ (^|\.)protonvpn\.com$ (^|\.)provideocoalition\.com$ (^|\.)provpnaccounts\.com$ (^|\.)proxfree\.com$ (^|\.)proxifier\.com$ (^|\.)proxomitron\.info$ (^|\.)proxpn\.com$ (^|\.)proxyanonimo\.es$ (^|\.)proxydns\.com$ (^|\.)proxylist\.org\.uk$ (^|\.)proxynetwork\.org\.uk$ (^|\.)proxypy\.net$ (^|\.)proxyroad\.com$ (^|\.)proxytunnel\.net$ (^|\.)proyectoclubes\.com$ (^|\.)prozz\.net$ (^|\.)psblog\.name$ (^|\.)pscp\.tv$ (^|\.)psiphon3\.com$ (^|\.)psiphon\.ca$ (^|\.)psiphon\.civisec\.org$ (^|\.)psiphontoday\.com$ (^|\.)pts\.org\.tw$ (^|\.)ptt\.cc$ (^|\.)pttvan\.org$ (^|\.)pubu\.com\.tw$ (^|\.)puffinbrowser\.com$ (^|\.)puffstore\.com$ (^|\.)pullfolio\.com$ (^|\.)pulse\.yahoo\.com$ (^|\.)punyu\.com$ (^|\.)pure18\.com$ (^|\.)pureconcepts\.net$ (^|\.)pureinsight\.org$ (^|\.)purepdf\.com$ (^|\.)purevpn\.com$ (^|\.)purplelotus\.org$ (^|\.)pursuestar\.com$ (^|\.)pushchinawall\.com$ (^|\.)pussyspace\.com$ (^|\.)putihome\.org$ (^|\.)putlocker\.com$ (^|\.)putty\.org$ (^|\.)puuko\.com$ (^|\.)pwned\.com$ (^|\.)python\.com$ (^|\.)python\.com\.tw$ (^|\.)pythonhackers\.com$ (^|\.)pytorch\.org$ (^|\.)qanote\.com$ (^|\.)qgirl\.com\.tw$ (^|\.)qhigh\.com$ (^|\.)qiandao\.today$ (^|\.)qiangyou\.org$ (^|\.)qidian\.ca$ (^|\.)qienkuen\.org$ (^|\.)qi-gong\.me$ (^|\.)qiwen\.lu$ (^|\.)qixianglu\.cn$ (^|\.)qkshare\.com$ (^|\.)qoos\.com$ (^|\.)qpoe\.com$ (^|\.)qq\.co\.za$ (^|\.)qstatus\.com$ (^|\.)qtrac\.eu$ (^|\.)qtweeter\.com$ (^|\.)quannengshen\.org$ (^|\.)quantumbooter\.net$ (^|\.)questvisual\.com$ (^|\.)quitccp\.net$ (^|\.)quitccp\.org$ (^|\.)quoracdn\.net$ (^|\.)quora\.com$ (^|\.)quran\.com$ (^|\.)quranexplorer\.com$ (^|\.)qusi8\.net$ (^|\.)qvodzy\.org$ (^|\.)qxbbs\.org$ (^|\.)qz\.com$ (^|\.)r18\.com$ (^|\.)radicalparty\.org$ (^|\.)radiko\.jp$ (^|\.)radioaustralia\.net\.au$ (^|\.)radiohilight\.net$ (^|\.)radiovaticana\.org$ (^|\.)radiovncr\.com$ (^|\.)rael\.org$ (^|\.)ra\.gg$ (^|\.)raggedbanner\.com$ (^|\.)raidcall\.com\.tw$ (^|\.)raidtalk\.com\.tw$ (^|\.)rainbowplan\.org$ (^|\.)raindrop\.io$ (^|\.)raizoji\.or\.jp$ (^|\.)ramcity\.com\.au$ (^|\.)rangwang\.biz$ (^|\.)rangzen\.com$ (^|\.)rangzen\.net$ (^|\.)rangzen\.org$ (^|\.)ranyunfei\.com$ (^|\.)rapbull\.net$ (^|\.)rapidgator\.net$ (^|\.)rapidmoviez\.com$ (^|\.)rapidvpn\.com$ (^|\.)rarbgprx\.org$ (^|\.)raremovie\.cc$ (^|\.)raremovie\.net$ (^|\.)rawgit\.com$ (^|\.)rawgithub\.com$ (^|\.)raw\.githubusercontent\.com$ (^|\.)razyboard\.com$ (^|\.)rcam\.target\.com$ (^|\.)rcinet\.ca$ (^|\.)rconversation\.blogs\.com$ (^|\.)rd\.com$ (^|\.)rdio\.com$ (^|\.)read01\.com$ (^|\.)read100\.com$ (^|\.)readingtimes\.com\.tw$ (^|\.)readmoo\.com$ (^|\.)readydown\.com$ (^|\.)realcourage\.org$ (^|\.)realforum\.zkiz\.com$ (^|\.)realitykings\.com$ (^|\.)realraptalk\.com$ (^|\.)realsexpass\.com$ (^|\.)rebatesrule\.net$ (^|\.)recordhistory\.org$ (^|\.)recovery\.org\.tw$ (^|\.)recoveryversion\.com\.tw$ (^|\.)redballoonsolidarity\.org$ (^|\.)redchinacn\.net$ (^|\.)redchinacn\.org$ (^|\.)redd\.it$ (^|\.)reddit\.com$ (^|\.)redditlist\.com$ (^|\.)redditmedia\.com$ (^|\.)redditstatic\.com$ (^|\.)redhotlabs\.com$ (^|\.)red-lang\.org$ (^|\.)redtube\.com$ (^|\.)referer\.us$ (^|\.)reflectivecode\.com$ (^|\.)registry\.google$ (^|\.)relaxbbs\.com$ (^|\.)relay\.com\.tw$ (^|\.)releaseinternational\.org$ (^|\.)religioustolerance\.org$ (^|\.)renminbao\.com$ (^|\.)renyurenquan\.org$ (^|\.)research\.jmsc\.hku\.hk$ (^|\.)resilio\.com$ (^|\.)retweeteffect\.com$ (^|\.)retweetist\.com$ (^|\.)retweetrank\.com$ (^|\.)reuters\.com$ (^|\.)reutersmedia\.net$ (^|\.)revleft\.com$ (^|\.)revver\.com$ (^|\.)rfachina\.com$ (^|\.)rfalive1\.akacast\.akamaistream\.net$ (^|\.)rfamobile\.org$ (^|\.)rfa\.org$ (^|\.)rfaweb\.org$ (^|\.)rferl\.org$ (^|\.)rfi\.fr$ (^|\.)rfi\.my$ (^|\.)rg3\.github\.io$ (^|\.)rightbtc\.com$ (^|\.)rigpa\.org$ (^|\.)riku\.me$ (^|\.)rileyguide\.com$ (^|\.)riseup\.net$ (^|\.)ritouki\.jp$ (^|\.)ritter\.vg$ (^|\.)rixcloud\.com$ (^|\.)rixcloud\.us$ (^|\.)rlwlw\.com$ (^|\.)rmjdw132\.info$ (^|\.)rmjdw\.com$ (^|\.)roadshow\.hk$ (^|\.)roboforex\.com$ (^|\.)robustnessiskey\.com$ (^|\.)rocket-inc\.net$ (^|\.)rocksdb\.org$ (^|\.)rojo\.com$ (^|\.)rolia\.net$ (^|\.)ronjoneswriter\.com$ (^|\.)roodo\.com$ (^|\.)rosechina\.net$ (^|\.)rotten\.com$ (^|\.)rsdlmonitor\.com$ (^|\.)rsf-chinese\.org$ (^|\.)rsf\.org$ (^|\.)rsgamen\.org$ (^|\.)rssmeme\.com$ (^|\.)rtalabel\.org$ (^|\.)rthk\.hk$ (^|\.)rthklive2-lh\.akamaihd\.net$ (^|\.)rthk\.org\.hk$ (^|\.)rti\.org\.tw$ (^|\.)rtycminnesota\.org$ (^|\.)ruanyifeng\.com$ (^|\.)rukor\.org$ (^|\.)runbtx\.com$ (^|\.)rushbee\.com$ (^|\.)ruten\.com\.tw$ (^|\.)rutube\.ru$ (^|\.)ruyiseek\.com$ (^|\.)rxhj\.net$ (^|\.)s1heng\.com$ (^|\.)s1\.nudezz\.com$ (^|\.)s1s1s1\.com$ (^|\.)s3\.amazonaws\.com$ (^|\.)s3-ap-northeast-1\.amazonaws\.com$ (^|\.)s3-ap-southeast-2\.amazonaws\.com$ (^|\.)s8forum\.com$ (^|\.)sacks\.com$ (^|\.)sacom\.hk$ (^|\.)sadistic-v\.com$ (^|\.)sadpanda\.us$ (^|\.)safervpn\.com$ (^|\.)safety\.google$ (^|\.)sa\.hao123\.com$ (^|\.)saintyculture\.com$ (^|\.)saiq\.me$ (^|\.)sakuralive\.com$ (^|\.)sakya\.org$ (^|\.)salvation\.org\.hk$ (^|\.)samair\.ru$ (^|\.)sambhota\.org$ (^|\.)sanmin\.com\.tw$ (^|\.)sapikachu\.net$ (^|\.)saveliuxiaobo\.com$ (^|\.)savemedia\.com$ (^|\.)savethedate\.foo$ (^|\.)savethesounds\.info$ (^|\.)savetibet\.de$ (^|\.)savetibet\.fr$ (^|\.)savetibet\.nl$ (^|\.)savetibet\.org$ (^|\.)savetibet\.ru$ (^|\.)savetibetstore\.org$ (^|\.)savevid\.com$ (^|\.)say2\.info$ (^|\.)sbme\.me$ (^|\.)sbs\.com\.au$ (^|\.)scache1\.vzw\.com$ (^|\.)scache2\.vzw\.com$ (^|\.)scache\.vzw\.com$ (^|\.)scasino\.com$ (^|\.)schema\.org$ (^|\.)sciencenets\.com$ (^|\.)scieron\.com$ (^|\.)scmpchinese\.com$ (^|\.)scmp\.com$ (^|\.)scramble\.io$ (^|\.)scribd\.com$ (^|\.)scriptspot\.com$ (^|\.)s-cute\.com$ (^|\.)s-dragon\.org$ (^|\.)seapuff\.com$ (^|\.)search\.aol\.com$ (^|\.)searchtruth\.com$ (^|\.)search\.xxx$ (^|\.)search\.yahoo\.co\.jp$ (^|\.)search\.yahoo\.com$ (^|\.)secretchina\.com$ (^|\.)secretgarden\.no$ (^|\.)secretsline\.biz$ (^|\.)secure\.hustler\.com$ (^|\.)secure\.logmein\.com$ (^|\.)secure\.raxcdn\.com$ (^|\.)securetunnel\.com$ (^|\.)securityinabox\.org$ (^|\.)securitykiss\.com$ (^|\.)seed4\.me$ (^|\.)seesmic\.com$ (^|\.)seevpn\.com$ (^|\.)seezone\.net$ (^|\.)sejie\.com$ (^|\.)sellclassics\.com$ (^|\.)sendsmtp\.com$ (^|\.)sendspace\.com$ (^|\.)servehttp\.com$ (^|\.)serveuser\.com$ (^|\.)serveusers\.com$ (^|\.)sesawe\.net$ (^|\.)sesawe\.org$ (^|\.)sethwklein\.net$ (^|\.)setn\.com$ (^|\.)settv\.com\.tw$ (^|\.)sevenload\.com$ (^|\.)sex-11\.com$ (^|\.)sex3\.com$ (^|\.)sex8\.cc$ (^|\.)sexandsubmission\.com$ (^|\.)sexbot\.com$ (^|\.)sex\.com$ (^|\.)sexhuang\.com$ (^|\.)sexhu\.com$ (^|\.)sexidude\.com$ (^|\.)sexinsex\.net$ (^|\.)sextvx\.com$ (^|\.)sexxxy\.biz$ (^|\.)sfileydy\.com$ (^|\.)sf\.net$ (^|\.)sfshibao\.com$ (^|\.)sftindia\.org$ (^|\.)sftuk\.org$ (^|\.)shadeyouvpn\.com$ (^|\.)shadow\.ma$ (^|\.)shadowsky\.xyz$ (^|\.)shadowsocks9\.com$ (^|\.)shadowsocks\.asia$ (^|\.)shadowsocks\.be$ (^|\.)shadowsocks\.com$ (^|\.)shadowsocks\.com\.hk$ (^|\.)shadowsocks\.org$ (^|\.)shadowsocks-r\.com$ (^|\.)shambalapost\.com$ (^|\.)shambhalasun\.com$ (^|\.)shangfang\.org$ (^|\.)shapeservices\.com$ (^|\.)share\.america\.gov$ (^|\.)sharebee\.com$ (^|\.)sharecool\.org$ (^|\.)share\.dmhy\.org$ (^|\.)share\.ovi\.com$ (^|\.)share\.youthwant\.com\.tw$ (^|\.)sharpdaily\.com\.hk$ (^|\.)sharpdaily\.hk$ (^|\.)sharpdaily\.tw$ (^|\.)shattered\.io$ (^|\.)shat-tibet\.com$ (^|\.)sheikyermami\.com$ (^|\.)shellfire\.de$ (^|\.)shenshou\.org$ (^|\.)shenyun\.com$ (^|\.)shenyunperformingarts\.org$ (^|\.)shenzhoufilm\.com$ (^|\.)sherabgyaltsen\.com$ (^|\.)shiatv\.net$ (^|\.)shicheng\.org$ (^|\.)shiksha\.com$ (^|\.)shinychan\.com$ (^|\.)shipcamouflage\.com$ (^|\.)shireyishunjian\.com$ (^|\.)shitaotv\.org$ (^|\.)shixiao\.org$ (^|\.)shizhao\.org$ (^|\.)shkspr\.mobi$ (^|\.)shodanhq\.com$ (^|\.)shooshtime\.com$ (^|\.)shop2000\.com\.tw$ (^|\.)shopping\.com$ (^|\.)showbiz\.omy\.sg$ (^|\.)showhaotu\.com$ (^|\.)showtime\.jp$ (^|\.)shutterstock\.com$ (^|\.)shwchurch3\.com$ (^|\.)shwchurch\.org$ (^|\.)siddharthasintent\.org$ (^|\.)sidelinesnews\.com$ (^|\.)sidelinessportseatery\.com$ (^|\.)sierrafriendsoftibet\.org$ (^|\.)sijihuisuo\.club$ (^|\.)sijihuisuo\.com$ (^|\.)sikaozhe1997\.github\.io$ (^|\.)silkbook\.com$ (^|\.)simbolostwitter\.com$ (^|\.)simplecd\.org$ (^|\.)simpleproductivityblog\.com$ (^|\.)sinchew\.com\.my$ (^|\.)singaporepools\.com\.sg$ (^|\.)singfortibet\.com$ (^|\.)singpao\.com\.hk$ (^|\.)singtao\.com$ (^|\.)singtaousa\.com$ (^|\.)sinoants\.com$ (^|\.)sinocast\.com$ (^|\.)sinocism\.com$ (^|\.)sino-monthly\.com$ (^|\.)sinomontreal\.ca$ (^|\.)sinonet\.ca$ (^|\.)sinopitt\.info$ (^|\.)sinoquebec\.com$ (^|\.)sipml5\.org$ (^|\.)sis001\.com$ (^|\.)sis001\.us$ (^|\.)sis\.xxx$ (^|\.)site2unblock\.com$ (^|\.)site90\.net$ (^|\.)sitebro\.tw$ (^|\.)sitekreator\.com$ (^|\.)siteks\.uk\.to$ (^|\.)sitemaps\.org$ (^|\.)six-degrees\.io$ (^|\.)sixth\.biz$ (^|\.)sjrt\.org$ (^|\.)sjum\.cn$ (^|\.)sketchappsources\.com$ (^|\.)skimtube\.com$ (^|\.)skybet\.com$ (^|\.)skyking\.com\.tw$ (^|\.)skyvegas\.com$ (^|\.)skyxvpn\.com$ (^|\.)slacker\.com$ (^|\.)slaytizle\.com$ (^|\.)sleazydream\.com$ (^|\.)slheng\.com$ (^|\.)slickvpn\.com$ (^|\.)slideshare\.net$ (^|\.)slinkset\.com$ (^|\.)slutload\.com$ (^|\.)slutmoonbeam\.com$ (^|\.)slyip\.com$ (^|\.)slyip\.net$ (^|\.)smartdnsproxy\.com$ (^|\.)smarthide\.com$ (^|\.)smchbooks\.com$ (^|\.)smh\.com\.au$ (^|\.)smhric\.org$ (^|\.)smith\.edu$ (^|\.)sm-miracle\.com$ (^|\.)smyxy\.org$ (^|\.)snapchat\.com$ (^|\.)snaptu\.com$ (^|\.)sndcdn\.com$ (^|\.)sneakme\.net$ (^|\.)snowlionpub\.com$ (^|\.)sobees\.com$ (^|\.)socialwhale\.com$ (^|\.)sockscap64\.com$ (^|\.)sockslist\.net$ (^|\.)socks-proxy\.net$ (^|\.)soc\.mil$ (^|\.)socrec\.org$ (^|\.)sodatea\.github\.io$ (^|\.)sod\.co\.jp$ (^|\.)softether\.co\.jp$ (^|\.)softether-download\.com$ (^|\.)softether\.org$ (^|\.)softfamous\.com$ (^|\.)softsmirror\.cf$ (^|\.)softwarebychuck\.com$ (^|\.)softwaredownload\.gitbooks\.io$ (^|\.)sogclub\.com$ (^|\.)sogrady\.me$ (^|\.)sohcradio\.com$ (^|\.)sohfrance\.org$ (^|\.)soh\.tw$ (^|\.)sokamonline\.com$ (^|\.)sokmil\.com$ (^|\.)solarsystem\.nasa\.gov$ (^|\.)solidaritetibet\.org$ (^|\.)solidfiles\.com$ (^|\.)somee\.com$ (^|\.)songjianjun\.com$ (^|\.)sonicbbs\.cc$ (^|\.)sonidodelaesperanza\.org$ (^|\.)sopcast\.com$ (^|\.)sopcast\.org$ (^|\.)sorazone\.net$ (^|\.)sorting-algorithms\.com$ (^|\.)sos\.org$ (^|\.)sosreader\.com$ (^|\.)sostibet\.org$ (^|\.)soubory\.com$ (^|\.)soulcaliburhentai\.net$ (^|\.)soul-plus\.net$ (^|\.)soumo\.info$ (^|\.)soundcloud\.com$ (^|\.)soundofhope\.kr$ (^|\.)soundofhope\.org$ (^|\.)soup\.io$ (^|\.)soupofmedia\.com$ (^|\.)sourceforge\.net$ (^|\.)sourcewadio\.com$ (^|\.)southnews\.com\.tw$ (^|\.)sowers\.org\.hk$ (^|\.)soylentnews\.org$ (^|\.)spaces\.hightail\.com$ (^|\.)spankbang\.com$ (^|\.)spankingtube\.com$ (^|\.)spankwire\.com$ (^|\.)spb\.com$ (^|\.)speakerdeck\.com$ (^|\.)specxinzl\.jigsy\.com$ (^|\.)speedify\.com$ (^|\.)spem\.at$ (^|\.)spencertipping\.com$ (^|\.)spendee\.com$ (^|\.)spicevpn\.com$ (^|\.)spideroak\.com$ (^|\.)spike\.com$ (^|\.)sports\.williamhill\.com$ (^|\.)spotflux\.com$ (^|\.)spotify\.com$ (^|\.)spreadshirt\.es$ (^|\.)spring4u\.info$ (^|\.)springboardplatform\.com$ (^|\.)sprite\.org$ (^|\.)sproutcore\.com$ (^|\.)sproxy\.info$ (^|\.)squirly\.info$ (^|\.)srcf\.ucam\.org$ (^|\.)srocket\.us$ (^|\.)ss7\.vzw\.com$ (^|\.)ss\.carryzhou\.com$ (^|\.)ssglobal\.co$ (^|\.)ssglobal\.me$ (^|\.)ssh91\.com$ (^|\.)ssl443\.org$ (^|\.)ss\.levyhsu\.com$ (^|\.)ss-link\.com$ (^|\.)ssl\.webpack\.de$ (^|\.)sspanel\.net$ (^|\.)sspro\.ml$ (^|\.)ss\.pythonic\.life$ (^|\.)ssrshare\.com$ (^|\.)ssr\.tools$ (^|\.)sss\.camp$ (^|\.)sstmlt\.moe$ (^|\.)sstmlt\.net$ (^|\.)stackoverflow\.com$ (^|\.)stage64\.hk$ (^|\.)standupfortibet\.org$ (^|\.)stanford\.edu$ (^|\.)starfishfx\.com$ (^|\.)starp2p\.com$ (^|\.)startpage\.com$ (^|\.)startuplivingchina\.com$ (^|\.)stat\.gov\.tw$ (^|\.)static01\.nyt\.com$ (^|\.)static\.comico\.tw$ (^|\.)static-economist\.com$ (^|\.)staticflickr\.com$ (^|\.)static\.shemalez\.com$ (^|\.)statueofdemocracy\.org$ (^|\.)stc\.com\.sa$ (^|\.)steamcommunity\.com$ (^|\.)steel-storm\.com$ (^|\.)steemit\.com$ (^|\.)steganos\.com$ (^|\.)steganos\.net$ (^|\.)stepchina\.com$ (^|\.)stephaniered\.com$ (^|\.)sthoo\.com$ (^|\.)stickam\.com$ (^|\.)stickeraction\.com$ (^|\.)stileproject\.com$ (^|\.)sto\.cc$ (^|\.)stoporganharvesting\.org$ (^|\.)stoptibetcrisis\.net$ (^|\.)storagenewsletter\.com$ (^|\.)store\.steampowered\.com$ (^|\.)stories\.google$ (^|\.)storify\.com$ (^|\.)stormmediagroup\.com$ (^|\.)storm\.mg$ (^|\.)stoweboyd\.com$ (^|\.)stranabg\.com$ (^|\.)straplessdildo\.com$ (^|\.)streamingthe\.net$ (^|\.)streema\.com$ (^|\.)strikingly\.com$ (^|\.)strongvpn\.com$ (^|\.)strongwindpress\.com$ (^|\.)studentsforafreetibet\.org$ (^|\.)student\.tw$ (^|\.)stumbleupon\.com$ (^|\.)stupidvideos\.com$ (^|\.)subacme\.rerouted\.org$ (^|\.)successfn\.com$ (^|\.)sugarsync\.com$ (^|\.)sugobbs\.com$ (^|\.)sugumiru18\.com$ (^|\.)suissl\.com$ (^|\.)sujiatun\.wordpress\.com$ (^|\.)sukebei\.nyaa\.si$ (^|\.)sulian\.me$ (^|\.)summify\.com$ (^|\.)sumrando\.com$ (^|\.)sun1911\.com$ (^|\.)sunmedia\.ca$ (^|\.)sunporno\.com$ (^|\.)sunskyforum\.com$ (^|\.)sunta\.com\.tw$ (^|\.)sunvpn\.net$ (^|\.)sunwinism\.joinbbs\.net$ (^|\.)suoluo\.org$ (^|\.)supchina\.com$ (^|\.)superfreevpn\.com$ (^|\.)superokayama\.com$ (^|\.)superpages\.com$ (^|\.)supervpn\.net$ (^|\.)superzooi\.com$ (^|\.)suppig\.net$ (^|\.)suprememastertv\.com$ (^|\.)surfeasy\.com$ (^|\.)surfeasy\.com\.au$ (^|\.)suroot\.com$ (^|\.)surrenderat20\.net$ (^|\.)sustainability\.google$ (^|\.)suyangg\.com$ (^|\.)svsfx\.com$ (^|\.)swagbucks\.com$ (^|\.)swissinfo\.ch$ (^|\.)swissvpn\.net$ (^|\.)switch1\.jp$ (^|\.)switchvpn\.net$ (^|\.)sydneytoday\.com$ (^|\.)sylfoundation\.org$ (^|\.)syncback\.com$ (^|\.)synergyse\.com$ (^|\.)sysresccd\.org$ (^|\.)sytes\.net$ (^|\.)szbbs\.net$ (^|\.)szetowah\.org\.hk$ (^|\.)t35\.com$ (^|\.)t66y\.com$ (^|\.)taa-usa\.org$ (^|\.)taaze\.tw$ (^|\.)tabtter\.jp$ (^|\.)tacc\.cwb\.gov\.tw$ (^|\.)tacem\.org$ (^|\.)taconet\.com\.tw$ (^|\.)taedp\.org\.tw$ (^|\.)tafm\.org$ (^|\.)tagwalk\.com$ (^|\.)tagwa\.org\.au$ (^|\.)tahr\.org\.tw$ (^|\.)taipei\.gov\.tw$ (^|\.)taipeisociety\.org$ (^|\.)taiwanbible\.com$ (^|\.)taiwancon\.com$ (^|\.)taiwandaily\.net$ (^|\.)taiwandc\.org$ (^|\.)taiwanjobs\.gov\.tw$ (^|\.)taiwanjustice\.com$ (^|\.)taiwanjustice\.net$ (^|\.)taiwankiss\.com$ (^|\.)taiwannation\.50webs\.com$ (^|\.)taiwannation\.com$ (^|\.)taiwannation\.com\.tw$ (^|\.)taiwanncf\.org\.tw$ (^|\.)taiwannews\.com\.tw$ (^|\.)taiwan-sex\.com$ (^|\.)taiwantp\.net$ (^|\.)taiwantt\.org\.tw$ (^|\.)taiwanus\.net$ (^|\.)taiwanyes\.com$ (^|\.)taiwanyes\.ning\.com$ (^|\.)talk853\.com$ (^|\.)talkboxapp\.com$ (^|\.)talkcc\.com$ (^|\.)talkonly\.net$ (^|\.)tamiaode\.tk$ (^|\.)tanc\.org$ (^|\.)tangben\.com$ (^|\.)tangren\.us$ (^|\.)taoism\.net$ (^|\.)taolun\.info$ (^|\.)tapanwap\.com$ (^|\.)tapatalk\.com$ (^|\.)tarr\.uspto\.gov$ (^|\.)tascn\.com\.au$ (^|\.)taup\.net$ (^|\.)taweet\.com$ (^|\.)tbcollege\.org$ (^|\.)tbicn\.org$ (^|\.)tbi\.org\.hk$ (^|\.)tbjyt\.org$ (^|\.)tbpic\.info$ (^|\.)tbrc\.org$ (^|\.)tbsec\.org$ (^|\.)tbskkinabalu\.page\.tl$ (^|\.)tbsmalaysia\.org$ (^|\.)tbsn\.org$ (^|\.)tbs-rainbow\.org$ (^|\.)tbsseattle\.org$ (^|\.)tbssqh\.org$ (^|\.)tbswd\.org$ (^|\.)tbtemple\.org\.uk$ (^|\.)tbthouston\.org$ (^|\.)tccwonline\.org$ (^|\.)tcewf\.org$ (^|\.)tchrd\.org$ (^|\.)tcnynj\.org$ (^|\.)t\.co$ (^|\.)tcpspeed\.co$ (^|\.)tcpspeed\.com$ (^|\.)tcsofbc\.org$ (^|\.)tcsovi\.org$ (^|\.)tdm\.com\.mo$ (^|\.)teachparentstech\.org$ (^|\.)teamamericany\.com$ (^|\.)tech2\.in\.com$ (^|\.)techviz\.net$ (^|\.)teck\.in$ (^|\.)teco-hk\.org$ (^|\.)teco-mo\.org$ (^|\.)teddysun\.com$ (^|\.)teeniefuck\.net$ (^|\.)teensinasia\.com$ (^|\.)telecomspace\.com$ (^|\.)telegram\.dog$ (^|\.)telegramdownload\.com$ (^|\.)telegram\.me$ (^|\.)telegram\.org$ (^|\.)telegraph\.co\.uk$ (^|\.)telesco\.pe$ (^|\.)tellme\.pw$ (^|\.)tenacy\.com$ (^|\.)tensorflow\.org$ (^|\.)tenzinpalmo\.com$ (^|\.)terminus2049\.github\.io$ (^|\.)tew\.org$ (^|\.)textnow\.me$ (^|\.)tfhub\.dev$ (^|\.)t-g\.com$ (^|\.)thaicn\.com$ (^|\.)thb\.gov\.tw$ (^|\.)theatrum-belli\.com$ (^|\.)thebcomplex\.com$ (^|\.)theblemish\.com$ (^|\.)thebobs\.com$ (^|\.)thebodyshop-usa\.com$ (^|\.)thecenter\.mit\.edu$ (^|\.)thechinabeat\.org$ (^|\.)thedalailamamovie\.com$ (^|\.)thedw\.us$ (^|\.)thefacebook\.com$ (^|\.)thefrontier\.hk$ (^|\.)thegioitinhoc\.vn$ (^|\.)thegly\.com$ (^|\.)thehots\.info$ (^|\.)thehousenews\.com$ (^|\.)thehun\.net$ (^|\.)theinitium\.com$ (^|\.)thenewslens\.com$ (^|\.)thepiratebay\.org$ (^|\.)theporndude\.com$ (^|\.)theportalwiki\.com$ (^|\.)thereallove\.kr$ (^|\.)therock\.net\.nz$ (^|\.)thespeeder\.com$ (^|\.)thestandnews\.com$ (^|\.)thetibetcenter\.org$ (^|\.)thetibetconnection\.org$ (^|\.)thetibetmuseum\.org$ (^|\.)thetibetpost\.com$ (^|\.)thetinhat\.com$ (^|\.)thetrotskymovie\.com$ (^|\.)thevivekspot\.com$ (^|\.)thewgo\.org$ (^|\.)theync\.com$ (^|\.)th\.hao123\.com$ (^|\.)thinkgeek\.com$ (^|\.)thinkingtaiwan\.com$ (^|\.)thinkwithgoogle\.com$ (^|\.)thisav\.com$ (^|\.)thlib\.org$ (^|\.)thomasbernhard\.org$ (^|\.)thongdreams\.com$ (^|\.)threatchaos\.com$ (^|\.)throughnightsfire\.com$ (^|\.)thumbzilla\.com$ (^|\.)thywords\.com$ (^|\.)thywords\.com\.tw$ (^|\.)tiananmenduizhi\.com$ (^|\.)tiananmenmother\.org$ (^|\.)tiananmenuniv\.com$ (^|\.)tiananmenuniv\.net$ (^|\.)tiandixing\.org$ (^|\.)tianhuayuan\.com$ (^|\.)tianlawoffice\.com$ (^|\.)tiantibooks\.org$ (^|\.)tianti\.io$ (^|\.)tianyantong\.org\.cn$ (^|\.)tianzhu\.org$ (^|\.)tibet3rdpole\.org$ (^|\.)tibetaction\.net$ (^|\.)tibetaid\.org$ (^|\.)tibetalk\.com$ (^|\.)tibetanaidproject\.org$ (^|\.)tibetan-alliance\.org$ (^|\.)tibetanarts\.org$ (^|\.)tibetanbuddhistinstitute\.org$ (^|\.)tibetancommunity\.org$ (^|\.)tibetancommunityuk\.net$ (^|\.)tibetanculture\.org$ (^|\.)tibetanfeministcollective\.org$ (^|\.)tibetan\.fr$ (^|\.)tibetanjournal\.com$ (^|\.)tibetanlanguage\.org$ (^|\.)tibetanliberation\.org$ (^|\.)tibetanpaintings\.com$ (^|\.)tibetanphotoproject\.com$ (^|\.)tibetanpoliticalreview\.org$ (^|\.)tibetanreview\.net$ (^|\.)tibetansports\.org$ (^|\.)tibetanwomen\.org$ (^|\.)tibetanyouthcongress\.org$ (^|\.)tibetanyouth\.org$ (^|\.)tibet\.a\.se$ (^|\.)tibet\.at$ (^|\.)tibet\.ca$ (^|\.)tibetcharity\.dk$ (^|\.)tibetcharity\.in$ (^|\.)tibetchild\.org$ (^|\.)tibetcity\.com$ (^|\.)tibetcollection\.com$ (^|\.)tibet\.com$ (^|\.)tibetcorps\.org$ (^|\.)tibet-envoy\.eu$ (^|\.)tibetexpress\.net$ (^|\.)tibetfocus\.com$ (^|\.)tibet-foundation\.org$ (^|\.)tibet\.fr$ (^|\.)tibetfund\.org$ (^|\.)tibetgermany\.com$ (^|\.)tibetgermany\.de$ (^|\.)tibethaus\.com$ (^|\.)tibetheritagefund\.org$ (^|\.)tibethouse\.jp$ (^|\.)tibethouse\.org$ (^|\.)tibet-house-trust\.co\.uk$ (^|\.)tibethouse\.us$ (^|\.)tibet-info\.net$ (^|\.)tibetinfonet\.net$ (^|\.)tibet-initiative\.de$ (^|\.)tibetjustice\.org$ (^|\.)tibetkomite\.dk$ (^|\.)tibetlibre\.free\.fr$ (^|\.)tibet-munich\.de$ (^|\.)tibetmuseum\.org$ (^|\.)tibet\.net$ (^|\.)tibetnetwork\.org$ (^|\.)tibet\.nu$ (^|\.)tibetoffice\.ch$ (^|\.)tibetoffice\.com\.au$ (^|\.)tibetoffice\.eu$ (^|\.)tibetoffice\.org$ (^|\.)tibetonline\.com$ (^|\.)tibetonline\.tv$ (^|\.)tibetoralhistory\.org$ (^|\.)tibet\.org$ (^|\.)tibet\.org\.tw$ (^|\.)tibetpolicy\.eu$ (^|\.)tibetrelieffund\.co\.uk$ (^|\.)tibetsites\.com$ (^|\.)tibet\.sk$ (^|\.)tibetsociety\.com$ (^|\.)tibetsun\.com$ (^|\.)tibetsupportgroup\.org$ (^|\.)tibetswiss\.ch$ (^|\.)tibettelegraph\.com$ (^|\.)tibettimes\.net$ (^|\.)tibet\.to$ (^|\.)tibetwrites\.org$ (^|\.)ticket\.com\.tw$ (^|\.)tigervpn\.com$ (^|\.)tiltbrush\.com$ (^|\.)timdir\.com$ (^|\.)time\.com$ (^|\.)times\.hinet\.net$ (^|\.)timesofindia\.indiatimes\.com$ (^|\.)timsah\.com$ (^|\.)tinc-vpn\.org$ (^|\.)tineye\.com$ (^|\.)tintuc101\.com$ (^|\.)tiny\.cc$ (^|\.)tinychat\.com$ (^|\.)tinypaste\.com$ (^|\.)tipo\.gov\.tw$ (^|\.)tistory\.com$ (^|\.)tkcs-collins\.com$ (^|\.)tl\.gd$ (^|\.)tma\.co\.jp$ (^|\.)tmagazine\.com$ (^|\.)tmdfish\.com$ (^|\.)t\.me$ (^|\.)tmi\.me$ (^|\.)tmpp\.org$ (^|\.)tn1\.shemalez\.com$ (^|\.)tn2\.shemalez\.com$ (^|\.)tn3\.shemalez\.com$ (^|\.)tnaflix\.com$ (^|\.)tngrnow\.com$ (^|\.)tngrnow\.net$ (^|\.)tnp\.org$ (^|\.)togetter\.com$ (^|\.)toh\.info$ (^|\.)tokyo-247\.com$ (^|\.)tokyocn\.com$ (^|\.)tokyo-hot\.com$ (^|\.)tokyo-porn-tube\.com$ (^|\.)tongil\.or\.kr$ (^|\.)tono-oka\.jp$ (^|\.)tonyyan\.net$ (^|\.)toodoc\.com$ (^|\.)toonel\.net$ (^|\.)top10vpn\.com$ (^|\.)top81\.ws$ (^|\.)topbtc\.com$ (^|\.)topic\.youthwant\.com\.tw$ (^|\.)topnews\.in$ (^|\.)to-porno\.com$ (^|\.)toppornsites\.com$ (^|\.)topshareware\.com$ (^|\.)topsy\.com$ (^|\.)toptip\.ca$ (^|\.)top\.tv$ (^|\.)tora\.to$ (^|\.)tor\.blingblingsquad\.net$ (^|\.)torcn\.com$ (^|\.)tor\.cn\.uptodown\.com$ (^|\.)torguard\.net$ (^|\.)torproject\.org$ (^|\.)torrentprivacy\.com$ (^|\.)torrentproject\.se$ (^|\.)torrenty\.org$ (^|\.)torrentz\.eu$ (^|\.)tor\.updatestar\.com$ (^|\.)torvpn\.com$ (^|\.)t\.orzdream\.com$ (^|\.)tosh\.comedycentral\.com$ (^|\.)totalvpn\.com$ (^|\.)toutiaoabc\.com$ (^|\.)toutyrater\.github\.io$ (^|\.)towngain\.com$ (^|\.)toypark\.in$ (^|\.)toythieves\.com$ (^|\.)toytractorshow\.com$ (^|\.)tparents\.org$ (^|\.)tpi\.org\.tw$ (^|\.)tracfone\.com$ (^|\.)traffichaus\.com$ (^|\.)transparency\.org$ (^|\.)trans\.wenweipo\.com$ (^|\.)treemall\.com\.tw$ (^|\.)trendsmap\.com$ (^|\.)trialofccp\.org$ (^|\.)trickip\.net$ (^|\.)trickip\.org$ (^|\.)trimondi\.de$ (^|\.)trouw\.nl$ (^|\.)trtc\.com\.tw$ (^|\.)trt\.net\.tr$ (^|\.)truebuddha-md\.org$ (^|\.)trulyergonomic\.com$ (^|\.)truth101\.co\.tv$ (^|\.)truthontour\.org$ (^|\.)truveo\.com$ (^|\.)tryheart\.jp$ (^|\.)tsctv\.net$ (^|\.)tsdr\.uspto\.gov$ (^|\.)tsemtulku\.com$ (^|\.)tsquare\.tv$ (^|\.)tsunagarumon\.com$ (^|\.)tsu\.org\.tw$ (^|\.)tt1069\.com$ (^|\.)tttan\.com$ (^|\.)ttvnw\.net$ (^|\.)tu8964\.com$ (^|\.)tubaholic\.com$ (^|\.)tube8\.com$ (^|\.)tube911\.com$ (^|\.)tube\.com$ (^|\.)tubecup\.com$ (^|\.)tubegals\.com$ (^|\.)tubeislam\.com$ (^|\.)tubepornclassic\.com$ (^|\.)tubestack\.com$ (^|\.)tubewolf\.com$ (^|\.)tuibeitu\.net$ (^|\.)tuidang\.net$ (^|\.)tuidang\.org$ (^|\.)tuidang\.se$ (^|\.)tui\.orzdream\.com$ (^|\.)tuitwit\.com$ (^|\.)tumblr\.com$ (^|\.)tumutanzi\.com$ (^|\.)tumview\.com$ (^|\.)tunein\.com$ (^|\.)tunnelbear\.com$ (^|\.)tunnelr\.com$ (^|\.)tuo8\.blue$ (^|\.)tuo8\.cc$ (^|\.)tuo8\.club$ (^|\.)tuo8\.fit$ (^|\.)tuo8\.hk$ (^|\.)tuo8\.in$ (^|\.)tuo8\.ninja$ (^|\.)tuo8\.org$ (^|\.)tuo8\.pw$ (^|\.)tuo8\.red$ (^|\.)tuo8\.space$ (^|\.)turansam\.org$ (^|\.)turbobit\.net$ (^|\.)turbohide\.com$ (^|\.)turbotwitter\.com$ (^|\.)turntable\.fm$ (^|\.)tushycash\.com$ (^|\.)tuvpn\.com$ (^|\.)tuzaijidi\.com$ (^|\.)tvants\.com$ (^|\.)tvboxnow\.com$ (^|\.)tv\.com$ (^|\.)tvider\.com$ (^|\.)tvmost\.com\.hk$ (^|\.)tvplayvideos\.com$ (^|\.)tvunetworks\.com$ (^|\.)tw01\.org$ (^|\.)twaitter\.com$ (^|\.)tw\.answers\.yahoo\.com$ (^|\.)twapperkeeper\.com$ (^|\.)twaud\.io$ (^|\.)twavi\.com$ (^|\.)twbbs\.net\.tw$ (^|\.)twbbs\.org$ (^|\.)twbbs\.tw$ (^|\.)tw\.bid\.yahoo\.com$ (^|\.)tw-blog\.com$ (^|\.)twblogger\.com$ (^|\.)tweepguide\.com$ (^|\.)tweeplike\.me$ (^|\.)tweepmag\.com$ (^|\.)tweepml\.org$ (^|\.)tweetbackup\.com$ (^|\.)tweetboard\.com$ (^|\.)tweetboner\.biz$ (^|\.)tweetcs\.com$ (^|\.)tweetdeck\.com$ (^|\.)tweetedtimes\.com$ (^|\.)tweetmylast\.fm$ (^|\.)tweetphoto\.com$ (^|\.)tweetrans\.com$ (^|\.)tweetree\.com$ (^|\.)tweets\.seraph\.me$ (^|\.)tweettunnel\.com$ (^|\.)tweetwally\.com$ (^|\.)tweetymail\.com$ (^|\.)tweez\.net$ (^|\.)twelve\.today$ (^|\.)twerkingbutt\.com$ (^|\.)twftp\.org$ (^|\.)tw\.gigacircle\.com$ (^|\.)twgreatdaily\.com$ (^|\.)tw\.hao123\.com$ (^|\.)twibase\.com$ (^|\.)twibble\.de$ (^|\.)twibbon\.com$ (^|\.)twibs\.com$ (^|\.)twicountry\.org$ (^|\.)twicsy\.com$ (^|\.)twiends\.com$ (^|\.)twifan\.com$ (^|\.)twiffo\.com$ (^|\.)twiggit\.org$ (^|\.)twilightsex\.com$ (^|\.)twilog\.org$ (^|\.)twimbow\.com$ (^|\.)twimg\.com$ (^|\.)twimg\.edgesuite\.net$ (^|\.)twindexx\.com$ (^|\.)twip\.me$ (^|\.)twipple\.jp$ (^|\.)tw\.iqiyi\.com$ (^|\.)twishort\.com$ (^|\.)twistar\.cc$ (^|\.)twisterio\.com$ (^|\.)twister\.net\.co$ (^|\.)twisternow\.com$ (^|\.)twistory\.net$ (^|\.)twit2d\.com$ (^|\.)twitbrowser\.net$ (^|\.)twitcause\.com$ (^|\.)twitchcdn\.net$ (^|\.)twitch\.tv$ (^|\.)twitgether\.com$ (^|\.)twitgoo\.com$ (^|\.)twitiq\.com$ (^|\.)twitlonger\.com$ (^|\.)twitmania\.com$ (^|\.)twitoaster\.com$ (^|\.)twitonmsn\.com$ (^|\.)twitpic\.com$ (^|\.)twitstat\.com$ (^|\.)twittbot\.net$ (^|\.)twitter4j\.org$ (^|\.)twitter\.com$ (^|\.)twittercounter\.com$ (^|\.)twitterfeed\.com$ (^|\.)twittergadget\.com$ (^|\.)twitter\.jp$ (^|\.)twitterkr\.com$ (^|\.)twittermail\.com$ (^|\.)twitterrific\.com$ (^|\.)twittertim\.es$ (^|\.)twitthat\.com$ (^|\.)twitturk\.com$ (^|\.)twitturly\.com$ (^|\.)twitvid\.com$ (^|\.)twitzap\.com$ (^|\.)twiyia\.com$ (^|\.)tw\.jiepang\.com$ (^|\.)tw\.knowledge\.yahoo\.com$ (^|\.)tw\.mall\.yahoo\.com$ (^|\.)tw\.mobi\.yahoo\.com$ (^|\.)tw\.money\.yahoo\.com$ (^|\.)tw\.myblog\.yahoo\.com$ (^|\.)tw\.news\.yahoo\.com$ (^|\.)twnorth\.org\.tw$ (^|\.)tw-npo\.org$ (^|\.)twskype\.com$ (^|\.)twstar\.net$ (^|\.)tw\.streetvoice\.com$ (^|\.)twtkr\.com$ (^|\.)tw\.tomonews\.net$ (^|\.)twtr2src\.ogaoga\.org$ (^|\.)twtrland\.com$ (^|\.)twt\.tl$ (^|\.)twttr\.com$ (^|\.)twurl\.nl$ (^|\.)tw\.voa\.mobi$ (^|\.)twyac\.org$ (^|\.)tw\.yahoo\.com$ (^|\.)txxx\.com$ (^|\.)tycool\.com$ (^|\.)typepad\.com$ (^|\.)u15\.info$ (^|\.)u9un\.com$ (^|\.)ub0\.cc$ (^|\.)ubddns\.org$ (^|\.)uberproxy\.net$ (^|\.)ucdc1998\.org$ (^|\.)uchicago\.edu$ (^|\.)uc-japan\.org$ (^|\.)uderzo\.it$ (^|\.)udnbkk\.com$ (^|\.)udn\.com$ (^|\.)udn\.com\.tw$ (^|\.)uforadio\.com\.tw$ (^|\.)ufreevpn\.com$ (^|\.)ugo\.com$ (^|\.)uhdwallpapers\.org$ (^|\.)uhrp\.org$ (^|\.)uighurbiz\.net$ (^|\.)uighur\.narod\.ru$ (^|\.)uighur\.nl$ (^|\.)ukcdp\.co\.uk$ (^|\.)ukliferadio\.co\.uk$ (^|\.)uku\.im$ (^|\.)ulike\.net$ (^|\.)ulop\.net$ (^|\.)ultravpn\.fr$ (^|\.)ultraxs\.com$ (^|\.)umich\.edu$ (^|\.)unblock\.cn\.com$ (^|\.)unblockdmm\.com$ (^|\.)unblocker\.yt$ (^|\.)unblocksit\.es$ (^|\.)unblock-us\.com$ (^|\.)uncyclomedia\.org$ (^|\.)uncyclopedia\.hk$ (^|\.)uncyclopedia\.tw$ (^|\.)underwoodammo\.com$ (^|\.)unholyknight\.com$ (^|\.)uni\.cc$ (^|\.)unification\.net$ (^|\.)unification\.org\.tw$ (^|\.)unirule\.cloud$ (^|\.)unitedsocialpress\.com$ (^|\.)unix100\.com$ (^|\.)unknownspace\.org$ (^|\.)unodedos\.com$ (^|\.)unpo\.org$ (^|\.)unseen\.is$ (^|\.)untraceable\.us$ (^|\.)uocn\.org$ (^|\.)upcoming\.yahoo\.com$ (^|\.)updates\.tdesktop\.com$ (^|\.)upholdjustice\.org$ (^|\.)upload4u\.info$ (^|\.)uploaded\.net$ (^|\.)uploaded\.to$ (^|\.)uploadstation\.com$ (^|\.)upmedia\.mg$ (^|\.)upornia\.com$ (^|\.)uproxy\.org$ (^|\.)upwill\.org$ (^|\.)ur7s\.com$ (^|\.)uraban\.me$ (^|\.)urbansurvival\.com$ (^|\.)urchin\.com$ (^|\.)urlborg\.com$ (^|\.)urlparser\.com$ (^|\.)usacn\.com$ (^|\.)usaip\.eu$ (^|\.)userapi\.nytlog\.com$ (^|\.)users\.skynet\.be$ (^|\.)usfk\.mil$ (^|\.)ushuarencity\.echainhost\.com$ (^|\.)usinfo\.state\.gov$ (^|\.)usma\.edu$ (^|\.)usmc\.mil$ (^|\.)usmgtcg\.ning\.com$ (^|\.)usno\.navy\.mil$ (^|\.)usocctn\.com$ (^|\.)us\.to$ (^|\.)ustream\.tv$ (^|\.)usunitednews\.com$ (^|\.)usus\.cc$ (^|\.)utopianpal\.com$ (^|\.)uu-gg\.com$ (^|\.)uukanshu\.com$ (^|\.)uvwxyz\.xyz$ (^|\.)uwants\.com$ (^|\.)uwants\.net$ (^|\.)uyghuramerican\.org$ (^|\.)uyghurcanadiansociety\.org$ (^|\.)uyghurcongress\.org$ (^|\.)uyghur\.co\.uk$ (^|\.)uyghurensemble\.co\.uk$ (^|\.)uyghur-j\.org$ (^|\.)uyghurpen\.org$ (^|\.)uyghurpress\.com$ (^|\.)uyghurstudies\.org$ (^|\.)uygur\.fc2web\.com$ (^|\.)uygur\.org$ (^|\.)uymaarip\.com$ (^|\.)v2ex\.com$ (^|\.)v2ray\.com$ (^|\.)van001\.com$ (^|\.)van698\.com$ (^|\.)vanemu\.cn$ (^|\.)vanilla-jp\.com$ (^|\.)vanpeople\.com$ (^|\.)vansky\.com$ (^|\.)vaticannews\.va$ (^|\.)vatn\.org$ (^|\.)vcfbuilder\.org$ (^|\.)vcf-online\.org$ (^|\.)vds\.rightster\.com$ (^|\.)vegasred\.com$ (^|\.)vegas\.williamhill\.com$ (^|\.)velkaepocha\.sk$ (^|\.)venbbs\.com$ (^|\.)venchina\.com$ (^|\.)venetianmacao\.com$ (^|\.)ventureswell\.com$ (^|\.)veoh\.com$ (^|\.)vermonttibet\.org$ (^|\.)versavpn\.com$ (^|\.)verybs\.com$ (^|\.)vevo\.com$ (^|\.)vft\.com\.tw$ (^|\.)viber\.com$ (^|\.)vica\.info$ (^|\.)victimsofcommunism\.org$ (^|\.)vidble\.com$ (^|\.)video\.aol\.ca$ (^|\.)video\.aol\.com$ (^|\.)video\.aol\.co\.uk$ (^|\.)video\.ap\.org$ (^|\.)videobam\.com$ (^|\.)videodetective\.com$ (^|\.)video\.fdbox\.com$ (^|\.)video\.foxbusiness\.com$ (^|\.)videomega\.tv$ (^|\.)videomo\.com$ (^|\.)video\.pbs\.org$ (^|\.)videopediaworld\.com$ (^|\.)videopress\.com$ (^|\.)video\.yahoo\.com$ (^|\.)vidinfo\.org$ (^|\.)vid\.me$ (^|\.)vietdaikynguyen\.com$ (^|\.)vijayatemple\.org$ (^|\.)vimeo\.com$ (^|\.)vimperator\.org$ (^|\.)vincnd\.com$ (^|\.)vine\.co$ (^|\.)vinniev\.com$ (^|\.)vip-enterprise\.com$ (^|\.)virtualrealporn\.com$ (^|\.)visibletweets\.com$ (^|\.)vital247\.org$ (^|\.)viu\.com$ (^|\.)viu\.tv$ (^|\.)vivahentai4u\.net$ (^|\.)vivatube\.com$ (^|\.)vivthomas\.com$ (^|\.)vizvaz\.com$ (^|\.)vjav\.com$ (^|\.)vjmedia\.com\.hk$ (^|\.)vllcs\.org$ (^|\.)vlog\.xuite\.net$ (^|\.)vmixcore\.com$ (^|\.)vmpsoft\.com$ (^|\.)vnet\.link$ (^|\.)vn\.hao123\.com$ (^|\.)voa-11\.akacast\.akamaistream\.net$ (^|\.)voacantonese\.com$ (^|\.)voachineseblog\.com$ (^|\.)voachinese\.com$ (^|\.)voagd\.com$ (^|\.)voanews\.com$ (^|\.)voatibetan\.com$ (^|\.)voatibetanenglish\.com$ (^|\.)vocativ\.com$ (^|\.)vocn\.tv$ (^|\.)vod-abematv\.akamaized\.net$ (^|\.)vod\.wwe\.com$ (^|\.)vot\.org$ (^|\.)vovo2000\.com$ (^|\.)voxer\.com$ (^|\.)voy\.com$ (^|\.)vpn4all\.com$ (^|\.)vpn\.ac$ (^|\.)vpnaccount\.org$ (^|\.)vpnaccounts\.com$ (^|\.)vpnbook\.com$ (^|\.)vpn\.cjb\.net$ (^|\.)vpn\.cmu\.edu$ (^|\.)vpncomparison\.org$ (^|\.)vpncoupons\.com$ (^|\.)vpncup\.com$ (^|\.)vpndada\.com$ (^|\.)vpnfan\.com$ (^|\.)vpnfire\.com$ (^|\.)vpnfires\.biz$ (^|\.)vpnforgame\.net$ (^|\.)vpngate\.jp$ (^|\.)vpngate\.net$ (^|\.)vpngratis\.net$ (^|\.)vpnhq\.com$ (^|\.)vpninja\.net$ (^|\.)vpnintouch\.com$ (^|\.)vpnintouch\.net$ (^|\.)vpnjack\.com$ (^|\.)vpnmaster\.com$ (^|\.)vpnmentor\.com$ (^|\.)vpnpick\.com$ (^|\.)vpnpop\.com$ (^|\.)vpnpronet\.com$ (^|\.)vpnreactor\.com$ (^|\.)vpnreviewz\.com$ (^|\.)vpnsecure\.me$ (^|\.)vpnshazam\.com$ (^|\.)vpnshieldapp\.com$ (^|\.)vpnsp\.com$ (^|\.)vpn\.sv\.cmu\.edu$ (^|\.)vpntraffic\.com$ (^|\.)vpntunnel\.com$ (^|\.)vpnuk\.info$ (^|\.)vpnunlimitedapp\.com$ (^|\.)vpnvip\.com$ (^|\.)vpnworldwide\.com$ (^|\.)vporn\.com$ (^|\.)vpser\.net$ (^|\.)vraiesagesse\.net$ (^|\.)vrmtr\.com$ (^|\.)vrsmash\.com$ (^|\.)vtunnel\.com$ (^|\.)vuku\.cc$ (^|\.)vultryhw\.com$ (^|\.)w3schools\.com$ (^|\.)waffle1999\.com$ (^|\.)wahas\.com$ (^|\.)waigaobu\.com$ (^|\.)waikeung\.org$ (^|\.)wailaike\.net$ (^|\.)waiwaier\.com$ (^|\.)wallmama\.com$ (^|\.)wallornot\.org$ (^|\.)wallpapercasa\.com$ (^|\.)wallproxy\.com$ (^|\.)waltermartin\.com$ (^|\.)waltermartin\.org$ (^|\.)wanderinghorse\.net$ (^|\.)wangafu\.net$ (^|\.)wangjinbo\.org$ (^|\.)wanglixiong\.com$ (^|\.)wango\.org$ (^|\.)wangruoshui\.net$ (^|\.)want-daily\.com$ (^|\.)wanz-factory\.com$ (^|\.)wapedia\.mobi$ (^|\.)warbler\.iconfactory\.net$ (^|\.)waselpro\.com$ (^|\.)washeng\.net$ (^|\.)washingtonpost\.com$ (^|\.)watch8x\.com$ (^|\.)watchinese\.com$ (^|\.)watchmygf\.net$ (^|\.)wattpad\.com$ (^|\.)waveprotocol\.org$ (^|\.)wav\.tv$ (^|\.)waymo\.com$ (^|\.)wda\.gov\.tw$ (^|\.)wdf5\.com$ (^|\.)wearehairy\.com$ (^|\.)wearn\.com$ (^|\.)web2project\.net$ (^|\.)webbang\.net$ (^|\.)web\.dev$ (^|\.)webevader\.org$ (^|\.)webfreer\.com$ (^|\.)webjb\.org$ (^|\.)weblagu\.com$ (^|\.)webmproject\.org$ (^|\.)webrtc\.org$ (^|\.)webrush\.net$ (^|\.)website\.informer\.com$ (^|\.)websitepulse\.com$ (^|\.)webs-tv\.net$ (^|\.)webwarper\.net$ (^|\.)webworkerdaily\.com$ (^|\.)weekmag\.info$ (^|\.)wefightcensorship\.org$ (^|\.)wefong\.com$ (^|\.)wego\.here\.com$ (^|\.)weiboleak\.com$ (^|\.)weiboscope\.jmsc\.hku\.hk$ (^|\.)weihuo\.org$ (^|\.)weijingsheng\.org$ (^|\.)weiming\.info$ (^|\.)weiquanwang\.org$ (^|\.)weisuo\.ws$ (^|\.)welovecock\.com$ (^|\.)wemigrate\.org$ (^|\.)wengewang\.com$ (^|\.)wengewang\.org$ (^|\.)wenhui\.ch$ (^|\.)wenxuecity\.com$ (^|\.)wenyunchao\.com$ (^|\.)wenzhao\.ca$ (^|\.)westca\.com$ (^|\.)westernshugdensociety\.org$ (^|\.)westernwolves\.com$ (^|\.)westkit\.net$ (^|\.)westpoint\.edu$ (^|\.)wetplace\.com$ (^|\.)wetpussygames\.com$ (^|\.)wexiaobo\.org$ (^|\.)wezhiyong\.org$ (^|\.)wezone\.net$ (^|\.)wforum\.com$ (^|\.)wha\.la$ (^|\.)whatblocked\.com$ (^|\.)whatbrowser\.org$ (^|\.)whatsapp\.com$ (^|\.)whatsapp\.net$ (^|\.)whatsonweibo\.com$ (^|\.)wheatseeds\.org$ (^|\.)wheelockslatin\.com$ (^|\.)whereiswerner\.com$ (^|\.)wheretowatch\.com$ (^|\.)whippedass\.com$ (^|\.)whitebear\.freebearblog\.org$ (^|\.)whodns\.xyz$ (^|\.)whoer\.net$ (^|\.)whotalking\.com$ (^|\.)whylover\.com$ (^|\.)whyx\.org$ (^|\.)w\.idaiwan\.com$ (^|\.)widevine\.com$ (^|\.)wikaba\.com$ (^|\.)wiki\.cnitter\.com$ (^|\.)wiki\.esu\.im$ (^|\.)wiki\.gamerp\.jp$ (^|\.)wiki\.jqueryui\.com$ (^|\.)wiki\.keso\.cn$ (^|\.)wikileaks\.ch$ (^|\.)wikileaks\.com$ (^|\.)wikileaks\.de$ (^|\.)wikileaks\.eu$ (^|\.)wikileaks-forum\.com$ (^|\.)wikileaks\.lu$ (^|\.)wikileaks\.org$ (^|\.)wikileaks\.pl$ (^|\.)wikilivres\.info$ (^|\.)wikimapia\.org$ (^|\.)wiki\.moegirl\.org$ (^|\.)wiki\.oauth\.net$ (^|\.)wikipedia\.org$ (^|\.)wiki\.phonegap\.com$ (^|\.)wikiwiki\.jp$ (^|\.)wildammo\.com$ (^|\.)williamhill\.com$ (^|\.)willw\.net$ (^|\.)windowsphoneme\.com$ (^|\.)windscribe\.com$ (^|\.)wingamestore\.com$ (^|\.)wingy\.site$ (^|\.)winning11\.com$ (^|\.)winwhispers\.info$ (^|\.)wire\.com$ (^|\.)wiredbytes\.com$ (^|\.)wiredpen\.com$ (^|\.)wisdompubs\.org$ (^|\.)wisevid\.com$ (^|\.)withgoogle\.com$ (^|\.)withyoutube\.com$ (^|\.)witnessleeteaching\.com$ (^|\.)witopia\.net$ (^|\.)wizcrafts\.net$ (^|\.)wjbk\.org$ (^|\.)wlcnew\.jigsy\.com$ (^|\.)wlx\.sowiki\.net$ (^|\.)wnacg\.com$ (^|\.)wnacg\.org$ (^|\.)wn\.com$ (^|\.)wo3ttt\.wordpress\.com$ (^|\.)woeser\.com$ (^|\.)woesermiddle-way\.net$ (^|\.)wokar\.org$ (^|\.)wolfax\.com$ (^|\.)woolyss\.com$ (^|\.)woopie\.jp$ (^|\.)woopie\.tv$ (^|\.)wordpress\.com$ (^|\.)workatruna\.com$ (^|\.)workerdemo\.org\.hk$ (^|\.)workerempowerment\.org$ (^|\.)workersthebig\.net$ (^|\.)worldcat\.org$ (^|\.)worldjournal\.com$ (^|\.)worldvpn\.net$ (^|\.)wo\.tc$ (^|\.)wow\.com$ (^|\.)wowgirls\.com$ (^|\.)wowlegacy\.ml$ (^|\.)wow-life\.net$ (^|\.)wowporn\.com$ (^|\.)wowrk\.com$ (^|\.)woxinghuiguo\.com$ (^|\.)woyaolian\.org$ (^|\.)wozy\.in$ (^|\.)wp\.com$ (^|\.)wpoforum\.com$ (^|\.)wqyd\.org$ (^|\.)wrchina\.org$ (^|\.)wretch\.cc$ (^|\.)writer\.zoho\.com$ (^|\.)wsgzao\.github\.io$ (^|\.)wsj\.com$ (^|\.)wsjhk\.com$ (^|\.)wsj\.net$ (^|\.)wtbn\.org$ (^|\.)wtfpeople\.com$ (^|\.)wuerkaixi\.com$ (^|\.)wufafangwen\.com$ (^|\.)wufi\.org\.tw$ (^|\.)wuguoguang\.com$ (^|\.)wujieliulan\.com$ (^|\.)wujie\.net$ (^|\.)wukangrui\.net$ (^|\.)wuw\.red$ (^|\.)wuyanblog\.com$ (^|\.)wwitv\.com$ (^|\.)www1\.american\.edu$ (^|\.)www1\.biz$ (^|\.)www2\.ohchr\.org$ (^|\.)www2\.rocketbbs\.com$ (^|\.)www\.abclite\.net$ (^|\.)www\.ajsands\.com$ (^|\.)www\.americorps\.gov$ (^|\.)www\.antd\.org$ (^|\.)www\.aolnews\.com$ (^|\.)www\.businessinsider\.com\.au$ (^|\.)www\.citizenlab\.org$ (^|\.)www\.cmoinc\.org$ (^|\.)www\.cool18\.com$ (^|\.)www\.dmm\.com$ (^|\.)www\.dwheeler\.com$ (^|\.)www\.eastturkistan\.net$ (^|\.)www\.gmiddle\.com$ (^|\.)www\.gmiddle\.net$ (^|\.)wwwhost\.biz$ (^|\.)www\.hustlercash\.com$ (^|\.)www\.idlcoyote\.com$ (^|\.)www\.imdb\.com$ (^|\.)www\.kindleren\.com$ (^|\.)www\.klip\.me$ (^|\.)www\.lamenhu\.com$ (^|\.)www\.lib\.virginia\.edu$ (^|\.)www\.linksalpha\.com$ (^|\.)www\.metro\.taipei$ (^|\.)www\.monlamit\.org$ (^|\.)www\.moztw\.org$ (^|\.)www\.m-sport\.co\.uk$ (^|\.)www\.nbc\.com$ (^|\.)www\.orchidbbs\.com$ (^|\.)www\.owind\.com$ (^|\.)www\.oxid\.it$ (^|\.)www\.powerpointninja\.com$ (^|\.)www\.s4miniarchive\.com$ (^|\.)www\.sciencemag\.org$ (^|\.)www\.shadowsocks\.com$ (^|\.)www\.shwchurch\.org$ (^|\.)www\.skype\.com$ (^|\.)www\.tablesgenerator\.com$ (^|\.)www\.taiwanonline\.cc$ (^|\.)www\.taup\.org\.tw$ (^|\.)www\.thechinastory\.org$ (^|\.)www\.wangruowang\.org$ (^|\.)www\.wan-press\.org$ (^|\.)www\.websnapr\.com$ (^|\.)www\.zensur\.freerk\.com$ (^|\.)wzyboy\.im$ (^|\.)x1949x\.com$ (^|\.)x24hr\.com$ (^|\.)x365x\.com$ (^|\.)xanga\.com$ (^|\.)x-art\.com$ (^|\.)xa\.yimg\.com$ (^|\.)xbabe\.com$ (^|\.)x-berry\.com$ (^|\.)xbookcn\.com$ (^|\.)xbtce\.com$ (^|\.)xcafe\.in$ (^|\.)xcity\.jp$ (^|\.)x\.company$ (^|\.)xcritic\.com$ (^|\.)xda-developers\.com$ (^|\.)xerotica\.com$ (^|\.)xfinity\.com$ (^|\.)xfm\.pp\.ru$ (^|\.)xgmyd\.com$ (^|\.)xhamster\.com$ (^|\.)xianba\.net$ (^|\.)xianchawang\.net$ (^|\.)xianjian\.tw$ (^|\.)xianqiao\.net$ (^|\.)xiaobaiwu\.com$ (^|\.)xiaochuncnjp\.com$ (^|\.)xiaod\.in$ (^|\.)xiaohexie\.com$ (^|\.)xiaolan\.me$ (^|\.)xiaoma\.org$ (^|\.)xiezhua\.com$ (^|\.)xihua\.es$ (^|\.)xijie\.wordpress\.com$ (^|\.)xing\.com$ (^|\.)xinhuanet\.org$ (^|\.)xinmiao\.com\.hk$ (^|\.)xinqimeng\.over-blog\.com$ (^|\.)xinsheng\.net$ (^|\.)xinshijue\.com$ (^|\.)xinyubbs\.net$ (^|\.)xiongpian\.com$ (^|\.)xiuren\.org$ (^|\.)xizang-zhiye\.org$ (^|\.)xjp\.cc$ (^|\.)xjtravelguide\.com$ (^|\.)xkiwi\.tk$ (^|\.)xlfmtalk\.com$ (^|\.)xlfmwz\.info$ (^|\.)xm\.com$ (^|\.)xml-training-guide\.com$ (^|\.)xmovies\.com$ (^|\.)xn--4gq171p\.com$ (^|\.)xn--czq75pvv1aj5c\.org$ (^|\.)xn--i2ru8q2qg\.com$ (^|\.)xn--ngstr-lra8j\.com$ (^|\.)xn--oiq\.cc$ (^|\.)xn--p8j9a0d9c9a\.xn--q9jyb4c$ (^|\.)xnxx\.com$ (^|\.)xpdo\.net$ (^|\.)xpud\.org$ (^|\.)xrentdvd\.com$ (^|\.)xskywalker\.com$ (^|\.)xskywalker\.net$ (^|\.)xtube\.com$ (^|\.)xuchao\.net$ (^|\.)xuchao\.org$ (^|\.)xuehua\.us$ (^|\.)xuzhiyong\.net$ (^|\.)xvideo\.cc$ (^|\.)xvideos\.com$ (^|\.)xvideos\.es$ (^|\.)x-wall\.org$ (^|\.)xxbbx\.com$ (^|\.)xxlmovies\.com$ (^|\.)xxuz\.com$ (^|\.)xxx\.com$ (^|\.)xxxfuckmom\.com$ (^|\.)xxxx\.com\.au$ (^|\.)xxx\.xxx$ (^|\.)xxxy\.biz$ (^|\.)xxxy\.info$ (^|\.)xxxymovies\.com$ (^|\.)xysblogs\.org$ (^|\.)xys\.dxiong\.com$ (^|\.)xys\.org$ (^|\.)xyy69\.com$ (^|\.)xyy69\.info$ (^|\.)yahoo\.com\.hk$ (^|\.)yakbutterblues\.com$ (^|\.)yam\.com$ (^|\.)yam\.org\.tw$ (^|\.)yanghengjun\.com$ (^|\.)yangjianli\.com$ (^|\.)yasni\.co\.uk$ (^|\.)yayabay\.com$ (^|\.)ydy\.com$ (^|\.)yeahteentube\.com$ (^|\.)yecl\.net$ (^|\.)yeelou\.com$ (^|\.)yeeyi\.com$ (^|\.)yegle\.net$ (^|\.)yes123\.com\.tw$ (^|\.)yesasia\.com$ (^|\.)yesasia\.com\.hk$ (^|\.)yes-news\.com$ (^|\.)yespornplease\.com$ (^|\.)yes\.xxx$ (^|\.)yeyeclub\.com$ (^|\.)ygto\.com$ (^|\.)yhcw\.net$ (^|\.)yibada\.com$ (^|\.)yibaochina\.com$ (^|\.)yidio\.com$ (^|\.)yigeni\.com$ (^|\.)yilubbs\.com$ (^|\.)yingsuoss\.com$ (^|\.)yinlei\.org$ (^|\.)yipub\.com$ (^|\.)yizhihongxing\.com$ (^|\.)yobit\.net$ (^|\.)yobt\.com$ (^|\.)yobt\.tv$ (^|\.)yogichen\.org$ (^|\.)yolasite\.com$ (^|\.)yomiuri\.co\.jp$ (^|\.)yong\.hu$ (^|\.)yorkbbs\.ca$ (^|\.)youdontcare\.com$ (^|\.)you-get\.org$ (^|\.)youjizz\.com$ (^|\.)youmaker\.com$ (^|\.)youngpornvideos\.com$ (^|\.)youngspiration\.hk$ (^|\.)youpai\.org$ (^|\.)youporn\.com$ (^|\.)youporngay\.com$ (^|\.)yourepeat\.com$ (^|\.)your-freedom\.net$ (^|\.)yourlisten\.com$ (^|\.)yourlust\.com$ (^|\.)yourprivatevpn\.com$ (^|\.)yourtrap\.com$ (^|\.)yousendit\.com$ (^|\.)youshun12\.com$ (^|\.)youthnetradio\.org$ (^|\.)youtu\.be$ (^|\.)youtubecn\.com$ (^|\.)youtube\.com$ (^|\.)youtubeeducation\.com$ (^|\.)youtubegaming\.com$ (^|\.)youtube-nocookie\.com$ (^|\.)youversion\.com$ (^|\.)youwin\.com$ (^|\.)youxu\.info$ (^|\.)yt\.be$ (^|\.)ytht\.net$ (^|\.)ytimg\.com$ (^|\.)ytn\.co\.kr$ (^|\.)yuanming\.net$ (^|\.)yuanzhengtang\.org$ (^|\.)yulghun\.com$ (^|\.)yunchao\.net$ (^|\.)yuntipub\.com$ (^|\.)yuvutu\.com$ (^|\.)yvesgeleyn\.com$ (^|\.)ywpw\.com$ (^|\.)yx51\.net$ (^|\.)yyii\.org$ (^|\.)yzzk\.com$ (^|\.)zacebook\.com$ (^|\.)zalmos\.com$ (^|\.)zannel\.com$ (^|\.)zaobao\.com$ (^|\.)zaobao\.com\.sg$ (^|\.)zaozon\.com$ (^|\.)zapto\.org$ (^|\.)zattoo\.com$ (^|\.)zb\.com$ (^|\.)zdnet\.com\.tw$ (^|\.)zello\.com$ (^|\.)zengjinyan\.org$ (^|\.)zenmate\.com$ (^|\.)zenmate\.com\.ru$ (^|\.)zeronet\.io$ (^|\.)zeutch\.com$ (^|\.)zfreet\.com$ (^|\.)zgsddh\.com$ (^|\.)zgzcjj\.net$ (^|\.)zhanbin\.net$ (^|\.)zhangboli\.net$ (^|\.)zhangtianliang\.com$ (^|\.)zhanlve\.org$ (^|\.)zhao\.1984\.city$ (^|\.)zhao\.jinhai\.de$ (^|\.)zh\.bitterwinter\.org$ (^|\.)zh\.ecdm\.wikia\.com$ (^|\.)zhenghui\.org$ (^|\.)zhengjian\.org$ (^|\.)zhengwunet\.org$ (^|\.)zhenlibu1984\.com$ (^|\.)zhenlibu\.info$ (^|\.)zhenxiang\.biz$ (^|\.)zhinengluyou\.com$ (^|\.)zhongguo\.ca$ (^|\.)zhongguorenquan\.org$ (^|\.)zhongguotese\.net$ (^|\.)zhongmeng\.org$ (^|\.)zhoushuguang\.com$ (^|\.)zh\.pokerstrategy\.com$ (^|\.)zh\.pttpedia\.wikia\.com$ (^|\.)zhreader\.com$ (^|\.)zhuangbi\.me$ (^|\.)zhuanxing\.cn$ (^|\.)zhuatieba\.com$ (^|\.)zhuichaguoji\.org$ (^|\.)zh\.uncyclopedia\.wikia\.com$ (^|\.)zh\.wikinews\.org$ (^|\.)zh\.wikisource\.org$ (^|\.)ziddu\.com$ (^|\.)zillionk\.com$ (^|\.)zim\.vn$ (^|\.)zinio\.com$ (^|\.)ziporn\.com$ (^|\.)zippyshare\.com$ (^|\.)zkaip\.com$ (^|\.)zmw\.cn$ (^|\.)zodgame\.us$ (^|\.)zomobo\.net$ (^|\.)zonaeuropa\.com$ (^|\.)zonghexinwen\.com$ (^|\.)zonghexinwen\.net$ (^|\.)zoogvpn\.com$ (^|\.)zootool\.com$ (^|\.)zoozle\.net$ (^|\.)zorrovpn\.com$ (^|\.)zozotown\.com$ (^|\.)zpn\.im$ (^|\.)zspeeder\.me$ (^|\.)zsrhao\.com$ (^|\.)zuobiao\.me$ (^|\.)zuo\.la$ (^|\.)zuola\.com$ (^|\.)zvereff\.com$ (^|\.)zynaima\.com$ (^|\.)zynamics\.com$ (^|\.)zyns\.com$ (^|\.)zyzc9\.com$ (^|\.)zzcartoon\.com$ (^|\.)zzcloud\.me$ (^|\.)zzux\.com$ ================================================ FILE: acl/local.acl ================================================ [reject_all] [white_list] 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.0.0.0/24 192.0.2.0/24 192.88.99.0/24 192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 224.0.0.0/4 240.0.0.0/4 255.255.255.255/32 ::1/128 fc00::/7 fe80::/10 ================================================ FILE: acl/server_block_chn.acl ================================================ # All IPs listed here will be blocked while the ss-server try to outbound. # Only IP is allowed, *NOT* domain name. # # The IPs bellow are all IPs in CHN. It'll block ss-server to access all # CHN hosts by command # `ss-server -s:: -p 8388 -k 123456 --acl acl/server_block_chn.acl` [outbound_block_list] 1.0.1.0/24 1.0.2.0/23 1.0.8.0/21 1.0.32.0/19 1.1.0.0/24 1.1.2.0/23 1.1.4.0/22 1.1.8.0/21 1.1.16.0/20 1.1.32.0/19 1.2.0.0/23 1.2.2.0/24 1.2.5.0/24 1.2.6.0/23 1.2.8.0/21 1.2.16.0/20 1.2.32.0/19 1.2.64.0/18 1.3.0.0/16 1.4.1.0/24 1.4.2.0/23 1.4.4.0/22 1.4.8.0/21 1.4.16.0/20 1.4.32.0/19 1.4.64.0/18 1.8.0.0/18 1.8.64.0/19 1.8.96.0/22 1.8.100.0/23 1.8.112.0/20 1.8.128.0/20 1.8.144.0/22 1.8.148.0/23 1.8.154.0/23 1.8.156.0/22 1.8.160.0/19 1.8.192.0/19 1.8.224.0/20 1.8.244.0/22 1.8.248.0/21 1.10.0.0/21 1.10.8.0/23 1.10.11.0/24 1.10.12.0/22 1.10.16.0/20 1.10.32.0/19 1.10.64.0/18 1.12.0.0/14 1.18.128.0/24 1.24.0.0/13 1.45.0.0/16 1.48.0.0/14 1.56.0.0/13 1.68.0.0/14 1.80.0.0/12 1.116.0.0/15 1.118.1.0/24 1.118.2.0/23 1.118.4.0/22 1.118.8.0/21 1.118.16.0/20 1.118.32.0/19 1.118.64.0/18 1.118.128.0/17 1.119.0.0/16 1.180.0.0/14 1.184.0.0/15 1.188.0.0/14 1.192.0.0/13 1.202.0.0/15 1.204.0.0/14 2.20.54.23/32 8.128.0.0/10 8.209.36.0/22 8.209.40.0/21 8.209.48.0/20 8.209.192.0/18 8.210.0.0/15 8.212.0.0/14 8.216.0.0/13 14.0.0.0/21 14.0.12.0/22 14.1.0.0/22 14.1.24.0/22 14.1.108.0/22 14.16.0.0/12 14.102.128.0/22 14.102.180.0/22 14.103.0.0/16 14.104.0.0/13 14.112.0.0/12 14.130.0.0/15 14.134.0.0/15 14.144.0.0/12 14.192.60.0/22 14.192.76.0/22 14.196.0.0/15 14.204.0.0/15 14.208.0.0/12 20.81.0.0/24 20.134.160.0/20 20.139.160.0/20 20.249.255.0/24 20.251.0.0/22 23.236.64.0/25 23.236.64.128/26 23.236.64.192/27 27.0.128.0/21 27.0.160.0/21 27.0.188.0/22 27.0.204.0/22 27.0.208.0/21 27.8.0.0/13 27.16.0.0/12 27.34.232.0/21 27.36.0.0/14 27.40.0.0/13 27.50.40.0/21 27.50.128.0/17 27.54.72.0/21 27.54.152.0/21 27.54.192.0/18 27.98.208.0/20 27.98.224.0/19 27.99.128.0/17 27.103.0.0/16 27.106.128.0/18 27.106.204.0/22 27.109.32.0/19 27.109.124.0/22 27.112.0.0/18 27.112.80.0/20 27.112.112.0/21 27.113.128.0/18 27.115.0.0/17 27.116.44.0/22 27.121.72.0/21 27.121.120.0/21 27.128.0.0/15 27.131.220.0/22 27.144.0.0/16 27.148.0.0/14 27.152.0.0/13 27.184.0.0/13 27.192.0.0/11 27.224.0.0/14 36.0.0.0/22 36.0.16.0/20 36.0.32.0/19 36.0.64.0/18 36.0.128.0/17 36.1.0.0/16 36.4.0.0/14 36.16.0.0/12 36.32.0.0/14 36.36.0.0/16 36.37.0.0/19 36.37.36.0/23 36.37.39.0/24 36.37.40.0/21 36.37.48.0/20 36.40.0.0/13 36.48.0.0/15 36.51.0.0/17 36.51.128.0/18 36.51.192.0/19 36.51.224.0/20 36.51.240.0/21 36.51.248.0/22 36.51.252.0/23 36.56.0.0/13 36.96.0.0/11 36.128.0.0/10 36.192.0.0/11 36.248.0.0/14 36.254.0.0/16 36.255.116.0/22 36.255.128.0/22 36.255.164.0/22 36.255.172.0/22 36.255.176.0/22 38.142.239.114/32 39.0.0.0/24 39.0.2.0/23 39.0.4.0/22 39.0.8.0/21 39.0.16.0/20 39.0.32.0/19 39.0.64.0/18 39.0.128.0/17 39.64.0.0/11 39.96.0.0/13 39.104.0.0/14 39.108.0.0/16 39.109.120.0/23 39.128.0.0/10 40.0.176.0/20 40.0.247.0/24 40.0.248.0/22 40.0.252.0/23 40.0.255.0/24 40.72.0.0/15 40.77.136.112/28 40.77.236.224/27 40.77.254.64/27 40.125.128.0/17 40.126.64.0/18 40.198.10.0/24 40.198.16.0/21 40.198.24.0/23 40.251.225.0/24 40.251.227.0/24 42.0.0.0/22 42.0.8.0/21 42.0.16.0/21 42.0.24.0/22 42.0.32.0/19 42.0.128.0/17 42.1.0.0/19 42.1.32.0/20 42.1.48.0/21 42.1.56.0/22 42.4.0.0/14 42.48.0.0/13 42.56.0.0/14 42.62.0.0/17 42.62.128.0/19 42.62.160.0/20 42.62.180.0/22 42.62.184.0/21 42.63.0.0/16 42.80.0.0/15 42.83.64.0/20 42.83.80.0/22 42.83.88.0/21 42.83.96.0/19 42.83.128.0/23 42.83.134.0/24 42.83.139.0/24 42.83.140.0/22 42.83.144.0/20 42.83.160.0/19 42.83.192.0/18 42.84.0.0/14 42.88.0.0/13 42.96.64.0/19 42.96.96.0/21 42.96.108.0/22 42.96.112.0/20 42.96.128.0/17 42.97.0.0/16 42.99.0.0/18 42.99.64.0/19 42.99.96.0/20 42.99.112.0/22 42.99.120.0/21 42.100.0.0/14 42.120.0.0/15 42.122.0.0/16 42.123.0.0/19 42.123.36.0/22 42.123.40.0/21 42.123.48.0/20 42.123.64.0/18 42.123.128.0/17 42.128.0.0/12 42.156.0.0/19 42.156.36.0/22 42.156.40.0/21 42.156.48.0/20 42.156.64.0/18 42.156.128.0/17 42.157.0.0/21 42.157.8.0/22 42.157.14.0/23 42.157.16.0/20 42.157.32.0/19 42.157.64.0/18 42.157.128.0/17 42.158.0.0/15 42.160.0.0/12 42.176.0.0/13 42.184.0.0/15 42.186.0.0/16 42.187.0.0/18 42.187.64.0/19 42.187.96.0/20 42.187.112.0/21 42.187.120.0/22 42.187.128.0/17 42.192.0.0/13 42.201.0.0/17 42.202.0.0/15 42.204.0.0/14 42.208.0.0/12 42.224.0.0/12 42.240.0.0/16 42.242.0.0/15 42.244.0.0/15 42.246.0.0/16 42.247.0.0/22 42.247.4.0/24 42.247.5.0/25 42.247.5.128/26 42.247.5.204/30 42.247.5.208/28 42.247.5.224/27 42.247.6.0/23 42.247.8.0/21 42.247.16.0/20 42.247.32.0/19 42.247.64.0/18 42.247.128.0/17 42.248.0.0/13 43.224.12.0/22 43.224.24.0/22 43.224.44.0/22 43.224.52.0/22 43.224.56.0/22 43.224.68.0/22 43.224.72.0/22 43.224.80.0/22 43.224.100.0/22 43.224.144.0/22 43.224.160.0/22 43.224.176.0/22 43.224.184.0/22 43.224.200.0/21 43.224.208.0/21 43.224.216.0/22 43.224.240.0/22 43.225.76.0/22 43.225.86.0/24 43.225.120.0/22 43.225.180.0/22 43.225.208.0/22 43.225.216.0/21 43.225.224.0/20 43.225.240.0/21 43.225.252.0/22 43.226.32.0/19 43.226.64.0/19 43.226.96.0/20 43.226.112.0/21 43.226.120.0/22 43.226.128.0/19 43.226.160.0/21 43.226.236.0/22 43.226.240.0/20 43.227.0.0/21 43.227.8.0/22 43.227.32.0/19 43.227.64.0/19 43.227.104.0/22 43.227.136.0/21 43.227.144.0/22 43.227.152.0/21 43.227.160.0/20 43.227.176.0/21 43.227.188.0/22 43.227.192.0/19 43.227.232.0/22 43.227.248.0/21 43.228.0.0/18 43.228.64.0/21 43.228.76.0/22 43.228.100.0/22 43.228.116.0/24 43.228.118.0/23 43.228.132.0/22 43.228.136.0/22 43.228.148.0/22 43.228.152.0/22 43.228.188.0/22 43.229.40.0/22 43.229.48.0/22 43.229.56.0/22 43.229.96.0/22 43.229.136.0/21 43.229.168.0/21 43.229.176.0/20 43.229.192.0/21 43.229.216.0/21 43.229.232.0/21 43.230.20.0/22 43.230.32.0/22 43.230.68.0/22 43.230.72.0/22 43.230.84.0/22 43.230.124.0/22 43.230.220.0/22 43.230.224.0/19 43.231.12.0/22 43.231.32.0/20 43.231.80.0/20 43.231.96.0/20 43.231.136.0/21 43.231.144.0/20 43.231.160.0/20 43.231.176.0/21 43.236.0.0/15 43.238.0.0/16 43.239.0.0/19 43.239.32.0/20 43.239.48.0/22 43.239.116.0/22 43.239.120.0/22 43.239.172.0/22 43.240.0.0/22 43.240.56.0/21 43.240.68.0/22 43.240.72.0/21 43.240.84.0/22 43.240.124.0/22 43.240.128.0/21 43.240.136.0/22 43.240.156.0/22 43.240.160.0/19 43.240.192.0/19 43.240.240.0/20 43.241.0.0/20 43.241.16.0/21 43.241.48.0/22 43.241.76.0/22 43.241.80.0/20 43.241.112.0/22 43.241.168.0/21 43.241.176.0/21 43.241.184.0/22 43.241.208.0/20 43.241.224.0/20 43.241.240.0/22 43.241.248.0/22 43.242.8.0/21 43.242.16.0/20 43.242.48.0/22 43.242.53.0/24 43.242.54.0/23 43.242.56.0/21 43.242.64.0/22 43.242.72.0/21 43.242.80.0/20 43.242.96.0/22 43.242.144.0/20 43.242.160.0/21 43.242.180.0/22 43.242.188.0/22 43.242.192.0/21 43.242.204.0/22 43.242.216.0/21 43.242.252.0/22 43.243.4.0/22 43.243.8.0/21 43.243.16.0/22 43.243.88.0/22 43.243.128.0/22 43.243.136.0/22 43.243.144.0/21 43.243.156.0/22 43.243.180.0/22 43.243.228.0/22 43.243.232.0/22 43.243.244.0/22 43.246.0.0/18 43.246.64.0/19 43.246.96.0/22 43.246.228.0/22 43.247.4.0/22 43.247.8.0/22 43.247.44.0/22 43.247.48.0/22 43.247.68.0/22 43.247.76.0/22 43.247.84.0/22 43.247.88.0/21 43.247.96.0/21 43.247.108.0/22 43.247.112.0/22 43.247.148.0/22 43.247.152.0/22 43.247.176.0/20 43.247.196.0/22 43.247.200.0/21 43.247.208.0/20 43.247.224.0/19 43.248.0.0/21 43.248.20.0/22 43.248.28.0/22 43.248.48.0/22 43.248.76.0/22 43.248.80.0/20 43.248.96.0/19 43.248.128.0/20 43.248.144.0/21 43.248.176.0/20 43.248.192.0/20 43.248.208.0/22 43.248.228.0/22 43.248.232.0/22 43.248.244.0/22 43.249.4.0/22 43.249.120.0/22 43.249.132.0/22 43.249.136.0/22 43.249.144.0/20 43.249.160.0/21 43.249.168.0/22 43.249.192.0/22 43.249.236.0/22 43.250.4.0/22 43.250.12.0/22 43.250.16.0/21 43.250.28.0/22 43.250.32.0/22 43.250.96.0/21 43.250.108.0/22 43.250.112.0/21 43.250.128.0/22 43.250.144.0/21 43.250.160.0/22 43.250.168.0/22 43.250.176.0/22 43.250.200.0/22 43.250.212.0/22 43.250.216.0/21 43.250.236.0/22 43.250.244.0/22 43.251.4.0/22 43.251.36.0/22 43.251.192.0/22 43.251.232.0/22 43.251.244.0/22 43.252.48.0/22 43.252.56.0/22 43.252.224.0/22 43.254.0.0/21 43.254.8.0/22 43.254.24.0/22 43.254.36.0/22 43.254.44.0/22 43.254.52.0/22 43.254.64.0/22 43.254.72.0/22 43.254.84.0/22 43.254.88.0/21 43.254.100.0/22 43.254.104.0/22 43.254.112.0/21 43.254.128.0/22 43.254.136.0/21 43.254.144.0/20 43.254.168.0/21 43.254.180.0/22 43.254.184.0/21 43.254.192.0/22 43.254.200.0/22 43.254.208.0/22 43.254.220.0/22 43.254.224.0/20 43.254.240.0/22 43.254.248.0/21 43.255.0.0/21 43.255.8.0/22 43.255.16.0/22 43.255.48.0/22 43.255.64.0/20 43.255.84.0/22 43.255.96.0/22 43.255.144.0/22 43.255.176.0/22 43.255.184.0/22 43.255.192.0/22 43.255.200.0/21 43.255.208.0/21 43.255.224.0/21 43.255.232.0/22 43.255.244.0/22 45.40.192.0/20 45.40.208.0/21 45.40.224.0/19 45.65.16.0/20 45.112.132.0/22 45.112.188.0/22 45.112.208.0/22 45.112.216.0/21 45.112.228.0/22 45.112.232.0/21 45.113.12.0/22 45.113.16.0/20 45.113.40.0/22 45.113.52.0/22 45.113.72.0/22 45.113.144.0/21 45.113.168.0/22 45.113.184.0/22 45.113.200.0/21 45.113.208.0/20 45.113.240.0/22 45.113.252.0/22 45.114.0.0/22 45.114.32.0/22 45.114.52.0/22 45.114.96.0/22 45.114.136.0/22 45.114.196.0/22 45.114.200.0/22 45.114.228.0/22 45.114.237.0/24 45.114.238.0/23 45.114.252.0/22 45.115.44.0/22 45.115.100.0/22 45.115.120.0/22 45.115.132.0/22 45.115.144.0/22 45.115.156.0/22 45.115.164.0/22 45.115.200.0/22 45.115.212.0/22 45.115.244.0/22 45.115.248.0/22 45.116.16.0/22 45.116.24.0/22 45.116.32.0/21 45.116.52.0/22 45.116.96.0/21 45.116.140.0/22 45.116.152.0/22 45.116.208.0/22 45.117.8.0/22 45.117.20.0/22 45.117.68.0/22 45.117.124.0/22 45.117.252.0/22 45.119.60.0/22 45.119.64.0/21 45.119.72.0/22 45.119.104.0/22 45.119.232.0/22 45.120.100.0/22 45.120.140.0/22 45.120.164.0/22 45.120.180.128/27 45.120.240.0/22 45.121.52.0/22 45.121.64.0/21 45.121.72.0/22 45.121.92.0/22 45.121.96.0/22 45.121.172.0/22 45.121.176.0/22 45.121.240.0/20 45.122.0.0/19 45.122.32.0/21 45.122.40.0/22 45.122.60.0/22 45.122.64.0/19 45.122.96.0/20 45.122.112.0/21 45.122.160.0/19 45.122.192.0/20 45.122.208.0/21 45.122.216.0/22 45.123.28.0/22 45.123.32.0/21 45.123.44.0/22 45.123.48.0/20 45.123.64.0/20 45.123.80.0/21 45.123.120.0/22 45.123.128.0/21 45.123.136.0/22 45.123.148.0/22 45.123.152.0/21 45.123.164.0/22 45.123.168.0/21 45.123.176.0/21 45.123.184.0/22 45.123.204.0/22 45.123.212.0/22 45.123.224.0/19 45.124.0.0/22 45.124.20.0/22 45.124.28.0/22 45.124.32.0/21 45.124.44.0/22 45.124.68.0/22 45.124.76.0/22 45.124.80.0/22 45.124.100.0/22 45.124.124.0/22 45.124.172.0/22 45.124.176.0/22 45.124.208.0/22 45.124.248.0/22 45.125.24.0/22 45.125.44.0/22 45.125.52.0/22 45.125.56.0/22 45.125.76.0/22 45.125.80.0/20 45.125.96.0/21 45.125.136.0/22 45.126.48.0/21 45.126.108.0/22 45.126.112.0/21 45.126.120.0/22 45.126.220.0/22 45.127.8.0/21 45.127.128.0/22 45.127.144.0/21 45.127.156.0/22 45.248.8.0/22 45.248.80.0/22 45.248.88.0/22 45.248.96.0/20 45.248.128.0/21 45.248.204.0/22 45.248.208.0/20 45.248.224.0/19 45.249.0.0/21 45.249.12.0/22 45.249.16.0/20 45.249.32.0/21 45.249.112.0/22 45.249.188.0/22 45.249.192.0/20 45.249.208.0/21 45.250.12.0/22 45.250.16.0/22 45.250.28.0/22 45.250.32.0/21 45.250.40.0/22 45.250.76.0/22 45.250.80.0/20 45.250.96.0/22 45.250.104.0/21 45.250.112.0/20 45.250.128.0/20 45.250.144.0/21 45.250.152.0/22 45.250.164.0/22 45.250.180.0/22 45.250.184.0/21 45.250.192.0/22 45.251.0.0/22 45.251.8.0/22 45.251.16.0/21 45.251.52.0/22 45.251.84.0/22 45.251.88.0/21 45.251.96.0/21 45.251.120.0/21 45.251.137.0/24 45.251.138.0/23 45.251.140.0/22 45.251.144.0/20 45.251.160.0/19 45.251.192.0/19 45.251.224.0/22 45.252.0.0/19 45.252.32.0/20 45.252.48.0/22 45.252.84.0/22 45.252.88.0/21 45.252.96.0/19 45.252.128.0/19 45.252.160.0/20 45.252.176.0/22 45.252.192.0/19 45.252.224.0/21 45.252.232.0/22 45.253.0.0/18 45.253.64.0/20 45.253.80.0/21 45.253.92.0/22 45.253.96.0/20 45.253.112.0/21 45.253.120.0/22 45.253.130.0/23 45.253.132.0/22 45.253.136.0/21 45.253.144.0/20 45.253.160.0/19 45.253.192.0/19 45.253.224.0/20 45.253.240.0/22 45.254.0.0/20 45.254.16.0/21 45.254.28.0/22 45.254.40.0/22 45.254.48.0/20 45.254.64.0/18 45.254.128.0/18 45.254.192.0/19 45.254.224.0/21 45.254.236.0/22 45.254.240.0/22 45.254.248.0/22 45.255.0.0/18 45.255.64.0/19 45.255.96.0/20 45.255.112.0/21 45.255.120.0/22 45.255.136.0/21 45.255.144.0/20 45.255.160.0/19 45.255.192.0/19 45.255.224.0/20 45.255.240.0/21 45.255.248.0/22 46.248.24.0/23 47.92.0.0/14 47.96.0.0/11 49.4.0.0/14 49.51.56.0/22 49.51.60.0/23 49.51.110.0/23 49.51.112.0/20 49.52.0.0/14 49.64.0.0/11 49.112.0.0/13 49.120.0.0/14 49.128.0.0/24 49.128.2.0/23 49.128.4.0/22 49.140.0.0/15 49.152.0.0/14 49.208.0.0/14 49.220.0.0/14 49.232.0.0/14 49.239.0.0/18 49.239.192.0/18 52.80.0.0/14 52.94.249.0/27 52.130.0.0/15 54.222.0.0/15 54.231.208.0/20 54.240.224.0/24 57.92.96.0/20 58.14.0.0/15 58.16.0.0/13 58.24.0.0/15 58.30.0.0/15 58.32.0.0/11 58.65.232.0/21 58.66.0.0/15 58.68.128.0/19 58.68.160.0/23 58.68.163.0/24 58.68.164.0/22 58.68.179.0/24 58.68.180.0/24 58.68.200.0/21 58.68.208.0/20 58.68.224.0/19 58.82.0.0/17 58.83.0.0/16 58.87.64.0/18 58.99.128.0/17 58.100.0.0/15 58.116.0.0/14 58.128.0.0/13 58.144.0.0/16 58.154.0.0/15 58.192.0.0/11 58.240.0.0/12 59.32.0.0/11 59.64.0.0/12 59.80.0.0/15 59.82.0.0/16 59.83.0.0/18 59.83.132.0/22 59.83.136.0/21 59.83.144.0/20 59.83.160.0/19 59.83.192.0/19 59.83.224.0/20 59.83.240.0/21 59.83.248.0/22 59.83.252.0/23 59.83.254.0/24 59.107.0.0/16 59.108.0.0/14 59.151.0.0/17 59.152.16.0/20 59.152.36.0/22 59.152.64.0/20 59.152.112.0/21 59.153.4.0/22 59.153.32.0/22 59.153.64.0/21 59.153.72.0/22 59.153.92.0/22 59.153.136.0/22 59.153.152.0/21 59.153.164.0/22 59.153.168.0/21 59.153.176.0/20 59.153.192.0/22 59.155.0.0/16 59.172.0.0/14 59.191.0.0/17 59.192.0.0/10 60.0.0.0/11 60.55.0.0/16 60.63.0.0/16 60.160.0.0/11 60.194.0.0/15 60.200.0.0/13 60.208.0.0/12 60.232.0.0/15 60.235.0.0/16 60.245.128.0/17 60.247.0.0/16 60.252.0.0/16 60.253.128.0/17 60.255.0.0/16 61.4.81.0/24 61.4.82.0/23 61.4.84.0/22 61.4.88.0/21 61.4.176.0/20 61.8.160.0/20 61.14.212.0/22 61.14.216.0/21 61.14.240.0/21 61.28.0.0/17 61.29.128.0/18 61.29.192.0/19 61.29.224.0/20 61.45.128.0/18 61.45.224.0/20 61.47.128.0/18 61.48.0.0/13 61.87.192.0/18 61.128.0.0/10 61.232.0.0/14 61.236.0.0/15 61.240.0.0/14 62.234.0.0/16 68.79.0.0/18 69.230.192.0/18 69.231.128.0/18 69.234.192.0/18 69.235.128.0/18 71.131.192.0/18 71.132.0.0/18 71.136.64.0/18 71.137.0.0/18 72.163.240.0/23 72.163.248.0/22 81.68.0.0/14 81.161.63.0/24 82.156.0.0/15 87.254.207.0/24 91.223.53.0/24 91.239.190.0/24 93.183.14.0/24 93.183.18.0/24 94.191.0.0/17 101.0.0.0/22 101.1.0.0/22 101.2.172.0/22 101.4.0.0/14 101.16.0.0/12 101.32.0.0/14 101.36.0.0/18 101.36.64.0/20 101.36.88.0/21 101.36.96.0/19 101.36.128.0/17 101.37.0.0/16 101.38.0.0/15 101.40.0.0/13 101.48.0.0/15 101.50.8.0/21 101.50.56.0/22 101.52.0.0/16 101.53.100.0/22 101.54.0.0/16 101.55.224.0/21 101.64.0.0/13 101.72.0.0/14 101.76.0.0/15 101.78.0.0/22 101.78.32.0/19 101.80.0.0/12 101.96.0.0/21 101.96.8.0/22 101.96.16.0/20 101.96.128.0/17 101.99.96.0/19 101.101.64.0/19 101.101.100.0/24 101.101.102.0/23 101.101.104.0/21 101.101.112.0/20 101.102.64.0/19 101.102.100.0/23 101.102.102.0/24 101.102.104.0/21 101.102.112.0/20 101.104.0.0/14 101.110.64.0/19 101.110.96.0/20 101.110.116.0/22 101.110.120.0/21 101.120.0.0/14 101.124.0.0/15 101.126.0.0/16 101.128.0.0/22 101.128.8.0/21 101.128.16.0/20 101.128.32.0/19 101.129.0.0/16 101.130.0.0/15 101.132.0.0/15 101.134.0.0/17 101.134.128.0/19 101.134.160.0/20 101.134.176.0/21 101.134.184.0/22 101.134.189.0/24 101.134.190.0/23 101.134.192.0/18 101.135.0.0/16 101.144.0.0/12 101.192.0.0/14 101.196.0.0/16 101.198.128.0/18 101.198.194.0/24 101.198.196.0/23 101.198.200.0/22 101.198.224.0/19 101.199.0.0/19 101.199.48.0/20 101.199.64.0/18 101.199.128.0/17 101.200.0.0/15 101.203.128.0/19 101.203.160.0/21 101.203.172.0/22 101.203.176.0/20 101.204.0.0/14 101.224.0.0/13 101.232.0.0/15 101.234.64.0/21 101.234.76.0/22 101.234.80.0/20 101.234.96.0/19 101.236.0.0/14 101.240.0.0/13 101.248.0.0/15 101.251.0.0/22 101.251.8.0/21 101.251.16.0/20 101.251.32.0/19 101.251.64.0/18 101.251.128.0/17 101.252.0.0/15 101.254.0.0/16 102.176.130.0/24 103.1.8.0/22 103.1.20.0/22 103.1.24.0/22 103.1.88.0/22 103.1.168.0/22 103.2.108.0/22 103.2.156.0/22 103.2.164.0/22 103.2.200.0/21 103.2.208.0/21 103.3.84.0/22 103.3.88.0/21 103.3.96.0/19 103.3.128.0/20 103.3.148.0/22 103.3.152.0/21 103.4.56.0/22 103.4.168.0/22 103.4.184.0/22 103.5.36.0/22 103.5.52.0/23 103.5.56.0/22 103.5.152.0/22 103.5.168.0/22 103.5.192.0/22 103.5.252.0/22 103.6.76.0/22 103.6.108.0/22 103.6.120.0/22 103.6.220.0/22 103.6.228.0/22 103.7.140.0/22 103.7.212.0/22 103.7.216.0/21 103.8.0.0/21 103.8.8.0/22 103.8.32.0/22 103.8.52.0/22 103.8.68.0/22 103.8.108.0/22 103.8.156.0/22 103.8.200.0/21 103.8.220.0/22 103.9.8.0/22 103.9.24.0/22 103.9.108.0/22 103.9.152.0/22 103.9.248.0/21 103.10.0.0/22 103.10.16.0/22 103.10.84.0/22 103.10.111.0/24 103.10.140.0/22 103.11.16.0/22 103.11.168.0/22 103.11.180.0/22 103.12.32.0/22 103.12.136.0/22 103.12.184.0/22 103.12.232.0/22 103.13.12.0/22 103.13.124.0/22 103.13.144.0/22 103.13.196.0/22 103.13.244.0/22 103.14.84.0/22 103.14.132.0/22 103.14.136.0/22 103.14.156.0/22 103.14.240.0/22 103.15.4.0/22 103.15.8.0/22 103.15.16.0/22 103.15.96.0/22 103.15.200.0/22 103.16.52.0/22 103.16.80.0/21 103.16.88.0/22 103.16.108.0/22 103.16.124.0/22 103.17.40.0/22 103.17.64.0/22 103.17.120.0/23 103.17.136.0/22 103.17.160.0/22 103.17.204.0/22 103.17.228.0/22 103.18.192.0/22 103.18.208.0/21 103.18.224.0/22 103.19.12.0/22 103.19.40.0/21 103.19.64.0/21 103.19.72.0/22 103.19.232.0/22 103.20.12.0/22 103.20.32.0/23 103.20.34.0/24 103.20.68.0/22 103.20.112.0/22 103.20.128.0/22 103.20.160.0/22 103.20.248.0/22 103.21.112.0/21 103.21.140.0/22 103.21.176.0/22 103.21.240.0/22 103.22.0.0/18 103.22.64.0/19 103.22.100.0/22 103.22.104.0/21 103.22.112.0/20 103.22.188.0/22 103.22.228.0/22 103.22.252.0/22 103.23.8.0/22 103.23.56.0/22 103.23.160.0/21 103.23.176.0/22 103.23.228.0/22 103.24.24.0/22 103.24.116.0/22 103.24.128.0/22 103.24.144.0/22 103.24.176.0/22 103.24.184.0/22 103.24.228.0/22 103.24.252.0/22 103.25.20.0/22 103.25.24.0/21 103.25.32.0/21 103.25.40.0/22 103.25.48.0/22 103.25.64.0/21 103.25.148.0/22 103.25.156.0/22 103.25.216.0/22 103.26.0.0/22 103.26.64.0/22 103.26.76.0/22 103.26.116.0/22 103.26.156.0/22 103.26.160.0/22 103.26.228.0/22 103.26.240.0/22 103.27.4.0/22 103.27.12.0/22 103.27.24.0/22 103.27.56.0/22 103.27.96.0/22 103.27.240.0/22 103.28.4.0/22 103.28.8.0/22 103.28.184.0/22 103.28.204.0/22 103.28.212.0/22 103.29.16.0/22 103.29.128.0/21 103.29.136.0/22 103.30.20.0/22 103.30.96.0/22 103.30.148.0/22 103.30.202.0/23 103.30.228.0/22 103.30.236.0/22 103.31.0.0/22 103.31.48.0/21 103.31.60.0/22 103.31.64.0/21 103.31.72.0/24 103.31.148.0/22 103.31.160.0/22 103.31.168.0/22 103.31.200.0/22 103.31.236.0/22 103.32.0.0/15 103.34.0.0/16 103.35.0.0/19 103.35.32.0/20 103.35.48.0/22 103.35.104.0/22 103.35.220.0/22 103.36.28.0/22 103.36.36.0/22 103.36.56.0/21 103.36.64.0/22 103.36.72.0/22 103.36.96.0/22 103.36.132.0/22 103.36.136.0/22 103.36.160.0/19 103.36.192.0/19 103.36.224.0/20 103.36.240.0/21 103.37.12.0/22 103.37.16.0/22 103.37.24.0/22 103.37.44.0/22 103.37.52.0/22 103.37.56.0/22 103.37.72.0/22 103.37.100.0/22 103.37.104.0/22 103.37.136.0/21 103.37.144.0/20 103.37.160.0/21 103.37.172.0/22 103.37.176.0/22 103.37.188.0/22 103.37.208.0/20 103.37.252.0/22 103.38.0.0/22 103.38.32.0/22 103.38.40.0/21 103.38.76.0/22 103.38.84.0/22 103.38.92.0/22 103.38.96.0/22 103.38.116.0/22 103.38.132.0/22 103.38.140.0/22 103.38.220.0/22 103.38.224.0/21 103.38.232.0/22 103.38.252.0/23 103.39.64.0/22 103.39.88.0/22 103.39.100.0/22 103.39.104.0/22 103.39.160.0/19 103.39.200.0/21 103.39.208.0/20 103.39.224.0/21 103.39.232.0/22 103.40.12.0/22 103.40.16.0/20 103.40.32.0/20 103.40.88.0/22 103.40.192.0/22 103.40.212.0/22 103.40.220.0/22 103.40.228.0/22 103.40.232.0/21 103.40.240.0/20 103.41.0.0/22 103.41.52.0/22 103.41.140.0/22 103.41.148.0/22 103.41.152.0/22 103.41.160.0/21 103.41.220.0/22 103.41.224.0/21 103.41.232.0/22 103.42.8.0/22 103.42.24.0/22 103.42.32.0/22 103.42.64.0/21 103.42.76.0/22 103.42.232.0/22 103.43.26.0/23 103.43.96.0/21 103.43.104.0/22 103.43.124.0/22 103.43.184.0/22 103.43.192.0/21 103.43.208.0/22 103.43.220.0/22 103.43.224.0/22 103.43.240.0/22 103.44.58.0/23 103.44.80.0/22 103.44.120.0/21 103.44.144.0/22 103.44.152.0/22 103.44.168.0/22 103.44.176.0/20 103.44.192.0/20 103.44.224.0/22 103.44.236.0/22 103.44.240.0/20 103.45.0.0/18 103.45.72.0/21 103.45.80.0/20 103.45.96.0/19 103.45.128.0/18 103.45.192.0/19 103.45.224.0/22 103.45.248.0/22 103.46.0.0/22 103.46.12.0/22 103.46.16.0/20 103.46.32.0/19 103.46.64.0/18 103.46.128.0/21 103.46.136.0/22 103.46.152.0/21 103.46.160.0/20 103.46.176.0/21 103.46.244.0/22 103.46.248.0/22 103.47.4.0/22 103.47.20.0/22 103.47.36.0/22 103.47.40.0/22 103.47.48.0/22 103.47.80.0/22 103.47.96.0/22 103.47.116.0/22 103.47.120.0/22 103.47.136.0/21 103.47.212.0/22 103.48.52.0/22 103.48.92.0/22 103.48.148.0/22 103.48.152.0/22 103.48.202.0/23 103.48.216.0/21 103.48.224.0/20 103.48.240.0/21 103.49.12.0/22 103.49.20.0/22 103.49.72.0/21 103.49.96.0/22 103.49.108.0/22 103.49.128.0/22 103.49.176.0/21 103.50.36.0/22 103.50.44.0/22 103.50.48.0/20 103.50.64.0/21 103.50.72.0/22 103.50.92.0/22 103.50.108.0/22 103.50.112.0/20 103.50.132.0/22 103.50.136.0/21 103.50.172.0/22 103.50.176.0/20 103.50.192.0/21 103.50.200.0/22 103.50.220.0/22 103.50.224.0/20 103.50.240.0/21 103.50.248.0/22 103.52.40.0/22 103.52.72.0/21 103.52.80.0/21 103.52.96.0/21 103.52.104.0/22 103.52.160.0/21 103.52.172.0/22 103.52.176.0/22 103.52.184.0/22 103.52.196.0/22 103.53.64.0/21 103.53.92.0/22 103.53.124.0/22 103.53.128.0/20 103.53.144.0/22 103.53.160.0/22 103.53.180.0/22 103.53.204.0/22 103.53.208.0/21 103.53.236.0/22 103.53.248.0/22 103.54.8.0/22 103.54.48.0/22 103.54.160.0/21 103.54.212.0/22 103.54.228.0/22 103.54.240.0/22 103.55.80.0/22 103.55.120.0/22 103.55.152.0/22 103.55.172.0/22 103.55.204.0/22 103.55.208.0/22 103.55.228.0/22 103.55.236.0/22 103.55.240.0/22 103.56.20.0/22 103.56.32.0/22 103.56.56.0/21 103.56.72.0/21 103.56.140.0/22 103.56.152.0/22 103.56.184.0/22 103.56.200.0/22 103.57.12.0/22 103.57.52.0/22 103.57.56.0/22 103.57.76.0/22 103.57.136.0/22 103.57.196.0/22 103.58.24.0/22 103.59.76.0/22 103.59.112.0/21 103.59.120.0/24 103.59.123.0/24 103.59.124.0/22 103.59.128.0/22 103.59.148.0/22 103.60.32.0/22 103.60.44.0/22 103.60.164.0/22 103.60.228.0/22 103.60.236.0/22 103.61.60.0/24 103.61.104.0/22 103.61.140.0/22 103.61.152.0/21 103.61.160.0/22 103.61.172.0/22 103.61.176.0/22 103.62.24.0/22 103.62.72.0/21 103.62.80.0/21 103.62.88.0/22 103.62.96.0/19 103.62.128.0/21 103.62.156.0/22 103.62.160.0/19 103.62.192.0/22 103.62.204.0/22 103.62.208.0/20 103.62.224.0/22 103.63.32.0/19 103.63.64.0/20 103.63.80.0/21 103.63.88.0/22 103.63.140.0/22 103.63.144.0/22 103.63.152.0/22 103.63.160.0/20 103.63.176.0/21 103.63.184.0/22 103.63.192.0/20 103.63.208.0/22 103.63.240.0/20 103.64.0.0/21 103.64.24.0/21 103.64.32.0/19 103.64.64.0/18 103.64.140.0/22 103.64.144.0/22 103.64.152.0/21 103.64.160.0/19 103.64.192.0/18 103.65.0.0/21 103.65.12.0/22 103.65.16.0/22 103.65.48.0/20 103.65.64.0/19 103.65.100.0/22 103.65.104.0/21 103.65.112.0/20 103.65.128.0/21 103.65.136.0/22 103.65.144.0/20 103.65.160.0/20 103.66.32.0/22 103.66.40.0/22 103.66.108.0/22 103.66.200.0/22 103.66.240.0/20 103.67.0.0/21 103.67.8.0/22 103.67.40.0/21 103.67.48.0/20 103.67.64.0/18 103.67.128.0/20 103.67.144.0/21 103.67.172.0/24 103.67.175.0/24 103.67.192.0/22 103.67.212.0/22 103.68.88.0/22 103.68.100.0/22 103.68.128.0/22 103.69.16.0/22 103.69.212.0/23 103.70.8.0/22 103.70.148.0/22 103.70.236.0/22 103.70.252.0/22 103.71.0.0/22 103.71.68.0/22 103.71.72.0/22 103.71.80.0/21 103.71.88.0/22 103.71.120.0/21 103.71.128.0/22 103.71.196.0/22 103.71.200.0/22 103.71.232.0/22 103.72.12.0/22 103.72.16.0/20 103.72.32.0/20 103.72.48.0/21 103.72.112.0/21 103.72.124.0/22 103.72.128.0/21 103.72.149.0/24 103.72.150.0/23 103.72.172.0/22 103.72.180.0/22 103.72.224.0/19 103.73.0.0/19 103.73.48.0/22 103.73.116.0/22 103.73.120.0/22 103.73.128.0/20 103.73.168.0/22 103.73.176.0/22 103.73.204.0/22 103.73.208.0/22 103.73.240.0/23 103.73.244.0/22 103.73.248.0/22 103.74.24.0/21 103.74.32.0/20 103.74.48.0/22 103.74.56.0/21 103.74.80.0/22 103.74.124.0/22 103.74.148.0/22 103.74.152.0/21 103.74.204.0/22 103.74.232.0/22 103.75.87.0/24 103.75.88.0/21 103.75.104.0/21 103.75.112.0/22 103.75.120.0/22 103.75.128.0/22 103.75.144.0/22 103.75.152.0/22 103.76.60.0/22 103.76.64.0/21 103.76.72.0/22 103.76.92.0/22 103.76.216.0/21 103.76.224.0/22 103.77.28.0/22 103.77.52.0/22 103.77.56.0/22 103.77.88.0/22 103.77.132.0/22 103.77.148.0/22 103.77.220.0/22 103.78.56.0/21 103.78.64.0/22 103.78.124.0/22 103.78.172.0/22 103.78.176.0/22 103.78.196.0/22 103.78.228.0/22 103.79.24.0/21 103.79.36.0/22 103.79.40.0/21 103.79.56.0/21 103.79.64.0/21 103.79.80.0/21 103.79.136.0/22 103.79.188.0/22 103.79.192.0/20 103.79.208.0/21 103.79.243.0/24 103.80.44.0/22 103.80.72.0/22 103.80.176.0/21 103.80.184.0/22 103.80.192.0/22 103.80.200.0/22 103.80.232.0/22 103.81.4.0/22 103.81.44.0/22 103.81.48.0/22 103.81.96.0/22 103.81.120.0/22 103.81.148.0/22 103.81.164.0/22 103.81.200.0/22 103.81.232.0/22 103.82.60.0/22 103.82.68.0/22 103.82.84.0/22 103.82.104.0/22 103.82.224.0/22 103.82.236.0/22 103.83.44.0/22 103.83.52.0/22 103.83.60.0/22 103.83.72.0/22 103.83.112.0/22 103.83.132.0/22 103.83.180.0/22 103.84.0.0/22 103.84.12.0/22 103.84.20.0/22 103.84.24.0/21 103.84.48.0/22 103.84.56.0/22 103.84.64.0/22 103.84.72.0/22 103.85.44.0/22 103.85.48.0/21 103.85.56.0/22 103.85.84.0/22 103.85.136.0/22 103.85.144.0/22 103.85.164.0/22 103.85.168.0/21 103.85.176.0/22 103.86.28.0/22 103.86.32.0/22 103.86.60.0/22 103.86.129.0/24 103.86.204.0/22 103.86.208.0/20 103.86.224.0/19 103.87.0.0/21 103.87.20.0/22 103.87.32.0/22 103.87.96.0/22 103.87.132.0/22 103.87.180.0/22 103.87.224.0/22 103.88.4.0/22 103.88.8.0/21 103.88.16.0/21 103.88.32.0/21 103.88.60.0/22 103.88.64.0/22 103.88.72.0/22 103.88.96.0/21 103.88.152.0/23 103.88.164.0/22 103.88.212.0/22 103.89.28.0/22 103.89.96.0/20 103.89.112.0/22 103.89.148.0/22 103.89.172.0/22 103.89.184.0/21 103.89.192.0/19 103.89.224.0/21 103.90.52.0/22 103.90.92.0/22 103.90.100.0/22 103.90.104.0/21 103.90.112.0/20 103.90.128.0/21 103.90.152.0/22 103.90.168.0/22 103.90.173.0/24 103.90.176.0/22 103.90.188.0/22 103.90.192.0/22 103.91.36.0/22 103.91.40.0/22 103.91.108.0/22 103.91.152.0/22 103.91.176.0/22 103.91.200.0/22 103.91.208.0/21 103.91.236.0/22 103.92.48.0/20 103.92.64.0/20 103.92.80.0/22 103.92.88.0/22 103.92.108.0/22 103.92.124.0/22 103.92.132.0/22 103.92.156.0/22 103.92.164.0/22 103.92.168.0/21 103.92.176.0/20 103.92.192.0/22 103.92.236.0/22 103.92.240.0/20 103.93.0.0/21 103.93.28.0/22 103.93.84.0/22 103.93.152.0/22 103.93.180.0/22 103.93.204.0/22 103.94.12.0/22 103.94.20.0/22 103.94.28.0/22 103.94.32.0/20 103.94.72.0/22 103.94.88.0/22 103.94.116.0/22 103.94.160.0/22 103.94.182.0/24 103.94.200.0/22 103.95.31.0/24 103.95.52.0/22 103.95.70.0/23 103.95.88.0/21 103.95.136.0/21 103.95.144.0/22 103.95.152.0/22 103.95.216.0/21 103.95.224.0/22 103.95.236.0/22 103.95.240.0/20 103.96.8.0/22 103.96.124.0/22 103.96.136.0/22 103.96.152.0/21 103.96.160.0/19 103.96.192.0/20 103.96.208.0/21 103.96.216.0/22 103.97.40.0/22 103.97.60.0/23 103.97.112.0/21 103.97.148.0/22 103.97.188.0/22 103.97.192.0/22 103.98.40.0/21 103.98.48.0/22 103.98.56.0/22 103.98.80.0/22 103.98.88.0/22 103.98.100.0/22 103.98.124.0/24 103.98.126.0/23 103.98.136.0/21 103.98.144.0/22 103.98.164.0/22 103.98.168.0/22 103.98.180.0/22 103.98.196.0/22 103.98.216.0/21 103.98.224.0/21 103.98.232.0/22 103.98.240.0/21 103.98.248.0/23 103.98.250.0/24 103.98.252.0/22 103.99.56.0/22 103.99.104.0/22 103.99.116.0/22 103.99.120.0/22 103.99.132.0/22 103.99.136.0/21 103.99.144.0/22 103.99.152.0/22 103.99.220.0/22 103.99.232.0/21 103.100.0.0/22 103.100.32.0/22 103.100.40.0/22 103.100.48.0/22 103.100.56.0/22 103.100.64.0/22 103.100.88.0/22 103.100.116.0/22 103.100.144.0/22 103.100.240.0/22 103.100.248.0/21 103.101.4.0/22 103.101.8.0/21 103.101.60.0/22 103.101.121.0/24 103.101.122.0/23 103.101.124.0/24 103.101.126.0/23 103.101.144.0/21 103.101.180.0/22 103.101.184.0/22 103.102.76.0/22 103.102.80.0/22 103.102.168.0/21 103.102.180.0/22 103.102.184.0/21 103.102.192.0/22 103.102.196.0/24 103.102.200.0/22 103.102.208.0/21 103.103.12.0/22 103.103.16.0/22 103.103.36.0/22 103.103.72.0/22 103.103.188.0/22 103.103.204.0/22 103.104.36.0/22 103.104.40.0/22 103.104.64.0/22 103.104.152.0/22 103.104.252.0/22 103.105.0.0/21 103.105.12.0/22 103.105.16.0/22 103.105.60.0/22 103.105.116.0/22 103.105.180.0/22 103.105.184.0/22 103.105.200.0/21 103.105.220.0/22 103.106.36.0/22 103.106.40.0/21 103.106.60.0/22 103.106.68.0/22 103.106.96.0/22 103.106.120.0/22 103.106.128.0/21 103.106.190.0/23 103.106.196.0/22 103.106.212.0/22 103.106.252.0/22 103.107.0.0/22 103.107.28.0/22 103.107.32.0/22 103.107.44.0/22 103.107.72.0/22 103.107.164.0/22 103.107.168.0/22 103.107.188.0/22 103.107.192.0/22 103.107.208.0/20 103.108.52.0/22 103.108.160.0/21 103.108.194.0/24 103.108.196.0/22 103.108.208.0/21 103.108.224.0/22 103.108.244.0/22 103.108.251.0/24 103.109.20.0/22 103.109.48.0/22 103.109.88.0/22 103.109.106.0/23 103.109.248.0/22 103.110.32.0/22 103.110.92.0/22 103.110.119.0/24 103.110.127.0/24 103.110.128.0/23 103.110.131.0/24 103.110.132.0/22 103.110.136.0/22 103.110.156.0/22 103.110.188.0/22 103.110.204.0/22 103.111.64.0/22 103.111.172.0/22 103.111.252.0/22 103.112.72.0/22 103.112.88.0/21 103.112.108.0/22 103.112.112.0/22 103.112.140.0/22 103.113.4.0/22 103.113.144.0/22 103.113.220.0/22 103.113.232.0/21 103.114.4.0/22 103.114.68.0/22 103.114.100.0/22 103.114.148.0/22 103.114.156.0/23 103.114.159.0/24 103.114.212.0/22 103.114.236.0/22 103.114.240.0/22 103.115.52.0/22 103.115.68.0/22 103.115.92.0/22 103.115.120.0/22 103.115.148.0/22 103.115.248.0/22 103.116.76.0/22 103.116.92.0/22 103.116.120.0/22 103.116.128.0/22 103.116.150.0/23 103.116.184.0/22 103.116.220.0/22 103.116.224.0/21 103.117.16.0/22 103.117.88.0/22 103.117.188.0/22 103.117.220.0/22 103.118.19.0/24 103.118.52.0/22 103.118.56.0/21 103.118.64.0/21 103.118.72.0/22 103.118.88.0/22 103.118.173.0/24 103.119.115.0/24 103.119.156.0/22 103.119.180.0/22 103.119.200.0/22 103.119.224.0/22 103.120.52.0/22 103.120.72.0/22 103.120.76.0/24 103.120.88.0/22 103.120.96.0/22 103.120.140.0/22 103.120.196.0/22 103.120.224.0/22 103.121.52.0/22 103.121.160.0/21 103.121.250.0/24 103.121.252.0/22 103.122.48.0/22 103.122.178.0/23 103.122.192.0/22 103.122.240.0/23 103.122.242.0/24 103.123.4.0/22 103.123.56.0/22 103.123.88.0/21 103.123.116.0/22 103.123.176.0/22 103.123.200.0/21 103.123.208.0/21 103.124.24.0/22 103.124.48.0/22 103.124.64.0/22 103.124.212.0/22 103.124.216.0/22 103.125.20.0/22 103.125.44.0/22 103.125.132.0/22 103.125.164.0/22 103.125.196.0/22 103.125.236.0/22 103.126.0.0/22 103.126.16.0/23 103.126.44.0/22 103.126.124.0/22 103.126.128.0/22 103.129.53.0/24 103.129.54.0/23 103.129.148.0/22 103.130.132.0/22 103.130.160.0/22 103.130.228.0/22 103.131.20.0/22 103.131.36.0/22 103.131.152.0/22 103.131.168.0/22 103.131.224.0/21 103.131.240.0/22 103.132.60.0/22 103.132.64.0/20 103.132.80.0/22 103.132.104.0/21 103.132.112.0/21 103.132.120.0/22 103.132.188.0/22 103.132.208.0/21 103.133.12.0/22 103.133.40.0/22 103.133.128.0/22 103.133.232.0/22 103.134.196.0/22 103.135.80.0/22 103.135.124.0/22 103.135.148.0/22 103.135.156.0/22 103.135.160.0/21 103.135.176.0/22 103.135.184.0/22 103.135.192.0/21 103.135.236.0/22 103.136.128.0/22 103.136.232.0/22 103.137.58.0/23 103.137.60.0/24 103.137.136.0/23 103.137.149.0/24 103.137.180.0/22 103.137.236.0/22 103.138.2.0/23 103.138.134.0/23 103.138.208.0/23 103.138.220.0/23 103.138.248.0/23 103.139.22.0/23 103.139.134.0/23 103.139.136.0/23 103.139.172.0/23 103.139.204.0/23 103.139.212.0/23 103.140.14.0/23 103.140.46.0/23 103.140.140.0/23 103.140.144.0/23 103.140.192.0/23 103.141.10.0/23 103.141.58.0/23 103.141.128.0/23 103.141.186.0/23 103.141.242.0/23 103.142.0.0/23 103.142.28.0/23 103.142.58.0/23 103.142.82.0/23 103.142.96.0/23 103.142.122.0/23 103.142.128.0/23 103.142.154.0/23 103.142.156.0/23 103.142.180.0/23 103.142.186.0/23 103.142.220.0/23 103.142.230.0/24 103.142.234.0/23 103.142.238.0/23 103.143.16.0/22 103.143.31.0/24 103.143.74.0/23 103.143.124.0/23 103.143.132.0/22 103.143.174.0/23 103.143.228.0/23 103.144.66.0/23 103.144.70.0/23 103.144.72.0/23 103.144.136.0/23 103.144.158.0/23 103.145.40.0/22 103.145.73.0/24 103.145.80.0/23 103.145.90.0/23 103.145.92.0/22 103.145.98.0/23 103.145.107.0/24 103.145.188.0/23 103.146.6.0/23 103.146.72.0/23 103.146.90.0/23 103.146.126.0/23 103.146.138.0/23 103.146.236.0/23 103.146.252.0/23 103.147.124.0/23 103.147.198.0/23 103.147.206.0/23 103.148.174.0/23 103.192.0.0/19 103.192.48.0/21 103.192.56.0/22 103.192.84.0/22 103.192.88.0/21 103.192.96.0/20 103.192.112.0/22 103.192.128.0/20 103.192.144.0/22 103.192.164.0/22 103.192.188.0/22 103.192.208.0/21 103.192.216.0/22 103.192.252.0/22 103.193.40.0/21 103.193.120.0/22 103.193.140.0/22 103.193.160.0/22 103.193.188.0/22 103.193.192.0/22 103.193.212.0/22 103.193.216.0/21 103.193.224.0/20 103.194.16.0/22 103.194.230.0/23 103.195.112.0/22 103.195.152.0/22 103.195.160.0/22 103.196.64.0/22 103.196.72.0/22 103.196.88.0/21 103.196.96.0/22 103.196.168.0/22 103.196.185.0/24 103.196.186.0/23 103.197.181.0/24 103.197.183.0/24 103.197.228.0/22 103.197.253.0/24 103.197.254.0/23 103.198.20.0/22 103.198.60.0/22 103.198.64.0/22 103.198.72.0/22 103.198.124.0/22 103.198.156.0/22 103.198.180.0/22 103.198.196.0/22 103.198.200.0/22 103.198.216.0/21 103.198.224.0/20 103.198.240.0/21 103.199.164.0/22 103.199.196.0/22 103.199.228.0/22 103.199.252.0/22 103.200.52.0/22 103.200.64.0/21 103.200.136.0/21 103.200.144.0/20 103.200.160.0/19 103.200.192.0/22 103.200.220.0/22 103.200.224.0/19 103.201.0.0/20 103.201.16.0/21 103.201.28.0/22 103.201.32.0/19 103.201.64.0/22 103.201.76.0/22 103.201.80.0/20 103.201.96.0/20 103.201.112.0/21 103.201.120.0/22 103.201.152.0/21 103.201.160.0/19 103.201.192.0/18 103.202.0.0/19 103.202.32.0/20 103.202.56.0/21 103.202.64.0/18 103.202.128.0/20 103.202.144.0/22 103.202.152.0/21 103.202.160.0/19 103.202.192.0/20 103.202.212.0/22 103.202.228.0/22 103.202.236.0/22 103.202.240.0/20 103.203.0.0/19 103.203.32.0/22 103.203.96.0/19 103.203.128.0/22 103.203.140.0/22 103.203.164.0/22 103.203.168.0/22 103.203.192.0/22 103.203.200.0/22 103.203.212.0/22 103.203.216.0/22 103.204.24.0/22 103.204.88.0/22 103.204.112.0/22 103.204.136.0/21 103.204.144.0/21 103.204.152.0/22 103.204.196.0/22 103.204.232.0/21 103.205.4.0/22 103.205.40.0/21 103.205.52.0/22 103.205.108.0/22 103.205.116.0/22 103.205.120.0/24 103.205.136.0/22 103.205.162.0/24 103.205.188.0/22 103.205.192.0/21 103.205.200.0/22 103.205.236.0/22 103.205.248.0/21 103.206.0.0/22 103.206.44.0/22 103.206.148.0/22 103.207.104.0/22 103.207.184.0/21 103.207.192.0/20 103.207.208.0/21 103.207.220.0/22 103.207.228.0/22 103.207.232.0/22 103.208.12.0/22 103.208.16.0/22 103.208.28.0/22 103.208.48.0/22 103.208.148.0/22 103.209.112.0/22 103.209.136.0/22 103.209.200.0/22 103.209.208.0/22 103.209.216.0/22 103.210.0.0/22 103.210.96.0/22 103.210.156.0/22 103.210.160.0/19 103.210.217.0/24 103.210.218.0/23 103.211.44.0/22 103.211.96.0/23 103.211.98.0/24 103.211.100.0/22 103.211.156.0/22 103.211.165.0/24 103.211.168.0/22 103.211.220.0/22 103.211.248.0/22 103.212.0.0/20 103.212.44.0/22 103.212.48.0/22 103.212.84.0/22 103.212.100.0/22 103.212.148.0/22 103.212.164.0/22 103.212.196.0/22 103.212.200.0/22 103.212.252.0/22 103.213.40.0/21 103.213.48.0/20 103.213.64.0/19 103.213.96.0/22 103.213.132.0/22 103.213.136.0/21 103.213.144.0/20 103.213.160.0/19 103.213.252.0/22 103.214.48.0/22 103.214.84.0/22 103.214.212.0/22 103.214.240.0/21 103.215.28.0/22 103.215.32.0/21 103.215.44.0/22 103.215.100.0/23 103.215.108.0/22 103.215.116.0/22 103.215.120.0/22 103.215.140.0/22 103.216.4.0/22 103.216.8.0/21 103.216.16.0/20 103.216.32.0/20 103.216.64.0/22 103.216.108.0/22 103.216.136.0/22 103.216.152.0/22 103.216.224.0/21 103.216.240.0/20 103.217.0.0/18 103.217.168.0/22 103.217.180.0/22 103.217.184.0/21 103.217.192.0/20 103.218.8.0/21 103.218.16.0/21 103.218.29.0/24 103.218.30.0/23 103.218.32.0/19 103.218.64.0/19 103.218.192.0/20 103.218.208.0/21 103.218.216.0/22 103.219.24.0/21 103.219.32.0/21 103.219.64.0/22 103.219.84.0/22 103.219.88.0/21 103.219.96.0/21 103.219.176.0/22 103.219.184.0/22 103.220.48.0/20 103.220.64.0/22 103.220.92.0/22 103.220.96.0/22 103.220.104.0/21 103.220.116.0/22 103.220.120.0/21 103.220.128.0/20 103.220.144.0/21 103.220.152.0/22 103.220.160.0/19 103.220.192.0/21 103.220.200.0/22 103.220.240.0/20 103.221.0.0/19 103.221.32.0/21 103.221.88.0/21 103.221.96.0/19 103.221.128.0/18 103.221.192.0/20 103.222.0.0/20 103.222.16.0/22 103.222.24.0/21 103.222.33.0/24 103.222.34.0/23 103.222.36.0/22 103.222.40.0/21 103.222.48.0/20 103.222.64.0/18 103.222.128.0/18 103.222.192.0/19 103.222.224.0/21 103.222.232.0/22 103.222.240.0/21 103.223.16.0/20 103.223.32.0/19 103.223.64.0/19 103.223.96.0/20 103.223.112.0/21 103.223.124.0/22 103.223.128.0/21 103.223.140.0/22 103.223.144.0/20 103.223.160.0/20 103.223.176.0/21 103.223.188.0/22 103.223.192.0/18 103.224.0.0/22 103.224.40.0/21 103.224.60.0/22 103.224.220.0/22 103.224.224.0/21 103.224.232.0/22 103.226.40.0/22 103.226.56.0/21 103.226.80.0/22 103.226.116.0/22 103.226.132.0/22 103.226.156.0/22 103.226.180.0/22 103.226.196.0/22 103.227.48.0/22 103.227.72.0/21 103.227.80.0/22 103.227.100.0/22 103.227.120.0/22 103.227.132.0/22 103.227.136.0/22 103.227.196.0/22 103.227.204.0/23 103.227.206.0/24 103.227.212.0/22 103.227.228.0/22 103.228.12.0/22 103.228.88.0/22 103.228.136.0/22 103.228.160.0/22 103.228.176.0/22 103.228.204.0/22 103.228.208.0/22 103.228.228.0/22 103.228.232.0/22 103.229.20.0/22 103.229.136.0/22 103.229.148.0/22 103.229.172.0/22 103.229.212.0/22 103.229.216.0/21 103.229.228.0/22 103.229.236.0/22 103.229.240.0/22 103.230.0.0/22 103.230.28.0/22 103.230.40.0/21 103.230.96.0/22 103.230.196.0/22 103.230.200.0/21 103.230.212.0/22 103.230.236.0/22 103.231.16.0/21 103.231.64.0/21 103.231.144.0/22 103.231.180.0/22 103.231.244.0/22 103.232.4.0/22 103.232.17.168/29 103.232.144.0/22 103.233.4.0/22 103.233.44.0/22 103.233.52.0/22 103.233.104.0/22 103.233.128.0/22 103.233.136.0/22 103.233.228.0/22 103.234.0.0/22 103.234.20.0/22 103.234.56.0/22 103.234.124.0/22 103.234.128.0/22 103.234.172.0/22 103.234.180.0/22 103.235.56.0/21 103.235.80.0/22 103.235.85.0/24 103.235.86.0/23 103.235.128.0/20 103.235.144.0/21 103.235.184.0/22 103.235.192.0/22 103.235.200.0/22 103.235.220.0/22 103.235.224.0/19 103.236.0.0/18 103.236.64.0/19 103.236.96.0/22 103.236.120.0/22 103.236.184.0/22 103.236.240.0/20 103.237.0.0/20 103.237.24.0/21 103.237.68.0/22 103.237.88.0/22 103.237.152.0/22 103.237.176.0/20 103.237.192.0/18 103.238.0.0/21 103.238.18.0/23 103.238.20.0/22 103.238.24.0/21 103.238.32.0/20 103.238.48.0/21 103.238.56.0/22 103.238.88.0/21 103.238.96.0/22 103.238.132.0/22 103.238.140.0/22 103.238.144.0/22 103.238.160.0/22 103.238.165.0/24 103.238.166.0/23 103.238.168.0/21 103.238.176.0/20 103.238.196.0/22 103.238.204.0/22 103.238.252.0/22 103.239.0.0/22 103.239.44.0/22 103.239.68.0/22 103.239.152.0/21 103.239.180.0/22 103.239.184.0/22 103.239.192.0/21 103.239.204.0/22 103.239.208.0/22 103.239.224.0/22 103.239.244.0/22 103.240.16.0/22 103.240.36.0/22 103.240.72.0/22 103.240.84.0/22 103.240.124.0/22 103.240.172.0/22 103.240.188.0/22 103.240.244.0/22 103.241.12.0/22 103.241.92.0/22 103.241.96.0/22 103.241.160.0/22 103.241.184.0/21 103.241.220.0/22 103.242.64.0/23 103.242.128.0/23 103.242.160.0/22 103.242.168.0/21 103.242.176.0/22 103.242.200.0/22 103.242.212.0/22 103.242.220.0/22 103.242.240.0/22 103.243.136.0/22 103.243.252.0/22 103.244.16.0/22 103.244.58.0/23 103.244.60.0/22 103.244.64.0/20 103.244.80.0/21 103.244.116.0/22 103.244.164.0/22 103.244.232.0/22 103.244.252.0/22 103.245.23.0/24 103.245.52.0/22 103.245.60.0/22 103.245.80.0/22 103.245.124.0/22 103.245.128.0/22 103.246.8.0/21 103.246.120.0/21 103.246.132.0/22 103.246.152.0/22 103.247.168.0/21 103.247.176.0/22 103.247.200.0/22 103.247.212.0/22 103.248.64.0/23 103.248.100.0/22 103.248.124.0/22 103.248.152.0/22 103.248.168.0/22 103.248.192.0/22 103.248.212.0/22 103.248.224.0/21 103.249.8.0/21 103.249.52.0/22 103.249.128.0/22 103.249.136.0/22 103.249.144.0/22 103.249.164.0/22 103.249.168.0/21 103.249.176.0/22 103.249.188.0/22 103.249.192.0/22 103.249.244.0/22 103.249.252.0/22 103.250.32.0/22 103.250.104.0/22 103.250.124.0/22 103.250.180.0/22 103.250.192.0/22 103.250.216.0/22 103.250.224.0/22 103.250.236.0/22 103.250.248.0/21 103.251.32.0/22 103.251.84.0/22 103.251.96.0/22 103.251.124.0/22 103.251.160.0/22 103.251.192.0/22 103.251.204.0/22 103.251.240.0/22 103.252.28.0/22 103.252.36.0/22 103.252.64.0/22 103.252.96.0/22 103.252.104.0/22 103.252.172.0/22 103.252.204.0/22 103.252.208.0/22 103.252.232.0/22 103.252.248.0/22 103.253.4.0/22 103.253.60.0/22 103.253.204.0/22 103.253.220.0/22 103.253.224.0/22 103.253.232.0/22 103.254.8.0/22 103.254.20.0/22 103.254.64.0/21 103.254.76.0/22 103.254.112.0/22 103.254.176.0/22 103.254.188.0/22 103.255.68.0/22 103.255.88.0/21 103.255.136.0/21 103.255.184.0/22 103.255.200.0/22 103.255.208.0/22 103.255.228.0/22 104.222.196.0/24 106.0.0.0/24 106.0.2.0/23 106.0.4.0/22 106.0.8.0/21 106.0.16.0/20 106.0.44.0/22 106.0.64.0/18 106.2.0.0/23 106.2.3.0/24 106.2.4.0/22 106.2.8.0/21 106.2.16.0/20 106.2.32.0/19 106.2.64.0/18 106.2.128.0/17 106.3.16.0/20 106.3.32.0/19 106.3.64.0/20 106.3.80.0/22 106.3.88.0/21 106.3.96.0/19 106.3.128.0/19 106.3.164.0/22 106.3.168.0/21 106.3.176.0/20 106.3.192.0/18 106.4.0.0/14 106.8.0.0/15 106.11.0.0/16 106.12.0.0/14 106.16.0.0/12 106.32.0.0/12 106.48.0.0/21 106.48.8.0/22 106.48.16.0/20 106.48.32.0/20 106.48.57.0/24 106.48.60.0/24 106.48.63.0/24 106.48.64.0/18 106.48.128.0/17 106.49.1.0/24 106.49.2.0/23 106.49.4.0/22 106.49.8.0/21 106.49.16.0/20 106.49.32.0/19 106.49.64.0/19 106.49.96.0/24 106.49.98.0/23 106.49.100.0/22 106.49.104.0/21 106.49.112.0/20 106.49.128.0/17 106.50.0.0/16 106.52.0.0/14 106.56.0.0/13 106.74.0.0/16 106.75.0.0/17 106.75.128.0/18 106.75.201.0/24 106.75.204.0/22 106.75.208.0/20 106.75.224.0/19 106.80.0.0/12 106.108.0.0/14 106.112.0.0/12 106.224.0.0/12 109.71.4.0/24 109.244.0.0/16 110.6.0.0/15 110.16.0.0/14 110.34.40.0/21 110.40.0.0/15 110.42.0.0/16 110.43.0.0/18 110.43.64.0/21 110.43.72.0/22 110.43.76.0/23 110.43.80.0/20 110.43.96.0/19 110.43.128.0/17 110.44.12.0/22 110.44.144.0/20 110.48.0.0/16 110.51.0.0/16 110.52.0.0/15 110.56.0.0/13 110.64.0.0/15 110.72.0.0/15 110.75.0.0/16 110.76.0.0/20 110.76.16.0/22 110.76.20.0/24 110.76.22.0/24 110.76.24.0/21 110.76.32.0/19 110.76.132.0/22 110.76.156.0/22 110.76.184.0/22 110.76.192.0/18 110.77.0.0/17 110.80.0.0/13 110.88.0.0/14 110.92.68.0/22 110.93.32.0/19 110.94.0.0/15 110.96.0.0/11 110.152.0.0/14 110.156.0.0/15 110.166.0.0/15 110.172.192.0/18 110.173.0.0/19 110.173.32.0/20 110.173.64.0/19 110.173.192.0/19 110.176.0.0/12 110.192.0.0/11 110.228.0.0/14 110.232.32.0/19 110.236.0.0/15 110.240.0.0/12 111.0.0.0/10 111.66.0.0/16 111.67.192.0/20 111.68.64.0/19 111.72.0.0/13 111.85.0.0/16 111.91.192.0/19 111.92.248.0/21 111.112.0.0/14 111.116.0.0/15 111.118.200.0/21 111.119.64.0/18 111.119.128.0/19 111.120.0.0/14 111.124.0.0/16 111.126.0.0/15 111.128.0.0/11 111.160.0.0/13 111.170.0.0/16 111.172.0.0/14 111.176.0.0/13 111.186.0.0/15 111.192.0.0/12 111.208.0.0/13 111.221.28.0/24 111.221.128.0/17 111.222.0.0/16 111.223.4.0/22 111.223.8.0/21 111.223.16.0/22 111.223.240.0/22 111.223.249.0/24 111.223.250.0/23 111.224.0.0/13 111.235.96.0/19 111.235.156.0/22 111.235.160.0/21 111.235.170.0/23 111.235.172.0/22 111.235.176.0/20 112.0.0.0/10 112.64.0.0/14 112.73.64.0/18 112.74.0.0/16 112.80.0.0/12 112.96.0.0/13 112.109.128.0/17 112.111.0.0/16 112.112.0.0/14 112.116.0.0/15 112.122.0.0/15 112.124.0.0/14 112.128.0.0/14 112.132.0.0/16 112.137.48.0/21 112.192.0.0/14 112.224.0.0/11 113.0.0.0/13 113.8.0.0/15 113.11.192.0/19 113.12.0.0/14 113.16.0.0/15 113.18.0.0/16 113.21.232.0/21 113.24.0.0/14 113.31.0.0/16 113.44.0.0/14 113.48.0.0/14 113.52.160.0/19 113.52.228.0/22 113.54.0.0/15 113.56.0.0/15 113.58.0.0/16 113.59.0.0/17 113.59.224.0/22 113.62.0.0/15 113.64.0.0/10 113.128.0.0/15 113.130.96.0/20 113.130.112.0/21 113.132.0.0/14 113.136.0.0/13 113.194.0.0/15 113.197.100.0/23 113.197.102.0/24 113.197.104.0/22 113.200.0.0/15 113.202.0.0/16 113.204.0.0/14 113.208.96.0/19 113.208.128.0/17 113.209.0.0/16 113.212.0.0/18 113.212.100.0/22 113.212.184.0/21 113.213.0.0/17 113.214.0.0/15 113.218.0.0/15 113.220.0.0/14 113.224.0.0/12 113.240.0.0/13 113.248.0.0/14 114.28.0.0/17 114.28.128.0/18 114.28.192.0/19 114.28.232.0/22 114.28.236.0/23 114.28.240.0/20 114.31.64.0/21 114.54.0.0/15 114.60.0.0/14 114.64.0.0/14 114.68.0.0/16 114.79.64.0/18 114.80.0.0/12 114.96.0.0/13 114.104.0.0/14 114.110.0.0/20 114.110.64.0/18 114.111.0.0/19 114.111.160.0/19 114.112.4.0/22 114.112.8.0/22 114.112.24.0/21 114.112.32.0/19 114.112.64.0/19 114.112.96.0/20 114.112.116.0/22 114.112.120.0/21 114.112.136.0/21 114.112.144.0/20 114.112.160.0/19 114.112.192.0/19 114.113.0.0/17 114.113.128.0/21 114.113.140.0/22 114.113.144.0/20 114.113.160.0/19 114.113.196.0/22 114.113.200.0/21 114.113.208.0/20 114.113.224.0/20 114.114.0.0/15 114.116.0.0/15 114.118.0.0/16 114.119.0.0/17 114.119.192.0/18 114.132.0.0/16 114.135.0.0/16 114.138.0.0/15 114.141.64.0/21 114.141.80.0/21 114.141.128.0/18 114.196.0.0/15 114.198.248.0/21 114.208.0.0/12 114.224.0.0/11 115.24.0.0/14 115.28.0.0/15 115.31.64.0/20 115.32.0.0/14 115.42.56.0/22 115.44.0.0/14 115.48.0.0/12 115.69.64.0/20 115.84.0.0/18 115.84.192.0/19 115.85.192.0/18 115.100.0.0/14 115.104.0.0/14 115.120.0.0/14 115.124.16.0/20 115.148.0.0/14 115.152.0.0/13 115.166.64.0/19 115.168.0.0/16 115.169.0.0/23 115.169.3.0/24 115.169.6.0/24 115.169.9.0/24 115.169.14.0/23 115.169.16.0/20 115.169.39.0/24 115.169.42.0/23 115.169.44.0/22 115.169.48.0/20 115.169.64.0/18 115.169.128.0/17 115.170.0.0/15 115.172.0.0/14 115.180.0.0/14 115.187.0.0/20 115.190.0.0/15 115.192.0.0/11 115.224.0.0/12 116.0.8.0/21 116.0.24.0/21 116.1.0.0/16 116.2.0.0/15 116.4.0.0/14 116.8.0.0/14 116.13.0.0/16 116.16.0.0/12 116.50.0.0/20 116.52.0.0/14 116.56.0.0/15 116.58.128.0/20 116.58.208.0/20 116.60.0.0/14 116.66.0.0/18 116.66.64.0/19 116.66.96.0/20 116.66.120.0/22 116.68.136.0/21 116.68.176.0/21 116.69.0.0/16 116.70.0.0/17 116.76.0.0/14 116.85.0.0/17 116.85.128.0/18 116.85.192.0/19 116.85.224.0/20 116.85.240.0/21 116.85.248.0/23 116.85.250.0/24 116.85.252.0/22 116.89.144.0/20 116.90.80.0/20 116.90.184.0/21 116.95.0.0/16 116.112.0.0/14 116.116.0.0/15 116.128.0.0/10 116.192.0.0/16 116.193.16.0/20 116.193.32.0/19 116.193.176.0/21 116.194.0.0/15 116.196.0.0/21 116.196.8.0/22 116.196.12.0/23 116.196.16.0/20 116.196.32.0/19 116.196.64.0/18 116.196.128.0/18 116.196.192.0/21 116.196.200.0/23 116.196.203.0/24 116.196.204.0/22 116.196.208.0/20 116.196.224.0/19 116.197.160.0/21 116.197.180.0/23 116.198.0.0/16 116.199.0.0/17 116.199.128.0/19 116.204.0.0/17 116.204.232.0/22 116.205.0.0/16 116.207.0.0/16 116.208.0.0/14 116.212.160.0/20 116.213.64.0/18 116.213.128.0/17 116.214.32.0/19 116.214.64.0/20 116.214.128.0/17 116.215.0.0/16 116.216.0.0/14 116.224.0.0/12 116.242.0.0/15 116.244.0.0/14 116.248.0.0/15 116.252.0.0/15 116.254.104.0/21 116.254.129.0/24 116.254.130.0/23 116.254.132.0/22 116.254.136.0/21 116.254.144.0/20 116.254.160.0/19 116.254.192.0/18 116.255.128.0/17 117.8.0.0/13 117.21.0.0/16 117.22.0.0/15 117.24.0.0/13 117.32.0.0/13 117.40.0.0/14 117.44.0.0/15 117.48.0.0/15 117.50.0.0/16 117.51.128.0/23 117.51.131.0/24 117.51.132.0/22 117.51.136.0/21 117.51.144.0/20 117.51.160.0/19 117.51.192.0/18 117.53.48.0/20 117.53.176.0/20 117.57.0.0/16 117.58.0.0/18 117.59.0.0/16 117.60.0.0/14 117.64.0.0/13 117.72.0.0/15 117.74.64.0/19 117.74.128.0/17 117.75.0.0/16 117.76.0.0/14 117.80.0.0/12 117.100.0.0/15 117.103.16.0/20 117.103.40.0/21 117.103.72.0/21 117.103.128.0/20 117.104.168.0/21 117.106.0.0/15 117.112.0.0/13 117.120.64.0/18 117.120.128.0/17 117.121.0.0/19 117.121.32.0/21 117.121.40.0/22 117.121.44.0/23 117.121.46.0/24 117.121.48.0/20 117.121.64.0/18 117.121.128.0/20 117.121.148.0/22 117.121.152.0/21 117.121.160.0/19 117.121.192.0/21 117.122.128.0/17 117.124.0.0/14 117.128.0.0/10 118.24.0.0/15 118.26.0.0/19 118.26.36.0/22 118.26.40.0/21 118.26.48.0/20 118.26.64.0/19 118.26.104.0/21 118.26.112.0/20 118.26.128.0/17 118.28.0.0/15 118.30.0.0/20 118.30.16.0/21 118.30.24.0/22 118.30.32.0/19 118.30.64.0/18 118.30.128.0/17 118.31.0.0/16 118.64.0.0/15 118.66.0.0/16 118.67.112.0/20 118.72.0.0/13 118.80.0.0/15 118.84.0.0/15 118.88.32.0/19 118.88.64.0/18 118.88.128.0/17 118.89.0.0/16 118.102.16.0/20 118.102.32.0/21 118.103.164.0/22 118.103.168.0/21 118.103.176.0/22 118.103.245.0/24 118.103.246.0/23 118.112.0.0/13 118.120.0.0/14 118.124.0.0/15 118.126.1.0/24 118.126.2.0/23 118.126.4.0/22 118.126.8.0/21 118.126.16.0/23 118.126.18.0/24 118.126.32.0/19 118.126.64.0/18 118.126.128.0/17 118.127.128.0/19 118.132.0.0/14 118.144.0.0/14 118.178.0.0/16 118.180.0.0/14 118.184.5.0/24 118.184.10.0/24 118.184.115.0/24 118.184.116.0/22 118.184.120.0/23 118.184.122.0/24 118.184.128.0/18 118.184.192.0/19 118.184.240.0/20 118.186.0.0/15 118.188.0.0/16 118.190.0.0/16 118.191.0.0/20 118.191.24.0/21 118.191.32.0/19 118.191.64.0/18 118.191.144.0/21 118.191.153.0/24 118.191.154.0/23 118.191.156.0/22 118.191.160.0/19 118.191.192.0/20 118.191.209.0/24 118.191.210.0/23 118.191.212.0/22 118.191.248.0/21 118.192.0.0/16 118.193.0.0/22 118.193.32.0/20 118.193.56.0/21 118.193.68.0/22 118.193.72.0/24 118.193.77.0/24 118.193.96.0/19 118.194.0.0/17 118.194.128.0/18 118.194.192.0/19 118.194.232.0/21 118.194.240.0/20 118.195.0.0/16 118.196.0.0/14 118.202.0.0/15 118.204.0.0/14 118.212.0.0/15 118.215.192.0/18 118.224.0.0/14 118.228.0.0/17 118.228.128.0/20 118.228.144.0/21 118.228.156.0/22 118.228.160.0/19 118.228.192.0/18 118.229.0.0/16 118.230.0.0/16 118.239.0.0/16 118.242.0.0/16 118.244.0.0/14 118.248.0.0/13 119.0.0.0/15 119.2.0.0/19 119.2.128.0/17 119.3.0.0/16 119.4.0.0/14 119.10.0.0/17 119.15.136.0/21 119.16.0.0/16 119.18.192.0/20 119.18.208.0/21 119.18.224.0/19 119.19.0.0/16 119.20.0.0/14 119.27.64.0/18 119.27.128.0/17 119.28.28.0/24 119.29.0.0/16 119.30.48.0/20 119.31.192.0/19 119.32.0.0/14 119.36.0.0/15 119.38.0.0/17 119.38.128.0/18 119.38.192.0/20 119.38.208.0/22 119.38.212.0/23 119.38.214.0/27 119.38.214.56/29 119.38.214.64/26 119.38.214.128/25 119.38.215.0/24 119.38.216.0/21 119.39.0.0/16 119.40.0.0/18 119.40.64.0/20 119.40.128.0/17 119.41.0.0/16 119.42.0.0/19 119.42.52.0/22 119.42.128.0/20 119.42.224.0/19 119.44.0.0/15 119.48.0.0/13 119.57.0.0/16 119.58.0.0/16 119.59.128.0/17 119.60.0.0/15 119.62.0.0/16 119.63.32.0/19 119.75.208.0/20 119.78.0.0/15 119.80.0.0/16 119.82.208.0/20 119.84.0.0/14 119.88.0.0/16 119.89.0.0/17 119.89.128.0/21 119.89.136.0/23 119.89.139.0/24 119.89.140.0/22 119.89.144.0/20 119.89.160.0/20 119.89.176.0/22 119.89.180.0/23 119.89.183.0/24 119.89.184.0/21 119.89.192.0/23 119.89.194.0/24 119.89.196.0/22 119.89.200.0/21 119.89.208.0/21 119.89.217.0/24 119.89.218.0/23 119.89.220.0/22 119.89.224.0/19 119.90.0.0/15 119.96.0.0/13 119.108.0.0/15 119.112.0.0/12 119.128.0.0/12 119.144.0.0/14 119.148.160.0/19 119.151.192.0/18 119.160.200.0/21 119.161.120.0/21 119.161.128.0/21 119.161.160.0/19 119.161.192.0/18 119.162.0.0/15 119.164.0.0/14 119.176.0.0/12 119.232.0.0/15 119.235.128.0/19 119.235.160.0/20 119.235.184.0/22 119.248.0.0/14 119.252.96.0/21 119.252.240.0/21 119.252.249.0/24 119.252.252.0/23 119.253.0.0/16 119.254.0.0/15 120.0.0.0/12 120.24.0.0/14 120.30.0.0/15 120.32.0.0/12 120.48.0.0/15 120.52.0.0/14 120.64.0.0/13 120.72.32.0/19 120.72.128.0/17 120.76.0.0/14 120.80.0.0/13 120.88.8.0/21 120.90.0.0/15 120.92.0.0/17 120.92.128.0/18 120.92.192.0/22 120.92.198.0/23 120.92.200.0/21 120.92.208.0/20 120.92.224.0/19 120.94.0.0/15 120.128.0.0/13 120.136.16.0/21 120.136.128.0/18 120.137.0.0/17 120.143.128.0/19 120.192.0.0/10 121.0.8.0/21 121.0.16.0/20 121.4.0.0/15 121.8.0.0/13 121.16.0.0/12 121.32.0.0/13 121.40.0.0/14 121.46.0.0/18 121.46.76.0/22 121.46.128.0/17 121.47.0.0/16 121.48.0.0/15 121.50.8.0/21 121.51.0.0/16 121.52.160.0/19 121.52.208.0/20 121.52.224.0/19 121.54.176.0/21 121.55.0.0/18 121.56.0.0/15 121.58.0.0/17 121.58.136.0/21 121.58.144.0/20 121.58.160.0/21 121.59.0.0/16 121.60.0.0/14 121.68.0.0/14 121.76.0.0/15 121.79.128.0/18 121.89.0.0/16 121.100.128.0/17 121.101.0.0/18 121.101.208.0/20 121.192.0.0/13 121.200.192.0/21 121.201.0.0/16 121.204.0.0/14 121.224.0.0/12 121.248.0.0/14 121.255.0.0/16 122.0.64.0/18 122.0.128.0/17 122.4.0.0/14 122.10.132.0/23 122.10.136.0/23 122.10.196.0/23 122.10.216.0/22 122.10.228.0/22 122.10.232.0/21 122.10.240.0/21 122.10.248.0/22 122.11.0.0/17 122.12.0.0/15 122.14.0.0/17 122.14.192.0/18 122.48.0.0/16 122.49.0.0/18 122.51.0.0/16 122.64.0.0/11 122.96.0.0/15 122.98.144.0/20 122.98.160.0/21 122.98.172.0/22 122.98.176.0/20 122.98.192.0/21 122.98.232.0/21 122.98.240.0/20 122.102.0.0/20 122.102.64.0/19 122.112.0.0/18 122.112.64.0/19 122.112.96.0/22 122.112.107.0/24 122.112.118.0/24 122.112.122.0/24 122.112.125.0/24 122.112.128.0/17 122.113.0.0/16 122.114.0.0/16 122.115.0.0/18 122.115.80.0/20 122.115.96.0/19 122.115.128.0/17 122.119.0.0/16 122.128.100.0/22 122.128.120.0/21 122.136.0.0/13 122.144.128.0/17 122.152.192.0/18 122.156.0.0/14 122.188.0.0/14 122.192.0.0/14 122.198.0.0/16 122.200.40.0/21 122.200.64.0/18 122.201.48.0/20 122.204.0.0/14 122.224.0.0/12 122.240.0.0/13 122.248.24.0/21 122.248.48.0/20 122.255.64.0/21 123.0.128.0/21 123.0.136.0/23 123.0.139.0/24 123.0.140.0/22 123.0.144.0/20 123.0.160.0/19 123.4.0.0/14 123.8.0.0/13 123.49.130.0/23 123.49.132.0/22 123.49.136.0/22 123.49.152.0/21 123.49.160.0/19 123.49.192.0/18 123.50.160.0/19 123.52.0.0/14 123.56.0.0/15 123.58.0.0/18 123.58.64.0/20 123.58.80.0/21 123.58.88.0/22 123.58.96.0/19 123.58.128.0/17 123.59.0.0/16 123.61.0.0/16 123.62.0.0/16 123.64.0.0/11 123.96.0.0/15 123.98.0.0/17 123.99.128.0/17 123.100.0.0/19 123.100.232.0/24 123.101.0.0/16 123.103.0.0/20 123.103.16.0/21 123.103.24.0/22 123.103.28.0/23 123.103.30.0/24 123.103.32.0/19 123.103.64.0/18 123.108.134.0/24 123.108.138.0/23 123.108.140.0/24 123.108.142.0/24 123.108.208.0/20 123.112.0.0/12 123.128.0.0/13 123.137.0.0/16 123.138.0.0/15 123.144.0.0/12 123.160.0.0/12 123.176.60.0/22 123.176.80.0/20 123.177.0.0/16 123.178.0.0/15 123.180.0.0/14 123.184.0.0/13 123.196.0.0/15 123.199.128.0/17 123.206.0.0/15 123.232.0.0/14 123.242.0.0/17 123.242.192.0/21 123.244.0.0/14 123.249.0.0/16 123.253.109.0/24 123.253.110.0/24 123.253.240.0/22 123.254.96.0/21 124.6.64.0/18 124.14.0.0/15 124.16.0.0/15 124.20.0.0/14 124.28.192.0/18 124.29.0.0/17 124.31.0.0/16 124.40.112.0/20 124.40.128.0/18 124.40.192.0/19 124.40.240.0/22 124.42.0.0/16 124.47.0.0/18 124.64.0.0/15 124.66.0.0/17 124.67.0.0/16 124.68.0.0/17 124.68.128.0/18 124.68.192.0/19 124.68.224.0/20 124.68.240.0/23 124.68.242.0/24 124.68.244.0/23 124.68.254.0/23 124.69.0.0/16 124.70.0.0/15 124.72.0.0/13 124.88.0.0/13 124.108.8.0/21 124.108.40.0/21 124.109.96.0/21 124.112.0.0/14 124.116.0.0/15 124.118.0.0/16 124.119.0.0/17 124.119.128.0/18 124.119.192.0/19 124.119.224.0/20 124.119.240.0/22 124.119.244.0/23 124.119.246.0/25 124.119.246.128/26 124.119.246.192/27 124.119.246.224/28 124.119.246.240/29 124.119.246.248/30 124.119.246.254/31 124.119.247.0/24 124.119.248.0/21 124.126.0.0/15 124.128.0.0/13 124.147.128.0/17 124.150.137.0/24 124.151.0.0/16 124.152.0.0/16 124.160.0.0/13 124.172.0.0/14 124.192.0.0/15 124.196.0.0/16 124.200.0.0/13 124.220.0.0/14 124.224.0.0/12 124.240.0.0/17 124.240.128.0/18 124.242.0.0/16 124.243.192.0/18 124.248.0.0/17 124.249.0.0/16 124.250.0.0/15 124.254.0.0/18 125.31.192.0/18 125.32.0.0/12 125.58.128.0/17 125.61.128.0/17 125.62.0.0/18 125.64.0.0/11 125.96.0.0/15 125.98.0.0/16 125.104.0.0/13 125.112.0.0/12 125.169.0.0/16 125.171.0.0/16 125.208.0.0/19 125.208.37.0/24 125.208.40.0/24 125.208.45.0/24 125.208.46.0/23 125.208.48.0/20 125.210.0.0/15 125.213.0.0/17 125.214.96.0/19 125.215.0.0/18 125.216.0.0/13 125.254.128.0/17 128.108.0.0/16 129.28.0.0/16 129.204.0.0/16 129.211.0.0/16 129.223.254.0/24 129.227.99.0/24 130.36.146.0/23 130.214.218.0/23 131.228.96.0/24 131.253.12.0/29 131.253.12.80/28 131.253.12.240/29 132.232.0.0/16 132.237.134.0/24 132.237.150.0/24 134.175.0.0/16 135.159.208.0/20 135.244.80.0/20 137.59.59.0/24 137.59.88.0/22 138.32.244.0/22 139.5.56.0/21 139.5.80.0/22 139.5.92.0/22 139.5.128.0/22 139.5.160.0/22 139.5.192.0/22 139.5.204.0/22 139.5.244.0/22 139.9.0.0/16 139.129.0.0/16 139.138.238.0/28 139.148.0.0/16 139.155.0.0/16 139.159.0.0/19 139.159.32.0/21 139.159.40.0/22 139.159.52.0/22 139.159.56.0/21 139.159.64.0/19 139.159.96.0/20 139.159.112.0/22 139.159.116.0/23 139.159.120.0/21 139.159.128.0/17 139.170.0.0/16 139.176.0.0/16 139.183.0.0/16 139.186.0.0/16 139.189.0.0/16 139.196.0.0/15 139.198.0.0/21 139.198.8.0/23 139.198.11.0/24 139.198.12.0/22 139.198.16.0/20 139.198.32.0/19 139.198.66.0/23 139.198.68.0/22 139.198.72.0/21 139.198.80.0/20 139.198.96.0/20 139.198.113.0/24 139.198.114.0/23 139.198.116.0/22 139.198.122.0/23 139.198.124.0/22 139.198.128.0/17 139.199.0.0/16 139.200.0.0/13 139.208.0.0/13 139.217.0.0/16 139.219.0.0/16 139.220.0.0/17 139.220.128.0/18 139.220.192.0/22 139.220.196.0/23 139.220.200.0/21 139.220.208.0/23 139.220.212.0/22 139.220.216.0/21 139.220.224.0/19 139.221.0.0/16 139.224.0.0/16 139.226.0.0/15 140.75.0.0/16 140.101.208.0/24 140.143.0.0/16 140.179.0.0/16 140.205.0.0/18 140.205.64.0/19 140.205.96.0/20 140.205.112.0/21 140.205.120.0/23 140.205.123.0/24 140.205.124.0/22 140.205.128.0/17 140.206.0.0/15 140.210.0.0/16 140.224.0.0/16 140.237.0.0/16 140.240.0.0/16 140.242.223.0/24 140.242.224.0/24 140.243.0.0/16 140.246.0.0/16 140.249.0.0/16 140.250.0.0/16 140.255.0.0/16 144.0.0.0/16 144.7.0.0/16 144.12.0.0/16 144.36.146.0/23 144.48.64.0/22 144.48.88.0/22 144.48.156.0/22 144.48.180.0/22 144.48.184.0/22 144.48.204.0/22 144.48.208.0/21 144.52.0.0/16 144.123.0.0/16 144.211.80.0/24 144.211.138.0/24 144.255.0.0/16 146.56.192.0/18 146.196.56.0/22 146.196.68.0/22 146.196.92.0/22 146.196.112.0/21 146.196.124.0/22 146.217.137.0/24 146.222.79.0/24 146.222.81.0/24 146.222.94.0/24 147.243.13.32/27 147.243.13.64/27 147.243.14.32/27 148.70.0.0/16 150.0.0.0/16 150.115.0.0/16 150.121.0.0/16 150.122.0.0/16 150.129.136.0/22 150.129.192.0/22 150.129.252.0/22 150.138.0.0/15 150.158.0.0/16 150.222.88.0/23 150.223.0.0/16 150.242.0.0/21 150.242.8.0/22 150.242.28.0/22 150.242.44.0/22 150.242.48.0/21 150.242.56.0/22 150.242.76.0/22 150.242.80.0/22 150.242.92.0/22 150.242.96.0/22 150.242.112.0/21 150.242.120.0/22 150.242.152.0/22 150.242.158.0/24 150.242.160.0/21 150.242.168.0/22 150.242.184.0/21 150.242.192.0/22 150.242.224.0/22 150.242.232.0/21 150.242.240.0/21 150.242.248.0/22 150.255.0.0/16 152.32.178.0/23 152.104.128.0/17 152.136.0.0/16 153.0.0.0/16 153.3.0.0/16 153.34.0.0/15 153.36.0.0/15 153.99.0.0/16 153.101.0.0/16 153.118.0.0/15 154.8.128.0/17 155.126.176.0/23 156.107.160.0/24 156.107.170.0/24 156.107.179.0/24 156.107.181.0/24 156.154.62.0/23 157.0.0.0/16 157.18.0.0/16 157.61.0.0/16 157.119.8.0/21 157.119.16.0/22 157.119.28.0/22 157.119.132.0/22 157.119.136.0/21 157.119.144.0/20 157.119.160.0/21 157.119.172.0/22 157.119.192.0/21 157.119.240.0/22 157.119.252.0/22 157.122.0.0/16 157.133.186.0/23 157.133.192.0/21 157.133.212.0/24 157.133.236.0/24 157.148.0.0/16 157.156.0.0/16 157.255.0.0/16 159.75.0.0/16 159.221.232.0/22 159.226.0.0/16 160.19.208.0/21 160.19.216.0/22 160.20.48.0/22 160.62.10.0/24 160.83.109.0/24 160.83.110.0/23 160.202.60.0/23 160.202.62.0/24 160.202.148.0/22 160.202.152.0/22 160.202.212.0/22 160.202.216.0/21 160.202.224.0/19 160.238.64.0/22 161.163.0.0/21 161.163.28.0/23 161.163.176.0/24 161.163.178.0/23 161.163.180.0/22 161.189.0.0/16 161.207.0.0/16 162.14.0.0/16 162.105.0.0/16 163.0.0.0/16 163.47.4.0/22 163.53.0.0/20 163.53.36.0/22 163.53.40.0/22 163.53.48.0/20 163.53.64.0/22 163.53.88.0/21 163.53.96.0/19 163.53.128.0/21 163.53.136.0/22 163.53.160.0/20 163.53.188.0/22 163.53.220.0/22 163.53.236.0/22 163.53.240.0/22 163.116.202.0/23 163.125.0.0/16 163.142.0.0/16 163.177.0.0/16 163.179.0.0/16 163.204.0.0/16 163.244.246.0/24 164.52.80.0/24 165.156.30.0/24 166.111.0.0/16 167.139.0.0/16 167.189.0.0/16 167.220.244.0/22 168.159.144.0/21 168.159.152.0/22 168.159.156.0/23 168.159.158.0/24 168.160.0.0/16 168.230.0.0/24 170.179.0.0/16 170.225.224.0/23 170.252.152.0/21 171.8.0.0/13 171.22.147.0/24 171.34.0.0/15 171.36.0.0/14 171.40.0.0/13 171.80.0.0/12 171.104.0.0/13 171.112.0.0/12 171.208.0.0/12 172.60.2.0/24 172.81.192.0/18 173.39.200.0/23 175.0.0.0/12 175.16.0.0/13 175.24.0.0/14 175.30.0.0/15 175.42.0.0/15 175.44.0.0/16 175.46.0.0/15 175.48.0.0/12 175.64.0.0/11 175.102.0.0/16 175.106.128.0/17 175.111.144.0/20 175.111.160.0/20 175.111.184.0/22 175.146.0.0/15 175.148.0.0/14 175.152.0.0/14 175.158.96.0/22 175.160.0.0/12 175.176.156.0/22 175.176.188.0/22 175.178.0.0/16 175.184.128.0/18 175.185.0.0/16 175.186.0.0/15 175.188.0.0/14 180.76.16.0/20 180.76.32.0/19 180.76.64.0/18 180.76.128.0/18 180.76.192.0/19 180.76.224.0/20 180.76.240.0/24 180.76.242.0/23 180.76.244.0/22 180.76.248.0/22 180.76.252.0/23 180.76.255.0/24 180.77.0.0/16 180.78.0.0/15 180.84.0.0/15 180.86.0.0/16 180.88.0.0/14 180.94.56.0/21 180.94.96.0/20 180.94.120.0/21 180.95.128.0/17 180.96.0.0/11 180.129.128.0/17 180.130.0.0/16 180.136.0.0/13 180.148.16.0/21 180.148.152.0/21 180.148.216.0/21 180.148.224.0/19 180.149.128.0/19 180.150.160.0/21 180.150.176.0/20 180.152.0.0/13 180.160.0.0/12 180.178.112.0/21 180.178.192.0/18 180.184.0.0/14 180.188.0.0/17 180.189.148.0/22 180.200.252.0/22 180.201.0.0/16 180.202.0.0/15 180.208.0.0/15 180.210.212.0/22 180.210.233.0/24 180.210.236.0/22 180.212.0.0/15 180.222.224.0/19 180.223.0.0/19 180.223.32.0/20 180.223.48.0/21 180.223.57.0/24 180.223.58.0/23 180.223.60.0/22 180.223.80.0/20 180.223.96.0/19 180.223.128.0/17 180.233.0.0/18 180.233.64.0/19 180.233.144.0/22 180.235.64.0/19 180.235.112.0/22 182.16.144.0/21 182.16.192.0/19 182.18.0.0/17 182.23.184.0/21 182.23.200.0/21 182.32.0.0/12 182.48.96.0/19 182.49.0.0/16 182.50.0.0/22 182.50.8.0/21 182.50.112.0/20 182.51.0.0/16 182.54.0.0/17 182.61.0.0/18 182.61.128.0/19 182.61.192.0/18 182.80.0.0/13 182.88.0.0/14 182.92.0.0/16 182.96.0.0/11 182.128.0.0/12 182.144.0.0/13 182.157.0.0/16 182.160.64.0/19 182.174.0.0/15 182.200.0.0/13 182.236.128.0/17 182.237.24.0/21 182.238.0.0/16 182.239.0.0/19 182.240.0.0/13 182.254.0.0/17 182.254.128.0/18 182.254.192.0/19 182.254.224.0/20 182.254.240.0/21 182.254.248.0/23 182.254.251.0/24 182.254.252.0/22 183.0.0.0/10 183.64.0.0/13 183.78.160.0/21 183.78.180.0/22 183.81.180.0/22 183.84.0.0/15 183.91.128.0/22 183.91.136.0/21 183.91.144.0/20 183.92.0.0/14 183.128.0.0/11 183.160.0.0/13 183.168.0.0/15 183.170.0.0/16 183.172.0.0/14 183.184.0.0/13 183.192.0.0/10 185.109.236.0/24 185.216.118.0/24 188.131.128.0/17 192.11.23.0/24 192.11.26.0/24 192.11.39.0/24 192.11.236.0/24 192.23.191.0/24 192.55.10.0/23 192.55.40.0/24 192.55.46.0/24 192.55.68.0/22 192.102.204.0/22 192.124.154.0/24 192.137.31.0/24 192.139.136.0/24 192.140.128.0/21 192.140.136.0/22 192.140.156.0/22 192.140.160.0/19 192.140.192.0/20 192.140.208.0/21 192.144.128.0/17 192.163.11.0/24 192.232.97.0/24 193.9.22.0/24 193.17.120.0/22 193.20.64.0/22 193.112.0.0/16 193.200.196.0/24 193.200.222.160/28 194.138.136.0/24 194.138.202.0/23 194.138.245.0/24 198.175.100.0/22 198.208.17.0/24 198.208.19.0/24 199.7.72.0/24 199.65.192.0/21 199.244.144.0/24 202.0.100.0/23 202.0.122.0/23 202.1.105.0/24 202.1.106.0/24 202.3.128.0/23 202.4.128.0/19 202.4.252.0/22 202.5.208.0/21 202.5.216.0/22 202.6.6.0/23 202.6.66.0/23 202.6.72.0/23 202.6.87.0/24 202.6.88.0/23 202.6.92.0/23 202.6.103.0/24 202.6.108.0/24 202.6.110.0/23 202.6.114.0/24 202.6.176.0/20 202.8.0.0/24 202.8.2.0/23 202.8.4.0/23 202.8.12.0/24 202.8.24.0/24 202.8.77.0/24 202.8.128.0/19 202.8.192.0/20 202.9.32.0/24 202.9.34.0/23 202.9.48.0/23 202.9.51.0/24 202.9.52.0/23 202.9.54.0/24 202.9.57.0/24 202.9.58.0/23 202.10.64.0/21 202.10.74.0/23 202.10.76.0/22 202.10.112.0/20 202.12.1.0/24 202.12.2.0/24 202.12.17.0/24 202.12.18.0/23 202.12.72.0/24 202.12.84.0/23 202.12.96.0/24 202.12.98.0/23 202.12.106.0/24 202.12.111.0/24 202.12.116.0/24 202.14.64.0/23 202.14.69.0/24 202.14.73.0/24 202.14.74.0/23 202.14.76.0/24 202.14.78.0/23 202.14.88.0/24 202.14.97.0/24 202.14.104.0/23 202.14.108.0/23 202.14.111.0/24 202.14.114.0/23 202.14.118.0/23 202.14.124.0/23 202.14.127.0/24 202.14.129.0/24 202.14.135.0/24 202.14.136.0/24 202.14.149.0/24 202.14.151.0/24 202.14.157.0/24 202.14.158.0/23 202.14.169.0/24 202.14.170.0/23 202.14.172.0/22 202.14.176.0/24 202.14.184.0/23 202.14.208.0/23 202.14.213.0/24 202.14.219.0/24 202.14.220.0/24 202.14.222.0/23 202.14.225.0/24 202.14.226.0/23 202.14.231.0/24 202.14.235.0/24 202.14.236.0/22 202.14.246.0/24 202.14.251.0/24 202.20.66.0/24 202.20.79.0/24 202.20.87.0/24 202.20.88.0/23 202.20.90.0/24 202.20.94.0/23 202.20.114.0/24 202.20.117.0/24 202.20.120.0/24 202.20.125.0/24 202.20.126.0/23 202.21.48.0/20 202.21.131.0/24 202.21.132.0/24 202.21.141.0/24 202.21.142.0/24 202.21.147.0/24 202.21.148.0/24 202.21.150.0/23 202.21.152.0/23 202.21.154.0/24 202.21.156.0/24 202.21.208.0/24 202.22.248.0/21 202.27.12.0/24 202.27.14.0/24 202.27.136.0/23 202.36.226.0/24 202.38.0.0/22 202.38.8.0/21 202.38.48.0/20 202.38.64.0/18 202.38.128.0/21 202.38.136.0/23 202.38.138.0/24 202.38.140.0/22 202.38.146.0/23 202.38.149.0/24 202.38.150.0/23 202.38.152.0/22 202.38.156.0/24 202.38.158.0/23 202.38.160.0/23 202.38.164.0/22 202.38.168.0/22 202.38.176.0/23 202.38.184.0/21 202.38.192.0/18 202.40.4.0/23 202.40.7.0/24 202.40.15.0/24 202.40.135.0/24 202.40.136.0/24 202.40.140.0/24 202.40.143.0/24 202.40.144.0/23 202.40.150.0/24 202.40.155.0/24 202.40.156.0/24 202.40.158.0/23 202.40.162.0/24 202.41.8.0/23 202.41.11.0/24 202.41.12.0/23 202.41.128.0/24 202.41.130.0/23 202.41.142.0/24 202.41.152.0/21 202.41.192.0/24 202.41.196.0/22 202.41.200.0/22 202.41.240.0/20 202.43.76.0/22 202.43.144.0/20 202.44.16.0/20 202.44.48.0/22 202.44.67.0/24 202.44.74.0/24 202.44.97.0/24 202.44.129.0/24 202.44.132.0/23 202.44.146.0/23 202.45.0.0/23 202.45.2.0/24 202.45.15.0/24 202.45.16.0/20 202.46.16.0/23 202.46.18.0/24 202.46.20.0/23 202.46.128.0/24 202.46.224.0/20 202.47.82.0/23 202.47.96.0/20 202.47.126.0/24 202.47.128.0/24 202.47.130.0/23 202.52.34.0/24 202.52.143.0/24 202.53.140.0/24 202.53.143.0/24 202.53.202.0/24 202.57.212.0/22 202.57.216.0/22 202.57.240.0/20 202.58.0.0/24 202.58.112.0/22 202.59.0.0/23 202.59.212.0/22 202.59.236.0/24 202.59.240.0/24 202.60.48.0/21 202.60.96.0/21 202.60.112.0/20 202.60.132.0/22 202.60.136.0/21 202.60.144.0/20 202.61.68.0/22 202.61.76.0/22 202.61.88.0/22 202.61.123.0/24 202.61.127.0/24 202.62.112.0/22 202.62.248.0/22 202.62.252.0/24 202.62.255.0/24 202.63.80.0/20 202.63.160.0/19 202.63.248.0/22 202.63.253.0/24 202.65.0.0/21 202.65.8.0/23 202.67.0.0/22 202.69.4.0/23 202.69.16.0/20 202.70.0.0/19 202.70.96.0/20 202.70.192.0/20 202.71.32.0/20 202.72.40.0/21 202.72.80.0/20 202.72.112.0/20 202.73.128.0/22 202.73.240.0/20 202.74.8.0/21 202.74.36.0/24 202.74.42.0/24 202.74.52.0/24 202.74.80.0/20 202.74.254.0/23 202.75.208.0/20 202.75.252.0/22 202.76.247.0/24 202.76.252.0/22 202.77.80.0/21 202.77.92.0/22 202.78.8.0/21 202.79.224.0/21 202.79.248.0/22 202.80.192.0/20 202.81.0.0/22 202.81.176.0/20 202.83.252.0/22 202.84.0.0/20 202.84.16.0/23 202.84.22.0/24 202.84.24.0/21 202.85.208.0/20 202.86.249.0/24 202.87.80.0/20 202.88.32.0/22 202.89.8.0/21 202.89.96.0/22 202.89.108.0/22 202.89.119.0/24 202.89.232.0/21 202.90.0.0/22 202.90.16.0/20 202.90.37.0/24 202.90.96.0/19 202.90.193.0/24 202.90.196.0/24 202.90.205.0/24 202.90.224.0/20 202.91.0.0/22 202.91.96.0/20 202.91.128.0/22 202.91.176.0/20 202.91.224.0/19 202.92.0.0/22 202.92.8.0/21 202.92.48.0/20 202.92.252.0/22 202.93.0.0/22 202.93.252.0/22 202.94.0.0/19 202.94.74.0/24 202.94.81.0/24 202.94.92.0/22 202.95.240.0/21 202.95.252.0/22 202.96.0.0/12 202.112.0.0/13 202.120.0.0/15 202.122.0.0/21 202.122.32.0/21 202.122.64.0/19 202.122.112.0/20 202.122.128.0/24 202.122.132.0/24 202.123.96.0/20 202.123.116.0/22 202.123.120.0/22 202.124.16.0/21 202.124.24.0/22 202.125.107.0/24 202.125.109.0/24 202.125.112.0/20 202.125.176.0/20 202.127.0.0/21 202.127.12.0/22 202.127.16.0/20 202.127.40.0/21 202.127.48.0/20 202.127.112.0/20 202.127.128.0/19 202.127.160.0/21 202.127.192.0/20 202.127.208.0/23 202.127.212.0/22 202.127.216.0/21 202.127.224.0/19 202.129.208.0/24 202.130.0.0/19 202.130.39.0/24 202.130.224.0/19 202.131.16.0/21 202.131.59.0/24 202.131.208.0/20 202.133.32.0/20 202.134.58.0/24 202.134.128.0/20 202.134.208.0/20 202.136.48.0/20 202.136.208.0/20 202.136.224.0/20 202.136.248.0/22 202.136.254.0/23 202.137.231.0/24 202.140.140.0/22 202.140.144.0/20 202.141.160.0/19 202.142.16.0/20 202.143.4.0/22 202.143.16.0/20 202.143.32.0/20 202.143.56.0/21 202.143.100.0/22 202.143.104.0/22 202.146.160.0/20 202.146.186.0/24 202.146.188.0/22 202.146.196.0/22 202.146.200.0/21 202.147.144.0/20 202.148.32.0/20 202.148.64.0/18 202.149.32.0/19 202.149.160.0/19 202.149.224.0/19 202.150.16.0/20 202.150.32.0/20 202.150.56.0/22 202.150.192.0/20 202.150.224.0/19 202.151.0.0/22 202.151.128.0/19 202.152.176.0/20 202.153.0.0/22 202.153.7.0/24 202.153.48.0/20 202.157.192.0/19 202.158.160.0/19 202.158.242.0/24 202.160.140.0/22 202.160.156.0/22 202.160.176.0/20 202.162.67.0/24 202.162.75.0/24 202.164.0.0/20 202.164.96.0/19 202.165.176.0/20 202.165.208.0/20 202.165.239.0/24 202.165.240.0/23 202.165.243.0/24 202.165.245.0/24 202.165.251.0/24 202.165.252.0/22 202.166.224.0/19 202.168.80.0/22 202.168.128.0/20 202.168.160.0/19 202.170.128.0/19 202.170.216.0/21 202.170.224.0/19 202.171.216.0/21 202.171.232.0/24 202.171.235.0/24 202.172.0.0/22 202.172.7.0/24 202.173.0.0/22 202.173.6.0/24 202.173.8.0/21 202.173.112.0/22 202.173.224.0/19 202.174.64.0/20 202.174.124.0/22 202.176.224.0/19 202.179.160.0/20 202.179.240.0/20 202.180.128.0/19 202.180.208.0/21 202.181.8.0/22 202.181.28.0/22 202.181.112.0/20 202.182.32.0/20 202.182.192.0/19 202.189.0.0/18 202.189.80.0/20 202.189.184.0/21 202.191.0.0/24 202.191.68.0/22 202.191.72.0/21 202.191.80.0/20 202.192.0.0/12 203.0.4.0/22 203.0.10.0/23 203.0.18.0/24 203.0.24.0/24 203.0.42.0/23 203.0.45.0/24 203.0.46.0/23 203.0.81.0/24 203.0.82.0/23 203.0.90.0/23 203.0.96.0/23 203.0.104.0/21 203.0.114.0/23 203.0.122.0/24 203.0.128.0/24 203.0.130.0/23 203.0.132.0/22 203.0.137.0/24 203.0.142.0/24 203.0.144.0/24 203.0.146.0/24 203.0.148.0/24 203.0.150.0/23 203.0.152.0/24 203.0.177.0/24 203.0.224.0/24 203.1.4.0/22 203.1.18.0/24 203.1.26.0/23 203.1.65.0/24 203.1.66.0/23 203.1.70.0/23 203.1.76.0/23 203.1.90.0/24 203.1.97.0/24 203.1.98.0/23 203.1.100.0/22 203.1.108.0/24 203.1.253.0/24 203.1.254.0/24 203.2.64.0/21 203.2.73.0/24 203.2.112.0/21 203.2.126.0/23 203.2.140.0/24 203.2.150.0/24 203.2.152.0/22 203.2.156.0/23 203.2.160.0/21 203.2.180.0/23 203.2.196.0/23 203.2.209.0/24 203.2.214.0/23 203.2.226.0/23 203.2.229.0/24 203.2.236.0/23 203.3.68.0/24 203.3.72.0/23 203.3.75.0/24 203.3.80.0/21 203.3.96.0/22 203.3.105.0/24 203.3.112.0/21 203.3.120.0/24 203.3.123.0/24 203.3.135.0/24 203.3.139.0/24 203.3.143.0/24 203.4.132.0/23 203.4.134.0/24 203.4.151.0/24 203.4.152.0/22 203.4.174.0/23 203.4.180.0/24 203.4.186.0/24 203.4.205.0/24 203.4.208.0/22 203.4.227.0/24 203.4.230.0/23 203.5.4.0/23 203.5.7.0/24 203.5.8.0/23 203.5.11.0/24 203.5.21.0/24 203.5.22.0/24 203.5.44.0/24 203.5.46.0/23 203.5.52.0/22 203.5.56.0/23 203.5.60.0/23 203.5.114.0/23 203.5.118.0/24 203.5.120.0/24 203.5.172.0/24 203.5.180.0/23 203.5.182.0/24 203.5.185.0/24 203.5.186.0/24 203.5.188.0/23 203.5.190.0/24 203.5.195.0/24 203.5.214.0/23 203.5.218.0/23 203.6.131.0/24 203.6.136.0/24 203.6.138.0/23 203.6.142.0/24 203.6.150.0/23 203.6.157.0/24 203.6.159.0/24 203.6.224.0/20 203.6.248.0/23 203.7.129.0/24 203.7.138.0/23 203.7.147.0/24 203.7.150.0/23 203.7.158.0/24 203.7.192.0/23 203.7.200.0/24 203.8.0.0/24 203.8.8.0/24 203.8.23.0/24 203.8.70.0/24 203.8.82.0/24 203.8.86.0/23 203.8.91.0/24 203.8.110.0/23 203.8.115.0/24 203.8.166.0/23 203.8.169.0/24 203.8.173.0/24 203.8.184.0/24 203.8.186.0/23 203.8.190.0/23 203.8.192.0/24 203.8.197.0/24 203.8.198.0/23 203.8.203.0/24 203.8.209.0/24 203.8.210.0/23 203.8.212.0/22 203.8.217.0/24 203.8.220.0/24 203.9.32.0/24 203.9.36.0/23 203.9.57.0/24 203.9.63.0/24 203.9.65.0/24 203.9.70.0/23 203.9.72.0/24 203.9.75.0/24 203.9.76.0/23 203.9.96.0/22 203.9.100.0/23 203.9.108.0/24 203.9.158.0/24 203.10.34.0/24 203.10.56.0/24 203.10.74.0/23 203.10.84.0/22 203.10.88.0/24 203.10.95.0/24 203.10.125.0/24 203.11.70.0/24 203.11.76.0/22 203.11.82.0/24 203.11.84.0/22 203.11.100.0/22 203.11.109.0/24 203.11.117.0/24 203.11.122.0/24 203.11.126.0/24 203.11.136.0/22 203.11.141.0/24 203.11.142.0/23 203.11.180.0/22 203.11.208.0/22 203.12.16.0/24 203.12.19.0/24 203.12.24.0/24 203.12.57.0/24 203.12.65.0/24 203.12.66.0/24 203.12.70.0/23 203.12.87.0/24 203.12.90.0/24 203.12.92.0/22 203.12.100.0/23 203.12.103.0/24 203.12.114.0/24 203.12.118.0/24 203.12.130.0/24 203.12.137.0/24 203.12.196.0/22 203.12.211.0/24 203.12.219.0/24 203.12.226.0/24 203.12.240.0/22 203.13.18.0/24 203.13.24.0/24 203.13.44.0/23 203.13.88.0/23 203.13.92.0/22 203.13.173.0/24 203.13.224.0/23 203.13.227.0/24 203.13.233.0/24 203.14.24.0/22 203.14.33.0/24 203.14.56.0/24 203.14.61.0/24 203.14.62.0/24 203.14.104.0/24 203.14.114.0/23 203.14.118.0/24 203.14.162.0/24 203.14.184.0/21 203.14.192.0/24 203.14.194.0/23 203.14.214.0/24 203.14.231.0/24 203.14.246.0/24 203.15.0.0/20 203.15.20.0/23 203.15.22.0/24 203.15.87.0/24 203.15.88.0/23 203.15.105.0/24 203.15.112.0/21 203.15.130.0/23 203.15.149.0/24 203.15.151.0/24 203.15.156.0/22 203.15.174.0/24 203.15.227.0/24 203.15.232.0/22 203.15.238.0/23 203.15.240.0/23 203.15.246.0/24 203.16.10.0/24 203.16.12.0/23 203.16.16.0/21 203.16.27.0/24 203.16.38.0/24 203.16.49.0/24 203.16.50.0/23 203.16.58.0/24 203.16.63.0/24 203.16.133.0/24 203.16.161.0/24 203.16.162.0/24 203.16.186.0/23 203.16.228.0/24 203.16.238.0/24 203.16.240.0/24 203.16.245.0/24 203.17.2.0/24 203.17.18.0/24 203.17.28.0/24 203.17.39.0/24 203.17.56.0/24 203.17.74.0/23 203.17.88.0/23 203.17.136.0/24 203.17.164.0/24 203.17.187.0/24 203.17.190.0/23 203.17.231.0/24 203.17.233.0/24 203.17.248.0/23 203.17.255.0/24 203.18.2.0/23 203.18.4.0/24 203.18.7.0/24 203.18.31.0/24 203.18.37.0/24 203.18.48.0/23 203.18.52.0/24 203.18.72.0/22 203.18.80.0/23 203.18.87.0/24 203.18.100.0/23 203.18.105.0/24 203.18.107.0/24 203.18.110.0/24 203.18.129.0/24 203.18.131.0/24 203.18.132.0/23 203.18.144.0/24 203.18.153.0/24 203.18.199.0/24 203.18.208.0/24 203.18.211.0/24 203.18.215.0/24 203.19.1.0/24 203.19.18.0/24 203.19.24.0/24 203.19.30.0/24 203.19.41.0/24 203.19.44.0/23 203.19.46.0/24 203.19.58.0/24 203.19.60.0/23 203.19.64.0/24 203.19.68.0/24 203.19.72.0/24 203.19.101.0/24 203.19.111.0/24 203.19.131.0/24 203.19.133.0/24 203.19.144.0/24 203.19.147.0/24 203.19.149.0/24 203.19.156.0/24 203.19.176.0/24 203.19.178.0/23 203.19.208.0/24 203.19.228.0/22 203.19.233.0/24 203.19.242.0/24 203.19.248.0/23 203.19.255.0/24 203.20.17.0/24 203.20.40.0/23 203.20.44.0/24 203.20.48.0/24 203.20.61.0/24 203.20.65.0/24 203.20.84.0/23 203.20.89.0/24 203.20.106.0/23 203.20.115.0/24 203.20.117.0/24 203.20.118.0/23 203.20.122.0/24 203.20.126.0/23 203.20.135.0/24 203.20.140.0/22 203.20.150.0/24 203.20.230.0/24 203.20.232.0/24 203.20.236.0/24 203.21.0.0/23 203.21.2.0/24 203.21.8.0/24 203.21.10.0/24 203.21.18.0/24 203.21.33.0/24 203.21.34.0/24 203.21.41.0/24 203.21.44.0/24 203.21.68.0/24 203.21.82.0/24 203.21.96.0/22 203.21.124.0/24 203.21.136.0/23 203.21.145.0/24 203.21.206.0/24 203.22.24.0/24 203.22.28.0/23 203.22.31.0/24 203.22.68.0/24 203.22.76.0/24 203.22.84.0/24 203.22.87.0/24 203.22.92.0/22 203.22.99.0/24 203.22.106.0/24 203.22.122.0/23 203.22.131.0/24 203.22.163.0/24 203.22.166.0/24 203.22.170.0/24 203.22.176.0/21 203.22.194.0/24 203.22.242.0/23 203.22.245.0/24 203.22.246.0/24 203.22.252.0/23 203.23.0.0/24 203.23.47.0/24 203.23.61.0/24 203.23.62.0/23 203.23.73.0/24 203.23.85.0/24 203.23.92.0/22 203.23.98.0/24 203.23.107.0/24 203.23.112.0/24 203.23.130.0/24 203.23.140.0/23 203.23.172.0/24 203.23.182.0/24 203.23.186.0/23 203.23.192.0/24 203.23.197.0/24 203.23.198.0/24 203.23.204.0/22 203.23.224.0/24 203.23.226.0/23 203.23.228.0/22 203.23.249.0/24 203.23.251.0/24 203.24.13.0/24 203.24.18.0/24 203.24.27.0/24 203.24.43.0/24 203.24.56.0/24 203.24.58.0/24 203.24.67.0/24 203.24.74.0/24 203.24.79.0/24 203.24.80.0/23 203.24.84.0/23 203.24.86.0/24 203.24.90.0/24 203.24.111.0/24 203.24.112.0/24 203.24.116.0/24 203.24.122.0/23 203.24.145.0/24 203.24.152.0/23 203.24.157.0/24 203.24.161.0/24 203.24.167.0/24 203.24.186.0/23 203.24.199.0/24 203.24.202.0/24 203.24.212.0/23 203.24.217.0/24 203.24.219.0/24 203.24.244.0/24 203.25.19.0/24 203.25.20.0/23 203.25.46.0/24 203.25.64.0/23 203.25.91.0/24 203.25.99.0/24 203.25.100.0/24 203.25.106.0/24 203.25.131.0/24 203.25.135.0/24 203.25.138.0/24 203.25.147.0/24 203.25.153.0/24 203.25.154.0/23 203.25.164.0/24 203.25.166.0/24 203.25.174.0/23 203.25.180.0/24 203.25.182.0/24 203.25.191.0/24 203.25.199.0/24 203.25.200.0/24 203.25.202.0/23 203.25.208.0/20 203.25.229.0/24 203.25.235.0/24 203.25.236.0/24 203.25.242.0/24 203.26.12.0/24 203.26.34.0/24 203.26.49.0/24 203.26.50.0/24 203.26.55.0/24 203.26.56.0/23 203.26.60.0/24 203.26.65.0/24 203.26.68.0/24 203.26.76.0/24 203.26.80.0/24 203.26.84.0/24 203.26.97.0/24 203.26.102.0/23 203.26.115.0/24 203.26.116.0/24 203.26.129.0/24 203.26.143.0/24 203.26.144.0/24 203.26.148.0/23 203.26.154.0/24 203.26.158.0/23 203.26.161.0/24 203.26.170.0/24 203.26.173.0/24 203.26.176.0/24 203.26.185.0/24 203.26.202.0/23 203.26.210.0/24 203.26.214.0/24 203.26.222.0/24 203.26.224.0/24 203.26.228.0/24 203.26.232.0/24 203.27.0.0/24 203.27.10.0/24 203.27.15.0/24 203.27.16.0/24 203.27.20.0/24 203.27.22.0/23 203.27.40.0/24 203.27.45.0/24 203.27.53.0/24 203.27.65.0/24 203.27.66.0/24 203.27.81.0/24 203.27.88.0/24 203.27.102.0/24 203.27.109.0/24 203.27.117.0/24 203.27.121.0/24 203.27.122.0/23 203.27.125.0/24 203.27.200.0/24 203.27.202.0/24 203.27.233.0/24 203.27.241.0/24 203.27.250.0/24 203.28.10.0/24 203.28.12.0/24 203.28.33.0/24 203.28.34.0/23 203.28.43.0/24 203.28.44.0/24 203.28.54.0/24 203.28.56.0/24 203.28.73.0/24 203.28.74.0/24 203.28.76.0/24 203.28.86.0/24 203.28.88.0/24 203.28.112.0/24 203.28.131.0/24 203.28.136.0/24 203.28.140.0/24 203.28.145.0/24 203.28.165.0/24 203.28.169.0/24 203.28.170.0/24 203.28.178.0/23 203.28.185.0/24 203.28.187.0/24 203.28.196.0/24 203.28.226.0/23 203.28.239.0/24 203.29.2.0/24 203.29.8.0/23 203.29.13.0/24 203.29.14.0/24 203.29.28.0/24 203.29.46.0/24 203.29.57.0/24 203.29.61.0/24 203.29.63.0/24 203.29.69.0/24 203.29.73.0/24 203.29.81.0/24 203.29.90.0/24 203.29.95.0/24 203.29.100.0/24 203.29.103.0/24 203.29.112.0/24 203.29.120.0/22 203.29.182.0/23 203.29.187.0/24 203.29.189.0/24 203.29.190.0/24 203.29.205.0/24 203.29.210.0/24 203.29.217.0/24 203.29.227.0/24 203.29.231.0/24 203.29.233.0/24 203.29.234.0/24 203.29.248.0/24 203.29.254.0/23 203.30.16.0/23 203.30.25.0/24 203.30.29.0/24 203.30.66.0/24 203.30.81.0/24 203.30.87.0/24 203.30.111.0/24 203.30.121.0/24 203.30.123.0/24 203.30.152.0/24 203.30.156.0/24 203.30.162.0/24 203.30.173.0/24 203.30.175.0/24 203.30.187.0/24 203.30.194.0/24 203.30.217.0/24 203.30.220.0/24 203.30.222.0/24 203.30.232.0/23 203.30.235.0/24 203.30.240.0/23 203.30.246.0/24 203.30.250.0/23 203.31.45.0/24 203.31.46.0/24 203.31.49.0/24 203.31.51.0/24 203.31.54.0/23 203.31.69.0/24 203.31.72.0/24 203.31.80.0/24 203.31.85.0/24 203.31.97.0/24 203.31.105.0/24 203.31.106.0/24 203.31.108.0/23 203.31.124.0/24 203.31.162.0/24 203.31.174.0/24 203.31.177.0/24 203.31.181.0/24 203.31.187.0/24 203.31.189.0/24 203.31.204.0/24 203.31.220.0/24 203.31.222.0/23 203.31.225.0/24 203.31.229.0/24 203.31.248.0/23 203.31.253.0/24 203.32.20.0/24 203.32.48.0/23 203.32.56.0/24 203.32.60.0/24 203.32.62.0/24 203.32.68.0/23 203.32.76.0/24 203.32.81.0/24 203.32.84.0/23 203.32.95.0/24 203.32.102.0/24 203.32.105.0/24 203.32.130.0/24 203.32.133.0/24 203.32.140.0/24 203.32.152.0/24 203.32.186.0/23 203.32.192.0/24 203.32.196.0/24 203.32.203.0/24 203.32.204.0/23 203.32.212.0/24 203.33.4.0/24 203.33.7.0/24 203.33.12.0/23 203.33.21.0/24 203.33.26.0/24 203.33.32.0/24 203.33.63.0/24 203.33.64.0/24 203.33.67.0/24 203.33.68.0/24 203.33.73.0/24 203.33.79.0/24 203.33.100.0/24 203.33.122.0/24 203.33.129.0/24 203.33.131.0/24 203.33.145.0/24 203.33.156.0/24 203.33.158.0/23 203.33.174.0/24 203.33.185.0/24 203.33.200.0/24 203.33.202.0/23 203.33.204.0/24 203.33.206.0/23 203.33.214.0/23 203.33.224.0/23 203.33.226.0/24 203.33.233.0/24 203.33.243.0/24 203.33.250.0/24 203.34.4.0/24 203.34.21.0/24 203.34.27.0/24 203.34.39.0/24 203.34.48.0/23 203.34.54.0/24 203.34.56.0/23 203.34.67.0/24 203.34.69.0/24 203.34.76.0/24 203.34.92.0/24 203.34.106.0/24 203.34.113.0/24 203.34.147.0/24 203.34.150.0/24 203.34.152.0/23 203.34.161.0/24 203.34.162.0/24 203.34.187.0/24 203.34.192.0/21 203.34.204.0/22 203.34.232.0/24 203.34.240.0/24 203.34.242.0/24 203.34.245.0/24 203.34.251.0/24 203.55.2.0/23 203.55.4.0/24 203.55.10.0/24 203.55.13.0/24 203.55.22.0/24 203.55.30.0/24 203.55.93.0/24 203.55.101.0/24 203.55.109.0/24 203.55.110.0/24 203.55.116.0/23 203.55.119.0/24 203.55.128.0/23 203.55.146.0/23 203.55.192.0/24 203.55.196.0/24 203.55.218.0/23 203.55.221.0/24 203.55.224.0/24 203.56.1.0/24 203.56.4.0/24 203.56.12.0/24 203.56.24.0/24 203.56.38.0/24 203.56.40.0/24 203.56.46.0/24 203.56.50.0/23 203.56.52.0/22 203.56.68.0/23 203.56.82.0/23 203.56.84.0/23 203.56.95.0/24 203.56.110.0/24 203.56.121.0/24 203.56.161.0/24 203.56.169.0/24 203.56.172.0/23 203.56.175.0/24 203.56.183.0/24 203.56.185.0/24 203.56.187.0/24 203.56.192.0/24 203.56.198.0/24 203.56.201.0/24 203.56.208.0/23 203.56.210.0/24 203.56.214.0/24 203.56.216.0/24 203.56.227.0/24 203.56.228.0/24 203.56.232.0/24 203.56.240.0/24 203.56.252.0/24 203.56.254.0/24 203.57.5.0/24 203.57.6.0/24 203.57.12.0/23 203.57.28.0/24 203.57.39.0/24 203.57.46.0/24 203.57.58.0/24 203.57.61.0/24 203.57.66.0/24 203.57.69.0/24 203.57.70.0/23 203.57.73.0/24 203.57.90.0/24 203.57.101.0/24 203.57.109.0/24 203.57.123.0/24 203.57.157.0/24 203.57.200.0/24 203.57.202.0/24 203.57.206.0/24 203.57.222.0/24 203.57.224.0/20 203.57.246.0/23 203.57.249.0/24 203.57.253.0/24 203.57.254.0/23 203.62.2.0/24 203.62.131.0/24 203.62.139.0/24 203.62.161.0/24 203.62.197.0/24 203.62.228.0/22 203.62.234.0/24 203.62.246.0/24 203.65.240.0/22 203.76.160.0/22 203.76.168.0/22 203.76.208.0/21 203.76.216.0/22 203.76.240.0/22 203.77.180.0/22 203.78.48.0/20 203.78.156.0/22 203.79.0.0/20 203.80.4.0/23 203.80.32.0/20 203.80.57.0/24 203.80.129.0/24 203.80.132.0/22 203.80.140.0/22 203.80.144.0/20 203.81.0.0/21 203.81.16.0/20 203.81.244.0/22 203.82.0.0/23 203.82.16.0/21 203.82.112.0/20 203.82.224.0/20 203.83.0.0/22 203.83.12.0/22 203.83.56.0/21 203.83.224.0/20 203.86.0.0/18 203.86.64.0/19 203.86.250.0/24 203.86.254.0/23 203.88.32.0/19 203.88.100.0/22 203.88.192.0/19 203.89.0.0/22 203.89.100.0/22 203.89.136.0/22 203.89.144.0/24 203.90.0.0/22 203.90.8.0/21 203.90.128.0/18 203.90.192.0/19 203.91.32.0/19 203.91.96.0/20 203.91.120.0/21 203.92.0.0/22 203.92.6.0/24 203.92.160.0/19 203.93.0.0/16 203.94.0.0/19 203.95.0.0/21 203.95.96.0/19 203.95.128.0/18 203.95.200.0/21 203.95.208.0/22 203.95.224.0/19 203.99.8.0/21 203.99.16.0/22 203.99.30.0/23 203.99.80.0/20 203.100.32.0/20 203.100.58.0/24 203.100.60.0/24 203.100.63.0/24 203.100.80.0/20 203.100.96.0/19 203.100.192.0/20 203.104.32.0/20 203.105.96.0/19 203.105.128.0/19 203.107.0.0/19 203.107.32.0/20 203.107.52.0/22 203.107.56.0/21 203.107.69.0/24 203.107.70.0/23 203.107.72.0/21 203.107.80.0/20 203.107.96.0/19 203.110.160.0/19 203.110.208.0/20 203.110.232.0/23 203.110.234.0/24 203.114.80.0/20 203.114.244.0/22 203.118.192.0/19 203.118.241.0/24 203.118.248.0/22 203.119.24.0/23 203.119.32.0/24 203.119.34.0/23 203.119.80.0/22 203.119.85.0/24 203.119.113.0/24 203.119.114.0/23 203.119.116.0/22 203.119.120.0/21 203.119.128.0/17 203.123.58.0/24 203.128.32.0/19 203.128.96.0/19 203.128.128.0/24 203.128.224.0/21 203.130.32.0/20 203.132.32.0/19 203.134.240.0/22 203.134.246.0/23 203.135.96.0/19 203.135.160.0/20 203.142.12.0/23 203.142.219.0/24 203.142.224.0/19 203.145.0.0/19 203.148.0.0/18 203.148.64.0/20 203.148.80.0/22 203.148.86.0/23 203.149.92.0/22 203.152.64.0/19 203.152.128.0/19 203.153.0.0/22 203.156.192.0/18 203.158.16.0/21 203.160.129.0/24 203.160.192.0/19 203.161.0.0/22 203.161.180.0/24 203.161.183.0/24 203.161.192.0/19 203.166.160.0/19 203.167.28.0/22 203.168.0.0/19 203.170.58.0/23 203.171.0.0/22 203.171.208.0/24 203.171.224.0/20 203.174.4.0/24 203.174.6.0/24 203.174.96.0/20 203.175.128.0/19 203.175.192.0/18 203.176.0.0/18 203.176.64.0/19 203.176.168.0/21 203.184.80.0/20 203.187.160.0/19 203.189.0.0/23 203.189.6.0/23 203.189.112.0/22 203.189.192.0/19 203.189.240.0/22 203.190.96.0/20 203.190.249.0/24 203.191.0.0/23 203.191.2.0/24 203.191.5.0/24 203.191.7.0/24 203.191.29.0/24 203.191.31.0/24 203.191.64.0/18 203.191.133.0/24 203.191.144.0/20 203.192.0.0/19 203.193.224.0/19 203.195.64.0/19 203.195.128.0/17 203.196.0.0/20 203.196.28.0/22 203.201.181.0/24 203.201.182.0/24 203.202.236.0/22 203.205.64.0/19 203.207.64.0/18 203.207.128.0/17 203.208.0.0/20 203.208.16.0/22 203.208.32.0/19 203.209.224.0/19 203.212.0.0/20 203.212.80.0/20 203.217.164.0/22 203.223.0.0/20 203.223.16.0/24 203.223.22.0/24 204.55.160.0/24 204.74.96.0/24 204.114.176.0/23 206.219.44.0/23 206.219.50.0/23 206.219.52.0/23 207.89.20.0/24 210.2.0.0/23 210.2.2.0/24 210.2.5.0/24 210.2.6.0/23 210.2.8.0/21 210.2.24.0/21 210.5.0.0/19 210.5.56.0/24 210.5.60.0/24 210.5.128.0/19 210.7.56.0/21 210.12.0.0/15 210.14.64.0/19 210.14.112.0/20 210.14.128.0/17 210.15.0.0/17 210.15.128.0/18 210.16.128.0/21 210.16.136.0/22 210.16.156.0/22 210.16.160.0/19 210.21.0.0/16 210.22.0.0/16 210.23.32.0/19 210.25.0.0/16 210.26.0.0/15 210.28.0.0/14 210.32.0.0/12 210.51.0.0/16 210.52.0.0/18 210.52.64.0/23 210.52.66.0/24 210.52.68.0/22 210.52.72.0/21 210.52.80.0/20 210.52.96.0/21 210.52.104.0/22 210.52.108.0/24 210.52.110.0/23 210.52.112.0/20 210.52.128.0/17 210.53.0.0/16 210.56.192.0/19 210.72.0.0/14 210.76.0.0/15 210.78.0.0/16 210.79.64.0/18 210.79.224.0/19 210.82.0.0/15 210.87.128.0/18 210.185.192.0/18 210.192.96.0/19 211.64.0.0/13 211.80.0.0/12 211.96.0.0/14 211.100.0.0/17 211.100.128.0/19 211.100.160.0/20 211.100.184.0/21 211.100.192.0/18 211.101.0.0/16 211.102.0.0/15 211.136.0.0/13 211.144.0.0/13 211.152.0.0/17 211.152.134.0/23 211.152.138.0/23 211.152.140.0/22 211.152.150.0/23 211.152.157.0/24 211.152.158.0/23 211.152.160.0/19 211.152.192.0/18 211.153.0.0/16 211.154.0.0/19 211.154.32.0/20 211.154.48.0/21 211.154.64.0/18 211.154.128.0/17 211.155.0.0/18 211.155.67.0/24 211.155.68.0/24 211.155.72.0/21 211.155.80.0/20 211.155.97.0/24 211.155.98.0/23 211.155.100.0/22 211.155.104.0/21 211.155.113.0/24 211.155.117.0/24 211.155.118.0/23 211.155.120.0/21 211.155.128.0/17 211.156.0.0/18 211.156.64.0/19 211.156.96.0/21 211.156.104.0/22 211.156.108.0/23 211.156.112.0/20 211.156.128.0/17 211.157.0.0/16 211.158.0.0/15 211.160.0.0/13 212.64.0.0/17 212.129.128.0/17 218.0.0.0/12 218.16.0.0/13 218.24.0.0/14 218.28.0.0/15 218.30.0.0/19 218.30.64.0/18 218.30.128.0/18 218.30.192.0/19 218.30.224.0/20 218.30.240.0/21 218.30.248.0/22 218.30.252.0/25 218.30.252.128/26 218.30.252.194/31 218.30.252.196/30 218.30.252.200/29 218.30.252.208/28 218.30.252.224/27 218.30.253.0/24 218.30.254.0/23 218.31.0.0/16 218.56.0.0/13 218.64.0.0/11 218.96.0.0/15 218.98.0.0/18 218.98.96.0/21 218.98.104.0/22 218.98.108.0/23 218.98.110.0/24 218.98.112.0/20 218.98.128.0/19 218.98.192.0/18 218.99.0.0/16 218.100.96.0/19 218.100.128.0/17 218.104.0.0/14 218.108.0.0/15 218.185.192.0/19 218.192.0.0/12 218.240.0.0/14 218.244.0.0/15 218.246.0.0/17 218.246.129.0/24 218.246.131.0/24 218.246.132.0/23 218.246.134.0/24 218.246.139.0/24 218.246.144.0/20 218.246.160.0/19 218.246.192.0/18 218.247.0.0/18 218.247.96.0/19 218.247.128.0/17 218.249.0.0/16 219.72.0.0/16 219.82.0.0/16 219.83.128.0/17 219.90.68.0/22 219.90.72.0/21 219.128.0.0/11 219.216.0.0/13 219.224.0.0/13 219.232.0.0/15 219.234.0.0/21 219.234.9.0/24 219.234.10.0/23 219.234.12.0/22 219.234.32.0/19 219.234.64.0/18 219.234.128.0/17 219.235.0.0/16 219.236.0.0/14 219.242.0.0/15 219.244.0.0/14 220.101.192.0/18 220.112.0.0/14 220.152.128.0/17 220.154.0.0/16 220.155.0.0/21 220.155.9.0/24 220.155.10.0/23 220.155.12.0/22 220.155.16.0/21 220.155.24.0/22 220.155.28.0/23 220.155.31.0/24 220.155.32.0/19 220.155.64.0/18 220.155.128.0/17 220.158.241.0/24 220.158.243.0/24 220.160.0.0/11 220.192.0.0/12 220.231.0.0/18 220.231.128.0/17 220.232.64.0/18 220.234.0.0/16 220.242.0.0/24 220.242.12.0/23 220.242.14.0/24 220.242.17.0/24 220.242.18.0/23 220.242.20.0/24 220.242.32.0/20 220.242.48.0/23 220.242.53.0/24 220.242.55.0/24 220.242.56.0/22 220.242.60.0/23 220.242.62.0/24 220.242.64.0/19 220.242.96.0/20 220.242.112.0/21 220.242.120.0/22 220.242.124.0/23 220.242.126.0/24 220.242.173.0/24 220.242.197.0/24 220.242.205.0/24 220.242.207.0/24 220.242.215.0/24 220.242.216.0/21 220.242.224.0/19 220.243.0.0/17 220.243.128.0/18 220.243.204.0/24 220.243.214.0/24 220.243.217.0/24 220.243.218.0/24 220.243.238.0/24 220.247.136.0/21 220.248.0.0/14 220.252.0.0/16 221.0.0.0/13 221.8.0.0/14 221.12.0.0/17 221.12.128.0/18 221.13.0.0/16 221.14.0.0/15 221.122.0.0/15 221.128.128.0/17 221.129.0.0/16 221.130.0.0/15 221.133.224.0/19 221.136.0.0/15 221.172.0.0/14 221.176.0.0/19 221.176.32.0/20 221.176.48.0/21 221.176.56.0/24 221.176.58.0/23 221.176.60.0/22 221.176.64.0/18 221.176.128.0/17 221.177.0.0/16 221.178.0.0/15 221.180.0.0/14 221.192.0.0/14 221.196.0.0/15 221.198.0.0/16 221.199.0.0/17 221.199.128.0/18 221.199.192.0/20 221.199.224.0/19 221.200.0.0/13 221.208.0.0/12 221.224.0.0/12 222.16.0.0/12 222.32.0.0/11 222.64.0.0/11 222.125.0.0/16 222.126.128.0/19 222.126.160.0/21 222.126.168.0/22 222.126.172.0/23 222.126.174.40/29 222.126.174.76/30 222.126.174.88/29 222.126.174.144/28 222.126.178.0/23 222.126.180.0/22 222.126.184.0/21 222.126.192.0/21 222.126.200.104/29 222.126.206.0/23 222.126.208.0/22 222.126.212.0/26 222.126.212.64/27 222.126.212.96/28 222.126.212.112/29 222.126.212.128/25 222.126.213.0/24 222.126.214.0/23 222.126.216.0/21 222.126.224.0/19 222.128.0.0/12 222.160.0.0/14 222.168.0.0/13 222.176.0.0/12 222.192.0.0/11 222.240.0.0/13 222.248.0.0/15 223.0.0.0/12 223.20.0.0/15 223.27.184.0/22 223.29.208.0/22 223.29.252.0/22 223.64.0.0/11 223.96.0.0/12 223.112.0.0/14 223.116.0.0/15 223.120.0.0/13 223.128.0.0/15 223.144.0.0/12 223.160.0.0/14 223.166.0.0/15 223.192.0.0/15 223.198.0.0/15 223.201.4.0/22 223.201.8.0/21 223.201.16.0/20 223.201.32.0/19 223.201.64.0/18 223.201.128.0/17 223.202.0.0/15 223.208.0.0/13 223.220.0.0/15 223.223.176.0/20 223.223.192.0/20 223.240.0.0/13 223.248.0.0/14 223.252.128.0/19 223.252.192.0/18 223.254.0.0/16 223.255.0.0/17 223.255.236.0/22 223.255.252.0/23 ================================================ FILE: acl/server_block_local.acl ================================================ # All IPs listed here will be blocked while the ss-server try to outbound. # Only IP is allowed, *NOT* domain name. # [outbound_block_list] 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.0.0.0/24 192.0.2.0/24 192.88.99.0/24 192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 224.0.0.0/4 240.0.0.0/4 255.255.255.255/32 ::1/128 ::ffff:127.0.0.1/104 fc00::/7 fe80::/10 ================================================ FILE: cmake/FindCares.cmake ================================================ # FindCares.cmake - Find c-ares library # # Sets: # CARES_FOUND # CARES_INCLUDE_DIRS # CARES_LIBRARIES find_path(CARES_INCLUDE_DIR NAMES ares.h HINTS /opt/homebrew/include /usr/local/include /opt/homebrew/opt/c-ares/include /usr/local/opt/c-ares/include /usr/include ) find_library(CARES_LIBRARY NAMES cares HINTS /opt/homebrew/lib /usr/local/lib /opt/homebrew/opt/c-ares/lib /usr/local/opt/c-ares/lib /usr/lib ) if(CARES_INCLUDE_DIR AND CARES_LIBRARY) set(CARES_FOUND TRUE) set(CARES_INCLUDE_DIRS ${CARES_INCLUDE_DIR}) set(CARES_LIBRARIES ${CARES_LIBRARY}) # Verify ares_library_init exists include(CheckLibraryExists) check_library_exists(cares ares_library_init "" CARES_HAS_INIT) if(NOT CARES_HAS_INIT) message(WARNING "c-ares found but ares_library_init not detected. Proceeding anyway.") endif() message(STATUS "Found c-ares: ${CARES_LIBRARY}") else() set(CARES_FOUND FALSE) message(FATAL_ERROR "Could not find c-ares library. Install libc-ares-dev or equivalent.") endif() ================================================ FILE: cmake/FindMbedTLS.cmake ================================================ # FindMbedTLS.cmake - Find mbedTLS library with feature detection # # Sets: # MBEDTLS_FOUND # MBEDTLS_INCLUDE_DIRS # MBEDTLS_CRYPTO_LIBRARY # MBEDTLS_TLS_LIBRARY include(CheckCSourceCompiles) # mbedtls@3 is keg-only on Homebrew; also check versioned opt paths find_path(MBEDTLS_INCLUDE_DIR NAMES mbedtls/cipher.h HINTS /opt/homebrew/opt/mbedtls@3/include /usr/local/opt/mbedtls@3/include /opt/homebrew/opt/mbedtls/include /usr/local/opt/mbedtls/include /opt/homebrew/include /usr/local/include /usr/include ) find_library(MBEDTLS_CRYPTO_LIBRARY NAMES mbedcrypto HINTS /opt/homebrew/opt/mbedtls@3/lib /usr/local/opt/mbedtls@3/lib /opt/homebrew/opt/mbedtls/lib /usr/local/opt/mbedtls/lib /opt/homebrew/lib /usr/local/lib /usr/lib ) find_library(MBEDTLS_TLS_LIBRARY NAMES mbedtls HINTS /opt/homebrew/opt/mbedtls@3/lib /usr/local/opt/mbedtls@3/lib /opt/homebrew/opt/mbedtls/lib /usr/local/opt/mbedtls/lib /opt/homebrew/lib /usr/local/lib /usr/lib ) if(MBEDTLS_INCLUDE_DIR AND MBEDTLS_CRYPTO_LIBRARY) set(MBEDTLS_FOUND TRUE) set(MBEDTLS_INCLUDE_DIRS ${MBEDTLS_INCLUDE_DIR}) # Check for required CFB mode support set(CMAKE_REQUIRED_INCLUDES ${MBEDTLS_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_CRYPTO_LIBRARY}) check_c_source_compiles(" #include #if !defined(MBEDTLS_CIPHER_MODE_CFB) #error CFB mode not supported #endif int main(void) { return 0; } " MBEDTLS_HAS_CFB) if(NOT MBEDTLS_HAS_CFB) # Try mbedtls 3.x config path check_c_source_compiles(" #include #include #if !defined(MBEDTLS_CIPHER_MODE_CFB) #error CFB mode not supported #endif int main(void) { return 0; } " MBEDTLS_HAS_CFB_V3) if(NOT MBEDTLS_HAS_CFB_V3) message(FATAL_ERROR "mbedTLS found but MBEDTLS_CIPHER_MODE_CFB is not enabled. " "Please enable CFB mode in your mbedTLS configuration.") endif() endif() unset(CMAKE_REQUIRED_INCLUDES) unset(CMAKE_REQUIRED_LIBRARIES) message(STATUS "Found mbedTLS: ${MBEDTLS_CRYPTO_LIBRARY}") else() set(MBEDTLS_FOUND FALSE) message(FATAL_ERROR "Could not find mbedTLS library. Install libmbedtls-dev or equivalent.") endif() ================================================ FILE: cmake/FindPCRE2.cmake ================================================ # FindPCRE2.cmake - Find PCRE2 library (8-bit) # # Sets: # PCRE2_FOUND # PCRE2_INCLUDE_DIRS # PCRE2_LIBRARIES include(FindPkgConfig) if(PKG_CONFIG_FOUND) pkg_check_modules(_PCRE2 QUIET libpcre2-8) endif() if(_PCRE2_FOUND) set(PCRE2_INCLUDE_DIRS ${_PCRE2_INCLUDE_DIRS}) set(PCRE2_LIBRARIES ${_PCRE2_LIBRARIES}) set(PCRE2_FOUND TRUE) else() # Try pcre2-config find_program(PCRE2_CONFIG pcre2-config) if(PCRE2_CONFIG) execute_process(COMMAND ${PCRE2_CONFIG} --cflags OUTPUT_VARIABLE PCRE2_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND ${PCRE2_CONFIG} --libs8 OUTPUT_VARIABLE PCRE2_LDFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) string(REGEX REPLACE "-I" "" PCRE2_INCLUDE_DIRS "${PCRE2_CFLAGS}") set(PCRE2_LIBRARIES ${PCRE2_LDFLAGS}) set(PCRE2_FOUND TRUE) else() # Manual search find_path(PCRE2_INCLUDE_DIR NAMES pcre2.h HINTS /opt/homebrew/include /usr/local/include /usr/include ) find_library(PCRE2_LIBRARY NAMES pcre2-8 HINTS /opt/homebrew/lib /usr/local/lib /usr/lib ) if(PCRE2_INCLUDE_DIR AND PCRE2_LIBRARY) set(PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIR}) set(PCRE2_LIBRARIES ${PCRE2_LIBRARY}) set(PCRE2_FOUND TRUE) else() set(PCRE2_FOUND FALSE) endif() endif() endif() if(PCRE2_FOUND) message(STATUS "Found PCRE2: ${PCRE2_LIBRARIES}") else() message(FATAL_ERROR "Could not find PCRE2 library. Install libpcre2-dev or equivalent.") endif() ================================================ FILE: cmake/FindSodium.cmake ================================================ # FindSodium.cmake - Find libsodium with version check # # Sets: # SODIUM_FOUND # SODIUM_INCLUDE_DIRS # SODIUM_LIBRARIES find_path(SODIUM_INCLUDE_DIR NAMES sodium.h HINTS /opt/homebrew/include /usr/local/include /usr/local/opt/libsodium/include /opt/homebrew/opt/libsodium/include /usr/include $ENV{LIBSODIUM_INCLUDE_DIR} $ENV{LIBSODIUM_DIR}/include ) find_library(SODIUM_LIBRARY NAMES sodium HINTS /opt/homebrew/lib /usr/local/lib /usr/local/opt/libsodium/lib /opt/homebrew/opt/libsodium/lib /usr/lib ) if(SODIUM_INCLUDE_DIR AND SODIUM_LIBRARY) set(SODIUM_FOUND TRUE) set(SODIUM_INCLUDE_DIRS ${SODIUM_INCLUDE_DIR}) set(SODIUM_LIBRARIES ${SODIUM_LIBRARY}) # Version check: require SODIUM_LIBRARY_VERSION_MAJOR >= 7 (libsodium >= 1.0.4) include(CheckCSourceCompiles) set(CMAKE_REQUIRED_INCLUDES ${SODIUM_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${SODIUM_LIBRARY}) check_c_source_compiles(" #include #if SODIUM_LIBRARY_VERSION_MAJOR < 7 #error libsodium too old #endif int main(void) { return 0; } " SODIUM_VERSION_OK) unset(CMAKE_REQUIRED_INCLUDES) unset(CMAKE_REQUIRED_LIBRARIES) if(NOT SODIUM_VERSION_OK) message(FATAL_ERROR "libsodium found but version is too old. Require >= 1.0.4 (SODIUM_LIBRARY_VERSION_MAJOR >= 7)") endif() message(STATUS "Found libsodium: ${SODIUM_LIBRARY}") else() set(SODIUM_FOUND FALSE) message(FATAL_ERROR "Could not find libsodium. Install libsodium-dev or equivalent.") endif() ================================================ FILE: cmake/config.h.cmake ================================================ #ifndef _SHADOWSOCKS_CONFIG_H #define _SHADOWSOCKS_CONFIG_H /* Define if building universal (internal helper macro) */ #cmakedefine AC_APPLE_UNIVERSAL_BUILD /* errno for incomplete non-blocking connect(2) */ #cmakedefine CONNECT_IN_PROGRESS @CONNECT_IN_PROGRESS@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ARPA_INET_H 1 /* Define to 1 if you have the declaration of `inet_ntop', and to 0 if you don't. */ #cmakedefine HAVE_DECL_INET_NTOP 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_EV_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_FCNTL_H 1 /* Define to 1 if you have the `fork' function. */ #cmakedefine HAVE_FORK 1 /* Define to 1 if you have the `getpwnam_r' function. */ #cmakedefine HAVE_GETPWNAM_R 1 /* Define to 1 if you have the `inet_ntop' function. */ #cmakedefine HAVE_INET_NTOP 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_INTTYPES_H 1 /* Enable IPv6 support in libudns */ #cmakedefine HAVE_IPv6 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LANGINFO_H 1 /* Compiling with pcre support */ #cmakedefine HAVE_LIBPCRE 1 /* Define to 1 if you have the `socket' library (-lsocket). */ #cmakedefine HAVE_LIBSOCKET 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_IF_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_TCP_H /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETINET_TCP_H /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_NETFILTER_IPV4_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LOCALE_H 1 /* Define to 1 if you have the `malloc' function. */ #cmakedefine HAVE_MALLOC 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_MEMORY_H 1 /* Define to 1 if you have the `memset' function. */ #cmakedefine HAVE_MEMSET 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NET_IF_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PCRE2_H 1 /* Have PTHREAD_PRIO_INHERIT. */ #cmakedefine HAVE_PTHREAD_PRIO_INHERIT 1 /* Define to 1 if you have the `select' function. */ #cmakedefine HAVE_SELECT 1 /* Define to 1 if you have the `setresuid' function. */ #cmakedefine HAVE_SETRESUID 1 /* Define to 1 if you have the `setreuid' function. */ #cmakedefine HAVE_SETREUID 1 /* Define to 1 if you have the `setrlimit' function. */ #cmakedefine HAVE_SETRLIMIT 1 /* Define to 1 if you have the `socket' function. */ #cmakedefine HAVE_SOCKET 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDLIB_H 1 /* Define to 1 if you have the `strerror' function. */ #cmakedefine HAVE_STRERROR 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TYPES_H 1 /* Define to 1 if you have that is POSIX.1 compatible. */ #cmakedefine HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UDNS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 /* Define to 1 if you have the `vfork' function. */ #cmakedefine HAVE_VFORK 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_VFORK_H 1 /* Define to 1 if `fork' works. */ #cmakedefine HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #cmakedefine HAVE_WORKING_VFORK 1 /* Define to the sub-directory where libtool stores uninstalled libraries. */ #cmakedefine LT_OBJDIR "@LT_OBJDIR@" /* Define to 1 if assertions should be disabled. */ #cmakedefine NDEBUG 1 /* Name of package */ #define PACKAGE "@PROJECT_NAME@" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" /* Define to the full name of this package. */ #define PACKAGE_NAME "@PROJECT_NAME@" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "@PROJECT_NAME@ @PROJECT_VERSION@" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "@PROJECT_NAME@" /* Define to the home page for this package. */ #define PACKAGE_URL "@PACKAGE_URL@" /* Define to the version of this package. */ #define PACKAGE_VERSION "@PROJECT_VERSION@" /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #cmakedefine PTHREAD_CREATE_JOINABLE 1 /* Define as the return type of signal handlers (`int' or `void'). */ #cmakedefine RETSIGTYPE @RETSIGTYPE@ /* Define to the type of arg 1 for `select'. */ #cmakedefine SELECT_TYPE_ARG1 @SELECT_TYPE_ARG1@ /* Define to the type of args 2, 3 and 4 for `select'. */ #cmakedefine SELECT_TYPE_ARG234 @SELECT_TYPE_ARG234@ /* Define to the type of arg 5 for `select'. */ #cmakedefine SELECT_TYPE_ARG5 @SELECT_TYPE_ARG5@ /* Define to 1 if you have the ANSI C header files. */ #cmakedefine STDC_HEADERS 1 /* Define to 1 if you can safely include both and . */ #cmakedefine TIME_WITH_SYS_TIME 1 /* If the compiler supports a TLS storage class define it to that here */ #cmakedefine TLS @TLS@ /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE #cmakedefine _ALL_SOURCE 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE #cmakedefine _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS #cmakedefine _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE #cmakedefine _TANDEM_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ #cmakedefine __EXTENSIONS__ 1 #endif /* Enable support for QOS netfilter mark preservation */ #cmakedefine USE_NFCONNTRACK_TOS 1 /* Enable support for nftables firewall */ #cmakedefine USE_NFTABLES 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_RANDOM_H 1 /* Define to 1 if you have the `get_current_dir_name' function. */ #cmakedefine HAVE_GET_CURRENT_DIR_NAME 1 /* Define to 1 if you have the `posix_memalign' function. */ #cmakedefine HAVE_POSIX_MEMALIGN 1 /* Define if use system shared lib. */ #cmakedefine USE_SYSTEM_SHARED_LIB 1 /* Version number of package */ #define VERSION "@PROJECT_VERSION@" /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN #cmakedefine WORDS_BIGENDIAN 1 # endif #endif /* Define to 1 if on MINIX. */ #cmakedefine _MINIX 1 /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #cmakedefine _POSIX_1_SOURCE 1 /* Define to 1 if you need to in order for `stat' and other things to work. */ #cmakedefine _POSIX_SOURCE 1 /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #cmakedefine _UINT8_T 1 /* Define to empty if `const' does not conform to ANSI C. */ #cmakedefine const 1 /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #cmakedefine inline 1 #endif /* Define to `int' if does not define. */ #cmakedefine pid_t @pid_t@ /* Define to `unsigned int' if does not define. */ #cmakedefine size_t unsigned int /* Define to `int' if does not define. */ #cmakedefine ssize_t int /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #cmakedefine uint16_t @uint16_t@ /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #cmakedefine uint8_t @uint8_t@ /* Define as `fork' if `vfork' does not work. */ #cmakedefine vfork #endif ================================================ FILE: cmake/configure.cmake ================================================ # ------------------------------------------------------------- # config.h # Use cmake to generate config.h include(CheckIncludeFiles) include(CheckFunctionExists) include(CheckSymbolExists) include(CheckLibraryExists) include(CheckTypeSize) include(CheckCSourceCompiles) include(CheckCCompilerFlag) # Define if building universal (internal helper macro) # AC_APPLE_UNIVERSAL_BUILD # Set CONNECT_IN_PROGRESS based on platform if(MINGW) set(CONNECT_IN_PROGRESS "WSAEWOULDBLOCK") else() set(CONNECT_IN_PROGRESS "EINPROGRESS") endif() if (CMAKE_SYSTEM_NAME STREQUAL Darwin) set(CMAKE_REQUIRED_INCLUDES "/usr/local/include" "/usr/include" "/opt/homebrew/include") endif () check_include_files(dlfcn.h HAVE_DLFCN_H) check_include_files(ev.h HAVE_EV_H) check_include_files(fcntl.h HAVE_FCNTL_H) check_function_exists(fork HAVE_FORK) check_function_exists(getpwnam_r HAVE_GETPWNAM_R) check_function_exists(inet_ntop HAVE_INET_NTOP) check_include_files(inttypes.h HAVE_INTTYPES_H) set(HAVE_IPv6 1) check_include_files(langinfo.h HAVE_LANGINFO_H) set(HAVE_LIBPCRE 1) check_library_exists(socket socket "" HAVE_LIBSOCKET) check_include_files(limits.h HAVE_LIMITS_H) check_include_files(linux/if.h HAVE_LINUX_IF_H) check_include_files(linux/netfilter_ipv4.h HAVE_LINUX_NETFILTER_IPV4_H) check_include_files(linux/netfilter_ipv6/ip6_tables.h HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H) check_include_files(locale.h HAVE_LOCALE_H) check_function_exists(malloc HAVE_MALLOC) check_include_files(memory.h HAVE_MEMORY_H) check_function_exists(memset HAVE_MEMSET) check_include_files(netdb.h HAVE_NETDB_H) check_include_files(netinet/in.h HAVE_NETINET_IN_H) if (CYGWIN) check_include_files("sys/types.h;netinet/tcp.h" HAVE_NETINET_TCP_H) else () check_include_files(netinet/tcp.h HAVE_NETINET_TCP_H) endif () check_include_files(linux/tcp.h HAVE_LINUX_TCP_H) check_include_files(net/if.h HAVE_NET_IF_H) set(CMAKE_REQUIRED_DEFINITIONS_SAVE ${CMAKE_REQUIRED_DEFINITIONS}) set(CMAKE_REQUIRED_DEFINITIONS "-DPCRE2_CODE_UNIT_WIDTH=8") check_include_files(pcre2.h HAVE_PCRE2_H) set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS_SAVE}) check_symbol_exists(PTHREAD_PRIO_INHERIT pthread.h HAVE_PTHREAD_PRIO_INHERIT) check_function_exists(select HAVE_SELECT) check_function_exists(setresuid HAVE_SETRESUID) check_function_exists(setreuid HAVE_SETREUID) check_function_exists(setrlimit HAVE_SETRLIMIT) check_function_exists(socket HAVE_SOCKET) check_include_files(stdint.h HAVE_STDINT_H) check_include_files(stdlib.h HAVE_STDLIB_H) check_function_exists(strerror HAVE_STRERROR) check_include_files(strings.h HAVE_STRINGS_H) check_include_files(string.h HAVE_STRING_H) check_include_files(sys/ioctl.h HAVE_SYS_IOCTL_H) check_include_files(sys/select.h HAVE_SYS_SELECT_H) check_include_files(sys/socket.h HAVE_SYS_SOCKET_H) check_include_files(sys/stat.h HAVE_SYS_STAT_H) check_include_files(sys/types.h HAVE_SYS_TYPES_H) check_include_files(sys/wait.h HAVE_SYS_WAIT_H) check_include_files(ares.h HAVE_ARES_H) check_include_files(unistd.h HAVE_UNISTD_H) check_include_files(arpa/inet.h HAVE_ARPA_INET_H) check_include_files(linux/random.h HAVE_LINUX_RANDOM_H) check_function_exists(fork HAVE_FORK) check_function_exists(vfork HAVE_VFORK) check_include_files(vfork.h HAVE_VFORK_H) if (HAVE_VFORK) set(HAVE_WORKING_VFORK 1) endif () if (HAVE_FORK) set(HAVE_WORKING_FORK 1) endif () # Additional function checks check_function_exists(get_current_dir_name HAVE_GET_CURRENT_DIR_NAME) check_function_exists(posix_memalign HAVE_POSIX_MEMALIGN) # Define to the sub-directory where libtool stores uninstalled libraries. set(LT_OBJDIR ".libs/") set(NDEBUG 1) set(PACKAGE ${PROJECT_NAME}) set(PACKAGE_BUGREPORT max.c.lv@gmail.com) set(PACKAGE_NAME ${PROJECT_NAME}) set(PACKAGE_VERSION ${PROJECT_VERSION}) set(PACKAGE_STRING "${PROJECT_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME ${PROJECT_NAME}) set(PACKAGE_URL "") # PTHREAD_CREATE_JOINABLE # Define as the return type of signal handlers (`int' or `void'). set(RETSIGTYPE void) # Define to the type of arg 1 for `select'. set(SELECT_TYPE_ARG1 int) # Define to the type of args 2, 3 and 4 for `select'. set(SELECT_TYPE_ARG234 "(fd_set *)") # Define to the type of arg 5 for `select'. set(SELECT_TYPE_ARG5 "(struct timeval *)") # Define to 1 if you have the ANSI C header files. set(STDC_HEADERS 1) check_include_files("sys/time.h;time.h" TIME_WITH_SYS_TIME) # If the compiler supports a TLS storage class define it to that here check_c_source_compiles(" __thread int tls; int main(void) { return 0; }" HAVE_GCC_THREAD_LOCAL_STORAGE) if (HAVE_GCC_THREAD_LOCAL_STORAGE) set(TLS __thread) endif () set(_ALL_SOURCE 1) set(_GNU_SOURCE 1) set(_POSIX_PTHREAD_SEMANTICS 1) set(_TANDEM_SOURCE 1) set(__EXTENSIONS__ 1) # USE_SYSTEM_SHARED_LIB set(VERSION ${PACKAGE_VERSION}) set(CMAKE_EXTRA_INCLUDE_FILES sys/types.h) check_type_size(pid_t PID_T) check_type_size(size_t SIZE_T) check_type_size(ssize_t SSIZE_T) set(CMAKE_EXTRA_INCLUDE_FILES) check_type_size(uint16_t UINT16_T) check_type_size(uint8_t UINT8_T) ## Inverse if (NOT HAVE_PID_T) set(pid_t int) endif () if (NOT HAVE_SIZE_T) set(size_t "unsigned int") endif () if (NOT HAVE_SSIZE_T) set(ssize_t int) endif () if (NOT HAVE_UINT8_T) set(uint8_t "unsigned char") endif () if (NOT HAVE_UINT16_T) set(uint16_t "unsigned short") endif () # Define as `fork' if `vfork' does not work. if (NOT HAVE_WORKING_VFORK) set(vfork fork) endif () # Stack protector detection option(DISABLE_SSP "Disable -fstack-protector" OFF) if(NOT DISABLE_SSP) check_c_compiler_flag(-fstack-protector HAS_STACK_PROTECTOR) if(HAS_STACK_PROTECTOR) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector") message(STATUS "Stack protector enabled") endif() endif() # MinGW/Cygwin compiler flags if(MINGW OR CYGWIN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mno-ms-bitfields") endif() ================================================ FILE: cmake/shadowsocks-libev.pc.cmake ================================================ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ Name: @PROJECT_NAME@ Description: @PROJECT_DESC@ URL: @PROJECT_URL@ Version: @PROJECT_VERSION@ Requires: Cflags: -I${includedir} Libs: -L${libdir} -lshadowsocks-libev ================================================ FILE: completions/bash/ss-local ================================================ _ss_local() { local cur prev opts ciphers opts='-s -p -l -k -m -a -f -t -c -n -i -b -u -U -v -h --reuse-port --fast-open --acl --mtu --mptcp --no-delay --key --plugin --plugin-opts --help' ciphers='rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf' cur=${COMP_WORDS[COMP_CWORD]} prev="${COMP_WORDS[COMP_CWORD-1]}" case "$prev" in -f|-c|--acl) _filedir || COMPREPLY=( $(compgen -o plusdirs -f ${cur}) ) ;; -s|-b) _known_hosts_real -- "${cur}" || OMPREPLY=( $(compgen -A hostname -- ${cur}) ) ;; -m) COMPREPLY=( $(compgen -W "$ciphers" -- ${cur}) ) ;; -a) _allowed_users || COMPREPLY=( $(compgen -u -- ${cur}) ) ;; -p|-l|-k|-t|-n|--mtu|--key|--plugin|--plugin-opts) ;; -i) _available_interfaces -a || true ;; *) COMPREPLY+=( $(compgen -W "${opts}" -- ${cur}) ) ;; esac return 0 } complete -F _ss_local ss-local ================================================ FILE: completions/bash/ss-manager ================================================ _ss_manager() { local cur prev opts ciphers opts='-s -p -l -k -m -a -f -t -c -n -i -b -u -U -v -h --reuse-port --manager-address --executable --mtu --mptcp --plugin --plugin-opts --help' ciphers='rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf' cur=${COMP_WORDS[COMP_CWORD]} prev="${COMP_WORDS[COMP_CWORD-1]}" case "$prev" in -f|-c|--executable) _filedir || COMPREPLY=( $(compgen -o plusdirs -f ${cur}) ) ;; -s|-b) _known_hosts_real -- "${cur}" || OMPREPLY=( $(compgen -A hostname -- ${cur}) ) ;; -m) COMPREPLY=( $(compgen -W "$ciphers" -- ${cur}) ) ;; -a) _allowed_users || COMPREPLY=( $(compgen -u -- ${cur}) ) ;; -p|-l|-k|-t|-n|--mtu|--plugin|--plugin-opts) ;; -i) _available_interfaces -a || true ;; --manager-address) _known_hosts_real -- "${cur}" || OMPREPLY=( $(compgen -A hostname -- ${cur}) ) _filedir || COMPREPLY+=( $(compgen -o plusdirs -f ${cur}) ) ;; *) COMPREPLY+=( $(compgen -W "${opts}" -- ${cur}) ) ;; esac return 0 } complete -F _ss_manager ss-manager ================================================ FILE: completions/bash/ss-redir ================================================ _ss_redir() { local cur prev opts ciphers opts='-s -p -l -k -m -a -f -t -c -n -b -u -U -T -v -h --reuse-port --mtu --mptcp --key --plugin --plugin-opts --help' ciphers='rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf' cur=${COMP_WORDS[COMP_CWORD]} prev="${COMP_WORDS[COMP_CWORD-1]}" case "$prev" in -f|-c) _filedir || COMPREPLY=( $(compgen -o plusdirs -f ${cur}) ) ;; -s|-b) _known_hosts_real -- "${cur}" || OMPREPLY=( $(compgen -A hostname -- ${cur}) ) ;; -m) COMPREPLY=( $(compgen -W "$ciphers" -- ${cur}) ) ;; -a) _allowed_users || COMPREPLY=( $(compgen -u -- ${cur}) ) ;; -p|-l|-k|-t|-n|--mtu|--key|--plugin|--plugin-opts) ;; *) COMPREPLY+=( $(compgen -W "${opts}" -- ${cur}) ) ;; esac return 0 } complete -F _ss_redir ss-redir ================================================ FILE: completions/bash/ss-server ================================================ _ss_server() { local cur prev opts ciphers opts='-s -p -l -k -m -a -f -t -c -n -i -b -u -U -6 -d -v -h --reuse-port --fast-open --acl --manager-address --mtu --mptcp --no-delay --key --plugin --plugin-opts --help' ciphers='rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf' COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev="${COMP_WORDS[COMP_CWORD-1]}" case "$prev" in -f|-c|--acl) _filedir || COMPREPLY=( $(compgen -o plusdirs -f ${cur}) ) ;; -s|-b) _known_hosts_real -- "${cur}" || OMPREPLY=( $(compgen -A hostname -- ${cur}) ) ;; -m) COMPREPLY=( $(compgen -W "$ciphers" -- ${cur}) ) ;; -a) _allowed_users || COMPREPLY=( $(compgen -u -- ${cur}) ) ;; -p|-l|-k|-t|-n|-d|--mtu|--key|--plugin|--plugin-opts) ;; --manager-address) _known_hosts_real -- "${cur}" || OMPREPLY=( $(compgen -A hostname -- ${cur}) ) _filedir || COMPREPLY+=( $(compgen -o plusdirs -f ${cur}) ) ;; -i) _available_interfaces -a || true ;; *) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) ;; esac } complete -F _ss_server ss-server ================================================ FILE: completions/bash/ss-tunnel ================================================ _ss_tunnel() { local cur prev opts ciphers opts='-s -p -l -k -m -a -f -t -c -n -i -b -u -U -L -v -h --reuse-port --mtu --mptcp --key --plugin --plugin-opts --help' ciphers='rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf' cur=${COMP_WORDS[COMP_CWORD]} prev="${COMP_WORDS[COMP_CWORD-1]}" compopt +o nospace case "$prev" in -f|-c) _filedir || COMPREPLY=( $(compgen -o plusdirs -f ${cur}) ) ;; -s|-b) _known_hosts_real -- "${cur}" || OMPREPLY=( $(compgen -A hostname -- ${cur}) ) ;; -L) compopt -o nospace _known_hosts_real -c -- "${cur}" || OMPREPLY=( $(compgen -A hostname -S : -- ${cur}) ) ;; -m) COMPREPLY=( $(compgen -W "$ciphers" -- ${cur}) ) ;; -a) _allowed_users || COMPREPLY=( $(compgen -u -- ${cur}) ) ;; -p|-l|-k|-t|-n|--mtu|--key|--plugin|--plugin-opts) ;; -i) _available_interfaces -a || true ;; *) COMPREPLY+=( $(compgen -W "${opts}" -- ${cur}) ) ;; esac return 0 } complete -F _ss_tunnel ss-tunnel ================================================ FILE: completions/zsh/_ss-local ================================================ #compdef ss-local local ciphers ciphers='(rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf)' _arguments "-h::" \ "-s:server host:_hosts" \ "-p:server port:" \ "-l:local port:" \ "-k:password:" \ "-m:encrypt method:$ciphers" \ "-a:run as user:_users" \ "-f:pid file:_files" \ "-t:timeout:" \ "-c:configure file:_files" \ "-n:max number of open files:" \ "-i:bind interface:_net_interfaces" \ "-b:local address:(127.0.0.1 \:\:1 0.0.0.0 \:\:)" \ "-u:enable udp:" \ "-U:udp only:" \ "-v:verbose mode:" \ "--reuse-port::" \ "--fast-open::" \ "--acl:acl file:_files" \ "--mtu::" \ "--mptcp::" \ "--no-delay::" \ "--key:key in base64:" \ "--plugin:plugin name:" \ "--plugin-opts:plugin options:" \ "--help::" ================================================ FILE: completions/zsh/_ss-manager ================================================ #compdef ss-manager local ciphers ciphers='(rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf)' _arguments "-h::" \ "-s:server host:_hosts" \ "-p:server port:" \ "-l:local port:" \ "-k:password:" \ "-m:encrypt method:$ciphers" \ "-a:run as user:_users" \ "-f:pid file:_files" \ "-t:timeout:" \ "-c:configure file:_files" \ "-n:max number of open files:" \ "-i:bind interface:_net_interfaces" \ "-b:local address:(127.0.0.1 \:\:1 0.0.0.0 \:\:)" \ "-u:enable udp:" \ "-U:udp only:" \ "-v:verbose mode:" \ "--executable:path to ss-server:_files" \ "--manager-address:manager address:" \ "--reuse-port::" \ "--acl:acl file:_files" \ "--mtu::" \ "--key:key in base64:" \ "--plugin:plugin name:" \ "--plugin-opts:plugin options:" \ "--help::" ================================================ FILE: completions/zsh/_ss-redir ================================================ #compdef ss-redir local ciphers ciphers='(rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf)' _arguments "-h::" \ "-s:server host:_hosts" \ "-p:server port:" \ "-l:local port:" \ "-k:password:" \ "-m:encrypt method:$ciphers" \ "-a:run as user:_users" \ "-f:pid file:_files" \ "-t:timeout:" \ "-c:configure file:_files" \ "-n:nofile:" \ "-b:local address:(127.0.0.1 \:\:1 0.0.0.0 \:\:)" \ "-u:enable udp:" \ "-U:udp only:" \ "-v:verbose mode:" \ "-T:tcp tproxy mode:" \ "--reuse-port::" \ "--fast-open::" \ "--acl:acl file:_files" \ "--mtu::" \ "--mptcp::" \ "--no-delay::" \ "--key:key in base64:" \ "--plugin:plugin name:" \ "--plugin-opts:plugin options:" \ "--help::" ================================================ FILE: completions/zsh/_ss-server ================================================ #compdef ss-server local ciphers ciphers='(rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf)' _arguments "-h::" \ "-s:server host:_hosts" \ "-p:server port:" \ "-l:local port:" \ "-k:password:" \ "-m:encrypt method:$ciphers" \ "-a:run as user:_users" \ "-f:pid file:_files" \ "-t:timeout:" \ "-c:configure file:_files" \ "-n:max number of open files:" \ "-i:bind interface:_net_interfaces" \ "-b:local address:(127.0.0.1 \:\:1 0.0.0.0 \:\:)" \ "-u:enable udp:" \ "-U:udp only:" \ "-v:verbose mode:" \ "-6:ipv6 first:" \ "-d:nameserver for internal dns:" \ "--manager-address:manager address:" \ "--reuse-port::" \ "--fast-open::" \ "--acl:acl file:_files" \ "--mtu::" \ "--mptcp::" \ "--no-delay::" \ "--key:key in base64:" \ "--plugin:plugin name:" \ "--plugin-opts:plugin options:" \ "--help::" ================================================ FILE: completions/zsh/_ss-tunnel ================================================ #compdef ss-tunnel local ciphers ciphers='(rc4-md5 aes-128-gcm aes-192-gcm aes-256-gcm aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr camellia-128-cfb camellia-192-cfb camellia-256-cfb bf-cfb chacha20-ietf-poly1305 xchacha20-ietf-poly1305 salsa20 chacha20 chacha20-ietf)' _arguments "-h::" \ "-s:server host:_hosts" \ "-p:server port:" \ "-l:local port:" \ "-k:password:" \ "-m:encrypt method:$ciphers" \ "-a:run as user:_users" \ "-f:pid file:_files" \ "-t:timeout:" \ "-c:configure file:_files" \ "-n:nofile:" \ "-i:bind interface:_net_interfaces" \ "-b:local address:(127.0.0.1 \:\:1 0.0.0.0 \:\:)" \ "-u:enable udp:" \ "-U:udp only:" \ "-v:verbose mode:" \ "-L:destination server address and port:" \ "--reuse-port::" \ "--acl:acl file:_files" \ "--mtu::" \ "--key:key in base64:" \ "--plugin:plugin name:" \ "--plugin-opts:plugin options:" \ "--help::" ================================================ FILE: debian/.gitignore ================================================ *.substvars debhelper-build-stamp libshadowsocks-libev*/ libshadowsocks-libev-dev/ tmp/ ================================================ FILE: debian/README.Debian ================================================ shadowsocks-libev for Debian ---------------------------- The Debian package has added systemd support. A default server service which reads the default configuration in /etc/default/shadowsocks-libev is installed and enabled by default, plus some other service templates placed in /lib/systemd/system, which can be used by users later. The systemd service templates accept one parameter to determine the configuration json file that is used by this instance. For example, if the user starts a service called "shadowsocks-libev-local@foobar.service", This service instance will start the "ss-local" client and read /etc/shadowsocks-libev/foobar.json as its configuration file. -- Boyuan Yang Thu, 08 Sep 2016 19:01:20 +0800 ================================================ FILE: debian/changelog ================================================ shadowsocks-libev (3.3.6-1) unstable; urgency=medium * Reduce memory copies in crypto encrypt/decrypt paths. * Fix unbounded buffer growth in aead_decrypt chunk reassembly. -- Max Lv Sun, 09 Feb 2026 08:00:00 +0800 shadowsocks-libev (3.3.5-1) unstable; urgency=medium * Remove the SNI proxy function. * Minor bug fixes. (#2581, #2582, #2590, #2595, #2599, #2600, #2620, #2687, #2692) -- Max Lv Tue, 15 Sep 2020 10:24:43 +0800 shadowsocks-libev (3.3.4-1) unstable; urgency=medium * Minor bug fixes. (#2539, #2565, #2566, #2577) * Security bug fixes. (CVE-2019-5163, CVE-2019-5164) -- Max Lv Fri, 10 Jan 2020 09:28:25 +0800 shadowsocks-libev (3.3.3-1) unstable; urgency=medium * Refine the handling of suspicious connections. -- Max Lv Thu, 31 Oct 2019 15:06:04 +0800 shadowsocks-libev (3.3.2-1) unstable; urgency=medium * Refine the handling of fragment request. * Minor bug fixes. (#2463, #2481, #2508) -- Max Lv Sat, 12 Oct 2019 08:42:24 +0800 shadowsocks-libev (3.3.1-1) unstable; urgency=high * Fix a high CPU bug introduced in 3.3.0. (#2449) * Fix MinGW build. (#2438) * Minor bug fixes. (#2402, #2412, #2427, #2443) -- Max Lv Fri, 09 Aug 2019 15:02:34 +0800 shadowsocks-libev (3.3.0-1) unstable; urgency=medium * Enlarge the socket buffer size to 16KB. * Fix the empty list bug in ss-manager. * Fix the IPv6 address parser. -- Max Lv Sat, 08 Jun 2019 07:53:20 +0800 shadowsocks-libev (3.2.5-1) unstable; urgency=medium * Fix a bug of port parser. -- Max Lv Sat, 09 Mar 2019 18:54:36 +0800 shadowsocks-libev (3.2.4-1) unstable; urgency=medium * Fix a crash with MinGW. * Refine SIP003 plugin interface. * Remove connection timeout from all clients. -- Max Lv Tue, 26 Feb 2019 09:40:18 +0800 shadowsocks-libev (3.2.3-1) unstable; urgency=medium * Fix the alignment issue again. -- Max Lv Wed, 28 Nov 2018 00:27:40 -0800 shadowsocks-libev (3.2.2-1) unstable; urgency=medium * Fix a bug on 32-bit arch. -- Max Lv Mon, 26 Nov 2018 20:07:21 -0800 shadowsocks-libev (3.2.1-1) unstable; urgency=medium * Add TCP fast open support to ss-tunnel by @PantherJohn. * Fix several security issues. -- Max Lv Wed, 07 Nov 2018 22:31:59 -0800 shadowsocks-libev (3.2.0-1) unstable; urgency=medium * Add MinGW support by @linusyang. * Refine c-ares integration by @xnoreq. * Fix building issues with GCC8 by @FlyingheartCN. * Minor bug fixes. -- Max Lv Mon, 28 May 2018 19:46:21 -0700 shadowsocks-libev (3.1.3-1) unstable; urgency=medium * Fix a bug in UDP relay. -- Max Lv Mon, 15 Jan 2018 17:19:31 -0800 shadowsocks-libev (3.1.2-1) unstable; urgency=medium * Fix a bug in DNS resolver. * Add new TFO API support. -- Max Lv Thu, 28 Dec 2017 21:01:56 -0800 shadowsocks-libev (3.1.1-1) unstable; urgency=high * Fix a security issue in ss-manager. (CVE-2017-15924) -- Max Lv Mon, 20 Nov 2017 12:13:04 +0800 shadowsocks-libev (3.1.0-1) unstable; urgency=low * Replace libudns with libc-ares. -- Max Lv Thu, 14 Sep 2017 19:27:51 -0700 shadowsocks-libev (3.0.8-1) unstable; urgency=medium * Refine the ping-pong bloom filter. * Minor bug fixes by @vfreex, @vlolteanu and @jackyyf. -- Max Lv Thu, 27 Jul 2017 11:01:37 +0800 shadowsocks-libev (3.0.7-1) unstable; urgency=medium * Refine manager mode by @mengxd. * Fix a potential memory leak by @vlolteanu. -- Max Lv Tue, 27 Jun 2017 14:08:27 +0800 shadowsocks-libev (3.0.6-1) unstable; urgency=medium * Fix a bug with AEAD ciphers. * Refine ACL support by @blackgear. -- Max Lv Wed, 26 Apr 2017 13:48:11 +0800 shadowsocks-libev (3.0.5-1) unstable; urgency=medium * Fix a bug of TCP Fast Open in ss-redir. -- Max Lv Tue, 21 Mar 2017 13:49:18 +0800 shadowsocks-libev (3.0.4-1) unstable; urgency=medium * Add CMake files by @wenerme. * Support TCP Fast Open in ss-redir by @lqs. * Support TOS/DESCP in ss-redir by @sduponch. * Refine MPTCP by @sduponch. -- Max Lv Thu, 16 Mar 2017 14:07:57 +0800 shadowsocks-libev (3.0.3-1) unstable; urgency=medium * Replace nonce cache with a ping-pong bloom filter. -- Max Lv Fri, 24 Feb 2017 12:08:31 +0800 shadowsocks-libev (3.0.2-1) unstable; urgency=high * Add session key for AEAD. (SIP007) -- Max Lv Mon, 13 Feb 2017 09:07:17 +0800 shadowsocks-libev (3.0.1-1) unstable; urgency=medium * Fix a crashe when using stream ciphers. * Fix a protocol bug in AEAD ciphers. (SIP004) * Allow setting keys directly. (SIP006) -- Max Lv Tue, 07 Feb 2017 13:18:02 +0800 shadowsocks-libev (3.0.0-1) unstable; urgency=medium * Drop dependencies of OpenSSL and PolarSSL. * Deprecate OTA (One-Time-Auth). * Add new ciphers for SIP004: aes-128-gcm, aes-192-gcm, aes-256-gcm, chacha20-poly1305 and chacha20-ietf-poly1305. * Refine SIP003 to support standalone mode of obfsproxy. -- Max Lv Wed, 01 Feb 2017 19:10:14 +0800 shadowsocks-libev (2.6.3-1) unstable; urgency=medium * Refine the project structure. -- Max Lv Tue, 24 Jan 2017 19:10:45 +0800 shadowsocks-libev (2.6.2-1) unstable; urgency=medium * Refine SIP003 plugin support. -- Max Lv Mon, 16 Jan 2017 10:16:12 +0800 shadowsocks-libev (2.6.1-1) unstable; urgency=medium * Deprecate HTTP/TLS obfuscating. * Add SIP003 plugin support. -- Max Lv Sun, 08 Jan 2017 15:14:19 +0800 shadowsocks-libev (2.6.0-1) unstable; urgency=medium * Add HTTP/TLS obfuscating. * Add support of aunch_activate_socket on macOS. -- Max Lv Tue, 27 Dec 2016 16:37:23 +0800 shadowsocks-libev (2.5.6-1) unstable; urgency=medium * Add outbound ACL for server. * Refine log format. -- Max Lv Tue, 01 Nov 2016 09:51:52 +0800 shadowsocks-libev (2.5.5-1) unstable; urgency=medium * Refine attack detection. -- Max Lv Tue, 11 Oct 2016 15:45:09 +0800 shadowsocks-libev (2.5.4-1) unstable; urgency=medium * Fix a bug of auto blocking mechanism. -- Max Lv Sun, 09 Oct 2016 19:36:37 +0800 shadowsocks-libev (2.5.3-1) unstable; urgency=medium * Fix TCP Fast Open on macOS. -- Max Lv Wed, 21 Sep 2016 19:31:57 +0800 shadowsocks-libev (2.5.2-1) unstable; urgency=medium * Fix a bug of UDP relay mode of ss-local. -- Max Lv Mon, 12 Sep 2016 12:54:33 +0800 shadowsocks-libev (2.5.1-1) unstable; urgency=medium * Refine ACL feature with hostname support. * Add HTTP/SNI parser for ss-local/ss-redir. -- Max Lv Sat, 10 Sep 2016 17:06:49 +0800 shadowsocks-libev (2.5.0-1) unstable; urgency=medium * Fix several bugs of the command line interface. * Add aes-128/192/256-ctr ciphers. * Add option MTU for UDP relay. * Add MultiPath TCP support. -- Max Lv Mon, 29 Aug 2016 13:07:51 +0800 shadowsocks-libev (2.4.8-1) unstable; urgency=low * Update manual pages with asciidoc. * Fix issues of bind_address option. -- Max Lv Wed, 20 Jul 2016 09:25:50 +0800 shadowsocks-libev (2.4.7-1) unstable; urgency=low * Add ss-nat, a helper script to set up NAT rules for ss-redir. * Fix several issues for debian package. -- Max Lv Wed, 1 Jun 2016 18:21:45 +0800 shadowsocks-libev (2.4.6-1) unstable; urgency=low * Update manual pages. -- Max Lv Thu, 21 Apr 2016 17:33:34 +0800 shadowsocks-libev (2.4.5-1) unstable; urgency=low * Fix build issues on OpenWRT. * Reduce the latency of redir mode. -- Max Lv Mon, 01 Feb 2016 13:22:50 +0800 shadowsocks-libev (2.4.4-1) unstable; urgency=low * Fix a potential memory leak. * Fix some compiler related issues. -- Max Lv Wed, 13 Jan 2016 11:50:12 +0800 shadowsocks-libev (2.4.3-1) unstable; urgency=high * Refine the buffer allocation. -- Max Lv Sat, 19 Dec 2015 12:30:21 +0900 shadowsocks-libev (2.4.1-1) unstable; urgency=high * Fix a security bug. -- Max Lv Thu, 29 Oct 2015 15:42:47 +0900 shadowsocks-libev (2.4.0-1) unstable; urgency=low * Update the one-time authentication -- Max Lv Thu, 24 Sep 2015 14:11:05 +0900 shadowsocks-libev (2.3.3-1) unstable; urgency=low * Refine the onetime authentication of header. * Enforce CRC16 on the payload. -- Max Lv Fri, 18 Sep 2015 10:38:21 +0900 shadowsocks-libev (2.3.2-1) unstable; urgency=low * Fix minor issues of build scripts. -- Max Lv Sun, 13 Sep 2015 15:22:28 +0900 shadowsocks-libev (2.3.1-1) unstable; urgency=low * Fix an issue of connection cache of UDP relay. * Add support of onetime authentication for header verification. -- Max Lv Fri, 04 Sep 2015 07:54:02 +0900 shadowsocks-libev (2.3.0-1) unstable; urgency=low * Add manager mode to support multi-user and traffic stat. * Fix a build issue on OS X El Capitan. -- Max Lv Thu, 30 Jul 2015 17:30:43 +0900 shadowsocks-libev (2.2.3-1) unstable; urgency=high * Fix the multiple UDP source port issue. * Allow working in UDP only mode. -- Max Lv Sat, 11 Jul 2015 08:31:02 +0900 shadowsocks-libev (2.2.2-1) unstable; urgency=low * Fix the timer of UDP relay. * Check name_len in the header. -- Max Lv Mon, 15 Jun 2015 10:26:40 +0900 shadowsocks-libev (2.2.1-1) unstable; urgency=low * Fix an issue of UDP relay. -- Max Lv Sun, 10 May 2015 21:23:44 +0900 shadowsocks-libev (2.2.0-1) unstable; urgency=low * Add TPROXY support in redir mode. -- Max Lv Mon, 04 May 2015 02:44:17 -0300 shadowsocks-libev (2.1.4-1) unstable; urgency=low * Fix a bug of server mode ACL. -- Max Lv Sun, 08 Feb 2015 20:24:43 +0900 shadowsocks-libev (2.1.3-1) unstable; urgency=low * Add ACL support to remote server. -- Max Lv Sun, 08 Feb 2015 10:59:44 +0900 shadowsocks-libev (2.1.2-1) unstable; urgency=low * Refine multiple port binding. -- Max Lv Sat, 31 Jan 2015 18:56:25 +0900 shadowsocks-libev (2.1.1-1) unstable; urgency=low * Fix a memory leak. -- Max Lv Wed, 21 Jan 2015 21:40:58 +0900 shadowsocks-libev (2.1.0-1) unstable; urgency=low * Fix a bug of tunnel mode. -- Max Lv Mon, 19 Jan 2015 09:59:52 +0900 shadowsocks-libev (2.0.8-1) unstable; urgency=low * Fix a bug of IPv6. -- Max Lv Fri, 16 Jan 2015 10:58:12 +0900 shadowsocks-libev (2.0.7-1) unstable; urgency=low * Fix some performance issue. -- Max Lv Tue, 13 Jan 2015 13:17:58 +0900 shadowsocks-libev (2.0.6-1) unstable; urgency=high * Fix a critical issue in redir mode. -- Max Lv Mon, 12 Jan 2015 21:51:19 +0900 shadowsocks-libev (2.0.5-1) unstable; urgency=low * Refine local, tunnel, and redir modes. -- Max Lv Mon, 12 Jan 2015 12:39:05 +0800 shadowsocks-libev (2.0.4-1) unstable; urgency=low * Fix building issues with MinGW32. -- Max Lv Sun, 11 Jan 2015 13:33:31 +0900 shadowsocks-libev (2.0.3-1) unstable; urgency=high * Fix some issues. -- Max Lv Sat, 10 Jan 2015 16:27:54 +0800 shadowsocks-libev (2.0.2-1) unstable; urgency=low * Fix issues with MinGW. -- Max Lv Sat, 10 Jan 2015 15:17:10 +0800 shadowsocks-libev (2.0.1-1) unstable; urgency=low * Implement a real asynchronous DNS resolver. -- Max Lv Sat, 10 Jan 2015 10:04:28 +0800 shadowsocks-libev (1.6.4-1) unstable; urgency=low * Update documents. -- Max Lv Wed, 07 Jan 2015 21:48:58 +0900 shadowsocks-libev (1.6.3-1) unstable; urgency=low * Refine ss-redir. -- Max Lv Sun, 04 Jan 2015 19:23:52 +0900 shadowsocks-libev (1.6.2-1) unstable; urgency=low * Fix some build issues. -- Max Lv Tue, 30 Dec 2014 10:30:28 +0800 shadowsocks-libev (1.6.1-1) unstable; urgency=high * Add salsa20 and chacha20 support. -- Max Lv Sat, 13 Dec 2014 15:11:34 +0800 shadowsocks-libev (1.6.0-1) unstable; urgency=low * Solve conflicts with other shadowsocks portings. -- Max Lv Mon, 17 Nov 2014 14:10:21 +0800 shadowsocks-libev (1.5.3-2) unstable; urgency=low * rename as shadowsocks-libev. -- Symeon Huang Sat, 15 Nov 2014 14:55:28 +0000 shadowsocks (1.5.3-1) unstable; urgency=low * Fix log on Win32. -- Max Lv Fri, 14 Nov 2014 09:10:06 +0800 shadowsocks (1.5.2-1) unstable; urgency=low * Handle SIGTERM and SIGKILL nicely. -- Max Lv Tue, 12 Nov 2014 13:11:29 +0800 shadowsocks (1.5.1-1) unstable; urgency=low * Fix a bug of tcp fast open. -- Max Lv Sat, 08 Nov 2014 19:45:37 +0900 shadowsocks (1.5.0-1) unstable; urgency=low * Support to build static or shared library. * Supprot IPv6 NAT in redirect mode. * Refine the cache size of UDPRelay. -- Max Lv Fri, 07 Nov 2014 09:33:19 +0800 shadowsocks (1.4.8-1) unstable; urgency=low * Fix a bug of tcp fast open. -- Max Lv Wed, 08 Oct 2014 18:02:02 +0800 shadowsocks (1.4.7-1) unstable; urgency=low * Add a new encryptor rc4-md5. -- Max Lv Tue, 09 Sep 2014 07:50:10 +0800 shadowsocks (1.4.6-1) unstable; urgency=low * Add ACL support. -- Max Lv Sat, 03 May 2014 04:37:10 -0400 shadowsocks (1.4.5-1) unstable; urgency=high * Fix the compatibility issue of udprelay. * Enhance asyncns to reduce the latency. * Add TCP_FASTOPEN support. -- Max Lv Sun, 20 Apr 2014 08:12:45 +0800 shadowsocks (1.4.4-1) unstable; urgency=low * Add CommonCrypto support for darwin. * Fix some config related issues. -- Max Lv Wed, 26 Mar 2014 13:29:03 +0800 shadowsocks (1.4.3-1) unstable; urgency=low * Add tunnel mode with local port forwarding feature. -- Max Lv Fri, 21 Feb 2014 11:52:13 +0900 shadowsocks (1.4.2-1) unstable; urgency=high * Fix the UDP relay issues. * Add syslog support. -- Max Lv Sun, 05 Jan 2014 10:05:29 +0900 shadowsocks (1.4.1-1) unstable; urgency=low * Add multi-port support. * Add PolarSSL support by @linusyang. -- Max Lv Tue, 12 Nov 2013 03:57:21 +0000 shadowsocks (1.4.0-1) unstable; urgency=low * Add standard socks5 udp support. -- Max Lv Sun, 08 Sep 2013 02:20:40 +0000 shadowsocks (1.3.3-1) unstable; urgency=high * Provide more info in verbose mode. -- Max Lv Fri, 21 Jun 2013 09:59:20 +0800 shadowsocks (1.3.2-1) unstable; urgency=high * Fix some ciphers by @linusyang. -- Max Lv Sun, 09 Jun 2013 09:52:31 +0000 shadowsocks (1.3.1-1) unstable; urgency=low * Support more cihpers: camellia, idea, rc2 and seed. -- Max Lv Tue, 04 Jun 2013 00:56:17 +0000 shadowsocks (1.3-1) unstable; urgency=low * Able to bind connections to specific interface. * Support more ciphers: aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb. -- Max Lv Thu, 16 May 2013 10:51:15 +0800 shadowsocks (1.2-2) unstable; urgency=low * Close timeouted TCP connections. -- Max Lv Tue, 07 May 2013 14:10:33 +0800 shadowsocks (1.2-1) unstable; urgency=low * Fix a high load issue. -- Max Lv Thu, 18 Apr 2013 10:52:34 +0800 shadowsocks (1.1-1) unstable; urgency=low * Fix a IPV6 resolve issue. -- Max Lv Wed, 10 Apr 2013 12:11:36 +0800 shadowsocks (1.0-2) unstable; urgency=low * Initial release. -- Max Lv Sat, 06 Apr 2013 16:59:15 +0800 ================================================ FILE: debian/compat ================================================ 10 ================================================ FILE: debian/config.json ================================================ { "server":["::1", "127.0.0.1"], "mode":"tcp_and_udp", "server_port":8388, "local_port":1080, "password":"barfoo!", "timeout":86400, "method":"chacha20-ietf-poly1305" } ================================================ FILE: debian/control ================================================ Source: shadowsocks-libev Section: net Priority: optional Maintainer: Debian Bridges Team Uploaders: Max Lv , Boyuan Yang , Roger Shimizu Build-Depends: asciidoc-base | asciidoc, debhelper (>= 10), libc-ares-dev, libev-dev, libmbedtls-dev, libpcre2-dev, libsodium-dev (>= 1.0.12), pkg-config, xmlto Standards-Version: 4.1.1 Rules-Requires-Root: no Homepage: https://www.shadowsocks.org Vcs-Git: https://github.com/shadowsocks/shadowsocks-libev.git Vcs-Browser: https://github.com/shadowsocks/shadowsocks-libev Package: shadowsocks-libev Replaces: shadowsocks (<< 1.5.3-2) Breaks: shadowsocks (<< 1.5.3-2) Architecture: any Pre-Depends: ${misc:Pre-Depends} Depends: libcap2-bin [linux-any], lsb-base (>= 3.0-6), ${misc:Depends}, ${shlibs:Depends} Suggests: haveged, kcptun, simple-obfs Description: lightweight and secure socks5 proxy Shadowsocks-libev is a lightweight and secure socks5 proxy for embedded devices and low end boxes. . Shadowsocks-libev was inspired by Shadowsocks (in Python). It's rewritten in pure C and only depends on libev, mbedTLS and a few other tiny libraries. Package: libshadowsocks-libev-dev Architecture: any Multi-Arch: same Section: libdevel Breaks: shadowsocks-libev (<< 2.4.0) Depends: libshadowsocks-libev2 (= ${binary:Version}), ${misc:Depends} Description: lightweight and secure socks5 proxy (development files) Shadowsocks-libev is a lightweight and secure socks5 proxy for embedded devices and low end boxes. . Shadowsocks-libev was inspired by Shadowsocks (in Python). It's rewritten in pure C and only depends on libev, mbedTLS and a few other tiny libraries. . This package provides C header files for the libraries. Package: libshadowsocks-libev2 Architecture: any Multi-Arch: same Section: libs Replaces: libshadowsocks-libev1 Breaks: libshadowsocks-libev1, shadowsocks-libev (<< 2.4.0) Pre-Depends: ${misc:Pre-Depends} Depends: ${misc:Depends}, ${shlibs:Depends} Description: lightweight and secure socks5 proxy (shared library) Shadowsocks-libev is a lightweight and secure socks5 proxy for embedded devices and low end boxes. . Shadowsocks-libev was inspired by Shadowsocks (in Python). It's rewritten in pure C and only depends on libev, mbedTLS and a few other tiny libraries. . This package provides shared libraries. ================================================ FILE: debian/copyright ================================================ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: shadowsocks-libev Upstream-Contact: Max Lv Source: https://github.com/shadowsocks/shadowsocks-libev Files: * Copyright: 2013-2015, Clow Windy 2013-2018, Max Lv 2014, Linus Yang License: GPL-3+ Files: debian/* Copyright: 2013-2015, Max Lv 2015-2018, Boyuan Yang <073plan@gmail.com> 2016-2019, Roger Shimizu License: GPL-3+ Files: doc/* Copyright: 2012-2018, Max Lv License: GFDL-1.1+ Files: m4/ax_pthread.m4 Copyright: 2008 Steven G. Johnson 2011 Daniel Richard G. License: GPL-3+ with Autoconf exception Files: m4/ax_tls.m4 Copyright: 2008 Alan Woodland 2010 Diego Elio Petteno` License: GPL-3+ with Autoconf exception Files: m4/pcre.m4 Copyright: 2015 Syrone Wong License: Apache-2.0 Files: m4/stack-protector.m4 Copyright: 2007 Google Inc. License: Apache-2.0 Files: scripts/build_deb.sh Copyright: 2018 Roger Shimizu License: GPL-3+ Files: src/base64.c src/base64.h Copyright: 2006 Ryan Martell License: LGPL-2.1+ Files: src/json.c src/json.h Copyright: 2012-2014, James McLaughlin et al. License: BSD-2-clause Files: src/resolv.c src/resolv.h Copyright: 2011-2014, Dustin Lundquist License: BSD-2-clause Files: src/rule.c src/rule.h Copyright: 2011-2012, Dustin Lundquist 2011, Manuel Kasper License: BSD-2-clause Files: src/ss-nat Copyright: 2015, OpenWrt-dist 2015, Jian Chang License: GPL-3+ Files: src/uthash.h Copyright: 2003-2016, Troy D. Hanson License: BSD-1-clause Files: tests/test.py Copyright: 2015, Clow Windy License: Apache-2.0 License: Apache-2.0 Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at . http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. . On Debian systems, the complete text of the Apache version 2.0 license can be found in "/usr/share/common-licenses/Apache-2.0". License: BSD-1-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: BSD-2-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. . 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: GFDL-1.1+ Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. . A copy of the license is included in the section entitled "GNU Free Documentation License". License: GPL-3+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". License: GPL-3+ with Autoconf exception This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . . As a special exception, the respective Autoconf Macro's copyright owner gives unlimited permission to copy, distribute and modify the configure scripts that are the output of Autoconf when processing the Macro. You need not follow the terms of the GNU General Public License when using or distributing such scripts, even though portions of the text of the Macro appear in them. The GNU General Public License (GPL) does govern all other use of the material that constitutes the Autoconf Macro. . This special exception to the GPL applies to versions of the Autoconf Macro released by the Autoconf Archive. When you make and distribute a modified version of the Autoconf Macro, you may extend this special exception to the GPL to apply to your modified version as well. License: LGPL-2.1+ This file is part of FFmpeg. . FFmpeg is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. . FFmpeg is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. . You should have received a copy of the GNU Lesser General Public License along with FFmpeg; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ================================================ FILE: debian/copyright.original ================================================ This work was packaged for Debian by: Max Lv on Sat, 06 Apr 2013 16:59:15 +0800 It was downloaded from: https://github.com/madeye/shadowsocks-libev Upstream Author(s): clowwindy Copyright: Copyright (C) 2013 Max Lv License: GPLv3 The Debian packaging is: Copyright (C) 2013 Max Lv ================================================ FILE: debian/libshadowsocks-libev-dev.install ================================================ usr/include/ usr/lib/*/libshadowsocks-libev.so usr/lib/*/pkgconfig/ ================================================ FILE: debian/libshadowsocks-libev2.install ================================================ usr/lib/*/libshadowsocks-libev.so.* ================================================ FILE: debian/rules ================================================ #!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. #export DH_VERBOSE = 1 # Security Hardening export DEB_BUILD_MAINT_OPTIONS = hardening=+all override_dh_auto_install: find src/ -name '*.la' -delete dh_auto_install override_dh_auto_configure: dh_auto_configure -- -DWITH_STATIC=OFF override_dh_installchangelogs: dh_installchangelogs -XChanges %: dh $@ ================================================ FILE: debian/shadowsocks-libev-local@.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This is a template unit file. Users may copy and rename the file into # config directories to make new service instances. See systemd.unit(5) # for details. [Unit] Description=Shadowsocks-Libev Custom Client Service for %I Documentation=man:ss-local(1) After=network-online.target [Service] Type=simple CapabilityBoundingSet=CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_BIND_SERVICE DynamicUser=true ExecStart=/usr/bin/ss-local -c /etc/shadowsocks-libev/%i.json [Install] WantedBy=multi-user.target ================================================ FILE: debian/shadowsocks-libev-redir@.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This is a template unit file. Users may copy and rename the file into # config directories to make new service instances. See systemd.unit(5) # for details. [Unit] Description=Shadowsocks-Libev Custom Client Service Redir Mode for %I Documentation=man:ss-redir(1) After=network-online.target [Service] Type=simple CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE DynamicUser=true ExecStart=/usr/bin/ss-redir -c /etc/shadowsocks-libev/%i.json [Install] WantedBy=multi-user.target ================================================ FILE: debian/shadowsocks-libev-server@.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This is a template unit file. Users may copy and rename the file into # config directories to make new service instances. See systemd.unit(5) # for details. [Unit] Description=Shadowsocks-Libev Custom Server Service for %I Documentation=man:ss-server(1) After=network-online.target [Service] Type=simple CapabilityBoundingSet=CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_BIND_SERVICE DynamicUser=true ExecStart=/usr/bin/ss-server -c /etc/shadowsocks-libev/%i.json [Install] WantedBy=multi-user.target ================================================ FILE: debian/shadowsocks-libev-tunnel@.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This is a template unit file. Users may copy and rename the file into # config directories to make new service instances. See systemd.unit(5) # for details. [Unit] Description=Shadowsocks-Libev Custom Client Service Tunnel Mode for %I Documentation=man:ss-tunnel(1) After=network-online.target [Service] Type=simple CapabilityBoundingSet=CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_BIND_SERVICE DynamicUser=true ExecStart=/usr/bin/ss-tunnel -c /etc/shadowsocks-libev/%i.json [Install] WantedBy=multi-user.target ================================================ FILE: debian/shadowsocks-libev.NEWS ================================================ shadowsocks-libev (3.2.0+ds-5) unstable; urgency=medium There is a mode setting to choose whether to enable both TCP and UDP, or only one of them. This setting was set to "tcp_and_udp" in /etc/default/shadowsocks-libev, /etc/init.d/shadowsocks-libev (for init system only), and maybe also in config.json added by user, which is quite confusing. So we moved this setting to config.json. Since we won't update config.json on package upgrade, please add the following to your /etc/shadowsocks-libev/config.json. "mode":"tcp_and_udp", Otherwise you setting will be TCP only. For more about TCP/UDP mode, please refer the ticket upstream: - https://github.com/shadowsocks/shadowsocks-libev/issues/1870 -- Roger Shimizu Sun, 07 Oct 2018 00:48:07 +0900 ================================================ FILE: debian/shadowsocks-libev.default ================================================ # Defaults for shadowsocks initscript # sourced by /etc/init.d/shadowsocks-libev # installed at /etc/default/shadowsocks-libev by the maintainer scripts # # This is a POSIX shell fragment # # Note: `START', `GROUP' and `MAXFD' options are not recognized by systemd. # Please change those settings in the corresponding systemd unit file. # Enable during startup? START=yes # Configuration file CONFFILE="/etc/shadowsocks-libev/config.json" # Extra command line arguments DAEMON_ARGS= # User and group to run the server as USER=nobody GROUP=nogroup # Number of maximum file descriptors MAXFD=32768 ================================================ FILE: debian/shadowsocks-libev.doc-base ================================================ Document: shadowsocks-libev Title: shadowsocks-libev documentation Author: Max Lv Abstract: This is the documentation of shadowsocks-libev Section: Network/Communication Format: HTML Index: /usr/share/doc/shadowsocks-libev/shadowsocks-libev.html Files: /usr/share/doc/shadowsocks-libev/*.html ================================================ FILE: debian/shadowsocks-libev.docs ================================================ AUTHORS README.md debian/copyright.original scripts doc/*.html ================================================ FILE: debian/shadowsocks-libev.init ================================================ #!/bin/sh ### BEGIN INIT INFO # Provides: shadowsocks-libev # Required-Start: $network $local_fs $remote_fs # Required-Stop: $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: lightweight secured socks5 proxy # Description: Shadowsocks-libev is a lightweight secured # socks5 proxy for embedded devices and low end boxes. ### END INIT INFO # Author: Max Lv # PATH should only include /usr/ if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC=shadowsocks-libev # Introduce a short description here NAME=shadowsocks-libev # Introduce the short server's name here DAEMON=/usr/bin/ss-server # Introduce the server's location here DAEMON_ARGS="" # Arguments to run the daemon with PIDFILE=/var/run/$NAME/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME # Exit if the package is not installed [ -x $DAEMON ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME [ "$START" = "yes" ] || exit 0 : ${USER:="nobody"} : ${GROUP:="nogroup"} # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.0-6) to ensure that this file is present. . /lib/lsb/init-functions # # Function that starts the daemon/service # do_start() { # Modify the file descriptor limit ulimit -n ${MAXFD} # Take care of pidfile permissions mkdir /var/run/$NAME 2>/dev/null || true chown "$USER:$GROUP" /var/run/$NAME # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$GROUP --exec $DAEMON --test > /dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$GROUP --exec $DAEMON -- \ -c "$CONFFILE" -f $PIDFILE $DAEMON_ARGS \ || return 2 } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/5 --pidfile $PIDFILE --exec $DAEMON RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. start-stop-daemon --stop --quiet --oknodo --retry=KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac : ================================================ FILE: debian/shadowsocks-libev.install ================================================ completions/bash/* usr/share/bash-completion/completions/ completions/zsh/* usr/share/zsh/vendor-completions/ debian/config.json usr/share/shadowsocks-libev debian/shadowsocks-libev-*.service lib/systemd/system usr/bin/ usr/share/man/ usr/share/doc/shadowsocks-libev/ ================================================ FILE: debian/shadowsocks-libev.lintian-overrides ================================================ # False positive: systemd service templates cannot fallback to sysvinit script package-supports-alternative-init-but-no-init.d-script lib/systemd/system/shadowsocks-libev-local@.service package-supports-alternative-init-but-no-init.d-script lib/systemd/system/shadowsocks-libev-redir@.service package-supports-alternative-init-but-no-init.d-script lib/systemd/system/shadowsocks-libev-server@.service package-supports-alternative-init-but-no-init.d-script lib/systemd/system/shadowsocks-libev-tunnel@.service ================================================ FILE: debian/shadowsocks-libev.postinst ================================================ #!/bin/sh set -e # POSIX-compliant maint function recommend by devref # to check for the existence of a command # https://www.debian.org/doc/manuals/developers-reference/ch06.html#bpp-debian-maint-scripts pathfind() { OLDIFS="$IFS" IFS=: for p in $PATH; do if [ -x "$p/$*" ]; then IFS="$OLDIFS" return 0 fi done IFS="$OLDIFS" return 1 } case "$1" in configure|reconfigure) if pathfind setcap; then if ! setcap \ cap_net_bind_service+ep /usr/bin/ss-local \ cap_net_bind_service,cap_net_admin+ep /usr/bin/ss-redir \ cap_net_bind_service+ep /usr/bin/ss-server \ cap_net_bind_service+ep /usr/bin/ss-tunnel; then echo "Failed to set capabilities; ss-* will only be runnable by root." fi else echo "setcap not installed; ss-* will only be runnable by root." fi if [ ! -f /etc/shadowsocks-libev/config.json ]; then set +e passwd=$(perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..12)') set -e mkdir -p /etc/shadowsocks-libev sed "s/barfoo!/$passwd/" /usr/share/shadowsocks-libev/config.json \ > /etc/shadowsocks-libev/config.json fi ;; abort-upgrade|abort-remove|abort-deconfigure) exit 0 ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 0 ;; esac #DEBHELPER# exit 0 ================================================ FILE: debian/shadowsocks-libev.postrm ================================================ #!/bin/sh set -e case "$1" in purge) rm -f /etc/shadowsocks-libev/config.json if test ! -e /etc/shadowsocks-libev ; then # If the config directory does not exist, do nothing : else if test -d /etc/shadowsocks-libev ; then # If it is an empty directory, remove it rmdir /etc/shadowsocks-libev || true fi fi ;; remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) exit 0 ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 0 ;; esac #DEBHELPER# exit 0 ================================================ FILE: debian/shadowsocks-libev.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This file is default for Debian packaging. See also # /etc/default/shadowsocks-libev for environment variables. [Unit] Description=Shadowsocks-libev Default Server Service Documentation=man:shadowsocks-libev(8) After=network-online.target Wants=network-online.target [Service] Type=simple CapabilityBoundingSet=CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_BIND_SERVICE DynamicUser=true EnvironmentFile=/etc/default/shadowsocks-libev LimitNOFILE=32768 ExecStart=/usr/bin/ss-server -c $CONFFILE $DAEMON_ARGS [Install] WantedBy=multi-user.target ================================================ FILE: debian/source/format ================================================ 3.0 (quilt) ================================================ FILE: debian/tests/control ================================================ Test-Command: bash tests/test.sh Depends: @, python3, curl, dnsutils Restrictions: allow-stderr ================================================ FILE: debian/upstream/metadata ================================================ Name: shadowsocks-libev Homepage: https://shadowsocks.org Repository: https://github.com/shadowsocks/shadowsocks-libev.git Repository-Browse: https://github.com/shadowsocks/shadowsocks-libev Bug-Database: https://github.com/shadowsocks/shadowsocks-libev/issues Contact: Max Lv ================================================ FILE: debian/watch ================================================ version=4 opts="repack,compression=xz, \ dversionmangle=s/\+ds\d*$//,repacksuffix=+ds, \ filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%shadowsocks-libev_$1.orig.tar.gz%" \ https://github.com/shadowsocks/shadowsocks-libev/tags \ (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate ================================================ FILE: doc/CMakeLists.txt ================================================ find_program(XMLTO_EXECUTABLE NAMES xmlto) find_program(ASCIIDOC_EXECUTABLE NAMES asciidoc asciidoc.py) # Opt-in doc build option if (NOT XMLTO_EXECUTABLE OR NOT ASCIIDOC_EXECUTABLE) option(WITH_DOC_MAN "Build manpage doc" OFF) else () option(WITH_DOC_MAN "Build manpage doc" ON) endif () if (NOT ASCIIDOC_EXECUTABLE) option(WITH_DOC_HTML "Build html doc" OFF) else () option(WITH_DOC_HTML "Build html doc" ON) endif () # NOTE For brew user, we have to setup this env var. see `brew info asciidoc' set(XMLTO_ENV) set(XMLTO_CATALOG_DIR_MACOS /usr/local/etc/xml/catalog) if (EXISTS ${XMLTO_CATALOG_DIR_MACOS}) set(XMLTO_ENV XML_CATALOG_FILES=${XMLTO_CATALOG_DIR_MACOS}) message(STATUS "Detect xmlto catalog dir ${XMLTO_CATALOG_DIR_MACOS}") 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) 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-libev.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 ${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} 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} 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 (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) set_target_properties(doc-html PROPERTIES EXCLUDE_FROM_ALL TRUE) 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) ================================================ FILE: doc/asciidoc.conf ================================================ [tags] bracket-emphasis={1?[{1}]}<|> [quotes] <|>=#bracket-emphasis [attributes] asterisk=* plus=+ caret=^ startsb=[ endsb=] backslash=\ tilde=~ apostrophe=' backtick=` litdd=-- ifdef::doctype-manpage[] ifdef::backend-docbook[] [header] template::[header-declarations] {mantitle} {manvolnum} Shadowsocks-libev {version} Shadowsocks-libev Manual {manname} {manpurpose} endif::backend-docbook[] endif::doctype-manpage[] ================================================ FILE: doc/manpage-base.xsl ================================================ sp br ================================================ FILE: doc/manpage-bold-literal.xsl ================================================ fB fR ================================================ FILE: doc/manpage-normal.xsl ================================================ \ . ================================================ FILE: doc/shadowsocks-libev.asciidoc ================================================ shadowsocks-libev(8) ==================== NAME ---- shadowsocks-libev - a lightweight and secure socks5 proxy SYNOPSIS -------- *ss-local*|*ss-redir*|*ss-server*|*ss-tunnel*|*ss-manager* [-s ] [-p ] [-l ] [-k ] [-m ] [-f ] [-t ] [-c ] DESCRIPTION ----------- *Shadowsocks-libev* is a lightweight and secure socks5 proxy. It is a port of the original shadowsocks created by clowwindy. *Shadowsocks-libev* is written in pure C and takes advantage of *libev* to achieve both high performance and low resource consumption. *Shadowsocks-libev* 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 ------- -s :: Set the server's hostname or IP. -l :: Set the local port number. + Not available in server nor manager mode. -k :: --password :: Set the password. The server and the client should use the same password. --key :: Set the key directly. The key should be encoded with URL-safe Base64. + Not available in manager mode. -m :: Set the cipher. + *Shadowsocks-libev* accepts 19 different ciphers: + aes-128-gcm, aes-192-gcm, aes-256-gcm, 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, chacha20-ietf-poly1305, xchacha20-ietf-poly1305, salsa20, chacha20 and chacha20-ietf. + The default cipher is 'chacha20-ietf-poly1305'. + If built with PolarSSL or custom OpenSSL libraries, some of these ciphers may not work. -a :: Run as a specific user. -f :: Start shadowsocks as a daemon with specific pid file. -t :: Set the socket timeout in seconds. The default value is 60. -c :: Use a configuration file. -n :: Specify max number of open files. + Not available in manager mode. + Only available on Linux. -i :: Send traffic through specific network interface. + For example, there are three interfaces in your device, which is lo (127.0.0.1), eth0 (192.168.0.1) and eth1 (192.168.0.2). Meanwhile, you configure *shadowsocks-libev* to listen on 0.0.0.0:8388 and bind to eth1. That results the traffic go out through eth1, but not lo nor eth0. This option is useful to control traffic in multi-interface environment. + Not available in redir mode. -b :: Specify the local address to bind. + For servers: Specify the local address to use while this server is making outbound connections to remote servers on behalf of the clients. + For clients: Specify the local address to use while this client is making outbound connections to the server. + Not available in manager mode. -u:: Enable UDP relay. + TPROXY is required in redir mode. You may need root permission. -U:: Enable UDP relay and disable TCP relay. + Not available in local mode. -T:: Use tproxy instead of redirect (for tcp). + Only available in redir mode. -L :: Specify destination server address and port for local port forwarding. + Only available in tunnel mode. -d :: Setup name servers for internal DNS resolver (libc-ares). The default server is fetched from /etc/resolv.conf. + Only available in server and manager mode. --fast-open:: Enable TCP fast open. + Not available in redir nor tunnel mode, with Linux kernel > 3.7.0. --reuse-port:: Enable port reuse. + Only available with Linux kernel > 3.9.0. --no-delay:: Enable TCP_NODELAY. --tcp-incoming-sndbuf :: Set TCP send buffer size for incoming connections. + Not available in manager mode. --tcp-incoming-rcvbuf :: Set TCP receive buffer size for incoming connections. + Not available in manager mode. --tcp-outgoing-sndbuf :: Set TCP send buffer size for outgoing connections. + Not available in manager mode. --tcp-outgoing-rcvbuf :: Set TCP receive buffer size for outgoing connections. + Not available in manager mode. --acl :: Enable ACL (Access Control List) and specify config file. + Not available in redir nor tunnel mode. --manager-address :: Specify UNIX domain socket address. + Only available in server and manager mode. --executable :: Specify the executable path of `ss-server`. + Only available in manager mode. -D :: --workdir :: Specify the working directory of ss-manager. + Only available in manager mode. --nftables-sets :: Specify nftables sets for reporting malicious IPs. + Only available in server mode, when built with nftables support. -v:: Enable verbose mode. -h|--help:: Print help message. 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 ================================================ FILE: doc/ss-local.asciidoc ================================================ ss-local(1) =========== NAME ---- ss-local - shadowsocks client as socks5 proxy, libev port SYNOPSIS -------- *ss-local* [-uv6] [-h|--help] [-s ] [-p ] [-l ] [-k ] [-m ] [-f ] [-t ] [-c ] [-i ] [-a ] [-b ] [-n ] [--fast-open] [--reuse-port] [--acl ] [--mtu ] [--no-delay] [--plugin ] [--plugin-opts ] [--password ] [--key ] DESCRIPTION ----------- *Shadowsocks-libev* is a lightweight and secure socks5 proxy. It is a port of the original shadowsocks created by clowwindy. *Shadowsocks-libev* is written in pure C and takes advantage of libev to achieve both high performance and low resource consumption. *Shadowsocks-libev* 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 ------- -s :: Set the server's hostname or IP. -p :: Set the server's port number. -l :: Set the local port number. -k :: --password :: Set the password. The server and the client should use the same password. --key :: Set the key directly. The key should be encoded with URL-safe Base64. -m :: Set the cipher. + *Shadowsocks-libev* accepts 19 different ciphers: + aes-128-gcm, aes-192-gcm, aes-256-gcm, 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, chacha20-ietf-poly1305, xchacha20-ietf-poly1305, salsa20, chacha20 and chacha20-ietf. + The default cipher is 'chacha20-ietf-poly1305'. + If built with PolarSSL or custom OpenSSL libraries, some of these ciphers may not work. -a :: Run as a specific user. -f :: Start shadowsocks as a daemon with specific pid file. -t :: Set the socket timeout in seconds. The default value is 60. -c :: Use a configuration file. + Refer to `shadowsocks-libev`(8) 'CONFIG FILE' section for more details. -n :: Specify max number of open files. + Only available on Linux. -i :: Send traffic through specific network interface. + For example, there are three interfaces in your device, which is lo (127.0.0.1), eth0 (192.168.0.1) and eth1 (192.168.0.2). Meanwhile, you configure `ss-local` to listen on 0.0.0.0:8388 and bind to eth1. That results the traffic go out through eth1, but not lo nor eth0. This option is useful to control traffic in multi-interface environment. -b :: Specify the local address to use while this client is making outbound connections to the server. -u:: Enable UDP relay. -U:: Enable UDP relay and disable TCP relay. -6:: Resolve hostname to IPv6 address first. --fast-open:: Enable TCP fast open. + Only available with Linux kernel > 3.7.0. --reuse-port:: Enable port reuse. + Only available with Linux kernel > 3.9.0. --acl :: Enable ACL (Access Control List) and specify config file. --mtu :: Specify the MTU of your network interface. --mptcp:: Enable Multipath TCP. + Only available with MPTCP enabled Linux kernel. --no-delay:: Enable TCP_NODELAY. --tcp-incoming-sndbuf :: Set TCP send buffer size for incoming connections. --tcp-incoming-rcvbuf :: Set TCP receive buffer size for incoming connections. --tcp-outgoing-sndbuf :: Set TCP send buffer size for outgoing connections. --tcp-outgoing-rcvbuf :: Set TCP receive buffer size for outgoing connections. --plugin :: Enable SIP003 plugin. (Experimental) --plugin-opts :: Set SIP003 plugin options. (Experimental) -v:: Enable verbose mode. -h|--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 ================================================ FILE: doc/ss-manager.asciidoc ================================================ ss-manager(1) ============= NAME ---- ss-manager - ss-server controller for multi-user management and traffic statistics SYNOPSIS -------- *ss-manager* [-AuUv] [-h|--help] [-s ] [-p ] [-l ] [-k ] [-m ] [-f ] [-t ] [-c ] [-i ] [-b ] [-a ] [-D ] [--manager-address ] [--executable ] [--fast-open] [--reuse-port] [--plugin ] [--plugin-opts ] DESCRIPTION ----------- *Shadowsocks-libev* is a lightweight and secure socks5 proxy. It is a port of the original shadowsocks created by clowwindy. *Shadowsocks-libev* is written in pure C and takes advantage of libev to achieve both high performance and low resource consumption. *Shadowsocks-libev* 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 ------- -s :: Set the server's hostname or IP. -k :: Set the password. The server and the client should use the same password. -m :: Set the cipher. + *Shadowsocks-libev* accepts 19 different ciphers: + aes-128-gcm, aes-192-gcm, aes-256-gcm, 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, chacha20-ietf-poly1305, xchacha20-ietf-poly1305, salsa20, chacha20 and chacha20-ietf. + The default cipher is 'chacha20-ietf-poly1305'. + If built with PolarSSL or custom OpenSSL libraries, some of these ciphers may not work. -a :: Run as a specific user. -f :: Start shadowsocks as a daemon with specific pid file. -t :: Set the socket timeout in seconds. The default value is 60. -c :: Use a configuration file. + You may use "port_password" field inside this configuration file to bring up multiple ss-server instances together. -i :: Send traffic through specific network interface. + For example, there are three interfaces in your device, which is lo (127.0.0.1), eth0 (192.168.0.1) and eth1 (192.168.0.2). Meanwhile, you configure `ss-local` to listen on 0.0.0.0:8388 and bind to eth1. That results the traffic go out through eth1, but not lo nor eth0. This option is useful to control traffic in multi-interface environment. -u:: Enable UDP relay. -U:: Enable UDP relay and disable TCP relay. -A:: Enable onetime authentication. -d :: Setup name servers for internal DNS resolver (libc-ares). The default server is fetched from `/etc/resolv.conf`. --fast-open:: Enable TCP fast open. + Only available with Linux kernel > 3.7.0. --reuse-port:: Enable port reuse. + Only available with Linux kernel > 3.9.0. --acl :: Enable ACL (Access Control List) and specify config file. --manager-address :: Specify UNIX domain socket address for the communication between ss-manager(1) and ss-server(1). + Only available in server and manager mode. --executable :: Specify the executable path of ss-server. + Only available in manager mode. -D :: --workdir :: Specify the working directory of ss-manager. + Only available in manager mode. --plugin :: Enable SIP003 plugin. (Experimental) --plugin-opts :: Set SIP003 plugin options. (Experimental) -v:: Enable verbose mode. -h|--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 ================================================ FILE: doc/ss-nat.asciidoc ================================================ ss-nat(1) ========= NAME ---- ss-nat - helper script to setup NAT rules for transparent proxy SYNOPSIS -------- *ss-nat* [-ouUfh] [-s ] [-S ] [-l ] [-L ] [-i ] [-a ] [-b ] [-w ] [-e ] DESCRIPTION ----------- *Shadowsocks-libev* is a lightweight and secure socks5 proxy. It is a port of the original shadowsocks created by clowwindy. *Shadowsocks-libev* is written in pure C and takes advantage of libev 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 ------- -s :: IP address of shadowsocks remote server -l :: Port number of shadowsocks local server -S :: IP address of shadowsocks remote UDP server -L :: Port number of shadowsocks local UDP server -i :: a file whose content is bypassed ip list -a :: LAN IP of access control, need a prefix to define access control mode -b :: WAN IP of will be bypassed -w :: WAN IP of will be forwarded -e :: 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 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 ================================================ FILE: doc/ss-redir.asciidoc ================================================ ss-redir(1) =========== NAME ---- ss-redir - shadowsocks client as transparent proxy, libev port SYNOPSIS -------- *ss-redir* [-uUv6] [-h|--help] [-s ] [-p ] [-l ] [-k ] [-m ] [-f ] [-t ] [-c ] [-b ] [-a ] [-n ] [--mtu ] [--no-delay] [--plugin ] [--plugin-opts ] [--password ] [--key ] DESCRIPTION ----------- *Shadowsocks-libev* is a lightweight and secure socks5 proxy. It is a port of the original shadowsocks created by clowwindy. *Shadowsocks-libev* is written in pure C and takes advantage of libev to achieve both high performance and low resource consumption. *Shadowsocks-libev* 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 ------- -s :: Set the server's hostname or IP. -p :: Set the server's port number. -l :: Set the local port number. -k :: --password :: Set the password. The server and the client should use the same password. --key :: Set the key directly. The key should be encoded with URL-safe Base64. -m :: Set the cipher. + *Shadowsocks-libev* accepts 19 different ciphers: + aes-128-gcm, aes-192-gcm, aes-256-gcm, 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, chacha20-ietf-poly1305, xchacha20-ietf-poly1305, salsa20, chacha20 and chacha20-ietf. + The default cipher is 'chacha20-ietf-poly1305'. + If built with PolarSSL or custom OpenSSL libraries, some of these ciphers may not work. -a :: Run as a specific user. -f :: Start shadowsocks as a daemon with specific pid file. -t :: Set the socket timeout in seconds. The default value is 60. -c :: Use a configuration file. + Refer to `shadowsocks-libev`(8) 'CONFIG FILE' section for more details. -n :: Specify max number of open files. + Only available on Linux. -b :: Specify the local address to use while this client is making outbound connections to the server. -u:: Enable UDP relay. + TPROXY is required in redir mode. You may need root permission. -U:: Enable UDP relay and disable TCP relay. -T:: Use tproxy instead of redirect. (for tcp) -6:: Resolve hostname to IPv6 address first. --mtu :: Specify the MTU of your network interface. --mptcp:: Enable Multipath TCP. + Only available with MPTCP enabled Linux kernel. --reuse-port:: Enable port reuse. + Only available with Linux kernel > 3.9.0. --no-delay:: Enable TCP_NODELAY. --tcp-incoming-sndbuf :: Set TCP send buffer size for incoming connections. --tcp-incoming-rcvbuf :: Set TCP receive buffer size for incoming connections. --tcp-outgoing-sndbuf :: Set TCP send buffer size for outgoing connections. --tcp-outgoing-rcvbuf :: Set TCP receive buffer size for outgoing connections. --plugin :: Enable SIP003 plugin. (Experimental) --plugin-opts :: Set SIP003 plugin options. (Experimental) -v:: Enable verbose mode. -h|--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 ================================================ FILE: doc/ss-server.asciidoc ================================================ ss-server(1) ============ NAME ---- ss-server - shadowsocks server, libev port SYNOPSIS -------- *ss-server* [-uUv] [-h|--help] [-s ] [-p ] [-l ] [-k ] [-m ] [-f ] [-t ] [-c ] [-i ] [-a ] [-d ] [-n ] [-b ] [--fast-open] [--reuse-port] [--mptcp] [--acl ] [--mtu ] [--no-delay] [--manager-address ] [--plugin ] [--plugin-opts ] [--password ] [--key ] DESCRIPTION ----------- *Shadowsocks-libev* is a lightweight and secure socks5 proxy. It is a port of the original shadowsocks created by clowwindy. *Shadowsocks-libev* is written in pure C and takes advantage of libev to achieve both high performance and low resource consumption. *Shadowsocks-libev* 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 ------- -s :: Set the server's hostname or IP. -p :: Set the server's port number. -k :: --password :: Set the password. The server and the client should use the same password. --key :: Set the key directly. The key should be encoded with URL-safe Base64. -m :: Set the cipher. + *Shadowsocks-libev* accepts 19 different ciphers: + aes-128-gcm, aes-192-gcm, aes-256-gcm, 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, chacha20-ietf-poly1305, xchacha20-ietf-poly1305, salsa20, chacha20 and chacha20-ietf. + If built with PolarSSL or custom OpenSSL libraries, some of these ciphers may not work. -a :: Run as a specific user. -f :: Start shadowsocks as a daemon with specific pid file. -t :: Set the socket timeout in seconds. The default value is 60. -c :: Use a configuration file. + Refer to `shadowsocks-libev`(8) 'CONFIG FILE' section for more details. -n :: Specify max number of open files. + Only available on Linux. -i :: Send traffic through specific network interface. + For example, there are three interfaces in your device, which is lo (127.0.0.1), eth0 (192.168.0.1) and eth1 (192.168.0.2). Meanwhile, you configure `ss-server` to listen on 0.0.0.0:8388 and bind to eth1. That results the traffic go out through eth1, but not lo nor eth0. This option is useful to control traffic in multi-interface environment. -b :: Specify the local address to use while this server is making outbound connections to remote servers on behalf of the clients. -u:: Enable UDP relay. -U:: Enable UDP relay and disable TCP relay. -6:: Resolve hostname to IPv6 address first. -d :: Setup name servers for internal DNS resolver (libc-ares). The default server is fetched from '/etc/resolv.conf'. --fast-open:: Enable TCP fast open. + Only available with Linux kernel > 3.7.0. --reuse-port:: Enable port reuse. + Only available with Linux kernel > 3.9.0. --no-delay:: Enable TCP_NODELAY. --tcp-incoming-sndbuf :: Set TCP send buffer size for incoming connections. --tcp-incoming-rcvbuf :: Set TCP receive buffer size for incoming connections. --tcp-outgoing-sndbuf :: Set TCP send buffer size for outgoing connections. --tcp-outgoing-rcvbuf :: Set TCP receive buffer size for outgoing connections. --acl :: Enable ACL (Access Control List) and specify config file. --manager-address :: Specify UNIX domain socket address for the communication between ss-manager(1) and ss-server(1). + Only available in server and manager mode. --mtu :: Specify the MTU of your network interface. --mptcp:: Enable Multipath TCP. + Only available with MPTCP enabled Linux kernel. --plugin :: Enable SIP003 plugin. (Experimental) --plugin-opts :: Set SIP003 plugin options. (Experimental) -v:: Enable verbose mode. -h|--help:: Print help message. 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 ================================================ FILE: doc/ss-tunnel.asciidoc ================================================ ss-tunnel(1) ============ NAME ---- ss-tunnel - shadowsocks tools for local port forwarding, libev port SYNOPSIS -------- *ss-tunnel* [-uUv6] [-h|--help] [-s ] [-p ] [-l ] [-k ] [-m ] [-f ] [-t ] [-c ] [-i ] [-b ] [-a ] [-n ] [-L addr:port] [--mtu ] [--mptcp] [--reuse-port] [--no-delay] [--plugin ] [--plugin-opts ] [--key ] DESCRIPTION ----------- *Shadowsocks-libev* is a lightweight and secure socks5 proxy. It is a port of the original shadowsocks created by clowwindy. *Shadowsocks-libev* is written in pure C and takes advantage of libev to achieve both high performance and low resource consumption. *Shadowsocks-libev* 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 ------- -s :: Set the server's hostname or IP. -p :: Set the server's port number. -l :: Set the local port number. -k :: --password :: Set the password. The server and the client should use the same password. --key :: Set the key directly. The key should be encoded with URL-safe Base64. -m :: Set the cipher. + *Shadowsocks-libev* accepts 19 different ciphers: + aes-128-gcm, aes-192-gcm, aes-256-gcm, 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, chacha20-ietf-poly1305, xchacha20-ietf-poly1305, salsa20, chacha20 and chacha20-ietf. + The default cipher is 'chacha20-ietf-poly1305'. + If built with PolarSSL or custom OpenSSL libraries, some of these ciphers may not work. -a :: Run as a specific user. -f :: Start shadowsocks as a daemon with specific pid file. -t :: Set the socket timeout in seconds. The default value is 60. -c :: Use a configuration file. + Refer to `shadowsocks-libev`(8) 'CONFIG FILE' section for more details. -n :: Specify max number of open files. + Only available on Linux. -i :: Send traffic through specific network interface. + For example, there are three interfaces in your device, which is lo (127.0.0.1), eth0 (192.168.0.1) and eth1 (192.168.0.2). Meanwhile, you configure `ss-tunnel` to listen on 0.0.0.0:8388 and bind to eth1. That results the traffic go out through eth1, but not lo nor eth0. This option is useful to control traffic in multi-interface environment. -b :: Specify the local address to use while this client is making outbound connections to the server. -u:: Enable UDP relay. -U:: Enable UDP relay and disable TCP relay. -6:: Resolve hostname to IPv6 address first. -L :: Specify destination server address and port for local port forwarding. + Only used and available in tunnel mode. --mtu :: Specify the MTU of your network interface. --mptcp:: Enable Multipath TCP. + Only available with MPTCP enabled Linux kernel. --reuse-port:: Enable port reuse. + Only available with Linux kernel > 3.9.0. --no-delay:: Enable TCP_NODELAY. --tcp-incoming-sndbuf :: Set TCP send buffer size for incoming connections. --tcp-incoming-rcvbuf :: Set TCP receive buffer size for incoming connections. --tcp-outgoing-sndbuf :: Set TCP send buffer size for outgoing connections. --tcp-outgoing-rcvbuf :: Set TCP receive buffer size for outgoing connections. --plugin :: Enable SIP003 plugin. (Experimental) --plugin-opts :: Set SIP003 plugin options. (Experimental) -v:: Enable verbose mode. -h|--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 ================================================ FILE: docker/alpine/Dockerfile ================================================ FROM alpine:3.16 LABEL maintainer="kev , Sah , vndroid " ENV SERVER_ADDR=0.0.0.0 ENV SERVER_PORT=8388 ENV PASSWORD= ENV METHOD=aes-256-gcm ENV TIMEOUT=300 ENV DNS_ADDRS="8.8.8.8,8.8.4.4" ENV TZ=UTC ENV ARGS= COPY . /tmp/repo RUN set -x \ # Build environment setup && apk add --no-cache --virtual .build-deps \ build-base \ cmake \ c-ares-dev \ libcap \ libev-dev \ libsodium-dev \ linux-headers \ mbedtls-dev \ pcre2-dev \ # Build & install && cd /tmp/repo \ && mkdir -p build && cd build \ && cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTING=OFF -DWITH_STATIC=OFF -DCMAKE_BUILD_TYPE=Release \ && make -j$(getconf _NPROCESSORS_ONLN) \ && make install \ && cd /usr/local/bin \ && ls /usr/local/bin/ss-* | xargs -n1 setcap cap_net_bind_service+ep \ && strip $(ls /usr/local/bin | grep -Ev 'ss-nat') \ && apk del .build-deps \ # Runtime dependencies setup && apk add --no-cache \ ca-certificates \ rng-tools \ tzdata \ $(scanelf --needed --nobanner /usr/local/bin/ss-* \ | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ | sort -u) \ && rm -rf /tmp/repo COPY ./docker/alpine/entrypoint.sh /usr/local/bin/docker-entrypoint.sh ENTRYPOINT ["docker-entrypoint.sh"] EXPOSE 8388 STOPSIGNAL SIGINT CMD ["ss-server"] ================================================ FILE: docker/alpine/README.md ================================================ # Shadowsocks-libev Docker Image [shadowsocks-libev][1] is a lightweight secured socks5 proxy for embedded devices and low end boxes. It is a port of [shadowsocks][2] created by @clowwindy maintained by @madeye and @linusyang. Docker images are built for quick deployment in various computing cloud providers. For more information on docker and containerization technologies, refer to [official document][9]. ## Prepare the host Many cloud providers offer docker-ready environments, for instance the [CoreOS Droplet in DigitalOcean][10] or the [Container-Optimized OS in Google Cloud][11]. If you need to install docker yourself, follow the [official installation guide][12]. ## Pull the image ```bash $ docker pull shadowsocks/shadowsocks-libev ``` This pulls the latest release of shadowsocks-libev. You can also choose to pull a previous release or to try the bleeding edge build: ```bash $ docker pull shadowsocks/shadowsocks-libev: $ docker pull shadowsocks/shadowsocks-libev:edge ``` > A list of supported tags can be found at [Docker Hub][13]. ## Start a container ```bash $ docker run -p 8388:8388 -p 8388:8388/udp -d --restart always shadowsocks/shadowsocks-libev:latest ``` This starts a container of the latest release with all the default settings, which is equivalent to ```bash $ ss-server -s 0.0.0.0 -p 8388 -k "$(hostname)" -m aes-256-gcm -t 300 -d "8.8.8.8,8.8.4.4" -u ``` > **Note**: It's the hostname in the container that is used as the password, not that of the host. ### With custom port In most cases you'll want to change a thing or two, for instance the port which the server listens on. This is done by changing the `-p` arguments. Here's an example to start a container that listens on `28388` (both TCP and UDP): ```bash $ docker run -p 28388:8388 -p 28388:8388/udp -d --restart always shadowsocks/shadowsocks-libev ``` ### With custom password Another thing you may want to change is the password. To change that, you can pass your own password as an environment variable when starting the container. Here's an example to start a container with `9MLSpPmNt` as the password: ```bash $ docker run -e PASSWORD=9MLSpPmNt -p 8388:8388 -p 8388:8388/udp -d --restart always shadowsocks/shadowsocks-libev ``` > :warning: Click [here][6] to generate a strong password to protect your server. ### With password as a mounted file or a Docker secret (swarm only) Instead of hardcoding a password to the docker-compose file or `docker run` command, you can mount in a file that contains the password. To do so, pass the path that you mounted to the container as the `PASSWORD_FILE` environment variable. If you are running Docker Swarm, you can also utilize Docker secrets. To do so, pass the name of the secret as the `PASSWORD_SECRET` environment variable. If you specify both `PASSWORD_FILE` and `PASSWORD_SECRET`, the latter will take effect. This is a sample `docker-compose.yml` file that uses the external Docker secret named `shadowsocks` as the password. ```yaml shadowsocks: image: shadowsocks/shadowsocks-libev ports: - "8388:8388" environment: - METHOD=aes-256-gcm - PASSWORD_SECRET=shadowsocks secrets: - shadowsocks ``` This is a sample `docker service create` command that uses the external Docker secret named `shadowsocks` as the password. ```bash docker service create -e PASSWORD_SECRET=shadowsocks -p 8388:8388 -p 8388:8388/udp --secret shadowsocks shadowsocks/shadowsocks-libev ``` ### With other customizations Besides `PASSWORD`, the image also defines the following environment variables that you can customize: * `SERVER_ADDR`: the IP/domain to bind to, defaults to `0.0.0.0` * `SERVER_ADDR_IPV6`: the IPv6 address to bind to, defaults to `::0` * `METHOD`: encryption method to use, defaults to `aes-256-gcm` * `TIMEOUT`: defaults to `300` * `DNS_ADDRS`: DNS servers to redirect NS lookup requests to, defaults to `8.8.8.8,8.8.4.4` * `TZ`: Timezone, defaults to `UTC` Additional arguments supported by `ss-server` can be passed with the environment variable `ARGS`, for instance to start in verbose mode: ```bash $ docker run -e ARGS=-v -p 8388:8388 -p 8388:8388/udp -d --restart always shadowsocks/shadowsocks-libev:latest ``` ## Use docker-compose to manage (optional) It is very handy to use [docker-compose][7] to manage docker containers. You can download the binary at . This is a sample `docker-compose.yml` file. ```yaml shadowsocks: image: shadowsocks/shadowsocks-libev ports: - "8388:8388" environment: - METHOD=aes-256-gcm - PASSWORD=9MLSpPmNt restart: always ``` It is highly recommended that you setup a directory tree to make things easy to manage. ```bash $ mkdir -p ~/fig/shadowsocks/ $ cd ~/fig/shadowsocks/ $ curl -sSLO https://github.com/shadowsocks/shadowsocks-libev/raw/master/docker/alpine/docker-compose.yml $ docker-compose up -d $ docker-compose ps ``` ## Finish At last, download shadowsocks client [here][8]. Don't forget to share internet with your friends. ```yaml { "server": "your-vps-ip", "server_port": 8388, "local_address": "0.0.0.0", "local_port": 1080, "password": "9MLSpPmNt", "timeout": 600, "method": "aes-256-gcm" } ``` [1]: https://github.com/shadowsocks/shadowsocks-libev [2]: https://shadowsocks.org/en/index.html [6]: https://duckduckgo.com/?q=password+12&t=ffsb&ia=answer [7]: https://github.com/docker/compose [8]: https://shadowsocks.org/en/download/clients.html [9]: https://docs.docker.com/ [10]: https://www.digitalocean.com/products/linux-distribution/coreos/ [11]: https://cloud.google.com/container-optimized-os/ [12]: https://docs.docker.com/install/ [13]: https://hub.docker.com/r/shadowsocks/shadowsocks-libev/tags/ ================================================ FILE: docker/alpine/docker-compose.yml ================================================ shadowsocks: image: shadowsocks/shadowsocks-libev ports: - "8388:8388/tcp" - "8388:8388/udp" environment: - METHOD=aes-256-gcm - PASSWORD=9MLSpPmNt restart: always ================================================ FILE: docker/alpine/entrypoint.sh ================================================ #!/bin/sh # vim:sw=4:ts=4:et set -e if [ "$1" = "ss-server" ]; then COREVER=$(uname -r | grep -Eo '[0-9].[0-9]+' | sed -n '1,1p') CMV=$(echo $COREVER | awk -F '.' '{print $1}') CSV=$(echo $COREVER | awk -F '.' '{print $2}') if [[ -f "$PASSWORD_FILE" ]]; then PASSWORD=$(cat "$PASSWORD_FILE") fi if [[ -f "/var/run/secrets/$PASSWORD_SECRET" ]]; then PASSWORD=$(cat "/var/run/secrets/$PASSWORD_SECRET") fi if [[ ! -z "$DNS_ADDRS" ]]; then DNS="-d $DNS_ADDRS" fi if [ $(echo "$CMV >= 3" | bc) ]; then if [ $(echo "$CSV > 7" | bc) ]; then TFO='--fast-open' fi fi RT_ARGS="-s $SERVER_ADDR -p $SERVER_PORT -k ${PASSWORD:-$(hostname)} -m $METHOD -a nobody -t $TIMEOUT -u $DNS $TFO $ARGS" fi exec $@ $RT_ARGS ================================================ FILE: docker/mingw/Dockerfile ================================================ # # Dockerfile for building MinGW port # # This file is part of the shadowsocks-libev. # # shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # shadowsocks-libev is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with shadowsocks-libev; see the file COPYING. If not, see # . # FROM debian:stretch ARG REPO=shadowsocks ARG REV=master ADD docker/mingw/apt.sh / RUN \ /bin/bash -c "source /apt.sh && dk_prepare" && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /build ADD docker/mingw/prepare.sh / RUN /bin/bash -c "source /prepare.sh && dk_download" ADD docker/mingw/deps.sh / RUN /bin/bash -c "source /deps.sh && dk_deps" ADD docker/mingw/build.sh / ARG REBUILD=0 ADD . /build/src/proj RUN /bin/bash -c "source /build.sh && dk_build" RUN /bin/bash -c "source /build.sh && dk_package" ================================================ FILE: docker/mingw/Makefile ================================================ # # Makefile for building MinGW port # # This file is part of the shadowsocks-libev. # # shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # shadowsocks-libev is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with shadowsocks-libev; see the file COPYING. If not, see # . # REPO=shadowsocks REV=master IMAGE=ss-build-mingw DIST=ss-libev-win-dist.tar.gz all: build build: cd ../../ && docker build -t $(IMAGE) \ -f docker/mingw/Dockerfile \ --build-arg REV=$(REV) --build-arg REPO=$(REPO) \ --build-arg REBUILD="$$(date +%Y-%m-%d-%H-%M-%S)" \ . docker run --rm --entrypoint cat $(IMAGE) /bin.tgz > $(DIST) clean: rm -f $(DIST) docker rmi $(IMAGE) || true .PHONY: all clean build ================================================ FILE: docker/mingw/apt.sh ================================================ #!/bin/bash # # Functions for building MinGW port in Docker # # This file is part of the shadowsocks-libev. # # shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # shadowsocks-libev is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with shadowsocks-libev; see the file COPYING. If not, see # . # # Exit on error set -e # Build steps dk_prepare() { apt-get update -y apt-get install --no-install-recommends -y \ mingw-w64 aria2 git make automake autoconf libtool ca-certificates } ================================================ FILE: docker/mingw/build.sh ================================================ #!/bin/bash # # Functions for building MinGW port in Docker # # This file is part of the shadowsocks-libev. # # shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # shadowsocks-libev is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with shadowsocks-libev; see the file COPYING. If not, see # . # # Exit on error set -e . /prepare.sh build_proj() { arch=$1 host=$arch-w64-mingw32 prefix=${DIST}/$arch dep=${PREFIX}/$arch cpu="$(nproc --all)" cd "$SRC" cd proj ./autogen.sh ./configure --host=${host} --prefix=${prefix} \ --disable-documentation \ --with-ev="$dep" \ --with-mbedtls="$dep" \ --with-sodium="$dep" \ --with-pcre="$dep" \ --with-cares="$dep" \ CFLAGS="-DCARES_STATICLIB -DPCRE_STATIC" make clean make -j$cpu LDFLAGS="-all-static -L${dep}/lib" make install } dk_build() { for arch in i686 x86_64; do build_proj $arch done } dk_package() { rm -rf "$BASE/pack" mkdir -p "$BASE/pack" cd "$BASE/pack" mkdir -p ss-libev-${PROJ_REV} cd ss-libev-${PROJ_REV} for bin in local server tunnel; do cp ${DIST}/i686/bin/ss-${bin}.exe ss-${bin}-x86.exe cp ${DIST}/x86_64/bin/ss-${bin}.exe ss-${bin}-x64.exe done cd .. tar zcf /bin.tgz ss-libev-${PROJ_REV} } ================================================ FILE: docker/mingw/deps.sh ================================================ #!/bin/bash # # Functions for building MinGW port in Docker # # This file is part of the shadowsocks-libev. # # shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # shadowsocks-libev is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with shadowsocks-libev; see the file COPYING. If not, see # . # # Exit on error set -e . /prepare.sh build_deps() { arch=$1 host=$arch-w64-mingw32 prefix=${PREFIX}/$arch args="--host=${host} --prefix=${prefix} --disable-shared --enable-static" cpu="$(nproc --all)" # libev cd "$SRC/$LIBEV_SRC" ./configure $args make clean make -j$cpu install # mbedtls cd "$SRC/$MBEDTLS_SRC" make clean make -j$cpu lib WINDOWS=1 CC="${host}-gcc" AR="${host}-ar" ## "make install" command from mbedtls DESTDIR="${prefix}" mkdir -p "${DESTDIR}"/include/mbedtls cp -r include/mbedtls "${DESTDIR}"/include mkdir -p "${DESTDIR}"/lib cp -RP library/libmbedtls.* "${DESTDIR}"/lib cp -RP library/libmbedx509.* "${DESTDIR}"/lib cp -RP library/libmbedcrypto.* "${DESTDIR}"/lib unset DESTDIR # sodium cd "$SRC/$SODIUM_SRC" ./autogen.sh ./configure $args make clean make -j$cpu install # pcre cd "$SRC/$PCRE_SRC" ./configure $args --disable-cpp \ --enable-unicode-properties make clean make -j$cpu install # c-ares cd "$SRC/$CARES_SRC" ./configure $args make clean make -j$cpu install } dk_deps() { for arch in i686 x86_64; do build_deps $arch done } ================================================ FILE: docker/mingw/make.bat ================================================ @echo off pushd %~dp0 set "REPO=shadowsocks" set "REV=master" set "PLUGIN=true" set "IMAGE=ss-build-mingw" set "DIST=ss-libev-win-dist.tar.gz" docker build --force-rm -t %IMAGE% ^ --build-arg REV=%REV% --build-arg REPO=%REPO% ^ --build-arg REBUILD=%RANDOM% ^ --build-arg PLUGIN=%PLUGIN% . docker run --rm --entrypoint cat %IMAGE% /bin.tgz > %DIST% pause ================================================ FILE: docker/mingw/prepare.sh ================================================ #!/bin/bash # # Functions for building MinGW port in Docker # # This file is part of the shadowsocks-libev. # # shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # shadowsocks-libev is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with shadowsocks-libev; see the file COPYING. If not, see # . # # Exit on error set -e # Build options BASE="/build" PREFIX="$BASE/stage" SRC="$BASE/src" DIST="$BASE/dist" # Project URL PROJ_SITE=$REPO # Change REPO in Makefile PROJ_REV=$REV # Change REV in Makefile PROJ_URL=https://github.com/${PROJ_SITE}/shadowsocks-libev.git # Libraries from project ## libev for MinGW LIBEV_VER=mingw LIBEV_SRC=libev-${LIBEV_VER} LIBEV_URL=https://github.com/${PROJ_SITE}/libev/archive/${LIBEV_VER}.tar.gz # Public libraries ## mbedTLS MBEDTLS_VER=2.16.5 MBEDTLS_SRC=mbedtls-${MBEDTLS_VER} MBEDTLS_URL=https://tls.mbed.org/download/mbedtls-${MBEDTLS_VER}-apache.tgz ## Sodium SODIUM_VER=1.0.18 SODIUM_SRC=libsodium-stable SODIUM_URL=https://download.libsodium.org/libsodium/releases/libsodium-${SODIUM_VER}-stable.tar.gz ## PCRE PCRE_VER=8.44 PCRE_SRC=pcre-${PCRE_VER} PCRE_URL=https://ftp.pcre.org/pub/pcre/${PCRE_SRC}.tar.gz ## c-ares CARES_VER=1.16.0 CARES_SRC=c-ares-${CARES_VER} CARES_URL=https://c-ares.haxx.se/download/${CARES_SRC}.tar.gz # Build steps dk_download() { mkdir -p "${SRC}" cd "${SRC}" DOWN="aria2c --file-allocation=trunc -s10 -x10 -j10 -c" for pkg in LIBEV SODIUM MBEDTLS PCRE CARES; do src=${pkg}_SRC url=${pkg}_URL out="${!src}".tar.gz $DOWN ${!url} -o "${out}" echo "Unpacking ${out}..." tar zxf ${out} done } ================================================ FILE: rpm/SOURCES/etc/init.d/shadowsocks-libev ================================================ #!/bin/bash # # Script to run Shadowsocks in daemon mode at boot time. # ScriptAuthor: icyboy # Revision 1.0 - 14th Sep 2013 #==================================================================== # Run level information: # chkconfig: 2345 99 99 # Description: lightweight secured socks5 proxy # processname: ss-server # Author: Max Lv ; # Run "/sbin/chkconfig --add shadowsocks" to add the Run levels. #==================================================================== #==================================================================== # Paths and variables and system checks. # Source function library . /etc/rc.d/init.d/functions # Check that networking is up. # [ ${NETWORKING} ="yes" ] || exit 0 # Daemon NAME=shadowsocks-server DAEMON=/usr/bin/ss-server # Path to the configuration file. # CONF=/etc/shadowsocks-libev/config.json #USER="nobody" #GROUP="nobody" # Take care of pidfile permissions mkdir /var/run/$NAME 2>/dev/null || true #chown "$USER:$GROUP" /var/run/$NAME # Check the configuration file exists. # if [ ! -f $CONF ] ; then echo "The configuration file cannot be found!" exit 0 fi # Path to the lock file. # LOCK_FILE=/var/lock/subsys/shadowsocks # Path to the pid file. # PID=/var/run/$NAME/pid #==================================================================== #==================================================================== # Run controls: RETVAL=0 # Start shadowsocks as daemon. # start() { if [ -f $LOCK_FILE ]; then echo "$NAME is already running!" exit 0 else echo -n $"Starting ${NAME}: " #daemon --check $DAEMON --user $USER "$DAEMON -f $PID -c $CONF > /dev/null" daemon $DAEMON -c $CONF -f $PID fi RETVAL=$? [ $RETVAL -eq 0 ] && success echo [ $RETVAL -eq 0 ] && touch $LOCK_FILE return $RETVAL } # Stop shadowsocks. # stop() { echo -n $"Shutting down ${NAME}: " killproc -p ${PID} RETVAL=$? [ $RETVAL -eq 0 ] rm -f $LOCK_FILE rm -f ${PID} echo return $RETVAL } # See how we were called. case "$1" in start) start ;; stop) stop ;; restart) stop start ;; condrestart) if [ -f $LOCK_FILE ]; then stop start RETVAL=$? fi ;; status) status $DAEMON RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|condrestart|status}" RETVAL=1 esac exit $RETVAL ================================================ FILE: rpm/SOURCES/systemd/shadowsocks-libev-local.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This file is default for RPM packaging. See also # /etc/sysconfig/shadowsocks-libev for environment variables. [Unit] Description=Shadowsocks-libev Default Local Service Documentation=man:shadowsocks-libev(8) After=network-online.target [Service] Type=simple EnvironmentFile=/etc/sysconfig/shadowsocks-libev User=nobody Group=nobody LimitNOFILE=32768 ExecStart=/usr/bin/ss-local -c "$CONFFILE" $DAEMON_ARGS CapabilityBoundingSet=CAP_NET_BIND_SERVICE [Install] WantedBy=multi-user.target ================================================ FILE: rpm/SOURCES/systemd/shadowsocks-libev-local@.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This is a template unit file. Users may copy and rename the file into # config directories to make new service instances. See systemd.unit(5) # for details. [Unit] Description=Shadowsocks-Libev Custom Client Service for %I Documentation=man:ss-local(1) After=network-online.target [Service] Type=simple CapabilityBoundingSet=CAP_NET_BIND_SERVICE ExecStart=/usr/bin/ss-local -c /etc/shadowsocks-libev/%i.json User=nobody Group=nobody LimitNOFILE=32768 [Install] WantedBy=multi-user.target ================================================ FILE: rpm/SOURCES/systemd/shadowsocks-libev-redir@.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This is a template unit file. Users may copy and rename the file into # config directories to make new service instances. See systemd.unit(5) # for details. [Unit] Description=Shadowsocks-Libev Custom Client Service Redir Mode for %I Documentation=man:ss-redir(1) After=network-online.target [Service] Type=simple CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE ExecStart=/usr/bin/ss-redir -c /etc/shadowsocks-libev/%i.json User=nobody Group=nobody LimitNOFILE=32768 [Install] WantedBy=multi-user.target ================================================ FILE: rpm/SOURCES/systemd/shadowsocks-libev-server@.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This is a template unit file. Users may copy and rename the file into # config directories to make new service instances. See systemd.unit(5) # for details. [Unit] Description=Shadowsocks-Libev Custom Server Service for %I Documentation=man:ss-server(1) After=network-online.target [Service] Type=simple CapabilityBoundingSet=CAP_NET_BIND_SERVICE ExecStart=/usr/bin/ss-server -c /etc/shadowsocks-libev/%i.json User=nobody Group=nobody LimitNOFILE=32768 [Install] WantedBy=multi-user.target ================================================ FILE: rpm/SOURCES/systemd/shadowsocks-libev-tunnel@.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This is a template unit file. Users may copy and rename the file into # config directories to make new service instances. See systemd.unit(5) # for details. [Unit] Description=Shadowsocks-Libev Custom Client Service Tunnel Mode for %I Documentation=man:ss-tunnel(1) After=network-online.target [Service] Type=simple CapabilityBoundingSet=CAP_NET_BIND_SERVICE ExecStart=/usr/bin/ss-tunnel -c /etc/shadowsocks-libev/%i.json User=nobody Group=nobody LimitNOFILE=32768 [Install] WantedBy=multi-user.target ================================================ FILE: rpm/SOURCES/systemd/shadowsocks-libev.default ================================================ # Defaults for shadowsocks initscript # sourced by /etc/init.d/shadowsocks-libev # installed at /etc/sysconfig/shadowsocks-libev by the maintainer scripts # # This is a POSIX shell fragment # # Note: `START', `GROUP' and `MAXFD' options are not recognized by systemd. # Please change those settings in the corresponding systemd unit file. # Enable during startup? START=yes # Configuration file CONFFILE="/etc/shadowsocks-libev/config.json" # Extra command line arguments DAEMON_ARGS="-u" # User and group to run the server as USER=nobody GROUP=nobody # Number of maximum file descriptors MAXFD=32768 ================================================ FILE: rpm/SOURCES/systemd/shadowsocks-libev.service ================================================ # This file is part of shadowsocks-libev. # # Shadowsocks-libev is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This file is default for RPM packaging. See also # /etc/sysconfig/shadowsocks-libev for environment variables. [Unit] Description=Shadowsocks-libev Default Server Service Documentation=man:shadowsocks-libev(8) After=network-online.target network-online.target [Service] Type=simple EnvironmentFile=/etc/sysconfig/shadowsocks-libev User=nobody Group=nobody LimitNOFILE=32768 ExecStart=/usr/bin/ss-server -c "$CONFFILE" $DAEMON_ARGS CapabilityBoundingSet=CAP_NET_BIND_SERVICE [Install] WantedBy=multi-user.target ================================================ FILE: rpm/SPECS/shadowsocks-libev.spec.in ================================================ %global requires pcre openssl mbedtls libsodium >= 1.0.4 libev c-ares %global conflicts python-shadowsocks python3-shadowsocks %if 0%{?fedora} || 0%{?rhel} %global requires %{?requires} libcap %endif %if 0%{?suse_version} %global requires %{?requires} libcap-progs %endif %global project_desc shadowsocks-libev is a lightweight secured socks5 proxy for embedded devices and low end boxes. %if 0%{?fedora} >= 15 || 0%{?rhel} >=7 || 0%{?suse_version} >= 1210 %global use_systemd 1 %else %global use_systemd 0 %endif # https://fedoraproject.org/wiki/Changes/RemoveLaFiles %global __brp_remove_la_files %nil Name: @NAME@ Version: @VERSION@ Release: @RELEASE@%{?dist} Summary: A lightweight and secure socks5 proxy Group: Applications/Internet License: GPLv3+ URL: https://github.com/shadowsocks/%{name} Source0: @SOURCE@ BuildRequires: make gcc pcre-devel asciidoc xmlto automake libtool mbedtls-devel libsodium-devel >= 1.0.4 libev-devel c-ares-devel %if 0%{?suse_version} BuildRequires: libopenssl-devel %else BuildRequires: openssl-devel %endif AutoReq: no Conflicts: %{?conflicts} Requires: %{?requires} %if 0%{?use_systemd} %{?systemd_requires} %if 0%{?suse_version} BuildRequires: systemd-rpm-macros %else BuildRequires: systemd %endif %endif %description %{?project_desc} %prep %setup -q -n @NAME_VERSION@ %build ./autogen.sh %if 0%{?use_system_lib} %configure --enable-shared --enable-system-shared-lib %else %configure --enable-shared %endif make %{?_smp_mflags} %install make install DESTDIR=%{buildroot} mkdir -p %{buildroot}/etc/shadowsocks-libev %if ! 0%{?use_systemd} mkdir -p %{buildroot}%{_initddir} install -m 755 %{_builddir}/%{buildsubdir}/rpm/SOURCES/etc/init.d/shadowsocks-libev %{buildroot}%{_initddir}/shadowsocks-libev %else mkdir -p %{buildroot}%{_sysconfdir}/sysconfig mkdir -p %{buildroot}%{_unitdir} install -m 644 %{_builddir}/%{buildsubdir}/rpm/SOURCES/systemd/shadowsocks-libev.default %{buildroot}%{_sysconfdir}/sysconfig/shadowsocks-libev install -m 644 %{_builddir}/%{buildsubdir}/rpm/SOURCES/systemd/shadowsocks-libev*.service %{buildroot}%{_unitdir}/ %endif install -m 644 %{_builddir}/%{buildsubdir}/debian/config.json %{buildroot}%{_sysconfdir}/shadowsocks-libev/config.json mkdir -p %{buildroot}%{_datadir}/bash-completion/completions/ install -m 644 %{_builddir}/%{buildsubdir}/completions/bash/* %{buildroot}%{_datadir}/bash-completion/completions/ mkdir -p %{buildroot}%{_datadir}/zsh/site-functions/ install -m 644 %{_builddir}/%{buildsubdir}/completions/zsh/* %{buildroot}%{_datadir}/zsh/site-functions/ %pre %if 0%{?use_systemd} && 0%{?suse_version} %service_add_pre shadowsocks-libev.service %endif %post %if ! 0%{?use_systemd} /sbin/chkconfig --add shadowsocks-libev > /dev/null 2>&1 || : %else %if 0%{?suse_version} %service_add_post shadowsocks-libev.service %else %systemd_post shadowsocks-libev.service %endif %endif setcap cap_net_bind_service+ep %{_bindir}/ss-local \ cap_net_bind_service,cap_net_admin+ep %{_bindir}/ss-redir \ cap_net_bind_service+ep %{_bindir}/ss-server \ cap_net_bind_service+ep %{_bindir}/ss-tunnel %preun %if ! 0%{?use_systemd} if [ $1 -eq 0 ]; then /sbin/service shadowsocks-libev stop > /dev/null 2>&1 || : /sbin/chkconfig --del shadowsocks-libev > /dev/null 2>&1 || : fi %else %if 0%{?suse_version} %service_del_preun shadowsocks-libev.service %service_del_preun shadowsocks-libev-local.service %else %systemd_preun shadowsocks-libev.service %systemd_preun shadowsocks-libev-local.service if [ $1 -eq 0 ] ; then # Package removal, not upgrade systemctl stop shadowsocks-libev-server@'*'.service > /dev/null 2>&1 || : systemctl stop shadowsocks-libev-local@'*'.service > /dev/null 2>&1 || : systemctl stop shadowsocks-libev-tunnel@'*'.service > /dev/null 2>&1 || : systemctl stop shadowsocks-libev-redir@'*'.service > /dev/null 2>&1 || : systemctl --no-reload disable shadowsocks-libev-server@.service > /dev/null 2>&1 || : systemctl --no-reload disable shadowsocks-libev-local@.service > /dev/null 2>&1 || : systemctl --no-reload disable shadowsocks-libev-tunnel@.service > /dev/null 2>&1 || : systemctl --no-reload disable shadowsocks-libev-redir@.service > /dev/null 2>&1 || : fi %endif %endif %postun %if 0%{?use_systemd} %if 0%{?suse_version} %service_del_postun shadowsocks-libev.service %else %systemd_postun_with_restart shadowsocks-libev.service %systemd_postun_with_restart shadowsocks-libev-local.service %systemd_postun_with_restart shadowsocks-libev-server@'*'.service %systemd_postun_with_restart shadowsocks-libev-local@'*'.service %systemd_postun_with_restart shadowsocks-libev-tunnel@'*'.service %systemd_postun_with_restart shadowsocks-libev-redir@'*'.service %endif %endif %files %doc %{_docdir}/shadowsocks-libev/*.html %exclude %{_docdir}/shadowsocks-libev/ss-nat.html %{_bindir}/* %exclude %{_bindir}/ss-nat %config(noreplace) %{_sysconfdir}/shadowsocks-libev/config.json %{_datadir}/bash-completion/completions/* %doc %{_mandir}/man*/* %exclude %{_mandir}/man1/ss-nat.1.* %if ! 0%{?use_systemd} %{_initddir}/shadowsocks-libev %else %{_unitdir}/shadowsocks-libev*.service %config(noreplace) %{_sysconfdir}/sysconfig/shadowsocks-libev %endif %package -n libshadowsocks-libev Summary: %{?summary} (shared library) AutoReq: no Requires: pcre openssl mbedtls libsodium >= 1.0.4 libev c-ares %description -n libshadowsocks-libev Shared library powered by shadowsocks-libev. %{?project_desc} %files -n libshadowsocks-libev %{_libdir}/*.so.* %post -n libshadowsocks-libev /sbin/ldconfig %postun -n libshadowsocks-libev /sbin/ldconfig %package -n libshadowsocks-libev-devel Summary: Development files for shadowsocks-libev Provides: shadowsocks-libev-devel = %{version}-%{release} Requires: libshadowsocks-libev = %{version}-%{release} Obsoletes: shadowsocks-libev-devel < %{version}-%{release} %description -n libshadowsocks-libev-devel Development files for libshadowsocks-libev. %{?project_desc} %files -n libshadowsocks-libev-devel %{_includedir}/* %{_libdir}/pkgconfig/*.pc %{_libdir}/libshadowsocks-libev.la %{_libdir}/libshadowsocks-libev.so %package zsh-completion Summary: This package installs zsh completion files for shadowsocks-libev. Requires: zsh shadowsocks-libev = %{version}-%{release} %description zsh-completion zsh completion files for shadowsocks-libev. %{?project_desc} %files zsh-completion %{_datadir}/zsh/site-functions/* %changelog ================================================ FILE: rpm/genrpm.sh ================================================ #!/usr/bin/env bash set -e NAME=shadowsocks-libev SELF=$(readlink -f -- "$0") HERE=$(dirname -- "$SELF") SOURCES="${HERE}"/SOURCES SPEC_TEMPLATE="${HERE}"/SPECS/${NAME}.spec.in SPEC_FILE="${SPEC_TEMPLATE%%.in}" GIT_VERSION=$("${HERE}"/../scripts/git_version.sh) OPT_OUTDIR="${HERE}/SRPMS" OPT_USE_SYSTEM_LIB=0 OUT_BUILD_RPM=0 version=$(echo ${GIT_VERSION} | cut -d' ' -f1) release=$(echo ${GIT_VERSION} | cut -d' ' -f2) name_version=${NAME}-${version}-${release} source_name=${name_version}.tar.gz archive() { "${HERE}"/../scripts/git_archive.sh -o "${SOURCES}" -n ${name_version} } build_src_rpm() { rpmbuild -bs "${SPEC_FILE}" \ --undefine "dist" \ --define "%_topdir ${HERE}" \ --define "%_srcrpmdir ${OPT_OUTDIR}" } build_rpm() { rpmbuild --rebuild "${OPT_OUTDIR}"/${name_version}.src.rpm \ --define "%_topdir ${HERE}" \ --define "%use_system_lib ${OPT_USE_SYSTEM_LIB}" } create_spec() { sed -e "s/@NAME@/${NAME}/g" \ -e "s/@VERSION@/${version}/g" \ -e "s/@RELEASE@/${release}/g" \ -e "s/@SOURCE@/${source_name}/g" \ -e "s/@NAME_VERSION@/${name_version}/g" \ "${SPEC_TEMPLATE}" > "${SPEC_FILE}" } show_help() { echo -e "$(basename $0) [OPTION...]" echo -e "Create and build shadowsocks-libev SRPM" echo echo -e "Options:" echo -e " -h show this help." echo -e " -b use rpmbuld to build resulting SRPM" echo -e " -s use system shared libraries (RPM only)" echo -e " -o output directory" } while getopts "hbso:" opt do case ${opt} in h) show_help exit 0 ;; b) OPT_BUILD_RPM=1 ;; s) OPT_USE_SYSTEM_LIB=1 ;; o) OPT_OUTDIR=$(readlink -f -- $OPTARG) ;; *) show_help exit 1 ;; esac done create_spec archive build_src_rpm if [ "${OPT_BUILD_RPM}" = "1" ] ; then build_rpm fi ================================================ FILE: scripts/build_deb.sh ================================================ #!/bin/sh # Copyright 2017-2018 Roger Shimizu # # This is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. help_usage() { cat << EOT Build shadowsocks-libev and its dependencies Usage: $(basename $0) [--help|-h] [lib|bin|all] --help|-h Show this usage. kcp Build kcptun package (with its dependencies) only. lib Build library packages only. bin Build binary packages only. However, you need the libraries built previously, in current working directory. For advanced user only. all Build both binary and library packages (default). The safe choice for everyone. Please run this script in a clean place. e.g. mkdir -p ~/build-area cd ~/build-area ln -s $(readlink -f $0) . ./$(basename $0) EOT exit } help_lib() { cat << EOT Failed to install required library: $1 You can try to fix it by: $0 lib EOT exit } apt_init() { DEPS="$1" DEPS_BPO="$2" DEPS_EXTRA="$3" if [ -n "$DEPS_BPO" ]; then BPO=${OSVER}-backports case "$OSID" in debian) REPO=http://deb.debian.org/debian ;; ubuntu) REPO=http://archive.ubuntu.com/ubuntu ;; esac sudo sh -c "printf \"deb $REPO ${OSVER}-backports main\" > /etc/apt/sources.list.d/${OSVER}-backports.list" [ -n "$DEPS_EXTRA" -a "$DEPS_EXTRA" = "sloppy" ] && sudo sh -c "printf \"\\ndeb $REPO ${OSVER}-backports-sloppy main\" >> /etc/apt/sources.list.d/${OSVER}-backports.list" sudo apt-get update sudo apt-get install --no-install-recommends -y -t $BPO $DEPS_BPO [ -n "$DEPS_EXTRA" -a "$DEPS_EXTRA" = "sloppy" ] && sudo apt-get install --no-install-recommends -y -t ${BPO}-sloppy $DEPS_BPO else sudo apt-get update fi sudo apt-get install -y $DEPS } # Cleanup apt_clean() { sudo apt-get purge -y $DEPS $DEPS_BPO debhelper \ libbloom-dev libcork-dev libcorkipset-dev libmbedtls-dev libsodium-dev sudo apt-get purge -y libcork-build-deps libcorkipset-build-deps \ libsodium-build-deps mbedtls-build-deps sudo apt-get purge -y libbloom-build-deps sudo apt-get purge -y simple-obfs-build-deps sudo apt-get purge -y shadowsocks-libev-build-deps if [ $BUILD_KCP -eq 1 ]; then sudo apt-get purge -y golang-github-klauspost-reedsolomon-build-deps \ golang-github-xtaci-kcp-build-deps golang-github-xtaci-smux-build-deps \ kcptun-build-deps sudo apt-get purge -y golang-github-urfave-cli-build-deps sudo apt-get purge -y golang-github-golang-snappy-build-deps \ dh-golang-build-deps golang-github-pkg-errors-build-deps sudo apt-get purge -y golang-github-klauspost-reedsolomon-dev \ golang-github-xtaci-kcp-dev golang-github-xtaci-smux-dev sudo apt-get purge -y golang-github-urfave-cli-dev sudo apt-get purge -y golang-github-pkg-errors-dev \ golang-github-golang-snappy-dev dh-golang fi sudo apt-get autoremove -y } gbp_build() { REPO=$1 BRANCH=$2 PROJECT_NAME=$(basename $1|sed s/\.git$//) gbp clone --pristine-tar $REPO cd $PROJECT_NAME [ -n "$BRANCH" ] && git checkout $BRANCH [ -n "$BRANCH" -a "$BRANCH" = "trusty" ] && # try to rebase the trusty patch if ! git rebase master; then git rebase --abort; git rebase debian; fi [ -n "$DEPS_BPO" ] && BPO_REPO="-t ${OSVER}-backports" mk-build-deps --root-cmd sudo --install --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y $BPO_REPO" rm -f ${PROJECT_NAME}-build-deps_*.deb gbp buildpackage -us -uc --git-ignore-branch --git-pristine-tar git clean -fdx git reset --hard HEAD cd - } git_build() { REPO=$1 BRANCH=$2 PROJECT_NAME=$(basename $1|sed s/\.git$//) git clone $REPO cd $PROJECT_NAME [ -n "$BRANCH" ] && git checkout $BRANCH mk-build-deps --root-cmd sudo --install --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y" rm ${PROJECT_NAME}-build-deps_*.deb gbp buildpackage -us -uc --git-ignore-branch git clean -fdx git reset --hard HEAD cd - } dsc_build() { DSC=$1 DSC_FILE=$(basename $1) dget -ux $DSC PROJECT_NAME=$(grep ^Source: $DSC_FILE|cut -d" " -f2) echo cd ${PROJECT_NAME}-* cd ${PROJECT_NAME}-* mk-build-deps --root-cmd sudo --install --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y" rm ${PROJECT_NAME}-build-deps_*.deb dpkg-buildpackage -us -uc cd - } # Build and install libcork deb build_install_libcork() { if [ $BUILD_LIB -eq 1 -o $BUILD_BIN -eq 1 ]; then BRANCH=$1 if [ $BUILD_LIB -eq 1 ]; then gbp_build https://github.com/rogers0/libcork $BRANCH else ls libcork-dev_*.deb libcork16_*.deb 2>&1 > /dev/null || help_lib "libcork-dev libcork16" fi sudo dpkg -i libcork-dev_*.deb libcork16_*.deb fi } # Build and install libcorkipset deb build_install_libcorkipset() { if [ $BUILD_LIB -eq 1 -o $BUILD_BIN -eq 1 ]; then BRANCH=$1 if [ $BUILD_LIB -eq 1 ]; then gbp_build https://github.com/rogers0/libcorkipset $BRANCH else ls libcorkipset-dev_*.deb libcorkipset1_*.deb 2>&1 > /dev/null || help_lib "libcorkipset-dev libcorkipset1" fi sudo dpkg -i libcorkipset-dev_*.deb libcorkipset1_*.deb fi } # Build libmbedtls deb build_install_libmbedtls() { if [ $BUILD_LIB -eq 1 -o $BUILD_BIN -eq 1 ]; then BRANCH=$1 if [ $BUILD_LIB -eq 1 ]; then gbp_build https://salsa.debian.org/debian/mbedtls.git $BRANCH else ls libmbed*.deb 2>&1 > /dev/null || help_lib libmbedtls fi sudo dpkg -i libmbed*.deb fi } # Build libsodium deb build_install_libsodium() { if [ $BUILD_LIB -eq 1 -o $BUILD_BIN -eq 1 ]; then if [ $BUILD_LIB -eq 1 ]; then git clone https://github.com/gcsideal/debian-libsodium.git libsodium cd libsodium; LIBSODIUM=$(dpkg-parsechangelog --show-field Version); cd - dget -ud https://deb.debian.org/debian/pool/main/libs/libsodium/libsodium_${LIBSODIUM}.dsc DHVER=$(dpkg -l debhelper|grep debhelper|awk '{print $3}'|head -n1) cd libsodium if dpkg --compare-versions $DHVER lt 10; then sed -i 's/debhelper ( >= 11)/debhelper (>= 9), dh-autoreconf/' debian/control; sed -i 's/debhelper ( >= 10)/debhelper (>= 9), dh-autoreconf/' debian/control; echo 9 > debian/compat; dch -D unstable -l~bpo~ "Rebuild as backports" git add -u; git commit -m "Patch to work with ubuntu" elif dpkg --compare-versions $DHVER lt 11; then sed -i 's/debhelper ( >= 11)/debhelper (>= 10)/' debian/control; echo 10 > debian/compat; dch -D unstable -l~bpo~ "Rebuild as backports" git add -u; git commit -m "Patch to work with ubuntu" fi mk-build-deps --root-cmd sudo --install --tool "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y" rm libsodium-build-deps_*.deb gbp buildpackage -us -uc --git-ignore-branch --git-tarball-dir=.. --git-export-dir=.. --git-overlay cd - else ls libsodium*.deb 2>&1 > /dev/null || help_lib libsodium fi sudo dpkg -i libsodium*.deb fi } # Build libbloom deb build_install_libbloom() { if [ $BUILD_LIB -eq 1 -o $BUILD_BIN -eq 1 ]; then BRANCH=$1 if [ $BUILD_LIB -eq 1 ]; then gbp_build https://salsa.debian.org/bridges-team/libbloom.git $BRANCH else ls libbloom-dev_*.deb libbloom1_*.deb 2>&1 > /dev/null || help_lib "libbloom-dev libbloom1" fi sudo dpkg -i libbloom-dev_*.deb libbloom1_*.deb fi } # Add patch to work on system with debhelper 9 only patch_sslibev_dh9() { if [ $BUILD_BIN -eq 1 ]; then BRANCH=$1 gbp clone --pristine-tar https://salsa.debian.org/bridges-team/shadowsocks-libev.git cd shadowsocks-libev [ -n "$BRANCH" ] && git checkout $BRANCH sed -i 's/dh $@/dh $@ --with systemd,autoreconf/' debian/rules sed -i 's/debhelper (>= 10)/debhelper (>= 9), dh-systemd, dh-autoreconf/' debian/control echo 9 > debian/compat dch -D unstable -l~bpo~ "Rebuild as backports" git add -u git commit -m "Patch to work with ubuntu trusty (14.04)" cd - fi } # Build and install shadowsocks-libev deb build_install_sslibev() { if [ $BUILD_BIN -eq 1 ]; then BRANCH=$1 gbp_build https://salsa.debian.org/bridges-team/shadowsocks-libev.git $BRANCH sudo dpkg -i shadowsocks-libev_*.deb sudo apt-get install -fy fi } # Build and install simple-obfs build_install_simpleobfs() { if [ $BUILD_BIN -eq 1 ]; then BRANCH=$1 git_build https://salsa.debian.org/bridges-team/simple-obfs.git $BRANCH sudo dpkg -i simple-obfs_*.deb sudo apt-get install -fy fi } # Build and install dh-golang deb build_install_dhgolang() { if [ $BUILD_KCP -eq 1 ]; then BRANCH=$1 gbp_build https://salsa.debian.org/go-team/packages/dh-golang.git $BRANCH sudo dpkg -i dh-golang_*.deb sudo apt-get install -fy fi } # Build and install golang-github-klauspost-reedsolomon deb build_install_reedsolomondev() { if [ $BUILD_KCP -eq 1 ]; then BRANCH=$1 gbp_build https://salsa.debian.org/go-team/packages/golang-github-klauspost-reedsolomon.git $BRANCH sudo dpkg -i golang-github-klauspost-reedsolomon-dev_*.deb sudo apt-get install -fy fi } # Build and install golang-github-pkg-errors deb build_install_errorsdev() { if [ $BUILD_KCP -eq 1 ]; then BRANCH=$1 gbp_build https://salsa.debian.org/go-team/packages/golang-github-pkg-errors.git $BRANCH sudo dpkg -i golang-github-pkg-errors-dev_*.deb sudo apt-get install -fy fi } # Add patch to work on system with xenial patch_urfaveclidev_xenial() { if [ $BUILD_KCP -eq 1 ]; then BRANCH=$1 gbp clone --pristine-tar https://salsa.debian.org/go-team/packages/golang-github-urfave-cli.git cd golang-github-urfave-cli [ -n "$BRANCH" ] && git checkout $BRANCH sed -i 's/golang-github-burntsushi-toml-dev/golang-toml-dev/; s/golang-gopkg-yaml.v2-dev/golang-yaml.v2-dev/' debian/control dch -D unstable -l~bpo~ "Rebuild as backports" git add -u git commit -m "Patch to work with ubuntu xenial (16.04)" cd - fi } # Build and install golang-github-urfave-cli-dev deb build_install_urfaveclidev() { if [ $BUILD_KCP -eq 1 ]; then BRANCH=$1 gbp_build https://salsa.debian.org/go-team/packages/golang-github-urfave-cli.git $BRANCH sudo dpkg -i build-area/golang-github-urfave-cli-dev_*.deb sudo apt-get install -fy fi } # Build and install golang-github-golang-snappy deb build_install_snappydev() { if [ $BUILD_KCP -eq 1 ]; then BRANCH=$1 gbp_build https://salsa.debian.org/go-team/packages/golang-github-golang-snappy.git $BRANCH sudo dpkg -i golang-github-golang-snappy-dev_*.deb sudo apt-get install -fy fi } # Build and install golang-github-xtaci-kcp deb build_install_kcpdev() { if [ $BUILD_KCP -eq 1 ]; then BRANCH=$1 gbp_build https://salsa.debian.org/go-team/packages/golang-github-xtaci-kcp.git $BRANCH sudo dpkg -i golang-github-xtaci-kcp-dev_*.deb sudo apt-get install -fy fi } # Build and install golang-github-xtaci-smux deb build_install_smuxdev() { if [ $BUILD_KCP -eq 1 ]; then BRANCH=$1 gbp_build https://salsa.debian.org/go-team/packages/golang-github-xtaci-smux.git $BRANCH sudo dpkg -i golang-github-xtaci-smux-dev_*.deb sudo apt-get install -fy fi } # Build and install kcptun deb build_install_kcptun() { if [ $BUILD_KCP -eq 1 ]; then BRANCH=$1 gbp_build https://salsa.debian.org/go-team/packages/kcptun.git $BRANCH sudo dpkg -i kcptun_*.deb sudo apt-get install -fy fi } export XZ_DEFAULTS=--memlimit=128MiB OSID=$(grep ^ID= /etc/os-release|cut -d= -f2) OSVER=$(lsb_release -cs) BUILD_KCP=0 BUILD_LIB=0 BUILD_BIN=0 case "$1" in --help|-h) help_usage ;; kcp) BUILD_KCP=1 ;; lib) BUILD_LIB=1 ;; bin) BUILD_BIN=1 ;; all|"") BUILD_LIB=1 BUILD_BIN=1 ;; *) echo Parameter error, exiting ... exit esac # Exit if in a git repo [ -d .git ] && help_usage case "$OSVER" in jessie) BPO="debhelper libbloom-dev libsodium-dev" BPOEXTRA=sloppy ;; stretch) BPO=libbloom-dev ;; xenial) BPO=debhelper ;; esac apt_init "git-buildpackage pristine-tar equivs" "$BPO" $BPOEXTRA [ $BUILD_KCP -eq 1 ] && case "$OSVER" in wheezy|precise|trusty) echo Sorry, your system $OSID/$OSVER is not supported. ;; jessie) build_install_urfaveclidev build_install_reedsolomondev build_install_kcpdev build_install_smuxdev build_install_kcptun ;; stretch|unstable|sid|yakkety|zesty) build_install_reedsolomondev build_install_kcpdev build_install_smuxdev build_install_kcptun ;; xenial) build_install_dhgolang debian/jessie-backports build_install_reedsolomondev build_install_errorsdev patch_urfaveclidev_xenial build_install_urfaveclidev build_install_snappydev debian/jessie-backports build_install_kcpdev build_install_smuxdev build_install_kcptun ;; esac [ $BUILD_LIB -eq 1 -o $BUILD_BIN -eq 1 ] && case "$OSVER" in wheezy|precise) echo Sorry, your system $OSID/$OSVER is not supported. ;; jessie|stretch|buster|testing|unstable|sid) build_install_sslibev ;; artful|bionic) build_install_libbloom build_install_sslibev build_install_simpleobfs ;; zesty) build_install_libsodium build_install_libbloom build_install_sslibev build_install_simpleobfs ;; xenial|yakkety) build_install_libcork debian build_install_libcorkipset debian build_install_libsodium build_install_libbloom build_install_sslibev build_install_simpleobfs ;; trusty) build_install_libcork trusty build_install_libcorkipset trusty build_install_libmbedtls debian/jessie-backports build_install_libsodium build_install_libbloom trusty patch_sslibev_dh9 build_install_sslibev build_install_simpleobfs trusty ;; *) echo Your system $OSID/$OSVER is not supported yet. echo Please report issue: echo " https://github.com/shadowsocks/shadowsocks-libev/issues/new" ;; esac apt_clean ================================================ FILE: scripts/chroot_build.sh ================================================ #!/bin/sh # Copyright 2018 Roger Shimizu # # This is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. set -e help_usage() { cat << EOT Call build_deb.sh script in a chrooted environment Usage: sudo $(basename $0) [--help|-h] [codename] --help|-h Show this usage. [code name] Debian/Ubuntu release codename e.g. jessie/stretch/trusty/xenial EOT exit } # POSIX-compliant maint function recommend by devref # to check for the existence of a command # https://www.debian.org/doc/manuals/developers-reference/ch06.html#bpp-debian-maint-scripts pathfind() { OLDIFS="$IFS" IFS=: for p in $PATH; do if [ -x "$p/$*" ]; then IFS="$OLDIFS" return 0 fi done IFS="$OLDIFS" return 1 } case "$1" in wheezy|precise) echo Sorry, the system $1 is not supported. ;; jessie|stretch|buster|testing|unstable|sid) OSID=debian REPO=http://deb.debian.org/debian ;; trusty|yakkety|zesty|xenial|artful|bionic) OSID=ubuntu REPO=http://archive.ubuntu.com/ubuntu ;; --help|-h|*) help_usage esac if ! pathfind debootstrap; then echo Please install debootstrap package. exit 1 fi OSVER=$1 CHROOT=/tmp/${OSVER}-build-$(date +%Y%m%d%H%M) TIMESTAMP0=$(date) mkdir -p ${CHROOT}/etc echo en_US.UTF-8 UTF-8 > ${CHROOT}/etc/locale.gen if ! debootstrap --variant=minbase --include=ca-certificates,git,sudo,wget,whiptail --exclude=upstart,systemd $OSVER $CHROOT $REPO; then echo debootstrap failed. Please kindly check whether proper sudo or not. exit 1 fi case "$OSID" in debian) echo deb $REPO ${OSVER} main > ${CHROOT}/etc/apt/sources.list echo deb $REPO ${OSVER}-updates main >> ${CHROOT}/etc/apt/sources.list echo deb $REPO-security ${OSVER}/updates main >> ${CHROOT}/etc/apt/sources.list ;; ubuntu) echo deb $REPO $OSVER main universe > ${CHROOT}/etc/apt/sources.list echo deb $REPO ${OSVER}-updates main universe >> ${CHROOT}/etc/apt/sources.list echo deb $REPO ${OSVER}-security main universe >> ${CHROOT}/etc/apt/sources.list ;; esac cat << EOL | chroot $CHROOT apt-get purge -y udev apt-get update apt-get -fy install apt-get -y upgrade apt-get -y install --no-install-recommends lsb-release # dh_auto_test of mbedtls (faketime) depends on /dev/shm. https://bugs.debian.org/778462 mkdir -p ~ /dev/shm mount tmpfs /dev/shm -t tmpfs date > /TIMESTAMP1 git config --global user.email "script@example.com" git config --global user.name "build script" if [ -n "$http_proxy" ]; then git config --global proxy.http $http_proxy echo Acquire::http::Proxy \"$http_proxy\"\; > /etc/apt/apt.conf export http_proxy=$http_proxy export https_proxy=$https_proxy export no_proxy=$no_proxy fi cd /tmp wget https://raw.githubusercontent.com/shadowsocks/shadowsocks-libev/master/scripts/build_deb.sh chmod 755 build_deb.sh ./build_deb.sh date > /TIMESTAMP2 ./build_deb.sh kcp umount /dev/shm EOL TIMESTAMP1=$(cat ${CHROOT}/TIMESTAMP1) TIMESTAMP2=$(cat ${CHROOT}/TIMESTAMP2) TIMESTAMP3=$(date) printf \\n"All built deb packages:"\\n ls -l ${CHROOT}/tmp/*.deb echo echo Start-Time: $TIMESTAMP0 echo ChrootDone: $TIMESTAMP1 echo SsDeb-Done: $TIMESTAMP2 echo \ Kcp-Done : $TIMESTAMP3 ================================================ FILE: scripts/code-format.bat ================================================ @echo off set root=%~dp0 set source=%root%src goto start :format set filelist=%1 for /r "%filelist%" %%f in (*) do ( if "%%~xf" equ ".h" ( call :format_file %%f ) else if "%%~xf" equ ".c" ( call :format_file %%f ) ) goto end :format_file set f=%1 if "%~n1" neq "base64" ( if "%~n1" neq "json" ( if "%~n1" neq "uthash" ( echo 'format file "%f%"' uncrustify -c %root%\.uncrustify.cfg -l C --replace --no-backup %f% DEL %~dp1*.uncrustify >nul 2>nul ) ) ) goto end :start call :format %source% :end ================================================ FILE: scripts/code-format.sh ================================================ #!/usr/bin/env bash root=$(pwd) source="$root"/src function format() { filelist=$(ls "$1") pushd "$1" for file in $filelist; do if test -d "$file"; then echo "format directory $file" format "$file" else if ([ "${file%%.*}" != "base64" ] && [ "${file%%.*}" != "json" ] && [ "${file%%.*}" != "uthash" ]) && ([ "${file##*.}" = "h" ] || [ "${file##*.}" = "c" ]); then echo "format file $file" uncrustify -c "$root"/.uncrustify.cfg -l C --replace --no-backup "$file" rm ./*.uncrustify >/dev/null 2>&1 fi fi done popd } format "$source" ================================================ FILE: scripts/git_archive.sh ================================================ #!/usr/bin/env bash set -e archive() { export TARBALL_NAME=$1 export TARBALL_OUTDIR=$2 # archive this repo cd "$(git rev-parse --show-toplevel)" git archive HEAD --format=tar --prefix="${TARBALL_NAME}/" \ -o "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" # archive submodules git submodule update --init git submodule foreach --quiet 'git archive HEAD --format=tar \ --prefix="${TARBALL_NAME}/${path}/" \ -o "${TARBALL_OUTDIR}/${TARBALL_NAME}-submodule-${path}-${sha1}.tar" tar -n --concatenate --file="${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" \ "${TARBALL_OUTDIR}/${TARBALL_NAME}-submodule-${path}-${sha1}.tar"' gzip -c "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" > "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar.gz" # clean-up git submodule foreach --quiet 'rm ${TARBALL_OUTDIR}/${TARBALL_NAME}-submodule-${path}-${sha1}.tar' rm "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" } TARGET_TARBALL_NAME=shadowsocks-libev TARGET_TARBALL_DIR=$(git rev-parse --show-toplevel) while getopts "n:o:" opt do case ${opt} in o) TARGET_TARBALL_DIR=$(readlink -f -- $OPTARG) ;; n) TARGET_TARBALL_NAME=$OPTARG ;; \?) exit 1 ;; esac done archive "${TARGET_TARBALL_NAME}" "${TARGET_TARBALL_DIR}" ================================================ FILE: scripts/git_version.sh ================================================ #!/usr/bin/env bash set -e # determine version and release number GIT_DESCRIBE=$(git describe --tags --match 'v*' --long) # GIT_DESCRIBE is like v3.0.3-11-g1e3f35c-dirty if [[ ! "$GIT_DESCRIBE" =~ ^v([^-]+)-([0-9]+)-g([0-9a-f]+)$ ]]; then >&2 echo 'ERROR - unrecognized `git describe` output: '"$GIT_DESCRIBE" exit 1 fi version=${BASH_REMATCH[1]} commits=${BASH_REMATCH[2]} short_hash=${BASH_REMATCH[3]} release=1 if [ "${commits}" -gt 0 ] ; then release+=.${commits}.git${short_hash} fi echo "${version} ${release}" ================================================ FILE: scripts/iperf.sh ================================================ #!/bin/bash number=$1 method=$2 ss-tunnel -k test -m $method -l 8387 -L 127.0.0.1:8388 -s 127.0.0.1 -p 8389 & ss_tunnel_pid=$! ss-server -k test -m $method -s 127.0.0.1 -p 8389 & ss_server_pid=$! iperf -s -p 8388 & iperf_pid=$! sleep 1 iperf -c 127.0.0.1 -p 8387 -n $number # Wait for iperf server to receive all data. # One second should be enough in most cases. sleep 1 kill $ss_tunnel_pid kill $ss_server_pid kill $iperf_pid sleep 1 echo "Test Finished" ================================================ FILE: scripts/ss-setup.sh ================================================ #!/usr/bin/env bash set -euo pipefail ############################################################################### # ss-setup -- Interactive TUI for shadowsocks-libev server/client setup # # Requires: whiptail or dialog, openssl (optional), curl (for plugin install) # Usage: sudo ss-setup (full server setup + service management) # ss-setup (config generation only, no service install) ############################################################################### readonly SS_SETUP_VERSION="1.0.0" readonly CONFIG_DIR="/etc/shadowsocks-libev" readonly SYSTEMD_UNIT_DIR="/etc/systemd/system" readonly SYSTEMD_TEMPLATE="shadowsocks-libev-server@.service" # AEAD ciphers supported by shadowsocks-libev (from src/aead.c) readonly AEAD_CIPHERS=( "chacha20-ietf-poly1305" "aes-256-gcm" "aes-192-gcm" "aes-128-gcm" "xchacha20-ietf-poly1305" ) # Known SIP003 plugins and their GitHub repos # Using a function instead of associative array for bash 3.x compatibility plugin_repo() { case "$1" in simple-obfs) echo "shadowsocks/simple-obfs" ;; v2ray-plugin) echo "shadowsocks/v2ray-plugin" ;; xray-plugin) echo "teddysun/xray-plugin" ;; kcptun) echo "xtaci/kcptun" ;; *) echo "" ;; esac } readonly KNOWN_PLUGINS=("simple-obfs" "v2ray-plugin" "xray-plugin" "kcptun") # Globals set by the setup flows TUI_BACKEND="" TMPDIR_CLEANUP="" # Server config globals CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="8388" CFG_METHOD="chacha20-ietf-poly1305" CFG_PASSWORD="" CFG_TIMEOUT="300" CFG_MODE="tcp_and_udp" CFG_FAST_OPEN="false" CFG_PLUGIN="" CFG_PLUGIN_OPTS="" CFG_INSTANCE_NAME="config" # Client config globals CFG_CLIENT_SERVER="" CFG_CLIENT_SERVER_PORT="8388" CFG_CLIENT_LOCAL_PORT="1080" CFG_CLIENT_METHOD="chacha20-ietf-poly1305" CFG_CLIENT_PASSWORD="" CFG_CLIENT_PLUGIN="" CFG_CLIENT_PLUGIN_OPTS="" CFG_CLIENT_OUTPUT="" ############################################################################### # Cleanup ############################################################################### cleanup() { if [[ -n "${TMPDIR_CLEANUP}" && -d "${TMPDIR_CLEANUP}" ]]; then rm -rf "${TMPDIR_CLEANUP}" fi } # Only set trap when executed directly (not when sourced for testing) if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then trap cleanup EXIT fi ############################################################################### # TUI Backend Detection & Wrappers ############################################################################### detect_tui_backend() { if command -v whiptail >/dev/null 2>&1; then TUI_BACKEND="whiptail" elif command -v dialog >/dev/null 2>&1; then TUI_BACKEND="dialog" else echo "Error: neither whiptail nor dialog found." >&2 echo "Install one of them:" >&2 echo " Debian/Ubuntu: sudo apt install whiptail" >&2 echo " RHEL/Fedora: sudo dnf install newt" >&2 echo " Arch: sudo pacman -S libnewt" >&2 exit 1 fi } # tui_msgbox title message tui_msgbox() { local title="$1" msg="$2" $TUI_BACKEND --title "$title" --msgbox "$msg" 20 70 } # tui_yesno title message → exit code 0=yes 1=no tui_yesno() { local title="$1" msg="$2" if $TUI_BACKEND --title "$title" --yesno "$msg" 12 70; then return 0 else return 1 fi } # tui_inputbox title message default → prints value tui_inputbox() { local title="$1" msg="$2" default="${3:-}" local result result=$($TUI_BACKEND --title "$title" --inputbox "$msg" 10 70 "$default" 3>&1 1>&2 2>&3) || return $? echo "$result" } # tui_passwordbox title message → prints value tui_passwordbox() { local title="$1" msg="$2" local result result=$($TUI_BACKEND --title "$title" --passwordbox "$msg" 10 70 3>&1 1>&2 2>&3) || return $? echo "$result" } # tui_menu title message tag1 item1 tag2 item2 ... → prints selected tag tui_menu() { local title="$1" msg="$2" shift 2 local items=("$@") local count=$(( ${#items[@]} / 2 )) local result result=$($TUI_BACKEND --title "$title" --menu "$msg" 20 70 "$count" "${items[@]}" 3>&1 1>&2 2>&3) || return $? echo "$result" } # tui_radiolist title message tag1 item1 status1 ... → prints selected tag tui_radiolist() { local title="$1" msg="$2" shift 2 local items=("$@") local count=$(( ${#items[@]} / 3 )) local result result=$($TUI_BACKEND --title "$title" --radiolist "$msg" 20 70 "$count" "${items[@]}" 3>&1 1>&2 2>&3) || return $? echo "$result" } ############################################################################### # Utility Functions ############################################################################### check_root() { if [[ $EUID -ne 0 ]]; then tui_msgbox "Notice" "Not running as root.\n\nYou can still generate config files, but service installation and plugin management will be skipped.\n\nRe-run with sudo for full functionality." return 1 fi return 0 } is_root() { [[ $EUID -eq 0 ]] } validate_port() { local port="$1" if [[ "$port" =~ ^[0-9]+$ ]] && (( port >= 1 && port <= 65535 )); then return 0 fi return 1 } validate_instance_name() { local name="$1" if [[ "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then return 0 fi return 1 } generate_password() { local len="${1:-32}" if command -v openssl >/dev/null 2>&1; then openssl rand -base64 "$len" | tr -d '\n' else head -c "$len" /dev/urandom | base64 | tr -d '\n' fi } generate_random_port() { local port if [[ -r /dev/urandom ]]; then port=$(( ($(od -An -tu2 -N2 /dev/urandom | tr -d ' ') % 55001) + 10000 )) else port=$(( (RANDOM % 55001) + 10000 )) fi echo "$port" } json_escape() { local str="$1" str="${str//\\/\\\\}" str="${str//\"/\\\"}" str="${str//$'\n'/\\n}" str="${str//$'\r'/\\r}" str="${str//$'\t'/\\t}" echo -n "$str" } urlencode() { local str="$1" local encoded="" local i c for (( i = 0; i < ${#str}; i++ )); do c="${str:$i:1}" case "$c" in [a-zA-Z0-9.~_-]) encoded+="$c" ;; *) encoded+=$(printf '%%%02X' "'$c") ;; esac done echo -n "$encoded" } # Generate SIP002 ss:// URI # ss://BASE64URL(method:password)@host:port[/?plugin=URLENCODE(plugin;opts)] generate_ss_uri() { local method="$1" password="$2" server="$3" port="$4" local plugin="${5:-}" plugin_opts="${6:-}" local userinfo userinfo=$(echo -n "${method}:${password}" | base64 | tr -d '\n' | tr '+/' '-_' | tr -d '=') local uri="ss://${userinfo}@${server}:${port}" if [[ -n "$plugin" ]]; then local plugin_str="$plugin" if [[ -n "$plugin_opts" ]]; then plugin_str="${plugin};${plugin_opts}" fi uri="${uri}/?plugin=$(urlencode "$plugin_str")" fi echo "$uri" } # Write JSON config from CFG_* globals (server mode) # Produces valid JSON with no trailing commas; booleans unquoted write_json_config() { local outfile="$1" local fast_open_val="false" [[ "$CFG_FAST_OPEN" == "true" ]] && fast_open_val="true" { printf '{\n' printf ' "server": "%s",\n' "$(json_escape "$CFG_SERVER")" printf ' "server_port": %s,\n' "$CFG_SERVER_PORT" printf ' "password": "%s",\n' "$(json_escape "$CFG_PASSWORD")" printf ' "timeout": %s,\n' "$CFG_TIMEOUT" printf ' "method": "%s",\n' "$(json_escape "$CFG_METHOD")" printf ' "mode": "%s",\n' "$(json_escape "$CFG_MODE")" if [[ -n "$CFG_PLUGIN" ]]; then printf ' "fast_open": %s,\n' "$fast_open_val" printf ' "plugin": "%s"' "$(json_escape "$CFG_PLUGIN")" if [[ -n "$CFG_PLUGIN_OPTS" ]]; then printf ',\n' printf ' "plugin_opts": "%s"' "$(json_escape "$CFG_PLUGIN_OPTS")" fi else printf ' "fast_open": %s' "$fast_open_val" fi printf '\n}\n' } > "$outfile" } # Write JSON config for client mode write_client_json_config() { local outfile="$1" { printf '{\n' printf ' "server": "%s",\n' "$(json_escape "$CFG_CLIENT_SERVER")" printf ' "server_port": %s,\n' "$CFG_CLIENT_SERVER_PORT" printf ' "local_address": "127.0.0.1",\n' printf ' "local_port": %s,\n' "$CFG_CLIENT_LOCAL_PORT" printf ' "password": "%s",\n' "$(json_escape "$CFG_CLIENT_PASSWORD")" printf ' "timeout": 300,\n' printf ' "method": "%s",\n' "$(json_escape "$CFG_CLIENT_METHOD")" if [[ -n "$CFG_CLIENT_PLUGIN" ]]; then printf ' "mode": "tcp_and_udp",\n' printf ' "plugin": "%s"' "$(json_escape "$CFG_CLIENT_PLUGIN")" if [[ -n "$CFG_CLIENT_PLUGIN_OPTS" ]]; then printf ',\n' printf ' "plugin_opts": "%s"' "$(json_escape "$CFG_CLIENT_PLUGIN_OPTS")" fi else printf ' "mode": "tcp_and_udp"' fi printf '\n}\n' } > "$outfile" } # Parse an existing config file and populate CFG_* globals parse_existing_config() { local file="$1" local val val=$(grep -o '"server"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | head -1 | sed 's/.*:.*"\(.*\)"/\1/') && [[ -n "$val" ]] && CFG_SERVER="$val" val=$(grep -o '"server_port"[[:space:]]*:[[:space:]]*[0-9]*' "$file" | head -1 | sed 's/.*:[[:space:]]*//') && [[ -n "$val" ]] && CFG_SERVER_PORT="$val" val=$(grep -o '"password"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | head -1 | sed 's/.*:.*"\(.*\)"/\1/') && [[ -n "$val" ]] && CFG_PASSWORD="$val" val=$(grep -o '"method"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | head -1 | sed 's/.*:.*"\(.*\)"/\1/') && [[ -n "$val" ]] && CFG_METHOD="$val" val=$(grep -o '"timeout"[[:space:]]*:[[:space:]]*[0-9]*' "$file" | head -1 | sed 's/.*:[[:space:]]*//') && [[ -n "$val" ]] && CFG_TIMEOUT="$val" val=$(grep -o '"mode"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | head -1 | sed 's/.*:.*"\(.*\)"/\1/') && [[ -n "$val" ]] && CFG_MODE="$val" val=$(grep -o '"fast_open"[[:space:]]*:[[:space:]]*[a-z]*' "$file" | head -1 | sed 's/.*:[[:space:]]*//') && [[ -n "$val" ]] && CFG_FAST_OPEN="$val" val=$(grep -o '"plugin"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | head -1 | sed 's/.*:.*"\(.*\)"/\1/') && [[ -n "$val" ]] && CFG_PLUGIN="$val" val=$(grep -o '"plugin_opts"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | head -1 | sed 's/.*:.*"\(.*\)"/\1/') && [[ -n "$val" ]] && CFG_PLUGIN_OPTS="$val" return 0 } detect_arch() { local arch arch=$(uname -m) case "$arch" in x86_64|amd64) echo "amd64" ;; aarch64|arm64) echo "arm64" ;; armv7*|armhf) echo "armv7" ;; i686|i386) echo "386" ;; *) echo "$arch" ;; esac } detect_os() { local os os=$(uname -s | tr '[:upper:]' '[:lower:]') case "$os" in linux*) echo "linux" ;; darwin*) echo "darwin" ;; *) echo "$os" ;; esac } detect_distro() { if [[ -f /etc/os-release ]]; then # shellcheck disable=SC1091 . /etc/os-release echo "${ID:-unknown}" elif command -v lsb_release >/dev/null 2>&1; then lsb_release -si | tr '[:upper:]' '[:lower:]' else echo "unknown" fi } has_systemd() { command -v systemctl >/dev/null 2>&1 && [[ -d /run/systemd/system ]] } systemd_version() { local ver ver=$(systemctl --version 2>/dev/null | head -1 | grep -oE '[0-9]+' | head -1) || ver="0" echo "$ver" } check_port_in_use() { local port="$1" if command -v ss >/dev/null 2>&1; then ss -tlnp 2>/dev/null | grep -q ":${port} " && return 0 elif command -v netstat >/dev/null 2>&1; then netstat -tlnp 2>/dev/null | grep -q ":${port} " && return 0 fi return 1 } find_installed_plugins() { local plugins=() local p for p in "${KNOWN_PLUGINS[@]}"; do if command -v "$p" >/dev/null 2>&1; then plugins+=("$p") fi done # Also check obfs-local (simple-obfs installs as obfs-local/obfs-server) if command -v obfs-local >/dev/null 2>&1; then local found=0 for p in "${plugins[@]}"; do [[ "$p" == "simple-obfs" ]] && found=1 done [[ $found -eq 0 ]] && plugins+=("obfs-local") fi echo "${plugins[*]}" } ############################################################################### # Server Setup Flow ############################################################################### server_ask_listen_address() { local addr while true; do addr=$(tui_inputbox "Listen Address" "Enter the server listen address:" "$CFG_SERVER") || return 1 if [[ -n "$addr" ]]; then CFG_SERVER="$addr" return 0 fi tui_msgbox "Error" "Address cannot be empty." done } server_ask_port() { local choice choice=$(tui_menu "Server Port" "Choose how to set the server port:" \ "manual" "Enter port manually (default: ${CFG_SERVER_PORT})" \ "random" "Generate a random high port") || return 1 if [[ "$choice" == "random" ]]; then CFG_SERVER_PORT=$(generate_random_port) tui_msgbox "Random Port" "Selected port: ${CFG_SERVER_PORT}" return 0 fi local port while true; do port=$(tui_inputbox "Server Port" "Enter the server port (1-65535):" "$CFG_SERVER_PORT") || return 1 if validate_port "$port"; then if check_port_in_use "$port"; then if ! tui_yesno "Port In Use" "Port ${port} appears to be in use.\n\nContinue anyway?"; then continue fi fi CFG_SERVER_PORT="$port" return 0 fi tui_msgbox "Error" "Invalid port number. Must be 1-65535." done } server_ask_method() { local items=() local cipher for cipher in "${AEAD_CIPHERS[@]}"; do if [[ "$cipher" == "$CFG_METHOD" ]]; then items+=("$cipher" "" "ON") else items+=("$cipher" "" "OFF") fi done local method method=$(tui_radiolist "Encryption Method" "Select the AEAD cipher to use:" "${items[@]}") || return 1 CFG_METHOD="$method" } server_ask_password() { if tui_yesno "Password" "Auto-generate a secure random password?\n\n(Select No to enter manually)"; then CFG_PASSWORD=$(generate_password 32) tui_msgbox "Generated Password" "Password (save this!):\n\n${CFG_PASSWORD}" return 0 fi local pass1 pass2 while true; do pass1=$(tui_passwordbox "Password" "Enter the password:") || return 1 if [[ -z "$pass1" ]]; then tui_msgbox "Error" "Password cannot be empty." continue fi pass2=$(tui_passwordbox "Confirm Password" "Confirm the password:") || return 1 if [[ "$pass1" == "$pass2" ]]; then CFG_PASSWORD="$pass1" return 0 fi tui_msgbox "Error" "Passwords do not match. Try again." done } server_ask_timeout() { local timeout while true; do timeout=$(tui_inputbox "Timeout" "Connection timeout in seconds:" "$CFG_TIMEOUT") || return 1 if [[ "$timeout" =~ ^[0-9]+$ ]] && (( timeout > 0 )); then CFG_TIMEOUT="$timeout" return 0 fi tui_msgbox "Error" "Timeout must be a positive integer." done } server_ask_mode() { local items=() local modes=("tcp_only" "tcp_and_udp" "udp_only") local m for m in "${modes[@]}"; do if [[ "$m" == "$CFG_MODE" ]]; then items+=("$m" "" "ON") else items+=("$m" "" "OFF") fi done local mode mode=$(tui_radiolist "Network Mode" "Select the network mode:" "${items[@]}") || return 1 CFG_MODE="$mode" } server_ask_fast_open() { # Check if TCP Fast Open is available (Linux only) if [[ -f /proc/sys/net/ipv4/tcp_fastopen ]]; then local tfo_val tfo_val=$(cat /proc/sys/net/ipv4/tcp_fastopen 2>/dev/null) || tfo_val="0" if (( tfo_val >= 2 )); then CFG_FAST_OPEN="true" fi if tui_yesno "TCP Fast Open" "Enable TCP Fast Open?\n\n(Current kernel setting: ${tfo_val})\nRequires kernel support and sysctl net.ipv4.tcp_fastopen >= 2 for server."; then CFG_FAST_OPEN="true" else CFG_FAST_OPEN="false" fi else CFG_FAST_OPEN="false" tui_msgbox "TCP Fast Open" "TCP Fast Open is not available on this system.\nSetting to disabled." fi } server_ask_plugin() { local installed installed=$(find_installed_plugins) local items=("none" "No plugin") local p for p in $installed; do items+=("$p" "$(command -v "$p" 2>/dev/null || echo "$p")") done items+=("custom" "Enter custom plugin path") local choice choice=$(tui_menu "SIP003 Plugin" "Select a plugin (optional):" "${items[@]}") || return 1 if [[ "$choice" == "none" ]]; then CFG_PLUGIN="" CFG_PLUGIN_OPTS="" return 0 fi if [[ "$choice" == "custom" ]]; then local plugin_path plugin_path=$(tui_inputbox "Custom Plugin" "Enter the plugin binary name or full path:" "") || return 1 if [[ -z "$plugin_path" ]]; then CFG_PLUGIN="" CFG_PLUGIN_OPTS="" return 0 fi CFG_PLUGIN="$plugin_path" else CFG_PLUGIN="$choice" fi local opts opts=$(tui_inputbox "Plugin Options" "Enter plugin options (or leave empty):" "$CFG_PLUGIN_OPTS") || return 1 CFG_PLUGIN_OPTS="$opts" } server_ask_instance_name() { local name while true; do name=$(tui_inputbox "Instance Name" "Enter a name for this config instance.\nThe config will be saved as ${CONFIG_DIR}/.json" "$CFG_INSTANCE_NAME") || return 1 if ! validate_instance_name "$name"; then tui_msgbox "Error" "Invalid name. Use only letters, numbers, hyphens, and underscores." continue fi if [[ -f "${CONFIG_DIR}/${name}.json" ]]; then local action action=$(tui_menu "Config Exists" "Config '${name}.json' already exists:" \ "overwrite" "Overwrite the existing config" \ "edit" "Load and edit the existing config" \ "rename" "Choose a different name") || return 1 case "$action" in overwrite) CFG_INSTANCE_NAME="$name" return 0 ;; edit) parse_existing_config "${CONFIG_DIR}/${name}.json" CFG_INSTANCE_NAME="$name" return 2 # signal to restart setup with loaded values ;; rename) continue ;; esac else CFG_INSTANCE_NAME="$name" return 0 fi done } server_generate_config() { local config_file="${CONFIG_DIR}/${CFG_INSTANCE_NAME}.json" if is_root; then mkdir -p "$CONFIG_DIR" write_json_config "$config_file" chmod 640 "$config_file" else # Non-root: write to current directory config_file="${CFG_INSTANCE_NAME}.json" write_json_config "$config_file" fi echo "$config_file" } server_install_systemd_template() { if ! has_systemd; then return 1 fi local template_path="${SYSTEMD_UNIT_DIR}/${SYSTEMD_TEMPLATE}" # Only install if missing if [[ -f "$template_path" ]]; then return 0 fi local ss_server_path ss_server_path=$(command -v ss-server 2>/dev/null) || ss_server_path="/usr/local/bin/ss-server" local sd_ver sd_ver=$(systemd_version) if (( sd_ver >= 232 )); then cat > "$template_path" < "$template_path" </dev/null systemctl restart "$unit" 2>/dev/null if systemctl is-active --quiet "$unit"; then return 0 else return 1 fi } server_show_summary() { local config_file="$1" local uri uri=$(generate_ss_uri "$CFG_METHOD" "$CFG_PASSWORD" "$CFG_SERVER" "$CFG_SERVER_PORT" "$CFG_PLUGIN" "$CFG_PLUGIN_OPTS") local service_status="(not installed)" if is_root && has_systemd; then local unit="shadowsocks-libev-server@${CFG_INSTANCE_NAME}.service" if systemctl is-active --quiet "$unit" 2>/dev/null; then service_status="active (running)" else service_status="inactive or failed" fi fi local summary="" summary+="Config file: ${config_file}\n" summary+="\n" summary+="Server: ${CFG_SERVER}:${CFG_SERVER_PORT}\n" summary+="Method: ${CFG_METHOD}\n" summary+="Password: ${CFG_PASSWORD}\n" summary+="Mode: ${CFG_MODE}\n" summary+="Fast Open: ${CFG_FAST_OPEN}\n" if [[ -n "$CFG_PLUGIN" ]]; then summary+="Plugin: ${CFG_PLUGIN}\n" [[ -n "$CFG_PLUGIN_OPTS" ]] && summary+="Opts: ${CFG_PLUGIN_OPTS}\n" fi summary+="Service: ${service_status}\n" summary+="\n" summary+="ss:// URI (for client import):\n" summary+="${uri}\n" tui_msgbox "Server Setup Complete" "$summary" } server_setup() { while true; do server_ask_instance_name local rc=$? if [[ $rc -eq 1 ]]; then return # user cancelled fi # rc=2 means config was loaded for editing, restart the flow # rc=0 means proceed server_ask_listen_address || return server_ask_port || return server_ask_method || return server_ask_password || return server_ask_timeout || return server_ask_mode || return server_ask_fast_open server_ask_plugin || return # Confirm before writing local confirm_msg="" confirm_msg+="Server: ${CFG_SERVER}:${CFG_SERVER_PORT}\n" confirm_msg+="Method: ${CFG_METHOD}\n" confirm_msg+="Mode: ${CFG_MODE}\n" confirm_msg+="Fast Open: ${CFG_FAST_OPEN}\n" confirm_msg+="Instance: ${CFG_INSTANCE_NAME}\n" [[ -n "$CFG_PLUGIN" ]] && confirm_msg+="Plugin: ${CFG_PLUGIN}\n" if ! tui_yesno "Confirm" "Review your settings:\n\n${confirm_msg}\nProceed?"; then if tui_yesno "Restart" "Start over with new settings?"; then continue fi return fi break done # Generate config local config_file config_file=$(server_generate_config) # Install systemd service if root if is_root && has_systemd; then if tui_yesno "Systemd Service" "Install and start a systemd service for this instance?"; then if server_install_service "$CFG_INSTANCE_NAME"; then tui_msgbox "Service Started" "Service shadowsocks-libev-server@${CFG_INSTANCE_NAME} is now running." else tui_msgbox "Service Error" "Service failed to start.\n\nCheck: journalctl -u shadowsocks-libev-server@${CFG_INSTANCE_NAME} -n 20" fi fi fi # Show summary server_show_summary "$config_file" } ############################################################################### # Client Config Flow ############################################################################### client_ask_server_address() { local addr while true; do addr=$(tui_inputbox "Server Address" "Enter the remote ss-server address (IP or hostname):" "$CFG_CLIENT_SERVER") || return 1 if [[ -n "$addr" ]]; then CFG_CLIENT_SERVER="$addr" return 0 fi tui_msgbox "Error" "Server address cannot be empty." done } client_ask_server_port() { local port while true; do port=$(tui_inputbox "Server Port" "Enter the remote ss-server port:" "$CFG_CLIENT_SERVER_PORT") || return 1 if validate_port "$port"; then CFG_CLIENT_SERVER_PORT="$port" return 0 fi tui_msgbox "Error" "Invalid port number. Must be 1-65535." done } client_ask_local_port() { local port while true; do port=$(tui_inputbox "Local Port" "Enter the local SOCKS5 listen port:" "$CFG_CLIENT_LOCAL_PORT") || return 1 if validate_port "$port"; then CFG_CLIENT_LOCAL_PORT="$port" return 0 fi tui_msgbox "Error" "Invalid port number. Must be 1-65535." done } client_ask_method() { local items=() local cipher for cipher in "${AEAD_CIPHERS[@]}"; do if [[ "$cipher" == "$CFG_CLIENT_METHOD" ]]; then items+=("$cipher" "" "ON") else items+=("$cipher" "" "OFF") fi done local method method=$(tui_radiolist "Encryption Method" "Select the cipher (must match server):" "${items[@]}") || return 1 CFG_CLIENT_METHOD="$method" } client_ask_password() { local pass while true; do pass=$(tui_passwordbox "Password" "Enter the password (must match server):") || return 1 if [[ -n "$pass" ]]; then CFG_CLIENT_PASSWORD="$pass" return 0 fi tui_msgbox "Error" "Password cannot be empty." done } client_ask_plugin() { local installed installed=$(find_installed_plugins) local items=("none" "No plugin") local p for p in $installed; do items+=("$p" "$(command -v "$p" 2>/dev/null || echo "$p")") done items+=("custom" "Enter custom plugin path") local choice choice=$(tui_menu "SIP003 Plugin" "Select a plugin (must match server):" "${items[@]}") || return 1 if [[ "$choice" == "none" ]]; then CFG_CLIENT_PLUGIN="" CFG_CLIENT_PLUGIN_OPTS="" return 0 fi if [[ "$choice" == "custom" ]]; then local plugin_path plugin_path=$(tui_inputbox "Custom Plugin" "Enter the plugin binary name or full path:" "") || return 1 if [[ -z "$plugin_path" ]]; then CFG_CLIENT_PLUGIN="" CFG_CLIENT_PLUGIN_OPTS="" return 0 fi CFG_CLIENT_PLUGIN="$plugin_path" else CFG_CLIENT_PLUGIN="$choice" fi local opts opts=$(tui_inputbox "Plugin Options" "Enter plugin options (or leave empty):" "$CFG_CLIENT_PLUGIN_OPTS") || return 1 CFG_CLIENT_PLUGIN_OPTS="$opts" } client_ask_output_path() { local default_path if is_root; then default_path="${CONFIG_DIR}/client.json" else default_path="${HOME}/ss-client.json" fi [[ -n "$CFG_CLIENT_OUTPUT" ]] && default_path="$CFG_CLIENT_OUTPUT" local path path=$(tui_inputbox "Output Path" "Where to save the client config:" "$default_path") || return 1 CFG_CLIENT_OUTPUT="$path" } client_generate_config() { local outdir outdir=$(dirname "$CFG_CLIENT_OUTPUT") if [[ ! -d "$outdir" ]]; then mkdir -p "$outdir" 2>/dev/null || { tui_msgbox "Error" "Cannot create directory: ${outdir}" return 1 } fi write_client_json_config "$CFG_CLIENT_OUTPUT" chmod 640 "$CFG_CLIENT_OUTPUT" 2>/dev/null || true } client_show_summary() { local uri uri=$(generate_ss_uri "$CFG_CLIENT_METHOD" "$CFG_CLIENT_PASSWORD" "$CFG_CLIENT_SERVER" "$CFG_CLIENT_SERVER_PORT" "$CFG_CLIENT_PLUGIN" "$CFG_CLIENT_PLUGIN_OPTS") local summary="" summary+="Config file: ${CFG_CLIENT_OUTPUT}\n" summary+="\n" summary+="Server: ${CFG_CLIENT_SERVER}:${CFG_CLIENT_SERVER_PORT}\n" summary+="Local: 127.0.0.1:${CFG_CLIENT_LOCAL_PORT}\n" summary+="Method: ${CFG_CLIENT_METHOD}\n" if [[ -n "$CFG_CLIENT_PLUGIN" ]]; then summary+="Plugin: ${CFG_CLIENT_PLUGIN}\n" [[ -n "$CFG_CLIENT_PLUGIN_OPTS" ]] && summary+="Opts: ${CFG_CLIENT_PLUGIN_OPTS}\n" fi summary+="\n" summary+="ss:// URI:\n${uri}\n" summary+="\n" summary+="Usage:\n ss-local -c ${CFG_CLIENT_OUTPUT}\n" tui_msgbox "Client Config Complete" "$summary" } client_setup() { client_ask_server_address || return client_ask_server_port || return client_ask_local_port || return client_ask_method || return client_ask_password || return client_ask_plugin || return client_ask_output_path || return # Confirm local confirm_msg="" confirm_msg+="Server: ${CFG_CLIENT_SERVER}:${CFG_CLIENT_SERVER_PORT}\n" confirm_msg+="Local: 127.0.0.1:${CFG_CLIENT_LOCAL_PORT}\n" confirm_msg+="Method: ${CFG_CLIENT_METHOD}\n" confirm_msg+="Output: ${CFG_CLIENT_OUTPUT}\n" [[ -n "$CFG_CLIENT_PLUGIN" ]] && confirm_msg+="Plugin: ${CFG_CLIENT_PLUGIN}\n" if ! tui_yesno "Confirm" "Review your settings:\n\n${confirm_msg}\nProceed?"; then return fi client_generate_config || return client_show_summary } ############################################################################### # Plugin Installation Flow ############################################################################### plugin_download_github_release() { local repo="$1" binary_name="$2" local os arch api_url assets_json download_url asset_name os=$(detect_os) arch=$(detect_arch) if ! command -v curl >/dev/null 2>&1; then tui_msgbox "Error" "curl is required for downloading plugins." return 1 fi api_url="https://api.github.com/repos/${repo}/releases/latest" tui_msgbox "Downloading" "Fetching latest release info from:\n${repo}\n\nPlease wait..." assets_json=$(curl -sS --connect-timeout 15 --max-time 30 "$api_url") || { tui_msgbox "Error" "Failed to fetch release info from GitHub.\n\nCheck your network connection." return 1 } # Find matching asset URL -- look for os and arch in filename download_url="" # Try common naming patterns local patterns=() patterns+=("${os}-${arch}") patterns+=("${os}_${arch}") # Map arch names for different projects case "$arch" in amd64) patterns+=("${os}-amd64" "${os}_amd64" "${os}-x86_64" "${os}_x86_64" "linux-64") ;; arm64) patterns+=("${os}-arm64" "${os}_arm64" "${os}-aarch64" "${os}_aarch64") ;; esac local p for p in "${patterns[@]}"; do download_url=$(echo "$assets_json" | grep -o '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*'"$p"'[^"]*"' | head -1 | sed 's/.*"\(http[^"]*\)".*/\1/') [[ -n "$download_url" ]] && break done if [[ -z "$download_url" ]]; then tui_msgbox "Error" "Could not find a matching release for ${os}-${arch}.\n\nYou may need to build from source or download manually." return 1 fi asset_name=$(basename "$download_url") TMPDIR_CLEANUP=$(mktemp -d) local tmpdir="$TMPDIR_CLEANUP" tui_msgbox "Downloading" "Downloading:\n${asset_name}\n\nThis may take a moment..." if ! curl -sSL --connect-timeout 15 --max-time 120 -o "${tmpdir}/${asset_name}" "$download_url"; then tui_msgbox "Error" "Download failed." return 1 fi # Extract based on file type local extract_dir="${tmpdir}/extract" mkdir -p "$extract_dir" case "$asset_name" in *.tar.gz|*.tgz) tar xzf "${tmpdir}/${asset_name}" -C "$extract_dir" || { tui_msgbox "Error" "Failed to extract archive." return 1 } ;; *.zip) unzip -q "${tmpdir}/${asset_name}" -d "$extract_dir" || { tui_msgbox "Error" "Failed to extract archive." return 1 } ;; *) # Assume it's the binary itself cp "${tmpdir}/${asset_name}" "${extract_dir}/${binary_name}" chmod +x "${extract_dir}/${binary_name}" ;; esac # Find the binary local found_binary="" found_binary=$(find "$extract_dir" -name "$binary_name" -type f 2>/dev/null | head -1) # Some plugins have different names in the archive if [[ -z "$found_binary" ]]; then # Try finding any executable found_binary=$(find "$extract_dir" -type f -executable 2>/dev/null | head -1) fi if [[ -z "$found_binary" ]]; then found_binary=$(find "$extract_dir" -type f -name "${binary_name}*" 2>/dev/null | head -1) fi if [[ -z "$found_binary" ]]; then tui_msgbox "Error" "Could not find '${binary_name}' in the downloaded archive.\n\nContents of archive:\n$(ls -la "$extract_dir" 2>/dev/null)" return 1 fi chmod +x "$found_binary" cp "$found_binary" "/usr/local/bin/${binary_name}" if command -v "$binary_name" >/dev/null 2>&1; then tui_msgbox "Success" "${binary_name} installed to /usr/local/bin/${binary_name}" return 0 else tui_msgbox "Warning" "Installed to /usr/local/bin/${binary_name} but it was not found in PATH." return 0 fi } plugin_install_simple_obfs() { local distro distro=$(detect_distro) local method method=$(tui_menu "Install simple-obfs" "Choose installation method:" \ "package" "Install via package manager (if available)" \ "source" "Build from source (requires git, build tools)") || return 1 if [[ "$method" == "package" ]]; then case "$distro" in ubuntu|debian) apt-get update && apt-get install -y simple-obfs && { tui_msgbox "Success" "simple-obfs installed via apt." return 0 } tui_msgbox "Notice" "Package not available. Trying source build..." ;; *) tui_msgbox "Notice" "No package available for ${distro}. Building from source..." ;; esac fi # Build from source if ! command -v git >/dev/null 2>&1; then tui_msgbox "Error" "git is required to build from source." return 1 fi if ! command -v make >/dev/null 2>&1; then tui_msgbox "Error" "make is required to build from source." return 1 fi TMPDIR_CLEANUP=$(mktemp -d) local tmpdir="$TMPDIR_CLEANUP" tui_msgbox "Building" "Cloning and building simple-obfs...\nThis may take a few minutes." ( cd "$tmpdir" git clone https://github.com/shadowsocks/simple-obfs.git cd simple-obfs git submodule update --init --recursive ./autogen.sh ./configure make make install ) || { tui_msgbox "Error" "Build failed. Check that build dependencies are installed:\n autoconf, automake, libtool, libev-dev" return 1 } if command -v obfs-local >/dev/null 2>&1; then tui_msgbox "Success" "simple-obfs built and installed.\nBinaries: obfs-local, obfs-server" else tui_msgbox "Warning" "Build completed but obfs-local not found in PATH." fi } plugin_install_custom() { local path path=$(tui_inputbox "Custom Plugin" "Enter the full path to the plugin binary:" "") || return 1 if [[ -z "$path" ]]; then return 1 fi if [[ ! -f "$path" ]]; then tui_msgbox "Error" "File not found: ${path}" return 1 fi if [[ ! -x "$path" ]]; then chmod +x "$path" fi local name name=$(basename "$path") if tui_yesno "Symlink" "Create a symlink in /usr/local/bin/${name}?"; then ln -sf "$path" "/usr/local/bin/${name}" tui_msgbox "Done" "Symlinked ${path} → /usr/local/bin/${name}" else tui_msgbox "Done" "Plugin at ${path} is ready to use.\nSpecify the full path when configuring." fi } plugin_install() { if ! is_root; then tui_msgbox "Root Required" "Plugin installation requires root privileges.\n\nRe-run with sudo." return fi local items=() local p for p in "${KNOWN_PLUGINS[@]}"; do local status="not installed" if command -v "$p" >/dev/null 2>&1; then status="installed" fi items+=("$p" "$(plugin_repo "$p") (${status})") done items+=("custom" "Install a custom binary") local choice choice=$(tui_menu "Install Plugin" "Select a plugin to install:" "${items[@]}") || return case "$choice" in simple-obfs) plugin_install_simple_obfs ;; v2ray-plugin) plugin_download_github_release "$(plugin_repo v2ray-plugin)" "v2ray-plugin" ;; xray-plugin) plugin_download_github_release "$(plugin_repo xray-plugin)" "xray-plugin" ;; kcptun) plugin_download_github_release "$(plugin_repo kcptun)" "kcptun-client" ;; custom) plugin_install_custom ;; esac } ############################################################################### # Service Management ############################################################################### service_list_instances() { local instances=() # Scan config files if [[ -d "$CONFIG_DIR" ]]; then local f name for f in "${CONFIG_DIR}"/*.json; do [[ -f "$f" ]] || continue name=$(basename "$f" .json) local status="no service" local unit="shadowsocks-libev-server@${name}.service" if has_systemd; then if systemctl is-active --quiet "$unit" 2>/dev/null; then status="running" elif systemctl is-enabled --quiet "$unit" 2>/dev/null; then status="stopped (enabled)" fi fi instances+=("$name" "${status}") done fi if [[ ${#instances[@]} -eq 0 ]]; then tui_msgbox "No Instances" "No config files found in ${CONFIG_DIR}/" return 1 fi local choice choice=$(tui_menu "Instances" "Select an instance:" "${instances[@]}") || return 1 echo "$choice" } service_action_menu() { local name="$1" local unit="shadowsocks-libev-server@${name}.service" while true; do local action action=$(tui_menu "Manage: ${name}" "Select an action:" \ "status" "View service status" \ "start" "Start the service" \ "stop" "Stop the service" \ "restart" "Restart the service" \ "enable" "Enable on boot" \ "disable" "Disable on boot" \ "logs" "View recent logs" \ "back" "Return to instance list") || return case "$action" in status) local st st=$(systemctl status "$unit" 2>&1 || true) tui_msgbox "Status: ${name}" "$st" ;; start) systemctl start "$unit" 2>&1 && \ tui_msgbox "Started" "Service ${unit} started." || \ tui_msgbox "Error" "Failed to start ${unit}." ;; stop) systemctl stop "$unit" 2>&1 && \ tui_msgbox "Stopped" "Service ${unit} stopped." || \ tui_msgbox "Error" "Failed to stop ${unit}." ;; restart) systemctl restart "$unit" 2>&1 && \ tui_msgbox "Restarted" "Service ${unit} restarted." || \ tui_msgbox "Error" "Failed to restart ${unit}." ;; enable) systemctl enable "$unit" 2>&1 && \ tui_msgbox "Enabled" "Service ${unit} enabled on boot." || \ tui_msgbox "Error" "Failed to enable ${unit}." ;; disable) systemctl disable "$unit" 2>&1 && \ tui_msgbox "Disabled" "Service ${unit} disabled." || \ tui_msgbox "Error" "Failed to disable ${unit}." ;; logs) local logs logs=$(journalctl -u "$unit" -n 50 --no-pager 2>&1 || echo "(no logs available)") tui_msgbox "Logs: ${name}" "$logs" ;; back) return ;; esac done } service_manage() { if ! is_root; then tui_msgbox "Root Required" "Service management requires root privileges.\n\nRe-run with sudo." return fi if ! has_systemd; then tui_msgbox "No systemd" "systemd was not detected on this system.\n\nService management is not available." return fi while true; do local instance instance=$(service_list_instances) || return service_action_menu "$instance" done } ############################################################################### # Main Menu ############################################################################### main_menu() { while true; do local choice choice=$(tui_menu "ss-setup v${SS_SETUP_VERSION}" "shadowsocks-libev setup tool" \ "server" "Setup ss-server (generate config + service)" \ "client" "Generate ss-local client config" \ "plugin" "Install a SIP003 plugin" \ "service" "Manage running services" \ "exit" "Exit") || break case "$choice" in server) server_setup ;; client) client_setup ;; plugin) plugin_install ;; service) service_manage ;; exit) break ;; esac done } ############################################################################### # Entry Point ############################################################################### main() { # Non-interactive check if [[ ! -t 0 ]]; then echo "Error: ss-setup requires an interactive terminal." >&2 echo "Usage: ss-setup" >&2 exit 1 fi detect_tui_backend check_root || true # warn but continue main_menu echo "Goodbye." } # Only run main when executed directly (not when sourced for testing) if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then main "$@" fi ================================================ FILE: snap/snapcraft.yaml ================================================ base: core22 name: shadowsocks-libev version: '3.3.6' summary: libev port of shadowsocks description: | Shadowsocks-libev is a lightweight and secure SOCKS5 proxy for embedded devices and low-end boxes. It is rewritten in pure C and depends on libev, designed to be a lightweight implementation of the shadowsocks protocol. grade: stable confinement: strict apps: ss-local: command: usr/bin/ss-local plugs: [network, network-bind] ss-local-daemon: command: usr/bin/ss-local daemon: simple plugs: [network, network-bind] ss-server: command: usr/bin/ss-server plugs: [network, network-bind] ss-server-daemon: command: usr/bin/ss-server daemon: simple plugs: [network, network-bind] ss-redir: command: usr/bin/ss-redir plugs: [network, network-bind] ss-tunnel: command: usr/bin/ss-tunnel plugs: [network, network-bind] ss-manager: command: usr/bin/ss-manager plugs: [network] layout: /etc/shadowsocks-libev: bind: $SNAP_COMMON/etc/shadowsocks-libev parts: shadowsocks-libev: plugin: cmake source: . source-type: git cmake-parameters: - -DCMAKE_INSTALL_PREFIX=/usr - -DCMAKE_BUILD_TYPE=Release - -DWITH_DOC_MAN=OFF - -DBUILD_TESTING=OFF build-packages: - libpcre2-dev - libev-dev - libc-ares-dev - libmbedtls-dev - libsodium-dev stage-packages: - libc-ares2 - libev4 - libmbedcrypto7 - libmbedtls14 - libmbedx509-1 - libpcre2-8-0 - libsodium23 override-build: | craftctl default rm -rf $SNAPCRAFT_PART_INSTALL/usr/share/doc ================================================ FILE: src/CMakeLists.txt ================================================ # redir need linux/* stuff if (LINUX) option(WITH_SS_REDIR "Build ss-redir" ON) option(WITH_SS_MANAGER "Build ss-manager" ON) else () option(WITH_SS_REDIR "Build ss-redir" OFF) option(WITH_SS_MANAGER "Build ss-manager" OFF) endif () set(SS_ACL_SOURCE acl.c rule.c ) set(SS_CRYPTO_SOURCE crypto.c aead.c stream.c base64.c ) set(SS_PLUGIN_SOURCE plugin.c ) set(SS_SHARED_SOURCES ppbloom.c utils.c jconf.c json.c netutils.c ) if (MINGW) set(SS_SHARED_SOURCES ${SS_SHARED_SOURCES} winsock.c) endif () set(LIBSHADOWSOCKS_LIBEV_SOURCE ${SS_SHARED_SOURCES} udprelay.c cache.c local.c ${SS_CRYPTO_SOURCE} ${SS_PLUGIN_SOURCE} ${SS_ACL_SOURCE} ) set(SS_LOCAL_SOURCE ${LIBSHADOWSOCKS_LIBEV_SOURCE} ) set(SS_TUNNEL_SOURCE ${SS_SHARED_SOURCES} udprelay.c cache.c tunnel.c ${SS_CRYPTO_SOURCE} ${SS_PLUGIN_SOURCE} ) set(SS_SERVER_SOURCE ${SS_SHARED_SOURCES} udprelay.c cache.c resolv.c server.c ${SS_CRYPTO_SOURCE} ${SS_PLUGIN_SOURCE} ${SS_ACL_SOURCE} ) set(SS_MANAGER_SOURCE ${SS_SHARED_SOURCES} manager.c ) set(SS_REDIR_SOURCE ${SS_SHARED_SOURCES} udprelay.c cache.c redir.c ${SS_CRYPTO_SOURCE} ${SS_PLUGIN_SOURCE} ) # Apply -Werror only to project sources (not bundled submodules) set(SS_WERROR_FLAGS -Werror) # Include directories from Find modules # MbedTLS must come first to avoid conflicts with other mbedtls versions # that may be in /opt/homebrew/include (e.g. mbedtls 4.x vs 3.x) include_directories(BEFORE ${MBEDTLS_INCLUDE_DIRS}) include_directories(${SODIUM_INCLUDE_DIRS}) include_directories(${PCRE2_INCLUDE_DIRS}) include_directories(${CARES_INCLUDE_DIRS}) # Extract mbedTLS lib dir to ensure static/shared libs come from same version get_filename_component(_MBEDTLS_LIB_DIR "${MBEDTLS_CRYPTO_LIBRARY}" DIRECTORY) if (WITH_STATIC) find_library(LIBSODIUM libsodium.a) find_library(LIBMBEDTLS libmbedtls.a HINTS ${_MBEDTLS_LIB_DIR} NO_DEFAULT_PATH) find_library(LIBMBEDTLS libmbedtls.a) find_library(LIBMBEDCRYPTO libmbedcrypto.a HINTS ${_MBEDTLS_LIB_DIR} NO_DEFAULT_PATH) find_library(LIBMBEDCRYPTO libmbedcrypto.a) find_library(LIBEV libev.a) find_library(LIBUDNS libcares.a) find_library(LIBPCRE2 libpcre2-8.a) # Dependencies we need for static and shared list(APPEND DEPS m bloom ${LIBEV} ${LIBUDNS} ${LIBPCRE2} ${LIBSODIUM} ${LIBMBEDTLS} ${LIBMBEDCRYPTO} ) if (MINGW) list(APPEND DEPS ws2_32 iphlpapi) add_compile_definitions(CARES_STATICLIB PCRE2_STATIC) endif () endif () find_library(LIBSODIUM_SHARED sodium) find_library(LIBMBEDTLS_SHARED mbedtls HINTS ${_MBEDTLS_LIB_DIR} NO_DEFAULT_PATH) find_library(LIBMBEDTLS_SHARED mbedtls) find_library(LIBMBEDCRYPTO_SHARED mbedcrypto HINTS ${_MBEDTLS_LIB_DIR} NO_DEFAULT_PATH) find_library(LIBMBEDCRYPTO_SHARED mbedcrypto) find_library(LIBEV_SHARED ev) find_library(LIBUDNS_SHARED cares) find_library(LIBPCRE2_SHARED pcre2-8) if (WITH_EMBEDDED_SRC) list(APPEND DEPS_SHARED m bloom cork ipset ${LIBEV_SHARED} ${LIBUDNS_SHARED} ${LIBPCRE2_SHARED} ${LIBSODIUM_SHARED} ${LIBMBEDTLS_SHARED} ${LIBMBEDCRYPTO_SHARED} ) else () find_library(LIBBLOOM_SHARED bloom) find_library(LIBCORK_SHARED cork) find_library(LIBCORKIPSET_SHARED corkipset) list(APPEND DEPS_SHARED m ${LIBBLOOM_SHARED} ${LIBCORK_SHARED} ${LIBCORKIPSET_SHARED} ${LIBEV_SHARED} ${LIBUDNS_SHARED} ${LIBPCRE2_SHARED} ${LIBSODIUM_SHARED} ${LIBMBEDTLS_SHARED} ${LIBMBEDCRYPTO_SHARED} ) endif () # Connmarktos/nftables libraries for ss-server if(ENABLE_CONNMARKTOS) list(APPEND DEPS_CONNMARKTOS ${NETFILTER_CONNTRACK_LIB}) if(NFNETLINK_LIB) list(APPEND DEPS_CONNMARKTOS ${NFNETLINK_LIB}) endif() endif() if(ENABLE_NFTABLES) list(APPEND DEPS_NFTABLES ${MNL_LIB} ${NFTNL_LIB}) endif() find_package (Threads) if (WITH_STATIC) # ------------------------------------------------------------------ # Static # By default we use normal name for static, all shared targets will add a `-shared' suffix add_executable(ss-server ${SS_SERVER_SOURCE}) add_executable(ss-tunnel ${SS_TUNNEL_SOURCE}) if (WITH_SS_MANAGER) add_executable(ss-manager ${SS_MANAGER_SOURCE}) else () add_executable(ss-manager EXCLUDE_FROM_ALL ${SS_MANAGER_SOURCE}) endif () add_executable(ss-local ${SS_LOCAL_SOURCE}) if (WITH_SS_REDIR) add_executable(ss-redir ${SS_REDIR_SOURCE}) else () add_executable(ss-redir EXCLUDE_FROM_ALL ${SS_REDIR_SOURCE}) endif () add_library(shadowsocks-libev STATIC ${LIBSHADOWSOCKS_LIBEV_SOURCE}) target_compile_definitions(ss-server PUBLIC -DMODULE_REMOTE) target_compile_definitions(ss-tunnel PUBLIC -DMODULE_TUNNEL) target_compile_definitions(ss-manager PUBLIC -DMODULE_MANAGER) target_compile_definitions(ss-local PUBLIC -DMODULE_LOCAL) target_compile_definitions(ss-redir PUBLIC -DMODULE_REDIR) target_compile_definitions(shadowsocks-libev PUBLIC -DMODULE_LOCAL -DLIB_ONLY) target_compile_options(ss-server PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(ss-tunnel PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(ss-manager PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(ss-local PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(ss-redir PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(shadowsocks-libev PRIVATE ${SS_WERROR_FLAGS}) # Connmarktos/nftables compile definitions if(ENABLE_CONNMARKTOS) target_compile_definitions(ss-server PUBLIC -DUSE_NFCONNTRACK_TOS) endif() if(ENABLE_NFTABLES) target_compile_definitions(ss-server PUBLIC -DUSE_NFTABLES) endif() target_include_directories(shadowsocks-libev PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(ss-server cork ipset ${DEPS} ${DEPS_CONNMARKTOS} ${DEPS_NFTABLES}) target_link_libraries(ss-tunnel cork ${DEPS}) target_link_libraries(ss-manager m bloom cork ${LIBEV} ${LIBUDNS}) target_link_libraries(ss-local cork ipset ${DEPS}) target_link_libraries(ss-redir cork ipset ${DEPS}) target_link_libraries(shadowsocks-libev cork ipset ${DEPS}) endif () # ------------------------------------------------------------------ # Shared # Shared target will have a `-shared' suffix # All shared dependency also have `-shared' suffix # For shared binary, we still use the same name as static, without `-shared', but will output to shared directory add_executable(ss-server-shared ${SS_SERVER_SOURCE}) add_executable(ss-tunnel-shared ${SS_TUNNEL_SOURCE}) if (WITH_SS_MANAGER) add_executable(ss-manager-shared ${SS_MANAGER_SOURCE}) else () add_executable(ss-manager-shared EXCLUDE_FROM_ALL ${SS_MANAGER_SOURCE}) endif () add_executable(ss-local-shared ${SS_LOCAL_SOURCE}) if (WITH_SS_REDIR) add_executable(ss-redir-shared ${SS_REDIR_SOURCE}) else () add_executable(ss-redir-shared EXCLUDE_FROM_ALL ${SS_REDIR_SOURCE}) endif () add_library(shadowsocks-libev-shared SHARED ${LIBSHADOWSOCKS_LIBEV_SOURCE}) target_compile_definitions(ss-server-shared PUBLIC -DMODULE_REMOTE) target_compile_definitions(ss-tunnel-shared PUBLIC -DMODULE_TUNNEL) target_compile_definitions(ss-manager-shared PUBLIC -DMODULE_MANAGER) target_compile_definitions(ss-local-shared PUBLIC -DMODULE_LOCAL) target_compile_definitions(ss-redir-shared PUBLIC -DMODULE_REDIR) target_compile_definitions(shadowsocks-libev-shared PUBLIC -DMODULE_LOCAL -DLIB_ONLY) target_compile_options(ss-server-shared PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(ss-tunnel-shared PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(ss-manager-shared PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(ss-local-shared PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(ss-redir-shared PRIVATE ${SS_WERROR_FLAGS}) target_compile_options(shadowsocks-libev-shared PRIVATE ${SS_WERROR_FLAGS}) # Connmarktos/nftables compile definitions for shared if(ENABLE_CONNMARKTOS) target_compile_definitions(ss-server-shared PUBLIC -DUSE_NFCONNTRACK_TOS) endif() if(ENABLE_NFTABLES) target_compile_definitions(ss-server-shared PUBLIC -DUSE_NFTABLES) endif() target_include_directories(shadowsocks-libev-shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(ss-server-shared ${DEPS_SHARED} ${DEPS_CONNMARKTOS} ${DEPS_NFTABLES}) target_link_libraries(ss-tunnel-shared ${DEPS_SHARED}) target_link_libraries(ss-manager-shared ${CMAKE_THREAD_LIBS_INIT} ${LIBEV_SHARED} ${LIBUDNS_SHARED} ${DEPS_SHARED}) target_link_libraries(ss-local-shared ${DEPS_SHARED}) target_link_libraries(ss-redir-shared ${DEPS_SHARED}) target_link_libraries(shadowsocks-libev-shared ${DEPS_SHARED}) set_target_properties(ss-server-shared PROPERTIES OUTPUT_NAME ss-server) set_target_properties(ss-tunnel-shared PROPERTIES OUTPUT_NAME ss-tunnel) set_target_properties(ss-manager-shared PROPERTIES OUTPUT_NAME ss-manager) set_target_properties(ss-local-shared PROPERTIES OUTPUT_NAME ss-local) set_target_properties(ss-redir-shared PROPERTIES OUTPUT_NAME ss-redir) set_target_properties(ss-server-shared ss-tunnel-shared ss-manager-shared ss-local-shared ss-redir-shared PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${RUNTIME_SHARED_OUTPUT_DIRECTORY} ) set_target_properties(shadowsocks-libev-shared PROPERTIES OUTPUT_NAME shadowsocks-libev) set_target_properties(shadowsocks-libev-shared PROPERTIES VERSION 2.0.0 SOVERSION 2) target_compile_definitions(shadowsocks-libev-shared PUBLIC -DMODULE_LOCAL) target_link_libraries(shadowsocks-libev-shared ${DEPS_SHARED}) # ------------------------------------------------------------------ # Misc # Recommend to install shared by default install(DIRECTORY ${RUNTIME_SHARED_OUTPUT_DIRECTORY}/ USE_SOURCE_PERMISSIONS DESTINATION ${CMAKE_INSTALL_BINDIR}) if (WITH_STATIC) install(TARGETS shadowsocks-libev ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif () install(TARGETS shadowsocks-libev-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES shadowsocks.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) add_custom_target(distclean COMMAND ${CMAKE_COMMAND} -E echo WARNING: distclean target is not functional COMMAND ${CMAKE_COMMAND} -E echo Use 'git clean -fdx' instead VERBATIM ) ================================================ FILE: src/acl.c ================================================ /* * acl.c - Manage the ACL (Access Control List) * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifdef USE_SYSTEM_SHARED_LIB #include #else #include #endif #include "rule.h" #include "netutils.h" #include "utils.h" #include "cache.h" #include "acl.h" static struct ip_set white_list_ipv4; static struct ip_set white_list_ipv6; static struct ip_set black_list_ipv4; static struct ip_set black_list_ipv6; static struct cork_dllist black_list_rules; static struct cork_dllist white_list_rules; static int acl_mode = BLACK_LIST; static struct ip_set outbound_block_list_ipv4; static struct ip_set outbound_block_list_ipv6; static struct cork_dllist outbound_block_list_rules; static void parse_addr_cidr(const char *str, char *host, int *cidr) { int ret = -1; char *pch; pch = strchr(str, '/'); while (pch != NULL) { ret = pch - str; pch = strchr(pch + 1, '/'); } if (ret == -1) { strcpy(host, str); *cidr = -1; } else { memcpy(host, str, ret); host[ret] = '\0'; *cidr = atoi(str + ret + 1); } } char * trimwhitespace(char *str) { char *end; // Trim leading space while (isspace((unsigned char)*str)) str++; if (*str == 0) // All spaces? return str; // Trim trailing space end = str + strlen(str) - 1; while (end > str && isspace((unsigned char)*end)) end--; // Write new null terminator *(end + 1) = 0; return str; } int init_acl(const char *path) { if (path == NULL) { return -1; } // initialize ipset ipset_init_library(); ipset_init(&white_list_ipv4); ipset_init(&white_list_ipv6); ipset_init(&black_list_ipv4); ipset_init(&black_list_ipv6); ipset_init(&outbound_block_list_ipv4); ipset_init(&outbound_block_list_ipv6); cork_dllist_init(&black_list_rules); cork_dllist_init(&white_list_rules); cork_dllist_init(&outbound_block_list_rules); struct ip_set *list_ipv4 = &black_list_ipv4; struct ip_set *list_ipv6 = &black_list_ipv6; struct cork_dllist *rules = &black_list_rules; FILE *f = fopen(path, "r"); if (f == NULL) { LOGE("Invalid acl path."); return -1; } char buf[MAX_HOSTNAME_LEN]; while (!feof(f)) if (fgets(buf, 256, f)) { // Discards the whole line if longer than 255 characters int long_line = 0; // 1: Long 2: Error while ((strlen(buf) == 255) && (buf[254] != '\n')) { long_line = 1; LOGE("Discarding long ACL content: %s", buf); if (fgets(buf, 256, f) == NULL) { long_line = 2; break; } } if (long_line) { if (long_line == 1) { LOGE("Discarding long ACL content: %s", buf); } continue; } // Trim the newline int len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') { buf[len - 1] = '\0'; } char *comment = strchr(buf, '#'); if (comment) { *comment = '\0'; } char *line = trimwhitespace(buf); if (strlen(line) == 0) { continue; } if (strcmp(line, "[outbound_block_list]") == 0) { list_ipv4 = &outbound_block_list_ipv4; list_ipv6 = &outbound_block_list_ipv6; rules = &outbound_block_list_rules; continue; } else if (strcmp(line, "[black_list]") == 0 || strcmp(line, "[bypass_list]") == 0) { list_ipv4 = &black_list_ipv4; list_ipv6 = &black_list_ipv6; rules = &black_list_rules; continue; } else if (strcmp(line, "[white_list]") == 0 || strcmp(line, "[proxy_list]") == 0) { list_ipv4 = &white_list_ipv4; list_ipv6 = &white_list_ipv6; rules = &white_list_rules; continue; } else if (strcmp(line, "[reject_all]") == 0 || strcmp(line, "[bypass_all]") == 0) { acl_mode = WHITE_LIST; continue; } else if (strcmp(line, "[accept_all]") == 0 || strcmp(line, "[proxy_all]") == 0) { acl_mode = BLACK_LIST; continue; } char host[MAX_HOSTNAME_LEN]; int cidr; parse_addr_cidr(line, host, &cidr); struct cork_ip addr; int err = cork_ip_init(&addr, host); if (!err) { if (addr.version == 4) { if (cidr >= 0) { ipset_ipv4_add_network(list_ipv4, &(addr.ip.v4), cidr); } else { ipset_ipv4_add(list_ipv4, &(addr.ip.v4)); } } else if (addr.version == 6) { if (cidr >= 0) { ipset_ipv6_add_network(list_ipv6, &(addr.ip.v6), cidr); } else { ipset_ipv6_add(list_ipv6, &(addr.ip.v6)); } } } else { rule_t *rule = new_rule(); accept_rule_arg(rule, line); init_rule(rule); add_rule(rules, rule); } } fclose(f); return 0; } void free_rules(struct cork_dllist *rules) { struct cork_dllist_item *iter; while ((iter = cork_dllist_head(rules)) != NULL) { rule_t *rule = cork_container_of(iter, rule_t, entries); remove_rule(rule); } } void free_acl(void) { ipset_done(&black_list_ipv4); ipset_done(&black_list_ipv6); ipset_done(&white_list_ipv4); ipset_done(&white_list_ipv6); free_rules(&black_list_rules); free_rules(&white_list_rules); } int get_acl_mode(void) { return acl_mode; } /* * Return 0, if not match. * Return 1, if match black list. * Return -1, if match white list. */ int acl_match_host(const char *host) { struct cork_ip addr; int ret = 0; int err = cork_ip_init(&addr, host); if (err) { int host_len = strlen(host); if (lookup_rule(&black_list_rules, host, host_len) != NULL) ret = 1; else if (lookup_rule(&white_list_rules, host, host_len) != NULL) ret = -1; return ret; } if (addr.version == 4) { if (ipset_contains_ipv4(&black_list_ipv4, &(addr.ip.v4))) ret = 1; else if (ipset_contains_ipv4(&white_list_ipv4, &(addr.ip.v4))) ret = -1; } else if (addr.version == 6) { if (ipset_contains_ipv6(&black_list_ipv6, &(addr.ip.v6))) ret = 1; else if (ipset_contains_ipv6(&white_list_ipv6, &(addr.ip.v6))) ret = -1; } return ret; } int acl_add_ip(const char *ip) { struct cork_ip addr; int err = cork_ip_init(&addr, ip); if (err) { return -1; } if (addr.version == 4) { ipset_ipv4_add(&black_list_ipv4, &(addr.ip.v4)); } else if (addr.version == 6) { ipset_ipv6_add(&black_list_ipv6, &(addr.ip.v6)); } return 0; } int acl_remove_ip(const char *ip) { struct cork_ip addr; int err = cork_ip_init(&addr, ip); if (err) { return -1; } if (addr.version == 4) { ipset_ipv4_remove(&black_list_ipv4, &(addr.ip.v4)); } else if (addr.version == 6) { ipset_ipv6_remove(&black_list_ipv6, &(addr.ip.v6)); } return 0; } /* * Return 0, if not match. * Return 1, if match black list. */ int outbound_block_match_host(const char *host) { struct cork_ip addr; int ret = 0; int err = cork_ip_init(&addr, host); if (err) { int host_len = strlen(host); if (lookup_rule(&outbound_block_list_rules, host, host_len) != NULL) ret = 1; return ret; } if (addr.version == 4) { if (ipset_contains_ipv4(&outbound_block_list_ipv4, &(addr.ip.v4))) ret = 1; } else if (addr.version == 6) { if (ipset_contains_ipv6(&outbound_block_list_ipv6, &(addr.ip.v6))) ret = 1; } return ret; } ================================================ FILE: src/acl.h ================================================ /* * acl.h - Define the ACL interface * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _ACL_H #define _ACL_H #define BLACK_LIST 0 #define WHITE_LIST 1 int init_acl(const char *path); void free_acl(void); int acl_match_host(const char *ip); int acl_add_ip(const char *ip); int acl_remove_ip(const char *ip); int get_acl_mode(void); int outbound_block_match_host(const char *host); #endif // _ACL_H ================================================ FILE: src/aead.c ================================================ /* * aead.c - Manage AEAD ciphers * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #define CIPHER_UNSUPPORTED "unsupported" #include #include #include #include #ifndef __MINGW32__ #include #endif #include "ppbloom.h" #include "aead.h" #include "utils.h" #include "winsock.h" #define NONE (-1) #define AES128GCM 0 #define AES192GCM 1 #define AES256GCM 2 /* * methods above requires gcm context * methods below doesn't require it, * then we need to fake one */ #define CHACHA20POLY1305IETF 3 #ifdef FS_HAVE_XCHACHA20IETF #define XCHACHA20POLY1305IETF 4 #endif #define CHUNK_SIZE_LEN 2 #define CHUNK_SIZE_MASK 0x3FFF /* * Spec: http://shadowsocks.org/en/spec/AEAD-Ciphers.html * * The way Shadowsocks using AEAD ciphers is specified in SIP004 and amended in SIP007. SIP004 was proposed by @Mygod * with design inspirations from @wongsyrone, @Noisyfox and @breakwa11. SIP007 was proposed by @riobard with input from * @madeye, @Mygod, @wongsyrone, and many others. * * Key Derivation * * HKDF_SHA1 is a function that takes a secret key, a non-secret salt, an info string, and produces a subkey that is * cryptographically strong even if the input secret key is weak. * * HKDF_SHA1(key, salt, info) => subkey * * The info string binds the generated subkey to a specific application context. In our case, it must be the string * "ss-subkey" without quotes. * * We derive a per-session subkey from a pre-shared master key using HKDF_SHA1. Salt must be unique through the entire * life of the pre-shared master key. * * TCP * * An AEAD encrypted TCP stream starts with a randomly generated salt to derive the per-session subkey, followed by any * number of encrypted chunks. Each chunk has the following structure: * * [encrypted payload length][length tag][encrypted payload][payload tag] * * Payload length is a 2-byte big-endian unsigned integer capped at 0x3FFF. The higher two bits are reserved and must be * set to zero. Payload is therefore limited to 16*1024 - 1 bytes. * * The first AEAD encrypt/decrypt operation uses a counting nonce starting from 0. After each encrypt/decrypt operation, * the nonce is incremented by one as if it were an unsigned little-endian integer. Note that each TCP chunk involves * two AEAD encrypt/decrypt operation: one for the payload length, and one for the payload. Therefore each chunk * increases the nonce twice. * * UDP * * An AEAD encrypted UDP packet has the following structure: * * [salt][encrypted payload][tag] * * The salt is used to derive the per-session subkey and must be generated randomly to ensure uniqueness. Each UDP * packet is encrypted/decrypted independently, using the derived subkey and a nonce with all zero bytes. * */ const char *supported_aead_ciphers[AEAD_CIPHER_NUM] = { "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", #ifdef FS_HAVE_XCHACHA20IETF "xchacha20-ietf-poly1305" #endif }; /* * use mbed TLS cipher wrapper to unify handling */ static const char *supported_aead_ciphers_mbedtls[AEAD_CIPHER_NUM] = { "AES-128-GCM", "AES-192-GCM", "AES-256-GCM", CIPHER_UNSUPPORTED, #ifdef FS_HAVE_XCHACHA20IETF CIPHER_UNSUPPORTED #endif }; static const int supported_aead_ciphers_nonce_size[AEAD_CIPHER_NUM] = { 12, 12, 12, 12, #ifdef FS_HAVE_XCHACHA20IETF 24 #endif }; static const int supported_aead_ciphers_key_size[AEAD_CIPHER_NUM] = { 16, 24, 32, 32, #ifdef FS_HAVE_XCHACHA20IETF 32 #endif }; static const int supported_aead_ciphers_tag_size[AEAD_CIPHER_NUM] = { 16, 16, 16, 16, #ifdef FS_HAVE_XCHACHA20IETF 16 #endif }; static int aead_cipher_encrypt(cipher_ctx_t *cipher_ctx, uint8_t *c, size_t *clen, uint8_t *m, size_t mlen, uint8_t *ad, size_t adlen, uint8_t *n, uint8_t *k) { int err = CRYPTO_OK; unsigned long long long_clen = 0; size_t nlen = cipher_ctx->cipher->nonce_len; size_t tlen = cipher_ctx->cipher->tag_len; switch (cipher_ctx->cipher->method) { case AES256GCM: // Only AES-256-GCM is supported by libsodium. if (cipher_ctx->aes256gcm_ctx != NULL) { // Use it if availble err = crypto_aead_aes256gcm_encrypt_afternm(c, &long_clen, m, mlen, ad, adlen, NULL, n, (const aes256gcm_ctx *)cipher_ctx->aes256gcm_ctx); *clen = (size_t)long_clen; // it's safe to cast 64bit to 32bit length here break; } // Otherwise, just use the mbedTLS one with crappy AES-NI. case AES192GCM: case AES128GCM: #if MBEDTLS_VERSION_NUMBER < 0x03000000 err = mbedtls_cipher_auth_encrypt(cipher_ctx->evp, n, nlen, ad, adlen, m, mlen, c, clen, c + mlen, tlen); #else err = mbedtls_cipher_auth_encrypt_ext(cipher_ctx->evp, n, nlen, ad, adlen, m, mlen, c, mlen + tlen, clen, tlen); #endif *clen += tlen; break; case CHACHA20POLY1305IETF: err = crypto_aead_chacha20poly1305_ietf_encrypt(c, &long_clen, m, mlen, ad, adlen, NULL, n, k); *clen = (size_t)long_clen; break; #ifdef FS_HAVE_XCHACHA20IETF case XCHACHA20POLY1305IETF: err = crypto_aead_xchacha20poly1305_ietf_encrypt(c, &long_clen, m, mlen, ad, adlen, NULL, n, k); *clen = (size_t)long_clen; break; #endif default: return CRYPTO_ERROR; } return err; } static int aead_cipher_decrypt(cipher_ctx_t *cipher_ctx, uint8_t *p, size_t *plen, uint8_t *m, size_t mlen, uint8_t *ad, size_t adlen, uint8_t *n, uint8_t *k) { int err = CRYPTO_ERROR; unsigned long long long_plen = 0; size_t nlen = cipher_ctx->cipher->nonce_len; size_t tlen = cipher_ctx->cipher->tag_len; switch (cipher_ctx->cipher->method) { case AES256GCM: // Only AES-256-GCM is supported by libsodium. if (cipher_ctx->aes256gcm_ctx != NULL) { // Use it if availble err = crypto_aead_aes256gcm_decrypt_afternm(p, &long_plen, NULL, m, mlen, ad, adlen, n, (const aes256gcm_ctx *)cipher_ctx->aes256gcm_ctx); *plen = (size_t)long_plen; // it's safe to cast 64bit to 32bit length here break; } // Otherwise, just use the mbedTLS one with crappy AES-NI. case AES192GCM: case AES128GCM: #if MBEDTLS_VERSION_NUMBER < 0x03000000 err = mbedtls_cipher_auth_decrypt(cipher_ctx->evp, n, nlen, ad, adlen, m, mlen - tlen, p, plen, m + mlen - tlen, tlen); #else err = mbedtls_cipher_auth_decrypt_ext(cipher_ctx->evp, n, nlen, ad, adlen, m, mlen, p, mlen - tlen, plen, tlen); #endif break; case CHACHA20POLY1305IETF: err = crypto_aead_chacha20poly1305_ietf_decrypt(p, &long_plen, NULL, m, mlen, ad, adlen, n, k); *plen = (size_t)long_plen; // it's safe to cast 64bit to 32bit length here break; #ifdef FS_HAVE_XCHACHA20IETF case XCHACHA20POLY1305IETF: err = crypto_aead_xchacha20poly1305_ietf_decrypt(p, &long_plen, NULL, m, mlen, ad, adlen, n, k); *plen = (size_t)long_plen; // it's safe to cast 64bit to 32bit length here break; #endif default: return CRYPTO_ERROR; } // The success return value ln libsodium and mbedTLS are both 0 if (err != 0) // Although we never return any library specific value in the caller, // here we still set the error code to CRYPTO_ERROR to avoid confusion. err = CRYPTO_ERROR; return err; } /* * get basic cipher info structure * it's a wrapper offered by crypto library */ const cipher_kt_t * aead_get_cipher_type(int method) { if (method < AES128GCM || method >= AEAD_CIPHER_NUM) { LOGE("aead_get_cipher_type(): Illegal method"); return NULL; } /* cipher that don't use mbed TLS, just return */ if (method >= CHACHA20POLY1305IETF) { return NULL; } const char *ciphername = supported_aead_ciphers[method]; const char *mbedtlsname = supported_aead_ciphers_mbedtls[method]; if (strcmp(mbedtlsname, CIPHER_UNSUPPORTED) == 0) { LOGE("Cipher %s currently is not supported by mbed TLS library", ciphername); return NULL; } return mbedtls_cipher_info_from_string(mbedtlsname); } static void aead_cipher_ctx_set_key(cipher_ctx_t *cipher_ctx, int enc) { const digest_type_t *md = mbedtls_md_info_from_string("SHA1"); if (md == NULL) { FATAL("SHA1 Digest not found in crypto library"); } int err = crypto_hkdf(md, cipher_ctx->salt, cipher_ctx->cipher->key_len, cipher_ctx->cipher->key, cipher_ctx->cipher->key_len, (uint8_t *)SUBKEY_INFO, strlen(SUBKEY_INFO), cipher_ctx->skey, cipher_ctx->cipher->key_len); if (err) { FATAL("Unable to generate subkey"); } memset(cipher_ctx->nonce, 0, cipher_ctx->cipher->nonce_len); /* cipher that don't use mbed TLS, just return */ if (cipher_ctx->cipher->method >= CHACHA20POLY1305IETF) { return; } if (cipher_ctx->aes256gcm_ctx != NULL) { if (crypto_aead_aes256gcm_beforenm(cipher_ctx->aes256gcm_ctx, cipher_ctx->skey) != 0) { FATAL("Cannot set libsodium cipher key"); } return; } if (mbedtls_cipher_setkey(cipher_ctx->evp, cipher_ctx->skey, cipher_ctx->cipher->key_len * 8, enc) != 0) { FATAL("Cannot set mbed TLS cipher key"); } if (mbedtls_cipher_reset(cipher_ctx->evp) != 0) { FATAL("Cannot finish preparation of mbed TLS cipher context"); } } static void aead_cipher_ctx_init(cipher_ctx_t *cipher_ctx, int method, int enc) { if (method < AES128GCM || method >= AEAD_CIPHER_NUM) { LOGE("cipher_context_init(): Illegal method"); return; } if (method >= CHACHA20POLY1305IETF) { return; } const char *ciphername = supported_aead_ciphers[method]; const cipher_kt_t *cipher = aead_get_cipher_type(method); if (method == AES256GCM && crypto_aead_aes256gcm_is_available()) { cipher_ctx->aes256gcm_ctx = ss_aligned_malloc(sizeof(aes256gcm_ctx)); memset(cipher_ctx->aes256gcm_ctx, 0, sizeof(aes256gcm_ctx)); } else { cipher_ctx->aes256gcm_ctx = NULL; cipher_ctx->evp = ss_malloc(sizeof(cipher_evp_t)); memset(cipher_ctx->evp, 0, sizeof(cipher_evp_t)); cipher_evp_t *evp = cipher_ctx->evp; mbedtls_cipher_init(evp); if (mbedtls_cipher_setup(evp, cipher) != 0) { FATAL("Cannot initialize mbed TLS cipher context"); } } if (cipher == NULL) { LOGE("Cipher %s not found in mbed TLS library", ciphername); FATAL("Cannot initialize mbed TLS cipher"); } #ifdef SS_DEBUG dump("KEY", (char *)cipher_ctx->cipher->key, cipher_ctx->cipher->key_len); #endif } void aead_ctx_init(cipher_t *cipher, cipher_ctx_t *cipher_ctx, int enc) { sodium_memzero(cipher_ctx, sizeof(cipher_ctx_t)); cipher_ctx->cipher = cipher; aead_cipher_ctx_init(cipher_ctx, cipher->method, enc); if (enc) { rand_bytes(cipher_ctx->salt, cipher->key_len); } } void aead_ctx_release(cipher_ctx_t *cipher_ctx) { if (cipher_ctx->chunk != NULL) { bfree(cipher_ctx->chunk); ss_free(cipher_ctx->chunk); cipher_ctx->chunk = NULL; } if (cipher_ctx->cipher->method >= CHACHA20POLY1305IETF) { return; } if (cipher_ctx->aes256gcm_ctx != NULL) { ss_aligned_free(cipher_ctx->aes256gcm_ctx); return; } mbedtls_cipher_free(cipher_ctx->evp); ss_free(cipher_ctx->evp); } int aead_encrypt_all(buffer_t *plaintext, cipher_t *cipher, size_t capacity) { cipher_ctx_t cipher_ctx; aead_ctx_init(cipher, &cipher_ctx, 1); size_t salt_len = cipher->key_len; size_t tag_len = cipher->tag_len; int err = CRYPTO_OK; static buffer_t tmp = { 0, 0, 0, NULL }; brealloc(&tmp, salt_len + tag_len + plaintext->len, capacity); buffer_t *ciphertext = &tmp; ciphertext->len = tag_len + plaintext->len; /* copy salt to first pos */ memcpy(ciphertext->data, cipher_ctx.salt, salt_len); ppbloom_add((void *)cipher_ctx.salt, salt_len); aead_cipher_ctx_set_key(&cipher_ctx, 1); size_t clen = ciphertext->len; err = aead_cipher_encrypt(&cipher_ctx, (uint8_t *)ciphertext->data + salt_len, &clen, (uint8_t *)plaintext->data, plaintext->len, NULL, 0, cipher_ctx.nonce, cipher_ctx.skey); aead_ctx_release(&cipher_ctx); if (err) return CRYPTO_ERROR; assert(ciphertext->len == clen); bswap_data(plaintext, ciphertext); plaintext->len = salt_len + ciphertext->len; return CRYPTO_OK; } int aead_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity) { size_t salt_len = cipher->key_len; size_t tag_len = cipher->tag_len; int err = CRYPTO_OK; if (ciphertext->len <= salt_len + tag_len) { return CRYPTO_ERROR; } cipher_ctx_t cipher_ctx; aead_ctx_init(cipher, &cipher_ctx, 0); static buffer_t tmp = { 0, 0, 0, NULL }; brealloc(&tmp, ciphertext->len, capacity); buffer_t *plaintext = &tmp; plaintext->len = ciphertext->len - salt_len - tag_len; /* get salt */ uint8_t *salt = cipher_ctx.salt; memcpy(salt, ciphertext->data, salt_len); if (ppbloom_check((void *)salt, salt_len) == 1) { LOGE("crypto: AEAD: repeat salt detected"); return CRYPTO_ERROR; } aead_cipher_ctx_set_key(&cipher_ctx, 0); size_t plen = plaintext->len; err = aead_cipher_decrypt(&cipher_ctx, (uint8_t *)plaintext->data, &plen, (uint8_t *)ciphertext->data + salt_len, ciphertext->len - salt_len, NULL, 0, cipher_ctx.nonce, cipher_ctx.skey); aead_ctx_release(&cipher_ctx); if (err) return CRYPTO_ERROR; ppbloom_add((void *)salt, salt_len); bswap_data(ciphertext, plaintext); ciphertext->len = plaintext->len; return CRYPTO_OK; } static int aead_chunk_encrypt(cipher_ctx_t *ctx, uint8_t *p, uint8_t *c, uint8_t *n, uint16_t plen) { size_t nlen = ctx->cipher->nonce_len; size_t tlen = ctx->cipher->tag_len; assert(plen <= CHUNK_SIZE_MASK); int err; size_t clen; uint8_t len_buf[CHUNK_SIZE_LEN]; uint16_t t = htons(plen & CHUNK_SIZE_MASK); memcpy(len_buf, &t, CHUNK_SIZE_LEN); clen = CHUNK_SIZE_LEN + tlen; err = aead_cipher_encrypt(ctx, c, &clen, len_buf, CHUNK_SIZE_LEN, NULL, 0, n, ctx->skey); if (err) return CRYPTO_ERROR; assert(clen == CHUNK_SIZE_LEN + tlen); sodium_increment(n, nlen); clen = plen + tlen; err = aead_cipher_encrypt(ctx, c + CHUNK_SIZE_LEN + tlen, &clen, p, plen, NULL, 0, n, ctx->skey); if (err) return CRYPTO_ERROR; assert(clen == plen + tlen); sodium_increment(n, nlen); return CRYPTO_OK; } /* TCP */ int aead_encrypt(buffer_t *plaintext, cipher_ctx_t *cipher_ctx, size_t capacity) { if (cipher_ctx == NULL) return CRYPTO_ERROR; if (plaintext->len == 0) { return CRYPTO_OK; } static buffer_t tmp = { 0, 0, 0, NULL }; buffer_t *ciphertext; cipher_t *cipher = cipher_ctx->cipher; int err = CRYPTO_ERROR; size_t salt_ofst = 0; size_t salt_len = cipher->key_len; size_t tag_len = cipher->tag_len; if (!cipher_ctx->init) { salt_ofst = salt_len; } size_t out_len = salt_ofst + 2 * tag_len + plaintext->len + CHUNK_SIZE_LEN; brealloc(&tmp, out_len, capacity); ciphertext = &tmp; ciphertext->len = out_len; if (!cipher_ctx->init) { memcpy(ciphertext->data, cipher_ctx->salt, salt_len); aead_cipher_ctx_set_key(cipher_ctx, 1); cipher_ctx->init = 1; ppbloom_add((void *)cipher_ctx->salt, salt_len); } err = aead_chunk_encrypt(cipher_ctx, (uint8_t *)plaintext->data, (uint8_t *)ciphertext->data + salt_ofst, cipher_ctx->nonce, plaintext->len); if (err) return err; bswap_data(plaintext, ciphertext); plaintext->len = ciphertext->len; return 0; } static int aead_chunk_decrypt(cipher_ctx_t *ctx, uint8_t *p, uint8_t *c, uint8_t *n, size_t *plen, size_t *clen) { int err; size_t mlen; size_t nlen = ctx->cipher->nonce_len; size_t tlen = ctx->cipher->tag_len; if (*clen <= 2 * tlen + CHUNK_SIZE_LEN) return CRYPTO_NEED_MORE; uint8_t len_buf[2]; err = aead_cipher_decrypt(ctx, len_buf, plen, c, CHUNK_SIZE_LEN + tlen, NULL, 0, n, ctx->skey); if (err) return CRYPTO_ERROR; assert(*plen == CHUNK_SIZE_LEN); mlen = load16_be(len_buf); mlen = mlen & CHUNK_SIZE_MASK; if (mlen == 0) return CRYPTO_ERROR; size_t chunk_len = 2 * tlen + CHUNK_SIZE_LEN + mlen; if (*clen < chunk_len) return CRYPTO_NEED_MORE; sodium_increment(n, nlen); err = aead_cipher_decrypt(ctx, p, plen, c + CHUNK_SIZE_LEN + tlen, mlen + tlen, NULL, 0, n, ctx->skey); if (err) return CRYPTO_ERROR; assert(*plen == mlen); sodium_increment(n, nlen); *clen = *clen - chunk_len; return CRYPTO_OK; } int aead_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity) { int err = CRYPTO_OK; cipher_t *cipher = cipher_ctx->cipher; size_t salt_len = cipher->key_len; if (cipher_ctx->chunk == NULL) { cipher_ctx->chunk = (buffer_t *)ss_malloc(sizeof(buffer_t)); memset(cipher_ctx->chunk, 0, sizeof(buffer_t)); balloc(cipher_ctx->chunk, capacity); } buffer_t *chunk = cipher_ctx->chunk; if (chunk->len == 0) { bswap_data(chunk, ciphertext); chunk->len = ciphertext->len; chunk->idx = 0; ciphertext->len = 0; } else { if (chunk->idx > 0) { memmove(chunk->data, chunk->data + chunk->idx, chunk->len); chunk->idx = 0; } brealloc(chunk, chunk->len + ciphertext->len, capacity); memcpy(chunk->data + chunk->len, ciphertext->data, ciphertext->len); chunk->len += ciphertext->len; } // Write plaintext directly into the (now-free) ciphertext buffer. brealloc(ciphertext, chunk->len, capacity); if (!cipher_ctx->init) { if (chunk->len <= salt_len) return CRYPTO_NEED_MORE; memcpy(cipher_ctx->salt, chunk->data + chunk->idx, salt_len); if (ppbloom_check((void *)cipher_ctx->salt, salt_len) == 1) { LOGE("crypto: AEAD: repeat salt detected"); return CRYPTO_ERROR; } aead_cipher_ctx_set_key(cipher_ctx, 0); chunk->idx += salt_len; chunk->len -= salt_len; cipher_ctx->init = 1; } size_t plen = 0; size_t cidx = 0; while (chunk->len > 0) { size_t chunk_clen = chunk->len; size_t chunk_plen = 0; err = aead_chunk_decrypt(cipher_ctx, (uint8_t *)ciphertext->data + plen, (uint8_t *)chunk->data + chunk->idx + cidx, cipher_ctx->nonce, &chunk_plen, &chunk_clen); if (err == CRYPTO_ERROR) { return err; } else if (err == CRYPTO_NEED_MORE) { if (plen == 0) return err; else { chunk->idx += cidx; break; } } chunk->len = chunk_clen; cidx += cipher_ctx->cipher->tag_len * 2 + CHUNK_SIZE_LEN + chunk_plen; plen += chunk_plen; } if (chunk->len == 0) chunk->idx = 0; ciphertext->len = plen; // Add the salt to bloom filter if (cipher_ctx->init == 1) { if (ppbloom_check((void *)cipher_ctx->salt, salt_len) == 1) { LOGE("crypto: AEAD: repeat salt detected"); return CRYPTO_ERROR; } ppbloom_add((void *)cipher_ctx->salt, salt_len); cipher_ctx->init = 2; } return CRYPTO_OK; } cipher_t * aead_key_init(int method, const char *pass, const char *key) { if (method < AES128GCM || method >= AEAD_CIPHER_NUM) { LOGE("aead_key_init(): Illegal method"); return NULL; } cipher_t *cipher = (cipher_t *)ss_malloc(sizeof(cipher_t)); memset(cipher, 0, sizeof(cipher_t)); if (method < CHACHA20POLY1305IETF && aead_get_cipher_type(method) == NULL) { LOGE("Cipher %s not found in crypto library", supported_aead_ciphers[method]); FATAL("Cannot initialize cipher"); } if (key != NULL) cipher->key_len = crypto_parse_key(key, cipher->key, supported_aead_ciphers_key_size[method]); else cipher->key_len = crypto_derive_key(pass, cipher->key, supported_aead_ciphers_key_size[method]); if (cipher->key_len == 0) { FATAL("Cannot generate key and nonce"); } cipher->nonce_len = supported_aead_ciphers_nonce_size[method]; cipher->tag_len = supported_aead_ciphers_tag_size[method]; cipher->method = method; return cipher; } cipher_t * aead_init(const char *pass, const char *key, const char *method) { int m = AES128GCM; if (method != NULL) { /* check method validity */ for (m = AES128GCM; m < AEAD_CIPHER_NUM; m++) if (strcmp(method, supported_aead_ciphers[m]) == 0) { break; } if (m >= AEAD_CIPHER_NUM) { LOGE("Invalid cipher name: %s, use chacha20-ietf-poly1305 instead", method); m = CHACHA20POLY1305IETF; } } return aead_key_init(m, pass, key); } ================================================ FILE: src/aead.h ================================================ /* * aead.h - Define the AEAD interface * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _AEAD_H #define _AEAD_H #include "crypto.h" // currently, XCHACHA20POLY1305IETF is not released yet // XCHACHA20POLY1305 is removed in upstream #ifdef FS_HAVE_XCHACHA20IETF #define AEAD_CIPHER_NUM 5 #else #define AEAD_CIPHER_NUM 4 #endif int aead_encrypt_all(buffer_t *, cipher_t *, size_t); int aead_decrypt_all(buffer_t *, cipher_t *, size_t); int aead_encrypt(buffer_t *, cipher_ctx_t *, size_t); int aead_decrypt(buffer_t *, cipher_ctx_t *, size_t); void aead_ctx_init(cipher_t *, cipher_ctx_t *, int); void aead_ctx_release(cipher_ctx_t *); cipher_t *aead_init(const char *pass, const char *key, const char *method); #endif // _AEAD_H ================================================ FILE: src/android.c ================================================ /* * android.c - Setup IPC for shadowsocks-android * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "netutils.h" #include "utils.h" int protect_socket(int fd) { int sock; struct sockaddr_un addr; if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), sock); return -1; } // Set timeout to 3s struct timeval tv; tv.tv_sec = 3; tv.tv_usec = 0; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, "protect_path", sizeof(addr.sun_path) - 1); if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { LOGE("[android] connect() failed for protect_path: %s (socket fd = %d)\n", strerror(errno), sock); close(sock); return -1; } if (ancil_send_fd(sock, fd)) { ERROR("[android] ancil_send_fd"); close(sock); return -1; } char ret = 0; if (recv(sock, &ret, 1, 0) == -1) { ERROR("[android] recv"); close(sock); return -1; } close(sock); return ret; } extern char *stat_path; int send_traffic_stat(uint64_t tx, uint64_t rx) { if (!stat_path) return 0; int sock; struct sockaddr_un addr; if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), sock); return -1; } // Set timeout to 1s struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, stat_path, sizeof(addr.sun_path) - 1); if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { LOGE("[android] connect() failed for stat_path: %s (socket fd = %d)\n", strerror(errno), sock); close(sock); return -1; } uint64_t stat[2] = { tx, rx }; if (send(sock, stat, sizeof(stat), 0) == -1) { ERROR("[android] send"); close(sock); return -1; } close(sock); return 0; } ================================================ FILE: src/base64.c ================================================ /* * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * @brief Base64 encode/decode * @author Ryan Martell (with lots of Michael) */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "base64.h" /* ---------------- private code */ static const uint8_t map2[] = { 0xff, 0xff, 0x3e, 0xff, 0xff, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33 }; int base64_decode(uint8_t *out, const char *in, int out_size) { int i, v; uint8_t *dst = out; v = 0; for (i = 0; in[i] && in[i] != '='; i++) { unsigned int index = in[i] - 43; if (index >= sizeof(map2) || map2[index] == 0xff) return -1; v = (v << 6) + map2[index]; if (i & 3) { if (dst - out < out_size) { *dst++ = v >> (6 - 2 * (i & 3)); } } } return dst - out; } /***************************************************************************** * b64_encode: Stolen from VLC's http.c. * Simplified by Michael. * Fixed edge cases and made it work from data (vs. strings) by Ryan. *****************************************************************************/ char *base64_encode(char *out, int out_size, const uint8_t *in, int in_size) { static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; char *ret, *dst; unsigned i_bits = 0; int i_shift = 0; int bytes_remaining = in_size; if (in_size >= UINT_MAX / 4 || out_size < BASE64_SIZE(in_size)) return NULL; ret = dst = out; while (bytes_remaining) { i_bits = (i_bits << 8) + *in++; bytes_remaining--; i_shift += 8; do { *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; i_shift -= 6; } while (i_shift > 6 || (bytes_remaining == 0 && i_shift > 0)); } while ((dst - ret) & 3) *dst++ = '='; *dst = '\0'; return ret; } ================================================ FILE: src/base64.h ================================================ /* * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef BASE64_H #define BASE64_H #include /** * Decode a base64-encoded string. * * @param out buffer for decoded data * @param in null-terminated input string * @param out_size size in bytes of the out buffer, must be at * least 3/4 of the length of in * @return number of bytes written, or a negative value in case of * invalid input */ int base64_decode(uint8_t *out, const char *in, int out_size); /** * Encode data to base64 and null-terminate. * * @param out buffer for encoded data * @param out_size size in bytes of the output buffer, must be at * least BASE64_SIZE(in_size) * @param in_size size in bytes of the 'in' buffer * @return 'out' or NULL in case of error */ char *base64_encode(char *out, int out_size, const uint8_t *in, int in_size); /** * Calculate the output size needed to base64-encode x bytes. */ #define BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) #endif /* BASE64_H */ ================================================ FILE: src/cache.c ================================================ /* * cache.c - Manage the connection cache for UDPRELAY * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ /* * Original Author: Oliver Lorenz (ol), olli@olorenz.org, https://olorenz.org * License: This is licensed under the same terms as uthash itself */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "cache.h" #include "utils.h" /** Creates a new cache object * * @param dst * Where the newly allocated cache object will be stored in * * @param capacity * The maximum number of elements this cache object can hold * * @return EINVAL if dst is NULL, ENOMEM if malloc fails, 0 otherwise */ int cache_create(struct cache **dst, const size_t capacity, void (*free_cb)(void *key, void *element)) { struct cache *new = NULL; if (!dst) { return EINVAL; } if ((new = malloc(sizeof(*new))) == NULL) { return ENOMEM; } new->max_entries = capacity; new->entries = NULL; new->free_cb = free_cb; *dst = new; return 0; } /** Frees an allocated cache object * * @param cache * The cache object to free * * @param keep_data * Whether to free contained data or just delete references to it * * @return EINVAL if cache is NULL, 0 otherwise */ int cache_delete(struct cache *cache, int keep_data) { struct cache_entry *entry, *tmp; if (!cache) { return EINVAL; } if (keep_data) { HASH_CLEAR(hh, cache->entries); } else { HASH_ITER(hh, cache->entries, entry, tmp){ HASH_DEL(cache->entries, entry); if (entry->data != NULL) { if (cache->free_cb) { cache->free_cb(entry->key, entry->data); } else { ss_free(entry->data); } } ss_free(entry->key); ss_free(entry); } } ss_free(cache); return 0; } /** Clear old cache object * * @param cache * The cache object to clear * * @param age * Clear only objects older than the age (sec) * * @return EINVAL if cache is NULL, 0 otherwise */ int cache_clear(struct cache *cache, ev_tstamp age) { struct cache_entry *entry, *tmp; if (!cache) { return EINVAL; } ev_tstamp now = ev_time(); HASH_ITER(hh, cache->entries, entry, tmp){ if (now - entry->ts > age) { HASH_DEL(cache->entries, entry); if (entry->data != NULL) { if (cache->free_cb) { cache->free_cb(entry->key, entry->data); } else { ss_free(entry->data); } } ss_free(entry->key); ss_free(entry); } } return 0; } /** Removes a cache entry * * @param cache * The cache object * * @param key * The key of the entry to remove * * @param key_len * The length of key * * @return EINVAL if cache is NULL, 0 otherwise */ int cache_remove(struct cache *cache, char *key, size_t key_len) { struct cache_entry *tmp; if (!cache || !key) { return EINVAL; } HASH_FIND(hh, cache->entries, key, key_len, tmp); if (tmp) { HASH_DEL(cache->entries, tmp); if (tmp->data != NULL) { if (cache->free_cb) { cache->free_cb(tmp->key, tmp->data); } else { ss_free(tmp->data); } } ss_free(tmp->key); ss_free(tmp); } return 0; } /** Checks if a given key is in the cache * * @param cache * The cache object * * @param key * The key to look-up * * @param key_len * The length of key * * @param result * Where to store the result if key is found. * * A warning: Even though result is just a pointer, * you have to call this function with a **ptr, * otherwise this will blow up in your face. * * @return EINVAL if cache is NULL, 0 otherwise */ int cache_lookup(struct cache *cache, char *key, size_t key_len, void *result) { struct cache_entry *tmp = NULL; char **dirty_hack = result; if (!cache || !key || !result) { return EINVAL; } HASH_FIND(hh, cache->entries, key, key_len, tmp); if (tmp) { HASH_DELETE(hh, cache->entries, tmp); tmp->ts = ev_time(); HASH_ADD_KEYPTR(hh, cache->entries, tmp->key, key_len, tmp); *dirty_hack = tmp->data; } else { *dirty_hack = result = NULL; } return 0; } int cache_key_exist(struct cache *cache, char *key, size_t key_len) { struct cache_entry *tmp = NULL; if (!cache || !key) { return 0; } HASH_FIND(hh, cache->entries, key, key_len, tmp); if (tmp) { HASH_DELETE(hh, cache->entries, tmp); tmp->ts = ev_time(); HASH_ADD_KEYPTR(hh, cache->entries, tmp->key, key_len, tmp); return 1; } return 0; } /** Inserts a given pair into the cache * * @param cache * The cache object * * @param key * The key that identifies * * @param key_len * The length of key * * @param data * Data associated with * * @return EINVAL if cache is NULL, ENOMEM if malloc fails, 0 otherwise */ int cache_insert(struct cache *cache, char *key, size_t key_len, void *data) { struct cache_entry *entry = NULL; struct cache_entry *tmp_entry = NULL; if (!cache) { return EINVAL; } if ((entry = malloc(sizeof(*entry))) == NULL) { return ENOMEM; } entry->key = ss_malloc(key_len + 1); memcpy(entry->key, key, key_len); entry->key[key_len] = 0; entry->data = data; entry->ts = ev_time(); HASH_ADD_KEYPTR(hh, cache->entries, entry->key, key_len, entry); if (HASH_COUNT(cache->entries) >= cache->max_entries) { HASH_ITER(hh, cache->entries, entry, tmp_entry){ HASH_DELETE(hh, cache->entries, entry); if (entry->data != NULL) { if (cache->free_cb) { cache->free_cb(entry->key, entry->data); } else { ss_free(entry->data); } } ss_free(entry->key); ss_free(entry); break; } } return 0; } ================================================ FILE: src/cache.h ================================================ /* * cache.h - Define the cache manager interface * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ /* * Original Author: Oliver Lorenz (ol), olli@olorenz.org, https://olorenz.org * License: This is licensed under the same terms as uthash itself */ #ifndef _CACHE_ #define _CACHE_ #include "uthash.h" #ifdef HAVE_LIBEV_EV_H #include #else #include #endif /** * A cache entry */ struct cache_entry { char *key; /** * * This file is part of the shadowsocks-libev. * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _COMMON_H #define _COMMON_H #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif #if defined(MODULE_TUNNEL) || defined(MODULE_REDIR) #define MODULE_LOCAL #endif #include "crypto.h" int init_udprelay(const char *server_host, const char *server_port, #ifdef MODULE_LOCAL const struct sockaddr *remote_addr, const int remote_addr_len, #ifdef MODULE_TUNNEL const ss_addr_t tunnel_addr, #endif #endif int mtu, crypto_t *crypto, int timeout, const char *iface); void free_udprelay(void); #ifdef __ANDROID__ int protect_socket(int fd); int send_traffic_stat(uint64_t tx, uint64_t rx); #endif #define STAGE_ERROR -1 /* Error detected */ #define STAGE_INIT 0 /* Initial stage */ #define STAGE_HANDSHAKE 1 /* Handshake with client */ #define STAGE_RESOLVE 4 /* Resolve the hostname */ #define STAGE_STREAM 5 /* Stream between client and server */ #define STAGE_STOP 6 /* Server stop to response */ /* Vals for long options */ enum { GETOPT_VAL_HELP = 257, GETOPT_VAL_REUSE_PORT, GETOPT_VAL_FAST_OPEN, GETOPT_VAL_NODELAY, GETOPT_VAL_ACL, GETOPT_VAL_MTU, GETOPT_VAL_MPTCP, GETOPT_VAL_PLUGIN, GETOPT_VAL_PLUGIN_OPTS, GETOPT_VAL_PASSWORD, GETOPT_VAL_KEY, GETOPT_VAL_MANAGER_ADDRESS, GETOPT_VAL_EXECUTABLE, GETOPT_VAL_WORKDIR, GETOPT_VAL_TCP_INCOMING_SNDBUF, GETOPT_VAL_TCP_INCOMING_RCVBUF, GETOPT_VAL_TCP_OUTGOING_SNDBUF, GETOPT_VAL_TCP_OUTGOING_RCVBUF, GETOPT_VAL_NFTABLES_SETS }; #endif // _COMMON_H ================================================ FILE: src/crypto.c ================================================ /* * crypto.c - Manage the global crypto * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined(__linux__) && defined(HAVE_LINUX_RANDOM_H) #include #include #include #include #endif #include #include #include #include #include "base64.h" #include "crypto.h" #include "stream.h" #include "aead.h" #include "utils.h" #include "ppbloom.h" int balloc(buffer_t *ptr, size_t capacity) { sodium_memzero(ptr, sizeof(buffer_t)); ptr->data = ss_malloc(capacity); ptr->capacity = capacity; return capacity; } int brealloc(buffer_t *ptr, size_t len, size_t capacity) { if (ptr == NULL) return -1; size_t real_capacity = max(len, capacity); if (ptr->capacity < real_capacity) { ptr->data = ss_realloc(ptr->data, real_capacity); ptr->capacity = real_capacity; } return real_capacity; } void bfree(buffer_t *ptr) { if (ptr == NULL) return; ptr->idx = 0; ptr->len = 0; ptr->capacity = 0; if (ptr->data != NULL) { ss_free(ptr->data); } } int bprepend(buffer_t *dst, buffer_t *src, size_t capacity) { brealloc(dst, dst->len + src->len, capacity); memmove(dst->data + src->len, dst->data, dst->len); memcpy(dst->data, src->data, src->len); dst->len = dst->len + src->len; return dst->len; } int rand_bytes(void *output, int len) { randombytes_buf(output, len); // always return success return 0; } unsigned char * crypto_md5(const unsigned char *d, size_t n, unsigned char *md) { static unsigned char m[16]; if (md == NULL) { md = m; } #if MBEDTLS_VERSION_NUMBER < 0x03000000 && MBEDTLS_VERSION_NUMBER >= 0x02070000 if (mbedtls_md5_ret(d, n, md) != 0) FATAL("Failed to calculate MD5"); #else mbedtls_md5(d, n, md); #endif return md; } static void entropy_check(void) { #if defined(__linux__) && defined(HAVE_LINUX_RANDOM_H) && defined(RNDGETENTCNT) int fd; int c; if ((fd = open("/dev/random", O_RDONLY)) != -1) { if (ioctl(fd, RNDGETENTCNT, &c) == 0 && c < 160) { LOGI("This system doesn't provide enough entropy to quickly generate high-quality random numbers.\n" "Installing the rng-utils/rng-tools, jitterentropy or haveged packages may help.\n" "On virtualized Linux environments, also consider using virtio-rng.\n" "The service will not start until enough entropy has been collected.\n"); } close(fd); } #endif } crypto_t * crypto_init(const char *password, const char *key, const char *method) { int i, m = -1; entropy_check(); // Initialize sodium for random generator if (sodium_init() == -1) { FATAL("Failed to initialize sodium"); } // Initialize NONCE bloom filter #ifdef MODULE_REMOTE ppbloom_init(BF_NUM_ENTRIES_FOR_SERVER, BF_ERROR_RATE_FOR_SERVER); #else ppbloom_init(BF_NUM_ENTRIES_FOR_CLIENT, BF_ERROR_RATE_FOR_CLIENT); #endif if (method != NULL) { for (i = 0; i < STREAM_CIPHER_NUM; i++) if (strcmp(method, supported_stream_ciphers[i]) == 0) { m = i; break; } if (m != -1) { LOGI("Stream ciphers are insecure, therefore deprecated, and should be almost always avoided."); cipher_t *cipher = stream_init(password, key, method); if (cipher == NULL) return NULL; crypto_t *crypto = (crypto_t *)ss_malloc(sizeof(crypto_t)); crypto_t tmp = { .cipher = cipher, .encrypt_all = &stream_encrypt_all, .decrypt_all = &stream_decrypt_all, .encrypt = &stream_encrypt, .decrypt = &stream_decrypt, .ctx_init = &stream_ctx_init, .ctx_release = &stream_ctx_release, }; memcpy(crypto, &tmp, sizeof(crypto_t)); return crypto; } for (i = 0; i < AEAD_CIPHER_NUM; i++) if (strcmp(method, supported_aead_ciphers[i]) == 0) { m = i; break; } if (m != -1) { cipher_t *cipher = aead_init(password, key, method); if (cipher == NULL) return NULL; crypto_t *crypto = (crypto_t *)ss_malloc(sizeof(crypto_t)); crypto_t tmp = { .cipher = cipher, .encrypt_all = &aead_encrypt_all, .decrypt_all = &aead_decrypt_all, .encrypt = &aead_encrypt, .decrypt = &aead_decrypt, .ctx_init = &aead_ctx_init, .ctx_release = &aead_ctx_release, }; memcpy(crypto, &tmp, sizeof(crypto_t)); return crypto; } } LOGE("invalid cipher name: %s", method); return NULL; } int crypto_derive_key(const char *pass, uint8_t *key, size_t key_len) { size_t datal; datal = strlen((const char *)pass); const digest_type_t *md = mbedtls_md_info_from_string("MD5"); if (md == NULL) { FATAL("MD5 Digest not found in crypto library"); } mbedtls_md_context_t c; unsigned char md_buf[MAX_MD_SIZE]; int addmd; unsigned int i, j, mds; mds = mbedtls_md_get_size(md); memset(&c, 0, sizeof(mbedtls_md_context_t)); if (pass == NULL) return key_len; if (mbedtls_md_setup(&c, md, 0)) return 0; for (j = 0, addmd = 0; j < key_len; addmd++) { mbedtls_md_starts(&c); if (addmd) { mbedtls_md_update(&c, md_buf, mds); } mbedtls_md_update(&c, (uint8_t *)pass, datal); mbedtls_md_finish(&c, &(md_buf[0])); for (i = 0; i < mds; i++, j++) { if (j >= key_len) break; key[j] = md_buf[i]; } } mbedtls_md_free(&c); return key_len; } /* HKDF-Extract + HKDF-Expand */ int crypto_hkdf(const mbedtls_md_info_t *md, const unsigned char *salt, int salt_len, const unsigned char *ikm, int ikm_len, const unsigned char *info, int info_len, unsigned char *okm, int okm_len) { unsigned char prk[MBEDTLS_MD_MAX_SIZE]; return crypto_hkdf_extract(md, salt, salt_len, ikm, ikm_len, prk) || crypto_hkdf_expand(md, prk, mbedtls_md_get_size(md), info, info_len, okm, okm_len); } /* HKDF-Extract(salt, IKM) -> PRK */ int crypto_hkdf_extract(const mbedtls_md_info_t *md, const unsigned char *salt, int salt_len, const unsigned char *ikm, int ikm_len, unsigned char *prk) { int hash_len; unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' }; if (salt_len < 0) { return CRYPTO_ERROR; } hash_len = mbedtls_md_get_size(md); if (salt == NULL) { salt = null_salt; salt_len = hash_len; } return mbedtls_md_hmac(md, salt, salt_len, ikm, ikm_len, prk); } /* HKDF-Expand(PRK, info, L) -> OKM */ int crypto_hkdf_expand(const mbedtls_md_info_t *md, const unsigned char *prk, int prk_len, const unsigned char *info, int info_len, unsigned char *okm, int okm_len) { int hash_len; int N; int T_len = 0, where = 0, i, ret; mbedtls_md_context_t ctx; unsigned char T[MBEDTLS_MD_MAX_SIZE]; if (info_len < 0 || okm_len < 0 || okm == NULL) { return CRYPTO_ERROR; } hash_len = mbedtls_md_get_size(md); if (prk_len < hash_len) { return CRYPTO_ERROR; } if (info == NULL) { info = (const unsigned char *)""; } N = okm_len / hash_len; if ((okm_len % hash_len) != 0) { N++; } if (N > 255) { return CRYPTO_ERROR; } mbedtls_md_init(&ctx); if ((ret = mbedtls_md_setup(&ctx, md, 1)) != 0) { mbedtls_md_free(&ctx); return ret; } /* Section 2.3. */ for (i = 1; i <= N; i++) { unsigned char c = i; ret = mbedtls_md_hmac_starts(&ctx, prk, prk_len) || mbedtls_md_hmac_update(&ctx, T, T_len) || mbedtls_md_hmac_update(&ctx, info, info_len) || /* The constant concatenated to the end of each T(n) is a single * octet. */ mbedtls_md_hmac_update(&ctx, &c, 1) || mbedtls_md_hmac_finish(&ctx, T); if (ret != 0) { mbedtls_md_free(&ctx); return ret; } memcpy(okm + where, T, (i != N) ? hash_len : (okm_len - where)); where += hash_len; T_len = hash_len; } mbedtls_md_free(&ctx); return 0; } int crypto_parse_key(const char *base64, uint8_t *key, size_t key_len) { size_t base64_len = strlen(base64); int out_len = BASE64_SIZE(base64_len); uint8_t out[out_len]; out_len = base64_decode(out, base64, out_len); if (out_len > 0 && out_len >= key_len) { memcpy(key, out, key_len); #ifdef SS_DEBUG dump("KEY", (char *)key, key_len); #endif return key_len; } out_len = BASE64_SIZE(key_len); char out_key[out_len]; rand_bytes(key, key_len); base64_encode(out_key, out_len, key, key_len); LOGE("Invalid key for your chosen cipher!"); LOGE("It requires a " SIZE_FMT "-byte key encoded with URL-safe Base64", key_len); LOGE("Generating a new random key: %s", out_key); FATAL("Please use the key above or input a valid key"); return key_len; } #ifdef SS_DEBUG void dump(char *tag, char *text, int len) { int i; printf("%s: ", tag); for (i = 0; i < len; i++) printf("0x%02x ", (uint8_t)text[i]); printf("\n"); } #endif ================================================ FILE: src/crypto.h ================================================ /* * crypto.h - Define the enryptor's interface * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have recenonceed a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _CRYPTO_H #define _CRYPTO_H #ifndef __MINGW32__ #include #endif #include #include #include #ifdef HAVE_STDINT_H #include #elif HAVE_INTTYPES_H #include #endif /* Definitions for libsodium */ #include typedef crypto_aead_aes256gcm_state aes256gcm_ctx; /* Definitions for mbedTLS */ #include #include typedef mbedtls_cipher_info_t cipher_kt_t; typedef mbedtls_cipher_context_t cipher_evp_t; typedef mbedtls_md_info_t digest_type_t; #define MAX_KEY_LENGTH 64 #define MAX_NONCE_LENGTH 32 #define MAX_MD_SIZE MBEDTLS_MD_MAX_SIZE /* we must have MBEDTLS_CIPHER_MODE_CFB defined */ #if !defined(MBEDTLS_CIPHER_MODE_CFB) #error Cipher Feedback mode a.k.a CFB not supported by your mbed TLS. #endif #ifndef MBEDTLS_GCM_C #error No GCM support detected #endif #ifdef crypto_aead_xchacha20poly1305_ietf_ABYTES #define FS_HAVE_XCHACHA20IETF #endif #define ADDRTYPE_MASK 0xF #define CRYPTO_ERROR -2 #define CRYPTO_NEED_MORE -1 #define CRYPTO_OK 0 #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) #define SUBKEY_INFO "ss-subkey" #define IV_INFO "ss-iv" #ifndef BF_NUM_ENTRIES_FOR_SERVER #define BF_NUM_ENTRIES_FOR_SERVER 1e6 #endif #ifndef BF_NUM_ENTRIES_FOR_CLIENT #define BF_NUM_ENTRIES_FOR_CLIENT 1e4 #endif #ifndef BF_ERROR_RATE_FOR_SERVER #define BF_ERROR_RATE_FOR_SERVER 1e-10 #endif #ifndef BF_ERROR_RATE_FOR_CLIENT #define BF_ERROR_RATE_FOR_CLIENT 1e-15 #endif typedef struct buffer { size_t idx; size_t len; size_t capacity; char *data; } buffer_t; typedef struct { int method; int skey; size_t nonce_len; size_t key_len; size_t tag_len; uint8_t key[MAX_KEY_LENGTH]; } cipher_t; typedef struct { uint32_t init; uint64_t counter; cipher_evp_t *evp; aes256gcm_ctx *aes256gcm_ctx; cipher_t *cipher; buffer_t *chunk; uint8_t salt[MAX_KEY_LENGTH]; uint8_t skey[MAX_KEY_LENGTH]; uint8_t nonce[MAX_NONCE_LENGTH]; } cipher_ctx_t; typedef struct crypto { cipher_t *cipher; int(*const encrypt_all) (buffer_t *, cipher_t *, size_t); int(*const decrypt_all) (buffer_t *, cipher_t *, size_t); int(*const encrypt) (buffer_t *, cipher_ctx_t *, size_t); int(*const decrypt) (buffer_t *, cipher_ctx_t *, size_t); void(*const ctx_init) (cipher_t *, cipher_ctx_t *, int); void(*const ctx_release) (cipher_ctx_t *); } crypto_t; int balloc(buffer_t *, size_t); int brealloc(buffer_t *, size_t, size_t); int bprepend(buffer_t *, buffer_t *, size_t); void bfree(buffer_t *); static inline void bswap_data(buffer_t *a, buffer_t *b) { char *tmp_data = a->data; size_t tmp_capacity = a->capacity; a->data = b->data; a->capacity = b->capacity; b->data = tmp_data; b->capacity = tmp_capacity; } int rand_bytes(void *, int); crypto_t *crypto_init(const char *, const char *, const char *); unsigned char *crypto_md5(const unsigned char *, size_t, unsigned char *); int crypto_derive_key(const char *, uint8_t *, size_t); int crypto_parse_key(const char *, uint8_t *, size_t); int crypto_hkdf(const mbedtls_md_info_t *md, const unsigned char *salt, int salt_len, const unsigned char *ikm, int ikm_len, const unsigned char *info, int info_len, unsigned char *okm, int okm_len); int crypto_hkdf_extract(const mbedtls_md_info_t *md, const unsigned char *salt, int salt_len, const unsigned char *ikm, int ikm_len, unsigned char *prk); int crypto_hkdf_expand(const mbedtls_md_info_t *md, const unsigned char *prk, int prk_len, const unsigned char *info, int info_len, unsigned char *okm, int okm_len); #ifdef SS_DEBUG void dump(char *tag, char *text, int len); #endif extern struct cache *nonce_cache; extern const char *supported_stream_ciphers[]; extern const char *supported_aead_ciphers[]; #endif // _CRYPTO_H ================================================ FILE: src/jconf.c ================================================ /* * jconf.c - Parse the JSON format config file * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #include #include #include #include #include #include "netutils.h" #include "utils.h" #include "jconf.h" #include "json.h" #include "string.h" #include #define check_json_value_type(value, expected_type, message) \ do { \ if ((value)->type != (expected_type)) \ FATAL((message)); \ } while (0) static char * to_string(const json_value *value) { if (value->type == json_string) { return ss_strndup(value->u.string.ptr, value->u.string.length); } else if (value->type == json_integer) { return strdup(ss_itoa(value->u.integer)); } else if (value->type == json_null) { return NULL; } else { LOGE("%d", value->type); FATAL("Invalid config format."); } return 0; } void free_addr(ss_addr_t *addr) { ss_free(addr->host); ss_free(addr->port); } void parse_addr(const char *str_in, ss_addr_t *addr) { if (str_in == NULL) return; int ipv6 = 0, ret = -1, n = 0, len; char *pch; char *str = strdup(str_in); len = strlen(str_in); struct cork_ip ip; if (cork_ip_init(&ip, str) != -1) { addr->host = str; addr->port = NULL; return; } pch = strchr(str, ':'); while (pch != NULL) { n++; ret = pch - str; pch = strchr(pch + 1, ':'); } if (n > 1) { ipv6 = 1; if (str[ret - 1] != ']') { ret = -1; } } if (ret == -1) { if (ipv6) { addr->host = ss_strndup(str + 1, strlen(str) - 2); } else { addr->host = strdup(str); } addr->port = NULL; } else { if (ipv6) { addr->host = ss_strndup(str + 1, ret - 2); } else { addr->host = ss_strndup(str, ret); } if (ret < len - 1) { addr->port = strdup(str + ret + 1); } else { addr->port = NULL; } } free(str); } static int parse_dscp(char *str) { size_t str_len = strlen(str); // Pre-defined values (EF, CSx, AFxy) if (str_len == 2 && strcasecmp(str, "EF") == 0) { return DSCP_EF; } if (str_len == DSCP_CS_LEN && strncasecmp(str, "CS", 2) == 0) { if (str[2] >= '0' && str[2] <= '7') { // CSx = 8x return (str[2] - '0') << 3; } } if (str_len == DSCP_AF_LEN && strncasecmp(str, "AF", 2) == 0) { if (str[2] >= '1' && str[2] <= '4' && str[3] >= '1' && str[3] <= '3') { // AFxy = 8x + 2y return ((str[2] - '0') << 3) | ((str[3] - '0') << 1); } } // Manual hexadecimal mode (0xYZ) char *endptr; int dscp = (int)strtol(str, &endptr, 0); if (*endptr == '\0' && dscp >= DSCP_MIN && dscp <= DSCP_MAX) { return dscp; } LOGE("Invalid DSCP value (%s)", str); return DSCP_DEFAULT; } jconf_t * read_jconf(const char *file) { static jconf_t conf; memset(&conf, 0, sizeof(jconf_t)); char *buf; json_value *obj; FILE *f = fopen(file, "rb"); if (f == NULL) { FATAL("Invalid config path."); } fseek(f, 0, SEEK_END); long pos = ftell(f); fseek(f, 0, SEEK_SET); if (pos < 0) { FATAL("Invalid config path."); } if (pos >= MAX_CONF_SIZE) { FATAL("Too large config file."); } buf = ss_malloc(pos + 1); if (buf == NULL) { FATAL("No enough memory."); } int nread = fread(buf, pos, 1, f); if (!nread) { FATAL("Failed to read the config file."); } fclose(f); buf[pos] = '\0'; // end of string json_settings settings = { 0UL, 0, NULL, NULL, NULL }; char error_buf[512]; obj = json_parse_ex(&settings, buf, pos, error_buf); if (obj == NULL) { FATAL(error_buf); } if (obj->type == json_object) { unsigned int i, j; for (i = 0; i < obj->u.object.length; i++) { char *name = obj->u.object.values[i].name; json_value *value = obj->u.object.values[i].value; if (strcmp(name, "server") == 0) { if (value->type == json_array) { for (j = 0; j < value->u.array.length; j++) { if (j >= MAX_REMOTE_NUM) { break; } json_value *v = value->u.array.values[j]; char *addr_str = to_string(v); parse_addr(addr_str, conf.remote_addr + j); ss_free(addr_str); conf.remote_num = j + 1; } } else if (value->type == json_string) { char* tmp_str = to_string(value); parse_addr(tmp_str, conf.remote_addr); ss_free(tmp_str); conf.remote_num = 1; } } else if (strcmp(name, "port_password") == 0) { if (value->type == json_object) { for (j = 0; j < value->u.object.length; j++) { if (j >= MAX_PORT_NUM) { break; } json_value *v = value->u.object.values[j].value; if (v->type == json_string) { conf.port_password[j].port = ss_strndup(value->u.object.values[j].name, value->u.object.values[j].name_length); conf.port_password[j].password = to_string(v); conf.port_password_num = j + 1; } } } } else if (strcmp(name, "server_port") == 0) { conf.remote_port = to_string(value); } else if (strcmp(name, "local_address") == 0) { conf.local_addr = to_string(value); } else if (strcmp(name, "local_ipv4_address") == 0) { conf.local_addr_v4 = to_string(value); } else if (strcmp(name, "local_ipv6_address") == 0) { conf.local_addr_v6 = to_string(value); } else if (strcmp(name, "local_port") == 0) { conf.local_port = to_string(value); } else if (strcmp(name, "password") == 0) { conf.password = to_string(value); } else if (strcmp(name, "key") == 0) { conf.key = to_string(value); } else if (strcmp(name, "method") == 0) { conf.method = to_string(value); } else if (strcmp(name, "timeout") == 0) { conf.timeout = to_string(value); } else if (strcmp(name, "user") == 0) { conf.user = to_string(value); } else if (strcmp(name, "plugin") == 0) { conf.plugin = to_string(value); if (conf.plugin && strlen(conf.plugin) == 0) { ss_free(conf.plugin); conf.plugin = NULL; } } else if (strcmp(name, "plugin_opts") == 0) { conf.plugin_opts = to_string(value); } else if (strcmp(name, "fast_open") == 0) { check_json_value_type(value, json_boolean, "invalid config file: option 'fast_open' must be a boolean"); conf.fast_open = value->u.boolean; } else if (strcmp(name, "reuse_port") == 0) { check_json_value_type(value, json_boolean, "invalid config file: option 'reuse_port' must be a boolean"); conf.reuse_port = value->u.boolean; } else if (strcmp(name, "tcp_incoming_sndbuf") == 0) { check_json_value_type(value, json_integer, "invalid config file: option 'tcp_incoming_sndbuf' must be an integer"); conf.tcp_incoming_sndbuf = value->u.integer; } else if (strcmp(name, "tcp_incoming_rcvbuf") == 0) { check_json_value_type(value, json_integer, "invalid config file: option 'tcp_incoming_rcvbuf' must be an integer"); conf.tcp_incoming_rcvbuf = value->u.integer; } else if (strcmp(name, "tcp_outgoing_sndbuf") == 0) { check_json_value_type(value, json_integer, "invalid config file: option 'tcp_outgoing_sndbuf' must be an integer"); conf.tcp_outgoing_sndbuf = value->u.integer; } else if (strcmp(name, "tcp_outgoing_rcvbuf") == 0) { check_json_value_type(value, json_integer, "invalid config file: option 'tcp_outgoing_rcvbuf' must be an integer"); conf.tcp_outgoing_rcvbuf = value->u.integer; } else if (strcmp(name, "auth") == 0) { FATAL("One time auth has been deprecated. Try AEAD ciphers instead."); } else if (strcmp(name, "nofile") == 0) { check_json_value_type(value, json_integer, "invalid config file: option 'nofile' must be an integer"); conf.nofile = value->u.integer; } else if (strcmp(name, "nameserver") == 0) { conf.nameserver = to_string(value); } else if (strcmp(name, "dscp") == 0) { if (value->type == json_object) { for (j = 0; j < value->u.object.length; j++) { if (j >= MAX_DSCP_NUM) { break; } json_value *v = value->u.object.values[j].value; if (v->type == json_string) { int dscp = parse_dscp(to_string(v)); char *port = ss_strndup(value->u.object.values[j].name, value->u.object.values[j].name_length); conf.dscp[j].port = port; conf.dscp[j].dscp = dscp; conf.dscp_num = j + 1; } } } } else if (strcmp(name, "tunnel_address") == 0) { conf.tunnel_address = to_string(value); } else if (strcmp(name, "mode") == 0) { char *mode_str = to_string(value); if (mode_str == NULL) conf.mode = TCP_ONLY; else if (strcmp(mode_str, "tcp_only") == 0) conf.mode = TCP_ONLY; else if (strcmp(mode_str, "tcp_and_udp") == 0) conf.mode = TCP_AND_UDP; else if (strcmp(mode_str, "udp_only") == 0) conf.mode = UDP_ONLY; else LOGI("ignore unknown mode: %s, use tcp_only as fallback", mode_str); ss_free(mode_str); } else if (strcmp(name, "mtu") == 0) { check_json_value_type(value, json_integer, "invalid config file: option 'mtu' must be an integer"); conf.mtu = value->u.integer; } else if (strcmp(name, "mptcp") == 0) { check_json_value_type(value, json_boolean, "invalid config file: option 'mptcp' must be a boolean"); conf.mptcp = get_mptcp(value->u.boolean); } else if (strcmp(name, "ipv6_first") == 0) { check_json_value_type(value, json_boolean, "invalid config file: option 'ipv6_first' must be a boolean"); conf.ipv6_first = value->u.boolean; #ifdef HAS_SYSLOG } else if (strcmp(name, "use_syslog") == 0) { check_json_value_type(value, json_boolean, "invalid config file: option 'use_syslog' must be a boolean"); use_syslog = value->u.boolean; #endif } else if (strcmp(name, "no_delay") == 0) { check_json_value_type( value, json_boolean, "invalid config file: option 'no_delay' must be a boolean"); conf.no_delay = value->u.boolean; } else if (strcmp(name, "tcp_tproxy") == 0) { check_json_value_type( value, json_boolean, "invalid config file: option 'tcp_tproxy' must be a boolean"); conf.tcp_tproxy = value->u.boolean; } else if (strcmp(name, "workdir") == 0) { conf.workdir = to_string(value); } else if (strcmp(name, "acl") == 0) { conf.acl = to_string(value); } else if (strcmp(name, "manager_address") == 0) { conf.manager_address = to_string(value); } } } else { FATAL("Invalid config file"); } ss_free(buf); json_value_free(obj); return &conf; } ================================================ FILE: src/jconf.h ================================================ /* * jconf.h - Define the config data structure * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _JCONF_H #define _JCONF_H #define MAX_PORT_NUM 1024 #define MAX_REMOTE_NUM 10 #define MAX_DSCP_NUM 64 #define MAX_CONF_SIZE (128 * 1024) #define MAX_CONNECT_TIMEOUT 10 #define MIN_TCP_IDLE_TIMEOUT (24 * 3600) #define MIN_UDP_TIMEOUT 10 #define DSCP_EF 0x2E #define DSCP_MIN 0x0 #define DSCP_MAX 0x3F #define DSCP_DEFAULT 0x0 #define DSCP_MIN_LEN 2 #define DSCP_MAX_LEN 4 #define DSCP_CS_LEN 3 #define DSCP_AF_LEN 4 #define TCP_ONLY 0 #define TCP_AND_UDP 1 #define UDP_ONLY 3 typedef struct { char *port; char *password; } ss_port_password_t; typedef struct { char *port; int dscp; } ss_dscp_t; typedef struct { int remote_num; ss_addr_t remote_addr[MAX_REMOTE_NUM]; int port_password_num; ss_port_password_t port_password[MAX_PORT_NUM]; char *remote_port; char *local_addr; char *local_addr_v4; char *local_addr_v6; char *local_port; char *password; char *key; char *method; char *timeout; char *user; char *plugin; char *plugin_opts; int fast_open; int reuse_port; int tcp_incoming_sndbuf; int tcp_incoming_rcvbuf; int tcp_outgoing_sndbuf; int tcp_outgoing_rcvbuf; int nofile; char *nameserver; int dscp_num; ss_dscp_t dscp[MAX_DSCP_NUM]; char *tunnel_address; int mode; int mtu; int mptcp; int ipv6_first; int no_delay; int tcp_tproxy; char *workdir; char *acl; char *manager_address; } jconf_t; jconf_t *read_jconf(const char *file); void parse_addr(const char *str, ss_addr_t *addr); void free_addr(ss_addr_t *addr); #endif // _JCONF_H ================================================ FILE: src/json.c ================================================ /* vim: set et ts=3 sw=3 sts=3 ft=c: * * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. * https://github.com/udp/json-parser * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "json.h" #ifdef _MSC_VER #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #endif #ifdef __MINGW32__ #define CONV_PTR (uintptr_t) #else #define CONV_PTR (unsigned long) #endif const struct _json_value json_value_none; #include #include #include #include #include typedef unsigned int json_uchar; static unsigned char hex_value (json_char c) { if (isdigit(c)) return c - '0'; switch (c) { case 'a': case 'A': return 0x0A; case 'b': case 'B': return 0x0B; case 'c': case 'C': return 0x0C; case 'd': case 'D': return 0x0D; case 'e': case 'E': return 0x0E; case 'f': case 'F': return 0x0F; default: return 0xFF; } } typedef struct { unsigned long used_memory; unsigned int uint_max; unsigned long ulong_max; json_settings settings; int first_pass; const json_char * ptr; unsigned int cur_line, cur_col; } json_state; static void * default_alloc (size_t size, int zero, void * user_data) { return zero ? calloc (1, size) : malloc (size); } static void default_free (void * ptr, void * user_data) { free (ptr); } static void * json_alloc (json_state * state, unsigned long size, int zero) { if ((state->ulong_max - state->used_memory) < size) return 0; if (state->settings.max_memory && (state->used_memory += size) > state->settings.max_memory) { return 0; } return state->settings.mem_alloc (size, zero, state->settings.user_data); } static int new_value (json_state * state, json_value ** top, json_value ** root, json_value ** alloc, json_type type) { json_value * value; int values_size; if (!state->first_pass) { value = *top = *alloc; *alloc = (*alloc)->_reserved.next_alloc; if (!*root) *root = value; switch (value->type) { case json_array: if (value->u.array.length == 0) break; if (! (value->u.array.values = (json_value **) json_alloc (state, value->u.array.length * sizeof (json_value *), 0)) ) { return 0; } value->u.array.length = 0; break; case json_object: if (value->u.object.length == 0) break; values_size = sizeof (*value->u.object.values) * value->u.object.length; if (! (value->u.object.values = (json_object_entry *) json_alloc (state, values_size + (CONV_PTR value->u.object.values), 0)) ) { return 0; } value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size; value->u.object.length = 0; break; case json_string: if (! (value->u.string.ptr = (json_char *) json_alloc (state, (value->u.string.length + 1) * sizeof (json_char), 0)) ) { return 0; } value->u.string.length = 0; break; default: break; }; return 1; } if (! (value = (json_value *) json_alloc (state, sizeof (json_value) + state->settings.value_extra, 1))) { return 0; } if (!*root) *root = value; value->type = type; value->parent = *top; #ifdef JSON_TRACK_SOURCE value->line = state->cur_line; value->col = state->cur_col; #endif if (*alloc) (*alloc)->_reserved.next_alloc = value; *alloc = *top = value; return 1; } #define whitespace \ case '\n': ++ state.cur_line; state.cur_col = 0; \ case ' ': case '\t': case '\r' #define string_add(b) \ do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); #define line_and_col \ state.cur_line, state.cur_col static const long flag_next = 1 << 0, flag_reproc = 1 << 1, flag_need_comma = 1 << 2, flag_seek_value = 1 << 3, flag_escaped = 1 << 4, flag_string = 1 << 5, flag_need_colon = 1 << 6, flag_done = 1 << 7, flag_num_negative = 1 << 8, flag_num_zero = 1 << 9, flag_num_e = 1 << 10, flag_num_e_got_sign = 1 << 11, flag_num_e_negative = 1 << 12, flag_line_comment = 1 << 13, flag_block_comment = 1 << 14; json_value * json_parse_ex (json_settings * settings, const json_char * json, size_t length, char * error_buf) { json_char error [json_error_max]; const json_char * end; json_value * top, * root, * alloc = 0; json_state state = { 0 }; long flags; long num_digits = 0, num_e = 0; json_int_t num_fraction = 0; /* Skip UTF-8 BOM */ if (length >= 3 && ((unsigned char) json [0]) == 0xEF && ((unsigned char) json [1]) == 0xBB && ((unsigned char) json [2]) == 0xBF) { json += 3; length -= 3; } error[0] = '\0'; end = (json + length); memcpy (&state.settings, settings, sizeof (json_settings)); if (!state.settings.mem_alloc) state.settings.mem_alloc = default_alloc; if (!state.settings.mem_free) state.settings.mem_free = default_free; memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); state.uint_max -= 8; /* limit of how much can be added before next check */ state.ulong_max -= 8; for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass) { json_uchar uchar; unsigned char uc_b1, uc_b2, uc_b3, uc_b4; json_char * string = 0; unsigned int string_length = 0; top = root = 0; flags = flag_seek_value; state.cur_line = 1; for (state.ptr = json ;; ++ state.ptr) { json_char b = (state.ptr == end ? 0 : *state.ptr); if (flags & flag_string) { if (!b) { sprintf (error, "Unexpected EOF in string (at %d:%d)", line_and_col); goto e_failed; } if (string_length > state.uint_max) goto e_overflow; if (flags & flag_escaped) { flags &= ~ flag_escaped; switch (b) { case 'b': string_add ('\b'); break; case 'f': string_add ('\f'); break; case 'n': string_add ('\n'); break; case 'r': string_add ('\r'); break; case 't': string_add ('\t'); break; case 'u': if (end - state.ptr < 4 || (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) { sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); goto e_failed; } uc_b1 = (uc_b1 << 4) | uc_b2; uc_b2 = (uc_b3 << 4) | uc_b4; uchar = (uc_b1 << 8) | uc_b2; if ((uchar & 0xF800) == 0xD800) { json_uchar uchar2; if (end - state.ptr < 6 || (*++ state.ptr) != '\\' || (*++ state.ptr) != 'u' || (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) { sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); goto e_failed; } uc_b1 = (uc_b1 << 4) | uc_b2; uc_b2 = (uc_b3 << 4) | uc_b4; uchar2 = (uc_b1 << 8) | uc_b2; uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF); } if (sizeof (json_char) >= sizeof (json_uchar) || (uchar <= 0x7F)) { string_add ((json_char) uchar); break; } if (uchar <= 0x7FF) { if (state.first_pass) string_length += 2; else { string [string_length ++] = 0xC0 | (uchar >> 6); string [string_length ++] = 0x80 | (uchar & 0x3F); } break; } if (uchar <= 0xFFFF) { if (state.first_pass) string_length += 3; else { string [string_length ++] = 0xE0 | (uchar >> 12); string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); string [string_length ++] = 0x80 | (uchar & 0x3F); } break; } if (state.first_pass) string_length += 4; else { string [string_length ++] = 0xF0 | (uchar >> 18); string [string_length ++] = 0x80 | ((uchar >> 12) & 0x3F); string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); string [string_length ++] = 0x80 | (uchar & 0x3F); } break; default: string_add (b); }; continue; } if (b == '\\') { flags |= flag_escaped; continue; } if (b == '"') { if (!state.first_pass) string [string_length] = 0; flags &= ~ flag_string; string = 0; switch (top->type) { case json_string: top->u.string.length = string_length; flags |= flag_next; break; case json_object: if (state.first_pass) (*(json_char **) &top->u.object.values) += string_length + 1; else { top->u.object.values [top->u.object.length].name = (json_char *) top->_reserved.object_mem; top->u.object.values [top->u.object.length].name_length = string_length; (*(json_char **) &top->_reserved.object_mem) += string_length + 1; } flags |= flag_seek_value | flag_need_colon; continue; default: break; }; } else { string_add (b); continue; } } if (state.settings.settings & json_enable_comments) { if (flags & (flag_line_comment | flag_block_comment)) { if (flags & flag_line_comment) { if (b == '\r' || b == '\n' || !b) { flags &= ~ flag_line_comment; -- state.ptr; /* so null can be reproc'd */ } continue; } if (flags & flag_block_comment) { if (!b) { sprintf (error, "%d:%d: Unexpected EOF in block comment", line_and_col); goto e_failed; } if (b == '*' && state.ptr < (end - 1) && state.ptr [1] == '/') { flags &= ~ flag_block_comment; ++ state.ptr; /* skip closing sequence */ } continue; } } else if (b == '/') { if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object) { sprintf (error, "%d:%d: Comment not allowed here", line_and_col); goto e_failed; } if (++ state.ptr == end) { sprintf (error, "%d:%d: EOF unexpected", line_and_col); goto e_failed; } switch (b = *state.ptr) { case '/': flags |= flag_line_comment; continue; case '*': flags |= flag_block_comment; continue; default: sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", line_and_col, b); goto e_failed; }; } } if (flags & flag_done) { if (!b) break; switch (b) { whitespace: continue; default: sprintf (error, "%d:%d: Trailing garbage: `%c`", state.cur_line, state.cur_col, b); goto e_failed; }; } if (flags & flag_seek_value) { switch (b) { whitespace: continue; case ']': if (top && top->type == json_array) flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; else { sprintf (error, "%d:%d: Unexpected ]", line_and_col); goto e_failed; } break; default: if (flags & flag_need_comma) { if (b == ',') { flags &= ~ flag_need_comma; continue; } else { sprintf (error, "%d:%d: Expected , before %c", state.cur_line, state.cur_col, b); goto e_failed; } } if (flags & flag_need_colon) { if (b == ':') { flags &= ~ flag_need_colon; continue; } else { sprintf (error, "%d:%d: Expected : before %c", state.cur_line, state.cur_col, b); goto e_failed; } } flags &= ~ flag_seek_value; switch (b) { case '{': if (!new_value (&state, &top, &root, &alloc, json_object)) goto e_alloc_failure; continue; case '[': if (!new_value (&state, &top, &root, &alloc, json_array)) goto e_alloc_failure; flags |= flag_seek_value; continue; case '"': if (!new_value (&state, &top, &root, &alloc, json_string)) goto e_alloc_failure; flags |= flag_string; string = top->u.string.ptr; string_length = 0; continue; case 't': if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' || *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e') { goto e_unknown_value; } if (!new_value (&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; top->u.boolean = 1; flags |= flag_next; break; case 'f': if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' || *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' || *(++ state.ptr) != 'e') { goto e_unknown_value; } if (!new_value (&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; flags |= flag_next; break; case 'n': if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' || *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l') { goto e_unknown_value; } if (!new_value (&state, &top, &root, &alloc, json_null)) goto e_alloc_failure; flags |= flag_next; break; default: if (isdigit (b) || b == '-') { if (!new_value (&state, &top, &root, &alloc, json_integer)) goto e_alloc_failure; if (!state.first_pass) { while (isdigit (b) || b == '+' || b == '-' || b == 'e' || b == 'E' || b == '.') { if ( (++ state.ptr) == end) { b = 0; break; } b = *state.ptr; } flags |= flag_next | flag_reproc; break; } flags &= ~ (flag_num_negative | flag_num_e | flag_num_e_got_sign | flag_num_e_negative | flag_num_zero); num_digits = 0; num_fraction = 0; num_e = 0; if (b != '-') { flags |= flag_reproc; break; } flags |= flag_num_negative; continue; } else { sprintf (error, "%d:%d: Unexpected %c when seeking value", line_and_col, b); goto e_failed; } }; }; } else { switch (top->type) { case json_object: switch (b) { whitespace: continue; case '"': if (flags & flag_need_comma) { sprintf (error, "%d:%d: Expected , before \"", line_and_col); goto e_failed; } flags |= flag_string; string = (json_char *) top->_reserved.object_mem; string_length = 0; break; case '}': flags = (flags & ~ flag_need_comma) | flag_next; break; case ',': if (flags & flag_need_comma) { flags &= ~ flag_need_comma; break; } default: sprintf (error, "%d:%d: Unexpected `%c` in object", line_and_col, b); goto e_failed; }; break; case json_integer: case json_double: if (isdigit (b)) { ++ num_digits; if (top->type == json_integer || flags & flag_num_e) { if (! (flags & flag_num_e)) { if (flags & flag_num_zero) { sprintf (error, "%d:%d: Unexpected `0` before `%c`", line_and_col, b); goto e_failed; } if (num_digits == 1 && b == '0') flags |= flag_num_zero; } else { flags |= flag_num_e_got_sign; /* Overflow check for exponent */ if (num_e > (LONG_MAX / 10) || (num_e == (LONG_MAX / 10) && (b - '0') > (LONG_MAX % 10))) { sprintf(error, "%d:%d: Exponent too large (overflow)", line_and_col); goto e_failed; } num_e = (num_e * 10) + (b - '0'); continue; } /* Overflow check for integer */ long prev = top->u.integer; if ((prev > 0 && (prev > (LONG_MAX / 10) || (prev == (LONG_MAX / 10) && (b - '0') > (LONG_MAX % 10)))) || (prev < 0 && (prev < (LONG_MIN / 10) || (prev == (LONG_MIN / 10) && -(b - '0') < (LONG_MIN % 10))))) { sprintf(error, "%d:%d: Integer too large (overflow)", line_and_col); goto e_failed; } top->u.integer = (top->u.integer * 10) + (b - '0'); continue; } /* Overflow check for fraction */ if (num_fraction > (LONG_MAX / 10) || (num_fraction == (LONG_MAX / 10) && (b - '0') > (LONG_MAX % 10))) { sprintf(error, "%d:%d: Fraction too large (overflow)", line_and_col); goto e_failed; } num_fraction = (num_fraction * 10) + (b - '0'); continue; } if (b == '+' || b == '-') { if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign)) { flags |= flag_num_e_got_sign; if (b == '-') flags |= flag_num_e_negative; continue; } } else if (b == '.' && top->type == json_integer) { if (!num_digits) { sprintf (error, "%d:%d: Expected digit before `.`", line_and_col); goto e_failed; } top->type = json_double; top->u.dbl = (double) top->u.integer; num_digits = 0; continue; } if (! (flags & flag_num_e)) { if (top->type == json_double) { if (!num_digits) { sprintf (error, "%d:%d: Expected digit after `.`", line_and_col); goto e_failed; } top->u.dbl += ((double) num_fraction) / (pow (10.0, (double) num_digits)); } if (b == 'e' || b == 'E') { flags |= flag_num_e; if (top->type == json_integer) { top->type = json_double; top->u.dbl = (double) top->u.integer; } num_digits = 0; flags &= ~ flag_num_zero; continue; } } else { if (!num_digits) { sprintf (error, "%d:%d: Expected digit after `e`", line_and_col); goto e_failed; } top->u.dbl *= pow (10.0, (double) (flags & flag_num_e_negative ? - num_e : num_e)); } if (flags & flag_num_negative) { if (top->type == json_integer) top->u.integer = - top->u.integer; else top->u.dbl = - top->u.dbl; } flags |= flag_next | flag_reproc; break; default: break; }; } if (flags & flag_reproc) { flags &= ~ flag_reproc; -- state.ptr; } if (flags & flag_next) { flags = (flags & ~ flag_next) | flag_need_comma; if (!top->parent) { /* root value done */ flags |= flag_done; continue; } if (top->parent->type == json_array) flags |= flag_seek_value; if (!state.first_pass) { json_value * parent = top->parent; switch (parent->type) { case json_object: parent->u.object.values [parent->u.object.length].value = top; break; case json_array: parent->u.array.values [parent->u.array.length] = top; break; default: break; }; } if ( (++ top->parent->u.array.length) > state.uint_max) goto e_overflow; top = top->parent; continue; } } alloc = root; } return root; e_unknown_value: sprintf (error, "%d:%d: Unknown value", line_and_col); goto e_failed; e_alloc_failure: strcpy (error, "Memory allocation failure"); goto e_failed; e_overflow: sprintf (error, "%d:%d: Too long (caught overflow)", line_and_col); goto e_failed; e_failed: if (error_buf) { if (*error) strcpy (error_buf, error); else strcpy (error_buf, "Unknown error"); } if (state.first_pass) alloc = root; while (alloc) { top = alloc->_reserved.next_alloc; state.settings.mem_free (alloc, state.settings.user_data); alloc = top; } if (!state.first_pass) json_value_free_ex (&state.settings, root); return 0; } json_value * json_parse (const json_char * json, size_t length) { json_settings settings = { 0 }; return json_parse_ex (&settings, json, length, 0); } void json_value_free_ex (json_settings * settings, json_value * value) { json_value * cur_value; if (!value) return; value->parent = 0; while (value) { switch (value->type) { case json_array: if (!value->u.array.length) { settings->mem_free (value->u.array.values, settings->user_data); break; } value = value->u.array.values [-- value->u.array.length]; continue; case json_object: if (!value->u.object.length) { settings->mem_free (value->u.object.values, settings->user_data); break; } value = value->u.object.values [-- value->u.object.length].value; continue; case json_string: settings->mem_free (value->u.string.ptr, settings->user_data); break; default: break; }; cur_value = value; value = value->parent; settings->mem_free (cur_value, settings->user_data); } } void json_value_free (json_value * value) { json_settings settings = { 0 }; settings.mem_free = default_free; json_value_free_ex (&settings, value); } ================================================ FILE: src/json.h ================================================ /* vim: set et ts=3 sw=3 sts=3 ft=c: * * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. * https://github.com/udp/json-parser * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _JSON_H #define _JSON_H #ifndef json_char #define json_char char #endif #ifndef json_int_t #ifndef _MSC_VER #include #define json_int_t int64_t #else #define json_int_t __int64 #endif #endif #include #ifdef __cplusplus #include extern "C" { #endif typedef struct { unsigned long max_memory; int settings; /* Custom allocator support (leave null to use malloc/free) */ void * (* mem_alloc) (size_t, int zero, void * user_data); void (* mem_free) (void *, void * user_data); void * user_data; /* will be passed to mem_alloc and mem_free */ size_t value_extra; /* how much extra space to allocate for values? */ } json_settings; #define json_enable_comments 0x01 typedef enum { json_none, json_object, json_array, json_integer, json_double, json_string, json_boolean, json_null } json_type; extern const struct _json_value json_value_none; typedef struct _json_object_entry { json_char * name; unsigned int name_length; struct _json_value * value; } json_object_entry; typedef struct _json_value { struct _json_value * parent; json_type type; union { int boolean; json_int_t integer; double dbl; struct { unsigned int length; json_char * ptr; /* null terminated */ } string; struct { unsigned int length; json_object_entry * values; #if defined(__cplusplus) && __cplusplus >= 201103L decltype(values) begin () const { return values; } decltype(values) end () const { return values + length; } #endif } object; struct { unsigned int length; struct _json_value ** values; #if defined(__cplusplus) && __cplusplus >= 201103L decltype(values) begin () const { return values; } decltype(values) end () const { return values + length; } #endif } array; } u; union { struct _json_value * next_alloc; void * object_mem; } _reserved; #ifdef JSON_TRACK_SOURCE /* Location of the value in the source JSON */ unsigned int line, col; #endif /* Some C++ operator sugar */ #ifdef __cplusplus public: inline _json_value () { memset (this, 0, sizeof (_json_value)); } inline const struct _json_value &operator [] (int index) const { if (type != json_array || index < 0 || ((unsigned int) index) >= u.array.length) { return json_value_none; } return *u.array.values [index]; } inline const struct _json_value &operator [] (const char * index) const { if (type != json_object) return json_value_none; for (unsigned int i = 0; i < u.object.length; ++ i) if (!strcmp (u.object.values [i].name, index)) return *u.object.values [i].value; return json_value_none; } inline operator const char * () const { switch (type) { case json_string: return u.string.ptr; default: return ""; }; } inline operator json_int_t () const { switch (type) { case json_integer: return u.integer; case json_double: return (json_int_t) u.dbl; default: return 0; }; } inline operator bool () const { if (type != json_boolean) return false; return u.boolean != 0; } inline operator double () const { switch (type) { case json_integer: return (double) u.integer; case json_double: return u.dbl; default: return 0; }; } #endif } json_value; json_value * json_parse (const json_char * json, size_t length); #define json_error_max 128 json_value * json_parse_ex (json_settings * settings, const json_char * json, size_t length, char * error); void json_value_free (json_value *); /* Not usually necessary, unless you used a custom mem_alloc and now want to * use a custom mem_free. */ void json_value_free_ex (json_settings * settings, json_value *); #ifdef __cplusplus } /* extern "C" */ #endif #endif ================================================ FILE: src/local.c ================================================ /* * local.c - Setup a socks5 proxy through remote shadowsocks server * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #ifndef __MINGW32__ #include #include #include #include #endif #ifdef LIB_ONLY #include "shadowsocks.h" #endif #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) #include #include #define SET_INTERFACE #endif #include #include "netutils.h" #include "utils.h" #include "socks5.h" #include "acl.h" #include "plugin.h" #include "local.h" #include "winsock.h" #ifndef LIB_ONLY #ifdef __APPLE__ #include #if defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10 #include #define HAVE_LAUNCHD #endif #endif #endif #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif int verbose = 0; int reuse_port = 0; int tcp_incoming_sndbuf = 0; int tcp_incoming_rcvbuf = 0; int tcp_outgoing_sndbuf = 0; int tcp_outgoing_rcvbuf = 0; #ifdef __ANDROID__ int vpn = 0; uint64_t tx = 0; uint64_t rx = 0; ev_tstamp last = 0; char *stat_path = NULL; #endif static crypto_t *crypto; static int acl = 0; static int mode = TCP_ONLY; static int ipv6first = 0; int fast_open = 0; static int no_delay = 0; static int udp_fd = 0; static int ret_val = 0; static struct ev_signal sigint_watcher; static struct ev_signal sigterm_watcher; #ifndef __MINGW32__ static struct ev_signal sigchld_watcher; static struct ev_signal sigusr1_watcher; #else #ifndef LIB_ONLY static struct plugin_watcher_t { ev_io io; SOCKET fd; uint16_t port; int valid; } plugin_watcher; #endif #endif #ifdef HAVE_SETRLIMIT #ifndef LIB_ONLY static int nofile = 0; #endif #endif static void server_recv_cb(EV_P_ ev_io *w, int revents); static void server_send_cb(EV_P_ ev_io *w, int revents); static void remote_recv_cb(EV_P_ ev_io *w, int revents); static void remote_send_cb(EV_P_ ev_io *w, int revents); static void accept_cb(EV_P_ ev_io *w, int revents); static void signal_cb(EV_P_ ev_signal *w, int revents); #if defined(__MINGW32__) && !defined(LIB_ONLY) static void plugin_watcher_cb(EV_P_ ev_io *w, int revents); #endif static int create_and_bind(const char *addr, const char *port); #ifdef HAVE_LAUNCHD static int launch_or_create(const char *addr, const char *port); #endif static remote_t *create_remote(listen_ctx_t *listener, struct sockaddr *addr, int direct); static void free_remote(remote_t *remote); static void close_and_free_remote(EV_P_ remote_t *remote); static void free_server(server_t *server); static void close_and_free_server(EV_P_ server_t *server); static remote_t *new_remote(int fd, int timeout); static server_t *new_server(int fd); static struct cork_dllist connections; #ifndef __MINGW32__ int setnonblocking(int fd) { int flags; if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { flags = 0; } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } #endif int create_and_bind(const char *addr, const char *port) { struct addrinfo hints; struct addrinfo *result, *rp; int s, listen_sock = -1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */ result = NULL; s = getaddrinfo(addr, port, &hints, &result); if (s != 0) { LOGI("getaddrinfo: %s", gai_strerror(s)); return -1; } if (result == NULL) { LOGE("Could not bind"); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { listen_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (listen_sock == -1) { continue; } int opt = 1; setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(listen_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif if (reuse_port) { int err = set_reuseport(listen_sock); if (err == 0) { LOGI("tcp port reuse enabled"); } } s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ break; } else { ERROR("bind"); } close(listen_sock); listen_sock = -1; } freeaddrinfo(result); return listen_sock; } #ifdef HAVE_LAUNCHD int launch_or_create(const char *addr, const char *port) { int *fds; size_t cnt; int error = launch_activate_socket("Listeners", &fds, &cnt); if (error == 0) { if (cnt == 1) { return fds[0]; } else { FATAL("please don't specify multi entry"); } } else if (error == ESRCH || error == ENOENT) { /* ESRCH: The calling process is not managed by launchd(8). * ENOENT: The socket name specified does not exist * in the caller's launchd.plist(5). */ if (port == NULL) { usage(); exit(EXIT_FAILURE); } return create_and_bind(addr, port); } else { FATAL("launch_activate_socket() error"); } return -1; } #endif static void free_connections(struct ev_loop *loop) { struct cork_dllist_item *curr, *next; cork_dllist_foreach_void(&connections, curr, next) { server_t *server = cork_container_of(curr, server_t, entries); remote_t *remote = server->remote; close_and_free_server(loop, server); close_and_free_remote(loop, remote); } } static void delayed_connect_cb(EV_P_ ev_timer *watcher, int revents) { server_t *server = cork_container_of(watcher, server_t, delayed_connect_watcher); server_recv_cb(EV_A_ & server->recv_ctx->io, revents); } static int server_handshake_reply(EV_P_ ev_io *w, int udp_assc, struct socks5_response *response) { server_ctx_t *server_recv_ctx = (server_ctx_t *)w; server_t *server = server_recv_ctx->server; remote_t *remote = server->remote; if (server->stage != STAGE_HANDSHAKE) return 0; struct sockaddr_in sock_addr; if (udp_assc) { socklen_t addr_len = sizeof(sock_addr); if (getsockname(server->fd, (struct sockaddr *)&sock_addr, &addr_len) < 0) { LOGE("getsockname: %s", strerror(errno)); response->rep = SOCKS5_REP_CONN_REFUSED; send(server->fd, (char *)response, sizeof(struct socks5_response), 0); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return -1; } } else memset(&sock_addr, 0, sizeof(sock_addr)); buffer_t resp_to_send; buffer_t *resp_buf = &resp_to_send; balloc(resp_buf, SOCKET_BUF_SIZE); memcpy(resp_buf->data, response, sizeof(struct socks5_response)); memcpy(resp_buf->data + sizeof(struct socks5_response), &sock_addr.sin_addr, sizeof(sock_addr.sin_addr)); memcpy(resp_buf->data + sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr), &sock_addr.sin_port, sizeof(sock_addr.sin_port)); int reply_size = sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr) + sizeof(sock_addr.sin_port); int s = send(server->fd, resp_buf->data, reply_size, 0); bfree(resp_buf); if (s < reply_size) { LOGE("failed to send fake reply"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return -1; } if (udp_assc) { // Wait until client closes the connection return -1; } return 0; } static int server_handshake(EV_P_ ev_io *w, buffer_t *buf) { server_ctx_t *server_recv_ctx = (server_ctx_t *)w; server_t *server = server_recv_ctx->server; remote_t *remote = server->remote; struct socks5_request *request = (struct socks5_request *)buf->data; size_t request_len = sizeof(struct socks5_request); if (buf->len < request_len) { return -1; } struct socks5_response response; response.ver = SVERSION; response.rep = SOCKS5_REP_SUCCEEDED; response.rsv = 0; response.atyp = SOCKS5_ATYP_IPV4; if (request->cmd == SOCKS5_CMD_UDP_ASSOCIATE) { if (verbose) { LOGI("udp assc request accepted"); } return server_handshake_reply(EV_A_ w, 1, &response); } else if (request->cmd != SOCKS5_CMD_CONNECT) { LOGE("unsupported command: %d", request->cmd); response.rep = SOCKS5_REP_CMD_NOT_SUPPORTED; char *send_buf = (char *)&response; send(server->fd, send_buf, 4, 0); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return -1; } char host[MAX_HOSTNAME_LEN + 1], ip[INET6_ADDRSTRLEN], port[16]; buffer_t *abuf = server->abuf; abuf->idx = 0; abuf->len = 0; abuf->data[abuf->len++] = request->atyp; int atyp = request->atyp; // get remote addr and port if (atyp == SOCKS5_ATYP_IPV4) { size_t in_addr_len = sizeof(struct in_addr); if (buf->len < request_len + in_addr_len + 2) { return -1; } memcpy(abuf->data + abuf->len, buf->data + request_len, in_addr_len + 2); abuf->len += in_addr_len + 2; if (acl || verbose) { uint16_t p = load16_be(buf->data + request_len + in_addr_len); if (!inet_ntop(AF_INET, (const void *)(buf->data + request_len), ip, INET_ADDRSTRLEN)) { LOGI("inet_ntop(AF_INET): %s", strerror(errno)); ip[0] = '\0'; } sprintf(port, "%d", p); } } else if (atyp == SOCKS5_ATYP_DOMAIN) { uint8_t name_len = *(uint8_t *)(buf->data + request_len); if (buf->len < request_len + 1 + name_len + 2) { return -1; } abuf->data[abuf->len++] = name_len; memcpy(abuf->data + abuf->len, buf->data + request_len + 1, name_len + 2); abuf->len += name_len + 2; if (acl || verbose) { uint16_t p = load16_be(buf->data + request_len + 1 + name_len); memcpy(host, buf->data + request_len + 1, name_len); host[name_len] = '\0'; sprintf(port, "%d", p); } } else if (atyp == SOCKS5_ATYP_IPV6) { size_t in6_addr_len = sizeof(struct in6_addr); if (buf->len < request_len + in6_addr_len + 2) { return -1; } memcpy(abuf->data + abuf->len, buf->data + request_len, in6_addr_len + 2); abuf->len += in6_addr_len + 2; if (acl || verbose) { uint16_t p = load16_be(buf->data + request_len + in6_addr_len); if (!inet_ntop(AF_INET6, (const void *)(buf->data + request_len), ip, INET6_ADDRSTRLEN)) { LOGI("inet_ntop(AF_INET6): %s", strerror(errno)); ip[0] = '\0'; } sprintf(port, "%d", p); } } else { LOGE("unsupported addrtype: %d", request->atyp); response.rep = SOCKS5_REP_ADDRTYPE_NOT_SUPPORTED; char *send_buf = (char *)&response; send(server->fd, send_buf, 4, 0); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return -1; } if (server_handshake_reply(EV_A_ w, 0, &response) < 0) return -1; server->stage = STAGE_STREAM; buf->len -= (3 + abuf->len); if (buf->len > 0) { memmove(buf->data, buf->data + 3 + abuf->len, buf->len); } if (verbose) { if (atyp == SOCKS5_ATYP_DOMAIN) LOGI("connect to %s:%s", host, port); else if (atyp == SOCKS5_ATYP_IPV4) LOGI("connect to %s:%s", ip, port); else if (atyp == SOCKS5_ATYP_IPV6) LOGI("connect to [%s]:%s", ip, port); } if (acl #ifdef __ANDROID__ && !(vpn && strcmp(port, "53") == 0) #endif ) { int bypass = 0; int resolved = 0; struct sockaddr_storage storage; memset(&storage, 0, sizeof(struct sockaddr_storage)); int err; int host_match = 0; if (atyp == SOCKS5_ATYP_DOMAIN) host_match = acl_match_host(host); if (host_match > 0) bypass = 1; // bypass hostnames in black list else if (host_match < 0) bypass = 0; // proxy hostnames in white list else { if (atyp == SOCKS5_ATYP_DOMAIN #ifdef __ANDROID__ && !vpn #endif ) { // resolve domain so we can bypass domain with geoip if (get_sockaddr(host, port, &storage, 0, ipv6first)) goto not_bypass; resolved = 1; switch (((struct sockaddr *)&storage)->sa_family) { case AF_INET: { struct sockaddr_in *addr_in = (struct sockaddr_in *)&storage; if (!inet_ntop(AF_INET, &(addr_in->sin_addr), ip, INET_ADDRSTRLEN)) goto not_bypass; break; } case AF_INET6: { struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&storage; if (!inet_ntop(AF_INET6, &(addr_in6->sin6_addr), ip, INET6_ADDRSTRLEN)) goto not_bypass; break; } default: goto not_bypass; } } int ip_match = (resolved || atyp == SOCKS5_ATYP_IPV4 || atyp == SOCKS5_ATYP_IPV6) ? acl_match_host(ip) : 0; switch (get_acl_mode()) { case BLACK_LIST: if (ip_match > 0) bypass = 1; // bypass IPs in black list break; case WHITE_LIST: bypass = 1; if (ip_match < 0) bypass = 0; // proxy IPs in white list break; } } if (bypass) { if (verbose) { if (atyp == SOCKS5_ATYP_DOMAIN) LOGI("bypass %s:%s", host, port); else if (atyp == 1) LOGI("bypass %s:%s", ip, port); else if (atyp == 4) LOGI("bypass [%s]:%s", ip, port); } if (atyp == SOCKS5_ATYP_DOMAIN && !resolved) #ifdef __ANDROID__ if (vpn) goto not_bypass; else #endif err = get_sockaddr(host, port, &storage, 0, ipv6first); else err = get_sockaddr(ip, port, &storage, 0, ipv6first); if (err != -1) { remote = create_remote(server->listener, (struct sockaddr *)&storage, 1); } } } not_bypass: // Not bypass if (remote == NULL) { remote = create_remote(server->listener, NULL, 0); } if (remote == NULL) { LOGE("invalid remote addr"); close_and_free_server(EV_A_ server); return -1; } if (!remote->direct) { int err = crypto->encrypt(abuf, server->e_ctx, SOCKET_BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return -1; } } if (buf->len > 0) { memcpy(remote->buf->data, buf->data, buf->len); remote->buf->len = buf->len; } server->remote = remote; remote->server = server; if (buf->len > 0) { return 0; } else { ev_timer_start(EV_A_ & server->delayed_connect_watcher); } return -1; } static void server_stream(EV_P_ ev_io *w, buffer_t *buf) { server_ctx_t *server_recv_ctx = (server_ctx_t *)w; server_t *server = server_recv_ctx->server; remote_t *remote = server->remote; if (remote == NULL) { LOGE("invalid remote"); close_and_free_server(EV_A_ server); return; } // insert shadowsocks header if (!remote->direct) { #ifdef __ANDROID__ tx += remote->buf->len; #endif int err = crypto->encrypt(remote->buf, server->e_ctx, SOCKET_BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } if (server->abuf) { bprepend(remote->buf, server->abuf, SOCKET_BUF_SIZE); bfree(server->abuf); ss_free(server->abuf); server->abuf = NULL; } } if (!remote->send_ctx->connected) { #ifdef __ANDROID__ if (vpn) { int not_protect = 0; if (remote->addr.ss_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)&remote->addr; if (s->sin_addr.s_addr == inet_addr("127.0.0.1")) not_protect = 1; } if (!not_protect) { if (protect_socket(remote->fd) == -1) { ERROR("protect_socket"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } } #endif remote->buf->idx = 0; if (!fast_open || remote->direct) { // connecting, wait until connected int r = connect(remote->fd, (struct sockaddr *)&(remote->addr), remote->addr_len); if (r == -1 && errno != CONNECT_IN_PROGRESS) { ERROR("connect"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } // wait on remote connected event ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); } else { #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) int s = -1; s = sendto(remote->fd, remote->buf->data, remote->buf->len, MSG_FASTOPEN, (struct sockaddr *)&(remote->addr), remote->addr_len); #elif defined(TCP_FASTOPEN_WINSOCK) DWORD s = -1; DWORD err = 0; do { int optval = 1; // Set fast open option if (setsockopt(remote->fd, IPPROTO_TCP, TCP_FASTOPEN, &optval, sizeof(optval)) != 0) { ERROR("setsockopt"); break; } // Load ConnectEx function LPFN_CONNECTEX ConnectEx = winsock_getconnectex(); if (ConnectEx == NULL) { LOGE("Cannot load ConnectEx() function"); err = WSAENOPROTOOPT; break; } // ConnectEx requires a bound socket if (winsock_dummybind(remote->fd, (struct sockaddr *)&(remote->addr)) != 0) { ERROR("bind"); break; } // Call ConnectEx to send data memset(&remote->olap, 0, sizeof(remote->olap)); remote->connect_ex_done = 0; if (ConnectEx(remote->fd, (const struct sockaddr *)&(remote->addr), remote->addr_len, remote->buf->data, remote->buf->len, &s, &remote->olap)) { remote->connect_ex_done = 1; break; } // XXX: ConnectEx pending, check later in remote_send if (WSAGetLastError() == ERROR_IO_PENDING) { err = CONNECT_IN_PROGRESS; break; } ERROR("ConnectEx"); } while (0); // Set error number if (err) { SetLastError(err); } #else int s = -1; #if defined(CONNECT_DATA_IDEMPOTENT) ((struct sockaddr_in *)&(remote->addr))->sin_len = sizeof(struct sockaddr_in); sa_endpoints_t endpoints; memset((char *)&endpoints, 0, sizeof(endpoints)); endpoints.sae_dstaddr = (struct sockaddr *)&(remote->addr); endpoints.sae_dstaddrlen = remote->addr_len; s = connectx(remote->fd, &endpoints, SAE_ASSOCID_ANY, CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, NULL, 0, NULL, NULL); #elif defined(TCP_FASTOPEN_CONNECT) int optval = 1; if (setsockopt(remote->fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&optval, sizeof(optval)) < 0) FATAL("failed to set TCP_FASTOPEN_CONNECT"); s = connect(remote->fd, (struct sockaddr *)&(remote->addr), remote->addr_len); #else FATAL("fast open is not enabled in this build"); #endif if (s == 0) s = send(remote->fd, remote->buf->data, remote->buf->len, 0); #endif if (s == -1) { if (errno == CONNECT_IN_PROGRESS) { // in progress, wait until connected remote->buf->idx = 0; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { if (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT || errno == ENOPROTOOPT) { LOGE("fast open is not supported on this platform"); // just turn it off fast_open = 0; } else { ERROR("fast_open_connect"); } close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else { remote->buf->len -= s; remote->buf->idx = s; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); return; } } } else { int s = send(remote->fd, remote->buf->data, remote->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send remote->buf->idx = 0; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { ERROR("server_recv_cb_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < (int)(remote->buf->len)) { remote->buf->len -= s; remote->buf->idx = s; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { remote->buf->idx = 0; remote->buf->len = 0; } } } static void server_recv_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_recv_ctx = (server_ctx_t *)w; server_t *server = server_recv_ctx->server; remote_t *remote = server->remote; buffer_t *buf; ssize_t r; ev_timer_stop(EV_A_ & server->delayed_connect_watcher); if (remote == NULL) { buf = server->buf; } else { buf = remote->buf; } if (revents != EV_TIMER) { r = recv(server->fd, buf->data + buf->len, SOCKET_BUF_SIZE - buf->len, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { if (verbose) ERROR("server_recv_cb_recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } buf->len += r; } while (1) { // local socks5 server if (server->stage == STAGE_STREAM) { server_stream(EV_A_ w, buf); // all processed return; } else if (server->stage == STAGE_INIT) { if (verbose) { struct sockaddr_in peer_addr; socklen_t peer_addr_len = sizeof peer_addr; if (getpeername(server->fd, (struct sockaddr *)&peer_addr, &peer_addr_len) == 0) { LOGI("connection from %s:%hu", inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port)); } } if (buf->len < 1) return; if (buf->data[0] != SVERSION) { close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } if (buf->len < sizeof(struct method_select_request)) { return; } struct method_select_request *method = (struct method_select_request *)buf->data; int method_len = method->nmethods + sizeof(struct method_select_request); if (buf->len < method_len) { return; } struct method_select_response response; response.ver = SVERSION; response.method = METHOD_UNACCEPTABLE; for (int i = 0; i < method->nmethods; i++) if (method->methods[i] == METHOD_NOAUTH) { response.method = METHOD_NOAUTH; break; } char *send_buf = (char *)&response; send(server->fd, send_buf, sizeof(response), 0); if (response.method == METHOD_UNACCEPTABLE) { close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } server->stage = STAGE_HANDSHAKE; if (method_len < (int)(buf->len)) { memmove(buf->data, buf->data + method_len, buf->len - method_len); buf->len -= method_len; continue; } buf->len = 0; return; } else if (server->stage == STAGE_HANDSHAKE) { int ret = server_handshake(EV_A_ w, buf); if (ret) return; } } } static void server_send_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_send_ctx = (server_ctx_t *)w; server_t *server = server_send_ctx->server; remote_t *remote = server->remote; if (server->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(server->fd, server->buf->data + server->buf->idx, server->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("server_send_cb_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < (ssize_t)(server->buf->len)) { // partly sent, move memory, wait for the next time to send server->buf->len -= s; server->buf->idx += s; return; } else { // all sent out, wait for reading server->buf->len = 0; server->buf->idx = 0; ev_io_stop(EV_A_ & server_send_ctx->io); ev_io_start(EV_A_ & remote->recv_ctx->io); return; } } } #ifdef __ANDROID__ void stat_update_cb() { ev_tstamp now = ev_time(); if (now - last > 0.5) { send_traffic_stat(tx, rx); last = now; } } #endif static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) { remote_ctx_t *remote_ctx = cork_container_of(watcher, remote_ctx_t, watcher); remote_t *remote = remote_ctx->remote; server_t *server = remote->server; if (verbose) { LOGI("TCP connection timeout"); } close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } static void remote_recv_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w; remote_t *remote = remote_recv_ctx->remote; server_t *server = remote->server; ssize_t r = recv(remote->fd, server->buf->data, SOCKET_BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("remote_recv_cb_recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } server->buf->len = r; if (!remote->direct) { #ifdef __ANDROID__ rx += server->buf->len; stat_update_cb(); #endif int err = crypto->decrypt(server->buf, server->d_ctx, SOCKET_BUF_SIZE); if (err == CRYPTO_ERROR) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (err == CRYPTO_NEED_MORE) { return; // Wait for more } } int s = send(server->fd, server->buf->data, server->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send server->buf->idx = 0; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); } else { ERROR("remote_recv_cb_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < (int)(server->buf->len)) { server->buf->len -= s; server->buf->idx = s; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); } // Disable TCP_NODELAY after the first response are sent if (!remote->recv_ctx->connected && !no_delay) { int opt = 0; setsockopt(server->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); setsockopt(remote->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); } remote->recv_ctx->connected = 1; } static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; if (!remote_send_ctx->connected) { #ifdef TCP_FASTOPEN_WINSOCK if (fast_open) { // Check if ConnectEx is done if (!remote->connect_ex_done) { DWORD numBytes; DWORD flags; // Non-blocking way to fetch ConnectEx result if (WSAGetOverlappedResult(remote->fd, &remote->olap, &numBytes, FALSE, &flags)) { remote->buf->len -= numBytes; remote->buf->idx = numBytes; remote->connect_ex_done = 1; } else if (WSAGetLastError() == WSA_IO_INCOMPLETE) { // XXX: ConnectEx still not connected, wait for next time return; } else { ERROR("WSAGetOverlappedResult"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } // Make getpeername work if (setsockopt(remote->fd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) != 0) { ERROR("setsockopt"); } } #endif struct sockaddr_storage addr; socklen_t len = sizeof addr; int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { remote_send_ctx->connected = 1; ev_timer_stop(EV_A_ & remote_send_ctx->watcher); ev_io_start(EV_A_ & remote->recv_ctx->io); // no need to send any data if (remote->buf->len == 0) { ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); return; } } else { // not connected ERROR("getpeername"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("remote_send_cb_send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < (ssize_t)(remote->buf->len)) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } } static remote_t * new_remote(int fd, int timeout) { remote_t *remote; remote = ss_malloc(sizeof(remote_t)); memset(remote, 0, sizeof(remote_t)); remote->buf = ss_malloc(sizeof(buffer_t)); remote->recv_ctx = ss_malloc(sizeof(remote_ctx_t)); remote->send_ctx = ss_malloc(sizeof(remote_ctx_t)); balloc(remote->buf, SOCKET_BUF_SIZE); memset(remote->recv_ctx, 0, sizeof(remote_ctx_t)); memset(remote->send_ctx, 0, sizeof(remote_ctx_t)); remote->recv_ctx->connected = 0; remote->send_ctx->connected = 0; remote->fd = fd; remote->recv_ctx->remote = remote; remote->send_ctx->remote = remote; ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ); ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE); ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb, min(MAX_CONNECT_TIMEOUT, timeout), 0); return remote; } static void free_remote(remote_t *remote) { if (remote->server != NULL) { remote->server->remote = NULL; } if (remote->buf != NULL) { bfree(remote->buf); ss_free(remote->buf); } ss_free(remote->recv_ctx); ss_free(remote->send_ctx); ss_free(remote); } static void close_and_free_remote(EV_P_ remote_t *remote) { if (remote != NULL) { ev_timer_stop(EV_A_ & remote->send_ctx->watcher); ev_io_stop(EV_A_ & remote->send_ctx->io); ev_io_stop(EV_A_ & remote->recv_ctx->io); close(remote->fd); free_remote(remote); } } static server_t * new_server(int fd) { server_t *server; server = ss_malloc(sizeof(server_t)); memset(server, 0, sizeof(server_t)); server->recv_ctx = ss_malloc(sizeof(server_ctx_t)); server->send_ctx = ss_malloc(sizeof(server_ctx_t)); server->buf = ss_malloc(sizeof(buffer_t)); server->abuf = ss_malloc(sizeof(buffer_t)); balloc(server->buf, SOCKET_BUF_SIZE); balloc(server->abuf, SOCKET_BUF_SIZE); memset(server->recv_ctx, 0, sizeof(server_ctx_t)); memset(server->send_ctx, 0, sizeof(server_ctx_t)); server->stage = STAGE_INIT; server->recv_ctx->connected = 0; server->send_ctx->connected = 0; server->fd = fd; server->recv_ctx->server = server; server->send_ctx->server = server; server->e_ctx = ss_malloc(sizeof(cipher_ctx_t)); server->d_ctx = ss_malloc(sizeof(cipher_ctx_t)); crypto->ctx_init(crypto->cipher, server->e_ctx, 1); crypto->ctx_init(crypto->cipher, server->d_ctx, 0); ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ); ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE); ev_timer_init(&server->delayed_connect_watcher, delayed_connect_cb, 0.05, 0); cork_dllist_add(&connections, &server->entries); return server; } static void free_server(server_t *server) { cork_dllist_remove(&server->entries); if (server->remote != NULL) { server->remote->server = NULL; } if (server->e_ctx != NULL) { crypto->ctx_release(server->e_ctx); ss_free(server->e_ctx); } if (server->d_ctx != NULL) { crypto->ctx_release(server->d_ctx); ss_free(server->d_ctx); } if (server->buf != NULL) { bfree(server->buf); ss_free(server->buf); } if (server->abuf != NULL) { bfree(server->abuf); ss_free(server->abuf); } ss_free(server->recv_ctx); ss_free(server->send_ctx); ss_free(server); } static void close_and_free_server(EV_P_ server_t *server) { if (server != NULL) { ev_io_stop(EV_A_ & server->send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); ev_timer_stop(EV_A_ & server->delayed_connect_watcher); close(server->fd); free_server(server); } } static remote_t * create_remote(listen_ctx_t *listener, struct sockaddr *addr, int direct) { struct sockaddr *remote_addr; int index = rand() % listener->remote_num; if (addr == NULL) { remote_addr = listener->remote_addr[index]; } else { remote_addr = addr; } int protocol = IPPROTO_TCP; if (listener->mptcp < 0) { protocol = IPPROTO_MPTCP; // Enable upstream MPTCP } int remotefd = socket(remote_addr->sa_family, SOCK_STREAM, protocol); if (remotefd == -1) { ERROR("socket"); return NULL; } int opt = 1; setsockopt(remotefd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif // Enable out-of-tree MPTCP if (listener->mptcp > 1) { int err = setsockopt(remotefd, SOL_TCP, listener->mptcp, &opt, sizeof(opt)); if (err == -1) { ERROR("failed to enable out-of-tree multipath TCP"); } } else if (listener->mptcp == 1) { int i = 0; while ((listener->mptcp = mptcp_enabled_values[i]) > 0) { int err = setsockopt(remotefd, SOL_TCP, listener->mptcp, &opt, sizeof(opt)); if (err != -1) { break; } i++; } if (listener->mptcp == 0) { ERROR("failed to enable out-of-tree multipath TCP"); } } if (tcp_outgoing_sndbuf > 0) { setsockopt(remotefd, SOL_SOCKET, SO_SNDBUF, &tcp_outgoing_sndbuf, sizeof(int)); } if (tcp_outgoing_rcvbuf > 0) { setsockopt(remotefd, SOL_SOCKET, SO_RCVBUF, &tcp_outgoing_rcvbuf, sizeof(int)); } // Setup setnonblocking(remotefd); #ifdef SET_INTERFACE if (listener->iface) { if (setinterface(remotefd, listener->iface) == -1) ERROR("setinterface"); } #endif remote_t *remote = new_remote(remotefd, direct ? MAX_CONNECT_TIMEOUT : listener->timeout); remote->addr_len = get_sockaddr_len(remote_addr); memcpy(&(remote->addr), remote_addr, remote->addr_len); remote->direct = direct; if (verbose) { struct sockaddr_in *sockaddr = (struct sockaddr_in *)&remote->addr; LOGI("remote: %s:%hu", inet_ntoa(sockaddr->sin_addr), ntohs(sockaddr->sin_port)); } return remote; } static void signal_cb(EV_P_ ev_signal *w, int revents) { if (revents & EV_SIGNAL) { switch (w->signum) { #ifndef __MINGW32__ case SIGCHLD: if (!is_plugin_running()) { LOGE("plugin service exit unexpectedly"); ret_val = -1; } else return; case SIGUSR1: #endif case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); #ifndef __MINGW32__ ev_signal_stop(EV_DEFAULT, &sigchld_watcher); ev_signal_stop(EV_DEFAULT, &sigusr1_watcher); #else #ifndef LIB_ONLY ev_io_stop(EV_DEFAULT, &plugin_watcher.io); #endif #endif ev_unloop(EV_A_ EVUNLOOP_ALL); } } } #if defined(__MINGW32__) && !defined(LIB_ONLY) static void plugin_watcher_cb(EV_P_ ev_io *w, int revents) { char buf[1]; SOCKET fd = accept(plugin_watcher.fd, NULL, NULL); if (fd == INVALID_SOCKET) { return; } recv(fd, buf, 1, 0); closesocket(fd); LOGE("plugin service exit unexpectedly"); ret_val = -1; ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); ev_io_stop(EV_DEFAULT, &plugin_watcher.io); ev_unloop(EV_A_ EVUNLOOP_ALL); } #endif void accept_cb(EV_P_ ev_io *w, int revents) { listen_ctx_t *listener = (listen_ctx_t *)w; int serverfd = accept(listener->fd, NULL, NULL); if (serverfd == -1) { ERROR("accept"); return; } setnonblocking(serverfd); int opt = 1; setsockopt(serverfd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif if (tcp_incoming_sndbuf > 0) { setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &tcp_incoming_sndbuf, sizeof(int)); } if (tcp_incoming_rcvbuf > 0) { setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &tcp_incoming_rcvbuf, sizeof(int)); } server_t *server = new_server(serverfd); server->listener = listener; ev_io_start(EV_A_ & server->recv_ctx->io); } #ifndef LIB_ONLY int main(int argc, char **argv) { int i, c; int pid_flags = 0; int mtu = 0; int mptcp = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; char *plugin = NULL; char *plugin_opts = NULL; char *plugin_host = NULL; char *plugin_port = NULL; char tmp_port[8]; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; memset(remote_addr, 0, sizeof(ss_addr_t) * MAX_REMOTE_NUM); srand(time(NULL)); 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 }, { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, { "tcp-outgoing-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_SNDBUF }, { "tcp-outgoing-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_RCVBUF }, { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "acl", required_argument, NULL, GETOPT_VAL_ACL }, { "mtu", required_argument, NULL, GETOPT_VAL_MTU }, { "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "key", required_argument, NULL, GETOPT_VAL_KEY }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; opterr = 0; USE_TTY(); #ifdef __ANDROID__ while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:S:huUvV6A", long_options, NULL)) != -1) { #else while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:n:huUv6A", long_options, NULL)) != -1) { #endif switch (c) { case GETOPT_VAL_FAST_OPEN: fast_open = 1; break; case GETOPT_VAL_ACL: LOGI("initializing acl..."); acl = !init_acl(optarg); break; case GETOPT_VAL_MTU: mtu = atoi(optarg); LOGI("set MTU to %d", mtu); break; case GETOPT_VAL_MPTCP: mptcp = get_mptcp(1); if (mptcp) LOGI("enable multipath TCP (%s)", mptcp > 0 ? "out-of-tree" : "upstream"); break; case GETOPT_VAL_NODELAY: no_delay = 1; LOGI("enable TCP no-delay"); break; case GETOPT_VAL_PLUGIN: plugin = optarg; break; case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; case GETOPT_VAL_KEY: key = optarg; break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; case GETOPT_VAL_TCP_INCOMING_SNDBUF: tcp_incoming_sndbuf = atoi(optarg); break; case GETOPT_VAL_TCP_INCOMING_RCVBUF: tcp_incoming_rcvbuf = atoi(optarg); break; case GETOPT_VAL_TCP_OUTGOING_SNDBUF: tcp_outgoing_sndbuf = atoi(optarg); break; case GETOPT_VAL_TCP_OUTGOING_RCVBUF: tcp_outgoing_rcvbuf = atoi(optarg); break; case 's': if (remote_num < MAX_REMOTE_NUM) { parse_addr(optarg, &remote_addr[remote_num++]); } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; case 'h': case GETOPT_VAL_HELP: usage(); exit(EXIT_SUCCESS); case '6': ipv6first = 1; break; #ifdef __ANDROID__ case 'S': stat_path = optarg; break; case 'V': vpn = 1; break; #endif case 'A': FATAL("One time auth has been deprecated. Try AEAD ciphers instead."); break; case '?': // The option character is not recognized. LOGE("Unrecognized option: %s", optarg); opterr = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = get_default_conf(); } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) remote_addr[i] = conf->remote_addr[i]; } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (key == NULL) { key = conf->key; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (user == NULL) { user = conf->user; } if (plugin == NULL) { plugin = conf->plugin; } if (plugin_opts == NULL) { plugin_opts = conf->plugin_opts; } if (reuse_port == 0) { reuse_port = conf->reuse_port; } if (tcp_incoming_sndbuf == 0) { tcp_incoming_sndbuf = conf->tcp_incoming_sndbuf; } if (tcp_incoming_rcvbuf == 0) { tcp_incoming_rcvbuf = conf->tcp_incoming_rcvbuf; } if (tcp_outgoing_sndbuf == 0) { tcp_outgoing_sndbuf = conf->tcp_outgoing_sndbuf; } if (tcp_outgoing_rcvbuf == 0) { tcp_outgoing_rcvbuf = conf->tcp_outgoing_rcvbuf; } if (fast_open == 0) { fast_open = conf->fast_open; } if (mode == TCP_ONLY) { mode = conf->mode; } if (mtu == 0) { mtu = conf->mtu; } if (mptcp == 0) { mptcp = conf->mptcp; } if (no_delay == 0) { no_delay = conf->no_delay; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } #endif if (ipv6first == 0) { ipv6first = conf->ipv6_first; } if (acl == 0 && conf->acl != NULL) { LOGI("initializing acl..."); acl = !init_acl(conf->acl); } } if (remote_num == 0) { fprintf(stderr, "remote_num is 0\n"); exit(EXIT_FAILURE); } if (!remote_port) { fprintf(stderr, "remote_port is NULL\n"); exit(EXIT_FAILURE); } #ifndef HAVE_LAUNCHD if (!local_port) { fprintf(stderr, "local_port is NULL\n"); exit(EXIT_FAILURE); } #endif if (!password && !key) { fprintf(stderr, "both password and key are NULL\n"); exit(EXIT_FAILURE); } #ifdef __MINGW32__ winsock_init(); #endif if (tcp_incoming_sndbuf != 0 && tcp_incoming_sndbuf < SOCKET_BUF_SIZE) { tcp_incoming_sndbuf = 0; } if (tcp_incoming_sndbuf != 0) { LOGI("set TCP incoming connection send buffer size to %d", tcp_incoming_sndbuf); } if (tcp_incoming_rcvbuf != 0 && tcp_incoming_rcvbuf < SOCKET_BUF_SIZE) { tcp_incoming_rcvbuf = 0; } if (tcp_incoming_rcvbuf != 0) { LOGI("set TCP incoming connection receive buffer size to %d", tcp_incoming_rcvbuf); } if (tcp_outgoing_sndbuf != 0 && tcp_outgoing_sndbuf < SOCKET_BUF_SIZE) { tcp_outgoing_sndbuf = 0; } if (tcp_outgoing_sndbuf != 0) { LOGI("set TCP outgoing connection send buffer size to %d", tcp_outgoing_sndbuf); } if (tcp_outgoing_rcvbuf != 0 && tcp_outgoing_rcvbuf < SOCKET_BUF_SIZE) { tcp_outgoing_rcvbuf = 0; } if (tcp_outgoing_rcvbuf != 0) { LOGI("set TCP outgoing connection receive buffer size to %d", tcp_outgoing_rcvbuf); } if (plugin != NULL) { uint16_t port = get_local_port(); if (port == 0) { FATAL("failed to find a free port"); } snprintf(tmp_port, 8, "%d", port); if (is_ipv6only(remote_addr, remote_num, ipv6first)) { plugin_host = "::1"; } else { plugin_host = "127.0.0.1"; } plugin_port = tmp_port; #ifdef __MINGW32__ memset(&plugin_watcher, 0, sizeof(plugin_watcher)); plugin_watcher.port = get_local_port(); if (plugin_watcher.port == 0) { LOGE("failed to assign a control port for plugin"); } #endif LOGI("plugin \"%s\" enabled", plugin); } if (method == NULL) { method = "chacha20-ietf-poly1305"; } if (timeout == NULL) { timeout = "60"; } #ifdef HAVE_SETRLIMIT /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif if (local_addr == NULL) { if (is_ipv6only(remote_addr, remote_num, ipv6first)) { local_addr = "::1"; } else { local_addr = "127.0.0.1"; } } USE_SYSLOG(argv[0], pid_flags); if (pid_flags) { daemonize(pid_path); } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); fast_open = 0; #endif } if (no_delay) { LOGI("enable TCP no-delay"); } if (ipv6first) { LOGI("resolving hostname to IPv6 address first"); } #ifdef __MINGW32__ // Listen on plugin control port if (plugin != NULL && plugin_watcher.port != 0) { SOCKET fd; fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd != INVALID_SOCKET) { plugin_watcher.valid = 0; do { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_port = htons(plugin_watcher.port); if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) { LOGE("failed to bind plugin control port"); break; } if (listen(fd, 1)) { LOGE("failed to listen on plugin control port"); break; } plugin_watcher.fd = fd; ev_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, EV_READ); ev_io_start(EV_DEFAULT, &plugin_watcher.io); plugin_watcher.valid = 1; } while (0); if (!plugin_watcher.valid) { closesocket(fd); plugin_watcher.port = 0; } } } #endif if (plugin != NULL) { int len = 0; size_t buf_size = 256 * remote_num; char *remote_str = ss_malloc(buf_size); snprintf(remote_str, buf_size, "%s", remote_addr[0].host); len = strlen(remote_str); for (int i = 1; i < remote_num; i++) { snprintf(remote_str + len, buf_size - len, "|%s", remote_addr[i].host); len = strlen(remote_str); } int err = start_plugin(plugin, plugin_opts, remote_str, remote_port, plugin_host, plugin_port, #ifdef __MINGW32__ plugin_watcher.port, #endif MODE_CLIENT); if (err) { ERROR("start_plugin"); FATAL("failed to start the plugin"); } } #ifndef __MINGW32__ // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif // Setup keys LOGI("initializing ciphers... %s", method); crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); // Setup proxy context listen_ctx_t listen_ctx; listen_ctx.remote_num = 0; listen_ctx.remote_addr = ss_malloc(sizeof(struct sockaddr *) * remote_num); memset(listen_ctx.remote_addr, 0, sizeof(struct sockaddr *) * remote_num); for (i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; if (plugin != NULL) { host = plugin_host; port = plugin_port; } struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; ++listen_ctx.remote_num; if (plugin != NULL) break; } listen_ctx.timeout = atoi(timeout); listen_ctx.iface = iface; listen_ctx.mptcp = mptcp; // Setup signal handler ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); #ifndef __MINGW32__ ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigchld_watcher); #endif if (ss_is_ipv6addr(local_addr)) LOGI("listening at [%s]:%s", local_addr, local_port); else LOGI("listening at %s:%s", local_addr, local_port); struct ev_loop *loop = EV_DEFAULT; if (mode != UDP_ONLY) { // Setup socket int listenfd; #ifdef HAVE_LAUNCHD listenfd = launch_or_create(local_addr, local_port); #else listenfd = create_and_bind(local_addr, local_port); #endif if (listenfd == -1) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("udprelay enabled"); char *host = remote_addr[0].host; char *port = remote_addr[0].port == NULL ? remote_port : remote_addr[0].port; struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } struct sockaddr *addr = (struct sockaddr *)storage; udp_fd = init_udprelay(local_addr, local_port, addr, get_sockaddr_len(addr), mtu, crypto, listen_ctx.timeout, iface); } #ifdef HAVE_LAUNCHD if (local_port == NULL) LOGI("listening through launchd"); else #endif #ifndef __MINGW32__ // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); } if (geteuid() == 0) { LOGI("running from root user"); } #endif // Init connections cork_dllist_init(&connections); // Enter the loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } // Clean up if (plugin != NULL) { stop_plugin(); } if (mode != UDP_ONLY) { ev_io_stop(loop, &listen_ctx.io); free_connections(loop); for (i = 0; i < listen_ctx.remote_num; i++) ss_free(listen_ctx.remote_addr[i]); ss_free(listen_ctx.remote_addr); } if (mode != TCP_ONLY) { free_udprelay(); } #ifdef __MINGW32__ if (plugin_watcher.valid) { closesocket(plugin_watcher.fd); } winsock_cleanup(); #endif return ret_val; } #else int _start_ss_local_server(profile_t profile, ss_local_callback callback, void *udata) { srand(time(NULL)); char *remote_host = profile.remote_host; char *local_addr = profile.local_addr; char *method = profile.method; char *password = profile.password; char *log = profile.log; int remote_port = profile.remote_port; int local_port = profile.local_port; int timeout = profile.timeout; int mtu = 0; int mptcp = 0; mode = profile.mode; fast_open = profile.fast_open; verbose = profile.verbose; mtu = profile.mtu; mptcp = profile.mptcp; char local_port_str[16]; char remote_port_str[16]; sprintf(local_port_str, "%d", local_port); sprintf(remote_port_str, "%d", remote_port); #ifdef __MINGW32__ winsock_init(); #endif USE_LOGFILE(log); if (profile.acl != NULL) { LOGI("initializing acl..."); acl = !init_acl(profile.acl); } if (local_addr == NULL) { local_addr = "127.0.0.1"; } #ifndef __MINGW32__ // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); #ifndef __MINGW32__ ev_signal_init(&sigusr1_watcher, signal_cb, SIGUSR1); ev_signal_start(EV_DEFAULT, &sigusr1_watcher); #endif // Setup keys LOGI("initializing ciphers... %s", method); crypto = crypto_init(password, NULL, method); if (crypto == NULL) FATAL("failed to init ciphers"); struct sockaddr_storage storage; memset(&storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(remote_host, remote_port_str, &storage, 0, ipv6first) == -1) { return -1; } // Setup proxy context struct ev_loop *loop = EV_DEFAULT; struct sockaddr *remote_addr_tmp[MAX_REMOTE_NUM]; listen_ctx_t listen_ctx; listen_ctx.remote_num = 1; listen_ctx.remote_addr = remote_addr_tmp; listen_ctx.remote_addr[0] = (struct sockaddr *)(&storage); listen_ctx.timeout = timeout; listen_ctx.iface = NULL; listen_ctx.mptcp = mptcp; if (ss_is_ipv6addr(local_addr)) LOGI("listening at [%s]:%s", local_addr, local_port_str); else LOGI("listening at %s:%s", local_addr, local_port_str); if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port_str); if (listenfd == -1) { ERROR("bind()"); return -1; } if (listen(listenfd, SOMAXCONN) == -1) { ERROR("listen()"); return -1; } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("udprelay enabled"); struct sockaddr *addr = (struct sockaddr *)(&storage); udp_fd = init_udprelay(local_addr, local_port_str, addr, get_sockaddr_len(addr), mtu, crypto, timeout, NULL); } // Init connections cork_dllist_init(&connections); if (callback) { callback(listen_ctx.fd, udp_fd, udata); } // Enter the loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } // Clean up if (mode != UDP_ONLY) { ev_io_stop(loop, &listen_ctx.io); free_connections(loop); close(listen_ctx.fd); } if (mode != TCP_ONLY) { free_udprelay(); } #ifdef __MINGW32__ winsock_cleanup(); #endif return ret_val; } int start_ss_local_server(profile_t profile) { return _start_ss_local_server(profile, NULL, NULL); } int start_ss_local_server_with_callback(profile_t profile, ss_local_callback callback, void *udata) { return _start_ss_local_server(profile, callback, udata); } #endif ================================================ FILE: src/local.h ================================================ /* * local.h - Define the client's buffers and callbacks * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _LOCAL_H #define _LOCAL_H #include #ifdef HAVE_LIBEV_EV_H #include #else #include #endif #ifdef __MINGW32__ #include "winsock.h" #endif #include "crypto.h" #include "jconf.h" #include "common.h" typedef struct listen_ctx { ev_io io; char *iface; int remote_num; int timeout; int fd; int mptcp; struct sockaddr **remote_addr; } listen_ctx_t; typedef struct server_ctx { ev_io io; int connected; struct server *server; } server_ctx_t; typedef struct server { int fd; int stage; cipher_ctx_t *e_ctx; cipher_ctx_t *d_ctx; struct server_ctx *recv_ctx; struct server_ctx *send_ctx; struct listen_ctx *listener; struct remote *remote; buffer_t *buf; buffer_t *abuf; ev_timer delayed_connect_watcher; struct cork_dllist_item entries; } server_t; typedef struct remote_ctx { ev_io io; ev_timer watcher; int connected; struct remote *remote; } remote_ctx_t; typedef struct remote { int fd; int direct; int addr_len; uint32_t counter; #ifdef TCP_FASTOPEN_WINSOCK OVERLAPPED olap; int connect_ex_done; #endif buffer_t *buf; struct remote_ctx *recv_ctx; struct remote_ctx *send_ctx; struct server *server; struct sockaddr_storage addr; } remote_t; #endif // _LOCAL_H ================================================ FILE: src/manager.c ================================================ /* * server.c - Provide shadowsocks service * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) #include #include #define SET_INTERFACE #endif #include "json.h" #include "utils.h" #include "netutils.h" #include "manager.h" #ifndef BUF_SIZE #define BUF_SIZE 65535 #endif int verbose = 0; char *executable = "ss-server"; char *working_dir = NULL; int working_dir_size = 0; static struct cork_hash_table *server_table; static int setnonblocking(int fd) { int flags; if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { flags = 0; } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } static void destroy_server(struct server *server) { // function used to free memories alloced in **get_server** if (server->method) ss_free(server->method); if (server->plugin) ss_free(server->plugin); if (server->plugin_opts) ss_free(server->plugin_opts); if (server->mode) ss_free(server->mode); } static void build_config(char *prefix, struct manager_ctx *manager, struct server *server) { char *path = NULL; int path_size = strlen(prefix) + strlen(server->port) + 20; path = ss_malloc(path_size); snprintf(path, path_size, "%s/.shadowsocks_%s.conf", prefix, server->port); FILE *f = fopen(path, "w+"); if (f == NULL) { if (verbose) { LOGE("unable to open config file"); } ss_free(path); return; } fprintf(f, "{\n"); fprintf(f, "\"server_port\":%d,\n", atoi(server->port)); fprintf(f, "\"password\":\"%s\"", server->password); if (server->method) fprintf(f, ",\n\"method\":\"%s\"", server->method); else if (manager->method) fprintf(f, ",\n\"method\":\"%s\"", manager->method); if (server->fast_open[0]) fprintf(f, ",\n\"fast_open\": %s", server->fast_open); else if (manager->fast_open) fprintf(f, ",\n\"fast_open\": true"); if (server->no_delay[0]) fprintf(f, ",\n\"no_delay\": %s", server->no_delay); else if (manager->no_delay) fprintf(f, ",\n\"no_delay\": true"); if (manager->reuse_port) fprintf(f, ",\n\"reuse_port\": true"); if (server->mode) fprintf(f, ",\n\"mode\":\"%s\"", server->mode); if (server->plugin) fprintf(f, ",\n\"plugin\":\"%s\"", server->plugin); if (server->plugin_opts) fprintf(f, ",\n\"plugin_opts\":\"%s\"", server->plugin_opts); fprintf(f, "\n}\n"); fclose(f); ss_free(path); } static char * construct_command_line(struct manager_ctx *manager, struct server *server) { static char cmd[BUF_SIZE]; int i; int port; port = atoi(server->port); build_config(working_dir, manager, server); memset(cmd, 0, BUF_SIZE); snprintf(cmd, BUF_SIZE, "%s --manager-address %s -f %s/.shadowsocks_%d.pid -c %s/.shadowsocks_%d.conf", executable, manager->manager_address, working_dir, port, working_dir, port); if (manager->acl != NULL) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " --acl %s", manager->acl); } if (manager->timeout != NULL) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -t %s", manager->timeout); } #ifdef HAVE_SETRLIMIT if (manager->nofile) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -n %d", manager->nofile); } #endif if (manager->user != NULL) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -a %s", manager->user); } if (manager->verbose) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -v"); } if (server->mode == NULL && manager->mode == UDP_ONLY) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -U"); } if (server->mode == NULL && manager->mode == TCP_AND_UDP) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -u"); } if (manager->iface) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -i \"%s\"", manager->iface); } if (server->fast_open[0] == 0 && manager->fast_open) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " --fast-open"); } if (server->no_delay[0] == 0 && manager->no_delay) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " --no-delay"); } if (manager->ipv6first) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -6"); } if (manager->mtu) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " --mtu %d", manager->mtu); } if (server->plugin == NULL && manager->plugin) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " --plugin \"%s\"", manager->plugin); } if (server->plugin_opts == NULL && manager->plugin_opts) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " --plugin-opts \"%s\"", manager->plugin_opts); } if (manager->nameservers) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -d \"%s\"", manager->nameservers); } for (i = 0; i < manager->host_num; i++) { int len = strlen(cmd); snprintf(cmd + len, BUF_SIZE - len, " -s %s", manager->hosts[i]); } if (verbose) { LOGI("cmd: %s", cmd); } return cmd; } static char * get_data(char *buf, int len) { char *data; int pos = 0; while (pos < len && buf[pos] != '{') pos++; if (pos == len) { return NULL; } data = buf + pos - 1; return data; } static char * get_action(char *buf, int len) { char *action; int pos = 0; while (pos < len && isspace((unsigned char)buf[pos])) pos++; if (pos == len) { return NULL; } action = buf + pos; while (pos < len && (!isspace((unsigned char)buf[pos]) && buf[pos] != ':')) pos++; buf[pos] = '\0'; return action; } static struct server * get_server(char *buf, int len) { char *data = get_data(buf, len); char error_buf[512]; if (data == NULL) { LOGE("No data found"); return NULL; } json_settings settings = { 0 }; json_value *obj = json_parse_ex(&settings, data, strlen(data), error_buf); if (obj == NULL) { LOGE("%s", error_buf); return NULL; } struct server *server = ss_malloc(sizeof(struct server)); memset(server, 0, sizeof(struct server)); if (obj->type == json_object) { int i = 0; for (i = 0; i < obj->u.object.length; i++) { char *name = obj->u.object.values[i].name; json_value *value = obj->u.object.values[i].value; if (strcmp(name, "server_port") == 0) { if (value->type == json_string) { strncpy(server->port, value->u.string.ptr, 7); } else if (value->type == json_integer) { snprintf(server->port, 8, "%" PRIu64 "", value->u.integer); } } else if (strcmp(name, "password") == 0) { if (value->type == json_string) { strncpy(server->password, value->u.string.ptr, 127); } } else if (strcmp(name, "method") == 0) { if (value->type == json_string) { server->method = strdup(value->u.string.ptr); } } else if (strcmp(name, "fast_open") == 0) { if (value->type == json_boolean) { strncpy(server->fast_open, (value->u.boolean ? "true" : "false"), 8); } } else if (strcmp(name, "no_delay") == 0) { if (value->type == json_boolean) { strncpy(server->no_delay, (value->u.boolean ? "true" : "false"), 8); } } else if (strcmp(name, "plugin") == 0) { if (value->type == json_string) { server->plugin = strdup(value->u.string.ptr); } } else if (strcmp(name, "plugin_opts") == 0) { if (value->type == json_string) { server->plugin_opts = strdup(value->u.string.ptr); } } else if (strcmp(name, "mode") == 0) { if (value->type == json_string) { server->mode = strdup(value->u.string.ptr); } } else { LOGE("invalid data: %s", data); break; } } } json_value_free(obj); return server; } static int parse_traffic(char *buf, int len, char *port, uint64_t *traffic) { char *data = get_data(buf, len); char error_buf[512]; json_settings settings = { 0 }; if (data == NULL) { LOGE("No data found"); return -1; } json_value *obj = json_parse_ex(&settings, data, strlen(data), error_buf); if (obj == NULL) { LOGE("%s", error_buf); return -1; } if (obj->type == json_object) { int i = 0; for (i = 0; i < obj->u.object.length; i++) { char *name = obj->u.object.values[i].name; json_value *value = obj->u.object.values[i].value; if (value->type == json_integer) { strncpy(port, name, 7); *traffic = value->u.integer; } } } json_value_free(obj); return 0; } static int create_and_bind(const char *host, const char *port, int protocol) { struct addrinfo hints; struct addrinfo *result, *rp, *ipv4v6bindall; int s, listen_sock = -1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ hints.ai_socktype = protocol == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM; /* We want a TCP or UDP socket */ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* For wildcard IP address */ hints.ai_protocol = protocol; s = getaddrinfo(host, port, &hints, &result); if (s != 0) { LOGE("getaddrinfo: %s", gai_strerror(s)); return -1; } rp = result; /* * On Linux, with net.ipv6.bindv6only = 0 (the default), getaddrinfo(NULL) with * AI_PASSIVE returns 0.0.0.0 and :: (in this order). AI_PASSIVE was meant to * return a list of addresses to listen on, but it is impossible to listen on * 0.0.0.0 and :: at the same time, if :: implies dualstack mode. */ if (!host) { ipv4v6bindall = result; /* Loop over all address infos found until a IPV6 address is found. */ while (ipv4v6bindall) { if (ipv4v6bindall->ai_family == AF_INET6) { rp = ipv4v6bindall; /* Take first IPV6 address available */ break; } ipv4v6bindall = ipv4v6bindall->ai_next; /* Get next address info, if any */ } } for (/*rp = result*/; rp != NULL; rp = rp->ai_next) { listen_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (listen_sock == -1) { continue; } if (rp->ai_family == AF_INET6) { int ipv6only = host ? 1 : 0; setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)); } int opt = 1; setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(listen_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ close(listen_sock); break; } else { ERROR("bind"); } } if (result != NULL) { freeaddrinfo(result); } if (rp == NULL) { LOGE("Could not bind"); return -1; } return listen_sock; } static int check_port(struct manager_ctx *manager, struct server *server) { bool both_tcp_udp = manager->mode == TCP_AND_UDP; int fd_count = manager->host_num * (both_tcp_udp ? 2 : 1); int bind_err = 0; int *sock_fds = (int *)ss_malloc(fd_count * sizeof(int)); memset(sock_fds, 0, fd_count * sizeof(int)); /* try to bind each interface */ for (int i = 0; i < manager->host_num; i++) { LOGI("try to bind interface: %s, port: %s", manager->hosts[i], server->port); if (manager->mode == UDP_ONLY) { sock_fds[i] = create_and_bind(manager->hosts[i], server->port, IPPROTO_UDP); } else { sock_fds[i] = create_and_bind(manager->hosts[i], server->port, IPPROTO_TCP); } if (both_tcp_udp) { sock_fds[i + manager->host_num] = create_and_bind(manager->hosts[i], server->port, IPPROTO_UDP); } if (sock_fds[i] == -1 || (both_tcp_udp && sock_fds[i + manager->host_num] == -1)) { bind_err = -1; break; } } /* clean socks */ for (int i = 0; i < fd_count; i++) if (sock_fds[i] > 0) { close(sock_fds[i]); } ss_free(sock_fds); return bind_err == -1 ? -1 : 0; } static int add_server(struct manager_ctx *manager, struct server *server) { int ret = check_port(manager, server); if (ret == -1) { LOGE("port is not available, please check."); return -1; } bool new = false; cork_hash_table_put(server_table, (void *)server->port, (void *)server, &new, NULL, NULL); char *cmd = construct_command_line(manager, server); if (system(cmd) == -1) { ERROR("add_server_system"); return -1; } return 0; } static void kill_server(char *prefix, char *pid_file) { char *path = NULL; int pid, path_size = strlen(prefix) + strlen(pid_file) + 2; path = ss_malloc(path_size); snprintf(path, path_size, "%s/%s", prefix, pid_file); FILE *f = fopen(path, "r"); if (f == NULL) { if (verbose) { LOGE("unable to open pid file"); } ss_free(path); return; } if (fscanf(f, "%d", &pid) != EOF) { kill(pid, SIGTERM); } fclose(f); remove(path); ss_free(path); } static void stop_server(char *prefix, char *port) { char *path = NULL; int pid, path_size = strlen(prefix) + strlen(port) + 20; path = ss_malloc(path_size); snprintf(path, path_size, "%s/.shadowsocks_%s.pid", prefix, port); FILE *f = fopen(path, "r"); if (f == NULL) { if (verbose) { LOGE("unable to open pid file"); } ss_free(path); return; } if (fscanf(f, "%d", &pid) != EOF) { kill(pid, SIGTERM); } fclose(f); ss_free(path); } static void remove_server(char *prefix, char *port) { char *old_port = NULL; struct server *old_server = NULL; cork_hash_table_delete(server_table, (void *)port, (void **)&old_port, (void **)&old_server); if (old_server != NULL) { destroy_server(old_server); ss_free(old_server); } stop_server(prefix, port); } static void update_stat(char *port, uint64_t traffic) { if (verbose) { LOGI("update traffic %" PRIu64 " for port %s", traffic, port); } void *ret = cork_hash_table_get(server_table, (void *)port); if (ret != NULL) { struct server *server = (struct server *)ret; server->traffic = traffic; } } static void manager_recv_cb(EV_P_ ev_io *w, int revents) { struct manager_ctx *manager = (struct manager_ctx *)w; socklen_t len; ssize_t r; struct sockaddr_un claddr; char buf[BUF_SIZE]; memset(buf, 0, BUF_SIZE); len = sizeof(struct sockaddr_un); r = recvfrom(manager->fd, buf, BUF_SIZE, 0, (struct sockaddr *)&claddr, &len); if (r == -1) { ERROR("manager_recvfrom"); return; } if (r > BUF_SIZE / 2) { LOGE("too large request: %d", (int)r); return; } // properly terminate string which recvfrom does not do buf[r] = '\0'; char *action = get_action(buf, r); if (action == NULL) { return; } if (strcmp(action, "add") == 0) { struct server *server = get_server(buf, r); if (server == NULL || server->port[0] == 0 || server->password[0] == 0) { LOGE("invalid command: %s:%s", buf, get_data(buf, r)); if (server != NULL) { destroy_server(server); ss_free(server); } goto ERROR_MSG; } remove_server(working_dir, server->port); int ret = add_server(manager, server); char *msg; int msg_len; if (ret == -1) { msg = "port is not available"; msg_len = 21; } else { msg = "ok"; msg_len = 2; } if (sendto(manager->fd, msg, msg_len, 0, (struct sockaddr *)&claddr, len) != 2) { ERROR("add_sendto"); } } else if (strcmp(action, "list") == 0) { struct cork_hash_table_iterator iter; struct cork_hash_table_entry *entry; char buf[BUF_SIZE]; memset(buf, 0, BUF_SIZE); sprintf(buf, "["); cork_hash_table_iterator_init(server_table, &iter); while ((entry = cork_hash_table_iterator_next(&iter)) != NULL) { struct server *server = (struct server *)entry->value; char *method = server->method ? server->method : manager->method; size_t pos = strlen(buf); size_t entry_len = strlen(server->port) + strlen(server->password) + strlen(method); if (pos > BUF_SIZE - entry_len - 50) { if (sendto(manager->fd, buf, pos, 0, (struct sockaddr *)&claddr, len) != pos) { ERROR("list_sendto"); } memset(buf, 0, BUF_SIZE); pos = 0; } sprintf(buf + pos, "\n\t{\"server_port\":\"%s\",\"password\":\"%s\",\"method\":\"%s\"},", server->port, server->password, method); } size_t pos = strlen(buf); strcpy(buf + max(pos - 1, 1), "\n]"); // Remove trailing "," pos = strlen(buf); if (sendto(manager->fd, buf, pos, 0, (struct sockaddr *)&claddr, len) != pos) { ERROR("list_sendto"); } } else if (strcmp(action, "remove") == 0) { struct server *server = get_server(buf, r); if (server == NULL || server->port[0] == 0) { LOGE("invalid command: %s:%s", buf, get_data(buf, r)); if (server != NULL) { destroy_server(server); ss_free(server); } goto ERROR_MSG; } remove_server(working_dir, server->port); destroy_server(server); ss_free(server); char msg[3] = "ok"; if (sendto(manager->fd, msg, 2, 0, (struct sockaddr *)&claddr, len) != 2) { ERROR("remove_sendto"); } } else if (strcmp(action, "stat") == 0) { char port[8]; uint64_t traffic = 0; if (parse_traffic(buf, r, port, &traffic) == -1) { LOGE("invalid command: %s:%s", buf, get_data(buf, r)); return; } update_stat(port, traffic); } else if (strcmp(action, "ping") == 0) { struct cork_hash_table_entry *entry; struct cork_hash_table_iterator server_iter; char buf[BUF_SIZE]; memset(buf, 0, BUF_SIZE); sprintf(buf, "stat: {"); cork_hash_table_iterator_init(server_table, &server_iter); while ((entry = cork_hash_table_iterator_next(&server_iter)) != NULL) { struct server *server = (struct server *)entry->value; size_t pos = strlen(buf); if (pos > BUF_SIZE / 2) { buf[pos - 1] = '}'; if (sendto(manager->fd, buf, pos, 0, (struct sockaddr *)&claddr, len) != pos) { ERROR("ping_sendto"); } memset(buf, 0, BUF_SIZE); } else { sprintf(buf + pos, "\"%s\":%" PRIu64 ",", server->port, server->traffic); } } size_t pos = strlen(buf); if (pos > 7) { buf[pos - 1] = '}'; } else { buf[pos] = '}'; pos++; } if (sendto(manager->fd, buf, pos, 0, (struct sockaddr *)&claddr, len) != pos) { ERROR("ping_sendto"); } } return; ERROR_MSG: strcpy(buf, "err"); if (sendto(manager->fd, buf, 3, 0, (struct sockaddr *)&claddr, len) != 3) { ERROR("error_sendto"); } } static void signal_cb(EV_P_ ev_signal *w, int revents) { if (revents & EV_SIGNAL) { switch (w->signum) { case SIGINT: case SIGTERM: ev_unloop(EV_A_ EVUNLOOP_ALL); } } } int create_server_socket(const char *host, const char *port) { struct addrinfo hints; struct addrinfo *result, *rp, *ipv4v6bindall; int s, server_sock; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ hints.ai_socktype = SOCK_DGRAM; /* We want a UDP socket */ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* For wildcard IP address */ hints.ai_protocol = IPPROTO_UDP; s = getaddrinfo(host, port, &hints, &result); if (s != 0) { LOGE("getaddrinfo: %s", gai_strerror(s)); return -1; } rp = result; /* * On Linux, with net.ipv6.bindv6only = 0 (the default), getaddrinfo(NULL) with * AI_PASSIVE returns 0.0.0.0 and :: (in this order). AI_PASSIVE was meant to * return a list of addresses to listen on, but it is impossible to listen on * 0.0.0.0 and :: at the same time, if :: implies dualstack mode. */ if (!host) { ipv4v6bindall = result; /* Loop over all address infos found until a IPV6 address is found. */ while (ipv4v6bindall) { if (ipv4v6bindall->ai_family == AF_INET6) { rp = ipv4v6bindall; /* Take first IPV6 address available */ break; } ipv4v6bindall = ipv4v6bindall->ai_next; /* Get next address info, if any */ } } for (/*rp = result*/; rp != NULL; rp = rp->ai_next) { server_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (server_sock == -1) { continue; } if (rp->ai_family == AF_INET6) { int ipv6only = host ? 1 : 0; setsockopt(server_sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)); } int opt = 1; setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); s = bind(server_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ break; } else { ERROR("bind"); } close(server_sock); } if (result != NULL) { freeaddrinfo(result); } if (rp == NULL) { LOGE("cannot bind"); return -1; } return server_sock; } int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *acl = NULL; char *user = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; char *manager_address = NULL; char *plugin = NULL; char *plugin_opts = NULL; char *workdir = NULL; int fast_open = 0; int no_delay = 0; int reuse_port = 0; int mode = TCP_ONLY; int mtu = 0; int ipv6first = 0; #ifdef HAVE_SETRLIMIT static int nofile = 0; #endif int server_num = 0; char *server_host[MAX_REMOTE_NUM]; char *nameservers = NULL; jconf_t *conf = NULL; static struct option long_options[] = { { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "acl", required_argument, NULL, GETOPT_VAL_ACL }, { "manager-address", required_argument, NULL, GETOPT_VAL_MANAGER_ADDRESS }, { "executable", required_argument, NULL, GETOPT_VAL_EXECUTABLE }, { "mtu", required_argument, NULL, GETOPT_VAL_MTU }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "workdir", required_argument, NULL, GETOPT_VAL_WORKDIR }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; opterr = 0; USE_TTY(); while ((c = getopt_long(argc, argv, "f:s:l:k:t:m:c:i:d:a:n:D:6huUvA", long_options, NULL)) != -1) switch (c) { case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; case GETOPT_VAL_FAST_OPEN: fast_open = 1; break; case GETOPT_VAL_NODELAY: no_delay = 1; break; case GETOPT_VAL_ACL: acl = optarg; break; case GETOPT_VAL_MANAGER_ADDRESS: manager_address = optarg; break; case GETOPT_VAL_EXECUTABLE: executable = optarg; break; case GETOPT_VAL_MTU: mtu = atoi(optarg); break; case GETOPT_VAL_PLUGIN: plugin = optarg; break; case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; case 's': if (server_num < MAX_REMOTE_NUM) { server_host[server_num++] = optarg; } break; case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'd': nameservers = optarg; break; case 'a': user = optarg; break; case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case '6': ipv6first = 1; break; case GETOPT_VAL_WORKDIR: case 'D': workdir = optarg; break; case 'v': verbose = 1; break; case GETOPT_VAL_HELP: case 'h': usage(); exit(EXIT_SUCCESS); #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'A': FATAL("One time auth has been deprecated. Try AEAD ciphers instead."); break; case '?': // The option character is not recognized. LOGE("Unrecognized option: %s", optarg); opterr = 1; break; } if (opterr) { usage(); exit(EXIT_FAILURE); } if (conf_path != NULL) { conf = read_jconf(conf_path); if (server_num == 0) { server_num = conf->remote_num; for (i = 0; i < server_num; i++) server_host[i] = conf->remote_addr[i].host; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (user == NULL) { user = conf->user; } if (fast_open == 0) { fast_open = conf->fast_open; } if (no_delay == 0) { no_delay = conf->no_delay; } if (reuse_port == 0) { reuse_port = conf->reuse_port; } if (nameservers == NULL) { nameservers = conf->nameserver; } if (mode == TCP_ONLY) { mode = conf->mode; } if (mtu == 0) { mtu = conf->mtu; } if (plugin == NULL) { plugin = conf->plugin; } if (plugin_opts == NULL) { plugin_opts = conf->plugin_opts; } if (ipv6first == 0) { ipv6first = conf->ipv6_first; } if (workdir == NULL) { workdir = conf->workdir; } if (acl == NULL) { acl = conf->acl; } if (manager_address == NULL) { manager_address = conf->manager_address; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } #endif } if (server_num == 0) { server_host[server_num++] = "0.0.0.0"; } if (method == NULL) { method = "table"; } if (timeout == NULL) { timeout = "60"; } USE_SYSLOG(argv[0], pid_flags); if (pid_flags) { daemonize(pid_path); } if (server_num == 0) { usage(); exit(EXIT_FAILURE); } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } if (no_delay == 1) { LOGI("using tcp no-delay"); } #ifndef __MINGW32__ // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); } if (geteuid() == 0) { LOGI("running from root user"); } #endif struct passwd *pw = getpwuid(getuid()); if (workdir == NULL || strlen(workdir) == 0) { workdir = pw->pw_dir; // If home dir is still not defined or set to nologin/nonexistent, fall back to /tmp if (workdir == NULL || strlen(workdir) == 0 || strstr(workdir, "nologin") || strstr(workdir, "nonexistent")) { workdir = "/tmp"; } working_dir_size = strlen(workdir) + 15; working_dir = ss_malloc(working_dir_size); snprintf(working_dir, working_dir_size, "%s/.shadowsocks", workdir); } else { working_dir_size = strlen(workdir) + 2; working_dir = ss_malloc(working_dir_size); snprintf(working_dir, working_dir_size, "%s", workdir); } LOGI("working directory points to %s", working_dir); int err = mkdir(working_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); if (err != 0 && errno != EEXIST) { ERROR("mkdir"); ss_free(working_dir); FATAL("unable to create working directory"); } if (manager_address == NULL) { size_t manager_address_size = strlen(workdir) + 20; manager_address = ss_malloc(manager_address_size); snprintf(manager_address, manager_address_size, "%s/.ss-manager.socks", workdir); LOGI("using the default manager address: %s", manager_address); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGABRT, SIG_IGN); struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); struct manager_ctx manager; memset(&manager, 0, sizeof(struct manager_ctx)); manager.reuse_port = reuse_port; manager.fast_open = fast_open; manager.no_delay = no_delay; manager.verbose = verbose; manager.mode = mode; manager.password = password; manager.timeout = timeout; manager.method = method; manager.iface = iface; manager.acl = acl; manager.user = user; manager.manager_address = manager_address; manager.hosts = server_host; manager.host_num = server_num; manager.nameservers = nameservers; manager.mtu = mtu; manager.plugin = plugin; manager.plugin_opts = plugin_opts; manager.ipv6first = ipv6first; manager.workdir = workdir; #ifdef HAVE_SETRLIMIT manager.nofile = nofile; #endif // initialize ev loop struct ev_loop *loop = EV_DEFAULT; // Clean up all existed processes DIR *dp; struct dirent *ep; dp = opendir(working_dir); if (dp != NULL) { while ((ep = readdir(dp)) != NULL) { size_t len = strlen(ep->d_name); if (strcmp(ep->d_name + len - 3, "pid") == 0) { kill_server(working_dir, ep->d_name); if (verbose) LOGI("kill %s", ep->d_name); } } closedir(dp); } else { ss_free(working_dir); FATAL("Couldn't open the directory"); } server_table = cork_string_hash_table_new(MAX_PORT_NUM, 0); if (conf != NULL) { for (i = 0; i < conf->port_password_num; i++) { struct server *server = ss_malloc(sizeof(struct server)); memset(server, 0, sizeof(struct server)); strncpy(server->port, conf->port_password[i].port, 7); strncpy(server->password, conf->port_password[i].password, 127); add_server(&manager, server); } } int sfd; ss_addr_t ip_addr = { .host = NULL, .port = NULL }; parse_addr(manager_address, &ip_addr); if (ip_addr.host == NULL || ip_addr.port == NULL) { struct sockaddr_un svaddr; sfd = socket(AF_UNIX, SOCK_DGRAM, 0); /* Create server socket */ if (sfd == -1) { ss_free(working_dir); FATAL("socket"); } setnonblocking(sfd); if (remove(manager_address) == -1 && errno != ENOENT) { ERROR("bind"); ss_free(working_dir); exit(EXIT_FAILURE); } memset(&svaddr, 0, sizeof(struct sockaddr_un)); svaddr.sun_family = AF_UNIX; strncpy(svaddr.sun_path, manager_address, sizeof(svaddr.sun_path) - 1); if (bind(sfd, (struct sockaddr *)&svaddr, sizeof(struct sockaddr_un)) == -1) { ERROR("bind"); ss_free(working_dir); exit(EXIT_FAILURE); } } else { sfd = create_server_socket(ip_addr.host, ip_addr.port); if (sfd == -1) { ss_free(working_dir); FATAL("socket"); } } manager.fd = sfd; ev_io_init(&manager.io, manager_recv_cb, manager.fd, EV_READ); ev_io_start(loop, &manager.io); // start ev loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } // Clean up struct cork_hash_table_entry *entry; struct cork_hash_table_iterator server_iter; cork_hash_table_iterator_init(server_table, &server_iter); while ((entry = cork_hash_table_iterator_next(&server_iter)) != NULL) { struct server *server = (struct server *)entry->value; stop_server(working_dir, server->port); } ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); ss_free(working_dir); free_addr(&ip_addr); return 0; } ================================================ FILE: src/manager.h ================================================ /* * server.h - Define shadowsocks server's buffers and callbacks * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _MANAGER_H #define _MANAGER_H #include #include #ifdef HAVE_LIBEV_EV_H #include #else #include #endif #include "jconf.h" #include "common.h" struct manager_ctx { ev_io io; int fd; int fast_open; int no_delay; int reuse_port; int verbose; int mode; char *password; char *key; char *timeout; char *method; char *iface; char *acl; char *user; char *plugin; char *plugin_opts; char *manager_address; char **hosts; int host_num; char *nameservers; int mtu; int ipv6first; char *workdir; #ifdef HAVE_SETRLIMIT int nofile; #endif }; struct server { char port[8]; char password[128]; char fast_open[8]; char no_delay[8]; char *mode; char *method; char *plugin; char *plugin_opts; uint64_t traffic; }; #endif // _MANAGER_H ================================================ FILE: src/netutils.c ================================================ /* * netutils.c - Network utilities * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef __MINGW32__ #include #include #include #include #endif #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) #include #include #define SET_INTERFACE #endif #include "netutils.h" #include "utils.h" #ifndef SO_REUSEPORT #define SO_REUSEPORT 15 #endif extern int verbose; static const char valid_label_bytes[] = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; int set_reuseport(int socket) { int opt = 1; return setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); } size_t get_sockaddr_len(struct sockaddr *addr) { if (addr->sa_family == AF_INET) { return sizeof(struct sockaddr_in); } else if (addr->sa_family == AF_INET6) { return sizeof(struct sockaddr_in6); } return 0; } #ifdef SET_INTERFACE int setinterface(int socket_fd, const char *interface_name) { struct ifreq interface; memset(&interface, 0, sizeof(struct ifreq)); strncpy(interface.ifr_name, interface_name, IFNAMSIZ - 1); int res = setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(struct ifreq)); return res; } #endif int parse_local_addr(struct sockaddr_storage *storage_v4, struct sockaddr_storage *storage_v6, const char *host) { if (host != NULL) { struct cork_ip ip; if (cork_ip_init(&ip, host) != -1) { if (ip.version == 4) { memset(storage_v4, 0, sizeof(struct sockaddr_storage)); struct sockaddr_in *addr = (struct sockaddr_in *)storage_v4; inet_pton(AF_INET, host, &addr->sin_addr); addr->sin_family = AF_INET; LOGI("binding to outbound IPv4 addr: %s", host); return AF_INET; } else if (ip.version == 6) { memset(storage_v6, 0, sizeof(struct sockaddr_storage)); struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage_v6; inet_pton(AF_INET6, host, &addr->sin6_addr); addr->sin6_family = AF_INET6; LOGI("binding to outbound IPv6 addr: %s", host); return AF_INET6; } } } return 0; } int bind_to_addr(struct sockaddr_storage *storage, int socket_fd) { if (storage->ss_family == AF_INET) { return bind(socket_fd, (struct sockaddr *)storage, sizeof(struct sockaddr_in)); } else if (storage->ss_family == AF_INET6) { return bind(socket_fd, (struct sockaddr *)storage, sizeof(struct sockaddr_in6)); } return -1; } ssize_t get_sockaddr(char *host, char *port, struct sockaddr_storage *storage, int block, int ipv6first) { struct cork_ip ip; if (cork_ip_init(&ip, host) != -1) { if (ip.version == 4) { struct sockaddr_in *addr = (struct sockaddr_in *)storage; addr->sin_family = AF_INET; inet_pton(AF_INET, host, &(addr->sin_addr)); if (port != NULL) { addr->sin_port = htons(atoi(port)); } } else if (ip.version == 6) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage; addr->sin6_family = AF_INET6; inet_pton(AF_INET6, host, &(addr->sin6_addr)); if (port != NULL) { addr->sin6_port = htons(atoi(port)); } } return 0; } else { #ifdef __ANDROID__ extern int vpn; assert(!vpn); // protecting DNS packets isn't supported yet #endif struct addrinfo hints; struct addrinfo *result, *rp; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */ int err = getaddrinfo(host, port, &hints, &result); if (err != 0) { LOGE("getaddrinfo: %s", gai_strerror(err)); return -1; } int prefer_af = ipv6first ? AF_INET6 : AF_INET; for (rp = result; rp != NULL; rp = rp->ai_next) if (rp->ai_family == prefer_af) { if (rp->ai_family == AF_INET) memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in)); else if (rp->ai_family == AF_INET6) memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6)); break; } if (rp == NULL) { for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in)); else if (rp->ai_family == AF_INET6) memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6)); break; } } if (rp == NULL) { LOGE("failed to resolve remote addr"); return -1; } freeaddrinfo(result); return 0; } return -1; } int sockaddr_cmp(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, socklen_t len) { struct sockaddr_in *p1_in = (struct sockaddr_in *)addr1; struct sockaddr_in *p2_in = (struct sockaddr_in *)addr2; struct sockaddr_in6 *p1_in6 = (struct sockaddr_in6 *)addr1; struct sockaddr_in6 *p2_in6 = (struct sockaddr_in6 *)addr2; if (p1_in->sin_family < p2_in->sin_family) return -1; if (p1_in->sin_family > p2_in->sin_family) return 1; /* compare ip4 */ if (p1_in->sin_family == AF_INET) { /* just order it, ntohs not required */ if (p1_in->sin_port < p2_in->sin_port) return -1; if (p1_in->sin_port > p2_in->sin_port) return 1; return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE); } else if (p1_in6->sin6_family == AF_INET6) { /* just order it, ntohs not required */ if (p1_in6->sin6_port < p2_in6->sin6_port) return -1; if (p1_in6->sin6_port > p2_in6->sin6_port) return 1; return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr, INET6_SIZE); } else { /* eek unknown type, perform this comparison for sanity. */ return memcmp(addr1, addr2, len); } } int sockaddr_cmp_addr(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, socklen_t len) { struct sockaddr_in *p1_in = (struct sockaddr_in *)addr1; struct sockaddr_in *p2_in = (struct sockaddr_in *)addr2; struct sockaddr_in6 *p1_in6 = (struct sockaddr_in6 *)addr1; struct sockaddr_in6 *p2_in6 = (struct sockaddr_in6 *)addr2; if (p1_in->sin_family < p2_in->sin_family) return -1; if (p1_in->sin_family > p2_in->sin_family) return 1; if (verbose) { LOGI("sockaddr_cmp_addr: sin_family equal? %d", p1_in->sin_family == p2_in->sin_family); } /* compare ip4 */ if (p1_in->sin_family == AF_INET) { return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE); } else if (p1_in6->sin6_family == AF_INET6) { return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr, INET6_SIZE); } else { /* eek unknown type, perform this comparison for sanity. */ return memcmp(addr1, addr2, len); } } int validate_hostname(const char *hostname, const int hostname_len) { if (hostname == NULL) return 0; if (hostname_len < 1 || hostname_len > 255) return 0; if (hostname[0] == '.') return 0; const char *label = hostname; while (label < hostname + hostname_len) { size_t label_len = hostname_len - (label - hostname); char *next_dot = strchr(label, '.'); if (next_dot != NULL) label_len = next_dot - label; if (label + label_len > hostname + hostname_len) return 0; if (label_len > 63 || label_len < 1) return 0; if (label[0] == '-' || label[label_len - 1] == '-') return 0; if (strspn(label, valid_label_bytes) < label_len) return 0; label += label_len + 1; } return 1; } int is_ipv6only(ss_addr_t *servers, size_t server_num, int ipv6first) { int i; for (i = 0; i < server_num; i++) { struct sockaddr_storage storage; memset(&storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(servers[i].host, servers[i].port, &storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } if (storage.ss_family != AF_INET6) { return 0; } } return 1; } ================================================ FILE: src/netutils.h ================================================ /* * netutils.h - Network utilities * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _NETUTILS_H #define _NETUTILS_H #ifdef __MINGW32__ #include "winsock.h" #else #include #endif #if defined(HAVE_LINUX_TCP_H) #include #elif defined(HAVE_NETINET_TCP_H) #include #elif defined(HAVE_NETDB_H) #include #endif /* Hard coded defines for TCP fast open on Android */ #ifdef __ANDROID__ #ifndef TCP_FASTOPEN #define TCP_FASTOPEN 23 #endif #ifndef MSG_FASTOPEN #define MSG_FASTOPEN 0x20000000 #endif #ifdef TCP_FASTOPEN_CONNECT #undef TCP_FASTOPEN_CONNECT #endif #endif #define MAX_HOSTNAME_LEN 256 // FQCN <= 255 characters #define MAX_PORT_STR_LEN 6 // PORT < 65536 #define SOCKET_BUF_SIZE (16 * 1024 - 1) // 16383 Byte, equals to the max chunk size typedef struct { char *host; char *port; } ss_addr_t; // Be compatible with older libc. #ifndef IPPROTO_MPTCP #define IPPROTO_MPTCP 262 #endif /* MPTCP_ENABLED setsockopt values for out-of-tree kernel 4 & 3, best behaviour * to be independent of kernel version is to test from newest to latest values. */ #ifndef MPTCP_ENABLED static const char mptcp_enabled_values[] = { 42, 26, 0 }; #else static const char mptcp_enabled_values[] = { MPTCP_ENABLED, 0 }; #endif #ifndef UPDATE_INTERVAL #define UPDATE_INTERVAL 5 #endif /** byte size of ip4 address */ #define INET_SIZE 4 /** byte size of ip6 address */ #define INET6_SIZE 16 size_t get_sockaddr_len(struct sockaddr *addr); ssize_t get_sockaddr(char *host, char *port, struct sockaddr_storage *storage, int block, int ipv6first); int set_reuseport(int socket); #ifdef SET_INTERFACE int setinterface(int socket_fd, const char *interface_name); #endif int parse_local_addr(struct sockaddr_storage *storage_v4, struct sockaddr_storage *storage_v6, const char *host); int bind_to_addr(struct sockaddr_storage *storage, int socket_fd); /** * Compare two sockaddrs. Imposes an ordering on the addresses. * Compares address and port. * @param addr1: address 1. * @param addr2: address 2. * @param len: lengths of addr. * @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger. */ int sockaddr_cmp(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, socklen_t len); /** * Compare two sockaddrs. Compares address, not the port. * @param addr1: address 1. * @param addr2: address 2. * @param len: lengths of addr. * @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger. */ int sockaddr_cmp_addr(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, socklen_t len); int validate_hostname(const char *hostname, const int hostname_len); int is_ipv6only(ss_addr_t *servers, size_t server_num, int ipv6first); #endif ================================================ FILE: src/plugin.c ================================================ /* * plugin.c - Manage plugins * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifndef __MINGW32__ #include #include #include #include #endif #include #include #include "utils.h" #include "plugin.h" #include "winsock.h" #define CMD_RESRV_LEN 128 #ifndef __MINGW32__ #define TEMPDIR "/tmp/" #else #define TEMPDIR #endif static int exit_code; static struct cork_env *env = NULL; static struct cork_exec *exec = NULL; static struct cork_subprocess *sub = NULL; #ifdef __MINGW32__ static uint16_t sub_control_port = 0; void cork_subprocess_set_control(struct cork_subprocess *self, uint16_t port); #endif static int plugin_log__data(struct cork_stream_consumer *vself, const void *buf, size_t size, bool is_first) { size_t bytes_written = fwrite(buf, 1, size, stderr); /* If there was an error writing to the file, then signal this * to the producer */ if (bytes_written == size) { return 0; } else { cork_system_error_set(); return -1; } } static int plugin_log__eof(struct cork_stream_consumer *vself) { /* We don't close the file, so there's nothing special to do at * end-of-stream. */ return 0; } static void plugin_log__free(struct cork_stream_consumer *vself) { return; } struct cork_stream_consumer plugin_log = { .data = plugin_log__data, .eof = plugin_log__eof, .free = plugin_log__free, }; static int start_ss_plugin(const char *plugin, const char *plugin_opts, const char *remote_host, const char *remote_port, const char *local_host, const char *local_port, enum plugin_mode mode) { cork_env_add(env, "SS_REMOTE_HOST", remote_host); cork_env_add(env, "SS_REMOTE_PORT", remote_port); cork_env_add(env, "SS_LOCAL_HOST", local_host); cork_env_add(env, "SS_LOCAL_PORT", local_port); if (plugin_opts != NULL) cork_env_add(env, "SS_PLUGIN_OPTIONS", plugin_opts); exec = cork_exec_new(plugin); cork_exec_add_param(exec, plugin); // argv[0] #ifdef __ANDROID__ extern int vpn; if (vpn) cork_exec_add_param(exec, "-V"); #endif cork_exec_set_env(exec, env); sub = cork_subprocess_new_exec(exec, NULL, NULL, &exit_code); #ifdef __MINGW32__ cork_subprocess_set_control(sub, sub_control_port); #endif return cork_subprocess_start(sub); } #define OBFSPROXY_OPTS_MAX 4096 /* * For obfsproxy, we use standalone mode for now. * Managed mode needs to use SOCKS5 proxy as forwarder, which is not supported * yet. * * The idea of using standalone mode is quite simple, just assemble the * internal port into obfsproxy parameters. * * Using manually ran scramblesuit as an example: * obfsproxy \ * --data-dir /tmp/ss_libev_plugin_with_suffix \ * scramblesuit \ * --password SOMEMEANINGLESSPASSWORDASEXAMPLE \ * --dest some.server.org:12345 \ * client \ * 127.0.0.1:54321 * * In above case, @plugin = "obfsproxy", * @plugin_opts = "scramblesuit --password SOMEMEANINGLESSPASSWORDASEXAMPLE" * For obfs3, it's even easier, just pass @plugin = "obfsproxy" * @plugin_opts = "obfs3" * * And the rest parameters are all assembled here. * Some old obfsproxy will not be supported as it doesn't even support * "--data-dir" option */ static int start_obfsproxy(const char *plugin, const char *plugin_opts, const char *remote_host, const char *remote_port, const char *local_host, const char *local_port, enum plugin_mode mode) { char *pch; char *opts_dump = NULL; char *buf = NULL; int ret, buf_size = 0; if (plugin_opts != NULL) { opts_dump = strndup(plugin_opts, OBFSPROXY_OPTS_MAX); if (!opts_dump) { ERROR("start_obfsproxy strndup failed"); if (env != NULL) { cork_env_free(env); } return -ENOMEM; } } exec = cork_exec_new(plugin); /* The first parameter will be skipped, so pass @plugin again */ cork_exec_add_param(exec, plugin); cork_exec_add_param(exec, "--data-dir"); buf_size = 20 + strlen(plugin) + strlen(remote_host) + strlen(remote_port) + strlen(local_host) + strlen(local_port); buf = ss_malloc(buf_size); snprintf(buf, buf_size, TEMPDIR "%s_%s:%s_%s:%s", plugin, remote_host, remote_port, local_host, local_port); cork_exec_add_param(exec, buf); /* * Iterate @plugin_opts by space */ if (opts_dump != NULL) { pch = strtok(opts_dump, " "); while (pch) { cork_exec_add_param(exec, pch); pch = strtok(NULL, " "); } } /* The rest options */ if (mode == MODE_CLIENT) { /* Client mode */ cork_exec_add_param(exec, "--dest"); snprintf(buf, buf_size, "%s:%s", remote_host, remote_port); cork_exec_add_param(exec, buf); cork_exec_add_param(exec, "client"); snprintf(buf, buf_size, "%s:%s", local_host, local_port); cork_exec_add_param(exec, buf); } else { /* Server mode */ cork_exec_add_param(exec, "--dest"); snprintf(buf, buf_size, "%s:%s", local_host, local_port); cork_exec_add_param(exec, buf); cork_exec_add_param(exec, "server"); snprintf(buf, buf_size, "%s:%s", remote_host, remote_port); cork_exec_add_param(exec, buf); } cork_exec_set_env(exec, env); sub = cork_subprocess_new_exec(exec, NULL, NULL, &exit_code); #ifdef __MINGW32__ cork_subprocess_set_control(sub, sub_control_port); #endif ret = cork_subprocess_start(sub); ss_free(opts_dump); free(buf); return ret; } int start_plugin(const char *plugin, const char *plugin_opts, const char *remote_host, const char *remote_port, const char *local_host, const char *local_port, #ifdef __MINGW32__ uint16_t control_port, #endif enum plugin_mode mode) { #ifndef __MINGW32__ char *new_path = NULL; const char *current_path; size_t new_path_len; #endif int ret; if (plugin == NULL) return -1; if (strlen(plugin) == 0) return 0; #ifndef __MINGW32__ /* * Add current dir to PATH, so we can search plugin in current dir */ env = cork_env_clone_current(); current_path = cork_env_get(env, "PATH"); if (current_path != NULL) { #ifdef HAVE_GET_CURRENT_DIR_NAME char *cwd = get_current_dir_name(); if (cwd) { #else char cwd[PATH_MAX]; if (getcwd(cwd, PATH_MAX) != NULL) { #endif new_path_len = strlen(current_path) + strlen(cwd) + 2; new_path = ss_malloc(new_path_len); snprintf(new_path, new_path_len, "%s:%s", cwd, current_path); #ifdef HAVE_GET_CURRENT_DIR_NAME free(cwd); #endif } } if (new_path != NULL) cork_env_add(env, "PATH", new_path); #else sub_control_port = control_port; #endif if (!strncmp(plugin, "obfsproxy", strlen("obfsproxy"))) ret = start_obfsproxy(plugin, plugin_opts, remote_host, remote_port, local_host, local_port, mode); else ret = start_ss_plugin(plugin, plugin_opts, remote_host, remote_port, local_host, local_port, mode); #ifndef __MINGW32__ ss_free(new_path); #endif env = NULL; return ret; } uint16_t get_local_port() { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { return 0; } struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = 0; if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { close(sock); return 0; } socklen_t len = sizeof(serv_addr); if (getsockname(sock, (struct sockaddr *)&serv_addr, &len) == -1) { close(sock); return 0; } if (close(sock) < 0) { return 0; } return ntohs(serv_addr.sin_port); } void stop_plugin() { if (sub != NULL) { cork_subprocess_abort(sub); #ifndef __MINGW32__ if (cork_subprocess_wait(sub) == -1) { LOGI("error on terminating the plugin."); } #endif cork_subprocess_free(sub); } } int is_plugin_running() { if (sub != NULL) { return cork_subprocess_is_finished(sub); } return 0; } ================================================ FILE: src/plugin.h ================================================ /* * acl.h - Define the ACL interface * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _PLUGIN_H #define _PLUGIN_H #define PLUGIN_EXIT_ERROR -2 #define PLUGIN_EXIT_NORMAL -1 #define PLUGIN_RUNNING 0 enum plugin_mode { MODE_CLIENT, MODE_SERVER }; /* * XXX: Since we have SS plugins and obfsproxy support, for now we will * do extra check against the plugin name. * For obfsproxy, we will not follow the SS specified protocol and * do special routine for obfsproxy. * This may change when the protocol is finally settled * * Main function to start a plugin. * * @plugin: name of the plugin * search from PATH and current directory. * @plugin_opts: Special options for plugin * @remote_host: * CLIENT mode: * The remote server address, which also runs corresponding plugin * SERVER mode: * The real listen address, which plugin will listen to * @remote_port: * CLIENT mode: * The remote server port, which corresponding plugin is listening to * SERVER mode: * The real listen port, which plugin will listen to * @local_host: * Where ss-libev will connect/listen to. * Normally localhost for both modes. * @local_port: * Where ss-libev will connect/listen to. * Internal user port. * @mode: * Indicates which mode the plugin should run at. */ int start_plugin(const char *plugin, const char *plugin_opts, const char *remote_host, const char *remote_port, const char *local_host, const char *local_port, #ifdef __MINGW32__ uint16_t control_port, #endif enum plugin_mode mode); uint16_t get_local_port(); void stop_plugin(); int is_plugin_running(); #endif // _PLUGIN_H ================================================ FILE: src/ppbloom.c ================================================ /* * ppbloom.c - Ping-Pong Bloom Filter for nonce reuse detection * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #include #include #include "bloom.h" #include "ppbloom.h" #include "utils.h" #define PING 0 #define PONG 1 static struct bloom ppbloom[2]; static int bloom_count[2]; static int current; static int entries; static double error; int ppbloom_init(int n, double e) { int err; entries = n / 2; error = e; err = bloom_init(ppbloom + PING, entries, error); if (err) return err; err = bloom_init(ppbloom + PONG, entries, error); if (err) return err; bloom_count[PING] = 0; bloom_count[PONG] = 0; current = PING; return 0; } int ppbloom_check(const void *buffer, int len) { int ret; ret = bloom_check(ppbloom + PING, buffer, len); if (ret) return ret; ret = bloom_check(ppbloom + PONG, buffer, len); if (ret) return ret; return 0; } int ppbloom_add(const void *buffer, int len) { int err; err = bloom_add(ppbloom + current, buffer, len); if (err == -1) return err; bloom_count[current]++; if (bloom_count[current] >= entries) { bloom_count[current] = 0; current = current == PING ? PONG : PING; bloom_reset(ppbloom + current); } return 0; } void ppbloom_free() { bloom_free(ppbloom + PING); bloom_free(ppbloom + PONG); } ================================================ FILE: src/ppbloom.h ================================================ /* * ppbloom.h - Define the Ping-Pong Bloom Filter interface * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _PPBLOOM_ #define _PPBLOOM_ int ppbloom_init(int entries, double error); int ppbloom_check(const void *buffer, int len); int ppbloom_add(const void *buffer, int len); void ppbloom_free(void); #endif ================================================ FILE: src/redir.c ================================================ /* * redir.c - Provide a transparent TCP proxy through remote shadowsocks * server * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "plugin.h" #include "netutils.h" #include "utils.h" #include "common.h" #include "redir.h" #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif #ifndef IP6T_SO_ORIGINAL_DST #define IP6T_SO_ORIGINAL_DST 80 #endif #ifndef IP_TRANSPARENT #define IP_TRANSPARENT 19 #endif #ifndef IPV6_TRANSPARENT #define IPV6_TRANSPARENT 75 #endif static void accept_cb(EV_P_ ev_io *w, int revents); static void server_recv_cb(EV_P_ ev_io *w, int revents); static void server_send_cb(EV_P_ ev_io *w, int revents); static void remote_recv_cb(EV_P_ ev_io *w, int revents); static void remote_send_cb(EV_P_ ev_io *w, int revents); static remote_t *new_remote(int fd, int timeout); static server_t *new_server(int fd); static void free_remote(remote_t *remote); static void close_and_free_remote(EV_P_ remote_t *remote); static void free_server(server_t *server); static void close_and_free_server(EV_P_ server_t *server); int verbose = 0; int reuse_port = 0; int tcp_incoming_sndbuf = 0; int tcp_incoming_rcvbuf = 0; int tcp_outgoing_sndbuf = 0; int tcp_outgoing_rcvbuf = 0; static crypto_t *crypto; static int ipv6first = 0; static int mode = TCP_ONLY; #ifdef HAVE_SETRLIMIT static int nofile = 0; #endif int fast_open = 0; static int no_delay = 0; static int ret_val = 0; static struct ev_signal sigint_watcher; static struct ev_signal sigterm_watcher; static struct ev_signal sigchld_watcher; static int tcp_tproxy = 0; /* use tproxy instead of redirect (for tcp) */ static int getdestaddr(int fd, struct sockaddr_storage *destaddr) { socklen_t socklen = sizeof(*destaddr); int error = 0; if (tcp_tproxy) { error = getsockname(fd, (void *)destaddr, &socklen); } else { error = getsockopt(fd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, destaddr, &socklen); if (error) { // Didn't find a proper way to detect IP version. error = getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, destaddr, &socklen); } } if (error) { return -1; } return 0; } int setnonblocking(int fd) { int flags; if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { flags = 0; } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } int create_and_bind(const char *addr, const char *port) { struct addrinfo hints; struct addrinfo *result, *rp; int s, listen_sock = -1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */ result = NULL; s = getaddrinfo(addr, port, &hints, &result); if (s != 0) { LOGI("getaddrinfo: %s", gai_strerror(s)); return -1; } if (result == NULL) { LOGE("Could not bind"); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { listen_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (listen_sock == -1) { continue; } int opt = 1; setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(listen_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif if (reuse_port) { int err = set_reuseport(listen_sock); if (err == 0) { LOGI("tcp port reuse enabled"); } } if (tcp_tproxy) { int level = 0, optname = 0; if (rp->ai_family == AF_INET) { level = IPPROTO_IP; optname = IP_TRANSPARENT; } else { level = IPPROTO_IPV6; optname = IPV6_TRANSPARENT; } if (setsockopt(listen_sock, level, optname, &opt, sizeof(opt)) != 0) { ERROR("setsockopt IP_TRANSPARENT"); exit(EXIT_FAILURE); } LOGI("tcp tproxy mode enabled"); } s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ break; } else { ERROR("bind"); } close(listen_sock); listen_sock = -1; } freeaddrinfo(result); return listen_sock; } static void server_recv_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_recv_ctx = (server_ctx_t *)w; server_t *server = server_recv_ctx->server; remote_t *remote = server->remote; ev_timer_stop(EV_A_ & server->delayed_connect_watcher); ssize_t r = recv(server->fd, remote->buf->data + remote->buf->len, SOCKET_BUF_SIZE - remote->buf->len, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("server recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } remote->buf->len += r; if (verbose) { uint16_t port = 0; char ipstr[INET6_ADDRSTRLEN]; memset(&ipstr, 0, INET6_ADDRSTRLEN); if (AF_INET == server->destaddr.ss_family) { struct sockaddr_in *sa = (struct sockaddr_in *)&(server->destaddr); inet_ntop(AF_INET, &(sa->sin_addr), ipstr, INET_ADDRSTRLEN); port = ntohs(sa->sin_port); } else { struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(server->destaddr); inet_ntop(AF_INET6, &(sa->sin6_addr), ipstr, INET6_ADDRSTRLEN); port = ntohs(sa->sin6_port); } LOGI("redir to %s:%d, len=%zu, recv=%zd", ipstr, port, remote->buf->len, r); } if (!remote->send_ctx->connected) { ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } int err = crypto->encrypt(remote->buf, server->e_ctx, SOCKET_BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } int s = send(remote->fd, remote->buf->data, remote->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send remote->buf->idx = 0; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { ERROR("send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < remote->buf->len) { remote->buf->len -= s; remote->buf->idx = s; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { remote->buf->idx = 0; remote->buf->len = 0; } } static void server_send_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_send_ctx = (server_ctx_t *)w; server_t *server = server_send_ctx->server; remote_t *remote = server->remote; if (server->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(server->fd, server->buf->data + server->buf->idx, server->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < server->buf->len) { // partly sent, move memory, wait for the next time to send server->buf->len -= s; server->buf->idx += s; return; } else { // all sent out, wait for reading server->buf->len = 0; server->buf->idx = 0; ev_io_stop(EV_A_ & server_send_ctx->io); ev_io_start(EV_A_ & remote->recv_ctx->io); } } } static void delayed_connect_cb(EV_P_ ev_timer *watcher, int revents) { server_t *server = cork_container_of(watcher, server_t, delayed_connect_watcher); remote_t *remote = server->remote; int r = connect(remote->fd, remote->addr, get_sockaddr_len(remote->addr)); remote->addr = NULL; if (r == -1 && errno != CONNECT_IN_PROGRESS) { ERROR("connect"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // listen to remote connected event ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); } } static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) { remote_ctx_t *remote_ctx = cork_container_of(watcher, remote_ctx_t, watcher); remote_t *remote = remote_ctx->remote; server_t *server = remote->server; ev_timer_stop(EV_A_ watcher); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } static void remote_recv_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w; remote_t *remote = remote_recv_ctx->remote; server_t *server = remote->server; ssize_t r = recv(remote->fd, server->buf->data, SOCKET_BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("remote recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } server->buf->len = r; int err = crypto->decrypt(server->buf, server->d_ctx, SOCKET_BUF_SIZE); if (err == CRYPTO_ERROR) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (err == CRYPTO_NEED_MORE) { return; // Wait for more } int s = send(server->fd, server->buf->data, server->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send server->buf->idx = 0; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); } else { ERROR("send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < server->buf->len) { server->buf->len -= s; server->buf->idx = s; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); } // Disable TCP_NODELAY after the first response are sent if (!remote->recv_ctx->connected && !no_delay) { int opt = 0; setsockopt(server->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); setsockopt(remote->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); } remote->recv_ctx->connected = 1; } static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; ev_timer_stop(EV_A_ & remote_send_ctx->watcher); if (!remote_send_ctx->connected) { int r = 0; if (remote->addr == NULL) { struct sockaddr_storage addr; memset(&addr, 0, sizeof(struct sockaddr_storage)); socklen_t len = sizeof addr; r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); } if (r == 0) { remote_send_ctx->connected = 1; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); ev_io_start(EV_A_ & remote->recv_ctx->io); // send destaddr buffer_t ss_addr_to_send; buffer_t *abuf = &ss_addr_to_send; balloc(abuf, SOCKET_BUF_SIZE); if (AF_INET6 == server->destaddr.ss_family) { // IPv6 abuf->data[abuf->len++] = 4; // Type 4 is IPv6 address size_t in6_addr_len = sizeof(struct in6_addr); memcpy(abuf->data + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr), in6_addr_len); abuf->len += in6_addr_len; memcpy(abuf->data + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port), 2); } else { // IPv4 abuf->data[abuf->len++] = 1; // Type 1 is IPv4 address size_t in_addr_len = sizeof(struct in_addr); memcpy(abuf->data + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_addr, in_addr_len); abuf->len += in_addr_len; memcpy(abuf->data + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_port, 2); } abuf->len += 2; int err = crypto->encrypt(abuf, server->e_ctx, SOCKET_BUF_SIZE); if (err) { LOGE("invalid password or cipher"); bfree(abuf); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } err = crypto->encrypt(remote->buf, server->e_ctx, SOCKET_BUF_SIZE); if (err) { LOGE("invalid password or cipher"); bfree(abuf); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } bprepend(remote->buf, abuf, SOCKET_BUF_SIZE); bfree(abuf); } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send int s = -1; if (remote->addr != NULL) { #if defined(TCP_FASTOPEN_CONNECT) int optval = 1; if (setsockopt(remote->fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&optval, sizeof(optval)) < 0) FATAL("failed to set TCP_FASTOPEN_CONNECT"); s = connect(remote->fd, remote->addr, get_sockaddr_len(remote->addr)); if (s == 0) s = send(remote->fd, remote->buf->data, remote->buf->len, 0); #elif defined(MSG_FASTOPEN) s = sendto(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, MSG_FASTOPEN, remote->addr, get_sockaddr_len(remote->addr)); #else FATAL("tcp fast open is not supported on this platform"); #endif remote->addr = NULL; if (s == -1) { if (errno == CONNECT_IN_PROGRESS) { ev_io_start(EV_A_ & remote_send_ctx->io); ev_timer_start(EV_A_ & remote_send_ctx->watcher); } else { if (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT || errno == ENOPROTOOPT) { fast_open = 0; LOGE("fast open is not supported on this platform"); } else { ERROR("fast_open_connect"); } close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } } else { s = send(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, 0); } if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf->len) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; ev_io_start(EV_A_ & remote_send_ctx->io); return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } } static remote_t * new_remote(int fd, int timeout) { remote_t *remote = ss_malloc(sizeof(remote_t)); memset(remote, 0, sizeof(remote_t)); remote->recv_ctx = ss_malloc(sizeof(remote_ctx_t)); remote->send_ctx = ss_malloc(sizeof(remote_ctx_t)); remote->buf = ss_malloc(sizeof(buffer_t)); balloc(remote->buf, SOCKET_BUF_SIZE); memset(remote->recv_ctx, 0, sizeof(remote_ctx_t)); memset(remote->send_ctx, 0, sizeof(remote_ctx_t)); remote->fd = fd; remote->recv_ctx->remote = remote; remote->recv_ctx->connected = 0; remote->send_ctx->remote = remote; remote->send_ctx->connected = 0; ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ); ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE); ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb, min(MAX_CONNECT_TIMEOUT, timeout), 0); return remote; } static void free_remote(remote_t *remote) { if (remote->server != NULL) { remote->server->remote = NULL; } if (remote->buf != NULL) { bfree(remote->buf); ss_free(remote->buf); } ss_free(remote->recv_ctx); ss_free(remote->send_ctx); ss_free(remote); } static void close_and_free_remote(EV_P_ remote_t *remote) { if (remote != NULL) { ev_timer_stop(EV_A_ & remote->send_ctx->watcher); ev_io_stop(EV_A_ & remote->send_ctx->io); ev_io_stop(EV_A_ & remote->recv_ctx->io); close(remote->fd); free_remote(remote); } } static server_t * new_server(int fd) { server_t *server = ss_malloc(sizeof(server_t)); memset(server, 0, sizeof(server_t)); server->recv_ctx = ss_malloc(sizeof(server_ctx_t)); server->send_ctx = ss_malloc(sizeof(server_ctx_t)); server->buf = ss_malloc(sizeof(buffer_t)); balloc(server->buf, SOCKET_BUF_SIZE); memset(server->recv_ctx, 0, sizeof(server_ctx_t)); memset(server->send_ctx, 0, sizeof(server_ctx_t)); server->fd = fd; server->recv_ctx->server = server; server->recv_ctx->connected = 0; server->send_ctx->server = server; server->send_ctx->connected = 0; server->e_ctx = ss_malloc(sizeof(cipher_ctx_t)); server->d_ctx = ss_malloc(sizeof(cipher_ctx_t)); crypto->ctx_init(crypto->cipher, server->e_ctx, 1); crypto->ctx_init(crypto->cipher, server->d_ctx, 0); ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ); ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE); ev_timer_init(&server->delayed_connect_watcher, delayed_connect_cb, 0.05, 0); return server; } static void free_server(server_t *server) { if (server->remote != NULL) { server->remote->server = NULL; } if (server->e_ctx != NULL) { crypto->ctx_release(server->e_ctx); ss_free(server->e_ctx); } if (server->d_ctx != NULL) { crypto->ctx_release(server->d_ctx); ss_free(server->d_ctx); } if (server->buf != NULL) { bfree(server->buf); ss_free(server->buf); } ss_free(server->recv_ctx); ss_free(server->send_ctx); ss_free(server); } static void close_and_free_server(EV_P_ server_t *server) { if (server != NULL) { ev_io_stop(EV_A_ & server->send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); ev_timer_stop(EV_A_ & server->delayed_connect_watcher); close(server->fd); free_server(server); } } static void accept_cb(EV_P_ ev_io *w, int revents) { listen_ctx_t *listener = (listen_ctx_t *)w; struct sockaddr_storage destaddr; memset(&destaddr, 0, sizeof(struct sockaddr_storage)); int err; int serverfd = accept(listener->fd, NULL, NULL); if (serverfd == -1) { ERROR("accept"); return; } err = getdestaddr(serverfd, &destaddr); if (err) { ERROR("getdestaddr"); return; } setnonblocking(serverfd); int opt = 1; setsockopt(serverfd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif if (tcp_incoming_sndbuf > 0) { setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &tcp_incoming_sndbuf, sizeof(int)); } if (tcp_incoming_rcvbuf > 0) { setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &tcp_incoming_rcvbuf, sizeof(int)); } int index = rand() % listener->remote_num; struct sockaddr *remote_addr = listener->remote_addr[index]; int protocol = IPPROTO_TCP; if (listener->mptcp < 0) { protocol = IPPROTO_MPTCP; // Enable upstream MPTCP } int remotefd = socket(remote_addr->sa_family, SOCK_STREAM, protocol); if (remotefd == -1) { ERROR("socket"); return; } // Set flags setsockopt(remotefd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif // Enable TCP keepalive feature int keepAlive = 1; int keepIdle = 40; int keepInterval = 20; int keepCount = 5; setsockopt(remotefd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive)); setsockopt(remotefd, SOL_TCP, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle)); setsockopt(remotefd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval)); setsockopt(remotefd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount)); // Set non blocking setnonblocking(remotefd); if (listener->tos >= 0) { int rc = setsockopt(remotefd, IPPROTO_IP, IP_TOS, &listener->tos, sizeof(listener->tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv4 dscp failed: %d", errno); } #ifdef IPV6_TCLASS rc = setsockopt(remotefd, IPPROTO_IPV6, IPV6_TCLASS, &listener->tos, sizeof(listener->tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv6 dscp failed: %d", errno); } #endif } // Enable out-of-tree MPTCP if (listener->mptcp > 1) { int err = setsockopt(remotefd, SOL_TCP, listener->mptcp, &opt, sizeof(opt)); if (err == -1) { ERROR("failed to enable out-of-tree multipath TCP"); } } else if (listener->mptcp == 1) { int i = 0; while ((listener->mptcp = mptcp_enabled_values[i]) > 0) { int err = setsockopt(remotefd, SOL_TCP, listener->mptcp, &opt, sizeof(opt)); if (err != -1) { break; } i++; } if (listener->mptcp == 0) { ERROR("failed to enable out-of-tree multipath TCP"); } } if (tcp_outgoing_sndbuf > 0) { setsockopt(remotefd, SOL_SOCKET, SO_SNDBUF, &tcp_outgoing_sndbuf, sizeof(int)); } if (tcp_outgoing_rcvbuf > 0) { setsockopt(remotefd, SOL_SOCKET, SO_RCVBUF, &tcp_outgoing_rcvbuf, sizeof(int)); } server_t *server = new_server(serverfd); remote_t *remote = new_remote(remotefd, listener->timeout); server->remote = remote; remote->server = server; server->destaddr = destaddr; if (fast_open) { // save remote addr for fast open remote->addr = remote_addr; ev_timer_start(EV_A_ & server->delayed_connect_watcher); } else { int r = connect(remotefd, remote_addr, get_sockaddr_len(remote_addr)); if (r == -1 && errno != CONNECT_IN_PROGRESS) { ERROR("connect"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } // listen to remote connected event ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); } ev_io_start(EV_A_ & server->recv_ctx->io); } static void signal_cb(EV_P_ ev_signal *w, int revents) { if (revents & EV_SIGNAL) { switch (w->signum) { case SIGCHLD: if (!is_plugin_running()) { LOGE("plugin service exit unexpectedly"); ret_val = -1; } else return; case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); ev_signal_stop(EV_DEFAULT, &sigchld_watcher); ev_unloop(EV_A_ EVUNLOOP_ALL); } } } int main(int argc, char **argv) { srand(time(NULL)); int i, c; int pid_flags = 0; int mptcp = 0; int mtu = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *plugin = NULL; char *plugin_opts = NULL; char *plugin_host = NULL; char *plugin_port = NULL; char tmp_port[8]; int dscp_num = 0; ss_dscp_t *dscp = NULL; int remote_num = 0; char *remote_port = NULL; ss_addr_t remote_addr[MAX_REMOTE_NUM]; memset(remote_addr, 0, sizeof(ss_addr_t) * MAX_REMOTE_NUM); static struct option long_options[] = { { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "mtu", required_argument, NULL, GETOPT_VAL_MTU }, { "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF }, { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, { "tcp-outgoing-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_SNDBUF }, { "tcp-outgoing-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_RCVBUF }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "key", required_argument, NULL, GETOPT_VAL_KEY }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; opterr = 0; USE_TTY(); while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUTv6A", long_options, NULL)) != -1) { switch (c) { case GETOPT_VAL_FAST_OPEN: fast_open = 1; break; case GETOPT_VAL_MTU: mtu = atoi(optarg); LOGI("set MTU to %d", mtu); break; case GETOPT_VAL_MPTCP: mptcp = get_mptcp(1); if (mptcp) LOGI("enable multipath TCP (%s)", mptcp > 0 ? "out-of-tree" : "upstream"); break; case GETOPT_VAL_NODELAY: no_delay = 1; LOGI("enable TCP no-delay"); break; case GETOPT_VAL_PLUGIN: plugin = optarg; break; case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; case GETOPT_VAL_KEY: key = optarg; break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; case GETOPT_VAL_TCP_INCOMING_SNDBUF: tcp_incoming_sndbuf = atoi(optarg); break; case GETOPT_VAL_TCP_INCOMING_RCVBUF: tcp_incoming_rcvbuf = atoi(optarg); break; case GETOPT_VAL_TCP_OUTGOING_SNDBUF: tcp_outgoing_sndbuf = atoi(optarg); break; case GETOPT_VAL_TCP_OUTGOING_RCVBUF: tcp_outgoing_rcvbuf = atoi(optarg); break; case 's': if (remote_num < MAX_REMOTE_NUM) { parse_addr(optarg, &remote_addr[remote_num++]); } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'T': tcp_tproxy = 1; break; case 'v': verbose = 1; break; case GETOPT_VAL_HELP: case 'h': usage(); exit(EXIT_SUCCESS); case '6': ipv6first = 1; break; case 'A': FATAL("One time auth has been deprecated. Try AEAD ciphers instead."); break; case '?': // The option character is not recognized. LOGE("Unrecognized option: %s", optarg); opterr = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = get_default_conf(); } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) remote_addr[i] = conf->remote_addr[i]; } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (key == NULL) { key = conf->key; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (user == NULL) { user = conf->user; } if (plugin == NULL) { plugin = conf->plugin; } if (plugin_opts == NULL) { plugin_opts = conf->plugin_opts; } if (mode == TCP_ONLY) { mode = conf->mode; } if (tcp_tproxy == 0) { tcp_tproxy = conf->tcp_tproxy; } if (mtu == 0) { mtu = conf->mtu; } if (mptcp == 0) { mptcp = conf->mptcp; } if (no_delay == 0) { no_delay = conf->no_delay; } if (reuse_port == 0) { reuse_port = conf->reuse_port; } if (tcp_incoming_sndbuf == 0) { tcp_incoming_sndbuf = conf->tcp_incoming_sndbuf; } if (tcp_incoming_rcvbuf == 0) { tcp_incoming_rcvbuf = conf->tcp_incoming_rcvbuf; } if (tcp_outgoing_sndbuf == 0) { tcp_outgoing_sndbuf = conf->tcp_outgoing_sndbuf; } if (tcp_outgoing_rcvbuf == 0) { tcp_outgoing_rcvbuf = conf->tcp_outgoing_rcvbuf; } if (fast_open == 0) { fast_open = conf->fast_open; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } #endif if (ipv6first == 0) { ipv6first = conf->ipv6_first; } dscp_num = conf->dscp_num; dscp = conf->dscp; } if (remote_num == 0 || remote_port == NULL || local_port == NULL || (password == NULL && key == NULL)) { usage(); exit(EXIT_FAILURE); } if (plugin != NULL) { uint16_t port = get_local_port(); if (port == 0) { FATAL("failed to find a free port"); } snprintf(tmp_port, 8, "%d", port); if (is_ipv6only(remote_addr, remote_num, ipv6first)) { plugin_host = "::1"; } else { plugin_host = "127.0.0.1"; } plugin_port = tmp_port; LOGI("plugin \"%s\" enabled", plugin); } if (method == NULL) { method = "chacha20-ietf-poly1305"; } if (timeout == NULL) { timeout = "600"; } #ifdef HAVE_SETRLIMIT /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif if (local_addr == NULL) { if (is_ipv6only(remote_addr, remote_num, ipv6first)) { local_addr = "::1"; } else { local_addr = "127.0.0.1"; } } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); fast_open = 0; #endif } USE_SYSLOG(argv[0], pid_flags); if (pid_flags) { daemonize(pid_path); } if (no_delay) { LOGI("enable TCP no-delay"); } if (ipv6first) { LOGI("resolving hostname to IPv6 address first"); } if (tcp_incoming_sndbuf != 0 && tcp_incoming_sndbuf < SOCKET_BUF_SIZE) { tcp_incoming_sndbuf = 0; } if (tcp_incoming_sndbuf != 0) { LOGI("set TCP incoming connection send buffer size to %d", tcp_incoming_sndbuf); } if (tcp_incoming_rcvbuf != 0 && tcp_incoming_rcvbuf < SOCKET_BUF_SIZE) { tcp_incoming_rcvbuf = 0; } if (tcp_incoming_rcvbuf != 0) { LOGI("set TCP incoming connection receive buffer size to %d", tcp_incoming_rcvbuf); } if (tcp_outgoing_sndbuf != 0 && tcp_outgoing_sndbuf < SOCKET_BUF_SIZE) { tcp_outgoing_sndbuf = 0; } if (tcp_outgoing_sndbuf != 0) { LOGI("set TCP outgoing connection send buffer size to %d", tcp_outgoing_sndbuf); } if (tcp_outgoing_rcvbuf != 0 && tcp_outgoing_rcvbuf < SOCKET_BUF_SIZE) { tcp_outgoing_rcvbuf = 0; } if (tcp_outgoing_rcvbuf != 0) { LOGI("set TCP outgoing connection receive buffer size to %d", tcp_outgoing_rcvbuf); } if (plugin != NULL) { int len = 0; size_t buf_size = 256 * remote_num; char *remote_str = ss_malloc(buf_size); snprintf(remote_str, buf_size, "%s", remote_addr[0].host); for (int i = 1; i < remote_num; i++) { snprintf(remote_str + len, buf_size - len, "|%s", remote_addr[i].host); len = strlen(remote_str); } int err = start_plugin(plugin, plugin_opts, remote_str, remote_port, plugin_host, plugin_port, MODE_CLIENT); if (err) { FATAL("failed to start the plugin"); } } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); ev_signal_start(EV_DEFAULT, &sigchld_watcher); // Setup keys LOGI("initializing ciphers... %s", method); crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); // Setup proxy context struct listen_ctx listen_ctx; memset(&listen_ctx, 0, sizeof(struct listen_ctx)); listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = ss_malloc(sizeof(struct sockaddr *) * remote_num); memset(listen_ctx.remote_addr, 0, sizeof(struct sockaddr *) * remote_num); for (i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; if (plugin != NULL) { host = plugin_host; port = plugin_port; } struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; if (plugin != NULL) break; } listen_ctx.timeout = atoi(timeout); listen_ctx.mptcp = mptcp; struct ev_loop *loop = EV_DEFAULT; listen_ctx_t *listen_ctx_current = &listen_ctx; do { if (listen_ctx_current->tos) { LOGI("listening at %s:%s (TOS 0x%x)", local_addr, local_port, listen_ctx_current->tos); } else { LOGI("listening at %s:%s", local_addr, local_port); } if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd == -1) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx_current->fd = listenfd; ev_io_init(&listen_ctx_current->io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx_current->io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); char *host = remote_addr[0].host; char *port = remote_addr[0].port == NULL ? remote_port : remote_addr[0].port; struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } struct sockaddr *addr = (struct sockaddr *)storage; init_udprelay(local_addr, local_port, addr, get_sockaddr_len(addr), mtu, crypto, listen_ctx_current->timeout, NULL); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } // Handle additionals TOS/DSCP listening ports if (dscp_num > 0) { listen_ctx_current = (listen_ctx_t *)ss_malloc(sizeof(listen_ctx_t)); listen_ctx_current = memcpy(listen_ctx_current, &listen_ctx, sizeof(listen_ctx_t)); local_port = dscp[dscp_num - 1].port; listen_ctx_current->tos = dscp[dscp_num - 1].dscp << 2; } } while (dscp_num-- > 0); // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); } if (geteuid() == 0) { LOGI("running from root user"); } ev_run(loop, 0); if (plugin != NULL) { stop_plugin(); } for (i = 0; i < remote_num; i++) ss_free(listen_ctx.remote_addr[i]); ss_free(listen_ctx.remote_addr); return ret_val; } ================================================ FILE: src/redir.h ================================================ /* * redir.h - Define the redirector's buffers and callbacks * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _REDIR_H #define _REDIR_H #ifdef HAVE_LIBEV_EV_H #include #else #include #endif #include "crypto.h" #include "jconf.h" typedef struct listen_ctx { ev_io io; int remote_num; int timeout; int fd; int mptcp; int tos; struct sockaddr **remote_addr; } listen_ctx_t; typedef struct server_ctx { ev_io io; int connected; struct server *server; } server_ctx_t; typedef struct server { int fd; buffer_t *buf; cipher_ctx_t *e_ctx; cipher_ctx_t *d_ctx; struct server_ctx *recv_ctx; struct server_ctx *send_ctx; struct remote *remote; struct sockaddr_storage destaddr; ev_timer delayed_connect_watcher; } server_t; typedef struct remote_ctx { ev_io io; ev_timer watcher; int connected; struct remote *remote; } remote_ctx_t; typedef struct remote { int fd; buffer_t *buf; struct remote_ctx *recv_ctx; struct remote_ctx *send_ctx; struct server *server; uint32_t counter; struct sockaddr *addr; } remote_t; #endif // _REDIR_H ================================================ FILE: src/resolv.c ================================================ /* * Copyright (c) 2014, Dustin Lundquist * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifndef __MINGW32__ #include #include #include #include #include #else #include "winsock.h" // Should be before #endif #include #ifdef HAVE_LIBEV_EV_H #include #else #include #endif #include #include "resolv.h" #include "utils.h" #include "netutils.h" #ifdef __MINGW32__ #define CONV_STATE_CB (ares_sock_state_cb) #else #define CONV_STATE_CB #endif /* * Implement DNS resolution interface using libc-ares */ #define SS_NUM_IOS 6 #define SS_INVALID_FD -1 #define SS_TIMER_AFTER 1.0 struct resolv_ctx { struct ev_io ios[SS_NUM_IOS]; struct ev_timer timer; ev_tstamp last_tick; ares_channel channel; struct ares_options options; }; struct resolv_query { int requests[2]; size_t response_count; struct sockaddr **responses; void (*client_cb)(struct sockaddr *, void *); void (*free_cb)(void *); uint16_t port; void *data; int is_closed; }; extern int verbose; static struct resolv_ctx default_ctx; static struct ev_loop *default_loop; enum { MODE_IPV4_FIRST = 0, MODE_IPV6_FIRST = 1 } RESOLV_MODE; static int resolv_mode = MODE_IPV4_FIRST; static void resolv_sock_cb(struct ev_loop *, struct ev_io *, int); static void resolv_timer_cb(struct ev_loop *, struct ev_timer *, int); static void resolv_sock_state_cb(void *, int, int, int); static void dns_query_v4_cb(void *, int, int, struct hostent *); static void dns_query_v6_cb(void *, int, int, struct hostent *); static void process_client_callback(struct resolv_query *); static inline int all_requests_are_null(struct resolv_query *); static struct sockaddr *choose_ipv4_first(struct resolv_query *); static struct sockaddr *choose_ipv6_first(struct resolv_query *); static struct sockaddr *choose_any(struct resolv_query *); /* * DNS UDP socket activity callback */ static void resolv_sock_cb(EV_P_ ev_io *w, int revents) { ares_socket_t rfd = ARES_SOCKET_BAD, wfd = ARES_SOCKET_BAD; if (revents & EV_READ) rfd = w->fd; if (revents & EV_WRITE) wfd = w->fd; default_ctx.last_tick = ev_now(default_loop); ares_process_fd(default_ctx.channel, rfd, wfd); } int resolv_init(struct ev_loop *loop, char *nameservers, int ipv6first) { int status; if (ipv6first) resolv_mode = MODE_IPV6_FIRST; else resolv_mode = MODE_IPV4_FIRST; default_loop = loop; if ((status = ares_library_init(ARES_LIB_INIT_ALL)) != ARES_SUCCESS) { LOGE("c-ares error: %s", ares_strerror(status)); FATAL("failed to initialize c-ares"); } memset(&default_ctx, 0, sizeof(struct resolv_ctx)); default_ctx.options.sock_state_cb_data = &default_ctx; default_ctx.options.sock_state_cb = CONV_STATE_CB resolv_sock_state_cb; default_ctx.options.timeout = 3000; default_ctx.options.tries = 2; status = ares_init_options(&default_ctx.channel, &default_ctx.options, #if ARES_VERSION_MAJOR >= 1 && ARES_VERSION_MINOR >= 12 ARES_OPT_NOROTATE | #endif ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES | ARES_OPT_SOCK_STATE_CB); if (status != ARES_SUCCESS) { FATAL("failed to initialize c-ares"); } if (nameservers != NULL) { #if ARES_VERSION_MAJOR >= 1 && ARES_VERSION_MINOR >= 11 status = ares_set_servers_ports_csv(default_ctx.channel, nameservers); #else status = ares_set_servers_csv(default_ctx.channel, nameservers); #endif } if (status != ARES_SUCCESS) { FATAL("failed to set nameservers"); } for (int i = 0; i < SS_NUM_IOS; i++) ev_io_init(&default_ctx.ios[i], resolv_sock_cb, SS_INVALID_FD, 0); default_ctx.last_tick = ev_now(default_loop); ev_init(&default_ctx.timer, resolv_timer_cb); resolv_timer_cb(default_loop, &default_ctx.timer, 0); return 0; } void resolv_shutdown(struct ev_loop *loop) { ev_timer_stop(default_loop, &default_ctx.timer); for (int i = 0; i < SS_NUM_IOS; i++) ev_io_stop(default_loop, &default_ctx.ios[i]); ares_cancel(default_ctx.channel); ares_destroy(default_ctx.channel); ares_library_cleanup(); } void resolv_start(const char *hostname, uint16_t port, void (*client_cb)(struct sockaddr *, void *), void (*free_cb)(void *), void *data) { /* * Wrap c-ares's call back in our own */ struct resolv_query *query = ss_malloc(sizeof(struct resolv_query)); memset(query, 0, sizeof(struct resolv_query)); query->port = port; query->client_cb = client_cb; query->response_count = 0; query->responses = NULL; query->data = data; query->free_cb = free_cb; query->requests[0] = AF_INET; query->requests[1] = AF_INET6; ares_gethostbyname(default_ctx.channel, hostname, AF_INET, dns_query_v4_cb, query); ares_gethostbyname(default_ctx.channel, hostname, AF_INET6, dns_query_v6_cb, query); } /* * Wrapper for client callback we provide to c-ares */ static void dns_query_v4_cb(void *arg, int status, int timeouts, struct hostent *he) { int i, n; struct resolv_query *query = (struct resolv_query *)arg; if (status == ARES_EDESTRUCTION) { return; } if (!he || status != ARES_SUCCESS) { if (verbose) { LOGI("failed to lookup v4 address %s", ares_strerror(status)); } goto CLEANUP; } if (verbose) { LOGI("found address name v4 address %s", he->h_name); } n = 0; while (he->h_addr_list[n]) n++; if (n > 0) { struct sockaddr **new_responses = ss_realloc(query->responses, (query->response_count + n) * sizeof(struct sockaddr *)); if (new_responses == NULL) { LOGE("failed to allocate memory for additional DNS responses"); } else { query->responses = new_responses; for (i = 0; i < n; i++) { struct sockaddr_in *sa = ss_malloc(sizeof(struct sockaddr_in)); memset(sa, 0, sizeof(struct sockaddr_in)); sa->sin_family = AF_INET; sa->sin_port = query->port; memcpy(&sa->sin_addr, he->h_addr_list[i], he->h_length); query->responses[query->response_count] = (struct sockaddr *)sa; if (query->responses[query->response_count] == NULL) { LOGE("failed to allocate memory for DNS query result address"); } else { query->response_count++; } } } } CLEANUP: query->requests[0] = 0; /* mark A query as being completed */ /* Once all requests have completed, call client callback */ if (all_requests_are_null(query)) { return process_client_callback(query); } } static void dns_query_v6_cb(void *arg, int status, int timeouts, struct hostent *he) { int i, n; struct resolv_query *query = (struct resolv_query *)arg; if (status == ARES_EDESTRUCTION) { return; } if (!he || status != ARES_SUCCESS) { if (verbose) { LOGI("failed to lookup v6 address %s", ares_strerror(status)); } goto CLEANUP; } if (verbose) { LOGI("found address name v6 address %s", he->h_name); } n = 0; while (he->h_addr_list[n]) n++; if (n > 0) { struct sockaddr **new_responses = ss_realloc(query->responses, (query->response_count + n) * sizeof(struct sockaddr *)); if (new_responses == NULL) { LOGE("failed to allocate memory for additional DNS responses"); } else { query->responses = new_responses; for (i = 0; i < n; i++) { struct sockaddr_in6 *sa = ss_malloc(sizeof(struct sockaddr_in6)); memset(sa, 0, sizeof(struct sockaddr_in6)); sa->sin6_family = AF_INET6; sa->sin6_port = query->port; memcpy(&sa->sin6_addr, he->h_addr_list[i], he->h_length); query->responses[query->response_count] = (struct sockaddr *)sa; if (query->responses[query->response_count] == NULL) { LOGE("failed to allocate memory for DNS query result address"); } else { query->response_count++; } } } } CLEANUP: query->requests[1] = 0; /* mark A query as being completed */ /* Once all requests have completed, call client callback */ if (all_requests_are_null(query)) { return process_client_callback(query); } } /* * Called once all requests have been completed */ static void process_client_callback(struct resolv_query *query) { struct sockaddr *best_address = NULL; if (resolv_mode == MODE_IPV4_FIRST) { best_address = choose_ipv4_first(query); } else if (resolv_mode == MODE_IPV6_FIRST) { best_address = choose_ipv6_first(query); } else { best_address = choose_any(query); } query->client_cb(best_address, query->data); for (int i = 0; i < query->response_count; i++) ss_free(query->responses[i]); ss_free(query->responses); if (query->free_cb != NULL) query->free_cb(query->data); else ss_free(query->data); ss_free(query); } static struct sockaddr * choose_ipv4_first(struct resolv_query *query) { for (int i = 0; i < query->response_count; i++) if (query->responses[i]->sa_family == AF_INET) { return query->responses[i]; } return choose_any(query); } static struct sockaddr * choose_ipv6_first(struct resolv_query *query) { for (int i = 0; i < query->response_count; i++) if (query->responses[i]->sa_family == AF_INET6) { return query->responses[i]; } return choose_any(query); } static struct sockaddr * choose_any(struct resolv_query *query) { if (query->response_count >= 1) { return query->responses[0]; } return NULL; } static inline int all_requests_are_null(struct resolv_query *query) { int result = 1; for (int i = 0; i < sizeof(query->requests) / sizeof(query->requests[0]); i++) result = result && query->requests[i] == 0; return result; } /* * Timer callback */ static void resolv_timer_cb(struct ev_loop *loop, struct ev_timer *w, int revents) { struct resolv_ctx *ctx = cork_container_of(w, struct resolv_ctx, timer); ev_tstamp now = ev_now(default_loop); ev_tstamp after = ctx->last_tick - now + SS_TIMER_AFTER; if (after < 0.0) { ctx->last_tick = now; ares_process_fd(ctx->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); ev_timer_set(w, SS_TIMER_AFTER, 0.0); } else { ev_timer_set(w, after, 0.0); } ev_timer_start(loop, w); } /* * Handle c-ares events */ static void resolv_sock_state_cb(void *data, int s, int read, int write) { struct resolv_ctx *ctx = (struct resolv_ctx *)data; int events = (read ? EV_READ : 0) | (write ? EV_WRITE : 0); int i = 0, ffi = -1; for (; i < SS_NUM_IOS; i++) { if (ctx->ios[i].fd == s) { break; } if (ffi < 0 && ctx->ios[i].fd == SS_INVALID_FD) { // first free index ffi = i; } } if (i < SS_NUM_IOS) { ev_io_stop(default_loop, &ctx->ios[i]); } else if (ffi > -1) { i = ffi; } else { LOGE("failed to find free I/O watcher slot for DNS query"); // last resort: stop io and re-use slot, will cause timeout i = 0; ev_io_stop(default_loop, &ctx->ios[i]); } if (events) { ev_io_set(&ctx->ios[i], s, events); ev_io_start(default_loop, &ctx->ios[i]); } else { ev_io_set(&ctx->ios[i], SS_INVALID_FD, 0); } } ================================================ FILE: src/resolv.h ================================================ /* * Copyright (c) 2014, Dustin Lundquist * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RESOLV_H #define RESOLV_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifndef __MINGW32__ #include #endif struct resolv_query; int resolv_init(struct ev_loop *, char *, int); void resolv_start(const char *hostname, uint16_t port, void (*client_cb)(struct sockaddr *, void *), void (*free_cb)(void *), void *data); void resolv_shutdown(struct ev_loop *); #endif ================================================ FILE: src/rule.c ================================================ /* * Copyright (c) 2011 and 2012, Dustin Lundquist * Copyright (c) 2011 Manuel Kasper * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "rule.h" #include "utils.h" static void free_rule(rule_t *); rule_t * new_rule() { rule_t *rule; rule = calloc(1, sizeof(rule_t)); if (rule == NULL) { ERROR("malloc"); return NULL; } return rule; } int accept_rule_arg(rule_t *rule, const char *arg) { if (rule->pattern == NULL) { rule->pattern = strdup(arg); if (rule->pattern == NULL) { ERROR("strdup failed"); return -1; } } else { LOGE("Unexpected table rule argument: %s", arg); return -1; } return 1; } void add_rule(struct cork_dllist *rules, rule_t *rule) { cork_dllist_add(rules, &rule->entries); } int init_rule(rule_t *rule) { if (rule->pattern_re == NULL) { int errcode; PCRE2_SIZE erroffset; rule->pattern_re = pcre2_compile((PCRE2_SPTR)rule->pattern, PCRE2_ZERO_TERMINATED, 0, &errcode, &erroffset, NULL); if (rule->pattern_re == NULL) { PCRE2_UCHAR errbuf[256]; pcre2_get_error_message(errcode, errbuf, sizeof(errbuf)); LOGE("Regex compilation of \"%s\" failed: %s, offset %d", rule->pattern, errbuf, (int)erroffset); return 0; } rule->match_data = pcre2_match_data_create_from_pattern( rule->pattern_re, NULL); } return 1; } rule_t * lookup_rule(const struct cork_dllist *rules, const char *name, size_t name_len) { struct cork_dllist_item *curr, *next; if (name == NULL) { name = ""; name_len = 0; } cork_dllist_foreach_void(rules, curr, next) { rule_t *rule = cork_container_of(curr, rule_t, entries); if (pcre2_match(rule->pattern_re, (PCRE2_SPTR)name, name_len, 0, 0, rule->match_data, NULL) >= 0) return rule; } return NULL; } void remove_rule(rule_t *rule) { cork_dllist_remove(&rule->entries); free_rule(rule); } static void free_rule(rule_t *rule) { if (rule == NULL) return; ss_free(rule->pattern); if (rule->match_data != NULL) pcre2_match_data_free(rule->match_data); if (rule->pattern_re != NULL) pcre2_code_free(rule->pattern_re); ss_free(rule); } ================================================ FILE: src/rule.h ================================================ /* * Copyright (c) 2011 and 2012, Dustin Lundquist * Copyright (c) 2011 Manuel Kasper * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef RULE_H #define RULE_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #define PCRE2_CODE_UNIT_WIDTH 8 #include typedef struct rule { char *pattern; /* Runtime fields */ pcre2_code *pattern_re; pcre2_match_data *match_data; struct cork_dllist_item entries; } rule_t; void add_rule(struct cork_dllist *, rule_t *); int init_rule(rule_t *); rule_t *lookup_rule(const struct cork_dllist *, const char *, size_t); void remove_rule(rule_t *); rule_t *new_rule(); int accept_rule_arg(rule_t *, const char *); #endif ================================================ FILE: src/server.c ================================================ /* * server.c - Provide shadowsocks service * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #ifndef __MINGW32__ #include #include #include #include #include #include #endif #include #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) #include #include #define SET_INTERFACE #endif #ifdef USE_NFTABLES #include #include #include #include #include /* the datatypes enum is picked from libnftables/datatype.h to avoid to depend libnftables */ enum datatypes { TYPE_IPADDR = 7, TYPE_IP6ADDR }; #endif #include "netutils.h" #include "utils.h" #include "acl.h" #include "plugin.h" #include "server.h" #include "winsock.h" #include "resolv.h" #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif #ifndef SSMAXCONN #define SSMAXCONN 1024 #endif #ifdef USE_NFCONNTRACK_TOS #ifndef MARK_MAX_PACKET #define MARK_MAX_PACKET 10 #endif #ifndef MARK_MASK_PREFIX #define MARK_MASK_PREFIX 0xDC00 #endif #endif static void signal_cb(EV_P_ ev_signal *w, int revents); static void accept_cb(EV_P_ ev_io *w, int revents); static void server_send_cb(EV_P_ ev_io *w, int revents); static void server_recv_cb(EV_P_ ev_io *w, int revents); static void remote_recv_cb(EV_P_ ev_io *w, int revents); static void remote_send_cb(EV_P_ ev_io *w, int revents); static void server_timeout_cb(EV_P_ ev_timer *watcher, int revents); static remote_t *new_remote(int fd); static server_t *new_server(int fd, listen_ctx_t *listener); static remote_t *connect_to_remote(EV_P_ struct addrinfo *res, server_t *server); static void free_remote(remote_t *remote); static void close_and_free_remote(EV_P_ remote_t *remote); static void free_server(server_t *server); static void close_and_free_server(EV_P_ server_t *server); static void resolv_cb(struct sockaddr *addr, void *data); static void resolv_free_cb(void *data); int verbose = 0; int reuse_port = 0; int tcp_incoming_sndbuf = 0; int tcp_incoming_rcvbuf = 0; int tcp_outgoing_sndbuf = 0; int tcp_outgoing_rcvbuf = 0; int is_bind_local_addr = 0; struct sockaddr_storage local_addr_v4; struct sockaddr_storage local_addr_v6; static crypto_t *crypto; static int acl = 0; static int mode = TCP_ONLY; static int ipv6first = 0; int fast_open = 0; static int no_delay = 0; static int ret_val = 0; #ifdef HAVE_SETRLIMIT static int nofile = 0; #endif static int remote_conn = 0; static int server_conn = 0; static char *plugin = NULL; static char *remote_port = NULL; static char *manager_addr = NULL; uint64_t tx = 0; uint64_t rx = 0; #ifndef __MINGW32__ ev_timer stat_update_watcher; #endif static struct ev_signal sigint_watcher; static struct ev_signal sigterm_watcher; #ifndef __MINGW32__ static struct ev_signal sigchld_watcher; #else static struct plugin_watcher_t { ev_io io; SOCKET fd; uint16_t port; int valid; } plugin_watcher; #endif static struct cork_dllist connections; #ifndef __MINGW32__ static void stat_update_cb(EV_P_ ev_timer *watcher, int revents) { struct sockaddr_un svaddr, claddr; int sfd = -1; size_t msgLen; char resp[SOCKET_BUF_SIZE]; if (verbose) { LOGI("update traffic stat: tx: %" PRIu64 " rx: %" PRIu64 "", tx, rx); } snprintf(resp, SOCKET_BUF_SIZE, "stat: {\"%s\":%" PRIu64 "}", remote_port, tx + rx); msgLen = strlen(resp) + 1; ss_addr_t ip_addr = { .host = NULL, .port = NULL }; parse_addr(manager_addr, &ip_addr); if (ip_addr.host == NULL || ip_addr.port == NULL) { sfd = socket(AF_UNIX, SOCK_DGRAM, 0); if (sfd == -1) { ERROR("stat_socket"); return; } memset(&claddr, 0, sizeof(struct sockaddr_un)); claddr.sun_family = AF_UNIX; snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/shadowsocks.%s", remote_port); unlink(claddr.sun_path); if (bind(sfd, (struct sockaddr *)&claddr, sizeof(struct sockaddr_un)) == -1) { ERROR("stat_bind"); close(sfd); return; } memset(&svaddr, 0, sizeof(struct sockaddr_un)); svaddr.sun_family = AF_UNIX; strncpy(svaddr.sun_path, manager_addr, sizeof(svaddr.sun_path) - 1); if (sendto(sfd, resp, strlen(resp) + 1, 0, (struct sockaddr *)&svaddr, sizeof(struct sockaddr_un)) != msgLen) { ERROR("stat_sendto"); close(sfd); return; } unlink(claddr.sun_path); } else { struct sockaddr_storage storage; memset(&storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(ip_addr.host, ip_addr.port, &storage, 0, ipv6first) == -1) { ERROR("failed to parse the manager addr"); return; } sfd = socket(storage.ss_family, SOCK_DGRAM, 0); if (sfd == -1) { ERROR("stat_socket"); return; } size_t addr_len = get_sockaddr_len((struct sockaddr *)&storage); if (sendto(sfd, resp, strlen(resp) + 1, 0, (struct sockaddr *)&storage, addr_len) != msgLen) { ERROR("stat_sendto"); close(sfd); return; } } close(sfd); } #endif static void free_connections(struct ev_loop *loop) { struct cork_dllist_item *curr, *next; cork_dllist_foreach_void(&connections, curr, next) { server_t *server = cork_container_of(curr, server_t, entries); remote_t *remote = server->remote; close_and_free_server(loop, server); close_and_free_remote(loop, remote); } } static char * get_peer_name(int fd) { static char peer_name[INET6_ADDRSTRLEN] = { 0 }; struct sockaddr_storage addr; socklen_t len = sizeof(struct sockaddr_storage); memset(&addr, 0, len); memset(peer_name, 0, INET6_ADDRSTRLEN); int err = getpeername(fd, (struct sockaddr *)&addr, &len); if (err == 0) { if (addr.ss_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)&addr; inet_ntop(AF_INET, &s->sin_addr, peer_name, INET_ADDRSTRLEN); } else if (addr.ss_family == AF_INET6) { struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; inet_ntop(AF_INET6, &s->sin6_addr, peer_name, INET6_ADDRSTRLEN); } } else { return NULL; } return peer_name; } static void stop_server(EV_P_ server_t *server) { server->stage = STAGE_STOP; } #ifdef USE_NFTABLES struct nftbl_set_info { uint32_t family; char *table; char *name; uint32_t type; }* nftbl_badip_sets[16]; static struct nftnl_set * nftbl_build_set(const char* table, const char* name, void* addr, size_t len) { struct nftnl_set *set = nftnl_set_alloc(); if (set == NULL) return NULL; nftnl_set_set_str(set, NFTNL_SET_TABLE, table); nftnl_set_set_str(set, NFTNL_SET_NAME, name); struct nftnl_set_elem *elem = nftnl_set_elem_alloc(); if (elem == NULL) { nftnl_set_free(set); return NULL; } nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY, addr, len); nftnl_set_elem_add(set, elem); return set; } static uint32_t nftbl_build_nlmsg(void* buf, size_t *len, uint32_t family, struct nftnl_set *set) { uint32_t seq = time(NULL); struct nlmsghdr *nlh; struct mnl_nlmsg_batch *batch = mnl_nlmsg_batch_start(buf, *len); nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq); mnl_nlmsg_batch_next(batch); nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSETELEM, family, NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK, ++seq); nftnl_set_elems_nlmsg_build_payload(nlh, set); mnl_nlmsg_batch_next(batch); nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq + 1); mnl_nlmsg_batch_next(batch); *len = mnl_nlmsg_batch_size(batch); mnl_nlmsg_batch_stop(batch); return seq; } static int nftbl_send_request(void *request, size_t len, uint32_t seq, mnl_cb_t cb, void *data) { struct mnl_socket *nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) return -1; int ret = -1; uint8_t buf[MNL_SOCKET_BUFFER_SIZE]; if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) == 0 && mnl_socket_sendto(nl, request, len) >= 0) { uint32_t portid = mnl_socket_get_portid(nl); while ((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) { ret = mnl_cb_run(buf, ret, seq, portid, cb, data); if (ret != MNL_CB_OK) break; } mnl_socket_close(nl); } return ret; } static void nftbl_report_addr(const struct sockaddr* addr) { uint32_t type; void* data; size_t size; if (addr->sa_family == AF_INET) { type = TYPE_IPADDR; data = &((struct sockaddr_in*)addr)->sin_addr; size = sizeof(struct in_addr); } else if (addr->sa_family == AF_INET6) { type = TYPE_IP6ADDR; data = &((struct sockaddr_in6*)addr)->sin6_addr; size = sizeof(struct in6_addr); } else { return; } char buf[MNL_SOCKET_BUFFER_SIZE]; for (int i = 0; nftbl_badip_sets[i]; ++i) { struct nftbl_set_info* si = nftbl_badip_sets[i]; struct nftnl_set *set; if (si->type == type && (set = nftbl_build_set(si->table, si->name, data, size))) { size_t len = sizeof(buf); uint32_t seq = nftbl_build_nlmsg(buf, &len, si->family, set); nftnl_set_free(set); if (nftbl_send_request(buf, len, seq, NULL, NULL) < 0 && errno != EEXIST) ERROR("nftbl_report_addr"); } } } static int nftbl_check_cb(const struct nlmsghdr *nlh, void *data) { struct nftnl_set *set = (struct nftnl_set*)data; if (nftnl_set_nlmsg_parse(nlh, set) < 0) return MNL_CB_ERROR; uint32_t type = nftnl_set_get_u32(set, NFTNL_SET_KEY_TYPE); if (type != TYPE_IPADDR && type != TYPE_IP6ADDR) return MNL_CB_OK; uint32_t len; const char *name = nftnl_set_get_data(set, NFTNL_SET_NAME, &len); for (int i = 0; nftbl_badip_sets[i]; ++i) { struct nftbl_set_info* si = nftbl_badip_sets[i]; if (!memcmp(name, si->name, len)) { name = nftnl_set_get_data(set, NFTNL_SET_TABLE, &len); if (!si->table) { size_t l = strlen(si->name) + 1; si = realloc(si, sizeof(*si) + l + len); si->name = (char*)(si + 1); si->table = memcpy(si->name + l, name, len); nftbl_badip_sets[i] = si; } else if (memcmp(name, si->table, len)) { continue; /* table name not match */ } si->family = nftnl_set_get_u32(set, NFTNL_SET_FAMILY); si->type = type; } } return MNL_CB_OK; } static int nftbl_check(void) { struct nftnl_set *set = nftnl_set_alloc(); if (!set) return -1; int ret; char buf[MNL_SOCKET_BUFFER_SIZE]; uint32_t seq = time(NULL); struct nlmsghdr *nlh; nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, NFPROTO_UNSPEC, NLM_F_DUMP|NLM_F_ACK, seq); nftnl_set_nlmsg_build_payload(nlh, set); ret = nftbl_send_request(nlh, nlh->nlmsg_len, seq, nftbl_check_cb, set); nftnl_set_free(set); if (ret < 0) return ret; for (int i = 0; nftbl_badip_sets[i]; ++i) { struct nftbl_set_info* si = nftbl_badip_sets[i]; if (si->family == NFPROTO_UNSPEC) { if (si->table) LOGE("set '%s' not found in table '%s'", si->name, si->table); else LOGE("set '%s' not found", si->name); ret = -1; } } if (ret < 0) FATAL("Check nftables configuration."); return ret; } static int nftbl_init(const char* set_str) { struct nftbl_set_info* si; const char *p0 = set_str, *p = p0, *d = NULL; int i = 0; do { if (*p == ':') { d = p; } else if (*p == ',' || *p == '\0') { size_t l = p - p0 + 1; si = malloc(sizeof(*si) + l); memset(si, 0, sizeof(*si)); si->name = memcpy(si + 1, p0, l); si->name[l - 1] = '\0'; if (d) { si->table = si->name; si->name = si->table + (d - p0); *(si->name++) = '\0'; d = NULL; } nftbl_badip_sets[i++] = si; if (i == sizeof(nftbl_badip_sets) / sizeof(*si) - 1) break; while (*p && isspace(*(++p))); p0 = p; } } while (*(p++)); return nftbl_check(); } #endif static void report_addr(int fd, const char *info) { char *peer_name; peer_name = get_peer_name(fd); if (peer_name != NULL) { LOGE("failed to handshake with %s: %s", peer_name, info); } #ifdef USE_NFTABLES struct sockaddr_in6 addr; socklen_t len = sizeof(struct sockaddr_in6); if (!getpeername(fd, (struct sockaddr *)&addr, &len)) nftbl_report_addr((struct sockaddr *)&addr); #endif } int setfastopen(int fd) { int s = 0; #ifdef TCP_FASTOPEN if (fast_open) { #if defined(__APPLE__) || defined(__MINGW32__) int opt = 1; #else int opt = 5; #endif s = setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &opt, sizeof(opt)); if (s == -1) { if (errno == EPROTONOSUPPORT || errno == ENOPROTOOPT) { LOGE("fast open is not supported on this platform"); fast_open = 0; } else { ERROR("setsockopt"); } } } #endif return s; } #ifndef __MINGW32__ int setnonblocking(int fd) { int flags; if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { flags = 0; } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } #endif int create_and_bind(const char *host, const char *port, int mptcp) { struct addrinfo hints; struct addrinfo *result, *rp, *ipv4v6bindall; int s, listen_sock = -1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* For wildcard IP address */ hints.ai_protocol = IPPROTO_TCP; result = NULL; s = getaddrinfo(host, port, &hints, &result); if (s != 0) { LOGE("failed to resolve server name %s", host); return -1; } if (result == NULL) { LOGE("Cannot bind"); return -1; } rp = result; /* * On Linux, with net.ipv6.bindv6only = 0 (the default), getaddrinfo(NULL) with * AI_PASSIVE returns 0.0.0.0 and :: (in this order). AI_PASSIVE was meant to * return a list of addresses to listen on, but it is impossible to listen on * 0.0.0.0 and :: at the same time, if :: implies dualstack mode. */ if (!host) { ipv4v6bindall = result; /* Loop over all address infos found until a IPV6 address is found. */ while (ipv4v6bindall) { if (ipv4v6bindall->ai_family == AF_INET6) { rp = ipv4v6bindall; /* Take first IPV6 address available */ break; } ipv4v6bindall = ipv4v6bindall->ai_next; /* Get next address info, if any */ } } for (/*rp = result*/; rp != NULL; rp = rp->ai_next) { int protocol = rp->ai_protocol; if (mptcp < 0) { protocol = IPPROTO_MPTCP; // Enable upstream MPTCP } listen_sock = socket(rp->ai_family, rp->ai_socktype, protocol); if (listen_sock == -1) { continue; } if (rp->ai_family == AF_INET6) { int opt = host ? 1 : 0; setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)); } int opt = 1; setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(listen_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif if (reuse_port) { int err = set_reuseport(listen_sock); if (err == 0) { LOGI("tcp port reuse enabled"); } } // Enable out-of-tree mptcp if (mptcp == 1) { int i = 0; while ((mptcp = mptcp_enabled_values[i]) > 0) { int err = setsockopt(listen_sock, IPPROTO_TCP, mptcp, &opt, sizeof(opt)); if (err != -1) { break; } i++; } if (mptcp == 0) { ERROR("failed to enable out-of-tree multipath TCP"); } } s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ break; } else { ERROR("bind"); FATAL("failed to bind address"); } close(listen_sock); listen_sock = -1; } freeaddrinfo(result); return listen_sock; } static remote_t * connect_to_remote(EV_P_ struct addrinfo *res, server_t *server) { int sockfd; #ifdef SET_INTERFACE const char *iface = server->listen_ctx->iface; #endif if (acl) { char ipstr[INET6_ADDRSTRLEN]; memset(ipstr, 0, INET6_ADDRSTRLEN); if (res->ai_addr->sa_family == AF_INET) { struct sockaddr_in s; memcpy(&s, res->ai_addr, sizeof(struct sockaddr_in)); inet_ntop(AF_INET, &s.sin_addr, ipstr, INET_ADDRSTRLEN); } else if (res->ai_addr->sa_family == AF_INET6) { struct sockaddr_in6 s; memcpy(&s, res->ai_addr, sizeof(struct sockaddr_in6)); inet_ntop(AF_INET6, &s.sin6_addr, ipstr, INET6_ADDRSTRLEN); } if (outbound_block_match_host(ipstr) == 1) { if (verbose) LOGI("outbound blocked %s", ipstr); return NULL; } } // initialize remote socks sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd == -1) { ERROR("socket"); close(sockfd); return NULL; } int opt = 1; setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (tcp_outgoing_sndbuf > 0) { setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &tcp_outgoing_sndbuf, sizeof(int)); } if (tcp_outgoing_rcvbuf > 0) { setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &tcp_outgoing_rcvbuf, sizeof(int)); } // setup remote socks if (setnonblocking(sockfd) == -1) ERROR("setnonblocking"); if (is_bind_local_addr) { struct sockaddr_storage *local_addr = res->ai_family == AF_INET ? &local_addr_v4 : &local_addr_v6; if (res->ai_family == local_addr->ss_family) { if (bind_to_addr(local_addr, sockfd) == -1) { ERROR("bind_to_addr"); FATAL("cannot bind socket"); return NULL; } } } #ifdef SET_INTERFACE if (iface) { if (setinterface(sockfd, iface) == -1) { ERROR("setinterface"); close(sockfd); return NULL; } } #endif remote_t *remote = new_remote(sockfd); if (fast_open) { #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) int s = -1; s = sendto(sockfd, server->buf->data + server->buf->idx, server->buf->len, MSG_FASTOPEN, res->ai_addr, res->ai_addrlen); #elif defined(TCP_FASTOPEN_WINSOCK) DWORD s = -1; DWORD err = 0; do { int optval = 1; // Set fast open option if (setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN, &optval, sizeof(optval)) != 0) { ERROR("setsockopt"); break; } // Load ConnectEx function LPFN_CONNECTEX ConnectEx = winsock_getconnectex(); if (ConnectEx == NULL) { LOGE("Cannot load ConnectEx() function"); err = WSAENOPROTOOPT; break; } // ConnectEx requires a bound socket if (winsock_dummybind(sockfd, res->ai_addr) != 0) { ERROR("bind"); break; } // Call ConnectEx to send data memset(&remote->olap, 0, sizeof(remote->olap)); remote->connect_ex_done = 0; if (ConnectEx(sockfd, res->ai_addr, res->ai_addrlen, server->buf->data + server->buf->idx, server->buf->len, &s, &remote->olap)) { remote->connect_ex_done = 1; break; } // XXX: ConnectEx pending, check later in remote_send if (WSAGetLastError() == ERROR_IO_PENDING) { err = CONNECT_IN_PROGRESS; break; } ERROR("ConnectEx"); } while (0); // Set error number if (err) { SetLastError(err); } #else int s = -1; #if defined(TCP_FASTOPEN_CONNECT) int optval = 1; if (setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&optval, sizeof(optval)) < 0) FATAL("failed to set TCP_FASTOPEN_CONNECT"); s = connect(sockfd, res->ai_addr, res->ai_addrlen); #elif defined(CONNECT_DATA_IDEMPOTENT) struct sockaddr_in sa; memcpy(&sa, res->ai_addr, sizeof(struct sockaddr_in)); sa.sin_len = sizeof(struct sockaddr_in); sa_endpoints_t endpoints; memset((char *)&endpoints, 0, sizeof(endpoints)); endpoints.sae_dstaddr = (struct sockaddr *)&sa; endpoints.sae_dstaddrlen = res->ai_addrlen; s = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, CONNECT_DATA_IDEMPOTENT, NULL, 0, NULL, NULL); #else FATAL("fast open is not enabled in this build"); #endif if (s == 0) s = send(sockfd, server->buf->data + server->buf->idx, server->buf->len, 0); #endif if (s == -1) { if (errno == CONNECT_IN_PROGRESS) { // The remote server doesn't support tfo or it's the first connection to the server. // It will automatically fall back to conventional TCP. } else if (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT || errno == ENOPROTOOPT) { // Disable fast open as it's not supported fast_open = 0; LOGE("fast open is not supported on this platform"); } else { ERROR("fast_open_connect"); } } else { server->buf->idx += s; server->buf->len -= s; } } if (!fast_open) { int r = connect(sockfd, res->ai_addr, res->ai_addrlen); if (r == -1 && errno != CONNECT_IN_PROGRESS) { ERROR("connect"); close_and_free_remote(EV_A_ remote); return NULL; } } return remote; } #ifdef USE_NFCONNTRACK_TOS int setMarkDscpCallback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { server_t *server = (server_t *)data; struct dscptracker *tracker = server->tracker; tracker->mark = nfct_get_attr_u32(ct, ATTR_MARK); if ((tracker->mark & 0xff00) == MARK_MASK_PREFIX) { // Extract DSCP value from mark value tracker->dscp = tracker->mark & 0x00ff; int tos = (tracker->dscp) << 2; if (setsockopt(server->fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) != 0) { ERROR("iptable setsockopt IP_TOS"); } } return NFCT_CB_CONTINUE; } void conntrackQuery(server_t *server) { struct dscptracker *tracker = server->tracker; if (tracker && tracker->ct) { // Trying query mark from nf conntrack struct nfct_handle *h = nfct_open(CONNTRACK, 0); if (h) { nfct_callback_register(h, NFCT_T_ALL, setMarkDscpCallback, (void *)server); int x = nfct_query(h, NFCT_Q_GET, tracker->ct); if (x == -1) { LOGE("QOS: Failed to retrieve connection mark %s", strerror(errno)); } nfct_close(h); } else { LOGE("QOS: Failed to open conntrack handle for upstream netfilter mark retrieval."); } } } void setTosFromConnmark(remote_t *remote, server_t *server) { if (server->tracker && server->tracker->ct) { if (server->tracker->mark == 0 && server->tracker->packet_count < MARK_MAX_PACKET) { server->tracker->packet_count++; conntrackQuery(server); } } else { socklen_t len; struct sockaddr_storage sin; len = sizeof(sin); if (getpeername(remote->fd, (struct sockaddr *)&sin, &len) == 0) { struct sockaddr_storage from_addr; len = sizeof from_addr; if (getsockname(remote->fd, (struct sockaddr *)&from_addr, &len) == 0) { if ((server->tracker = (struct dscptracker *)ss_malloc(sizeof(struct dscptracker)))) { if ((server->tracker->ct = nfct_new())) { // Build conntrack query SELECT if (from_addr.ss_family == AF_INET) { struct sockaddr_in *src = (struct sockaddr_in *)&from_addr; struct sockaddr_in *dst = (struct sockaddr_in *)&sin; nfct_set_attr_u8(server->tracker->ct, ATTR_L3PROTO, AF_INET); nfct_set_attr_u32(server->tracker->ct, ATTR_IPV4_DST, dst->sin_addr.s_addr); nfct_set_attr_u32(server->tracker->ct, ATTR_IPV4_SRC, src->sin_addr.s_addr); nfct_set_attr_u16(server->tracker->ct, ATTR_PORT_DST, dst->sin_port); nfct_set_attr_u16(server->tracker->ct, ATTR_PORT_SRC, src->sin_port); } else if (from_addr.ss_family == AF_INET6) { struct sockaddr_in6 *src = (struct sockaddr_in6 *)&from_addr; struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sin; nfct_set_attr_u8(server->tracker->ct, ATTR_L3PROTO, AF_INET6); nfct_set_attr(server->tracker->ct, ATTR_IPV6_DST, dst->sin6_addr.s6_addr); nfct_set_attr(server->tracker->ct, ATTR_IPV6_SRC, src->sin6_addr.s6_addr); nfct_set_attr_u16(server->tracker->ct, ATTR_PORT_DST, dst->sin6_port); nfct_set_attr_u16(server->tracker->ct, ATTR_PORT_SRC, src->sin6_port); } nfct_set_attr_u8(server->tracker->ct, ATTR_L4PROTO, IPPROTO_TCP); conntrackQuery(server); } else { LOGE("Failed to allocate new conntrack for upstream netfilter mark retrieval."); server->tracker->ct = NULL; } } } } } } #endif static void server_recv_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_recv_ctx = (server_ctx_t *)w; server_t *server = server_recv_ctx->server; remote_t *remote = NULL; buffer_t *buf = server->buf; if (server->stage == STAGE_STREAM) { remote = server->remote; buf = remote->buf; // Only timer the watcher if a valid connection is established ev_timer_again(EV_A_ & server->recv_ctx->watcher); } ssize_t r = recv(server->fd, buf->data, SOCKET_BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("server recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } // Ignore any new packet if the server is stopped if (server->stage == STAGE_STOP) { return; } tx += r; buf->len = r; int err = crypto->decrypt(buf, server->d_ctx, SOCKET_BUF_SIZE); if (err == CRYPTO_ERROR) { report_addr(server->fd, "authentication error"); stop_server(EV_A_ server); return; } else if (err == CRYPTO_NEED_MORE) { if (server->stage != STAGE_STREAM) { server->frag++; } return; } // handshake and transmit data if (server->stage == STAGE_STREAM) { int s = send(remote->fd, remote->buf->data, remote->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send remote->buf->idx = 0; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); } else { ERROR("server_recv_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } } else if (s < remote->buf->len) { remote->buf->len -= s; remote->buf->idx = s; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); } return; } else if (server->stage == STAGE_INIT) { /* * Shadowsocks TCP Relay Header: * * +------+----------+----------+ * | ATYP | DST.ADDR | DST.PORT | * +------+----------+----------+ * | 1 | Variable | 2 | * +------+----------+----------+ * */ int offset = 0; int need_query = 0; char atyp = server->buf->data[offset++]; char host[255] = { 0 }; uint16_t port = 0; struct addrinfo info; struct sockaddr_storage storage; memset(&info, 0, sizeof(struct addrinfo)); memset(&storage, 0, sizeof(struct sockaddr_storage)); // get remote addr and port if ((atyp & ADDRTYPE_MASK) == 1) { // IP V4 struct sockaddr_in *addr = (struct sockaddr_in *)&storage; size_t in_addr_len = sizeof(struct in_addr); addr->sin_family = AF_INET; if (server->buf->len >= in_addr_len + 3) { memcpy(&addr->sin_addr, server->buf->data + offset, in_addr_len); inet_ntop(AF_INET, (const void *)(server->buf->data + offset), host, INET_ADDRSTRLEN); offset += in_addr_len; } else { report_addr(server->fd, "invalid length for ipv4 address"); stop_server(EV_A_ server); return; } memcpy(&addr->sin_port, server->buf->data + offset, sizeof(uint16_t)); info.ai_family = AF_INET; info.ai_socktype = SOCK_STREAM; info.ai_protocol = IPPROTO_TCP; info.ai_addrlen = sizeof(struct sockaddr_in); info.ai_addr = (struct sockaddr *)addr; } else if ((atyp & ADDRTYPE_MASK) == 3) { // Domain name uint8_t name_len = *(uint8_t *)(server->buf->data + offset); if (name_len + 4 <= server->buf->len) { memcpy(host, server->buf->data + offset + 1, name_len); offset += name_len + 1; } else { report_addr(server->fd, "invalid host name length"); stop_server(EV_A_ server); return; } if (acl && outbound_block_match_host(host) == 1) { if (verbose) LOGI("outbound blocked %s", host); close_and_free_server(EV_A_ server); return; } struct cork_ip ip; if (cork_ip_init(&ip, host) != -1) { info.ai_socktype = SOCK_STREAM; info.ai_protocol = IPPROTO_TCP; if (ip.version == 4) { struct sockaddr_in *addr = (struct sockaddr_in *)&storage; inet_pton(AF_INET, host, &(addr->sin_addr)); memcpy(&addr->sin_port, server->buf->data + offset, sizeof(uint16_t)); addr->sin_family = AF_INET; info.ai_family = AF_INET; info.ai_addrlen = sizeof(struct sockaddr_in); info.ai_addr = (struct sockaddr *)addr; } else if (ip.version == 6) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage; inet_pton(AF_INET6, host, &(addr->sin6_addr)); memcpy(&addr->sin6_port, server->buf->data + offset, sizeof(uint16_t)); addr->sin6_family = AF_INET6; info.ai_family = AF_INET6; info.ai_addrlen = sizeof(struct sockaddr_in6); info.ai_addr = (struct sockaddr *)addr; } } else { if (!validate_hostname(host, name_len)) { report_addr(server->fd, "invalid host name"); stop_server(EV_A_ server); return; } need_query = 1; } } else if ((atyp & ADDRTYPE_MASK) == 4) { // IP V6 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage; size_t in6_addr_len = sizeof(struct in6_addr); addr->sin6_family = AF_INET6; if (server->buf->len >= in6_addr_len + 3) { memcpy(&addr->sin6_addr, server->buf->data + offset, in6_addr_len); inet_ntop(AF_INET6, (const void *)(server->buf->data + offset), host, INET6_ADDRSTRLEN); offset += in6_addr_len; } else { LOGE("invalid header with addr type %d", atyp); report_addr(server->fd, "invalid length for ipv6 address"); stop_server(EV_A_ server); return; } memcpy(&addr->sin6_port, server->buf->data + offset, sizeof(uint16_t)); info.ai_family = AF_INET6; info.ai_socktype = SOCK_STREAM; info.ai_protocol = IPPROTO_TCP; info.ai_addrlen = sizeof(struct sockaddr_in6); info.ai_addr = (struct sockaddr *)addr; } if (offset == 1) { report_addr(server->fd, "invalid address type"); stop_server(EV_A_ server); return; } port = ntohs(load16_be(server->buf->data + offset)); offset += 2; if (server->buf->len < offset) { report_addr(server->fd, "invalid request length"); stop_server(EV_A_ server); return; } else { server->buf->len -= offset; server->buf->idx = offset; } if (verbose) { if ((atyp & ADDRTYPE_MASK) == 4) LOGI("[%s] connect to [%s]:%d", remote_port, host, ntohs(port)); else LOGI("[%s] connect to %s:%d", remote_port, host, ntohs(port)); } if (!need_query) { remote_t *remote = connect_to_remote(EV_A_ & info, server); if (remote == NULL) { LOGE("connect error"); close_and_free_server(EV_A_ server); return; } else { server->remote = remote; remote->server = server; // XXX: should handle buffer carefully if (server->buf->len > 0) { brealloc(remote->buf, server->buf->len, SOCKET_BUF_SIZE); memcpy(remote->buf->data, server->buf->data + server->buf->idx, server->buf->len); remote->buf->len = server->buf->len; remote->buf->idx = 0; server->buf->len = 0; server->buf->idx = 0; } // waiting on remote connected event ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); } } else { ev_io_stop(EV_A_ & server_recv_ctx->io); query_t *query = ss_malloc(sizeof(query_t)); memset(query, 0, sizeof(query_t)); query->server = server; server->query = query; snprintf(query->hostname, MAX_HOSTNAME_LEN, "%s", host); server->stage = STAGE_RESOLVE; resolv_start(host, port, resolv_cb, resolv_free_cb, query); } return; } // should not reach here FATAL("server context error"); } static void server_send_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_send_ctx = (server_ctx_t *)w; server_t *server = server_send_ctx->server; remote_t *remote = server->remote; if (remote == NULL) { LOGE("invalid server"); close_and_free_server(EV_A_ server); return; } if (server->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(server->fd, server->buf->data + server->buf->idx, server->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("server_send_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < server->buf->len) { // partly sent, move memory, wait for the next time to send server->buf->len -= s; server->buf->idx += s; return; } else { // all sent out, wait for reading server->buf->len = 0; server->buf->idx = 0; ev_io_stop(EV_A_ & server_send_ctx->io); if (remote != NULL) { ev_io_start(EV_A_ & remote->recv_ctx->io); return; } else { LOGE("invalid remote"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } } } static void server_timeout_cb(EV_P_ ev_timer *watcher, int revents) { server_ctx_t *server_ctx = cork_container_of(watcher, server_ctx_t, watcher); server_t *server = server_ctx->server; remote_t *remote = server->remote; if (verbose) { LOGI("TCP connection timeout"); } close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } static void resolv_free_cb(void *data) { query_t *query = (query_t *)data; if (query != NULL) { if (query->server != NULL) query->server->query = NULL; ss_free(query); } } static void resolv_cb(struct sockaddr *addr, void *data) { query_t *query = (query_t *)data; server_t *server = query->server; if (server == NULL) return; struct ev_loop *loop = server->listen_ctx->loop; if (addr == NULL) { LOGE("unable to resolve %s", query->hostname); close_and_free_server(EV_A_ server); } else { if (verbose) { LOGI("successfully resolved %s", query->hostname); } struct addrinfo info; memset(&info, 0, sizeof(struct addrinfo)); info.ai_socktype = SOCK_STREAM; info.ai_protocol = IPPROTO_TCP; info.ai_addr = addr; if (addr->sa_family == AF_INET) { info.ai_family = AF_INET; info.ai_addrlen = sizeof(struct sockaddr_in); } else if (addr->sa_family == AF_INET6) { info.ai_family = AF_INET6; info.ai_addrlen = sizeof(struct sockaddr_in6); } remote_t *remote = connect_to_remote(EV_A_ & info, server); if (remote == NULL) { close_and_free_server(EV_A_ server); } else { server->remote = remote; remote->server = server; // XXX: should handle buffer carefully if (server->buf->len > 0) { brealloc(remote->buf, server->buf->len, SOCKET_BUF_SIZE); memcpy(remote->buf->data, server->buf->data + server->buf->idx, server->buf->len); remote->buf->len = server->buf->len; remote->buf->idx = 0; server->buf->len = 0; server->buf->idx = 0; } // listen to remote connected event ev_io_start(EV_A_ & remote->send_ctx->io); } } } static void remote_recv_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w; remote_t *remote = remote_recv_ctx->remote; server_t *server = remote->server; if (server == NULL) { LOGE("invalid server"); close_and_free_remote(EV_A_ remote); return; } ev_timer_again(EV_A_ & server->recv_ctx->watcher); ssize_t r = recv(remote->fd, server->buf->data, SOCKET_BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("remote recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } rx += r; // Ignore any new packet if the server is stopped if (server->stage == STAGE_STOP) { return; } server->buf->len = r; int err = crypto->encrypt(server->buf, server->e_ctx, SOCKET_BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } #ifdef USE_NFCONNTRACK_TOS setTosFromConnmark(remote, server); #endif int s = send(server->fd, server->buf->data, server->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send server->buf->idx = 0; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); } else { ERROR("remote_recv_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < server->buf->len) { server->buf->len -= s; server->buf->idx = s; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); } // Disable TCP_NODELAY after the first response are sent if (!remote->recv_ctx->connected && !no_delay) { int opt = 0; setsockopt(server->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); setsockopt(remote->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); } remote->recv_ctx->connected = 1; } static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; if (server == NULL) { LOGE("invalid server"); close_and_free_remote(EV_A_ remote); return; } if (!remote_send_ctx->connected) { #ifdef TCP_FASTOPEN_WINSOCK if (fast_open) { // Check if ConnectEx is done if (!remote->connect_ex_done) { DWORD numBytes; DWORD flags; // Non-blocking way to fetch ConnectEx result if (WSAGetOverlappedResult(remote->fd, &remote->olap, &numBytes, FALSE, &flags)) { remote->buf->len -= numBytes; remote->buf->idx = numBytes; remote->connect_ex_done = 1; } else if (WSAGetLastError() == WSA_IO_INCOMPLETE) { // XXX: ConnectEx still not connected, wait for next time return; } else { ERROR("WSAGetOverlappedResult"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } // Make getpeername work if (setsockopt(remote->fd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) != 0) { ERROR("setsockopt"); } } #endif struct sockaddr_storage addr; socklen_t len = sizeof(struct sockaddr_storage); memset(&addr, 0, len); int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { remote_send_ctx->connected = 1; if (remote->buf->len == 0) { server->stage = STAGE_STREAM; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); ev_io_start(EV_A_ & remote->recv_ctx->io); return; } } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("remote_send_send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf->len) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); if (server != NULL) { ev_io_start(EV_A_ & server->recv_ctx->io); if (server->stage != STAGE_STREAM) { server->stage = STAGE_STREAM; ev_io_start(EV_A_ & remote->recv_ctx->io); } } else { LOGE("invalid server"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } } } static remote_t * new_remote(int fd) { if (verbose) { remote_conn++; LOGI("new connection to remote, %d opened remote connections", remote_conn); } remote_t *remote = ss_malloc(sizeof(remote_t)); memset(remote, 0, sizeof(remote_t)); remote->recv_ctx = ss_malloc(sizeof(remote_ctx_t)); remote->send_ctx = ss_malloc(sizeof(remote_ctx_t)); remote->buf = ss_malloc(sizeof(buffer_t)); balloc(remote->buf, SOCKET_BUF_SIZE); memset(remote->recv_ctx, 0, sizeof(remote_ctx_t)); memset(remote->send_ctx, 0, sizeof(remote_ctx_t)); remote->fd = fd; remote->recv_ctx->remote = remote; remote->recv_ctx->connected = 0; remote->send_ctx->remote = remote; remote->send_ctx->connected = 0; remote->server = NULL; ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ); ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE); return remote; } static void free_remote(remote_t *remote) { if (remote->server != NULL) { remote->server->remote = NULL; } if (remote->buf != NULL) { bfree(remote->buf); ss_free(remote->buf); } ss_free(remote->recv_ctx); ss_free(remote->send_ctx); ss_free(remote); } static void close_and_free_remote(EV_P_ remote_t *remote) { if (remote != NULL) { ev_io_stop(EV_A_ & remote->send_ctx->io); ev_io_stop(EV_A_ & remote->recv_ctx->io); close(remote->fd); free_remote(remote); if (verbose) { remote_conn--; LOGI("close a connection to remote, %d opened remote connections", remote_conn); } } } static server_t * new_server(int fd, listen_ctx_t *listener) { if (verbose) { server_conn++; LOGI("new connection from client, %d opened client connections", server_conn); } server_t *server; server = ss_malloc(sizeof(server_t)); memset(server, 0, sizeof(server_t)); server->recv_ctx = ss_malloc(sizeof(server_ctx_t)); server->send_ctx = ss_malloc(sizeof(server_ctx_t)); server->buf = ss_malloc(sizeof(buffer_t)); memset(server->recv_ctx, 0, sizeof(server_ctx_t)); memset(server->send_ctx, 0, sizeof(server_ctx_t)); balloc(server->buf, SOCKET_BUF_SIZE); server->fd = fd; server->recv_ctx->server = server; server->recv_ctx->connected = 0; server->send_ctx->server = server; server->send_ctx->connected = 0; server->stage = STAGE_INIT; server->frag = 0; server->query = NULL; server->listen_ctx = listener; server->remote = NULL; server->e_ctx = ss_malloc(sizeof(cipher_ctx_t)); server->d_ctx = ss_malloc(sizeof(cipher_ctx_t)); crypto->ctx_init(crypto->cipher, server->e_ctx, 1); crypto->ctx_init(crypto->cipher, server->d_ctx, 0); int timeout = max(MIN_TCP_IDLE_TIMEOUT, server->listen_ctx->timeout); ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ); ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE); ev_timer_init(&server->recv_ctx->watcher, server_timeout_cb, timeout, timeout); cork_dllist_add(&connections, &server->entries); return server; } static void free_server(server_t *server) { #ifdef USE_NFCONNTRACK_TOS if (server->tracker) { struct dscptracker *tracker = server->tracker; struct nf_conntrack *ct = server->tracker->ct; server->tracker = NULL; if (ct) { nfct_destroy(ct); } free(tracker); } #endif cork_dllist_remove(&server->entries); if (server->remote != NULL) { server->remote->server = NULL; } if (server->e_ctx != NULL) { crypto->ctx_release(server->e_ctx); ss_free(server->e_ctx); } if (server->d_ctx != NULL) { crypto->ctx_release(server->d_ctx); ss_free(server->d_ctx); } if (server->buf != NULL) { bfree(server->buf); ss_free(server->buf); } ss_free(server->recv_ctx); ss_free(server->send_ctx); ss_free(server); } static void close_and_free_server(EV_P_ server_t *server) { if (server != NULL) { if (server->query != NULL) { server->query->server = NULL; server->query = NULL; } ev_io_stop(EV_A_ & server->send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); ev_timer_stop(EV_A_ & server->recv_ctx->watcher); close(server->fd); free_server(server); if (verbose) { server_conn--; LOGI("close a connection from client, %d opened client connections", server_conn); } } } static void signal_cb(EV_P_ ev_signal *w, int revents) { if (revents & EV_SIGNAL) { switch (w->signum) { #ifndef __MINGW32__ case SIGCHLD: if (!is_plugin_running()) { LOGE("plugin service exit unexpectedly"); ret_val = -1; } else return; #endif case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); #ifndef __MINGW32__ ev_signal_stop(EV_DEFAULT, &sigchld_watcher); #else ev_io_stop(EV_DEFAULT, &plugin_watcher.io); #endif ev_unloop(EV_A_ EVUNLOOP_ALL); } } } #ifdef __MINGW32__ static void plugin_watcher_cb(EV_P_ ev_io *w, int revents) { char buf[1]; SOCKET fd = accept(plugin_watcher.fd, NULL, NULL); if (fd == INVALID_SOCKET) { return; } recv(fd, buf, 1, 0); closesocket(fd); LOGE("plugin service exit unexpectedly"); ret_val = -1; ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); ev_io_stop(EV_DEFAULT, &plugin_watcher.io); ev_unloop(EV_A_ EVUNLOOP_ALL); } #endif static void accept_cb(EV_P_ ev_io *w, int revents) { listen_ctx_t *listener = (listen_ctx_t *)w; int serverfd = accept(listener->fd, NULL, NULL); if (serverfd == -1) { ERROR("accept"); return; } char *peer_name = get_peer_name(serverfd); if (peer_name != NULL) { if (acl) { if ((get_acl_mode() == BLACK_LIST && acl_match_host(peer_name) == 1) || (get_acl_mode() == WHITE_LIST && acl_match_host(peer_name) >= 0)) { LOGE("Access denied from %s", peer_name); close(serverfd); return; } } } int opt = 1; setsockopt(serverfd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif if (tcp_incoming_sndbuf > 0) { setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &tcp_incoming_sndbuf, sizeof(int)); } if (tcp_incoming_rcvbuf > 0) { setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &tcp_incoming_rcvbuf, sizeof(int)); } setnonblocking(serverfd); server_t *server = new_server(serverfd, listener); ev_io_start(EV_A_ & server->recv_ctx->io); ev_timer_start(EV_A_ & server->recv_ctx->watcher); } int main(int argc, char **argv) { int i, c; int pid_flags = 0; int mptcp = 0; int mtu = 0; char *user = NULL; char *password = NULL; char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; char *server_port = NULL; char *plugin_opts = NULL; char *plugin_host = NULL; char *plugin_port = NULL; char tmp_port[8]; char *nameservers = NULL; int server_num = 0; ss_addr_t server_addr[MAX_REMOTE_NUM]; memset(server_addr, 0, sizeof(ss_addr_t) * MAX_REMOTE_NUM); memset(&local_addr_v4, 0, sizeof(struct sockaddr_storage)); memset(&local_addr_v6, 0, sizeof(struct sockaddr_storage)); static struct option long_options[] = { { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF }, { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, { "tcp-outgoing-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_SNDBUF }, { "tcp-outgoing-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_RCVBUF }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "acl", required_argument, NULL, GETOPT_VAL_ACL }, { "manager-address", required_argument, NULL, GETOPT_VAL_MANAGER_ADDRESS }, { "mtu", required_argument, NULL, GETOPT_VAL_MTU }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "key", required_argument, NULL, GETOPT_VAL_KEY }, #ifdef __linux__ { "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP }, #ifdef USE_NFTABLES { "nftables-sets", required_argument, NULL, GETOPT_VAL_NFTABLES_SETS }, #endif #endif { NULL, 0, NULL, 0 } }; opterr = 0; USE_TTY(); while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:b:c:i:d:a:n:huUv6A", long_options, NULL)) != -1) { switch (c) { case GETOPT_VAL_FAST_OPEN: fast_open = 1; break; case GETOPT_VAL_NODELAY: no_delay = 1; LOGI("enable TCP no-delay"); break; case GETOPT_VAL_ACL: LOGI("initializing acl..."); acl = !init_acl(optarg); break; case GETOPT_VAL_MANAGER_ADDRESS: manager_addr = optarg; break; case GETOPT_VAL_MTU: mtu = atoi(optarg); LOGI("set MTU to %d", mtu); break; case GETOPT_VAL_PLUGIN: plugin = optarg; break; case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; case GETOPT_VAL_MPTCP: mptcp = get_mptcp(1); if (mptcp) LOGI("enable multipath TCP (%s)", mptcp > 0 ? "out-of-tree" : "upstream"); break; case GETOPT_VAL_KEY: key = optarg; break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; case GETOPT_VAL_TCP_INCOMING_SNDBUF: tcp_incoming_sndbuf = atoi(optarg); break; case GETOPT_VAL_TCP_INCOMING_RCVBUF: tcp_incoming_rcvbuf = atoi(optarg); break; case GETOPT_VAL_TCP_OUTGOING_SNDBUF: tcp_outgoing_sndbuf = atoi(optarg); break; case GETOPT_VAL_TCP_OUTGOING_RCVBUF: tcp_outgoing_rcvbuf = atoi(optarg); break; #ifdef USE_NFTABLES case GETOPT_VAL_NFTABLES_SETS: nftbl_init(optarg); break; #endif case 's': if (server_num < MAX_REMOTE_NUM) { parse_addr(optarg, &server_addr[server_num++]); } break; case 'b': is_bind_local_addr += parse_local_addr(&local_addr_v4, &local_addr_v6, optarg); break; case 'p': server_port = optarg; break; case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'd': nameservers = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; case GETOPT_VAL_HELP: case 'h': usage(); exit(EXIT_SUCCESS); case '6': ipv6first = 1; break; case 'A': FATAL("One time auth has been deprecated. Try AEAD ciphers instead."); break; case '?': // The option character is not recognized. LOGE("Unrecognized option: %s", optarg); opterr = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = get_default_conf(); } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (server_num == 0) { server_num = conf->remote_num; for (i = 0; i < server_num; i++) server_addr[i] = conf->remote_addr[i]; } if (server_port == NULL) { server_port = conf->remote_port; } if (password == NULL) { password = conf->password; } if (key == NULL) { key = conf->key; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (user == NULL) { user = conf->user; } if (plugin == NULL) { plugin = conf->plugin; } if (plugin_opts == NULL) { plugin_opts = conf->plugin_opts; } if (mode == TCP_ONLY) { mode = conf->mode; } if (mtu == 0) { mtu = conf->mtu; } if (mptcp == 0) { mptcp = conf->mptcp; } if (no_delay == 0) { no_delay = conf->no_delay; } if (reuse_port == 0) { reuse_port = conf->reuse_port; } if (tcp_incoming_sndbuf == 0) { tcp_incoming_sndbuf = conf->tcp_incoming_sndbuf; } if (tcp_incoming_rcvbuf == 0) { tcp_incoming_rcvbuf = conf->tcp_incoming_rcvbuf; } if (tcp_outgoing_sndbuf == 0) { tcp_outgoing_sndbuf = conf->tcp_outgoing_sndbuf; } if (tcp_outgoing_rcvbuf == 0) { tcp_outgoing_rcvbuf = conf->tcp_outgoing_rcvbuf; } if (fast_open == 0) { fast_open = conf->fast_open; } if (is_bind_local_addr == 0) { is_bind_local_addr += parse_local_addr(&local_addr_v4, &local_addr_v6, conf->local_addr); } if (is_bind_local_addr == 0) { is_bind_local_addr += parse_local_addr(&local_addr_v4, &local_addr_v6, conf->local_addr_v4); is_bind_local_addr += parse_local_addr(&local_addr_v4, &local_addr_v6, conf->local_addr_v6); } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } #endif if (nameservers == NULL) { nameservers = conf->nameserver; } if (ipv6first == 0) { ipv6first = conf->ipv6_first; } if (acl == 0 && conf->acl != NULL) { LOGI("initializing acl..."); acl = !init_acl(conf->acl); } } if (tcp_incoming_sndbuf != 0 && tcp_incoming_sndbuf < SOCKET_BUF_SIZE) { tcp_incoming_sndbuf = 0; } if (tcp_incoming_sndbuf != 0) { LOGI("set TCP incoming connection send buffer size to %d", tcp_incoming_sndbuf); } if (tcp_incoming_rcvbuf != 0 && tcp_incoming_rcvbuf < SOCKET_BUF_SIZE) { tcp_incoming_rcvbuf = 0; } if (tcp_incoming_rcvbuf != 0) { LOGI("set TCP incoming connection receive buffer size to %d", tcp_incoming_rcvbuf); } if (tcp_outgoing_sndbuf != 0 && tcp_outgoing_sndbuf < SOCKET_BUF_SIZE) { tcp_outgoing_sndbuf = 0; } if (tcp_outgoing_sndbuf != 0) { LOGI("set TCP outgoing connection send buffer size to %d", tcp_outgoing_sndbuf); } if (tcp_outgoing_rcvbuf != 0 && tcp_outgoing_rcvbuf < SOCKET_BUF_SIZE) { tcp_outgoing_rcvbuf = 0; } if (tcp_outgoing_rcvbuf != 0) { LOGI("set TCP outgoing connection receive buffer size to %d", tcp_outgoing_rcvbuf); } if (server_num == 0) { server_addr[server_num++].host = "0.0.0.0"; } if (server_num == 0 || server_port == NULL || (password == NULL && key == NULL)) { usage(); exit(EXIT_FAILURE); } if (is_ipv6only(server_addr, server_num, ipv6first)) { plugin_host = "::1"; } else { plugin_host = "127.0.0.1"; } remote_port = server_port; #ifdef __MINGW32__ winsock_init(); #endif if (plugin != NULL) { uint16_t port = get_local_port(); if (port == 0) { FATAL("failed to find a free port"); } snprintf(tmp_port, 8, "%d", port); plugin_port = server_port; server_port = tmp_port; #ifdef __MINGW32__ memset(&plugin_watcher, 0, sizeof(plugin_watcher)); plugin_watcher.port = get_local_port(); if (plugin_watcher.port == 0) { LOGE("failed to assign a control port for plugin"); } #endif } if (method == NULL) { method = "chacha20-ietf-poly1305"; } if (timeout == NULL) { timeout = "60"; } #ifdef HAVE_SETRLIMIT /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif USE_SYSLOG(argv[0], pid_flags); if (pid_flags) { daemonize(pid_path); } if (ipv6first) { LOGI("resolving hostname to IPv6 address first"); } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); fast_open = 0; #endif } if (plugin != NULL) { LOGI("plugin \"%s\" enabled", plugin); } if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } if (no_delay) { LOGI("enable TCP no-delay"); } #ifndef __MINGW32__ // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); #ifndef __MINGW32__ ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigchld_watcher); #endif // setup keys LOGI("initializing ciphers... %s", method); crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); // initialize ev loop struct ev_loop *loop = EV_DEFAULT; // setup dns resolv_init(loop, nameservers, ipv6first); if (nameservers != NULL) LOGI("using nameserver: %s", nameservers); #ifdef __MINGW32__ // Listen on plugin control port if (plugin != NULL && plugin_watcher.port != 0) { SOCKET fd; fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd != INVALID_SOCKET) { plugin_watcher.valid = 0; do { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_port = htons(plugin_watcher.port); if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) { LOGE("failed to bind plugin control port"); break; } if (listen(fd, 1)) { LOGE("failed to listen on plugin control port"); break; } plugin_watcher.fd = fd; ev_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, EV_READ); ev_io_start(EV_DEFAULT, &plugin_watcher.io); plugin_watcher.valid = 1; } while (0); if (!plugin_watcher.valid) { closesocket(fd); plugin_watcher.port = 0; } } } #endif // Start plugin server if (plugin != NULL) { int len = 0; size_t buf_size = 256 * server_num; char *server_str = ss_malloc(buf_size); snprintf(server_str, buf_size, "%s", server_addr[0].host); len = strlen(server_str); for (int i = 1; i < server_num; i++) { snprintf(server_str + len, buf_size - len, "|%s", server_addr[i].host); len = strlen(server_str); } int err = start_plugin(plugin, plugin_opts, server_str, plugin_port, plugin_host, server_port, #ifdef __MINGW32__ plugin_watcher.port, #endif MODE_SERVER); if (err) { ERROR("start_plugin"); FATAL("failed to start the plugin"); } } // initialize listen context listen_ctx_t listen_ctx_list[server_num]; // bind to each interface if (mode != UDP_ONLY) { int num_listen_ctx = 0; for (int i = 0; i < server_num; i++) { const char *host = server_addr[i].host; const char *port = server_addr[i].port ? server_addr[i].port : server_port; if (plugin != NULL) { host = plugin_host; } if (host && ss_is_ipv6addr(host)) LOGI("tcp server listening at [%s]:%s", host, port); else LOGI("tcp server listening at %s:%s", host ? host : "0.0.0.0", port); // Bind to port int listenfd; listenfd = create_and_bind(host, port, mptcp); if (listenfd == -1) { continue; } if (listen(listenfd, SSMAXCONN) == -1) { ERROR("listen()"); continue; } setfastopen(listenfd); setnonblocking(listenfd); listen_ctx_t *listen_ctx = &listen_ctx_list[i]; // Setup proxy context listen_ctx->timeout = atoi(timeout); listen_ctx->fd = listenfd; listen_ctx->iface = iface; listen_ctx->loop = loop; ev_io_init(&listen_ctx->io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx->io); num_listen_ctx++; if (plugin != NULL) break; } if (num_listen_ctx == 0) { FATAL("failed to listen on any address"); } } if (mode != TCP_ONLY) { int num_listen_ctx = 0; for (int i = 0; i < server_num; i++) { const char *host = server_addr[i].host; const char *port = server_addr[i].port ? server_addr[i].port : server_port; if (plugin != NULL) { port = plugin_port; } if (host && ss_is_ipv6addr(host)) LOGI("udp server listening at [%s]:%s", host, port); else LOGI("udp server listening at %s:%s", host ? host : "0.0.0.0", port); // Setup UDP int err = init_udprelay(host, port, mtu, crypto, atoi(timeout), iface); if (err == -1) continue; num_listen_ctx++; } if (num_listen_ctx == 0) { FATAL("failed to listen on any address"); } } #ifndef __MINGW32__ if (manager_addr != NULL) { ev_timer_init(&stat_update_watcher, stat_update_cb, UPDATE_INTERVAL, UPDATE_INTERVAL); ev_timer_start(EV_DEFAULT, &stat_update_watcher); } #endif #ifndef __MINGW32__ // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); } if (geteuid() == 0) { LOGI("running from root user"); } #endif // Init connections cork_dllist_init(&connections); // start ev loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } #ifndef __MINGW32__ if (manager_addr != NULL) { ev_timer_stop(EV_DEFAULT, &stat_update_watcher); } #endif if (plugin != NULL) { stop_plugin(); } // Clean up resolv_shutdown(loop); for (int i = 0; i < server_num; i++) { listen_ctx_t *listen_ctx = &listen_ctx_list[i]; if (mode != UDP_ONLY) { ev_io_stop(loop, &listen_ctx->io); close(listen_ctx->fd); } if (plugin != NULL) break; } if (mode != UDP_ONLY) { free_connections(loop); } if (mode != TCP_ONLY) { free_udprelay(); } #ifdef __MINGW32__ if (plugin_watcher.valid) { closesocket(plugin_watcher.fd); } winsock_cleanup(); #endif return ret_val; } ================================================ FILE: src/server.h ================================================ /* * server.h - Define shadowsocks server's buffers and callbacks * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _SERVER_H #define _SERVER_H #include #include #ifdef HAVE_LIBEV_EV_H #include #else #include #endif #ifdef __MINGW32__ #include "winsock.h" #endif #include "crypto.h" #include "jconf.h" #include "netutils.h" #include "common.h" typedef struct listen_ctx { ev_io io; int fd; int timeout; char *iface; struct ev_loop *loop; } listen_ctx_t; typedef struct server_ctx { ev_io io; ev_timer watcher; int connected; struct server *server; } server_ctx_t; #ifdef USE_NFCONNTRACK_TOS #include #include struct dscptracker { struct nf_conntrack *ct; long unsigned int mark; unsigned int dscp; unsigned int packet_count; }; #endif struct query; typedef struct server { int fd; int stage; int frag; buffer_t *buf; cipher_ctx_t *e_ctx; cipher_ctx_t *d_ctx; struct server_ctx *recv_ctx; struct server_ctx *send_ctx; struct listen_ctx *listen_ctx; struct remote *remote; struct query *query; struct cork_dllist_item entries; #ifdef USE_NFCONNTRACK_TOS struct dscptracker *tracker; #endif } server_t; typedef struct query { server_t *server; char hostname[MAX_HOSTNAME_LEN]; } query_t; typedef struct remote_ctx { ev_io io; int connected; struct remote *remote; } remote_ctx_t; typedef struct remote { int fd; #ifdef TCP_FASTOPEN_WINSOCK OVERLAPPED olap; int connect_ex_done; #endif buffer_t *buf; struct remote_ctx *recv_ctx; struct remote_ctx *send_ctx; struct server *server; } remote_t; #endif // _SERVER_H ================================================ FILE: src/shadowsocks.h ================================================ /* * shadowsocks.h - Header files of library interfaces * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _SHADOWSOCKS_H #define _SHADOWSOCKS_H typedef struct { /* Required */ char *remote_host; // hostname or ip of remote server char *local_addr; // local ip to bind char *method; // encryption method char *password; // password of remote server int remote_port; // port number of remote server int local_port; // port number of local server int timeout; // connection timeout /* Optional, set NULL if not valid */ char *acl; // file path to acl char *log; // file path to log int fast_open; // enable tcp fast open int mode; // enable udp relay int mtu; // MTU of interface int mptcp; // enable multipath TCP int verbose; // verbose mode } profile_t; /* An example profile * * const profile_t EXAMPLE_PROFILE = { * .remote_host = "example.com", * .local_addr = "127.0.0.1", * .method = "bf-cfb", * .password = "barfoo!", * .remote_port = 8338, * .local_port = 1080, * .timeout = 600; * .acl = NULL, * .log = NULL, * .fast_open = 0, * .mode = 0, * .verbose = 0 * }; */ #ifdef __cplusplus extern "C" { #endif typedef void (*ss_local_callback)(int socks_fd, int udp_fd, void *data); /* * Create and start a shadowsocks local server. * * Calling this function will block the current thread forever if the server * starts successfully. * * Make sure start the server in a separate process to avoid any potential * memory and socket leak. * * If failed, -1 is returned. Errors will output to the log file. */ int start_ss_local_server(profile_t profile); /* * Create and start a shadowsocks local server, specifying a callback. * * The callback is invoked when the local server has started successfully. It passes the SOCKS * server and UDP relay file descriptors, along with any supplied user data. * * Returns -1 on failure. */ int start_ss_local_server_with_callback(profile_t profile, ss_local_callback callback, void *udata); #ifdef __cplusplus } #endif // To stop the service on posix system, just kill the daemon process // kill(pid, SIGKILL); // Otherwise, If you start the service in a thread, you may need to send a signal SIGUSER1 to the thread. // pthread_kill(pthread_t, SIGUSR1); #endif // _SHADOWSOCKS_H ================================================ FILE: src/socks5.h ================================================ /* * socks5.h - Define SOCKS5's header * * Copyright (C) 2013, clowwindy * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _SOCKS5_H #define _SOCKS5_H #define SVERSION 0x05 #define METHOD_NOAUTH 0x00 #define METHOD_UNACCEPTABLE 0xff // see also: https://www.ietf.org/rfc/rfc1928.txt #define SOCKS5_CMD_CONNECT 0x01 #define SOCKS5_CMD_BIND 0x02 #define SOCKS5_CMD_UDP_ASSOCIATE 0x03 #define SOCKS5_ATYP_IPV4 0x01 #define SOCKS5_ATYP_DOMAIN 0x03 #define SOCKS5_ATYP_IPV6 0x04 #define SOCKS5_REP_SUCCEEDED 0x00 #define SOCKS5_REP_GENERAL 0x01 #define SOCKS5_REP_CONN_DISALLOWED 0x02 #define SOCKS5_REP_NETWORK_UNREACHABLE 0x03 #define SOCKS5_REP_HOST_UNREACHABLE 0x04 #define SOCKS5_REP_CONN_REFUSED 0x05 #define SOCKS5_REP_TTL_EXPIRED 0x06 #define SOCKS5_REP_CMD_NOT_SUPPORTED 0x07 #define SOCKS5_REP_ADDRTYPE_NOT_SUPPORTED 0x08 #define SOCKS5_REP_FF_UNASSIGNED 0x09 struct method_select_request { unsigned char ver; unsigned char nmethods; unsigned char methods[0]; } __attribute__((packed, aligned(1))); struct method_select_response { unsigned char ver; unsigned char method; } __attribute__((packed, aligned(1))); struct socks5_request { unsigned char ver; unsigned char cmd; unsigned char rsv; unsigned char atyp; } __attribute__((packed, aligned(1))); struct socks5_response { unsigned char ver; unsigned char rep; unsigned char rsv; unsigned char atyp; } __attribute__((packed, aligned(1))); #endif // _SOCKS5_H ================================================ FILE: src/ss-nat ================================================ #!/bin/bash # # Copyright (C) 2015 OpenWrt-dist # Copyright (C) 2015 Jian Chang # # This is free software, licensed under the GNU General Public License v3. # See /LICENSE for more information. # TAG="SS_SPEC" # iptables tag IPT="iptables -t nat" # alias of iptables FWI=$(uci get firewall.shadowsocks.path 2>/dev/null) # firewall include file IP_REGEX="^([0-9]{1,3}\.){3}[0-9]{1,3}" # used to check if input is a valid IP usage() { cat <<-EOF Copyright (C) 2015 OpenWrt-dist Copyright (C) 2015 Jian Chang Usage: ss-nat [options] Valid options are: -s hostname (requires dig) or ip address of shadowsocks remote server -l port number of shadowsocks local server -S hostname (requires dig) or ip address of shadowsocks remote UDP server -L port number of shadowsocks local UDP server -i a file content is bypassed ip list -I lan interface of nat, default: eth0 -a lan ip of access control, need a prefix to define access control mode -b wan ip of will be bypassed -w wan ip of will be forwarded -e 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 This is free software, licensed under the GNU General Public License v3. See /LICENSE for more information. EOF exit $1 } loger() { # 1.alert 2.crit 3.err 4.warn 5.notice 6.info 7.debug logger -st ss-nat[$$] -p$1 $2 } flush_r() { iptables-save -c | grep -v "$TAG" | iptables-restore -c ip rule del fwmark 0x01/0x01 table 100 2>/dev/null ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null ipset -X ss_spec_lan_ac 2>/dev/null ipset -X ss_spec_wan_ac 2>/dev/null [ -n "$FWI" ] && echo '#!/bin/sh' >$FWI return 0 } ipset_r() { ipset -! -R <<-EOF || return 1 create ss_spec_wan_ac hash:net $(gen_iplist | sed "/^\s*$/d" | sed -e "s/^/add ss_spec_wan_ac /") $(for ip in $WAN_FW_IP; do echo "add ss_spec_wan_ac $ip nomatch"; done) EOF $IPT -N SS_SPEC_WAN_AC && \ $IPT -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN && \ $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW return $? } fw_rule() { $IPT -N SS_SPEC_WAN_FW && \ $IPT -A SS_SPEC_WAN_FW -p tcp \ -j REDIRECT --to-ports $local_port 2>/dev/null || { loger 3 "Can't redirect, please check the iptables." exit 1 } return $? } ac_rule() { if [ -n "$LAN_AC_IP" ]; then case "${LAN_AC_IP:0:1}" in w|W) MATCH_SET="-m set --match-set ss_spec_lan_ac src" ;; b|B) MATCH_SET="-m set ! --match-set ss_spec_lan_ac src" ;; *) loger 3 "Illegal argument \`-a $LAN_AC_IP\`." return 2 ;; esac fi IFNAME=${IFNAME:-eth0} ipset -! -R <<-EOF || return 1 create ss_spec_lan_ac hash:net $(for ip in ${LAN_AC_IP:1}; do echo "add ss_spec_lan_ac $ip"; done) EOF $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET \ -j SS_SPEC_WAN_AC if [ "$OUTPUT" = 1 ]; then $IPT -I OUTPUT 1 -p tcp $EXT_ARGS -j SS_SPEC_WAN_AC fi return $? } tp_rule() { lsmod | grep -q TPROXY || return 0 [ -n "$TPROXY" ] || return 0 ip rule add fwmark 0x01/0x01 table 100 ip route add local 0.0.0.0/0 dev lo table 100 local ipt="iptables -t mangle" $ipt -N SS_SPEC_TPROXY $ipt -A SS_SPEC_TPROXY -p udp -m set ! --match-set ss_spec_wan_ac dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 $ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET \ -j SS_SPEC_TPROXY return $? } get_wan_ip() { cat <<-EOF | grep -E $IP_REGEX $server $SERVER $WAN_BP_IP EOF } gen_iplist() { cat <<-EOF 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.0.0.0/24 192.0.2.0/24 192.88.99.0/24 192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 224.0.0.0/4 240.0.0.0/4 255.255.255.255 $(get_wan_ip) $(cat ${IGNORE_LIST:=/dev/null} 2>/dev/null) EOF } gen_include() { [ -n "$FWI" ] || return 0 cat <<-EOF >>$FWI iptables-restore -n <<-EOT $(iptables-save | grep -E "$TAG|^\*|^COMMIT" |\ sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/") EOT EOF return $? } while getopts ":s:l:S:L:i:I:e:a:b:w:ouUfh" arg; do case "$arg" in s) if [[ $OPTARG =~ $IP_REGEX ]] then server=$OPTARG else server=$(ping -4 -q -c 1 -s 0 -W 1 -w 1 $OPTARG| head -n 1 | sed -n 's/[^(]*(\([^)]*\)).*/\1/p') fi ;; l) local_port=$OPTARG ;; S) if [[ $OPTARG =~ $IP_REGEX ]] then SERVER=$OPTARG else SERVER=$(ping -4 -q -c 1 -s 0 -W 1 -w 1 $OPTARG| head -n 1 | sed -n 's/[^(]*(\([^)]*\)).*/\1/p') fi ;; L) LOCAL_PORT=$OPTARG ;; i) IGNORE_LIST=$OPTARG ;; I) IFNAME=$OPTARG ;; e) EXT_ARGS=$OPTARG ;; a) LAN_AC_IP=$OPTARG ;; b) WAN_BP_IP=$(for ip in $OPTARG; do echo $ip; done) ;; w) WAN_FW_IP=$OPTARG ;; o) OUTPUT=1 ;; u) TPROXY=1 ;; U) TPROXY=2 ;; f) flush_r exit 0 ;; h) usage 0 ;; esac done if [ -z "$server" -o -z "$local_port" ]; then usage 2 fi if [ "$TPROXY" = 1 ]; then SERVER=$server LOCAL_PORT=$local_port elif [ "$TPROXY" = 2 ]; then : ${SERVER:?"You must assign an ip for the udp relay server."} : ${LOCAL_PORT:?"You must assign a port for the udp relay server."} fi flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include [ "$?" = 0 ] || loger 3 "Start failed!" exit $? ================================================ FILE: src/stream.c ================================================ /* * stream.c - Manage stream ciphers * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #define CIPHER_UNSUPPORTED "unsupported" #include #include "ppbloom.h" #include "stream.h" #include "utils.h" #define SODIUM_BLOCK_SIZE 64 /* * Spec: http://shadowsocks.org/en/spec/Stream-Ciphers.html * * Stream ciphers provide only confidentiality. Data integrity and authenticity is not guaranteed. Users should use AEAD * ciphers whenever possible. * * Stream Encryption/Decryption * * Stream_encrypt is a function that takes a secret key, an initialization vector, a message, and produces a ciphertext * with the same length as the message. * * Stream_encrypt(key, IV, message) => ciphertext * * Stream_decrypt is a function that takes a secret key, an initializaiton vector, a ciphertext, and produces the * original message. * * Stream_decrypt(key, IV, ciphertext) => message * * TCP * * A stream cipher encrypted TCP stream starts with a randomly generated initializaiton vector, followed by encrypted * payload data. * * [IV][encrypted payload] * * UDP * * A stream cipher encrypted UDP packet has the following structure: * * [IV][encrypted payload] * * Each UDP packet is encrypted/decrypted independently with a randomly generated initialization vector. * */ #define NONE -1 #define TABLE 0 #define RC4 1 #define RC4_MD5 2 #define AES_128_CFB 3 #define AES_192_CFB 4 #define AES_256_CFB 5 #define AES_128_CTR 6 #define AES_192_CTR 7 #define AES_256_CTR 8 #define BF_CFB 9 #define CAMELLIA_128_CFB 10 #define CAMELLIA_192_CFB 11 #define CAMELLIA_256_CFB 12 #define CAST5_CFB 13 #define DES_CFB 14 #define IDEA_CFB 15 #define RC2_CFB 16 #define SEED_CFB 17 #define SALSA20 18 #define CHACHA20 19 #define CHACHA20IETF 20 const char *supported_stream_ciphers[STREAM_CIPHER_NUM] = { "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" }; static const char *supported_stream_ciphers_mbedtls[STREAM_CIPHER_NUM] = { "table", "ARC4-128", "ARC4-128", "AES-128-CFB128", "AES-192-CFB128", "AES-256-CFB128", "AES-128-CTR", "AES-192-CTR", "AES-256-CTR", "BLOWFISH-CFB64", "CAMELLIA-128-CFB128", "CAMELLIA-192-CFB128", "CAMELLIA-256-CFB128", CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, "salsa20", "chacha20", "chacha20-ietf" }; static const int supported_stream_ciphers_nonce_size[STREAM_CIPHER_NUM] = { 0, 0, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 8, 8, 8, 8, 16, 8, 8, 12 }; static const int supported_stream_ciphers_key_size[STREAM_CIPHER_NUM] = { 0, 16, 16, 16, 24, 32, 16, 24, 32, 16, 16, 24, 32, 16, 8, 16, 16, 16, 32, 32, 32 }; static int crypto_stream_xor_ic(uint8_t *c, const uint8_t *m, uint64_t mlen, const uint8_t *n, uint64_t ic, const uint8_t *k, int method) { switch (method) { case SALSA20: return crypto_stream_salsa20_xor_ic(c, m, mlen, n, ic, k); case CHACHA20: return crypto_stream_chacha20_xor_ic(c, m, mlen, n, ic, k); case CHACHA20IETF: return crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, n, (uint32_t)ic, k); } // always return 0 return 0; } const cipher_kt_t * stream_get_cipher_type(int method) { if (method <= TABLE || method >= STREAM_CIPHER_NUM) { LOGE("stream_get_cipher_type(): Illegal method"); return NULL; } if (method == RC4_MD5) { method = RC4; } if (method >= SALSA20) { return NULL; } const char *ciphername = supported_stream_ciphers[method]; const char *mbedtlsname = supported_stream_ciphers_mbedtls[method]; if (strcmp(mbedtlsname, CIPHER_UNSUPPORTED) == 0) { LOGE("Cipher %s currently is not supported by mbed TLS library", ciphername); return NULL; } return mbedtls_cipher_info_from_string(mbedtlsname); } void stream_cipher_ctx_init(cipher_ctx_t *ctx, int method, int enc) { if (method <= TABLE || method >= STREAM_CIPHER_NUM) { LOGE("stream_ctx_init(): Illegal method"); return; } if (method >= SALSA20) { return; } const char *ciphername = supported_stream_ciphers[method]; const cipher_kt_t *cipher = stream_get_cipher_type(method); ctx->evp = ss_malloc(sizeof(cipher_evp_t)); memset(ctx->evp, 0, sizeof(cipher_evp_t)); cipher_evp_t *evp = ctx->evp; if (cipher == NULL) { LOGE("Cipher %s not found in mbed TLS library", ciphername); FATAL("Cannot initialize mbed TLS cipher"); } mbedtls_cipher_init(evp); if (mbedtls_cipher_setup(evp, cipher) != 0) { FATAL("Cannot initialize mbed TLS cipher context"); } } void stream_ctx_release(cipher_ctx_t *cipher_ctx) { if (cipher_ctx->chunk != NULL) { bfree(cipher_ctx->chunk); ss_free(cipher_ctx->chunk); cipher_ctx->chunk = NULL; } if (cipher_ctx->cipher->method >= SALSA20) { return; } mbedtls_cipher_free(cipher_ctx->evp); ss_free(cipher_ctx->evp); } void cipher_ctx_set_nonce(cipher_ctx_t *cipher_ctx, uint8_t *nonce, size_t nonce_len, int enc) { const unsigned char *true_key; cipher_t *cipher = cipher_ctx->cipher; if (nonce == NULL) { LOGE("cipher_ctx_set_nonce(): NONCE is null"); return; } if (cipher->method >= SALSA20) { return; } if (cipher->method == RC4_MD5) { unsigned char key_nonce[32]; memcpy(key_nonce, cipher->key, 16); memcpy(key_nonce + 16, nonce, 16); true_key = crypto_md5(key_nonce, 32, NULL); nonce_len = 0; } else { true_key = cipher->key; } cipher_evp_t *evp = cipher_ctx->evp; if (evp == NULL) { LOGE("cipher_ctx_set_nonce(): Cipher context is null"); return; } if (mbedtls_cipher_setkey(evp, true_key, cipher->key_len * 8, enc) != 0) { mbedtls_cipher_free(evp); FATAL("Cannot set mbed TLS cipher key"); } if (mbedtls_cipher_set_iv(evp, nonce, nonce_len) != 0) { mbedtls_cipher_free(evp); FATAL("Cannot set mbed TLS cipher NONCE"); } if (mbedtls_cipher_reset(evp) != 0) { mbedtls_cipher_free(evp); FATAL("Cannot finalize mbed TLS cipher context"); } #ifdef SS_DEBUG dump("NONCE", (char *)nonce, nonce_len); dump("KEY", (char *)true_key, 32); #endif } static int cipher_ctx_update(cipher_ctx_t *ctx, uint8_t *output, size_t *olen, const uint8_t *input, size_t ilen) { cipher_evp_t *evp = ctx->evp; return mbedtls_cipher_update(evp, (const uint8_t *)input, ilen, (uint8_t *)output, olen); } int stream_encrypt_all(buffer_t *plaintext, cipher_t *cipher, size_t capacity) { cipher_ctx_t cipher_ctx; stream_ctx_init(cipher, &cipher_ctx, 1); size_t nonce_len = cipher->nonce_len; int err = CRYPTO_OK; static buffer_t tmp = { 0, 0, 0, NULL }; brealloc(&tmp, nonce_len + plaintext->len, capacity); buffer_t *ciphertext = &tmp; ciphertext->len = plaintext->len; uint8_t *nonce = cipher_ctx.nonce; cipher_ctx_set_nonce(&cipher_ctx, nonce, nonce_len, 1); memcpy(ciphertext->data, nonce, nonce_len); #ifdef MODULE_REMOTE ppbloom_add((void *)nonce, nonce_len); #endif if (cipher->method >= SALSA20) { crypto_stream_xor_ic((uint8_t *)(ciphertext->data + nonce_len), (const uint8_t *)plaintext->data, (uint64_t)(plaintext->len), (const uint8_t *)nonce, 0, cipher->key, cipher->method); } else { err = cipher_ctx_update(&cipher_ctx, (uint8_t *)(ciphertext->data + nonce_len), &ciphertext->len, (const uint8_t *)plaintext->data, plaintext->len); } stream_ctx_release(&cipher_ctx); if (err) return CRYPTO_ERROR; #ifdef SS_DEBUG dump("PLAIN", plaintext->data, plaintext->len); dump("CIPHER", ciphertext->data + nonce_len, ciphertext->len); dump("NONCE", ciphertext->data, nonce_len); #endif bswap_data(plaintext, ciphertext); plaintext->len = nonce_len + ciphertext->len; return CRYPTO_OK; } int stream_encrypt(buffer_t *plaintext, cipher_ctx_t *cipher_ctx, size_t capacity) { if (cipher_ctx == NULL) return CRYPTO_ERROR; cipher_t *cipher = cipher_ctx->cipher; // In-place fast path for non-Salsa20 ciphers after init. // mbedtls_cipher_update supports output == input for CFB/CTR stream modes. if (cipher_ctx->init && cipher->method < SALSA20) { size_t out_len = plaintext->len; int err = cipher_ctx_update(cipher_ctx, (uint8_t *)plaintext->data, &out_len, (const uint8_t *)plaintext->data, plaintext->len); if (err) return CRYPTO_ERROR; plaintext->len = out_len; return CRYPTO_OK; } static buffer_t tmp = { 0, 0, 0, NULL }; int err = CRYPTO_OK; size_t nonce_len = 0; if (!cipher_ctx->init) { nonce_len = cipher_ctx->cipher->nonce_len; } brealloc(&tmp, nonce_len + plaintext->len, capacity); buffer_t *ciphertext = &tmp; ciphertext->len = plaintext->len; if (!cipher_ctx->init) { cipher_ctx_set_nonce(cipher_ctx, cipher_ctx->nonce, nonce_len, 1); memcpy(ciphertext->data, cipher_ctx->nonce, nonce_len); cipher_ctx->counter = 0; cipher_ctx->init = 1; #ifdef MODULE_REMOTE ppbloom_add((void *)cipher_ctx->nonce, nonce_len); #endif } if (cipher->method >= SALSA20) { int padding = cipher_ctx->counter % SODIUM_BLOCK_SIZE; brealloc(ciphertext, nonce_len + (padding + ciphertext->len) * 2, capacity); if (padding) { brealloc(plaintext, plaintext->len + padding, capacity); memmove(plaintext->data + padding, plaintext->data, plaintext->len); sodium_memzero(plaintext->data, padding); } crypto_stream_xor_ic((uint8_t *)(ciphertext->data + nonce_len), (const uint8_t *)plaintext->data, (uint64_t)(plaintext->len + padding), (const uint8_t *)cipher_ctx->nonce, cipher_ctx->counter / SODIUM_BLOCK_SIZE, cipher->key, cipher->method); cipher_ctx->counter += plaintext->len; if (padding) { memmove(ciphertext->data + nonce_len, ciphertext->data + nonce_len + padding, ciphertext->len); } } else { err = cipher_ctx_update(cipher_ctx, (uint8_t *)(ciphertext->data + nonce_len), &ciphertext->len, (const uint8_t *)plaintext->data, plaintext->len); if (err) { return CRYPTO_ERROR; } } #ifdef SS_DEBUG dump("PLAIN", plaintext->data, plaintext->len); dump("CIPHER", ciphertext->data + nonce_len, ciphertext->len); #endif bswap_data(plaintext, ciphertext); plaintext->len = nonce_len + ciphertext->len; return CRYPTO_OK; } int stream_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity) { size_t nonce_len = cipher->nonce_len; int err = CRYPTO_OK; if (ciphertext->len <= nonce_len) { return CRYPTO_ERROR; } cipher_ctx_t cipher_ctx; stream_ctx_init(cipher, &cipher_ctx, 0); static buffer_t tmp = { 0, 0, 0, NULL }; brealloc(&tmp, ciphertext->len, capacity); buffer_t *plaintext = &tmp; plaintext->len = ciphertext->len - nonce_len; uint8_t *nonce = cipher_ctx.nonce; memcpy(nonce, ciphertext->data, nonce_len); if (ppbloom_check((void *)nonce, nonce_len) == 1) { LOGE("crypto: stream: repeat IV detected"); return CRYPTO_ERROR; } cipher_ctx_set_nonce(&cipher_ctx, nonce, nonce_len, 0); if (cipher->method >= SALSA20) { crypto_stream_xor_ic((uint8_t *)plaintext->data, (const uint8_t *)(ciphertext->data + nonce_len), (uint64_t)(ciphertext->len - nonce_len), (const uint8_t *)nonce, 0, cipher->key, cipher->method); } else { err = cipher_ctx_update(&cipher_ctx, (uint8_t *)plaintext->data, &plaintext->len, (const uint8_t *)(ciphertext->data + nonce_len), ciphertext->len - nonce_len); } stream_ctx_release(&cipher_ctx); if (err) return CRYPTO_ERROR; #ifdef SS_DEBUG dump("PLAIN", plaintext->data, plaintext->len); dump("CIPHER", ciphertext->data + nonce_len, ciphertext->len - nonce_len); dump("NONCE", ciphertext->data, nonce_len); #endif ppbloom_add((void *)nonce, nonce_len); bswap_data(ciphertext, plaintext); ciphertext->len = plaintext->len; return CRYPTO_OK; } int stream_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity) { if (cipher_ctx == NULL) return CRYPTO_ERROR; cipher_t *cipher = cipher_ctx->cipher; // In-place fast path for non-Salsa20 ciphers after init. // mbedtls_cipher_update supports output == input for CFB/CTR stream modes. if (cipher_ctx->init && cipher->method < SALSA20) { if (ciphertext->len <= 0) return CRYPTO_NEED_MORE; size_t out_len = ciphertext->len; int err = cipher_ctx_update(cipher_ctx, (uint8_t *)ciphertext->data, &out_len, (const uint8_t *)ciphertext->data, ciphertext->len); if (err) return CRYPTO_ERROR; ciphertext->len = out_len; if (cipher_ctx->init == 1 && cipher->method >= RC4_MD5) { if (ppbloom_check((void *)cipher_ctx->nonce, cipher->nonce_len) == 1) { LOGE("crypto: stream: repeat IV detected"); return CRYPTO_ERROR; } ppbloom_add((void *)cipher_ctx->nonce, cipher->nonce_len); cipher_ctx->init = 2; } return CRYPTO_OK; } static buffer_t tmp = { 0, 0, 0, NULL }; int err = CRYPTO_OK; brealloc(&tmp, ciphertext->len, capacity); buffer_t *plaintext = &tmp; plaintext->len = ciphertext->len; if (!cipher_ctx->init) { if (cipher_ctx->chunk == NULL) { cipher_ctx->chunk = (buffer_t *)ss_malloc(sizeof(buffer_t)); memset(cipher_ctx->chunk, 0, sizeof(buffer_t)); balloc(cipher_ctx->chunk, cipher->nonce_len); } size_t left_len = min(cipher->nonce_len - cipher_ctx->chunk->len, ciphertext->len); if (left_len > 0) { memcpy(cipher_ctx->chunk->data + cipher_ctx->chunk->len, ciphertext->data, left_len); memmove(ciphertext->data, ciphertext->data + left_len, ciphertext->len - left_len); cipher_ctx->chunk->len += left_len; ciphertext->len -= left_len; } if (cipher_ctx->chunk->len < cipher->nonce_len) return CRYPTO_NEED_MORE; uint8_t *nonce = cipher_ctx->nonce; size_t nonce_len = cipher->nonce_len; plaintext->len -= left_len; memcpy(nonce, cipher_ctx->chunk->data, nonce_len); cipher_ctx_set_nonce(cipher_ctx, nonce, nonce_len, 0); cipher_ctx->counter = 0; cipher_ctx->init = 1; if (cipher->method >= RC4_MD5) { if (ppbloom_check((void *)nonce, nonce_len) == 1) { LOGE("crypto: stream: repeat IV detected"); return CRYPTO_ERROR; } } } if (ciphertext->len <= 0) return CRYPTO_NEED_MORE; if (cipher->method >= SALSA20) { int padding = cipher_ctx->counter % SODIUM_BLOCK_SIZE; brealloc(plaintext, (plaintext->len + padding) * 2, capacity); if (padding) { brealloc(ciphertext, ciphertext->len + padding, capacity); memmove(ciphertext->data + padding, ciphertext->data, ciphertext->len); sodium_memzero(ciphertext->data, padding); } crypto_stream_xor_ic((uint8_t *)plaintext->data, (const uint8_t *)(ciphertext->data), (uint64_t)(ciphertext->len + padding), (const uint8_t *)cipher_ctx->nonce, cipher_ctx->counter / SODIUM_BLOCK_SIZE, cipher->key, cipher->method); cipher_ctx->counter += ciphertext->len; if (padding) { memmove(plaintext->data, plaintext->data + padding, plaintext->len); } } else { err = cipher_ctx_update(cipher_ctx, (uint8_t *)plaintext->data, &plaintext->len, (const uint8_t *)(ciphertext->data), ciphertext->len); } if (err) return CRYPTO_ERROR; #ifdef SS_DEBUG dump("PLAIN", plaintext->data, plaintext->len); dump("CIPHER", ciphertext->data, ciphertext->len); #endif // Add to bloom filter if (cipher_ctx->init == 1) { if (cipher->method >= RC4_MD5) { if (ppbloom_check((void *)cipher_ctx->nonce, cipher->nonce_len) == 1) { LOGE("crypto: stream: repeat IV detected"); return CRYPTO_ERROR; } ppbloom_add((void *)cipher_ctx->nonce, cipher->nonce_len); cipher_ctx->init = 2; } } bswap_data(ciphertext, plaintext); ciphertext->len = plaintext->len; return CRYPTO_OK; } void stream_ctx_init(cipher_t *cipher, cipher_ctx_t *cipher_ctx, int enc) { sodium_memzero(cipher_ctx, sizeof(cipher_ctx_t)); stream_cipher_ctx_init(cipher_ctx, cipher->method, enc); cipher_ctx->cipher = cipher; if (enc) { rand_bytes(cipher_ctx->nonce, cipher->nonce_len); } } cipher_t * stream_key_init(int method, const char *pass, const char *key) { if (method <= TABLE || method >= STREAM_CIPHER_NUM) { LOGE("cipher->key_init(): Illegal method"); return NULL; } cipher_t *cipher = (cipher_t *)ss_malloc(sizeof(cipher_t)); memset(cipher, 0, sizeof(cipher_t)); if (method < SALSA20 && stream_get_cipher_type(method) == NULL) { LOGE("Cipher %s not found in crypto library", supported_stream_ciphers[method]); FATAL("Cannot initialize cipher"); } if (key != NULL) cipher->key_len = crypto_parse_key(key, cipher->key, supported_stream_ciphers_key_size[method]); else cipher->key_len = crypto_derive_key(pass, cipher->key, supported_stream_ciphers_key_size[method]); if (cipher->key_len == 0) { FATAL("Cannot generate key and NONCE"); } cipher->nonce_len = supported_stream_ciphers_nonce_size[method]; cipher->method = method; return cipher; } cipher_t * stream_init(const char *pass, const char *key, const char *method) { int m = TABLE; if (method != NULL) { for (m = TABLE; m < STREAM_CIPHER_NUM; m++) if (strcmp(method, supported_stream_ciphers[m]) == 0) { break; } if (m >= STREAM_CIPHER_NUM) { LOGE("Invalid cipher name: %s, use chacha20-ietf instead", method); m = CHACHA20IETF; } } if (m == TABLE) { LOGE("Table is deprecated"); return NULL; } return stream_key_init(m, pass, key); } ================================================ FILE: src/stream.h ================================================ /* * encrypt.h - Define the enryptor's interface * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _STREAM_H #define _STREAM_H #ifndef __MINGW32__ #include #endif #include #include #include #include #ifdef HAVE_STDINT_H #include #elif HAVE_INTTYPES_H #include #endif #include #define STREAM_CIPHER_NUM 21 #include "crypto.h" int stream_encrypt_all(buffer_t *, cipher_t *, size_t); int stream_decrypt_all(buffer_t *, cipher_t *, size_t); int stream_encrypt(buffer_t *, cipher_ctx_t *, size_t); int stream_decrypt(buffer_t *, cipher_ctx_t *, size_t); void stream_ctx_init(cipher_t *, cipher_ctx_t *, int); void stream_ctx_release(cipher_ctx_t *); cipher_t *stream_init(const char *pass, const char *key, const char *method); #endif // _STREAM_H ================================================ FILE: src/tunnel.c ================================================ /* * tunnel.c - Setup a local port forwarding through remote shadowsocks server * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #include #include #include #include #include #include #include #include #include #ifndef __MINGW32__ #include #include #include #include #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) #include #include #define SET_INTERFACE #endif #include #include "netutils.h" #include "utils.h" #include "plugin.h" #include "tunnel.h" #include "winsock.h" #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif static void accept_cb(EV_P_ ev_io *w, int revents); static void server_recv_cb(EV_P_ ev_io *w, int revents); static void server_send_cb(EV_P_ ev_io *w, int revents); static void remote_recv_cb(EV_P_ ev_io *w, int revents); static void remote_send_cb(EV_P_ ev_io *w, int revents); static remote_t *new_remote(int fd, int timeout); static server_t *new_server(int fd); static void free_remote(remote_t *remote); static void close_and_free_remote(EV_P_ remote_t *remote); static void free_server(server_t *server); static void close_and_free_server(EV_P_ server_t *server); #ifdef __ANDROID__ int vpn = 0; #endif int verbose = 0; int reuse_port = 0; int tcp_incoming_sndbuf = 0; int tcp_incoming_rcvbuf = 0; int tcp_outgoing_sndbuf = 0; int tcp_outgoing_rcvbuf = 0; static crypto_t *crypto; static int ipv6first = 0; static int mode = TCP_ONLY; #ifdef HAVE_SETRLIMIT static int nofile = 0; #endif static int no_delay = 0; int fast_open = 0; static int ret_val = 0; static struct ev_signal sigint_watcher; static struct ev_signal sigterm_watcher; #ifndef __MINGW32__ static struct ev_signal sigchld_watcher; #else static struct plugin_watcher_t { ev_io io; SOCKET fd; uint16_t port; int valid; } plugin_watcher; #endif #ifndef __MINGW32__ static int setnonblocking(int fd) { int flags; if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { flags = 0; } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } #endif int create_and_bind(const char *addr, const char *port) { struct addrinfo hints; struct addrinfo *result, *rp; int s, listen_sock = -1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */ result = NULL; s = getaddrinfo(addr, port, &hints, &result); if (s != 0) { LOGI("getaddrinfo: %s", gai_strerror(s)); return -1; } if (result == NULL) { LOGE("Could not bind"); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { listen_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (listen_sock == -1) { continue; } int opt = 1; setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(listen_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif if (reuse_port) { int err = set_reuseport(listen_sock); if (err == 0) { LOGI("tcp port reuse enabled"); } } s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ break; } else { ERROR("bind"); } close(listen_sock); listen_sock = -1; } freeaddrinfo(result); return listen_sock; } static void server_recv_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_recv_ctx = (server_ctx_t *)w; server_t *server = server_recv_ctx->server; remote_t *remote = server->remote; if (remote == NULL) { close_and_free_server(EV_A_ server); return; } ssize_t r = recv(server->fd, remote->buf->data, SOCKET_BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("server recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } remote->buf->len = r; int err = crypto->encrypt(remote->buf, server->e_ctx, SOCKET_BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } int s = send(remote->fd, remote->buf->data, remote->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send remote->buf->idx = 0; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { ERROR("send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < remote->buf->len) { remote->buf->len -= s; remote->buf->idx = s; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } } static void server_send_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_send_ctx = (server_ctx_t *)w; server_t *server = server_send_ctx->server; remote_t *remote = server->remote; if (server->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(server->fd, server->buf->data + server->buf->idx, server->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < server->buf->len) { // partly sent, move memory, wait for the next time to send server->buf->len -= s; server->buf->idx += s; return; } else { // all sent out, wait for reading server->buf->len = 0; server->buf->idx = 0; ev_io_stop(EV_A_ & server_send_ctx->io); if (remote != NULL) { ev_io_start(EV_A_ & remote->recv_ctx->io); } else { close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } } } static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) { remote_ctx_t *remote_ctx = cork_container_of(watcher, remote_ctx_t, watcher); remote_t *remote = remote_ctx->remote; server_t *server = remote->server; if (verbose) { LOGI("TCP connection timeout"); } ev_timer_stop(EV_A_ watcher); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } static void remote_recv_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w; remote_t *remote = remote_recv_ctx->remote; server_t *server = remote->server; ssize_t r = recv(remote->fd, server->buf->data, SOCKET_BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("remote recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } server->buf->len = r; int err = crypto->decrypt(server->buf, server->d_ctx, SOCKET_BUF_SIZE); if (err == CRYPTO_ERROR) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (err == CRYPTO_NEED_MORE) { return; // Wait for more } int s = send(server->fd, server->buf->data, server->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send server->buf->idx = 0; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); } else { ERROR("send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < server->buf->len) { server->buf->len -= s; server->buf->idx = s; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); } // Disable TCP_NODELAY after the first response are sent if (!remote->recv_ctx->connected && !no_delay) { int opt = 0; setsockopt(server->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); setsockopt(remote->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); } remote->recv_ctx->connected = 1; } static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; ev_timer_stop(EV_A_ & remote_send_ctx->watcher); if (!remote_send_ctx->connected) { int r = 0; if (remote->addr == NULL) { struct sockaddr_storage addr; socklen_t len = sizeof(struct sockaddr_storage); r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); } if (r == 0) { remote_send_ctx->connected = 1; assert(remote->buf->len == 0); buffer_t *abuf = remote->buf; ss_addr_t *sa = &server->destaddr; struct cork_ip ip; if (cork_ip_init(&ip, sa->host) != -1) { if (ip.version == 4) { // send as IPv4 struct in_addr host; memset(&host, 0, sizeof(struct in_addr)); int host_len = sizeof(struct in_addr); if (inet_pton(AF_INET, sa->host, &host) == -1) { FATAL("IP parser error"); } abuf->data[abuf->len++] = 1; memcpy(abuf->data + abuf->len, &host, host_len); abuf->len += host_len; } else if (ip.version == 6) { // send as IPv6 struct in6_addr host; memset(&host, 0, sizeof(struct in6_addr)); int host_len = sizeof(struct in6_addr); if (inet_pton(AF_INET6, sa->host, &host) == -1) { FATAL("IP parser error"); } abuf->data[abuf->len++] = 4; memcpy(abuf->data + abuf->len, &host, host_len); abuf->len += host_len; } else { FATAL("IP parser error"); } } else { // send as domain int host_len = strlen(sa->host); abuf->data[abuf->len++] = 3; abuf->data[abuf->len++] = host_len; memcpy(abuf->data + abuf->len, sa->host, host_len); abuf->len += host_len; } uint16_t port = htons(atoi(sa->port)); memcpy(abuf->data + abuf->len, &port, 2); abuf->len += 2; int err = crypto->encrypt(abuf, server->e_ctx, SOCKET_BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } ev_io_start(EV_A_ & remote->recv_ctx->io); } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = -1; if (remote->addr != NULL) { #if defined(TCP_FASTOPEN_WINSOCK) DWORD s = -1; DWORD err = 0; do { int optval = 1; // Set fast open option if (setsockopt(remote->fd, IPPROTO_TCP, TCP_FASTOPEN, &optval, sizeof(optval)) != 0) { ERROR("setsockopt"); break; } // Load ConnectEx function LPFN_CONNECTEX ConnectEx = winsock_getconnectex(); if (ConnectEx == NULL) { LOGE("Cannot load ConnectEx() function"); err = WSAENOPROTOOPT; break; } // ConnectEx requires a bound socket if (winsock_dummybind(remote->fd, (struct sockaddr *)&(remote->addr)) != 0) { ERROR("bind"); break; } // Call ConnectEx to send data memset(&remote->olap, 0, sizeof(remote->olap)); remote->connect_ex_done = 0; if (ConnectEx(remote->fd, (const struct sockaddr *)&(remote->addr), get_sockaddr_len(remote->addr), remote->buf->data, remote->buf->len, &s, &remote->olap)) { remote->connect_ex_done = 1; break; } // XXX: ConnectEx pending, check later in remote_send if (WSAGetLastError() == ERROR_IO_PENDING) { err = CONNECT_IN_PROGRESS; break; } ERROR("ConnectEx"); } while (0); // Set error number if (err) { SetLastError(err); } #elif defined(CONNECT_DATA_IDEMPOTENT) ((struct sockaddr_in *)&(remote->addr))->sin_len = sizeof(struct sockaddr_in); sa_endpoints_t endpoints; memset((char *)&endpoints, 0, sizeof(endpoints)); endpoints.sae_dstaddr = (struct sockaddr *)&(remote->addr); endpoints.sae_dstaddrlen = get_sockaddr_len(remote->addr); s = connectx(remote->fd, &endpoints, SAE_ASSOCID_ANY, CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, NULL, 0, NULL, NULL); #elif defined(TCP_FASTOPEN_CONNECT) int optval = 1; if (setsockopt(remote->fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&optval, sizeof(optval)) < 0) FATAL("failed to set TCP_FASTOPEN_CONNECT"); s = connect(remote->fd, remote->addr, get_sockaddr_len(remote->addr)); if (s == 0) s = send(remote->fd, remote->buf->data, remote->buf->len, 0); #elif defined(MSG_FASTOPEN) s = sendto(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, MSG_FASTOPEN, remote->addr, get_sockaddr_len(remote->addr)); #else FATAL("tcp fast open is not supported on this platform"); #endif remote->addr = NULL; if (s == -1) { if (errno == CONNECT_IN_PROGRESS) { ev_io_start(EV_A_ & remote_send_ctx->io); ev_timer_start(EV_A_ & remote_send_ctx->watcher); } else { fast_open = 0; if (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT || errno == ENOPROTOOPT) { LOGE("fast open is not supported on this platform"); } else { ERROR("fast_open_connect"); } close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } } else { s = send(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, 0); } if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf->len) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } } static remote_t * new_remote(int fd, int timeout) { remote_t *remote = ss_malloc(sizeof(remote_t)); memset(remote, 0, sizeof(remote_t)); remote->recv_ctx = ss_malloc(sizeof(remote_ctx_t)); remote->send_ctx = ss_malloc(sizeof(remote_ctx_t)); remote->buf = ss_malloc(sizeof(buffer_t)); balloc(remote->buf, SOCKET_BUF_SIZE); memset(remote->recv_ctx, 0, sizeof(remote_ctx_t)); memset(remote->send_ctx, 0, sizeof(remote_ctx_t)); remote->fd = fd; remote->recv_ctx->remote = remote; remote->recv_ctx->connected = 0; remote->send_ctx->remote = remote; remote->send_ctx->connected = 0; ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ); ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE); ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb, min(MAX_CONNECT_TIMEOUT, timeout), 0); return remote; } static void free_remote(remote_t *remote) { if (remote->server != NULL) { remote->server->remote = NULL; } if (remote->buf != NULL) { bfree(remote->buf); ss_free(remote->buf); } ss_free(remote->recv_ctx); ss_free(remote->send_ctx); ss_free(remote); } static void close_and_free_remote(EV_P_ remote_t *remote) { if (remote != NULL) { ev_timer_stop(EV_A_ & remote->send_ctx->watcher); ev_io_stop(EV_A_ & remote->send_ctx->io); ev_io_stop(EV_A_ & remote->recv_ctx->io); close(remote->fd); free_remote(remote); } } static server_t * new_server(int fd) { server_t *server = ss_malloc(sizeof(server_t)); memset(server, 0, sizeof(server_t)); server->recv_ctx = ss_malloc(sizeof(server_ctx_t)); server->send_ctx = ss_malloc(sizeof(server_ctx_t)); server->buf = ss_malloc(sizeof(buffer_t)); balloc(server->buf, SOCKET_BUF_SIZE); memset(server->recv_ctx, 0, sizeof(server_ctx_t)); memset(server->send_ctx, 0, sizeof(server_ctx_t)); server->fd = fd; server->recv_ctx->server = server; server->recv_ctx->connected = 0; server->send_ctx->server = server; server->send_ctx->connected = 0; server->e_ctx = ss_malloc(sizeof(cipher_ctx_t)); server->d_ctx = ss_malloc(sizeof(cipher_ctx_t)); crypto->ctx_init(crypto->cipher, server->e_ctx, 1); crypto->ctx_init(crypto->cipher, server->d_ctx, 0); ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ); ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE); return server; } static void free_server(server_t *server) { if (server->remote != NULL) { server->remote->server = NULL; } if (server->e_ctx != NULL) { crypto->ctx_release(server->e_ctx); ss_free(server->e_ctx); } if (server->d_ctx != NULL) { crypto->ctx_release(server->d_ctx); ss_free(server->d_ctx); } if (server->buf != NULL) { bfree(server->buf); ss_free(server->buf); } ss_free(server->recv_ctx); ss_free(server->send_ctx); ss_free(server); } static void close_and_free_server(EV_P_ server_t *server) { if (server != NULL) { ev_io_stop(EV_A_ & server->send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); close(server->fd); free_server(server); } } static void accept_cb(EV_P_ ev_io *w, int revents) { struct listen_ctx *listener = (struct listen_ctx *)w; int serverfd = accept(listener->fd, NULL, NULL); if (serverfd == -1) { ERROR("accept"); return; } setnonblocking(serverfd); int opt = 1; setsockopt(serverfd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif if (tcp_incoming_sndbuf > 0) { setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &tcp_incoming_sndbuf, sizeof(int)); } if (tcp_incoming_rcvbuf > 0) { setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &tcp_incoming_rcvbuf, sizeof(int)); } int index = rand() % listener->remote_num; struct sockaddr *remote_addr = listener->remote_addr[index]; int protocol = IPPROTO_TCP; if (listener->mptcp < 0) { protocol = IPPROTO_MPTCP; // Enable upstream MPTCP } int remotefd = socket(remote_addr->sa_family, SOCK_STREAM, protocol); if (remotefd == -1) { ERROR("socket"); return; } #ifdef __ANDROID__ if (vpn) { int not_protect = 0; if (remote_addr->sa_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)remote_addr; if (s->sin_addr.s_addr == inet_addr("127.0.0.1")) not_protect = 1; } if (!not_protect) { if (protect_socket(remotefd) == -1) { ERROR("protect_socket"); close(remotefd); return; } } } #endif int keepAlive = 1; setsockopt(remotefd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive)); setsockopt(remotefd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif // Enable out-of-tree MPTCP if (listener->mptcp > 1) { int err = setsockopt(remotefd, SOL_TCP, listener->mptcp, &opt, sizeof(opt)); if (err == -1) { ERROR("failed to enable out-of-tree multipath TCP"); } } else if (listener->mptcp == 1) { int i = 0; while ((listener->mptcp = mptcp_enabled_values[i]) > 0) { int err = setsockopt(remotefd, SOL_TCP, listener->mptcp, &opt, sizeof(opt)); if (err != -1) { break; } i++; } if (listener->mptcp == 0) { ERROR("failed to enable out-of-tree multipath TCP"); } } if (tcp_outgoing_sndbuf > 0) { setsockopt(remotefd, SOL_SOCKET, SO_SNDBUF, &tcp_outgoing_sndbuf, sizeof(int)); } if (tcp_outgoing_rcvbuf > 0) { setsockopt(remotefd, SOL_SOCKET, SO_RCVBUF, &tcp_outgoing_rcvbuf, sizeof(int)); } // Setup setnonblocking(remotefd); #ifdef SET_INTERFACE if (listener->iface) { if (setinterface(remotefd, listener->iface) == -1) ERROR("setinterface"); } #endif server_t *server = new_server(serverfd); remote_t *remote = new_remote(remotefd, listener->timeout); server->destaddr = listener->tunnel_addr; server->remote = remote; remote->server = server; if (fast_open) { remote->addr = remote_addr; } else { int r = connect(remotefd, remote_addr, get_sockaddr_len(remote_addr)); if (r == -1 && errno != CONNECT_IN_PROGRESS) { ERROR("connect"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } // listen to remote connected event ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); } static void signal_cb(EV_P_ ev_signal *w, int revents) { if (revents & EV_SIGNAL) { switch (w->signum) { #ifndef __MINGW32__ case SIGCHLD: if (!is_plugin_running()) { LOGE("plugin service exit unexpectedly"); ret_val = -1; } else return; #endif case SIGINT: case SIGTERM: ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); #ifndef __MINGW32__ ev_signal_stop(EV_DEFAULT, &sigchld_watcher); #else ev_io_stop(EV_DEFAULT, &plugin_watcher.io); #endif ev_unloop(EV_A_ EVUNLOOP_ALL); } } } #ifdef __MINGW32__ static void plugin_watcher_cb(EV_P_ ev_io *w, int revents) { char buf[1]; SOCKET fd = accept(plugin_watcher.fd, NULL, NULL); if (fd == INVALID_SOCKET) { return; } recv(fd, buf, 1, 0); closesocket(fd); LOGE("plugin service exit unexpectedly"); ret_val = -1; ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); ev_io_stop(EV_DEFAULT, &plugin_watcher.io); ev_unloop(EV_A_ EVUNLOOP_ALL); } #endif int main(int argc, char **argv) { srand(time(NULL)); int i, c; int pid_flags = 0; int mptcp = 0; int mtu = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; char *plugin = NULL; char *plugin_opts = NULL; char *plugin_host = NULL; char *plugin_port = NULL; char tmp_port[8]; ss_addr_t tunnel_addr = { .host = NULL, .port = NULL }; char *tunnel_addr_str = NULL; int remote_num = 0; char *remote_port = NULL; ss_addr_t remote_addr[MAX_REMOTE_NUM]; memset(remote_addr, 0, sizeof(ss_addr_t) * MAX_REMOTE_NUM); static struct option long_options[] = { { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "mtu", required_argument, NULL, GETOPT_VAL_MTU }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "tcp-incoming-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_SNDBUF }, { "tcp-incoming-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_INCOMING_RCVBUF }, { "tcp-outgoing-sndbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_SNDBUF }, { "tcp-outgoing-rcvbuf", required_argument, NULL, GETOPT_VAL_TCP_OUTGOING_RCVBUF }, { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "key", required_argument, NULL, GETOPT_VAL_KEY }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; opterr = 0; USE_TTY(); #ifdef __ANDROID__ while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:n:huUvV6A", long_options, NULL)) != -1) { #else while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:n:huUv6A", long_options, NULL)) != -1) { #endif switch (c) { case GETOPT_VAL_FAST_OPEN: fast_open = 1; break; case GETOPT_VAL_MTU: mtu = atoi(optarg); LOGI("set MTU to %d", mtu); break; case GETOPT_VAL_MPTCP: mptcp = get_mptcp(1); if (mptcp) LOGI("enable multipath TCP (%s)", mptcp > 0 ? "out-of-tree" : "upstream"); break; case GETOPT_VAL_NODELAY: no_delay = 1; LOGI("enable TCP no-delay"); break; case GETOPT_VAL_PLUGIN: plugin = optarg; break; case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; case GETOPT_VAL_KEY: key = optarg; break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; case GETOPT_VAL_TCP_INCOMING_SNDBUF: tcp_incoming_sndbuf = atoi(optarg); break; case GETOPT_VAL_TCP_INCOMING_RCVBUF: tcp_incoming_rcvbuf = atoi(optarg); break; case GETOPT_VAL_TCP_OUTGOING_SNDBUF: tcp_outgoing_sndbuf = atoi(optarg); break; case GETOPT_VAL_TCP_OUTGOING_RCVBUF: tcp_outgoing_rcvbuf = atoi(optarg); break; case 's': if (remote_num < MAX_REMOTE_NUM) { parse_addr(optarg, &remote_addr[remote_num++]); } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'L': tunnel_addr_str = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'v': verbose = 1; break; case GETOPT_VAL_HELP: case 'h': usage(); exit(EXIT_SUCCESS); case '6': ipv6first = 1; break; #ifdef __ANDROID__ case 'V': vpn = 1; break; #endif case 'A': FATAL("One time auth has been deprecated. Try AEAD ciphers instead."); break; case '?': // The option character is not recognized. LOGE("Unrecognized option: %s", optarg); opterr = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = get_default_conf(); } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) remote_addr[i] = conf->remote_addr[i]; } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (key == NULL) { key = conf->key; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (user == NULL) { user = conf->user; } if (plugin == NULL) { plugin = conf->plugin; } if (plugin_opts == NULL) { plugin_opts = conf->plugin_opts; } if (tunnel_addr_str == NULL) { tunnel_addr_str = conf->tunnel_address; } if (mode == TCP_ONLY) { mode = conf->mode; } if (mtu == 0) { mtu = conf->mtu; } if (mptcp == 0) { mptcp = conf->mptcp; } if (no_delay == 0) { no_delay = conf->no_delay; } if (reuse_port == 0) { reuse_port = conf->reuse_port; } if (tcp_incoming_sndbuf == 0) { tcp_incoming_sndbuf = conf->tcp_incoming_sndbuf; } if (tcp_incoming_rcvbuf == 0) { tcp_incoming_rcvbuf = conf->tcp_incoming_rcvbuf; } if (tcp_outgoing_sndbuf == 0) { tcp_outgoing_sndbuf = conf->tcp_outgoing_sndbuf; } if (tcp_outgoing_rcvbuf == 0) { tcp_outgoing_rcvbuf = conf->tcp_outgoing_rcvbuf; } if (fast_open == 0) { fast_open = conf->fast_open; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } #endif } if (remote_num == 0 || remote_port == NULL || tunnel_addr_str == NULL || local_port == NULL || (password == NULL && key == NULL)) { usage(); exit(EXIT_FAILURE); } #ifdef __MINGW32__ winsock_init(); #endif if (tcp_incoming_sndbuf != 0 && tcp_incoming_sndbuf < SOCKET_BUF_SIZE) { tcp_incoming_sndbuf = 0; } if (tcp_incoming_sndbuf != 0) { LOGI("set TCP incoming connection send buffer size to %d", tcp_incoming_sndbuf); } if (tcp_incoming_rcvbuf != 0 && tcp_incoming_rcvbuf < SOCKET_BUF_SIZE) { tcp_incoming_rcvbuf = 0; } if (tcp_incoming_rcvbuf != 0) { LOGI("set TCP incoming connection receive buffer size to %d", tcp_incoming_rcvbuf); } if (tcp_outgoing_sndbuf != 0 && tcp_outgoing_sndbuf < SOCKET_BUF_SIZE) { tcp_outgoing_sndbuf = 0; } if (tcp_outgoing_sndbuf != 0) { LOGI("set TCP outgoing connection send buffer size to %d", tcp_outgoing_sndbuf); } if (tcp_outgoing_rcvbuf != 0 && tcp_outgoing_rcvbuf < SOCKET_BUF_SIZE) { tcp_outgoing_rcvbuf = 0; } if (tcp_outgoing_rcvbuf != 0) { LOGI("set TCP outgoing connection receive buffer size to %d", tcp_outgoing_rcvbuf); } if (plugin != NULL) { uint16_t port = get_local_port(); if (port == 0) { FATAL("failed to find a free port"); } snprintf(tmp_port, 8, "%d", port); if (is_ipv6only(remote_addr, remote_num, ipv6first)) { plugin_host = "::1"; } else { plugin_host = "127.0.0.1"; } plugin_port = tmp_port; #ifdef __MINGW32__ memset(&plugin_watcher, 0, sizeof(plugin_watcher)); plugin_watcher.port = get_local_port(); if (plugin_watcher.port == 0) { LOGE("failed to assign a control port for plugin"); } #endif LOGI("plugin \"%s\" enabled", plugin); } if (method == NULL) { method = "chacha20-ietf-poly1305"; } if (timeout == NULL) { timeout = "60"; } #ifdef HAVE_SETRLIMIT /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif if (local_addr == NULL) { if (is_ipv6only(remote_addr, remote_num, ipv6first)) { local_addr = "::1"; } else { local_addr = "127.0.0.1"; } } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); fast_open = 0; #endif } USE_SYSLOG(argv[0], pid_flags); if (pid_flags) { daemonize(pid_path); } if (ipv6first) { LOGI("resolving hostname to IPv6 address first"); } // parse tunnel addr parse_addr(tunnel_addr_str, &tunnel_addr); if (tunnel_addr.port == NULL) { FATAL("tunnel port is not defined"); } #ifdef __MINGW32__ // Listen on plugin control port if (plugin != NULL && plugin_watcher.port != 0) { SOCKET fd; fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd != INVALID_SOCKET) { plugin_watcher.valid = 0; do { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_port = htons(plugin_watcher.port); if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) { LOGE("failed to bind plugin control port"); break; } if (listen(fd, 1)) { LOGE("failed to listen on plugin control port"); break; } plugin_watcher.fd = fd; ev_io_init(&plugin_watcher.io, plugin_watcher_cb, fd, EV_READ); ev_io_start(EV_DEFAULT, &plugin_watcher.io); plugin_watcher.valid = 1; } while (0); if (!plugin_watcher.valid) { closesocket(fd); plugin_watcher.port = 0; } } } #endif if (plugin != NULL) { int len = 0; size_t buf_size = 256 * remote_num; char *remote_str = ss_malloc(buf_size); snprintf(remote_str, buf_size, "%s", remote_addr[0].host); for (int i = 1; i < remote_num; i++) { snprintf(remote_str + len, buf_size - len, "|%s", remote_addr[i].host); len = strlen(remote_str); } int err = start_plugin(plugin, plugin_opts, remote_str, remote_port, plugin_host, plugin_port, #ifdef __MINGW32__ plugin_watcher.port, #endif MODE_CLIENT); if (err) { ERROR("start_plugin"); FATAL("failed to start the plugin"); } } #ifndef __MINGW32__ // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); #ifndef __MINGW32__ ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigchld_watcher); #endif // Setup keys LOGI("initializing ciphers... %s", method); crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); // Setup proxy context struct listen_ctx listen_ctx; memset(&listen_ctx, 0, sizeof(struct listen_ctx)); listen_ctx.tunnel_addr = tunnel_addr; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = ss_malloc(sizeof(struct sockaddr *) * remote_num); memset(listen_ctx.remote_addr, 0, sizeof(struct sockaddr *) * remote_num); for (i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; if (plugin != NULL) { host = plugin_host; port = plugin_port; } struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; if (plugin != NULL) break; } listen_ctx.timeout = atoi(timeout); listen_ctx.iface = iface; listen_ctx.mptcp = mptcp; LOGI("listening at %s:%s", local_addr, local_port); struct ev_loop *loop = EV_DEFAULT; if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd == -1) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); char *host = remote_addr[0].host; char *port = remote_addr[0].port == NULL ? remote_port : remote_addr[0].port; struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } struct sockaddr *addr = (struct sockaddr *)storage; init_udprelay(local_addr, local_port, addr, get_sockaddr_len(addr), tunnel_addr, mtu, crypto, listen_ctx.timeout, iface); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } #ifndef __MINGW32__ // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); } if (geteuid() == 0) { LOGI("running from root user"); } #endif ev_run(loop, 0); if (plugin != NULL) { stop_plugin(); } for (i = 0; i < remote_num; i++) ss_free(listen_ctx.remote_addr[i]); ss_free(listen_ctx.remote_addr); #ifdef __MINGW32__ if (plugin_watcher.valid) { closesocket(plugin_watcher.fd); } winsock_cleanup(); #endif return ret_val; } ================================================ FILE: src/tunnel.h ================================================ /* * tunnel.h - Define tunnel's buffers and callbacks * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _TUNNEL_H #define _TUNNEL_H #ifdef HAVE_LIBEV_EV_H #include #else #include #endif #ifdef __MINGW32__ #include "winsock.h" #endif #include "crypto.h" #include "jconf.h" #include "common.h" typedef struct listen_ctx { ev_io io; ss_addr_t tunnel_addr; char *iface; int remote_num; int timeout; int fd; int mptcp; struct sockaddr **remote_addr; } listen_ctx_t; typedef struct server_ctx { ev_io io; int connected; struct server *server; } server_ctx_t; typedef struct server { int fd; buffer_t *buf; cipher_ctx_t *e_ctx; cipher_ctx_t *d_ctx; struct server_ctx *recv_ctx; struct server_ctx *send_ctx; struct remote *remote; ss_addr_t destaddr; } server_t; typedef struct remote_ctx { ev_io io; ev_timer watcher; int connected; struct remote *remote; } remote_ctx_t; typedef struct remote { int fd; #ifdef TCP_FASTOPEN_WINSOCK OVERLAPPED olap; int connect_ex_done; #endif buffer_t *buf; struct remote_ctx *recv_ctx; struct remote_ctx *send_ctx; struct server *server; struct sockaddr *addr; uint32_t counter; } remote_t; #endif // _TUNNEL_H ================================================ FILE: src/udprelay.c ================================================ /* * udprelay.c - Setup UDP relay for both client and server * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #include #include #include #include #include #include #include #include #include #ifndef __MINGW32__ #include #include #include #include #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) #include #include #define SET_INTERFACE #endif #include #include "utils.h" #include "netutils.h" #include "cache.h" #include "udprelay.h" #include "winsock.h" #ifdef MODULE_REMOTE #define MAX_UDP_CONN_NUM 512 #else #define MAX_UDP_CONN_NUM 256 #endif #ifdef MODULE_REMOTE #ifdef MODULE_ #error "MODULE_REMOTE and MODULE_LOCAL should not be both defined" #endif #endif #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif static void server_recv_cb(EV_P_ ev_io *w, int revents); static void remote_recv_cb(EV_P_ ev_io *w, int revents); static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents); static char *hash_key(const int af, const struct sockaddr_storage *addr); #ifdef MODULE_REMOTE static void resolv_free_cb(void *data); static void resolv_cb(struct sockaddr *addr, void *data); #endif static void close_and_free_remote(EV_P_ remote_ctx_t *ctx); static remote_ctx_t *new_remote(int fd, server_ctx_t *server_ctx); #ifdef __ANDROID__ extern uint64_t tx; extern uint64_t rx; extern int vpn; extern void stat_update_cb(); #endif extern int verbose; extern int reuse_port; #ifdef MODULE_REMOTE extern uint64_t tx; extern uint64_t rx; extern int is_bind_local_addr; extern struct sockaddr_storage local_addr_v4; extern struct sockaddr_storage local_addr_v6; #endif static int packet_size = DEFAULT_PACKET_SIZE; static int buf_size = DEFAULT_PACKET_SIZE * 2; static int server_num = 0; static server_ctx_t *server_ctx_list[MAX_REMOTE_NUM] = { NULL }; const char *s_port = NULL; #ifndef __MINGW32__ static int setnonblocking(int fd) { int flags; if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { flags = 0; } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } #endif #if defined(MODULE_REMOTE) && defined(SO_BROADCAST) static int set_broadcast(int socket_fd) { int opt = 1; return setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)); } #endif #ifdef SO_NOSIGPIPE static int set_nosigpipe(int socket_fd) { int opt = 1; return setsockopt(socket_fd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); } #endif #ifdef MODULE_REDIR #ifndef IP_TRANSPARENT #define IP_TRANSPARENT 19 #endif #ifndef IPV6_TRANSPARENT #define IPV6_TRANSPARENT 75 #endif #ifndef IP_RECVORIGDSTADDR #ifdef IP_ORIGDSTADDR #define IP_RECVORIGDSTADDR IP_ORIGDSTADDR #else #define IP_RECVORIGDSTADDR 20 #endif #endif #ifndef IPV6_RECVORIGDSTADDR #ifdef IPV6_ORIGDSTADDR #define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR #else #define IPV6_RECVORIGDSTADDR 74 #endif #endif static int get_dstaddr(struct msghdr *msg, struct sockaddr_storage *dstaddr) { struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVORIGDSTADDR) { memcpy(dstaddr, CMSG_DATA(cmsg), sizeof(struct sockaddr_in)); dstaddr->ss_family = AF_INET; return 0; } else if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVORIGDSTADDR) { memcpy(dstaddr, CMSG_DATA(cmsg), sizeof(struct sockaddr_in6)); dstaddr->ss_family = AF_INET6; return 0; } } return 1; } #endif #define HASH_KEY_LEN sizeof(struct sockaddr_storage) + sizeof(int) static char * hash_key(const int af, const struct sockaddr_storage *addr) { size_t addr_len = sizeof(struct sockaddr_storage); static char key[HASH_KEY_LEN]; memset(key, 0, HASH_KEY_LEN); memcpy(key, &af, sizeof(int)); memcpy(key + sizeof(int), (const uint8_t *)addr, addr_len); return key; } #if defined(MODULE_REDIR) || defined(MODULE_REMOTE) static int construct_udprelay_header(const struct sockaddr_storage *in_addr, char *addr_header) { int addr_header_len = 0; if (in_addr->ss_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)in_addr; size_t addr_len = sizeof(struct in_addr); addr_header[addr_header_len++] = 1; memcpy(addr_header + addr_header_len, &addr->sin_addr, addr_len); addr_header_len += addr_len; memcpy(addr_header + addr_header_len, &addr->sin_port, 2); addr_header_len += 2; } else if (in_addr->ss_family == AF_INET6) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)in_addr; size_t addr_len = sizeof(struct in6_addr); addr_header[addr_header_len++] = 4; memcpy(addr_header + addr_header_len, &addr->sin6_addr, addr_len); addr_header_len += addr_len; memcpy(addr_header + addr_header_len, &addr->sin6_port, 2); addr_header_len += 2; } else { return 0; } return addr_header_len; } #endif static int parse_udprelay_header(const char *buf, const size_t buf_len, char *host, char *port, struct sockaddr_storage *storage) { const uint8_t atyp = *(uint8_t *)buf; int offset = 1; // get remote addr and port if ((atyp & ADDRTYPE_MASK) == 1) { // IP V4 size_t in_addr_len = sizeof(struct in_addr); if (buf_len >= in_addr_len + 3) { if (storage != NULL) { struct sockaddr_in *addr = (struct sockaddr_in *)storage; addr->sin_family = AF_INET; memcpy(&addr->sin_addr, buf + offset, sizeof(struct in_addr)); memcpy(&addr->sin_port, buf + offset + in_addr_len, sizeof(uint16_t)); } if (host != NULL) { inet_ntop(AF_INET, (const void *)(buf + offset), host, INET_ADDRSTRLEN); } offset += in_addr_len; } } else if ((atyp & ADDRTYPE_MASK) == 3) { // Domain name uint8_t name_len = *(uint8_t *)(buf + offset); if (name_len + 4 <= buf_len) { if (storage != NULL) { char tmp[MAX_HOSTNAME_LEN] = { 0 }; struct cork_ip ip; memcpy(tmp, buf + offset + 1, name_len); if (cork_ip_init(&ip, tmp) != -1) { if (ip.version == 4) { struct sockaddr_in *addr = (struct sockaddr_in *)storage; inet_pton(AF_INET, tmp, &(addr->sin_addr)); memcpy(&addr->sin_port, buf + offset + 1 + name_len, sizeof(uint16_t)); addr->sin_family = AF_INET; } else if (ip.version == 6) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage; inet_pton(AF_INET, tmp, &(addr->sin6_addr)); memcpy(&addr->sin6_port, buf + offset + 1 + name_len, sizeof(uint16_t)); addr->sin6_family = AF_INET6; } } } if (host != NULL) { memcpy(host, buf + offset + 1, name_len); } offset += 1 + name_len; } } else if ((atyp & ADDRTYPE_MASK) == 4) { // IP V6 size_t in6_addr_len = sizeof(struct in6_addr); if (buf_len >= in6_addr_len + 3) { if (storage != NULL) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage; addr->sin6_family = AF_INET6; memcpy(&addr->sin6_addr, buf + offset, sizeof(struct in6_addr)); memcpy(&addr->sin6_port, buf + offset + in6_addr_len, sizeof(uint16_t)); } if (host != NULL) { inet_ntop(AF_INET6, (const void *)(buf + offset), host, INET6_ADDRSTRLEN); } offset += in6_addr_len; } } if (offset == 1) { LOGE("[udp] invalid header with addr type %d", atyp); return 0; } if (port != NULL) { sprintf(port, "%d", load16_be(buf + offset)); } offset += 2; return offset; } static char * get_addr_str(const struct sockaddr *sa, bool has_port) { static char s[SS_ADDRSTRLEN]; memset(s, 0, SS_ADDRSTRLEN); char addr[INET6_ADDRSTRLEN] = { 0 }; char port[PORTSTRLEN] = { 0 }; uint16_t p; struct sockaddr_in sa_in; struct sockaddr_in6 sa_in6; switch (sa->sa_family) { case AF_INET: memcpy(&sa_in, sa, sizeof(struct sockaddr_in)); inet_ntop(AF_INET, &sa_in.sin_addr, addr, INET_ADDRSTRLEN); p = ntohs(sa_in.sin_port); sprintf(port, "%d", p); break; case AF_INET6: memcpy(&sa_in6, sa, sizeof(struct sockaddr_in6)); inet_ntop(AF_INET6, &sa_in6.sin6_addr, addr, INET6_ADDRSTRLEN); p = ntohs(sa_in6.sin6_port); sprintf(port, "%d", p); break; default: strncpy(s, "Unknown AF", SS_ADDRSTRLEN); } int addr_len = strlen(addr); int port_len = strlen(port); memcpy(s, addr, addr_len); if (has_port) { memcpy(s + addr_len + 1, port, port_len); s[addr_len] = ':'; } return s; } int create_remote_socket(int ipv6) { int remote_sock; if (ipv6) { // Try to bind IPv6 first struct sockaddr_in6 addr; memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_family = AF_INET6; addr.sin6_addr = in6addr_any; addr.sin6_port = 0; remote_sock = socket(AF_INET6, SOCK_DGRAM, 0); if (remote_sock == -1) { ERROR("[udp] cannot create socket"); return -1; } #ifdef MODULE_REMOTE if (is_bind_local_addr) { if (local_addr_v6.ss_family == AF_INET6) { if (bind_to_addr(&local_addr_v6, remote_sock) == -1) { ERROR("bind_to_addr"); FATAL("[udp] cannot bind socket"); return -1; } } } else { #endif if (bind(remote_sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { FATAL("[udp] cannot bind socket"); return -1; } #ifdef MODULE_REMOTE } #endif } else { // Or else bind to IPv4 struct sockaddr_in addr; memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = 0; remote_sock = socket(AF_INET, SOCK_DGRAM, 0); if (remote_sock == -1) { ERROR("[udp] cannot create socket"); return -1; } #ifdef MODULE_REMOTE if (is_bind_local_addr) { if (local_addr_v4.ss_family == AF_INET) { if (bind_to_addr(&local_addr_v4, remote_sock) == -1) { ERROR("bind_to_addr"); FATAL("[udp] cannot bind socket"); return -1; } } } else { #endif if (bind(remote_sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { FATAL("[udp] cannot bind remote"); return -1; } #ifdef MODULE_REMOTE } #endif } #if defined(__linux__) // Disable fragmentation int val = IP_PMTUDISC_DO; setsockopt(remote_sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); #endif return remote_sock; } int create_server_socket(const char *host, const char *port) { struct addrinfo hints; struct addrinfo *result, *rp, *ipv4v6bindall; int s, server_sock = -1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ hints.ai_socktype = SOCK_DGRAM; /* We want a UDP socket */ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* For wildcard IP address */ hints.ai_protocol = IPPROTO_UDP; s = getaddrinfo(host, port, &hints, &result); if (s != 0) { LOGE("[udp] getaddrinfo: %s", gai_strerror(s)); return -1; } if (result == NULL) { LOGE("[udp] cannot bind"); return -1; } rp = result; /* * On Linux, with net.ipv6.bindv6only = 0 (the default), getaddrinfo(NULL) with * AI_PASSIVE returns 0.0.0.0 and :: (in this order). AI_PASSIVE was meant to * return a list of addresses to listen on, but it is impossible to listen on * 0.0.0.0 and :: at the same time, if :: implies dualstack mode. */ if (!host) { ipv4v6bindall = result; /* Loop over all address infos found until a IPV6 address is found. */ while (ipv4v6bindall) { if (ipv4v6bindall->ai_family == AF_INET6) { rp = ipv4v6bindall; /* Take first IPV6 address available */ break; } ipv4v6bindall = ipv4v6bindall->ai_next; /* Get next address info, if any */ } } for (/*rp = result*/; rp != NULL; rp = rp->ai_next) { server_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (server_sock == -1) { continue; } if (rp->ai_family == AF_INET6) { int ipv6only = host ? 1 : 0; setsockopt(server_sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)); } int opt = 1; setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE set_nosigpipe(server_sock); #endif if (reuse_port) { int err = set_reuseport(server_sock); if (err == 0) { LOGI("udp port reuse enabled"); } } #ifdef IP_TOS // Set QoS flag int tos = 46 << 2; int rc = setsockopt(server_sock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv4 dscp failed: %d", errno); } #ifdef IPV6_TCLASS rc = setsockopt(server_sock, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv6 dscp failed: %d", errno); } #endif #endif #ifdef MODULE_REDIR int sol = rp->ai_family == AF_INET ? SOL_IP : SOL_IPV6; int flag_t = rp->ai_family == AF_INET ? IP_TRANSPARENT : IPV6_TRANSPARENT; int flag_r = rp->ai_family == AF_INET ? IP_RECVORIGDSTADDR : IPV6_RECVORIGDSTADDR; if (setsockopt(server_sock, sol, flag_t, &opt, sizeof(opt))) { ERROR("[udp] setsockopt IP_TRANSPARENT"); exit(EXIT_FAILURE); } if (setsockopt(server_sock, sol, flag_r, &opt, sizeof(opt))) { FATAL("[udp] setsockopt IP_RECVORIGDSTADDR"); } #endif s = bind(server_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ break; } else { ERROR("[udp] bind"); } close(server_sock); server_sock = -1; } freeaddrinfo(result); #if defined(__linux__) // Disable fragmentation int val = IP_PMTUDISC_DO; setsockopt(server_sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); #endif return server_sock; } remote_ctx_t * new_remote(int fd, server_ctx_t *server_ctx) { remote_ctx_t *ctx = ss_malloc(sizeof(remote_ctx_t)); memset(ctx, 0, sizeof(remote_ctx_t)); ctx->fd = fd; ctx->server_ctx = server_ctx; ctx->af = AF_UNSPEC; ev_io_init(&ctx->io, remote_recv_cb, fd, EV_READ); ev_timer_init(&ctx->watcher, remote_timeout_cb, server_ctx->timeout, server_ctx->timeout); return ctx; } server_ctx_t * new_server_ctx(int fd) { server_ctx_t *ctx = ss_malloc(sizeof(server_ctx_t)); memset(ctx, 0, sizeof(server_ctx_t)); ctx->fd = fd; ev_io_init(&ctx->io, server_recv_cb, fd, EV_READ); return ctx; } #ifdef MODULE_REMOTE struct query_ctx * new_query_ctx(char *buf, size_t len) { struct query_ctx *ctx = ss_malloc(sizeof(struct query_ctx)); memset(ctx, 0, sizeof(struct query_ctx)); ctx->buf = ss_malloc(sizeof(buffer_t)); balloc(ctx->buf, len); memcpy(ctx->buf->data, buf, len); ctx->buf->len = len; return ctx; } void close_and_free_query(EV_P_ struct query_ctx *ctx) { if (ctx != NULL) { if (ctx->buf != NULL) { bfree(ctx->buf); ss_free(ctx->buf); } ss_free(ctx); } } #endif void close_and_free_remote(EV_P_ remote_ctx_t *ctx) { if (ctx != NULL) { ev_timer_stop(EV_A_ & ctx->watcher); ev_io_stop(EV_A_ & ctx->io); close(ctx->fd); ss_free(ctx); } } static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) { remote_ctx_t *remote_ctx = cork_container_of(watcher, remote_ctx_t, watcher); if (verbose) { LOGI("[udp] connection timeout"); } char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr); cache_remove(remote_ctx->server_ctx->conn_cache, key, HASH_KEY_LEN); } #ifdef MODULE_REMOTE static void resolv_free_cb(void *data) { struct query_ctx *ctx = (struct query_ctx *)data; if (ctx->buf != NULL) { bfree(ctx->buf); ss_free(ctx->buf); } ss_free(ctx); } static void resolv_cb(struct sockaddr *addr, void *data) { struct query_ctx *query_ctx = (struct query_ctx *)data; struct ev_loop *loop = query_ctx->server_ctx->loop; if (addr == NULL) { LOGE("[udp] unable to resolve"); } else { remote_ctx_t *remote_ctx = query_ctx->remote_ctx; int cache_hit = 0; // Lookup in the conn cache if (remote_ctx == NULL) { char *key = hash_key(AF_UNSPEC, &query_ctx->src_addr); cache_lookup(query_ctx->server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx); } if (remote_ctx == NULL) { int remotefd = create_remote_socket(addr->sa_family == AF_INET6); if (remotefd != -1) { setnonblocking(remotefd); #ifdef SO_BROADCAST set_broadcast(remotefd); #endif #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef IP_TOS // Set QoS flag int tos = 46 << 2; int rc = setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv4 dscp failed: %d", errno); } #ifdef IPV6_TCLASS rc = setsockopt(remotefd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv6 dscp failed: %d", errno); } #endif #endif #ifdef SET_INTERFACE if (query_ctx->server_ctx->iface) { if (setinterface(remotefd, query_ctx->server_ctx->iface) == -1) ERROR("setinterface"); } #endif remote_ctx = new_remote(remotefd, query_ctx->server_ctx); remote_ctx->src_addr = query_ctx->src_addr; remote_ctx->server_ctx = query_ctx->server_ctx; } else { ERROR("[udp] bind() error"); } } else { cache_hit = 1; } if (remote_ctx != NULL) { if (addr->sa_family == AF_INET) memcpy(&remote_ctx->dst_addr, addr, sizeof(struct sockaddr_in)); else memcpy(&remote_ctx->dst_addr, addr, sizeof(struct sockaddr_in6)); size_t addr_len = get_sockaddr_len(addr); int s = sendto(remote_ctx->fd, query_ctx->buf->data, query_ctx->buf->len, 0, addr, addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); if (!cache_hit) { close_and_free_remote(EV_A_ remote_ctx); } } else { if (!cache_hit) { // Add to conn cache char *key = hash_key(AF_UNSPEC, &remote_ctx->src_addr); cache_insert(query_ctx->server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } } } } } #endif void convert_ipv4_mapped_ipv6(struct sockaddr_storage* addr) { if (addr->ss_family == AF_INET) { struct sockaddr_in* ipv4_addr = (struct sockaddr_in*)addr; struct sockaddr_storage mapped_addr; memset(&mapped_addr, 0, sizeof(mapped_addr)); struct sockaddr_in6* mapped_ipv6_addr = (struct sockaddr_in6*)&mapped_addr; mapped_ipv6_addr->sin6_family = AF_INET6; mapped_ipv6_addr->sin6_port = ipv4_addr->sin_port; uint8_t* ipv6_raw_addr = mapped_ipv6_addr->sin6_addr.s6_addr; ipv6_raw_addr[10] = 0xff; ipv6_raw_addr[11] = 0xff; in_addr_t ipv4_raw_addr = ntohl(ipv4_addr->sin_addr.s_addr); ipv6_raw_addr[12] = (ipv4_raw_addr >> 24) & 0xff; ipv6_raw_addr[13] = (ipv4_raw_addr >> 16) & 0xff; ipv6_raw_addr[14] = (ipv4_raw_addr >> 8) & 0xff; ipv6_raw_addr[15] = ipv4_raw_addr & 0xff; memcpy(addr, &mapped_addr, sizeof(mapped_addr)); } } static void remote_recv_cb(EV_P_ ev_io *w, int revents) { ssize_t r; remote_ctx_t *remote_ctx = (remote_ctx_t *)w; server_ctx_t *server_ctx = remote_ctx->server_ctx; // server has been closed if (server_ctx == NULL) { LOGE("[udp] invalid server"); close_and_free_remote(EV_A_ remote_ctx); return; } if (verbose) { LOGI("[udp] remote receive a packet"); } struct sockaddr_storage src_addr; socklen_t src_addr_len = sizeof(struct sockaddr_storage); memset(&src_addr, 0, src_addr_len); buffer_t *buf = ss_malloc(sizeof(buffer_t)); balloc(buf, buf_size); // recv r = recvfrom(remote_ctx->fd, buf->data, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (r == -1) { // error on recv // simply drop that packet ERROR("[udp] remote_recv_recvfrom"); goto CLEAN_UP; } else if (r > packet_size) { if (verbose) { LOGI("[udp] remote_recv_recvfrom fragmentation, MTU at least be: " SSIZE_FMT, r + PACKET_HEADER_SIZE); } } buf->len = r; #ifdef MODULE_LOCAL int err = server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { LOGE("failed to handshake with %s: %s", get_addr_str((struct sockaddr *)&src_addr, false), "suspicious UDP packet"); // drop the packet silently goto CLEAN_UP; } #ifdef MODULE_REDIR struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); int len = parse_udprelay_header(buf->data, buf->len, NULL, NULL, &dst_addr); if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) { LOGI("[udp] ss-redir does not support domain name"); goto CLEAN_UP; } #else int len = parse_udprelay_header(buf->data, buf->len, NULL, NULL, NULL); #endif if (len == 0) { // error when parsing header LOGE("[udp] error in parse header"); goto CLEAN_UP; } #if defined(MODULE_TUNNEL) || defined(MODULE_REDIR) // Construct packet buf->len -= len; memmove(buf->data, buf->data + len, buf->len); #else #ifdef __ANDROID__ rx += buf->len; stat_update_cb(); #endif // Construct packet brealloc(buf, buf->len + 3, buf_size); memmove(buf->data + 3, buf->data, buf->len); memset(buf->data, 0, 3); buf->len += 3; #endif #endif #ifdef MODULE_REMOTE rx += buf->len; // Reconstruct UDP response header char addr_header[MAX_ADDR_HEADER_SIZE]; int addr_header_len = construct_udprelay_header(&src_addr, addr_header); // Construct packet brealloc(buf, buf->len + addr_header_len, buf_size); memmove(buf->data + addr_header_len, buf->data, buf->len); memcpy(buf->data, addr_header, addr_header_len); buf->len += addr_header_len; int err = server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } #endif if (buf->len > packet_size) { if (verbose) { LOGI("[udp] remote_recv_sendto fragmentation, MTU at least be: " SSIZE_FMT, buf->len + PACKET_HEADER_SIZE); } } #ifdef MODULE_REDIR convert_ipv4_mapped_ipv6(&dst_addr); size_t remote_dst_addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr); int src_fd = socket(AF_INET6, SOCK_DGRAM, 0); if (src_fd < 0) { ERROR("[udp] remote_recv_socket"); goto CLEAN_UP; } int opt = 1; if (setsockopt(src_fd, SOL_IPV6, IPV6_TRANSPARENT, &opt, sizeof(opt))) { ERROR("[udp] remote_recv_setsockopt"); close(src_fd); goto CLEAN_UP; } if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { ERROR("[udp] remote_recv_setsockopt"); close(src_fd); goto CLEAN_UP; } if (reuse_port) { if (set_reuseport(src_fd) != 0) { ERROR("[udp] remote_recv port_reuse"); } } #ifdef IP_TOS // Set QoS flag int tos = 46 << 2; int rc = setsockopt(src_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv4 dscp failed: %d", errno); } #ifdef IPV6_TCLASS rc = setsockopt(src_fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv6 dscp failed: %d", errno); } #endif #endif if (bind(src_fd, (struct sockaddr *)&dst_addr, remote_dst_addr_len) != 0) { ERROR("[udp] remote_recv_bind"); close(src_fd); goto CLEAN_UP; } struct sockaddr_storage mapped_src_addr; memcpy(&mapped_src_addr, &remote_ctx->src_addr, sizeof(remote_ctx->src_addr)); convert_ipv4_mapped_ipv6(&mapped_src_addr); size_t remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&mapped_src_addr); int s = sendto(src_fd, buf->data, buf->len, 0, (struct sockaddr *)&mapped_src_addr, remote_src_addr_len); if (s == -1 && !(errno == EAGAIN || errno == EWOULDBLOCK)) { ERROR("[udp] remote_recv_sendto"); close(src_fd); goto CLEAN_UP; } close(src_fd); #else size_t remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&remote_ctx->src_addr); int s = sendto(server_ctx->fd, buf->data, buf->len, 0, (struct sockaddr *)&remote_ctx->src_addr, remote_src_addr_len); if (s == -1 && !(errno == EAGAIN || errno == EWOULDBLOCK)) { ERROR("[udp] remote_recv_sendto"); goto CLEAN_UP; } #endif // handle the UDP packet successfully, // triger the timer ev_timer_again(EV_A_ & remote_ctx->watcher); CLEAN_UP: bfree(buf); ss_free(buf); } static void server_recv_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_ctx = (server_ctx_t *)w; struct sockaddr_storage src_addr; memset(&src_addr, 0, sizeof(struct sockaddr_storage)); buffer_t *buf = ss_malloc(sizeof(buffer_t)); balloc(buf, buf_size); socklen_t src_addr_len = sizeof(struct sockaddr_storage); unsigned int offset = 0; #ifdef MODULE_REDIR char control_buffer[64] = { 0 }; struct msghdr msg; memset(&msg, 0, sizeof(struct msghdr)); struct iovec iov[1]; struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); msg.msg_name = &src_addr; msg.msg_namelen = src_addr_len; msg.msg_control = control_buffer; msg.msg_controllen = sizeof(control_buffer); iov[0].iov_base = buf->data; iov[0].iov_len = buf_size; msg.msg_iov = iov; msg.msg_iovlen = 1; buf->len = recvmsg(server_ctx->fd, &msg, 0); if (buf->len == -1) { ERROR("[udp] server_recvmsg"); goto CLEAN_UP; } else if (buf->len > packet_size) { if (verbose) { LOGI("[udp] UDP server_recv_recvmsg fragmentation, MTU at least be: " SSIZE_FMT, buf->len + PACKET_HEADER_SIZE); } } if (get_dstaddr(&msg, &dst_addr)) { LOGE("[udp] unable to get dest addr"); goto CLEAN_UP; } src_addr_len = msg.msg_namelen; #else ssize_t r; r = recvfrom(server_ctx->fd, buf->data, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (r == -1) { // error on recv // simply drop that packet ERROR("[udp] server_recv_recvfrom"); goto CLEAN_UP; } else if (r > packet_size) { if (verbose) { LOGI("[udp] server_recv_recvfrom fragmentation, MTU at least be: " SSIZE_FMT, r + PACKET_HEADER_SIZE); } } buf->len = r; #endif if (verbose) { LOGI("[udp] server receive a packet"); } #ifdef MODULE_REMOTE tx += buf->len; int err = server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { LOGE("failed to handshake with %s: %s", get_addr_str((struct sockaddr *)&src_addr, false), "suspicious UDP packet"); // drop the packet silently goto CLEAN_UP; } #endif #ifdef MODULE_LOCAL #if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR) #ifdef __ANDROID__ tx += buf->len; #endif uint8_t frag = *(uint8_t *)(buf->data + 2); offset += 3; #endif #endif /* * * SOCKS5 UDP Request * +----+------+------+----------+----------+----------+ * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | * +----+------+------+----------+----------+----------+ * | 2 | 1 | 1 | Variable | 2 | Variable | * +----+------+------+----------+----------+----------+ * * SOCKS5 UDP Response * +----+------+------+----------+----------+----------+ * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | * +----+------+------+----------+----------+----------+ * | 2 | 1 | 1 | Variable | 2 | Variable | * +----+------+------+----------+----------+----------+ * * shadowsocks UDP Request (before encrypted) * +------+----------+----------+----------+ * | ATYP | DST.ADDR | DST.PORT | DATA | * +------+----------+----------+----------+ * | 1 | Variable | 2 | Variable | * +------+----------+----------+----------+ * * shadowsocks UDP Response (before encrypted) * +------+----------+----------+----------+ * | ATYP | DST.ADDR | DST.PORT | DATA | * +------+----------+----------+----------+ * | 1 | Variable | 2 | Variable | * +------+----------+----------+----------+ * * shadowsocks UDP Request and Response (after encrypted) * +-------+--------------+ * | IV | PAYLOAD | * +-------+--------------+ * | Fixed | Variable | * +-------+--------------+ * */ #ifdef MODULE_REDIR char addr_header[MAX_ADDR_HEADER_SIZE] = { 0 }; int addr_header_len = construct_udprelay_header(&dst_addr, addr_header); if (addr_header_len == 0) { LOGE("[udp] failed to parse tproxy addr"); goto CLEAN_UP; } // reconstruct the buffer brealloc(buf, buf->len + addr_header_len, buf_size); memmove(buf->data + addr_header_len, buf->data, buf->len); memcpy(buf->data, addr_header, addr_header_len); buf->len += addr_header_len; #elif MODULE_TUNNEL char addr_header[MAX_ADDR_HEADER_SIZE] = { 0 }; char *host = server_ctx->tunnel_addr.host; char *port = server_ctx->tunnel_addr.port; uint16_t port_num = (uint16_t)atoi(port); uint16_t port_net_num = htons(port_num); int addr_header_len = 0; struct cork_ip ip; if (cork_ip_init(&ip, host) != -1) { if (ip.version == 4) { // send as IPv4 struct in_addr host_addr; memset(&host_addr, 0, sizeof(struct in_addr)); int host_len = sizeof(struct in_addr); if (inet_pton(AF_INET, host, &host_addr) == -1) { FATAL("IP parser error"); } addr_header[addr_header_len++] = 1; memcpy(addr_header + addr_header_len, &host_addr, host_len); addr_header_len += host_len; } else if (ip.version == 6) { // send as IPv6 struct in6_addr host_addr; memset(&host_addr, 0, sizeof(struct in6_addr)); int host_len = sizeof(struct in6_addr); if (inet_pton(AF_INET6, host, &host_addr) == -1) { FATAL("IP parser error"); } addr_header[addr_header_len++] = 4; memcpy(addr_header + addr_header_len, &host_addr, host_len); addr_header_len += host_len; } else { FATAL("IP parser error"); } } else { // send as domain int host_len = strlen(host); addr_header[addr_header_len++] = 3; addr_header[addr_header_len++] = host_len; memcpy(addr_header + addr_header_len, host, host_len); addr_header_len += host_len; } memcpy(addr_header + addr_header_len, &port_net_num, 2); addr_header_len += 2; // reconstruct the buffer brealloc(buf, buf->len + addr_header_len, buf_size); memmove(buf->data + addr_header_len, buf->data, buf->len); memcpy(buf->data, addr_header, addr_header_len); buf->len += addr_header_len; #else char host[MAX_HOSTNAME_LEN] = { 0 }; char port[MAX_PORT_STR_LEN] = { 0 }; struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); int addr_header_len = parse_udprelay_header(buf->data + offset, buf->len - offset, host, port, &dst_addr); if (addr_header_len == 0) { // error in parse header goto CLEAN_UP; } #endif #ifdef MODULE_LOCAL char *key = hash_key(server_ctx->remote_addr->sa_family, &src_addr); #else char *key = hash_key(dst_addr.ss_family, &src_addr); #endif struct cache *conn_cache = server_ctx->conn_cache; remote_ctx_t *remote_ctx = NULL; cache_lookup(conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx); if (remote_ctx != NULL) { if (sockaddr_cmp(&src_addr, &remote_ctx->src_addr, sizeof(src_addr))) { remote_ctx = NULL; } } // reset the timer if (remote_ctx != NULL) { ev_timer_again(EV_A_ & remote_ctx->watcher); } if (remote_ctx == NULL) { if (verbose) { #ifdef MODULE_REDIR char src[SS_ADDRSTRLEN]; char dst[SS_ADDRSTRLEN]; strcpy(src, get_addr_str((struct sockaddr *)&src_addr, true)); strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr, true)); LOGI("[%s] [udp] cache miss: %s <-> %s", s_port, dst, src); #else LOGI("[%s] [udp] cache miss: %s:%s <-> %s", s_port, host, port, get_addr_str((struct sockaddr *)&src_addr, true)); #endif } } else { if (verbose) { #ifdef MODULE_REDIR char src[SS_ADDRSTRLEN]; char dst[SS_ADDRSTRLEN]; strcpy(src, get_addr_str((struct sockaddr *)&src_addr, true)); strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr, true)); LOGI("[%s] [udp] cache hit: %s <-> %s", s_port, dst, src); #else LOGI("[%s] [udp] cache hit: %s:%s <-> %s", s_port, host, port, get_addr_str((struct sockaddr *)&src_addr, true)); #endif } } #ifdef MODULE_LOCAL #if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR) if (frag) { LOGE("[udp] drop a message since frag is not 0, but %d", frag); goto CLEAN_UP; } #endif const struct sockaddr *remote_addr = server_ctx->remote_addr; const int remote_addr_len = server_ctx->remote_addr_len; if (remote_ctx == NULL) { // Bind to any port int remotefd = create_remote_socket(remote_addr->sa_family == AF_INET6); if (remotefd < 0) { ERROR("[udp] udprelay bind() error"); goto CLEAN_UP; } setnonblocking(remotefd); #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef IP_TOS // Set QoS flag int tos = 46 << 2; int rc = setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv4 dscp failed: %d", errno); } #ifdef IPV6_TCLASS rc = setsockopt(remotefd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv6 dscp failed: %d", errno); } #endif #endif #ifdef SET_INTERFACE if (server_ctx->iface) { if (setinterface(remotefd, server_ctx->iface) == -1) ERROR("setinterface"); } #endif #ifdef __ANDROID__ if (vpn) { if (protect_socket(remotefd) == -1) { ERROR("protect_socket"); close(remotefd); goto CLEAN_UP; } } #endif // Init remote_ctx remote_ctx = new_remote(remotefd, server_ctx); remote_ctx->src_addr = src_addr; remote_ctx->af = remote_addr->sa_family; // Add to conn cache cache_insert(conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); // Start remote io ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } if (offset > 0) { buf->len -= offset; memmove(buf->data, buf->data + offset, buf->len); } int err = server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } if (buf->len > packet_size) { if (verbose) { LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SSIZE_FMT, buf->len + PACKET_HEADER_SIZE); } } int s = sendto(remote_ctx->fd, buf->data, buf->len, 0, remote_addr, remote_addr_len); if (s == -1) { ERROR("[udp] server_recv_sendto"); } #else int cache_hit = 0; int need_query = 0; char *addr_header = buf->data + offset; if (buf->len - addr_header_len > packet_size) { if (verbose) { LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SSIZE_FMT, buf->len - addr_header_len + PACKET_HEADER_SIZE); } } if (remote_ctx != NULL) { cache_hit = 1; if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) { need_query = 1; } } else { if (dst_addr.ss_family == AF_INET || dst_addr.ss_family == AF_INET6) { int remotefd = create_remote_socket(dst_addr.ss_family == AF_INET6); if (remotefd != -1) { setnonblocking(remotefd); #ifdef SO_BROADCAST set_broadcast(remotefd); #endif #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef IP_TOS // Set QoS flag int tos = 46 << 2; int rc = setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv4 dscp failed: %d", errno); } #ifdef IPV6_TCLASS rc = setsockopt(remotefd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); if (rc < 0 && errno != ENOPROTOOPT) { LOGE("setting ipv6 dscp failed: %d", errno); } #endif #endif #ifdef SET_INTERFACE if (server_ctx->iface) { if (setinterface(remotefd, server_ctx->iface) == -1) ERROR("setinterface"); } #endif remote_ctx = new_remote(remotefd, server_ctx); remote_ctx->src_addr = src_addr; remote_ctx->server_ctx = server_ctx; memcpy(&remote_ctx->dst_addr, &dst_addr, sizeof(struct sockaddr_storage)); } else { ERROR("[udp] bind() error"); goto CLEAN_UP; } } } if (remote_ctx != NULL && !need_query) { size_t addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr); int s = sendto(remote_ctx->fd, buf->data + addr_header_len, buf->len - addr_header_len, 0, (struct sockaddr *)&dst_addr, addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); if (!cache_hit) { close_and_free_remote(EV_A_ remote_ctx); } } else { if (!cache_hit) { // Add to conn cache remote_ctx->af = dst_addr.ss_family; char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr); cache_insert(server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } } } else { struct query_ctx *query_ctx = new_query_ctx(buf->data + addr_header_len, buf->len - addr_header_len); query_ctx->server_ctx = server_ctx; query_ctx->addr_header_len = addr_header_len; query_ctx->src_addr = src_addr; memcpy(query_ctx->addr_header, addr_header, addr_header_len); if (need_query) { query_ctx->remote_ctx = remote_ctx; } resolv_start(host, htons(atoi(port)), resolv_cb, resolv_free_cb, query_ctx); } #endif CLEAN_UP: bfree(buf); ss_free(buf); } void free_cb(void *key, void *element) { remote_ctx_t *remote_ctx = (remote_ctx_t *)element; if (verbose) { LOGI("[udp] one connection freed"); } close_and_free_remote(EV_DEFAULT, remote_ctx); } int init_udprelay(const char *server_host, const char *server_port, #ifdef MODULE_LOCAL const struct sockaddr *remote_addr, const int remote_addr_len, #ifdef MODULE_TUNNEL const ss_addr_t tunnel_addr, #endif #endif int mtu, crypto_t *crypto, int timeout, const char *iface) { s_port = server_port; // Initialize ev loop struct ev_loop *loop = EV_DEFAULT; // Initialize MTU if (mtu > 0) { packet_size = mtu - PACKET_HEADER_SIZE; buf_size = packet_size * 2; } // //////////////////////////////////////////////// // Setup server context // Bind to port int serverfd = create_server_socket(server_host, server_port); if (serverfd < 0) { return -1; } setnonblocking(serverfd); // Initialize cache struct cache *conn_cache; cache_create(&conn_cache, MAX_UDP_CONN_NUM, free_cb); server_ctx_t *server_ctx = new_server_ctx(serverfd); #ifdef MODULE_REMOTE server_ctx->loop = loop; #endif server_ctx->timeout = max(timeout, MIN_UDP_TIMEOUT); server_ctx->crypto = crypto; server_ctx->iface = iface; server_ctx->conn_cache = conn_cache; #ifdef MODULE_LOCAL server_ctx->remote_addr = remote_addr; server_ctx->remote_addr_len = remote_addr_len; #ifdef MODULE_TUNNEL server_ctx->tunnel_addr = tunnel_addr; #endif #endif ev_io_start(loop, &server_ctx->io); server_ctx_list[server_num++] = server_ctx; return serverfd; } void free_udprelay() { struct ev_loop *loop = EV_DEFAULT; while (server_num > 0) { server_ctx_t *server_ctx = server_ctx_list[--server_num]; ev_io_stop(loop, &server_ctx->io); close(server_ctx->fd); cache_delete(server_ctx->conn_cache, 0); #ifdef MODULE_LOCAL free((char*) server_ctx->remote_addr); #endif ss_free(server_ctx); server_ctx_list[server_num] = NULL; } } ================================================ FILE: src/udprelay.h ================================================ /* * udprelay.h - Define UDP relay's buffers and callbacks * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _UDPRELAY_H #define _UDPRELAY_H #include #ifdef HAVE_LIBEV_EV_H #include #else #include #endif #include "crypto.h" #include "jconf.h" #ifdef MODULE_REMOTE #include "resolv.h" #endif #include "cache.h" #include "common.h" #define MAX_UDP_PACKET_SIZE (65507) #define PACKET_HEADER_SIZE (1 + 28 + 2 + 64) #define DEFAULT_PACKET_SIZE 1397 // 1492 - PACKET_HEADER_SIZE = 1397, the default MTU for UDP relay #define MAX_ADDR_HEADER_SIZE (1 + 256 + 2) // 1-byte atyp + 256-byte hostname + 2-byte port typedef struct server_ctx { ev_io io; int fd; crypto_t *crypto; int timeout; const char *iface; struct cache *conn_cache; #ifdef MODULE_LOCAL const struct sockaddr *remote_addr; int remote_addr_len; #ifdef MODULE_TUNNEL ss_addr_t tunnel_addr; #endif #endif #ifdef MODULE_REMOTE struct ev_loop *loop; #endif } server_ctx_t; #ifdef MODULE_REMOTE typedef struct query_ctx { struct sockaddr_storage src_addr; buffer_t *buf; int addr_header_len; char addr_header[MAX_ADDR_HEADER_SIZE]; struct server_ctx *server_ctx; struct remote_ctx *remote_ctx; } query_ctx_t; #endif typedef struct remote_ctx { ev_io io; ev_timer watcher; int af; int fd; struct sockaddr_storage src_addr; #ifdef MODULE_REMOTE struct sockaddr_storage dst_addr; #endif struct server_ctx *server_ctx; } remote_ctx_t; #endif // _UDPRELAY_H ================================================ FILE: src/uthash.h ================================================ /* Copyright (c) 2003-2016, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTHASH_H #define UTHASH_H #define UTHASH_VERSION 2.0.1 #include /* memcmp,strlen */ #include /* ptrdiff_t */ #include /* exit() */ /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #if defined(_MSC_VER) /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #define DECLTYPE(x) #endif #elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE #define DECLTYPE(x) #else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #ifdef NO_DECLTYPE #define DECLTYPE_ASSIGN(dst,src) \ do { \ char **_da_dst = (char**)(&(dst)); \ *_da_dst = (char*)(src); \ } while (0) #else #define DECLTYPE_ASSIGN(dst,src) \ do { \ (dst) = DECLTYPE(dst)(src); \ } while (0) #endif /* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ #if defined(_WIN32) #if defined(_MSC_VER) && _MSC_VER >= 1600 #include #elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) #include #else typedef unsigned int uint32_t; typedef unsigned char uint8_t; #endif #elif defined(__GNUC__) && !defined(__VXWORKS__) #include #else typedef unsigned int uint32_t; typedef unsigned char uint8_t; #endif #ifndef uthash_fatal #define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ #endif #ifndef uthash_malloc #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #endif #ifndef uthash_free #define uthash_free(ptr,sz) free(ptr) /* free fcn */ #endif #ifndef uthash_strlen #define uthash_strlen(s) strlen(s) #endif #ifndef uthash_memcmp #define uthash_memcmp(a,b,n) memcmp(a,b,n) #endif #ifndef uthash_noexpand_fyi #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #endif #ifndef uthash_expand_fyi #define uthash_expand_fyi(tbl) /* can be defined to log expands */ #endif /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ #define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhp */ #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) /* calculate the hash handle from element address elp */ #define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho))) #define HASH_VALUE(keyptr,keylen,hashv) \ do { \ HASH_FCN(keyptr, keylen, hashv); \ } while (0) #define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ do { \ (out) = NULL; \ if (head) { \ unsigned _hf_bkt; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ } \ } \ } while (0) #define HASH_FIND(hh,head,keyptr,keylen,out) \ do { \ unsigned _hf_hashv; \ HASH_VALUE(keyptr, keylen, _hf_hashv); \ HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ } while (0) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) #define HASH_BLOOM_MAKE(tbl) \ do { \ (tbl)->bloom_nbits = HASH_BLOOM; \ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ } while (0) #define HASH_BLOOM_FREE(tbl) \ do { \ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ } while (0) #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) #define HASH_BLOOM_ADD(tbl,hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) #define HASH_BLOOM_TEST(tbl,hashv) \ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) #else #define HASH_BLOOM_MAKE(tbl) #define HASH_BLOOM_FREE(tbl) #define HASH_BLOOM_ADD(tbl,hashv) #define HASH_BLOOM_TEST(tbl,hashv) (1) #define HASH_BLOOM_BYTELEN 0U #endif #define HASH_MAKE_TABLE(hh,head) \ do { \ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ sizeof(UT_hash_table)); \ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ (head)->hh.tbl->tail = &((head)->hh); \ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl->buckets, 0, \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_MAKE((head)->hh.tbl); \ (head)->hh.tbl->signature = HASH_SIGNATURE; \ } while (0) #define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ do { \ (replaced) = NULL; \ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ if (replaced) { \ HASH_DELETE(hh, head, replaced); \ } \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ } while (0) #define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ do { \ (replaced) = NULL; \ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ if (replaced) { \ HASH_DELETE(hh, head, replaced); \ } \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ } while (0) #define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ do { \ unsigned _hr_hashv; \ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ } while (0) #define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ do { \ unsigned _hr_hashv; \ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ } while (0) #define HASH_APPEND_LIST(hh, head, add) \ do { \ (add)->hh.next = NULL; \ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ (head)->hh.tbl->tail->next = (add); \ (head)->hh.tbl->tail = &((add)->hh); \ } while (0) #define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ do { \ unsigned _ha_bkt; \ (add)->hh.hashv = (hashval); \ (add)->hh.key = (char*) (keyptr); \ (add)->hh.keylen = (unsigned) (keylen_in); \ if (!(head)) { \ (add)->hh.next = NULL; \ (add)->hh.prev = NULL; \ (head) = (add); \ HASH_MAKE_TABLE(hh, head); \ } else { \ struct UT_hash_handle *_hs_iter = &(head)->hh; \ (add)->hh.tbl = (head)->hh.tbl; \ do { \ if (cmpfcn(DECLTYPE(head) ELMT_FROM_HH((head)->hh.tbl, _hs_iter), add) > 0) \ break; \ } while ((_hs_iter = _hs_iter->next)); \ if (_hs_iter) { \ (add)->hh.next = _hs_iter; \ if (((add)->hh.prev = _hs_iter->prev)) { \ HH_FROM_ELMT((head)->hh.tbl, _hs_iter->prev)->next = (add); \ } else { \ (head) = (add); \ } \ _hs_iter->prev = (add); \ } else { \ HASH_APPEND_LIST(hh, head, add); \ } \ } \ (head)->hh.tbl->num_items++; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ HASH_FSCK(hh, head); \ } while (0) #define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ do { \ unsigned _hs_hashv; \ HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ } while (0) #define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) #define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) #define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ do { \ unsigned _ha_bkt; \ (add)->hh.hashv = (hashval); \ (add)->hh.key = (char*) (keyptr); \ (add)->hh.keylen = (unsigned) (keylen_in); \ if (!(head)) { \ (add)->hh.next = NULL; \ (add)->hh.prev = NULL; \ (head) = (add); \ HASH_MAKE_TABLE(hh, head); \ } else { \ (add)->hh.tbl = (head)->hh.tbl; \ HASH_APPEND_LIST(hh, head, add); \ } \ (head)->hh.tbl->num_items++; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ HASH_FSCK(hh, head); \ } while (0) #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ do { \ unsigned _ha_hashv; \ HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ } while (0) #define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) #define HASH_TO_BKT(hashv,num_bkts,bkt) \ do { \ bkt = ((hashv) & ((num_bkts) - 1U)); \ } while (0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. * The use of _hd_hh_del below deserves special explanation. * These used to be expressed using (delptr) but that led to a bug * if someone used the same symbol for the head and deletee, like * HASH_DELETE(hh,users,users); * We want that to work, but by changing the head (users) below * we were forfeiting our ability to further refer to the deletee (users) * in the patch-up process. Solution: use scratch space to * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ #define HASH_DELETE(hh,head,delptr) \ do { \ struct UT_hash_handle *_hd_hh_del; \ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ head = NULL; \ } else { \ unsigned _hd_bkt; \ _hd_hh_del = &((delptr)->hh); \ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ (head)->hh.tbl->tail = \ (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ (head)->hh.tbl->hho); \ } \ if ((delptr)->hh.prev != NULL) { \ ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ } else { \ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ } \ if (_hd_hh_del->next != NULL) { \ ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ (head)->hh.tbl->hho))->prev = \ _hd_hh_del->prev; \ } \ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ (head)->hh.tbl->num_items--; \ } \ HASH_FSCK(hh,head); \ } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ #define HASH_FIND_STR(head,findstr,out) \ HASH_FIND(hh,head,findstr,(unsigned)uthash_strlen(findstr),out) #define HASH_ADD_STR(head,strfield,add) \ HASH_ADD(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add) #define HASH_REPLACE_STR(head,strfield,add,replaced) \ HASH_REPLACE(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add,replaced) #define HASH_FIND_INT(head,findint,out) \ HASH_FIND(hh,head,findint,sizeof(int),out) #define HASH_ADD_INT(head,intfield,add) \ HASH_ADD(hh,head,intfield,sizeof(int),add) #define HASH_REPLACE_INT(head,intfield,add,replaced) \ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) #define HASH_FIND_PTR(head,findptr,out) \ HASH_FIND(hh,head,findptr,sizeof(void *),out) #define HASH_ADD_PTR(head,ptrfield,add) \ HASH_ADD(hh,head,ptrfield,sizeof(void *),add) #define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) #define HASH_DEL(head,delptr) \ HASH_DELETE(hh,head,delptr) /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) #define HASH_FSCK(hh,head) \ do { \ struct UT_hash_handle *_thh; \ if (head) { \ unsigned _bkt_i; \ unsigned _count; \ char *_prev; \ _count = 0; \ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ unsigned _bkt_count = 0; \ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ _prev = NULL; \ while (_thh) { \ if (_prev != (char*)(_thh->hh_prev)) { \ HASH_OOPS("invalid hh_prev %p, actual %p\n", \ _thh->hh_prev, _prev ); \ } \ _bkt_count++; \ _prev = (char*)(_thh); \ _thh = _thh->hh_next; \ } \ _count += _bkt_count; \ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ HASH_OOPS("invalid bucket count %u, actual %u\n", \ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid hh item count %u, actual %u\n", \ (head)->hh.tbl->num_items, _count ); \ } \ /* traverse hh in app order; check next/prev integrity, count */ \ _count = 0; \ _prev = NULL; \ _thh = &(head)->hh; \ while (_thh) { \ _count++; \ if (_prev !=(char*)(_thh->prev)) { \ HASH_OOPS("invalid prev %p, actual %p\n", \ _thh->prev, _prev ); \ } \ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ (head)->hh.tbl->hho) : NULL ); \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid app item count %u, actual %u\n", \ (head)->hh.tbl->num_items, _count ); \ } \ } \ } while (0) #else #define HASH_FSCK(hh,head) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ do { \ unsigned _klen = fieldlen; \ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ } while (0) #else #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) #endif /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ #ifdef HASH_FUNCTION #define HASH_FCN HASH_FUNCTION #else #define HASH_FCN HASH_JEN #endif /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ #define HASH_BER(key,keylen,hashv) \ do { \ unsigned _hb_keylen=(unsigned)keylen; \ const unsigned char *_hb_key=(const unsigned char*)(key); \ (hashv) = 0; \ while (_hb_keylen-- != 0U) { \ (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ } \ } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ #define HASH_SAX(key,keylen,hashv) \ do { \ unsigned _sx_i; \ const unsigned char *_hs_key=(const unsigned char*)(key); \ hashv = 0; \ for(_sx_i=0; _sx_i < keylen; _sx_i++) { \ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ } \ } while (0) /* FNV-1a variation */ #define HASH_FNV(key,keylen,hashv) \ do { \ unsigned _fn_i; \ const unsigned char *_hf_key=(const unsigned char*)(key); \ hashv = 2166136261U; \ for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ hashv = hashv ^ _hf_key[_fn_i]; \ hashv = hashv * 16777619U; \ } \ } while (0) #define HASH_OAT(key,keylen,hashv) \ do { \ unsigned _ho_i; \ const unsigned char *_ho_key=(const unsigned char*)(key); \ hashv = 0; \ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ hashv += _ho_key[_ho_i]; \ hashv += (hashv << 10); \ hashv ^= (hashv >> 6); \ } \ hashv += (hashv << 3); \ hashv ^= (hashv >> 11); \ hashv += (hashv << 15); \ } while (0) #define HASH_JEN_MIX(a,b,c) \ do { \ a -= b; a -= c; a ^= ( c >> 13 ); \ b -= c; b -= a; b ^= ( a << 8 ); \ c -= a; c -= b; c ^= ( b >> 13 ); \ a -= b; a -= c; a ^= ( c >> 12 ); \ b -= c; b -= a; b ^= ( a << 16 ); \ c -= a; c -= b; c ^= ( b >> 5 ); \ a -= b; a -= c; a ^= ( c >> 3 ); \ b -= c; b -= a; b ^= ( a << 10 ); \ c -= a; c -= b; c ^= ( b >> 15 ); \ } while (0) #define HASH_JEN(key,keylen,hashv) \ do { \ unsigned _hj_i,_hj_j,_hj_k; \ unsigned const char *_hj_key=(unsigned const char*)(key); \ hashv = 0xfeedbeefu; \ _hj_i = _hj_j = 0x9e3779b9u; \ _hj_k = (unsigned)(keylen); \ while (_hj_k >= 12U) { \ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + ( (unsigned)_hj_key[2] << 16 ) \ + ( (unsigned)_hj_key[3] << 24 ) ); \ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + ( (unsigned)_hj_key[6] << 16 ) \ + ( (unsigned)_hj_key[7] << 24 ) ); \ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + ( (unsigned)_hj_key[10] << 16 ) \ + ( (unsigned)_hj_key[11] << 24 ) ); \ \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ \ _hj_key += 12; \ _hj_k -= 12U; \ } \ hashv += (unsigned)(keylen); \ switch ( _hj_k ) { \ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ case 1: _hj_i += _hj_key[0]; \ } \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ } while (0) /* The Paul Hsieh hash function */ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) #define get16bits(d) (*((const uint16_t *) (d))) #endif #if !defined (get16bits) #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ +(uint32_t)(((const uint8_t *)(d))[0]) ) #endif #define HASH_SFH(key,keylen,hashv) \ do { \ unsigned const char *_sfh_key=(unsigned const char*)(key); \ uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ \ unsigned _sfh_rem = _sfh_len & 3U; \ _sfh_len >>= 2; \ hashv = 0xcafebabeu; \ \ /* Main loop */ \ for (;_sfh_len > 0U; _sfh_len--) { \ hashv += get16bits (_sfh_key); \ _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ hashv = (hashv << 16) ^ _sfh_tmp; \ _sfh_key += 2U*sizeof (uint16_t); \ hashv += hashv >> 11; \ } \ \ /* Handle end cases */ \ switch (_sfh_rem) { \ case 3: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 16; \ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ hashv += hashv >> 11; \ break; \ case 2: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 11; \ hashv += hashv >> 17; \ break; \ case 1: hashv += *_sfh_key; \ hashv ^= hashv << 10; \ hashv += hashv >> 1; \ } \ \ /* Force "avalanching" of final 127 bits */ \ hashv ^= hashv << 3; \ hashv += hashv >> 5; \ hashv ^= hashv << 4; \ hashv += hashv >> 17; \ hashv ^= hashv << 25; \ hashv += hashv >> 6; \ } while (0) #ifdef HASH_USING_NO_STRICT_ALIASING /* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. * MurmurHash uses the faster approach only on CPU's where we know it's safe. * * Note the preprocessor built-in defines can be emitted using: * * gcc -m64 -dM -E - < /dev/null (on gcc) * cc -## a.c (where a.c is a simple test file) (Sun Studio) */ #if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) #define MUR_GETBLOCK(p,i) p[i] #else /* non intel */ #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL) #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL) #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) #if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) #else /* assume little endian non-intel */ #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) #endif #define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ MUR_ONE_THREE(p)))) #endif #define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) #define MUR_FMIX(_h) \ do { \ _h ^= _h >> 16; \ _h *= 0x85ebca6bu; \ _h ^= _h >> 13; \ _h *= 0xc2b2ae35u; \ _h ^= _h >> 16; \ } while (0) #define HASH_MUR(key,keylen,hashv) \ do { \ const uint8_t *_mur_data = (const uint8_t*)(key); \ const int _mur_nblocks = (int)(keylen) / 4; \ uint32_t _mur_h1 = 0xf88D5353u; \ uint32_t _mur_c1 = 0xcc9e2d51u; \ uint32_t _mur_c2 = 0x1b873593u; \ uint32_t _mur_k1 = 0; \ const uint8_t *_mur_tail; \ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \ int _mur_i; \ for(_mur_i = -_mur_nblocks; _mur_i!=0; _mur_i++) { \ _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ \ _mur_h1 ^= _mur_k1; \ _mur_h1 = MUR_ROTL32(_mur_h1,13); \ _mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \ } \ _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \ _mur_k1=0; \ switch((keylen) & 3U) { \ case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \ case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \ case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ _mur_h1 ^= _mur_k1; \ } \ _mur_h1 ^= (uint32_t)(keylen); \ MUR_FMIX(_mur_h1); \ hashv = _mur_h1; \ } while (0) #endif /* HASH_USING_NO_STRICT_ALIASING */ /* iterate over items in a known bucket to find desired item */ #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ do { \ if ((head).hh_head != NULL) { \ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ } else { \ (out) = NULL; \ } \ while ((out) != NULL) { \ if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ if (uthash_memcmp((out)->hh.key, keyptr, keylen_in) == 0) { \ break; \ } \ } \ if ((out)->hh.hh_next != NULL) { \ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ } else { \ (out) = NULL; \ } \ } \ } while (0) /* add an item to a bucket */ #define HASH_ADD_TO_BKT(head,addhh) \ do { \ head.count++; \ (addhh)->hh_next = head.hh_head; \ (addhh)->hh_prev = NULL; \ if (head.hh_head != NULL) { (head).hh_head->hh_prev = (addhh); } \ (head).hh_head=addhh; \ if ((head.count >= ((head.expand_mult+1U) * HASH_BKT_CAPACITY_THRESH)) \ && ((addhh)->tbl->noexpand != 1U)) { \ HASH_EXPAND_BUCKETS((addhh)->tbl); \ } \ } while (0) /* remove an item from a given bucket */ #define HASH_DEL_IN_BKT(hh,head,hh_del) \ (head).count--; \ if ((head).hh_head == hh_del) { \ (head).hh_head = hh_del->hh_next; \ } \ if (hh_del->hh_prev) { \ hh_del->hh_prev->hh_next = hh_del->hh_next; \ } \ if (hh_del->hh_next) { \ hh_del->hh_next->hh_prev = hh_del->hh_prev; \ } /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the * items will distribute more or less evenly into the new buckets * (the extent to which this is true is a measure of the quality of * the hash function as it applies to the key domain). * * With the items distributed into more buckets, the chain length * (item count) in each bucket is reduced. Thus by expanding buckets * the hash keeps a bound on the chain length. This bounded chain * length is the essence of how a hash provides constant time lookup. * * The calculation of tbl->ideal_chain_maxlen below deserves some * explanation. First, keep in mind that we're calculating the ideal * maximum chain length based on the *new* (doubled) bucket count. * In fractions this is just n/b (n=number of items,b=new num buckets). * Since the ideal chain length is an integer, we want to calculate * ceil(n/b). We don't depend on floating point arithmetic in this * hash, so to calculate ceil(n/b) with integers we could write * * ceil(n/b) = (n/b) + ((n%b)?1:0) * * and in fact a previous version of this hash did just that. * But now we have improved things a bit by recognizing that b is * always a power of two. We keep its base 2 log handy (call it lb), * so now we can write this with a bit shift and logical AND: * * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ #define HASH_EXPAND_BUCKETS(tbl) \ do { \ unsigned _he_bkt; \ unsigned _he_bkt_i; \ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ 2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ memset(_he_new_buckets, 0, \ 2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ tbl->ideal_chain_maxlen = \ (tbl->num_items >> (tbl->log2_num_buckets+1U)) + \ (((tbl->num_items & ((tbl->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ tbl->nonideal_items = 0; \ for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ { \ _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ while (_he_thh != NULL) { \ _he_hh_nxt = _he_thh->hh_next; \ HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2U, _he_bkt); \ _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ tbl->nonideal_items++; \ _he_newbkt->expand_mult = _he_newbkt->count / \ tbl->ideal_chain_maxlen; \ } \ _he_thh->hh_prev = NULL; \ _he_thh->hh_next = _he_newbkt->hh_head; \ if (_he_newbkt->hh_head != NULL) { _he_newbkt->hh_head->hh_prev = \ _he_thh; } \ _he_newbkt->hh_head = _he_thh; \ _he_thh = _he_hh_nxt; \ } \ } \ uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ tbl->num_buckets *= 2U; \ tbl->log2_num_buckets++; \ tbl->buckets = _he_new_buckets; \ tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ (tbl->ineff_expands+1U) : 0U; \ if (tbl->ineff_expands > 1U) { \ tbl->noexpand=1; \ uthash_noexpand_fyi(tbl); \ } \ uthash_expand_fyi(tbl); \ } while (0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) #define HASH_SRT(hh,head,cmpfcn) \ do { \ unsigned _hs_i; \ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ if (head != NULL) { \ _hs_insize = 1; \ _hs_looping = 1; \ _hs_list = &((head)->hh); \ while (_hs_looping != 0U) { \ _hs_p = _hs_list; \ _hs_list = NULL; \ _hs_tail = NULL; \ _hs_nmerges = 0; \ while (_hs_p != NULL) { \ _hs_nmerges++; \ _hs_q = _hs_p; \ _hs_psize = 0; \ for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ _hs_psize++; \ _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ if (! (_hs_q) ) { break; } \ } \ _hs_qsize = _hs_insize; \ while ((_hs_psize > 0U) || ((_hs_qsize > 0U) && (_hs_q != NULL))) {\ if (_hs_psize == 0U) { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } else if ( (_hs_qsize == 0U) || (_hs_q == NULL) ) { \ _hs_e = _hs_p; \ if (_hs_p != NULL){ \ _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ } \ _hs_psize--; \ } else if (( \ cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ ) <= 0) { \ _hs_e = _hs_p; \ if (_hs_p != NULL){ \ _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ } \ _hs_psize--; \ } else { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } \ if ( _hs_tail != NULL ) { \ _hs_tail->next = ((_hs_e != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ } else { \ _hs_list = _hs_e; \ } \ if (_hs_e != NULL) { \ _hs_e->prev = ((_hs_tail != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ } \ _hs_tail = _hs_e; \ } \ _hs_p = _hs_q; \ } \ if (_hs_tail != NULL){ \ _hs_tail->next = NULL; \ } \ if ( _hs_nmerges <= 1U ) { \ _hs_looping=0; \ (head)->hh.tbl->tail = _hs_tail; \ DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ } \ _hs_insize *= 2U; \ } \ HASH_FSCK(hh,head); \ } \ } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ do { \ unsigned _src_bkt, _dst_bkt; \ void *_last_elt=NULL, *_elt; \ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ if (src != NULL) { \ for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ _src_hh != NULL; \ _src_hh = _src_hh->hh_next) { \ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ if (cond(_elt)) { \ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ _dst_hh->key = _src_hh->key; \ _dst_hh->keylen = _src_hh->keylen; \ _dst_hh->hashv = _src_hh->hashv; \ _dst_hh->prev = _last_elt; \ _dst_hh->next = NULL; \ if (_last_elt_hh != NULL) { _last_elt_hh->next = _elt; } \ if (dst == NULL) { \ DECLTYPE_ASSIGN(dst,_elt); \ HASH_MAKE_TABLE(hh_dst,dst); \ } else { \ _dst_hh->tbl = (dst)->hh_dst.tbl; \ } \ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ (dst)->hh_dst.tbl->num_items++; \ _last_elt = _elt; \ _last_elt_hh = _dst_hh; \ } \ } \ } \ } \ HASH_FSCK(hh_dst,dst); \ } while (0) #define HASH_CLEAR(hh,head) \ do { \ if (head != NULL) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ (head)=NULL; \ } \ } while (0) #define HASH_OVERHEAD(hh,head) \ ((head != NULL) ? ( \ (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ sizeof(UT_hash_table) + \ (HASH_BLOOM_BYTELEN))) : 0U) #ifdef NO_DECLTYPE #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) #else #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) #endif /* obtain a count of items in the hash */ #define HASH_COUNT(head) HASH_CNT(hh,head) #define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) typedef struct UT_hash_bucket { struct UT_hash_handle *hh_head; unsigned count; /* expand_mult is normally set to 0. In this situation, the max chain length * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If * the bucket's chain exceeds this length, bucket expansion is triggered). * However, setting expand_mult to a non-zero value delays bucket expansion * (that would be triggered by additions to this particular bucket) * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. * (The multiplier is simply expand_mult+1). The whole idea of this * multiplier is to reduce bucket expansions, since they are expensive, in * situations where we know that a particular bucket tends to be overused. * It is better to let its chain length grow to a longer yet-still-bounded * value, than to do an O(n) bucket expansion too often. */ unsigned expand_mult; } UT_hash_bucket; /* random signature used only to find hash tables in external analysis */ #define HASH_SIGNATURE 0xa0111fe1u #define HASH_BLOOM_SIGNATURE 0xb12220f2u typedef struct UT_hash_table { UT_hash_bucket *buckets; unsigned num_buckets, log2_num_buckets; unsigned num_items; struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ /* in an ideal situation (all buckets used equally), no bucket would have * more than ceil(#items/#buckets) items. that's the ideal chain length. */ unsigned ideal_chain_maxlen; /* nonideal_items is the number of items in the hash whose chain position * exceeds the ideal chain maxlen. these items pay the penalty for an uneven * hash distribution; reaching them in a chain traversal takes >ideal steps */ unsigned nonideal_items; /* ineffective expands occur when a bucket doubling was performed, but * afterward, more than half the items in the hash had nonideal chain * positions. If this happens on two consecutive expansions we inhibit any * further expansion, as it's not helping; this happens when the hash * function isn't a good fit for the key domain. When expansion is inhibited * the hash will still work, albeit no longer in constant time. */ unsigned ineff_expands, noexpand; uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ uint8_t *bloom_bv; uint8_t bloom_nbits; #endif } UT_hash_table; typedef struct UT_hash_handle { struct UT_hash_table *tbl; void *prev; /* prev element in app order */ void *next; /* next element in app order */ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ struct UT_hash_handle *hh_next; /* next hh in bucket order */ void *key; /* ptr to enclosing struct's key */ unsigned keylen; /* enclosing struct's key len */ unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */ ================================================ FILE: src/utils.c ================================================ /* * utils.c - Misc utilities * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifndef __MINGW32__ #include #include #include #include #else #include #endif #include #include #include #include #include "crypto.h" #include "utils.h" #ifdef HAVE_SETRLIMIT #include #include #endif #define INT_DIGITS 19 /* enough for 64 bit integer */ #ifdef LIB_ONLY FILE *logfile; #endif #ifdef HAS_SYSLOG int use_syslog = 0; #endif #ifndef __MINGW32__ void ERROR(const char *s) { char *msg = strerror(errno); LOGE("%s: %s", s, msg); } #endif int use_tty = 1; char * ss_itoa(int i) { /* Room for INT_DIGITS digits, - and '\0' */ static char buf[INT_DIGITS + 2]; char *p = buf + INT_DIGITS + 1; /* points to terminating '\0' */ if (i >= 0) { do { *--p = '0' + (i % 10); i /= 10; } while (i != 0); return p; } else { /* i < 0 */ do { *--p = '0' - (i % 10); i /= 10; } while (i != 0); *--p = '-'; } return p; } int ss_isnumeric(const char *s) { if (!s || !*s) return 0; while (isdigit((unsigned char)*s)) ++s; return *s == '\0'; } /* * setuid() and setgid() for a specified user. */ int run_as(const char *user) { #ifndef __MINGW32__ if (user[0]) { /* Convert user to a long integer if it is a non-negative number. * -1 means it is a user name. */ long uid = -1; if (ss_isnumeric(user)) { errno = 0; char *endptr; uid = strtol(user, &endptr, 10); if (errno || endptr == user) uid = -1; } #ifdef HAVE_GETPWNAM_R struct passwd pwdbuf, *pwd; memset(&pwdbuf, 0, sizeof(struct passwd)); size_t buflen; int err; for (buflen = 128;; buflen *= 2) { char buf[buflen]; /* variable length array */ /* Note that we use getpwnam_r() instead of getpwnam(), * which returns its result in a statically allocated buffer and * cannot be considered thread safe. */ err = uid >= 0 ? getpwuid_r((uid_t)uid, &pwdbuf, buf, buflen, &pwd) : getpwnam_r(user, &pwdbuf, buf, buflen, &pwd); if (err == 0 && pwd) { /* setgid first, because we may not be allowed to do it anymore after setuid */ if (setgid(pwd->pw_gid) != 0) { LOGE( "Could not change group id to that of run_as user '%s': %s", pwd->pw_name, strerror(errno)); return 0; } #ifndef __CYGWIN__ if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { LOGE("Could not change supplementary groups for user '%s'.", pwd->pw_name); return 0; } #endif if (setuid(pwd->pw_uid) != 0) { LOGE( "Could not change user id to that of run_as user '%s': %s", pwd->pw_name, strerror(errno)); return 0; } break; } else if (err != ERANGE) { if (err) { LOGE("run_as user '%s' could not be found: %s", user, strerror(err)); } else { LOGE("run_as user '%s' could not be found.", user); } return 0; } else if (buflen >= 16 * 1024) { /* If getpwnam_r() seems defective, call it quits rather than * keep on allocating ever larger buffers until we crash. */ LOGE( "getpwnam_r() requires more than %u bytes of buffer space.", (unsigned)buflen); return 0; } /* Else try again with larger buffer. */ } #else /* No getpwnam_r() :-( We'll use getpwnam() and hope for the best. */ struct passwd *pwd; if (!(pwd = uid >= 0 ? getpwuid((uid_t)uid) : getpwnam(user))) { LOGE("run_as user %s could not be found.", user); return 0; } /* setgid first, because we may not allowed to do it anymore after setuid */ if (setgid(pwd->pw_gid) != 0) { LOGE("Could not change group id to that of run_as user '%s': %s", pwd->pw_name, strerror(errno)); return 0; } if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { LOGE("Could not change supplementary groups for user '%s'.", pwd->pw_name); return 0; } if (setuid(pwd->pw_uid) != 0) { LOGE("Could not change user id to that of run_as user '%s': %s", pwd->pw_name, strerror(errno)); return 0; } #endif } #else LOGE("run_as(): not implemented in MinGW port"); #endif return 1; } char * ss_strndup(const char *s, size_t n) { size_t len = strlen(s); char *ret; if (len <= n) { return strdup(s); } ret = ss_malloc(n + 1); strncpy(ret, s, n); ret[n] = '\0'; return ret; } void FATAL(const char *msg) { LOGE("%s", msg); exit(-1); } void * ss_malloc(size_t size) { void *tmp = malloc(size); if (tmp == NULL) exit(EXIT_FAILURE); return tmp; } void * ss_aligned_malloc(size_t size) { int err; void *tmp = NULL; #ifdef HAVE_POSIX_MEMALIGN /* ensure 16 byte alignment */ err = posix_memalign(&tmp, 16, size); #elif __MINGW32__ tmp = _aligned_malloc(size, 16); err = tmp == NULL; #else err = -1; #endif if (err) { return ss_malloc(size); } else { return tmp; } } void * ss_realloc(void *ptr, size_t new_size) { void *new = realloc(ptr, new_size); if (new == NULL) { free(ptr); ptr = NULL; exit(EXIT_FAILURE); } return new; } int ss_is_ipv6addr(const char *addr) { return strcmp(addr, ":") > 0; } void usage() { printf("\n"); printf("shadowsocks-libev %s\n\n", VERSION); printf( " maintained by Max Lv and Linus Yang \n\n"); printf(" usage:\n\n"); #ifdef MODULE_LOCAL printf(" ss-local\n"); #elif MODULE_REMOTE printf(" ss-server\n"); #elif MODULE_TUNNEL printf(" ss-tunnel\n"); #elif MODULE_REDIR printf(" ss-redir\n"); #elif MODULE_MANAGER printf(" ss-manager\n"); #endif printf("\n"); printf( " -s Host name or IP address of your remote server.\n"); printf( " -p Port number of your remote server.\n"); printf( " -l Port number of your local server.\n"); printf( " -k Password of your remote server.\n"); printf( " -m Encrypt method: rc4-md5, \n"); printf( " aes-128-gcm, aes-192-gcm, aes-256-gcm,\n"); printf( " aes-128-cfb, aes-192-cfb, aes-256-cfb,\n"); printf( " aes-128-ctr, aes-192-ctr, aes-256-ctr,\n"); printf( " camellia-128-cfb, camellia-192-cfb,\n"); printf( " camellia-256-cfb, bf-cfb,\n"); printf( " chacha20-ietf-poly1305,\n"); #ifdef FS_HAVE_XCHACHA20IETF printf( " xchacha20-ietf-poly1305,\n"); #endif printf( " salsa20, chacha20 and chacha20-ietf.\n"); printf( " The default cipher is chacha20-ietf-poly1305.\n"); printf("\n"); printf( " [-a ] Run as another user.\n"); printf( " [-f ] The file path to store pid.\n"); printf( " [-t ] Socket timeout in seconds.\n"); printf( " [-c ] The path to config file.\n"); #ifdef HAVE_SETRLIMIT printf( " [-n ] Max number of open files.\n"); #endif #ifndef MODULE_REDIR printf( " [-i ] Network interface to bind.\n"); #endif printf( " [-b ] Local address to bind.\n"); printf("\n"); printf( " [-u] Enable UDP relay.\n"); #ifdef MODULE_REDIR printf( " TPROXY is required in redir mode.\n"); #endif printf( " [-U] Enable UDP relay and disable TCP relay.\n"); #ifdef MODULE_REDIR printf( " [-T] Use tproxy instead of redirect (for tcp).\n"); #endif #ifdef MODULE_REMOTE printf( " [-6] Resovle hostname to IPv6 address first.\n"); #endif printf("\n"); #ifdef MODULE_TUNNEL printf( " [-L :] Destination server address and port\n"); printf( " for local port forwarding.\n"); #endif #ifdef MODULE_REMOTE printf( " [-d ] Name servers for internal DNS resolver.\n"); #endif printf( " [--reuse-port] Enable port reuse.\n"); #if defined(MODULE_REMOTE) || defined(MODULE_LOCAL) || defined(MODULE_REDIR) printf( " [--fast-open] Enable TCP fast open.\n"); printf( " with Linux kernel > 3.7.0.\n"); #endif printf( " [--tcp-incoming-sndbuf] Size of the incoming connection TCP send buffer.\n"); printf( " [--tcp-incoming-rcvbuf] Size of the incoming connection TCP receive buffer.\n"); printf( " [--tcp-outgoing-sndbuf] Size of the outgoing connection TCP send buffer.\n"); printf( " [--tcp-outgoing-rcvbuf] Size of the outgoing connection TCP receive buffer.\n"); #if defined(MODULE_REMOTE) || defined(MODULE_LOCAL) printf( " [--acl ] Path to ACL (Access Control List).\n"); #endif #if defined(MODULE_REMOTE) || defined(MODULE_MANAGER) printf( " [--manager-address ] UNIX domain socket address.\n"); #endif #ifdef MODULE_MANAGER printf( " [--executable ] Path to the executable of ss-server.\n"); printf( " [-D ] Path to the working directory of ss-manager.\n"); #endif printf( " [--mtu ] MTU of your network interface.\n"); #ifdef __linux__ printf( " [--mptcp] Enable Multipath TCP on MPTCP Kernel.\n"); #ifdef USE_NFTABLES printf( " [--nftables-sets ] Add malicious IP into nftables sets.\n"); printf( " sets spec: [:][,[:]...]\n"); #endif #endif #ifndef MODULE_MANAGER printf( " [--no-delay] Enable TCP_NODELAY.\n"); printf( " [--key ] Key of your remote server.\n"); #endif printf( " [--plugin ] Enable SIP003 plugin. (Experimental)\n"); printf( " [--plugin-opts ] Set SIP003 plugin options. (Experimental)\n"); printf("\n"); printf( " [-v] Verbose mode.\n"); printf( " [-h, --help] Print this message.\n"); printf("\n"); } void daemonize(const char *path) { #ifndef __MINGW32__ /* Our process ID and Session ID */ pid_t pid, sid; /* Fork off the parent process */ pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } /* If we got a good PID, then * we can exit the parent process. */ if (pid > 0) { FILE *file = fopen(path, "w"); if (file == NULL) { FATAL("Invalid pid file\n"); } fprintf(file, "%d", (int)pid); fclose(file); exit(EXIT_SUCCESS); } /* Change the file mode mask */ umask(0); /* Open any logs here */ /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { /* Log the failure */ exit(EXIT_FAILURE); } /* Change the current working directory */ if ((chdir("/")) < 0) { /* Log the failure */ exit(EXIT_FAILURE); } int dev_null = open("/dev/null", O_WRONLY); if (dev_null > 0) { /* Redirect to null device */ dup2(dev_null, STDOUT_FILENO); dup2(dev_null, STDERR_FILENO); } else { /* Close the standard file descriptors */ close(STDOUT_FILENO); close(STDERR_FILENO); } /* Close the standard file descriptors */ close(STDIN_FILENO); #else LOGE("daemonize(): not implemented in MinGW port"); #endif } #ifdef HAVE_SETRLIMIT int set_nofile(int nofile) { struct rlimit limit = { nofile, nofile }; /* set both soft and hard limit */ if (nofile <= 0) { FATAL("nofile must be greater than 0\n"); } if (setrlimit(RLIMIT_NOFILE, &limit) < 0) { if (errno == EPERM) { LOGE( "insufficient permission to change NOFILE, not starting as root?"); return -1; } else if (errno == EINVAL) { LOGE("invalid nofile, decrease nofile and try again"); return -1; } else { LOGE("setrlimit failed: %s", strerror(errno)); return -1; } } return 0; } #endif char * get_default_conf(void) { #ifndef __MINGW32__ static char sysconf[] = "/etc/shadowsocks-libev/config.json"; static char *userconf = NULL; static int buf_size = 0; char *conf_home; conf_home = getenv("XDG_CONFIG_HOME"); // Memory of userconf only gets allocated once, and will not be // freed. It is used as static buffer. if (!conf_home) { if (buf_size == 0) { buf_size = 50 + strlen(getenv("HOME")); userconf = malloc(buf_size); } snprintf(userconf, buf_size, "%s%s", getenv("HOME"), "/.config/shadowsocks-libev/config.json"); } else { if (buf_size == 0) { buf_size = 50 + strlen(conf_home); userconf = malloc(buf_size); } snprintf(userconf, buf_size, "%s%s", conf_home, "/shadowsocks-libev/config.json"); } // Check if the user-specific config exists. if (access(userconf, F_OK) != -1) return userconf; // If not, fall back to the system-wide config. free(userconf); return sysconf; #else return "config.json"; #endif } uint16_t load16_be(const void *s) { const uint8_t *in = (const uint8_t *)s; return ((uint16_t)in[0] << 8) | ((uint16_t)in[1]); } int get_mptcp(int enable) { const char oldpath[] = "/proc/sys/net/mptcp/mptcp_enabled"; if (enable) { // Check if kernel has out-of-tree MPTCP support. if (access(oldpath, F_OK) != -1) return 1; // Otherwise, just use IPPROTO_MPTCP. return -1; } return 0; } ================================================ FILE: src/utils.h ================================================ /* * utils.h - Misc utilities * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _UTILS_H #define _UTILS_H #include #include #include #include #include #define PORTSTRLEN 16 #define SS_ADDRSTRLEN (INET6_ADDRSTRLEN + PORTSTRLEN + 1) #ifdef __ANDROID__ #include #define USE_TTY() #define USE_SYSLOG(ident, _cond) #define LOGI(...) \ ((void)__android_log_print(ANDROID_LOG_DEBUG, "shadowsocks", \ __VA_ARGS__)) #define LOGE(...) \ ((void)__android_log_print(ANDROID_LOG_ERROR, "shadowsocks", \ __VA_ARGS__)) #else // not __ANDROID__ #define STR(x) # x #define TOSTR(x) STR(x) #ifdef LIB_ONLY extern FILE *logfile; #define TIME_FORMAT "%Y-%m-%d %H:%M:%S" #define USE_TTY() #define USE_SYSLOG(ident, _cond) #define USE_LOGFILE(ident) \ do { \ if (ident != NULL) { logfile = fopen(ident, "w+"); } } \ while (0) #define CLOSE_LOGFILE \ do { \ if (logfile != NULL) { fclose(logfile); } } \ while (0) #define LOGI(format, ...) \ do { \ if (logfile != NULL) { \ time_t now = time(NULL); \ char timestr[20]; \ strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ fprintf(logfile, " %s INFO: " format "\n", timestr, ## __VA_ARGS__); \ fflush(logfile); } \ } \ while (0) #define LOGE(format, ...) \ do { \ if (logfile != NULL) { \ time_t now = time(NULL); \ char timestr[20]; \ strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ fprintf(logfile, " %s ERROR: " format "\n", timestr, \ ## __VA_ARGS__); \ fflush(logfile); } \ } \ while (0) #else // not LIB_ONLY #ifdef __MINGW32__ #define USE_TTY() #define USE_SYSLOG(ident, _cond) #define USE_LOGFILE(ident) #define TIME_FORMAT "%Y-%m-%d %H:%M:%S" #define LOGI(format, ...) \ do { \ time_t now = time(NULL); \ char timestr[20]; \ strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ ss_color_info(); \ fprintf(stdout, " %s INFO: ", timestr); \ ss_color_reset(); \ fprintf(stdout, format "\n", ## __VA_ARGS__); \ fflush(stdout); \ } \ while (0) #define LOGE(format, ...) \ do { \ time_t now = time(NULL); \ char timestr[20]; \ strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ ss_color_error(); \ fprintf(stderr, " %s ERROR: ", timestr); \ ss_color_reset(); \ fprintf(stderr, format "\n", ## __VA_ARGS__); \ fflush(stderr); \ } \ while (0) #else // not __MINGW32__ #include extern int use_tty; extern int use_syslog; #define HAS_SYSLOG #define TIME_FORMAT "%F %T" #define USE_TTY() \ do { \ use_tty = isatty(STDERR_FILENO); \ } while (0) #define USE_SYSLOG(_ident, _cond) \ do { \ if (!use_syslog && (_cond)) { \ use_syslog = 1; \ } \ if (use_syslog) { \ openlog((_ident), LOG_CONS | LOG_PID, LOG_DAEMON); \ } \ } while (0) #define LOGI(format, ...) \ do { \ if (use_syslog) { \ syslog(LOG_INFO, format, ## __VA_ARGS__); \ } else { \ time_t now = time(NULL); \ char timestr[20]; \ strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ if (use_tty) { \ fprintf(stdout, "\e[01;32m %s INFO: \e[0m" format "\n", timestr, \ ## __VA_ARGS__); \ fflush(stdout); \ } else { \ fprintf(stdout, " %s INFO: " format "\n", timestr, \ ## __VA_ARGS__); \ fflush(stdout); \ } \ } \ } \ while (0) #define LOGE(format, ...) \ do { \ if (use_syslog) { \ syslog(LOG_ERR, format, ## __VA_ARGS__); \ } else { \ time_t now = time(NULL); \ char timestr[20]; \ strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ if (use_tty) { \ fprintf(stderr, "\e[01;35m %s ERROR: \e[0m" format "\n", timestr, \ ## __VA_ARGS__); \ fflush(stderr); \ } else { \ fprintf(stderr, " %s ERROR: " format "\n", timestr, \ ## __VA_ARGS__); \ fflush(stderr); \ } \ } } \ while (0) #endif // if __MINGW32__ #endif // if LIB_ONLY #endif // if __ANDROID__ // Workaround for "%z" in Windows printf #ifdef __MINGW32__ #define SSIZE_FMT "%Id" #define SIZE_FMT "%Iu" #else #define SSIZE_FMT "%zd" #define SIZE_FMT "%zu" #endif #ifdef __MINGW32__ // Override Windows built-in functions #ifdef ERROR #undef ERROR #endif #define ERROR(s) ss_error(s) // Implemented in winsock.c void ss_error(const char *s); void ss_color_info(void); void ss_color_error(void); void ss_color_reset(void); #else void ERROR(const char *s); #endif char *ss_itoa(int i); int ss_isnumeric(const char *s); int run_as(const char *user); void FATAL(const char *msg); void usage(void); void daemonize(const char *path); char *ss_strndup(const char *s, size_t n); #ifdef HAVE_SETRLIMIT int set_nofile(int nofile); #endif void *ss_malloc(size_t size); void *ss_aligned_malloc(size_t size); void *ss_realloc(void *ptr, size_t new_size); #define ss_free(ptr) \ { \ free(ptr); \ ptr = NULL; \ } #ifdef __MINGW32__ #define ss_aligned_free(ptr) \ { \ _aligned_free(ptr); \ ptr = NULL; \ } #else #define ss_aligned_free(ptr) ss_free(ptr) #endif int ss_is_ipv6addr(const char *addr); char *get_default_conf(void); uint16_t load16_be(const void *s); int get_mptcp(int enable); #endif // _UTILS_H ================================================ FILE: src/winsock.c ================================================ /* * winsock.c - Windows socket compatibility layer * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifdef __MINGW32__ #include "winsock.h" #include "utils.h" #ifndef ENABLE_QUICK_EDIT #define ENABLE_QUICK_EDIT 0x0040 #endif #ifndef STD_INPUT_HANDLE #define STD_INPUT_HANDLE ((DWORD)-10) #endif #ifndef ENABLE_EXTENDED_FLAGS #define ENABLE_EXTENDED_FLAGS 0x0080 #endif #ifndef STD_OUTPUT_HANDLE #define STD_OUTPUT_HANDLE ((DWORD)-11) #endif static void disable_quick_edit(void) { DWORD mode = 0; HANDLE console = GetStdHandle(STD_INPUT_HANDLE); // Get current console mode if (console == NULL || console == INVALID_HANDLE_VALUE || !GetConsoleMode(console, &mode)) { return; } // Clear the quick edit bit in the mode flags mode &= ~ENABLE_QUICK_EDIT; mode |= ENABLE_EXTENDED_FLAGS; SetConsoleMode(console, mode); } void winsock_init(void) { int ret; WSADATA wsa_data; ret = WSAStartup(MAKEWORD(2, 2), &wsa_data); if (ret != 0) { FATAL("Failed to initialize winsock"); } // Disable quick edit mode to prevent stuck disable_quick_edit(); } void winsock_cleanup(void) { WSACleanup(); } int setnonblocking(SOCKET socket) { u_long arg = 1; return ioctlsocket(socket, FIONBIO, &arg); } void ss_error(const char *s) { char *msg = NULL; DWORD err = WSAGetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&msg, 0, NULL); if (msg != NULL) { // Remove trailing newline character ssize_t len = strlen(msg) - 1; if (len >= 0 && msg[len] == '\n') { msg[len] = '\0'; } LOGE("%s: [%ld] %s", s, err, msg); LocalFree(msg); } } char * ss_gai_strerror(int ecode) { static TCHAR buff[GAI_STRERROR_BUFFER_SIZE + 1]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ecode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)buff, GAI_STRERROR_BUFFER_SIZE, NULL); return (char *)buff; } static BOOL get_conattr(HANDLE console, WORD *out_attr) { static BOOL done = FALSE; static WORD saved_attr = 0; if (!done) { CONSOLE_SCREEN_BUFFER_INFO info; if (GetConsoleScreenBufferInfo(console, &info)) { saved_attr = info.wAttributes; done = TRUE; } } if (out_attr != NULL) { *out_attr = saved_attr; } return done; } static BOOL set_concolor(WORD color, BOOL reset) { static HANDLE console = NULL; if (console == NULL) { console = GetStdHandle(STD_OUTPUT_HANDLE); } if (console == NULL || console == INVALID_HANDLE_VALUE) { // If no console is available, we will not try again console = INVALID_HANDLE_VALUE; return FALSE; } WORD attr; if (!get_conattr(console, &attr)) { return FALSE; } if (!reset) { // Only override foreground color without changing background attr &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); attr |= (color | FOREGROUND_INTENSITY); } return SetConsoleTextAttribute(console, attr); } void ss_color_info(void) { set_concolor(FOREGROUND_GREEN, FALSE); } void ss_color_error(void) { set_concolor(FOREGROUND_RED | FOREGROUND_BLUE, FALSE); } void ss_color_reset(void) { set_concolor(0, TRUE); } #ifdef TCP_FASTOPEN_WINSOCK LPFN_CONNECTEX winsock_getconnectex(void) { static LPFN_CONNECTEX pConnectEx = NULL; if (pConnectEx != NULL) { return pConnectEx; } // Dummy socket for WSAIoctl SOCKET s = socket(AF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { ERROR("socket"); return NULL; } // Load ConnectEx function GUID guid = WSAID_CONNECTEX; DWORD numBytes; int ret = -1; ret = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, (void *)&guid, sizeof(guid), (void *)&pConnectEx, sizeof(pConnectEx), &numBytes, NULL, NULL); if (ret != 0) { ERROR("WSAIoctl"); closesocket(s); return NULL; } closesocket(s); return pConnectEx; } int winsock_dummybind(SOCKET fd, struct sockaddr *sa) { struct sockaddr_storage ss; memset(&ss, 0, sizeof(ss)); if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)&ss; sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; sin6->sin6_family = AF_INET6; sin6->sin6_addr = in6addr_any; } else { return -1; } if (bind(fd, (struct sockaddr *)&ss, sizeof(ss)) < 0 && WSAGetLastError() != WSAEINVAL) { return -1; } return 0; } #endif #endif // __MINGW32__ ================================================ FILE: src/winsock.h ================================================ /* * winsock.h - Windows socket compatibility layer * * Copyright (C) 2013 - 2019, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #ifndef _WINSOCK_H #define _WINSOCK_H #ifdef __MINGW32__ // Target NT6 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 #undef _WIN32_WINNT #endif #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0600 #endif // Winsock headers #include #include #include #include // Override POSIX error number #ifdef errno #undef errno #endif #define errno WSAGetLastError() #ifdef EWOULDBLOCK #undef EWOULDBLOCK #endif #define EWOULDBLOCK WSAEWOULDBLOCK #ifdef CONNECT_IN_PROGRESS #undef CONNECT_IN_PROGRESS #endif #define CONNECT_IN_PROGRESS WSAEWOULDBLOCK #ifdef EOPNOTSUPP #undef EOPNOTSUPP #endif #define EOPNOTSUPP WSAEOPNOTSUPP #ifdef EPROTONOSUPPORT #undef EPROTONOSUPPORT #endif #define EPROTONOSUPPORT WSAEPROTONOSUPPORT #ifdef ENOPROTOOPT #undef ENOPROTOOPT #endif #define ENOPROTOOPT WSAENOPROTOOPT // Check if ConnectEx supported in header #ifdef WSAID_CONNECTEX // Hardcode TCP fast open option #ifndef TCP_FASTOPEN #define TCP_FASTOPEN 15 #endif // Enable TFO support #define TCP_FASTOPEN_WINSOCK 1 #endif // Override close function #define close(fd) closesocket(fd) // Override MinGW functions #define setsockopt(a, b, c, d, e) setsockopt(a, b, c, (const char *)(d), e) #define inet_ntop(a, b, c, d) inet_ntop(a, (void *)(b), c, d) // Override Windows built-in functions #ifdef ERROR #undef ERROR #endif #define ERROR(s) ss_error(s) #ifdef gai_strerror #undef gai_strerror #endif #define gai_strerror(e) ss_gai_strerror(e) char *ss_gai_strerror(int ecode); // Missing Unix functions #define sleep(x) Sleep((x) * 1000) #define bzero(s, n) memset(s, 0, n) #define strndup(s, n) ss_strndup(s, n) // Winsock compatibility functions int setnonblocking(SOCKET socket); void winsock_init(void); void winsock_cleanup(void); #ifdef TCP_FASTOPEN_WINSOCK LPFN_CONNECTEX winsock_getconnectex(void); int winsock_dummybind(SOCKET fd, struct sockaddr *sa); #endif #endif // __MINGW32__ #endif // _WINSOCK_H ================================================ FILE: tests/CMakeLists.txt ================================================ # Unit tests using CTest include_directories(BEFORE ${MBEDTLS_INCLUDE_DIRS}) include_directories(${PROJECT_SOURCE_DIR}/src) include_directories(${PROJECT_BINARY_DIR}/src) include_directories(${SODIUM_INCLUDE_DIRS}) include_directories(${PCRE2_INCLUDE_DIRS}) include_directories(${CARES_INCLUDE_DIRS}) if(WITH_EMBEDDED_SRC) include_directories(${PROJECT_SOURCE_DIR}/libcork/include) include_directories(${PROJECT_SOURCE_DIR}/libipset/include) include_directories(${PROJECT_SOURCE_DIR}/libbloom/murmur2) include_directories(${PROJECT_SOURCE_DIR}/libbloom) endif() # Helper function to add a unit test function(ss_add_test name sources libs) add_executable(${name} ${sources}) target_compile_definitions(${name} PRIVATE -DHAVE_CONFIG_H) target_link_libraries(${name} ${libs}) add_test(NAME ${name} COMMAND ${name}) endfunction() # test_base64 - no external deps ss_add_test(test_base64 "test_base64.c;${PROJECT_SOURCE_DIR}/src/base64.c" "") # test_utils - needs sodium (for ss_malloc -> uses sodium in utils.c) ss_add_test(test_utils "test_utils.c;${PROJECT_SOURCE_DIR}/src/utils.c" "${LIBSODIUM_SHARED}") # test_json - standalone json parser ss_add_test(test_json "test_json.c;${PROJECT_SOURCE_DIR}/src/json.c" "m") # test_netutils - needs cork for ip address parsing set(TEST_NETUTILS_LIBS ${LIBSODIUM_SHARED} ${LIBEV_SHARED} ${LIBUDNS_SHARED} ) if(WITH_EMBEDDED_SRC) list(APPEND TEST_NETUTILS_LIBS cork) else() list(APPEND TEST_NETUTILS_LIBS ${LIBCORK_SHARED}) endif() ss_add_test(test_netutils "test_netutils.c;${PROJECT_SOURCE_DIR}/src/netutils.c;${PROJECT_SOURCE_DIR}/src/utils.c" "${TEST_NETUTILS_LIBS}") # test_cache - needs libev for ev_time() ss_add_test(test_cache "test_cache.c;${PROJECT_SOURCE_DIR}/src/cache.c;${PROJECT_SOURCE_DIR}/src/utils.c" "${LIBEV_SHARED};${LIBSODIUM_SHARED}") # test_ppbloom - needs bloom set(TEST_PPBLOOM_LIBS "") if(WITH_EMBEDDED_SRC) list(APPEND TEST_PPBLOOM_LIBS bloom) else() list(APPEND TEST_PPBLOOM_LIBS ${LIBBLOOM_SHARED}) endif() ss_add_test(test_ppbloom "test_ppbloom.c;${PROJECT_SOURCE_DIR}/src/ppbloom.c;${PROJECT_SOURCE_DIR}/src/utils.c" "${TEST_PPBLOOM_LIBS};${LIBSODIUM_SHARED};m") # test_rule - needs pcre and cork set(TEST_RULE_LIBS ${LIBPCRE2_SHARED} ${LIBSODIUM_SHARED} ) if(WITH_EMBEDDED_SRC) list(APPEND TEST_RULE_LIBS cork) else() list(APPEND TEST_RULE_LIBS ${LIBCORK_SHARED}) endif() ss_add_test(test_rule "test_rule.c;${PROJECT_SOURCE_DIR}/src/rule.c;${PROJECT_SOURCE_DIR}/src/utils.c" "${TEST_RULE_LIBS}") # test_jconf - needs cork and json set(TEST_JCONF_LIBS ${LIBSODIUM_SHARED} ${LIBEV_SHARED} ${LIBUDNS_SHARED} ) if(WITH_EMBEDDED_SRC) list(APPEND TEST_JCONF_LIBS cork) else() list(APPEND TEST_JCONF_LIBS ${LIBCORK_SHARED}) endif() ss_add_test(test_jconf "test_jconf.c;${PROJECT_SOURCE_DIR}/src/jconf.c;${PROJECT_SOURCE_DIR}/src/json.c;${PROJECT_SOURCE_DIR}/src/utils.c;${PROJECT_SOURCE_DIR}/src/netutils.c" "${TEST_JCONF_LIBS};m") # test_buffer - needs sodium and mbedtls for crypto.c buffer functions ss_add_test(test_buffer "test_buffer.c;${PROJECT_SOURCE_DIR}/src/crypto.c;${PROJECT_SOURCE_DIR}/src/utils.c;${PROJECT_SOURCE_DIR}/src/base64.c;${PROJECT_SOURCE_DIR}/src/aead.c;${PROJECT_SOURCE_DIR}/src/stream.c;${PROJECT_SOURCE_DIR}/src/ppbloom.c;${PROJECT_SOURCE_DIR}/src/cache.c" "${LIBSODIUM_SHARED};${LIBMBEDTLS_SHARED};${LIBMBEDCRYPTO_SHARED};${LIBEV_SHARED};${TEST_PPBLOOM_LIBS};m") # test_crypto - full crypto test set(TEST_CRYPTO_LIBS ${LIBSODIUM_SHARED} ${LIBMBEDTLS_SHARED} ${LIBMBEDCRYPTO_SHARED} ${LIBEV_SHARED} ) if(WITH_EMBEDDED_SRC) list(APPEND TEST_CRYPTO_LIBS bloom) else() list(APPEND TEST_CRYPTO_LIBS ${LIBBLOOM_SHARED}) endif() ss_add_test(test_crypto "test_crypto.c;${PROJECT_SOURCE_DIR}/src/crypto.c;${PROJECT_SOURCE_DIR}/src/aead.c;${PROJECT_SOURCE_DIR}/src/stream.c;${PROJECT_SOURCE_DIR}/src/ppbloom.c;${PROJECT_SOURCE_DIR}/src/cache.c;${PROJECT_SOURCE_DIR}/src/base64.c;${PROJECT_SOURCE_DIR}/src/utils.c" "${TEST_CRYPTO_LIBS};m") # test_ss_setup - bash unit tests for the ss-setup TUI tool add_test(NAME test_ss_setup COMMAND bash "${PROJECT_SOURCE_DIR}/tests/test_ss_setup.sh" WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}") ================================================ FILE: tests/aes-ctr.json ================================================ { "server":"127.0.0.1", "server_port":8389, "local_port":1081, "password":"aes_password", "timeout":60, "method":"aes-256-ctr", "local":"127.0.0.1", "fast_open":false } ================================================ FILE: tests/aes-gcm.json ================================================ { "server":"127.0.0.1", "server_port":8389, "local_port":1081, "password":"aes_password", "timeout":60, "method":"aes-256-gcm", "local":"127.0.0.1", "fast_open":false } ================================================ FILE: tests/aes.json ================================================ { "server":"127.0.0.1", "server_port":8389, "local_port":1081, "password":"aes_password", "timeout":60, "method":"aes-256-cfb", "local":"127.0.0.1", "fast_open":false } ================================================ FILE: tests/chacha20-ietf-poly1305.json ================================================ { "server":"127.0.0.1", "server_port":8389, "local_port":1081, "password":"salsa20_password", "timeout":60, "method":"chacha20-ietf-poly1305", "local":"127.0.0.1", "fast_open":false } ================================================ FILE: tests/chacha20-ietf.json ================================================ { "server":"127.0.0.1", "server_port":8389, "local_port":1081, "password":"salsa20_password", "timeout":60, "method":"chacha20-ietf", "local":"127.0.0.1", "fast_open":false } ================================================ FILE: tests/chacha20.json ================================================ { "server":"127.0.0.1", "server_port":8389, "local_port":1081, "password":"chacha20_password", "timeout":60, "method":"chacha20", "local":"127.0.0.1", "fast_open":false } ================================================ FILE: tests/qemu/guest-init.sh ================================================ #!/bin/bash # # Guest init script (PID 1) for ss-redir transparent proxy test. # Runs inside a QEMU Alpine Linux VM. # # Flow: # 1. Mount filesystems and load kernel modules # 2. Configure networking (QEMU user-mode: guest 10.0.2.15, host 10.0.2.2) # 3. Start ss-redir pointing at ss-server on the host # 4. Run ss-nat to set up iptables REDIRECT rules # 5. Test with curl through the transparent proxy # 6. Print REDIR_TEST_PASS or REDIR_TEST_FAIL to serial console # set -e # --- helpers ---------------------------------------------------------------- pass() { echo "" echo "=========================================" echo "REDIR_TEST_PASS" echo "=========================================" sync echo o > /proc/sysrq-trigger sleep 10 } fail() { local msg="${1:-unknown error}" echo "" echo "=========================================" echo "REDIR_TEST_FAIL: $msg" echo "=========================================" sync echo o > /proc/sysrq-trigger sleep 10 } # --- mount filesystems ------------------------------------------------------ mount -t proc proc /proc mount -t sysfs sysfs /sys mount -t devtmpfs devtmpfs /dev mkdir -p /dev/pts /tmp /run mount -t devpts devpts /dev/pts mount -t tmpfs tmpfs /tmp mount -t tmpfs tmpfs /run # Enable sysrq for clean poweroff echo 1 > /proc/sys/kernel/sysrq echo "=== Guest init starting ===" # --- load kernel modules ---------------------------------------------------- for mod in \ virtio_net \ ip_tables iptable_nat iptable_filter \ nf_nat nf_conntrack \ xt_REDIRECT xt_set xt_tcpudp \ ip_set ip_set_hash_net; do modprobe "$mod" 2>/dev/null || echo "WARN: failed to load $mod (may be built-in)" done echo "=== Kernel modules loaded ===" # --- configure network ------------------------------------------------------ # Find the non-lo network interface IFACE="" for f in /sys/class/net/*/type; do iface=$(basename "$(dirname "$f")") if [ "$iface" != "lo" ]; then IFACE="$iface" break fi done if [ -z "$IFACE" ]; then fail "no network interface found" fi echo "=== Using network interface: $IFACE ===" ip link set lo up ip link set "$IFACE" up ip addr add 10.0.2.15/24 dev "$IFACE" ip route add default via 10.0.2.2 # DNS (QEMU user-mode DNS forwarder) echo "nameserver 10.0.2.3" > /etc/resolv.conf # Wait for link to come up sleep 2 # Connectivity check echo "=== Checking connectivity to host ===" if ! ping -c 2 -W 5 10.0.2.2; then fail "cannot reach host at 10.0.2.2" fi echo "=== Host reachable ===" # --- start ss-redir --------------------------------------------------------- echo "=== Starting ss-redir ===" /usr/bin/ss-redir -c /etc/ss-redir.json -v & SS_REDIR_PID=$! sleep 3 if ! kill -0 "$SS_REDIR_PID" 2>/dev/null; then fail "ss-redir died immediately" fi echo "=== ss-redir running (PID $SS_REDIR_PID) ===" # --- run ss-nat (set up iptables REDIRECT) ---------------------------------- echo "=== Running ss-nat ===" if ! /usr/bin/ss-nat -s 10.0.2.2 -l 1080 -o; then fail "ss-nat failed" fi echo "=== ss-nat rules applied ===" # Show iptables state for debugging echo "=== iptables -t nat -L -n ===" iptables -t nat -L -n 2>&1 || true echo "=== ipset list ===" ipset list 2>&1 || true # --- test with curl --------------------------------------------------------- echo "=== Testing transparent proxy with curl ===" # Try multiple URLs for reliability (captive portal detection endpoints # are lightweight and highly available) # Test 1: Mozilla captive portal echo "--- Test 1: detectportal.firefox.com ---" BODY=$(curl -s --connect-timeout 15 -m 30 http://detectportal.firefox.com/success.txt 2>&1) || true echo "Response: $BODY" if echo "$BODY" | grep -q "success"; then echo "Test 1 PASSED" pass fi # Test 2: Google (expect redirect or 200) echo "--- Test 2: www.google.com ---" HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 15 -m 30 http://www.google.com/ 2>&1) || true echo "HTTP code: $HTTP_CODE" if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "301" ] || [ "$HTTP_CODE" = "302" ]; then echo "Test 2 PASSED" pass fi # Test 3: Apple captive portal echo "--- Test 3: captive.apple.com ---" BODY=$(curl -s --connect-timeout 15 -m 30 http://captive.apple.com/ 2>&1) || true echo "Response: $BODY" if echo "$BODY" | grep -qi "success"; then echo "Test 3 PASSED" pass fi # If we get here, all tests failed fail "all curl tests failed" ================================================ FILE: tests/rc4-md5.json ================================================ { "server":"127.0.0.1", "server_port":8389, "local_port":1081, "password":"aes_password", "timeout":60, "method":"rc4-md5", "local":"127.0.0.1", "fast_open":false } ================================================ FILE: tests/redir.json ================================================ { "server":"10.0.2.2", "server_port":8389, "local_port":1080, "password":"test_redir_password", "timeout":60, "method":"aes-256-gcm" } ================================================ FILE: tests/salsa20.json ================================================ { "server":"127.0.0.1", "server_port":8389, "local_port":1081, "password":"salsa20_password", "timeout":60, "method":"salsa20", "local":"127.0.0.1", "fast_open":false } ================================================ FILE: tests/stress_test.py ================================================ #!/usr/bin/env python3 """ Stress test for shadowsocks-libev: measures bandwidth on loopback with different ciphers using ss-server and ss-tunnel, and monitors for memory leaks. Usage: python3 tests/stress_test.py --bin build/bin/ python3 tests/stress_test.py --bin build/bin/ --size 50 --duration 10 python3 tests/stress_test.py --bin build/bin/ --cipher aes-256-gcm """ from __future__ import print_function import argparse import json import os import platform import signal import socket import sys import threading import time from subprocess import Popen # Ciphers to test: AEAD (recommended) + common stream ciphers AEAD_CIPHERS = [ "aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", ] STREAM_CIPHERS = [ "aes-128-cfb", "aes-256-cfb", "aes-256-ctr", "chacha20-ietf", ] ALL_CIPHERS = AEAD_CIPHERS + STREAM_CIPHERS # Ports (picked high to avoid conflicts) SERVER_PORT = 18388 TUNNEL_LOCAL_PORT = 18389 SINK_PORT = 18390 def get_rss_kb(pid): """Get resident set size in KB for a process.""" system = platform.system() try: if system == "Linux": with open("/proc/%d/status" % pid) as f: for line in f: if line.startswith("VmRSS:"): return int(line.split()[1]) elif system == "Darwin": import subprocess out = subprocess.check_output( ["ps", "-o", "rss=", "-p", str(pid)], stderr=subprocess.DEVNULL ).decode().strip() if out: return int(out) except (IOError, OSError, ValueError): pass return None class SinkServer: """A simple TCP server that accepts connections and discards all data. Sends back a small acknowledgement per chunk so the sender knows data was received (for accurate bandwidth measurement).""" def __init__(self, port): self.port = port self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind(("127.0.0.1", port)) self.sock.listen(5) self.sock.settimeout(1.0) self.running = True self.bytes_received = 0 self.thread = threading.Thread(target=self._run, daemon=True) self.thread.start() def _run(self): while self.running: try: conn, addr = self.sock.accept() t = threading.Thread( target=self._handle, args=(conn,), daemon=True ) t.start() except socket.timeout: continue except OSError: break def _handle(self, conn): conn.settimeout(5.0) try: while self.running: data = conn.recv(65536) if not data: break self.bytes_received += len(data) except (socket.timeout, OSError): pass finally: conn.close() def stop(self): self.running = False self.sock.close() self.thread.join(timeout=3) def server_args(ss_server, cipher, password, server_port): """Build command-line args for ss-server.""" return [ ss_server, "-s", "127.0.0.1", "-p", str(server_port), "-k", password, "-m", cipher, ] def tunnel_args(ss_tunnel, cipher, password, server_port, local_port, fwd_host, fwd_port): """Build command-line args for ss-tunnel.""" return [ ss_tunnel, "-s", "127.0.0.1", "-p", str(server_port), "-l", str(local_port), "-k", password, "-m", cipher, "-L", "%s:%d" % (fwd_host, fwd_port), ] def kill_proc(proc): """Kill a process gracefully.""" if proc and proc.poll() is None: try: proc.send_signal(signal.SIGTERM) proc.wait(timeout=5) except Exception: try: proc.kill() proc.wait(timeout=3) except Exception: pass def run_bandwidth_test(bin_dir, cipher, data_size_mb, password="stress_test_pw"): """Run a single bandwidth test with the given cipher. Returns dict with: cipher, bandwidth_mbps, duration_sec, server_rss_before_kb, server_rss_after_kb, tunnel_rss_before_kb, tunnel_rss_after_kb, bytes_transferred, error """ result = { "cipher": cipher, "bandwidth_mbps": 0, "duration_sec": 0, "bytes_transferred": 0, "server_rss_before_kb": None, "server_rss_after_kb": None, "tunnel_rss_before_kb": None, "tunnel_rss_after_kb": None, "error": None, } ss_server_bin = os.path.join(bin_dir, "ss-server") ss_tunnel_bin = os.path.join(bin_dir, "ss-tunnel") if not os.path.isfile(ss_server_bin) or not os.path.isfile(ss_tunnel_bin): result["error"] = "binaries not found in %s" % bin_dir return result server_proc = None tunnel_proc = None sink = None devnull = open(os.devnull, "w") try: # Start sink server (the destination ss-tunnel forwards to) sink = SinkServer(SINK_PORT) # Start ss-server server_proc = Popen( server_args(ss_server_bin, cipher, password, SERVER_PORT), stdout=devnull, stderr=devnull, close_fds=True ) # Start ss-tunnel forwarding to the sink tunnel_proc = Popen( tunnel_args(ss_tunnel_bin, cipher, password, SERVER_PORT, TUNNEL_LOCAL_PORT, "127.0.0.1", SINK_PORT), stdout=devnull, stderr=devnull, close_fds=True ) # Wait for processes to start and bind ports # Don't probe the ports as ss-tunnel crashes on empty connections time.sleep(3.0) if server_proc.poll() is not None: result["error"] = "ss-server exited prematurely (code %d)" % server_proc.returncode return result if tunnel_proc.poll() is not None: result["error"] = "ss-tunnel exited prematurely (code %d)" % tunnel_proc.returncode return result # Record RSS before result["server_rss_before_kb"] = get_rss_kb(server_proc.pid) result["tunnel_rss_before_kb"] = get_rss_kb(tunnel_proc.pid) # Send data through the tunnel chunk_size = 64 * 1024 # 64KB chunks total_bytes = data_size_mb * 1024 * 1024 data_chunk = b"\x00" * chunk_size sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(30) try: sock.connect(("127.0.0.1", TUNNEL_LOCAL_PORT)) except (socket.error, OSError) as e: result["error"] = "connect to tunnel failed: %s" % e return result sent = 0 start_time = time.time() try: while sent < total_bytes: remaining = total_bytes - sent to_send = min(chunk_size, remaining) if to_send < chunk_size: data_chunk = b"\x00" * to_send sock.sendall(data_chunk) sent += to_send except (socket.error, OSError) as e: result["error"] = "send error at %d bytes: %s" % (sent, e) finally: elapsed = time.time() - start_time try: sock.shutdown(socket.SHUT_WR) except OSError: pass sock.close() # Wait a bit for data to flow through time.sleep(0.5) result["bytes_transferred"] = sent result["duration_sec"] = elapsed if elapsed > 0: result["bandwidth_mbps"] = (sent * 8) / (elapsed * 1e6) # Record RSS after result["server_rss_after_kb"] = get_rss_kb(server_proc.pid) result["tunnel_rss_after_kb"] = get_rss_kb(tunnel_proc.pid) except Exception as e: result["error"] = str(e) finally: kill_proc(tunnel_proc) kill_proc(server_proc) if sink: sink.stop() devnull.close() return result def format_size(nbytes): if nbytes >= 1024 * 1024 * 1024: return "%.1f GB" % (nbytes / (1024 * 1024 * 1024)) elif nbytes >= 1024 * 1024: return "%.1f MB" % (nbytes / (1024 * 1024)) elif nbytes >= 1024: return "%.1f KB" % (nbytes / 1024) return "%d B" % nbytes def format_rss(kb): if kb is None: return "N/A" if kb >= 1024: return "%.1f MB" % (kb / 1024.0) return "%d KB" % kb def main(): parser = argparse.ArgumentParser( description="Stress test ss-server + ss-tunnel bandwidth on loopback" ) parser.add_argument( "--bin", type=str, required=True, help="Path to directory containing ss-server and ss-tunnel binaries" ) parser.add_argument( "--size", type=int, default=100, help="Data size to transfer per cipher in MB (default: 100)" ) parser.add_argument( "--cipher", type=str, default=None, help="Test only this specific cipher" ) parser.add_argument( "--repeat", type=int, default=1, help="Number of times to repeat each cipher test (default: 1)" ) parser.add_argument( "--stream", action="store_true", help="Include stream ciphers (deprecated, insecure)" ) parser.add_argument( "--leak-threshold", type=int, default=10240, help="RSS growth threshold in KB to flag as potential leak (default: 10240)" ) parser.add_argument( "--json", type=str, default=None, help="Write results as JSON to this file" ) args = parser.parse_args() # Determine ciphers to test if args.cipher: ciphers = [args.cipher] elif args.stream: ciphers = ALL_CIPHERS else: ciphers = AEAD_CIPHERS print("=" * 72) print("shadowsocks-libev stress test") print("=" * 72) print(" Binaries : %s" % os.path.abspath(args.bin)) print(" Data size: %d MB per cipher" % args.size) print(" Ciphers : %s" % ", ".join(ciphers)) print(" Repeats : %d" % args.repeat) print("=" * 72) print() all_results = [] leak_warnings = [] for cipher in ciphers: for run in range(args.repeat): label = cipher if args.repeat > 1: label = "%s (run %d/%d)" % (cipher, run + 1, args.repeat) sys.stdout.write("Testing %-35s ... " % label) sys.stdout.flush() result = run_bandwidth_test(args.bin, cipher, args.size) all_results.append(result) if result["error"]: print("FAILED: %s" % result["error"]) continue bw = result["bandwidth_mbps"] dur = result["duration_sec"] print("%8.1f Mbps (%5.2fs, %s)" % ( bw, dur, format_size(result["bytes_transferred"]) )) # Check for memory leaks for role in ["server", "tunnel"]: before = result["%s_rss_before_kb" % role] after = result["%s_rss_after_kb" % role] if before is not None and after is not None: growth = after - before if growth > args.leak_threshold: msg = ( " WARNING: ss-%s RSS grew by %s " "(%s -> %s) during %s test" % (role, format_rss(growth), format_rss(before), format_rss(after), cipher) ) print(msg) leak_warnings.append(msg) # Summary print() print("=" * 72) print("RESULTS SUMMARY") print("=" * 72) print() print("%-30s %10s %8s %12s %12s" % ( "Cipher", "Bandwidth", "Time", "Server RSS", "Tunnel RSS" )) print("-" * 72) for r in all_results: if r["error"]: print("%-30s %10s" % (r["cipher"], "FAILED")) continue srv_rss = "" tun_rss = "" if r["server_rss_before_kb"] and r["server_rss_after_kb"]: srv_rss = "%s->%s" % ( format_rss(r["server_rss_before_kb"]), format_rss(r["server_rss_after_kb"]) ) if r["tunnel_rss_before_kb"] and r["tunnel_rss_after_kb"]: tun_rss = "%s->%s" % ( format_rss(r["tunnel_rss_before_kb"]), format_rss(r["tunnel_rss_after_kb"]) ) print("%-30s %7.1f Mbps %6.2fs %12s %12s" % ( r["cipher"], r["bandwidth_mbps"], r["duration_sec"], srv_rss or "N/A", tun_rss or "N/A" )) if leak_warnings: print() print("MEMORY LEAK WARNINGS:") for w in leak_warnings: print(w) print() sys.exit(1) print() passed = [r for r in all_results if not r["error"]] failed = [r for r in all_results if r["error"]] print("%d passed, %d failed" % (len(passed), len(failed))) if args.json: with open(args.json, "w") as f: json.dump(all_results, f, indent=2) print("Results written to %s" % args.json) if failed: sys.exit(1) if __name__ == "__main__": main() ================================================ FILE: tests/test.py ================================================ #!/usr/bin/python # -*- coding: utf-8 -*- # # Copyright 2015 clowwindy # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from __future__ import absolute_import, division, print_function, \ with_statement import sys import os import signal import select import time import argparse from subprocess import Popen, PIPE default_url = 'http://www.google.com/' parser = argparse.ArgumentParser(description='test Shadowsocks') parser.add_argument('-c', '--client-conf', type=str, default=None) parser.add_argument('-s', '--server-conf', type=str, default=None) parser.add_argument('-a', '--client-args', type=str, default=None) parser.add_argument('-b', '--server-args', type=str, default=None) parser.add_argument('--should-fail', action='store_true', default=None) parser.add_argument('--url', type=str, default=default_url) parser.add_argument('--dns', type=str, default='8.8.8.8') parser.add_argument('--bin', type=str, default='') config = parser.parse_args() client_args = ['%s%s' % (config.bin, 'ss-local'), '-v'] server_args = ['%s%s' % (config.bin, 'ss-server'), '-v', '-u'] tunnel_args = ['%s%s' % (config.bin, 'ss-tunnel'), '-v', '-u', '-l1082', '-L%s:53' % config.dns] if config.client_conf: client_args.extend(['-c', config.client_conf]) tunnel_args.extend(['-c', config.client_conf]) if config.server_conf: server_args.extend(['-c', config.server_conf]) else: server_args.extend(['-c', config.client_conf]) if config.client_args: client_args.extend(config.client_args.split()) tunnel_args.extend(config.client_args.split()) if config.server_args: server_args.extend(config.server_args.split()) else: server_args.extend(config.client_args.split()) p1 = Popen(server_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) p2 = Popen(client_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) p5 = Popen(tunnel_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) p3 = None p4 = None p3_fin = False p4_fin = False # 1 shadowsocks started # 2 curl started # 3 curl finished # 4 dig started # 5 dig finished stage = 1 try: fdset = [] time.sleep(2) p3 = Popen(['curl', config.url, '-v', '-L', '--socks5-hostname', '127.0.0.1:1081', '-m', '15', '--connect-timeout', '10'], stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) if p3 is not None: fdset.append(p3.stdout) fdset.append(p3.stderr) stage = 2 else: sys.exit(1) while True: r, w, e = select.select(fdset, [], fdset) if e: break for fd in r: line = fd.readline() if not line: if stage == 2 and fd == p3.stdout: stage = 3 if stage == 4 and fd == p4.stdout: stage = 5 if bytes != str: line = bytes(line) sys.stderr.buffer.write(line) else: sys.stderr.write(line) if stage == 3 and p3 is not None: fdset.remove(p3.stdout) fdset.remove(p3.stderr) r = p3.wait() if config.should_fail: if r == 0: sys.exit(1) else: if r != 0: sys.exit(1) p4 = Popen(['dig', '@127.0.0.1', '-p1082', 'www.google.com'], stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) if p4 is not None: fdset.append(p4.stdout) fdset.append(p4.stderr) stage = 4 else: sys.exit(1) if stage == 5: r = p4.wait() if config.should_fail: if r == 0: sys.exit(1) print('test passed (expecting failure)') else: if r != 0: sys.exit(1) print('test passed') break finally: for p in [p1, p2, p5]: try: os.kill(p.pid, signal.SIGINT) os.waitpid(p.pid, 0) except OSError: pass ================================================ FILE: tests/test.sh ================================================ #!/bin/bash result=0 function run_test { printf '\e[0;36m' echo "running test: $command $@" printf '\e[0m' $command "$@" status=$? if [ $status -ne 0 ]; then printf '\e[0;31m' echo "test failed: $command $@" printf '\e[0m' echo result=1 else printf '\e[0;32m' echo OK printf '\e[0m' echo fi return 0 } [ -d src -a -x src/ss-local ] && BIN="--bin src/" if [ "$http_proxy" ]; then echo "SKIP: shadowsocks-libev does not support an upstream HTTP proxy" exit 0 fi run_test python tests/test.py $BIN -c tests/aes.json run_test python tests/test.py $BIN -c tests/aes-gcm.json run_test python tests/test.py $BIN -c tests/aes-ctr.json run_test python tests/test.py $BIN -c tests/rc4-md5.json run_test python tests/test.py $BIN -c tests/salsa20.json run_test python tests/test.py $BIN -c tests/chacha20.json run_test python tests/test.py $BIN -c tests/chacha20-ietf.json run_test python tests/test.py $BIN -c tests/chacha20-ietf-poly1305.json exit $result ================================================ FILE: tests/test_base64.c ================================================ #include #include #include #include "base64.h" static void test_encode_decode(void) { /* Known test vector: "Hello" */ const uint8_t input[] = "Hello"; char encoded[BASE64_SIZE(5)]; uint8_t decoded[5]; char *ret = base64_encode(encoded, sizeof(encoded), input, 5); assert(ret != NULL); assert(strlen(encoded) > 0); int decoded_len = base64_decode(decoded, encoded, sizeof(decoded)); assert(decoded_len == 5); assert(memcmp(decoded, input, 5) == 0); } static void test_empty_input(void) { char encoded[BASE64_SIZE(0)]; char *ret = base64_encode(encoded, sizeof(encoded), (const uint8_t *)"", 0); assert(ret != NULL); assert(strlen(encoded) == 0); } static void test_single_byte(void) { const uint8_t input[] = { 0x41 }; /* 'A' */ char encoded[BASE64_SIZE(1)]; uint8_t decoded[1]; char *ret = base64_encode(encoded, sizeof(encoded), input, 1); assert(ret != NULL); int decoded_len = base64_decode(decoded, encoded, sizeof(decoded)); assert(decoded_len == 1); assert(decoded[0] == 0x41); } static void test_two_bytes(void) { const uint8_t input[] = { 0x41, 0x42 }; /* "AB" */ char encoded[BASE64_SIZE(2)]; uint8_t decoded[2]; char *ret = base64_encode(encoded, sizeof(encoded), input, 2); assert(ret != NULL); int decoded_len = base64_decode(decoded, encoded, sizeof(decoded)); assert(decoded_len == 2); assert(decoded[0] == 0x41); assert(decoded[1] == 0x42); } static void test_three_bytes(void) { const uint8_t input[] = { 0x00, 0xFF, 0x80 }; char encoded[BASE64_SIZE(3)]; uint8_t decoded[3]; char *ret = base64_encode(encoded, sizeof(encoded), input, 3); assert(ret != NULL); int decoded_len = base64_decode(decoded, encoded, sizeof(decoded)); assert(decoded_len == 3); assert(decoded[0] == 0x00); assert(decoded[1] == 0xFF); assert(decoded[2] == 0x80); } static void test_roundtrip_binary(void) { const uint8_t input[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; char encoded[BASE64_SIZE(17)]; uint8_t decoded[17]; char *ret = base64_encode(encoded, sizeof(encoded), input, 17); assert(ret != NULL); int decoded_len = base64_decode(decoded, encoded, sizeof(decoded)); assert(decoded_len == 17); assert(memcmp(decoded, input, 17) == 0); } static void test_invalid_chars(void) { /* Character '!' (ASCII 33) is below the base64 range start ('+' = 43) */ int decoded_len = base64_decode((uint8_t[4]){}, "!!!!", 4); assert(decoded_len == -1); } int main(void) { test_encode_decode(); test_empty_input(); test_single_byte(); test_two_bytes(); test_three_bytes(); test_roundtrip_binary(); test_invalid_chars(); return 0; } ================================================ FILE: tests/test_buffer.c ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include int verbose = 0; #include "crypto.h" /* Provide nonce_cache symbol needed by crypto.c */ struct cache *nonce_cache = NULL; static void test_balloc(void) { buffer_t buf; memset(&buf, 0, sizeof(buf)); int ret = balloc(&buf, 100); assert(ret == 0); (void)ret; assert(buf.data != NULL); assert(buf.capacity >= 100); assert(buf.len == 0); assert(buf.idx == 0); bfree(&buf); assert(buf.data == NULL); assert(buf.capacity == 0); } static void test_brealloc(void) { buffer_t buf; memset(&buf, 0, sizeof(buf)); balloc(&buf, 50); buf.len = 10; /* Grow the buffer */ int ret = brealloc(&buf, 10, 200); assert(ret == 0); (void)ret; assert(buf.capacity >= 200); assert(buf.len == 10); bfree(&buf); } static void test_bprepend(void) { buffer_t dst, src; memset(&dst, 0, sizeof(dst)); memset(&src, 0, sizeof(src)); balloc(&dst, 100); balloc(&src, 100); /* Put some data in src */ memcpy(src.data, "HEADER", 6); src.len = 6; /* Put some data in dst */ memcpy(dst.data, "BODY", 4); dst.len = 4; int ret = bprepend(&dst, &src, 200); assert(ret == 0); (void)ret; assert(dst.len == 10); assert(memcmp(dst.data, "HEADERBODY", 10) == 0); bfree(&dst); bfree(&src); } static void test_balloc_zero(void) { buffer_t buf; memset(&buf, 0, sizeof(buf)); int ret = balloc(&buf, 0); assert(ret == 0); (void)ret; /* A zero-capacity buffer should still succeed */ bfree(&buf); } int main(void) { test_balloc(); test_brealloc(); test_bprepend(); test_balloc_zero(); return 0; } ================================================ FILE: tests/test_cache.c ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include int verbose = 0; #include "cache.h" static void test_create_delete(void) { struct cache *c = NULL; int ret = cache_create(&c, 100, NULL); assert(ret == 0); assert(c != NULL); ret = cache_delete(c, 0); assert(ret == 0); (void)ret; } static void test_create_null(void) { int ret = cache_create(NULL, 100, NULL); assert(ret == EINVAL); (void)ret; } static void test_insert_lookup(void) { struct cache *c = NULL; cache_create(&c, 100, NULL); char *data = strdup("test_data"); cache_insert(c, "key1", 4, data); char *result = NULL; cache_lookup(c, "key1", 4, &result); assert(result != NULL); assert(strcmp(result, "test_data") == 0); cache_delete(c, 0); } static void test_key_exist(void) { struct cache *c = NULL; cache_create(&c, 100, NULL); char *data = strdup("value"); cache_insert(c, "mykey", 5, data); assert(cache_key_exist(c, "mykey", 5) == 1); assert(cache_key_exist(c, "nokey", 5) == 0); cache_delete(c, 0); } static void test_remove(void) { struct cache *c = NULL; cache_create(&c, 100, NULL); char *data = strdup("to_remove"); cache_insert(c, "rmkey", 5, data); assert(cache_key_exist(c, "rmkey", 5) == 1); cache_remove(c, "rmkey", 5); assert(cache_key_exist(c, "rmkey", 5) == 0); cache_delete(c, 0); } static void test_lookup_missing(void) { struct cache *c = NULL; cache_create(&c, 100, NULL); char *result = (char *)0xdeadbeef; cache_lookup(c, "missing", 7, &result); assert(result == NULL); cache_delete(c, 0); } static void test_eviction(void) { struct cache *c = NULL; cache_create(&c, 3, NULL); /* Insert 3 entries to fill cache */ cache_insert(c, "k1", 2, strdup("v1")); cache_insert(c, "k2", 2, strdup("v2")); cache_insert(c, "k3", 2, strdup("v3")); /* This should trigger eviction of the oldest entry */ cache_insert(c, "k4", 2, strdup("v4")); /* k1 should have been evicted */ assert(cache_key_exist(c, "k1", 2) == 0); /* k4 should exist */ assert(cache_key_exist(c, "k4", 2) == 1); cache_delete(c, 0); } int main(void) { test_create_delete(); test_create_null(); test_insert_lookup(); test_key_exist(); test_remove(); test_lookup_missing(); test_eviction(); return 0; } ================================================ FILE: tests/test_crypto.c ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include int verbose = 0; #include "crypto.h" /* Provide nonce_cache symbol needed by crypto.c */ struct cache *nonce_cache = NULL; static void test_crypto_md5(void) { /* MD5("") = d41d8cd98f00b204e9800998ecf8427e */ unsigned char result[16]; crypto_md5((const unsigned char *)"", 0, result); unsigned char expected[] = { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e }; assert(memcmp(result, expected, 16) == 0); (void)expected; /* MD5("abc") = 900150983cd24fb0d6963f7d28e17f72 */ crypto_md5((const unsigned char *)"abc", 3, result); unsigned char expected_abc[] = { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 }; assert(memcmp(result, expected_abc, 16) == 0); (void)expected_abc; } static void test_crypto_derive_key(void) { uint8_t key[32]; /* derive_key should produce deterministic output from a password */ int ret = crypto_derive_key("password", key, 32); assert(ret == 32); /* Same password should produce same key */ uint8_t key2[32]; ret = crypto_derive_key("password", key2, 32); assert(ret == 32); assert(memcmp(key, key2, 32) == 0); /* Different password should produce different key */ uint8_t key3[32]; ret = crypto_derive_key("different", key3, 32); assert(ret == 32); assert(memcmp(key, key3, 32) != 0); (void)ret; } static void test_crypto_hkdf(void) { /* RFC 5869 Test Case 1 */ const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); assert(md != NULL); unsigned char ikm[22]; memset(ikm, 0x0b, 22); unsigned char salt[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; unsigned char info[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; unsigned char okm[42]; int ret = crypto_hkdf(md, salt, sizeof(salt), ikm, sizeof(ikm), info, sizeof(info), okm, sizeof(okm)); assert(ret == 0); (void)ret; unsigned char expected_okm[] = { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65 }; assert(memcmp(okm, expected_okm, 42) == 0); (void)expected_okm; } static void test_crypto_hkdf_extract(void) { const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); assert(md != NULL); unsigned char ikm[22]; memset(ikm, 0x0b, 22); unsigned char salt[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; unsigned char prk[32]; int ret = crypto_hkdf_extract(md, salt, sizeof(salt), ikm, sizeof(ikm), prk); assert(ret == 0); (void)ret; /* RFC 5869 Test Case 1 PRK */ unsigned char expected_prk[] = { 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5 }; assert(memcmp(prk, expected_prk, 32) == 0); (void)expected_prk; } static void test_crypto_parse_key(void) { /* base64_encode uses URL-safe base64 with -_ instead of +/ */ uint8_t key[32]; /* A known base64-encoded 32-byte key (all zeros) */ /* 32 zero bytes = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" in standard base64 */ /* With URL-safe: same since no +/ needed */ int ret = crypto_parse_key("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", key, 32); assert(ret == 32); (void)ret; /* All bytes should be 0 */ for (int i = 0; i < 32; i++) { assert(key[i] == 0); } } int main(void) { if (sodium_init() < 0) { return 1; } test_crypto_md5(); test_crypto_derive_key(); test_crypto_hkdf(); test_crypto_hkdf_extract(); test_crypto_parse_key(); return 0; } ================================================ FILE: tests/test_deb_build.sh ================================================ #!/bin/bash # # Test that Debian packages build, contain expected files, install, and work. # # Usage: bash tests/test_deb_build.sh # # Requirements (Linux only): # - dpkg-buildpackage, debhelper, fakeroot # - Build dependencies listed in debian/control # - sudo (for install phase) # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" # --- helpers ---------------------------------------------------------------- PASS_COUNT=0 FAIL_COUNT=0 FAILURES="" log() { echo "=== [test_deb_build] $* ===" } check_pass() { PASS_COUNT=$((PASS_COUNT + 1)) echo " PASS: $*" } check_fail() { FAIL_COUNT=$((FAIL_COUNT + 1)) FAILURES="${FAILURES} FAIL: $*"$'\n' echo " FAIL: $*" } # check_file_in_deb DEB_FILE PATTERN DESCRIPTION # Verifies that at least one file matching PATTERN exists in the .deb check_file_in_deb() { local deb="$1" pattern="$2" desc="$3" # Avoid grep -q: with pipefail, early grep exit causes SIGPIPE on dpkg-deb if dpkg-deb -c "$deb" | grep -E "$pattern" >/dev/null; then check_pass "$desc" else check_fail "$desc" fi } # check_command CMD DESCRIPTION # Verifies that a command runs successfully (exit 0) check_command() { local desc="$2" if eval "$1" >/dev/null 2>&1; then check_pass "$desc" else check_fail "$desc" fi } summary() { echo "" log "Results: $PASS_COUNT passed, $FAIL_COUNT failed" if [ "$FAIL_COUNT" -gt 0 ]; then echo "" echo "Failures:" printf '%s' "$FAILURES" exit 1 fi } # --- phase 1: build -------------------------------------------------------- log "Phase 1: Build Debian packages" cd "$PROJECT_DIR" # dpkg-buildpackage -b builds binary-only packages (no .orig.tar.gz needed) dpkg-buildpackage -b -us -uc -j"$(nproc)" # .deb files are placed in the parent directory PARENT_DIR="$(dirname "$PROJECT_DIR")" DEB_MAIN="" DEB_LIB="" DEB_DEV="" for f in "$PARENT_DIR"/shadowsocks-libev_*.deb; do [ -f "$f" ] && DEB_MAIN="$f" && break done for f in "$PARENT_DIR"/libshadowsocks-libev2_*.deb; do [ -f "$f" ] && DEB_LIB="$f" && break done for f in "$PARENT_DIR"/libshadowsocks-libev-dev_*.deb; do [ -f "$f" ] && DEB_DEV="$f" && break done # --- phase 2: verify contents ---------------------------------------------- log "Phase 2: Verify package contents" # Check all three .deb files exist if [ -n "$DEB_MAIN" ] && [ -f "$DEB_MAIN" ]; then check_pass "shadowsocks-libev .deb exists: $(basename "$DEB_MAIN")" else check_fail "shadowsocks-libev .deb not found" fi if [ -n "$DEB_LIB" ] && [ -f "$DEB_LIB" ]; then check_pass "libshadowsocks-libev2 .deb exists: $(basename "$DEB_LIB")" else check_fail "libshadowsocks-libev2 .deb not found" fi if [ -n "$DEB_DEV" ] && [ -f "$DEB_DEV" ]; then check_pass "libshadowsocks-libev-dev .deb exists: $(basename "$DEB_DEV")" else check_fail "libshadowsocks-libev-dev .deb not found" fi # Bail early if any .deb is missing - remaining checks would all fail if [ "$FAIL_COUNT" -gt 0 ]; then summary fi # Main package: binaries for bin in ss-local ss-server ss-redir ss-tunnel ss-manager; do check_file_in_deb "$DEB_MAIN" "usr/bin/${bin}" "$bin binary in main package" done # Main package: man pages for bin in ss-local ss-server ss-redir ss-tunnel ss-manager; do check_file_in_deb "$DEB_MAIN" "usr/share/man/man1/$bin\\.1" "$bin man page in main package" done # Shared library package check_file_in_deb "$DEB_LIB" "usr/lib/.*/libshadowsocks-libev\\.so\\." "shared library in lib package" # Dev package: header check_file_in_deb "$DEB_DEV" "usr/include/shadowsocks\\.h" "shadowsocks.h header in dev package" # Dev package: pkg-config check_file_in_deb "$DEB_DEV" "usr/lib/.*/pkgconfig/shadowsocks-libev\\.pc" "pkg-config file in dev package" # Dev package: unversioned .so symlink check_file_in_deb "$DEB_DEV" "usr/lib/.*/libshadowsocks-libev\\.so[^.]" "unversioned .so symlink in dev package" # --- phase 3: install ------------------------------------------------------- log "Phase 3: Install packages" sudo dpkg -i "$DEB_LIB" "$DEB_DEV" "$DEB_MAIN" || true sudo apt-get -f install -y # Verify dpkg thinks they are installed for pkg in shadowsocks-libev libshadowsocks-libev2 libshadowsocks-libev-dev; do if dpkg -s "$pkg" >/dev/null 2>&1; then check_pass "$pkg installed" else check_fail "$pkg not installed" fi done # --- phase 4: smoke-test ---------------------------------------------------- log "Phase 4: Smoke-test installed binaries" # Each binary should respond to --help for bin in ss-local ss-server ss-redir ss-tunnel ss-manager; do check_command "$bin --help" "$bin --help runs" done # Shared library should be findable by ldconfig sudo ldconfig if ldconfig -p | grep -q libshadowsocks-libev; then check_pass "libshadowsocks-libev found by ldconfig" else check_fail "libshadowsocks-libev not found by ldconfig" fi # Header should be in the include path if [ -f /usr/include/shadowsocks.h ]; then check_pass "shadowsocks.h installed in /usr/include" else check_fail "shadowsocks.h not installed in /usr/include" fi # --- summary ---------------------------------------------------------------- summary ================================================ FILE: tests/test_jconf.c ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include int verbose = 0; #include "netutils.h" #include "jconf.h" static void test_parse_addr_ipv4_with_port(void) { ss_addr_t addr; memset(&addr, 0, sizeof(addr)); parse_addr("192.168.1.1:8080", &addr); assert(addr.host != NULL); assert(addr.port != NULL); assert(strcmp(addr.host, "192.168.1.1") == 0); assert(strcmp(addr.port, "8080") == 0); free_addr(&addr); } static void test_parse_addr_ipv6_with_port(void) { ss_addr_t addr; memset(&addr, 0, sizeof(addr)); parse_addr("[::1]:443", &addr); assert(addr.host != NULL); assert(addr.port != NULL); assert(strcmp(addr.host, "::1") == 0); assert(strcmp(addr.port, "443") == 0); free_addr(&addr); } static void test_parse_addr_hostname_with_port(void) { ss_addr_t addr; memset(&addr, 0, sizeof(addr)); parse_addr("example.com:1234", &addr); assert(addr.host != NULL); assert(addr.port != NULL); assert(strcmp(addr.host, "example.com") == 0); assert(strcmp(addr.port, "1234") == 0); free_addr(&addr); } static void test_parse_addr_no_port(void) { ss_addr_t addr; memset(&addr, 0, sizeof(addr)); parse_addr("10.0.0.1", &addr); assert(addr.host != NULL); assert(strcmp(addr.host, "10.0.0.1") == 0); /* Port may be NULL when no port is specified */ free_addr(&addr); } static void test_parse_addr_ipv6_no_port(void) { ss_addr_t addr; memset(&addr, 0, sizeof(addr)); parse_addr("::1", &addr); assert(addr.host != NULL); assert(strcmp(addr.host, "::1") == 0); free_addr(&addr); } int main(void) { test_parse_addr_ipv4_with_port(); test_parse_addr_ipv6_with_port(); test_parse_addr_hostname_with_port(); test_parse_addr_no_port(); test_parse_addr_ipv6_no_port(); return 0; } ================================================ FILE: tests/test_json.c ================================================ #include #include #include #include "json.h" static void test_parse_simple_object(void) { const char *json_str = "{\"key\": \"value\", \"num\": 42}"; json_value *val = json_parse(json_str, strlen(json_str)); assert(val != NULL); assert(val->type == json_object); assert(val->u.object.length == 2); /* Check first entry */ assert(strcmp(val->u.object.values[0].name, "key") == 0); assert(val->u.object.values[0].value->type == json_string); assert(strcmp(val->u.object.values[0].value->u.string.ptr, "value") == 0); /* Check second entry */ assert(strcmp(val->u.object.values[1].name, "num") == 0); assert(val->u.object.values[1].value->type == json_integer); assert(val->u.object.values[1].value->u.integer == 42); json_value_free(val); } static void test_parse_array(void) { const char *json_str = "[1, 2, 3]"; json_value *val = json_parse(json_str, strlen(json_str)); assert(val != NULL); assert(val->type == json_array); assert(val->u.array.length == 3); assert(val->u.array.values[0]->type == json_integer); assert(val->u.array.values[0]->u.integer == 1); assert(val->u.array.values[1]->u.integer == 2); assert(val->u.array.values[2]->u.integer == 3); json_value_free(val); } static void test_parse_nested(void) { const char *json_str = "{\"outer\": {\"inner\": true}}"; json_value *val = json_parse(json_str, strlen(json_str)); assert(val != NULL); assert(val->type == json_object); assert(val->u.object.length == 1); json_value *outer = val->u.object.values[0].value; assert(outer->type == json_object); assert(outer->u.object.length == 1); assert(outer->u.object.values[0].value->type == json_boolean); assert(outer->u.object.values[0].value->u.boolean != 0); json_value_free(val); } static void test_parse_types(void) { const char *json_str = "{\"s\": \"hello\", \"i\": -5, \"d\": 3.14, \"b\": false, \"n\": null}"; json_value *val = json_parse(json_str, strlen(json_str)); assert(val != NULL); assert(val->type == json_object); assert(val->u.object.length == 5); assert(val->u.object.values[0].value->type == json_string); assert(val->u.object.values[1].value->type == json_integer); assert(val->u.object.values[1].value->u.integer == -5); assert(val->u.object.values[2].value->type == json_double); assert(val->u.object.values[3].value->type == json_boolean); assert(val->u.object.values[3].value->u.boolean == 0); assert(val->u.object.values[4].value->type == json_null); json_value_free(val); } static void test_parse_invalid(void) { /* Missing closing brace */ assert(json_parse("{\"key\": 1", 9) == NULL); /* Empty string */ assert(json_parse("", 0) == NULL); /* Just garbage */ assert(json_parse("not json", 8) == NULL); } static void test_parse_empty_object(void) { const char *json_str = "{}"; json_value *val = json_parse(json_str, strlen(json_str)); assert(val != NULL); assert(val->type == json_object); assert(val->u.object.length == 0); json_value_free(val); } static void test_parse_empty_array(void) { const char *json_str = "[]"; json_value *val = json_parse(json_str, strlen(json_str)); assert(val != NULL); assert(val->type == json_array); assert(val->u.array.length == 0); json_value_free(val); } int main(void) { test_parse_simple_object(); test_parse_array(); test_parse_nested(); test_parse_types(); test_parse_invalid(); test_parse_empty_object(); test_parse_empty_array(); return 0; } ================================================ FILE: tests/test_netutils.c ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include int verbose = 0; #include "netutils.h" static void test_get_sockaddr_len(void) { struct sockaddr_in addr4; struct sockaddr_in6 addr6; struct sockaddr_storage unknown; memset(&addr4, 0, sizeof(addr4)); addr4.sin_family = AF_INET; assert(get_sockaddr_len((struct sockaddr *)&addr4) == sizeof(struct sockaddr_in)); memset(&addr6, 0, sizeof(addr6)); addr6.sin6_family = AF_INET6; assert(get_sockaddr_len((struct sockaddr *)&addr6) == sizeof(struct sockaddr_in6)); memset(&unknown, 0, sizeof(unknown)); unknown.ss_family = AF_UNSPEC; assert(get_sockaddr_len((struct sockaddr *)&unknown) == 0); } static void test_sockaddr_cmp(void) { struct sockaddr_storage a, b; struct sockaddr_in *a4 = (struct sockaddr_in *)&a; struct sockaddr_in *b4 = (struct sockaddr_in *)&b; /* Same address and port */ memset(&a, 0, sizeof(a)); memset(&b, 0, sizeof(b)); a4->sin_family = AF_INET; b4->sin_family = AF_INET; a4->sin_port = htons(80); b4->sin_port = htons(80); inet_pton(AF_INET, "127.0.0.1", &a4->sin_addr); inet_pton(AF_INET, "127.0.0.1", &b4->sin_addr); assert(sockaddr_cmp(&a, &b, sizeof(struct sockaddr_in)) == 0); /* Different port */ b4->sin_port = htons(81); assert(sockaddr_cmp(&a, &b, sizeof(struct sockaddr_in)) != 0); } static void test_sockaddr_cmp_addr(void) { struct sockaddr_storage a, b; struct sockaddr_in *a4 = (struct sockaddr_in *)&a; struct sockaddr_in *b4 = (struct sockaddr_in *)&b; memset(&a, 0, sizeof(a)); memset(&b, 0, sizeof(b)); a4->sin_family = AF_INET; b4->sin_family = AF_INET; a4->sin_port = htons(80); b4->sin_port = htons(443); inet_pton(AF_INET, "10.0.0.1", &a4->sin_addr); inet_pton(AF_INET, "10.0.0.1", &b4->sin_addr); /* Same address, different port - should be equal */ assert(sockaddr_cmp_addr(&a, &b, sizeof(struct sockaddr_in)) == 0); /* Different address */ inet_pton(AF_INET, "10.0.0.2", &b4->sin_addr); assert(sockaddr_cmp_addr(&a, &b, sizeof(struct sockaddr_in)) != 0); } static void test_validate_hostname(void) { /* Valid hostnames */ assert(validate_hostname("example.com", 11) == 1); assert(validate_hostname("sub.example.com", 15) == 1); assert(validate_hostname("a", 1) == 1); assert(validate_hostname("a-b", 3) == 1); assert(validate_hostname("123.456", 7) == 1); /* Invalid hostnames */ assert(validate_hostname(NULL, 0) == 0); assert(validate_hostname("", 0) == 0); assert(validate_hostname(".example.com", 12) == 0); /* starts with dot */ assert(validate_hostname("-example.com", 12) == 0); /* label starts with hyphen */ assert(validate_hostname("example-.com", 12) == 0); /* label ends with hyphen */ /* Too long hostname (> 255) */ char long_name[260]; memset(long_name, 'a', 259); long_name[259] = '\0'; assert(validate_hostname(long_name, 259) == 0); } int main(void) { test_get_sockaddr_len(); test_sockaddr_cmp(); test_sockaddr_cmp_addr(); test_validate_hostname(); return 0; } ================================================ FILE: tests/test_ppbloom.c ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include int verbose = 0; #include "ppbloom.h" static void test_init_free(void) { int ret = ppbloom_init(1000, 0.01); assert(ret == 0); (void)ret; ppbloom_free(); } static void test_add_check(void) { ppbloom_init(1000, 0.01); const char *item1 = "hello"; const char *item2 = "world"; const char *item3 = "missing"; /* Not in filter initially */ assert(ppbloom_check(item1, strlen(item1)) == 0); assert(ppbloom_check(item2, strlen(item2)) == 0); /* Add items */ ppbloom_add(item1, strlen(item1)); ppbloom_add(item2, strlen(item2)); /* Should be found */ assert(ppbloom_check(item1, strlen(item1)) == 1); assert(ppbloom_check(item2, strlen(item2)) == 1); /* Should not be found */ assert(ppbloom_check(item3, strlen(item3)) == 0); (void)item3; ppbloom_free(); } static void test_binary_data(void) { ppbloom_init(1000, 0.01); const uint8_t data1[] = { 0x00, 0x01, 0x02, 0x03 }; const uint8_t data2[] = { 0xFF, 0xFE, 0xFD, 0xFC }; ppbloom_add(data1, sizeof(data1)); assert(ppbloom_check(data1, sizeof(data1)) == 1); assert(ppbloom_check(data2, sizeof(data2)) == 0); (void)data2; ppbloom_free(); } int main(void) { test_init_free(); test_add_check(); test_binary_data(); return 0; } ================================================ FILE: tests/test_redir_qemu.sh ================================================ #!/bin/bash # # End-to-end test for ss-redir transparent proxy using QEMU. # # Architecture: # Host: ss-server listens on 0.0.0.0:8389 # QEMU guest (Alpine Linux): # - ss-redir connects to host ss-server via 10.0.2.2:8389 # - ss-nat sets up iptables OUTPUT chain REDIRECT to ss-redir # - curl through the transparent proxy verifies the full chain # # Usage: bash tests/test_redir_qemu.sh [BIN_DIR] # BIN_DIR: directory containing ss-server and ss-redir binaries # (default: build/shared/bin/) # # Requirements (Linux only): # - qemu-system-x86_64 # - Internet access (for Alpine download and curl test targets) # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" BIN_DIR="${1:-$PROJECT_DIR/build/shared/bin}" # Resolve to absolute path BIN_DIR="$(cd "$BIN_DIR" && pwd)" WORK_DIR="" SS_SERVER_PID="" QEMU_PID="" ALPINE_VERSION="3.21" ALPINE_ARCH="x86_64" ALPINE_MIRROR="https://dl-cdn.alpinelinux.org/alpine" ALPINE_MINIROOTFS="alpine-minirootfs-${ALPINE_VERSION}.0-${ALPINE_ARCH}.tar.gz" ALPINE_URL="${ALPINE_MIRROR}/v${ALPINE_VERSION}/releases/${ALPINE_ARCH}/${ALPINE_MINIROOTFS}" TIMEOUT=240 SS_SERVER_PORT=8389 SS_PASSWORD="test_redir_password" SS_METHOD="aes-256-gcm" # --- helpers ---------------------------------------------------------------- log() { echo "=== [test_redir_qemu] $* ===" } die() { echo "FATAL: $*" >&2 exit 1 } cleanup() { log "Cleaning up" if [ -n "$SS_SERVER_PID" ] && kill -0 "$SS_SERVER_PID" 2>/dev/null; then kill "$SS_SERVER_PID" 2>/dev/null || true wait "$SS_SERVER_PID" 2>/dev/null || true fi if [ -n "$QEMU_PID" ] && kill -0 "$QEMU_PID" 2>/dev/null; then kill "$QEMU_PID" 2>/dev/null || true wait "$QEMU_PID" 2>/dev/null || true fi if [ -n "$WORK_DIR" ] && [ -d "$WORK_DIR" ]; then sudo rm -rf "$WORK_DIR" fi } trap cleanup EXIT # --- pre-flight checks ------------------------------------------------------ if [ "$(uname -s)" != "Linux" ]; then die "This test requires Linux (iptables, QEMU)" fi if ! command -v qemu-system-x86_64 >/dev/null 2>&1; then die "qemu-system-x86_64 not found. Install with: sudo apt-get install qemu-system-x86" fi if [ ! -x "$BIN_DIR/ss-server" ]; then die "ss-server not found at $BIN_DIR/ss-server" fi if [ ! -x "$BIN_DIR/ss-redir" ]; then die "ss-redir not found at $BIN_DIR/ss-redir" fi # --- create work directory -------------------------------------------------- WORK_DIR="$(mktemp -d /tmp/ss-redir-test.XXXXXX)" log "Work directory: $WORK_DIR" # --- phase 1: collect ss-redir and its shared library dependencies ---------- log "Collecting ss-redir shared library dependencies" # Copy ss-redir binary SYSROOT="$WORK_DIR/sysroot" mkdir -p "$SYSROOT/usr/bin" cp "$BIN_DIR/ss-redir" "$SYSROOT/usr/bin/ss-redir" # Copy all shared library dependencies (including the dynamic linker) ldd "$BIN_DIR/ss-redir" | while read -r line; do # Parse lines like: libev.so.4 => /lib/x86_64-linux-gnu/libev.so.4 (0x...) # or: /lib64/ld-linux-x86-64.so.2 (0x...) lib_path="" if echo "$line" | grep -q "=>"; then lib_path=$(echo "$line" | awk '{print $3}') elif echo "$line" | grep -qE "^\s*/"; then lib_path=$(echo "$line" | awk '{print $1}') fi if [ -n "$lib_path" ] && [ -f "$lib_path" ]; then dest="$SYSROOT$lib_path" mkdir -p "$(dirname "$dest")" cp "$lib_path" "$dest" fi done log "Shared libraries collected into sysroot" # --- phase 2: assemble Alpine rootfs ---------------------------------------- log "Downloading Alpine minirootfs" ROOTFS="$WORK_DIR/rootfs" mkdir -p "$ROOTFS" curl -sSL "$ALPINE_URL" -o "$WORK_DIR/$ALPINE_MINIROOTFS" sudo tar xzf "$WORK_DIR/$ALPINE_MINIROOTFS" -C "$ROOTFS" log "Installing packages in Alpine rootfs" # Set up DNS for chroot sudo cp /etc/resolv.conf "$ROOTFS/etc/resolv.conf" # Mount necessary filesystems for chroot sudo mount --bind /dev "$ROOTFS/dev" sudo mount --bind /proc "$ROOTFS/proc" sudo mount --bind /sys "$ROOTFS/sys" # Install packages inside chroot sudo chroot "$ROOTFS" /sbin/apk add --no-cache \ iptables ipset curl iproute2 kmod bash linux-virt # Unmount after package installation sudo umount "$ROOTFS/sys" 2>/dev/null || true sudo umount "$ROOTFS/proc" 2>/dev/null || true sudo umount "$ROOTFS/dev" 2>/dev/null || true # Extract kernel VMLINUZ=$(find "$ROOTFS/boot" -name 'vmlinuz-*' -type f | head -1) if [ -z "$VMLINUZ" ]; then die "No vmlinuz found in Alpine rootfs" fi cp "$VMLINUZ" "$WORK_DIR/vmlinuz" log "Kernel: $(basename "$VMLINUZ")" # --- phase 3: inject artifacts into rootfs ---------------------------------- log "Injecting test artifacts into rootfs" # ss-redir binary and its glibc shared library dependencies # These go into the rootfs at their original absolute paths so the # ELF dynamic linker (PT_INTERP) can find everything. sudo cp -a "$SYSROOT/." "$ROOTFS/" # ss-nat script sudo cp "$PROJECT_DIR/src/ss-nat" "$ROOTFS/usr/bin/ss-nat" sudo chmod 755 "$ROOTFS/usr/bin/ss-nat" # Config file sudo cp "$SCRIPT_DIR/redir.json" "$ROOTFS/etc/ss-redir.json" # Guest init script (becomes PID 1) sudo cp "$SCRIPT_DIR/qemu/guest-init.sh" "$ROOTFS/init" sudo chmod 755 "$ROOTFS/init" # --- phase 4: pack initramfs ----------------------------------------------- log "Packing initramfs" (cd "$ROOTFS" && sudo find . | sudo cpio -o -H newc 2>/dev/null | gzip -1 > "$WORK_DIR/initramfs.gz") log "Initramfs size: $(du -h "$WORK_DIR/initramfs.gz" | cut -f1)" # --- phase 5: start ss-server on host -------------------------------------- log "Starting ss-server on host" "$BIN_DIR/ss-server" \ -s 0.0.0.0 \ -p "$SS_SERVER_PORT" \ -k "$SS_PASSWORD" \ -m "$SS_METHOD" \ -v & SS_SERVER_PID=$! sleep 2 if ! kill -0 "$SS_SERVER_PID" 2>/dev/null; then die "ss-server failed to start" fi log "ss-server running (PID $SS_SERVER_PID)" # --- phase 6: boot QEMU ---------------------------------------------------- log "Booting QEMU" KVM_FLAG="" if [ -e /dev/kvm ] && [ -r /dev/kvm ] && [ -w /dev/kvm ]; then KVM_FLAG="-enable-kvm" log "KVM acceleration available" else log "KVM not available, using TCG (slower)" fi SERIAL_LOG="$WORK_DIR/serial.log" qemu-system-x86_64 \ $KVM_FLAG \ -m 512 \ -kernel "$WORK_DIR/vmlinuz" \ -initrd "$WORK_DIR/initramfs.gz" \ -append "console=ttyS0 init=/init panic=1" \ -nographic \ -serial "file:$SERIAL_LOG" \ -monitor none \ -net nic,model=virtio \ -net user \ -no-reboot & QEMU_PID=$! log "QEMU running (PID $QEMU_PID)" # --- phase 7: monitor serial log ------------------------------------------- log "Waiting for test result (timeout: ${TIMEOUT}s)" ELAPSED=0 POLL_INTERVAL=2 RESULT="" while [ $ELAPSED -lt $TIMEOUT ]; do if [ -f "$SERIAL_LOG" ]; then if grep -q "REDIR_TEST_PASS" "$SERIAL_LOG" 2>/dev/null; then RESULT="PASS" break fi if grep -q "REDIR_TEST_FAIL" "$SERIAL_LOG" 2>/dev/null; then RESULT="FAIL" break fi fi # Check if QEMU is still running if ! kill -0 "$QEMU_PID" 2>/dev/null; then RESULT="QEMU_DIED" break fi sleep $POLL_INTERVAL ELAPSED=$((ELAPSED + POLL_INTERVAL)) done # --- phase 8: report ------------------------------------------------------- echo "" echo "============================================================" echo "Serial console output:" echo "============================================================" if [ -f "$SERIAL_LOG" ]; then cat "$SERIAL_LOG" else echo "(no serial log file)" fi echo "============================================================" echo "" case "$RESULT" in PASS) log "TEST PASSED" exit 0 ;; FAIL) FAIL_MSG=$(grep "REDIR_TEST_FAIL" "$SERIAL_LOG" 2>/dev/null || echo "unknown") log "TEST FAILED: $FAIL_MSG" exit 1 ;; QEMU_DIED) log "TEST FAILED: QEMU exited unexpectedly" exit 1 ;; *) log "TEST FAILED: timeout after ${TIMEOUT}s" # Kill QEMU if still running if kill -0 "$QEMU_PID" 2>/dev/null; then kill "$QEMU_PID" 2>/dev/null || true fi exit 1 ;; esac ================================================ FILE: tests/test_rule.c ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include int verbose = 0; #include "rule.h" #include "utils.h" static void test_new_rule(void) { rule_t *rule = new_rule(); assert(rule != NULL); assert(rule->pattern == NULL); assert(rule->pattern_re == NULL); free(rule); } static void test_accept_rule_arg(void) { rule_t *rule = new_rule(); assert(rule != NULL); int ret = accept_rule_arg(rule, "^example\\.com$"); assert(ret == 1); assert(rule->pattern != NULL); assert(strcmp(rule->pattern, "^example\\.com$") == 0); /* Second call should fail - pattern already set */ ret = accept_rule_arg(rule, "another"); assert(ret == -1); (void)ret; free(rule->pattern); free(rule); } static void test_init_rule(void) { rule_t *rule = new_rule(); accept_rule_arg(rule, "^test.*$"); int ret = init_rule(rule); assert(ret == 1); (void)ret; assert(rule->pattern_re != NULL); if (rule->match_data) pcre2_match_data_free(rule->match_data); if (rule->pattern_re) pcre2_code_free(rule->pattern_re); free(rule->pattern); free(rule); } static void test_init_rule_invalid(void) { rule_t *rule = new_rule(); accept_rule_arg(rule, "[invalid"); /* Unclosed bracket */ int ret = init_rule(rule); assert(ret == 0); /* Should fail */ (void)ret; free(rule->pattern); free(rule); } static void test_lookup_rule(void) { struct cork_dllist rules; cork_dllist_init(&rules); rule_t *rule1 = new_rule(); accept_rule_arg(rule1, "^google\\.com$"); init_rule(rule1); add_rule(&rules, rule1); rule_t *rule2 = new_rule(); accept_rule_arg(rule2, ".*\\.example\\.com$"); init_rule(rule2); add_rule(&rules, rule2); /* Should match rule1 */ rule_t *found = lookup_rule(&rules, "google.com", 10); assert(found == rule1); /* Should match rule2 */ found = lookup_rule(&rules, "sub.example.com", 15); assert(found == rule2); /* Should not match */ found = lookup_rule(&rules, "other.net", 9); assert(found == NULL); (void)found; /* Clean up */ if (rule1->match_data) pcre2_match_data_free(rule1->match_data); if (rule1->pattern_re) pcre2_code_free(rule1->pattern_re); free(rule1->pattern); free(rule1); if (rule2->match_data) pcre2_match_data_free(rule2->match_data); if (rule2->pattern_re) pcre2_code_free(rule2->pattern_re); free(rule2->pattern); free(rule2); } int main(void) { test_new_rule(); test_accept_rule_arg(); test_init_rule(); test_init_rule_invalid(); test_lookup_rule(); return 0; } ================================================ FILE: tests/test_ss_setup.sh ================================================ #!/usr/bin/env bash ############################################################################### # test_ss_setup.sh -- Unit tests for ss-setup.sh utility functions # # Sources ss-setup.sh (which skips main() due to BASH_SOURCE guard) and # exercises every pure/utility function that doesn't require a TUI backend. ############################################################################### set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" SS_SETUP="${PROJECT_ROOT}/scripts/ss-setup.sh" PASS=0 FAIL=0 TMPDIR_TEST="" cleanup_test() { if [[ -n "$TMPDIR_TEST" && -d "$TMPDIR_TEST" ]]; then rm -rf "$TMPDIR_TEST" fi } trap cleanup_test EXIT TMPDIR_TEST=$(mktemp -d) # Source the script under test (main() won't run due to BASH_SOURCE guard) # shellcheck source=../scripts/ss-setup.sh source "$SS_SETUP" ############################################################################### # Test helpers ############################################################################### assert_eq() { local test_name="$1" expected="$2" actual="$3" if [[ "$expected" == "$actual" ]]; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) echo "FAIL: ${test_name}" >&2 echo " expected: '${expected}'" >&2 echo " actual: '${actual}'" >&2 fi } assert_match() { local test_name="$1" pattern="$2" actual="$3" if [[ "$actual" =~ $pattern ]]; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) echo "FAIL: ${test_name}" >&2 echo " expected match: '${pattern}'" >&2 echo " actual: '${actual}'" >&2 fi } assert_ok() { local test_name="$1" shift if "$@" 2>/dev/null; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) echo "FAIL: ${test_name} (command returned non-zero)" >&2 fi } assert_fail() { local test_name="$1" shift if "$@" 2>/dev/null; then FAIL=$((FAIL + 1)) echo "FAIL: ${test_name} (expected failure but got success)" >&2 else PASS=$((PASS + 1)) fi } assert_contains() { local test_name="$1" needle="$2" haystack="$3" if [[ "$haystack" == *"$needle"* ]]; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) echo "FAIL: ${test_name}" >&2 echo " expected to contain: '${needle}'" >&2 echo " actual: '${haystack}'" >&2 fi } assert_not_contains() { local test_name="$1" needle="$2" haystack="$3" if [[ "$haystack" != *"$needle"* ]]; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) echo "FAIL: ${test_name}" >&2 echo " expected NOT to contain: '${needle}'" >&2 echo " actual: '${haystack}'" >&2 fi } ############################################################################### # Tests: AEAD_CIPHERS constant ############################################################################### test_aead_ciphers_count() { assert_eq "AEAD_CIPHERS has 5 entries" "5" "${#AEAD_CIPHERS[@]}" } test_aead_ciphers_contains_chacha20() { local found=0 for c in "${AEAD_CIPHERS[@]}"; do [[ "$c" == "chacha20-ietf-poly1305" ]] && found=1 done assert_eq "AEAD_CIPHERS contains chacha20-ietf-poly1305" "1" "$found" } test_aead_ciphers_contains_aes256gcm() { local found=0 for c in "${AEAD_CIPHERS[@]}"; do [[ "$c" == "aes-256-gcm" ]] && found=1 done assert_eq "AEAD_CIPHERS contains aes-256-gcm" "1" "$found" } test_aead_ciphers_contains_aes128gcm() { local found=0 for c in "${AEAD_CIPHERS[@]}"; do [[ "$c" == "aes-128-gcm" ]] && found=1 done assert_eq "AEAD_CIPHERS contains aes-128-gcm" "1" "$found" } ############################################################################### # Tests: validate_port ############################################################################### test_validate_port_valid() { assert_ok "validate_port 1" validate_port "1" assert_ok "validate_port 80" validate_port "80" assert_ok "validate_port 443" validate_port "443" assert_ok "validate_port 8388" validate_port "8388" assert_ok "validate_port 65535" validate_port "65535" } test_validate_port_invalid() { assert_fail "validate_port 0" validate_port "0" assert_fail "validate_port 65536" validate_port "65536" assert_fail "validate_port -1" validate_port "-1" assert_fail "validate_port abc" validate_port "abc" assert_fail "validate_port empty" validate_port "" assert_fail "validate_port 99999" validate_port "99999" assert_fail "validate_port 8.8" validate_port "8.8" } ############################################################################### # Tests: validate_instance_name ############################################################################### test_validate_instance_name_valid() { assert_ok "instance: config" validate_instance_name "config" assert_ok "instance: my-server" validate_instance_name "my-server" assert_ok "instance: server_1" validate_instance_name "server_1" assert_ok "instance: Test123" validate_instance_name "Test123" assert_ok "instance: a" validate_instance_name "a" assert_ok "instance: A-B_c-1" validate_instance_name "A-B_c-1" } test_validate_instance_name_invalid() { assert_fail "instance: empty" validate_instance_name "" assert_fail "instance: has space" validate_instance_name "has space" assert_fail "instance: has.dot" validate_instance_name "has.dot" assert_fail "instance: has/slash" validate_instance_name "has/slash" assert_fail "instance: has@at" validate_instance_name "has@at" assert_fail "instance: has:colon" validate_instance_name "has:colon" } ############################################################################### # Tests: generate_password ############################################################################### test_generate_password_nonempty() { local pw pw=$(generate_password 32) assert_match "password is non-empty" ".+" "$pw" } test_generate_password_length() { # base64 of 16 bytes = 24 chars (before newline strip) local pw pw=$(generate_password 16) # Should be at least 20 chars (base64 encoding of 16 bytes) local len=${#pw} if (( len >= 20 )); then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) echo "FAIL: password length too short: ${len} chars" >&2 fi } test_generate_password_no_newlines() { local pw pw=$(generate_password 32) assert_not_contains "password has no newline" $'\n' "$pw" } test_generate_password_different() { local pw1 pw2 pw1=$(generate_password 32) pw2=$(generate_password 32) if [[ "$pw1" != "$pw2" ]]; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) echo "FAIL: two passwords are identical: '${pw1}'" >&2 fi } ############################################################################### # Tests: generate_random_port ############################################################################### test_generate_random_port_range() { local port for _ in $(seq 1 10); do port=$(generate_random_port) if (( port >= 10000 && port <= 65000 )); then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) echo "FAIL: random port ${port} out of range 10000-65000" >&2 fi done } test_generate_random_port_numeric() { local port port=$(generate_random_port) assert_match "random port is numeric" "^[0-9]+$" "$port" } ############################################################################### # Tests: json_escape ############################################################################### test_json_escape_plain() { local result result=$(json_escape "hello world") assert_eq "json_escape plain" "hello world" "$result" } test_json_escape_quotes() { local result result=$(json_escape 'say "hi"') assert_eq "json_escape quotes" 'say \"hi\"' "$result" } test_json_escape_backslash() { local result result=$(json_escape 'path\to\file') assert_eq "json_escape backslash" 'path\\to\\file' "$result" } test_json_escape_tab() { local result result=$(json_escape "col1 col2") assert_eq "json_escape tab" 'col1\tcol2' "$result" } test_json_escape_newline() { local result result=$(json_escape "line1 line2") assert_eq "json_escape newline" 'line1\nline2' "$result" } test_json_escape_empty() { local result result=$(json_escape "") assert_eq "json_escape empty" "" "$result" } ############################################################################### # Tests: urlencode ############################################################################### test_urlencode_plain() { local result result=$(urlencode "hello") assert_eq "urlencode plain" "hello" "$result" } test_urlencode_space() { local result result=$(urlencode "hello world") assert_eq "urlencode space" "hello%20world" "$result" } test_urlencode_special() { local result result=$(urlencode "a=b&c=d") assert_eq "urlencode special" "a%3Db%26c%3Dd" "$result" } test_urlencode_semicolon() { local result result=$(urlencode "obfs-local;obfs=http") assert_eq "urlencode semicolon" "obfs-local%3Bobfs%3Dhttp" "$result" } test_urlencode_safe_chars() { local result result=$(urlencode "a-b_c.d~e") assert_eq "urlencode safe chars" "a-b_c.d~e" "$result" } test_urlencode_empty() { local result result=$(urlencode "") assert_eq "urlencode empty" "" "$result" } ############################################################################### # Tests: generate_ss_uri ############################################################################### test_ss_uri_basic() { local uri uri=$(generate_ss_uri "aes-256-gcm" "testpass" "1.2.3.4" "8388" "" "") # Should start with ss:// assert_match "ss uri starts with ss://" "^ss://" "$uri" # Should contain @host:port assert_contains "ss uri has host:port" "@1.2.3.4:8388" "$uri" # Should NOT have plugin query assert_not_contains "ss uri no plugin query" "/?plugin=" "$uri" } test_ss_uri_with_plugin() { local uri uri=$(generate_ss_uri "chacha20-ietf-poly1305" "mypass" "example.com" "443" "v2ray-plugin" "server;tls;host=example.com") assert_match "ss uri+plugin starts with ss://" "^ss://" "$uri" assert_contains "ss uri+plugin has host:port" "@example.com:443" "$uri" assert_contains "ss uri+plugin has plugin param" "/?plugin=" "$uri" # v2ray-plugin should be URL-encoded with the opts assert_contains "ss uri+plugin has v2ray" "v2ray-plugin" "$uri" } test_ss_uri_with_plugin_no_opts() { local uri uri=$(generate_ss_uri "aes-128-gcm" "pw" "10.0.0.1" "9000" "obfs-local" "") assert_contains "ss uri plugin-no-opts has plugin" "/?plugin=" "$uri" assert_contains "ss uri plugin-no-opts has obfs-local" "obfs-local" "$uri" } test_ss_uri_base64_encoding() { # Verify the userinfo part is valid base64url local uri uri=$(generate_ss_uri "aes-256-gcm" "test" "1.2.3.4" "8388" "" "") # Extract the base64 part between ss:// and @ local b64_part b64_part=$(echo "$uri" | sed 's|^ss://\([^@]*\)@.*|\1|') # base64url should only contain [A-Za-z0-9_-] assert_match "ss uri base64url valid chars" "^[A-Za-z0-9_-]+$" "$b64_part" } ############################################################################### # Tests: write_json_config (server) ############################################################################### test_write_json_config_basic() { local outfile="${TMPDIR_TEST}/server_basic.json" CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="8388" CFG_PASSWORD="testpassword123" CFG_TIMEOUT="300" CFG_METHOD="aes-256-gcm" CFG_MODE="tcp_and_udp" CFG_FAST_OPEN="false" CFG_PLUGIN="" CFG_PLUGIN_OPTS="" write_json_config "$outfile" local content content=$(cat "$outfile") assert_contains "server json has server" '"server": "0.0.0.0"' "$content" assert_contains "server json has port" '"server_port": 8388' "$content" assert_contains "server json has password" '"password": "testpassword123"' "$content" assert_contains "server json has timeout" '"timeout": 300' "$content" assert_contains "server json has method" '"method": "aes-256-gcm"' "$content" assert_contains "server json has mode" '"mode": "tcp_and_udp"' "$content" assert_contains "server json has fast_open false" '"fast_open": false' "$content" assert_not_contains "server json no plugin" '"plugin"' "$content" # No trailing comma before closing brace assert_not_contains "server json no trailing comma" ', }' "$content" } test_write_json_config_fast_open_true() { local outfile="${TMPDIR_TEST}/server_tfo.json" CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="443" CFG_PASSWORD="pw" CFG_TIMEOUT="60" CFG_METHOD="chacha20-ietf-poly1305" CFG_MODE="tcp_only" CFG_FAST_OPEN="true" CFG_PLUGIN="" CFG_PLUGIN_OPTS="" write_json_config "$outfile" local content content=$(cat "$outfile") assert_contains "server json fast_open true" '"fast_open": true' "$content" assert_not_contains "server json fast_open not quoted" '"fast_open": "true"' "$content" } test_write_json_config_with_plugin() { local outfile="${TMPDIR_TEST}/server_plugin.json" CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="443" CFG_PASSWORD="pw" CFG_TIMEOUT="300" CFG_METHOD="aes-256-gcm" CFG_MODE="tcp_and_udp" CFG_FAST_OPEN="false" CFG_PLUGIN="v2ray-plugin" CFG_PLUGIN_OPTS="server;tls;host=example.com" write_json_config "$outfile" local content content=$(cat "$outfile") assert_contains "server json has plugin" '"plugin": "v2ray-plugin"' "$content" assert_contains "server json has plugin_opts" '"plugin_opts": "server;tls;host=example.com"' "$content" } test_write_json_config_with_plugin_no_opts() { local outfile="${TMPDIR_TEST}/server_plugin_noopts.json" CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="8388" CFG_PASSWORD="pw" CFG_TIMEOUT="300" CFG_METHOD="aes-256-gcm" CFG_MODE="tcp_and_udp" CFG_FAST_OPEN="false" CFG_PLUGIN="obfs-local" CFG_PLUGIN_OPTS="" write_json_config "$outfile" local content content=$(cat "$outfile") assert_contains "server json plugin no opts has plugin" '"plugin": "obfs-local"' "$content" assert_not_contains "server json plugin no opts has no plugin_opts" '"plugin_opts"' "$content" } test_write_json_config_password_special_chars() { local outfile="${TMPDIR_TEST}/server_special.json" CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="8388" CFG_PASSWORD='pass"word\with/special' CFG_TIMEOUT="300" CFG_METHOD="aes-256-gcm" CFG_MODE="tcp_and_udp" CFG_FAST_OPEN="false" CFG_PLUGIN="" CFG_PLUGIN_OPTS="" write_json_config "$outfile" local content content=$(cat "$outfile") # Quotes and backslashes should be escaped assert_contains "special password escaped quote" '\"' "$content" assert_contains "special password escaped backslash" '\\' "$content" } ############################################################################### # Tests: write_client_json_config ############################################################################### test_write_client_json_config_basic() { local outfile="${TMPDIR_TEST}/client_basic.json" CFG_CLIENT_SERVER="1.2.3.4" CFG_CLIENT_SERVER_PORT="8388" CFG_CLIENT_LOCAL_PORT="1080" CFG_CLIENT_PASSWORD="clientpw" CFG_CLIENT_METHOD="aes-256-gcm" CFG_CLIENT_PLUGIN="" CFG_CLIENT_PLUGIN_OPTS="" write_client_json_config "$outfile" local content content=$(cat "$outfile") assert_contains "client json has server" '"server": "1.2.3.4"' "$content" assert_contains "client json has server_port" '"server_port": 8388' "$content" assert_contains "client json has local_address" '"local_address": "127.0.0.1"' "$content" assert_contains "client json has local_port" '"local_port": 1080' "$content" assert_contains "client json has password" '"password": "clientpw"' "$content" assert_contains "client json has method" '"method": "aes-256-gcm"' "$content" assert_contains "client json has timeout" '"timeout": 300' "$content" assert_contains "client json has mode" '"mode": "tcp_and_udp"' "$content" assert_not_contains "client json no plugin" '"plugin"' "$content" } test_write_client_json_config_with_plugin() { local outfile="${TMPDIR_TEST}/client_plugin.json" CFG_CLIENT_SERVER="example.com" CFG_CLIENT_SERVER_PORT="443" CFG_CLIENT_LOCAL_PORT="1080" CFG_CLIENT_PASSWORD="pw" CFG_CLIENT_METHOD="chacha20-ietf-poly1305" CFG_CLIENT_PLUGIN="v2ray-plugin" CFG_CLIENT_PLUGIN_OPTS="tls;host=example.com" write_client_json_config "$outfile" local content content=$(cat "$outfile") assert_contains "client json plugin" '"plugin": "v2ray-plugin"' "$content" assert_contains "client json plugin_opts" '"plugin_opts": "tls;host=example.com"' "$content" } ############################################################################### # Tests: parse_existing_config (round-trip) ############################################################################### test_parse_existing_config_roundtrip() { local outfile="${TMPDIR_TEST}/roundtrip.json" # Set known values CFG_SERVER="10.20.30.40" CFG_SERVER_PORT="9999" CFG_PASSWORD="roundtrip_pw" CFG_TIMEOUT="600" CFG_METHOD="aes-128-gcm" CFG_MODE="udp_only" CFG_FAST_OPEN="true" CFG_PLUGIN="obfs-local" CFG_PLUGIN_OPTS="obfs=http;obfs-host=example.com" write_json_config "$outfile" # Reset globals CFG_SERVER="" CFG_SERVER_PORT="" CFG_PASSWORD="" CFG_TIMEOUT="" CFG_METHOD="" CFG_MODE="" CFG_FAST_OPEN="" CFG_PLUGIN="" CFG_PLUGIN_OPTS="" # Parse back parse_existing_config "$outfile" assert_eq "roundtrip server" "10.20.30.40" "$CFG_SERVER" assert_eq "roundtrip port" "9999" "$CFG_SERVER_PORT" assert_eq "roundtrip password" "roundtrip_pw" "$CFG_PASSWORD" assert_eq "roundtrip timeout" "600" "$CFG_TIMEOUT" assert_eq "roundtrip method" "aes-128-gcm" "$CFG_METHOD" assert_eq "roundtrip mode" "udp_only" "$CFG_MODE" assert_eq "roundtrip fast_open" "true" "$CFG_FAST_OPEN" assert_eq "roundtrip plugin" "obfs-local" "$CFG_PLUGIN" assert_eq "roundtrip plugin_opts" "obfs=http;obfs-host=example.com" "$CFG_PLUGIN_OPTS" } test_parse_existing_config_no_plugin() { local outfile="${TMPDIR_TEST}/roundtrip_noplugin.json" CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="8388" CFG_PASSWORD="simplepw" CFG_TIMEOUT="300" CFG_METHOD="aes-256-gcm" CFG_MODE="tcp_and_udp" CFG_FAST_OPEN="false" CFG_PLUGIN="" CFG_PLUGIN_OPTS="" write_json_config "$outfile" # Reset and parse CFG_SERVER="" CFG_SERVER_PORT="" CFG_PASSWORD="" CFG_METHOD="" CFG_MODE="" CFG_PLUGIN="should_be_cleared_if_found" parse_existing_config "$outfile" assert_eq "roundtrip-noplugin server" "0.0.0.0" "$CFG_SERVER" assert_eq "roundtrip-noplugin port" "8388" "$CFG_SERVER_PORT" assert_eq "roundtrip-noplugin password" "simplepw" "$CFG_PASSWORD" assert_eq "roundtrip-noplugin method" "aes-256-gcm" "$CFG_METHOD" assert_eq "roundtrip-noplugin mode" "tcp_and_udp" "$CFG_MODE" } ############################################################################### # Tests: detect_os ############################################################################### test_detect_os() { local os os=$(detect_os) # Should be one of the known values assert_match "detect_os returns known value" "^(linux|darwin|freebsd|openbsd|netbsd)$" "$os" } ############################################################################### # Tests: detect_arch ############################################################################### test_detect_arch() { local arch arch=$(detect_arch) # Should be one of the known mapped values or raw uname -m assert_match "detect_arch returns a value" ".+" "$arch" } ############################################################################### # Tests: KNOWN_PLUGINS constant ############################################################################### test_known_plugins_count() { assert_eq "KNOWN_PLUGINS has 4 entries" "4" "${#KNOWN_PLUGINS[@]}" } test_known_plugins_entries() { local found_simpleobfs=0 found_v2ray=0 found_xray=0 found_kcptun=0 for p in "${KNOWN_PLUGINS[@]}"; do case "$p" in simple-obfs) found_simpleobfs=1 ;; v2ray-plugin) found_v2ray=1 ;; xray-plugin) found_xray=1 ;; kcptun) found_kcptun=1 ;; esac done assert_eq "KNOWN_PLUGINS has simple-obfs" "1" "$found_simpleobfs" assert_eq "KNOWN_PLUGINS has v2ray-plugin" "1" "$found_v2ray" assert_eq "KNOWN_PLUGINS has xray-plugin" "1" "$found_xray" assert_eq "KNOWN_PLUGINS has kcptun" "1" "$found_kcptun" } ############################################################################### # Tests: plugin_repo function ############################################################################### test_plugin_repos() { assert_eq "plugin_repo simple-obfs" "shadowsocks/simple-obfs" "$(plugin_repo simple-obfs)" assert_eq "plugin_repo v2ray-plugin" "shadowsocks/v2ray-plugin" "$(plugin_repo v2ray-plugin)" assert_eq "plugin_repo xray-plugin" "teddysun/xray-plugin" "$(plugin_repo xray-plugin)" assert_eq "plugin_repo kcptun" "xtaci/kcptun" "$(plugin_repo kcptun)" assert_eq "plugin_repo unknown" "" "$(plugin_repo unknown)" } ############################################################################### # Tests: SS_SETUP_VERSION ############################################################################### test_version_set() { assert_match "SS_SETUP_VERSION is semver" "^[0-9]+\.[0-9]+\.[0-9]+$" "$SS_SETUP_VERSION" } ############################################################################### # Tests: Config directory constant ############################################################################### test_config_dir() { assert_eq "CONFIG_DIR" "/etc/shadowsocks-libev" "$CONFIG_DIR" } ############################################################################### # Tests: JSON output is valid (no trailing commas, booleans unquoted) ############################################################################### test_json_no_trailing_comma() { local outfile="${TMPDIR_TEST}/no_trailing.json" CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="8388" CFG_PASSWORD="pw" CFG_TIMEOUT="300" CFG_METHOD="aes-256-gcm" CFG_MODE="tcp_and_udp" CFG_FAST_OPEN="false" CFG_PLUGIN="" CFG_PLUGIN_OPTS="" write_json_config "$outfile" # Check that the file doesn't have ",\n}" pattern (trailing comma) if grep -qP ',\s*\}' "$outfile" 2>/dev/null || grep -q ',$' "$outfile" 2>/dev/null; then # Try a more portable check local last_data_line last_data_line=$(grep -v '^[[:space:]]*[{}]' "$outfile" | tail -1) if [[ "$last_data_line" == *"," ]]; then FAIL=$((FAIL + 1)) echo "FAIL: JSON has trailing comma on last data line: ${last_data_line}" >&2 else PASS=$((PASS + 1)) fi else PASS=$((PASS + 1)) fi } test_json_booleans_unquoted() { local outfile="${TMPDIR_TEST}/bool_check.json" CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="8388" CFG_PASSWORD="pw" CFG_TIMEOUT="300" CFG_METHOD="aes-256-gcm" CFG_MODE="tcp_and_udp" CFG_FAST_OPEN="true" CFG_PLUGIN="" CFG_PLUGIN_OPTS="" write_json_config "$outfile" local content content=$(cat "$outfile") assert_not_contains "boolean not quoted string" '"fast_open": "true"' "$content" assert_contains "boolean is unquoted true" '"fast_open": true' "$content" } test_json_integers_unquoted() { local outfile="${TMPDIR_TEST}/int_check.json" CFG_SERVER="0.0.0.0" CFG_SERVER_PORT="8388" CFG_PASSWORD="pw" CFG_TIMEOUT="300" CFG_METHOD="aes-256-gcm" CFG_MODE="tcp_and_udp" CFG_FAST_OPEN="false" CFG_PLUGIN="" CFG_PLUGIN_OPTS="" write_json_config "$outfile" local content content=$(cat "$outfile") assert_contains "server_port is unquoted int" '"server_port": 8388' "$content" assert_not_contains "server_port not quoted string" '"server_port": "8388"' "$content" assert_contains "timeout is unquoted int" '"timeout": 300' "$content" assert_not_contains "timeout not quoted string" '"timeout": "300"' "$content" } ############################################################################### # Tests: Client JSON integers unquoted ############################################################################### test_client_json_integers_unquoted() { local outfile="${TMPDIR_TEST}/client_int_check.json" CFG_CLIENT_SERVER="1.2.3.4" CFG_CLIENT_SERVER_PORT="443" CFG_CLIENT_LOCAL_PORT="1080" CFG_CLIENT_PASSWORD="pw" CFG_CLIENT_METHOD="aes-256-gcm" CFG_CLIENT_PLUGIN="" CFG_CLIENT_PLUGIN_OPTS="" write_client_json_config "$outfile" local content content=$(cat "$outfile") assert_contains "client server_port unquoted" '"server_port": 443' "$content" assert_contains "client local_port unquoted" '"local_port": 1080' "$content" assert_contains "client timeout unquoted" '"timeout": 300' "$content" } ############################################################################### # Run all tests ############################################################################### echo "Running ss-setup unit tests..." echo # Constants test_aead_ciphers_count test_aead_ciphers_contains_chacha20 test_aead_ciphers_contains_aes256gcm test_aead_ciphers_contains_aes128gcm test_known_plugins_count test_known_plugins_entries test_plugin_repos test_version_set test_config_dir # Validation test_validate_port_valid test_validate_port_invalid test_validate_instance_name_valid test_validate_instance_name_invalid # Password generation test_generate_password_nonempty test_generate_password_length test_generate_password_no_newlines test_generate_password_different # Random port test_generate_random_port_range test_generate_random_port_numeric # JSON escaping test_json_escape_plain test_json_escape_quotes test_json_escape_backslash test_json_escape_tab test_json_escape_newline test_json_escape_empty # URL encoding test_urlencode_plain test_urlencode_space test_urlencode_special test_urlencode_semicolon test_urlencode_safe_chars test_urlencode_empty # ss:// URI test_ss_uri_basic test_ss_uri_with_plugin test_ss_uri_with_plugin_no_opts test_ss_uri_base64_encoding # Server JSON config test_write_json_config_basic test_write_json_config_fast_open_true test_write_json_config_with_plugin test_write_json_config_with_plugin_no_opts test_write_json_config_password_special_chars # Client JSON config test_write_client_json_config_basic test_write_client_json_config_with_plugin test_client_json_integers_unquoted # Parse existing config (round-trip) test_parse_existing_config_roundtrip test_parse_existing_config_no_plugin # Platform detection test_detect_os test_detect_arch # JSON validity test_json_no_trailing_comma test_json_booleans_unquoted test_json_integers_unquoted echo echo "=================================" echo "Results: ${PASS} passed, ${FAIL} failed" echo "=================================" if [[ $FAIL -gt 0 ]]; then exit 1 fi exit 0 ================================================ FILE: tests/test_utils.c ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include int verbose = 0; #include "utils.h" static void test_ss_itoa(void) { char *s; s = ss_itoa(0); assert(s != NULL); assert(strcmp(s, "0") == 0); s = ss_itoa(42); assert(s != NULL); assert(strcmp(s, "42") == 0); s = ss_itoa(-1); assert(s != NULL); assert(strcmp(s, "-1") == 0); s = ss_itoa(12345); assert(s != NULL); assert(strcmp(s, "12345") == 0); (void)s; } static void test_ss_isnumeric(void) { assert(ss_isnumeric("12345") == 1); assert(ss_isnumeric("0") == 1); assert(ss_isnumeric("") == 0); assert(ss_isnumeric("abc") == 0); assert(ss_isnumeric("123abc") == 0); assert(ss_isnumeric("12.34") == 0); } static void test_ss_strndup(void) { char *s; s = ss_strndup("hello world", 5); assert(s != NULL); assert(strcmp(s, "hello") == 0); assert(strlen(s) == 5); free(s); s = ss_strndup("short", 10); assert(s != NULL); assert(strcmp(s, "short") == 0); free(s); s = ss_strndup("", 0); assert(s != NULL); assert(strcmp(s, "") == 0); free(s); } int main(void) { test_ss_itoa(); test_ss_isnumeric(); test_ss_strndup(); return 0; }