diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc10dee6..d671e3e9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,51 +2,43 @@ name: build on: push: - push: - branches: - - master - tags: - - v* - - latest + branches: [master] + pull_request: + branches: [master] jobs: build: - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2.3.4 + - uses: actions/checkout@v4 with: - submodules: true + submodules: recursive - - uses: docker/setup-qemu-action@v1.1.0 - - uses: docker/setup-buildx-action@v1.3.0 - - uses: docker/login-action@v1.9.0 - with: - password: ${{ secrets.DOCKER_PASSWORD }} - username: ${{ secrets.DOCKER_USERNAME }} - - - name: check and set image version - id: prepare + - name: Install dependencies (Linux) + if: runner.os == 'Linux' run: | - case ${{ github.ref }} in - refs/heads/master) - echo ::set-output name=version::edge - echo ::set-output name=push::true - ;; - refs/tags/*) - echo ::set-output name=version::$(echo ${{ github.ref }} | sed -E 's|refs/tags/||') - echo ::set-output name=push::true - ;; - *) - echo ::set-output name=version::${{ github.sha }} - echo ::set-output name=push::false - ;; - esac; + sudo apt-get update + sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev - - name: build & push image - uses: docker/build-push-action@v2.4.0 - with: - context: . - file: docker/alpine/Dockerfile - platforms: linux/amd64,linux/arm64 - push: ${{ steps.prepare.outputs.push }} - tags: ${{ github.repository }}:${{ steps.prepare.outputs.version }} \ No newline at end of file + - 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: Stress test + run: | + python3 tests/stress_test.py --bin build/shared/bin/ --size 10 diff --git a/.travis.yml b/.travis.yml index ee3424c2..e2ca4429 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ 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 autoconf automake xmlto c-ares libev mbedtls libsodium asciidoc >> /dev/null 2>&1; + 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; @@ -39,19 +39,17 @@ addons: sources: - george-edison55-precise-backports # cmake 3.2.3 / doxygen 1.8.3 packages: + - cmake - libc-ares-dev - libev-dev - asciidoc - xmlto script: - - ./autogen.sh - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - ./configure --disable-documentation --with-mbedtls=/usr/local/opt/mbedtls --with-sodium=/usr/local/opt/libsodium; - else - ./configure; - fi + - git submodule update --init --recursive + - mkdir -p build && cd build + - cmake .. - make - - cd build && cmake ../ && make + - ctest --output-on-failure branches: only: - master diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c1c2d06..6ca505f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set(PROJECT_NAME shadowsocks-libev) set(RELEASE_DATE 2020-09-15) @@ -8,9 +8,14 @@ set(PROJECT_URL "https://shadowsocks.org") set(PROJECT_ISSUES_URL "https://github.com/shadowsocks/shadowsocks-libev") project(${PROJECT_NAME} VERSION ${PROJECT_VERSION}) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") +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(PROJECT_BINARY_DIR ${PROJECT_SOURCE_DIR}/out) 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) @@ -33,15 +38,48 @@ 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) - -# Will set GIT_EXECUTABLE and GIT_FOUND -# find_package(Git) +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) @@ -56,7 +94,7 @@ configure_file( ) install(FILES ${PROJECT_BINARY_DIR}/pkgconfig/shadowsocks-libev.pc - DESTINATION lib/pkgconfig + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) if (WITH_EMBEDDED_SRC) @@ -158,3 +196,13 @@ 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() diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 7d1c323b..00000000 --- a/INSTALL +++ /dev/null @@ -1,365 +0,0 @@ -Installation Instructions -************************* - -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, -2006, 2007, 2008, 2009 Free Software Foundation, Inc. - - Copying and distribution of this file, with or without modification, -are permitted in any medium without royalty provided the copyright -notice and this notice are preserved. This file is offered as-is, -without warranty of any kind. - -Basic Installation -================== - - Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following -more-detailed instructions are generic; see the `README' file for -instructions specific to this package. Some packages provide this -`INSTALL' file but do not implement all of the features documented -below. The lack of an optional feature in a given package is not -necessarily a bug. More recommendations for GNU packages can be found -in *note Makefile Conventions: (standards)Makefile Conventions. - - The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation. It uses -those values to create a `Makefile' in each directory of the package. -It may also create one or more `.h' files containing system-dependent -definitions. Finally, it creates a shell script `config.status' that -you can run in the future to recreate the current configuration, and a -file `config.log' containing compiler output (useful mainly for -debugging `configure'). - - It can also use an optional file (typically called `config.cache' -and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. Caching is -disabled by default to prevent problems with accidental use of stale -cache files. - - If you need to do unusual things to compile the package, please try -to figure out how `configure' could check whether to do them, and mail -diffs or instructions to the address given in the `README' so they can -be considered for the next release. If you are using the cache, and at -some point `config.cache' contains results you don't want to keep, you -may remove or edit it. - - The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You need `configure.ac' if -you want to change it or regenerate `configure' using a newer version -of `autoconf'. - - The simplest way to compile this package is: - - 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. - - Running `configure' might take a while. While running, it prints - some messages telling which features it is checking for. - - 2. Type `make' to compile the package. - - 3. Optionally, type `make check' to run any self-tests that come with - the package, generally using the just-built uninstalled binaries. - - 4. Type `make install' to install the programs and any data files and - documentation. When installing into a prefix owned by root, it is - recommended that the package be configured and built as a regular - user, and only the `make install' phase executed with root - privileges. - - 5. Optionally, type `make installcheck' to repeat any self-tests, but - this time using the binaries in their final installed location. - This target does not install anything. Running this target as a - regular user, particularly if the prior `make install' required - root privileges, verifies that the installation completed - correctly. - - 6. You can remove the program binaries and object files from the - source code directory by typing `make clean'. To also remove the - files that `configure' created (so you can compile the package for - a different kind of computer), type `make distclean'. There is - also a `make maintainer-clean' target, but that is intended mainly - for the package's developers. If you use it, you may have to get - all sorts of other programs in order to regenerate files that came - with the distribution. - - 7. Often, you can also type `make uninstall' to remove the installed - files again. In practice, not all packages have tested that - uninstallation works correctly, even though it is required by the - GNU Coding Standards. - - 8. Some packages, particularly those that use Automake, provide `make - distcheck', which can by used by developers to test that all other - targets like `make install' and `make uninstall' work correctly. - This target is generally not run by end users. - -Compilers and Options -===================== - - Some systems require unusual options for compilation or linking that -the `configure' script does not know about. Run `./configure --help' -for details on some of the pertinent environment variables. - - You can give `configure' initial values for configuration parameters -by setting variables in the command line or in the environment. Here -is an example: - - ./configure CC=c99 CFLAGS=-g LIBS=-lposix - - *Note Defining Variables::, for more details. - -Compiling For Multiple Architectures -==================================== - - You can compile the package for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you can use GNU `make'. `cd' to the -directory where you want the object files and executables to go and run -the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. This -is known as a "VPATH" build. - - With a non-GNU `make', it is safer to compile the package for one -architecture at a time in the source code directory. After you have -installed the package for one architecture, use `make distclean' before -reconfiguring for another architecture. - - On MacOS X 10.5 and later systems, you can create libraries and -executables that work on multiple system types--known as "fat" or -"universal" binaries--by specifying multiple `-arch' options to the -compiler but only a single `-arch' option to the preprocessor. Like -this: - - ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ - CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ - CPP="gcc -E" CXXCPP="g++ -E" - - This is not guaranteed to produce working output in all cases, you -may have to build one architecture at a time and combine the results -using the `lipo' tool if you have problems. - -Installation Names -================== - - By default, `make install' installs the package's commands under -`/usr/local/bin', include files under `/usr/local/include', etc. You -can specify an installation prefix other than `/usr/local' by giving -`configure' the option `--prefix=PREFIX', where PREFIX must be an -absolute file name. - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -pass the option `--exec-prefix=PREFIX' to `configure', the package uses -PREFIX as the prefix for installing programs and libraries. -Documentation and other data files still use the regular prefix. - - In addition, if you use an unusual directory layout you can give -options like `--bindir=DIR' to specify different values for particular -kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. In general, the -default for these options is expressed in terms of `${prefix}', so that -specifying just `--prefix' will affect all of the other directory -specifications that were not explicitly provided. - - The most portable way to affect installation locations is to pass the -correct locations to `configure'; however, many packages provide one or -both of the following shortcuts of passing variable assignments to the -`make install' command line to change installation locations without -having to reconfigure or recompile. - - The first method involves providing an override variable for each -affected directory. For example, `make install -prefix=/alternate/directory' will choose an alternate location for all -directory configuration variables that were expressed in terms of -`${prefix}'. Any directories that were specified during `configure', -but not in terms of `${prefix}', must each be overridden at install -time for the entire installation to be relocated. The approach of -makefile variable overrides for each directory variable is required by -the GNU Coding Standards, and ideally causes no recompilation. -However, some platforms have known limitations with the semantics of -shared libraries that end up requiring recompilation when using this -method, particularly noticeable in packages that use GNU Libtool. - - The second method involves providing the `DESTDIR' variable. For -example, `make install DESTDIR=/alternate/directory' will prepend -`/alternate/directory' before all installation names. The approach of -`DESTDIR' overrides is not required by the GNU Coding Standards, and -does not work on platforms that have drive letters. On the other hand, -it does better at avoiding recompilation issues, and works well even -when some directory options were not specified in terms of `${prefix}' -at `configure' time. - -Optional Features -================= - - If the package supports it, you can cause programs to be installed -with an extra prefix or suffix on their names by giving `configure' the -option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. - - Some packages pay attention to `--enable-FEATURE' options to -`configure', where FEATURE indicates an optional part of the package. -They may also pay attention to `--with-PACKAGE' options, where PACKAGE -is something like `gnu-as' or `x' (for the X Window System). The -`README' should mention any `--enable-' and `--with-' options that the -package recognizes. - - For packages that use the X Window System, `configure' can usually -find the X include and library files automatically, but if it doesn't, -you can use the `configure' options `--x-includes=DIR' and -`--x-libraries=DIR' to specify their locations. - - Some packages offer the ability to configure how verbose the -execution of `make' will be. For these packages, running `./configure ---enable-silent-rules' sets the default to minimal output, which can be -overridden with `make V=1'; while running `./configure ---disable-silent-rules' sets the default to verbose, which can be -overridden with `make V=0'. - -Particular systems -================== - - On HP-UX, the default C compiler is not ANSI C compatible. If GNU -CC is not installed, it is recommended to use the following options in -order to use an ANSI C compiler: - - ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" - -and if that doesn't work, install pre-built binaries of GCC for HP-UX. - - On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot -parse its `' header file. The option `-nodtk' can be used as -a workaround. If GNU CC is not installed, it is therefore recommended -to try - - ./configure CC="cc" - -and if that doesn't work, try - - ./configure CC="cc -nodtk" - - On Solaris, don't put `/usr/ucb' early in your `PATH'. This -directory contains several dysfunctional programs; working variants of -these programs are available in `/usr/bin'. So, if you need `/usr/ucb' -in your `PATH', put it _after_ `/usr/bin'. - - On Haiku, software installed for all users goes in `/boot/common', -not `/usr/local'. It is recommended to use the following options: - - ./configure --prefix=/boot/common - -Specifying the System Type -========================== - - There may be some features `configure' cannot figure out -automatically, but needs to determine by the type of machine the package -will run on. Usually, assuming the package is built to be run on the -_same_ architectures, `configure' can figure that out, but if it prints -a message saying it cannot guess the machine type, give it the -`--build=TYPE' option. TYPE can either be a short name for the system -type, such as `sun4', or a canonical name which has the form: - - CPU-COMPANY-SYSTEM - -where SYSTEM can have one of these forms: - - OS - KERNEL-OS - - See the file `config.sub' for the possible values of each field. If -`config.sub' isn't included in this package, then this package doesn't -need to know the machine type. - - If you are _building_ compiler tools for cross-compiling, you should -use the option `--target=TYPE' to select the type of system they will -produce code for. - - If you want to _use_ a cross compiler, that generates code for a -platform different from the build platform, you should specify the -"host" platform (i.e., that on which the generated programs will -eventually be run) with `--host=TYPE'. - -Sharing Defaults -================ - - If you want to set default values for `configure' scripts to share, -you can create a site shell script called `config.site' that gives -default values for variables like `CC', `cache_file', and `prefix'. -`configure' looks for `PREFIX/share/config.site' if it exists, then -`PREFIX/etc/config.site' if it exists. Or, you can set the -`CONFIG_SITE' environment variable to the location of the site script. -A warning: not all `configure' scripts look for a site script. - -Defining Variables -================== - - Variables not defined in a site shell script can be set in the -environment passed to `configure'. However, some packages may run -configure again during the build, and the customized values of these -variables may be lost. In order to avoid this problem, you should set -them in the `configure' command line, using `VAR=value'. For example: - - ./configure CC=/usr/local2/bin/gcc - -causes the specified `gcc' to be used as the C compiler (unless it is -overridden in the site shell script). - -Unfortunately, this technique does not work for `CONFIG_SHELL' due to -an Autoconf bug. Until the bug is fixed you can use this workaround: - - CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash - -`configure' Invocation -====================== - - `configure' recognizes the following options to control how it -operates. - -`--help' -`-h' - Print a summary of all of the options to `configure', and exit. - -`--help=short' -`--help=recursive' - Print a summary of the options unique to this package's - `configure', and exit. The `short' variant lists options used - only in the top level, while the `recursive' variant lists options - also present in any nested packages. - -`--version' -`-V' - Print the version of Autoconf used to generate the `configure' - script, and exit. - -`--cache-file=FILE' - Enable the cache: use and save the results of the tests in FILE, - traditionally `config.cache'. FILE defaults to `/dev/null' to - disable caching. - -`--config-cache' -`-C' - Alias for `--cache-file=config.cache'. - -`--quiet' -`--silent' -`-q' - Do not print messages saying which checks are being made. To - suppress all normal output, redirect it to `/dev/null' (any error - messages will still be shown). - -`--srcdir=DIR' - Look for the package's source code in directory DIR. Usually - `configure' can determine that directory automatically. - -`--prefix=DIR' - Use DIR as the installation prefix. *note Installation Names:: - for more details, including other options available for fine-tuning - the installation locations. - -`--no-create' -`-n' - Run the configure checks, but stop before creating any output - files. - -`configure' also accepts some other, not widely useful, options. Run -`configure --help' for more details. - diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 12a0b0bd..00000000 --- a/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -if USE_SYSTEM_SHARED_LIB -SUBDIRS = src -else -SUBDIRS = libcork libipset libbloom src -endif - -if ENABLE_DOCUMENTATION -SUBDIRS += doc -endif - -ACLOCAL_AMFLAGS = -I m4 - -pkgconfiglibdir = $(libdir)/pkgconfig -pkgconfiglib_DATA = shadowsocks-libev.pc - -EXTRA_DIST = acl Changes completions debian docker rpm scripts README.md -EXTRA_DIST += libbloom -EXTRA_DIST += libcork/include libipset/include -EXTRA_DIST += libipset/src/libipset/map/inspection-template.c.in -EXTRA_DIST += libipset/src/libipset/set/inspection-template.c.in diff --git a/README.md b/README.md index 8a874db8..327a9592 100644 --- a/README.md +++ b/README.md @@ -79,8 +79,8 @@ git submodule update --init --recursive ### Pre-build configure guide -For a complete list of available configure-time option, -try `configure --help`. +For a complete list of available configure-time options, +try `cmake -LH` from a build directory. ### Debian & Ubuntu @@ -203,12 +203,12 @@ nix-env -iA nixpkgs.shadowsocks-libev In general, you need the following build dependencies: -* autotools (autoconf, automake, libtool) -* gettext +* cmake (>= 3.2) +* a C compiler (gcc or clang) * pkg-config * libmbedtls -* libsodium -* libpcre3 (old pcre library) +* libsodium (>= 1.0.4) +* libpcre2 * libev * libc-ares * asciidoc (for documentation only) @@ -218,18 +218,18 @@ Notes: Fedora 26 libsodium version >= 1.0.12, so you can install via dnf instal If your system is too old to provide libmbedtls and libsodium (later than **v1.0.8**), you will need to either install those libraries manually or upgrade your system. -If your system provides with those libraries, you **should not** install them from source.You should jump to this section and install them from the distribution repository instead. +If your system provides with those libraries, you **should not** install them from source. You should jump to this section and install them from the distribution repository instead. For some of the distributions, you might install build dependencies like this: ```bash # Installation of basic build dependencies ## Debian / Ubuntu -sudo apt-get install --no-install-recommends gettext build-essential autoconf libtool libpcre3-dev asciidoc xmlto libev-dev libc-ares-dev automake libmbedtls-dev libsodium-dev pkg-config +sudo apt-get install --no-install-recommends build-essential cmake libpcre2-dev asciidoc xmlto libev-dev libc-ares-dev libmbedtls-dev libsodium-dev pkg-config ## CentOS / Fedora / RHEL -sudo yum install gettext gcc autoconf libtool automake make asciidoc xmlto c-ares-devel libev-devel +sudo yum install gcc cmake make asciidoc xmlto c-ares-devel libev-devel ## Arch -sudo pacman -S gettext gcc autoconf libtool automake make asciidoc xmlto c-ares libev +sudo pacman -S gcc cmake make asciidoc xmlto c-ares libev # Installation of libsodium export LIBSODIUM_VER=1.0.16 @@ -252,10 +252,20 @@ popd sudo ldconfig # Start building -./autogen.sh && ./configure && make +git submodule update --init --recursive +mkdir -p build && cd build +cmake .. +make sudo make install ``` +To run unit tests: + +```bash +cd build +ctest --output-on-failure +``` + You may need to manually install missing softwares. ### FreeBSD diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index 01db361f..00000000 --- a/autogen.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -autoreconf --install --force diff --git a/build/.gitkeep b/build/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/cmake/FindCares.cmake b/cmake/FindCares.cmake new file mode 100644 index 00000000..07c24861 --- /dev/null +++ b/cmake/FindCares.cmake @@ -0,0 +1,44 @@ +# 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() diff --git a/cmake/FindMbedTLS.cmake b/cmake/FindMbedTLS.cmake new file mode 100644 index 00000000..6b832b62 --- /dev/null +++ b/cmake/FindMbedTLS.cmake @@ -0,0 +1,88 @@ +# 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() diff --git a/cmake/FindPCRE2.cmake b/cmake/FindPCRE2.cmake new file mode 100644 index 00000000..a89e9354 --- /dev/null +++ b/cmake/FindPCRE2.cmake @@ -0,0 +1,63 @@ +# 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() diff --git a/cmake/FindSodium.cmake b/cmake/FindSodium.cmake new file mode 100644 index 00000000..19013bc5 --- /dev/null +++ b/cmake/FindSodium.cmake @@ -0,0 +1,57 @@ +# 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() diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index 3a627f7c..82216519 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -87,11 +87,8 @@ /* 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_PCRE_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_PCRE_PCRE_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 @@ -236,6 +233,21 @@ #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 diff --git a/cmake/configure.cmake b/cmake/configure.cmake index 17049a98..2c2d915f 100644 --- a/cmake/configure.cmake +++ b/cmake/configure.cmake @@ -2,9 +2,6 @@ # ------------------------------------------------------------- # config.h -# If we generate config.h by automake -#include_directories(.) - # Use cmake to generate config.h include(CheckIncludeFiles) include(CheckFunctionExists) @@ -12,14 +9,20 @@ 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 "EINPROGRESS") -set(CONNECT_IN_PROGRESS "EINPROGRESS" CACHE STRING "") + +# 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") + set(CMAKE_REQUIRED_INCLUDES "/usr/local/include" "/usr/include" "/opt/homebrew/include") endif () check_include_files(dlfcn.h HAVE_DLFCN_H) @@ -53,8 +56,10 @@ else () endif () check_include_files(linux/tcp.h HAVE_LINUX_TCP_H) check_include_files(net/if.h HAVE_NET_IF_H) -check_include_files(pcre.h HAVE_PCRE_H) -check_include_files(pcre/pcre.h HAVE_PCRE_PCRE_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) @@ -78,6 +83,8 @@ 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) @@ -89,6 +96,9 @@ 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/") @@ -101,8 +111,6 @@ set(PACKAGE_STRING "${PROJECT_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME ${PROJECT_NAME}) set(PACKAGE_URL "") -#message(${PACKAGE_NAME} - v${PACKAGE_VERSION} - v${PROJECT_VERSION}) - # PTHREAD_CREATE_JOINABLE # Define as the return type of signal handlers (`int' or `void'). @@ -140,31 +148,7 @@ set(_TANDEM_SOURCE 1) set(__EXTENSIONS__ 1) # USE_SYSTEM_SHARED_LIB set(VERSION ${PACKAGE_VERSION}) -# TODO WORDS_BIGENDIAN -# _MINIX -# _POSIX_1_SOURCE -# _POSIX_SOURCE -# _UINT8_T -# Define to empty if `const' does not conform to ANSI C. -# undef const - -# 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 -#undef inline -#endif -# TODO Assume we got inline support -# https://cmake.org/Wiki/CMakeTestInline - -# Define to `int' if does not define. -# undef pid_t -# 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. -# undef 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. -# undef uint8_t set(CMAKE_EXTRA_INCLUDE_FILES sys/types.h) check_type_size(pid_t PID_T) check_type_size(size_t SIZE_T) @@ -197,3 +181,18 @@ endif () 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() diff --git a/cmake/shadowsocks-libev.pc.cmake b/cmake/shadowsocks-libev.pc.cmake index a8f6f1bd..2ddd75ef 100644 --- a/cmake/shadowsocks-libev.pc.cmake +++ b/cmake/shadowsocks-libev.pc.cmake @@ -1,9 +1,7 @@ -prefix=@prefix@ -exec_prefix=${prefix}/@CMAKE_INSTALL_BINDIR@ -libdir=${exec_prefix}/@CMAKE_INSTALL_FULL_LIBDIR@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ -sharedir=${prefix}/@CMAKE_INSTALL_DATAROOTDIR@ -mandir=${prefix}/@CMAKE_INSTALL_MANDIR@ Name: @PROJECT_NAME@ Description: @PROJECT_DESC@ @@ -11,4 +9,4 @@ URL: @PROJECT_URL@ Version: @PROJECT_VERSION@ Requires: Cflags: -I${includedir} -Libs: -L${libdir} -lshadowsocks-libev -lcrypto +Libs: -L${libdir} -lshadowsocks-libev diff --git a/configure.ac b/configure.ac deleted file mode 100755 index 134ea5f6..00000000 --- a/configure.ac +++ /dev/null @@ -1,311 +0,0 @@ -dnl -*- Autoconf -*- -dnl Process this file with autoconf to produce a configure script. - -AC_PREREQ([2.67]) -AC_INIT([shadowsocks-libev], [3.3.5], [max.c.lv@gmail.com]) -AC_CONFIG_SRCDIR([src/crypto.c]) -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_AUX_DIR(auto) -AC_CONFIG_MACRO_DIR([m4]) -AC_USE_SYSTEM_EXTENSIONS - -AM_INIT_AUTOMAKE([subdir-objects foreign -Wno-gnu -Werror]) -m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -AM_MAINTAINER_MODE -AM_DEP_TRACK - -dnl Checks for lib -AC_DISABLE_STATIC -AC_DISABLE_SHARED -LT_INIT([dlopen]) - -dnl Check for pcre library -TS_CHECK_PCRE -if test "x${enable_pcre}" != "xyes"; then - AC_MSG_ERROR([Cannot find pcre library. Configure --with-pcre=DIR]) -fi - -dnl Checks for using shared libraries from system -AC_ARG_ENABLE( - [system-shared-lib], - AS_HELP_STRING([--enable-system-shared-lib], [build against shared libraries when possible]), - [ - case "${enableval}" in - yes) enable_system_shared_lib=true ;; - no) enable_system_shared_lib=false ;; - *) AC_MSG_ERROR([bad value ${enableval} for --enable-system-shared-lib]) ;; - esac], [enable_system_shared_lib=false]) -AM_CONDITIONAL([USE_SYSTEM_SHARED_LIB], [test x$enable_system_shared_lib = xtrue]) - -AC_ARG_ENABLE([documentation], - AS_HELP_STRING([--disable-documentation], [do not build documentation]), - [disable_documentation=true], - [disable_documentation=false]) -AM_CONDITIONAL([ENABLE_DOCUMENTATION], [test x$disable_documentation = xfalse]) - -AM_COND_IF([ENABLE_DOCUMENTATION], [ - AC_PATH_PROG([ASCIIDOC], [asciidoc]) - test x"${ASCIIDOC}" != x || AC_MSG_ERROR([Cannot find `asciidoc` in PATH.]) - AC_PATH_PROG([XMLTO], [xmlto]) - test x"$XMLTO" != x || AC_MSG_ERROR([Cannot find `xmlto` in PATH.]) - AC_PATH_PROG([GZIP], [gzip], [gzip]) - AC_PATH_PROG([MV], [mv], [mv]) - AC_PROG_SED -]) - -dnl Checks for programs. -AC_PROG_CC -AM_PROG_CC_C_O -AC_PROG_INSTALL -AC_PROG_LN_S -AC_PROG_MAKE_SET -AC_LANG_SOURCE - -dnl Add library for mingw -case $host in - *-mingw*) - CFLAGS="$CFLAGS -mno-ms-bitfields" - LIBS="$LIBS -lws2_32 -liphlpapi" - ;; - *-cygwin*) - CFLAGS="$CFLAGS -mno-ms-bitfields" - ;; - *) - ;; -esac - -dnl Checks for TLS -AX_TLS([:], [:]) - -dnl Checks for crypto libraries -ss_MBEDTLS -ss_SODIUM -ss_CARES - -dnl Checks for inet_ntop -ss_FUNC_INET_NTOP - -dnl Checks for host. -AC_MSG_CHECKING(for what kind of host) -case $host in - *-linux*) - os_support=linux - AC_MSG_RESULT(Linux) - ;; - *-mingw*) - os_support=mingw - AC_MSG_RESULT(MinGW) - ;; - *) - AC_MSG_RESULT(transparent proxy does not support for $host) - ;; -esac - -dnl Checks for pthread -AX_PTHREAD([LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - CC="$PTHREAD_CC"], AC_MSG_ERROR(Can not find pthreads. This is required.)) - -dnl Checks for stack protector -GGL_CHECK_STACK_PROTECTOR([has_stack_protector=yes], [has_stack_protector=no]) -# XXX - disable -fstack-protector due to missing libssp_nonshared -case "$host_os" in - *aix*) - AC_MSG_NOTICE([-fstack-protector disabled on AIX]) - has_stack_protector=no - ;; - *sunos*) - AC_MSG_NOTICE([-fstack-protector disabled on SunOS]) - has_stack_protector=no - ;; - *solaris*) - AC_MSG_NOTICE([-fstack-protector disabled on Solaris]) - has_stack_protector=no - ;; -esac - -AC_ARG_ENABLE(ssp, -[AS_HELP_STRING(--disable-ssp,Do not compile with -fstack-protector)], -[ - enable_ssp="no" -], -[ - enable_ssp="yes" -]) - -if test x$has_stack_protector = xyes && test x$enable_ssp = xyes; then - CFLAGS="$CFLAGS -fstack-protector" - AC_MSG_NOTICE([-fstack-protector enabled in CFLAGS]) -fi - -AM_CONDITIONAL(BUILD_REDIRECTOR, test "$os_support" = "linux") -AM_CONDITIONAL(BUILD_WINCOMPAT, test "$os_support" = "mingw") - -dnl Checks for header files. -AC_CHECK_HEADERS([limits.h stdint.h inttypes.h arpa/inet.h fcntl.h langinfo.h locale.h linux/tcp.h netinet/tcp.h netdb.h netinet/in.h stdlib.h string.h strings.h unistd.h sys/ioctl.h linux/random.h]) - -dnl A special check required for on Darwin. See -dnl http://www.gnu.org/software/autoconf/manual/html_node/Header-Portability.html. -AC_CHECK_HEADERS([sys/socket.h]) -AC_CHECK_HEADERS([net/if.h], [], [], -[ -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -]) - -case $host in - *-mingw*) - AC_DEFINE([CONNECT_IN_PROGRESS], [WSAEWOULDBLOCK], [errno for incomplete non-blocking connect(2)]) - AC_CHECK_HEADERS([winsock2.h ws2tcpip.h mswsock.h], [], [AC_MSG_ERROR([Missing MinGW headers])], []) - ;; - *-linux*) - AC_DEFINE([CONNECT_IN_PROGRESS], [EINPROGRESS], [errno for incomplete non-blocking connect(2)]) - dnl Checks for netfilter headers - AC_CHECK_HEADERS([linux/if.h linux/netfilter_ipv4.h linux/netfilter_ipv6/ip6_tables.h], - [], [AC_MSG_ERROR([Missing netfilter headers])], - [[ - #if HAVE_LIMITS_H - #include - #endif - /* Netfilter ip(6)tables v1.4.0 has broken headers */ - #if HAVE_NETINET_IN_H - #include - #endif - #if HAVE_LINUX_IF_H - #include - #endif - #if HAVE_SYS_SOCKET_H - #include - #endif - ]]) - ;; - *) - # These are POSIX-like systems using BSD-like sockets API. - AC_DEFINE([CONNECT_IN_PROGRESS], [EINPROGRESS], [errno for incomplete non-blocking connect(2)]) - ;; -esac - -AC_C_BIGENDIAN - -dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_INLINE -AC_TYPE_SSIZE_T - -dnl Checks for header files. -AC_HEADER_ASSERT -AC_HEADER_STDC -AC_HEADER_SYS_WAIT - -dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_TYPE_PID_T -AC_TYPE_SIZE_T -AC_TYPE_SSIZE_T -AC_TYPE_UINT16_T -AC_TYPE_UINT8_T -AC_HEADER_TIME - -dnl Checks for library functions. -AC_FUNC_FORK -AC_FUNC_SELECT_ARGTYPES -AC_TYPE_SIGNAL -AC_CHECK_FUNCS([memset select setresuid setreuid strerror get_current_dir_name getpwnam_r setrlimit]) - -AC_CHECK_LIB(socket, connect) - -dnl Checks for library functions. -AC_CHECK_FUNCS([malloc memset posix_memalign socket]) - -AC_ARG_WITH(ev, - AS_HELP_STRING([--with-ev=DIR], [use a specific libev library]), - [CFLAGS="$CFLAGS -I$withval/include" - CPPFLAGS="$CPPFLAGS -I$withval/include" - LDFLAGS="$LDFLAGS -L$withval/lib"] -) -AC_CHECK_HEADERS([ev.h libev/ev.h], [], []) -AC_CHECK_LIB([ev], [ev_loop_destroy], [LIBS="-lev $LIBS"], [AC_MSG_ERROR([Couldn't find libev. Try installing libev-dev@<:@el@:>@.])]) - -AC_CONFIG_FILES([shadowsocks-libev.pc - Makefile - doc/Makefile - src/Makefile]) - -AM_COND_IF([USE_SYSTEM_SHARED_LIB], - [AC_DEFINE([USE_SYSTEM_SHARED_LIB], [1], [Define if use system shared lib.])], - [AC_CONFIG_FILES([libbloom/Makefile libcork/Makefile libipset/Makefile])]) - -AC_ARG_ENABLE(connmarktos, -[AS_HELP_STRING(--enable-connmarktos, Enable saved connmark to IP TOS QoS feature)], -[ enable_connmarktos="$enableval" ]) - -if test x"$enable_connmarktos" = "xyes" ; then - AC_MSG_NOTICE([Linux Netfilter Conntrack support requested by --enable-connmarktos: ${enable_connmarktos}]) - if test "x$enable_connmarktos" != "xno"; then - PKG_CHECK_MODULES([NETFILTER_CONNTRACK], [libnetfilter_conntrack],, - [AC_SEARCH_LIBS([nfct_query], [netfilter_conntrack],,[ - if test x"$enable_connmarktos" = "xyes"; then - AC_MSG_ERROR([--enable-connmarktos specified but libnetfilter-conntrack library not found]) - fi - with_netfilter_conntrack=no], [-lnfnetlink]) - AC_CHECK_HEADERS([libnetfilter_conntrack/libnetfilter_conntrack.h \ - libnetfilter_conntrack/libnetfilter_conntrack_tcp.h],,[ - if test x"$enable_connmarktos" = "xyes"; then - AC_MSG_ERROR([--enable-connmarktos specified but libnetfilter-conntrack headers not found]) - fi - with_netfilter_conntrack=no])]) - # If nothing is broken; enable the libraries usage. - if test "x$with_netfilter_conntrack" != "xno"; then - with_netfilter_conntrack=yes - AC_DEFINE(USE_NFCONNTRACK_TOS, 1, [Enable support for QOS netfilter mark preservation]) - fi - fi -fi - -AC_ARG_ENABLE(nftables, -[AS_HELP_STRING(--enable-nftables, report malicious IP to nftables)], -[ enable_nftables="$enableval" ]) - -if test x"$enable_nftables" = "xyes" ; then - AC_MSG_NOTICE([Linux nftables support requested by --enable-nftables: ${enable_nftables}]) - if test "x$enable_nftables" != "xno"; then - PKG_CHECK_MODULES([NFTABLES], [libmnl libnftnl],, - [AC_SEARCH_LIBS([mnl_socket_open], [mnl],,[ - if test x"$enable_nftables" = "xyes"; then - AC_MSG_ERROR([--enable-nftables specified but libmnl library not found]) - fi - with_nftables=no], [-lmnl]) - AC_CHECK_HEADERS([libmnl/libmnl.h],,[ - if test x"$enable_nftables" = "xyes"; then - AC_MSG_ERROR([--enable-nftables specified but libmnl headers not found]) - fi - with_nftables=no]) - AC_SEARCH_LIBS([nftnl_nlmsg_build_hdr], [nftnl],,[ - if test x"$enable_nftables" = "xyes"; then - AC_MSG_ERROR([--enable-nftables specified but libnftnl library not found]) - fi - with_nftables=no], [-lnftnl]) - AC_CHECK_HEADERS([libnftnl/common.h],,[ - if test x"$enable_nftables" = "xyes"; then - AC_MSG_ERROR([--enable-nftables specified but libnftnl headers not found]) - fi - with_nftables=no])]) - # If nothing is broken; enable the libraries usage. - if test "x$with_nftables" != "xno"; then - with_nftables=yes - AC_DEFINE(USE_NFTABLES, 1, [Enable support for nftables firewall]) - fi - fi -fi - -AC_OUTPUT diff --git a/doc/Makefile.am b/doc/Makefile.am deleted file mode 100644 index e2cfbf6d..00000000 --- a/doc/Makefile.am +++ /dev/null @@ -1,60 +0,0 @@ -ASCIIDOC = @ASCIIDOC@ -ASCIIDOC_EXTRA = -MANPAGE_XSL = $(srcdir)/manpage-normal.xsl -XMLTO = @XMLTO@ -XMLTO_EXTRA = -m $(srcdir)/manpage-bold-literal.xsl -GZIPCMD = @GZIP@ -INSTALL = @INSTALL@ -RM = @RM@ -MV = @MV@ -SED = @SED@ -VERSION = `$(SED) -n 's/.*PACKAGE_VERSION "\(.*\)"/\1/p'\ - ../config.h` - -# Guard against environment variables -MAN1_DOC = -MAN1_DOC += ss-local.1 -MAN1_DOC += ss-manager.1 -MAN1_DOC += ss-nat.1 -MAN1_DOC += ss-redir.1 -MAN1_DOC += ss-server.1 -MAN1_DOC += ss-tunnel.1 - -MAN8_DOC = -MAN8_DOC += shadowsocks-libev.8 - -MAN8_XML = $(MAN8_DOC:%.8=%.xml) -MAN1_XML = $(MAN1_DOC:%.1=%.xml) -MAN_XML = $(MAN8_XML) $(MAN1_XML) - -MAN8_HTML = $(MAN8_DOC:%.8=%.html) -MAN1_HTML = $(MAN1_DOC:%.1=%.html) -MAN_HTML = $(MAN8_HTML) $(MAN1_HTML) - -MAN8_TXT = $(MAN8_DOC:%.8=%.asciidoc) -MAN1_TXT = $(MAN1_DOC:%.1=%.asciidoc) -MAN_TXT = $(MAN8_TXT) $(MAN1_TXT) - -man_MANS = $(MAN8_DOC) $(MAN1_DOC) - -html-local: $(MAN_HTML) - -%.1: %.xml - $(AM_V_GEN)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< - -%.8: %.xml - $(AM_V_GEN)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< - -%.xml: %.asciidoc - $(AM_V_GEN)$(ASCIIDOC) -b docbook -d manpage -f $(srcdir)/asciidoc.conf \ - -aversion=$(VERSION) $(ASCIIDOC_EXTRA) -o $@ $< - -%.html: %.asciidoc - $(AM_V_GEN)$(ASCIIDOC) -b html4 -d article -f $(srcdir)/asciidoc.conf \ - -aversion=$(VERSION) $(ASCIIDOC_EXTRA) -o $@ $< - -doc_DATA = $(MAN_HTML) - -CLEANFILES = $(MAN_XML) $(man_MANS) $(MAN_HTML) - -EXTRA_DIST = *.asciidoc asciidoc.conf *.xsl diff --git a/doc/shadowsocks-libev.asciidoc b/doc/shadowsocks-libev.asciidoc index 4a283dd6..4cb0f50c 100644 --- a/doc/shadowsocks-libev.asciidoc +++ b/doc/shadowsocks-libev.asciidoc @@ -151,6 +151,26 @@ 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. + @@ -166,6 +186,17 @@ 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. diff --git a/doc/ss-local.asciidoc b/doc/ss-local.asciidoc index 46ce8c82..19ba7002 100644 --- a/doc/ss-local.asciidoc +++ b/doc/ss-local.asciidoc @@ -104,7 +104,7 @@ Enable UDP relay. Enable UDP relay and disable TCP relay. -6:: -Resovle hostname to IPv6 address first. +Resolve hostname to IPv6 address first. --fast-open:: Enable TCP fast open. @@ -130,6 +130,18 @@ 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) diff --git a/doc/ss-manager.asciidoc b/doc/ss-manager.asciidoc index 0c127570..632789e7 100644 --- a/doc/ss-manager.asciidoc +++ b/doc/ss-manager.asciidoc @@ -117,7 +117,8 @@ Specify the executable path of ss-server. + Only available in manager mode. ---executable :: +-D :: +--workdir :: Specify the working directory of ss-manager. + Only available in manager mode. diff --git a/doc/ss-redir.asciidoc b/doc/ss-redir.asciidoc index ea15ef31..5d17c51e 100644 --- a/doc/ss-redir.asciidoc +++ b/doc/ss-redir.asciidoc @@ -99,7 +99,7 @@ Enable UDP relay and disable TCP relay. Use tproxy instead of redirect. (for tcp) -6:: -Resovle hostname to IPv6 address first. +Resolve hostname to IPv6 address first. --mtu :: Specify the MTU of your network interface. @@ -117,6 +117,18 @@ 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) diff --git a/doc/ss-server.asciidoc b/doc/ss-server.asciidoc index d06cd191..932a6194 100644 --- a/doc/ss-server.asciidoc +++ b/doc/ss-server.asciidoc @@ -99,7 +99,7 @@ Enable UDP relay. Enable UDP relay and disable TCP relay. -6:: -Resovle hostname to IPv6 address first. +Resolve hostname to IPv6 address first. -d :: Setup name servers for internal DNS resolver (libc-ares). @@ -118,6 +118,18 @@ 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. diff --git a/doc/ss-tunnel.asciidoc b/doc/ss-tunnel.asciidoc index 26fabafb..9dfda6b8 100644 --- a/doc/ss-tunnel.asciidoc +++ b/doc/ss-tunnel.asciidoc @@ -103,7 +103,7 @@ Enable UDP relay. Enable UDP relay and disable TCP relay. -6:: -Resovle hostname to IPv6 address first. +Resolve hostname to IPv6 address first. -L :: Specify destination server address and port for local port forwarding. @@ -126,6 +126,18 @@ 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) @@ -138,6 +150,19 @@ 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), diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index f6988d48..79949746 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -14,21 +14,19 @@ COPY . /tmp/repo RUN set -x \ # Build environment setup && apk add --no-cache --virtual .build-deps \ - autoconf \ - automake \ build-base \ + cmake \ c-ares-dev \ libcap \ libev-dev \ - libtool \ libsodium-dev \ linux-headers \ mbedtls-dev \ - pcre-dev \ + pcre2-dev \ # Build & install && cd /tmp/repo \ - && ./autogen.sh \ - && ./configure --prefix=/usr/local --disable-documentation \ + && 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 \ diff --git a/docker/build/builder.Dockerfile b/docker/build/builder.Dockerfile index a1402c57..8aa92c21 100644 --- a/docker/build/builder.Dockerfile +++ b/docker/build/builder.Dockerfile @@ -5,4 +5,4 @@ MAINTAINER wener # Better for cache and dev RUN apk add --no-cache --virtual .build-deps \ alpine-sdk cmake \ - linux-headers libev-dev libsodium-dev mbedtls-static mbedtls-dev pcre-dev udns-dev + linux-headers libev-dev libsodium-dev mbedtls-static mbedtls-dev pcre2-dev udns-dev diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4 deleted file mode 100644 index 4c4051ea..00000000 --- a/m4/ax_pthread.m4 +++ /dev/null @@ -1,485 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_pthread.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -# -# DESCRIPTION -# -# This macro figures out how to build C programs using POSIX threads. It -# sets the PTHREAD_LIBS output variable to the threads library and linker -# flags, and the PTHREAD_CFLAGS output variable to any special C compiler -# flags that are needed. (The user can also force certain compiler -# flags/libs to be tested by setting these environment variables.) -# -# Also sets PTHREAD_CC to any special C compiler that is needed for -# multi-threaded programs (defaults to the value of CC otherwise). (This -# is necessary on AIX to use the special cc_r compiler alias.) -# -# NOTE: You are assumed to not only compile your program with these flags, -# but also to link with them as well. For example, you might link with -# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS -# -# If you are only building threaded programs, you may wish to use these -# variables in your default LIBS, CFLAGS, and CC: -# -# LIBS="$PTHREAD_LIBS $LIBS" -# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -# CC="$PTHREAD_CC" -# -# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to -# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -# -# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the -# PTHREAD_PRIO_INHERIT symbol is defined when compiling with -# PTHREAD_CFLAGS. -# -# ACTION-IF-FOUND is a list of shell commands to run if a threads library -# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it -# is not found. If ACTION-IF-FOUND is not specified, the default action -# will define HAVE_PTHREAD. -# -# Please let the authors know if this macro fails on any platform, or if -# you have any other suggestions or comments. This macro was based on work -# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help -# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by -# Alejandro Forero Cuervo to the autoconf macro repository. We are also -# grateful for the helpful feedback of numerous users. -# -# Updated for Autoconf 2.68 by Daniel Richard G. -# -# LICENSE -# -# Copyright (c) 2008 Steven G. Johnson -# Copyright (c) 2011 Daniel Richard G. -# -# 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. - -#serial 23 - -AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) -AC_DEFUN([AX_PTHREAD], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_REQUIRE([AC_PROG_CC]) -AC_REQUIRE([AC_PROG_SED]) -AC_LANG_PUSH([C]) -ax_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on Tru64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then - ax_pthread_save_CC="$CC" - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) - AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) - AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = "xno"; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - CC="$ax_pthread_save_CC" - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. - -ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 -# (Note: HP C rejects this with "bad form for `-t' option") -# -pthreads: Solaris/gcc (Note: HP C also rejects) -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads and -# -D_REENTRANT too), HP C (must be checked before -lpthread, which -# is present but should not be used directly; and before -mthreads, -# because the compiler interprets this as "-mt" + "-hreads") -# -mthreads: Mingw32/gcc, Lynx/gcc -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case $host_os in - - freebsd*) - - # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) - # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) - - ax_pthread_flags="-kthread lthread $ax_pthread_flags" - ;; - - hpux*) - - # From the cc(1) man page: "[-mt] Sets various -D flags to enable - # multi-threading and also sets -lpthread." - - ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" - ;; - - openedition*) - - # IBM z/OS requires a feature-test macro to be defined in order to - # enable POSIX threads at all, so give the user a hint if this is - # not set. (We don't define these ourselves, as they can affect - # other portions of the system API in unpredictable ways.) - - AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], - [ -# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) - AX_PTHREAD_ZOS_MISSING -# endif - ], - [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) - ;; - - solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (N.B.: The stubs are missing - # pthread_cleanup_push, or rather a function called by this macro, - # so we could check for that, but who knows whether they'll stub - # that too in a future libc.) So we'll check first for the - # standard Solaris way of linking pthreads (-mt -lpthread). - - ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" - ;; -esac - -# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) - -AS_IF([test "x$GCC" = "xyes"], - [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) - -# The presence of a feature test macro requesting re-entrant function -# definitions is, on some systems, a strong hint that pthreads support is -# correctly enabled - -case $host_os in - darwin* | hpux* | linux* | osf* | solaris*) - ax_pthread_check_macro="_REENTRANT" - ;; - - aix*) - ax_pthread_check_macro="_THREAD_SAFE" - ;; - - *) - ax_pthread_check_macro="--" - ;; -esac -AS_IF([test "x$ax_pthread_check_macro" = "x--"], - [ax_pthread_check_cond=0], - [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) - -# Are we compiling with Clang? - -AC_CACHE_CHECK([whether $CC is Clang], - [ax_cv_PTHREAD_CLANG], - [ax_cv_PTHREAD_CLANG=no - # Note that Autoconf sets GCC=yes for Clang as well as GCC - if test "x$GCC" = "xyes"; then - AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], - [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ -# if defined(__clang__) && defined(__llvm__) - AX_PTHREAD_CC_IS_CLANG -# endif - ], - [ax_cv_PTHREAD_CLANG=yes]) - fi - ]) -ax_pthread_clang="$ax_cv_PTHREAD_CLANG" - -ax_pthread_clang_warning=no - -# Clang needs special handling, because older versions handle the -pthread -# option in a rather... idiosyncratic way - -if test "x$ax_pthread_clang" = "xyes"; then - - # Clang takes -pthread; it has never supported any other flag - - # (Note 1: This will need to be revisited if a system that Clang - # supports has POSIX threads in a separate library. This tends not - # to be the way of modern systems, but it's conceivable.) - - # (Note 2: On some systems, notably Darwin, -pthread is not needed - # to get POSIX threads support; the API is always present and - # active. We could reasonably leave PTHREAD_CFLAGS empty. But - # -pthread does define _REENTRANT, and while the Darwin headers - # ignore this macro, third-party headers might not.) - - PTHREAD_CFLAGS="-pthread" - PTHREAD_LIBS= - - ax_pthread_ok=yes - - # However, older versions of Clang make a point of warning the user - # that, in an invocation where only linking and no compilation is - # taking place, the -pthread option has no effect ("argument unused - # during compilation"). They expect -pthread to be passed in only - # when source code is being compiled. - # - # Problem is, this is at odds with the way Automake and most other - # C build frameworks function, which is that the same flags used in - # compilation (CFLAGS) are also used in linking. Many systems - # supported by AX_PTHREAD require exactly this for POSIX threads - # support, and in fact it is often not straightforward to specify a - # flag that is used only in the compilation phase and not in - # linking. Such a scenario is extremely rare in practice. - # - # Even though use of the -pthread flag in linking would only print - # a warning, this can be a nuisance for well-run software projects - # that build with -Werror. So if the active version of Clang has - # this misfeature, we search for an option to squash it. - - AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], - [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], - [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown - # Create an alternate version of $ac_link that compiles and - # links in two steps (.c -> .o, .o -> exe) instead of one - # (.c -> exe), because the warning occurs only in the second - # step - ax_pthread_save_ac_link="$ac_link" - ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' - ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` - ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" - ax_pthread_save_CFLAGS="$CFLAGS" - for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do - AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) - CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" - ac_link="$ax_pthread_save_ac_link" - AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], - [ac_link="$ax_pthread_2step_ac_link" - AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], - [break]) - ]) - done - ac_link="$ax_pthread_save_ac_link" - CFLAGS="$ax_pthread_save_CFLAGS" - AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) - ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" - ]) - - case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in - no | unknown) ;; - *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; - esac - -fi # $ax_pthread_clang = yes - -if test "x$ax_pthread_ok" = "xno"; then -for ax_pthread_try_flag in $ax_pthread_flags; do - - case $ax_pthread_try_flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -mt,pthread) - AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) - PTHREAD_CFLAGS="-mt" - PTHREAD_LIBS="-lpthread" - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) - PTHREAD_CFLAGS="$ax_pthread_try_flag" - ;; - - pthread-config) - AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) - PTHREAD_LIBS="-l$ax_pthread_try_flag" - ;; - esac - - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include -# if $ax_pthread_check_cond -# error "$ax_pthread_check_macro must be defined" -# endif - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) - - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" - - AC_MSG_RESULT([$ax_pthread_ok]) - AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$ax_pthread_ok" = "xyes"; then - ax_pthread_save_CFLAGS="$CFLAGS" - ax_pthread_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_CACHE_CHECK([for joinable pthread attribute], - [ax_cv_PTHREAD_JOINABLE_ATTR], - [ax_cv_PTHREAD_JOINABLE_ATTR=unknown - for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $ax_pthread_attr; return attr /* ; */])], - [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], - []) - done - ]) - AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ - test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ - test "x$ax_pthread_joinable_attr_defined" != "xyes"], - [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], - [$ax_cv_PTHREAD_JOINABLE_ATTR], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - ax_pthread_joinable_attr_defined=yes - ]) - - AC_CACHE_CHECK([whether more special flags are required for pthreads], - [ax_cv_PTHREAD_SPECIAL_FLAGS], - [ax_cv_PTHREAD_SPECIAL_FLAGS=no - case $host_os in - solaris*) - ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" - ;; - esac - ]) - AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ - test "x$ax_pthread_special_flags_added" != "xyes"], - [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" - ax_pthread_special_flags_added=yes]) - - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ - test "x$ax_pthread_prio_inherit_defined" != "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) - ax_pthread_prio_inherit_defined=yes - ]) - - CFLAGS="$ax_pthread_save_CFLAGS" - LIBS="$ax_pthread_save_LIBS" - - # More AIX lossage: compile with *_r variant - if test "x$GCC" != "xyes"; then - case $host_os in - aix*) - AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], - [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) - ;; - esac - fi -fi - -test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" - -AC_SUBST([PTHREAD_LIBS]) -AC_SUBST([PTHREAD_CFLAGS]) -AC_SUBST([PTHREAD_CC]) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test "x$ax_pthread_ok" = "xyes"; then - ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) - : -else - ax_pthread_ok=no - $2 -fi -AC_LANG_POP -])dnl AX_PTHREAD diff --git a/m4/ax_tls.m4 b/m4/ax_tls.m4 deleted file mode 100644 index 809b761a..00000000 --- a/m4/ax_tls.m4 +++ /dev/null @@ -1,74 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_tls.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_TLS([action-if-found], [action-if-not-found]) -# -# DESCRIPTION -# -# Provides a test for the compiler support of thread local storage (TLS) -# extensions. Defines TLS if it is found. Currently knows about GCC/ICC -# and MSVC. I think SunPro uses the same as GCC, and Borland apparently -# supports either. -# -# LICENSE -# -# Copyright (c) 2008 Alan Woodland -# Copyright (c) 2010 Diego Elio Petteno` -# -# 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. - -#serial 11 - -AC_DEFUN([AX_TLS], [ - AC_MSG_CHECKING([for thread local storage (TLS) class]) - AC_CACHE_VAL([ac_cv_tls], - [for ax_tls_keyword in __thread '__declspec(thread)' none; do - AS_CASE([$ax_tls_keyword], - [none], [ac_cv_tls=none ; break], - [AC_TRY_COMPILE( - [#include - static void - foo(void) { - static ] $ax_tls_keyword [ int bar; - exit(1); - }], - [], - [ac_cv_tls=$ax_tls_keyword ; break], - ac_cv_tls=none - )]) - done - ]) - AC_MSG_RESULT([$ac_cv_tls]) - - AS_IF([test "$ac_cv_tls" != "none"], - [AC_DEFINE_UNQUOTED([TLS],[$ac_cv_tls],[If the compiler supports a TLS storage class define it to that here]) - m4_ifnblank([$1],[$1])], - [m4_ifnblank([$2],[$2])]) -]) diff --git a/m4/cares.m4 b/m4/cares.m4 deleted file mode 100644 index a6853ce8..00000000 --- a/m4/cares.m4 +++ /dev/null @@ -1,30 +0,0 @@ -dnl Check to find the libcares headers/libraries - -AC_DEFUN([ss_CARES], -[ - - AC_ARG_WITH(cares, - AS_HELP_STRING([--with-cares=DIR], [The c-ares library base directory, or:]), - [cares="$withval" - CFLAGS="$CFLAGS -I$withval/include" - LDFLAGS="$LDFLAGS -L$withval/lib"] - ) - - AC_ARG_WITH(cares-include, - AS_HELP_STRING([--with-cares-include=DIR], [The c-ares library headers directory (without trailing /cares)]), - [cares_include="$withval" - CFLAGS="$CFLAGS -I$withval"] - ) - - AC_ARG_WITH(cares-lib, - AS_HELP_STRING([--with-cares-lib=DIR], [The c-ares library library directory]), - [cares_lib="$withval" - LDFLAGS="$LDFLAGS -L$withval"] - ) - - AC_CHECK_LIB(cares, ares_library_init, - [LIBS="-lcares $LIBS"], - [AC_MSG_ERROR([The c-ares library libraries not found.])] - ) - -]) diff --git a/m4/inet_ntop.m4 b/m4/inet_ntop.m4 deleted file mode 100644 index adb439b4..00000000 --- a/m4/inet_ntop.m4 +++ /dev/null @@ -1,41 +0,0 @@ -# inet_ntop.m4 serial 19 -dnl Copyright (C) 2005-2006, 2008-2013 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -AC_DEFUN([ss_FUNC_INET_NTOP], -[ - AC_REQUIRE([AC_C_RESTRICT]) - - dnl Most platforms that provide inet_ntop define it in libc. - dnl Solaris 8..10 provide inet_ntop in libnsl instead. - dnl Solaris 2.6..7 provide inet_ntop in libresolv instead. - HAVE_INET_NTOP=1 - INET_NTOP_LIB= - ss_save_LIBS=$LIBS - AC_SEARCH_LIBS([inet_ntop], [nsl resolv], [], - [AC_CHECK_FUNCS([inet_ntop]) - if test $ac_cv_func_inet_ntop = no; then - HAVE_INET_NTOP=0 - fi - ]) - LIBS=$ss_save_LIBS - - if test "$ac_cv_search_inet_ntop" != "no" \ - && test "$ac_cv_search_inet_ntop" != "none required"; then - INET_NTOP_LIB="$ac_cv_search_inet_ntop" - fi - - AC_CHECK_HEADERS_ONCE([netdb.h]) - AC_CHECK_DECLS([inet_ntop],,, - [[#include - #if HAVE_NETDB_H - # include - #endif - ]]) - if test $ac_cv_have_decl_inet_ntop = no; then - HAVE_DECL_INET_NTOP=0 - fi - AC_SUBST([INET_NTOP_LIB]) -]) diff --git a/m4/mbedtls.m4 b/m4/mbedtls.m4 deleted file mode 100644 index a795790c..00000000 --- a/m4/mbedtls.m4 +++ /dev/null @@ -1,114 +0,0 @@ -dnl Check to find the mbed TLS headers/libraries - -AC_DEFUN([ss_MBEDTLS], -[ - - AC_ARG_WITH(mbedtls, - AS_HELP_STRING([--with-mbedtls=DIR], [mbed TLS base directory, or:]), - [mbedtls="$withval" - CFLAGS="$CFLAGS -I$withval/include" - LDFLAGS="$LDFLAGS -L$withval/lib"] - ) - - AC_ARG_WITH(mbedtls-include, - AS_HELP_STRING([--with-mbedtls-include=DIR], [mbed TLS headers directory (without trailing /mbedtls)]), - [mbedtls_include="$withval" - CFLAGS="$CFLAGS -I$withval"] - ) - - AC_ARG_WITH(mbedtls-lib, - AS_HELP_STRING([--with-mbedtls-lib=DIR], [mbed TLS library directory]), - [mbedtls_lib="$withval" - LDFLAGS="$LDFLAGS -L$withval"] - ) - - AC_CHECK_LIB(mbedcrypto, mbedtls_cipher_setup, - [LIBS="-lmbedcrypto $LIBS"], - [AC_MSG_ERROR([mbed TLS libraries not found.])] - ) - - AC_MSG_CHECKING([whether mbedtls supports Cipher Feedback mode or not]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [[ -#include -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 -#include -#else -#include -#endif - ]], - [[ -#ifndef MBEDTLS_CIPHER_MODE_CFB -#error Cipher Feedback mode a.k.a CFB not supported by your mbed TLS. -#endif - ]] - )], - [AC_MSG_RESULT([ok])], - [AC_MSG_ERROR([MBEDTLS_CIPHER_MODE_CFB required])] - ) - - - AC_MSG_CHECKING([whether mbedtls supports the ARC4 stream cipher or not]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [[ -#include -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 -#include -#else -#include -#endif - ]], - [[ -#ifndef MBEDTLS_ARC4_C -#error the ARC4 stream cipher not supported by your mbed TLS. -#endif - ]] - )], - [AC_MSG_RESULT([ok])], - [AC_MSG_WARN([We will continue without ARC4 stream cipher support, MBEDTLS_ARC4_C required])] - ) - - AC_MSG_CHECKING([whether mbedtls supports the Blowfish block cipher or not]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [[ -#include -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 -#include -#else -#include -#endif - ]], - [[ -#ifndef MBEDTLS_BLOWFISH_C -#error the Blowfish block cipher not supported by your mbed TLS. -#endif - ]] - )], - [AC_MSG_RESULT([ok])], - [AC_MSG_WARN([We will continue without Blowfish block cipher support, MBEDTLS_BLOWFISH_C required])] - ) - - AC_MSG_CHECKING([whether mbedtls supports the Camellia block cipher or not]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [[ -#include -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 -#include -#else -#include -#endif - ]], - [[ -#ifndef MBEDTLS_CAMELLIA_C -#error the Camellia block cipher not supported by your mbed TLS. -#endif - ]] - )], - [AC_MSG_RESULT([ok])], - [AC_MSG_WARN([We will continue without Camellia block cipher support, MBEDTLS_CAMELLIA_C required])] - ) -]) diff --git a/m4/pcre.m4 b/m4/pcre.m4 deleted file mode 100644 index 4d965bc7..00000000 --- a/m4/pcre.m4 +++ /dev/null @@ -1,152 +0,0 @@ -dnl -------------------------------------------------------- -*- autoconf -*- -dnl Licensed to the Apache Software Foundation (ASF) under one or more -dnl contributor license agreements. See the NOTICE file distributed with -dnl this work for additional information regarding copyright ownership. -dnl The ASF licenses this file to You under the Apache License, Version 2.0 -dnl (the "License"); you may not use this file except in compliance with -dnl the License. You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. - -dnl -dnl TS_ADDTO(variable, value) -dnl -dnl Add value to variable -dnl -AC_DEFUN([TS_ADDTO], [ - if test "x$$1" = "x"; then - test "x$verbose" = "xyes" && echo " setting $1 to \"$2\"" - $1="$2" - else - ats_addto_bugger="$2" - for i in $ats_addto_bugger; do - ats_addto_duplicate="0" - for j in $$1; do - if test "x$i" = "x$j"; then - ats_addto_duplicate="1" - break - fi - done - if test $ats_addto_duplicate = "0"; then - test "x$verbose" = "xyes" && echo " adding \"$i\" to $1" - $1="$$1 $i" - fi - done - fi -])dnl - -dnl -dnl TS_ADDTO_RPATH(path) -dnl -dnl Adds path to variable with the '-rpath' directive. -dnl -AC_DEFUN([TS_ADDTO_RPATH], [ - AC_MSG_NOTICE([adding $1 to RPATH]) - TS_ADDTO(LIBTOOL_LINK_FLAGS, [-R$1]) -])dnl - -dnl -dnl pcre.m4: Trafficserver's pcre autoconf macros -dnl - -dnl -dnl TS_CHECK_PCRE: look for pcre libraries and headers -dnl -AC_DEFUN([TS_CHECK_PCRE], [ -enable_pcre=no -AC_ARG_WITH(pcre, [AC_HELP_STRING([--with-pcre=DIR],[use a specific pcre library])], -[ - if test "x$withval" != "xyes" && test "x$withval" != "x"; then - pcre_base_dir="$withval" - if test "$withval" != "no"; then - enable_pcre=yes - case "$withval" in - *":"*) - pcre_include="`echo $withval |sed -e 's/:.*$//'`" - pcre_ldflags="`echo $withval |sed -e 's/^.*://'`" - AC_MSG_CHECKING(checking for pcre includes in $pcre_include libs in $pcre_ldflags ) - ;; - *) - pcre_include="$withval/include" - pcre_ldflags="$withval/lib" - AC_MSG_CHECKING(checking for pcre includes in $withval) - ;; - esac - fi - fi -], -[ - AC_CHECK_PROG(PCRE_CONFIG, pcre-config, pcre-config) - if test "x$PCRE_CONFIG" != "x"; then - enable_pcre=yes - pcre_base_dir="`$PCRE_CONFIG --prefix`" - pcre_include="`$PCRE_CONFIG --cflags | sed -es/-I//`" - pcre_ldflags="`$PCRE_CONFIG --libs | sed -es/-lpcre// -es/-L//`" - fi -]) - -if test "x$pcre_base_dir" = "x"; then - AC_MSG_CHECKING([for pcre location]) - AC_CACHE_VAL(ats_cv_pcre_dir,[ - for dir in /usr/local /usr ; do - if test -d $dir && ( test -f $dir/include/pcre.h || test -f $dir/include/pcre/pcre.h ); then - ats_cv_pcre_dir=$dir - break - fi - done - ]) - pcre_base_dir=$ats_cv_pcre_dir - if test "x$pcre_base_dir" = "x"; then - enable_pcre=no - AC_MSG_RESULT([not found]) - else - enable_pcre=yes - pcre_include="$pcre_base_dir/include" - pcre_ldflags="$pcre_base_dir/lib" - AC_MSG_RESULT([$pcre_base_dir]) - fi -else - AC_MSG_CHECKING(for pcre headers in $pcre_include) - if test -d $pcre_include && test -d $pcre_ldflags && ( test -f $pcre_include/pcre.h || test -f $pcre_include/pcre/pcre.h ); then - AC_MSG_RESULT([ok]) - else - AC_MSG_RESULT([not found]) - fi -fi - -pcreh=0 -pcre_pcreh=0 -if test "$enable_pcre" != "no"; then - saved_ldflags=$LDFLAGS - saved_cppflags=$CFLAGS - pcre_have_headers=0 - pcre_have_libs=0 - if test "$pcre_base_dir" != "/usr"; then - TS_ADDTO(CFLAGS, [-I${pcre_include}]) - TS_ADDTO(CFLAGS, [-DPCRE_STATIC]) - TS_ADDTO(LDFLAGS, [-L${pcre_ldflags}]) - TS_ADDTO_RPATH(${pcre_ldflags}) - fi - AC_SEARCH_LIBS([pcre_exec], [pcre], [pcre_have_libs=1]) - if test "$pcre_have_libs" != "0"; then - AC_CHECK_HEADERS(pcre.h, [pcre_have_headers=1]) - AC_CHECK_HEADERS(pcre/pcre.h, [pcre_have_headers=1]) - fi - if test "$pcre_have_headers" != "0"; then - AC_DEFINE(HAVE_LIBPCRE,1,[Compiling with pcre support]) - AC_SUBST(LIBPCRE, [-lpcre]) - else - enable_pcre=no - CFLAGS=$saved_cppflags - LDFLAGS=$saved_ldflags - fi -fi -AC_SUBST(pcreh) -AC_SUBST(pcre_pcreh) -]) diff --git a/m4/sodium.m4 b/m4/sodium.m4 deleted file mode 100644 index b4c254e6..00000000 --- a/m4/sodium.m4 +++ /dev/null @@ -1,40 +0,0 @@ -dnl Check to find the libsodium headers/libraries - -AC_DEFUN([ss_SODIUM], -[ - - AC_ARG_WITH(sodium, - AS_HELP_STRING([--with-sodium=DIR], [The Sodium crypto library base directory, or:]), - [sodium="$withval" - CFLAGS="$CFLAGS -I$withval/include" - LDFLAGS="$LDFLAGS -L$withval/lib"] - ) - - AC_ARG_WITH(sodium-include, - AS_HELP_STRING([--with-sodium-include=DIR], [The Sodium crypto library headers directory (without trailing /sodium)]), - [sodium_include="$withval" - CFLAGS="$CFLAGS -I$withval"] - ) - - AC_ARG_WITH(sodium-lib, - AS_HELP_STRING([--with-sodium-lib=DIR], [The Sodium crypto library library directory]), - [sodium_lib="$withval" - LDFLAGS="$LDFLAGS -L$withval"] - ) - - AC_CHECK_LIB(sodium, sodium_init, - [LIBS="-lsodium $LIBS"], - [AC_MSG_ERROR([The Sodium crypto library libraries not found.])] - ) - - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ - #include - ], [ - #if SODIUM_LIBRARY_VERSION_MAJOR < 7 || SODIUM_LIBRARY_VERSION_MAJOR ==7 && SODIUM_LIBRARY_VERSION_MINOR < 6 - # error - #endif - ])], - [AC_MSG_RESULT([checking for version of libsodium... yes])], - [AC_MSG_ERROR([Wrong libsodium: version >= 1.0.4 required])]) - -]) diff --git a/m4/stack-protector.m4 b/m4/stack-protector.m4 deleted file mode 100644 index 33b3aae0..00000000 --- a/m4/stack-protector.m4 +++ /dev/null @@ -1,58 +0,0 @@ -# -# Copyright 2007 Google Inc. -# -# 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. -# -# GGL_CHECK_STACK_PROTECTOR([ACTION-IF-OK], [ACTION-IF-NOT-OK]) -# Check if c compiler supports -fstack-protector and -fstack-protector-all -# options. - -AC_DEFUN([GGL_CHECK_STACK_PROTECTOR], [ -ggl_check_stack_protector_save_CXXFLAGS="$CXXFLAGS" -ggl_check_stack_protector_save_CFLAGS="$CFLAGS" - -AC_MSG_CHECKING([if -fstack-protector and -fstack-protector-all are supported.]) - -CXXFLAGS="$CXXFLAGS -fstack-protector" -CFLAGS="$CFLAGS -fstack-protector" -AC_COMPILE_IFELSE([AC_LANG_SOURCE([ -int main() { - return 0; -} -])], -[ggl_check_stack_protector_ok=yes], -[ggl_check_stack_protector_ok=no]) - -CXXFLAGS="$ggl_check_stack_protector_save_CXXFLAGS -fstack-protector-all" -CFLAGS="$ggl_check_stack_protector_save_CFLAGS -fstack-protector-all" -AC_COMPILE_IFELSE([AC_LANG_SOURCE([ -int main() { - return 0; -} -])], -[ggl_check_stack_protector_all_ok=yes], -[ggl_check_stack_protector_all_ok=no]) - -if test "x$ggl_check_stack_protector_ok" = "xyes" -a \ - "x$ggl_check_stack_protector_all_ok" = "xyes"; then - AC_MSG_RESULT([yes]) - ifelse([$1], , :, [$1]) -else - AC_MSG_RESULT([no]) - ifelse([$2], , :, [$2]) -fi - -CXXFLAGS="$ggl_check_stack_protector_save_CXXFLAGS" -CFLAGS="$ggl_check_stack_protector_save_CFLAGS" - -]) # GGL_CHECK_STACK_PROTECTOR diff --git a/shadowsocks-libev.pc.in b/shadowsocks-libev.pc.in deleted file mode 100644 index e3738766..00000000 --- a/shadowsocks-libev.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: shadowsocks-libev -Description: a lightweight secured socks5 proxy -URL: https://shadowsocks.org -Version: @VERSION@ -Requires: -Cflags: -I${includedir} -Libs: -L${libdir} -lshadowsocks-libev diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9ca9d852..18ae7ba0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,25 +84,29 @@ set(SS_REDIR_SOURCE ${SS_PLUGIN_SOURCE} ) -if (CMAKE_SYSTEM_NAME STREQUAL Darwin) -find_path(LIBSODIUM_INCLUDE_DIR sodium.h - PATHS - $ENV{LIBSODIUM_INCLUDE_DIR} - $ENV{LIBSODIUM_DIR}/include - /usr/local/libsodium/include - /opt/libsodium/include - /usr/local/include -) -include_directories(${LIBSODIUM_INCLUDE_DIR}) -endif () +# 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(LIBPCRE libpcre.a) +find_library(LIBPCRE2 libpcre2-8.a) # Dependencies we need for static and shared list(APPEND DEPS @@ -110,7 +114,7 @@ list(APPEND DEPS bloom ${LIBEV} ${LIBUDNS} - ${LIBPCRE} + ${LIBPCRE2} ${LIBSODIUM} ${LIBMBEDTLS} ${LIBMBEDCRYPTO} @@ -118,16 +122,18 @@ list(APPEND DEPS if (MINGW) list(APPEND DEPS ws2_32 iphlpapi) -add_compile_definitions(CARES_STATICLIB PCRE_STATIC) +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(LIBPCRE_SHARED pcre) +find_library(LIBPCRE2_SHARED pcre2-8) if (WITH_EMBEDDED_SRC) list(APPEND DEPS_SHARED @@ -137,7 +143,7 @@ list(APPEND DEPS_SHARED ipset-shared ${LIBEV_SHARED} ${LIBUDNS_SHARED} - ${LIBPCRE_SHARED} + ${LIBPCRE2_SHARED} ${LIBSODIUM_SHARED} ${LIBMBEDTLS_SHARED} ${LIBMBEDCRYPTO_SHARED} @@ -153,13 +159,24 @@ list(APPEND DEPS_SHARED ${LIBCORKIPSET_SHARED} ${LIBEV_SHARED} ${LIBUDNS_SHARED} - ${LIBPCRE_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) @@ -189,9 +206,24 @@ 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}) +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}) @@ -226,9 +258,24 @@ 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}) +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}) @@ -247,6 +294,7 @@ set_target_properties(ss-server-shared ss-tunnel-shared ss-manager-shared ss-loc ) 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}) @@ -255,17 +303,17 @@ target_link_libraries(shadowsocks-libev-shared ${DEPS_SHARED}) # Recommend to install shared by default install(DIRECTORY ${RUNTIME_SHARED_OUTPUT_DIRECTORY}/ USE_SOURCE_PERMISSIONS - DESTINATION bin) + DESTINATION ${CMAKE_INSTALL_BINDIR}) if (WITH_STATIC) install(TARGETS shadowsocks-libev - ARCHIVE DESTINATION lib) + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif () install(TARGETS shadowsocks-libev-shared - LIBRARY DESTINATION lib) + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(FILES shadowsocks.h DESTINATION include) +install(FILES shadowsocks.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) add_custom_target(distclean diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index c255b608..00000000 --- a/src/Makefile.am +++ /dev/null @@ -1,115 +0,0 @@ -VERSION_INFO = 2:0:0 - -AM_CFLAGS = -g -O2 -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -std=gnu99 -D_GNU_SOURCE -AM_CFLAGS += $(PTHREAD_CFLAGS) -if !USE_SYSTEM_SHARED_LIB -AM_CFLAGS += -I$(top_srcdir)/libbloom -AM_CFLAGS += -I$(top_srcdir)/libipset/include -AM_CFLAGS += -I$(top_srcdir)/libcork/include -endif -AM_CFLAGS += $(LIBPCRE_CFLAGS) - -SS_COMMON_LIBS = $(INET_NTOP_LIB) $(LIBPCRE_LIBS) $(NETFILTER_CONNTRACK_LIBS) $(NFTABLES_LIBS) -if !USE_SYSTEM_SHARED_LIB -SS_COMMON_LIBS += $(top_builddir)/libbloom/libbloom.la \ - $(top_builddir)/libipset/libipset.la \ - $(top_builddir)/libcork/libcork.la -else -SS_COMMON_LIBS += -lbloom -lcork -lcorkipset -endif -SS_COMMON_LIBS += -lev -lsodium -lm - -bin_PROGRAMS = ss-local ss-tunnel ss-server -if !BUILD_WINCOMPAT -bin_PROGRAMS += ss-manager -endif - -acl_src = rule.c \ - acl.c - -crypto_src = crypto.c \ - aead.c \ - stream.c \ - ppbloom.c \ - base64.c - -plugin_src = plugin.c - -common_src = utils.c \ - jconf.c \ - json.c \ - udprelay.c \ - cache.c \ - netutils.c - -if BUILD_WINCOMPAT -common_src += winsock.c -endif - -ss_local_SOURCES = local.c \ - $(common_src) \ - $(crypto_src) \ - $(plugin_src) \ - $(acl_src) - -ss_tunnel_SOURCES = tunnel.c \ - $(common_src) \ - $(crypto_src) \ - $(plugin_src) - -ss_server_SOURCES = resolv.c \ - server.c \ - $(common_src) \ - $(crypto_src) \ - $(plugin_src) \ - ${acl_src} - -ss_manager_SOURCES = utils.c \ - jconf.c \ - json.c \ - netutils.c \ - manager.c - -ss_local_LDADD = $(SS_COMMON_LIBS) -ss_tunnel_LDADD = $(SS_COMMON_LIBS) -ss_server_LDADD = $(SS_COMMON_LIBS) -ss_manager_LDADD = $(SS_COMMON_LIBS) -ss_local_LDADD += -lcares -ss_tunnel_LDADD += -lcares -ss_server_LDADD += -lcares -ss_manager_LDADD += -lcares - -ss_local_CFLAGS = $(AM_CFLAGS) -DMODULE_LOCAL -ss_tunnel_CFLAGS = $(AM_CFLAGS) -DMODULE_TUNNEL -ss_server_CFLAGS = $(AM_CFLAGS) -DMODULE_REMOTE -ss_manager_CFLAGS = $(AM_CFLAGS) -DMODULE_MANAGER - -if BUILD_REDIRECTOR -bin_SCRIPTS = ss-nat -bin_PROGRAMS += ss-redir -ss_redir_SOURCES = utils.c \ - jconf.c \ - json.c \ - netutils.c \ - cache.c \ - udprelay.c \ - redir.c \ - $(crypto_src) \ - $(plugin_src) - -ss_redir_CFLAGS = $(AM_CFLAGS) -DMODULE_REDIR -ss_redir_LDADD = $(SS_COMMON_LIBS) -ss_redir_LDADD += -lcares -endif - -lib_LTLIBRARIES = libshadowsocks-libev.la -libshadowsocks_libev_la_SOURCES = $(ss_local_SOURCES) -libshadowsocks_libev_la_CFLAGS = $(ss_local_CFLAGS) -DLIB_ONLY -libshadowsocks_libev_la_LDFLAGS = -version-info $(VERSION_INFO) -libshadowsocks_libev_la_LIBADD = $(ss_local_LDADD) -include_HEADERS = shadowsocks.h - -noinst_HEADERS = acl.h crypto.h stream.h aead.h json.h netutils.h redir.h server.h uthash.h \ - cache.h local.h plugin.h resolv.h tunnel.h utils.h base64.h ppbloom.h \ - common.h jconf.h manager.h rule.h socks5.h udprelay.h winsock.h -EXTRA_DIST = ss-nat diff --git a/src/rule.c b/src/rule.c index 737013e6..6f8428de 100644 --- a/src/rule.c +++ b/src/rule.c @@ -78,16 +78,21 @@ int init_rule(rule_t *rule) { if (rule->pattern_re == NULL) { - const char *reerr; - int reerroffset; + int errcode; + PCRE2_SIZE erroffset; rule->pattern_re = - pcre_compile(rule->pattern, 0, &reerr, &reerroffset, NULL); + 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, reerr, reerroffset); + rule->pattern, errbuf, (int)erroffset); return 0; } + rule->match_data = pcre2_match_data_create_from_pattern( + rule->pattern_re, NULL); } return 1; @@ -105,8 +110,8 @@ lookup_rule(const struct cork_dllist *rules, const char *name, size_t name_len) cork_dllist_foreach_void(rules, curr, next) { rule_t *rule = cork_container_of(curr, rule_t, entries); - if (pcre_exec(rule->pattern_re, NULL, - name, name_len, 0, 0, NULL, 0) >= 0) + if (pcre2_match(rule->pattern_re, (PCRE2_SPTR)name, + name_len, 0, 0, rule->match_data, NULL) >= 0) return rule; } @@ -127,7 +132,9 @@ free_rule(rule_t *rule) return; ss_free(rule->pattern); + if (rule->match_data != NULL) + pcre2_match_data_free(rule->match_data); if (rule->pattern_re != NULL) - pcre_free(rule->pattern_re); + pcre2_code_free(rule->pattern_re); ss_free(rule); } diff --git a/src/rule.h b/src/rule.h index 015bc42b..ae907f77 100644 --- a/src/rule.h +++ b/src/rule.h @@ -33,17 +33,15 @@ #include -#ifdef HAVE_PCRE_H -#include -#elif HAVE_PCRE_PCRE_H -#include -#endif +#define PCRE2_CODE_UNIT_WIDTH 8 +#include typedef struct rule { char *pattern; /* Runtime fields */ - pcre *pattern_re; + pcre2_code *pattern_re; + pcre2_match_data *match_data; struct cork_dllist_item entries; } rule_t; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 00000000..bba512f5 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,118 @@ +# 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-shared) +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-shared) +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-shared) +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-shared) +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-shared) +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") diff --git a/tests/stress_test.py b/tests/stress_test.py new file mode 100755 index 00000000..0ec13aae --- /dev/null +++ b/tests/stress_test.py @@ -0,0 +1,445 @@ +#!/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() diff --git a/tests/test_base64.c b/tests/test_base64.c new file mode 100644 index 00000000..f9c9d45f --- /dev/null +++ b/tests/test_base64.c @@ -0,0 +1,116 @@ +#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; +} diff --git a/tests/test_buffer.c b/tests/test_buffer.c new file mode 100644 index 00000000..5d5639f9 --- /dev/null +++ b/tests/test_buffer.c @@ -0,0 +1,103 @@ +#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; +} diff --git a/tests/test_cache.c b/tests/test_cache.c new file mode 100644 index 00000000..d0e00b7f --- /dev/null +++ b/tests/test_cache.c @@ -0,0 +1,129 @@ +#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; +} diff --git a/tests/test_crypto.c b/tests/test_crypto.c new file mode 100644 index 00000000..7359ad0c --- /dev/null +++ b/tests/test_crypto.c @@ -0,0 +1,164 @@ +#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; +} diff --git a/tests/test_jconf.c b/tests/test_jconf.c new file mode 100644 index 00000000..797112e6 --- /dev/null +++ b/tests/test_jconf.c @@ -0,0 +1,85 @@ +#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; +} diff --git a/tests/test_json.c b/tests/test_json.c new file mode 100644 index 00000000..9606284d --- /dev/null +++ b/tests/test_json.c @@ -0,0 +1,130 @@ +#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; +} diff --git a/tests/test_netutils.c b/tests/test_netutils.c new file mode 100644 index 00000000..beb99dd8 --- /dev/null +++ b/tests/test_netutils.c @@ -0,0 +1,115 @@ +#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; +} diff --git a/tests/test_ppbloom.c b/tests/test_ppbloom.c new file mode 100644 index 00000000..0ef17bbc --- /dev/null +++ b/tests/test_ppbloom.c @@ -0,0 +1,74 @@ +#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; +} diff --git a/tests/test_rule.c b/tests/test_rule.c new file mode 100644 index 00000000..8c14b27a --- /dev/null +++ b/tests/test_rule.c @@ -0,0 +1,126 @@ +#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; +} diff --git a/tests/test_utils.c b/tests/test_utils.c new file mode 100644 index 00000000..83046dab --- /dev/null +++ b/tests/test_utils.c @@ -0,0 +1,76 @@ +#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; +}