diff --git a/.ci/build-project.ps1 b/.ci/build-project.ps1 new file mode 100644 index 0000000..b0d7643 --- /dev/null +++ b/.ci/build-project.ps1 @@ -0,0 +1,45 @@ +# Build project. +# +# The script assumes that it will be called from inside the project directory. +# +# Usage: .ci\build-project.ps1 [vcpkg-directory [build-directory-name]] +# - vcpkg-directory: Optional full path to Vcpkg directory. Default: $HOME\vcpkg +# - build-directory-name: Optional name of build directory. Default: build. +# Can only be set of vcpkg-directory is set as well. +# +# Example 1: .ci\build-project.ps1 +# Example 2: .ci\build-project.ps1 $HOME\vcpkg-clang +# Example 3: .ci\build-project.ps1 $HOME\vcpkg-clang build-clang + +$ErrorActionPreference="Stop" + +$VCPKG_DIR=$args[0] +$BUILD_DIR=$args[1] + +if ($null -eq $VCPKG_DIR) { $VCPKG_DIR="$HOME\vcpkg" } +if ($null -eq $BUILD_DIR) { $BUILD_DIR="build" } + +# only pass toolchain file to CMake if Vcpkg is installed +if (Test-Path "$VCPKG_DIR" -PathType Container) { + $TOOLCHAIN="$VCPKG_DIR\scripts\buildsystems\vcpkg.cmake" +} else { + $TOOLCHAIN="False" +} + +Write-Host "---- build-project.ps1 ----" +Write-Host "VCPKG_DIR: $VCPKG_DIR" +Write-Host "BUILD_DIR: $BUILD_DIR" +Write-Host "CMAKE_TOOLCHAIN_FILE: $TOOLCHAIN" +Write-Host "---------------------------" + +if (-not (Get-Command cmake -ErrorAction SilentlyContinue)) { + New-Alias -Name cmake -Value "$Env:ProgramFiles\CMake\bin\cmake.exe" +} + +New-Item -Name $BUILD_DIR -ItemType Directory +Push-Location $BUILD_DIR +$ErrorActionPreference = "Stop"; +cmake -DCMAKE_BUILD_TYPE=Release -DVCPKG_TARGET_TRIPLET=x64-windows -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN" .. +cmake --build . --config Release +if ($LASTEXITCODE) { Throw "BUILD FAILED!" } +Pop-Location \ No newline at end of file diff --git a/.ci/install-vcpkg.ps1 b/.ci/install-vcpkg.ps1 new file mode 100644 index 0000000..a9f4bc1 --- /dev/null +++ b/.ci/install-vcpkg.ps1 @@ -0,0 +1,38 @@ + +# Build Vcpkg and install dependency packages. +# +# Usage: .ci\install-vcpkg.ps1 [vcpkg directory name] +# - project directory: Path to the project sources where the .vcpkg file is located. +# - vcpkg directory name: optional name of directory where Vcpkg will be clone'd into +# +# Example 1: .ci\install-vcpkg.ps1 $Env:GITHUB_WORKSPACE +# Example 2: .ci\install-vcpkg.ps1 $Env:APPVEYOR_BUILD_FOLDER vcpkg-msvc + +$ErrorActionPreference="Stop" + +if ($args.Count -lt 1) { Exit 1 } + +$PROJECT_DIR=$args[0] +$VCPKG_DIR=$args[1] + +if ($null -eq $VCPKG_DIR) { $VCPKG_DIR="vcpkg" } + +# do nothing if .vcpkg file doesn't exist +if (-not (Test-Path "$PROJECT_DIR\.vcpkg" -PathType Leaf)) { Write-Host ".vcpkg file does not exist, skipping Vcpkg installation."; Exit 0 } + +Write-Host "---- install-vcpkg.ps1 ----" +Write-Host "PROJECT_DIR: $PROJECT_DIR" +Write-Host "VCPKG_DIR: $VCPKG_DIR" +Write-Host "---------------------------" + +if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + New-Alias -Name git -Value "$Env:ProgramFiles\Git\bin\git.exe" +} + +Push-Location "$HOME" +git clone --quiet --depth 1 https://github.com/Microsoft/vcpkg.git $VCPKG_DIR +Set-Location $VCPKG_DIR +.\bootstrap-vcpkg.bat -disableMetrics +$packages = Get-Content "$PROJECT_DIR\.vcpkg" +.\vcpkg.exe install --triplet x64-windows $packages +Pop-Location \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..56bec80 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,42 @@ +--- +version: 2.1 + +orbs: + win: circleci/windows@2.4.0 + +jobs: + linux-gcc: + machine: + image: ubuntu-1604:201903-01 + steps: + - checkout + - run: + name: Install Software + command: | + sudo apt-get update + sudo apt-get install -y cmake build-essential + mkdir build + cd build + cmake .. + make + windows-msvc: + executor: win/default + steps: + - checkout + - run: + name: Download CMake + # yamllint disable rule:line-length + command: | + $ProgressPreference = "SilentlyContinue" + Invoke-WebRequest -URI https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-win64-x64.zip -OutFile $Env:HOMEPATH\cmake-3.16.4-win64-x64.zip + Expand-Archive $Env:HOMEPATH\cmake-3.16.4-win64-x64.zip -DestinationPath "$Env:ProgramFiles" + Rename-Item "$Env:ProgramFiles\cmake-3.16.4-win64-x64" -NewName CMake + # yamllint enable rule:line-length + - run: .ci\install-vcpkg.ps1 "$Env:CIRCLE_WORKING_DIRECTORY" + - run: .ci\build-project.ps1 +workflows: + version: 2 + run-all: + jobs: + - linux-gcc + - windows-msvc diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 0000000..bd04bd9 --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,82 @@ +--- +name: CMake + +# yamllint disable-line rule:truthy +on: + push: + pull_request: + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should + # work equally well on Windows or Mac. You can convert this to a matrix + # build if you need cross-platform coverage. + # yamllint disable-line rule:line-length + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + - os: windows-latest + - os: macos-latest + + steps: + - uses: actions/checkout@v2 + with: + submodules: true + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Create Build Environment + # Some projects don't allow in-source building, so create a separate + # build directory. We'll use this as our working directory for all + # subsequent commands + run: cmake -E make_directory ${{github.workspace}}/build + + - name: Configure CMake + # Use a bash shell so we can use the same syntax for environment + # variable access regardless of the host operating system + shell: bash + working-directory: ${{github.workspace}}/build + # Note the current convention is to use the -S and -B options here to + # specify source and build directories, but this is only available + # with CMake 3.13 and higher. The CMake binaries on the Github Actions + # machines are (as of this writing) 3.12 + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + + - name: Build + working-directory: ${{github.workspace}}/build + shell: bash + # Execute the build. You can specify a specific target + # with "--target " + run: cmake --build . --config $BUILD_TYPE + + - name: Test + working-directory: ${{github.workspace}}/build + shell: bash + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more + # detail + run: ctest -C $BUILD_TYPE + + - if: ${{ failure() }} + name: Upload test data + uses: actions/upload-artifact@v2 + with: + name: tests-out + path: tests + + - if: ${{ failure() }} + name: Upload cmake test output + uses: actions/upload-artifact@v2 + with: + name: tests-out + path: build/Testing diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml new file mode 100644 index 0000000..4365177 --- /dev/null +++ b/.github/workflows/debug.yml @@ -0,0 +1,55 @@ +--- +name: Debug + +# yamllint disable-line rule:truthy +on: + workflow_dispatch: + +jobs: + + # Oh, github, for a company that is built around the git VCS, how is it + # that you have managed to break the repositories so much? + # + debug_github_repo: + name: Debug Github Repo + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Debug data output + run: | + echo ========== + echo git status + git status + echo ========== + echo git tag + git tag + echo ========== + echo git describe + git describe || true + echo ========== + echo git for-each-ref refs/heads + git for-each-ref refs/heads + echo ========== + echo git for-each-ref refs/tags + git for-each-ref refs/tags + echo ========== + echo ls .git/refs/heads + ls .git/refs/heads + echo ========== + echo ls .git/refs/tags + ls .git/refs/tags + echo ========== + TYPE=$(git cat-file -t $GITHUB_REF) + echo REF=$GITHUB_REF + echo TAGTYPE=$TYPE + echo ========== + echo git cat-file $TYPE $GITHUB_REF + git cat-file $TYPE $GITHUB_REF diff --git a/.github/workflows/openwrt.yml b/.github/workflows/openwrt.yml new file mode 100644 index 0000000..7ed488a --- /dev/null +++ b/.github/workflows/openwrt.yml @@ -0,0 +1,112 @@ +--- +name: Openwrt Build + +# yamllint disable-line rule:truthy +on: + release: + types: + - published + - created + - edited + push: + branches: + - openwrt + + workflow_dispatch: + +jobs: + build: + name: Build ipkg + runs-on: ubuntu-latest + + defaults: + run: + working-directory: openwrt + + steps: + - name: Checkout openwrt + uses: actions/checkout@v2 + with: + path: openwrt + repository: openwrt/openwrt + + - name: Set openwrt ref + id: openwrt_ref + run: | + echo ::set-output name=REF::$(git rev-parse --short HEAD) + git rev-parse --short HEAD + + - name: Checkout n2n + uses: actions/checkout@v2 + with: + path: n2n + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + working-directory: n2n + + - name: Set n2n ref + id: n2n_ref + run: | + echo ::set-output name=REF::$(./scripts/version.sh) + ./scripts/version.sh + working-directory: n2n + + - name: Copy n2n package definition into openwrt + run: | + cp -r n2n/packages/openwrt openwrt/package/n2n + working-directory: ./ + + - name: Cache openwrt source downloads + uses: actions/cache@v2 + with: + path: openwrt/dl + key: openwrt-dl-${{ steps.openwrt_ref.outputs.REF }} + + - name: Setup openwrt config and environment + run: | + echo "CONFIG_TARGET_x86=y" >.config + echo "CONFIG_TARGET_x86_64=y" >>.config + + - name: Add n2n package to openwrt config + run: | + echo "CONFIG_PACKAGE_n2n-edge=m" >>.config + echo "CONFIG_PACKAGE_n2n-supernode=m" >>.config + + - name: Build a full config from our stub file + run: | + make defconfig + + - name: Download openwrt sources + run: | + make download + + - name: Build openwrt build environment + run: | + make -j `nproc` tools/install toolchain/install + + - name: Build n2n dependancies + run: | + make -j `nproc` package/libs/libpcap/compile + + - name: Build n2n openwrt packages + env: + N2N_PKG_VERSION: ${{ steps.n2n_ref.outputs.REF }} + run: | + echo "Build for $N2N_PKG_VERSION" + export N2N_PKG_VERSION + make package/n2n/clean V=s + make package/n2n/prepare USE_SOURCE_DIR=$GITHUB_WORKSPACE/n2n V=s + make package/n2n/compile V=s + +# FIXME: add a way to run the test suite! +# - name: Run embedded tests +# run: make test + + - name: Upload built artifacts + uses: actions/upload-artifact@v2 + with: + name: built-ipkgs + path: openwrt/bin/packages/*/base/*.ipk diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..20fac5d --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,598 @@ +--- +name: Testing + +# yamllint disable-line rule:truthy +on: + push: + pull_request: + +jobs: + smoketest: + name: Smoke test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Run minimal test set + run: | + ./autogen.sh + ./configure + make test + + lint: + name: Code syntax + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Fix Checkout + run: | + git fetch --force --tags + + + - name: Make the makefiles + run: | + ./autogen.sh + ./configure + + - name: Install essential + run: | + sudo apt update + make build-dep + + - name: Run the lint tools + run: | + make lint + + test_linux: + needs: smoketest + name: Test Linux + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: + - ubuntu-20.04 + - ubuntu-18.04 + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Fix Checkout + run: | + git fetch --force --tags + + + - name: Install essential + run: | + sudo apt-get update + sudo apt-get install build-essential + + - name: generate a makefile and use it to install more packages + run: | + ./autogen.sh + ./configure + make build-dep + shell: bash + + - name: Run the real configure step + run: | + export CFLAGS="-fprofile-arcs -ftest-coverage" + export LDFLAGS="--coverage" + ./configure + shell: bash + + - name: Run embedded unit tests + run: make test.units + shell: bash + + - if: ${{ failure() }} + name: Move test outputs to an arch specific location + shell: bash + run: | + mkdir -p tests/${{ matrix.os }} + mv tests/*.out tests/${{ matrix.os }} + + - if: ${{ failure() }} + name: Upload tests output + uses: actions/upload-artifact@v2 + with: + name: tests-out + path: tests + + - name: Generate coverage reports + run: | + make gcov + make cover COVERAGEDIR=coverage/${{ matrix.os }} + shell: bash + + - name: Upload gcovr report artifact + uses: actions/upload-artifact@v2 + with: + name: coverage + path: coverage + + - name: Upload data to codecov + uses: codecov/codecov-action@v2 + + test_macos: + needs: smoketest + name: Test MacOS + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: + - macos-10.15 + - macos-11 + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Fix Checkout + run: | + git fetch --force --tags + + + - name: Install packages + run: | + brew install automake + + - name: generate a makefile and use it to install more packages + run: | + ./autogen.sh + ./configure + make build-dep + shell: bash + + - name: Run the real configure step + run: | + export CFLAGS="-fprofile-arcs -ftest-coverage" + export LDFLAGS="--coverage" + ./configure + shell: bash + + - name: Run embedded unit tests + run: make test.units + shell: bash + + - if: ${{ failure() }} + name: Move test outputs to an arch specific location + shell: bash + run: | + mkdir -p tests/${{ matrix.os }} + mv tests/*.out tests/${{ matrix.os }} + + - if: ${{ failure() }} + name: Upload tests output + uses: actions/upload-artifact@v2 + with: + name: tests-out + path: tests + + - name: Generate coverage reports + run: | + make gcov + # This was working fine for tens of jobs, up until + # 2021-10-19T18:53+0100 and it still works fine when run from my + # personal github actions. The next run at 2021-10-19T19:08+0100 + # didnt work. + # Assume that they changed something on the runner - I cannot debug + # it as I do not have a Mac. + # + # make cover COVERAGEDIR=coverage/${{ matrix.os }} + shell: bash + + # - name: Upload gcovr report artifact + # uses: actions/upload-artifact@v2 + # with: + # name: coverage + # path: coverage + + - name: Upload data to codecov + uses: codecov/codecov-action@v2 + + test_windows: + needs: smoketest + name: Test Windows + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: + - windows-2019 + - windows-2022 + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Fix Checkout + run: | + git fetch --force --tags + + + - name: generate a makefile and use it to install more packages + run: | + # This is a pretty big hammer, but gets the windows compile moving + ./scripts/hack_fakeautoconf.sh + make build-dep + shell: bash + + - name: Run a configure step + run: | + export CFLAGS="-fprofile-arcs -ftest-coverage" + export LDFLAGS="--coverage" + ./scripts/hack_fakeautoconf.sh + shell: bash + + - name: Run embedded unit tests + run: make test.units + shell: bash + + - if: ${{ failure() }} + name: Move test outputs to an arch specific location + shell: bash + run: | + mkdir -p tests/${{ matrix.os }} + mv tests/*.out tests/${{ matrix.os }} + + - if: ${{ failure() }} + name: Upload tests output + uses: actions/upload-artifact@v2 + with: + name: tests-out + path: tests + + - name: Generate coverage data + run: | + make gcov + shell: bash + + - name: Upload data to codecov + uses: codecov/codecov-action@v2 + + package_dpkg: + name: Package for Debian/Ubuntu + needs: + - test_linux + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + arch: + - amd64 + - arm64 + - armhf + - i386 + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Install packages needed for build + run: | + sudo apt-get update + sudo apt-get install debhelper build-essential \ + crossbuild-essential-${{ matrix.arch }} + + - name: Configure + # The HOST_TRIPLET line is not easily foldable + # yamllint disable rule:line-length + run: | + # This will warn about CC, but we cannot set CC until we run it :-S + HOST_TRIPLET=$(dpkg-architecture -a${{ matrix.arch }} -q DEB_HOST_GNU_TYPE) + export CC=$HOST_TRIPLET-gcc + export AR=$HOST_TRIPLET-ar + ./autogen.sh + ./configure --host $HOST_TRIPLET + cd packages/debian/ + ./configure EXTN=${{ matrix.arch }} + # yamllint enable rule:line-length + + - name: Build + run: | + cd packages/debian/ + make + + - name: Upload dpkg + uses: actions/upload-artifact@v2 + with: + name: packages-dpkg + path: packages/debian/*.deb + + package_rpm: + name: Package for Redhat/RPM + needs: + - test_linux + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Install packages needed for build + run: | + sudo apt-get install rpm + + - name: Configure + run: | + ./autogen.sh + ./configure + cd packages/rpm/ + ./configure + + - name: Build + run: | + make + HOME=$(pwd)/../ + cd packages/rpm/ + make + cd ../../ + mv ../rpmbuild ./ + + - name: Upload rpm + uses: actions/upload-artifact@v2 + with: + name: packages-rpm + path: rpmbuild/RPMS/x86_64/*.rpm + + binaries_windows: + name: Binaries for Windows (x86_64-pc-mingw64) + needs: + - test_windows + runs-on: windows-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Configure and Build + shell: bash + run: | + ./scripts/hack_fakeautoconf.sh + make + + - name: Create binary dir + shell: bash + run: | + make install DESTDIR=binaries/x86_64-pc-mingw64 + + - name: Upload binary artifacts + uses: actions/upload-artifact@v2 + with: + name: binaries + path: binaries + + binaries_macos: + name: Binaries for MacOS + needs: + - test_macos + runs-on: macos-latest + strategy: + fail-fast: true + matrix: + arch: + - x86_64-apple-macos + - arm64-apple-macos + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Install packages needed for build + run: | + brew install automake + + - name: Configure and Build + shell: bash + run: | + # this is a hack! it assumes the default SDK is the 'right' one + export SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk + ./autogen.sh + export CC=clang + export CFLAGS="-target ${{ matrix.arch }}" + export LDFLAGS="-target ${{ matrix.arch }}" + ./configure --host=${{ matrix.arch }} + make + + - if: ${{ failure() }} + name: Upload config.log output + uses: actions/upload-artifact@v2 + with: + name: config-log-${{ matrix.arch }} + path: config.log + + - name: Create binary dir + shell: bash + run: | + make install DESTDIR=binaries/${{ matrix.arch }} + + - name: Upload binary artifacts + uses: actions/upload-artifact@v2 + with: + name: binaries + path: binaries + + binaries_macos_universal: + name: Binaries for MacOS (universal arch) + needs: + - test_macos + runs-on: macos-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Install packages needed for build + run: | + brew install automake + + - name: Configure and Build + shell: bash + run: | + # this is a hack! it assumes the default SDK is the 'right' one + export SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk + ./autogen.sh + export CC=clang + export CFLAGS="-arch x86_64 -arch arm64" + export LDFLAGS="-arch x86_64 -arch arm64" + ./configure + make + + - name: Create binary dir + shell: bash + run: | + make install DESTDIR=binaries/universal-apple-darwin + + - name: Upload binary artifacts + uses: actions/upload-artifact@v2 + with: + name: binaries + path: binaries + + binaries_linux_crosscompile: + name: Binaries for linux + needs: + - test_linux + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + arch: + - arm-linux-gnueabi + + # I assume these architectures produce working code, but this has + # not been directly confirmed. + # They are compiled dynamically against normal libc, so will not + # work on openwrt. + - aarch64-linux-gnu + - mips-linux-gnu + - mipsel-linux-gnu + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Install cross compiler + run: | + sudo apt-get update + sudo apt-get install \ + binutils-${{ matrix.arch }} \ + gcc-${{ matrix.arch }} + + - name: Configure and Build + shell: bash + run: | + ./autogen.sh + export CC=${{ matrix.arch }}-gcc + export AR=${{ matrix.arch }}-ar + ./configure --host ${{ matrix.arch }} + make + + - name: Create binary dir + shell: bash + run: | + make install DESTDIR=binaries/${{ matrix.arch }} + + - name: Upload binary artifacts + uses: actions/upload-artifact@v2 + with: + name: binaries + path: binaries + + # Given the clearly documented use of annotated tags to signal releases, + # it seems strange that there is no simple way to trigger actions if the + # tag is annotated. So we need to jump through some extra hoops. + # + # Looking at https://github.com/actions/checkout/issues/290 seems to show + # that github just doesnt care about how git expects annotated tags to be + # used. + # + # This workflow has added a `git fetch --force --tags` to every job that + # needs to have working tags + + upload_release: + name: Upload Release Assets + if: startsWith(github.ref, 'refs/tags/') + needs: + - package_dpkg + - package_rpm + - binaries_windows + - binaries_macos + - binaries_macos_universal + - binaries_linux_crosscompile + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fix Checkout + run: | + git fetch --force --tags + + - name: Get Tag Type + id: get_tagtype + run: | + TYPE=$(git cat-file -t $GITHUB_REF) + echo "::set-output name=TAGTYPE::$TYPE" + echo ========== + echo REF=$GITHUB_REF + echo TAGTYPE=$TYPE + + - name: Fetch all Artifacts + if: steps.get_tagtype.outputs.TAGTYPE == 'tag' + uses: actions/download-artifact@v2 + with: + path: artifacts + + - name: Upload Assets to Release + if: steps.get_tagtype.outputs.TAGTYPE == 'tag' + uses: softprops/action-gh-release@v1 + with: + prerelease: true + files: | + artifacts/packages-dpkg/*.deb + artifacts/packages-rpm/*.rpm diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84c2026 --- /dev/null +++ b/.gitignore @@ -0,0 +1,52 @@ +*.o +*.a +*.gz +configure +config.* +/Makefile +tools/Makefile +autom4te.cache +edge +example_edge_embed_quick_edge_init +example_edge_embed +example_sn_embed +supernode +tools/n2n-benchmark +tools/n2n-decode +tools/n2n-keygen +build +.idea +.vscode +cmake-build-default +packages/debian/debian/changelog +packages/debian/debian/control +packages/debian/debian/files +packages/debian/debian/rules +packages/etc/systemd/system/edge-ntopng@.service +packages/etc/systemd/system/edge.service +packages/etc/systemd/system/edge@.service +packages/etc/systemd/system/supernode.service +*dSYM* + +cmake-build-*/ + +# Binaries built to run tests +tools/tests-compress +tools/tests-elliptic +tools/tests-hashing +tools/tests-transform +tools/tests-wire + +# Files generated while running tests +tests/*.out + +# Files generated while running coverage reports +*.gcno +*.gcda +*.gcov +coverage/ + +# Files generated while running linting +*.indent +*.unc-backup.md5~ +*.unc-backup~ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..df11e25 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,8 @@ +[submodule "thirdparty/miniupnp"] + path = thirdparty/miniupnp + url = https://github.com/miniupnp/miniupnp.git + ignore = dirty +[submodule "thirdparty/libnatpmp"] + path = thirdparty/libnatpmp + url = https://github.com/miniupnp/libnatpmp.git + ignore = dirty diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..08d9211 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,26 @@ +--- +language: c++ +dist: xenial + +compiler: + - clang + - gcc + +install: + - sudo apt-get update || true + - sudo apt-get install build-essential + +before_script: + - git clone https://github.com/ntop/n2n.git; cd n2n; ./autogen.sh; make; cd .. + - ./autogen.sh + +script: + - ./configure + - make + +notifications: + email: + recipients: + - deri@ntop.org + on_success: never + on_failure: always diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..b54dd76 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,8 @@ +--- +extends: default + +rules: + # 80 chars should be enough, but don't fail if a line is longer + line-length: + max: 80 + level: warning diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3893fcc --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,89 @@ +# Changelog + +## n2n 2.8 (August 2020) + +This release brings significant new features to n2n's crypto world and offers +some compression opportunities. The added support for routing table manipulation +might increase comfort. Besides further honing existing features, this release +addresses some bugs. + +### New Features + +* Two lightweight stream ciphers: ChaCha20 (optional, through OpenSSL) & SPECK (integrated) +* Full Header Encryption (including packet checksumming as well as replay protection) +* A callback interface to better integrate n2n in third party software (you can still use it stand-alone) +* Enable the integrated LZO1x compression +* Add optional ZSTD compression (through zstdlib) +* Support for changing system routes at program start and end +* User and group id parameter for supernode +* Application of cryptography in n2n is seperately documented +* Add a new pseudo random number generator with higher periodicity seeded with more entropy if available + +### Improvements + +* Have AES and ChaCha20 use OpenSSL's `evp_*` interface to make better use of available hardware acceleration +* Fix invalid sendto when supernode name resolution fails +* Update to supernode's purge logic +* Extended management supernode's port output +* Fix read tap device failed when OS wakes up from sleep +* Free choice of supernode's management UDP port (for multiple supernodes on one machine) +* Additional trace messages to better indicate established connections and connection type +* Fix edge's register-to-supernode loop +* Remove redundant code +* Restructure the code in directories +* Clean-up platform-dependant code +* Compile fixes for Windows +* Fix build warnings +* …and many more under-the-hood fixes and tunings + +## n2n 2.6 (March 2020) + +The 2.6 release is mostly a maintenance release to address the issues +of 2.4 that has been the first release since a long time of silence. + +### New Features + +* AES encryption that features an overall speed bump (12x speed) and security with respect to Twofish used in the previous n2n version +* Add ability to specify a whitelist of allowed communities on the supernode +* Implement local peers discovery via multicast +* Full peer-to-peer topology support. +* Add support for multiple edge systemd services +* Add benchmark tool for the encryption throughput +* Implement packet stats for P2P vs supernode communication +* Automatically drop privileges to user n2n +* Add support for ARM64 build +* More options to control MTU, P2P connections, TOS and log verbosity +* Implement a wireshark dissector for the n2n protocol +* Implement n2n-decode utility to decode and dump traffic to PCAP + + +### Improvements +* Extensive Windows and OpenWRT support. +* Windows compilation fixes and instructions +* Instructions and makefile file to build n2n on OpenWRT +* MacOS compilation fixes and instructions +* Improve the connection stability and the chances to establish a P2P connection +* Stable and more resilient connection. +* Remove keyschedule support to simplify the encryption code +* Replace peers linked list with hash table for faster lookup in big networks +* Integrate the changes made in the meyerd fork of n2n +* Remove calls to system() in tuntap_linux and use netlink instead +* n2n version improvements + +## n2n 2.4 (August 2018) + +This is the first release after 2012 and thus it is focusing mainly +on making it work on current operating system versions, so that the +next release will be based on modern code. + +### New Features +* Added deb/rpm packages +* Added systemd configuration files +* Added ability to read configuration files instead of using only the CLI (needed for packaging) +* Added n2n Android app +* Implemented simple API to embed n2n in applications (in addition to use it stand-alone) + +### Improvements +* Major code cleanup +* Fixed compilation issues on MacOS +* Fixed Linux segmentation fault diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..80677a5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,331 @@ +project(n2n) +cmake_minimum_required(VERSION 2.6) +include(CheckFunctionExists) +SET(CMAKE_VERBOSE_MAKEFILE ON) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# N2n release information +execute_process( + COMMAND scripts/version.sh + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE PACKAGE_VERSION + RESULT_VARIABLE GIT_ERROR_CODE +) +if (NOT GIT_ERROR_CODE EQUAL 0) + # - if we can run version.sh and it exits with an error that is signaling + # a build failure. + # - if we are on windows with no MSYS or Cygwin, we cannot run version.sh + # which is the fallback case handled below + # TODO: Distinguish between these two cases + + # Fallback to just using the non dynamic short version string + file(STRINGS VERSION PACKAGE_VERSION) +endif (NOT GIT_ERROR_CODE EQUAL 0) + +string(STRIP "${PACKAGE_VERSION}" PACKAGE_VERSION) +MESSAGE(STATUS "Build for version: ${PACKAGE_VERSION}") + +add_definitions(-DCMAKE_BUILD) +add_definitions(-DPACKAGE_OSNAME="${CMAKE_SYSTEM_NAME}") +add_definitions(-DPACKAGE_VERSION="${PACKAGE_VERSION}") + +# third-party directory +set(THIRD_PARTY_DIR ${CMAKE_SOURCE_DIR}/thirdparty) + +# Build information +OPTION(BUILD_SHARED_LIBS "BUILD Shared Library" OFF) + +# N2n specific params +OPTION(N2N_OPTION_USE_PTHREAD "USE PTHREAD Library" OFF) +OPTION(N2N_OPTION_USE_OPENSSL "USE OPENSSL Library" OFF) +OPTION(N2N_OPTION_USE_CAPLIB "USE CAP Library" OFF) +OPTION(N2N_OPTION_USE_PCAPLIB "USE PCAP Library" OFF) +OPTION(N2N_OPTION_USE_ZSTD "USE ZSTD Library" OFF) +OPTION(N2N_OPTION_USE_PORTMAPPING "USE MINIUPNP and NATPMP Libraries" OFF) + + +if(N2N_OPTION_USE_PTHREAD) + find_library(PTHREAD_LIB pthread) + if(NOT PTHREAD_LIB) + MESSAGE(FATAL_ERROR "libpthread not found.") + endif(NOT PTHREAD_LIB) + MESSAGE(STATUS "Using libpthread.") + ADD_DEFINITIONS("-DHAVE_PTHREAD") +endif(N2N_OPTION_USE_PTHREAD) + +if(N2N_OPTION_USE_OPENSSL) + find_package(OpenSSL QUIET) + if(NOT OPENSSL_FOUND) + MESSAGE(FATAL_ERROR "OpenSSL not found.") + endif(NOT OPENSSL_FOUND) + MESSAGE(STATUS "Found OpenSSL ${OPENSSL_VERSION}") + string(COMPARE GREATER "${OPENSSL_VERSION}" "1.1" OPENSSL_V11) + if(NOT OPENSSL_V11) + MESSAGE(FATAL_ERROR "OpenSSL too old") + endif() + include_directories(${OPENSSL_INCLUDE_DIR}) + add_definitions(-DHAVE_OPENSSL_1_1) +endif(N2N_OPTION_USE_OPENSSL) + +if(N2N_OPTION_USE_ZSTD) + find_library(LIBZSTD zstd) + if(NOT LIBZSTD) + MESSAGE(FATAL_ERROR "libzstd not found.") + endif(NOT LIBZSTD) + MESSAGE(STATUS "Using libztd.") + add_definitions(-DHAVE_ZSTD) +endif(N2N_OPTION_USE_ZSTD) + +if(N2N_OPTION_USE_PCAPLIB) + find_library(PCAP_LIB pcap) + if(NOT PCAP_LIB) + MESSAGE(FATAL_ERROR "libpcap not found.") + endif(NOT PCAP_LIB) + + # Set var needed for check_function_exists() + set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIB}) + + # TODO + # - pcap_set_immediate_mode has been available since libpcap 1.5 in 2013 + # probably should remove this check + check_function_exists(pcap_set_immediate_mode HAVE_PCAP_IMMEDIATE_MODE) + IF(NOT HAVE_PCAP_IMMEDIATE_MODE) + MESSAGE(FATAL_ERROR "libpcap not support pcap_set_immediate_mode()") + ENDIF(NOT HAVE_PCAP_IMMEDIATE_MODE) + MESSAGE(STATUS "Using libpcap.") + + ADD_DEFINITIONS("-DHAVE_PCAP_IMMEDIATE_MODE") + add_executable(n2n-decode tools/n2n-decode.c) + target_link_libraries(n2n-decode n2n pcap) + install(TARGETS n2n-decode RUNTIME DESTINATION bin) + +endif(N2N_OPTION_USE_PCAPLIB) + +if(N2N_OPTION_USE_CAPLIB) + # Linux Capabilities + find_library(CAP_LIB cap) + if(NOT CAP_LIB) + MESSAGE(FATAL_ERROR "libcap not found.") + endif(NOT CAP_LIB) + MESSAGE(STATUS "Using libcap.") + + ADD_DEFINITIONS("-DHAVE_LIBCAP") + +endif(N2N_OPTION_USE_CAPLIB) + +if(N2N_OPTION_USE_PORTMAPPING) + ADD_DEFINITIONS("-DHAVE_MINIUPNP") + include_directories(${THIRD_PARTY_DIR}/miniupnp/miniupnpc/include) + add_subdirectory(${THIRD_PARTY_DIR}/miniupnp/miniupnpc lib_miniupnpc) + link_directories(${PROJECT_BINARY_DIR}/lib_miniupnpc) + + ADD_DEFINITIONS("-DHAVE_NATPMP") + include_directories(${THIRD_PARTY_DIR}/libnatpmp) + add_subdirectory(${THIRD_PARTY_DIR}/libnatpmp libnatpmp) + link_directories(${PROJECT_BINARY_DIR}/libnatpmp) + + # Turns on the generic code for supporting either of the above + ADD_DEFINITIONS("-DHAVE_PORT_FORWARDING") + + # TODO: + # - this is the odd one out, is it needed? + include_directories(${PROJECT_BINARY_DIR}/lib_miniupnpc) +endif(N2N_OPTION_USE_PORTMAPPING) + + +if(NOT DEFINED CMAKE_BUILD_TYPE) +set(CMAKE_BUILD_TYPE None) +endif(NOT DEFINED CMAKE_BUILD_TYPE) +#set(CMAKE_BUILD_TYPE Debug) +#set(CMAKE_BUILD_TYPE Release) + +if (DEFINED UNIX) +# None +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs") +set(CMAKE_CXX_FLAGS "-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs") +# Debug +set(CMAKE_C_FLAGS_DEBUG "-g") +set(CMAKE_CXX_FLAGS_DEBUG "-g") +# Release +set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") +endif(DEFINED UNIX) + +# Static target. +#SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static") + + +INCLUDE_DIRECTORIES(.) +INCLUDE_DIRECTORIES(include) +if(DEFINED WIN32) + INCLUDE_DIRECTORIES(win32) +# Customize include. +# INCLUDE_DIRECTORIES("D:/Program Files/MinGW/opt/include/" "D:/Program Files/MinGW/x86_64-w64-mingw32/include/") +# Customize library. +# LINK_DIRECTORIES("D:/Program Files/MinGW/opt/lib/" "D:/Program Files/MinGW/x86_64-w64-mingw32/lib/") +endif(DEFINED WIN32) + + +#aux_source_directory(./src N2N_DIR_SRCS) +#add_library(n2n STATIC ${N2N_DIR_SRCS}) +add_library(n2n STATIC + src/n2n.c + src/edge_management.c + src/edge_utils.c + src/sn_management.c + src/sn_utils.c + src/wire.c + src/hexdump.c + src/minilzo.c + src/tf.c + src/cc20.c + src/transform_null.c + src/transform_tf.c + src/transform_aes.c + src/transform_cc20.c + src/transform_speck.c + src/transform_lzo.c + src/transform_zstd.c + src/aes.c + src/speck.c + src/random_numbers.c + src/pearson.c + src/header_encryption.c + src/tuntap_freebsd.c + src/tuntap_netbsd.c + src/tuntap_linux.c + src/tuntap_osx.c + src/n2n_regex.c + src/network_traffic_filter.c + src/sn_selection.c + src/auth.c + src/curve25519.c + src/n2n_port_mapping.c) + + +if(DEFINED WIN32) + add_library(edge_utils_win32 src/edge_utils_win32.c) + add_subdirectory(win32) + target_link_libraries(n2n edge_utils_win32 n2n_win32 iphlpapi) +endif(DEFINED WIN32) + +add_executable(edge src/edge.c) +target_link_libraries(edge n2n) + +add_executable(supernode src/supernode.c) +target_link_libraries(supernode n2n) + +add_executable(example_edge_embed_quick_edge_init src/example_edge_embed_quick_edge_init.c) +target_link_libraries(example_edge_embed_quick_edge_init n2n) + +add_executable(example_edge_embed src/example_edge_embed.c) +target_link_libraries(example_edge_embed n2n) + +add_executable(example_sn_embed src/example_sn_embed.c) +target_link_libraries(example_sn_embed n2n) + +if(N2N_OPTION_USE_PTHREAD) + target_link_libraries(n2n pthread) +endif(N2N_OPTION_USE_PTHREAD) + +if(N2N_OPTION_USE_OPENSSL) +# target_link_libraries(n2n crypto) + target_link_libraries(n2n ${OPENSSL_LIBRARIES}) +endif(N2N_OPTION_USE_OPENSSL) + +if(N2N_OPTION_USE_ZSTD) + target_link_libraries(n2n zstd) +endif(N2N_OPTION_USE_ZSTD) + +if(N2N_OPTION_USE_CAPLIB) + # TODO: this is a static library, shouldnt we have a generic one? + target_link_libraries(edge cap.a) +endif(N2N_OPTION_USE_CAPLIB) + +if(N2N_OPTION_USE_PORTMAPPING) + target_link_libraries(n2n libminiupnpc-static) + target_link_libraries(n2n natpmp) +endif(N2N_OPTION_USE_PORTMAPPING) + +install(TARGETS edge supernode + RUNTIME DESTINATION sbin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + ) + + +# Tools +add_executable(n2n-benchmark tools/n2n-benchmark.c) +target_link_libraries(n2n-benchmark n2n) +add_executable(n2n-keygen tools/n2n-keygen.c) +target_link_libraries(n2n-keygen n2n) + +add_executable(tests-auth tools/tests-auth.c) +target_link_libraries(tests-auth n2n) +add_executable(tests-compress tools/tests-compress.c) +target_link_libraries(tests-compress n2n) +add_executable(tests-elliptic tools/tests-elliptic.c) +target_link_libraries(tests-elliptic n2n) +add_executable(tests-hashing tools/tests-hashing.c) +target_link_libraries(tests-hashing n2n) +add_executable(tests-transform tools/tests-transform.c) +target_link_libraries(tests-transform n2n) +add_executable(tests-wire tools/tests-wire.c) +target_link_libraries(tests-wire n2n) + +install(TARGETS n2n-benchmark RUNTIME DESTINATION bin) + +# Documentation +if(DEFINED UNIX) +add_dependencies(n2n doc) +file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/doc) +add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/edge.8.gz + COMMAND gzip -c ${PROJECT_SOURCE_DIR}/edge.8 > ${PROJECT_BINARY_DIR}/doc/edge.8.gz + DEPENDS ${PROJECT_SOURCE_DIR}/edge.8 + ) + +add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + COMMAND gzip -c ${PROJECT_SOURCE_DIR}/supernode.1 > ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + DEPENDS ${PROJECT_SOURCE_DIR}/supernode.1 + ) + +add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/n2n.7.gz + COMMAND gzip -c ${PROJECT_SOURCE_DIR}/n2n.7 > ${PROJECT_BINARY_DIR}/doc/n2n.7.gz + DEPENDS ${PROJECT_SOURCE_DIR}/n2n.7 + ) + +add_custom_target(doc DEPENDS ${PROJECT_BINARY_DIR}/doc/edge.8.gz + ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + ${PROJECT_BINARY_DIR}/doc/n2n.7.gz + ) + +set_source_files_properties(${PROJECT_BINARY_DIR}/doc/edge.8.gz + ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + ${PROJECT_BINARY_DIR}/doc/n2n.7.gz + PROPERTIES GENERATED 1) + +install(FILES ${PROJECT_BINARY_DIR}/doc/edge.8.gz + DESTINATION /usr/share/man/man8) +install(FILES ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + DESTINATION /usr/share/man/man1) +install(FILES ${PROJECT_BINARY_DIR}/doc/n2n.7.gz + DESTINATION /usr/share/man/man7) +endif(DEFINED UNIX) + +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + +# TODO: +# - Add the right dependancy so that the tests binaries get built first +enable_testing() +add_test(NAME unit + COMMAND ${CMAKE_COMMAND} -E env + TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR} + ${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_SOURCE_DIR}/tests/tests_units.list +) +add_test(NAME integration + COMMAND ${CMAKE_COMMAND} -E env + TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR} + ${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_SOURCE_DIR}/tests/tests_integration.list +) +endif() diff --git a/INSTALL b/INSTALL index 45221d4..2200032 100644 --- a/INSTALL +++ b/INSTALL @@ -43,8 +43,8 @@ line in it: To build an RPM the hard way follow these steps. -$ cp -a n2ndir n2n-1.3 -$ tar czf n2n-1.3.tar.gz n2n-1.3 -$ mv n2n-1.3.tar.gz /usr/src/redhat/SOURCES +$ cp -a n2ndir n2n-2.0 +$ tar czf n2n-2.0.tar.gz n2n-2.0 +$ mv n2n-2.0.tar.gz /usr/src/redhat/SOURCES $ cp n2ndir/n2n.spec /usr/src/redhat/SPECS $ rpmbuild -bb n2n.spec diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Makefile b/Makefile deleted file mode 100644 index 485adc3..0000000 --- a/Makefile +++ /dev/null @@ -1,76 +0,0 @@ - -N2N_VERSION="1.3.2" - -######## - -CC=gcc -DEBUG?=-g -WARN?=-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs - -#Ultrasparc64 users experiencing SIGBUS should try the following gcc options -#(thanks to Robert Gibbon) -PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs - - -CFLAGS+=$(DEBUG) $(WARN) $(OPTIONS) $(PLATOPTS) - -INSTALL=install -MKDIR=mkdir -p - -INSTALL_PROG=$(INSTALL) -m755 -INSTALL_DOC=$(INSTALL) -m644 - - -# DESTDIR set in debian make system -PREFIX?=$(DESTDIR)/usr -BINDIR=$(PREFIX)/bin -SBINDIR=$(PREFIX)/sbin -MANDIR?=$(PREFIX)/share/man -MAN1DIR=$(MANDIR)/man1 -MAN8DIR=$(MANDIR)/man8 - -N2N_LIB=n2n.a -N2N_OBJS=n2n.o minilzo.o twofish.o tuntap_freebsd.o tuntap_linux.o tuntap_osx.o version.o -LIBS=-lpthread - -APPS=edge supernode -DOCS=edge.8.gz supernode.1.gz - -all: $(APPS) #$(DOCS) - -edge: edge.c $(N2N_LIB) n2n.h Makefile - $(CC) $(CFLAGS) edge.c $(N2N_LIB) $(LIBS) -o edge - -supernode: supernode.c $(N2N_LIB) n2n.h Makefile - $(CC) $(CFLAGS) supernode.c $(N2N_LIB) $(LIBS) -o supernode - -.c.o: n2n.h Makefile - $(CC) $(CFLAGS) -c $< - -%.gz : % - gzip -c $< > $@ - -$(N2N_LIB): $(N2N_OBJS) - ar rcs $(N2N_LIB) $(N2N_OBJS) -# $(RANLIB) $@ - -version.c: - @echo $(N2N_VERSION) | sed -e 's/.*/const char * version = "&";/' > version.c - @uname -p | sed -e 's/.*/const char * osName = "&";/' >> version.c - @date +"%D %r" | sed -e 's/.*/const char * buildDate = "&";/' >> version.c - -clean: - rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) *.dSYM *~ version.c - -install: edge supernode edge.8.gz supernode.1.gz - echo "MANDIR=$(MANDIR)" - $(MKDIR) $(BINDIR) $(SBINDIR) $(MAN1DIR) $(MAN8DIR) - $(INSTALL_PROG) supernode $(BINDIR)/ - $(INSTALL_PROG) edge $(SBINDIR)/ - $(INSTALL_DOC) edge.8.gz $(MAN8DIR)/ - $(INSTALL_DOC) supernode.1.gz $(MAN1DIR)/ - -# Courtesy of Ole Tange - -deb: - dpkg-buildpackage \ No newline at end of file diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..1f54f58 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,321 @@ + +# NOTE: these are needed by the configure.in inside the packages folder +N2N_VERSION=@N2N_VERSION@ + +######## + +export CC +export AR +CC=@CC@ +AR=@AR@ + +#Ultrasparc64 users experiencing SIGBUS should try the following gcc options +#(thanks to Robert Gibbon) +PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs + +export CFLAGS +export LDFLAGS + +CFLAGS=@CFLAGS@ -I ./include +LDFLAGS=@LDFLAGS@ -L . + +OPENSSL_CFLAGS=$(shell pkg-config openssl; echo $$?) +ifeq ($(OPENSSL_CFLAGS), 0) + CFLAGS+=$(shell pkg-config --cflags-only-I openssl) +endif + +WARN=-Wall +CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN) $(OPTIONS) $(PLATOPTS) + +# Quick sanity check on our build environment +UNAME_S := $(shell uname -s) +ifndef UNAME_S +# This could happen if the Makefile is unable to run "uname", which can +# happen if the shell has a bad path (or is the wrong shell) +$(error Could not run uname command, cannot continue) +endif + +# Any compile environment that needs different flags, libraries, includes or +# other settings will get its own CONFIG_TARGET value. For cross compiling, +# this might be set externally to the Makefile, but if not set we try to +# set a reasonable default. + +export CONFIG_TARGET +ifndef CONFIG_TARGET +ifeq ($(shell uname -o),Msys) +CONFIG_TARGET=mingw +else ifeq ($(shell uname -s),Darwin) +CONFIG_TARGET=darwin +else ifeq ($(shell uname), SunOS) +CONFIG_TARGET=sunos +else +CONFIG_TARGET=generic +endif +endif + +export MKDIR +export INSTALL +export INSTALL_PROG +export INSTALL_DOC +export SBINDIR + +MKDIR=mkdir -p +INSTALL=install +INSTALL_PROG=$(INSTALL) -m755 +INSTALL_DOC=$(INSTALL) -m644 + +# DESTDIR set in debian make system +PREFIX?=$(DESTDIR)/usr +ifeq ($(CONFIG_TARGET),darwin) +SBINDIR=$(PREFIX)/local/sbin +else +SBINDIR=$(PREFIX)/sbin +endif + +MANDIR?=$(PREFIX)/share/man +MAN1DIR=$(MANDIR)/man1 +MAN7DIR=$(MANDIR)/man7 +MAN8DIR=$(MANDIR)/man8 + +N2N_LIB=libn2n.a +N2N_OBJS=$(patsubst src/%.c, src/%.o, $(wildcard src/*.c)) +N2N_DEPS=$(wildcard include/*.h) $(wildcard src/*.c) Makefile + +# As source files pass the linter, they can be added here (If all the source +# is passing the linter tests, this can be refactored) +LINT_CCODE=\ + include/curve25519.h \ + include/edge_utils_win32.h \ + include/header_encryption.h \ + include/hexdump.h \ + include/n2n_define.h \ + include/n2n_wire.h \ + include/network_traffic_filter.h \ + include/pearson.h \ + include/random_numbers.h \ + include/sn_selection.h \ + include/speck.h \ + include/tf.h \ + src/edge_management.c \ + src/edge_utils_win32.c \ + src/example_edge_embed_quick_edge_init.c \ + src/header_encryption.c \ + src/sn_management.c \ + src/sn_selection.c \ + src/transform_cc20.c \ + src/transform_null.c \ + src/tuntap_freebsd.c \ + src/tuntap_linux.c \ + src/tuntap_netbsd.c \ + src/tuntap_osx.c \ + src/wire.c \ + tools/tests-auth.c \ + tools/tests-compress.c \ + tools/tests-elliptic.c \ + tools/tests-hashing.c \ + tools/tests-transform.c \ + tools/tests-wire.c \ + +export LDLIBS + +LDLIBS+=-ln2n +LDLIBS+=@N2N_LIBS@ + +#For OpenSolaris (Solaris too?) +ifeq ($(CONFIG_TARGET), sunos) +LDLIBS+=-lsocket -lnsl +endif + +ifeq ($(CONFIG_TARGET),mingw) +CFLAGS+=-I. -I./win32 -DWIN32 +LDLIBS+=$(abspath win32/n2n_win32.a) +LDLIBS+=-lws2_32 -liphlpapi +N2N_DEPS+=win32/n2n_win32.a +SUBDIRS+=win32 +endif + +APPS=edge +APPS+=supernode +APPS+=example_edge_embed_quick_edge_init +APPS+=example_edge_embed +APPS+=example_sn_embed + +DOCS=edge.8.gz supernode.1.gz n2n.7.gz + +# This is the superset of all packages that might be needed during the build. +# Mostly of use in automated build systems. +BUILD_DEP:=\ + autoconf \ + build-essential \ + flake8 \ + gcovr \ + libcap-dev \ + libzstd-dev \ + shellcheck \ + uncrustify \ + yamllint \ + +SUBDIRS+=tools + +COVERAGEDIR?=coverage + +.PHONY: $(SUBDIRS) + +.PHONY: all +all: version $(APPS) $(DOCS) $(SUBDIRS) + +# This allows breaking the build if the version.sh script discovers +# any inconsistancies +.PHONY: version +version: + @echo -n "Build for version: " + @scripts/version.sh + +tools: $(N2N_LIB) + $(MAKE) -C $@ + +win32: + $(MAKE) -C $@ + +src/edge.o: $(N2N_DEPS) +src/supernode.o: $(N2N_DEPS) +src/example_edge_embed_quick_edge_init.o: $(N2N_DEPS) +src/example_sn_embed.o: $(N2N_DEPS) +src/example_edge_embed.o: $(N2N_DEPS) + +src/edge: $(N2N_LIB) +src/supernode: $(N2N_LIB) +src/example_edge_embed_quick_edge_init: $(N2N_LIB) +src/example_sn_embed: $(N2N_LIB) +src/example_edge_embed: $(N2N_LIB) + +%: src/% + cp $< $@ + +%.gz : % + gzip -c $< > $@ + +$(N2N_LIB): $(N2N_OBJS) + $(AR) rcs $(N2N_LIB) $(N2N_OBJS) +# $(RANLIB) $@ + +win32/n2n_win32.a: win32 + +.PHONY: test test.units test.integration +test: test.units test.integration + +test.units: tools + scripts/test_harness.sh tests/tests_units.list + +test.integration: $(APPS) + scripts/test_harness.sh tests/tests_integration.list + +.PHONY: lint lint.python lint.ccode lint.shell lint.yaml +lint: lint.python lint.ccode lint.shell lint.yaml + +lint.python: + flake8 scripts/n2n-ctl scripts/n2n-httpd + +lint.ccode: + scripts/indent.sh $(LINT_CCODE) + +lint.shell: + shellcheck scripts/*.sh + +lint.yaml: + yamllint . + +# To generate coverage information, run configure with +# CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="--coverage" +# and run the desired tests. Ensure that package gcovr is installed +# and then run "make cover" +.PHONY: cover +cover: + mkdir -p $(COVERAGEDIR) + gcovr -s --html --html-details --output=$(COVERAGEDIR)/index.html + +# Use coverage data to generate gcov text report files. +# Unfortunately, these end up in the wrong directory due to the +# makefile layout +# The steps to use this are similar to the "make cover" above +.PHONY: gcov +gcov: + gcov $(N2N_OBJS) + $(MAKE) -C tools gcov + +# This is a convinent target to use during development or from a CI/CD system +.PHONY: build-dep +build-dep: +ifeq ($(CONFIG_TARGET),generic) + sudo apt install $(BUILD_DEP) +else ifeq ($(CONFIG_TARGET),darwin) + brew install automake gcovr +else + echo Not attempting to install dependancies for system $(CONFIG_TARGET) +endif + +.PHONY: clean +clean: + rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) $(COVERAGEDIR)/ *.dSYM *~ + rm -f tests/*.out src/*.gcno src/*.gcda + for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done + +.PHONY: distclean +distclean: + rm -f tests/*.out src/*.gcno src/*.gcda src/*.indent src/*.unc-backup* + rm -rf autom4te.cache/ + rm -f config.log config.status configure Makefile tools/Makefile include/config.h include/config.h.in + rm -f doc/edge.8.gz doc/n2n.7.gz doc/supernode.1.gz + rm -f packages/debian/config.log packages/debian/config.status + rm -rf packages/debian/autom4te.cache/ + rm -f packages/rpm/config.log packages/rpm/config.status + rm -f $(addprefix src/,$(APPS)) + +.PHONY: install +install: edge supernode edge.8.gz supernode.1.gz n2n.7.gz + echo "MANDIR=$(MANDIR)" + $(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR) + $(INSTALL_PROG) supernode $(SBINDIR)/ + $(INSTALL_PROG) edge $(SBINDIR)/ + $(INSTALL_DOC) edge.8.gz $(MAN8DIR)/ + $(INSTALL_DOC) supernode.1.gz $(MAN1DIR)/ + $(INSTALL_DOC) n2n.7.gz $(MAN7DIR)/ + $(MAKE) -C tools install SBINDIR=$(abspath $(SBINDIR)) + +# Docker builder section +DOCKER_IMAGE_NAME=ntop/supernode +DOCKER_IMAGE_VERSION=$N2N_VERSION_SHORT +N2N_COMMIT_HASH=$(shell scripts/version.sh hash) + +.PHONY: default steps build push +default: steps + +steps: + $(info This code appears to have been bitrotted since 2019 - please let us know if you are using it) + if [ "$(TARGET_ARCHITECTURE)" = "arm32v7" ] || [ "$(TARGET_ARCHITECTURE)" = "" ]; then DOCKER_IMAGE_FILENAME="Dockerfile.arm32v7" DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION)-arm32v7 make build; fi + if [ "$(TARGET_ARCHITECTURE)" = "x86_64" ] || [ "$(TARGET_ARCHITECTURE)" = "" ]; then DOCKER_IMAGE_FILENAME="Dockerfile.x86_64" DOCKER_IMAGE_TAGNAME=$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION)-x86_64 make build; fi + +build: + $(eval OS := $(shell uname -s)) + $(eval ARCHITECTURE := $(shell export DOCKER_IMAGE_TAGNAME="$(DOCKER_IMAGE_TAGNAME)"; echo $$DOCKER_IMAGE_TAGNAME | grep -oe -.*)) + + docker build --target builder --build-arg COMMIT_HASH=$(N2N_COMMIT_HASH) -t $(DOCKER_IMAGE_TAGNAME) -f image-platforms/$(DOCKER_IMAGE_FILENAME) . + + docker container create --name builder $(DOCKER_IMAGE_TAGNAME) + if [ ! -d "./build" ]; then mkdir ./build; fi + docker container cp builder:/usr/src/n2n/supernode ./build/supernode-$(OS)$(ARCHITECTURE) + docker container cp builder:/usr/src/n2n/edge ./build/edge-$(OS)$(ARCHITECTURE) + docker container rm -f builder + + docker build --build-arg COMMIT_HASH=$(N2N_COMMIT_HASH) -t $(DOCKER_IMAGE_TAGNAME) -f image-platforms/$(DOCKER_IMAGE_FILENAME) . + docker tag $(DOCKER_IMAGE_TAGNAME) $(DOCKER_IMAGE_NAME):latest$(ARCHITECTURE) + +push: + if [ ! "$(TARGET_ARCHITECTURE)" = "" ]; then \ + docker push $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_VERSION)-$(TARGET_ARCHITECTURE); \ + docker push $(DOCKER_IMAGE_NAME):latest-$(TARGET_ARCHITECTURE); \ + else \ + echo "Please pass TARGET_ARCHITECTURE, see README.md."; \ + fi + +# End Docker builder section diff --git a/README b/README deleted file mode 100644 index e021f41..0000000 --- a/README +++ /dev/null @@ -1,95 +0,0 @@ - - -Edge node ---------- - -You need to start an egde node on each host you want to connect with the *same* -community. - -0. become root - -1. create tun device -# tunctl -t tun0 - -3. enable the edge process -# ./edge -d n2n0 -c mynetwork -k encryptme -u 99 -g 99 -m 3C:A0:12:34:56:78 -a 1.2.3.4 -l a.b.c.d:xyw - or -# N2N_KEY=encryptme ./edge -d n2n0 -c mynetwork -u 99 -g 99 -m 3C:A0:12:34:56:78 -a 1.2.3.4 -l a.b.c.d:xyw - -Once you have this worked out, you can add the "-f" option to make edge detach -and run as a daemon. - -Note that -u, -g and -f options are not available for Windows. - -Supernode --------- - -You need to start the supernode once - -1. ./supernode -l 1234 -v - - -Dropping Root Privileges and SUID-Root Executables (UNIX) --------------------------------------------------- - -The edge node uses superuser privileges to create a TAP network interface -device. Once this is created root privileges are not required and can constitute -a security hazard if there is some way for an attacker to take control of an -edge process while it is running. Edge will drop to a non-privileged user if you -specify the -u and -g options. These are numeric IDs. Consult -/etc/passwd. - -You may choose to install edge SUID-root to do this: - -1. Become root -2. chown root:root edge -3. chmod +s edge -done - -Any user can now run edge. You may not want this, but it may be convenient and -safe if your host has only one login user. - - -Running As a Daemon (UNIX) -------------------- - -When given "-f" as a command line option, edge will call daemon(3) after -successful setup. This causes the process to fork a child which closes stdin, -stdout and stderr then sets itself as process group leader. When this is done, -the edge command returns immediately and you will only see the edge process in -the process listings, eg. from ps or top. - -If the edge command returns 0 then the daemon started successfully. If it -returns non-zero then edge failed to start up for some reason. When edge starts -running as a daemon, all logging goes to syslog daemon.info facility. - - -IPv6 Support (added r3650) ------------- - -n2n supports the carriage of IPv6 packets within the n2n tunnel. N2n does not -yet use IPv6 for transport between edges and supernodes. - -To make IPv6 carriage work you need to manually add IPv6 addresses to the TAP -interfaces at each end. There is currently no way to specify an IPv6 address on -the edge command line. - -eg. under linux: - -on hostA: -[hostA] # /sbin/ip -6 addr add fc00:abcd:1234::7/48 dev n2n0 - -on hostB: -[hostB] # /sbin/ip -6 addr add fc00:abcd:1234::6/48 dev n2n0 - -You may find it useful to make use of tunctl from the uml-utilities -package. Tunctl allow you to bring up a TAP interface and configure addressing -prior to starting edge. It also allows edge to be restarted without the -interface closing (which would normally affect routing tables). - -Once the IPv6 addresses are configured and edge started, IPv6 neighbor discovery -packets flow (get broadcast) and IPv6 entities self arrange. Test your IPv6 -setup with ping6 - the IPv6 ping command. - - -(C) 2007,2008 - Luca Deri , Richard Andrews diff --git a/README.md b/README.md new file mode 100644 index 0000000..43331b8 --- /dev/null +++ b/README.md @@ -0,0 +1,118 @@ +[![Build Status](https://travis-ci.org/ntop/n2n.png?branch=dev)](https://travis-ci.org/ntop/n2n) + + +# n2n + +n2n is a light VPN software which makes it easy to create virtual networks bypassing intermediate firewalls. + +In order to start using n2n, two elements are required: + +- A _supernode_: it allows edge nodes to announce and discover other nodes. It must have a port publicly accessible on internet. +- _edge_ nodes: the nodes which will be a part of the virtual networks + +A virtual network shared between multiple edge nodes in n2n is called a _community_. A single supernode can relay multiple communities and a single computer can be part of multiple communities at the same time. An encryption key can be used by the edge nodes to encrypt the packets within their community. + +n2n tries to establish a direct peer-to-peer connection via udp between the edge nodes when possible. When this is not possible (usually due to special NAT devices), the supernode is also used to relay the packets. + + +## Quick Setup + +Some Linux distributions already provide n2n as a package so a simple `sudo apt install n2n` will do the work. Alternatively, up-to-date packages for most distributions are available on [ntop repositories](http://packages.ntop.org/). + +On host1 run: + +```sh +$ sudo edge -c mynetwork -k mysecretpass -a 192.168.100.1 -f -l supernode.ntop.org:7777 +``` + +On host2 run: + +```sh +$ sudo edge -c mynetwork -k mysecretpass -a 192.168.100.2 -f -l supernode.ntop.org:7777 +``` + +Now the two hosts can ping each other. + +**IMPORTANT** It is strongly advised to choose a custom community name (`-c`) and a secret encryption key (`-k`) in order to prevent other users from connecting to your computer. For the privacy of your data sent and to reduce the server load of `supernode.ntop.org`, it is also suggested to set up a custom supernode as explained below. + + +## Setting up a Custom Supernode + +You can create your own infrastructure by setting up a supernode on a public server (e.g. a VPS). You just need to open a single port (1234 in the example below) on your firewall (usually `iptables`). + +1. Install the n2n package +2. Edit `/etc/n2n/supernode.conf` and add the following: + ``` + -p=1234 + ``` +3. Start the supernode service with `sudo systemctl start supernode` +4. Optionally enable supernode start on boot: `sudo systemctl enable supernode` + +Now the supernode service should be up and running on port 1234. On your edge nodes you can now specify `-l your_supernode_ip:1234` to use it. All the edge nodes must use the same supernode. + + +## Manual Compilation + +On Linux, compilation from source is straight forward: + +```sh +./autogen.sh +./configure +make + +# optionally install +make install +``` + +For Windows, MacOS, CMake, optimizations and general building options, please check out [Building documentation](doc/Building.md) for compilation and running. + +**IMPORTANT** It is generally recommended to use the [latest stable release](https://github.com/ntop/n2n/releases). Please note that the current _dev_ branch usually is not guaranteed to be backward compatible neither with the latest stable release nor with previous _dev_ states. On the other hand, if you dare to try bleeding edge features, you are encouraged to compile from _dev_ – just keep track of sometimes rapidly occuring changes. Feedback in the _Issues_ section is appreciated. + + +## Security Considerations + +When payload encryption is enabled (provide a key using `-k`), the supernode will not be able to decrypt +the traffic exchanged between two edge nodes but it will know that edge A is talking with edge B. + +The choice of encryption schemes that can be applied to payload has recently been enhanced. Please have +a look at [Crypto description](doc/Crypto.md) for a quick comparison chart to help make a choice. n2n edge nodes use +AES encryption by default. Other ciphers can be chosen using the `-A_` option. + +A benchmark of the encryption methods is available when compiled from source with `tools/n2n-benchmark`. + +The header which contains some metadata like the virtual MAC address of the edge nodes, their IP address, their real +hostname and the community name optionally can be encrypted applying `-H` on the edges. + + +## Advanced Configuration + +More information about communities, support for multiple supernodes, routing, traffic restrictions and on how to run an edge as +a service is available in the [more detailed documentation](doc/Advanced.md). + + +## Contribution + +You can contribute to n2n in various ways: + +- Update an [open issue](https://github.com/ntop/n2n/issues) or create a new one with detailed information +- Propose new features +- Improve the documentation +- Provide pull requests with enhancements + +For details about the internals of n2n check out the [Hacking guide](https://github.com/ntop/n2n/blob/dev/doc/Hacking.md). + + +## Further Readings and Related Projects + +Answers to frequently asked questions can be found in our [FAQ document](https://github.com/ntop/n2n/blob/dev/doc/Faq.md). + +Here is a list of third-party projects connected to this repository: + +- Collection of pre-built binaries for Windows: [lucktu](https://github.com/lucktu/n2n) +- n2n for Android: [hin2n](https://github.com/switch-iot/hin2n) +- Docker images: [Docker Hub](https://hub.docker.com/r/supermock/supernode/) +- Go bindings, management daemons and CLIs for n2n edges and supernodes, Docker, Kubernetes & Helm Charts: [pojntfx/gon2n](https://pojntfx.github.io/gon2n/) + +--- + +(C) 2007-22 - ntop.org and contributors diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..94ff29c --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +3.1.1 diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..0ff6b12 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +rm -f include/config.h include/config.h.in include/config.h.in~ Makefile configure + +echo "Wait please..." +autoreconf -if diff --git a/community.list b/community.list new file mode 100644 index 0000000..64f3658 --- /dev/null +++ b/community.list @@ -0,0 +1,63 @@ +# +# List of allowed communities +# --------------------------- +# +# these could either be fixed-name communities such as the following lines ... +# +mynetwork +netleo +# +# ... or regular expressions that a community name must fully match +# such as ntop[0-1][0-9] for communities from "ntop00" through "ntop19" +# +ntop[0-1][0-9] +# +# * Note that fixed-name communities may not contain one of the following characters +# . * + ? [ ] \ +# as otherwise, they are interpreted as regular expression +# +# * Only fixed-name communities are supported for header encryption (-H) +# +# * Regular expression support the following placeholders +# '.' Dot, matches any character +# '*' Asterisk, match zero or more (greedy) +# '+' Plus, match one or more (greedy) +# '?' Question, match zero or one (non-greedy) +# '[abc]' Character class, match if one of {'a', 'b', 'c'} +# '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} (feature is currently broken) +# '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z } +# '\s' Whitespace, \t \f \r \n \v and spaces +# '\S' Non-whitespace +# '\w' Alphanumeric, [a-zA-Z0-9_] +# '\W' Non-alphanumeric +# '\d' Digits, [0-9] +# '\D' Non-digits +# +# fixed-name communities can optionally be followed by a network using the +# network/bitlen syntax such as the following line +# +home 192.168.168.0/24 +# +# the supernode draws ip addresses to assign to the edges (if they omit the `-a` +# parameter) from this network. note that the network is delimited by [SPACE] so +# community names cannot contain [SPACE] either. +# +# if no network is provided here, the supernode assigns some other network to each +# community. networks are taken from the default range 10.128.0.0 - 10.255.255.0/24 +# as long as no other network range is provided through the supernode's command line +# option `-d`. those sub-networks are distinct so several edges with different +# communities can be used at the same computer (being served ip addresses from the +# same supernode). also, the sub-networks described in this file are avoided. +# +# however, all networks assigned in this file are not mutually checked for colliding +# ranges so different communities can use same or overlapping sub-networks. that does +# not impose a problem if the communities do not share edge nodes. +# +# there seems to be no sense in pre-assigning sub-networks to communities whose +# names are defined by regular expressions. those will be assigned distinct +# sub-networks from the default range or the `-d` range. +# +# if `-a` is used with the edge, the edge uses the ip address specified with the +# `-a xxx.xxx.xxx.xxx` option. also, the enhanced syntax `-r -a dhcp:0.0.0.0` is +# still available to have more professional needs served by a full dhcp server. +# diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..f7eb141 --- /dev/null +++ b/config.guess @@ -0,0 +1,1438 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2015 Free Software Foundation, Inc. + +timestamp='2015-03-04' + +# This file 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 to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2015 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..5241e8f --- /dev/null +++ b/configure.ac @@ -0,0 +1,161 @@ +odnl> Do not add anything above +AC_INIT([edge], m4_esyscmd([scripts/version.sh | tr -d '\n'])) +dnl> Do not add anything above + +N2N_VERSION=${PACKAGE_VERSION} + +if test "${CC+set}" != set; then + CC=gcc +fi +if test "${AR+set}" != set; then + AR=ar +fi + +N2N_LIBS= + +AC_PROG_CC + +# TODO: ideally, should use AC_ARG_ENABLE +AC_ARG_WITH([edgex], + AS_HELP_STRING([--with-edgex], [Build for Ubiquity-X]), + [], [with_edgex=no]) +AS_IF([test "x$with_edgex" != "xno"], + [ + AC_MSG_NOTICE([Please contact us with your use case]) + CC=mipsel-linux-gnu-gcc + AR=mipsel-linux-gnu-arzls + ], +) + +# TODO: ideally, should use AC_ARG_ENABLE +AC_ARG_WITH([zstd], + AS_HELP_STRING([--with-zstd], [use zstd library]), + [], [with_zstd=no]) +AS_IF([test "x$with_zstd" != "xno"], + [AC_CHECK_LIB([zstd], [ZSTD_compress], + [ + AC_DEFINE([HAVE_ZSTD], [1], [Have ZSTD support]) + N2N_LIBS="-lzstd ${N2N_LIBS}" + ], + [AC_MSG_ERROR([zstd library not found])] + )], +) + +# TODO: ideally, should use AC_ARG_ENABLE +AC_ARG_WITH([openssl], + [AS_HELP_STRING([--with-openssl], [enable support for OpenSSL])], + [], [with_openssl=no]) +AS_IF([test "x$with_openssl" != xno], + [AC_CHECK_LIB([crypto], [EVP_CIPHER_CTX_reset], + [ + AC_DEFINE([HAVE_OPENSSL_1_1], [1], [OpenSSL 1.1 is present]) + N2N_LIBS="-lcrypto ${N2N_LIBS}" + ], + [AC_MSG_ERROR([openssl library not found])] + )], +) + +AC_ARG_ENABLE([miniupnp], + [AS_HELP_STRING([--enable-miniupnp], [support for miniupnp])], + [], [enable_miniupnp=no]) +AS_IF([test "x$enable_miniupnp" != xno], + [AC_CHECK_LIB([miniupnpc], [upnpDiscover], + [ + AC_DEFINE([HAVE_MINIUPNP], [1], [Have miniupnp library]) + AC_DEFINE([HAVE_PORT_FORWARDING],[1],[upnp libs are used]) + N2N_LIBS="-lminiupnpc ${N2N_LIBS}" + ], + [AC_MSG_ERROR([miniupnp library not found])] + )], +) + +AC_ARG_ENABLE([natpmp], + [AS_HELP_STRING([--enable-natpmp], [support for natpmp])], + [], [enable_natpmp=no]) +AS_IF([test "x$enable_natpmp" != xno], + [AC_CHECK_LIB([natpmp], [initnatpmp], + [ + AC_DEFINE([HAVE_NATPMP], [1], [Have natpmp library]) + AC_DEFINE([HAVE_PORT_FORWARDING],[1],[upnp libs are used]) + N2N_LIBS="-lnatpmp ${N2N_LIBS}" + ], + [AC_MSG_ERROR([natpmp library not found])] + )], +) + +AC_ARG_ENABLE([pcap], + [AS_HELP_STRING([--enable-pcap], [support for pcap])], + [], [enable_pcap=no]) +AS_IF([test "x$enable_pcap" != xno], + [AC_CHECK_LIB([pcap], [pcap_open_live], + [ + AC_DEFINE([N2N_HAVE_PCAP], [1], [Have PCAP library]) + N2N_LIBS="-lpcap ${N2N_LIBS}" + ADDITIONAL_TOOLS="$ADDITIONAL_TOOLS n2n-decode" + + # TODO + # - pcap_set_immediate_mode has been available since libpcap 1.5 + # in 2013 - probably should remove this check + AC_CHECK_LIB([pcap], [pcap_set_immediate_mode], + AC_DEFINE([HAVE_PCAP_IMMEDIATE_MODE], [1], [Have pcap_immediate_mode]) + ) + ], + [AC_MSG_ERROR([pcap library not found])] + )], +) + +AC_ARG_ENABLE([cap], + [AS_HELP_STRING([--enable-cap], [support for cap])], + [], [enable_cap=no]) +AS_IF([test "x$enable_cap" != xno], + [AC_CHECK_LIB([cap], [cap_get_proc], + [ + AC_DEFINE([HAVE_LIBCAP],[1],[Support for linux capabilities]) + N2N_LIBS="${N2N_LIBS} -lcap" + ], + [AC_MSG_ERROR([cap library not found])] + )], +) + +AC_ARG_ENABLE([pthread], + [AS_HELP_STRING([--enable-pthread], [support for pthread])], + [], [enable_pthread=no]) +AS_IF([test "x$enable_pthread" != xno], + [AC_CHECK_LIB([pthread], [pthread_mutex_trylock], + [ + AC_DEFINE([HAVE_PTHREAD],[1],[pthread is present]) + LDFLAGS="${LDFLAGS} -pthread" + ], + [AC_MSG_ERROR([pthread library not found])] + )], +) + + +MACHINE=`uname -m` +SYSTEM=`uname -s` + +if test $SYSTEM = "Linux"; then + if test -f /etc/debian_version; then + DEBIAN_VERSION=`cat /etc/debian_version` + OSNAME="Debian $DEBIAN_VERSION" + else + OSNAME=`./config.guess` + fi +else +dnl> wget -O config.guess 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD' + OSNAME=`./config.guess` +fi +AC_DEFINE_UNQUOTED(PACKAGE_OSNAME, "${OSNAME}", [OS name]) + +AC_SUBST(CC) +AC_SUBST(AR) +AC_SUBST(CFLAGS) +AC_SUBST(LDFLAGS) +AC_SUBST(N2N_VERSION) +AC_SUBST(N2N_LIBS) +AC_SUBST(ADDITIONAL_TOOLS) +AC_CONFIG_HEADERS(include/config.h) +AC_CONFIG_FILES(Makefile) +AC_CONFIG_FILES(tools/Makefile) + +AC_OUTPUT diff --git a/contributors.txt b/contributors.txt new file mode 100644 index 0000000..905f13a --- /dev/null +++ b/contributors.txt @@ -0,0 +1,9 @@ +Code contributions courtesy of: + * Richard Andrews + * Don Bindner + * Sylwester Sosnowski + * Wilfried "Wonka" Klaebe + * Lukasz Taczuk + * Alaric Snell-Pym + * Babak Farrokhi [FreeBSD port] + * Logan oos Even diff --git a/debian/README.Debian b/debian/README.Debian deleted file mode 100644 index 3e61212..0000000 --- a/debian/README.Debian +++ /dev/null @@ -1,42 +0,0 @@ -QUICKSTART ----------- - -To establish a VPN you need to run the edge binary on all the client computers -you want to participate. n2n has another binary called supernode which enables -the clients to talk to each other. Even a compromised supernode cannot sniff -the traffic or the passwords for clients that are connected to it so most users -will not need to bother with running their own but can simply rely on -publically available supernodes. - -public n2n supernodes: -- bytemark.leggewie.org:1234 (sponsored by www.bytemark.co.uk) -- gandi.leggewie.org:1234 (sponsored by www.gandi.net) -- remoteqth.com:82 - -Go through the rest of the configuration file in /etc/default/n2n and run -"/etc/init.d/n2n start" as root when you are ready. Ping your local and a -remote address to test your network - -For more info check http://www.ntop.org/n2n - -SECURITY --------- - -n2n was abandoned upstream many years ago. It is also a leaf package in use by -only a limited number of users. Therefore, users should take into account the -possibility of security vulnerabilities in the VPNs it creates. n2n is probably -not the best solution for you if you need a very high level of security for your -communications going over the VPN. Consider one of the alternatives like -freelan, another p2p VPN solution available in Debian and its derivatives. - -That being said, n2n is still in use on an almost daily basis by the Debian -maintainer who is not aware of any exploits. He likes n2n for its availability -on a number of platforms including routers (OpenWRT, Freetz), low footprint, -simple configuration and independence from a trusted central relay. - -TROUBLESHOOTING ---------------- - -This package depends on the kernel having the TUN/TAP driver configured in using -CONFIG_TUN=yes. Check "grep CONFIG_TUN /boot/config-*" for the kernel you want -to run. diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 8a6f1ce..0000000 --- a/debian/changelog +++ /dev/null @@ -1,71 +0,0 @@ -n2n (1.3.1~svn3789-6) unstable; urgency=medium - - * control: - - bump to Debian Standard 4.1.4 - - add run-time dependency on lsb-base - - update git URIs - - change priority from extra to optional - - drop inactive co-maintainer - Thank you for your work. Welcome back anytime! - * copyright: update to 2018 - * default: change default supernode to bytemark.leggewie.org - * init: merge two N2N_SUPERNODE* variables into one - * README: - - improve some botched wording - - add information about two new public supernodes - - -- Rolf Leggewie Sun, 15 Apr 2018 15:03:20 +0800 - -n2n (1.3.1~svn3789-5) unstable; urgency=medium - - * ship init script for controlling the n2n VPN. Closes: #742098 - * make the README more userfriendly and relevant to ordinary users - * control: bump to Standard 3.9.6. No further changes. - - -- Rolf Leggewie Sun, 26 Oct 2014 13:27:55 +0900 - -n2n (1.3.1~svn3789-4) unstable; urgency=low - - * move the updated package from experimental to unstable now - * copyright: Update copyright information. - * control: Update to policy 3.9.4. No further changes. - - -- Rolf Leggewie Wed, 29 May 2013 17:55:10 +0800 - -n2n (1.3.1~svn3789-3) experimental; urgency=low - - * update build process from dh7 to dh9 - * backport upstream-svn4235.patch to fix compile error - * patch Makefile to import $LDFLAGS and $CPPFLAGS into $CFLAGS - - -- Rolf Leggewie Fri, 28 Dec 2012 03:09:08 +0100 - -n2n (1.3.1~svn3789-2) experimental; urgency=low - - * debian/control: - - add myself to Uploaders - - add ${misc:Depends} to run-time dependencies - - add Homepage and VCS fields - - bump standards version to 3.9.3 (no further changes) - * debian/rules: radically simplify and rely on dh7 build intelligence - * debian/source/format: use DebSrc3 format - * debian/README.Debian: add information about public supernode - - -- Rolf Leggewie Fri, 14 Dec 2012 13:01:40 +0100 - -n2n (1.3.1~svn3789-1) unstable; urgency=low - - * Update package to version 1.3 from upstream cvs - * Removed "libc6-dev (>= 2.0)" build dependency (closes: Bug#533881) - * DH compatibility level is 7 - * Run dh_prep instead of dh_clean -k - * Standards Version is 3.8.2 - - -- cristian paul peñaranda rojas Sun, 22 Jun 2009 21:19:58 -0500 - -n2n (1.2.2~svn3653) unstable; urgency=low - - * Initial release (closes: Bug#507750) - - -- cristian paul peñaranda rojas Sat, 29 Nov 2008 00:31:58 -0500 - diff --git a/debian/control b/debian/control deleted file mode 100644 index 80e9c50..0000000 --- a/debian/control +++ /dev/null @@ -1,18 +0,0 @@ -Source: n2n -Section: net -Priority: optional -Maintainer: Rolf Leggewie -Build-Depends: debhelper (>= 9) -Standards-Version: 4.1.4 -Homepage: http://www.ntop.org/products/n2n/ -Vcs-Browser: https://github.com/leggewie-DM/n2n -Vcs-Git: https://github.com/leggewie-DM/n2n.git - -Package: n2n -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, - lsb-base (>= 3.0-6), net-tools -Description: Peer-to-Peer VPN network daemon - n2n is an open source VPN application which utilizes - a Peer-to-peer architecture for network membership - and routing. diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index cc9c1f7..0000000 --- a/debian/copyright +++ /dev/null @@ -1,112 +0,0 @@ -This package was debianized by cristian paul peñaranda rojas - on Sat, 29 Nov 2008 00:31:58 -0500. -It was downloaded from https://svn.ntop.org/svn/ntop/trunk/n2n - -The current Debian packaging is © 2008-2009 cristian paul peñaranda rojas -and © 2012-2018 Rolf Leggewie and is licensed under the GNU General -Public License (GPL) version 3. A copy of the GNU GPL version 3 can be -found in `/usr/share/common-licenses/GPL-3'. - -The current Debian maintainer is cristian paul peñaranda rojas -with Rolf Leggewie as co-maintainer. - -Upstream Author: Luca Deri deri@ntop.org - -Copyright: - - Copyright (C) 2008 Luca Deri - Copyright (C) 2008 Richard Andrews - - -License: - - 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 with - the Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 51 Franklin St, - Fifth Floor, Boston, MA 02110-1301, USA. - - - On Debian systems, the complete text of the GNU General Public - License, version 3, can be found in /usr/share/common-licenses/GPL-3. - -The Files: - - twofish.c - twofish.h - - Copyright (C) 1997-2000 The Cryptix Foundation Limited. - Copyright (C) 2000 Farm9. - Copyright (C) 2001 Frank Knobbe. - All rights reserved. - -For Cryptix code: - Use, modification, copying and distribution of this software is subject - the terms and conditions of the Cryptix General Licence. - - Cryptix General License - -Copyright (c) 1995 -2005 The Cryptix Foundation Limited. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - 1. Redistributions of source code must retain the copyright notice, - this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - -THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND -CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The Files: - - minilzo.c - minilzo.h - lzodefs.h - -Copyright (C) 1996 - 2005 Markus Franz Xaver Johannes Oberhumer - -These files are part of the LZO real-time data compression library. - - All Rights Reserved. - - The LZO library 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 2 of - the License, or (at your option) any later version. - - The LZO library 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 the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - diff --git a/debian/default b/debian/default deleted file mode 100644 index 3536a2e..0000000 --- a/debian/default +++ /dev/null @@ -1,28 +0,0 @@ -# Config file for the n2n edge node daemon. - -# Sets the n2n community name. All edges within the same community appear on -# the same LAN (layer 2 network segment). Community name is 16 bytes in length. -N2N_COMMUNITY="DEBIAN_n2n_Testers" - -# Sets the twofish encryption key from ASCII text. All edges communicating must -# use the same key and community name. -N2N_KEY="SuperSecurePassword" - -# Sets the n2n supernode IP address and port to register to. -N2N_SUPERNODE="bytemark.leggewie.org:1234" -#N2N_SUPERNODE="gandi.leggewie.org:1234" -#N2N_SUPERNODE="remoteqth.com:82" - -# Sets the n2n virtual LAN IP address being claimed. This is a private IP -# address. All IP addresses in an n2n community typical belong to the same /24 -# net‐ work (ie. only the last octet of the IP addresses varies). -N2N_IP="10.1.2.3" - -N2N_DAEMON_OPTS="" - -# Uncomment this to get edge node started. -#N2N_EDGE_CONFIG_DONE="yes" - -#TODO -# add routing option -# sudo ip route add 192.168.1.0/24 via 10.1.2.1 diff --git a/debian/dirs b/debian/dirs deleted file mode 100644 index ca882bb..0000000 --- a/debian/dirs +++ /dev/null @@ -1,2 +0,0 @@ -usr/bin -usr/sbin diff --git a/debian/init b/debian/init deleted file mode 100644 index 2a38509..0000000 --- a/debian/init +++ /dev/null @@ -1,172 +0,0 @@ -#!/bin/sh -### BEGIN INIT INFO -# Provides: n2n -# Required-Start: $network $remote_fs $local_fs -# Required-Stop: $remote_fs $local_fs -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start or stop the n2n VPN -# Description: This script controls the n2n VPN service. -# It is called from the boot, halt and reboot scripts. -# So far, only 1 PVN is supported by this script. -# More can be started via the command line. -### END INIT INFO -# -# Author: Rolf Leggewie - -set -e - -# PATH should only include /usr/* if it runs after the mountnfs.sh script -PATH=/sbin:/usr/sbin:/bin:/usr/bin -DESC='n2n P2P VPN' -NAME=n2n -DAEMON=/usr/sbin/edge -DAEMON_ARGS="" # Arguments to run the daemon with -#PIDFILE=/var/run/$NAME-edge.pid -SCRIPTNAME=/etc/init.d/$NAME - -# Exit if the package is not installed -[ -x "$DAEMON" ] || exit 0 - -# Read configuration variable file if it is present -[ -r /etc/default/$NAME ] && . /etc/default/$NAME - -# Check config -if [ -z "$N2N_EDGE_CONFIG_DONE" ] -then - echo "Warning: n2n VPN client is not configured, edit config file in /etc/default/$NAME." 1>&2 - exit 0 -fi - -# Load the VERBOSE setting and other rcS variables -. /lib/init/vars.sh -. /lib/lsb/init-functions - -## Make sure /var/run/n2n exists. -#if [ ! -e /var/run/$NAME ] ; then -# mkdir -p /var/run/$NAME -# chown proxy:proxy /var/run/$NAME -# chmod 755 /var/run/$NAME -#fi - -# Function that starts the daemon/service -# -do_start() -{ - if [ -r /sys/class/net/edge0 ]; then - echo edge node is already running. - exit 0 - fi - - # Return - # 0 if daemon has been started - # 1 if daemon was already running - # 2 if daemon could not be started - start-stop-daemon --start --quiet --user nobody --exec $DAEMON --test > /dev/null \ - || return 1 - export N2N_KEY - start-stop-daemon --start --quiet --user nobody --exec $DAEMON -- \ - -f -a $N2N_IP -c $N2N_COMMUNITY -l $N2N_SUPERNODE \ - -u $(id -u nobody) -g $(id -g nobody) $DAEMON_ARGS \ - || return 2 -} - -# -# Function that stops the daemon/service -# -do_stop() -{ - # Return - # 0 if daemon has been stopped - # 1 if daemon was already stopped - # 2 if daemon could not be stopped - # other if a failure occurred - start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user nobody --exec $DAEMON - RETVAL="$?" - [ "$RETVAL" = 2 ] && return 2 - # Wait for children to finish too if this is a daemon that forks - # and if the daemon is only ever run from this initscript. - # If the above conditions are not satisfied then add some other code - # that waits for the process to drop all resources that could be - # needed by services started subsequently. A last resort is to - # sleep for some time. - start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON - [ "$?" = 2 ] && return 2 - # Many daemons don't delete their pidfiles when they exit. - rm -f $PIDFILE - return "$RETVAL" -} - -# -# Function that sends a SIGHUP to the daemon/service -# -do_reload() { - # - # If the daemon can reload its configuration without - # restarting (for example, when it is sent a SIGHUP), - # then implement that here. - # - start-stop-daemon --stop --signal 1 --quiet --name $NAME - return 0 -} - -case "$1" in - start) - [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" - do_start - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - stop) - [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" - do_stop - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - status) - status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? - ;; - #reload|force-reload) - # - # If do_reload() is not implemented then leave this commented out - # and leave 'force-reload' as an alias for 'restart'. - # - #log_daemon_msg "Reloading $DESC" "$NAME" - #do_reload - #log_end_msg $? - #;; - restart|force-reload) - # - # If the "reload" option is implemented then remove the - # 'force-reload' alias - # - log_daemon_msg "Restarting $DESC" "$NAME" - do_stop - case "$?" in - 0|1) - do_start - case "$?" in - 0) log_end_msg 0 ;; - 1) log_end_msg 1 ;; # Old process is still running - *) log_end_msg 1 ;; # Failed to start - esac - ;; - *) - # Failed to stop - log_end_msg 1 - ;; - esac - ;; - *) - N=/etc/init.d/$NAME - #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 - echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 - exit 3 - ;; -esac - -exit 0 diff --git a/debian/patches/01-edge.8.diff b/debian/patches/01-edge.8.diff deleted file mode 100644 index a5ccc5e..0000000 --- a/debian/patches/01-edge.8.diff +++ /dev/null @@ -1,8 +0,0 @@ ---- a/edge.8.old 2008-12-02 20:33:54.000000000 -0500 -+++ b/edge.8 2008-12-02 20:34:13.000000000 -0500 -@@ -1,4 +1,4 @@ --.TH edge 1 "Jan 3, 2009" "revision 3679" "SUPERUSER COMMANDS" -+.TH edge 8 "Jan 3, 2009" "revision 3679" "SUPERUSER COMMANDS" - .SH NAME - edge \- n2n edge node daemon - .SH SYNOPSIS diff --git a/debian/patches/02-reproducible-build.diff b/debian/patches/02-reproducible-build.diff deleted file mode 100644 index 39af2bf..0000000 --- a/debian/patches/02-reproducible-build.diff +++ /dev/null @@ -1,22 +0,0 @@ -Description: Make the build reproducible -Author: Chris Lamb -Last-Update: 2016-08-08 -X-Bug: https://bugs.debian.org/833819 - -Make the build reproducible: -https://wiki.debian.org/ReproducibleBuilds - ---- n2n-1.3.1~svn3789.orig/Makefile -+++ n2n-1.3.1~svn3789/Makefile -@@ -57,7 +57,11 @@ $(N2N_LIB): $(N2N_OBJS) - version.c: - @echo $(N2N_VERSION) | sed -e 's/.*/const char * version = "&";/' > version.c - @uname -p | sed -e 's/.*/const char * osName = "&";/' >> version.c -+ifdef SOURCE_DATE_EPOCH -+ @LC_ALL=C date --utc --date="@$(SOURCE_DATE_EPOCH)" +"%D %r" | sed -e 's/.*/const char * buildDate = "&";/' >> version.c -+else - @date +"%D %r" | sed -e 's/.*/const char * buildDate = "&";/' >> version.c -+endif - - clean: - rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) *.dSYM *~ version.c diff --git a/debian/patches/makefile.patch b/debian/patches/makefile.patch deleted file mode 100644 index 18aebea..0000000 --- a/debian/patches/makefile.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/Makefile b/Makefile -index 485adc3..191845a 100644 ---- a/Makefile -+++ b/Makefile -@@ -12,7 +12,7 @@ WARN?=-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs - PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs - - --CFLAGS+=$(DEBUG) $(WARN) $(OPTIONS) $(PLATOPTS) -+CFLAGS+=$(DEBUG) $(WARN) $(LDFLAGS) $(CPPFLAGS) $(OPTIONS) $(PLATOPTS) - - INSTALL=install - MKDIR=mkdir -p diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index 9c0306c..0000000 --- a/debian/patches/series +++ /dev/null @@ -1,4 +0,0 @@ -01-edge.8.diff -upstream-svn4235.patch -makefile.patch -02-reproducible-build.diff diff --git a/debian/patches/upstream-svn4235.patch b/debian/patches/upstream-svn4235.patch deleted file mode 100644 index 078d74c..0000000 --- a/debian/patches/upstream-svn4235.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/n2n.c b/n2n.c -index cfcfb74..ac98ad6 100644 ---- a/n2n.c -+++ b/n2n.c -@@ -120,7 +120,7 @@ void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...) { - } - - snprintf(out_buf, sizeof(out_buf), "%s%s", extra_msg, buf); -- syslog(LOG_INFO, out_buf); -+ syslog(LOG_INFO, "%s", out_buf); - } else { - snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, file, line, extra_msg, buf); - printf("%s\n", out_buf); diff --git a/debian/rules b/debian/rules deleted file mode 100755 index ed7f152..0000000 --- a/debian/rules +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/make -f - -%: - dh $@ \ No newline at end of file diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 163aaf8..0000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/doc/Advanced.md b/doc/Advanced.md new file mode 100644 index 0000000..e118cb8 --- /dev/null +++ b/doc/Advanced.md @@ -0,0 +1,41 @@ +# Advanced Configuration + + +## Configuration Files + +Read about [Configuration Files](ConfigurationFiles.md) as they might come in handy – especially, but not limited to, if edges or supernodes shall be run as a service (see below) or in case of bulk automated parameter generation for mass deployment. + +## Running edge as a Service + +edge can also be run as a service instead of cli: + +1. Edit `/etc/n2n/edge.conf` with your custom options. See `/etc/n2n/edge.conf.sample`. +2. Start the service: `sudo systemctl start edge` +3. Optionally enable edge start on boot: `sudo systemctl enable edge` + +You can run multiple edge service instances by creating `/etc/n2n/edge-instance1.conf` and +starting it with `sudo systemctl start edge@instance1`. + + +## Communities + +You might be interested to learn some [details about Communities](Communities.md) and understand how to limit supernodes' services to only a specified set of communities. + + +## Federation + +It is available a special community which provides interconnection between supernodes. Details about how it works and how you can use it are available in [Federation](Federation.md). + +## Virtual Network Device Configuration + +The [TAP Configuration Guide](TapConfiguration.md) contains hints on various settings that can be applied to the virtual network device, including IPv6 addresses as well as notes on MTU and on how to draw IP addresses from DHCP servers. + + +## Routing the Traffic + +Reaching a remote network or tunneling all the internet traffic via n2n are two common tasks which require a proper routing setup. n2n supports routing needs providing options for packet forwarding (`-r`) including broadcasts (`-E`) as well as temporarily modifying the routing table (`-n`). Details can be found in the [Routing document](Routing.md). + + +## Traffic Restrictions + +It is possible to drop or accept specific packet transmit over edge network interface by rules. Rules can be specify by (`-R rule_str`) multiple times. Details can be found in the [Traffic Restrictions](TrafficRestrictions.md). diff --git a/doc/Authentication.md b/doc/Authentication.md new file mode 100644 index 0000000..fc14ebd --- /dev/null +++ b/doc/Authentication.md @@ -0,0 +1,105 @@ +# Edge Authentication + +From a discussion on how to prevent MAC address spoofing, the need of edge authentication became evident. In fact, the REGISTER_SUPER type messages already have shown a so far unused `auth` field which gets used for the first time starting in the course of n2n version 2.9 development. + +## Implementation + +n2n implements two different authentication schemes the user can chose from. + +### Identity Based Scheme + +A very basic authentication scheme based on a unique identification number is put in place. This ID is randomly generated during edge start-up and remains unchanged until the edge terminates. With every REGISTER_SUPER, it is transmitted to the supernode which remembers it from the first REGISTER_SUPER and can compare it to all the following ones. It is a verification based on "showing the ID". The supernode accepts REGISTER_SUPER (and thus changed MAC address or internet socket) and UNREGISTER type messages only if verification passes. + +This does not only prevent UNREGISTER attacks but also MAC spoofing even in case of several federated supernodes because each REGISTER_SUPER message is forwarded to all other supernodes. If a new edge (un)intentionally tries to claim a MAC address which already has been in use by another edge, this would be detected as unauthorized MAC change because the new edge presents a different authentication ID. The supernode which rejects it (based on a failed comparison) sends a REGISTER_SUPER_**NAK** type message to the new edge as well as the supernode through which the new edge tried to register. The REGISTER_SUPER_NAK will cause the edge to output an ERROR message, it does not stop the edge anymore to prevent de-auth attacks. + +As opposed to the MAC address which is sent out with each packet also between edges, the ID remains between the edge and the supernode. Other edges do not become aware of it and thus are not able to spoof. + +A somewhat hurdling network sniffing attack aimed at observing the authentication ID could break this scheme. Thus, further development towards a more sophisticated crypto-based authentication scheme is intended. + +In case of edges unexpectedly shutting down with no opportunity for a clean exit, this auth scheme prevents re-connection to the supernode until it internally is removed from the list (after some 90 seconds or so). Although `-M` command line option at the supernode can disable authentication ID comparison to circumvent this situation, usage of user / password based authentication scheme is highly recommended instead. + +### User / Password Based Authentication + +A more advanced scheme relies on username and especially password. Public key cryptography, namely Curve25519, ensures safety. Basically, the password along with the mixed in user name, serve as private key. The corresponding public key is generated by the `tools/n2n-keygen` utility. The such generated public key gets depoisted at the supernode. + +#### Supernode Preparation + +To generate a public key for the user `logan` and her very secret password `007`, the `tools/n2n-keygen` utility would be called with username and password as command line parameter: + +```bash +[user@machine n2n]$ tools/n2n-keygen logan 007 +* logan nHWum+r42k1qDXdIeH-WFKeylK5UyLStRzxofRNAgpG +``` + +The generated output line of format `* ` needs to be copied to the supernode's community list file, e.g. to the exemplary `community.list` file. + +``` +# +# List of allowed communities +# --------------------------- +# +# these could either be fixed-name communities such as the following lines ... +# +mynetwork +netleo +* logan nHWum+r42k1qDXdIeH-WFKeylK5UyLStRzxofRNAgpG +* sister HwHpPrdMft+38tFDDiunUds6927t0+zhCMMkQdJafcC +# +# ... or regular expressions that a community name must fully match +# such as ntop[0-1][0-9] for communities from "ntop00" through "ntop19" +# +ntop[0-1][0-9] + + ... +``` + +This example also lists another user `sister` (with the same secret password `007`). The users become part of the preceding community name, `netleo` in this case. The public keys are cryptographically tied only to the user name, not to the community name. That way, to switch a user from one community to another, her line can easily be copied from one community section to another. By the way, do not forget to provide the `community.list` file to the supernode through the `-c community.list` parameter. + +Current supernode behavior does not limit the simultaneous usage of usernames, i.e. one username can be used from several edges at the same time. However, it is recommended to use a distinct username and password for each edge or computer. Your management port output will be much more meaningful then with the `HINT` column showing the related username. Also, the auto IP address feature, i.e. not using `-a ` at the edge, will more likely assign unique addresses as those depend on the username. + +If a user chooses a new password or needs to be excluded from accessing the community (stolen edge scenario), the corresponding line of the `community.list` file can be replaced with a newly generated one or be deleted respectively. Restarting the supernode or issuing the `reload_communities` command to the management port is required after performing changes to make the supernode(s) read in this data again. + +When using this feature federation-wide, i.e. across several supernodes, please make sure to keep all supernodes' `community.list` files in sync. So, if you delete or change a user one supernode (or add it), you need to do it at all supernodes. There is no built-in sync for the `community.list` files across the federation. External tools such as _Syncthing_ or your very own script-driven scp-based-file-distribution might be of assistance. Also, with every change, you need to restart the supernode or issue the `reload_communites` command to the management port as outlined above. + +With a view to the detailed explanations below, your supernode(s) should have a non-default federation name given by the `-F ` command line parameter, e.g. `-F secretFed`. Alternatively, it can be passed through the environment variable `N2N_FEDERATION`. It is used to derive a private key at the supernode side and is only to be shared among supernodes. + + +#### Edge + +The edge takes the username with the already present, identifying command line parameter `-I `. The password goes into `-J `. Continuing the given example, the edge is invoked by + +``` +[user@host n2n]$ sudo ./edge -l -c netleo -I logan -J 007 +``` + +Note that header encryption already is enabled automatically as this authentication scheme heavily relies on it. Also, currently only the stream ciphers work with this authentication scheme reliably in terms of security. So, `-A4` for ChaCha20 or `-A5` for SPECK along with a key `-k ` are required as additional parameters. + +The edges need to know the public key of the supernode. By default, the edges assume the default federation name, or more specific, the corresponding public key. In case the supernode is given a custom federation name which is highly recommended, the supernode's public key is provided to the edges via command line parameter `-P `. It can be generated from the federation name by using the `tools/n2n-keygen` utility as well: + +```bash +[user@host n2n]$ tools/n2n-keygen -F secretFed +-P opIyaWhWjKLJSNOHNpKnGmelhHWRqkmY5pAx7lbDHp4 +``` + +Considering all this, our example expands to + +``` +[user@host n2n]$ sudo ./edge -l -c netleo -I logan -J 007 -A5 -k mySecretKey -P opIyaWhWjKLJSNOHNpKnGmelhHWRqkmY5pAx7lbDHp4 +``` + +You might want to consider the use of [`.conf` files](https://github.com/ntop/n2n/blob/dev/doc/ConfigurationFiles.md) to accomodate all the command line parameters more easily. Alternatively, the `N2N_PASSWORD` environment variable can be used to set the password without having it show up as part of the command line. + + +#### How Does It Work? + +In order to make this authentication scheme work, the existing header encryption scheme is split into using two keys: a _static_ and a _dynamic_ one. The static key remains unchanged and is the [classic header encryption key](https://github.com/ntop/n2n/blob/dev/doc/Crypto.md#header) derived from the community name. It only is applied to the very basic registration traffic between edge and supernode (REGISTER_SUPER, REGISTER_SUPER_ACK, REGISTER_SUPER_NAK). The dynamic key is derived (among others) from the federation name – keep it secret! – and applied to all the other packets, especially the data packets (PACKET) and peer-to-peer building packets (REGISTER), but also the ping and peer information (QUERY_PEER, PEER_INFO). An edge not provided with a valid dynamic key is not able to participate in the further communication. + +In regular header encryption mode, static key and dynamic key are equal. With activated user-password scheme, the supernode generates and transmits a dynamic key with the REGISTER_SUPER for further use. This happens in a secure way based on public key cryptography. A non-authenticated edge, i.e. without corresponding entry at the supernode or valid credentials, will not receive a valid dynmic key for communication beyond registration. + +In user-password scheme, the packets encrypted with the static key (REGISTER_SUPER, REGISTER_SUPER_ACK, useless for REGISTER_SUPER_NAK) are "signed" with an encrypted outer hash using the shared secret which is only known to the federated supernodes and that specific edge. + +#### Possible Extensions + +Tools for automizing [`.conf` file](https://github.com/ntop/n2n/blob/dev/doc/ConfigurationFiles.md) generation for deployment ot delivery to freshly registered and approved users could greatly enhance this ecosystem; a user would not have to mess around with command line parameters but just copy a `.conf` file into a specified directory. + +Let us know if you are interested in implementing or furthering these ideas. diff --git a/doc/BuildConfig.md b/doc/BuildConfig.md new file mode 100644 index 0000000..aa3b61c --- /dev/null +++ b/doc/BuildConfig.md @@ -0,0 +1,185 @@ +# Configuration at Build time + +There are a number of configuration options that are made only at build time. + +In order to assist with cross compilation, minimising test cases, repeatable +builds and minimising externalities, the build options are generally defaulted +to off. + +As part of simplifying cross compilation, the use of auto-detected +configuration settings are being removed. + +## Options + +After changing any configuration, please do no forget to `make clean` after +the (re-)configuration and before building (again) using `make`. (Or the +equivalent with `cmake`) + +### `--with-zstd` + +ZSTD Compression Support + +In addition to the built-in LZO1x for payload compression (`-z1` at the edge's +commandline), n2n optionally supports [ZSTD](https://github.com/facebook/zstd). +As of 2020, it is considered cutting edge and [praised](https://en.wikipedia.org/wiki/Zstandard) +for reaching the currently technologically possible Pareto frontier in terms +of CPU power versus compression ratio. + +#### Makefile + +ZSTD support can be configured using + +`./configure --with-zstd` + +which then will include ZSTD. It will be available via `-z2` at the edges. Of course, it can be combined with the other optimisation features: + +`./configure --with-zstd --with-openssl CFLAGS="-O3 -march=native"` + +Again, and this needs to be reiterated sufficiently often, please do no forget to `make clean` after (re-)configuration and before building (again) using `make`. + +### `--with-openssl` + +Use openssl instead of the built-in AES code + +The speed of some ciphers' can take advantage of OpenSSL support This is +disabled by default as the built-in ciphers already prove reasonably fast +in most cases. + +When enabled, this will include OpenSSL 1.1. This can also be combined with +the hardware support and compiler optimizations such as. + +`./configure --with-openssl CFLAGS="-O3 -march=native"` + +#### Makefile + +Add `--with-openssl` to the `configure` command + +#### Cmake + +Add `-DN2N_OPTION_USE_OPENSSL=ON` to the cmake configure step. + +Additionally, it is possible to statically link the OpenSSL library. +Add `-DOPENSSL_USE_STATIC_LIBS=true` to the cmake configure step. + +Building statically with openssl in this way has been known to have +issues recently on Windows (See #944) + +### `--with-edgex` + +A legacy option intended to help cross compilation - if you use this option +please let us know as there are probably more modern options for +cross-compiling + +### `--enable-pthread` + +Enable threading using the pthread library + +### `--enable-cap` + +Use the libcap to provide reduction of the security privileges needed in the +running daemon + +### `--enable-pcap` + +If the pcap library is available then the `n2n-decode` tool can be compiled. + +### `--enable-natpmp` + +One of the two UPnP libraries, this one supports the NATPMP protocol. +See also the next option. + +This option depends on the library being installed - on Debian and Ubuntu, +this is `apt-get install libnatpmp-dev` + +### `--enable-miniupnp` + +Enables the other kind of UPnP port mapping protocol. + +Turning on either of these two UPnP libraries will enable UPnP support within +the edge. + +Both the natpmp and miniupnp depend on the pthread library being enabled. + +This option depends on the library being installed - on Debian and Ubuntu, +this is `apt-get install libminiupnpc-dev` + +### Disable Multicast Local Peer Detection + +For better local peer detection, the edges try to detect local peers by sending REGISTER +packets to a certain multicast address. Also, edges listen to this address to eventually +fetch such packets. + +If these packets disturb network's peace or even get forwarded by (other) edges through the +n2n network, this behavior can be disabled + +#### Makefile + +Add +`-DSKIP_MULTICAST_PEERS_DISCOVERY` + +to your `CFLAGS` when configuring, e.g. + +`./configure --with-zstd CFLAGS="-O3 -march=native -DSKIP_MULTICAST_PEERS_DISCOVERY"` + +### Deprecation of --with options + +Due to historical reasons, the autoconf system does not validate the syntax +of any `--with-X` style options, thus to provide the highest confidence in +the correctness of configuration and compilation, `--enable-X` style options +are preferred. As part of this, the older `--with-X` options will eventually +be migrated to use `--enable-X` + +## CMake configuration + +There are a number of OPTION statements in the CMakeLists.txt file that can +have their settings changed. This is done by adding a commandline option +to the cmake configure stage. + +e.g: +`cmake -DN2N_OPTION_USE_ZSTD=ON ..` + +Note that the names of the configure option variables used in the cmake +process will probably change to make the source code consistent. + +# Optimisation options + +## Compiler Optimizations + +The easiest way to boosting speed is by allowing the compiler to apply optimization to the code. To let the compiler know, the configuration process can take in the optionally specified compiler flag `-O3`: + +`./configure CFLAGS="-O3"` + +The `tools/n2n-benchmark` tool reports speed-ups of 200% or more! There is no known risk in terms of instable code or so. + +## Hardware Features + +Some parts of the code significantly benefit from compiler optimizations (`-O3`) and platform features +such as NEON, SSE and AVX. It needs to be decided at compile-time. Hence if compiling for a specific +platform with known features (maybe the local one), it should be specified to the compiler – for +example through the `-march=sandybridge` (you name it) or just `-march=native` for local use. + +So far, the following portions of n2n's code benefit from hardware features: + +``` +AES: AES-NI +ChaCha20: SSE2, SSSE3 +SPECK: SSE2, SSSE3, AVX2, AVX512, (NEON) +Random Numbers: RDSEED, RDRND (not faster but more random seed) +``` + +The compilations flags could easily be combined: + +`./configure CFLAGS="-O3 -march=native"`. + +There are reports of compile errors showing `n2n_seed': random_numbers.c:(.text+0x214): undefined reference to _rdseed64_step'` even though the CPU should support it, see #696. In this case, best solution found so far is to disable `RDSEED` support by adding `-U__RDSEED__` to the `CFLAGS`. + +## SPECK – ARM NEON Hardware Acceleration + +By default, SPECK does not take advantage of ARM NEON hardware acceleration even if compiled with `-march=native`. The reason is that the NEON implementation proved to be slower than the 64-bit scalar code on Raspberry Pi 3B+, see [here](https://github.com/ntop/n2n/issues/563). + +Your specific ARM mileage may vary, so it can be enabled by configuring the definition of the `SPECK_ARM_NEON` macro: + +`./configure CFLAGS="-DSPECK_ARM_NEON"` + +Just make sure that the correct architecture is set, too. `-march=native` usually works quite well. + diff --git a/doc/Building.md b/doc/Building.md new file mode 100644 index 0000000..cca09c7 --- /dev/null +++ b/doc/Building.md @@ -0,0 +1,173 @@ +This document describes the process for compiling n2n in several different +scenarios. + +There are some configuration options available during the build process, +which are documented in the [Build time Configuration](BuildConfig.md) page. + +Also of use are the steps used for the automated Continuous Integration +process, which can be found in the [Github actions config file](../.github/workflows/tests.yml) + +# Git submodules + +If you are compiling with the UPnP libraries, it is possible that your +operating system or your build system do not include binaries for the +required libraries. + +Using these libraries can cause issues with some build systems, so be +aware that not all combinations are supportable. + +To make this scenario simpler, the required source code has been added +to this repository as git `submodules` which require one extra step to +complete their checkout. + +So the very first time after cloning the n2n git repo, you should run +this command in the n2n directory to fetch the submodules: + +```bash +git submodule update --init --recursive +``` + +# Build on macOS + +In order to use n2n on macOS, you first need to install support for TUN/TAP interfaces: + +```bash +brew tap homebrew/cask +brew cask install tuntap +``` + +If you are on a modern version of macOS (i.e. Catalina), the commands above will ask you to enable the TUN/TAP kernel extension in System Preferences → Security & Privacy → General. + +For more information refer to vendor documentation or the [Apple Technical Note](https://developer.apple.com/library/content/technotes/tn2459/_index.html). + +Note that on the newest MacOS versions and on Apple Silicon, there may be +increasing security restrictions in the OS that make installing the TUN/TAP +kernel extension difficult. Alternative software implementations to avoid +these difficulties are being discussed for future n2n versions. + +# Build on Windows + +The following document some possible windows compile recipes. Of them, the +MinGW build process is more tested as it is more friendly to open source +development. + +## Visual Studio + +### Requirements +In order to build with Vidual Studio on Windows the following tools should be installed: + +- Visual Studio. For a minimal install, the command line only build tools can be + downloaded and installed from https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2017. + +- CMake (From https://cmake.org/download/) + + NOTE: You should always use the official cmake stable release as otherwise + you may have issues finding libraries (e.g: the installed OpenSSL library). + If you still have problems, you can try invoking it with `C:\Program Files\CMake\bin\cmake`. + +- (optional) The OpenSSL library. This optional library can be enabled as + per the steps in the [Build time Configuration](BuildConfig.md) + + Pre-built OpenSSL binaries can be downloaded from + https://slproweb.com/products/Win32OpenSSL.html. + The full version is required, i.e. not the "Light" version. The Win32 + version of it is usually required for a standard build. + +### CLI steps + +In order to build from the command line, open a terminal window change to +the directory where the git checkout of this repository is and run the +following commands: + +Building using `cmake` works as follows: + +```batch +cmake -E make_directory build +cd build + +rem Append any options to the next line +cmake .. + +cmake --build . --config Release +``` + +The compiled `.exe` files should now be available in the `build\Release` directory. + +## MinGW + +These steps were tested on a fresh install of Windows 10 Pro with all patches +applied as of 2021-09-29. + +- Install Chocolatey (Following instructions on https://chocolatey.org/install) +- from an admin cmd prompt + - `choco install git mingw make` +- All the remaining commands must be run from inside a bash shell ("C:\Program Files\Git\usr\bin\bash.exe") + - `git clone $THIS_REPO` + - `cd n2n` + - `./scripts/hack_fakeautoconf.sh` + - `make` + - `make test` + +Due to limitations in the Windows environment, the normal autotools steps have +been emulated by the `hack_fakeautoconf` - This currently results in the +version number reported by the compiled software being inaccurate. + +Note: MinGW builds have had a history of incompatibility reports with other OS +builds (for example [#617](https://github.com/ntop/n2n/issues/617) and [#642](https://github.com/ntop/n2n/issues/642)) +However, if the tests pass, you should have a high confidence that your build +will be compatible. + +## Run on Windows + +In order to run n2n on Windows, you will need the following: + +- The TAP drivers should be installed into the system. They can be installed from + http://build.openvpn.net/downloads/releases, search for "tap-windows". + +- If OpenSSL has been linked dynamically, the corresponding `.dll` file should be available + onto the target computer. + +The `edge.exe` program reads the `edge.conf` file located into the current directory if no option is provided. + +The `supernode.exe` program reads the `supernode.conf` file located into the current directory if no option is provided. + +Example [edge.conf](../packages/etc/n2n/edge.conf.sample) +and [supernode.conf](../packages/etc/n2n/supernode.conf.sample) are available. + +See `edge.exe --help` and `supernode.exe --help` for a full list of supported options. + +# Cross compiling on Linux + +## Using the Makefiles and Autoconf + +The Makefiles are all setup to allow cross compiling of this code. You +will need to have the cross compiler, binutils and any additional libraries +desired installed for the target architecture. Then you can run the `./configure` +with the appropriate CC and AR environment and the right `--host` option. + +If compiling on Debian or Ubuntu, this can be as simple as the following example: + +``` +HOST_TRIPLET=arm-linux-gnueabi +sudo apt-get install binutils-$HOST_TRIPLET gcc-$HOST_TRIPLET +./autogen.sh +export CC=$HOST_TRIPLET-gcc +export AR=$HOST_TRIPLET-ar +./configure --host $HOST_TRIPLET +make +``` + +A good starting point to determine the host triplet for your destination platform +can be found by copying the `./config.guess` script to it and running it on the +destination. + +This is not a good way to produce binaries for embedded environments (like OpenWRT) +as they will often use a different libc environment. + +# N2N Packages + +There are also some example package build recipes included with the source. + +- [Debian](../packages/debian/README) +- [RPM](../packages/rpm) +- [OpenWRT](../packages/openwrt/README.md) diff --git a/doc/Communities.md b/doc/Communities.md new file mode 100644 index 0000000..1285a56 --- /dev/null +++ b/doc/Communities.md @@ -0,0 +1,81 @@ +# Communities + + +## Names + +As communities designate virtual networks, they must be distinguishable from each other. Its their name that makes them distinguishable and which therefore should be unique per network. The community name is composed of 19 byte-sized characters and it internally always is terminated by an additional zero character totalling up to 20 characters. Hence, the zero character cannot be part of the regular community name. There are some other characters that cannot be used, namely `. * + ? [ ] \`. + +To make full use of character space, hex values could be used, e.g. from Linux bash applying the `edge … -c $(echo -en '\x3a\x3b\x4a\x6a\xfa') …` command line syntax. If used with a configuration file, the bytes must be directly filled as characters into a corresponding `-c :;Jjþ` line. + +Apart from command line `-c` and configuration file, the community name can be supplied through the `N2N_COMMUNITY` environment variable. This might prove useful to hide the community name from command line if used with header encryption enabled, see below. + + +## Restrict Supernode Access + +By default, a supernode offers its service to all communities and allows them to connect. If a self-setup supernode shall handle certain communities only, the supernode can be given a list of allowed communities. This list is a simple text file containg the allowed community names, one per line: + +``` + # community.list (a text file) + ----------------------------------------------------- + myCommunity + yourCommunity +``` + +This file is provided to the supernode through the `-c community.list` command line parameter. This example would allow the supernode to only accept connections from communities called "myCommunity" and "yourCommunity", these are fixed-name communities. + + +## Somewhat Flexible Community Names + +If you want to allow all community names from a certain name range, e.g. from "myCommunity00" to "myCommunity99", the `community.list` file (or whatever you name it) could look as follows: + +``` + # community.list (a text file) + ----------------------------------------------------- + myCommunity[0-9][0-9] +``` + +Advanced users recognize the so called regular expression. To prevent users from stop reading, the author did not dare to name this section "Regular Expressions". Anyway, community names can be provided as regular expressions using the following placeholders: + +``` + '.' Dot, matches any character + '*' Asterisk, match zero or more of previous element (greedy) + '+' Plus, match one or more of previous element (greedy) + '?' Question, match zero or one (non-greedy) + '[abc]' Character class, match if one of {'a', 'b', 'c'} + '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} (feature is currently broken) + '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z } + '\s' Whitespace, \t \f \r \n \v and spaces + '\S' Non-whitespace + '\w' Alphanumeric, [a-zA-Z0-9_] + '\W' Non-alphanumeric + '\d' Digits, [0-9] + '\D' Non-digits +``` + +Knowing this, we can as well express the exemplary `community.list` above the following way: + +``` + # community.list (a text file) + ----------------------------------------------------- + myCommunity\d\d +``` + +Also, as the `. * + ? [ ] \` characters indicate parts of regular expressions, we now understand why those are not allowed in fixed-name community names. + + +## Header Encryption + +By default, the community name is transmitted in plain witch each packet. So, a fixed-name community might keep your younger siblings out of your community (as long as they do not know the community name) but sniffing attackers will find out the community name. Using this name, they will be able to access it by just connecting to the supernode then. + +[Header encryption](Crypto.md#header) can be enabled to prevent plain transmission. It is important to understand that header encryption, if enabled, only works on fixed-name communities. It will not work on community names described by regular expressions. + +On the other hand, the provision of fixed-name communities blocks all other, non-listed communities. To allow a mixed operation of certain encrypted and hence fixed-name communities along with all other open communities, the following "trick" can be applied: + +``` + # community.list (a text file) + ----------------------------------------------------- + mySecretCom + .* +``` + +This is not really a trick but just making use of a very permissive regular expression at the second line. diff --git a/doc/ConfigurationFiles.md b/doc/ConfigurationFiles.md new file mode 100644 index 0000000..e5f8513 --- /dev/null +++ b/doc/ConfigurationFiles.md @@ -0,0 +1,73 @@ +# Configuration Files + +To help deployment and better handle locally different configurations, n2n supports the optional use of configuration files for `edge` and `supernode`. + +They are plain text files and contain the desired command line options, **one per line**. + +The exemplary command line + +```bash +sudo edge -c mynetwork -k mysecretpass -a 192.168.100.1 -f -l supernode.ntop.org:7777 +``` + +translates into the following `edge.conf` file: + +``` +-c mynetwork +-k mysecretpass +-a 192.168.100.1 +-f +-l supernode.ntop.org:7777 +-A5 +``` + +which can be loaded by + +``` +sudo ./edge edge.conf +``` + +Comment lines starting with a hash '#' are ignored. + +``` +# automated edge configuration +# created by bot7 +# on April 31, 2038 – 1800Z +-c mynetwork +-k mysecretpass +-a 192.168.100.1 +-f +-A5 +# --- supernode section --- +-l supernode.ntop.org:7777 +``` + +Long options can be used as well. Please note the double minus/dash-character `--`, just like you would use them on the command line with long options: + +``` +--community mynetwork +-k mysecretpass +-a 192.168.100.1 +-f +-A5 +-l supernode.ntop.org:7777 +``` + +If using a configuration file, its filename needs to be supplied as first parameter to `edge` or `supernode`. If required, additional command line parameters can be supplied afterwards: + +``` +sudo edge edge.conf -z1 -I myComputer +``` + +Finally, the `.conf` file syntax also allows `=` between parameter and its option: + +``` +-c=mynetwork +-k=mysecretpass +-a=192.168.100.1 +-f +-A5 +-l=supernode.ntop.org:7777 +``` + +When used with `=`, there is no whitespace allowed between parameter, delimiter (`=`), and option. So, do **not** put `-c = mynetwork` – it is required to be `-c=mynetwork`. diff --git a/doc/Crypto.md b/doc/Crypto.md new file mode 100644 index 0000000..9883c83 --- /dev/null +++ b/doc/Crypto.md @@ -0,0 +1,216 @@ +# Cryptography in n2n + +## Payload + +### Overview + +Payload encryption currently comes in four different flavors using ciphers of different origins. Supported ciphers are enabled using the indicated command line option: + +- Twofish in CTS mode (`-A2`) +- AES in CBC mode (`-A3`) +- ChaCha20 (CTR) (`-A4`) +- SPECK in CTR mode (`-A5`) + +The following chart might help to make a quick comparison and decide what cipher to use: + +| Cipher | Mode | Block Size | Key Size | IV length |Speed | Built-In | Origin | +| :---: | :---:| :---: | :---: | :---: |:---: | :---: | --- | +|Twofish | CTS | 128 bits | 256 bit | 128 bit | -..O | Y | Bruce Schneier | +|AES | CTS | 128 bits | 128, 192, 256 bit| 128 bit | O..+ | Y | Joan Daemen, Vincent Rijmen, NSA-approved | +|ChaCha20| CTR | Stream | 256 bit | 128 bit | +..++| Y | Daniel J. Bernstein | +|SPECK | CTR | Stream | 256 bit | 128 bit | ++ | Y | NSA | + +The two block ciphers Twofish and AES are used in CTS mode. + +n2n has all four ciphers built-in as basic versions. Some of them optionally compile to faster versions by the means of available hardware support (AES-NI, SSE, AVX – please see the [Building document](./Building.md) for details. Depending on your platform, AES and ChaCha20 might also draw notable acceleration from optionally compiling with openSSL 1.1 support. + +The`-k ` command line parameter supplies the key. As even non-privileged users might get to see the command line parameters (try `ps -Af | grep edge`), the key can also be supplied through the `N2N_KEY` environment variable: `sudo N2N_KEY=mysecretpass edge -c mynetwork -a 192.168.100.1 -f -l supernode.ntop.org:7777`. + +Providing `-k ` without specifying any cipher by `-A_` will default to AES encryption. + +To renounce encryption, `-A1` enables the so called `null_transform` transmitting all payload data unencryptedly. Omitting `-A_` and not providing a key through `-k ` shows the same effect. + +### Twofish + +This implementation prepends a 128 bit random value to the plain text. Its size is adjustable by changing the `TF_PREAMBLE_SIZE` definition found in `src/transform_tf.c`. It defaults to TF_BLOCK_SIZE (== 16). As CTS uses underlying CBC mode, this basically has the same effect as a respectively shorter IV. However, this flexibility does not come for free as an additional block needs to be encrypted. + +Twofish requires no padding as it employs a CBC/CTS scheme which can send out plaintext-length ciphertexts. The scheme however has a small flaw in handling messages shorter than one block, only low-level programmer might encounter this. + +On Intel CPUs, Twofish usually is the slowest of the ciphers present. However, on Raspberry Pi 3B+, Twofish was observed to be faster than AES-CTS. Your mileage may vary. Cipher speed's can be compared running the `tools/n2n-benchmark` tool. + +### AES + +AES also prepends a random value to the plaintext. Its size is adjustable by changing the `AES_PREAMBLE_SIZE` definition found in `src/transform_aes.c`. It defaults to AES_BLOCK_SIZE (== 16). The AES scheme uses a CBC/CTS scheme which can send out plaintext-length ciphertexts as long as they are one block or more in length. + +Apart from n2n's plain C implementation, Intel's AES-NI is supported – again, please have a look at the [Building document](./Building.md). In case of openSSL support its `evp_*` interface gets used which also offers hardware acceleration where available (SSE, AES-NI, …). It however is slower than the following stream ciphers because the CBC mode cannot compete with the optimized stream ciphers. + +This cipher's different key-sizes are triggered by the length of the user-provided key: 22 characters or less make n2n use AES-128, between 23 and 32 characters lead to AES-192, and 33 or more characters trigger AES-256. + +### ChaCha20 + +ChaCha20 was the first stream cipher supported by n2n. + +In addition to the basic C implementation, an SSE version is offered. If compiled with openSSL support, ChaCha20 is provided via the `evp_*` interface. It is not used together with the Poly1305 message tag from the same author though. Whole packet's checksum will be handled in the header (see below). + +The random full 128-bit IV is transmitted in plain. + +ChaCha20 usually performs faster than AES-CTS. + +### SPECK + +SPECK is recommended by the NSA for offical use in case AES implementation is not feasible due to system constraints (performance, size, …). The block cipher is used in CTR mode making it a stream cipher. The random full 128-bit IV is transmitted in plain. + +On modern Intel CPUs, SPECK performs even faster than openSSL's ChaCha20 as it takes advantage of SSE4, AVX2, or AVX512 if available. On Raspberry's ARM CPU, it is second place behind ChaCha20 and before Twofish. + +### Random Numbers + +Throughout n2n, pseudo-random numbers are generated for several purposes, e.g. random MAC assignment and the IVs for use with the various ciphers. Regarding IVs, especially for using in the stream ciphers, the pseudo-random numbers shall be as collision-free as possible. n2n uses an implementation of XORSHIFT128+ which shows a periodicity of 2¹²⁸. + +Its initialization relies on seeding with a value as random as possible. Various sources are tapped including a syscall to Linux' `SYS_getrandom` as well as Intels hardware random number generators `RDRND` and `RDSEED`, if available (compile using `-march=native`). + +### Pearson Block Hashing + +For general purpose hashing, n2n employs [Pearson Block Hashing](https://github.com/Logan007/pearsonB) as it offers variable hash sizes and is said not to be too "collidy". However, this is not a cryptographically secure hashing function which by the way is not required here: The hashing is never applied in a way that the hash value shall publicly prove the knowledge of a secret without showing the secret itself. + +_Pearson hashing is tweakable by using your own block-sized permutation._ Here, we use a three-round xor-rotate-multiply permutation scheme on 64-bit wide integer numbers with constants discovered by [David Stafford](http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html) (`mix13`, permission obtained via eMail) which, meanwhile, is better known as part of `splitmix64()`. + +_Pearson hashing allows verification of block-sized parts of the hash only – just in case performance requirements would urge to do so._ + +## Header + +### Overview + +Packet's header consist of a COMMON section followed by a packet-type specific section, e.g. REGISTER, REGISTER_ACK, PACKET including the payload, REGISTER_SUPER, … + +The COMMON section is built as follows: + +``` +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Version = 3 ! TTL ! Flags ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 4 ! Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 8 ! ... Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +12 ! ... Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +16 ! ... Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +20 ! ... Community ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` + +In case of a PACKET-type, it is succeeded by the fields depicted below: + +``` + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +24 ! Source MAC Address : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +28 : ! Destination MAC Address : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +32 : ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +36 ! Socket Flags (v=IPv4) ! Destination UDP Port ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +40 ! Destination IPv4 Address ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +44 ! Compress'n ID ! Transform ID ! Payload ... ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +48 ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+... +``` + +### Encryption + +If enabled (`-H`), all fields but the payload (which is handled separately as outlined above) get encrypted using SPECK in CTR mode. As packet headers need to be decryptable by the supernode and we do not want to add another key (to keep it a simple interface), the community name serves as key (keep it secret!) because it is already known to the supernode. The community name consists of up to 20 characters (well, 19 + `0x00`), so key size of 128 bit is a reasonable choice here. + +The scheme applied tries to maintain compatibility with current packet format and works as follows: + +- First line of 4 bytes (Version, TTL, Flags) goes to sixth line: + +``` + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 4 ! ... Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 8 ! ... Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +12 ! ... Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +16 ! ... Community ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +20 ! Version = 3 ! TTL ! Flags ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` +- To be able to identify a correctly decrpyted header later on, a magic number is stamped in fourth line starting at byte number 16. We use "n2" string and add the 16-bit header length to be able to stop header decryption right before an eventually following ethernet data payload begins – in case of PACKET-type, header-length does not equal packet-length. 16-bit length is required because REGISTER_SUPER_ACK packets consist of header only and could grow quite large due to their payload (other supernodes of federation) – don't mix up this kind of payload (part of the header) with the ethernet data payload of PACKET messages. + +- The rest of the community field, namely the first 16 bytes, is reframed towards a 128-bit IV for the header encryption. + +``` + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! IV ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 4 ! ... IV ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 8 ! ... IV ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +12 ! ... IV ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +16 ! Magic Number "n2" = 0x6E32 ! Header Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +20 ! Version = 3 ! TTL ! Flags ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` + +- As we use a stream cipher, the IV should be a nonce. The IV plays an additional role sketched later, see the following sections on checksum and replay protection. + +- To make a less predictable use of the key space – just think of the typically reset MSB of ASCII characters of community names – we actually use a hash of the community name as key. + +- Encryption starts at byte number 16 and ends at header's end. It does not comprise PACKET's ethernet data payload which eventually has its own encryption scheme as chosen with the `-A_` options. + +Decryption checks all known communities (several in case of supernode, only one at edge) as keys. On success, the emerging magic number along with a reasonable header's length value will reveal the correct community whose name will be copied back to the original fields allowing for regular packet handling. + +Thus, header encryption will only work with previously determined community names introduced to the supernode by `-c ` parameter. Also, it should be clear that header encryption is a per-community decision, i.e. all nodes and the supernode need to have it enabled. However, the supernode supports encrypted and unencrypted communities in parallel, it determines their status online at arrival of the first packet. Use a fresh community name for encrypted communities; do not use a previously used one of former unecrypted communities: their names were transmitted openly. + +### Checksum + +The whole packet including the eventually present payload is checksummed using a Person block hashing scheme. The 64-bit checksum is exclusive-ored with a (shifted by 32 bit) 64-bit time stamp and filled up with 32 more random bits to obtain a 128-bit pre-IV. This pre-IV gets encrypted using a single block-cipher step to get the pseudo-random looking IV. This way, the checksum resists targeted bit-flips (to header, payload, and IV) as any change to the whole 128-bit IV would render the header un-decryptable. Also, as explained below, the checksum comes along with a time stamp minimizing opportunities for random attacks. + +The single block-cipher step employs SPECK because it is quite fast and it offers a 128-bit block cipher version. The key is derived from the header key – a hash of the hash. + +The checksum is calculated by the edges and the supernode. Changes to the payload will cause a different locally calculated checksum. Extracting the time stamp by exclusive-oring an erroneous checksum will lead to an invalid timestamp. So, checksum errors are indirectly detected when checking for a valid time stamp. + +### Replay Protection + +The aforementioned 128-bit pre-IV can be depicted as follows: + +``` + 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567 + +----------------------------------------------------------------+-------------------------------+-------------------------------+ + ! 64-bit checksum of the whole packet ! 0x00 ! ! + + - - - - - - - - - - - - - - - - - - - - - - - XOR - - - - - - - - - - - - - - - - - - - - - - -! 32 pseudo-random bits ! + ! 0x00 ! 52-bit time stamp with microsecond-accuracy ! countr ! F ! ! + +------------------------------------------------------------------------------------------------+-------------------------------+ + +``` + +The time stamp consists of the 52-bit microsecond value, a 8-bit counter in case of equal following time stamps and, a 4-bit flag field F (accuracy indicator in last bit). edge and supernode monitor their own time stamps for doublets which would indicate an accuracy issue. If the counter overflows on the same time stamp, the sub-second part of the time stamp will also become counter. In this case, the whole stamp carries the accuracy bit flag (lowest bit) set so other edges and supernodes can handle this stamp appropriately. + +Encrypting this pre-IV using a block cipher step will generate a pseudo-random looking IV which gets written to the packet and used for the header encryption. + +Due to the time-stamp encoded, the IV will more likely be unique, close to a real nonce. + +Upon receival, the time stamp as well as the checksum can be extracted from the IV by performing a 128-bit block-cipher decryption step. Verification of the time stamp happens in two steps: + +- The (remote) time stamp is checked against the local clock. It may not deviate more than plus/minus 16 seconds. So, edges and supernode need to keep a somewhat current time. This limit can be adjusted by changing the `TIME_STAMP_FRAME` definition. It is time-zone indifferent as UTC is used. + +- Valid (remote) time stamps get stored as "last valid time stamp" seen from each node (supernode and edges). So, a newly arriving packet's time stamp can be compared to the last valid one. It should be equal or higher. However, as UDP packets may overtake each other just by taking another path through the internet, they are allowed to be 160 millisecond earlier than the last valid one. This limit is set with the `TIME_STAMP_JITTER` definition. If the accuracy flag is set, the time stamp will be allowed a jitter eight times as high, corresponding to 1.25 seconds by default. + +- However, the systemic packets such as REGISTER_SUPER are not allowed any time stamp jitter because n2n relies on the actual sender's socket. A replay from another IP within any allowed jitter time frame would deviate the traffic which shall be prevented (even if it remains undecryptable). Under absolutely rare (!) circumstances, this might cause a re-registration requirement which happens automatically but might cause a small delay – security (including network availability) first! REGISTER packets from the local multicast environment are exempt from the very strict no-jitter requirement because they indeed regularly can show some deviation if compared to time stamps in packets received on the regular socket. As these packets are incoming on different sockets, their processing is more likely to no take place in the order these packets were sent. + +The way the IV is used for replay protection and for checksumming makes enabled header encryption a prerequisite for these features. diff --git a/doc/Faq.md b/doc/Faq.md new file mode 100644 index 0000000..7958248 --- /dev/null +++ b/doc/Faq.md @@ -0,0 +1,72 @@ +# n2n Frequently Asked Questions + + +## Supernode + + +### I want to setup a supernode that only I can use. Perhaps even password protected? + +Please think of the community-name as password and start the supernode with the `-c ` parameter where the `` is the path to a simple text file containing a single line with the name of your secret community. It will be the only community allowed. Only edge nodes from that community can join (`-c ` at the edge). + +If you additionally want to prevent open transmission of your secret community name via the network, **all** edge nodes should use `-H` command line option for header encryption. + +Also, please see the `community.list` file coming with n2n for advanced use of that file. + +Beyond this access barrier you may want to use payload encryption `-A_` at the edges. Only the edges – not the supernode – are able to decipher the payload data. So, even if anyone would be able to break the access barrier to the supernode, the payload remains protected by the payload crypto, see [this document](https://github.com/ntop/n2n/blob/dev/doc/Crypto.md) for details. + + +### Can I get a list of connected edge nodes and their community and source IP address from the supernode? + +The supernode provides basic information via its localhost udp management port. It defaults to 5645 and can be changed using supernode's `-t` command line option. + +You can request the current status by just sending a new line, i.e. pressing [ENTER] key, running the following command (localhost only) + +`netcat -u localhost 5645` + + +### Is there support for multiple supernodes? + +Yes, there is. Please [read](https://github.com/ntop/n2n/blob/dev/doc/Federation.md) about how several supernodes can form a Federation to increase network resilience. + + +### Can a supernode listen on multiple ports? + +The supernode itself can only listen on one port. However, your firewall might be able to map additional UDP ports to the supernode's regular port: + +`sudo iptables -t nat -A PREROUTING -i -d -p udp --dport -j REDIRECT --to-ports ` + +This command line can be put down as additional `ExecStartPost=` line (without `sudo`) in the supernode's `.service` file which can hold several such lines if required. + + +### How to handle the error message "process_udp dropped a packet with seemingly encrypted header for which no matching community which uses encrypted headers was found"? + +This error message means that the supernode is not able to identify a packet as unencrypted. It does check for a sane packet format. If it fails the header is assumed encrypted (thus, "_seemingly_ encrypted header") and the supernode tries all communities that would make a key (some have already been ruled out as they definitely are unenecrypted). If no matching community is found, the error occurs. + +If all edges use the same `-H` setting (all edges either with it or without it) and restarting the supernode does not help, most probably one of the components (an edge or the supernode) is outdated, i.e. uses a different packet format – from time to time, a lot of changes happen to the packet format in a very short period of time, especially in _dev_ branch. + +So, please make sure that all edges **and** the supernode have the exact same built version, e.g. all from current _dev_. + + +## Edge + + +### How can I know if peer-to-peer connection has successfully been established? + +The edge also offers a local udp management port at which it provides some information about connected _peers_ allowing a peer-to-peer connection, and _pending peers_ whose connections are forwarded through the supernode. + +The edge's management port defaults to 5644 and can be changed using edge's `-t` command line option. Connecting using the following command (localhost only) + +`netcat -u localhost 5644` + +answers every new line, i.e. pressing [ENTER] key, with current information. The edge even understands some simple commands, try `help`. + + +### The edge repeatedly throws an "Authentication error. MAC or IP address already in use or not released yet by supernode" message. What is wrong? + +The edge encountered n2n's protection against spoofing. It prevents that one edge's identity, MAC and IP address, can be impersonated by some other while the original one is still online, see some [details](Authentication.md). Mostly, there are two situations which can trigger this: + +If you use a MAC or IP address that already is in use, just change those parameters. + +If the edge prematurely has ended in a non-regular way, i.e. by killing it using `kill -9 ...` or `kill -SIGKILL ...`, it did not have a chance to un-register with the supernode which still counts the edge for online. A re-registration with the same MAC or IP address will be unsuccessful then. After two minutes or so the supernode will have forgotten. A new registration with the same parameters will be possible then. So, either wait two minutes or chose different parameters to restart with. + +And, as a matter of principal, always end an edge by either pressing `CTRL` + `C` or by sending SIGTERM or SIGINT by using `kill -SIGTERM ...` or `kill -SIGINT ...`! A plain `kill ...` without `-9` will do, too. And finally, a `stop` command to the management port peacefully ends the edge as well. diff --git a/doc/Federation.md b/doc/Federation.md new file mode 100644 index 0000000..a674d8a --- /dev/null +++ b/doc/Federation.md @@ -0,0 +1,41 @@ +# Supernode Federation + +## Idea +To enhance resilience in terms of backup and fail-over, also for load-balancing, multiple supernodes can easily interconnect and form a special community, called **federation**. + + +## Using Multiple Supernodes + +### Form a Federation + +To form a federation, multiple supernodes need to be aware of each other. To get them connected, an additional `-l` option from command line is required at the supernode. + +This option takes the IP address (or name) and the UDP port of another known supernode, e.g. `-l 192.168.1.1:1234`. + +### Use a Federation + +Federated supernodes take care of propagating their knowledge about other supernodes to all other supernodes and the edges. + +So, in the first place, edges only need to connect to one supernode (called anchor supernode) using `-l` option. This supernode needs to be present at start-up. + +Optionally, more anchor supernodes of the same federation can be provided to an edge using several `-l` options. This will counter scenarios with reduced assured initial supernode availability. + +## How It Works + +Supernodes should be able to communicate among each other as regular edges already do. For this purpose, a special community called federation was introduced. The federation feature provides some mechanisms to inter-connect the supernodes of the network enhancing backup, fail-over and load-sharing, without any visible behavioral change. + +The default name for the federation is `*Federation`. Internally, a mandatory special character is prepended to the name: that way, an edge won't be able to provide a regular community with the same name of the federation. Optionally, a user can choose a federation name (same on all supernodes) and provide it via `-F mySecretFed` option to the supernode. Alternatively, the federation name can be passed through the environment variable `N2N_FEDERATION`. + +Federated supernodes register to each other using REGISTER_SUPER message type. The answer, REGISTER_SUPER_ACK, contains a payload with information about other supernodes in the network. + +This specific mechanism is also used during the registration process taking place between edges and supernodes, so edges are able to learn about other supernodes. + +Once edges have received this information, it is up to them choosing the supernode they want to connect to. Each edge pings supernodes from time to time and receives information about them inside the answer. We decided to implement a work-load based selection strategy because it is more in line with the idea of keeping the workload low on supernodes. Moreover, this way, the entire network load is evenly distributed among all available supernodes. + +An edge connects to the supernode with the lowest work-load and it is re-considered from time to time, with each re-registration. We use a stickyness factor to avoid too much jumping between supernodes. + +Thanks to this feature, n2n is now able to handle security attacks such as DoS against supernodes and it can redistribute the entire load of the network in a fair manner between all the supernodes. + +To serve scenarios in which an edge is supposed to select the supernode by round trip time, i.e. choosing the "closest" one, the `--select-rtt` command line option is available at the edge. Note, that workload distribution among supernodes might not be so fair then. + +Furthermore, `--select-mac` would switch to a MAC address based selection strategy choosing the supernode active with the lowest MAC address. diff --git a/HACKING b/doc/Hacking.md similarity index 70% rename from HACKING rename to doc/Hacking.md index b0b9e67..1dd4774 100644 --- a/HACKING +++ b/doc/Hacking.md @@ -1,13 +1,10 @@ -file: HACKING - -Last updated: 2008-04-10 +# Hacking -------- -(C) 2008 - Richard Andrews -This program and document 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 +This program and document 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, @@ -16,18 +13,15 @@ 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 see +along with this program; if not see see [](http://www.gnu.org/licenses/) -------- - This file describes the internals of n2n. Read this before starting to modify the code. Because coding examples may be present in this document it is licensed under the GPL rather than FDL. - -SYMMETRIC NAT -------------- +## Symmetric NAT Symmetric NAT is a form of firewall NAT in which an UDP packets are only passed back to an inside host socket when the return packets originate from the outside @@ -35,29 +29,44 @@ socket to which the initiating UDP packets were sent. This means that when an inside host sends UDP to some outside socket; other hosts cannot piggyback on this opening in the firewall to send data to the inside host. -When two inside hosts are both behind symmetric NAT, peer-to-peer packet -exchange is not possible via n2n. These hosts will require the supernode to -relay packets. +For example, an asymmetric NAT would keep the mapping: + ` -> ` -ARP CACHE ---------- +and would redirect all the packets on external port ExtPort to the internal host +regardless of the remote IP. + +Whereas a symmetric NAT would keep the mapping: + + ` -> ` + +so only RemoteIP can send packets to the internal host. RemoteIP is the supernode +IP in case of n2n, to which the internal host has registered. + +In n2n, P2P can work monodirectionally if only one of the two peers is behind a symmetric +NAT. For example, if A is behind symmetric NAT and B is behind asymmetric NAT + - A->B packets are P2P (will have the B public IP as destination) + - B->A packets must go through the supernode + +If both the peers are behind symmetric NAT, then no P2P communication is possible. + +## ARP Cache n2n makes use of the host operating system's own ARP cache. Each edge node allocates a random MAC address to itself. This MAC is constant for the life of the edge process. ARP packets are passed around as broadcast ethernet packets over n2n and these packets cause the native ARP cache to be updated. -Edge nodes send gratuitous ARP packets on startup. See GRATUITOUS ARP below. +Edge nodes send gratuitous ARP packets on startup. See section on gratuitous ARP below. -REGISTRATION AND PEER-TO-PEER COMMUNICATION SETUP -------------------------------------------------- +## Registration and Peer-to-Peer Communication Setup A and B are edge nodes with public sockets Apub and Bpub; and private network addresses A and B respectively. S is the supernode. A sends {REGISTER,Amac} to S. S registers {Amac->Apub}. + B sends {REGISTER,Bmac} to S. S registers {Bmac->Bpub}. Now ping from A to B. @@ -91,12 +100,10 @@ receives {REGISTER,Amac} from A. The supernode never forwards REGISTER messages because the public socket seen by the supervisor for some edge (eg. A) may be different to the socket seen by -another edge due to the actions of symmetric NAT (alocating a new public socket +another edge due to the actions of symmetric NAT (allocating a new public socket for the new outbound UDP "connection"). - -EDGE REGISTRATION DESIGN AMMENDMENTS (starting from 2008-04-10) ------------------------------------- +## Edge Resgitration Design Ammendments (starting from 2008-04-10) * Send REGISTER on rx of PACKET or REGISTER only when dest_mac == device MAC (do not send REGISTER on Rx of broadcast packets). @@ -114,7 +121,6 @@ exists. Direct peer-to-peer sockets are always given more priority as the supernode socket will not be usable for direct contact if the peer is behind symmetric NAT. - The pending_peers list concept is to prevent massive registration traffic when supernode relay is in force - this would occur if REGISTER was sent for every incident packet sent via supernode. Periodic REGISTER attempts will still occur; @@ -135,9 +141,7 @@ If a peer wants to be remembered it can send gratuitous ARP traffic which will keep its entry in the known_peers list of any peers which already have the entry. - - - +``` peer = find_by_src_mac( hdr, known_peers ); /* return NULL or entry */ if ( peer ) @@ -160,21 +164,20 @@ else } } } +``` - -(Notes): +### Notes * In testing it was noted that if a symmetric NAT firewall shuts down the UDP association but the known_peers registration is still active, then the peer becomes unreachable until the known_peers registration is deleted. Suggest two ways to mitigate this problem: - (a) make the known_peers purge timeout a config paramter; + (a) make the known_peers purge timeout a config parameter; (b) send packets direct and via supernode if the registration is older than eg. 60 sec. -GRATUITOUS ARP --------------- +## Gratuitous ARP In addition to the ARP who-has mechanism noted above, two edge nodes can become aware of one another by gratuitous ARP. A gratuitous ARP packet is a broadcast @@ -183,91 +186,77 @@ identify its MAC and IP address. Gratuitous ARP packets are to keep ARP caches up to date so contacting the host will be faster after an long idle time. -MAN PAGES ---------- +## man Pages Look at a non-installed man page like this (linux/UNIX): -nroff -man edge.8 | less +`nroff -man edge.8 | less` -PACKET FORMAT -------------- +## PACKET message format -Version 1 +All message encoding and decoding is contained in wire.c. The PACKET message is +of main concern as it is the most frequently transferred as it contains +encapsulated ethernet packets. + +``` +Version 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - 0 ! Version=1 ! Message Type ! TTL ! Origin ! + ! Version=3 ! TTL ! Flags ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - 4 ! ! - 8 ! Community Name ! -12 ! ! -16 ! ! + 4 ! Community : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -20 ! Source MAC Address : + 8 ! ... Community ... : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -24 : Source MAC Address ! Destination MAC Address : +12 ! ... Community ... : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -28 : Destination MAC Address ! +16 ! ... Community ... : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -32 ! Public Peer ! +20 ! ... Community ... ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : : +24 ! Source MAC Address : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -40 : : +28 : ! Destination MAC Address : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : : +32 : ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -48 : ! Alignment ! +36 ! Socket Flags (v=IPv4) ! Destination UDP Port ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Private Peer : +40 ! Destination IPv4 Address ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -56 : : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -64 : : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : ! Alignment ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -72 ! Packet Type ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Seq Number ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -80 ! CRC32 ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - Payload +44 ! Compress'n ID ! Transform ID ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +48 ! Payload + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` +So each n2n PACKET has a 48 byte overhead. For a 1500 byte ethernet packet this +is roughly 3%. -Version = 1 -MessageType = 1 -TTL = 1 -Origin = 1 -Community = 16 -src MAC = 6 -dst MAC = 6 -Pub Peer = 19 (20) -Priv Peer = 19 (20) -Pkt Type = 1 (4) -Seq = 4 -CRC = 4 -====================== -Total = 79 (84) +Socket flags provides support for IPv6. In this case the PACKET message ends as +follows: -Sizes in parentheses indicate alignment adjusted sizes on i686. The intel -alignment is also shown in the diagram. Some platforms have different alignment -padding. - -The above packet format describes the header of IP packets carried between edge -nodes. Payload is an encoded ethernet frame appended to the packet header. The -ethernet payload is encrypted and compressed. - -When the payload is created it is first encrypted with twofish, then compressed -using lzo1x_compress. When the payload is decoded it is first decompressed using -lzo1x_decompress_safe then decrypted using twofish. +``` + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +36 ! Socket Flags (v=IPv6) ! Destination UDP Port ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +40 ! Destination IPv6 Address : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +44 : : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +48 : : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +52 : ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +56 ! Compress'n ID ! Transform ID ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +60 ! Encapsulated ethernet payload + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` ------- +(C) 2008-2010 - Richard Andrews -January 2009 - Richard Andrews +January 2010 - Richard Andrews \ No newline at end of file diff --git a/doc/ManagementAPI.md b/doc/ManagementAPI.md new file mode 100644 index 0000000..3f179f4 --- /dev/null +++ b/doc/ManagementAPI.md @@ -0,0 +1,242 @@ +# Management API + +This document is focused on the machine readable API interfaces. + +Both the edge and the supernode provide a management interface UDP port. +These interfaces have some documentation on their non machine readable +commands in the respective daemon man pages. + +Default Ports: +- UDP/5644 - edge +- UDP/5645 - supernode + +A Quick start example query: + `echo r 1 help | nc -w1 -u 127.0.0.1 5644` + +## JSON Query interface + +A machine readable API is available for both the edge and supernode. It +takes a simple text request and replies with JSON formatted data. + +The request is in simple text so that the daemon does not need to include any +complex parser. + +The replies are all in JSON so that the data is fully machine readable and +the schema can be updated as needed - the burden is entirely on the client +to handle different replies with different fields. It is expected that +any client software will be written in higher level programming languages +where this flexibility is easy to provide. + +Since the API is over UDP, the replies are structured so that each part of +the reply is clearly tagged as belonging to one request and there is a +clear begin and end marker for the reply. This is expected to support the +future possibilities of pipelined and overlapping transactions as well as +pub/sub asynchronous event channels. + +The replies will also handle some small amount of re-ordering of the +packets, but that is not an specific goal of the protocol. + +Note that this API will reply with a relatively large number of UDP packets +and that it is not intended for high frequency or high volume data transfer. +It was written to use a low amount of memory and to support incremental +generation of the reply data. + +With a small amount of effort, the API is intended to be human readable, +but this is intended for debugging. + +## Request API + +The request is a single UDP packet containing one line of text with at least +three space separated fields. Any text after the third field is available for +the API method to use for additional parameters + +Fields: +- Message Type +- Options +- Method +- Optional Additional Parameters + +The maximum length of the entire line of text is 80 octets. + +All request packets should generate a reply. However, this reply may simply +be an error. + +### Message Type + +This is a single octet specifying the type: + +- "r" for a read-only method (or one that does not need change permissions) +- "w" for a write method (or one that makes changes) +- "s" for a subscribe method to request this socket receive some events + +To simplify the interface, the reply from both read and write calls to the +same method is expected to contain the same data. In the case of a write +call, the reply will contain the new state after making the requested change. + +The subscribe and events message flow works with a different set of messages. + +### Options + +The options field is a colon separated set of options for this request. Only +the first subfield (the "tag") is mandatory. The second subfield is a set +of flags that describe which optional subfields are present. +If there are no additional subfields then the flags can be omitted. + +SubFields: +- Message Tag +- Optional Message Flags (defaults to 0) +- Optional Authentication Key + +#### Message Tag + +Each request provides a tag value. Any non error reply associated with this +request will include this tag value, allowing all related messages to be +collected within the client. The tag will be truncated if needed by the +daemon, but there will be at least 8 octets of space available. + +Where possible, the error replies will also include this tag, however some +errors occur before the tag is parsed. + +The tag is not interpreted by the daemon, it is simply echoed back in all +the replies. It is expected to be a short string that the client knows +will be unique amongst all recent, still outstanding or subscription requests +on a given socket. + +One possible client implementation is a number between 0 and 999, incremented +for each request and wrapping around to zero when it is greater than 999. + +#### Message Flags + +This subfield is a set of bit flags that are hex-encoded and describe any +remaining optional subfields. + +Currently, only one flag is defined. The presence of that flag indicates +that an authentication key subfield is also present. + +Values: +- 0 - No additional subfields are present +- 1 - One additional field, containing the authentication key + +#### Authentication Key + +A simple string password that is provided by the client to authenticate +this request. See the Authentication section below for more discussion. + +#### Example Options value + +e.g: + `102:1:PassWord` + +### Example Request string + +e.g: + `r 103:1:PassWord peer` + +## Reply API + +Each UDP packet in the reply is a complete and valid JSON dictionary +containing a fragment of information related to the entire reply. + +Reply packets are generated both in response to requests and whenever +an event is published to a subscribed channel. + +### Common metadata + +There are two keys in each dictionary containing metadata. First +is the `_tag`, containing the Message Tag from the original request. +Second is the `_type` which identifies the expected contents of this +packet. + +### `_type: error` + +If an error condition occurs, a packet with a `error` key describing +the error will be sent. This usually also indicates that there will +be no more substantial data arriving related to this request. + +e.g: + `{"_tag":"107","_type":"error","error":"badauth"}` + +### `_type: begin` + +Before the start of any substantial data packets, a `begin` packet is +sent. For consistency checking, the method in the request is echoed +back in the `error` key. + +e.g: + `{"_tag":"108","_type":"begin","cmd":"peer"}` + +For simplicity in decoding, if a `begin` packet is sent, all attempts +are made to ensure that a final `end` packet is also sent. + +### `_type: end` + +After the last substantial data packet, a final `end` packet is sent +to signal to the client that this reply is finished. + +e.g: + `{"_tag":"108","_type":"end"}` + +### `_type: row` + +The substantial bulk of the data in the reply is contained within one or +more `row` packets. The non metadata contents of each `row` packet is +defined entirely by the method called and may change from version to version. + +Each `row` packet contains exactly one complete JSON object. The row replies +may be processed incrementally as each row arrives and no batching of multiple +packets will be required. + +e.g: + `{"_tag":"108","_type":"row","mode":"p2p","ip4addr":"10.135.98.84","macaddr":"86:56:21:E4:AA:39","sockaddr":"192.168.7.191:41701","desc":"client4","lastseen":1584682200}` + +### `_type: subscribed` + +Signals that the subscription request has been successfully completed. +Any future events on the requested channel will be asynchronously sent +as `event` packets using the same tag as the subscribe request. + +### `_type: unsubscribed` + +Only one management client can be subscribed to any given event topic, so if +another subscribe request arrives, the older client will be sent this message +to let them know that they have been replaced. + +(In the future, this may also be sent as a reply to a explicit unsubscribe +request) + +### `_type: replacing` + +If a new subscription request will replace an existing one, this message is +sent to the new client to inform them that they have replaced an older +connection. + +### `_type: event` + +Asynchronous events will arrive with this message type, using the same tag as +the original subscribe request. Just like with the `row` packets, the non +metadata contents are entirely defined by the topic and the specific n2n +version. + +## Subscribe API + +A client can subscribe to events using a request with the type of "s". +Once a subscribe has been successfully completed, any events published +on that channel will be forwarded to the client. + +Only one management client can be subscribed to any given event topic, +with newer subscriptions replacing older ones. + +The special channel "debug" will receive copies of all events published. +Note that this is for debugging of events and the packets may not have +the same tag as the debug subscription. + +## Authentication + +Some API requests will make global changes to the running daemon and may +affect the availability of the n2n networking. Therefore the machine +readable API include an authentication component. + +Currently, the only authentication is a simple password that the client +must provide. It defaults to 'n2n' and can manually be set through the +command line parameter `--management-password ` – for edge as well +as for supernode. diff --git a/doc/Routing.md b/doc/Routing.md new file mode 100644 index 0000000..c4d57f2 --- /dev/null +++ b/doc/Routing.md @@ -0,0 +1,188 @@ +# IPv4 Routing (Linux) + +## General Remarks + +Reaching a remote network or tunneling all the internet traffic via n2n are two common tasks which require a proper routing setup. n2n supports routing needs providing options for packet forwarding including broadcasts as well as modifying the routing table. + +In this context, the `server` is the edge node which provides access to the remote network/internet, whereas the `client` is the connecting edge node. + +In order to enable routing, the `server` must be configured as follows: + +1. Add the `-r` option to the edge options to enable routing +2. Enable packet forwarding with `sudo sysctl -w net.ipv4.ip_forward=1` +3. Enable IP masquerading: `sudo iptables -t nat -A POSTROUTING -j MASQUERADE` + +On the client side, the easiest way to configure routing is via the `-n` option. For example: + +- In order to connect to the remote network `192.168.100.0/24`, use `-n 192.168.100.0/24:10.0.0.1` +- In order to tunnel all the internet traffic, use `-n 0.0.0.0/0:10.0.0.1` + +10.0.0.1 is the IP address of the gateway to use to route the specified network. It should correspond to the IP address of the `server` within n2n. Multiple `-n` options can be specified. + +As an alternative to the `-n` option, the `ip route` linux command can be manually used. See the [n2n-gateway.sh](scripts/n2n-gateway.sh) script for an example. See also the following description of other use cases and in depth explanation. + +## Special Scenarios + +### Assumptions + +- There are two Local Area Networks, namely 10.11.12.0/24 (maybe at + **h**ome) and 192.168.1.0/24 (maybe in **o**ffice). +- These networks are connected to the internet via routers 10.11.12.1 + and 192.168.1.1, respectively. +- In each network, there is a computer running a successfully setup n2n + node: 10.11.12.5 (**h**ickory) and 192.168.1.6 (**o**scar). They are + connected to their networks through a device called _eth0_. Their n2n + devices shall be called _n2n0_, and their n2n IP addresses are + 10.99.99.50 (**h**ickory) and 10.99.99.60 (**o**scar) in the + 10.99.99.0/24 network. +- The _iptables_ are flushed. + +### Prerequisites + +- Both, **h**ickory and **o**scar have ip forwarding enabled: `echo 1 > /proc/sys/net/ipv4/ip_forward` or `sysctl -w net.ipv4.ip_forward=1`. To + make this setting persistent over reboot, a file containing the line + `net.ipv4.ip_forward=1` could be added in /etc/sysctl.d/ – your distro + may vary. +- To allow n2n to forward packets, both edge nodes need to be started + with `-r` option on their command line. All other regular network + interfaces usually already allow packet forwarding and thus do not need + any further configuration. + +### Reach Complete Office Network from n2n Node at Home + +- To make **h**ickory send all packets with office destination via + **o**scar, **h**ickory needs to be made aware of where to route this + packets to. On **h**ickory: `ip route add 192.168.1.0/24 via 10.99.99.60 dev n2n0 src 10.11.12.5`. +- **o**scar needs to know where to send packets to, too. So, on + **o**scar: `ip route add 10.11.12.5 via 10.99.99.50 dev n2n0 src 192.168.1.6`. + +**o**scar and **h**ickory should now be able to exchange packets by +using just their regular (non-n2n) IP addresses 10.11.12.5 and 192.168.1.6. +To make the complete office network aware of how packets or answers are +sent to **h**ickory, one more step is required: + +- Packets from any office computer to **h**ickory need to be directed to + **o**scar that – thanks to enabled IP forwarding and the routing rule – + already knows how to handle this kind of packets. + - To handle it in a one-stop-shop, the office router 192.168.1.1 can + be configured to direct those packets to **o**scar. Luckily, even most + modern small-office-and-home routers allow to add static routing rules + via a web interface. A rule like "All packets for host 10.11.12.5 (or + network 10.11.12.0/24) need to be sent to another router, namely + 192.168.1.5" will do. This is the **recommended** solution. + - However, a **less recommended** but working option would be to add + static routes to each single of those computers in the office network + that shall be able to connect to or be accessed by **h**ickory. On + those, e.g. **o**livia with IP address 192.168.1.123: `ip route add 10.11.12.5 via 192.168.1.5 dev eth0 src 192.168.1.123`. + - Alternatively, in case the office router does not allow to have + added own static routing rules, **o**scar needs to perform NAT for all + connections initiated from **h**ickory: + `iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE` + `iptables -A FORWARD -i eth0 -o n2n0 -m state --state RELATED,ESTABLISHED -j ACCEPT` + `iptables -A FORWARD -i n2n0 -o eth0 -j ACCEPT` + There is a major drawback with this solution which thus is the **least + recommended**: Connections between **h**ickory and the office network + will only work if initiated by **h**ickory – not the other way 'round. + By the way, in case _iptables_ are messed up, they can be flushed by: + `iptables -F` + `iptables -X` + `iptables -t nat -F` + `iptables -t nat -X` + `iptables -t mangle -F` + `iptables -t mangle -X` + `iptables -t raw -F` + `iptables -t raw -X` + `iptables -t security -F` + `iptables -t security -X` + `iptables -P INPUT ACCEPT` + `iptables -P FORWARD ACCEPT` + `iptables -P OUTPUT ACCEPT` + +### Reach n2n Node in Office from Whole Home Network + +This is easy: + +- Just exchange home and office IP addresses and the computer names in + the instructions given above. + +### Reach Whole Home Network from Whole Office Network + +This is not too complicated either. Basically, follow the given example +above and apply the following changes: + +- The instructions used above need to be expanded from **h**ickory's IP + 10.11.12.5 to its full network 10.11.12.0/24 in the route commands on + **o**scar:, especially: `ip route add 10.11.12.0/24 via 10.99.99.50 dev n2n0 src 192.168.1.6`. +- In case of adding a static route to the office network router + 192.168.1.1, the home network 10.11.12.0/24 must be specified instead of + **h**ickory's more specific IP address 11.11.12.5. Same for the less + recommended static routes on other office computers. +- Packets from home network's computers to the office network need to be + sent through the n2n tunnel. The three alternatives given above can be + used just with exchanged office and home IP addresses. One needs to be + aware that NAT only (third alternative) on both sides will not allow any + connection, i.e. at least on one side static routes need to be added + either to the router (best option) or all those computers that shall be + able to connect to the other network. + +### Route All Internet Traffic from n2n Node at Home through Office Network + +This scenario could be considered a n2n-tunneled VPN connection which +also would work for travelling users on their laptop. All external +internet traffic will appear to originate from **o**scar and the office +network. + +- First, one of the setups described above needs to be in place, with + the following change: +- NAT on **o**scar (see the three _iptables_ commands above) must be + enabled. It will not work without because the office router 192.168.1.1 + usually denies forwarding to packets not originating from its own + network. It could be in addition to the eventually installed static + routes for 10.11.12.0/24 in the router 192.168.1.1 or on other office + computers – it will not interfere. However, **o**scar definitely needs + the route given above: `ip route add 10.11.12.5 via 10.99.99.50 dev n2n0 src 192.168.1.6`. +- To have **h**ickory's complete internet traffic going through the n2n + tunnel, its default route needs to be changed: + `ip route del default` + `ip route add default via 10.99.99.60 dev n2n0 src 10.11.12.5` + +- **h**ickory's home network should still be reachable as usually, + _eth0_ and the associated network 10.11.12.0/24 get their very own + route. If not, i.e. it was only covered by default route before, it + needs to be added: `ip route add 10.11.12.0/24 dev eth0 src 10.11.12.5`. +- Unfortunately (unless the supernode is on **h**ickory's local + network), n2n supernode becomes unreachable for **h**ickory. To fix it: + `ip route add via 10.11.12.1 dev eth0 src 10.11.12.5` + +The supernode's IP address needs to be known to have this work. However, +if the supernode's IP needs to be resolved from some domain name (FQDN), +e.g. in case of using dynamic domain name services, a DNS server needs +to remain reachable, too. Either the reachable home network router +10.11.12.1 is good enough for that (if it offers DNS) or another route +could to be added and **h**ickory's DNS settings might be set +accordingly, maybe to Google's 8.8.8.8. + +If [DNS leaks](https://en.wikipedia.org/wiki/DNS_leak) do not matter, +this setup is complete. + +### Preventing DNS Leaks + +Otherwise, there is more to it: Without changes, all future DNS queries +go through the home router 10.11.12.1 to the ISP's servers or directly +to Google (via the home router 10.11.12.1 along the configured route for +8.8.8.8 and not through the n2n tunnel) while the remaining traffic +ships through the n2n tunnel. + +To prevent such a DNS leak, the supernode's IP address must be +determined independently from **h**ickory's DNS configuration, e.g. by +digesting `dig +short mysupernode.myfavoritednsservice.com @8.8.8.8`'s +output in the n2n-edge's setup script for both, the edge node command +line as well as the static route mentioned above. Without further +additional work, dynamic address changes remain undetected. A static +route to 8.8.8.8 is still required. **h**ickory's regular DNS +configuration should query a different DNS server for its regular DNS +needs, e.g. 9.9.9.9 or 1.1.1.1 or maybe the office DNS server, maybe +192.168.1.1. This guarantees the regular DNS queries also to get sent +through the n2n tunnel. + +A test for DNS leaks can be found [here](https://www.dnsleaktest.com/). diff --git a/doc/Scratchpad.md b/doc/Scratchpad.md new file mode 100644 index 0000000..68d5f88 --- /dev/null +++ b/doc/Scratchpad.md @@ -0,0 +1,61 @@ +# n2n's Scratchpad + +## RPM Packaging + +``` +bash +./autogen.sh +./configure +make + +cd packages/rpm +./configure +rpmbuild -bb ./n2n.spec +``` + +## New Features between 2.0.x and 2.1.x + +- Better ming Windows build support. +- Added `-E` flag to allow multicast ethernet traffic. + +## Draft changelog between 2.8 and 3.0 (as of September 27, 2021) + +### New Features + +- Federated supernodes to allow multiple supernodes for load balancing and fail-over (`doc/Federation.md`) +- Automatic IP address assignment allows edges to draw IP addresses from the supernode (just skip `-a`) +- Allowed community names can be restricted by regular expressions (`community.list` file) +- Network filter for rules (`-R`) allowing and denying specific traffic to tunnel +- Experimental TCP support (`-S2`) lets edges connect to the supernodes via TCP in case firewalls block UDP (not available on Windows yet) +- All four supported ciphers offer integrated versions rendering OpenSSL dependency non-mandatory (optionally still available) +- MAC and IP address spoofing prevention +- Network interface metric can be set by command-line option `-x` (Windows only) +- Re-enabled local peer detection by multicast on Windows +- Edge identifier (`-I`) helps to identify edges more easily in management port output +- Optionally bind edge to one local IP address only (extension to `-p`) +- A preferred local socket can be advertised to other edges for better local peer-to-peer connections (`-e`) +- Optional edge user and password authentication (`-J`, `-P`, `doc/Authentication.md`) +- Optional json format at management port allows for machine-driven handling such as `.html` page generation (`scripts/n2n-httpd`) or script-based evaluation (`scripts/n2n-ctl`) +- Completely overhauled build system including GitHub's action runners performing code syntax and formal checks, creating and running test builds, providing binairies and packages as artifacts and running verification tests + + +### Improvements + +- Increased edges' resilience to temporary supernode failure +- Fixed a compression-related memory leak +- Ciphers partly come with platform-specific hardware acceleration +- Added a test framework (`tools/test-*.c` and `tests/`) +- Clean-up management port output +- Polished benchmark tool output +- Spun-off the name resolution into a separate thread avoiding lags +- Added support for additional environment variables (`N2N_COMMUNITY`, `N2N_PASSWORD`, and `N2N_FEDERATION`) +- Implemented new `reload_communities` command to make supernode hot-reload the `-c` provided `community.list` file, issued through management port +- Reactivated send out of gratuitous ARP packet on establishing connection +- Enhanced documentation (`doc/` folder) including the man pages and command-line help text (`-h` and more detailed `--help`) +- Self-monitoring time stamp accuracy for use on systems with less accurate clocks +- Fixed man pages' and config files' paths +- Code clean-up + + + + diff --git a/doc/Scripts.md b/doc/Scripts.md new file mode 100644 index 0000000..63e5833 --- /dev/null +++ b/doc/Scripts.md @@ -0,0 +1,117 @@ +# Scripts + +There are a number of useful scripts included with the distribution. +Some of these scripts are only useful during build and development, but +other scripts are intended for end users to be able to use. These scripts +may be installed with n2n as part of your operating system package. + +All scripts can be found in the `scripts` directory. + +Short descriptions of these scripts are below. + +## End user scripts + +### `n2n-ctl` + +This python script provides an easy command line interface to the running +n2n processes. It uses UDP communications to talk to the Management API. +By specifying the right UDP port, it can talk to both the edge and the +supernode daemons. + +Example: +- `scripts/n2n-ctl --help` +- `scripts/n2n-ctl help` + +### `n2n-httpd` + +This python script is a simple http gateway to the running edge. It provides +a proxy for REST-like HTTP requests to talk to the Management API. + +By default it runs on port 8080. + +It also provides a simple HTML page showing some edge information, which when +run with default settings can be seen at http://localhost:8080/ (Also +a http://localhost:8080/supernode.html page for the supernode) + +Example: +- `scripts/n2n-httpd --help` +- `scripts/n2n-httpd 8087` + +## Build and Development scripts + +### `hack_fakeautoconf.sh` + +This shell script is used during development to help build on Windows +systems. An example of how to use it is shown in +the [Building document](Building.md) + +### `indent.sh` + +This shell script is a wrapper for the `uncrustify` C code style checker +which checks or applies a set of rules to the code. It is used during +the automated lint checks. + +### `n2n-gateway.sh` + +A sample script to route all the host traffic towards a remote gateway, +which is reachable via the n2n virtual interface. + +### `version.sh` + +This script is used to determine the current version number during the +build process. + +It looks at both the VERSION file and the GIT tags and outputs the +version number to use. + +## Monitoring and statistics + +### `munin/n2n_` + +This is a simple monitoring script that can be used with the munin-node +system to monitor the n2n daemons. + +This is a fully autoconfigurable wildcard munin plugin, but to get a quick +sample: + +get a list of suggested plugin names: +``` +munin/n2n_ suggest +``` + +Enable some of those names: + +``` +ln -s /usr/share/munin/plugins/n2n_ /etc/munin/plugins/n2n_supernode_pkts +ln -s /usr/share/munin/plugins/n2n_ /etc/munin/plugins/n2n_supernode_counts +``` + +Manually test fetching and config: + +``` +/etc/munin/plugins/n2n_supernode_pkts +/etc/munin/plugins/n2n_supernode_pkts config +``` + +## Testing scripts + +### `test_harness.sh` + +This shell script is used to run automated tests during development. It is +run with a testlist filename - pointing at a file containing the list of +tests to run. + +Each test needs a file containing the expected output `${TESTNAME}.expected` +which is expected to exist in the same directory as the testlist (this dir is +referred to as `${listdir}` below). + +Each test is a program, searched for in several locations, including the +`${listdir}/../scripts` dir. + +Each test is run with its output being sent to `*.out` files in the `listdir` +and compared with the expected output. + +### `scripts/test_integration_supernode.sh` + +This starts a supernode and runs an integration test on the Json API using +the `n2n-ctl` command. diff --git a/doc/TapConfiguration.md b/doc/TapConfiguration.md new file mode 100644 index 0000000..69c9491 --- /dev/null +++ b/doc/TapConfiguration.md @@ -0,0 +1,151 @@ +# TAP Device Configuration + +n2n provides its service through a TAP device which is the virtual ethernet device seen by the computer and user. As a prerequisite, it requires the appropriate TAP driver to be installed. Most Linux systems come with it. If not loaded, `sudo modprobe tap` will do. + +For MacOS and Windows there are specific instructions; please see the [Building](./Building.md) document. + +## Device Name + +If the OS specific driver allows **naming** the virtual Ethernet device created by n2n, the `-d ` command-line option can be used to give a name, e.g. `-d n2n0`. This device name makes the virtual ethernet device easily accessible to all `ip` command activity, `iptables`, `tcpdump` and any other of your preferred network tools. It defaults to `edge0` if not provided through `-d`. + +One exception applies to Windows: As the installed TAP driver(s) come with fixed names, `-d ` **selects** the appropriate device by name out of the present ones. This is only required if more than one TAP devices are present. To help with it, `edge --help` lists the available TAP adapters at the bottom of its output (Windows only). + +## MAC + +Even virtual ethernet devices have a MAC address. As in real networks, it should be unique as it is used to identify the different participants and transport packets accordingly. The MAC address can optionally be specified by using the `-m ` command line parameter, e.g. `-m 01:02:03:04:05:06`. If omitted, n2n tries to assign a random MAC address. + +## IP Address + +n2n supports several ways to assign an IPv4 address to the virtual ethernet device. Support for IPv6 addresses relies on OS support. + +### Manually Assigned IP Address + +The command line parameter `-a ` assigns a static IP address, e.g. `-a static:192.168.8.5` to the device. The optional `static` keyword (and the delimiting colon) can be omitted, so `-a 192.168.8.5` works as well. + +The netmask in CIDR notation can optionally be appended to the address, e.g. `-a 192.168.8.5/24` for netmask `255.255.255.0` which also is the default should the netmask not be provided. + +### Auto IP Address + +If `-a` is omitted, the supernode assigns an IP address to the node. This feature uses different IP address pools on a per-community basis. So, all edges of the same community will find themselves in the same sub-network. + +By default, `/24`-sized IP address sub-network pools from the upper half of the `10.0.0.0` class A network will be used, that is from `10.128.0.0/24` … `10.255.255.0/24`. The supernode can be configured to assign addresses from a different network range: `-a 10.0.0.0-10.255.0.0/16` would the supernode make use of the complete `10.0.0.0` class A range but handle `/16`-sized sub-networks. Also, named communities could be pre-assigned certain sub-networks, please see the explanatory comments in the `community.list` file. + +### DHCP + +If an edge of the community runs a DHCP server, the others could draw their IP addresses from there. It requires the new edges to start-up with the `-r -a dhcp:0.0.0.0` parameters (literally). More details can be found [at this discussion](https://github.com/ntop/n2n/issues/629). + +### IPv6 + +n2n supports the carriage of IPv6 packets within the n2n tunnel. n2n does not +yet use IPv6 for transport between edges and supernodes. + +To make IPv6 carriage work you need to manually add IPv6 addresses to the TAP +interfaces at each end. There is currently no way to specify an IPv6 address on +the edge command line. + +For example, under Linux + +on hostA: +`[hostA] $ /sbin/ip -6 addr add fc00:abcd:1234::7/48 dev n2n0` + +on hostB: +`[hostB] $ /sbin/ip -6 addr add fc00:abcd:1234::6/48 dev n2n0` + +You may find it useful to make use of `tunctl` from the uml-utilities +package. `tunctl` allows you to bring up a TAP interface and configure addressing +prior to starting the edge. It also allows the edge to be restarted without the +interface closing (which would normally affect routing tables). + +Once the IPv6 addresses are configured and edge is started, IPv6 neighbor discovery +packets flow (get broadcast) and IPv6 entities self-arrange. Test your IPv6 +setup with `ping6` - the IPv6 ping command. + +## MTU + +The MTU of the VPN interface is set to a lower value (rather than the standard +value of 1500 bytes) to avoid excessive fragmentation of the datagram sent over the internet. +This is required because n2n adds additional headers to the packets received from +the VPN interface. The size of the final frame sent through the internet interface +must have a size lower or equal to the internet interface MTU (usually 1500 bytes). + +As a fragmentation example, suppose that a 3000 byte TCP segment should be sent through +the VPN. If the VPN interface MTU is set to 1500, the packet will be split into two +fragments of 1500 bytes each. However, n2n will add its headers to each fragment, so +each fragment becomes a 1540 byte packet. The internet interface MTU of 1500 bytes +will fragment each packet again in two further fragments, e.g. 1500 + 50 bytes, so a +total of 4 fragments will be sent over the internet. On the other hand, if the VPN interface +MTU was set to 1460 bytes, it would result in only 3 fragments sent as the initial segment of +3000 bytes would be split in 1460 + 1460 + 80 bytes without further fragmentation. + +IP packet fragmentation in general is something to avoid, as described in +http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-87-3.pdf. If possible, +the fragmentation should be moved to the TCP layer by a proper MSS value. +This can be forced by mangling the packet MSS, which is called "MSS clamping" (currently not +implemented in n2n). See https://github.com/gsliepen/tinc/blob/228a03aaa707a5fcced9dd5148a4bdb7e5ef025b/src/route.c#L386. + +The exact value to use as a clamp value, however, depends on the PMTU, which is the minimum +MTU of the path between two hosts. Knowing the PMTU is also useful for a sender in order to +avoid fragmentation at IP level. Trying to find the highest non-fragmenting MTU possible is useful since it allows to +maximize bandwidth. + +### PMTU Discovery Failures + +Most operating systems try to periodically discover the PMTU by using a PMTU discovery algorithm. +This involves setting the DF (don't fragment) flag on the IP packets. When a large IP packet exceeds +the MTU of a router in the path, an "ICMP Fragmentation Needed" message should be received, which will +help the OS along to tune the size of the next IP packets. However, some routers do not report such ICMP message, +which results in packets being silently dropped. The `tracepath` tool can be used to detect the PMTU. + +The main problem with this situation is that the actual PMTU is unknown, so an automatic +solution is not applicable. The user must manually specify a lower MTU for the VPN interface +in order to solve the issue. + +### n2n and MTU + +n2n shall work by default in different environments. For this reason, the following solution +has been provided: + +- PMTU discovery is disabled if possible (via the IP_MTU_DISCOVER socket option). This avoids + silently dropping an oversized packet due to the DF flag; however, it possibly increments fragmentation on the path. +- As explained above, a lower MTU is set on the VPN interface, thus removing excessive fragmentation on + the sender. +- A value of 1290 bytes is used instead of 1500 bytes as reference value for the internet interface MTU. + This essentially avoids fragmentation if the PMTU is greater or equal than 1400 bytes. + +This is a conservative solution which should make n2n work by default. The user can manually +specify the MTU (`-M `) and re-enable PMTU discovery (`-D`) via the command-line interface options. + +## Interface Metric and Broadcasts + +On Windows, broadcasts are sent out to the network interface with the lowest metric only. This usually is the +WAN interface with its default metric of `25`. The `-x ` option could be used to configure the TAP with a +lower interface metric and hence facilitate service and online game server detection over n2n. + +Linux and others do not require this feature as broadcasts are sent to all network interfaces by default, also to the +virtual ones. + +## Multicast + +n2n does not transmit multicast packets by default. It can be enabled by edge's `-E` command-line parameter. + +## Egde Description + +To keep edge's and supernode's management port output well arranged and understandable, each edge can have a plain text description +fed to the edge by the optional `-I ` command-line parameter. If not provided, n2n uses the +hostname by default. + +A description field's hash value is used to choose an auto IP address. So, just be aware that changing the hostname +can lead to assigning a different auto IP address on next edge start-up – if auto IP address is used. + +## Routing + +n2n supports routing the traffic through its network. `-r` enables an edge to accept packets at its TAP interface not originating from the local IP address or not destined to the local IP address. As there is more to routing than just this one command-line option, please refer to the dedicated [Routing](Routing.md) document +explaining it all in detail. + +## Traffic Filter + +Setting up the integrated traffic filter permits to define exactly the kind of allowed traffic or deny +other on edge's TAP interface. It helps to keep unwanted traffic out of the n2n network for +bandwidth and security reasons. The traffic filter is disabled by default and gets activated by providing +as many `-R `-rules as required through edge's command-line. Specifics are written down in the +[Traffic Restrictions](TrafficRestricitons.md) documentation. diff --git a/doc/TrafficRestrictions.md b/doc/TrafficRestrictions.md new file mode 100644 index 0000000..8d6441a --- /dev/null +++ b/doc/TrafficRestrictions.md @@ -0,0 +1,41 @@ +# Traffic Restrictions + +It is possible to drop or accept specific packet transmit over edge network interface by rules. Rules can be specify by (`-R rule_str`) multiple times. + +## Rule String Format + +rule_str format: `src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/-` + +`ip/len` indicate a cidr block, len can be ignore, means single ip (not cidr block) will be use in filter rule. + +`+`,`-` after `TCP`,`UDP`,`ICMP` proto type indicate allow or drop packet of that proto. if any of above three proto missed, the rule will not take effect for that proto. + +Ports range `[s_port,e_port]` can be instead by single port number. If not specify, `[0,65535]` will be used. Ports range include start_port and end_port. + +examples: +`192.168.1.5/32:[0,65535],192.168.0.0/24:[8081,65535],TCP-,UDP-,ICMP+` +`192.168.1.5:[0,65535],192.168.0.0/24:8000,ICMP+` +`192.168.1.5,192.168.0.7,TCP-,UDP-,ICMP-` // packets by all proto of all ports from 192.158.1.5 to any ports of 192.168.0.7 will be dropped. + +## Multiple Rules + +`-R rule_str` can be used multiple times to add multiple rules. Each `-R rule_str` add one rule. for example: + +`edge -c xxxx -k xxxx -a 192.168.100.5 -l xxx.xxx.xxx.xxx:1234 -r -R 192.168.1.5/32:[0,65535],192.168.0.0/24:[8081,65535],TCP-,UDP-,ICMP+ -R 192.168.1.5:[0,65535],192.168.0.0/24:8000,ICMP+ -R 192.168.1.5,192.168.0.7,TCP-` + +## Matching Rules Priority + +If multiple rules matching packet's ips and ports, the rule with smaller cidr block(smaller address space) will be selected. That means rules with larger `len` value has higher priority. + +Actually, current implementation will add the `len` of src cidr and dst cidr of each matched rules as priority value, the rule with largest priority value will take effect. + +## Blocklist/Allowlist mode + +Packets that cannot match any rule will be accepted by default. Users can add rules to block traffics. + +This behavior can be change by add the rule : `0.0.0.0/0:[0,65535],0.0.0.0/0:[0,65535],TCP-,UDP-,ICMP-`. Then all traffic will be dropped, users need add rules to allow traffics. + +for example, `-R 0.0.0.0/0,0.0.0.0/0,TCP-,UDP-,ICMP- -R 192.168.100.0/24,192.168.100.0/24,ICMP+` dropped all traffic, except ICMP traffics inside `192.168.100.0/24`. + +More complex behavior can be set with the feature of `Matching Rules Priority`. + diff --git a/edge.8 b/edge.8 index 37d6861..75861f6 100644 --- a/edge.8 +++ b/edge.8 @@ -1,100 +1,244 @@ -.TH edge 1 "Jan 3, 2009" "revision 3679" "SUPERUSER COMMANDS" +.TH edge 8 "18 Jul 2021" "version 3" "SUPERUSER COMMANDS" .SH NAME edge \- n2n edge node daemon .SH SYNOPSIS .B edge -[\-d ] \-a \-c \-k \-l -[\-p ] [\-u ] [\-g ] [-f] [\-m ] [\-t] [\-r] [\-v] + +.br +.B edge +\-c \-l [further options]... .SH DESCRIPTION N2N is a peer-to-peer VPN system. Edge is the edge node daemon for n2n which creates a TAP interface to expose the n2n virtual LAN. On startup n2n creates the TAP interface and configures it then registers with the supernode so it can begin to find other nodes in the community. .PP -.SH OPTIONS +The config file is similar to the command line, with one option per line. +Lines starting with a "#" are ignored. +An equal sign ('=') should be used between key and value. Example: -p=7777 +.SH OPTIONS FOR THE UNDERLYING NETWORK CONNECTION .TP -\-d -sets the TAP device name as seen in ifconfig. +\fB\-c \fR<\fIcommunity\fR>, \fB\-\-community\fR=<\fIcommunity\fR> +sets the n2n community name (see also N2N_COMMUNITY in ENVIRONMENT). All edges +within the same community appear on the same LAN (layer 2 network segment). +Community name is 16 bytes in length. A name smaller than this is padded with +0x00 bytes and a name longer than this is truncated to take the first 16 bytes. .TP -\-a -sets the n2n virtual LAN IP address being claimed. This is a private IP -address. All IP addresses in an n2n community should belong to the same /24 -network (ie. only the last segment of the IP addresses varies). +\fB\-l \fR<\fIhost:port\fR>, \fB\-\-supernode-list\fR=<\fIhost:port\fR> +sets the n2n supernode IP address and port to register to. Multiple supernodes +can be specified. .TP -\-b -cause edge to perform hostname resolution for the supernode address each time -the supernode is periodically contacted. -.TP -\-c -sets the n2n community name. All edges within the same community look to be on -the same LAN (layer 2 network segment). All edges communicating must use the -same key and community name. -.TP -\-h -write usage to tty then exit. -.TP -\-k -sets the twofish encryption key from ASCII text (see also N2N_KEY in -ENVIRONMENT). All edges communicating must use the same key and community name. -.TP -\-l : -sets the n2n supernode IP address and port to register to. -.TP -\-p +\fB\-p \fR[<\fIlocal_ip_address\fR>:]<\fIlocal_port\fR> binds edge to the given UDP port. Useful for keeping the same external socket -across restarts of edge. +across restarts of edge. This allows peer edges which know the edge socket to +continue p2p operation without going back to the supernode. Also, home router's +port forwarding feature can refer to that fixed port. +Optionally, the edge can bind to the provided local ip address only. This is +useful in case restriction to a certain LAN or WiFi interface is desired. +By default, the edge binds to any interface. .TP -\-u -causes the edge process to drop to the given user ID when privileges are no -longer required. +\fB\-T \fR<\fItos\fR> +TOS for packets, e.g. 0x48 for SSH like priority .TP -\-g -causes the edge process to drop to the given group ID when privileges are no -longer required. +\fB\-D\fR +enable PMTU discovery, it can reduce fragmentation but +causes connections to stall if not properly supported .TP -\-f -causes the edge process to fork and run as a daemon, closing stdin, stdout, -stderr and becoming a process group leader. +\fB\-e \fR<\fIlocal_ip_address\fR> +advertises the provided local IP address as preferred, +useful if multicast peer detection is not available, e.g. +disabled on routers. \fB\-e auto\fR tries auto-detection of +local IP address. .TP -\-m +\fB\-S1\fR ... \fB\-S2\fR +do not connect p2p, always use the supernode, +\-S1 = via UDP, \-S2 = via TCP +.TP +\fB\-i \fR<\fIreg_interval\fR> +Supernode registration interval. It specifies the interval in seconds +between consecutive REGISTER_SUPER packets and it's used to keep NAT hole +open via the UDP NAT hole punching technique. This only works for asymmetric +NATs and allows for P2P communication. +.TP +\fB\-L \fR<\fIreg_ttl\fR> +set the TTL for the hole punching packet. This is an advanced flag to make +sure that the registration packet is dropped immediately when it goes out of +local nat so that it will not trigger some firewall behavior on target peer. +Actually, the registration packet is only expected to make local nat UDP hole +and is not expected to reach the target peer, see +https://tools.ietf.org/html/rfc5389. To achieve this, the flag should be set as +nat level + 1. For example, if we have 2 layer nat in local, we should set -L 3. +Usually we know exactly how much nat layers in local. +If we are not sure how much nat layers in local, we can use traceroute on +Linux to check. The following example shows a local single layer nat because on +second jump it shows a public ip address. In this case it should set -L 2. + +$ /usr/sbin/traceroute -w1 8.8.8.8 +.br +traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets + 1 192.168.3.1 (192.168.3.1) 0.464 ms 0.587 ms 0.719 ms + 2 112.65.17.217 (112.65.17.217) 5.269 ms 7.031 ms 8.666 ms + +But this method does not always work due to various local network device policy. +.TP +\fB\-k \fR<\fIkey\fR> +encryption key (ASCII) - also N2N_KEY= +\-k +sets the encryption key from ASCII text (see also N2N_KEY in +ENVIRONMENT). All edges communicating must use the same key and community +name. If -k not specified then edge uses cleartext mode (no encryption). +.TP +\fB\-A1\fR +disable payload encryption, do not use with key, defaults to AES then +.TP +\fB\-A2\fR ... \fB\-A5\fR +choose a cipher for payload encryption, requires a key, +\-A2 = Twofish, \-A3 = AES (default if key provided), +\-A4 = ChaCha20, \-A5 = Speck-CTR +.TP +\fB\-H\fR +use header encryption, supernode needs fixed community +.TP +\fB\-z1\fR ... \fB\-z2\fR +compress outgoing data packets, -z1 = lzo1x, disabled by default +.TP +\fB\-\-select-rtt\fR +select supernode by round trip time if several to choose from (federation), +defaults to load-based selection strategy if not provided. +.TP +\fB\-\-select-mac\fR +select supernode by MAC address if several to choose from (federation), +lowest MAC address first. +.TP +\fB\-\-no-port-forwarding\fR +disables the default behavior of trying to have the edge's port forwarded +through a router eventually supporting it (only if compiled with miniupnp +and/or natpmp library support). +.SH TAP DEVICE AND OVERLAY NETWORK CONFIGURATION +.TP +\fB\-a \fR[\fImode\fR]<\fIip\fR>[\fI/n\fR] +interface address and optional CIDR subnet, default '/24', +mode = [static|dhcp]:, for DHCP use '\-r -a dhcp:0.0.0.0', +edge draws IP address from supernode if no '\-a ...' given +.TP +\fB\-m \fR<\fImac\fR> start the TAP interface with the given MAC address. This is highly recommended as it means the same address will be used if edge stops and restarts. If this is not done, the ARP caches of all peers will be wrong and packets will not flow to this edge until the next ARP refresh. +e.g. '\-m 10:20:30:40:50:60', by default a random MAC address is used. .TP -\-M -set the MTU of the edge interface in bytes. MTU is the largest packet fragment -size allowed to be moved throught the interface. The default is 1400. +\fB\-d \fR<\fIdevice\fR>, \fB\-\-device\fR=<\fIdevice\fR> +TAP device name .TP -\-s -set the netmask of edge interface in IPv4 dotted decimal notation. The default -is 255.255.255.0 (ie. /24). +\fB\-M \fR<\fImtu\fR> +specify n2n MTU of TAP interface, default 1290 .TP -\-t -use HTTP tunneling instead of the normal UDP mechanism (experimental). +\fB\-r\fR +enable IP packet forwarding/routing through the n2n virtual LAN. Without this +option, IP packets arriving over n2n are dropped if not for the -a (or +DHCP assigned) IP address of the edge interface. .TP -\-r -enable packet forwarding/routing through the n2n virtual LAN. Without this -option, packets arriving over n2n which are not for the -a IP address are -dropped. +\fB\-E\fR +accept packets destined for multicast ethernet MAC addresses. These addresses +are used in multicast ethernet and IPv6 neighbour discovery. If this option is +not present these multicast packets are discarded as most users do not need or +understand them. .TP -\-v -use verbose logging. +\fB\-I \fR<\fIdescription\fR> +annotate the edge's description used for easier +identification in management port output or username +.TP +\fB\-J \fR<\fIpassword\fR> +password for user-password edge authentication (see also N2N_PASSWORD in ENVIRONMENT) +.TP +\fB\-P \fR<\fIpublic key\fR> +federation public key for user-password authentication +.TP +\fB\-R \fR<\fIrule_str\fR> +Add rule to drop or accept specific packet transmit over edge network interface. +-R rule_str can be used multiple times to add multiple rules. Each -R rule_str add +one rule. + +rule_str format:"src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/-". + +ip/len indicate a cidr block, len can be ignore, means single ip(not cidr block) +will be use in filter rule. + ++,- after TCP,UDP,ICMP proto type indicate allow or drop packet of that proto. +if any of above three proto missed, the rule will not take effect for that proto. + +Ports range [s_port,e_port] can be instead by single port number. If not specify, [0,65535] +will be used. Ports range include start_port and end_port. If multiple rules matching packet's +ips and ports, the rule with smaller cidr block(smaller address space) will be selected. That +means rules with larger len value has higher priority. + +Packets that cannot match any rule will be accepted by default. Users can add rules to +block traffics. This behavior can be change by add the rule : `0.0.0.0/0:[0,65535],0.0.0.0/0: +[0,65535],TCP-,UDP-,ICMP-`. Then all traffic will be dropped, users need add rules to allow +traffics. + +for example : `-R 0.0.0.0/0,0.0.0.0/0,TCP-,UDP-,ICMP- -R 192.168.100.0/24,192.168.100.0/24,ICMP+`, +.TP +\fB\-x \fR<\fImetric\fR> +set TAP interface metric, defaults to 0 (auto), +e.g. set to 1 for better multiplayer game detection. +.br +(Windows only) +.SH LOCAL OPTIONS +.TP +\fB\-f\fR +do not fork and run as a daemon, rather run in foreground +.TP +\fB\-t \fR<\fIport\fR> +binds the edge management system to the given UDP port. Default 5644. Use this +if you need to run multiple instance of edge; or something is bound to that +port. +.TP +\fB\-\-management-password \fR<\fIpassword\fR> +sets the password for access to JSON API at the management port, defaults to 'n2n'. The password +has to be provided when using 'scripts/n2n-ctl', 'scripts/n2n-httpd' or for any other relevant +access to JSON API at the management port. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +make more verbose, repeat as required +.TP +\fB\-n \fR<\fIcidr:gateway\fR> +route an IPv4 network via the gateway, use 0.0.0.0/0 for +the default gateway, can be set multiple times +.TP +\fB\-u \fR<\fIUID\fR>, \fB\-\-euid\fR=<\fIUID\fR> +numeric user ID to use when privileges are dropped +.TP +\fB\-g \fR<\fIGID\fR>, \fB\-\-egid\fR=<\fIGID\fR> +numeric group ID to use when privileges are dropped +.TP +\fb\-h\fr +write usage then exit. +.TP +\fb\--help\fr +shows detailed parameter description .SH ENVIRONMENT .TP .B N2N_KEY -set the encryption key so it is not visible on the command line +set the encryption key so it is not visible at the command line +.TP +.B N2N_COMMUNITY +set the community name so it is not visible at the command line +.TP +.B N2N_PASSWORD +set the password for user-password authentication so it is not visible at the command line .SH EXAMPLES .TP .B edge \-d n2n0 \-c mynetwork \-k encryptme \-u 99 \-g 99 \-m DE:AD:BE:EF:01:23 \-a 192.168.254.7 \-p 50001 \-l 123.121.120.119:7654 Start edge with TAP device n2n0 on community "mynetwork" with community supernode at 123.121.120.119 UDP port 7654 and bind the locally used UDP port to -50001. Use "encryptme" as the shared encryption key. Assign MAC address -DE:AD:BE:EF:01:23 to the n2n interface and drop to user=99 and group=99 after -the TAP device is successfull configured. +50001. Use "encryptme" as the single permanent shared encryption key. Assign MAC +address DE:AD:BE:EF:01:23 to the n2n interface and drop to user=99 and group=99 +after the TAP device is successfully configured. .PP -Add the -f option to make edge run as a daemon. +Add the -f option to stop edge running as a daemon. .PP Somewhere else setup another edge with similar parameters, eg. @@ -102,15 +246,45 @@ Somewhere else setup another edge with similar parameters, eg. .PP Now you can ping from 192.168.254.5 to 192.168.254.7. .PP -The MAC address (-m ) and virtual IP address (-a ) must be different on all edges in the same community. +The MAC address (-m ) and virtual IP address (-a ) must be different +on all edges in the same community. + +.SH CLEARTEXT MODE +If +.B -k +is not specified then edge uses cleartext mode. In cleartext mode there is no +transform of the packet data it is simply encrypted. This is useful for +debugging n2n as packet contents can be seen clearly. + +To prevent accidental exposure of data, edge only enters cleartext mode when no +keying parameters are specified. In the case where keying parameters are +specified but no valid keys can be determined, edge exits with an error at +startup. If all keys become invalid while running, edge continues to encode +using the last key that was valid. + +.SH MANAGEMENT INTERFACE +Edge provides a very simple management system on UDP port 5644. Send a newline +to receive a status output. Send 'stop' to cause edge to exit cleanly. + +.TP +.B echo | nc -w1 -u 127.0.0.1 5644 +Shows the current statistics of a running edge. -.SH CONFIGURATION -All configuration for edge is from the command line and environment -variables. If you wish to reconfigure edge you should kill the process and -restart with the desired options. .SH EXIT STATUS edge is a daemon and any exit is an error. -.SH AUTHOR -Luca Deri ( deri (at) ntop.org ), Richard Andrews ( andrews (at) ntop.org ), Don Bindner +.SH AUTHORS +.TP +Richard Andrews +andrews (at) ntop.org - n2n-1 maintainer and main author of n2n-2 +.TP +Luca Deri +deri (at) ntop.org - original author of n2n +.TP +Don Bindner +(--) - significant contributions to n2n-1 .SH SEE ALSO -ifconfig(8) supernode(1) tunctl(8) +ifconfig(8) supernode(1) tunctl(8) n2n(7) +.br +the documentation contained in the source code +.br +the extensive documentation found in n2n's \fBdoc/\fR folder diff --git a/edge.c b/edge.c deleted file mode 100644 index 5f69c5a..0000000 --- a/edge.c +++ /dev/null @@ -1,1449 +0,0 @@ -/* - * (C) 2007-09 - Luca Deri - * Richard Andrews - * - * 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 see - * - * Code contributions courtesy of: - * Don Bindner - * Sylwester Sosnowski - * Wilfried "Wonka" Klaebe - * - */ - -#include "minilzo.h" -#include "n2n.h" -#include -#include - -/** Time between logging system STATUS messages */ -#define STATUS_UPDATE_INTERVAL (30 * 60) /*secs*/ - -/* maximum length of command line arguments */ -#define MAX_CMDLINE_BUFFER_LENGTH 4096 -/* maximum length of a line in the configuration file */ -#define MAX_CONFFILE_LINE_LENGTH 1024 - -struct n2n_edge -{ - u_char re_resolve_supernode_ip; - struct peer_addr supernode; - char supernode_ip[48]; - char * community_name /*= NULL*/; - - /* int sock; */ - /* char is_udp_socket /\*= 1*\/; */ - n2n_sock_info_t sinfo; - - u_int pkt_sent /*= 0*/; - tuntap_dev device; - int allow_routing /*= 0*/; - int drop_ipv6_ndp /*= 0*/; - char * encrypt_key /* = NULL*/; - TWOFISH * enc_tf; - TWOFISH * dec_tf; - - struct peer_info * known_peers /* = NULL*/; - struct peer_info * pending_peers /* = NULL*/; - time_t last_register /* = 0*/; -}; - -static void supernode2addr(n2n_edge_t * eee, char* addr); - -static void send_packet2net(n2n_edge_t * eee, - char *decrypted_msg, size_t len); - - -/* ************************************** */ - -/* parse the configuration file */ -static int readConfFile(const char * filename, char * const linebuffer) { - struct stat stats; - FILE * fd; - char * buffer = NULL; - - buffer = (char *)malloc(MAX_CONFFILE_LINE_LENGTH); - if (!buffer) { - traceEvent( TRACE_ERROR, "Unable to allocate memory"); - return -1; - } - - if (stat(filename, &stats)) { - if (errno == ENOENT) - traceEvent(TRACE_ERROR, "parameter file %s not found/unable to access\n", filename); - else - traceEvent(TRACE_ERROR, "cannot stat file %s, errno=%d\n",filename, errno); - free(buffer); - return -1; - } - - fd = fopen(filename, "rb"); - if (!fd) { - traceEvent(TRACE_ERROR, "Unable to open parameter file '%s' (%d)...\n",filename,errno); - free(buffer); - return -1; - } - while(fgets(buffer, MAX_CONFFILE_LINE_LENGTH,fd)) { - char * p = NULL; - - /* strip out comments */ - p = strchr(buffer, '#'); - if (p) *p ='\0'; - - /* remove \n */ - p = strchr(buffer, '\n'); - if (p) *p ='\0'; - - /* strip out heading spaces */ - p = buffer; - while(*p == ' ' && *p != '\0') ++p; - if (p != buffer) strncpy(buffer,p,strlen(p)+1); - - /* strip out trailing spaces */ - while(strlen(buffer) && buffer[strlen(buffer)-1]==' ') - buffer[strlen(buffer)-1]= '\0'; - - /* check for nested @file option */ - if (strchr(buffer, '@')) { - traceEvent(TRACE_ERROR, "@file in file nesting is not supported\n"); - free(buffer); - return -1; - } - if ((strlen(linebuffer)+strlen(buffer)+2)< MAX_CMDLINE_BUFFER_LENGTH) { - strncat(linebuffer, " ", 1); - strncat(linebuffer, buffer, strlen(buffer)); - } else { - traceEvent(TRACE_ERROR, "too many argument"); - free(buffer); - return -1; - } - } - - free(buffer); - fclose(fd); - - return 0; -} - -/* Create the argv vector */ -static char ** buildargv(char * const linebuffer) { - const int INITIAL_MAXARGC = 16; /* Number of args + NULL in initial argv */ - int maxargc; - int argc=0; - char ** argv; - char * buffer, * buff; - - buffer = (char *)calloc(1, strlen(linebuffer)+2); - if (!buffer) { - traceEvent( TRACE_ERROR, "Unable to allocate memory"); - return NULL; - } - strncpy(buffer, linebuffer,strlen(linebuffer)); - - maxargc = INITIAL_MAXARGC; - argv = (char **)malloc(maxargc * sizeof(char*)); - if (argv == NULL) { - traceEvent( TRACE_ERROR, "Unable to allocate memory"); - return NULL; - } - buff = buffer; - while(buff) { - char * p = strchr(buff,' '); - if (p) { - *p='\0'; - argv[argc++] = strdup(buff); - while(*++p == ' ' && *p != '\0'); - buff=p; - if (argc >= maxargc) { - maxargc *= 2; - argv = (char **)realloc(argv, maxargc * sizeof(char*)); - if (argv == NULL) { - traceEvent(TRACE_ERROR, "Unable to re-allocate memory"); - free(buffer); - return NULL; - } - } - } else { - argv[argc++] = strdup(buff); - break; - } - } - argv[argc] = NULL; - free(buffer); - return argv; -} - - - -/* ************************************** */ - -static int edge_init(n2n_edge_t * eee) { -#ifdef WIN32 - initWin32(); -#endif - memset(eee, 0, sizeof(n2n_edge_t)); - - eee->re_resolve_supernode_ip = 0; - eee->community_name = NULL; - eee->sinfo.sock = -1; - eee->sinfo.is_udp_socket = 1; - eee->pkt_sent = 0; - eee->allow_routing = 0; - eee->drop_ipv6_ndp = 0; - eee->encrypt_key = NULL; - eee->enc_tf = NULL; - eee->dec_tf = NULL; - eee->known_peers = NULL; - eee->pending_peers = NULL; - eee->last_register = 0; - - if(lzo_init() != LZO_E_OK) { - traceEvent(TRACE_ERROR, "LZO compression error"); - return(-1); - } - - return(0); -} - -static int edge_init_twofish( n2n_edge_t * eee, u_int8_t *encrypt_pwd, u_int32_t encrypt_pwd_len ) -{ - eee->enc_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len); - eee->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len); - - if ( (eee->enc_tf) && (eee->dec_tf) ) - { - return 0; - } - else - { - return 1; - } -} - -/* ************************************** */ - -static void edge_deinit(n2n_edge_t * eee) { - TwoFishDestroy(eee->enc_tf); - TwoFishDestroy(eee->dec_tf); - if ( eee->sinfo.sock >=0 ) - { - close( eee->sinfo.sock ); - } -} - -static void readFromIPSocket( n2n_edge_t * eee ); - -static void help() { - print_n2n_version(); - - printf("edge " -#ifdef __linux__ - "-d " -#endif - "-a " - "-c " - "-k " - "-s " -#ifndef WIN32 - "[-u -g ]" - "[-f]" -#endif - "[-m ]" - "\n" - "-l " - "[-p ] [-M ] " - "[-t] [-r] [-v] [-b] [-h]\n\n"); - -#ifdef __linux__ - printf("-d | tun device name\n"); -#endif - - printf("-a | n2n IP address\n"); - printf("-c | n2n community name\n"); - printf("-k | Encryption key (ASCII) - also N2N_KEY=\n"); - printf("-s | Edge interface netmask in dotted decimal notation (255.255.255.0)\n"); - printf("-l | Supernode IP:port\n"); - printf("-b | Periodically resolve supernode IP\n"); - printf(" | (when supernodes are running on dynamic IPs)\n"); - printf("-p | Local port used for connecting to supernode\n"); -#ifndef WIN32 - printf("-u | User ID (numeric) to use when privileges are dropped\n"); - printf("-g | Group ID (numeric) to use when privileges are dropped\n"); - printf("-f | Fork and run as a daemon. Use syslog.\n"); -#endif - printf("-m | Choose a MAC address for the TAP interface\n" - " | eg. -m 01:02:03:04:05:06\n"); - printf("-M | Specify n2n MTU (default %d)\n", DEFAULT_MTU); - printf("-t | Use http tunneling (experimental)\n"); - printf("-r | Enable packet forwarding through n2n community\n"); - printf("-v | Verbose\n"); - - printf("\nEnvironment variables:\n"); - printf(" N2N_KEY | Encryption key (ASCII)\n" ); - - exit(0); -} - -/* *********************************************** */ - -static void send_register( n2n_edge_t * eee, - const struct peer_addr *remote_peer, - u_char is_ack) { - struct n2n_packet_header hdr; - char pkt[N2N_PKT_HDR_SIZE]; - size_t len = sizeof(hdr); - ipstr_t ip_buf; - - fill_standard_header_fields( &(eee->sinfo), &hdr, (char*)(eee->device.mac_addr)); - hdr.sent_by_supernode = 0; - hdr.msg_type = (is_ack == 0) ? MSG_TYPE_REGISTER : MSG_TYPE_REGISTER_ACK; - memcpy(hdr.community_name, eee->community_name, COMMUNITY_LEN); - - marshall_n2n_packet_header( (u_int8_t *)pkt, &hdr ); - send_packet( &(eee->sinfo), pkt, &len, remote_peer, N2N_COMPRESSION_ENABLED ); - - traceEvent(TRACE_INFO, "Sent %s message to %s:%hd", - ((hdr.msg_type==MSG_TYPE_REGISTER)?"MSG_TYPE_REGISTER":"MSG_TYPE_REGISTER_ACK"), - intoa(ntohl(remote_peer->addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(remote_peer->port)); -} - -/* *********************************************** */ - -static void send_deregister(n2n_edge_t * eee, - struct peer_addr *remote_peer) { - struct n2n_packet_header hdr; - char pkt[N2N_PKT_HDR_SIZE]; - size_t len = sizeof(hdr); - - fill_standard_header_fields( &(eee->sinfo), &hdr, (char*)(eee->device.mac_addr) ); - hdr.sent_by_supernode = 0; - hdr.msg_type = MSG_TYPE_DEREGISTER; - memcpy(hdr.community_name, eee->community_name, COMMUNITY_LEN); - - marshall_n2n_packet_header( (u_int8_t *)pkt, &hdr ); - send_packet( &(eee->sinfo), pkt, &len, remote_peer, N2N_COMPRESSION_ENABLED); -} - -/* *********************************************** */ - -static void update_peer_address(n2n_edge_t * eee, - const struct n2n_packet_header * hdr, - time_t when); -void trace_registrations( struct peer_info * scan ); -int is_ip6_discovery( const void * buf, size_t bufsize ); -void check_peer( n2n_edge_t * eee, - const struct n2n_packet_header * hdr ); -void try_send_register( n2n_edge_t * eee, - const struct n2n_packet_header * hdr ); -void set_peer_operational( n2n_edge_t * eee, const struct n2n_packet_header * hdr ); - - - -/** Start the registration process. - * - * If the peer is already in pending_peers, ignore the request. - * If not in pending_peers, add it and send a REGISTER. - * - * If hdr is for a direct peer-to-peer packet, try to register back to sender - * even if the MAC is in pending_peers. This is because an incident direct - * packet indicates that peer-to-peer exchange should work so more aggressive - * registration can be permitted (once per incoming packet) as this should only - * last for a small number of packets.. - * - * Called from the main loop when Rx a packet for our device mac. - */ -void try_send_register( n2n_edge_t * eee, - const struct n2n_packet_header * hdr ) -{ - ipstr_t ip_buf; - - /* REVISIT: purge of pending_peers not yet done. */ - struct peer_info * scan = find_peer_by_mac( eee->pending_peers, hdr->src_mac ); - - if ( NULL == scan ) - { - scan = calloc( 1, sizeof( struct peer_info ) ); - - memcpy(scan->mac_addr, hdr->src_mac, 6); - scan->public_ip = hdr->public_ip; - scan->last_seen = time(NULL); /* Don't change this it marks the pending peer for removal. */ - - peer_list_add( &(eee->pending_peers), scan ); - - traceEvent( TRACE_NORMAL, "Pending peers list size=%ld", - peer_list_size( eee->pending_peers ) ); - - traceEvent( TRACE_NORMAL, "Sending REGISTER request to %s:%hd", - intoa(ntohl(scan->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(scan->public_ip.port)); - - send_register(eee, - &(scan->public_ip), - 0 /* is not ACK */ ); - - /* pending_peers now owns scan. */ - } - else - { - /* scan already in pending_peers. */ - - if ( 0 == hdr->sent_by_supernode ) - { - /* over-write supernode-based socket with direct socket. */ - scan->public_ip = hdr->public_ip; - - traceEvent( TRACE_NORMAL, "Sending additional REGISTER request to %s:%hd", - intoa(ntohl(scan->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(scan->public_ip.port)); - - - send_register(eee, - &(scan->public_ip), - 0 /* is not ACK */ ); - } - } -} - - -/** Update the last_seen time for this peer, or get registered. */ -void check_peer( n2n_edge_t * eee, - const struct n2n_packet_header * hdr ) -{ - struct peer_info * scan = find_peer_by_mac( eee->known_peers, hdr->src_mac ); - - if ( NULL == scan ) - { - /* Not in known_peers - start the REGISTER process. */ - try_send_register( eee, hdr ); - } - else - { - /* Already in known_peers. */ - update_peer_address( eee, hdr, time(NULL) ); - } -} - - -/* Move the peer from the pending_peers list to the known_peers lists. - * - * peer must be a pointer to an element of the pending_peers list. - * - * Called by main loop when Rx a REGISTER_ACK. - */ -void set_peer_operational( n2n_edge_t * eee, const struct n2n_packet_header * hdr ) -{ - struct peer_info * prev = NULL; - struct peer_info * scan; - macstr_t mac_buf; - ipstr_t ip_buf; - - scan=eee->pending_peers; - - while ( NULL != scan ) - { - if ( 0 != memcmp( scan->mac_addr, hdr->dst_mac, 6 ) ) - { - break; /* found. */ - } - - prev = scan; - scan = scan->next; - } - - if ( scan ) - { - - /* Remove scan from pending_peers. */ - if ( prev ) - { - prev->next = scan->next; - } - else - { - eee->pending_peers = scan->next; - } - - /* Add scan to known_peers. */ - scan->next = eee->known_peers; - eee->known_peers = scan; - - scan->public_ip = hdr->public_ip; - - traceEvent(TRACE_INFO, "=== new peer [mac=%s][socket=%s:%hd]", - macaddr_str(scan->mac_addr, mac_buf, sizeof(mac_buf)), - intoa(ntohl(scan->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(scan->public_ip.port)); - - traceEvent( TRACE_NORMAL, "Pending peers list size=%ld", - peer_list_size( eee->pending_peers ) ); - - traceEvent( TRACE_NORMAL, "Operational peers list size=%ld", - peer_list_size( eee->known_peers ) ); - - - scan->last_seen = time(NULL); - } - else - { - traceEvent( TRACE_WARNING, "Failed to find sender in pending_peers." ); - } -} - - -void trace_registrations( struct peer_info * scan ) -{ - macstr_t mac_buf; - ipstr_t ip_buf; - - while ( scan ) - { - traceEvent(TRACE_INFO, "=== peer [mac=%s][socket=%s:%hd]", - macaddr_str(scan->mac_addr, mac_buf, sizeof(mac_buf)), - intoa(ntohl(scan->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(scan->public_ip.port)); - - scan = scan->next; - } - -} - -u_int8_t broadcast_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - -/** Keep the known_peers list straight. - * - * Ignore broadcast L2 packets, and packets with invalid public_ip. - * If the dst_mac is in known_peers make sure the entry is correct: - * - if the public_ip socket has changed, erase the entry - * - if the same, update its last_seen = when - */ -static void update_peer_address(n2n_edge_t * eee, - const struct n2n_packet_header * hdr, - time_t when) -{ - ipstr_t ip_buf; - struct peer_info *scan = eee->known_peers; - struct peer_info *prev = NULL; /* use to remove bad registrations. */ - - if ( 0 == hdr->public_ip.addr_type.v4_addr ) - { - /* Not to be registered. */ - return; - } - - if ( 0 == memcmp( hdr->dst_mac, broadcast_mac, 6 ) ) - { - /* Not to be registered. */ - return; - } - - - while(scan != NULL) - { - if(memcmp(hdr->dst_mac, scan->mac_addr, 6) == 0) - { - break; - } - - prev = scan; - scan = scan->next; - } - - if ( NULL == scan ) - { - /* Not in known_peers. */ - return; - } - - if ( 0 != memcmp( &(scan->public_ip), &(hdr->public_ip), sizeof(struct peer_addr))) - { - if ( 0 == hdr->sent_by_supernode ) - { - traceEvent( TRACE_NORMAL, "Peer changed public socket, Was %s:%hd", - intoa(ntohl(hdr->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(hdr->public_ip.port)); - - /* The peer has changed public socket. It can no longer be assumed to be reachable. */ - /* Remove the peer. */ - if ( NULL == prev ) - { - /* scan was head of list */ - eee->known_peers = scan->next; - } - else - { - prev->next = scan->next; - } - free(scan); - - try_send_register( eee, hdr ); - } - else - { - /* Don't worry about what the supernode reports, it could be seeing a different socket. */ - } - } - else - { - /* Found and unchanged. */ - scan->last_seen = when; - } -} - - - -#if defined(DUMMY_ID_00001) /* Disabled waiting for config option to enable it */ - -/* *********************************************** */ - -static char gratuitous_arp[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Dest mac */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */ - 0x08, 0x06, /* ARP */ - 0x00, 0x01, /* Ethernet */ - 0x08, 0x00, /* IP */ - 0x06, /* Hw Size */ - 0x04, /* Protocol Size */ - 0x00, 0x01, /* ARP Request */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */ - 0x00, 0x00, 0x00, 0x00, /* Src IP */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Target mac */ - 0x00, 0x00, 0x00, 0x00 /* Target IP */ -}; - -static int build_gratuitous_arp(char *buffer, u_short buffer_len) { - if(buffer_len < sizeof(gratuitous_arp)) return(-1); - - memcpy(buffer, gratuitous_arp, sizeof(gratuitous_arp)); - memcpy(&buffer[6], device.mac_addr, 6); - memcpy(&buffer[22], device.mac_addr, 6); - memcpy(&buffer[28], &device.ip_addr, 4); - - /* REVISIT: BbMaj7 - use a real netmask here. This is valid only by accident - * for /24 IPv4 networks. */ - buffer[31] = 0xFF; /* Use a faked broadcast address */ - memcpy(&buffer[38], &device.ip_addr, 4); - return(sizeof(gratuitous_arp)); -} - -/** Called from update_registrations to periodically send gratuitous ARP - * broadcasts. */ -static void send_grat_arps(n2n_edge_t * eee,) { - char buffer[48]; - size_t len; - - traceEvent(TRACE_NORMAL, "Sending gratuitous ARP..."); - len = build_gratuitous_arp(buffer, sizeof(buffer)); - send_packet2net(eee, buffer, len); - send_packet2net(eee, buffer, len); /* Two is better than one :-) */ -} -#endif /* #if defined(DUMMY_ID_00001) */ - - - -/* *********************************************** */ - -/** @brief Check to see if we should re-register with our peers and the - * supernode. - * - * This is periodically called by the main loop. The list of registrations is - * not modified. Registration packets may be sent. - */ -static void update_registrations( n2n_edge_t * eee ) { - /* REVISIT: BbMaj7: have shorter timeout to REGISTER to supernode if this has - * not yet succeeded. */ - - if(time(NULL) < (eee->last_register+REGISTER_FREQUENCY)) return; /* Too early */ - - traceEvent(TRACE_NORMAL, "Registering with supernode"); - if(eee->re_resolve_supernode_ip) - supernode2addr(eee, eee->supernode_ip); - - send_register(eee, &(eee->supernode), 0); /* Register with supernode */ - - /* REVISIT: turn-on gratuitous ARP with config option. */ - /* send_grat_arps(sock_fd, is_udp_sock); */ - - eee->last_register = time(NULL); -} - -/* ***************************************************** */ - -static int find_peer_destination(n2n_edge_t * eee, - const u_char *mac_address, - struct peer_addr *destination) { - const struct peer_info *scan = eee->known_peers; - macstr_t mac_buf; - ipstr_t ip_buf; - int retval=0; - - traceEvent(TRACE_INFO, "Searching destination peer for MAC %02X:%02X:%02X:%02X:%02X:%02X", - mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF, - mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF); - - while(scan != NULL) { - traceEvent(TRACE_INFO, "Evaluating peer [MAC=%02X:%02X:%02X:%02X:%02X:%02X][ip=%s:%hd]", - scan->mac_addr[0] & 0xFF, scan->mac_addr[1] & 0xFF, scan->mac_addr[2] & 0xFF, - scan->mac_addr[3] & 0xFF, scan->mac_addr[4] & 0xFF, scan->mac_addr[5] & 0xFF, - intoa(ntohl(scan->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(scan->public_ip.port)); - - if((scan->last_seen > 0) && - (memcmp(mac_address, scan->mac_addr, 6) == 0)) - { - memcpy(destination, &scan->public_ip, sizeof(struct sockaddr_in)); - retval=1; - break; - } - scan = scan->next; - } - - if ( 0 == retval ) - { - memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in)); - } - - traceEvent(TRACE_INFO, "find_peer_address(%s) -> [socket=%s:%hd]", - macaddr_str( (char *)mac_address, mac_buf, sizeof(mac_buf)), - intoa(ntohl(destination->addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(destination->port)); - - return retval; -} - -/* *********************************************** */ - -static const struct option long_options[] = { - { "community", required_argument, NULL, 'c' }, - { "supernode-list", required_argument, NULL, 'l' }, - { "tun-device", required_argument, NULL, 'd' }, - { "euid", required_argument, NULL, 'u' }, - { "egid", required_argument, NULL, 'g' }, - { "help" , no_argument, NULL, 'h' }, - { "verbose", no_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } -}; - -/* ***************************************************** */ - - -/** A layer-2 packet was received at the tunnel and needs to be sent via UDP. */ -static void send_packet2net(n2n_edge_t * eee, - char *decrypted_msg, size_t len) { - ipstr_t ip_buf; - char packet[2048]; - int data_sent_len; - struct n2n_packet_header hdr; - struct peer_addr destination; - macstr_t mac_buf; - macstr_t mac2_buf; - struct ether_header *eh = (struct ether_header*)decrypted_msg; - - /* Discard IP packets that are not originated by this hosts */ - if(!(eee->allow_routing)) { - if(ntohs(eh->ether_type) == 0x0800) { - /* This is an IP packet from the local source address - not forwarded. */ -#define ETH_FRAMESIZE 14 -#define IP4_SRCOFFSET 12 - u_int32_t *dst = (u_int32_t*)&decrypted_msg[ETH_FRAMESIZE + IP4_SRCOFFSET]; - - /* Note: all elements of the_ip are in network order */ - if( *dst != eee->device.ip_addr) { - /* This is a packet that needs to be routed */ - traceEvent(TRACE_INFO, "Discarding routed packet [%s]", - intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); - return; - } else { - /* This packet is originated by us */ - /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ - } - } - } - - /* Encrypt "decrypted_msg" into the second half of the n2n packet. */ - len = TwoFishEncryptRaw((u_int8_t *)decrypted_msg, - (u_int8_t *)&packet[N2N_PKT_HDR_SIZE], len, eee->enc_tf); - - /* Add the n2n header to the start of the n2n packet. */ - fill_standard_header_fields( &(eee->sinfo), &hdr, (char*)(eee->device.mac_addr) ); - hdr.msg_type = MSG_TYPE_PACKET; - hdr.sent_by_supernode = 0; - memcpy(hdr.community_name, eee->community_name, COMMUNITY_LEN); - memcpy(hdr.dst_mac, decrypted_msg, 6); - - marshall_n2n_packet_header( (u_int8_t *)packet, &hdr ); - - len += N2N_PKT_HDR_SIZE; - - if(find_peer_destination(eee, eh->ether_dhost, &destination)) - traceEvent(TRACE_INFO, "** Going direct [dst_mac=%s][dest=%s:%hd]", - macaddr_str((char*)eh->ether_dhost, mac_buf, sizeof(mac_buf)), - intoa(ntohl(destination.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(destination.port)); - else - traceEvent(TRACE_INFO, " Going via supernode [src_mac=%s][dst_mac=%s]", - macaddr_str((char*)eh->ether_shost, mac_buf, sizeof(mac_buf)), - macaddr_str((char*)eh->ether_dhost, mac2_buf, sizeof(mac2_buf))); - - data_sent_len = reliable_sendto( &(eee->sinfo), packet, &len, &destination, - N2N_COMPRESSION_ENABLED); - - if(data_sent_len != len) - traceEvent(TRACE_WARNING, "sendto() [sent=%d][attempted_to_send=%d] [%s]\n", - data_sent_len, len, strerror(errno)); - else { - ++(eee->pkt_sent); - traceEvent(TRACE_INFO, "Sent %d byte MSG_TYPE_PACKET ok", data_sent_len); - } -} - -/* ***************************************************** */ - -/** Destination MAC 33:33:0:00:00:00 - 33:33:FF:FF:FF:FF is reserved for IPv6 - * neighbour discovery. - */ -int is_ip6_discovery( const void * buf, size_t bufsize ) -{ - int retval = 0; - - if ( bufsize >= sizeof(struct ether_header) ) - { - struct ether_header *eh = (struct ether_header*)buf; - if ( (0x33 == eh->ether_dhost[0]) && - (0x33 == eh->ether_dhost[1]) ) - { - retval = 1; /* This is an IPv6 neighbour discovery packet. */ - } - } - return retval; -} - - -/* ***************************************************** */ - -/* - * Return: 0 = ok, -1 = invalid packet - * - */ -static int check_received_packet(n2n_edge_t * eee, char *pkt, - u_int pkt_len) { - - if(pkt_len == 42) { - /* ARP */ - if((pkt[12] != 0x08) || (pkt[13] != 0x06)) return(0); /* No ARP */ - if((pkt[20] != 0x00) || (pkt[21] != 0x02)) return(0); /* No ARP Reply */ - if(memcmp(&pkt[28], &(eee->device.ip_addr), 4)) return(0); /* This is not me */ - - if(memcmp(eee->device.mac_addr, &pkt[22], 6) == 0) { - traceEvent(TRACE_WARNING, "Bounced packet received: supernode bug?"); - return(0); - } - - traceEvent(TRACE_ERROR, "Duplicate address found. Your IP is used by MAC %02X:%02X:%02X:%02X:%02X:%02X", - pkt[22+0] & 0xFF, pkt[22+1] & 0xFF, pkt[22+2] & 0xFF, - pkt[22+3] & 0xFF, pkt[22+4] & 0xFF, pkt[22+5] & 0xFF); - exit(0); - } else if(pkt_len > 32 /* IP + Ethernet */) { - /* Check if this packet is for us or if it's routed */ - struct ether_header *eh = (struct ether_header*)pkt; - - const struct in_addr bcast = { 0xffffffff }; - - if(ntohs(eh->ether_type) == 0x0800) { - - /* Note: all elements of the_ip are in network order */ - struct ip *the_ip = (struct ip*)(pkt+sizeof(struct ether_header)); - - if((the_ip->ip_dst.s_addr != eee->device.ip_addr) - && ((the_ip->ip_dst.s_addr & eee->device.device_mask) != (eee->device.ip_addr & eee->device.device_mask)) /* Not a broadcast */ - && ((the_ip->ip_dst.s_addr & 0xE0000000) != (0xE0000000 /* 224.0.0.0-239.255.255.255 */)) /* Not a multicast */ - && ((the_ip->ip_dst.s_addr) != (bcast.s_addr)) /* always broadcast (RFC919) */ - && (!(eee->allow_routing)) /* routing is enabled so let it in */ - ) - { - /* Dropping the packet */ - - ipstr_t ip_buf; - ipstr_t ip_buf2; - - /* This is a packet that needs to be routed */ - traceEvent(TRACE_INFO, "Discarding routed packet [rcvd=%s][expected=%s]", - intoa(ntohl(the_ip->ip_dst.s_addr), ip_buf, sizeof(ip_buf)), - intoa(ntohl(eee->device.ip_addr), ip_buf2, sizeof(ip_buf2))); - } else { - /* This packet is for us */ - - /* traceEvent(TRACE_INFO, "Received non-routed packet"); */ - return(0); - } - } else - return(0); - } else { - traceEvent(TRACE_INFO, "Packet too short (%d bytes): discarded", pkt_len); - } - - return(-1); -} - -/* ***************************************************** */ - -/** Read a single packet from the TAP interface, process it and write out the - * corresponding packet to the cooked socket. - * - * REVISIT: fails if more than one packet is waiting to be read. - */ -static void readFromTAPSocket( n2n_edge_t * eee ) -{ - /* tun -> remote */ - u_char decrypted_msg[2048]; - size_t len; - - len = tuntap_read(&(eee->device), decrypted_msg, sizeof(decrypted_msg)); - - if((len <= 0) || (len > sizeof(decrypted_msg))) - traceEvent(TRACE_WARNING, "read()=%d [%d/%s]\n", - len, errno, strerror(errno)); - else { - traceEvent(TRACE_INFO, "### Rx L2 Msg (%d) tun -> network", len); - - if ( eee->drop_ipv6_ndp && is_ip6_discovery( decrypted_msg, len ) ) { - traceEvent(TRACE_WARNING, "Dropping unsupported IPv6 neighbour discovery packet"); - } else { - send_packet2net(eee, (char*)decrypted_msg, len); - } - } -} - -/* ***************************************************** */ - - -void readFromIPSocket( n2n_edge_t * eee ) -{ - ipstr_t ip_buf; - macstr_t mac_buf; - char packet[2048], decrypted_msg[2048]; - size_t len; - int data_sent_len; - struct peer_addr sender; - - /* remote -> tun */ - u_int8_t discarded_pkt; - struct n2n_packet_header hdr_storage; - - len = receive_data( &(eee->sinfo), packet, sizeof(packet), &sender, - &discarded_pkt, (char*)(eee->device.mac_addr), - N2N_COMPRESSION_ENABLED, &hdr_storage); - - if(len <= 0) return; - - traceEvent(TRACE_INFO, "### Rx N2N Msg network -> tun"); - - if(discarded_pkt) { - traceEvent(TRACE_INFO, "Discarded incoming pkt"); - } else { - if(len <= 0) - traceEvent(TRACE_WARNING, "receive_data()=%d [%s]\n", len, strerror(errno)); - else { - if(len < N2N_PKT_HDR_SIZE) - traceEvent(TRACE_WARNING, "received packet too short [len=%d]\n", len); - else { - struct n2n_packet_header *hdr = &hdr_storage; - - traceEvent(TRACE_INFO, "Received packet from %s:%hd", - intoa(ntohl(sender.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(sender.port)); - - traceEvent(TRACE_INFO, "Received message [msg_type=%s] from %s [dst mac=%s]", - msg_type2str(hdr->msg_type), - hdr->sent_by_supernode ? "supernode" : "peer", - macaddr_str(hdr->dst_mac, mac_buf, sizeof(mac_buf))); - - if(hdr->version != N2N_PKT_VERSION) { - traceEvent(TRACE_WARNING, - "Received packet with unknown protocol version (%d): discarded\n", - hdr->version); - return; - } - - /* FIX - Add IPv6 support */ - if(hdr->public_ip.addr_type.v4_addr == 0) { - hdr->public_ip.addr_type.v4_addr = sender.addr_type.v4_addr; - hdr->public_ip.port = sender.port; - hdr->public_ip.family = AF_INET; - } - - if(strncmp(hdr->community_name, eee->community_name, COMMUNITY_LEN) != 0) { - traceEvent(TRACE_WARNING, "Received packet with invalid community [expected=%s][received=%s]\n", - eee->community_name, hdr->community_name); - } else { - if(hdr->msg_type == MSG_TYPE_PACKET) { - /* assert: the packet received is destined for device.mac_addr or broadcast MAC. */ - - len -= N2N_PKT_HDR_SIZE; - - /* Decrypt message first */ - len = TwoFishDecryptRaw((u_int8_t *)&packet[N2N_PKT_HDR_SIZE], - (u_int8_t *)decrypted_msg, len, eee->dec_tf); - - if(len > 0) { - if(check_received_packet(eee, decrypted_msg, len) == 0) { - - if ( 0 == memcmp(hdr->dst_mac, eee->device.mac_addr, 6) ) - { - check_peer( eee, hdr ); - } - - data_sent_len = tuntap_write(&(eee->device), (u_char*)decrypted_msg, len); - - if(data_sent_len != len) - traceEvent(TRACE_WARNING, "tuntap_write() [sent=%d][attempted_to_send=%d] [%s]\n", - data_sent_len, len, strerror(errno)); - else { - /* Normal situation. */ - traceEvent(TRACE_INFO, "### Tx L2 Msg -> tun"); - } - } else { - traceEvent(TRACE_WARNING, "Bad destination: message discarded"); - } - } - /* else silently ignore empty packet. */ - - } else if(hdr->msg_type == MSG_TYPE_REGISTER) { - traceEvent(TRACE_INFO, "Received registration request from remote peer [ip=%s:%hd]", - intoa(ntohl(hdr->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(hdr->public_ip.port)); - if ( 0 == memcmp(hdr->dst_mac, (eee->device.mac_addr), 6) ) - { - check_peer( eee, hdr ); - } - - - send_register(eee, &hdr->public_ip, 1); /* Send ACK back */ - } else if(hdr->msg_type == MSG_TYPE_REGISTER_ACK) { - traceEvent(TRACE_NORMAL, "Received REGISTER_ACK from remote peer [ip=%s:%hd]", - intoa(ntohl(hdr->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(hdr->public_ip.port)); - - /* if ( 0 == memcmp(hdr->dst_mac, eee->device.mac_addr, 6) ) */ - { - if ( hdr->sent_by_supernode ) - { - /* Response to supernode registration. Supernode is not in the pending_peers list. */ - } - else - { - /* Move from pending_peers to known_peers; ignore if not in pending. */ - set_peer_operational( eee, hdr ); - } - } - - } else { - traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored\n", hdr->msg_type); - return; - } - } - } - } - } -} - -/* ***************************************************** */ - - -#ifdef WIN32 -static DWORD tunReadThread(LPVOID lpArg ) -{ - n2n_edge_t *eee = (n2n_edge_t*)lpArg; - - while(1) { - readFromTAPSocket(eee); - } - - return((DWORD)NULL); -} - -/* ***************************************************** */ - -static void startTunReadThread(n2n_edge_t *eee) { - HANDLE hThread; - DWORD dwThreadId; - - hThread = CreateThread(NULL, /* no security attributes */ - 0, /* use default stack size */ - (LPTHREAD_START_ROUTINE)tunReadThread, /* thread function */ - (void*)eee, /* argument to thread function */ - 0, /* use default creation flags */ - &dwThreadId); /* returns the thread identifier */ -} -#endif - -/* ***************************************************** */ - -static void supernode2addr(n2n_edge_t * eee, char* addr) { - char *supernode_host = strtok(addr, ":"); - - if(supernode_host) { - char *supernode_port = strtok(NULL, ":"); - const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL}; - struct addrinfo * ainfo = NULL; - int nameerr; - ipstr_t ip_buf; - - if ( supernode_port ) - eee->supernode.port = htons(atoi(supernode_port)); - else - traceEvent(TRACE_WARNING, "Bad supernode parameter (-l )"); - - nameerr = getaddrinfo( supernode_host, NULL, &aihints, &ainfo ); - - if( 0 == nameerr ) - { - struct sockaddr_in * saddr; - - /* ainfo s the head of a linked list if non-NULL. */ - if ( ainfo && (PF_INET == ainfo->ai_family) ) - { - /* It is definitely and IPv4 address -> sockaddr_in */ - saddr = (struct sockaddr_in *)ainfo->ai_addr; - - eee->supernode.addr_type.v4_addr = saddr->sin_addr.s_addr; - } - else - { - /* Should only return IPv4 addresses due to aihints. */ - traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host); - } - - freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */ - ainfo = NULL; - } else { - traceEvent(TRACE_WARNING, "Failed to resolve supernode host %s, assuming numeric", supernode_host); - eee->supernode.addr_type.v4_addr = inet_addr(supernode_host); - } - - traceEvent(TRACE_NORMAL, "Using supernode %s:%hd", - intoa(ntohl(eee->supernode.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(eee->supernode.port)); - } else - traceEvent(TRACE_WARNING, "Wrong supernode parameter (-l )"); -} - -/* ***************************************************** */ - -extern int useSyslog; - -#define N2N_NETMASK_STR_SIZE 16 /* dotted decimal 12 numbers + 3 dots */ - - -int main(int argc, char* argv[]) { - int opt, local_port = 0 /* any port */; - char *tuntap_dev_name = "edge0"; - char *ip_addr = NULL; - char netmask[N2N_NETMASK_STR_SIZE]="255.255.255.0"; - int mtu = DEFAULT_MTU; - int got_s = 0; - -#ifndef WIN32 - uid_t userid=0; /* root is the only guaranteed ID */ - gid_t groupid=0; /* root is the only guaranteed ID */ - int fork_as_daemon=0; -#endif - - size_t numPurged; - time_t lastStatus=0; - - char * device_mac=NULL; - char * encrypt_key=NULL; - - int i, effectiveargc=0; - char ** effectiveargv=NULL; - char * linebuffer = NULL; - - n2n_edge_t eee; /* single instance for this program */ - - if (-1 == edge_init(&eee) ){ - traceEvent( TRACE_ERROR, "Failed in edge_init" ); - exit(1); - } - - if( getenv( "N2N_KEY" )) { - encrypt_key = strdup( getenv( "N2N_KEY" )); - } - -#ifdef WIN32 - tuntap_dev_name = ""; -#endif - memset(&(eee.supernode), 0, sizeof(eee.supernode)); - eee.supernode.family = AF_INET; - - linebuffer = (char *)malloc(MAX_CMDLINE_BUFFER_LENGTH); - if (!linebuffer) { - traceEvent( TRACE_ERROR, "Unable to allocate memory"); - exit(1); - } - snprintf(linebuffer, MAX_CMDLINE_BUFFER_LENGTH, "%s",argv[0]); - -#ifdef WIN32 - for(i=0; i COMMUNITY_LEN) - eee.community_name[COMMUNITY_LEN] = '\0'; - break; -#ifndef WIN32 - - case 'u': /* uid */ - { - userid = atoi(optarg); - break; - } - case 'g': /* uid */ - { - groupid = atoi(optarg); - break; - } - case 'f' : /* fork as daemon */ - { - fork_as_daemon = 1; - break; - } -#endif - case 'm' : /* device_mac */ - { - device_mac = strdup(optarg); - break; - } - case 'M' : /* device_mac */ - { - mtu = atoi(optarg); - break; - } - case 'k': /* encrypt key */ - encrypt_key = strdup(optarg); - break; - case 'r': /* enable packet routing across n2n endpoints */ - eee.allow_routing = 1; - break; - case 'l': /* supernode-list */ - snprintf(eee.supernode_ip, sizeof(eee.supernode_ip), "%s", optarg); - supernode2addr(&eee, eee.supernode_ip); - break; -#ifdef __linux__ - case 'd': /* tun-device */ - tuntap_dev_name = strdup(optarg); - break; -#endif - case 't': /* Use HTTP tunneling */ - eee.sinfo.is_udp_socket = 0; - break; - case 'b': - eee.re_resolve_supernode_ip = 1; - break; - case 'p': - local_port = atoi(optarg); - break; - case 's': /* Subnet Mask */ - if (0 != got_s) { - traceEvent(TRACE_WARNING, "Multiple subnet masks supplied."); - } - strncpy(netmask, optarg, N2N_NETMASK_STR_SIZE); - got_s = 1; - break; - case 'h': /* help */ - help(); - break; - case 'v': /* verbose */ - traceLevel = 3; - break; - } - } - - if(!( -#ifdef __linux__ - tuntap_dev_name && -#endif - eee.community_name && - ip_addr && - eee.supernode.addr_type.v4_addr && - encrypt_key)) - help(); - -#ifndef WIN32 - /* If running suid root then we need to setuid before using the force. */ - setuid( 0 ); - /* setgid( 0 ); */ -#endif - - if(tuntap_open(&(eee.device), tuntap_dev_name, ip_addr, netmask, device_mac, mtu) < 0) - return(-1); - -#ifndef WIN32 - if ( (userid != 0) || (groupid != 0 ) ) { - traceEvent(TRACE_NORMAL, "Interface up. Dropping privileges to uid=%d, gid=%d", userid, groupid); - - /* Finished with the need for root privileges. Drop to unprivileged user. */ - setreuid( userid, userid ); - setregid( groupid, groupid ); - } -#endif - - if(local_port > 0) - traceEvent(TRACE_NORMAL, "Binding to local port %d", local_port); - - if(edge_init_twofish( &eee, (u_int8_t *)(encrypt_key), strlen(encrypt_key) ) < 0) return(-1); - eee.sinfo.sock = open_socket(local_port, eee.sinfo.is_udp_socket, 0); - if(eee.sinfo.sock < 0) return(-1); - - if( !(eee.sinfo.is_udp_socket) ) { - int rc = connect_socket(eee.sinfo.sock, &(eee.supernode)); - - if(rc == -1) { - traceEvent(TRACE_WARNING, "Error while connecting to supernode\n"); - return(-1); - } - } - -#ifndef WIN32 - if ( fork_as_daemon ) - { - useSyslog=1; /* traceEvent output now goes to syslog. */ - daemon( 0, 0 ); - } -#endif - - update_registrations(&eee); - - traceEvent(TRACE_NORMAL, ""); - traceEvent(TRACE_NORMAL, "Ready"); - -#ifdef WIN32 - startTunReadThread(&eee); -#endif - - /* Main loop - * - * select() is used to wait for input on either the TAP fd or the UDP/TCP - * socket. When input is present the data is read and processed by either - * readFromIPSocket() or readFromTAPSocket() - */ - - while(1) { - int rc, max_sock = 0; - fd_set socket_mask; - struct timeval wait_time; - time_t nowTime; - - FD_ZERO(&socket_mask); - FD_SET(eee.sinfo.sock, &socket_mask); -#ifndef WIN32 - FD_SET(eee.device.fd, &socket_mask); - max_sock = max( eee.sinfo.sock, eee.device.fd ); -#endif - - wait_time.tv_sec = SOCKET_TIMEOUT_INTERVAL_SECS; wait_time.tv_usec = 0; - - rc = select(max_sock+1, &socket_mask, NULL, NULL, &wait_time); - nowTime=time(NULL); - - if(rc > 0) - { - /* Any or all of the FDs could have input; check them all. */ - - if(FD_ISSET(eee.sinfo.sock, &socket_mask)) - { - /* Read a cooked socket from the internet socket. Writes on the TAP - * socket. */ - readFromIPSocket(&eee); - } - -#ifndef WIN32 - if(FD_ISSET(eee.device.fd, &socket_mask)) - { - /* Read an ethernet frame from the TAP socket. Write on the IP - * socket. */ - readFromTAPSocket(&eee); - } -#endif - } - - update_registrations(&eee); - - numPurged = purge_expired_registrations( &(eee.known_peers) ); - numPurged += purge_expired_registrations( &(eee.pending_peers) ); - if ( numPurged > 0 ) - { - traceEvent( TRACE_NORMAL, "Peer removed: pending=%ld, operational=%ld", - peer_list_size( eee.pending_peers ), peer_list_size( eee.known_peers ) ); - } - - if ( ( nowTime - lastStatus ) > STATUS_UPDATE_INTERVAL ) - { - lastStatus = nowTime; - - traceEvent( TRACE_NORMAL, "STATUS: pending=%ld, operational=%ld", - peer_list_size( eee.pending_peers ), peer_list_size( eee.known_peers ) ); - } - } /* while */ - - send_deregister( &eee, &(eee.supernode)); - - closesocket(eee.sinfo.sock); - tuntap_close(&(eee.device)); - - edge_deinit( &eee ); - - return(0); -} - - diff --git a/include/aes.h b/include/aes.h new file mode 100644 index 0000000..b22f0f8 --- /dev/null +++ b/include/aes.h @@ -0,0 +1,88 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" // HAVE_OPENSSL_1_1, traceEvent ... + + +#ifndef AES_H +#define AES_H + + +#include +#include + +#include "portable_endian.h" + +#define AES_BLOCK_SIZE 16 +#define AES_IV_SIZE (AES_BLOCK_SIZE) + +#define AES256_KEY_BYTES (256/8) +#define AES192_KEY_BYTES (192/8) +#define AES128_KEY_BYTES (128/8) + + +#if defined (HAVE_OPENSSL_1_1) // openSSL 1.1 --------------------------------------------------------------------- + +#include +#include +#include + +typedef struct aes_context_t { + EVP_CIPHER_CTX *enc_ctx; /* openssl's reusable evp_* en/de-cryption context */ + EVP_CIPHER_CTX *dec_ctx; /* openssl's reusable evp_* en/de-cryption context */ + const EVP_CIPHER *cipher; /* cipher to use: e.g. EVP_aes_128_cbc */ + uint8_t key[AES256_KEY_BYTES]; /* the pure key data for payload encryption & decryption */ + AES_KEY ecb_dec_key; /* one step ecb decryption key */ +} aes_context_t; + +#elif defined (__AES__) && defined (__SSE2__) // Intel's AES-NI --------------------------------------------------- + +#include + +typedef struct aes_context_t { + __m128i rk_enc[15]; + __m128i rk_dec[15]; + int Nr; +} aes_context_t; + +#else // plain C -------------------------------------------------------------------------------------------------- + +typedef struct aes_context_t { + uint32_t enc_rk[60]; // round keys for encryption + uint32_t dec_rk[60]; // round keys for decryption + int Nr; // number of rounds +} aes_context_t; + +#endif // --------------------------------------------------------------------------------------------------------- + + +int aes_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, aes_context_t *ctx); + +int aes_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, aes_context_t *ctx); + +int aes_ecb_decrypt (unsigned char *out, const unsigned char *in, aes_context_t *ctx); + +int aes_init (const unsigned char *key, size_t key_size, aes_context_t **ctx); + +int aes_deinit (aes_context_t *ctx); + + +#endif // AES_H diff --git a/include/auth.h b/include/auth.h new file mode 100644 index 0000000..0376d3f --- /dev/null +++ b/include/auth.h @@ -0,0 +1,43 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + + +#include "n2n.h" + + +#ifndef AUTH_H +#define AUTH_H + + +int bin_to_ascii (char *out, uint8_t *in, size_t in_len); + +int ascii_to_bin (uint8_t *out, char *in); + +int generate_private_key (n2n_private_public_key_t key, char *in); + +int generate_public_key (n2n_private_public_key_t pub, n2n_private_public_key_t prv); + +int generate_shared_secret (n2n_private_public_key_t shared, n2n_private_public_key_t prv, n2n_private_public_key_t pub); + +int bind_private_key_to_username (n2n_private_public_key_t prv, char *username); + +int calculate_dynamic_key (uint8_t out_key[N2N_AUTH_CHALLENGE_SIZE], + uint32_t key_time, n2n_community_t comm, n2n_community_t fed); + + +#endif diff --git a/include/cc20.h b/include/cc20.h new file mode 100644 index 0000000..3a5b553 --- /dev/null +++ b/include/cc20.h @@ -0,0 +1,78 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#ifndef CC20_H +#define CC20_H + + +#include + +#include "n2n.h" // HAVE_OPENSSL_1_1, traceEvent ... + + +#define CC20_IV_SIZE 16 +#define CC20_KEY_BYTES (256/8) + + +#ifdef HAVE_OPENSSL_1_1 // openSSL 1.1 ---------------------------------------------------------------------------- + + +#include +#include + +typedef struct cc20_context_t { + EVP_CIPHER_CTX *ctx; /* openssl's reusable evp_* en/de-cryption context */ + const EVP_CIPHER *cipher; /* cipher to use: e.g. EVP_chacha20() */ + uint8_t key[CC20_KEY_BYTES]; /* the pure key data for payload encryption & decryption */ +} cc20_context_t; + + +#elif defined (__SSE2__) // SSE2 --------------------------------------------------------------------------------- + + +#include + +typedef struct cc20_context { + uint32_t keystream32[16]; + uint8_t key[CC20_KEY_BYTES]; +} cc20_context_t; + + +#else // plain C -------------------------------------------------------------------------------------------------- + + +typedef struct cc20_context { + uint32_t keystream32[16]; + uint32_t state[16]; + uint8_t key[CC20_KEY_BYTES]; +} cc20_context_t; + + +#endif // openSSL 1.1, plain C ------------------------------------------------------------------------------------ + + +int cc20_crypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, cc20_context_t *ctx); + +int cc20_init (const unsigned char *key, cc20_context_t **ctx); + +int cc20_deinit (cc20_context_t *ctx); + + +#endif // CC20_H diff --git a/include/curve25519.h b/include/curve25519.h new file mode 100644 index 0000000..e816bf5 --- /dev/null +++ b/include/curve25519.h @@ -0,0 +1,20 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +void curve25519 (unsigned char *q, const unsigned char *n, const unsigned char *p); diff --git a/include/edge_utils_win32.h b/include/edge_utils_win32.h new file mode 100644 index 0000000..09f8366 --- /dev/null +++ b/include/edge_utils_win32.h @@ -0,0 +1,52 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#ifndef _EDGE_UTILS_WIN32_H_ +#define _EDGE_UTILS_WIN32_H_ + +#ifdef WIN32 + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include + + +/* Multicast peers discovery disabled due to https://github.com/ntop/n2n/issues/65 */ + +/* Currently, multicast is performed by specifying the default routing network adapter. + * If the solution is determined to be stable and effective, + * all macro definitions "SKIP_MULTICAST_PEERS_DISCOVERY" will be completely deleted in the future. + */ +//#define SKIP_MULTICAST_PEERS_DISCOVERY + +// TODO: this struct is pretty empty now, collapse it to just n2n_edge_t ? +struct tunread_arg { + n2n_edge_t *eee; +}; + +extern HANDLE startTunReadThread (struct tunread_arg *arg); +int get_best_interface_ip (n2n_edge_t * eee, dec_ip_str_t ip_addr); + + +#endif /* WIN32 */ + +#endif /* _EDGE_UTILS_WIN32_H_ */ + diff --git a/include/header_encryption.h b/include/header_encryption.h new file mode 100644 index 0000000..a5e3f89 --- /dev/null +++ b/include/header_encryption.h @@ -0,0 +1,35 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +int packet_header_decrypt (uint8_t packet[], uint16_t packet_len, + char *community_name, + he_context_t *ctx, he_context_t *ctx_iv, + uint64_t *stamp); + +int packet_header_encrypt (uint8_t packet[], uint16_t header_len, uint16_t packet_len, + he_context_t *ctx, he_context_t *ctx_iv, + uint64_t stamp); + +void packet_header_setup_key (const char *community_name, + he_context_t **ctx_static, he_context_t **ctx_dynamic, + he_context_t **ctx_iv_static, he_context_t **ctx_iv_dynamic); + +void packet_header_change_dynamic_key (uint8_t *key_dynamic, + he_context_t **ctx_dynamic, + he_context_t **ctx_iv_dynamic); diff --git a/include/hexdump.h b/include/hexdump.h new file mode 100644 index 0000000..4480319 --- /dev/null +++ b/include/hexdump.h @@ -0,0 +1,6 @@ +#ifndef HEXDUMP_H +#define HEXDUMP_H + +void fhexdump(unsigned int display_addr, void *in, int size, FILE *stream); + +#endif diff --git a/lzoconf.h b/include/lzoconf.h similarity index 58% rename from lzoconf.h rename to include/lzoconf.h index cc437f1..67e832e 100644 --- a/lzoconf.h +++ b/include/lzoconf.h @@ -1,20 +1,27 @@ -/* lzoconf.h -- configuration for the LZO real-time data compression library +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +/* lzoconf.h -- configuration of the LZO data compression library This file is part of the LZO real-time data compression library. - Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library is free software; you can redistribute it and/or @@ -39,11 +46,11 @@ #ifndef __LZOCONF_H_INCLUDED -#define __LZOCONF_H_INCLUDED +#define __LZOCONF_H_INCLUDED 1 -#define LZO_VERSION 0x2030 -#define LZO_VERSION_STRING "2.03" -#define LZO_VERSION_DATE "Apr 30 2008" +#define LZO_VERSION 0x20a0 /* 2.10 */ +#define LZO_VERSION_STRING "2.10" +#define LZO_VERSION_DATE "Mar 01 2017" /* internal Autoconf configuration file - only used when building LZO */ #if defined(LZO_HAVE_CONFIG_H) @@ -60,7 +67,7 @@ #if !defined(CHAR_BIT) || (CHAR_BIT != 8) # error "invalid CHAR_BIT" #endif -#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX) +#if !defined(UCHAR_MAX) || !defined(USHRT_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX) # error "check your compiler installation" #endif #if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1) @@ -69,7 +76,7 @@ /* get OS and architecture defines */ #ifndef __LZODEFS_H_INCLUDED -#include "lzodefs.h" +#include #endif @@ -82,14 +89,6 @@ extern "C" { // some core defines ************************************************************************/ -#if !defined(LZO_UINT32_C) -# if (UINT_MAX < LZO_0xffffffffL) -# define LZO_UINT32_C(c) c ## UL -# else -# define LZO_UINT32_C(c) ((c) + 0U) -# endif -#endif - /* memory checkers */ #if !defined(__LZO_CHECKER) # if defined(__BOUNDS_CHECKING_ON) @@ -108,28 +107,35 @@ extern "C" { // integral and pointer types ************************************************************************/ -/* lzo_uint should match size_t */ +/* lzo_uint must match size_t */ #if !defined(LZO_UINT_MAX) -# if defined(LZO_ABI_LLP64) /* WIN64 */ -# if defined(LZO_OS_WIN64) +# if (LZO_ABI_LLP64) +# if (LZO_OS_WIN64) typedef unsigned __int64 lzo_uint; typedef __int64 lzo_int; +# define LZO_TYPEOF_LZO_INT LZO_TYPEOF___INT64 # else - typedef unsigned long long lzo_uint; - typedef long long lzo_int; + typedef lzo_ullong_t lzo_uint; + typedef lzo_llong_t lzo_int; +# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG_LONG # endif +# define LZO_SIZEOF_LZO_INT 8 # define LZO_UINT_MAX 0xffffffffffffffffull # define LZO_INT_MAX 9223372036854775807LL # define LZO_INT_MIN (-1LL - LZO_INT_MAX) -# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */ +# elif (LZO_ABI_IP32L64) /* MIPS R5900 */ typedef unsigned int lzo_uint; typedef int lzo_int; +# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_INT +# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_INT # define LZO_UINT_MAX UINT_MAX # define LZO_INT_MAX INT_MAX # define LZO_INT_MIN INT_MIN # elif (ULONG_MAX >= LZO_0xffffffffL) typedef unsigned long lzo_uint; typedef long lzo_int; +# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_LONG +# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG # define LZO_UINT_MAX ULONG_MAX # define LZO_INT_MAX LONG_MAX # define LZO_INT_MIN LONG_MIN @@ -138,42 +144,23 @@ extern "C" { # endif #endif -/* Integral types with 32 bits or more. */ -#if !defined(LZO_UINT32_MAX) -# if (UINT_MAX >= LZO_0xffffffffL) - typedef unsigned int lzo_uint32; - typedef int lzo_int32; -# define LZO_UINT32_MAX UINT_MAX -# define LZO_INT32_MAX INT_MAX -# define LZO_INT32_MIN INT_MIN -# elif (ULONG_MAX >= LZO_0xffffffffL) - typedef unsigned long lzo_uint32; - typedef long lzo_int32; -# define LZO_UINT32_MAX ULONG_MAX -# define LZO_INT32_MAX LONG_MAX -# define LZO_INT32_MIN LONG_MIN -# else -# error "lzo_uint32" -# endif -#endif - -/* The larger type of lzo_uint and lzo_uint32. */ -#if (LZO_UINT_MAX >= LZO_UINT32_MAX) +/* The larger type of lzo_uint and lzo_uint32_t. */ +#if (LZO_SIZEOF_LZO_INT >= 4) # define lzo_xint lzo_uint #else -# define lzo_xint lzo_uint32 +# define lzo_xint lzo_uint32_t #endif -/* Memory model that allows to access memory at offsets of lzo_uint. */ -#if !defined(__LZO_MMODEL) -# if (LZO_UINT_MAX <= UINT_MAX) -# define __LZO_MMODEL -# elif defined(LZO_HAVE_MM_HUGE_PTR) -# define __LZO_MMODEL_HUGE 1 -# define __LZO_MMODEL __huge -# else -# define __LZO_MMODEL -# endif +typedef int lzo_bool; + +/* sanity checks */ +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int) == LZO_SIZEOF_LZO_INT) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_INT) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint)) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t)) + +#ifndef __LZO_MMODEL +#define __LZO_MMODEL /*empty*/ #endif /* no typedef here because of const-pointer issues */ @@ -182,17 +169,52 @@ extern "C" { #define lzo_voidp void __LZO_MMODEL * #define lzo_shortp short __LZO_MMODEL * #define lzo_ushortp unsigned short __LZO_MMODEL * -#define lzo_uint32p lzo_uint32 __LZO_MMODEL * -#define lzo_int32p lzo_int32 __LZO_MMODEL * -#define lzo_uintp lzo_uint __LZO_MMODEL * #define lzo_intp lzo_int __LZO_MMODEL * +#define lzo_uintp lzo_uint __LZO_MMODEL * #define lzo_xintp lzo_xint __LZO_MMODEL * #define lzo_voidpp lzo_voidp __LZO_MMODEL * #define lzo_bytepp lzo_bytep __LZO_MMODEL * -/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */ -#define lzo_byte unsigned char __LZO_MMODEL -typedef int lzo_bool; +#define lzo_int8_tp lzo_int8_t __LZO_MMODEL * +#define lzo_uint8_tp lzo_uint8_t __LZO_MMODEL * +#define lzo_int16_tp lzo_int16_t __LZO_MMODEL * +#define lzo_uint16_tp lzo_uint16_t __LZO_MMODEL * +#define lzo_int32_tp lzo_int32_t __LZO_MMODEL * +#define lzo_uint32_tp lzo_uint32_t __LZO_MMODEL * +#if defined(lzo_int64_t) +#define lzo_int64_tp lzo_int64_t __LZO_MMODEL * +#define lzo_uint64_tp lzo_uint64_t __LZO_MMODEL * +#endif + +/* Older LZO versions used to support ancient systems and memory models + * such as 16-bit MSDOS with __huge pointers or Cray PVP, but these + * obsolete configurations are not supported any longer. + */ +#if defined(__LZO_MMODEL_HUGE) +#error "__LZO_MMODEL_HUGE memory model is unsupported" +#endif +#if (LZO_MM_PVP) +#error "LZO_MM_PVP memory model is unsupported" +#endif +#if (LZO_SIZEOF_INT < 4) +#error "LZO_SIZEOF_INT < 4 is unsupported" +#endif +#if (__LZO_UINTPTR_T_IS_POINTER) +#error "__LZO_UINTPTR_T_IS_POINTER is unsupported" +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) >= 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) >= 4) +/* Strange configurations where sizeof(lzo_uint) != sizeof(size_t) should + * work but have not received much testing lately, so be strict here. + */ +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(size_t)) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(ptrdiff_t)) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(lzo_uintptr_t)) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_uintptr_t)) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_uintptr_t)) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long *) == sizeof(lzo_uintptr_t)) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_voidp)) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_bytep)) /*********************************************************************** @@ -215,21 +237,21 @@ typedef int lzo_bool; /* DLL export information */ #if !defined(__LZO_EXPORT1) -# define __LZO_EXPORT1 +# define __LZO_EXPORT1 /*empty*/ #endif #if !defined(__LZO_EXPORT2) -# define __LZO_EXPORT2 +# define __LZO_EXPORT2 /*empty*/ #endif /* __cdecl calling convention for public C and assembly functions */ #if !defined(LZO_PUBLIC) -# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL +# define LZO_PUBLIC(r) __LZO_EXPORT1 r __LZO_EXPORT2 __LZO_CDECL #endif #if !defined(LZO_EXTERN) -# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype) +# define LZO_EXTERN(r) __LZO_EXTERN_C LZO_PUBLIC(r) #endif #if !defined(LZO_PRIVATE) -# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL +# define LZO_PRIVATE(r) static r __LZO_CDECL #endif /* function types */ @@ -287,7 +309,7 @@ struct lzo_callback_t /* a progress indicator callback function (set to 0 to disable) */ lzo_progress_func_t nprogress; - /* NOTE: the first parameter "self" of the nalloc/nfree/nprogress + /* INFO: the first parameter "self" of the nalloc/nfree/nprogress * callbacks points back to this struct, so you are free to store * some extra info in the following variables. */ lzo_voidp user1; @@ -306,7 +328,7 @@ struct lzo_callback_t */ #define LZO_E_OK 0 #define LZO_E_ERROR (-1) -#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */ +#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */ #define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ #define LZO_E_INPUT_OVERRUN (-4) #define LZO_E_OUTPUT_OVERRUN (-5) @@ -314,6 +336,10 @@ struct lzo_callback_t #define LZO_E_EOF_NOT_FOUND (-7) #define LZO_E_INPUT_NOT_CONSUMED (-8) #define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ +#define LZO_E_INVALID_ARGUMENT (-10) +#define LZO_E_INVALID_ALIGNMENT (-11) /* pointer argument is not properly aligned */ +#define LZO_E_OUTPUT_NOT_CONSUMED (-12) +#define LZO_E_INTERNAL_ERROR (-99) #ifndef lzo_sizeof_dict_t @@ -327,7 +353,7 @@ struct lzo_callback_t * compiler's view of various types are consistent. */ #define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\ - (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\ + (int)sizeof(long),(int)sizeof(lzo_uint32_t),(int)sizeof(lzo_uint),\ (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\ (int)sizeof(lzo_callback_t)) LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int); @@ -341,38 +367,67 @@ LZO_EXTERN(const lzo_charp) _lzo_version_date(void); /* string functions */ LZO_EXTERN(int) -lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len); + lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len); LZO_EXTERN(lzo_voidp) -lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); + lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len); LZO_EXTERN(lzo_voidp) -lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); + lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len); LZO_EXTERN(lzo_voidp) -lzo_memset(lzo_voidp _s, int _c, lzo_uint _len); + lzo_memset(lzo_voidp buf, int c, lzo_uint len); /* checksum functions */ -LZO_EXTERN(lzo_uint32) -lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len); -LZO_EXTERN(lzo_uint32) -lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len); -LZO_EXTERN(const lzo_uint32p) -lzo_get_crc32_table(void); +LZO_EXTERN(lzo_uint32_t) + lzo_adler32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len); +LZO_EXTERN(lzo_uint32_t) + lzo_crc32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len); +LZO_EXTERN(const lzo_uint32_tp) + lzo_get_crc32_table(void); /* misc. */ LZO_EXTERN(int) _lzo_config_check(void); -typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u; -typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u; -typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t; +typedef union { + lzo_voidp a00; lzo_bytep a01; lzo_uint a02; lzo_xint a03; lzo_uintptr_t a04; + void *a05; unsigned char *a06; unsigned long a07; size_t a08; ptrdiff_t a09; +#if defined(lzo_int64_t) + lzo_uint64_t a10; +#endif +} lzo_align_t; -/* align a char pointer on a boundary that is a multiple of `size' */ -LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size); -#define LZO_PTR_ALIGN_UP(_ptr,_size) \ - ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size))) +/* align a char pointer on a boundary that is a multiple of 'size' */ +LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size); +#define LZO_PTR_ALIGN_UP(p,size) \ + ((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size))) /*********************************************************************** -// deprecated macros - only for backward compatibility with LZO v1.xx +// deprecated macros - only for backward compatibility ************************************************************************/ +/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */ +#define lzo_byte unsigned char +/* deprecated type names */ +#define lzo_int32 lzo_int32_t +#define lzo_uint32 lzo_uint32_t +#define lzo_int32p lzo_int32_t __LZO_MMODEL * +#define lzo_uint32p lzo_uint32_t __LZO_MMODEL * +#define LZO_INT32_MAX LZO_INT32_C(2147483647) +#define LZO_UINT32_MAX LZO_UINT32_C(4294967295) +#if defined(lzo_int64_t) +#define lzo_int64 lzo_int64_t +#define lzo_uint64 lzo_uint64_t +#define lzo_int64p lzo_int64_t __LZO_MMODEL * +#define lzo_uint64p lzo_uint64_t __LZO_MMODEL * +#define LZO_INT64_MAX LZO_INT64_C(9223372036854775807) +#define LZO_UINT64_MAX LZO_UINT64_C(18446744073709551615) +#endif +/* deprecated types */ +typedef union { lzo_bytep a; lzo_uint b; } __lzo_pu_u; +typedef union { lzo_bytep a; lzo_uint32_t b; } __lzo_pu32_u; +/* deprecated defines */ +#if !defined(LZO_SIZEOF_LZO_UINT) +# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LZO_INT +#endif + #if defined(LZO_CFG_COMPAT) #define __LZOCONF_H 1 @@ -395,8 +450,8 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size); # define __LZO_WIN 1 #endif -#define __LZO_CMODEL -#define __LZO_DMODEL +#define __LZO_CMODEL /*empty*/ +#define __LZO_DMODEL /*empty*/ #define __LZO_ENTRY __LZO_CDECL #define LZO_EXTERN_CDECL LZO_EXTERN #define LZO_ALIGN LZO_PTR_ALIGN_UP @@ -414,4 +469,4 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size); #endif /* already included */ -/* vim:set ts=4 et: */ +/* vim:set ts=4 sw=4 et: */ diff --git a/include/lzodefs.h b/include/lzodefs.h new file mode 100644 index 0000000..ab55efa --- /dev/null +++ b/include/lzodefs.h @@ -0,0 +1,3286 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +/* lzodefs.h -- architecture, OS and compiler specific defines + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library 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 2 of + the License, or (at your option) any later version. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __LZODEFS_H_INCLUDED +#define __LZODEFS_H_INCLUDED 1 + +#if defined(__CYGWIN32__) && !defined(__CYGWIN__) +# define __CYGWIN__ __CYGWIN32__ +#endif +#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) +# define _ALL_SOURCE 1 +#endif +#if defined(__mips__) && defined(__R5900__) +# if !defined(__LONG_MAX__) +# define __LONG_MAX__ 9223372036854775807L +# endif +#endif +#if 0 +#elif !defined(__LZO_LANG_OVERRIDE) +#if (defined(__clang__) || defined(__GNUC__)) && defined(__ASSEMBLER__) +# if (__ASSEMBLER__+0) <= 0 +# error "__ASSEMBLER__" +# else +# define LZO_LANG_ASSEMBLER 1 +# endif +#elif defined(__cplusplus) +# if (__cplusplus+0) <= 0 +# error "__cplusplus" +# elif (__cplusplus < 199711L) +# define LZO_LANG_CXX 1 +# elif defined(_MSC_VER) && defined(_MSVC_LANG) && (_MSVC_LANG+0 >= 201402L) && 1 +# define LZO_LANG_CXX _MSVC_LANG +# else +# define LZO_LANG_CXX __cplusplus +# endif +# define LZO_LANG_CPLUSPLUS LZO_LANG_CXX +#else +# if defined(__STDC_VERSION__) && (__STDC_VERSION__+0 >= 199409L) +# define LZO_LANG_C __STDC_VERSION__ +# else +# define LZO_LANG_C 1 +# endif +#endif +#endif +#if !defined(LZO_CFG_NO_DISABLE_WUNDEF) +#if defined(__ARMCC_VERSION) +# pragma diag_suppress 193 +#elif defined(__clang__) && defined(__clang_minor__) +# pragma clang diagnostic ignored "-Wundef" +#elif defined(__INTEL_COMPILER) +# pragma warning(disable: 193) +#elif defined(__KEIL__) && defined(__C166__) +# pragma warning disable = 322 +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__PATHSCALE__) +# if ((__GNUC__-0) >= 5 || ((__GNUC__-0) == 4 && (__GNUC_MINOR__-0) >= 2)) +# pragma GCC diagnostic ignored "-Wundef" +# endif +#elif defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) +# if ((_MSC_VER-0) >= 1300) +# pragma warning(disable: 4668) +# endif +#endif +#endif +#if 0 && defined(__POCC__) && defined(_WIN32) +# if (__POCC__ >= 400) +# pragma warn(disable: 2216) +# endif +#endif +#if 0 && defined(__WATCOMC__) +# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) +# pragma warning 203 9 +# endif +#endif +#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) +# pragma option -h +#endif +#if !(LZO_CFG_NO_DISABLE_WCRTNONSTDC) +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#endif +#ifndef _CRT_NONSTDC_NO_WARNINGS +#define _CRT_NONSTDC_NO_WARNINGS 1 +#endif +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif +#endif +#if 0 +#define LZO_0xffffUL 0xfffful +#define LZO_0xffffffffUL 0xfffffffful +#else +#define LZO_0xffffUL 65535ul +#define LZO_0xffffffffUL 4294967295ul +#endif +#define LZO_0xffffL LZO_0xffffUL +#define LZO_0xffffffffL LZO_0xffffffffUL +#if (LZO_0xffffL == LZO_0xffffffffL) +# error "your preprocessor is broken 1" +#endif +#if (16ul * 16384ul != 262144ul) +# error "your preprocessor is broken 2" +#endif +#if 0 +#if (32767 >= 4294967295ul) +# error "your preprocessor is broken 3" +#endif +#if (65535u >= 4294967295ul) +# error "your preprocessor is broken 4" +#endif +#endif +#if defined(__COUNTER__) +# ifndef LZO_CFG_USE_COUNTER +# define LZO_CFG_USE_COUNTER 1 +# endif +#else +# undef LZO_CFG_USE_COUNTER +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) +# if !defined(MSDOS) +# define MSDOS 1 +# endif +# if !defined(_MSDOS) +# define _MSDOS 1 +# endif +#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) +# if (__VERSION == 520) && (MB_LEN_MAX == 1) +# if !defined(__AZTEC_C__) +# define __AZTEC_C__ __VERSION +# endif +# if !defined(__DOS__) +# define __DOS__ 1 +# endif +# endif +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(_MSC_VER) && defined(M_I86HM) +# define ptrdiff_t long +# define _PTRDIFF_T_DEFINED 1 +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +# if defined(__AZTEC_C__) && defined(__DOS__) +# define __LZO_RENAME_A 1 +# elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define __LZO_RENAME_A 1 +# elif (_MSC_VER < 700) +# define __LZO_RENAME_B 1 +# endif +# elif defined(__TSC__) && defined(__OS2__) +# define __LZO_RENAME_A 1 +# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) +# define __LZO_RENAME_A 1 +# elif defined(__PACIFIC__) && defined(DOS) +# if !defined(__far) +# define __far far +# endif +# if !defined(__near) +# define __near near +# endif +# endif +# if defined(__LZO_RENAME_A) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__far) +# define __far far +# endif +# if !defined(__huge) +# define __huge huge +# endif +# if !defined(__near) +# define __near near +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# if !defined(__huge) +# define __huge huge +# endif +# elif defined(__LZO_RENAME_B) +# if !defined(__cdecl) +# define __cdecl _cdecl +# endif +# if !defined(__far) +# define __far _far +# endif +# if !defined(__huge) +# define __huge _huge +# endif +# if !defined(__near) +# define __near _near +# endif +# if !defined(__pascal) +# define __pascal _pascal +# endif +# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# endif +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__AZTEC_C__) && defined(__DOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +#elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# endif +# if (_MSC_VER < 700) +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# define LZO_BROKEN_SIZEOF 1 +# endif +#elif defined(__PACIFIC__) && defined(DOS) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#elif defined(__TURBOC__) && defined(__MSDOS__) +# if (__TURBOC__ < 0x0150) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# endif +# if (__TURBOC__ < 0x0200) +# define LZO_BROKEN_SIZEOF 1 +# endif +# if (__TURBOC__ < 0x0400) && defined(__cplusplus) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# endif +#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_SIZEOF 1 +#endif +#endif +#if defined(__WATCOMC__) && (__WATCOMC__ < 900) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#endif +#if defined(_CRAY) && defined(_CRAY1) +# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 +#endif +#define LZO_PP_STRINGIZE(x) #x +#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) +#define LZO_PP_CONCAT0() /*empty*/ +#define LZO_PP_CONCAT1(a) a +#define LZO_PP_CONCAT2(a,b) a ## b +#define LZO_PP_CONCAT3(a,b,c) a ## b ## c +#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_PP_CONCAT6(a,b,c,d,e,f) a ## b ## c ## d ## e ## f +#define LZO_PP_CONCAT7(a,b,c,d,e,f,g) a ## b ## c ## d ## e ## f ## g +#define LZO_PP_ECONCAT0() LZO_PP_CONCAT0() +#define LZO_PP_ECONCAT1(a) LZO_PP_CONCAT1(a) +#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) +#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) +#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) +#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) +#define LZO_PP_ECONCAT6(a,b,c,d,e,f) LZO_PP_CONCAT6(a,b,c,d,e,f) +#define LZO_PP_ECONCAT7(a,b,c,d,e,f,g) LZO_PP_CONCAT7(a,b,c,d,e,f,g) +#define LZO_PP_EMPTY /*empty*/ +#define LZO_PP_EMPTY0() /*empty*/ +#define LZO_PP_EMPTY1(a) /*empty*/ +#define LZO_PP_EMPTY2(a,b) /*empty*/ +#define LZO_PP_EMPTY3(a,b,c) /*empty*/ +#define LZO_PP_EMPTY4(a,b,c,d) /*empty*/ +#define LZO_PP_EMPTY5(a,b,c,d,e) /*empty*/ +#define LZO_PP_EMPTY6(a,b,c,d,e,f) /*empty*/ +#define LZO_PP_EMPTY7(a,b,c,d,e,f,g) /*empty*/ +#if 1 +#define LZO_CPP_STRINGIZE(x) #x +#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) +#define LZO_CPP_CONCAT2(a,b) a ## b +#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c +#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_CPP_CONCAT6(a,b,c,d,e,f) a ## b ## c ## d ## e ## f +#define LZO_CPP_CONCAT7(a,b,c,d,e,f,g) a ## b ## c ## d ## e ## f ## g +#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) +#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) +#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) +#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) +#define LZO_CPP_ECONCAT6(a,b,c,d,e,f) LZO_CPP_CONCAT6(a,b,c,d,e,f) +#define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g) +#endif +#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-((b)!=0))) - (o)) << 1) + (o)*((b)!=0)) +#if 1 && defined(__cplusplus) +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS 1 +# endif +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS 1 +# endif +#endif +#if defined(__cplusplus) +# define LZO_EXTERN_C extern "C" +# define LZO_EXTERN_C_BEGIN extern "C" { +# define LZO_EXTERN_C_END } +#else +# define LZO_EXTERN_C extern +# define LZO_EXTERN_C_BEGIN /*empty*/ +# define LZO_EXTERN_C_END /*empty*/ +#endif +#if !defined(__LZO_OS_OVERRIDE) +#if (LZO_OS_FREESTANDING) +# define LZO_INFO_OS "freestanding" +#elif (LZO_OS_EMBEDDED) +# define LZO_INFO_OS "embedded" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_OS_EMBEDDED 1 +# define LZO_INFO_OS "embedded" +#elif defined(__CYGWIN__) && defined(__GNUC__) +# define LZO_OS_CYGWIN 1 +# define LZO_INFO_OS "cygwin" +#elif defined(__EMX__) && defined(__GNUC__) +# define LZO_OS_EMX 1 +# define LZO_INFO_OS "emx" +#elif defined(__BEOS__) +# define LZO_OS_BEOS 1 +# define LZO_INFO_OS "beos" +#elif defined(__Lynx__) +# define LZO_OS_LYNXOS 1 +# define LZO_INFO_OS "lynxos" +#elif defined(__OS400__) +# define LZO_OS_OS400 1 +# define LZO_INFO_OS "os400" +#elif defined(__QNX__) +# define LZO_OS_QNX 1 +# define LZO_INFO_OS "qnx" +#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__BORLANDC__) && defined(__DPMI16__) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +#elif defined(__ZTC__) && defined(DOS386) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__OS2__) || defined(__OS2V2__) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_OS216 1 +# define LZO_INFO_OS "os216" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_OS2 1 +# define LZO_INFO_OS "os2" +# else +# error "check your limits.h header" +# endif +#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) +# define LZO_OS_WIN64 1 +# define LZO_INFO_OS "win64" +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__MWERKS__) && defined(__INTEL__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_WIN16 1 +# define LZO_INFO_OS "win16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# else +# error "check your limits.h header" +# endif +#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +# else +# error "check your limits.h header" +# endif +#elif defined(__WATCOMC__) +# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif defined(__NT__) && (__WATCOMC__ < 1100) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# elif defined(__linux__) || defined(__LINUX__) +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +# else +# error "please specify a target using the -bt compiler option" +# endif +#elif defined(__palmos__) +# define LZO_OS_PALMOS 1 +# define LZO_INFO_OS "palmos" +#elif defined(__TOS__) || defined(__atarist__) +# define LZO_OS_TOS 1 +# define LZO_INFO_OS "tos" +#elif defined(macintosh) && !defined(__arm__) && !defined(__i386__) && !defined(__ppc__) && !defined(__x64_64__) +# define LZO_OS_MACCLASSIC 1 +# define LZO_INFO_OS "macclassic" +#elif defined(__VMS) +# define LZO_OS_VMS 1 +# define LZO_INFO_OS "vms" +#elif (defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PS2 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "ps2" +#elif defined(__mips__) && defined(__psp__) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PSP 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "psp" +#else +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +#endif +#if (LZO_OS_POSIX) +# if defined(_AIX) || defined(__AIX__) || defined(__aix__) +# define LZO_OS_POSIX_AIX 1 +# define LZO_INFO_OS_POSIX "aix" +# elif defined(__FreeBSD__) +# define LZO_OS_POSIX_FREEBSD 1 +# define LZO_INFO_OS_POSIX "freebsd" +# elif defined(__hpux__) || defined(__hpux) +# define LZO_OS_POSIX_HPUX 1 +# define LZO_INFO_OS_POSIX "hpux" +# elif defined(__INTERIX) +# define LZO_OS_POSIX_INTERIX 1 +# define LZO_INFO_OS_POSIX "interix" +# elif defined(__IRIX__) || defined(__irix__) +# define LZO_OS_POSIX_IRIX 1 +# define LZO_INFO_OS_POSIX "irix" +# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) +# define LZO_OS_POSIX_LINUX 1 +# define LZO_INFO_OS_POSIX "linux" +# elif defined(__APPLE__) && defined(__MACH__) +# if ((__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__-0) >= 20000) +# define LZO_OS_POSIX_DARWIN 1040 +# define LZO_INFO_OS_POSIX "darwin_iphone" +# elif ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) >= 1040) +# define LZO_OS_POSIX_DARWIN __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ +# define LZO_INFO_OS_POSIX "darwin" +# else +# define LZO_OS_POSIX_DARWIN 1 +# define LZO_INFO_OS_POSIX "darwin" +# endif +# define LZO_OS_POSIX_MACOSX LZO_OS_POSIX_DARWIN +# elif defined(__minix__) || defined(__minix) +# define LZO_OS_POSIX_MINIX 1 +# define LZO_INFO_OS_POSIX "minix" +# elif defined(__NetBSD__) +# define LZO_OS_POSIX_NETBSD 1 +# define LZO_INFO_OS_POSIX "netbsd" +# elif defined(__OpenBSD__) +# define LZO_OS_POSIX_OPENBSD 1 +# define LZO_INFO_OS_POSIX "openbsd" +# elif defined(__osf__) +# define LZO_OS_POSIX_OSF 1 +# define LZO_INFO_OS_POSIX "osf" +# elif defined(__solaris__) || defined(__sun) +# if defined(__SVR4) || defined(__svr4__) +# define LZO_OS_POSIX_SOLARIS 1 +# define LZO_INFO_OS_POSIX "solaris" +# else +# define LZO_OS_POSIX_SUNOS 1 +# define LZO_INFO_OS_POSIX "sunos" +# endif +# elif defined(__ultrix__) || defined(__ultrix) +# define LZO_OS_POSIX_ULTRIX 1 +# define LZO_INFO_OS_POSIX "ultrix" +# elif defined(_UNICOS) +# define LZO_OS_POSIX_UNICOS 1 +# define LZO_INFO_OS_POSIX "unicos" +# else +# define LZO_OS_POSIX_UNKNOWN 1 +# define LZO_INFO_OS_POSIX "unknown" +# endif +#endif +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# if (UINT_MAX != LZO_0xffffL) +# error "unexpected configuration - check your compiler defines" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (UINT_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) +# define LZO_CC_CILLY 1 +# define LZO_INFO_CC "Cilly" +# if defined(__CILLY__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) +# define LZO_CC_SDCC 1 +# define LZO_INFO_CC "sdcc" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) +#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) +# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + (__PATHCC_MINOR__-0) * 0x100 + (__PATHCC_PATCHLEVEL__-0)) +# define LZO_INFO_CC "Pathscale C" +# define LZO_INFO_CCVER __PATHSCALE__ +# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# define LZO_CC_PATHSCALE_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# endif +#elif defined(__INTEL_COMPILER) && ((__INTEL_COMPILER-0) > 0) +# define LZO_CC_INTELC __INTEL_COMPILER +# define LZO_INFO_CC "Intel C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) +# if defined(_MSC_VER) && ((_MSC_VER-0) > 0) +# define LZO_CC_INTELC_MSC _MSC_VER +# elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# define LZO_CC_INTELC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# endif +#elif defined(__POCC__) && defined(_WIN32) +# define LZO_CC_PELLESC 1 +# define LZO_INFO_CC "Pelles C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) +#elif defined(__ARMCC_VERSION) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_ARMCC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# else +# define LZO_CC_ARMCC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100) +# endif +# define LZO_CC_ARMCC __ARMCC_VERSION +# define LZO_INFO_CC "ARM C Compiler" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__clang__) && defined(__c2__) && defined(__c2_version__) && defined(_MSC_VER) +# define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0)) +# define LZO_CC_CLANG_C2 _MSC_VER +# define LZO_CC_CLANG_VENDOR_MICROSOFT 1 +# define LZO_INFO_CC "clang/c2" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__c2_version__) +#elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__) +# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +# define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0)) +# else +# define LZO_CC_CLANG 0x010000L +# endif +# if defined(_MSC_VER) && ((_MSC_VER-0) > 0) +# define LZO_CC_CLANG_MSC _MSC_VER +# elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# endif +# if defined(__APPLE_CC__) +# define LZO_CC_CLANG_VENDOR_APPLE 1 +# define LZO_INFO_CC "clang/apple" +# else +# define LZO_CC_CLANG_VENDOR_LLVM 1 +# define LZO_INFO_CC "clang" +# endif +# if defined(__clang_version__) +# define LZO_INFO_CCVER __clang_version__ +# else +# define LZO_INFO_CCVER __VERSION__ +# endif +#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# else +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100) +# endif +# define LZO_CC_LLVM LZO_CC_LLVM_GNUC +# define LZO_INFO_CC "llvm-gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__ACK__) && defined(_ACK) +# define LZO_CC_ACK 1 +# define LZO_INFO_CC "Amsterdam Compiler Kit C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__ARMCC_VERSION) && !defined(__GNUC__) +# define LZO_CC_ARMCC __ARMCC_VERSION +# define LZO_CC_ARMCC_ARMCC __ARMCC_VERSION +# define LZO_INFO_CC "ARM C Compiler" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ARMCC_VERSION) +#elif defined(__AZTEC_C__) +# define LZO_CC_AZTECC 1 +# define LZO_INFO_CC "Aztec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__CODEGEARC__) +# define LZO_CC_CODEGEARC 1 +# define LZO_INFO_CC "CodeGear C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) +#elif defined(__BORLANDC__) +# define LZO_CC_BORLANDC 1 +# define LZO_INFO_CC "Borland C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) +#elif defined(_CRAYC) && defined(_RELEASE) +# define LZO_CC_CRAYC 1 +# define LZO_INFO_CC "Cray C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) +#elif defined(__DMC__) && defined(__SC__) +# define LZO_CC_DMC 1 +# define LZO_INFO_CC "Digital Mars C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) +#elif defined(__DECC) +# define LZO_CC_DECC 1 +# define LZO_INFO_CC "DEC C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) +#elif (defined(__ghs) || defined(__ghs__)) && defined(__GHS_VERSION_NUMBER) && ((__GHS_VERSION_NUMBER-0) > 0) +# define LZO_CC_GHS 1 +# define LZO_INFO_CC "Green Hills C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__GHS_VERSION_NUMBER) +# if defined(_MSC_VER) && ((_MSC_VER-0) > 0) +# define LZO_CC_GHS_MSC _MSC_VER +# elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# define LZO_CC_GHS_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# endif +#elif defined(__HIGHC__) +# define LZO_CC_HIGHC 1 +# define LZO_INFO_CC "MetaWare High C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__HP_aCC) && ((__HP_aCC-0) > 0) +# define LZO_CC_HPACC __HP_aCC +# define LZO_INFO_CC "HP aCC" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__HP_aCC) +#elif defined(__IAR_SYSTEMS_ICC__) +# define LZO_CC_IARC 1 +# define LZO_INFO_CC "IAR C" +# if defined(__VER__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__IBMC__) && ((__IBMC__-0) > 0) +# define LZO_CC_IBMC __IBMC__ +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) +#elif defined(__IBMCPP__) && ((__IBMCPP__-0) > 0) +# define LZO_CC_IBMC __IBMCPP__ +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMCPP__) +#elif defined(__KEIL__) && defined(__C166__) +# define LZO_CC_KEILC 1 +# define LZO_INFO_CC "Keil C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) +#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) +# define LZO_CC_LCCWIN32 1 +# define LZO_INFO_CC "lcc-win32" +# define LZO_INFO_CCVER "unknown" +#elif defined(__LCC__) +# define LZO_CC_LCC 1 +# define LZO_INFO_CC "lcc" +# if defined(__LCC_VERSION__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__MWERKS__) && ((__MWERKS__-0) > 0) +# define LZO_CC_MWERKS __MWERKS__ +# define LZO_INFO_CC "Metrowerks C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) +#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) +# define LZO_CC_NDPC 1 +# define LZO_INFO_CC "Microway NDP C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PACIFIC__) +# define LZO_CC_PACIFICC 1 +# define LZO_INFO_CC "Pacific C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) +#elif defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define LZO_CC_PGI (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100 + (__PGIC_PATCHLEVEL__-0)) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PGIC__) "." LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) "." LZO_PP_MACRO_EXPAND(__PGIC_PATCHLEVEL__) +# else +# define LZO_CC_PGI (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PGIC__) "." LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) ".0" +# endif +# define LZO_INFO_CC "Portland Group PGI C" +#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) +# define LZO_CC_PGI 1 +# define LZO_INFO_CC "Portland Group PGI C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PUREC__) && defined(__TOS__) +# define LZO_CC_PUREC 1 +# define LZO_INFO_CC "Pure C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) +#elif defined(__SC__) && defined(__ZTC__) +# define LZO_CC_SYMANTECC 1 +# define LZO_INFO_CC "Symantec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) +#elif defined(__SUNPRO_C) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_C-0) > 0) +# define LZO_CC_SUNPROC __SUNPRO_C +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__SUNPRO_CC) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_CC-0) > 0) +# define LZO_CC_SUNPROC __SUNPRO_CC +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__TINYC__) +# define LZO_CC_TINYC 1 +# define LZO_INFO_CC "Tiny C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) +#elif defined(__TSC__) +# define LZO_CC_TOPSPEEDC 1 +# define LZO_INFO_CC "TopSpeed C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) +#elif defined(__WATCOMC__) +# define LZO_CC_WATCOMC 1 +# define LZO_INFO_CC "Watcom C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) +#elif defined(__TURBOC__) +# define LZO_CC_TURBOC 1 +# define LZO_INFO_CC "Turbo C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) +#elif defined(__ZTC__) +# define LZO_CC_ZORTECHC 1 +# define LZO_INFO_CC "Zortech C" +# if ((__ZTC__-0) == 0x310) +# define LZO_INFO_CCVER "0x310" +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) +# endif +#elif defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# elif defined(__GNUC_MINOR__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100) +# else +# define LZO_CC_GNUC (__GNUC__ * 0x10000L) +# endif +# define LZO_INFO_CC "gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(_MSC_VER) && ((_MSC_VER-0) > 0) +# define LZO_CC_MSC _MSC_VER +# define LZO_INFO_CC "Microsoft C" +# if defined(_MSC_FULL_VER) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) +# endif +#else +# define LZO_CC_UNKNOWN 1 +# define LZO_INFO_CC "unknown" +# define LZO_INFO_CCVER "unknown" +#endif +#if (LZO_CC_GNUC) && defined(__OPEN64__) +# if defined(__OPENCC__) && defined(__OPENCC_MINOR__) && defined(__OPENCC_PATCHLEVEL__) +# define LZO_CC_OPEN64 (__OPENCC__ * 0x10000L + (__OPENCC_MINOR__-0) * 0x100 + (__OPENCC_PATCHLEVEL__-0)) +# define LZO_CC_OPEN64_GNUC LZO_CC_GNUC +# endif +#endif +#if (LZO_CC_GNUC) && defined(__PCC__) +# if defined(__PCC__) && defined(__PCC_MINOR__) && defined(__PCC_MINORMINOR__) +# define LZO_CC_PCC (__PCC__ * 0x10000L + (__PCC_MINOR__-0) * 0x100 + (__PCC_MINORMINOR__-0)) +# define LZO_CC_PCC_GNUC LZO_CC_GNUC +# endif +#endif +#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) +# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" +#endif +#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) +# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) +# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) +# define LZO_ARCH_CRAY_MPP 1 +# elif defined(_CRAY1) +# define LZO_ARCH_CRAY_PVP 1 +# endif +# endif +#endif +#if !defined(__LZO_ARCH_OVERRIDE) +#if (LZO_ARCH_GENERIC) +# define LZO_INFO_ARCH "generic" +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086 1 +# define LZO_INFO_ARCH "i086" +#elif defined(__aarch64__) || defined(_M_ARM64) +# define LZO_ARCH_ARM64 1 +# define LZO_INFO_ARCH "arm64" +#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) +# define LZO_ARCH_AMD64 1 +# define LZO_INFO_ARCH "amd64" +#elif defined(__arm__) || defined(_M_ARM) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) +# define LZO_ARCH_AVR 1 +# define LZO_INFO_ARCH "avr" +#elif defined(__avr32__) || defined(__AVR32__) +# define LZO_ARCH_AVR32 1 +# define LZO_INFO_ARCH "avr32" +#elif defined(__bfin__) +# define LZO_ARCH_BLACKFIN 1 +# define LZO_INFO_ARCH "blackfin" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) +# define LZO_ARCH_C166 1 +# define LZO_INFO_ARCH "c166" +#elif defined(__cris__) +# define LZO_ARCH_CRIS 1 +# define LZO_INFO_ARCH "cris" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) +# define LZO_ARCH_EZ80 1 +# define LZO_INFO_ARCH "ez80" +#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_ARCH_H8300 1 +# define LZO_INFO_ARCH "h8300" +#elif defined(__hppa__) || defined(__hppa) +# define LZO_ARCH_HPPA 1 +# define LZO_INFO_ARCH "hppa" +#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_CC_ZORTECHC && defined(__I86__)) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) +# define LZO_ARCH_IA64 1 +# define LZO_INFO_ARCH "ia64" +#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__m32r__) +# define LZO_ARCH_M32R 1 +# define LZO_INFO_ARCH "m32r" +#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) +# define LZO_ARCH_M68K 1 +# define LZO_INFO_ARCH "m68k" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) +# define LZO_ARCH_MCS251 1 +# define LZO_INFO_ARCH "mcs251" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) +# define LZO_ARCH_MIPS 1 +# define LZO_INFO_ARCH "mips" +#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__powerpc64__) || defined(__powerpc64) || defined(__ppc64__) || defined(__PPC64__) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__powerpc64le__) || defined(__powerpc64le) || defined(__ppc64le__) || defined(__PPC64LE__) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__riscv) +# define LZO_ARCH_RISCV 1 +# define LZO_INFO_ARCH "riscv" +#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) +# define LZO_ARCH_S390 1 +# define LZO_INFO_ARCH "s390" +#elif defined(__sh__) || defined(_M_SH) +# define LZO_ARCH_SH 1 +# define LZO_INFO_ARCH "sh" +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) +# define LZO_ARCH_SPARC 1 +# define LZO_INFO_ARCH "sparc" +#elif defined(__SPU__) +# define LZO_ARCH_SPU 1 +# define LZO_INFO_ARCH "spu" +#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) +# define LZO_ARCH_Z80 1 +# define LZO_INFO_ARCH "z80" +#elif (LZO_ARCH_CRAY_PVP) +# if defined(_CRAYSV1) +# define LZO_ARCH_CRAY_SV1 1 +# define LZO_INFO_ARCH "cray_sv1" +# elif (_ADDR64) +# define LZO_ARCH_CRAY_T90 1 +# define LZO_INFO_ARCH "cray_t90" +# elif (_ADDR32) +# define LZO_ARCH_CRAY_YMP 1 +# define LZO_INFO_ARCH "cray_ymp" +# else +# define LZO_ARCH_CRAY_XMP 1 +# define LZO_INFO_ARCH "cray_xmp" +# endif +#else +# define LZO_ARCH_UNKNOWN 1 +# define LZO_INFO_ARCH "unknown" +#endif +#endif +#if !defined(LZO_ARCH_ARM_THUMB2) +#if (LZO_ARCH_ARM) +# if defined(__thumb__) || defined(__thumb) || defined(_M_THUMB) +# if defined(__thumb2__) +# define LZO_ARCH_ARM_THUMB2 1 +# elif 1 && defined(__TARGET_ARCH_THUMB) && ((__TARGET_ARCH_THUMB)+0 >= 4) +# define LZO_ARCH_ARM_THUMB2 1 +# elif 1 && defined(_MSC_VER) && defined(_M_THUMB) && ((_M_THUMB)+0 >= 7) +# define LZO_ARCH_ARM_THUMB2 1 +# endif +# endif +#endif +#endif +#if (LZO_ARCH_ARM_THUMB2) +# undef LZO_INFO_ARCH +# define LZO_INFO_ARCH "arm_thumb2" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) +# error "FIXME - missing define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) +# error "FIXME - missing LZO_OS_WIN32 define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) +# error "FIXME - missing LZO_OS_WIN64 define for CPU architecture" +#endif +#if (LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) +# define LZO_ARCH_I086PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) +# define LZO_ARCH_I086PM 1 +#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) +# define LZO_ARCH_I086PM 1 +#endif +#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64) +# define LZO_ARCH_X64 1 +#elif (!LZO_ARCH_AMD64 && LZO_ARCH_X64) && defined(__LZO_ARCH_OVERRIDE) +# define LZO_ARCH_AMD64 1 +#endif +#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64) +# define LZO_ARCH_AARCH64 1 +#elif (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64) && defined(__LZO_ARCH_OVERRIDE) +# define LZO_ARCH_ARM64 1 +#endif +#if (LZO_ARCH_I386 && !LZO_ARCH_X86) +# define LZO_ARCH_X86 1 +#elif (!LZO_ARCH_I386 && LZO_ARCH_X86) && defined(__LZO_ARCH_OVERRIDE) +# define LZO_ARCH_I386 1 +#endif +#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64) || (!LZO_ARCH_AMD64 && LZO_ARCH_X64) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64) || (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_I086PM && !LZO_ARCH_I086) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_I086) +# if (UINT_MAX != LZO_0xffffL) +# error "unexpected configuration - check your compiler defines" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if (LZO_ARCH_I386) +# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) +# error "unexpected configuration - check your compiler defines" +# endif +# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) +# error "unexpected configuration - check your compiler defines" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if (LZO_ARCH_AMD64 || LZO_ARCH_I386) +# if !defined(LZO_TARGET_FEATURE_SSE2) +# if defined(__SSE2__) +# define LZO_TARGET_FEATURE_SSE2 1 +# elif defined(_MSC_VER) && (defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) +# define LZO_TARGET_FEATURE_SSE2 1 +# elif (LZO_CC_INTELC_MSC || LZO_CC_MSC) && defined(_M_AMD64) +# define LZO_TARGET_FEATURE_SSE2 1 +# endif +# endif +# if !defined(LZO_TARGET_FEATURE_SSSE3) +# if (LZO_TARGET_FEATURE_SSE2) +# if defined(__SSSE3__) +# define LZO_TARGET_FEATURE_SSSE3 1 +# elif defined(_MSC_VER) && defined(__AVX__) +# define LZO_TARGET_FEATURE_SSSE3 1 +# endif +# endif +# endif +# if !defined(LZO_TARGET_FEATURE_SSE4_2) +# if (LZO_TARGET_FEATURE_SSSE3) +# if defined(__SSE4_2__) +# define LZO_TARGET_FEATURE_SSE4_2 1 +# endif +# endif +# endif +# if !defined(LZO_TARGET_FEATURE_AVX) +# if (LZO_TARGET_FEATURE_SSSE3) +# if defined(__AVX__) +# define LZO_TARGET_FEATURE_AVX 1 +# endif +# endif +# endif +# if !defined(LZO_TARGET_FEATURE_AVX2) +# if (LZO_TARGET_FEATURE_AVX) +# if defined(__AVX2__) +# define LZO_TARGET_FEATURE_AVX2 1 +# endif +# endif +# endif +#endif +#if (LZO_TARGET_FEATURE_SSSE3 && !(LZO_TARGET_FEATURE_SSE2)) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_TARGET_FEATURE_SSE4_2 && !(LZO_TARGET_FEATURE_SSSE3)) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_TARGET_FEATURE_AVX && !(LZO_TARGET_FEATURE_SSSE3)) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_TARGET_FEATURE_AVX2 && !(LZO_TARGET_FEATURE_AVX)) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM) +# if !defined(LZO_TARGET_FEATURE_NEON) +# if defined(__ARM_NEON) && ((__ARM_NEON)+0) +# define LZO_TARGET_FEATURE_NEON 1 +# elif 1 && defined(__ARM_NEON__) && ((__ARM_NEON__)+0) +# define LZO_TARGET_FEATURE_NEON 1 +# elif 1 && defined(__TARGET_FEATURE_NEON) && ((__TARGET_FEATURE_NEON)+0) +# define LZO_TARGET_FEATURE_NEON 1 +# endif +# endif +#elif (LZO_ARCH_ARM64) +# if !defined(LZO_TARGET_FEATURE_NEON) +# if 1 +# define LZO_TARGET_FEATURE_NEON 1 +# endif +# endif +#endif +#if 0 +#elif !defined(__LZO_MM_OVERRIDE) +#if (LZO_ARCH_I086) +#if (UINT_MAX != LZO_0xffffL) +# error "unexpected configuration - check your compiler defines" +#endif +#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) +# define LZO_MM_TINY 1 +#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) +# define LZO_MM_HUGE 1 +#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) +# define LZO_MM_SMALL 1 +#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) +# define LZO_MM_MEDIUM 1 +#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) +# define LZO_MM_COMPACT 1 +#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) +# define LZO_MM_LARGE 1 +#elif (LZO_CC_AZTECC) +# if defined(_LARGE_CODE) && defined(_LARGE_DATA) +# define LZO_MM_LARGE 1 +# elif defined(_LARGE_CODE) +# define LZO_MM_MEDIUM 1 +# elif defined(_LARGE_DATA) +# define LZO_MM_COMPACT 1 +# else +# define LZO_MM_SMALL 1 +# endif +#elif (LZO_CC_ZORTECHC && defined(__VCM__)) +# define LZO_MM_LARGE 1 +#else +# error "unknown LZO_ARCH_I086 memory model" +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +#define LZO_HAVE_MM_HUGE_PTR 1 +#define LZO_HAVE_MM_HUGE_ARRAY 1 +#if (LZO_MM_TINY) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) +# undef LZO_HAVE_MM_HUGE_PTR +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_MSC && defined(_QC)) +# undef LZO_HAVE_MM_HUGE_ARRAY +# if (_MSC_VER < 600) +# undef LZO_HAVE_MM_HUGE_PTR +# endif +#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) +# if (LZO_OS_DOS16) +# error "unexpected configuration - check your compiler defines" +# elif (LZO_CC_ZORTECHC) +# else +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if defined(__cplusplus) +extern "C" { +#endif +#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) +# define LZO_MM_AHSHIFT 12 +#elif (LZO_CC_WATCOMC) + extern unsigned char _HShift; +# define LZO_MM_AHSHIFT ((unsigned) _HShift) +#else +# error "FIXME - implement LZO_MM_AHSHIFT" +#endif +#if defined(__cplusplus) +} +#endif +#endif +#elif (LZO_ARCH_C166) +#if !defined(__MODEL__) +# error "FIXME - LZO_ARCH_C166 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - LZO_ARCH_C166 __MODEL__" +#endif +#elif (LZO_ARCH_MCS251) +#if !defined(__MODEL__) +# error "FIXME - LZO_ARCH_MCS251 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - LZO_ARCH_MCS251 __MODEL__" +#endif +#elif (LZO_ARCH_MCS51) +#if !defined(__MODEL__) +# error "FIXME - LZO_ARCH_MCS51 __MODEL__" +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - LZO_ARCH_MCS51 __MODEL__" +#endif +#elif (LZO_ARCH_CRAY_PVP) +# define LZO_MM_PVP 1 +#else +# define LZO_MM_FLAT 1 +#endif +#if (LZO_MM_COMPACT) +# define LZO_INFO_MM "compact" +#elif (LZO_MM_FLAT) +# define LZO_INFO_MM "flat" +#elif (LZO_MM_HUGE) +# define LZO_INFO_MM "huge" +#elif (LZO_MM_LARGE) +# define LZO_INFO_MM "large" +#elif (LZO_MM_MEDIUM) +# define LZO_INFO_MM "medium" +#elif (LZO_MM_PVP) +# define LZO_INFO_MM "pvp" +#elif (LZO_MM_SMALL) +# define LZO_INFO_MM "small" +#elif (LZO_MM_TINY) +# define LZO_INFO_MM "tiny" +#else +# error "unknown memory model" +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +#if (LZO_CC_GNUC >= 0x020800ul) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_IBMC >= 600) +# define __lzo_gnuc_extension__ __extension__ +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +# define __lzo_gnuc_extension__ /*empty*/ +#endif +#if !defined(lzo_has_builtin) +#if (LZO_CC_CLANG) && defined(__has_builtin) +# define lzo_has_builtin __has_builtin +#endif +#endif +#if !defined(lzo_has_builtin) +# define lzo_has_builtin(x) 0 +#endif +#if !defined(lzo_has_attribute) +#if (LZO_CC_CLANG) && defined(__has_attribute) +# define lzo_has_attribute __has_attribute +#endif +#endif +#if !defined(lzo_has_attribute) +# define lzo_has_attribute(x) 0 +#endif +#if !defined(lzo_has_declspec_attribute) +#if (LZO_CC_CLANG) && defined(__has_declspec_attribute) +# define lzo_has_declspec_attribute __has_declspec_attribute +#endif +#endif +#if !defined(lzo_has_declspec_attribute) +# define lzo_has_declspec_attribute(x) 0 +#endif +#if !defined(lzo_has_feature) +#if (LZO_CC_CLANG) && defined(__has_feature) +# define lzo_has_feature __has_feature +#endif +#endif +#if !defined(lzo_has_feature) +# define lzo_has_feature(x) 0 +#endif +#if !defined(lzo_has_extension) +#if (LZO_CC_CLANG) && defined(__has_extension) +# define lzo_has_extension __has_extension +#elif (LZO_CC_CLANG) && defined(__has_feature) +# define lzo_has_extension __has_feature +#endif +#endif +#if !defined(lzo_has_extension) +# define lzo_has_extension(x) 0 +#endif +#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0 +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) +# define LZO_CFG_USE_NEW_STYLE_CASTS 0 +# elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1200)) +# define LZO_CFG_USE_NEW_STYLE_CASTS 0 +# else +# define LZO_CFG_USE_NEW_STYLE_CASTS 1 +# endif +#endif +#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_CFG_USE_NEW_STYLE_CASTS 0 +#endif +#if !defined(__cplusplus) +# if defined(LZO_CFG_USE_NEW_STYLE_CASTS) +# undef LZO_CFG_USE_NEW_STYLE_CASTS +# endif +# define LZO_CFG_USE_NEW_STYLE_CASTS 0 +#endif +#if !defined(LZO_REINTERPRET_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_REINTERPRET_CAST(t,e) (reinterpret_cast (e)) +# endif +#endif +#if !defined(LZO_REINTERPRET_CAST) +# define LZO_REINTERPRET_CAST(t,e) ((t) (e)) +#endif +#if !defined(LZO_STATIC_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_STATIC_CAST(t,e) (static_cast (e)) +# endif +#endif +#if !defined(LZO_STATIC_CAST) +# define LZO_STATIC_CAST(t,e) ((t) (e)) +#endif +#if !defined(LZO_STATIC_CAST2) +# define LZO_STATIC_CAST2(t1,t2,e) LZO_STATIC_CAST(t1, LZO_STATIC_CAST(t2, e)) +#endif +#if !defined(LZO_UNCONST_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_UNCONST_CAST(t,e) (const_cast (e)) +# elif (LZO_HAVE_MM_HUGE_PTR) +# define LZO_UNCONST_CAST(t,e) ((t) (e)) +# elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((lzo_uintptr_t) ((const void *) (e))))) +# endif +#endif +#if !defined(LZO_UNCONST_CAST) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((const void *) (e)))) +#endif +#if !defined(LZO_UNCONST_VOLATILE_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_UNCONST_VOLATILE_CAST(t,e) (const_cast (e)) +# elif (LZO_HAVE_MM_HUGE_PTR) +# define LZO_UNCONST_VOLATILE_CAST(t,e) ((t) (e)) +# elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_VOLATILE_CAST(t,e) ((t) ((volatile void *) ((lzo_uintptr_t) ((volatile const void *) (e))))) +# endif +#endif +#if !defined(LZO_UNCONST_VOLATILE_CAST) +# define LZO_UNCONST_VOLATILE_CAST(t,e) ((t) ((volatile void *) ((volatile const void *) (e)))) +#endif +#if !defined(LZO_UNVOLATILE_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_UNVOLATILE_CAST(t,e) (const_cast (e)) +# elif (LZO_HAVE_MM_HUGE_PTR) +# define LZO_UNVOLATILE_CAST(t,e) ((t) (e)) +# elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNVOLATILE_CAST(t,e) ((t) ((void *) ((lzo_uintptr_t) ((volatile void *) (e))))) +# endif +#endif +#if !defined(LZO_UNVOLATILE_CAST) +# define LZO_UNVOLATILE_CAST(t,e) ((t) ((void *) ((volatile void *) (e)))) +#endif +#if !defined(LZO_UNVOLATILE_CONST_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_UNVOLATILE_CONST_CAST(t,e) (const_cast (e)) +# elif (LZO_HAVE_MM_HUGE_PTR) +# define LZO_UNVOLATILE_CONST_CAST(t,e) ((t) (e)) +# elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNVOLATILE_CONST_CAST(t,e) ((t) ((const void *) ((lzo_uintptr_t) ((volatile const void *) (e))))) +# endif +#endif +#if !defined(LZO_UNVOLATILE_CONST_CAST) +# define LZO_UNVOLATILE_CONST_CAST(t,e) ((t) ((const void *) ((volatile const void *) (e)))) +#endif +#if !defined(LZO_PCAST) +# if (LZO_HAVE_MM_HUGE_PTR) +# define LZO_PCAST(t,e) ((t) (e)) +# endif +#endif +#if !defined(LZO_PCAST) +# define LZO_PCAST(t,e) LZO_STATIC_CAST(t, LZO_STATIC_CAST(void *, e)) +#endif +#if !defined(LZO_CCAST) +# if (LZO_HAVE_MM_HUGE_PTR) +# define LZO_CCAST(t,e) ((t) (e)) +# endif +#endif +#if !defined(LZO_CCAST) +# define LZO_CCAST(t,e) LZO_STATIC_CAST(t, LZO_STATIC_CAST(const void *, e)) +#endif +#if !defined(LZO_ICONV) +# define LZO_ICONV(t,e) LZO_STATIC_CAST(t, e) +#endif +#if !defined(LZO_ICAST) +# define LZO_ICAST(t,e) LZO_STATIC_CAST(t, e) +#endif +#if !defined(LZO_ITRUNC) +# define LZO_ITRUNC(t,e) LZO_STATIC_CAST(t, e) +#endif +#if !defined(__lzo_cte) +# if (LZO_CC_MSC || LZO_CC_WATCOMC) +# define __lzo_cte(e) ((void)0,(e)) +# elif 1 +# define __lzo_cte(e) ((void)0,(e)) +# endif +#endif +#if !defined(__lzo_cte) +# define __lzo_cte(e) (e) +#endif +#if !defined(LZO_BLOCK_BEGIN) +# define LZO_BLOCK_BEGIN do { +# define LZO_BLOCK_END } while __lzo_cte(0) +#endif +#if !defined(LZO_UNUSED) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030200ul)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNUSED(var) ((void) var) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_KEILC) +# define LZO_UNUSED(var) {extern int lzo_unused__[1-2*!(sizeof(var)>0)]; (void)lzo_unused__;} +# elif (LZO_CC_PACIFICC) +# define LZO_UNUSED(var) ((void) sizeof(var)) +# elif (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED(var) ((void) var) +# else +# define LZO_UNUSED(var) ((void) &var) +# endif +#endif +#if !defined(LZO_UNUSED_RESULT) +# define LZO_UNUSED_RESULT(var) LZO_UNUSED(var) +#endif +#if !defined(LZO_UNUSED_FUNC) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED_FUNC(func) ((void) func) +# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_MSC) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_KEILC || LZO_CC_PELLESC) +# define LZO_UNUSED_FUNC(func) {extern int lzo_unused__[1-2*!(sizeof((int)func)>0)]; (void)lzo_unused__;} +# else +# define LZO_UNUSED_FUNC(func) ((void) func) +# endif +#endif +#if !defined(LZO_UNUSED_LABEL) +# if (LZO_CC_CLANG >= 0x020800ul) +# define LZO_UNUSED_LABEL(l) (__lzo_gnuc_extension__ ((void) ((const void *) &&l))) +# elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) +# define LZO_UNUSED_LABEL(l) if __lzo_cte(0) goto l +# else +# define LZO_UNUSED_LABEL(l) switch (0) case 1:goto l +# endif +#endif +#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) +# if 0 +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var +# elif 0 && (LZO_CC_GNUC) +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var +# else +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init +# endif +#endif +#if !defined(__lzo_inline) +#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) +#elif defined(__cplusplus) +# define __lzo_inline inline +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L) +# define __lzo_inline inline +#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) +# define __lzo_inline __inline +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_inline __inline__ +#elif (LZO_CC_DMC) +# define __lzo_inline __inline +#elif (LZO_CC_GHS) +# define __lzo_inline __inline__ +#elif (LZO_CC_IBMC >= 600) +# define __lzo_inline __inline__ +#elif (LZO_CC_INTELC) +# define __lzo_inline __inline +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) +# define __lzo_inline __inline +#elif (LZO_CC_MSC && (_MSC_VER >= 900)) +# define __lzo_inline __inline +#elif (LZO_CC_SUNPROC >= 0x5100) +# define __lzo_inline __inline__ +#endif +#endif +#if defined(__lzo_inline) +# ifndef __lzo_HAVE_inline +# define __lzo_HAVE_inline 1 +# endif +#else +# define __lzo_inline /*empty*/ +#endif +#if !defined(__lzo_forceinline) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_IBMC >= 700) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800)) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_PGI >= 0x0d0a00ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_SUNPROC >= 0x5100) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#endif +#endif +#if defined(__lzo_forceinline) +# ifndef __lzo_HAVE_forceinline +# define __lzo_HAVE_forceinline 1 +# endif +#else +# define __lzo_forceinline __lzo_inline +#endif +#if !defined(__lzo_noinline) +#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) +# define __lzo_noinline __attribute__((__noinline__,__used__)) +#elif (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_IBMC >= 700) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800)) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) +# if defined(__cplusplus) +# else +# define __lzo_noinline __declspec(noinline) +# endif +#elif (LZO_CC_PGI >= 0x0d0a00ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_SUNPROC >= 0x5100) +# define __lzo_noinline __attribute__((__noinline__)) +#endif +#endif +#if defined(__lzo_noinline) +# ifndef __lzo_HAVE_noinline +# define __lzo_HAVE_noinline 1 +# endif +#else +# define __lzo_noinline /*empty*/ +#endif +#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) +# error "unexpected configuration - check your compiler defines" +#endif +#if !defined(__lzo_static_inline) +#if (LZO_CC_IBMC) +# define __lzo_static_inline __lzo_gnuc_extension__ static __lzo_inline +#endif +#endif +#if !defined(__lzo_static_inline) +# define __lzo_static_inline static __lzo_inline +#endif +#if !defined(__lzo_static_forceinline) +#if (LZO_CC_IBMC) +# define __lzo_static_forceinline __lzo_gnuc_extension__ static __lzo_forceinline +#endif +#endif +#if !defined(__lzo_static_forceinline) +# define __lzo_static_forceinline static __lzo_forceinline +#endif +#if !defined(__lzo_static_noinline) +#if (LZO_CC_IBMC) +# define __lzo_static_noinline __lzo_gnuc_extension__ static __lzo_noinline +#endif +#endif +#if !defined(__lzo_static_noinline) +# define __lzo_static_noinline static __lzo_noinline +#endif +#if !defined(__lzo_c99_extern_inline) +#if defined(__GNUC_GNU_INLINE__) +# define __lzo_c99_extern_inline __lzo_inline +#elif defined(__GNUC_STDC_INLINE__) +# define __lzo_c99_extern_inline extern __lzo_inline +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L) +# define __lzo_c99_extern_inline extern __lzo_inline +#endif +#if !defined(__lzo_c99_extern_inline) && (__lzo_HAVE_inline) +# define __lzo_c99_extern_inline __lzo_inline +#endif +#endif +#if defined(__lzo_c99_extern_inline) +# ifndef __lzo_HAVE_c99_extern_inline +# define __lzo_HAVE_c99_extern_inline 1 +# endif +#else +# define __lzo_c99_extern_inline /*empty*/ +#endif +#if !defined(__lzo_may_alias) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_may_alias __attribute__((__may_alias__)) +#elif (LZO_CC_CLANG >= 0x020900ul) +# define __lzo_may_alias __attribute__((__may_alias__)) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1210)) && 0 +# define __lzo_may_alias __attribute__((__may_alias__)) +#elif (LZO_CC_PGI >= 0x0d0a00ul) && 0 +# define __lzo_may_alias __attribute__((__may_alias__)) +#endif +#endif +#if defined(__lzo_may_alias) +# ifndef __lzo_HAVE_may_alias +# define __lzo_HAVE_may_alias 1 +# endif +#else +# define __lzo_may_alias /*empty*/ +#endif +#if !defined(__lzo_noreturn) +#if (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_IBMC >= 700) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600)) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_PGI >= 0x0d0a00ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#endif +#endif +#if defined(__lzo_noreturn) +# ifndef __lzo_HAVE_noreturn +# define __lzo_HAVE_noreturn 1 +# endif +#else +# define __lzo_noreturn /*empty*/ +#endif +#if !defined(__lzo_nothrow) +#if (LZO_CC_GNUC >= 0x030300ul) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 900)) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#endif +#endif +#if defined(__lzo_nothrow) +# ifndef __lzo_HAVE_nothrow +# define __lzo_HAVE_nothrow 1 +# endif +#else +# define __lzo_nothrow /*empty*/ +#endif +#if !defined(__lzo_restrict) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_IBMC >= 800) && !defined(__cplusplus) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_IBMC >= 1210) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600)) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600)) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) +# define __lzo_restrict __restrict +#elif (LZO_CC_PGI >= 0x0d0a00ul) +# define __lzo_restrict __restrict__ +#endif +#endif +#if defined(__lzo_restrict) +# ifndef __lzo_HAVE_restrict +# define __lzo_HAVE_restrict 1 +# endif +#else +# define __lzo_restrict /*empty*/ +#endif +#if !defined(__lzo_alignof) +#if (LZO_CC_ARMCC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_GHS) && !defined(__cplusplus) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_IBMC >= 600) +# define __lzo_alignof(e) (__lzo_gnuc_extension__ __alignof__(e)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_alignof(e) __alignof(e) +#elif (LZO_CC_SUNPROC >= 0x5100) +# define __lzo_alignof(e) __alignof__(e) +#endif +#endif +#if defined(__lzo_alignof) +# ifndef __lzo_HAVE_alignof +# define __lzo_HAVE_alignof 1 +# endif +#endif +#if !defined(__lzo_struct_packed) +#if (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul)) +#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul)) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus) +#elif (LZO_CC_GNUC >= 0x030400ul) && !(LZO_CC_PCC_GNUC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) +# define __lzo_struct_packed(s) struct s { +# define __lzo_struct_packed_end() } __attribute__((__gcc_struct__,__packed__)); +# define __lzo_struct_packed_ma_end() } __lzo_may_alias __attribute__((__gcc_struct__,__packed__)); +#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_struct_packed(s) struct s { +# define __lzo_struct_packed_end() } __attribute__((__packed__)); +# define __lzo_struct_packed_ma_end() } __lzo_may_alias __attribute__((__packed__)); +#elif (LZO_CC_IBMC >= 700) +# define __lzo_struct_packed(s) __lzo_gnuc_extension__ struct s { +# define __lzo_struct_packed_end() } __attribute__((__packed__)); +# define __lzo_struct_packed_ma_end() } __lzo_may_alias __attribute__((__packed__)); +#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_struct_packed(s) __pragma(pack(push,1)) struct s { +# define __lzo_struct_packed_end() } __pragma(pack(pop)); +#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900)) +# define __lzo_struct_packed(s) _Packed struct s { +# define __lzo_struct_packed_end() }; +#endif +#endif +#if defined(__lzo_struct_packed) && !defined(__lzo_struct_packed_ma) +# define __lzo_struct_packed_ma(s) __lzo_struct_packed(s) +#endif +#if defined(__lzo_struct_packed_end) && !defined(__lzo_struct_packed_ma_end) +# define __lzo_struct_packed_ma_end() __lzo_struct_packed_end() +#endif +#if !defined(__lzo_byte_struct) +#if defined(__lzo_struct_packed) +# define __lzo_byte_struct(s,n) __lzo_struct_packed(s) unsigned char a[n]; __lzo_struct_packed_end() +# define __lzo_byte_struct_ma(s,n) __lzo_struct_packed_ma(s) unsigned char a[n]; __lzo_struct_packed_ma_end() +#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_PGI || (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_byte_struct(s,n) struct s { unsigned char a[n]; } __attribute__((__packed__)); +# define __lzo_byte_struct_ma(s,n) struct s { unsigned char a[n]; } __lzo_may_alias __attribute__((__packed__)); +#endif +#endif +#if defined(__lzo_byte_struct) && !defined(__lzo_byte_struct_ma) +# define __lzo_byte_struct_ma(s,n) __lzo_byte_struct(s,n) +#endif +#if !defined(__lzo_struct_align16) && (__lzo_HAVE_alignof) +#if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul)) +#elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_CILLY || LZO_CC_PCC) +#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_struct_align16(s) struct __declspec(align(16)) s { +# define __lzo_struct_align16_end() }; +# define __lzo_struct_align32(s) struct __declspec(align(32)) s { +# define __lzo_struct_align32_end() }; +# define __lzo_struct_align64(s) struct __declspec(align(64)) s { +# define __lzo_struct_align64_end() }; +#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || (LZO_CC_IBMC >= 700) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_struct_align16(s) struct s { +# define __lzo_struct_align16_end() } __attribute__((__aligned__(16))); +# define __lzo_struct_align32(s) struct s { +# define __lzo_struct_align32_end() } __attribute__((__aligned__(32))); +# define __lzo_struct_align64(s) struct s { +# define __lzo_struct_align64_end() } __attribute__((__aligned__(64))); +#endif +#endif +#if !defined(__lzo_union_um) +#if (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul)) +#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER < 810)) +#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul)) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus) +#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_union_am(s) union s { +# define __lzo_union_am_end() } __lzo_may_alias; +# define __lzo_union_um(s) union s { +# define __lzo_union_um_end() } __lzo_may_alias __attribute__((__packed__)); +#elif (LZO_CC_IBMC >= 700) +# define __lzo_union_am(s) __lzo_gnuc_extension__ union s { +# define __lzo_union_am_end() } __lzo_may_alias; +# define __lzo_union_um(s) __lzo_gnuc_extension__ union s { +# define __lzo_union_um_end() } __lzo_may_alias __attribute__((__packed__)); +#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_union_um(s) __pragma(pack(push,1)) union s { +# define __lzo_union_um_end() } __pragma(pack(pop)); +#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900)) +# define __lzo_union_um(s) _Packed union s { +# define __lzo_union_um_end() }; +#endif +#endif +#if !defined(__lzo_union_am) +# define __lzo_union_am(s) union s { +# define __lzo_union_am_end() }; +#endif +#if !defined(__lzo_constructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_constructor __attribute__((__constructor__)) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800)) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_constructor __attribute__((__constructor__)) +#endif +#endif +#if defined(__lzo_constructor) +# ifndef __lzo_HAVE_constructor +# define __lzo_HAVE_constructor 1 +# endif +#endif +#if !defined(__lzo_destructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_destructor __attribute__((__destructor__)) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800)) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_destructor __attribute__((__destructor__)) +#endif +#endif +#if defined(__lzo_destructor) +# ifndef __lzo_HAVE_destructor +# define __lzo_HAVE_destructor 1 +# endif +#endif +#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) +# error "unexpected configuration - check your compiler defines" +#endif +#if !defined(__lzo_likely) && !defined(__lzo_unlikely) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_IBMC >= 1010) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_CLANG && LZO_CC_CLANG_C2) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#endif +#endif +#if defined(__lzo_likely) +# ifndef __lzo_HAVE_likely +# define __lzo_HAVE_likely 1 +# endif +#else +# define __lzo_likely(e) (e) +#endif +#if defined(__lzo_very_likely) +# ifndef __lzo_HAVE_very_likely +# define __lzo_HAVE_very_likely 1 +# endif +#else +# define __lzo_very_likely(e) __lzo_likely(e) +#endif +#if defined(__lzo_unlikely) +# ifndef __lzo_HAVE_unlikely +# define __lzo_HAVE_unlikely 1 +# endif +#else +# define __lzo_unlikely(e) (e) +#endif +#if defined(__lzo_very_unlikely) +# ifndef __lzo_HAVE_very_unlikely +# define __lzo_HAVE_very_unlikely 1 +# endif +#else +# define __lzo_very_unlikely(e) __lzo_unlikely(e) +#endif +#if !defined(__lzo_loop_forever) +# if (LZO_CC_IBMC) +# define __lzo_loop_forever() LZO_BLOCK_BEGIN for (;;) { ; } LZO_BLOCK_END +# else +# define __lzo_loop_forever() do { ; } while __lzo_cte(1) +# endif +#endif +#if !defined(__lzo_unreachable) +#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) && lzo_has_builtin(__builtin_unreachable) +# define __lzo_unreachable() __builtin_unreachable(); +#elif (LZO_CC_GNUC >= 0x040500ul) +# define __lzo_unreachable() __builtin_unreachable(); +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1300)) && 1 +# define __lzo_unreachable() __builtin_unreachable(); +#endif +#endif +#if defined(__lzo_unreachable) +# ifndef __lzo_HAVE_unreachable +# define __lzo_HAVE_unreachable 1 +# endif +#else +# if 0 +# define __lzo_unreachable() ((void)0); +# else +# define __lzo_unreachable() __lzo_loop_forever(); +# endif +#endif +#if !defined(lzo_unused_funcs_impl) +# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define lzo_unused_funcs_impl(r,f) static r __attribute__((__unused__)) f +# elif 1 && (LZO_CC_BORLANDC || LZO_CC_GNUC) +# define lzo_unused_funcs_impl(r,f) static r f +# else +# define lzo_unused_funcs_impl(r,f) __lzo_static_forceinline r f +# endif +#endif +#ifndef __LZO_CTA_NAME +#if (LZO_CFG_USE_COUNTER) +# define __LZO_CTA_NAME(a) LZO_PP_ECONCAT2(a,__COUNTER__) +#else +# define __LZO_CTA_NAME(a) LZO_PP_ECONCAT2(a,__LINE__) +#endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) +# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1u-2*!(e)]; LZO_EXTERN_C_END +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END +# elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020900ul)) && defined(__cplusplus) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN int __LZO_CTA_NAME(lzo_cta_f__)(int [1-2*!(e)]); LZO_EXTERN_C_END +# elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__)); LZO_EXTERN_C_END +# else +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-2*!(e)]; LZO_EXTERN_C_END +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT) +# if (LZO_CC_AZTECC) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];} +# elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030000ul)) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));} +# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__) +# define LZO_COMPILE_TIME_ASSERT(e) {(void) (0/!!(e));} +# elif (LZO_CC_GNUC >= 0x040700ul) && (LZO_CFG_USE_COUNTER) && defined(__cplusplus) +# define LZO_COMPILE_TIME_ASSERT(e) {enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__));} +# elif (LZO_CC_GNUC >= 0x040700ul) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));} +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# else +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];} +# endif +#endif +#if (LZO_LANG_ASSEMBLER) +# undef LZO_COMPILE_TIME_ASSERT_HEADER +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) /*empty*/ +#else +LZO_COMPILE_TIME_ASSERT_HEADER(1 == 1) +#if defined(__cplusplus) +extern "C" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) } +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3) +#endif +#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit /*empty*/ +# define __lzo_cdecl_main __cdecl +# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_qsort __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_qsort _stdcall +# else +# define __lzo_cdecl_qsort __cdecl +# endif +# elif (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +# else +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit __cdecl +# define __lzo_cdecl_main __cdecl +# define __lzo_cdecl_qsort __cdecl +# endif +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) +# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_sighandler __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_sighandler _stdcall +# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) +# define __lzo_cdecl_sighandler __clrcall +# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) +# if defined(_DLL) +# define __lzo_cdecl_sighandler _far _cdecl _loadds +# elif defined(_MT) +# define __lzo_cdecl_sighandler _far _cdecl +# else +# define __lzo_cdecl_sighandler _cdecl +# endif +# else +# define __lzo_cdecl_sighandler __cdecl +# endif +#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) +# define __lzo_cdecl cdecl +#endif +#if !defined(__lzo_cdecl) +# define __lzo_cdecl /*empty*/ +#endif +#if !defined(__lzo_cdecl_atexit) +# define __lzo_cdecl_atexit /*empty*/ +#endif +#if !defined(__lzo_cdecl_main) +# define __lzo_cdecl_main /*empty*/ +#endif +#if !defined(__lzo_cdecl_qsort) +# define __lzo_cdecl_qsort /*empty*/ +#endif +#if !defined(__lzo_cdecl_sighandler) +# define __lzo_cdecl_sighandler /*empty*/ +#endif +#if !defined(__lzo_cdecl_va) +# define __lzo_cdecl_va __lzo_cdecl +#endif +#if !(LZO_CFG_NO_WINDOWS_H) +#if !defined(LZO_HAVE_WINDOWS_H) +#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +# elif ((LZO_OS_WIN32 && defined(__PW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul))) +# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) +# else +# define LZO_HAVE_WINDOWS_H 1 +# endif +#endif +#endif +#endif +#define LZO_SIZEOF_CHAR 1 +#ifndef LZO_SIZEOF_SHORT +#if defined(SIZEOF_SHORT) +# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +#elif defined(__SIZEOF_SHORT__) +# define LZO_SIZEOF_SHORT (__SIZEOF_SHORT__) +#endif +#endif +#ifndef LZO_SIZEOF_INT +#if defined(SIZEOF_INT) +# define LZO_SIZEOF_INT (SIZEOF_INT) +#elif defined(__SIZEOF_INT__) +# define LZO_SIZEOF_INT (__SIZEOF_INT__) +#endif +#endif +#ifndef LZO_SIZEOF_LONG +#if defined(SIZEOF_LONG) +# define LZO_SIZEOF_LONG (SIZEOF_LONG) +#elif defined(__SIZEOF_LONG__) +# define LZO_SIZEOF_LONG (__SIZEOF_LONG__) +#endif +#endif +#ifndef LZO_SIZEOF_LONG_LONG +#if defined(SIZEOF_LONG_LONG) +# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) +#elif defined(__SIZEOF_LONG_LONG__) +# define LZO_SIZEOF_LONG_LONG (__SIZEOF_LONG_LONG__) +#endif +#endif +#ifndef LZO_SIZEOF___INT16 +#if defined(SIZEOF___INT16) +# define LZO_SIZEOF___INT16 (SIZEOF___INT16) +#endif +#endif +#ifndef LZO_SIZEOF___INT32 +#if defined(SIZEOF___INT32) +# define LZO_SIZEOF___INT32 (SIZEOF___INT32) +#endif +#endif +#ifndef LZO_SIZEOF___INT64 +#if defined(SIZEOF___INT64) +# define LZO_SIZEOF___INT64 (SIZEOF___INT64) +#endif +#endif +#ifndef LZO_SIZEOF_VOID_P +#if defined(SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) +#elif defined(__SIZEOF_POINTER__) +# define LZO_SIZEOF_VOID_P (__SIZEOF_POINTER__) +#endif +#endif +#ifndef LZO_SIZEOF_SIZE_T +#if defined(SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) +#elif defined(__SIZEOF_SIZE_T__) +# define LZO_SIZEOF_SIZE_T (__SIZEOF_SIZE_T__) +#endif +#endif +#ifndef LZO_SIZEOF_PTRDIFF_T +#if defined(SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) +#elif defined(__SIZEOF_PTRDIFF_T__) +# define LZO_SIZEOF_PTRDIFF_T (__SIZEOF_PTRDIFF_T__) +#endif +#endif +#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) +#if !defined(LZO_SIZEOF_SHORT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_SHORT 8 +# elif (USHRT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,7) == 1) +# define LZO_SIZEOF_SHORT 1 +# elif (__LZO_LSR(USHRT_MAX,15) == 1) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,31) == 1) +# define LZO_SIZEOF_SHORT 4 +# elif (__LZO_LSR(USHRT_MAX,63) == 1) +# define LZO_SIZEOF_SHORT 8 +# elif (__LZO_LSR(USHRT_MAX,127) == 1) +# define LZO_SIZEOF_SHORT 16 +# else +# error "LZO_SIZEOF_SHORT" +# endif +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SHORT == sizeof(short)) +#if !defined(LZO_SIZEOF_INT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_INT 8 +# elif (UINT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_INT 2 +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,7) == 1) +# define LZO_SIZEOF_INT 1 +# elif (__LZO_LSR(UINT_MAX,15) == 1) +# define LZO_SIZEOF_INT 2 +# elif (__LZO_LSR(UINT_MAX,31) == 1) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,63) == 1) +# define LZO_SIZEOF_INT 8 +# elif (__LZO_LSR(UINT_MAX,127) == 1) +# define LZO_SIZEOF_INT 16 +# else +# error "LZO_SIZEOF_INT" +# endif +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_INT == sizeof(int)) +#if !defined(LZO_SIZEOF_LONG) +# if (ULONG_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,7) == 1) +# define LZO_SIZEOF_LONG 1 +# elif (__LZO_LSR(ULONG_MAX,15) == 1) +# define LZO_SIZEOF_LONG 2 +# elif (__LZO_LSR(ULONG_MAX,31) == 1) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,39) == 1) +# define LZO_SIZEOF_LONG 5 +# elif (__LZO_LSR(ULONG_MAX,63) == 1) +# define LZO_SIZEOF_LONG 8 +# elif (__LZO_LSR(ULONG_MAX,127) == 1) +# define LZO_SIZEOF_LONG 16 +# else +# error "LZO_SIZEOF_LONG" +# endif +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long)) +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) +# if (LZO_CC_GNUC >= 0x030300ul) +# if ((__LONG_MAX__-0) == (__LONG_LONG_MAX__-0)) +# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG +# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) +# define LZO_SIZEOF_LONG_LONG 4 +# endif +# endif +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +#if (LZO_ARCH_I086 && LZO_CC_DMC) +#elif (LZO_CC_CILLY) && defined(__GNUC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_SIZEOF_LONG_LONG 8 +#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_OS_WIN64 || defined(_WIN64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_CC_GHS && defined(__LLONG_BIT) && ((__LLONG_BIT-0) == 64)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && ((_INTEGRAL_MAX_BITS-0) == 64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (defined(__vms) || defined(__VMS)) && ((__INITIAL_POINTER_SIZE-0) == 64) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) +#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define LZO_SIZEOF_LONG_LONG 8 +#endif +#endif +#endif +#if defined(__cplusplus) && (LZO_CC_GNUC) +# if (LZO_CC_GNUC < 0x020800ul) +# undef LZO_SIZEOF_LONG_LONG +# endif +#endif +#if (LZO_CFG_NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#elif defined(__NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#elif defined(_NO_LONGLONG) +# undef LZO_SIZEOF_LONG_LONG +#endif +#if !defined(LZO_WORDSIZE) +#if (LZO_ARCH_ALPHA) +# define LZO_WORDSIZE 8 +#elif (LZO_ARCH_AMD64) +# define LZO_WORDSIZE 8 +#elif (LZO_ARCH_ARM64) +# define LZO_WORDSIZE 8 +#elif (LZO_ARCH_AVR) +# define LZO_WORDSIZE 1 +#elif (LZO_ARCH_H8300) +# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_WORDSIZE 4 +# else +# define LZO_WORDSIZE 2 +# endif +#elif (LZO_ARCH_I086) +# define LZO_WORDSIZE 2 +#elif (LZO_ARCH_IA64) +# define LZO_WORDSIZE 8 +#elif (LZO_ARCH_M16C) +# define LZO_WORDSIZE 2 +#elif (LZO_ARCH_SPU) +# define LZO_WORDSIZE 4 +#elif (LZO_ARCH_Z80) +# define LZO_WORDSIZE 1 +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_WORDSIZE 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) +# define LZO_WORDSIZE 8 +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_WORDSIZE 8 +#endif +#endif +#if !defined(LZO_SIZEOF_VOID_P) +#if defined(__ILP32__) || defined(__ILP32) || defined(_ILP32) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) == 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4) +# define LZO_SIZEOF_VOID_P 4 +#elif defined(__ILP64__) || defined(__ILP64) || defined(_ILP64) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) == 8) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8) +# define LZO_SIZEOF_VOID_P 8 +#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4) +# define LZO_SIZEOF_VOID_P 8 +#elif defined(__LP64__) || defined(__LP64) || defined(_LP64) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8) +# define LZO_SIZEOF_VOID_P 8 +#elif (LZO_ARCH_AVR) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_H8300) +# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) + LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 4) +# if defined(__NORMAL_MODE__) +# define LZO_SIZEOF_VOID_P 2 +# else +# define LZO_SIZEOF_VOID_P 4 +# endif +# else + LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 2) +# define LZO_SIZEOF_VOID_P 2 +# endif +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT +# endif +#elif (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) +# define LZO_SIZEOF_VOID_P 2 +# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) +# define LZO_SIZEOF_VOID_P 4 +# else +# error "invalid LZO_ARCH_I086 memory model" +# endif +#elif (LZO_ARCH_M16C) +# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) +# define LZO_SIZEOF_VOID_P 4 +# else +# define LZO_SIZEOF_VOID_P 2 +# endif +#elif (LZO_ARCH_SPU) +# define LZO_SIZEOF_VOID_P 4 +#elif (LZO_ARCH_Z80) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_SIZEOF_VOID_P 4 +#elif (LZO_OS_OS400 || defined(__OS400__)) +# if defined(__LLP64_IFC__) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +# else +# define LZO_SIZEOF_VOID_P 16 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +# endif +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#endif +#endif +#if !defined(LZO_SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_VOID_P == sizeof(void *)) +#if !defined(LZO_SIZEOF_SIZE_T) +#if (LZO_ARCH_I086 || LZO_ARCH_M16C) +# define LZO_SIZEOF_SIZE_T 2 +#endif +#endif +#if !defined(LZO_SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P +#endif +#if defined(offsetof) +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SIZE_T == sizeof(size_t)) +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +#if (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P +# elif (LZO_MM_COMPACT || LZO_MM_LARGE) +# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) +# define LZO_SIZEOF_PTRDIFF_T 4 +# else +# define LZO_SIZEOF_PTRDIFF_T 2 +# endif +# else +# error "invalid LZO_ARCH_I086 memory model" +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T +#endif +#if defined(offsetof) +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) +#endif +#if !defined(LZO_WORDSIZE) +# define LZO_WORDSIZE LZO_SIZEOF_VOID_P +#endif +#if (LZO_ABI_NEUTRAL_ENDIAN) +# undef LZO_ABI_BIG_ENDIAN +# undef LZO_ABI_LITTLE_ENDIAN +#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) +# define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430 || LZO_ARCH_RISCV) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) +# if (__LITTLE_ENDIAN__ == 1) +# define LZO_ABI_LITTLE_ENDIAN 1 +# else +# define LZO_ABI_BIG_ENDIAN 1 +# endif +#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(_MSC_VER) && defined(_WIN32) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC) +# if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) +# error "unexpected configuration - check your compiler defines" +# elif defined(__BIG_ENDIAN) +# define LZO_ABI_BIG_ENDIAN 1 +# else +# define LZO_ABI_LITTLE_ENDIAN 1 +# endif +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM64) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM64) && defined(_MSC_VER) && defined(_WIN32) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#endif +#endif +#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ABI_BIG_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "be" +#elif (LZO_ABI_LITTLE_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "le" +#elif (LZO_ABI_NEUTRAL_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "neutral" +#endif +#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_I8LP16 1 +# define LZO_INFO_ABI_PM "i8lp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_ILP16 1 +# define LZO_INFO_ABI_PM "ilp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_LP32 1 +# define LZO_INFO_ABI_PM "lp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_ILP32 1 +# define LZO_INFO_ABI_PM "ilp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) +# define LZO_ABI_LLP64 1 +# define LZO_INFO_ABI_PM "llp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_LP64 1 +# define LZO_INFO_ABI_PM "lp64" +#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_ILP64 1 +# define LZO_INFO_ABI_PM "ilp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_IP32L64 1 +# define LZO_INFO_ABI_PM "ip32l64" +#endif +#if (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_VOID_P == 4 && LZO_WORDSIZE == 8) +# define LZO_ABI_IP32W64 1 +# ifndef LZO_INFO_ABI_PM +# define LZO_INFO_ABI_PM "ip32w64" +# endif +#endif +#if 0 +#elif !defined(__LZO_LIBC_OVERRIDE) +#if (LZO_LIBC_NAKED) +# define LZO_INFO_LIBC "naked" +#elif (LZO_LIBC_FREESTANDING) +# define LZO_INFO_LIBC "freestanding" +#elif (LZO_LIBC_MOSTLY_FREESTANDING) +# define LZO_INFO_LIBC "mfreestanding" +#elif (LZO_LIBC_ISOC90) +# define LZO_INFO_LIBC "isoc90" +#elif (LZO_LIBC_ISOC99) +# define LZO_INFO_LIBC "isoc99" +#elif (LZO_CC_ARMCC_ARMCC) && defined(__ARMCLIB_VERSION) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#elif defined(__dietlibc__) +# define LZO_LIBC_DIETLIBC 1 +# define LZO_INFO_LIBC "dietlibc" +#elif defined(_NEWLIB_VERSION) +# define LZO_LIBC_NEWLIB 1 +# define LZO_INFO_LIBC "newlib" +#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) +# if defined(__UCLIBC_SUBLEVEL__) +# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + (__UCLIBC_MINOR__-0) * 0x100 + (__UCLIBC_SUBLEVEL__-0)) +# else +# define LZO_LIBC_UCLIBC 0x00090bL +# endif +# define LZO_INFO_LIBC "uc" "libc" +#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) +# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + (__GLIBC_MINOR__-0) * 0x100) +# define LZO_INFO_LIBC "glibc" +#elif (LZO_CC_MWERKS) && defined(__MSL__) +# define LZO_LIBC_MSL __MSL__ +# define LZO_INFO_LIBC "msl" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#else +# define LZO_LIBC_DEFAULT 1 +# define LZO_INFO_LIBC "default" +#endif +#endif +#if (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +# define LZO_ASM_SYNTAX_MSC 1 +#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) +#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_CC_GNUC) +# define LZO_ASM_SYNTAX_GNUC 1 +#endif +#if (LZO_ASM_SYNTAX_GNUC) +#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) +# define __LZO_ASM_CLOBBER "ax" +# define __LZO_ASM_CLOBBER_LIST_CC /*empty*/ +# define __LZO_ASM_CLOBBER_LIST_CC_MEMORY /*empty*/ +# define __LZO_ASM_CLOBBER_LIST_EMPTY /*empty*/ +#elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1000)) +# define __LZO_ASM_CLOBBER "memory" +# define __LZO_ASM_CLOBBER_LIST_CC /*empty*/ +# define __LZO_ASM_CLOBBER_LIST_CC_MEMORY : "memory" +# define __LZO_ASM_CLOBBER_LIST_EMPTY /*empty*/ +#else +# define __LZO_ASM_CLOBBER "cc", "memory" +# define __LZO_ASM_CLOBBER_LIST_CC : "cc" +# define __LZO_ASM_CLOBBER_LIST_CC_MEMORY : "cc", "memory" +# define __LZO_ASM_CLOBBER_LIST_EMPTY /*empty*/ +#endif +#endif +#if (LZO_ARCH_ALPHA) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_AMD64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_ARM) +# if defined(__ARM_FEATURE_UNALIGNED) +# if ((__ARM_FEATURE_UNALIGNED)+0) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# endif +# elif 1 && (LZO_ARCH_ARM_THUMB2) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# elif 1 && defined(__ARM_ARCH) && ((__ARM_ARCH)+0 >= 7) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 7) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 6) && (defined(__TARGET_PROFILE_A) || defined(__TARGET_PROFILE_R)) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# elif 1 && defined(_MSC_VER) && defined(_M_ARM) && ((_M_ARM)+0 >= 7) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# endif +#elif (LZO_ARCH_ARM64) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_CRIS) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_I386) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_IA64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_PREFER_POSTINC 1 +#elif (LZO_ARCH_M68K) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(__mc68020__) && !defined(__mcoldfire__) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# endif +#elif (LZO_ARCH_MIPS) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_POWERPC) +# define LZO_OPT_PREFER_PREINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if (LZO_ABI_BIG_ENDIAN) || (LZO_WORDSIZE == 8) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# if (LZO_WORDSIZE == 8) +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +# endif +# endif +#elif (LZO_ARCH_RISCV) +# define LZO_OPT_AVOID_UINT_INDEX 1 +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# if (LZO_WORDSIZE == 8) +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +# endif +#elif (LZO_ARCH_S390) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# if (LZO_WORDSIZE == 8) +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +# endif +#elif (LZO_ARCH_SH) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +#endif +#ifndef LZO_CFG_NO_INLINE_ASM +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) +# define LZO_CFG_NO_INLINE_ASM 1 +#elif (LZO_CC_LLVM) +# define LZO_CFG_NO_INLINE_ASM 1 +#endif +#endif +#if (LZO_CFG_NO_INLINE_ASM) +# undef LZO_ASM_SYNTAX_MSC +# undef LZO_ASM_SYNTAX_GNUC +# undef __LZO_ASM_CLOBBER +# undef __LZO_ASM_CLOBBER_LIST_CC +# undef __LZO_ASM_CLOBBER_LIST_CC_MEMORY +# undef __LZO_ASM_CLOBBER_LIST_EMPTY +#endif +#ifndef LZO_CFG_NO_UNALIGNED +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) +# define LZO_CFG_NO_UNALIGNED 1 +#endif +#endif +#if (LZO_CFG_NO_UNALIGNED) +# undef LZO_OPT_UNALIGNED16 +# undef LZO_OPT_UNALIGNED32 +# undef LZO_OPT_UNALIGNED64 +#endif +#if defined(__LZO_INFOSTR_MM) +#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) +# define __LZO_INFOSTR_MM "" +#elif defined(LZO_INFO_MM) +# define __LZO_INFOSTR_MM "." LZO_INFO_MM +#else +# define __LZO_INFOSTR_MM "" +#endif +#if defined(__LZO_INFOSTR_PM) +#elif defined(LZO_INFO_ABI_PM) +# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM +#else +# define __LZO_INFOSTR_PM "" +#endif +#if defined(__LZO_INFOSTR_ENDIAN) +#elif defined(LZO_INFO_ABI_ENDIAN) +# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN +#else +# define __LZO_INFOSTR_ENDIAN "" +#endif +#if defined(__LZO_INFOSTR_OSNAME) +#elif defined(LZO_INFO_OS_CONSOLE) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE +#elif defined(LZO_INFO_OS_POSIX) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX +#else +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS +#endif +#if defined(__LZO_INFOSTR_LIBC) +#elif defined(LZO_INFO_LIBC) +# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC +#else +# define __LZO_INFOSTR_LIBC "" +#endif +#if defined(__LZO_INFOSTR_CCVER) +#elif defined(LZO_INFO_CCVER) +# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER +#else +# define __LZO_INFOSTR_CCVER "" +#endif +#define LZO_INFO_STRING \ + LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ + " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER +#if !(LZO_CFG_SKIP_LZO_TYPES) +#if (!(LZO_SIZEOF_SHORT+0 > 0 && LZO_SIZEOF_INT+0 > 0 && LZO_SIZEOF_LONG+0 > 0)) +# error "missing defines for sizes" +#endif +#if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0)) +# error "missing defines for sizes" +#endif +#define LZO_TYPEOF_CHAR 1u +#define LZO_TYPEOF_SHORT 2u +#define LZO_TYPEOF_INT 3u +#define LZO_TYPEOF_LONG 4u +#define LZO_TYPEOF_LONG_LONG 5u +#define LZO_TYPEOF___INT8 17u +#define LZO_TYPEOF___INT16 18u +#define LZO_TYPEOF___INT32 19u +#define LZO_TYPEOF___INT64 20u +#define LZO_TYPEOF___INT128 21u +#define LZO_TYPEOF___INT256 22u +#define LZO_TYPEOF___MODE_QI 33u +#define LZO_TYPEOF___MODE_HI 34u +#define LZO_TYPEOF___MODE_SI 35u +#define LZO_TYPEOF___MODE_DI 36u +#define LZO_TYPEOF___MODE_TI 37u +#define LZO_TYPEOF_CHAR_P 129u +#if !defined(lzo_llong_t) +#if (LZO_SIZEOF_LONG_LONG+0 > 0) +# if !(LZO_LANG_ASSEMBLER) + __lzo_gnuc_extension__ typedef long long lzo_llong_t__; + __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; +# endif +# define lzo_llong_t lzo_llong_t__ +# define lzo_ullong_t lzo_ullong_t__ +#endif +#endif +#if !defined(lzo_int16e_t) +#if (LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) && (LZO_SIZEOF_SHORT != 2) +# undef LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T +#endif +#if (LZO_SIZEOF_LONG == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) +# define lzo_int16e_t long +# define lzo_uint16e_t unsigned long +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG +#elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) +# define lzo_int16e_t int +# define lzo_uint16e_t unsigned int +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_SHORT == 2) +# define lzo_int16e_t short int +# define lzo_uint16e_t unsigned short int +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_SHORT +#elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) +# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__))); + typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__))); +# endif +# define lzo_int16e_t lzo_int16e_hi_t__ +# define lzo_uint16e_t lzo_uint16e_hi_t__ +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI +#elif (LZO_SIZEOF___INT16 == 2) +# define lzo_int16e_t __int16 +# define lzo_uint16e_t unsigned __int16 +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16 +#else +#endif +#endif +#if defined(lzo_int16e_t) +# define LZO_SIZEOF_LZO_INT16E_T 2 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == 2) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T) +#endif +#if !defined(lzo_int32e_t) +#if (LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) && (LZO_SIZEOF_INT != 4) +# undef LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T +#endif +#if (LZO_SIZEOF_LONG == 4) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) +# define lzo_int32e_t long int +# define lzo_uint32e_t unsigned long int +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG +#elif (LZO_SIZEOF_INT == 4) +# define lzo_int32e_t int +# define lzo_uint32e_t unsigned int +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_SHORT == 4) +# define lzo_int32e_t short int +# define lzo_uint32e_t unsigned short int +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_SHORT +#elif (LZO_SIZEOF_LONG_LONG == 4) +# define lzo_int32e_t lzo_llong_t +# define lzo_uint32e_t lzo_ullong_t +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG_LONG +#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L) +# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); + typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); +# endif +# define lzo_int32e_t lzo_int32e_si_t__ +# define lzo_uint32e_t lzo_uint32e_si_t__ +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI +#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L) +# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); + typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); +# endif +# define lzo_int32e_t lzo_int32e_si_t__ +# define lzo_uint32e_t lzo_uint32e_si_t__ +# define LZO_INT32_C(c) (c##LL) +# define LZO_UINT32_C(c) (c##ULL) +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI +#elif (LZO_SIZEOF___INT32 == 4) +# define lzo_int32e_t __int32 +# define lzo_uint32e_t unsigned __int32 +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32 +#else +#endif +#endif +#if defined(lzo_int32e_t) +# define LZO_SIZEOF_LZO_INT32E_T 4 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == LZO_SIZEOF_LZO_INT32E_T) +#endif +#if !defined(lzo_int64e_t) +#if (LZO_SIZEOF___INT64 == 8) +# if (LZO_CC_BORLANDC) && !defined(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T) +# define LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T LZO_TYPEOF___INT64 +# endif +#endif +#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && (LZO_SIZEOF_LONG_LONG != 8) +# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T +#endif +#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) && (LZO_SIZEOF___INT64 != 8) +# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T +#endif +#if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) +# define lzo_int64e_t int +# define lzo_uint64e_t unsigned int +# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) +# define lzo_int64e_t long int +# define lzo_uint64e_t unsigned long int +# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG +#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) +# define lzo_int64e_t lzo_llong_t +# define lzo_uint64e_t lzo_ullong_t +# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG_LONG +# if (LZO_CC_BORLANDC) +# define LZO_INT64_C(c) ((c) + 0ll) +# define LZO_UINT64_C(c) ((c) + 0ull) +# elif 0 +# define LZO_INT64_C(c) (__lzo_gnuc_extension__ (c##LL)) +# define LZO_UINT64_C(c) (__lzo_gnuc_extension__ (c##ULL)) +# else +# define LZO_INT64_C(c) (c##LL) +# define LZO_UINT64_C(c) (c##ULL) +# endif +#elif (LZO_SIZEOF___INT64 == 8) +# define lzo_int64e_t __int64 +# define lzo_uint64e_t unsigned __int64 +# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF___INT64 +# if (LZO_CC_BORLANDC) +# define LZO_INT64_C(c) ((c) + 0i64) +# define LZO_UINT64_C(c) ((c) + 0ui64) +# else +# define LZO_INT64_C(c) (c##i64) +# define LZO_UINT64_C(c) (c##ui64) +# endif +#else +#endif +#endif +#if defined(lzo_int64e_t) +# define LZO_SIZEOF_LZO_INT64E_T 8 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T) +#endif +#if !defined(lzo_int32l_t) +#if defined(lzo_int32e_t) +# define lzo_int32l_t lzo_int32e_t +# define lzo_uint32l_t lzo_uint32e_t +# define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LZO_INT32E_T +# define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T +#elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) +# define lzo_int32l_t int +# define lzo_uint32l_t unsigned int +# define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT +# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT +#elif (LZO_SIZEOF_LONG >= 4) +# define lzo_int32l_t long int +# define lzo_uint32l_t unsigned long int +# define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LONG +# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_LONG +#else +# error "lzo_int32l_t" +#endif +#endif +#if 1 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) >= 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) == LZO_SIZEOF_LZO_INT32L_T) +#endif +#if !defined(lzo_int64l_t) +#if defined(lzo_int64e_t) +# define lzo_int64l_t lzo_int64e_t +# define lzo_uint64l_t lzo_uint64e_t +# define LZO_SIZEOF_LZO_INT64L_T LZO_SIZEOF_LZO_INT64E_T +# define LZO_TYPEOF_LZO_INT64L_T LZO_TYPEOF_LZO_INT64E_T +#else +#endif +#endif +#if defined(lzo_int64l_t) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) >= 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) == LZO_SIZEOF_LZO_INT64L_T) +#endif +#if !defined(lzo_int32f_t) +#if (LZO_SIZEOF_SIZE_T >= 8) +# define lzo_int32f_t lzo_int64l_t +# define lzo_uint32f_t lzo_uint64l_t +# define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT64L_T +# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT64L_T +#else +# define lzo_int32f_t lzo_int32l_t +# define lzo_uint32f_t lzo_uint32l_t +# define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT32L_T +# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT32L_T +#endif +#endif +#if 1 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) >= 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) == LZO_SIZEOF_LZO_INT32F_T) +#endif +#if !defined(lzo_int64f_t) +#if defined(lzo_int64l_t) +# define lzo_int64f_t lzo_int64l_t +# define lzo_uint64f_t lzo_uint64l_t +# define LZO_SIZEOF_LZO_INT64F_T LZO_SIZEOF_LZO_INT64L_T +# define LZO_TYPEOF_LZO_INT64F_T LZO_TYPEOF_LZO_INT64L_T +#else +#endif +#endif +#if defined(lzo_int64f_t) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) >= 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) == LZO_SIZEOF_LZO_INT64F_T) +#endif +#if !defined(lzo_intptr_t) +#if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16)) +# define __LZO_INTPTR_T_IS_POINTER 1 +# if !(LZO_LANG_ASSEMBLER) + typedef char * lzo_intptr_t; + typedef char * lzo_uintptr_t; +# endif +# define lzo_intptr_t lzo_intptr_t +# define lzo_uintptr_t lzo_uintptr_t +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_VOID_P +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_CHAR_P +#elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4)) +# if !(LZO_LANG_ASSEMBLER) + typedef __w64 int lzo_intptr_t; + typedef __w64 unsigned int lzo_uintptr_t; +# endif +# define lzo_intptr_t lzo_intptr_t +# define lzo_uintptr_t lzo_uintptr_t +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P) +# define lzo_intptr_t short +# define lzo_uintptr_t unsigned short +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_SHORT +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT +#elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) +# define lzo_intptr_t int +# define lzo_uintptr_t unsigned int +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P) +# define lzo_intptr_t long +# define lzo_uintptr_t unsigned long +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LONG +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LONG +#elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P) +# define lzo_intptr_t lzo_int64l_t +# define lzo_uintptr_t lzo_uint64l_t +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LZO_INT64L_T +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LZO_INT64L_T +#else +# error "lzo_intptr_t" +#endif +#endif +#if 1 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) >= sizeof(void *)) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) == sizeof(lzo_uintptr_t)) +#endif +#if !defined(lzo_word_t) +#if defined(LZO_WORDSIZE) && (LZO_WORDSIZE+0 > 0) +#if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER) +# define lzo_word_t lzo_uintptr_t +# define lzo_sword_t lzo_intptr_t +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LZO_INTPTR_T +#elif (LZO_WORDSIZE == LZO_SIZEOF_LONG) +# define lzo_word_t unsigned long +# define lzo_sword_t long +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG +#elif (LZO_WORDSIZE == LZO_SIZEOF_INT) +# define lzo_word_t unsigned int +# define lzo_sword_t int +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT +#elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT) +# define lzo_word_t unsigned short +# define lzo_sword_t short +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_SHORT +#elif (LZO_WORDSIZE == 1) +# define lzo_word_t unsigned char +# define lzo_sword_t signed char +# define LZO_SIZEOF_LZO_WORD_T 1 +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_CHAR +#elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T) +# define lzo_word_t lzo_uint64l_t +# define lzo_sword_t lzo_int64l_t +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T +# define LZO_TYPEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T +#elif (LZO_ARCH_SPU) && (LZO_CC_GNUC) +#if 0 +# if !(LZO_LANG_ASSEMBLER) + typedef unsigned lzo_word_t __attribute__((__mode__(__V16QI__))); + typedef int lzo_sword_t __attribute__((__mode__(__V16QI__))); +# endif +# define lzo_word_t lzo_word_t +# define lzo_sword_t lzo_sword_t +# define LZO_SIZEOF_LZO_WORD_T 16 +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF___MODE_V16QI +#endif +#else +# error "lzo_word_t" +#endif +#endif +#endif +#if 1 && defined(lzo_word_t) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_word_t) == LZO_WORDSIZE) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_sword_t) == LZO_WORDSIZE) +#endif +#if 1 +#define lzo_int8_t signed char +#define lzo_uint8_t unsigned char +#define LZO_SIZEOF_LZO_INT8_T 1 +#define LZO_TYPEOF_LZO_INT8_T LZO_TYPEOF_CHAR +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t)) +#endif +#if defined(lzo_int16e_t) +#define lzo_int16_t lzo_int16e_t +#define lzo_uint16_t lzo_uint16e_t +#define LZO_SIZEOF_LZO_INT16_T LZO_SIZEOF_LZO_INT16E_T +#define LZO_TYPEOF_LZO_INT16_T LZO_TYPEOF_LZO_INT16E_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t)) +#endif +#if defined(lzo_int32e_t) +#define lzo_int32_t lzo_int32e_t +#define lzo_uint32_t lzo_uint32e_t +#define LZO_SIZEOF_LZO_INT32_T LZO_SIZEOF_LZO_INT32E_T +#define LZO_TYPEOF_LZO_INT32_T LZO_TYPEOF_LZO_INT32E_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t)) +#endif +#if defined(lzo_int64e_t) +#define lzo_int64_t lzo_int64e_t +#define lzo_uint64_t lzo_uint64e_t +#define LZO_SIZEOF_LZO_INT64_T LZO_SIZEOF_LZO_INT64E_T +#define LZO_TYPEOF_LZO_INT64_T LZO_TYPEOF_LZO_INT64E_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t)) +#endif +#if 1 +#define lzo_int_least32_t lzo_int32l_t +#define lzo_uint_least32_t lzo_uint32l_t +#define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T +#define LZO_TYPEOF_LZO_INT_LEAST32_T LZO_TYPEOF_LZO_INT32L_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t)) +#endif +#if defined(lzo_int64l_t) +#define lzo_int_least64_t lzo_int64l_t +#define lzo_uint_least64_t lzo_uint64l_t +#define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T +#define LZO_TYPEOF_LZO_INT_LEAST64_T LZO_TYPEOF_LZO_INT64L_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t)) +#endif +#if 1 +#define lzo_int_fast32_t lzo_int32f_t +#define lzo_uint_fast32_t lzo_uint32f_t +#define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T +#define LZO_TYPEOF_LZO_INT_FAST32_T LZO_TYPEOF_LZO_INT32F_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t)) +#endif +#if defined(lzo_int64f_t) +#define lzo_int_fast64_t lzo_int64f_t +#define lzo_uint_fast64_t lzo_uint64f_t +#define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T +#define LZO_TYPEOF_LZO_INT_FAST64_T LZO_TYPEOF_LZO_INT64F_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t)) +#endif +#if !defined(LZO_INT16_C) +# if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 2) +# define LZO_INT16_C(c) ((c) + 0) +# define LZO_UINT16_C(c) ((c) + 0U) +# elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 2) +# define LZO_INT16_C(c) ((c) + 0L) +# define LZO_UINT16_C(c) ((c) + 0UL) +# elif (LZO_SIZEOF_INT >= 2) +# define LZO_INT16_C(c) (c) +# define LZO_UINT16_C(c) (c##U) +# elif (LZO_SIZEOF_LONG >= 2) +# define LZO_INT16_C(c) (c##L) +# define LZO_UINT16_C(c) (c##UL) +# else +# error "LZO_INT16_C" +# endif +#endif +#if !defined(LZO_INT32_C) +# if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 4) +# define LZO_INT32_C(c) ((c) + 0) +# define LZO_UINT32_C(c) ((c) + 0U) +# elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 4) +# define LZO_INT32_C(c) ((c) + 0L) +# define LZO_UINT32_C(c) ((c) + 0UL) +# elif (LZO_SIZEOF_INT >= 4) +# define LZO_INT32_C(c) (c) +# define LZO_UINT32_C(c) (c##U) +# elif (LZO_SIZEOF_LONG >= 4) +# define LZO_INT32_C(c) (c##L) +# define LZO_UINT32_C(c) (c##UL) +# elif (LZO_SIZEOF_LONG_LONG >= 4) +# define LZO_INT32_C(c) (c##LL) +# define LZO_UINT32_C(c) (c##ULL) +# else +# error "LZO_INT32_C" +# endif +#endif +#if !defined(LZO_INT64_C) && defined(lzo_int64l_t) +# if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 8) +# define LZO_INT64_C(c) ((c) + 0) +# define LZO_UINT64_C(c) ((c) + 0U) +# elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 8) +# define LZO_INT64_C(c) ((c) + 0L) +# define LZO_UINT64_C(c) ((c) + 0UL) +# elif (LZO_SIZEOF_INT >= 8) +# define LZO_INT64_C(c) (c) +# define LZO_UINT64_C(c) (c##U) +# elif (LZO_SIZEOF_LONG >= 8) +# define LZO_INT64_C(c) (c##L) +# define LZO_UINT64_C(c) (c##UL) +# else +# error "LZO_INT64_C" +# endif +#endif +#endif + +#endif /* already included */ + +/* vim:set ts=4 sw=4 et: */ diff --git a/minilzo.h b/include/minilzo.h similarity index 66% rename from minilzo.h rename to include/minilzo.h index 0aff50e..08e2b44 100644 --- a/minilzo.h +++ b/include/minilzo.h @@ -1,20 +1,27 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + /* minilzo.h -- mini subset of the LZO real-time data compression library This file is part of the LZO real-time data compression library. - Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library is free software; you can redistribute it and/or @@ -44,15 +51,25 @@ */ -#ifndef __MINILZO_H -#define __MINILZO_H +#ifndef __MINILZO_H_INCLUDED +#define __MINILZO_H_INCLUDED 1 -#define MINILZO_VERSION 0x2030 +#define MINILZO_VERSION 0x20a0 /* 2.10 */ -#ifdef __LZOCONF_H +#if defined(__LZOCONF_H_INCLUDED) # error "you cannot use both LZO and miniLZO" #endif +/* internal Autoconf configuration file - only used when building miniLZO */ +#ifdef MINILZO_HAVE_CONFIG_H +# include +#endif +#include +#include + +#ifndef __LZODEFS_H_INCLUDED +#include "lzodefs.h" +#endif #undef LZO_HAVE_CONFIG_H #include "lzoconf.h" @@ -75,7 +92,7 @@ extern "C" { */ #define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS -#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) +#define LZO1X_1_MEM_COMPRESS ((lzo_uint32_t) (16384L * lzo_sizeof_dict_t)) #define LZO1X_MEM_DECOMPRESS (0) @@ -104,3 +121,5 @@ lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len, #endif /* already included */ + +/* vim:set ts=4 sw=4 et: */ diff --git a/include/n2n.h b/include/n2n.h new file mode 100644 index 0000000..602458c --- /dev/null +++ b/include/n2n.h @@ -0,0 +1,295 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#ifndef _N2N_H_ +#define _N2N_H_ + +/* + tunctl -t tun0 + tunctl -t tun1 + ifconfig tun0 1.2.3.4 up + ifconfig tun1 1.2.3.5 up + ./edge -d tun0 -l 2000 -r 127.0.0.1:3000 -c hello + ./edge -d tun1 -l 3000 -r 127.0.0.1:2000 -c hello + + + tunctl -u UID -t tunX +*/ + +#define SN_MANUAL_MAC /* allows supernode MAC address to be set manually */ + +#define N2N_HAVE_DAEMON /* needs to be defined before it gets undefined */ +#define N2N_HAVE_TCP /* needs to be defined before it gets undefined */ + +/* #define N2N_CAN_NAME_IFACE */ + +/* Moved here to define _CRT_SECURE_NO_WARNINGS before all the including takes place */ +#ifdef WIN32 +#ifndef CMAKE_BUILD +#include "config.h" /* Visual C++ */ +#else +#include "winconfig.h" +#endif +#define N2N_CAN_NAME_IFACE 1 +#undef N2N_HAVE_DAEMON +#undef N2N_HAVE_TCP /* as explained on https://github.com/ntop/n2n/pull/627#issuecomment-782093706 */ +#undef N2N_HAVE_SETUID +#else +#ifndef CMAKE_BUILD +#include "config.h" +#endif +#endif + + + +#define PACKAGE_BUILDDATE (__DATE__ " " __TIME__) + +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +#ifndef _MSC_VER +#include +#endif /* #ifndef _MSC_VER */ + +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#include + +#ifdef __linux__ +#define N2N_CAN_NAME_IFACE 1 +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* #ifdef __linux__ */ + +#ifdef __FreeBSD__ +#include +#endif /* #ifdef __FreeBSD__ */ + +#include +#include + +#ifdef HAVE_ZSTD +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined (HAVE_OPENSSL_1_1) +#include +#include +#endif + +#define closesocket(a) close(a) +#endif /* #ifndef WIN32 */ + +#include "minilzo.h" +#include +#include +#include +#include "lzoconf.h" +#include "uthash.h" +#include "n2n_define.h" +#include "n2n_typedefs.h" + +#ifdef WIN32 +#include /* for tcp */ +#define SHUT_RDWR SD_BOTH /* for tcp */ +#include "wintap.h" +#include +#else +#include +#endif /* #ifdef WIN32 */ + +#include "n2n_wire.h" +#include "random_numbers.h" +#include "pearson.h" +#include "portable_endian.h" +#include "aes.h" +#include "cc20.h" +#include "speck.h" +#include "curve25519.h" +#include "n2n_regex.h" +#include "sn_selection.h" +#include "network_traffic_filter.h" +#include "auth.h" + +#if defined(HAVE_MINIUPNP) || defined(HAVE_NATPMP) +#include "n2n_port_mapping.h" +#endif // HAVE_MINIUPNP || HAVE_NATPMP + +/* ************************************** */ + +#include "header_encryption.h" +#include "tf.h" + +#ifndef TRACE_ERROR +#define TRACE_ERROR 0, __FILE__, __LINE__ +#define TRACE_WARNING 1, __FILE__, __LINE__ +#define TRACE_NORMAL 2, __FILE__, __LINE__ +#define TRACE_INFO 3, __FILE__, __LINE__ +#define TRACE_DEBUG 4, __FILE__, __LINE__ +#endif + +/* ************************************** */ + +/* Transop Init Functions */ +int n2n_transop_null_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); +int n2n_transop_tf_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); +int n2n_transop_aes_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); +int n2n_transop_cc20_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); +int n2n_transop_speck_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); +int n2n_transop_lzo_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); +#ifdef HAVE_ZSTD +int n2n_transop_zstd_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); +#endif + +/* Log */ +void setTraceLevel (int level); +void setUseSyslog (int use_syslog); +void setTraceFile (FILE *f); +int getTraceLevel (); +void closeTraceFile (); +void traceEvent (int eventTraceLevel, char* file, int line, char * format, ...); + +/* Tuntap API */ +int tuntap_open (struct tuntap_dev *device, char *dev, const char *address_mode, char *device_ip, + char *device_mask, const char * device_mac, int mtu +#ifdef WIN32 + , int metric +#endif + ); +int tuntap_read (struct tuntap_dev *tuntap, unsigned char *buf, int len); +int tuntap_write (struct tuntap_dev *tuntap, unsigned char *buf, int len); +void tuntap_close (struct tuntap_dev *tuntap); +void tuntap_get_address (struct tuntap_dev *tuntap); + +/* Utils */ +char* intoa (uint32_t addr, char* buf, uint16_t buf_len); +uint32_t bitlen2mask (uint8_t bitlen); +uint8_t mask2bitlen (uint32_t mask); +char* macaddr_str (macstr_t buf, const n2n_mac_t mac); +int str2mac (uint8_t * outmac /* 6 bytes */, const char * s); +int supernode2sock (n2n_sock_t * sn, const n2n_sn_name_t addrIn); +uint8_t is_multi_broadcast (const n2n_mac_t dest_mac); +uint8_t is_broadcast (const n2n_mac_t dest_mac); +uint8_t is_null_mac (const n2n_mac_t dest_mac); +char* msg_type2str (uint16_t msg_type); +void hexdump (const uint8_t * buf, size_t len); +void print_n2n_version (); +int is_empty_ip_address (const n2n_sock_t * sock); +void print_edge_stats (const n2n_edge_t *eee); +int memrnd (uint8_t *address, size_t len); +int memxor (uint8_t *destination, const uint8_t *source, size_t len); + +/* Sockets */ +char* sock_to_cstr (n2n_sock_str_t out, + const n2n_sock_t * sock); +char * ip_subnet_to_str (dec_ip_bit_str_t buf, const n2n_ip_subnet_t *ipaddr); +SOCKET open_socket (int local_port, in_addr_t address, int type); +int sock_equal (const n2n_sock_t * a, + const n2n_sock_t * b); + +/* Header encryption */ +uint64_t time_stamp (void); +uint64_t initial_time_stamp (void); +int time_stamp_verify_and_update (uint64_t stamp, uint64_t * previous_stamp, int allow_jitter); + +/* Operations on peer_info lists. */ +size_t purge_peer_list (struct peer_info ** peer_list, + SOCKET socket_not_to_close, + n2n_tcp_connection_t **tcp_connections, + time_t purge_before); + +size_t clear_peer_list (struct peer_info ** peer_list); + +size_t purge_expired_nodes (struct peer_info **peer_list, + SOCKET socket_not_to_close, + n2n_tcp_connection_t **tcp_connections, + time_t *p_last_purge, + int frequency, int timeout); + +/* Edge conf */ +void edge_init_conf_defaults (n2n_edge_conf_t *conf); +int edge_verify_conf (const n2n_edge_conf_t *conf); +int edge_conf_add_supernode (n2n_edge_conf_t *conf, const char *ip_and_port); +const n2n_edge_conf_t* edge_get_conf (const n2n_edge_t *eee); +void edge_term_conf (n2n_edge_conf_t *conf); + +/* Public functions */ +n2n_edge_t* edge_init (const n2n_edge_conf_t *conf, int *rv); +void update_supernode_reg (n2n_edge_t * eee, time_t nowTime); +void readFromIPSocket (n2n_edge_t * eee, int in_sock); +void edge_term (n2n_edge_t *eee); +void edge_set_callbacks (n2n_edge_t *eee, const n2n_edge_callbacks_t *callbacks); +void edge_set_userdata (n2n_edge_t *eee, void *user_data); +void* edge_get_userdata (n2n_edge_t *eee); +void edge_send_packet2net (n2n_edge_t *eee, uint8_t *tap_pkt, size_t len); +void edge_read_from_tap (n2n_edge_t *eee); +int edge_get_n2n_socket (n2n_edge_t *eee); +int edge_get_management_socket (n2n_edge_t *eee); +int run_edge_loop (n2n_edge_t *eee); +int quick_edge_init (char *device_name, char *community_name, + char *encrypt_key, char *device_mac, + char *local_ip_address, + char *supernode_ip_address_port, + int *keep_on_running); +int comm_init (struct sn_community *comm, char *cmn); +int sn_init_defaults (n2n_sn_t *sss); +void sn_init (n2n_sn_t *sss); +void sn_term (n2n_sn_t *sss); +int supernode2sock (n2n_sock_t * sn, const n2n_sn_name_t addrIn); +struct peer_info* add_sn_to_list_by_mac_or_sock (struct peer_info **sn_list, n2n_sock_t *sock, const n2n_mac_t mac, int *skip_add); +int run_sn_loop (n2n_sn_t *sss); +int assign_one_ip_subnet (n2n_sn_t *sss, struct sn_community *comm); +const char* compression_str (uint8_t cmpr); +const char* transop_str (enum n2n_transform tr); + +void readFromMgmtSocket (n2n_edge_t *eee); + +void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1); +#endif /* _N2N_H_ */ diff --git a/include/n2n_define.h b/include/n2n_define.h new file mode 100644 index 0000000..010f469 --- /dev/null +++ b/include/n2n_define.h @@ -0,0 +1,221 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +/* N2N packet header indicators. */ +#define MSG_TYPE_REGISTER 1 +#define MSG_TYPE_DEREGISTER 2 +#define MSG_TYPE_PACKET 3 +#define MSG_TYPE_REGISTER_ACK 4 +#define MSG_TYPE_REGISTER_SUPER 5 +#define MSG_TYPE_UNREGISTER_SUPER 6 +#define MSG_TYPE_REGISTER_SUPER_ACK 7 +#define MSG_TYPE_REGISTER_SUPER_NAK 8 +#define MSG_TYPE_FEDERATION 9 +#define MSG_TYPE_PEER_INFO 10 +#define MSG_TYPE_QUERY_PEER 11 +#define MSG_TYPE_MAX_TYPE 11 +#define MSG_TYPE_RE_REGISTER_SUPER 12 + +/* Max available space to add supernodes' informations (sockets and MACs) in REGISTER_SUPER_ACK + * Field sizes of REGISTER_SUPER_ACK as used in encode/decode fucntions in src/wire.c + */ +#define REG_SUPER_ACK_PAYLOAD_SPACE (DEFAULT_MTU - (sizeof(n2n_common_t) + sizeof(n2n_REGISTER_SUPER_ACK_t))) + +/* Space needed to store socket and MAC address of a supernode */ +#define REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE (sizeof(n2n_REGISTER_SUPER_ACK_payload_t)) + +#define BOOTSTRAP_TIMEOUT 3 +#define PURGE_REGISTRATION_FREQUENCY 30 +#define RE_REG_AND_PURGE_FREQUENCY 10 +#define REGISTRATION_TIMEOUT 60 + +#define SOCKET_TIMEOUT_INTERVAL_SECS 10 +#define REGISTER_SUPER_INTERVAL_DFL 20 /* sec, usually UDP NAT entries in a firewall expire after 30 seconds */ +#define SWEEP_TIME 30 /* sec, indicates the value after which we have to sort the hash list of supernodes in edges + * and when we send out packets to query selection-relevant informations from supernodes. */ + +#define NUMBER_SN_PINGS_INITIAL 15 /* number of supernodes to concurrently ping during bootstrap and immediately afterwards */ +#define NUMBER_SN_PINGS_REGULAR 5 /* number of supernodes to concurrently ping during regular edge operation */ + +/* Timeouts used in re_register_and_purge_supernodes. LAST_SEEN_SN_ACTIVE and LAST_SEEN_SN_INACTIVE + * values should be at least 3*SOCKET_TIMEOUT_INTERVAL_SECS apart. */ +#define LAST_SEEN_SN_ACTIVE 20 /* sec, indicates supernodes that are proven to be active */ +#define LAST_SEEN_SN_INACTIVE 90 /* sec, indicates supernodes that are proven to be inactive: they will be purged */ +#define LAST_SEEN_SN_NEW (LAST_SEEN_SN_INACTIVE - 3 * RE_REG_AND_PURGE_FREQUENCY) /* sec, indicates supernodes with unsure status, must be tested to check if they are active */ + +#define IFACE_UPDATE_INTERVAL (30) /* sec. How long it usually takes to get an IP lease. */ +#define TRANSOP_TICK_INTERVAL (10) /* sec */ + +#define SORT_COMMUNITIES_INTERVAL 90 /* sec. until supernode sorts communities' hash list again */ + +#define AF_INVALID -1 /* to mark a socket invalid by an invalid address family (do not use AF_UNSPEC, it could turn into auto-detect) */ +#define N2N_RESOLVE_INTERVAL 300 /* seconds until edge and supernode try to resolve supernode names again */ +#define N2N_RESOLVE_CHECK_INTERVAL 30 /* seconds until main loop checking in on changes from resolver thread */ + +#define ETH_FRAMESIZE 14 +#define IP4_SRCOFFSET 12 +#define IP4_DSTOFFSET 16 +#define IP4_MIN_SIZE 20 +#define UDP_SIZE 8 + +/* parameters for replay protection */ +#define TIME_STAMP_FRAME 0x0000001000000000LL /* clocks of different computers are allowed +/- 16 seconds to be off */ +#define TIME_STAMP_JITTER 0x0000000027100000LL /* we allow a packet to arrive 160 ms (== 0x27100 us) before another + * set to 0x0000000000000000LL if increasing (or equal) time stamps allowed only */ +#define TIME_STAMP_ALLOW_JITTER 1 /* constant for allowing or... */ +#define TIME_STAMP_NO_JITTER 0 /* not allowing jitter to be considered */ + +/* N2N compression indicators. */ +/* Compression is disabled by default for outgoing packets if no cli + * option is given. All edges are built with decompression support so + * they are able to understand each other (this applies to lzo only). */ +#define N2N_COMPRESSION_ID_INVALID 0 +#define N2N_COMPRESSION_ID_NONE 1 /* default, see edge_init_conf_defaults(...) in edge_utils.c */ +#define N2N_COMPRESSION_ID_LZO 2 /* set if '-z1' or '-z' cli option is present, see setOption(...) in edge.c */ +#define N2N_COMPRESSION_ID_ZSTD 3 /* set if '-z2' cli option is present, available only if compiled with zstd lib */ +#define ZSTD_COMPRESSION_LEVEL 7 /* 1 (faster) ... 22 (more compression) */ + +/* Federation name and indicators */ +#define FEDERATION_NAME "*Federation" +enum federation {IS_NO_FEDERATION = 0,IS_FEDERATION = 1}; + +/* (un)purgeable community indicator (supernode) */ +#define COMMUNITY_UNPURGEABLE 0 +#define COMMUNITY_PURGEABLE 1 + +/* (un)purgeable supernode indicator */ +enum sn_purge {SN_PURGEABLE = 0, SN_UNPURGEABLE = 1}; + +/* Header encryption indicators */ +#define HEADER_ENCRYPTION_UNKNOWN 0 +#define HEADER_ENCRYPTION_NONE 1 +#define HEADER_ENCRYPTION_ENABLED 2 + +/* REGISTER_SUPER_ACK packet hash length with user/pw auth, up to 16 bytes */ +#define N2N_REG_SUP_HASH_CHECK_LEN 16 + +#define DEFAULT_MTU 1290 + +#define HASH_ADD_PEER(head,add) \ + HASH_ADD(hh,head,mac_addr,sizeof(n2n_mac_t),add) +#define HASH_FIND_PEER(head,mac,out) \ + HASH_FIND(hh,head,mac,sizeof(n2n_mac_t),out) +#define N2N_EDGE_SN_HOST_SIZE 48 +#define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */ +#define N2N_PATHNAME_MAXLEN 256 +#define N2N_EDGE_MGMT_PORT 5644 +#define N2N_SN_MGMT_PORT 5645 + +enum n2n_event_topic { + N2N_EVENT_DEBUG = 0, + N2N_EVENT_TEST = 1, + N2N_EVENT_PEER = 2, +}; + +#define N2N_EVENT_PEER_PURGE 1 +#define N2N_EVENT_PEER_CLEAR 2 +#define N2N_EVENT_PEER_DEL_P2P 3 +#define N2N_EVENT_PEER_ADD_P2P 4 + +#define N2N_MGMT_PASSWORD "n2n" /* default password for management port access (so far, json only) */ + + +#define N2N_TCP_BACKLOG_QUEUE_SIZE 3 /* number of concurrently pending connections to be accepted */ + /* NOT the number of max. TCP connections */ + +#define N2N_CLOSE_SOCKET_COUNTER_MAX 15 /* number of times of edge's reconnects to supernode after */ + /* which the socket explicitly is closed before reopening */ + +/* flag used in add_sn_to_list_by_mac_or_sock */ +enum skip_add {SN_ADD = 0, SN_ADD_SKIP = 1, SN_ADD_ADDED = 2}; + +#define N2N_NETMASK_STR_SIZE 16 /* dotted decimal 12 numbers + 3 dots */ +#define N2N_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/ +#define N2N_IF_MODE_SIZE 16 /* static | dhcp */ + +#define N2N_EDGE_DEFAULT_DEV_NAME "edge0" +#define N2N_EDGE_DEFAULT_NETMASK "255.255.255.0" /* default netmask for edge ip address... */ +#define N2N_EDGE_DEFAULT_CIDR_NM 24 /* ... also in cidr format */ + +#define N2N_SN_LPORT_DEFAULT 7654 +#define N2N_SN_PKTBUF_SIZE 2048 + + +/* The way TUNTAP allocated IP. */ +#define TUNTAP_IP_MODE_SN_ASSIGN 0 +#define TUNTAP_IP_MODE_STATIC 1 +#define TUNTAP_IP_MODE_DHCP 2 + +/* Default network segment of the auto ip address service provided by sn. */ +#define N2N_SN_MIN_AUTO_IP_NET_DEFAULT "10.128.0.0" +#define N2N_SN_MAX_AUTO_IP_NET_DEFAULT "10.255.255.0" +#define N2N_SN_AUTO_IP_NET_BIT_DEFAULT 24 + +/* ************************************** */ + +#define SUPERNODE_IP "127.0.0.1" +#define SUPERNODE_PORT 1234 + +/* ************************************** */ + +#define N2N_PKT_VERSION 3 +#define N2N_DEFAULT_TTL 2 /* can be forwarded twice at most */ +#define N2N_COMMUNITY_SIZE 20 +#define N2N_PRIVATE_PUBLIC_KEY_SIZE 32 +#define N2N_USER_KEY_LINE_STARTER '*' +#define N2N_MAC_SIZE 6 +#define N2N_NO_REG_COOKIE 0x00000000 +#define N2N_FORWARDED_REG_COOKIE 0x00001000 +#define N2N_PORT_REG_COOKIE 0x00004000 +#define N2N_REGULAR_REG_COOKIE 0x00010000 +#define N2N_MCAST_REG_COOKIE 0x00400000 +#define N2N_LOCAL_REG_COOKIE 0x01000000 +#define N2N_DESC_SIZE 16 +#define N2N_PKT_BUF_SIZE 2048 +#define N2N_SOCKBUF_SIZE 64 /* string representation of INET or INET6 sockets */ + +#define N2N_MULTICAST_PORT 1968 +#define N2N_MULTICAST_GROUP "224.0.0.68" + +#ifdef WIN32 +#define N2N_IFNAMSIZ 64 +#else +#define N2N_IFNAMSIZ 16 /* 15 chars * NULL */ +#endif + +#ifdef _MSC_VER +#define N2N_THREAD_RETURN_DATATYPE DWORD WINAPI +#define N2N_THREAD_PARAMETER_DATATYPE LPVOID +#else +#define N2N_THREAD_RETURN_DATATYPE void* +#define N2N_THREAD_PARAMETER_DATATYPE void* +#endif + +#define SN_SELECTION_CRITERION_DATA_TYPE uint64_t +#define SN_SELECTION_CRITERION_BUF_SIZE 16 + +#define N2N_TRANSFORM_ID_USER_START 64 +#define N2N_TRANSFORM_ID_MAX 65535 + +#ifndef max +#define max(a, b) (((a) < (b)) ? (b) : (a)) +#endif + +#ifndef min +#define min(a, b) (((a) >(b)) ? (b) : (a)) +#endif diff --git a/include/n2n_port_mapping.h b/include/n2n_port_mapping.h new file mode 100644 index 0000000..46b2511 --- /dev/null +++ b/include/n2n_port_mapping.h @@ -0,0 +1,51 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#ifndef _N2N_PORT_MAPPING_H_ +#define _N2N_PORT_MAPPING_H_ + +#ifdef HAVE_PORT_FORWARDING + +#include + +#ifdef HAVE_MINIUPNP +#ifdef CMAKE_BUILD +// CMAKE uses static linked lib as submodule which requires different includes than +// the dynamically linked, intalled library in case of plain make +#include +#include +#include +#else +#include +#include +#include +#endif // CMAKE_BUILD +#endif // HAVE_MINIUPNP + + +#ifdef HAVE_NATPMP +#include "natpmp.h" +#endif // HAVE_NATPMP + + +void n2n_chg_port_mapping (struct n2n_edge *eee, const uint16_t port); + + +#endif // HAVE_PORT_FORWARDING +#endif // _N2N_PORT_MAPPING_H_ diff --git a/include/n2n_regex.h b/include/n2n_regex.h new file mode 100644 index 0000000..bbf416e --- /dev/null +++ b/include/n2n_regex.h @@ -0,0 +1,76 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +// taken from https://github.com/kokke/tiny-regex-c +// under Unlicense as of August 4, 2020 + +/* + * + * Mini regex-module inspired by Rob Pike's regex code described in: + * + * http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html + * + * + * + * Supports: + * --------- + * '.' Dot, matches any character + * '^' Start anchor, matches beginning of string + * '$' End anchor, matches end of string + * '*' Asterisk, match zero or more (greedy) + * '+' Plus, match one or more (greedy) + * '?' Question, match zero or one (non-greedy) + * '[abc]' Character class, match if one of {'a', 'b', 'c'} + * '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} -- NOTE: feature is currently broken! + * '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z } + * '\s' Whitespace, \t \f \r \n \v and spaces + * '\S' Non-whitespace + * '\w' Alphanumeric, [a-zA-Z0-9_] + * '\W' Non-alphanumeric + * '\d' Digits, [0-9] + * '\D' Non-digits + * + * + */ + +#ifndef _N2N_REGEX_ +#define _N2N_REGEX_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Compile regex string pattern to a regex_t-array. */ +re_t re_compile (const char* pattern); + + +/* Find matches of the compiled pattern inside text. */ +int re_matchp (re_t pattern, const char* text, int* matchlenght); + + +/* Find matches of the txt pattern inside text (will compile automatically first). */ +int re_match (const char* pattern, const char* text, int* matchlenght); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/n2n_typedefs.h b/include/n2n_typedefs.h new file mode 100644 index 0000000..b390d52 --- /dev/null +++ b/include/n2n_typedefs.h @@ -0,0 +1,868 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#ifndef _N2N_TYPEDEFS_H_ +#define _N2N_TYPEDEFS_H_ + + +typedef uint8_t n2n_community_t[N2N_COMMUNITY_SIZE]; +typedef uint8_t n2n_private_public_key_t[N2N_PRIVATE_PUBLIC_KEY_SIZE]; +typedef uint8_t n2n_mac_t[N2N_MAC_SIZE]; +typedef uint32_t n2n_cookie_t; +typedef uint8_t n2n_desc_t[N2N_DESC_SIZE]; +typedef char n2n_sock_str_t[N2N_SOCKBUF_SIZE]; /* tracing string buffer */ + + +#if defined(_MSC_VER) || defined(__MINGW32__) +#include "getopt.h" + +/* Other Win environments are expected to support stdint.h */ + +/* stdint.h typedefs (C99) (not present in Visual Studio) */ +typedef unsigned int uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; + +/* sys/types.h typedefs (not present in Visual Studio) */ +typedef unsigned int u_int32_t; +typedef unsigned short u_int16_t; +typedef unsigned char u_int8_t; + +#ifndef __MINGW32__ +typedef int ssize_t; +#endif + +typedef unsigned long in_addr_t; + +#include "n2n_win32.h" + +#endif /* #if defined(_MSC_VER) || defined(__MINGW32__) */ + + + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#include +#endif + +#ifdef __OpenBSD__ +#include +#define __BYTE_ORDER BYTE_ORDER +#if BYTE_ORDER == LITTLE_ENDIAN +#ifndef __LITTLE_ENDIAN__ +#define __LITTLE_ENDIAN__ +#endif /* __LITTLE_ENDIAN__ */ +#else +#define __BIG_ENDIAN__ +#endif/* BYTE_ORDER */ +#endif/* __OPENBSD__ */ + + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#ifndef __LITTLE_ENDIAN__ +#define __LITTLE_ENDIAN__ +#endif +#else +#ifndef __BIG_ENDIAN__ +#define __BIG_ENDIAN__ +#endif +#endif + +#ifdef WIN32 +#ifndef __LITTLE_ENDIAN__ +#define __LITTLE_ENDIAN__ 1 +#endif +#endif + +#if !(defined(__LITTLE_ENDIAN__) || defined(__BIG_ENDIAN__)) +#if defined(__mips__) +#undef __LITTLE_ENDIAN__ +#undef __LITTLE_ENDIAN +#define __BIG_ENDIAN__ +#endif + +/* Everything else */ +#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define __LITTLE_ENDIAN__ +#else +#define __BIG_ENDIAN__ +#endif +#endif + +#endif + +/* *************************************** */ + +#ifdef __GNUC__ +#define PACK_STRUCT __attribute__((__packed__)) +#else +#define PACK_STRUCT +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) +#pragma pack(push,1) +#endif + + +// those are definitely not typedefs (with a view to the filename) but neither are they defines +static const n2n_mac_t broadcast_mac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const n2n_mac_t multicast_mac = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */ +static const n2n_mac_t ipv6_multicast_mac = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; /* First 2 bytes are meaningful */ +static const n2n_mac_t null_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + +#define ETH_ADDR_LEN 6 + +struct ether_hdr { + uint8_t dhost[ETH_ADDR_LEN]; + uint8_t shost[ETH_ADDR_LEN]; + uint16_t type; /* higher layer protocol encapsulated */ +} PACK_STRUCT; + +typedef struct ether_hdr ether_hdr_t; + + +struct n2n_iphdr { +#if defined(__LITTLE_ENDIAN__) + u_int8_t ihl:4, version:4; +#elif defined(__BIG_ENDIAN__) + u_int8_t version:4, ihl:4; +#else +# error "Byte order must be defined" +#endif + u_int8_t tos; + u_int16_t tot_len; + u_int16_t id; + u_int16_t frag_off; + u_int8_t ttl; + u_int8_t protocol; + u_int16_t check; + u_int32_t saddr; + u_int32_t daddr; +} PACK_STRUCT; + +struct n2n_tcphdr { + u_int16_t source; + u_int16_t dest; + u_int32_t seq; + u_int32_t ack_seq; +#if defined(__LITTLE_ENDIAN__) + u_int16_t res1:4, doff:4, fin:1, syn:1, rst:1, psh:1, ack:1, urg:1, ece:1, cwr:1; +#elif defined(__BIG_ENDIAN__) + u_int16_t doff:4, res1:4, cwr:1, ece:1, urg:1, ack:1, psh:1, rst:1, syn:1, fin:1; +#else +# error "Byte order must be defined" +#endif + u_int16_t window; + u_int16_t check; + u_int16_t urg_ptr; +} PACK_STRUCT; + +struct n2n_udphdr { + u_int16_t source; + u_int16_t dest; + u_int16_t len; + u_int16_t check; +} PACK_STRUCT; + +#if defined(_MSC_VER) || defined(__MINGW32__) +#pragma pack(pop) +#endif + + +typedef struct port_range { + uint16_t start_port; // range contain 'start_port' self + uint16_t end_port; // range contain 'end_port' self +} port_range_t; + +typedef struct filter_rule_key { + in_addr_t src_net_cidr; + uint8_t src_net_bit_len; + port_range_t src_port_range; + in_addr_t dst_net_cidr; + uint8_t dst_net_bit_len; + port_range_t dst_port_range; + uint8_t bool_tcp_configured; + uint8_t bool_udp_configured; + uint8_t bool_icmp_configured; +} filter_rule_key_t; + +typedef struct filter_rule { + filter_rule_key_t key; + + uint8_t bool_accept_icmp; + uint8_t bool_accept_udp; + uint8_t bool_accept_tcp; + + UT_hash_handle hh; /* makes this structure hashable */ +} filter_rule_t; + + +#ifndef WIN32 +typedef struct tuntap_dev { + int fd; + int if_idx; + n2n_mac_t mac_addr; + uint32_t ip_addr; + uint32_t device_mask; + uint16_t mtu; + char dev_name[N2N_IFNAMSIZ]; +} tuntap_dev; + +#define SOCKET int +#endif /* #ifndef WIN32 */ + +/** Uncomment this to enable the MTU check, then try to ssh to generate a fragmented packet. */ +/** NOTE: see doc/MTU.md for an explanation on the 1400 value */ +//#define MTU_ASSERT_VALUE 1400 + +/** Common type used to hold stringified IP addresses. */ +typedef char ipstr_t[32]; + +/** Common type used to hold stringified MAC addresses. */ +#define N2N_MACSTR_SIZE 32 +typedef char macstr_t[N2N_MACSTR_SIZE]; +typedef char dec_ip_str_t[N2N_NETMASK_STR_SIZE]; +typedef char dec_ip_bit_str_t[N2N_NETMASK_STR_SIZE + 4]; + +typedef struct speck_context_t he_context_t; +typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE]; + +typedef enum n2n_pc { + n2n_ping = 0, /* Not used */ + n2n_register = 1, /* Register edge to edge */ + n2n_deregister = 2, /* Deregister this edge */ + n2n_packet = 3, /* PACKET data content */ + n2n_register_ack = 4, /* ACK of a registration from edge to edge */ + n2n_register_super = 5, /* Register edge to supernode */ + n2n_unregister_super = 6, /* Deregister edge from supernode */ + n2n_register_super_ack = 7, /* ACK from supernode to edge */ + n2n_register_super_nak = 8, /* NAK from supernode to edge - registration refused */ + n2n_federation = 9, /* Not used by edge */ + n2n_peer_info = 10, /* Send info on a peer from sn to edge */ + n2n_query_peer = 11, /* ask supernode for info on a peer */ + n2n_re_register_super = 12 /* ask edge to re-register with supernode */ +} n2n_pc_t; + +#define N2N_FLAGS_OPTIONS 0x0080 +#define N2N_FLAGS_SOCKET 0x0040 +#define N2N_FLAGS_FROM_SUPERNODE 0x0020 + +/* The bits in flag that are the packet type */ +#define N2N_FLAGS_TYPE_MASK 0x001f /* 0 - 31 */ +#define N2N_FLAGS_BITS_MASK 0xffe0 + +#define IPV4_SIZE 4 +#define IPV6_SIZE 16 + + +#define N2N_AUTH_MAX_TOKEN_SIZE 48 /* max token size in bytes */ +#define N2N_AUTH_CHALLENGE_SIZE 16 /* challenge always is of same size as dynamic key */ +#define N2N_AUTH_ID_TOKEN_SIZE 16 +#define N2N_AUTH_PW_TOKEN_SIZE (N2N_PRIVATE_PUBLIC_KEY_SIZE + N2N_AUTH_CHALLENGE_SIZE) + +#define N2N_EUNKNOWN -1 +#define N2N_ENOTIMPL -2 +#define N2N_EINVAL -3 +#define N2N_ENOSPACE -4 + + +#define N2N_VERSION_STRING_SIZE 20 +typedef char n2n_version_t[N2N_VERSION_STRING_SIZE]; + + +#define SN_SELECTION_STRATEGY_LOAD 1 +#define SN_SELECTION_STRATEGY_RTT 2 +#define SN_SELECTION_STRATEGY_MAC 3 + + +typedef struct n2n_ip_subnet { + uint32_t net_addr; /* Host order IP address. */ + uint8_t net_bitlen; /* Subnet prefix. */ +} n2n_ip_subnet_t; + +typedef struct n2n_sock { + uint8_t family; /* AF_INET or AF_INET6; or 0 if invalid */ + uint16_t port; /* host order */ + union { + uint8_t v6[IPV6_SIZE]; /* byte sequence */ + uint8_t v4[IPV4_SIZE]; /* byte sequence */ + } addr; +} n2n_sock_t; + +typedef enum { + n2n_auth_none = 0, + n2n_auth_simple_id = 1, + n2n_auth_user_password = 2 +} n2n_auth_scheme_t; + +typedef enum { + update_edge_no_change = 0, + update_edge_sock_change = 1, + update_edge_new_sn = 2, + update_edge_auth_fail = -1 +} update_edge_ret_value_t; + +typedef struct n2n_auth { + uint16_t scheme; /* What kind of auth */ + uint16_t token_size; /* Size of auth token */ + uint8_t token[N2N_AUTH_MAX_TOKEN_SIZE]; /* Auth data interpreted based on scheme */ +} n2n_auth_t; + +typedef struct n2n_common { + /* NOTE: wire representation is different! */ + /* int version; */ + + uint8_t ttl; + uint8_t pc; + uint16_t flags; + n2n_community_t community; +} n2n_common_t; + +typedef struct n2n_REGISTER { + n2n_cookie_t cookie; /**< Link REGISTER and REGISTER_ACK */ + n2n_mac_t srcMac; /**< MAC of registering party */ + n2n_mac_t dstMac; /**< MAC of target edge */ + n2n_sock_t sock; /**< Supernode's view of edge socket OR edge's preferred local socket */ + n2n_ip_subnet_t dev_addr; /**< IP address of the tuntap adapter. */ + n2n_desc_t dev_desc; /**< Hint description correlated with the edge */ +} n2n_REGISTER_t; + +typedef struct n2n_REGISTER_ACK { + n2n_cookie_t cookie; /**< Return cookie from REGISTER */ + n2n_mac_t srcMac; /**< MAC of acknowledging party (supernode or edge) */ + n2n_mac_t dstMac; /**< Reflected MAC of registering edge from REGISTER */ + n2n_sock_t sock; /**< Supernode's view of edge socket (IP Addr, port) */ +} n2n_REGISTER_ACK_t; + +typedef struct n2n_PACKET { + n2n_mac_t srcMac; + n2n_mac_t dstMac; + n2n_sock_t sock; + uint8_t transform; + uint8_t compression; +} n2n_PACKET_t; + +/* Linked with n2n_register_super in n2n_pc_t. Only from edge to supernode. */ +typedef struct n2n_REGISTER_SUPER { + n2n_cookie_t cookie; /**< Link REGISTER_SUPER and REGISTER_SUPER_ACK */ + n2n_mac_t edgeMac; /**< MAC to register with edge sending socket */ + n2n_sock_t sock; /**< Sending socket associated with edgeMac */ + n2n_ip_subnet_t dev_addr; /**< IP address of the tuntap adapter. */ + n2n_desc_t dev_desc; /**< Hint description correlated with the edge */ + n2n_auth_t auth; /**< Authentication scheme and tokens */ + uint32_t key_time; /**< key time for dynamic key, used between federatred supernodes only */ +} n2n_REGISTER_SUPER_t; + + +/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */ +typedef struct n2n_REGISTER_SUPER_ACK { + n2n_cookie_t cookie; /**< Return cookie from REGISTER_SUPER */ + n2n_mac_t srcMac; /**< MAC of answering supernode */ + n2n_ip_subnet_t dev_addr; /**< Assign an IP address to the tuntap adapter of edge. */ + uint16_t lifetime; /**< How long the registration will live */ + n2n_sock_t sock; /**< Sending sockets associated with edge */ + n2n_auth_t auth; /**< Authentication scheme and tokens */ + + /** The packet format provides additional supernode definitions here. + * uint8_t count, then for each count there is one + * n2n_sock_t. + */ + uint8_t num_sn; /**< Number of supernodes that were send + * even if we cannot store them all. */ + + uint32_t key_time; /**< key time for dynamic key, used between federatred supernodes only */ +} n2n_REGISTER_SUPER_ACK_t; + + +/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */ +typedef struct n2n_REGISTER_SUPER_NAK { + n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */ + n2n_mac_t srcMac; + n2n_auth_t auth; /* Authentication scheme and tokens */ +} n2n_REGISTER_SUPER_NAK_t; + + +/* REGISTER_SUPER_ACK may contain extra payload (their number given by num_sn) + * of following type describing a(nother) supernode */ +typedef struct n2n_REGISTER_SUPER_ACK_payload { + n2n_sock_t sock; /**< socket of supernode */ + n2n_mac_t mac; /**< MAC of supernode */ +} n2n_REGISTER_SUPER_ACK_payload_t; + + +/* Linked with n2n_unregister_super in n2n_pc_t. */ +typedef struct n2n_UNREGISTER_SUPER { + n2n_auth_t auth; + n2n_mac_t srcMac; +} n2n_UNREGISTER_SUPER_t; + + +typedef struct n2n_PEER_INFO { + uint16_t aflags; + n2n_mac_t srcMac; + n2n_mac_t mac; + n2n_sock_t sock; + n2n_sock_t preferred_sock; + uint32_t load; + n2n_version_t version; + time_t uptime; +} n2n_PEER_INFO_t; + + +typedef struct n2n_QUERY_PEER { + uint16_t aflags; + n2n_mac_t srcMac; + n2n_sock_t sock; + n2n_mac_t targetMac; + +} n2n_QUERY_PEER_t; + +typedef struct n2n_buf n2n_buf_t; + +struct peer_info { + n2n_mac_t mac_addr; + n2n_ip_subnet_t dev_addr; + n2n_desc_t dev_desc; + n2n_sock_t sock; + SOCKET socket_fd; + n2n_sock_t preferred_sock; + n2n_cookie_t last_cookie; + n2n_auth_t auth; + int timeout; + uint8_t purgeable; + time_t last_seen; + time_t last_p2p; + time_t last_sent_query; + SN_SELECTION_CRITERION_DATA_TYPE selection_criterion; + uint64_t last_valid_time_stamp; + char *ip_addr; + uint8_t local; + time_t uptime; + n2n_version_t version; + + UT_hash_handle hh; /* makes this structure hashable */ +}; + +typedef struct peer_info peer_info_t; + +typedef struct n2n_route { + in_addr_t net_addr; + uint8_t net_bitlen; + in_addr_t gateway; +} n2n_route_t; + +typedef struct n2n_edge n2n_edge_t; + +/* *************************************************** */ + +typedef enum { + N2N_ACCEPT = 0, + N2N_DROP = 1 +} n2n_verdict; + +/* *************************************************** */ + +typedef enum { + FPP_UNKNOWN = 0, + FPP_ARP = 1, + FPP_TCP = 2, + FPP_UDP = 3, + FPP_ICMP = 4, + FPP_IGMP = 5 +} filter_packet_proto; + + +typedef struct packet_address_proto_info { + in_addr_t src_ip; + uint16_t src_port; + in_addr_t dst_ip; + uint16_t dst_port; + filter_packet_proto proto; +}packet_address_proto_info_t; + +typedef struct filter_rule_pair_cache { + packet_address_proto_info_t key; + + uint8_t bool_allow_traffic; + uint32_t active_count; + + UT_hash_handle hh; /* makes this structure hashable */ +} filter_rule_pair_cache_t; + +struct network_traffic_filter; +typedef struct network_traffic_filter network_traffic_filter_t; + +struct network_traffic_filter { + n2n_verdict (*filter_packet_from_peer)(network_traffic_filter_t* filter, n2n_edge_t *eee, + const n2n_sock_t *peer, uint8_t *payload, uint16_t payload_size); + + n2n_verdict (*filter_packet_from_tap)(network_traffic_filter_t* filter, n2n_edge_t *eee, uint8_t *payload, uint16_t payload_size); + + filter_rule_t *rules; + + filter_rule_pair_cache_t *connections_rule_cache; + + uint32_t work_count_scene_last_clear; + +}; + +/* *************************************************** */ + +/* Callbacks allow external programs to attach functions in response to + * N2N events. */ +typedef struct n2n_edge_callbacks { + /* The supernode registration has been updated */ + void (*sn_registration_updated)(n2n_edge_t *eee, time_t now, const n2n_sock_t *sn); + + /* A packet has been received from a peer. N2N_DROP can be returned to + * drop the packet. The packet payload can be modified. This only allows + * the packet size to be reduced */ + n2n_verdict (*packet_from_peer)(n2n_edge_t *eee, const n2n_sock_t *peer, uint8_t *payload, uint16_t *payload_size); + + /* A packet has been received from the TAP interface. N2N_DROP can be + * returned to drop the packet. The packet payload can be modified. + * This only allows the packet size to be reduced */ + n2n_verdict (*packet_from_tap)(n2n_edge_t *eee, uint8_t *payload, uint16_t *payload_size); + + /* Called whenever the IP address of the TAP interface changes. */ + void (*ip_address_changed)(n2n_edge_t *eee, uint32_t old_ip, uint32_t new_ip); + + /* Called periodically in the main loop. */ + void (*main_loop_period)(n2n_edge_t *eee, time_t now); + + /* Called when a new socket to supernode is created. */ + void (*sock_opened)(n2n_edge_t *eee); +} n2n_edge_callbacks_t; + +typedef struct n2n_tuntap_priv_config { + char tuntap_dev_name[N2N_IFNAMSIZ]; + char ip_mode[N2N_IF_MODE_SIZE]; + dec_ip_str_t ip_addr; + dec_ip_str_t netmask; + char device_mac[N2N_MACNAMSIZ]; + int mtu; + int metric; + uint8_t daemon; +#ifndef WIN32 + uid_t userid; + gid_t groupid; +#endif +} n2n_tuntap_priv_config_t; + +/* *************************************************** */ + +typedef enum n2n_transform { + N2N_TRANSFORM_ID_INVAL = 0, + N2N_TRANSFORM_ID_NULL = 1, + N2N_TRANSFORM_ID_TWOFISH = 2, + N2N_TRANSFORM_ID_AES = 3, + N2N_TRANSFORM_ID_CHACHA20 = 4, + N2N_TRANSFORM_ID_SPECK = 5, +} n2n_transform_t; + +struct n2n_trans_op; /* Circular definition */ + +typedef int (*n2n_transdeinit_f)(struct n2n_trans_op * arg); +typedef void (*n2n_transtick_f)(struct n2n_trans_op * arg, time_t now); +typedef int (*n2n_transform_f)(struct n2n_trans_op * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len, + const n2n_mac_t peer_mac); +/** Holds the info associated with a data transform plugin. + * + * When a packet arrives the transform ID is extracted. This defines the code + * to use to decode the packet content. The transform code then decodes the + * packet and consults its internal key lookup. + */ +typedef struct n2n_trans_op { + void * priv; /* opaque data. Key schedule goes here. */ + uint8_t no_encryption; /* 1 if this transop does not perform encryption */ + n2n_transform_t transform_id; + size_t tx_cnt; + size_t rx_cnt; + + n2n_transdeinit_f deinit; /* destructor function */ + n2n_transtick_f tick; /* periodic maintenance */ + n2n_transform_f fwd; /* encode a payload */ + n2n_transform_f rev; /* decode a payload */ +} n2n_trans_op_t; + + +/* *************************************************** */ + + +typedef struct n2n_resolve_ip_sock { + char *org_ip; /* pointer to original ip/named address string (used read only) */ + n2n_sock_t sock; /* resolved socket */ + n2n_sock_t *org_sock; /* pointer to original socket where 'sock' gets copied to from time to time */ + int error_code; /* result of last resolution attempt */ + + UT_hash_handle hh; /* makes this structure hashable */ +} n2n_resolve_ip_sock_t; + + +// structure to hold resolver thread's parameters +typedef struct n2n_resolve_parameter { + n2n_resolve_ip_sock_t *list; /* pointer to list of to be resolved nodes */ + uint8_t changed; /* indicates a change */ +#ifdef HAVE_PTHREAD + pthread_t id; /* thread id */ + pthread_mutex_t access; /* mutex for shared access */ +#endif + uint8_t request; /* flags main thread's need for intermediate resolution */ + time_t check_interval;/* interval to checik resolover results */ + time_t last_checked; /* last time the resolver results were cheked */ + time_t last_resolved; /* last time the resolver completed */ +} n2n_resolve_parameter_t; + + +/* *************************************************** */ + + +// structure to hold port mapping thread's parameters +typedef struct n2n_port_map_parameter { +#ifdef HAVE_PTHREAD + pthread_t id; /* thread id */ + pthread_mutex_t access; /* mutex for shared access */ +#endif + uint16_t mgmt_port; + uint16_t mapped_port; + uint16_t new_port; /* REVISIT: remove with management port subscriptions */ +} n2n_port_map_parameter_t; + + +/* *************************************************** */ + + +typedef struct n2n_edge_conf { + struct peer_info *supernodes; /**< List of supernodes */ + n2n_route_t *routes; /**< Networks to route through n2n */ + n2n_community_t community_name; /**< The community. 16 full octets. */ + n2n_desc_t dev_desc; /**< The device description (hint) */ + n2n_private_public_key_t *public_key; /**< edge's public key (for user/password based authentication) */ + n2n_private_public_key_t *shared_secret; /**< shared secret derived from federation public key, username and password */ + he_context_t *shared_secret_ctx; /**< context holding the roundkeys derived from shared secret */ + n2n_private_public_key_t *federation_public_key; /**< federation public key provided by command line */ + uint8_t header_encryption; /**< Header encryption indicator. */ + he_context_t *header_encryption_ctx_static; /**< Header encryption cipher context. */ + he_context_t *header_encryption_ctx_dynamic; /**< Header encryption cipher context. */ + he_context_t *header_iv_ctx_static; /**< Header IV ecnryption cipher context, REMOVE as soon as separate fileds for checksum and replay protection available */ + he_context_t *header_iv_ctx_dynamic; /**< Header IV ecnryption cipher context, REMOVE as soon as separate fileds for checksum and replay protection available */ + n2n_transform_t transop_id; /**< The transop to use. */ + uint8_t compression; /**< Compress outgoing data packets before encryption */ + uint16_t num_routes; /**< Number of routes in routes */ + uint8_t tuntap_ip_mode; /**< Interface IP address allocated mode, eg. DHCP. */ + uint8_t allow_routing; /**< Accept packet no to interface address. */ + uint8_t drop_multicast; /**< Multicast ethernet addresses. */ + uint8_t disable_pmtu_discovery; /**< Disable the Path MTU discovery. */ + uint8_t allow_p2p; /**< Allow P2P connection */ + uint8_t sn_num; /**< Number of supernode addresses defined. */ + uint8_t tos; /** TOS for sent packets */ + char *encrypt_key; + int register_interval; /**< Interval for supernode registration, also used for UDP NAT hole punching. */ + int register_ttl; /**< TTL for registration packet when UDP NAT hole punching through supernode. */ + in_addr_t bind_address; /**< The address to bind to if provided (-b) */ + n2n_sock_t preferred_sock; /**< propagated local sock for better p2p in LAN (-e) */ + uint8_t preferred_sock_auto; /**< indicates desired auto detect for preferred sock */ + int local_port; + int mgmt_port; + uint8_t connect_tcp; /** connection to supernode 0 = UDP; 1 = TCP */ + n2n_auth_t auth; + filter_rule_t *network_traffic_filter_rules; + int metric; /**< Network interface metric (Windows only). */ + uint8_t sn_selection_strategy; /**< encodes currently chosen supernode selection strategy. */ + uint8_t number_max_sn_pings; /**< Number of maximum concurrently allowed supernode pings. */ + uint64_t mgmt_password_hash; /**< contains hash of managament port password. */ + uint8_t port_forwarding; /**< indicates if port forwarding UPNP/PMP is enabled */ +} n2n_edge_conf_t; + + +struct n2n_edge_stats { + uint32_t tx_p2p; + uint32_t rx_p2p; + uint32_t tx_sup; + uint32_t rx_sup; + uint32_t tx_sup_broadcast; + uint32_t rx_sup_broadcast; +}; + +struct n2n_edge { + n2n_edge_conf_t conf; + + /* Status */ + int *keep_running; /**< Pointer to edge loop stop/go flag */ + struct peer_info *curr_sn; /**< Currently active supernode. */ + uint8_t sn_wait; /**< Whether we are waiting for a supernode response. */ + uint8_t sn_pong; /**< Whether we have seen a PONG since last time reset. */ + size_t sup_attempts; /**< Number of remaining attempts to this supernode. */ + tuntap_dev device; /**< All about the TUNTAP device */ + n2n_trans_op_t transop; /**< The transop to use when encoding */ + n2n_trans_op_t transop_lzo; /**< The transop for LZO compression */ +#ifdef HAVE_ZSTD + n2n_trans_op_t transop_zstd; /**< The transop for ZSTD compression */ +#endif + n2n_route_t *sn_route_to_clean; /**< Supernode route to clean */ + n2n_edge_callbacks_t cb; /**< API callbacks */ + void *user_data; /**< Can hold user data */ + SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_common_data; + + /* Sockets */ + /* supernode socket is in eee->curr_sn->sock (of type n2n_sock_t) */ + int sock; + int close_socket_counter; /**< counter for close-event before re-opening */ + int udp_mgmt_sock; /**< socket for status info. */ + +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + n2n_sock_t multicast_peer; /**< Multicast peer group (for local edges) */ + int udp_multicast_sock; /**< socket for local multicast registrations. */ + int multicast_joined; /**< 1 if the group has been joined.*/ +#endif + + /* Peers */ + struct peer_info * known_peers; /**< Edges we are connected to. */ + struct peer_info * pending_peers; /**< Edges we have tried to register with. */ + + /* Timers */ + time_t last_register_req; /**< Check if time to re-register with super*/ + time_t last_p2p; /**< Last time p2p traffic was received. */ + time_t last_sup; /**< Last time a packet arrived from supernode. */ + time_t last_sweep; /**< Last time a sweep was performed. */ + time_t start_time; /**< For calculating uptime */ + + + struct n2n_edge_stats stats; /**< Statistics */ + + n2n_resolve_parameter_t *resolve_parameter; /**< Pointer to name resolver's parameter block */ + uint8_t resolution_request; /**< Flag an immediate DNS resolution request */ + + n2n_port_map_parameter_t *port_map_parameter; /**< Pointer to port mapping thread's parameter block */ + + n2n_tuntap_priv_config_t tuntap_priv_conf; /**< Tuntap config */ + + network_traffic_filter_t *network_traffic_filter; +}; + +typedef struct sn_stats { + size_t errors; /* Number of errors encountered. */ + size_t reg_super; /* Number of REGISTER_SUPER requests received. */ + size_t reg_super_nak; /* Number of REGISTER_SUPER requests declined. */ + size_t fwd; /* Number of messages forwarded. */ + size_t broadcast; /* Number of messages broadcast to a community. */ + time_t last_fwd; /* Time when last message was forwarded. */ + time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */ +} sn_stats_t; + +typedef struct node_supernode_association { + + n2n_mac_t mac; /* mac address of an edge */ + const struct sockaddr_in sock; /* network order socket of that edge's supernode */ + time_t last_seen; /* time mark to keep track of purging requirements */ + + UT_hash_handle hh; /* makes this structure hashable */ +} node_supernode_association_t; + +typedef struct sn_user { + n2n_private_public_key_t public_key; + n2n_private_public_key_t shared_secret; + he_context_t *shared_secret_ctx; + n2n_desc_t name; + + UT_hash_handle hh; +} sn_user_t; + +struct sn_community { + char community[N2N_COMMUNITY_SIZE]; + uint8_t is_federation; /* if not-zero, then the current community is the federation of supernodes */ + uint8_t purgeable; /* indicates purgeable community (fixed-name, predetermined (-c parameter) communties usually are unpurgeable) */ + uint8_t header_encryption; /* Header encryption indicator. */ + he_context_t *header_encryption_ctx_static; /* Header encryption cipher context. */ + he_context_t *header_encryption_ctx_dynamic; /* Header encryption cipher context. */ + he_context_t *header_iv_ctx_static; /* Header IV encryption cipher context, REMOVE as soon as separate fields for checksum and replay protection available */ + he_context_t *header_iv_ctx_dynamic; /* Header IV encryption cipher context, REMOVE as soon as separate fields for checksum and replay protection available */ + uint8_t dynamic_key[N2N_AUTH_CHALLENGE_SIZE]; /* dynamic key */ + struct peer_info *edges; /* Link list of registered edges. */ + node_supernode_association_t *assoc; /* list of other edges from this community and their supernodes */ + sn_user_t *allowed_users; /* list of allowed users */ + int64_t number_enc_packets; /* Number of encrypted packets handled so far, required for sorting from time to time */ + n2n_ip_subnet_t auto_ip_net; /* Address range of auto ip address service. */ + + UT_hash_handle hh; /* makes this structure hashable */ +}; + +/* Typedef'd pointer to get abstract datatype. */ +typedef struct regex_t* re_t; + +struct sn_community_regular_expression { + re_t rule; /* compiles regular expression */ + + UT_hash_handle hh; /* makes this structure hashable */ +}; + + +typedef struct n2n_tcp_connection { + int socket_fd; /* file descriptor for tcp socket */ + struct sockaddr sock; /* network order socket */ + + uint16_t expected; /* number of bytes expected to be read */ + uint16_t position; /* current position in the buffer */ + uint8_t buffer[N2N_PKT_BUF_SIZE + sizeof(uint16_t)]; /* buffer for data collected from tcp socket incl. prepended length */ + uint8_t inactive; /* connection not be handled if set, already closed and to be deleted soon */ + + UT_hash_handle hh; /* makes this structure hashable */ +} n2n_tcp_connection_t; + + +typedef struct n2n_sn { + int *keep_running; /* Pointer to sn loop stop/go flag */ + time_t start_time; /* Used to measure uptime. */ + n2n_version_t version; /* version string sent to edges along with PEER_INFO a.k.a. PONG */ + sn_stats_t stats; + int daemon; /* If non-zero then daemonise. */ + n2n_mac_t mac_addr; + uint16_t lport; /* Local UDP port to bind to. */ + uint16_t mport; /* Management UDP port to bind to. */ + int sock; /* Main socket for UDP traffic with edges. */ + int tcp_sock; /* auxiliary socket for optional TCP connections */ + n2n_tcp_connection_t *tcp_connections;/* list of established TCP connections */ + int mgmt_sock; /* management socket. */ + n2n_ip_subnet_t min_auto_ip_net; /* Address range of auto_ip service. */ + n2n_ip_subnet_t max_auto_ip_net; /* Address range of auto_ip service. */ +#ifndef WIN32 + uid_t userid; + gid_t groupid; +#endif + int lock_communities; /* If true, only loaded and matching communities can be used. */ + char *community_file; + struct sn_community *communities; + struct sn_community_regular_expression *rules; + struct sn_community *federation; + n2n_private_public_key_t private_key; /* private federation key derived from federation name */ + n2n_auth_t auth; + uint32_t dynamic_key_time; /* UTC time of last dynamic key generation (second accuracy) */ + uint8_t override_spoofing_protection; /* set if overriding MAC/IP spoofing protection (cli option '-M') */ + n2n_resolve_parameter_t *resolve_parameter;/*Pointer to name resolver's parameter block */ + uint64_t mgmt_password_hash;/* contains hash of managament port password */ +} n2n_sn_t; + + +/* *************************************************** */ + +#endif /* _N2N_TYPEDEFS_H_ */ diff --git a/include/n2n_wire.h b/include/n2n_wire.h new file mode 100644 index 0000000..6ca11ed --- /dev/null +++ b/include/n2n_wire.h @@ -0,0 +1,226 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#if !defined( N2N_WIRE_H_ ) +#define N2N_WIRE_H_ + +#include +#ifndef _MSC_VER +/* Not included in Visual Studio 2008 */ +#include +#endif + +#if defined(WIN32) +#include "n2n_win32.h" +#else /* #if defined(WIN32) */ +#include +#include /* AF_INET and AF_INET6 */ +#endif /* #if defined(WIN32) */ + +#include "sn_selection.h" + + +int encode_uint8 (uint8_t * base, + size_t * idx, + const uint8_t v); + +int decode_uint8 (uint8_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_uint16 (uint8_t * base, + size_t * idx, + const uint16_t v); + +int decode_uint16 (uint16_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_uint32 (uint8_t * base, + size_t * idx, + const uint32_t v); + +int decode_uint32 (uint32_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_uint64 (uint8_t * base, + size_t * idx, + const uint64_t v); + +int decode_uint64 (uint64_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_buf (uint8_t * base, + size_t * idx, + const void * p, + size_t s); + +int decode_buf (uint8_t * out, + size_t bufsize, + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_mac (uint8_t * base, + size_t * idx, + const n2n_mac_t m); + +int decode_mac (n2n_mac_t out, + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_cookie (uint8_t * base, + size_t * idx, + const n2n_cookie_t c); + +int decode_cookie (n2n_cookie_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_common (uint8_t * base, + size_t * idx, + const n2n_common_t * common); + +int decode_common (n2n_common_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_sock (uint8_t * base, + size_t * idx, + const n2n_sock_t * sock); + +int decode_sock (n2n_sock_t * sock, + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_REGISTER (uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_t * reg); + +int decode_REGISTER (n2n_REGISTER_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_REGISTER_SUPER (uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_SUPER_t * reg); + +int decode_REGISTER_SUPER (n2n_REGISTER_SUPER_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_UNREGISTER_SUPER (uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_UNREGISTER_SUPER_t *unreg); + +int decode_UNREGISTER_SUPER (n2n_UNREGISTER_SUPER_t *unreg, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx); + +int encode_REGISTER_ACK (uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_ACK_t * reg); + +int decode_REGISTER_ACK (n2n_REGISTER_ACK_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_REGISTER_SUPER_ACK (uint8_t * base, + size_t * idx, + const n2n_common_t * cmn, + const n2n_REGISTER_SUPER_ACK_t * reg, + uint8_t * tmpbuf); + +int decode_REGISTER_SUPER_ACK (n2n_REGISTER_SUPER_ACK_t * reg, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx, + uint8_t * tmpbuf); + +int encode_REGISTER_SUPER_NAK (uint8_t * base, + size_t * idx, + const n2n_common_t * cmn, + const n2n_REGISTER_SUPER_NAK_t * nak); + +int decode_REGISTER_SUPER_NAK (n2n_REGISTER_SUPER_NAK_t * nak, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx); + +int fill_sockaddr (struct sockaddr * addr, + size_t addrlen, + const n2n_sock_t * sock); + +int encode_PACKET (uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_PACKET_t * pkt); + +int decode_PACKET (n2n_PACKET_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_PEER_INFO (uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_PEER_INFO_t * pkt); + +int decode_PEER_INFO (n2n_PEER_INFO_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx); + +int encode_QUERY_PEER (uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_QUERY_PEER_t * pkt); + +int decode_QUERY_PEER (n2n_QUERY_PEER_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx); + +#endif /* #if !defined( N2N_WIRE_H_ ) */ diff --git a/include/network_traffic_filter.h b/include/network_traffic_filter.h new file mode 100644 index 0000000..d3eda87 --- /dev/null +++ b/include/network_traffic_filter.h @@ -0,0 +1,37 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +// +// Zhou Bin +// + +#ifndef N2N_NETWORK_TRAFFIC_FILTER_H +#define N2N_NETWORK_TRAFFIC_FILTER_H + +#include "n2n_typedefs.h" + +network_traffic_filter_t* create_network_traffic_filter (); + +void destroy_network_traffic_filter (network_traffic_filter_t* filter); + +void network_traffic_filter_add_rule (network_traffic_filter_t* filter, filter_rule_t* rules); + +//rule_str format: src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/- +uint8_t process_traffic_filter_rule_str (const char* rule_str, filter_rule_t* rule_struct); + +#endif //N2N_NETWORK_TRAFFIC_FILTER_H diff --git a/include/pearson.h b/include/pearson.h new file mode 100644 index 0000000..908f24f --- /dev/null +++ b/include/pearson.h @@ -0,0 +1,36 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include +#include + +#include "portable_endian.h" + + +void pearson_hash_256 (uint8_t *out, const uint8_t *in, size_t len); + +void pearson_hash_128 (uint8_t *out, const uint8_t *in, size_t len); + +uint64_t pearson_hash_64 (const uint8_t *in, size_t len); + +uint32_t pearson_hash_32 (const uint8_t *in, size_t len); + +uint16_t pearson_hash_16 (const uint8_t *in, size_t len); + +void pearson_hash_init (); diff --git a/include/portable_endian.h b/include/portable_endian.h new file mode 100644 index 0000000..6b18236 --- /dev/null +++ b/include/portable_endian.h @@ -0,0 +1,245 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +// taken from +// https://raw.githubusercontent.com/pyca/bcrypt/master/src/_csrc/portable_endian.h +// as of June 11, 2020 + +// "License": Public Domain +// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. +// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to +// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it +// an example on how to get the endian conversion functions on different platforms. + +#ifndef PORTABLE_ENDIAN_H__ +#define PORTABLE_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +# define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) +/* Define necessary macros for the header to expose all fields. */ +# if !defined(_BSD_SOURCE) +# define _BSD_SOURCE +# endif +# if !defined(__USE_BSD) +# define __USE_BSD +# endif +# if !defined(_DEFAULT_SOURCE) +# define _DEFAULT_SOURCE +# endif +# include +# include +/* See http://linux.die.net/man/3/endian */ +# if defined(htobe16) && defined(htole16) && defined(be16toh) && defined(le16toh) && defined(htobe32) && defined(htole32) && defined(be32toh) && defined(htole32) && defined(htobe64) && defined(htole64) && defined(htobe64) && defined(be64toh) && defined(htole64) && defined(le64toh) +/* Do nothing. The macros we need already exist. */ +# elif !defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 9))) +# include +# if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN) +# define htobe16(x) htons(x) +# define htole16(x) (x) +# define be16toh(x) ntohs(x) +# define le16toh(x) (x) + +# define htobe32(x) htonl(x) +# define htole32(x) (x) +# define be32toh(x) ntohl(x) +# define le32toh(x) (x) + +# define htobe64(x) (((uint64_t)htonl(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)htonl(((uint32_t)(x)))) << 32)) +# define htole64(x) (x) +# define be64toh(x) (((uint64_t)ntohl(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)ntohl(((uint32_t)(x)))) << 32)) +# define le64toh(x) (x) +# elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN) +# define htobe16(x) (x) +# define htole16(x) (((((uint16_t)(x)) >> 8))|((((uint16_t)(x)) << 8))) +# define be16toh(x) (x) +# define le16toh(x) (((((uint16_t)(x)) >> 8))|((((uint16_t)(x)) << 8))) + +# define htobe32(x) (x) +# define htole32(x) (((uint32_t)htole16(((uint16_t)(((uint32_t)(x)) >> 16)))) | (((uint32_t)htole16(((uint16_t)(x)))) << 16)) +# define be32toh(x) (x) +# define le32toh(x) (((uint32_t)le16toh(((uint16_t)(((uint32_t)(x)) >> 16)))) | (((uint32_t)le16toh(((uint16_t)(x)))) << 16)) + +# define htobe64(x) (x) +# define htole64(x) (((uint64_t)htole32(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)htole32(((uint32_t)(x)))) << 32)) +# define be64toh(x) (x) +# define le64toh(x) (((uint64_t)le32toh(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)le32toh(((uint32_t)(x)))) << 32)) +# else +# error Byte Order not supported or not defined. +# endif +# endif + +#elif defined(__APPLE__) + +# include + +# define htobe16(x) OSSwapHostToBigInt16(x) +# define htole16(x) OSSwapHostToLittleInt16(x) +# define be16toh(x) OSSwapBigToHostInt16(x) +# define le16toh(x) OSSwapLittleToHostInt16(x) + +# define htobe32(x) OSSwapHostToBigInt32(x) +# define htole32(x) OSSwapHostToLittleInt32(x) +# define be32toh(x) OSSwapBigToHostInt32(x) +# define le32toh(x) OSSwapLittleToHostInt32(x) + +# define htobe64(x) OSSwapHostToBigInt64(x) +# define htole64(x) OSSwapHostToLittleInt64(x) +# define be64toh(x) OSSwapBigToHostInt64(x) +# define le64toh(x) OSSwapLittleToHostInt64(x) + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +# include + +#elif defined(__HAIKU__) + +# include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + +# include + +# if !defined(be16toh) + # define be16toh(x) betoh16(x) + # define le16toh(x) letoh16(x) +# endif + +# if !defined(be32toh) + # define be32toh(x) betoh32(x) + # define le32toh(x) letoh32(x) +# endif + +# if !defined(be64toh) + # define be64toh(x) betoh64(x) + # define le64toh(x) letoh64(x) +# endif + +#elif defined(__WINDOWS__) + +# if BYTE_ORDER == LITTLE_ENDIAN + +# define htobe16(x) _byteswap_ushort(x) +# define htole16(x) (x) +# define be16toh(x) _byteswap_ushort(x) +# define le16toh(x) (x) + +# define htobe32(x) _byteswap_ulong(x) +# define htole32(x) (x) +# define be32toh(x) _byteswap_ulong(x) +# define le32toh(x) (x) + +# define htobe64(x) (((uint64_t)htobe32(((uint32_t)(((uint64_t)(x)) >> 32))) & 0x00000000FFFFFFFFULL) | (((uint64_t)htobe32(((uint32_t)(x)))) << 32)) +# define be64toh(x) (((uint64_t)be32toh(((uint32_t)(((uint64_t)(x)) >> 32))) & 0x00000000FFFFFFFFULL) | (((uint64_t)be32toh(((uint32_t)(x)))) << 32)) +# define htole64(x) (x) +# define le64toh(x) (x) + +# elif BYTE_ORDER == BIG_ENDIAN + + /* that would be xbox 360 */ +# define htobe16(x) (x) +# define htole16(x) __builtin_bswap16(x) +# define be16toh(x) (x) +# define le16toh(x) __builtin_bswap16(x) + +# define htobe32(x) (x) +# define htole32(x) __builtin_bswap32(x) +# define be32toh(x) (x) +# define le32toh(x) __builtin_bswap32(x) + +# define htobe64(x) (x) +# define htole64(x) __builtin_bswap64(x) +# define be64toh(x) (x) +# define le64toh(x) __builtin_bswap64(x) + +# else + +# error byte order not supported + +# endif + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__sun) + +# include + +# define htobe16(x) BE_16(x) +# define htole16(x) LE_16(x) +# define be16toh(x) BE_16(x) +# define le16toh(x) LE_16(x) + +# define htobe32(x) BE_32(x) +# define htole32(x) LE_32(x) +# define be32toh(x) BE_32(x) +# define le32toh(x) LE_32(x) + +# define htobe64(x) BE_64(x) +# define htole64(x) LE_64(x) +# define be64toh(x) BE_64(x) +# define le64toh(x) LE_64(x) + +#elif defined _AIX /* AIX is always big endian */ +# define be64toh(x) (x) +# define be32toh(x) (x) +# define be16toh(x) (x) +# define le32toh(x) \ + ((((x) & 0xff) << 24) | \ + (((x) & 0xff00) << 8) | \ + (((x) & 0xff0000) >> 8) | \ + (((x) & 0xff000000) >> 24)) +# define le64toh(x) \ + ((((x) & 0x00000000000000ffL) << 56) | \ + (((x) & 0x000000000000ff00L) << 40) | \ + (((x) & 0x0000000000ff0000L) << 24) | \ + (((x) & 0x00000000ff000000L) << 8) | \ + (((x) & 0x000000ff00000000L) >> 8) | \ + (((x) & 0x0000ff0000000000L) >> 24) | \ + (((x) & 0x00ff000000000000L) >> 40) | \ + (((x) & 0xff00000000000000L) >> 56)) +# ifndef htobe64 +# define htobe64(x) be64toh(x) +# endif +# ifndef htobe32 +# define htobe32(x) be32toh(x) +# endif +# ifndef htobe16 +# define htobe16(x) be16toh(x) +# endif + + +#else + +# error platform not supported + +#endif + +#endif diff --git a/include/random_numbers.h b/include/random_numbers.h new file mode 100644 index 0000000..b998bcf --- /dev/null +++ b/include/random_numbers.h @@ -0,0 +1,69 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#ifndef RND_H +#define RND_H + + +#include +#include +#include /* time, clock */ + +#include "n2n.h" /* traceEvent */ + + +// syscall and inquiring random number from hardware generators might fail, so we will retry +#define RND_RETRIES 1000 + +#if defined (__linux__) +#include /* syscall, SYS_getrandom */ +#ifdef SYS_getrandom +#define GRND_NONBLOCK 1 +#include /* errno, EAGAIN */ +#endif +#endif + +#if defined (__RDRND__) || defined (__RDSEED__) +#include /* _rdrand64_step, rdseed4_step */ +#endif + +#if defined (WIN32) +#include // HCTYPTPROV, Crypt*-functions +#endif + + +typedef struct rn_generator_state_t { + uint64_t a, b; +} rn_generator_state_t; + +typedef struct splitmix64_state_t { + uint64_t s; +} splitmix64_state_t; + + +int n2n_srand (uint64_t seed); + +uint64_t n2n_rand (void); + +uint64_t n2n_seed (void); + +uint32_t n2n_rand_sqr (uint32_t max_n); + + +#endif // RND_H diff --git a/include/sn_selection.h b/include/sn_selection.h new file mode 100644 index 0000000..a55f52f --- /dev/null +++ b/include/sn_selection.h @@ -0,0 +1,46 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#ifndef _SN_SELECTION_ +#define _SN_SELECTION_ + +typedef char selection_criterion_str_t[SN_SELECTION_CRITERION_BUF_SIZE]; + +#include "n2n.h" + +/* selection criterion's functions */ +int sn_selection_criterion_init (peer_info_t *peer); +int sn_selection_criterion_default (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion); +int sn_selection_criterion_bad (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion); +int sn_selection_criterion_good (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion); +int sn_selection_criterion_calculate (n2n_edge_t *eee, peer_info_t *peer, SN_SELECTION_CRITERION_DATA_TYPE *data); + +/* common data's functions */ +int sn_selection_criterion_common_data_default (n2n_edge_t *eee); + +/* sorting function */ +int sn_selection_sort (peer_info_t **peer_list); + +/* gathering data function */ +SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_gather_data (n2n_sn_t *sss); + +/* management port output function */ +extern char * sn_selection_criterion_str (n2n_edge_t *eee, selection_criterion_str_t out, peer_info_t *peer); + + +#endif /* _SN_SELECTION_ */ diff --git a/include/speck.h b/include/speck.h new file mode 100644 index 0000000..686818b --- /dev/null +++ b/include/speck.h @@ -0,0 +1,142 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +// cipher SPECK -- 128 bit block size -- 128 and 256 bit key size -- CTR mode +// taken from (and modified: removed pure crypto-stream generation and seperated key expansion) +// https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/ + + +#ifndef SPECK_H +#define SPECK_H + + +#include +#include + +#include "portable_endian.h" + + +#define u32 uint32_t +#define u64 uint64_t + +#define N2N_SPECK_IVEC_SIZE 16 +#define SPECK_KEY_BYTES (256/8) + + +#if defined (__AVX512F__) // AVX512 support ----------------------------------------------------------------------- + + +#include +#include /* memcpy() */ + +#define u512 __m512i + +#define SPECK_ALIGNED_CTX 64 + +typedef struct { + u512 rk[34]; + u64 key[34]; + u32 keysize; +} speck_context_t; + + +#elif defined (__AVX2__) // AVX2 support -------------------------------------------------------------------------- + + +#include + +#define u256 __m256i + +#define SPECK_ALIGNED_CTX 32 + +typedef struct { + u256 rk[34]; + u64 key[34]; + u32 keysize; +} speck_context_t; + + +#elif defined (__SSE2__) // SSE support --------------------------------------------------------------------------- + + +#include + +#define u128 __m128i + +#define SPECK_ALIGNED_CTX 16 +#define SPECK_CTX_BYVAL 1 + +typedef struct { + u128 rk[34]; + u64 key[34]; + u32 keysize; +} speck_context_t; + + +#elif defined (__ARM_NEON) && defined (SPECK_ARM_NEON) // NEON support --------------------------------------- + + +#include + +#define u128 uint64x2_t + +typedef struct { + u128 rk[34]; + u64 key[34]; + u32 keysize; +} speck_context_t; + + +#else // plain C -------------------------------------------------------------------------------------------------- + + +typedef struct { + u64 key[34]; + u32 keysize; +} speck_context_t; + + +#endif // --------------------------------------------------------------------------------------------------------- + + +int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen, + const unsigned char *n, + speck_context_t *ctx); + +int speck_init (speck_context_t **ctx, const unsigned char *k, int keysize); + +int speck_deinit (speck_context_t *ctx); + + +// ---------------------------------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------------------------------- + + +// cipher SPECK -- 128 bit block size -- 128 bit key size -- ECB mode +// follows endianess rules as used in official implementation guide and NOT as in original 2013 cipher presentation +// used for IV in header encryption (one block) and challenge encryption (user/password) +// for now: just plain C -- probably no need for AVX, SSE, NEON + + +int speck_128_decrypt (unsigned char *inout, speck_context_t *ctx); + +int speck_128_encrypt (unsigned char *inout, speck_context_t *ctx); + + +#endif // SPECK_H diff --git a/include/tf.h b/include/tf.h new file mode 100644 index 0000000..5f13f76 --- /dev/null +++ b/include/tf.h @@ -0,0 +1,87 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +// taken (and modified) from github/fudanchii/twofish as of August 2020 +// which itself is a modified copy of Andrew T. Csillag's implementation +// published on github/drewcsillag/twofish + + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Andrew T. Csillag + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef TF_H +#define TF_H + + +#include +#include +#include + +#include "portable_endian.h" + + +#define TF_BLOCK_SIZE 16 +#define TF_IV_SIZE (TF_BLOCK_SIZE) + + +typedef struct tf_context_t { + int N; + uint32_t K[40]; + uint32_t QF[4][256]; +} tf_context_t; + + +int tf_ecb_decrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx); + +int tf_ecb_encrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx); + +int tf_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, tf_context_t *ctx); + +int tf_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, tf_context_t *ctx); + +int tf_init (const unsigned char *key, size_t key_size, tf_context_t **ctx); + +int tf_deinit (tf_context_t *ctx); + + +#endif // TF_H diff --git a/include/uthash.h b/include/uthash.h new file mode 100644 index 0000000..eca723d --- /dev/null +++ b/include/uthash.h @@ -0,0 +1,1249 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +/* +Copyright (c) 2003-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#define UTHASH_VERSION 2.1.0 + +#include /* memcmp, memset, strlen */ +#include /* ptrdiff_t */ +#include /* exit */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(DECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE(x) +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while (0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while (0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ +#if defined(_WIN32) +#if defined(_MSC_VER) && _MSC_VER >= 1600 +#include +#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif +#elif defined(__GNUC__) && !defined(__VXWORKS__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif +#ifndef uthash_bzero +#define uthash_bzero(a,n) memset(a,'\0',n) +#endif +#ifndef uthash_strlen +#define uthash_strlen(s) strlen(s) +#endif + +#ifdef uthash_memcmp +/* This warning will not catch programs that define uthash_memcmp AFTER including uthash.h. */ +#warning "uthash_memcmp is deprecated; please use HASH_KEYCMP instead" +#else +#define uthash_memcmp(a,b,n) memcmp(a,b,n) +#endif + +#ifndef HASH_KEYCMP +#define HASH_KEYCMP(a,b,n) uthash_memcmp(a,b,n) +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +#ifndef HASH_NONFATAL_OOM +#define HASH_NONFATAL_OOM 0 +#endif + +#if HASH_NONFATAL_OOM +/* malloc failures can be recovered from */ + +#ifndef uthash_nonfatal_oom +#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) +#define IF_HASH_NONFATAL_OOM(x) x + +#else +/* malloc failures result in lost memory, hash tables are unusable */ + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") +#define IF_HASH_NONFATAL_OOM(x) + +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhp */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +/* calculate the hash handle from element address elp */ +#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho))) + +#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ +do { \ + struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ + unsigned _hd_bkt; \ + HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + (head)->hh.tbl->buckets[_hd_bkt].count++; \ + _hd_hh_item->hh_next = NULL; \ + _hd_hh_item->hh_prev = NULL; \ +} while (0) + +#define HASH_VALUE(keyptr,keylen,hashv) \ +do { \ + HASH_FCN(keyptr, keylen, hashv); \ +} while (0) + +#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ + } \ + } \ +} while (0) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl,oomed) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ + } \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#else +#define HASH_BLOOM_MAKE(tbl,oomed) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0U +#endif + +#define HASH_MAKE_TABLE(hh,head,oomed) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ + if (!(head)->hh.tbl->buckets) { \ + HASH_RECORD_OOM(oomed); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } else { \ + uthash_bzero((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + uthash_free((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } \ + ) \ + } \ + } \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ +} while (0) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ +} while (0) + +#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ +} while (0) + +#define HASH_APPEND_LIST(hh, head, add) \ +do { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ +} while (0) + +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + do { \ + if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ + break; \ + } \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) + +#ifdef NO_DECLTYPE +#undef HASH_AKBI_INNER_LOOP +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + char *_hs_saved_head = (char*)(head); \ + do { \ + DECLTYPE_ASSIGN(head, _hs_iter); \ + if (cmpfcn(head, add) > 0) { \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + break; \ + } \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) +#endif + +#if HASH_NONFATAL_OOM + +#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ +do { \ + if (!(oomed)) { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + if (oomed) { \ + HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ + HASH_DELETE_HH(hh, head, &(add)->hh); \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } else { \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } \ + } else { \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ +} while (0) + +#else + +#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ +do { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ +} while (0) + +#endif + + +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ +do { \ + IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ + } else { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } else { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ +} while (0) + +#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ +do { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) + +#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ + HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) + +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ +do { \ + IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ +} while (0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) + +#define HASH_TO_BKT(hashv,num_bkts,bkt) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ +} while (0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ + HASH_DELETE_HH(hh, head, &(delptr)->hh) + +#define HASH_DELETE_HH(hh,head,delptrhh) \ +do { \ + struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } else { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) { \ + (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ + } else { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ +} while (0) + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ +do { \ + unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ + HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ +} while (0) +#define HASH_ADD_STR(head,strfield,add) \ +do { \ + unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ +} while (0) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ +do { \ + unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ +} while (0) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head,where) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + (where), (void*)_thh->hh_prev, (void*)_prev); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev != (char*)_thh->prev) { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", \ + (where), (void*)_thh->prev, (void*)_prev); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head,where) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,hashv) \ +do { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,hashv) \ +do { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char*)(key); \ + hashv = 0; \ + for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,hashv) \ +do { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char*)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ +} while (0) + +#define HASH_OAT(key,keylen,hashv) \ +do { \ + unsigned _ho_i; \ + const unsigned char *_ho_key=(const unsigned char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ +} while (0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,hashv) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned const char *_hj_key=(unsigned const char*)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ + case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ +} while (0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,hashv) \ +do { \ + unsigned const char *_sfh_key=(unsigned const char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0U; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ +} while (0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6bu; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35u; \ + _h ^= _h >> 16; \ +} while (0) + +#define HASH_MUR(key,keylen,hashv) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (int)(keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353u; \ + uint32_t _mur_c1 = 0xcc9e2d51u; \ + uint32_t _mur_c2 = 0x1b873593u; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \ + int _mur_i; \ + for (_mur_i = -_mur_nblocks; _mur_i != 0; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \ + _mur_k1=0; \ + switch ((keylen) & 3U) { \ + case 0: break; \ + case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \ + case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \ + case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (uint32_t)(keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ +} while (0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ +do { \ + if ((head).hh_head != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } else { \ + (out) = NULL; \ + } \ + while ((out) != NULL) { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ + if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } else { \ + (out) = NULL; \ + } \ + } \ +} while (0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ +do { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ + && !(addhh)->tbl->noexpand) { \ + HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + HASH_DEL_IN_BKT(head,addhh); \ + } \ + ) \ + } \ +} while (0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(head,delhh) \ +do { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ +} while (0) + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero(_he_new_buckets, \ + 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ + (tbl)->nonideal_items = 0; \ + for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ + _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh != NULL) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ + (tbl)->nonideal_items++; \ + if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ + _he_newbkt->expand_mult++; \ + } \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ + ((tbl)->ineff_expands+1U) : 0U; \ + if ((tbl)->ineff_expands > 1U) { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ + } \ +} while (0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ + _hs_psize++; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + if (_hs_q == NULL) { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ + if (_hs_psize == 0U) { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else if ((cmpfcn( \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ + )) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail != NULL ) { \ + _hs_tail->next = ((_hs_e != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) { \ + _hs_e->prev = ((_hs_tail != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if ((src) != NULL) { \ + for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) { \ + _last_elt_hh->next = _elt; \ + } \ + if ((dst) == NULL) { \ + DECLTYPE_ASSIGN(dst, _elt); \ + HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + uthash_nonfatal_oom(_elt); \ + (dst) = NULL; \ + continue; \ + } \ + ) \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ + (dst)->hh_dst.tbl->num_items++; \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ + HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ + _dst_hh->tbl = NULL; \ + uthash_nonfatal_oom(_elt); \ + continue; \ + } \ + ) \ + HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if ((head) != NULL) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } \ +} while (0) + +#define HASH_OVERHEAD(hh,head) \ + (((head) != NULL) ? ( \ + (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + \ + (HASH_BLOOM_BYTELEN))) : 0U) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1u +#define HASH_BLOOM_SIGNATURE 0xb12220f2u + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/legacy/README.md b/legacy/README.md new file mode 100644 index 0000000..174c114 --- /dev/null +++ b/legacy/README.md @@ -0,0 +1,33 @@ +# Removed Features + +This folder contains a list N2N legacy features which have been dropped due to +maintainance cost versus effective use and benefits. + +Multiple Transops +----------------- + +N2N used to initialize all the available transops and use the "tick" function of +the transops to decide which transop to use before sending a packet. This however +has the following problems: + +- It only works with the keyfile, whereas with normal encryption we inizialize and + keep structures that we don't need. +- It is unfeasable as an edge node is required to implement all the transops in order + to properly talk with other edge nodes (via keyfile). +- It rises the complexity of the code. +- It is not clear which transop will be used. +- Mixing multiple encyptions together is not necessarily a good idea to improve security + as a vulnerability in at least one encryption method will leak some information. + +Keyfile and Key Rotation +------------------------ + +The keyfile mechanism allowed N2N users to specify a keyfile to be used to periodically +rotate keys and encryption methods. However, it has the following problems: + +- This feature is obscure for most of the users and poorly documented. +- It is tightly integrated in the core whereas it is used by only a few people (if any). + +In conclusion the main problem is the complexity that it adds to the code. In a possible +future rework this could be integrated as an extention (e.g. a specific trasop) without +rising the core complexity. diff --git a/legacy/edge_keyschedule.c b/legacy/edge_keyschedule.c new file mode 100644 index 0000000..5e3af35 --- /dev/null +++ b/legacy/edge_keyschedule.c @@ -0,0 +1,103 @@ +typedef struct n2n_tostat { + uint8_t can_tx; /* Does this transop have a valid SA for encoding. */ + n2n_cipherspec_t tx_spec; /* If can_tx, the spec used to encode. */ +} n2n_tostat_t; + +typedef uint32_t n2n_sa_t; /* security association number */ +typedef int (*n2n_transaddspec_f)( struct n2n_trans_op * arg, + const n2n_cipherspec_t * cspec ); + +typedef n2n_tostat_t (*n2n_transtick_f)( struct n2n_trans_op * arg, + time_t now ); + +/** Read in a key-schedule file, parse the lines and pass each line to the + * appropriate trans_op for parsing of key-data and adding key-schedule + * entries. The lookup table of time->trans_op is constructed such that + * encoding can be passed to the correct trans_op. The trans_op internal table + * will then determine the best SA for that trans_op from the key schedule to + * use for encoding. */ + +static int edge_init_keyschedule(n2n_edge_t *eee) { +#define N2N_NUM_CIPHERSPECS 32 + + int retval = -1; + ssize_t numSpecs=0; + n2n_cipherspec_t specs[N2N_NUM_CIPHERSPECS]; + size_t i; + time_t now = time(NULL); + + numSpecs = n2n_read_keyfile(specs, N2N_NUM_CIPHERSPECS, eee->conf.keyschedule); + + if(numSpecs > 0) + { + traceEvent(TRACE_NORMAL, "keyfile = %s read -> %d specs.\n", optarg, (signed int)numSpecs); + + for (i=0; i < (size_t)numSpecs; ++i) + { + n2n_transform_t idx = (n2n_transform_t) specs[i].t; + if(idx != eee->transop.transform_id) { + traceEvent(TRACE_ERROR, "changing transop in keyschedule is not supported"); + retval = -1; + } + + if(eee->transop.addspec != NULL) + retval = eee->transop.addspec(&eee->transop, &(specs[i])); + + if (0 != retval) + { + traceEvent(TRACE_ERROR, "keyschedule failed to add spec[%u] to transop[%d].\n", + (unsigned int)i, idx); + + return retval; + } + } + + n2n_tick_transop(eee, now); + } + else + traceEvent(TRACE_ERROR, "Failed to process '%s'", eee->conf.keyschedule); + + return retval; +} + +#if 0 + if(recvlen >= 6) + { + if(0 == memcmp(udp_buf, "reload", 6)) + { + if(strlen(eee->conf.keyschedule) > 0) + { + if(edge_init_keyschedule(eee) == 0) + { + msg_len=0; + msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "> OK\n"); + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in)); + } + return; + } + } + } +#endif + +#if 0 + case'K': + { + if(conf->encrypt_key) { + traceEvent(TRACE_ERROR, "Error: -K and -k options are mutually exclusive"); + exit(1); + } else { + strncpy(conf->keyschedule, optargument, N2N_PATHNAME_MAXLEN-1); + /* strncpy does not add NULL if the source has no NULL. */ + conf->keyschedule[N2N_PATHNAME_MAXLEN-1] = 0; + + traceEvent(TRACE_NORMAL, "keyfile = '%s'\n", conf->keyschedule); + } + break; + } +#endif + +#if 0 + printf("-K | Specify a key schedule file to load. Not with -k.\n"); +#endif diff --git a/legacy/gen_keyfile.py b/legacy/gen_keyfile.py new file mode 100755 index 0000000..b6dc3e6 --- /dev/null +++ b/legacy/gen_keyfile.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +# (c) 2009 Richard Andrews + +# Program to generate a n2n_edge key schedule file for twofish keys +# Each key line consists of the following element +# +# +# where , are UNIX time_t values of key valid period +# is the transform ID (=2 for twofish) +# is twofish-specific data as follows +# _ + +import os +import sys +import time +import random + +NUM_KEYS=30 +KEY_LIFE=300 +KEY_LEN=16 + +now=time.time() +start_sa=random.randint( 0, 0xffffffff ) + +random.seed(now) # note now is a floating point time value + +def rand_key(): + key=str() + for i in range(0,KEY_LEN): + key += "%02x"%( random.randint( 0, 255) ) + + return key + +for i in range(0,NUM_KEYS): + from_time = now + (KEY_LIFE * (i-1) ) + until_time = now + (KEY_LIFE * (i+1) ) + key = rand_key() + sa_idx = start_sa + i + transform_id = random.randint( 2, 3 ) + + sys.stdout.write("%d %d %d %d_%s\n"%(from_time, until_time, transform_id,sa_idx, key) ) + + diff --git a/legacy/n2n_keyfile.c b/legacy/n2n_keyfile.c new file mode 100644 index 0000000..eda6c83 --- /dev/null +++ b/legacy/n2n_keyfile.c @@ -0,0 +1,216 @@ +/** + * (C) 2007-18 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" +#include "n2n_keyfile.h" +#include +#include +#include +#include + + +#ifdef WIN32 +char *strsep( char **ppsz_string, const char *psz_delimiters ) +{ + char *p; + char *psz_string = *ppsz_string; + if( !psz_string ) + return NULL; + + p = strpbrk( psz_string, psz_delimiters ); + if( !p ) + { + *ppsz_string = NULL; + return psz_string; + } + *p++ = '\0'; + + *ppsz_string = p; + return psz_string; +} +#endif + + +/* Parse hex nibbles in ascii until a non-nibble character is found. Nibble + * characters are 0-9, a-f and A-F. + * + * Return number of bytes parsed into keyBuf or a negative error code. + */ +ssize_t n2n_parse_hex( uint8_t * keyBuf, + size_t keyLen, + const char * textKey, + size_t textLen) +{ + ssize_t retval=0; + uint8_t * pout=keyBuf; + size_t octet=0; + const char * textEnd; + const char * pbeg; + + textEnd = textKey+textLen; + pbeg=textKey; + + while ( ( pbeg + 1 < textEnd ) && ( retval < (ssize_t)keyLen ) ) + { + if ( 1 != sscanf( pbeg, "%02x", (unsigned int*)&octet ) ) + { + retval=-1; + break; + } + + *pout = (octet & 0xff); + ++pout; + ++retval; + pbeg += 2; + } + + return retval; +} + + +static int parseKeyLine( n2n_cipherspec_t * spec, + const char * linein ) +{ + /* parameters are separated by whitespace */ + char line[N2N_KEYFILE_LINESIZE]; + char * lp=line; + const char * token; + strncpy( line, linein, N2N_KEYFILE_LINESIZE ); + + memset( spec, 0, sizeof( n2n_cipherspec_t ) ); + + /* decode valid_from time */ + token = strsep( &lp, DELIMITERS ); + if ( !token ) { goto error; } + spec->valid_from = atol(token); + + /* decode valid_until time */ + token = strsep( &lp, DELIMITERS ); + if ( !token ) { goto error; } + spec->valid_until = atol(token); + + /* decode the transform number */ + token = strsep( &lp, DELIMITERS ); + if ( !token ) { goto error; } + spec->t = atoi(token); + + /* The reset if opaque key data */ + token = strsep( &lp, DELIMITERS ); + if ( !token ) { goto error; } + strncpy( (char *)spec->opaque, token, N2N_MAX_KEYSIZE ); + spec->opaque_size=strlen( (char *)spec->opaque); + + return 0; + +error: + return -1; +} + + +#define SEP "/" + + +int validCipherSpec( const n2n_cipherspec_t * k, + time_t now ) +{ + if ( k->valid_until < k->valid_from ) { goto bad; } + if ( k->valid_from > now ) { goto bad; } + if ( k->valid_until < now ) { goto bad; } + + return 0; + +bad: + return -1; +} + +/* Read key control file and return the number of specs stored or a negative + * error code. + * + * As the specs are read in the from and until time values are compared to + * present time. Only those keys which are valid are stored. + */ +int n2n_read_keyfile( n2n_cipherspec_t * specs, /* fill out this array of cipherspecs */ + size_t numspecs, /* number of slots in the array. */ + const char * ctrlfile_path ) /* path to control file */ +{ + /* Each line contains one cipherspec. */ + + int retval=0; + FILE * fp=NULL; + size_t idx=0; + time_t now = time(NULL); + + traceEvent( TRACE_DEBUG, "Reading '%s'\n", ctrlfile_path ); + + fp = fopen( ctrlfile_path, "r" ); + if ( fp ) + { + /* Read the file a line a time with fgets. */ + char line[N2N_KEYFILE_LINESIZE]; + size_t lineNum=0; + + while ( idx < numspecs ) + { + n2n_cipherspec_t * k = &(specs[idx]); + fgets( line, N2N_KEYFILE_LINESIZE, fp ); + ++lineNum; + + if ( strlen(line) > 1 ) + { + if ( 0 == parseKeyLine( k, line ) ) + { + if ( k->valid_until > now ) + { + traceEvent( TRACE_INFO, " --> [%u] from %lu, until %lu, transform=%hu, data=%s\n", + idx, k->valid_from, k->valid_until, k->t, k->opaque ); + + ++retval; + ++idx; + } + else + { + traceEvent( TRACE_INFO, " --X [%u] from %lu, until %lu, transform=%hu, data=%s\n", + idx, k->valid_from, k->valid_until, k->t, k->opaque ); + + } + } + else + { + traceEvent( TRACE_WARNING, "Failed to decode line %u\n", lineNum ); + } + } + + if ( feof(fp) ) + { + break; + } + + line[0]=0; /* this line has been consumed */ + } + + fclose( fp); + fp=NULL; + } + else + { + traceEvent( TRACE_ERROR, "Failed to open '%s'\n", ctrlfile_path ); + retval = -1; + } + + return retval; +} diff --git a/legacy/n2n_keyfile.h b/legacy/n2n_keyfile.h new file mode 100644 index 0000000..05cdf60 --- /dev/null +++ b/legacy/n2n_keyfile.h @@ -0,0 +1,117 @@ +/** + * (C) 2007-18 - ntop.org and contributors + * + * 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 see + * + */ + +/** Key files + * + * Edge implements a very simple interface for getting instructions about + * rolling keys. + * + * Key definitions are written as individual files in /.key. The + * format of each key is a single line of hex nibbles as follows: + * + * 0102030405060708090a0b0c0d0e0f + * + * Any external key exchange mechanism can receive the key data write it into + * the keyfiles. + * + * To control which keys are active at what times the key control file is + * used. This is a single file which is periodically reread. It contains key + * definitions in chronological order with one line per key definition as + * follows: + * + * + * + * edge reads the key control file periodically to get updates in policy. edge + * holds a number of keys in memory. Data can be decoded if it was encoded by + * any of the keys still in memory. By having at least 2 keys in memory it + * allows for clock skew and transmission delay when encoder and decoder roll + * keys at slightly different times. The amount of overlap in the valid time + * ranges provides the tolerance to timing skews in the system. + * + * The keys have the same level of secrecy as any other user file. Existing + * UNIX permission systems can be used to provide access controls. + * + */ + +/** How Edge Uses The Key Schedule + * + * Edge provides state space for a number of transform algorithms. Each + * transform uses its state space to store the SA information for its keys as + * found in the key file. When a packet is received the transform ID is in + * plain text. The packets is then sent to that transform for decoding. Each + * transform can store its SA numbers differently (or not at all). The + * transform code then finds the SA number, then finds the cipher (with key) in + * the state space and uses this to decode the packet. + * + * To support this, as edge reads each key line, it passes it to the + * appropriate transform to parse the line and store the SA information in its + * state space. + * + * When encoding a packet, edge has several transforms and potentially valid + * SAs to choose from. To keep track of which one to use for encoding edge does + * its own book-keeping as each key line is passed to the transform code: it + * stores a lookup of valid_from -> transform. When encoding a packet it then + * just calls the transform with the best valid_from in the table. The + * transform's own state space has all the SAs for its keys and the best of + * those is chosen. + */ + +#if !defined( N2N_KEYFILE_H_ ) +#define N2N_KEYFILE_H_ + + +#include "n2n_wire.h" +#include + +#define N2N_MAX_KEYSIZE 256 /* bytes */ +#define N2N_MAX_NUM_CIPHERSPECS 8 +#define N2N_KEYPATH_SIZE 256 +#define N2N_KEYFILE_LINESIZE 256 + +/** This structure stores an encryption cipher spec. */ +struct n2n_cipherspec +{ + n2n_transform_t t; /* N2N_TRANSFORM_ID_xxx for this spec. */ + time_t valid_from; /* Start using the key at this time. */ + time_t valid_until; /* Key is valid if time < valid_until. */ + uint16_t opaque_size; /* Size in bytes of key. */ + uint8_t opaque[N2N_MAX_KEYSIZE];/* Key matter. */ +}; + +typedef struct n2n_cipherspec n2n_cipherspec_t; + + +static const char * const DELIMITERS=" \t\n\r"; + + +/** @return number of cipherspec items filled. */ +int n2n_read_keyfile( n2n_cipherspec_t * specs, /* fill out this array of cipherspecs */ + size_t numspecs, /* number of slots in the array. */ + const char * ctrlfile_path ); /* path to control file */ + +int validCipherSpec( const n2n_cipherspec_t * k, + time_t now ); + +ssize_t n2n_parse_hex( uint8_t * keyBuf, + size_t keyMax, + const char * textKey, + size_t textLen ); + +/*----------------------------------------------------------------------------*/ + +#endif /* #if !defined( N2N_KEYFILE_H_ ) */ diff --git a/legacy/transform_aes.c b/legacy/transform_aes.c new file mode 100644 index 0000000..7b198ff --- /dev/null +++ b/legacy/transform_aes.c @@ -0,0 +1,730 @@ +/** + * (C) 2007-18 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" +#include "n2n_transforms.h" + +#if defined(N2N_HAVE_AES) + +#include "openssl/aes.h" +#include "openssl/sha.h" +#ifndef _MSC_VER +/* Not included in Visual Studio 2008 */ +#include /* index() */ +#endif + +#define N2N_AES_NUM_SA 32 /* space for SAa */ + +#define N2N_AES_TRANSFORM_VERSION 1 /* version of the transform encoding */ +#define N2N_AES_IVEC_SIZE 32 /* Enough space for biggest AES ivec */ + +#define AES256_KEY_BYTES (256/8) +#define AES192_KEY_BYTES (192/8) +#define AES128_KEY_BYTES (128/8) + +typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE]; + +struct sa_aes +{ + n2n_cipherspec_t spec; /* cipher spec parameters */ + n2n_sa_t sa_id; /* security association index */ + AES_KEY enc_key; /* tx key */ + AES_KEY dec_key; /* tx key */ + AES_KEY iv_enc_key; /* key used to encrypt the IV */ + uint8_t iv_ext_val[AES128_KEY_BYTES]; /* key used to extend the random IV seed to full block size */ +}; + +typedef struct sa_aes sa_aes_t; + + +/** Aes transform state data. + * + * With a key-schedule in place this will be populated with a number of + * SAs. Each SA has a lifetime and some opque data. The opaque data for aes + * consists of the SA number and key material. + * + */ +struct transop_aes +{ + ssize_t tx_sa; + size_t num_sa; + sa_aes_t sa[N2N_AES_NUM_SA]; + u_int8_t psk_mode; +}; + +typedef struct transop_aes transop_aes_t; + +static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id ); +static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size, size_t sa_num); + +static int transop_deinit_aes( n2n_trans_op_t * arg ) +{ + transop_aes_t * priv = (transop_aes_t *)arg->priv; + size_t i; + + if ( priv ) + { + /* Memory was previously allocated */ + for (i=0; isa[i]); + + sa->sa_id=0; + } + + priv->num_sa=0; + priv->tx_sa=-1; + + free(priv); + } + + arg->priv=NULL; /* return to fully uninitialised state */ + + return 0; +} + +static size_t aes_choose_tx_sa( transop_aes_t * priv, const u_int8_t * peer_mac ) { + return priv->tx_sa; /* set in tick */ +} + +static ssize_t aes_choose_rx_sa( transop_aes_t * priv, const u_int8_t * peer_mac, ssize_t sa_rx) { + if(!priv->psk_mode) + return aes_find_sa(priv, sa_rx); + else + /* NOTE the sa_rx of the packet is ignored in this case */ + return 0; +} + +/* AES plaintext preamble */ +#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */ +#define TRANSOP_AES_SA_SIZE 4 +#define TRANSOP_AES_IV_SEED_SIZE 8 +#define TRANSOP_AES_PREAMBLE_SIZE (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_IV_SEED_SIZE) + +/* AES ciphertext preamble */ +#define TRANSOP_AES_NONCE_SIZE 4 + +/* Return the best acceptable AES key size (in bytes) given an input keysize. + * + * The value returned will be one of AES128_KEY_BYTES, AES192_KEY_BYTES or + * AES256_KEY_BYTES. + */ +static size_t aes_best_keysize(size_t numBytes) +{ + if (numBytes >= AES256_KEY_BYTES ) + { + return AES256_KEY_BYTES; + } + else if (numBytes >= AES192_KEY_BYTES) + { + return AES192_KEY_BYTES; + } + else + { + return AES128_KEY_BYTES; + } +} + +static void set_aes_cbc_iv(sa_aes_t *sa, n2n_aes_ivec_t ivec, uint64_t iv_seed) { + uint8_t iv_full[AES_BLOCK_SIZE]; + + /* Extend the seed to full block size via the fixed ext value */ + memcpy(iv_full, sa->iv_ext_val, sizeof(iv_seed)); // note: only 64bits used of 128 available + memcpy(iv_full + sizeof(iv_seed), &iv_seed, sizeof(iv_seed)); + + /* Encrypt the IV with secret key to make it unpredictable. + * As discussed in https://github.com/ntop/n2n/issues/72, it's important to + * have an unpredictable IV since the initial part of the packet plaintext + * can be easily reconstructed from plaintext headers and used by an attacker + * to perform differential analysis. + */ + AES_ecb_encrypt(iv_full, ivec, &sa->iv_enc_key, AES_ENCRYPT); +} + +/** The aes packet format consists of: + * + * - a 8-bit aes encoding version in clear text + * - a 32-bit SA number in clear text + * - a 64-bit random IV seed + * - ciphertext encrypted from a 32-bit nonce followed by the payload. + * + * [V|SSSS|II|nnnnDDDDDDDDDDDDDDDDDDDDD] + * |<------ encrypted ------>| + */ +static int transop_encode_aes( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len, + const uint8_t * peer_mac) +{ + int len2=-1; + transop_aes_t * priv = (transop_aes_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE] = {0}; + uint32_t * pnonce; + + if ( (in_len + TRANSOP_AES_NONCE_SIZE) <= N2N_PKT_BUF_SIZE ) + { + if ( (in_len + TRANSOP_AES_NONCE_SIZE + TRANSOP_AES_PREAMBLE_SIZE) <= out_len ) + { + int len=-1; + size_t idx=0; + sa_aes_t * sa; + size_t tx_sa_num = 0; + uint64_t iv_seed = 0; + uint8_t padding = 0; + n2n_aes_ivec_t enc_ivec = {0}; + + /* The transmit sa is periodically updated */ + tx_sa_num = aes_choose_tx_sa( priv, peer_mac ); + + sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */ + + traceEvent( TRACE_DEBUG, "encode_aes %lu with SA %lu.", in_len, sa->sa_id ); + + /* Encode the aes format version. */ + encode_uint8( outbuf, &idx, N2N_AES_TRANSFORM_VERSION ); + + /* Encode the security association (SA) number */ + encode_uint32( outbuf, &idx, sa->sa_id ); + + /* Generate and encode the IV seed. + * Using two calls to rand() because RAND_MAX is usually < 64bit + * (e.g. linux) and sometimes < 32bit (e.g. Windows). + */ + ((uint32_t*)&iv_seed)[0] = rand(); + ((uint32_t*)&iv_seed)[1] = rand(); + encode_buf(outbuf, &idx, &iv_seed, sizeof(iv_seed)); + + /* Encrypt the assembly contents and write the ciphertext after the SA. */ + len = in_len + TRANSOP_AES_NONCE_SIZE; + + /* The assembly buffer is a source for encrypting data. The nonce is + * written in first followed by the packet payload. The whole + * contents of assembly are encrypted. */ + pnonce = (uint32_t *)assembly; + *pnonce = rand(); + memcpy( assembly + TRANSOP_AES_NONCE_SIZE, inbuf, in_len ); + + /* Need at least one encrypted byte at the end for the padding. */ + len2 = ( (len / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* Round up to next whole AES adding at least one byte. */ + padding = (len2-len); + assembly[len2 - 1] = padding; + traceEvent( TRACE_DEBUG, "padding = %u, seed = %016lx", padding, iv_seed ); + + set_aes_cbc_iv(sa, enc_ivec, iv_seed); + + AES_cbc_encrypt( assembly, /* source */ + outbuf + TRANSOP_AES_PREAMBLE_SIZE, /* dest */ + len2, /* enc size */ + &(sa->enc_key), enc_ivec, AES_ENCRYPT ); + + len2 += TRANSOP_AES_PREAMBLE_SIZE; /* size of data carried in UDP. */ + } + else + { + traceEvent( TRACE_ERROR, "encode_aes outbuf too small." ); + } + } + else + { + traceEvent( TRACE_ERROR, "encode_aes inbuf too big to encrypt." ); + } + + return len2; +} + + +/* Search through the array of SAs to find the one with the required ID. + * + * @return array index where found or -1 if not found + */ +static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id ) +{ + size_t i; + + for (i=0; i < priv->num_sa; ++i) + { + const sa_aes_t * sa=NULL; + + sa = &(priv->sa[i]); + if (req_id == sa->sa_id) + { + return i; + } + } + + return -1; +} + + +/* See transop_encode_aes for packet format */ +static int transop_decode_aes( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len, + const uint8_t * peer_mac) +{ + int len=0; + transop_aes_t * priv = (transop_aes_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE]; + + if ( ( (in_len - TRANSOP_AES_PREAMBLE_SIZE) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */ + && (in_len >= (TRANSOP_AES_PREAMBLE_SIZE + TRANSOP_AES_NONCE_SIZE) ) /* Has at least version, SA, iv seed and nonce */ + ) + { + n2n_sa_t sa_rx; + ssize_t sa_idx=-1; + size_t rem=in_len; + size_t idx=0; + uint8_t aes_enc_ver=0; + uint64_t iv_seed=0; + + /* Get the encoding version to make sure it is supported */ + decode_uint8( &aes_enc_ver, inbuf, &rem, &idx ); + + if ( N2N_AES_TRANSFORM_VERSION == aes_enc_ver ) + { + /* Get the SA number and make sure we are decrypting with the right one. */ + decode_uint32( &sa_rx, inbuf, &rem, &idx ); + + sa_idx = aes_choose_rx_sa(priv, peer_mac, sa_rx); + + if ( sa_idx >= 0 ) + { + sa_aes_t * sa = &(priv->sa[sa_idx]); + + /* Get the IV seed */ + decode_buf((uint8_t *)&iv_seed, sizeof(iv_seed), inbuf, &rem, &idx); + + traceEvent( TRACE_DEBUG, "decode_aes %lu with SA %lu and seed %016lx", in_len, sa->sa_id, iv_seed ); + + len = (in_len - TRANSOP_AES_PREAMBLE_SIZE); + + if ( 0 == (len % AES_BLOCK_SIZE ) ) + { + uint8_t padding; + n2n_aes_ivec_t dec_ivec = {0}; + + set_aes_cbc_iv(sa, dec_ivec, iv_seed); + + AES_cbc_encrypt( (inbuf + TRANSOP_AES_PREAMBLE_SIZE), + assembly, /* destination */ + len, + &(sa->dec_key), + dec_ivec, AES_DECRYPT ); + + /* last byte is how much was padding: max value should be + * AES_BLOCKSIZE-1 */ + padding = assembly[ len-1 ] & 0xff; + + if ( len >= (padding + TRANSOP_AES_NONCE_SIZE)) + { + /* strictly speaking for this to be an ethernet packet + * it is going to need to be even bigger; but this is + * enough to prevent segfaults. */ + traceEvent( TRACE_DEBUG, "padding = %u", padding ); + len -= padding; + + len -= TRANSOP_AES_NONCE_SIZE; /* size of ethernet packet */ + + /* Step over 4-byte random nonce value */ + memcpy( outbuf, + assembly + TRANSOP_AES_NONCE_SIZE, + len ); + } + else + { + traceEvent( TRACE_WARNING, "UDP payload decryption failed." ); + } + } + else + { + traceEvent( TRACE_WARNING, "Encrypted length %d is not a multiple of AES_BLOCK_SIZE (%d)", len, AES_BLOCK_SIZE ); + len = 0; + } + + } + else + { + /* Wrong security association; drop the packet as it is undecodable. */ + traceEvent( TRACE_ERROR, "decode_aes SA number %lu not found.", sa_rx ); + + /* REVISIT: should be able to load a new SA at this point to complete the decoding. */ + } + } + else + { + /* Wrong security association; drop the packet as it is undecodable. */ + traceEvent( TRACE_ERROR, "decode_aes unsupported aes version %u.", aes_enc_ver ); + + /* REVISIT: should be able to load a new SA at this point to complete the decoding. */ + } + } + else + { + traceEvent( TRACE_ERROR, "decode_aes inbuf wrong size (%ul) to decrypt.", in_len ); + } + + return len; +} + +struct sha512_keybuf { + uint8_t enc_dec_key[AES256_KEY_BYTES]; /* The key to use for AES CBC encryption/decryption */ + uint8_t iv_enc_key[AES128_KEY_BYTES]; /* The key to use to encrypt the IV with AES ECB */ + uint8_t iv_ext_val[AES128_KEY_BYTES]; /* A value to extend the IV seed */ +}; /* size: SHA512_DIGEST_LENGTH */ + +/* NOTE: the caller should adjust priv->num_sa accordingly */ +static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size, size_t sa_num) { + sa_aes_t * sa = &(priv->sa[sa_num]); + size_t aes_keysize_bytes; + size_t aes_keysize_bits; + struct sha512_keybuf keybuf; + + /* Clear out any old possibly longer key matter. */ + memset( &(sa->enc_key), 0, sizeof(sa->enc_key) ); + memset( &(sa->dec_key), 0, sizeof(sa->dec_key) ); + memset( &(sa->iv_enc_key), 0, sizeof(sa->iv_enc_key) ); + memset( &(sa->iv_ext_val), 0, sizeof(sa->iv_ext_val) ); + + /* We still use aes_best_keysize (even not necessary since we hash the key + * into the 256bits enc_dec_key) to let the users choose the degree of encryption. + * Long keys will pick AES192 or AES256 with more robust but expensive encryption. + */ + aes_keysize_bytes = aes_best_keysize(key_size); + aes_keysize_bits = 8 * aes_keysize_bytes; + + /* Hash the main key to generate subkeys */ + SHA512(key, key_size, (u_char*)&keybuf); + + /* setup of enc_key/dec_key, used for the CBC encryption */ + AES_set_encrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(sa->enc_key)); + AES_set_decrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(sa->dec_key)); + + /* setup of iv_enc_key and iv_ext_val, used for generating the CBC IV */ + AES_set_encrypt_key(keybuf.iv_enc_key, sizeof(keybuf.iv_enc_key) * 8, &(sa->iv_enc_key)); + memcpy(sa->iv_ext_val, keybuf.iv_ext_val, sizeof(keybuf.iv_ext_val)); + + traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits key=%s.\n", + priv->sa[sa_num].sa_id, aes_keysize_bits, key); + + return(0); +} + +/* + * priv: pointer to transform state + * keybuf: buffer holding the key + * pstat: length of keybuf + */ +static void add_aes_key(transop_aes_t *priv, uint8_t *keybuf, ssize_t pstat) { + setup_aes_key(priv, keybuf, pstat, priv->num_sa); + ++(priv->num_sa); +} + +static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec ) +{ + int retval = 1; + ssize_t pstat=-1; + transop_aes_t * priv = (transop_aes_t *)arg->priv; + uint8_t keybuf[N2N_MAX_KEYSIZE]; + + if ( priv->num_sa < N2N_AES_NUM_SA ) + { + const char * op = (const char *)cspec->opaque; + const char * sep = index( op, '_' ); + + if ( sep ) + { + char tmp[256]; + size_t s; + + s = sep - op; + memcpy( tmp, cspec->opaque, s ); + tmp[s]=0; + + s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */ + + priv->sa[priv->num_sa].spec = *cspec; + priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10); + + memset( keybuf, 0, N2N_MAX_KEYSIZE ); + pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s ); + if ( pstat > 0 ) + { + add_aes_key(priv, keybuf, pstat); + retval = 0; + } + } + else + { + traceEvent( TRACE_ERROR, "transop_addspec_aes : bad key data - missing '_'.\n"); + } + } + else + { + traceEvent( TRACE_ERROR, "transop_addspec_aes : full.\n"); + } + + return retval; +} + + +static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now ) +{ + transop_aes_t * priv = (transop_aes_t *)arg->priv; + size_t i; + int found=0; + n2n_tostat_t r; + + memset( &r, 0, sizeof(r) ); + + traceEvent( TRACE_DEBUG, "transop_aes tick num_sa=%u now=%lu", priv->num_sa, now ); + + for ( i=0; i < priv->num_sa; ++i ) + { + if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) ) + { + time_t remaining = priv->sa[i].spec.valid_until - now; + + traceEvent( TRACE_INFO, "transop_aes choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining ); + priv->tx_sa=i; + found=1; + break; + } + else + { + traceEvent( TRACE_DEBUG, "transop_aes tick rejecting sa=%u %lu -> %lu", + priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until ); + } + } + + if ( 0==found) + { + traceEvent( TRACE_INFO, "transop_aes no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa ); + } + else + { + r.can_tx = 1; + r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC; + r.tx_spec = priv->sa[priv->tx_sa].spec; + } + + return r; +} + +static n2n_tostat_t transop_tick_aes_psk(n2n_trans_op_t * arg, time_t now) { + transop_aes_t * priv = (transop_aes_t *)arg->priv; + n2n_tostat_t r; + + memset(&r, 0, sizeof(r)); + + // Always tx + r.can_tx = 1; + r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC; + r.tx_spec = priv->sa[priv->tx_sa].spec; + + return r; +} + +int transop_aes_init( n2n_trans_op_t * ttt ) +{ + int retval = 1; + transop_aes_t * priv = NULL; + + if ( ttt->priv ) + { + transop_deinit_aes( ttt ); + } + + memset( ttt, 0, sizeof( n2n_trans_op_t ) ); + + priv = (transop_aes_t *) calloc(1, sizeof(transop_aes_t)); + + if ( NULL != priv ) + { + size_t i; + sa_aes_t * sa=NULL; + + /* install the private structure. */ + ttt->priv = priv; + priv->num_sa=0; + priv->tx_sa=0; /* We will use this sa index for encoding. */ + priv->psk_mode = 0; + + ttt->transform_id = N2N_TRANSFORM_ID_AESCBC; + ttt->addspec = transop_addspec_aes; + ttt->tick = transop_tick_aes; /* chooses a new tx_sa */ + ttt->deinit = transop_deinit_aes; + ttt->fwd = transop_encode_aes; + ttt->rev = transop_decode_aes; + + for(i=0; isa[i]); + sa->sa_id=0; + memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) ); + memset( &(sa->enc_key), 0, sizeof(sa->enc_key) ); + memset( &(sa->dec_key), 0, sizeof(sa->dec_key) ); + memset( &(sa->iv_enc_key), 0, sizeof(sa->iv_enc_key) ); + memset( &(sa->iv_ext_val), 0, sizeof(sa->iv_ext_val) ); + } + + retval = 0; + } + else + { + memset( ttt, 0, sizeof(n2n_trans_op_t) ); + traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" ); + } + + return retval; +} + +/* Setup AES in pre-shared key mode */ +int transop_aes_setup_psk(n2n_trans_op_t *ttt, + n2n_sa_t sa_num, + uint8_t *encrypt_pwd, + uint32_t encrypt_pwd_len) { + int retval = 1; + transop_aes_t *priv = (transop_aes_t *)ttt->priv; + + if(ttt->priv) { + /* Replace the tick function with the PSK version of it */ + ttt->tick = transop_tick_aes_psk; + priv->psk_mode = 1; + priv->num_sa=0; + priv->tx_sa=0; + + /* Setup the key to use for encryption/decryption */ + add_aes_key(priv, encrypt_pwd, encrypt_pwd_len); + + retval = 0; + } else + traceEvent(TRACE_ERROR, "AES priv is not allocated"); + + return retval; +} + +#else /* #if defined(N2N_HAVE_AES) */ + +struct transop_aes +{ + ssize_t tx_sa; +}; + +typedef struct transop_aes transop_aes_t; + + +static int transop_deinit_aes( n2n_trans_op_t * arg ) +{ + transop_aes_t * priv = (transop_aes_t *)arg->priv; + + if ( priv ) + { + free(priv); + } + + arg->priv=NULL; /* return to fully uninitialised state */ + + return 0; +} + +static int transop_encode_aes( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + return -1; +} + +static int transop_decode_aes( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + return -1; +} + +static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec ) +{ + traceEvent( TRACE_DEBUG, "transop_addspec_aes AES not built into edge.\n"); + + return -1; +} + +static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now ) +{ + n2n_tostat_t r; + + memset( &r, 0, sizeof(r) ); + + return r; +} + +int transop_aes_init( n2n_trans_op_t * ttt ) +{ + int retval = 1; + transop_aes_t * priv = NULL; + + if ( ttt->priv ) + { + transop_deinit_aes( ttt ); + } + + memset( ttt, 0, sizeof( n2n_trans_op_t ) ); + + priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) ); + + if ( NULL != priv ) + { + /* install the private structure. */ + ttt->priv = priv; + priv->tx_sa=0; /* We will use this sa index for encoding. */ + + ttt->transform_id = N2N_TRANSFORM_ID_AESCBC; + ttt->addspec = transop_addspec_aes; + ttt->tick = transop_tick_aes; /* chooses a new tx_sa */ + ttt->deinit = transop_deinit_aes; + ttt->fwd = transop_encode_aes; + ttt->rev = transop_decode_aes; + + retval = 0; + } + else + { + memset( ttt, 0, sizeof(n2n_trans_op_t) ); + traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" ); + } + + return retval; +} + + +int transop_aes_setup_psk(n2n_trans_op_t *ttt, + n2n_sa_t sa_num, + uint8_t *encrypt_pwd, + uint32_t encrypt_pwd_len) { + return 0; +} + +#endif /* #if defined(N2N_HAVE_AES) */ + diff --git a/legacy/transform_tf.c b/legacy/transform_tf.c new file mode 100644 index 0000000..6b4d606 --- /dev/null +++ b/legacy/transform_tf.c @@ -0,0 +1,467 @@ +/** + * (C) 2007-18 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" +#include "n2n_transforms.h" +#include "twofish.h" +#ifndef _MSC_VER +/* Not included in Visual Studio 2008 */ +#include /* index() */ +#endif + +#define N2N_TWOFISH_NUM_SA 32 /* space for SAa */ + +#define N2N_TWOFISH_TRANSFORM_VERSION 1 /* version of the transform encoding */ + +struct sa_twofish +{ + n2n_cipherspec_t spec; /* cipher spec parameters */ + n2n_sa_t sa_id; /* security association index */ + TWOFISH * enc_tf; /* tx state */ + TWOFISH * dec_tf; /* rx state */ +}; + +typedef struct sa_twofish sa_twofish_t; + + +/** Twofish transform state data. + * + * With a key-schedule in place this will be populated with a number of + * SAs. Each SA has a lifetime and some opque data. The opaque data for twofish + * consists of the SA number and key material. + * + */ +struct transop_tf +{ + ssize_t tx_sa; + size_t num_sa; + sa_twofish_t sa[N2N_TWOFISH_NUM_SA]; +}; + +typedef struct transop_tf transop_tf_t; + +static int transop_deinit_twofish( n2n_trans_op_t * arg ) +{ + transop_tf_t * priv = (transop_tf_t *)arg->priv; + size_t i; + + if ( priv ) + { + /* Memory was previously allocated */ + for (i=0; isa[i]); + + TwoFishDestroy(sa->enc_tf); /* deallocate TWOFISH */ + sa->enc_tf=NULL; + + TwoFishDestroy(sa->dec_tf); /* deallocate TWOFISH */ + sa->dec_tf=NULL; + + sa->sa_id=0; + } + + priv->num_sa=0; + priv->tx_sa=-1; + + free(priv); + } + + arg->priv=NULL; /* return to fully uninitialised state */ + + return 0; +} + +static size_t tf_choose_tx_sa( transop_tf_t * priv ) +{ + return priv->tx_sa; /* set in tick */ +} + +#define TRANSOP_TF_VER_SIZE 1 /* Support minor variants in encoding in one module. */ +#define TRANSOP_TF_NONCE_SIZE 4 +#define TRANSOP_TF_SA_SIZE 4 + +/** The twofish packet format consists of: + * + * - a 8-bit twofish encoding version in clear text + * - a 32-bit SA number in clear text + * - ciphertext encrypted from a 32-bit nonce followed by the payload. + * + * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD] + * |<------ encrypted ------>| + */ +static int transop_encode_twofish( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len, + const uint8_t * peer_mac) +{ + int len=-1; + transop_tf_t * priv = (transop_tf_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE]; + uint32_t * pnonce; + + if ( (in_len + TRANSOP_TF_NONCE_SIZE) <= N2N_PKT_BUF_SIZE ) + { + if ( (in_len + TRANSOP_TF_NONCE_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_VER_SIZE) <= out_len ) + { + size_t idx=0; + sa_twofish_t * sa; + size_t tx_sa_num = 0; + + /* The transmit sa is periodically updated */ + tx_sa_num = tf_choose_tx_sa( priv ); + + sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */ + + traceEvent( TRACE_DEBUG, "encode_twofish %lu with SA %lu.", in_len, sa->sa_id ); + + /* Encode the twofish format version. */ + encode_uint8( outbuf, &idx, N2N_TWOFISH_TRANSFORM_VERSION ); + + /* Encode the security association (SA) number */ + encode_uint32( outbuf, &idx, sa->sa_id ); + + /* The assembly buffer is a source for encrypting data. The nonce is + * written in first followed by the packet payload. The whole + * contents of assembly are encrypted. */ + pnonce = (uint32_t *)assembly; + *pnonce = rand(); + memcpy( assembly + TRANSOP_TF_NONCE_SIZE, inbuf, in_len ); + + /* Encrypt the assembly contents and write the ciphertext after the SA. */ + len = TwoFishEncryptRaw( assembly, /* source */ + outbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE, + in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */ + sa->enc_tf); + if ( len > 0 ) + { + len += TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE; /* size of data carried in UDP. */ + } + else + { + traceEvent( TRACE_ERROR, "encode_twofish encryption failed." ); + } + + } + else + { + traceEvent( TRACE_ERROR, "encode_twofish outbuf too small." ); + } + } + else + { + traceEvent( TRACE_ERROR, "encode_twofish inbuf too big to encrypt." ); + } + + return len; +} + + +/* Search through the array of SAs to find the one with the required ID. + * + * @return array index where found or -1 if not found + */ +static ssize_t twofish_find_sa( const transop_tf_t * priv, const n2n_sa_t req_id ) +{ + size_t i; + + for (i=0; i < priv->num_sa; ++i) + { + const sa_twofish_t * sa=NULL; + + sa = &(priv->sa[i]); + if (req_id == sa->sa_id) + { + return i; + } + } + + return -1; +} + + +/** The twofish packet format consists of: + * + * - a 8-bit twofish encoding version in clear text + * - a 32-bit SA number in clear text + * - ciphertext encrypted from a 32-bit nonce followed by the payload. + * + * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD] + * |<------ encrypted ------>| + */ +static int transop_decode_twofish( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len, + const uint8_t * peer_mac) +{ + int len=0; + transop_tf_t * priv = (transop_tf_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE]; + + if ( ( (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */ + && (in_len >= (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_NONCE_SIZE) ) /* Has at least version, SA and nonce */ + ) + { + n2n_sa_t sa_rx; + ssize_t sa_idx=-1; + size_t rem=in_len; + size_t idx=0; + uint8_t tf_enc_ver=0; + + /* Get the encoding version to make sure it is supported */ + decode_uint8( &tf_enc_ver, inbuf, &rem, &idx ); + + if ( N2N_TWOFISH_TRANSFORM_VERSION == tf_enc_ver ) + { + /* Get the SA number and make sure we are decrypting with the right one. */ + decode_uint32( &sa_rx, inbuf, &rem, &idx ); + + sa_idx = twofish_find_sa(priv, sa_rx); + if ( sa_idx >= 0 ) + { + sa_twofish_t * sa = &(priv->sa[sa_idx]); + + traceEvent( TRACE_DEBUG, "decode_twofish %lu with SA %lu.", in_len, sa_rx, sa->sa_id ); + + len = TwoFishDecryptRaw( (void *)(inbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE), + assembly, /* destination */ + (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)), + sa->dec_tf); + + if ( len > 0 ) + { + /* Step over 4-byte random nonce value */ + len -= TRANSOP_TF_NONCE_SIZE; /* size of ethernet packet */ + + memcpy( outbuf, + assembly + TRANSOP_TF_NONCE_SIZE, + len ); + } + else + { + traceEvent( TRACE_ERROR, "decode_twofish decryption failed." ); + } + + } + else + { + /* Wrong security association; drop the packet as it is undecodable. */ + traceEvent( TRACE_ERROR, "decode_twofish SA number %lu not found.", sa_rx ); + + /* REVISIT: should be able to load a new SA at this point to complete the decoding. */ + } + } + else + { + /* Wrong security association; drop the packet as it is undecodable. */ + traceEvent( TRACE_ERROR, "decode_twofish unsupported twofish version %u.", tf_enc_ver ); + + /* REVISIT: should be able to load a new SA at this point to complete the decoding. */ + } + } + else + { + traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len ); + } + + return len; +} + +static int transop_addspec_twofish( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec ) +{ + int retval = 1; + ssize_t pstat=-1; + transop_tf_t * priv = (transop_tf_t *)arg->priv; + uint8_t keybuf[N2N_MAX_KEYSIZE]; + + if ( priv->num_sa < N2N_TWOFISH_NUM_SA ) + { + const char * op = (const char *)cspec->opaque; +#ifdef __ANDROID_NDK__ + const char *sep = strchr(op, '_'); +#else + const char * sep = index( op, '_' ); +#endif // __ANDROID_NDK__ + + if ( sep ) + { + char tmp[256]; + size_t s; + + s = sep - op; + memcpy( tmp, cspec->opaque, s ); + tmp[s]=0; + + s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */ + + priv->sa[priv->num_sa].spec = *cspec; + priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10); + + pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s ); + if ( pstat > 0 ) + { + priv->sa[priv->num_sa].enc_tf = TwoFishInit( keybuf, pstat); + priv->sa[priv->num_sa].dec_tf = TwoFishInit( keybuf, pstat); + + traceEvent( TRACE_DEBUG, "transop_addspec_twofish sa_id=%u data=%s.\n", + priv->sa[priv->num_sa].sa_id, sep+1); + + ++(priv->num_sa); + retval = 0; + } + } + else + { + traceEvent( TRACE_ERROR, "transop_addspec_twofish : bad key data - missing '_'.\n"); + } + } + else + { + traceEvent( TRACE_ERROR, "transop_addspec_twofish : full.\n"); + } + + return retval; +} + + +static n2n_tostat_t transop_tick_twofish( n2n_trans_op_t * arg, time_t now ) +{ + transop_tf_t * priv = (transop_tf_t *)arg->priv; + size_t i; + int found=0; + n2n_tostat_t r; + + memset( &r, 0, sizeof(r) ); + + traceEvent( TRACE_DEBUG, "transop_tf tick num_sa=%u", priv->num_sa ); + + for ( i=0; i < priv->num_sa; ++i ) + { + if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) ) + { + time_t remaining = priv->sa[i].spec.valid_until - now; + + traceEvent( TRACE_INFO, "transop_tf choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining ); + priv->tx_sa=i; + found=1; + break; + } + else + { + traceEvent( TRACE_DEBUG, "transop_tf tick rejecting sa=%u %lu -> %lu", + priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until ); + } + } + + if ( 0==found) + { + traceEvent( TRACE_INFO, "transop_tf no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa ); + } + else + { + r.can_tx = 1; + r.tx_spec.t = N2N_TRANSFORM_ID_TWOFISH; + r.tx_spec = priv->sa[priv->tx_sa].spec; + } + + return r; +} + +int transop_twofish_setup_psk( n2n_trans_op_t * ttt, + n2n_sa_t sa_num, + uint8_t * encrypt_pwd, + uint32_t encrypt_pwd_len ) +{ + int retval = 1; + transop_tf_t * priv = (transop_tf_t *)ttt->priv; + + if(priv) { + sa_twofish_t *sa; + + priv->num_sa=1; /* There is one SA in the array. */ + priv->tx_sa=0; + sa = &(priv->sa[priv->tx_sa]); + sa->sa_id=sa_num; + sa->spec.valid_until = 0x7fffffff; + + /* This is a preshared key setup. Both Tx and Rx are using the same security association. */ + + sa->enc_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len); + sa->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len); + + if ( (sa->enc_tf) && (sa->dec_tf) ) + retval = 0; + else + traceEvent( TRACE_ERROR, "transop_twofish_setup_psk" ); + } else + traceEvent( TRACE_ERROR, "twofish priv is not allocated" ); + + return retval; +} + +int transop_twofish_init( n2n_trans_op_t * ttt ) +{ + int retval = 1; + transop_tf_t * priv = NULL; + + if ( ttt->priv ) + { + transop_deinit_twofish( ttt ); + } + + memset( ttt, 0, sizeof( n2n_trans_op_t ) ); + + priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) ); + + if ( NULL != priv ) { + size_t i; + sa_twofish_t * sa=NULL; + + /* install the private structure. */ + ttt->priv = priv; + priv->num_sa=0; + priv->tx_sa=0; /* We will use this sa index for encoding. */ + + ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH; + ttt->addspec = transop_addspec_twofish; + ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */ + ttt->deinit = transop_deinit_twofish; + ttt->fwd = transop_encode_twofish; + ttt->rev = transop_decode_twofish; + + for(i=0; isa[i]); + sa->sa_id=0; + memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) ); + sa->enc_tf=NULL; + sa->dec_tf=NULL; + } + + retval = 0; + } else { + memset( ttt, 0, sizeof(n2n_trans_op_t) ); + traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" ); + } + + return retval; +} diff --git a/lzodefs.h b/lzodefs.h deleted file mode 100644 index 1805637..0000000 --- a/lzodefs.h +++ /dev/null @@ -1,1807 +0,0 @@ -/* lzodefs.h -- architecture, OS and compiler specific defines - - This file is part of the LZO real-time data compression library. - - Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - The LZO library 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 2 of - the License, or (at your option) any later version. - - The LZO library 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 the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Markus F.X.J. Oberhumer - - http://www.oberhumer.com/opensource/lzo/ - */ - - -#ifndef __LZODEFS_H_INCLUDED -#define __LZODEFS_H_INCLUDED 1 - -#if defined(__CYGWIN32__) && !defined(__CYGWIN__) -# define __CYGWIN__ __CYGWIN32__ -#endif -#if defined(__IBMCPP__) && !defined(__IBMC__) -# define __IBMC__ __IBMCPP__ -#endif -#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) -# define __INTEL_COMPILER __ICL -#endif -#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) -# define _ALL_SOURCE 1 -#endif -#if defined(__mips__) && defined(__R5900__) -# if !defined(__LONG_MAX__) -# define __LONG_MAX__ 9223372036854775807L -# endif -#endif -#if defined(__INTEL_COMPILER) && defined(__linux__) -# pragma warning(disable: 193) -#endif -#if defined(__KEIL__) && defined(__C166__) -# pragma warning disable = 322 -#elif 0 && defined(__C251__) -# pragma warning disable = 322 -#endif -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) -# if (_MSC_VER >= 1300) -# pragma warning(disable: 4668) -# endif -#endif -#if 0 && defined(__WATCOMC__) -# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) -# pragma warning 203 9 -# endif -#endif -#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) -# pragma option -h -#endif -#if 0 -#define LZO_0xffffL 0xfffful -#define LZO_0xffffffffL 0xfffffffful -#else -#define LZO_0xffffL 65535ul -#define LZO_0xffffffffL 4294967295ul -#endif -#if (LZO_0xffffL == LZO_0xffffffffL) -# error "your preprocessor is broken 1" -#endif -#if (16ul * 16384ul != 262144ul) -# error "your preprocessor is broken 2" -#endif -#if 0 -#if (32767 >= 4294967295ul) -# error "your preprocessor is broken 3" -#endif -#if (65535u >= 4294967295ul) -# error "your preprocessor is broken 4" -#endif -#endif -#if (UINT_MAX == LZO_0xffffL) -#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) -# if !defined(MSDOS) -# define MSDOS 1 -# endif -# if !defined(_MSDOS) -# define _MSDOS 1 -# endif -#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) -# if (__VERSION == 520) && (MB_LEN_MAX == 1) -# if !defined(__AZTEC_C__) -# define __AZTEC_C__ __VERSION -# endif -# if !defined(__DOS__) -# define __DOS__ 1 -# endif -# endif -#endif -#endif -#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) -# define ptrdiff_t long -# define _PTRDIFF_T_DEFINED -#endif -#if (UINT_MAX == LZO_0xffffL) -# undef __LZO_RENAME_A -# undef __LZO_RENAME_B -# if defined(__AZTEC_C__) && defined(__DOS__) -# define __LZO_RENAME_A 1 -# elif defined(_MSC_VER) && defined(MSDOS) -# if (_MSC_VER < 600) -# define __LZO_RENAME_A 1 -# elif (_MSC_VER < 700) -# define __LZO_RENAME_B 1 -# endif -# elif defined(__TSC__) && defined(__OS2__) -# define __LZO_RENAME_A 1 -# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) -# define __LZO_RENAME_A 1 -# elif defined(__PACIFIC__) && defined(DOS) -# if !defined(__far) -# define __far far -# endif -# if !defined(__near) -# define __near near -# endif -# endif -# if defined(__LZO_RENAME_A) -# if !defined(__cdecl) -# define __cdecl cdecl -# endif -# if !defined(__far) -# define __far far -# endif -# if !defined(__huge) -# define __huge huge -# endif -# if !defined(__near) -# define __near near -# endif -# if !defined(__pascal) -# define __pascal pascal -# endif -# if !defined(__huge) -# define __huge huge -# endif -# elif defined(__LZO_RENAME_B) -# if !defined(__cdecl) -# define __cdecl _cdecl -# endif -# if !defined(__far) -# define __far _far -# endif -# if !defined(__huge) -# define __huge _huge -# endif -# if !defined(__near) -# define __near _near -# endif -# if !defined(__pascal) -# define __pascal _pascal -# endif -# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) -# if !defined(__cdecl) -# define __cdecl cdecl -# endif -# if !defined(__pascal) -# define __pascal pascal -# endif -# endif -# undef __LZO_RENAME_A -# undef __LZO_RENAME_B -#endif -#if (UINT_MAX == LZO_0xffffL) -#if defined(__AZTEC_C__) && defined(__DOS__) -# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -#elif defined(_MSC_VER) && defined(MSDOS) -# if (_MSC_VER < 600) -# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -# endif -# if (_MSC_VER < 700) -# define LZO_BROKEN_INTEGRAL_PROMOTION 1 -# define LZO_BROKEN_SIZEOF 1 -# endif -#elif defined(__PACIFIC__) && defined(DOS) -# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -#elif defined(__TURBOC__) && defined(__MSDOS__) -# if (__TURBOC__ < 0x0150) -# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -# define LZO_BROKEN_INTEGRAL_PROMOTION 1 -# endif -# if (__TURBOC__ < 0x0200) -# define LZO_BROKEN_SIZEOF 1 -# endif -# if (__TURBOC__ < 0x0400) && defined(__cplusplus) -# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -# endif -#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) -# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -# define LZO_BROKEN_SIZEOF 1 -#endif -#endif -#if defined(__WATCOMC__) && (__WATCOMC__ < 900) -# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -#endif -#if defined(_CRAY) && defined(_CRAY1) -# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 -#endif -#define LZO_PP_STRINGIZE(x) #x -#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) -#define LZO_PP_CONCAT2(a,b) a ## b -#define LZO_PP_CONCAT3(a,b,c) a ## b ## c -#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d -#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e -#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) -#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) -#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) -#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) -#if 1 -#define LZO_CPP_STRINGIZE(x) #x -#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) -#define LZO_CPP_CONCAT2(a,b) a ## b -#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c -#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d -#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e -#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) -#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) -#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) -#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) -#endif -#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) -#if 1 && defined(__cplusplus) -# if !defined(__STDC_CONSTANT_MACROS) -# define __STDC_CONSTANT_MACROS 1 -# endif -# if !defined(__STDC_LIMIT_MACROS) -# define __STDC_LIMIT_MACROS 1 -# endif -#endif -#if defined(__cplusplus) -# define LZO_EXTERN_C extern "C" -#else -# define LZO_EXTERN_C extern -#endif -#if !defined(__LZO_OS_OVERRIDE) -#if defined(LZO_OS_FREESTANDING) -# define LZO_INFO_OS "freestanding" -#elif defined(LZO_OS_EMBEDDED) -# define LZO_INFO_OS "embedded" -#elif 1 && defined(__IAR_SYSTEMS_ICC__) -# define LZO_OS_EMBEDDED 1 -# define LZO_INFO_OS "embedded" -#elif defined(__CYGWIN__) && defined(__GNUC__) -# define LZO_OS_CYGWIN 1 -# define LZO_INFO_OS "cygwin" -#elif defined(__EMX__) && defined(__GNUC__) -# define LZO_OS_EMX 1 -# define LZO_INFO_OS "emx" -#elif defined(__BEOS__) -# define LZO_OS_BEOS 1 -# define LZO_INFO_OS "beos" -#elif defined(__Lynx__) -# define LZO_OS_LYNXOS 1 -# define LZO_INFO_OS "lynxos" -#elif defined(__OS400__) -# define LZO_OS_OS400 1 -# define LZO_INFO_OS "os400" -#elif defined(__QNX__) -# define LZO_OS_QNX 1 -# define LZO_INFO_OS "qnx" -#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) -# define LZO_OS_DOS32 1 -# define LZO_INFO_OS "dos32" -#elif defined(__BORLANDC__) && defined(__DPMI16__) -# define LZO_OS_DOS16 1 -# define LZO_INFO_OS "dos16" -#elif defined(__ZTC__) && defined(DOS386) -# define LZO_OS_DOS32 1 -# define LZO_INFO_OS "dos32" -#elif defined(__OS2__) || defined(__OS2V2__) -# if (UINT_MAX == LZO_0xffffL) -# define LZO_OS_OS216 1 -# define LZO_INFO_OS "os216" -# elif (UINT_MAX == LZO_0xffffffffL) -# define LZO_OS_OS2 1 -# define LZO_INFO_OS "os2" -# else -# error "check your limits.h header" -# endif -#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) -# define LZO_OS_WIN64 1 -# define LZO_INFO_OS "win64" -#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) -# define LZO_OS_WIN32 1 -# define LZO_INFO_OS "win32" -#elif defined(__MWERKS__) && defined(__INTEL__) -# define LZO_OS_WIN32 1 -# define LZO_INFO_OS "win32" -#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) -# if (UINT_MAX == LZO_0xffffL) -# define LZO_OS_WIN16 1 -# define LZO_INFO_OS "win16" -# elif (UINT_MAX == LZO_0xffffffffL) -# define LZO_OS_WIN32 1 -# define LZO_INFO_OS "win32" -# else -# error "check your limits.h header" -# endif -#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) -# if (UINT_MAX == LZO_0xffffL) -# define LZO_OS_DOS16 1 -# define LZO_INFO_OS "dos16" -# elif (UINT_MAX == LZO_0xffffffffL) -# define LZO_OS_DOS32 1 -# define LZO_INFO_OS "dos32" -# else -# error "check your limits.h header" -# endif -#elif defined(__WATCOMC__) -# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) -# define LZO_OS_DOS16 1 -# define LZO_INFO_OS "dos16" -# elif defined(__NT__) && (__WATCOMC__ < 1100) -# define LZO_OS_WIN32 1 -# define LZO_INFO_OS "win32" -# elif defined(__linux__) || defined(__LINUX__) -# define LZO_OS_POSIX 1 -# define LZO_INFO_OS "posix" -# else -# error "please specify a target using the -bt compiler option" -# endif -#elif defined(__palmos__) -# define LZO_OS_PALMOS 1 -# define LZO_INFO_OS "palmos" -#elif defined(__TOS__) || defined(__atarist__) -# define LZO_OS_TOS 1 -# define LZO_INFO_OS "tos" -#elif defined(macintosh) && !defined(__ppc__) -# define LZO_OS_MACCLASSIC 1 -# define LZO_INFO_OS "macclassic" -#elif defined(__VMS) -# define LZO_OS_VMS 1 -# define LZO_INFO_OS "vms" -#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) -# define LZO_OS_CONSOLE 1 -# define LZO_OS_CONSOLE_PS2 1 -# define LZO_INFO_OS "console" -# define LZO_INFO_OS_CONSOLE "ps2" -#elif (defined(__mips__) && defined(__psp__)) -# define LZO_OS_CONSOLE 1 -# define LZO_OS_CONSOLE_PSP 1 -# define LZO_INFO_OS "console" -# define LZO_INFO_OS_CONSOLE "psp" -#else -# define LZO_OS_POSIX 1 -# define LZO_INFO_OS "posix" -#endif -#if (LZO_OS_POSIX) -# if defined(_AIX) || defined(__AIX__) || defined(__aix__) -# define LZO_OS_POSIX_AIX 1 -# define LZO_INFO_OS_POSIX "aix" -# elif defined(__FreeBSD__) -# define LZO_OS_POSIX_FREEBSD 1 -# define LZO_INFO_OS_POSIX "freebsd" -# elif defined(__hpux__) || defined(__hpux) -# define LZO_OS_POSIX_HPUX 1 -# define LZO_INFO_OS_POSIX "hpux" -# elif defined(__INTERIX) -# define LZO_OS_POSIX_INTERIX 1 -# define LZO_INFO_OS_POSIX "interix" -# elif defined(__IRIX__) || defined(__irix__) -# define LZO_OS_POSIX_IRIX 1 -# define LZO_INFO_OS_POSIX "irix" -# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) -# define LZO_OS_POSIX_LINUX 1 -# define LZO_INFO_OS_POSIX "linux" -# elif defined(__APPLE__) || defined(__MACOS__) -# define LZO_OS_POSIX_MACOSX 1 -# define LZO_INFO_OS_POSIX "macosx" -# elif defined(__minix__) || defined(__minix) -# define LZO_OS_POSIX_MINIX 1 -# define LZO_INFO_OS_POSIX "minix" -# elif defined(__NetBSD__) -# define LZO_OS_POSIX_NETBSD 1 -# define LZO_INFO_OS_POSIX "netbsd" -# elif defined(__OpenBSD__) -# define LZO_OS_POSIX_OPENBSD 1 -# define LZO_INFO_OS_POSIX "openbsd" -# elif defined(__osf__) -# define LZO_OS_POSIX_OSF 1 -# define LZO_INFO_OS_POSIX "osf" -# elif defined(__solaris__) || defined(__sun) -# if defined(__SVR4) || defined(__svr4__) -# define LZO_OS_POSIX_SOLARIS 1 -# define LZO_INFO_OS_POSIX "solaris" -# else -# define LZO_OS_POSIX_SUNOS 1 -# define LZO_INFO_OS_POSIX "sunos" -# endif -# elif defined(__ultrix__) || defined(__ultrix) -# define LZO_OS_POSIX_ULTRIX 1 -# define LZO_INFO_OS_POSIX "ultrix" -# elif defined(_UNICOS) -# define LZO_OS_POSIX_UNICOS 1 -# define LZO_INFO_OS_POSIX "unicos" -# else -# define LZO_OS_POSIX_UNKNOWN 1 -# define LZO_INFO_OS_POSIX "unknown" -# endif -#endif -#endif -#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -# if (UINT_MAX != LZO_0xffffL) -# error "this should not happen" -# endif -# if (ULONG_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -#endif -#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) -# if (UINT_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -# if (ULONG_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -#endif -#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) -# define LZO_CC_CILLY 1 -# define LZO_INFO_CC "Cilly" -# if defined(__CILLY__) -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) -# else -# define LZO_INFO_CCVER "unknown" -# endif -#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) -# define LZO_CC_SDCC 1 -# define LZO_INFO_CC "sdcc" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) -#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) -# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) -# define LZO_INFO_CC "Pathscale C" -# define LZO_INFO_CCVER __PATHSCALE__ -#elif defined(__INTEL_COMPILER) -# define LZO_CC_INTELC 1 -# define LZO_INFO_CC "Intel C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) -# if defined(_WIN32) || defined(_WIN64) -# define LZO_CC_SYNTAX_MSC 1 -# else -# define LZO_CC_SYNTAX_GNUC 1 -# endif -#elif defined(__POCC__) && defined(_WIN32) -# define LZO_CC_PELLESC 1 -# define LZO_INFO_CC "Pelles C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) -#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__) -# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) -# else -# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) -# endif -# define LZO_INFO_CC "llvm-gcc" -# define LZO_INFO_CCVER __VERSION__ -#elif defined(__GNUC__) && defined(__VERSION__) -# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) -# elif defined(__GNUC_MINOR__) -# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) -# else -# define LZO_CC_GNUC (__GNUC__ * 0x10000L) -# endif -# define LZO_INFO_CC "gcc" -# define LZO_INFO_CCVER __VERSION__ -#elif defined(__ACK__) && defined(_ACK) -# define LZO_CC_ACK 1 -# define LZO_INFO_CC "Amsterdam Compiler Kit C" -# define LZO_INFO_CCVER "unknown" -#elif defined(__AZTEC_C__) -# define LZO_CC_AZTECC 1 -# define LZO_INFO_CC "Aztec C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) -#elif defined(__BORLANDC__) -# define LZO_CC_BORLANDC 1 -# define LZO_INFO_CC "Borland C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) -#elif defined(_CRAYC) && defined(_RELEASE) -# define LZO_CC_CRAYC 1 -# define LZO_INFO_CC "Cray C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) -#elif defined(__DMC__) && defined(__SC__) -# define LZO_CC_DMC 1 -# define LZO_INFO_CC "Digital Mars C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) -#elif defined(__DECC) -# define LZO_CC_DECC 1 -# define LZO_INFO_CC "DEC C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) -#elif defined(__HIGHC__) -# define LZO_CC_HIGHC 1 -# define LZO_INFO_CC "MetaWare High C" -# define LZO_INFO_CCVER "unknown" -#elif defined(__IAR_SYSTEMS_ICC__) -# define LZO_CC_IARC 1 -# define LZO_INFO_CC "IAR C" -# if defined(__VER__) -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) -# else -# define LZO_INFO_CCVER "unknown" -# endif -#elif defined(__IBMC__) -# define LZO_CC_IBMC 1 -# define LZO_INFO_CC "IBM C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) -#elif defined(__KEIL__) && defined(__C166__) -# define LZO_CC_KEILC 1 -# define LZO_INFO_CC "Keil C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) -#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) -# define LZO_CC_LCCWIN32 1 -# define LZO_INFO_CC "lcc-win32" -# define LZO_INFO_CCVER "unknown" -#elif defined(__LCC__) -# define LZO_CC_LCC 1 -# define LZO_INFO_CC "lcc" -# if defined(__LCC_VERSION__) -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) -# else -# define LZO_INFO_CCVER "unknown" -# endif -#elif defined(_MSC_VER) -# define LZO_CC_MSC 1 -# define LZO_INFO_CC "Microsoft C" -# if defined(_MSC_FULL_VER) -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) -# else -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) -# endif -#elif defined(__MWERKS__) -# define LZO_CC_MWERKS 1 -# define LZO_INFO_CC "Metrowerks C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) -#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) -# define LZO_CC_NDPC 1 -# define LZO_INFO_CC "Microway NDP C" -# define LZO_INFO_CCVER "unknown" -#elif defined(__PACIFIC__) -# define LZO_CC_PACIFICC 1 -# define LZO_INFO_CC "Pacific C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) -#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) -# define LZO_CC_PGI 1 -# define LZO_INFO_CC "Portland Group PGI C" -# define LZO_INFO_CCVER "unknown" -#elif defined(__PUREC__) && defined(__TOS__) -# define LZO_CC_PUREC 1 -# define LZO_INFO_CC "Pure C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) -#elif defined(__SC__) && defined(__ZTC__) -# define LZO_CC_SYMANTECC 1 -# define LZO_INFO_CC "Symantec C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) -#elif defined(__SUNPRO_C) -# define LZO_INFO_CC "SunPro C" -# if ((__SUNPRO_C)+0 > 0) -# define LZO_CC_SUNPROC __SUNPRO_C -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) -# else -# define LZO_CC_SUNPROC 1 -# define LZO_INFO_CCVER "unknown" -# endif -#elif defined(__SUNPRO_CC) -# define LZO_INFO_CC "SunPro C" -# if ((__SUNPRO_CC)+0 > 0) -# define LZO_CC_SUNPROC __SUNPRO_CC -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) -# else -# define LZO_CC_SUNPROC 1 -# define LZO_INFO_CCVER "unknown" -# endif -#elif defined(__TINYC__) -# define LZO_CC_TINYC 1 -# define LZO_INFO_CC "Tiny C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) -#elif defined(__TSC__) -# define LZO_CC_TOPSPEEDC 1 -# define LZO_INFO_CC "TopSpeed C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) -#elif defined(__WATCOMC__) -# define LZO_CC_WATCOMC 1 -# define LZO_INFO_CC "Watcom C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) -#elif defined(__TURBOC__) -# define LZO_CC_TURBOC 1 -# define LZO_INFO_CC "Turbo C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) -#elif defined(__ZTC__) -# define LZO_CC_ZORTECHC 1 -# define LZO_INFO_CC "Zortech C" -# if (__ZTC__ == 0x310) -# define LZO_INFO_CCVER "0x310" -# else -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) -# endif -#else -# define LZO_CC_UNKNOWN 1 -# define LZO_INFO_CC "unknown" -# define LZO_INFO_CCVER "unknown" -#endif -#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) -# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" -#endif -#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY) -# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) -# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) -# define LZO_ARCH_CRAY_MPP 1 -# elif defined(_CRAY1) -# define LZO_ARCH_CRAY_PVP 1 -# endif -# endif -#endif -#if !defined(__LZO_ARCH_OVERRIDE) -#if defined(LZO_ARCH_GENERIC) -# define LZO_INFO_ARCH "generic" -#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -# define LZO_ARCH_I086 1 -# define LZO_ARCH_IA16 1 -# define LZO_INFO_ARCH "i086" -#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) -# define LZO_ARCH_ALPHA 1 -# define LZO_INFO_ARCH "alpha" -#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) -# define LZO_ARCH_ALPHA 1 -# define LZO_INFO_ARCH "alpha" -#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) -# define LZO_ARCH_AMD64 1 -# define LZO_INFO_ARCH "amd64" -#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) -# define LZO_ARCH_ARM 1 -# define LZO_ARCH_ARM_THUMB 1 -# define LZO_INFO_ARCH "arm_thumb" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) -# define LZO_ARCH_ARM 1 -# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) -# define LZO_ARCH_ARM_THUMB 1 -# define LZO_INFO_ARCH "arm_thumb" -# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) -# define LZO_INFO_ARCH "arm" -# else -# define LZO_INFO_ARCH "arm" -# endif -#elif defined(__arm__) || defined(_M_ARM) -# define LZO_ARCH_ARM 1 -# define LZO_INFO_ARCH "arm" -#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) -# define LZO_ARCH_AVR 1 -# define LZO_INFO_ARCH "avr" -#elif defined(__bfin__) -# define LZO_ARCH_BLACKFIN 1 -# define LZO_INFO_ARCH "blackfin" -#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) -# define LZO_ARCH_C166 1 -# define LZO_INFO_ARCH "c166" -#elif defined(__cris__) -# define LZO_ARCH_CRIS 1 -# define LZO_INFO_ARCH "cris" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) -# define LZO_ARCH_EZ80 1 -# define LZO_INFO_ARCH "ez80" -#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) -# define LZO_ARCH_H8300 1 -# define LZO_INFO_ARCH "h8300" -#elif defined(__hppa__) || defined(__hppa) -# define LZO_ARCH_HPPA 1 -# define LZO_INFO_ARCH "hppa" -#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) -# define LZO_ARCH_I386 1 -# define LZO_ARCH_IA32 1 -# define LZO_INFO_ARCH "i386" -#elif (LZO_CC_ZORTECHC && defined(__I86__)) -# define LZO_ARCH_I386 1 -# define LZO_ARCH_IA32 1 -# define LZO_INFO_ARCH "i386" -#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) -# define LZO_ARCH_I386 1 -# define LZO_ARCH_IA32 1 -# define LZO_INFO_ARCH "i386" -#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) -# define LZO_ARCH_IA64 1 -# define LZO_INFO_ARCH "ia64" -#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) -# define LZO_ARCH_M16C 1 -# define LZO_INFO_ARCH "m16c" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) -# define LZO_ARCH_M16C 1 -# define LZO_INFO_ARCH "m16c" -#elif defined(__m32r__) -# define LZO_ARCH_M32R 1 -# define LZO_INFO_ARCH "m32r" -#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) -# define LZO_ARCH_M68K 1 -# define LZO_INFO_ARCH "m68k" -#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) -# define LZO_ARCH_MCS251 1 -# define LZO_INFO_ARCH "mcs251" -#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) -# define LZO_ARCH_MCS51 1 -# define LZO_INFO_ARCH "mcs51" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) -# define LZO_ARCH_MCS51 1 -# define LZO_INFO_ARCH "mcs51" -#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) -# define LZO_ARCH_MIPS 1 -# define LZO_INFO_ARCH "mips" -#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) -# define LZO_ARCH_MSP430 1 -# define LZO_INFO_ARCH "msp430" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) -# define LZO_ARCH_MSP430 1 -# define LZO_INFO_ARCH "msp430" -#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) -# define LZO_ARCH_POWERPC 1 -# define LZO_INFO_ARCH "powerpc" -#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) -# define LZO_ARCH_S390 1 -# define LZO_INFO_ARCH "s390" -#elif defined(__sh__) || defined(_M_SH) -# define LZO_ARCH_SH 1 -# define LZO_INFO_ARCH "sh" -#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) -# define LZO_ARCH_SPARC 1 -# define LZO_INFO_ARCH "sparc" -#elif defined(__SPU__) -# define LZO_ARCH_SPU 1 -# define LZO_INFO_ARCH "spu" -#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) -# define LZO_ARCH_Z80 1 -# define LZO_INFO_ARCH "z80" -#elif (LZO_ARCH_CRAY_PVP) -# if defined(_CRAYSV1) -# define LZO_ARCH_CRAY_SV1 1 -# define LZO_INFO_ARCH "cray_sv1" -# elif (_ADDR64) -# define LZO_ARCH_CRAY_T90 1 -# define LZO_INFO_ARCH "cray_t90" -# elif (_ADDR32) -# define LZO_ARCH_CRAY_YMP 1 -# define LZO_INFO_ARCH "cray_ymp" -# else -# define LZO_ARCH_CRAY_XMP 1 -# define LZO_INFO_ARCH "cray_xmp" -# endif -#else -# define LZO_ARCH_UNKNOWN 1 -# define LZO_INFO_ARCH "unknown" -#endif -#endif -#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) -# error "FIXME - missing define for CPU architecture" -#endif -#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) -# error "FIXME - missing WIN32 define for CPU architecture" -#endif -#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) -# error "FIXME - missing WIN64 define for CPU architecture" -#endif -#if (LZO_OS_OS216 || LZO_OS_WIN16) -# define LZO_ARCH_I086PM 1 -# define LZO_ARCH_IA16PM 1 -#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) -# define LZO_ARCH_I086PM 1 -# define LZO_ARCH_IA16PM 1 -#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) -# define LZO_ARCH_I086PM 1 -# define LZO_ARCH_IA16PM 1 -#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) -# define LZO_ARCH_I086PM 1 -# define LZO_ARCH_IA16PM 1 -#endif -#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM) -# error "this should not happen" -#endif -#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086) -# error "this should not happen" -#endif -#if (LZO_ARCH_I086) -# if (UINT_MAX != LZO_0xffffL) -# error "this should not happen" -# endif -# if (ULONG_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -#endif -#if (LZO_ARCH_I386) -# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) -# error "this should not happen" -# endif -# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) -# error "this should not happen" -# endif -# if (ULONG_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -#endif -#if !defined(__LZO_MM_OVERRIDE) -#if (LZO_ARCH_I086) -#if (UINT_MAX != LZO_0xffffL) -# error "this should not happen" -#endif -#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) -# define LZO_MM_TINY 1 -#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) -# define LZO_MM_HUGE 1 -#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) -# define LZO_MM_SMALL 1 -#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) -# define LZO_MM_MEDIUM 1 -#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) -# define LZO_MM_COMPACT 1 -#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) -# define LZO_MM_LARGE 1 -#elif (LZO_CC_AZTECC) -# if defined(_LARGE_CODE) && defined(_LARGE_DATA) -# define LZO_MM_LARGE 1 -# elif defined(_LARGE_CODE) -# define LZO_MM_MEDIUM 1 -# elif defined(_LARGE_DATA) -# define LZO_MM_COMPACT 1 -# else -# define LZO_MM_SMALL 1 -# endif -#elif (LZO_CC_ZORTECHC && defined(__VCM__)) -# define LZO_MM_LARGE 1 -#else -# error "unknown memory model" -#endif -#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -#define LZO_HAVE_MM_HUGE_PTR 1 -#define LZO_HAVE_MM_HUGE_ARRAY 1 -#if (LZO_MM_TINY) -# undef LZO_HAVE_MM_HUGE_ARRAY -#endif -#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) -# undef LZO_HAVE_MM_HUGE_PTR -# undef LZO_HAVE_MM_HUGE_ARRAY -#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) -# undef LZO_HAVE_MM_HUGE_ARRAY -#elif (LZO_CC_MSC && defined(_QC)) -# undef LZO_HAVE_MM_HUGE_ARRAY -# if (_MSC_VER < 600) -# undef LZO_HAVE_MM_HUGE_PTR -# endif -#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) -# undef LZO_HAVE_MM_HUGE_ARRAY -#endif -#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR) -# if (LZO_OS_DOS16) -# error "this should not happen" -# elif (LZO_CC_ZORTECHC) -# else -# error "this should not happen" -# endif -#endif -#ifdef __cplusplus -extern "C" { -#endif -#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) - extern void __near __cdecl _AHSHIFT(void); -# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) - extern void __near __cdecl _AHSHIFT(void); -# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) - extern void __near __cdecl _AHSHIFT(void); -# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) - extern void __near __cdecl _AHSHIFT(void); -# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) -# define LZO_MM_AHSHIFT 12 -#elif (LZO_CC_WATCOMC) - extern unsigned char _HShift; -# define LZO_MM_AHSHIFT ((unsigned) _HShift) -#else -# error "FIXME - implement LZO_MM_AHSHIFT" -#endif -#ifdef __cplusplus -} -#endif -#endif -#elif (LZO_ARCH_C166) -#if !defined(__MODEL__) -# error "FIXME - C166 __MODEL__" -#elif ((__MODEL__) == 0) -# define LZO_MM_SMALL 1 -#elif ((__MODEL__) == 1) -# define LZO_MM_SMALL 1 -#elif ((__MODEL__) == 2) -# define LZO_MM_LARGE 1 -#elif ((__MODEL__) == 3) -# define LZO_MM_TINY 1 -#elif ((__MODEL__) == 4) -# define LZO_MM_XTINY 1 -#elif ((__MODEL__) == 5) -# define LZO_MM_XSMALL 1 -#else -# error "FIXME - C166 __MODEL__" -#endif -#elif (LZO_ARCH_MCS251) -#if !defined(__MODEL__) -# error "FIXME - MCS251 __MODEL__" -#elif ((__MODEL__) == 0) -# define LZO_MM_SMALL 1 -#elif ((__MODEL__) == 2) -# define LZO_MM_LARGE 1 -#elif ((__MODEL__) == 3) -# define LZO_MM_TINY 1 -#elif ((__MODEL__) == 4) -# define LZO_MM_XTINY 1 -#elif ((__MODEL__) == 5) -# define LZO_MM_XSMALL 1 -#else -# error "FIXME - MCS251 __MODEL__" -#endif -#elif (LZO_ARCH_MCS51) -#if !defined(__MODEL__) -# error "FIXME - MCS51 __MODEL__" -#elif ((__MODEL__) == 1) -# define LZO_MM_SMALL 1 -#elif ((__MODEL__) == 2) -# define LZO_MM_LARGE 1 -#elif ((__MODEL__) == 3) -# define LZO_MM_TINY 1 -#elif ((__MODEL__) == 4) -# define LZO_MM_XTINY 1 -#elif ((__MODEL__) == 5) -# define LZO_MM_XSMALL 1 -#else -# error "FIXME - MCS51 __MODEL__" -#endif -#elif (LZO_ARCH_CRAY_PVP) -# define LZO_MM_PVP 1 -#else -# define LZO_MM_FLAT 1 -#endif -#if (LZO_MM_COMPACT) -# define LZO_INFO_MM "compact" -#elif (LZO_MM_FLAT) -# define LZO_INFO_MM "flat" -#elif (LZO_MM_HUGE) -# define LZO_INFO_MM "huge" -#elif (LZO_MM_LARGE) -# define LZO_INFO_MM "large" -#elif (LZO_MM_MEDIUM) -# define LZO_INFO_MM "medium" -#elif (LZO_MM_PVP) -# define LZO_INFO_MM "pvp" -#elif (LZO_MM_SMALL) -# define LZO_INFO_MM "small" -#elif (LZO_MM_TINY) -# define LZO_INFO_MM "tiny" -#else -# error "unknown memory model" -#endif -#endif -#if defined(SIZEOF_SHORT) -# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) -#endif -#if defined(SIZEOF_INT) -# define LZO_SIZEOF_INT (SIZEOF_INT) -#endif -#if defined(SIZEOF_LONG) -# define LZO_SIZEOF_LONG (SIZEOF_LONG) -#endif -#if defined(SIZEOF_LONG_LONG) -# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) -#endif -#if defined(SIZEOF___INT16) -# define LZO_SIZEOF___INT16 (SIZEOF___INT16) -#endif -#if defined(SIZEOF___INT32) -# define LZO_SIZEOF___INT32 (SIZEOF___INT32) -#endif -#if defined(SIZEOF___INT64) -# define LZO_SIZEOF___INT64 (SIZEOF___INT64) -#endif -#if defined(SIZEOF_VOID_P) -# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) -#endif -#if defined(SIZEOF_SIZE_T) -# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) -#endif -#if defined(SIZEOF_PTRDIFF_T) -# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) -#endif -#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) -#if !defined(LZO_SIZEOF_SHORT) -# if (LZO_ARCH_CRAY_PVP) -# define LZO_SIZEOF_SHORT 8 -# elif (USHRT_MAX == LZO_0xffffL) -# define LZO_SIZEOF_SHORT 2 -# elif (__LZO_LSR(USHRT_MAX,7) == 1) -# define LZO_SIZEOF_SHORT 1 -# elif (__LZO_LSR(USHRT_MAX,15) == 1) -# define LZO_SIZEOF_SHORT 2 -# elif (__LZO_LSR(USHRT_MAX,31) == 1) -# define LZO_SIZEOF_SHORT 4 -# elif (__LZO_LSR(USHRT_MAX,63) == 1) -# define LZO_SIZEOF_SHORT 8 -# elif (__LZO_LSR(USHRT_MAX,127) == 1) -# define LZO_SIZEOF_SHORT 16 -# else -# error "LZO_SIZEOF_SHORT" -# endif -#endif -#if !defined(LZO_SIZEOF_INT) -# if (LZO_ARCH_CRAY_PVP) -# define LZO_SIZEOF_INT 8 -# elif (UINT_MAX == LZO_0xffffL) -# define LZO_SIZEOF_INT 2 -# elif (UINT_MAX == LZO_0xffffffffL) -# define LZO_SIZEOF_INT 4 -# elif (__LZO_LSR(UINT_MAX,7) == 1) -# define LZO_SIZEOF_INT 1 -# elif (__LZO_LSR(UINT_MAX,15) == 1) -# define LZO_SIZEOF_INT 2 -# elif (__LZO_LSR(UINT_MAX,31) == 1) -# define LZO_SIZEOF_INT 4 -# elif (__LZO_LSR(UINT_MAX,63) == 1) -# define LZO_SIZEOF_INT 8 -# elif (__LZO_LSR(UINT_MAX,127) == 1) -# define LZO_SIZEOF_INT 16 -# else -# error "LZO_SIZEOF_INT" -# endif -#endif -#if !defined(LZO_SIZEOF_LONG) -# if (ULONG_MAX == LZO_0xffffffffL) -# define LZO_SIZEOF_LONG 4 -# elif (__LZO_LSR(ULONG_MAX,7) == 1) -# define LZO_SIZEOF_LONG 1 -# elif (__LZO_LSR(ULONG_MAX,15) == 1) -# define LZO_SIZEOF_LONG 2 -# elif (__LZO_LSR(ULONG_MAX,31) == 1) -# define LZO_SIZEOF_LONG 4 -# elif (__LZO_LSR(ULONG_MAX,63) == 1) -# define LZO_SIZEOF_LONG 8 -# elif (__LZO_LSR(ULONG_MAX,127) == 1) -# define LZO_SIZEOF_LONG 16 -# else -# error "LZO_SIZEOF_LONG" -# endif -#endif -#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) -#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) -# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) -# if (LZO_CC_GNUC >= 0x030300ul) -# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) -# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG -# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) -# define LZO_SIZEOF_LONG_LONG 4 -# endif -# endif -# endif -#endif -#endif -#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) -#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) -#if (LZO_ARCH_I086 && LZO_CC_DMC) -#elif (LZO_CC_CILLY) && defined(__GNUC__) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define LZO_SIZEOF_LONG_LONG 8 -#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_OS_WIN64 || defined(_WIN64)) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) -# define LZO_SIZEOF___INT64 8 -#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) -#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -# define LZO_SIZEOF_LONG_LONG 8 -#endif -#endif -#endif -#if defined(__cplusplus) && defined(LZO_CC_GNUC) -# if (LZO_CC_GNUC < 0x020800ul) -# undef LZO_SIZEOF_LONG_LONG -# endif -#endif -#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) -# undef LZO_SIZEOF_LONG_LONG -#endif -#if !defined(LZO_SIZEOF_VOID_P) -#if (LZO_ARCH_I086) -# define __LZO_WORDSIZE 2 -# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) -# define LZO_SIZEOF_VOID_P 2 -# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) -# define LZO_SIZEOF_VOID_P 4 -# else -# error "LZO_MM" -# endif -#elif (LZO_ARCH_AVR || LZO_ARCH_Z80) -# define __LZO_WORDSIZE 1 -# define LZO_SIZEOF_VOID_P 2 -#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) -# define LZO_SIZEOF_VOID_P 2 -#elif (LZO_ARCH_H8300) -# if defined(__NORMAL_MODE__) -# define __LZO_WORDSIZE 4 -# define LZO_SIZEOF_VOID_P 2 -# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) -# define __LZO_WORDSIZE 4 -# define LZO_SIZEOF_VOID_P 4 -# else -# define __LZO_WORDSIZE 2 -# define LZO_SIZEOF_VOID_P 2 -# endif -# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT -# endif -#elif (LZO_ARCH_M16C) -# define __LZO_WORDSIZE 2 -# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) -# define LZO_SIZEOF_VOID_P 4 -# else -# define LZO_SIZEOF_VOID_P 2 -# endif -#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) -# define __LZO_WORDSIZE 8 -# define LZO_SIZEOF_VOID_P 4 -#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) -# define __LZO_WORDSIZE 8 -# define LZO_SIZEOF_VOID_P 8 -#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) -# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG -#elif (LZO_OS_OS400 || defined(__OS400__)) -# define __LZO_WORDSIZE LZO_SIZEOF_LONG -# define LZO_SIZEOF_VOID_P 16 -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG -#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) -# define LZO_SIZEOF_VOID_P 8 -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG -#elif (LZO_ARCH_SPU) -# if 0 -# define __LZO_WORDSIZE 16 -# endif -# define LZO_SIZEOF_VOID_P 4 -#else -# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG -#endif -#endif -#if !defined(LZO_WORDSIZE) -# if defined(__LZO_WORDSIZE) -# define LZO_WORDSIZE __LZO_WORDSIZE -# else -# define LZO_WORDSIZE LZO_SIZEOF_VOID_P -# endif -#endif -#if !defined(LZO_SIZEOF_SIZE_T) -#if (LZO_ARCH_I086 || LZO_ARCH_M16C) -# define LZO_SIZEOF_SIZE_T 2 -#else -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P -#endif -#endif -#if !defined(LZO_SIZEOF_PTRDIFF_T) -#if (LZO_ARCH_I086) -# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P -# elif (LZO_MM_COMPACT || LZO_MM_LARGE) -# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) -# define LZO_SIZEOF_PTRDIFF_T 4 -# else -# define LZO_SIZEOF_PTRDIFF_T 2 -# endif -# else -# error "LZO_MM" -# endif -#else -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T -#endif -#endif -#if defined(LZO_ABI_NEUTRAL_ENDIAN) -# undef LZO_ABI_BIG_ENDIAN -# undef LZO_ABI_LITTLE_ENDIAN -#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN) -#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) -# define LZO_ABI_BIG_ENDIAN 1 -#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) -# define LZO_ABI_LITTLE_ENDIAN 1 -#elif (LZO_ARCH_M68K || LZO_ARCH_S390) -# define LZO_ABI_BIG_ENDIAN 1 -#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) -# if (__LITTLE_ENDIAN__ == 1) -# define LZO_ABI_LITTLE_ENDIAN 1 -# else -# define LZO_ABI_BIG_ENDIAN 1 -# endif -#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) -# define LZO_ABI_BIG_ENDIAN 1 -#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) -# define LZO_ABI_LITTLE_ENDIAN 1 -#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) -# define LZO_ABI_BIG_ENDIAN 1 -#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) -# define LZO_ABI_LITTLE_ENDIAN 1 -#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) -# define LZO_ABI_BIG_ENDIAN 1 -#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) -# define LZO_ABI_LITTLE_ENDIAN 1 -#endif -#endif -#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN) -# error "this should not happen" -#endif -#if defined(LZO_ABI_BIG_ENDIAN) -# define LZO_INFO_ABI_ENDIAN "be" -#elif defined(LZO_ABI_LITTLE_ENDIAN) -# define LZO_INFO_ABI_ENDIAN "le" -#elif defined(LZO_ABI_NEUTRAL_ENDIAN) -# define LZO_INFO_ABI_ENDIAN "neutral" -#endif -#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) -# define LZO_ABI_I8LP16 1 -# define LZO_INFO_ABI_PM "i8lp16" -#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) -# define LZO_ABI_ILP16 1 -# define LZO_INFO_ABI_PM "ilp16" -#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) -# define LZO_ABI_ILP32 1 -# define LZO_INFO_ABI_PM "ilp32" -#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) -# define LZO_ABI_LLP64 1 -# define LZO_INFO_ABI_PM "llp64" -#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) -# define LZO_ABI_LP64 1 -# define LZO_INFO_ABI_PM "lp64" -#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) -# define LZO_ABI_ILP64 1 -# define LZO_INFO_ABI_PM "ilp64" -#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) -# define LZO_ABI_IP32L64 1 -# define LZO_INFO_ABI_PM "ip32l64" -#endif -#if !defined(__LZO_LIBC_OVERRIDE) -#if defined(LZO_LIBC_NAKED) -# define LZO_INFO_LIBC "naked" -#elif defined(LZO_LIBC_FREESTANDING) -# define LZO_INFO_LIBC "freestanding" -#elif defined(LZO_LIBC_MOSTLY_FREESTANDING) -# define LZO_INFO_LIBC "mfreestanding" -#elif defined(LZO_LIBC_ISOC90) -# define LZO_INFO_LIBC "isoc90" -#elif defined(LZO_LIBC_ISOC99) -# define LZO_INFO_LIBC "isoc99" -#elif defined(__dietlibc__) -# define LZO_LIBC_DIETLIBC 1 -# define LZO_INFO_LIBC "dietlibc" -#elif defined(_NEWLIB_VERSION) -# define LZO_LIBC_NEWLIB 1 -# define LZO_INFO_LIBC "newlib" -#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) -# if defined(__UCLIBC_SUBLEVEL__) -# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) -# else -# define LZO_LIBC_UCLIBC 0x00090bL -# endif -# define LZO_INFO_LIBC "uclibc" -#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) -# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) -# define LZO_INFO_LIBC "glibc" -#elif (LZO_CC_MWERKS) && defined(__MSL__) -# define LZO_LIBC_MSL __MSL__ -# define LZO_INFO_LIBC "msl" -#elif 1 && defined(__IAR_SYSTEMS_ICC__) -# define LZO_LIBC_ISOC90 1 -# define LZO_INFO_LIBC "isoc90" -#else -# define LZO_LIBC_DEFAULT 1 -# define LZO_INFO_LIBC "default" -#endif -#endif -#if !defined(__lzo_gnuc_extension__) -#if (LZO_CC_GNUC >= 0x020800ul) -# define __lzo_gnuc_extension__ __extension__ -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_gnuc_extension__ __extension__ -#else -# define __lzo_gnuc_extension__ -#endif -#endif -#if !defined(__lzo_ua_volatile) -# define __lzo_ua_volatile volatile -#endif -#if !defined(__lzo_alignof) -#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) -# define __lzo_alignof(e) __alignof__(e) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) -# define __lzo_alignof(e) __alignof__(e) -#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) -# define __lzo_alignof(e) __alignof(e) -#endif -#endif -#if defined(__lzo_alignof) -# define __lzo_HAVE_alignof 1 -#endif -#if !defined(__lzo_constructor) -#if (LZO_CC_GNUC >= 0x030400ul) -# define __lzo_constructor __attribute__((__constructor__,__used__)) -#elif (LZO_CC_GNUC >= 0x020700ul) -# define __lzo_constructor __attribute__((__constructor__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_constructor __attribute__((__constructor__)) -#endif -#endif -#if defined(__lzo_constructor) -# define __lzo_HAVE_constructor 1 -#endif -#if !defined(__lzo_destructor) -#if (LZO_CC_GNUC >= 0x030400ul) -# define __lzo_destructor __attribute__((__destructor__,__used__)) -#elif (LZO_CC_GNUC >= 0x020700ul) -# define __lzo_destructor __attribute__((__destructor__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_destructor __attribute__((__destructor__)) -#endif -#endif -#if defined(__lzo_destructor) -# define __lzo_HAVE_destructor 1 -#endif -#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor) -# error "this should not happen" -#endif -#if !defined(__lzo_inline) -#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) -#elif defined(__cplusplus) -# define __lzo_inline inline -#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) -# define __lzo_inline __inline -#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) -# define __lzo_inline __inline__ -#elif (LZO_CC_DMC) -# define __lzo_inline __inline -#elif (LZO_CC_INTELC) -# define __lzo_inline __inline -#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) -# define __lzo_inline __inline -#elif (LZO_CC_MSC && (_MSC_VER >= 900)) -# define __lzo_inline __inline -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -# define __lzo_inline inline -#endif -#endif -#if defined(__lzo_inline) -# define __lzo_HAVE_inline 1 -#else -# define __lzo_inline -#endif -#if !defined(__lzo_forceinline) -#if (LZO_CC_GNUC >= 0x030200ul) -# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) -# define __lzo_forceinline __forceinline -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) -# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) -# define __lzo_forceinline __forceinline -#endif -#endif -#if defined(__lzo_forceinline) -# define __lzo_HAVE_forceinline 1 -#else -# define __lzo_forceinline -#endif -#if !defined(__lzo_noinline) -#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) -# define __lzo_noinline __attribute__((__noinline__,__used__)) -#elif (LZO_CC_GNUC >= 0x030200ul) -# define __lzo_noinline __attribute__((__noinline__)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) -# define __lzo_noinline __declspec(noinline) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) -# define __lzo_noinline __attribute__((__noinline__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_noinline __attribute__((__noinline__)) -#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) -# define __lzo_noinline __declspec(noinline) -#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) -# if defined(__cplusplus) -# else -# define __lzo_noinline __declspec(noinline) -# endif -#endif -#endif -#if defined(__lzo_noinline) -# define __lzo_HAVE_noinline 1 -#else -# define __lzo_noinline -#endif -#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline) -# error "this should not happen" -#endif -#if !defined(__lzo_noreturn) -#if (LZO_CC_GNUC >= 0x020700ul) -# define __lzo_noreturn __attribute__((__noreturn__)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) -# define __lzo_noreturn __declspec(noreturn) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) -# define __lzo_noreturn __attribute__((__noreturn__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_noreturn __attribute__((__noreturn__)) -#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) -# define __lzo_noreturn __declspec(noreturn) -#endif -#endif -#if defined(__lzo_noreturn) -# define __lzo_HAVE_noreturn 1 -#else -# define __lzo_noreturn -#endif -#if !defined(__lzo_nothrow) -#if (LZO_CC_GNUC >= 0x030300ul) -# define __lzo_nothrow __attribute__((__nothrow__)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) -# define __lzo_nothrow __declspec(nothrow) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) -# define __lzo_nothrow __attribute__((__nothrow__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_nothrow __attribute__((__nothrow__)) -#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) -# define __lzo_nothrow __declspec(nothrow) -#endif -#endif -#if defined(__lzo_nothrow) -# define __lzo_HAVE_nothrow 1 -#else -# define __lzo_nothrow -#endif -#if !defined(__lzo_restrict) -#if (LZO_CC_GNUC >= 0x030400ul) -# define __lzo_restrict __restrict__ -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) -# define __lzo_restrict __restrict__ -#elif (LZO_CC_LLVM) -# define __lzo_restrict __restrict__ -#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) -# define __lzo_restrict __restrict -#endif -#endif -#if defined(__lzo_restrict) -# define __lzo_HAVE_restrict 1 -#else -# define __lzo_restrict -#endif -#if !defined(__lzo_likely) && !defined(__lzo_unlikely) -#if (LZO_CC_GNUC >= 0x030200ul) -# define __lzo_likely(e) (__builtin_expect(!!(e),1)) -# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) -# define __lzo_likely(e) (__builtin_expect(!!(e),1)) -# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_likely(e) (__builtin_expect(!!(e),1)) -# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -#endif -#endif -#if defined(__lzo_likely) -# define __lzo_HAVE_likely 1 -#else -# define __lzo_likely(e) (e) -#endif -#if defined(__lzo_unlikely) -# define __lzo_HAVE_unlikely 1 -#else -# define __lzo_unlikely(e) (e) -#endif -#if !defined(LZO_UNUSED) -# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) -# define LZO_UNUSED(var) ((void) &var) -# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) -# define LZO_UNUSED(var) if (&var) ; else -# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define LZO_UNUSED(var) ((void) var) -# elif (LZO_CC_MSC && (_MSC_VER < 900)) -# define LZO_UNUSED(var) if (&var) ; else -# elif (LZO_CC_KEILC) -# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} -# elif (LZO_CC_PACIFICC) -# define LZO_UNUSED(var) ((void) sizeof(var)) -# elif (LZO_CC_WATCOMC) && defined(__cplusplus) -# define LZO_UNUSED(var) ((void) var) -# else -# define LZO_UNUSED(var) ((void) &var) -# endif -#endif -#if !defined(LZO_UNUSED_FUNC) -# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) -# define LZO_UNUSED_FUNC(func) ((void) func) -# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) -# define LZO_UNUSED_FUNC(func) if (func) ; else -# elif (LZO_CC_LLVM) -# define LZO_UNUSED_FUNC(func) ((void) &func) -# elif (LZO_CC_MSC && (_MSC_VER < 900)) -# define LZO_UNUSED_FUNC(func) if (func) ; else -# elif (LZO_CC_MSC) -# define LZO_UNUSED_FUNC(func) ((void) &func) -# elif (LZO_CC_KEILC || LZO_CC_PELLESC) -# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} -# else -# define LZO_UNUSED_FUNC(func) ((void) func) -# endif -#endif -#if !defined(LZO_UNUSED_LABEL) -# if (LZO_CC_WATCOMC) && defined(__cplusplus) -# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l -# elif (LZO_CC_INTELC || LZO_CC_WATCOMC) -# define LZO_UNUSED_LABEL(l) if (0) goto l -# else -# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l -# endif -#endif -#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) -# if 0 -# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var -# elif 0 && (LZO_CC_GNUC) -# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var -# else -# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init -# endif -#endif -#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) -# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) -# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; -# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) -# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; -# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) -# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; -# else -# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; -# endif -#endif -#if !defined(LZO_COMPILE_TIME_ASSERT) -# if (LZO_CC_AZTECC) -# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} -# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) -# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; -# elif (LZO_CC_MSC && (_MSC_VER < 900)) -# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; -# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) -# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; -# else -# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} -# endif -#endif -#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) -# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) -# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) -# define __lzo_cdecl __cdecl -# define __lzo_cdecl_atexit -# define __lzo_cdecl_main __cdecl -# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) -# define __lzo_cdecl_qsort __pascal -# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) -# define __lzo_cdecl_qsort _stdcall -# else -# define __lzo_cdecl_qsort __cdecl -# endif -# elif (LZO_CC_WATCOMC) -# define __lzo_cdecl __cdecl -# else -# define __lzo_cdecl __cdecl -# define __lzo_cdecl_atexit __cdecl -# define __lzo_cdecl_main __cdecl -# define __lzo_cdecl_qsort __cdecl -# endif -# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) -# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) -# define __lzo_cdecl_sighandler __pascal -# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) -# define __lzo_cdecl_sighandler _stdcall -# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) -# define __lzo_cdecl_sighandler __clrcall -# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) -# if defined(_DLL) -# define __lzo_cdecl_sighandler _far _cdecl _loadds -# elif defined(_MT) -# define __lzo_cdecl_sighandler _far _cdecl -# else -# define __lzo_cdecl_sighandler _cdecl -# endif -# else -# define __lzo_cdecl_sighandler __cdecl -# endif -#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) -# define __lzo_cdecl __cdecl -#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) -# define __lzo_cdecl cdecl -#endif -#if !defined(__lzo_cdecl) -# define __lzo_cdecl -#endif -#if !defined(__lzo_cdecl_atexit) -# define __lzo_cdecl_atexit -#endif -#if !defined(__lzo_cdecl_main) -# define __lzo_cdecl_main -#endif -#if !defined(__lzo_cdecl_qsort) -# define __lzo_cdecl_qsort -#endif -#if !defined(__lzo_cdecl_sighandler) -# define __lzo_cdecl_sighandler -#endif -#if !defined(__lzo_cdecl_va) -# define __lzo_cdecl_va __lzo_cdecl -#endif -#if !defined(LZO_CFG_NO_WINDOWS_H) -#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) -# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) -# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) -# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) -# else -# define LZO_HAVE_WINDOWS_H 1 -# endif -#endif -#endif -#if (LZO_ARCH_ALPHA) -# define LZO_OPT_AVOID_UINT_INDEX 1 -# define LZO_OPT_AVOID_SHORT 1 -# define LZO_OPT_AVOID_USHORT 1 -#elif (LZO_ARCH_AMD64) -# define LZO_OPT_AVOID_INT_INDEX 1 -# define LZO_OPT_AVOID_UINT_INDEX 1 -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -# define LZO_OPT_UNALIGNED64 1 -#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) -#elif (LZO_ARCH_ARM) -# define LZO_OPT_AVOID_SHORT 1 -# define LZO_OPT_AVOID_USHORT 1 -#elif (LZO_ARCH_CRIS) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -#elif (LZO_ARCH_I386) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -#elif (LZO_ARCH_IA64) -# define LZO_OPT_AVOID_INT_INDEX 1 -# define LZO_OPT_AVOID_UINT_INDEX 1 -# define LZO_OPT_PREFER_POSTINC 1 -#elif (LZO_ARCH_M68K) -# define LZO_OPT_PREFER_POSTINC 1 -# define LZO_OPT_PREFER_PREDEC 1 -# if defined(__mc68020__) && !defined(__mcoldfire__) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -# endif -#elif (LZO_ARCH_MIPS) -# define LZO_OPT_AVOID_UINT_INDEX 1 -#elif (LZO_ARCH_POWERPC) -# define LZO_OPT_PREFER_PREINC 1 -# define LZO_OPT_PREFER_PREDEC 1 -# if defined(LZO_ABI_BIG_ENDIAN) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -# endif -#elif (LZO_ARCH_S390) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -# if (LZO_SIZEOF_SIZE_T == 8) -# define LZO_OPT_UNALIGNED64 1 -# endif -#elif (LZO_ARCH_SH) -# define LZO_OPT_PREFER_POSTINC 1 -# define LZO_OPT_PREFER_PREDEC 1 -#endif -#if !defined(LZO_CFG_NO_INLINE_ASM) -#if defined(LZO_CC_LLVM) -# define LZO_CFG_NO_INLINE_ASM 1 -#endif -#endif -#if !defined(LZO_CFG_NO_UNALIGNED) -#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC) -# define LZO_CFG_NO_UNALIGNED 1 -#endif -#endif -#if defined(LZO_CFG_NO_UNALIGNED) -# undef LZO_OPT_UNALIGNED16 -# undef LZO_OPT_UNALIGNED32 -# undef LZO_OPT_UNALIGNED64 -#endif -#if defined(LZO_CFG_NO_INLINE_ASM) -#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) -# define LZO_ASM_SYNTAX_MSC 1 -#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) -#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) -# define LZO_ASM_SYNTAX_GNUC 1 -#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) -# define LZO_ASM_SYNTAX_GNUC 1 -#endif -#if (LZO_ASM_SYNTAX_GNUC) -#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) -# define __LZO_ASM_CLOBBER "ax" -#elif (LZO_CC_INTELC) -# define __LZO_ASM_CLOBBER "memory" -#else -# define __LZO_ASM_CLOBBER "cc", "memory" -#endif -#endif -#if defined(__LZO_INFOSTR_MM) -#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) -# define __LZO_INFOSTR_MM "" -#elif defined(LZO_INFO_MM) -# define __LZO_INFOSTR_MM "." LZO_INFO_MM -#else -# define __LZO_INFOSTR_MM "" -#endif -#if defined(__LZO_INFOSTR_PM) -#elif defined(LZO_INFO_ABI_PM) -# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM -#else -# define __LZO_INFOSTR_PM "" -#endif -#if defined(__LZO_INFOSTR_ENDIAN) -#elif defined(LZO_INFO_ABI_ENDIAN) -# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN -#else -# define __LZO_INFOSTR_ENDIAN "" -#endif -#if defined(__LZO_INFOSTR_OSNAME) -#elif defined(LZO_INFO_OS_CONSOLE) -# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE -#elif defined(LZO_INFO_OS_POSIX) -# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX -#else -# define __LZO_INFOSTR_OSNAME LZO_INFO_OS -#endif -#if defined(__LZO_INFOSTR_LIBC) -#elif defined(LZO_INFO_LIBC) -# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC -#else -# define __LZO_INFOSTR_LIBC "" -#endif -#if defined(__LZO_INFOSTR_CCVER) -#elif defined(LZO_INFO_CCVER) -# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER -#else -# define __LZO_INFOSTR_CCVER "" -#endif -#define LZO_INFO_STRING \ - LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ - " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER - -#endif /* already included */ - -/* vim:set ts=4 et: */ diff --git a/minilzo.c b/minilzo.c deleted file mode 100644 index 6a62b31..0000000 --- a/minilzo.c +++ /dev/null @@ -1,4112 +0,0 @@ -/* minilzo.c -- mini subset of the LZO real-time data compression library - - This file is part of the LZO real-time data compression library. - - Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - The LZO library 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 2 of - the License, or (at your option) any later version. - - The LZO library 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 the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Markus F.X.J. Oberhumer - - http://www.oberhumer.com/opensource/lzo/ - */ - -/* - * NOTE: - * the full LZO package can be found at - * http://www.oberhumer.com/opensource/lzo/ - */ - -#define __LZO_IN_MINILZO -#define LZO_BUILD - -#if defined(LZO_CFG_FREESTANDING) -# undef MINILZO_HAVE_CONFIG_H -# define LZO_LIBC_FREESTANDING 1 -# define LZO_OS_FREESTANDING 1 -#endif - -#ifdef MINILZO_HAVE_CONFIG_H -# include -#endif -#include -#include -#if defined(MINILZO_CFG_USE_INTERNAL_LZODEFS) - -#ifndef __LZODEFS_H_INCLUDED -#define __LZODEFS_H_INCLUDED 1 - -#if defined(__CYGWIN32__) && !defined(__CYGWIN__) -# define __CYGWIN__ __CYGWIN32__ -#endif -#if defined(__IBMCPP__) && !defined(__IBMC__) -# define __IBMC__ __IBMCPP__ -#endif -#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) -# define __INTEL_COMPILER __ICL -#endif -#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) -# define _ALL_SOURCE 1 -#endif -#if defined(__mips__) && defined(__R5900__) -# if !defined(__LONG_MAX__) -# define __LONG_MAX__ 9223372036854775807L -# endif -#endif -#if defined(__INTEL_COMPILER) && defined(__linux__) -# pragma warning(disable: 193) -#endif -#if defined(__KEIL__) && defined(__C166__) -# pragma warning disable = 322 -#elif 0 && defined(__C251__) -# pragma warning disable = 322 -#endif -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) -# if (_MSC_VER >= 1300) -# pragma warning(disable: 4668) -# endif -#endif -#if 0 && defined(__WATCOMC__) -# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) -# pragma warning 203 9 -# endif -#endif -#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) -# pragma option -h -#endif -#if 0 -#define LZO_0xffffL 0xfffful -#define LZO_0xffffffffL 0xfffffffful -#else -#define LZO_0xffffL 65535ul -#define LZO_0xffffffffL 4294967295ul -#endif -#if (LZO_0xffffL == LZO_0xffffffffL) -# error "your preprocessor is broken 1" -#endif -#if (16ul * 16384ul != 262144ul) -# error "your preprocessor is broken 2" -#endif -#if 0 -#if (32767 >= 4294967295ul) -# error "your preprocessor is broken 3" -#endif -#if (65535u >= 4294967295ul) -# error "your preprocessor is broken 4" -#endif -#endif -#if (UINT_MAX == LZO_0xffffL) -#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) -# if !defined(MSDOS) -# define MSDOS 1 -# endif -# if !defined(_MSDOS) -# define _MSDOS 1 -# endif -#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) -# if (__VERSION == 520) && (MB_LEN_MAX == 1) -# if !defined(__AZTEC_C__) -# define __AZTEC_C__ __VERSION -# endif -# if !defined(__DOS__) -# define __DOS__ 1 -# endif -# endif -#endif -#endif -#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) -# define ptrdiff_t long -# define _PTRDIFF_T_DEFINED -#endif -#if (UINT_MAX == LZO_0xffffL) -# undef __LZO_RENAME_A -# undef __LZO_RENAME_B -# if defined(__AZTEC_C__) && defined(__DOS__) -# define __LZO_RENAME_A 1 -# elif defined(_MSC_VER) && defined(MSDOS) -# if (_MSC_VER < 600) -# define __LZO_RENAME_A 1 -# elif (_MSC_VER < 700) -# define __LZO_RENAME_B 1 -# endif -# elif defined(__TSC__) && defined(__OS2__) -# define __LZO_RENAME_A 1 -# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) -# define __LZO_RENAME_A 1 -# elif defined(__PACIFIC__) && defined(DOS) -# if !defined(__far) -# define __far far -# endif -# if !defined(__near) -# define __near near -# endif -# endif -# if defined(__LZO_RENAME_A) -# if !defined(__cdecl) -# define __cdecl cdecl -# endif -# if !defined(__far) -# define __far far -# endif -# if !defined(__huge) -# define __huge huge -# endif -# if !defined(__near) -# define __near near -# endif -# if !defined(__pascal) -# define __pascal pascal -# endif -# if !defined(__huge) -# define __huge huge -# endif -# elif defined(__LZO_RENAME_B) -# if !defined(__cdecl) -# define __cdecl _cdecl -# endif -# if !defined(__far) -# define __far _far -# endif -# if !defined(__huge) -# define __huge _huge -# endif -# if !defined(__near) -# define __near _near -# endif -# if !defined(__pascal) -# define __pascal _pascal -# endif -# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) -# if !defined(__cdecl) -# define __cdecl cdecl -# endif -# if !defined(__pascal) -# define __pascal pascal -# endif -# endif -# undef __LZO_RENAME_A -# undef __LZO_RENAME_B -#endif -#if (UINT_MAX == LZO_0xffffL) -#if defined(__AZTEC_C__) && defined(__DOS__) -# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -#elif defined(_MSC_VER) && defined(MSDOS) -# if (_MSC_VER < 600) -# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -# endif -# if (_MSC_VER < 700) -# define LZO_BROKEN_INTEGRAL_PROMOTION 1 -# define LZO_BROKEN_SIZEOF 1 -# endif -#elif defined(__PACIFIC__) && defined(DOS) -# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -#elif defined(__TURBOC__) && defined(__MSDOS__) -# if (__TURBOC__ < 0x0150) -# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -# define LZO_BROKEN_INTEGRAL_PROMOTION 1 -# endif -# if (__TURBOC__ < 0x0200) -# define LZO_BROKEN_SIZEOF 1 -# endif -# if (__TURBOC__ < 0x0400) && defined(__cplusplus) -# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -# endif -#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) -# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -# define LZO_BROKEN_SIZEOF 1 -#endif -#endif -#if defined(__WATCOMC__) && (__WATCOMC__ < 900) -# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -#endif -#if defined(_CRAY) && defined(_CRAY1) -# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 -#endif -#define LZO_PP_STRINGIZE(x) #x -#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) -#define LZO_PP_CONCAT2(a,b) a ## b -#define LZO_PP_CONCAT3(a,b,c) a ## b ## c -#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d -#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e -#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) -#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) -#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) -#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) -#if 1 -#define LZO_CPP_STRINGIZE(x) #x -#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) -#define LZO_CPP_CONCAT2(a,b) a ## b -#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c -#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d -#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e -#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) -#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) -#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) -#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) -#endif -#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) -#if 1 && defined(__cplusplus) -# if !defined(__STDC_CONSTANT_MACROS) -# define __STDC_CONSTANT_MACROS 1 -# endif -# if !defined(__STDC_LIMIT_MACROS) -# define __STDC_LIMIT_MACROS 1 -# endif -#endif -#if defined(__cplusplus) -# define LZO_EXTERN_C extern "C" -#else -# define LZO_EXTERN_C extern -#endif -#if !defined(__LZO_OS_OVERRIDE) -#if defined(LZO_OS_FREESTANDING) -# define LZO_INFO_OS "freestanding" -#elif defined(LZO_OS_EMBEDDED) -# define LZO_INFO_OS "embedded" -#elif 1 && defined(__IAR_SYSTEMS_ICC__) -# define LZO_OS_EMBEDDED 1 -# define LZO_INFO_OS "embedded" -#elif defined(__CYGWIN__) && defined(__GNUC__) -# define LZO_OS_CYGWIN 1 -# define LZO_INFO_OS "cygwin" -#elif defined(__EMX__) && defined(__GNUC__) -# define LZO_OS_EMX 1 -# define LZO_INFO_OS "emx" -#elif defined(__BEOS__) -# define LZO_OS_BEOS 1 -# define LZO_INFO_OS "beos" -#elif defined(__Lynx__) -# define LZO_OS_LYNXOS 1 -# define LZO_INFO_OS "lynxos" -#elif defined(__OS400__) -# define LZO_OS_OS400 1 -# define LZO_INFO_OS "os400" -#elif defined(__QNX__) -# define LZO_OS_QNX 1 -# define LZO_INFO_OS "qnx" -#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) -# define LZO_OS_DOS32 1 -# define LZO_INFO_OS "dos32" -#elif defined(__BORLANDC__) && defined(__DPMI16__) -# define LZO_OS_DOS16 1 -# define LZO_INFO_OS "dos16" -#elif defined(__ZTC__) && defined(DOS386) -# define LZO_OS_DOS32 1 -# define LZO_INFO_OS "dos32" -#elif defined(__OS2__) || defined(__OS2V2__) -# if (UINT_MAX == LZO_0xffffL) -# define LZO_OS_OS216 1 -# define LZO_INFO_OS "os216" -# elif (UINT_MAX == LZO_0xffffffffL) -# define LZO_OS_OS2 1 -# define LZO_INFO_OS "os2" -# else -# error "check your limits.h header" -# endif -#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) -# define LZO_OS_WIN64 1 -# define LZO_INFO_OS "win64" -#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) -# define LZO_OS_WIN32 1 -# define LZO_INFO_OS "win32" -#elif defined(__MWERKS__) && defined(__INTEL__) -# define LZO_OS_WIN32 1 -# define LZO_INFO_OS "win32" -#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) -# if (UINT_MAX == LZO_0xffffL) -# define LZO_OS_WIN16 1 -# define LZO_INFO_OS "win16" -# elif (UINT_MAX == LZO_0xffffffffL) -# define LZO_OS_WIN32 1 -# define LZO_INFO_OS "win32" -# else -# error "check your limits.h header" -# endif -#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) -# if (UINT_MAX == LZO_0xffffL) -# define LZO_OS_DOS16 1 -# define LZO_INFO_OS "dos16" -# elif (UINT_MAX == LZO_0xffffffffL) -# define LZO_OS_DOS32 1 -# define LZO_INFO_OS "dos32" -# else -# error "check your limits.h header" -# endif -#elif defined(__WATCOMC__) -# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) -# define LZO_OS_DOS16 1 -# define LZO_INFO_OS "dos16" -# elif defined(__NT__) && (__WATCOMC__ < 1100) -# define LZO_OS_WIN32 1 -# define LZO_INFO_OS "win32" -# elif defined(__linux__) || defined(__LINUX__) -# define LZO_OS_POSIX 1 -# define LZO_INFO_OS "posix" -# else -# error "please specify a target using the -bt compiler option" -# endif -#elif defined(__palmos__) -# define LZO_OS_PALMOS 1 -# define LZO_INFO_OS "palmos" -#elif defined(__TOS__) || defined(__atarist__) -# define LZO_OS_TOS 1 -# define LZO_INFO_OS "tos" -#elif defined(macintosh) && !defined(__ppc__) -# define LZO_OS_MACCLASSIC 1 -# define LZO_INFO_OS "macclassic" -#elif defined(__VMS) -# define LZO_OS_VMS 1 -# define LZO_INFO_OS "vms" -#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) -# define LZO_OS_CONSOLE 1 -# define LZO_OS_CONSOLE_PS2 1 -# define LZO_INFO_OS "console" -# define LZO_INFO_OS_CONSOLE "ps2" -#elif (defined(__mips__) && defined(__psp__)) -# define LZO_OS_CONSOLE 1 -# define LZO_OS_CONSOLE_PSP 1 -# define LZO_INFO_OS "console" -# define LZO_INFO_OS_CONSOLE "psp" -#else -# define LZO_OS_POSIX 1 -# define LZO_INFO_OS "posix" -#endif -#if (LZO_OS_POSIX) -# if defined(_AIX) || defined(__AIX__) || defined(__aix__) -# define LZO_OS_POSIX_AIX 1 -# define LZO_INFO_OS_POSIX "aix" -# elif defined(__FreeBSD__) -# define LZO_OS_POSIX_FREEBSD 1 -# define LZO_INFO_OS_POSIX "freebsd" -# elif defined(__hpux__) || defined(__hpux) -# define LZO_OS_POSIX_HPUX 1 -# define LZO_INFO_OS_POSIX "hpux" -# elif defined(__INTERIX) -# define LZO_OS_POSIX_INTERIX 1 -# define LZO_INFO_OS_POSIX "interix" -# elif defined(__IRIX__) || defined(__irix__) -# define LZO_OS_POSIX_IRIX 1 -# define LZO_INFO_OS_POSIX "irix" -# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) -# define LZO_OS_POSIX_LINUX 1 -# define LZO_INFO_OS_POSIX "linux" -# elif defined(__APPLE__) || defined(__MACOS__) -# define LZO_OS_POSIX_MACOSX 1 -# define LZO_INFO_OS_POSIX "macosx" -# elif defined(__minix__) || defined(__minix) -# define LZO_OS_POSIX_MINIX 1 -# define LZO_INFO_OS_POSIX "minix" -# elif defined(__NetBSD__) -# define LZO_OS_POSIX_NETBSD 1 -# define LZO_INFO_OS_POSIX "netbsd" -# elif defined(__OpenBSD__) -# define LZO_OS_POSIX_OPENBSD 1 -# define LZO_INFO_OS_POSIX "openbsd" -# elif defined(__osf__) -# define LZO_OS_POSIX_OSF 1 -# define LZO_INFO_OS_POSIX "osf" -# elif defined(__solaris__) || defined(__sun) -# if defined(__SVR4) || defined(__svr4__) -# define LZO_OS_POSIX_SOLARIS 1 -# define LZO_INFO_OS_POSIX "solaris" -# else -# define LZO_OS_POSIX_SUNOS 1 -# define LZO_INFO_OS_POSIX "sunos" -# endif -# elif defined(__ultrix__) || defined(__ultrix) -# define LZO_OS_POSIX_ULTRIX 1 -# define LZO_INFO_OS_POSIX "ultrix" -# elif defined(_UNICOS) -# define LZO_OS_POSIX_UNICOS 1 -# define LZO_INFO_OS_POSIX "unicos" -# else -# define LZO_OS_POSIX_UNKNOWN 1 -# define LZO_INFO_OS_POSIX "unknown" -# endif -#endif -#endif -#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -# if (UINT_MAX != LZO_0xffffL) -# error "this should not happen" -# endif -# if (ULONG_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -#endif -#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) -# if (UINT_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -# if (ULONG_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -#endif -#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) -# define LZO_CC_CILLY 1 -# define LZO_INFO_CC "Cilly" -# if defined(__CILLY__) -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) -# else -# define LZO_INFO_CCVER "unknown" -# endif -#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) -# define LZO_CC_SDCC 1 -# define LZO_INFO_CC "sdcc" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) -#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) -# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) -# define LZO_INFO_CC "Pathscale C" -# define LZO_INFO_CCVER __PATHSCALE__ -#elif defined(__INTEL_COMPILER) -# define LZO_CC_INTELC 1 -# define LZO_INFO_CC "Intel C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) -# if defined(_WIN32) || defined(_WIN64) -# define LZO_CC_SYNTAX_MSC 1 -# else -# define LZO_CC_SYNTAX_GNUC 1 -# endif -#elif defined(__POCC__) && defined(_WIN32) -# define LZO_CC_PELLESC 1 -# define LZO_INFO_CC "Pelles C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) -#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__) -# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) -# else -# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) -# endif -# define LZO_INFO_CC "llvm-gcc" -# define LZO_INFO_CCVER __VERSION__ -#elif defined(__GNUC__) && defined(__VERSION__) -# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) -# elif defined(__GNUC_MINOR__) -# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) -# else -# define LZO_CC_GNUC (__GNUC__ * 0x10000L) -# endif -# define LZO_INFO_CC "gcc" -# define LZO_INFO_CCVER __VERSION__ -#elif defined(__ACK__) && defined(_ACK) -# define LZO_CC_ACK 1 -# define LZO_INFO_CC "Amsterdam Compiler Kit C" -# define LZO_INFO_CCVER "unknown" -#elif defined(__AZTEC_C__) -# define LZO_CC_AZTECC 1 -# define LZO_INFO_CC "Aztec C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) -#elif defined(__BORLANDC__) -# define LZO_CC_BORLANDC 1 -# define LZO_INFO_CC "Borland C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) -#elif defined(_CRAYC) && defined(_RELEASE) -# define LZO_CC_CRAYC 1 -# define LZO_INFO_CC "Cray C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) -#elif defined(__DMC__) && defined(__SC__) -# define LZO_CC_DMC 1 -# define LZO_INFO_CC "Digital Mars C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) -#elif defined(__DECC) -# define LZO_CC_DECC 1 -# define LZO_INFO_CC "DEC C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) -#elif defined(__HIGHC__) -# define LZO_CC_HIGHC 1 -# define LZO_INFO_CC "MetaWare High C" -# define LZO_INFO_CCVER "unknown" -#elif defined(__IAR_SYSTEMS_ICC__) -# define LZO_CC_IARC 1 -# define LZO_INFO_CC "IAR C" -# if defined(__VER__) -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) -# else -# define LZO_INFO_CCVER "unknown" -# endif -#elif defined(__IBMC__) -# define LZO_CC_IBMC 1 -# define LZO_INFO_CC "IBM C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) -#elif defined(__KEIL__) && defined(__C166__) -# define LZO_CC_KEILC 1 -# define LZO_INFO_CC "Keil C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) -#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) -# define LZO_CC_LCCWIN32 1 -# define LZO_INFO_CC "lcc-win32" -# define LZO_INFO_CCVER "unknown" -#elif defined(__LCC__) -# define LZO_CC_LCC 1 -# define LZO_INFO_CC "lcc" -# if defined(__LCC_VERSION__) -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) -# else -# define LZO_INFO_CCVER "unknown" -# endif -#elif defined(_MSC_VER) -# define LZO_CC_MSC 1 -# define LZO_INFO_CC "Microsoft C" -# if defined(_MSC_FULL_VER) -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) -# else -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) -# endif -#elif defined(__MWERKS__) -# define LZO_CC_MWERKS 1 -# define LZO_INFO_CC "Metrowerks C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) -#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) -# define LZO_CC_NDPC 1 -# define LZO_INFO_CC "Microway NDP C" -# define LZO_INFO_CCVER "unknown" -#elif defined(__PACIFIC__) -# define LZO_CC_PACIFICC 1 -# define LZO_INFO_CC "Pacific C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) -#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) -# define LZO_CC_PGI 1 -# define LZO_INFO_CC "Portland Group PGI C" -# define LZO_INFO_CCVER "unknown" -#elif defined(__PUREC__) && defined(__TOS__) -# define LZO_CC_PUREC 1 -# define LZO_INFO_CC "Pure C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) -#elif defined(__SC__) && defined(__ZTC__) -# define LZO_CC_SYMANTECC 1 -# define LZO_INFO_CC "Symantec C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) -#elif defined(__SUNPRO_C) -# define LZO_INFO_CC "SunPro C" -# if ((__SUNPRO_C)+0 > 0) -# define LZO_CC_SUNPROC __SUNPRO_C -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) -# else -# define LZO_CC_SUNPROC 1 -# define LZO_INFO_CCVER "unknown" -# endif -#elif defined(__SUNPRO_CC) -# define LZO_INFO_CC "SunPro C" -# if ((__SUNPRO_CC)+0 > 0) -# define LZO_CC_SUNPROC __SUNPRO_CC -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) -# else -# define LZO_CC_SUNPROC 1 -# define LZO_INFO_CCVER "unknown" -# endif -#elif defined(__TINYC__) -# define LZO_CC_TINYC 1 -# define LZO_INFO_CC "Tiny C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) -#elif defined(__TSC__) -# define LZO_CC_TOPSPEEDC 1 -# define LZO_INFO_CC "TopSpeed C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) -#elif defined(__WATCOMC__) -# define LZO_CC_WATCOMC 1 -# define LZO_INFO_CC "Watcom C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) -#elif defined(__TURBOC__) -# define LZO_CC_TURBOC 1 -# define LZO_INFO_CC "Turbo C" -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) -#elif defined(__ZTC__) -# define LZO_CC_ZORTECHC 1 -# define LZO_INFO_CC "Zortech C" -# if (__ZTC__ == 0x310) -# define LZO_INFO_CCVER "0x310" -# else -# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) -# endif -#else -# define LZO_CC_UNKNOWN 1 -# define LZO_INFO_CC "unknown" -# define LZO_INFO_CCVER "unknown" -#endif -#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) -# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" -#endif -#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY) -# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) -# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) -# define LZO_ARCH_CRAY_MPP 1 -# elif defined(_CRAY1) -# define LZO_ARCH_CRAY_PVP 1 -# endif -# endif -#endif -#if !defined(__LZO_ARCH_OVERRIDE) -#if defined(LZO_ARCH_GENERIC) -# define LZO_INFO_ARCH "generic" -#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -# define LZO_ARCH_I086 1 -# define LZO_ARCH_IA16 1 -# define LZO_INFO_ARCH "i086" -#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) -# define LZO_ARCH_ALPHA 1 -# define LZO_INFO_ARCH "alpha" -#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) -# define LZO_ARCH_ALPHA 1 -# define LZO_INFO_ARCH "alpha" -#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) -# define LZO_ARCH_AMD64 1 -# define LZO_INFO_ARCH "amd64" -#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) -# define LZO_ARCH_ARM 1 -# define LZO_ARCH_ARM_THUMB 1 -# define LZO_INFO_ARCH "arm_thumb" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) -# define LZO_ARCH_ARM 1 -# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) -# define LZO_ARCH_ARM_THUMB 1 -# define LZO_INFO_ARCH "arm_thumb" -# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) -# define LZO_INFO_ARCH "arm" -# else -# define LZO_INFO_ARCH "arm" -# endif -#elif defined(__arm__) || defined(_M_ARM) -# define LZO_ARCH_ARM 1 -# define LZO_INFO_ARCH "arm" -#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) -# define LZO_ARCH_AVR 1 -# define LZO_INFO_ARCH "avr" -#elif defined(__bfin__) -# define LZO_ARCH_BLACKFIN 1 -# define LZO_INFO_ARCH "blackfin" -#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) -# define LZO_ARCH_C166 1 -# define LZO_INFO_ARCH "c166" -#elif defined(__cris__) -# define LZO_ARCH_CRIS 1 -# define LZO_INFO_ARCH "cris" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) -# define LZO_ARCH_EZ80 1 -# define LZO_INFO_ARCH "ez80" -#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) -# define LZO_ARCH_H8300 1 -# define LZO_INFO_ARCH "h8300" -#elif defined(__hppa__) || defined(__hppa) -# define LZO_ARCH_HPPA 1 -# define LZO_INFO_ARCH "hppa" -#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) -# define LZO_ARCH_I386 1 -# define LZO_ARCH_IA32 1 -# define LZO_INFO_ARCH "i386" -#elif (LZO_CC_ZORTECHC && defined(__I86__)) -# define LZO_ARCH_I386 1 -# define LZO_ARCH_IA32 1 -# define LZO_INFO_ARCH "i386" -#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) -# define LZO_ARCH_I386 1 -# define LZO_ARCH_IA32 1 -# define LZO_INFO_ARCH "i386" -#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) -# define LZO_ARCH_IA64 1 -# define LZO_INFO_ARCH "ia64" -#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) -# define LZO_ARCH_M16C 1 -# define LZO_INFO_ARCH "m16c" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) -# define LZO_ARCH_M16C 1 -# define LZO_INFO_ARCH "m16c" -#elif defined(__m32r__) -# define LZO_ARCH_M32R 1 -# define LZO_INFO_ARCH "m32r" -#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) -# define LZO_ARCH_M68K 1 -# define LZO_INFO_ARCH "m68k" -#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) -# define LZO_ARCH_MCS251 1 -# define LZO_INFO_ARCH "mcs251" -#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) -# define LZO_ARCH_MCS51 1 -# define LZO_INFO_ARCH "mcs51" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) -# define LZO_ARCH_MCS51 1 -# define LZO_INFO_ARCH "mcs51" -#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) -# define LZO_ARCH_MIPS 1 -# define LZO_INFO_ARCH "mips" -#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) -# define LZO_ARCH_MSP430 1 -# define LZO_INFO_ARCH "msp430" -#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) -# define LZO_ARCH_MSP430 1 -# define LZO_INFO_ARCH "msp430" -#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) -# define LZO_ARCH_POWERPC 1 -# define LZO_INFO_ARCH "powerpc" -#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) -# define LZO_ARCH_S390 1 -# define LZO_INFO_ARCH "s390" -#elif defined(__sh__) || defined(_M_SH) -# define LZO_ARCH_SH 1 -# define LZO_INFO_ARCH "sh" -#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) -# define LZO_ARCH_SPARC 1 -# define LZO_INFO_ARCH "sparc" -#elif defined(__SPU__) -# define LZO_ARCH_SPU 1 -# define LZO_INFO_ARCH "spu" -#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) -# define LZO_ARCH_Z80 1 -# define LZO_INFO_ARCH "z80" -#elif (LZO_ARCH_CRAY_PVP) -# if defined(_CRAYSV1) -# define LZO_ARCH_CRAY_SV1 1 -# define LZO_INFO_ARCH "cray_sv1" -# elif (_ADDR64) -# define LZO_ARCH_CRAY_T90 1 -# define LZO_INFO_ARCH "cray_t90" -# elif (_ADDR32) -# define LZO_ARCH_CRAY_YMP 1 -# define LZO_INFO_ARCH "cray_ymp" -# else -# define LZO_ARCH_CRAY_XMP 1 -# define LZO_INFO_ARCH "cray_xmp" -# endif -#else -# define LZO_ARCH_UNKNOWN 1 -# define LZO_INFO_ARCH "unknown" -#endif -#endif -#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) -# error "FIXME - missing define for CPU architecture" -#endif -#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) -# error "FIXME - missing WIN32 define for CPU architecture" -#endif -#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) -# error "FIXME - missing WIN64 define for CPU architecture" -#endif -#if (LZO_OS_OS216 || LZO_OS_WIN16) -# define LZO_ARCH_I086PM 1 -# define LZO_ARCH_IA16PM 1 -#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) -# define LZO_ARCH_I086PM 1 -# define LZO_ARCH_IA16PM 1 -#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) -# define LZO_ARCH_I086PM 1 -# define LZO_ARCH_IA16PM 1 -#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) -# define LZO_ARCH_I086PM 1 -# define LZO_ARCH_IA16PM 1 -#endif -#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM) -# error "this should not happen" -#endif -#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086) -# error "this should not happen" -#endif -#if (LZO_ARCH_I086) -# if (UINT_MAX != LZO_0xffffL) -# error "this should not happen" -# endif -# if (ULONG_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -#endif -#if (LZO_ARCH_I386) -# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) -# error "this should not happen" -# endif -# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) -# error "this should not happen" -# endif -# if (ULONG_MAX != LZO_0xffffffffL) -# error "this should not happen" -# endif -#endif -#if !defined(__LZO_MM_OVERRIDE) -#if (LZO_ARCH_I086) -#if (UINT_MAX != LZO_0xffffL) -# error "this should not happen" -#endif -#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) -# define LZO_MM_TINY 1 -#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) -# define LZO_MM_HUGE 1 -#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) -# define LZO_MM_SMALL 1 -#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) -# define LZO_MM_MEDIUM 1 -#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) -# define LZO_MM_COMPACT 1 -#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) -# define LZO_MM_LARGE 1 -#elif (LZO_CC_AZTECC) -# if defined(_LARGE_CODE) && defined(_LARGE_DATA) -# define LZO_MM_LARGE 1 -# elif defined(_LARGE_CODE) -# define LZO_MM_MEDIUM 1 -# elif defined(_LARGE_DATA) -# define LZO_MM_COMPACT 1 -# else -# define LZO_MM_SMALL 1 -# endif -#elif (LZO_CC_ZORTECHC && defined(__VCM__)) -# define LZO_MM_LARGE 1 -#else -# error "unknown memory model" -#endif -#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -#define LZO_HAVE_MM_HUGE_PTR 1 -#define LZO_HAVE_MM_HUGE_ARRAY 1 -#if (LZO_MM_TINY) -# undef LZO_HAVE_MM_HUGE_ARRAY -#endif -#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) -# undef LZO_HAVE_MM_HUGE_PTR -# undef LZO_HAVE_MM_HUGE_ARRAY -#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) -# undef LZO_HAVE_MM_HUGE_ARRAY -#elif (LZO_CC_MSC && defined(_QC)) -# undef LZO_HAVE_MM_HUGE_ARRAY -# if (_MSC_VER < 600) -# undef LZO_HAVE_MM_HUGE_PTR -# endif -#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) -# undef LZO_HAVE_MM_HUGE_ARRAY -#endif -#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR) -# if (LZO_OS_DOS16) -# error "this should not happen" -# elif (LZO_CC_ZORTECHC) -# else -# error "this should not happen" -# endif -#endif -#ifdef __cplusplus -extern "C" { -#endif -#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) - extern void __near __cdecl _AHSHIFT(void); -# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) - extern void __near __cdecl _AHSHIFT(void); -# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) - extern void __near __cdecl _AHSHIFT(void); -# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) - extern void __near __cdecl _AHSHIFT(void); -# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) -# define LZO_MM_AHSHIFT 12 -#elif (LZO_CC_WATCOMC) - extern unsigned char _HShift; -# define LZO_MM_AHSHIFT ((unsigned) _HShift) -#else -# error "FIXME - implement LZO_MM_AHSHIFT" -#endif -#ifdef __cplusplus -} -#endif -#endif -#elif (LZO_ARCH_C166) -#if !defined(__MODEL__) -# error "FIXME - C166 __MODEL__" -#elif ((__MODEL__) == 0) -# define LZO_MM_SMALL 1 -#elif ((__MODEL__) == 1) -# define LZO_MM_SMALL 1 -#elif ((__MODEL__) == 2) -# define LZO_MM_LARGE 1 -#elif ((__MODEL__) == 3) -# define LZO_MM_TINY 1 -#elif ((__MODEL__) == 4) -# define LZO_MM_XTINY 1 -#elif ((__MODEL__) == 5) -# define LZO_MM_XSMALL 1 -#else -# error "FIXME - C166 __MODEL__" -#endif -#elif (LZO_ARCH_MCS251) -#if !defined(__MODEL__) -# error "FIXME - MCS251 __MODEL__" -#elif ((__MODEL__) == 0) -# define LZO_MM_SMALL 1 -#elif ((__MODEL__) == 2) -# define LZO_MM_LARGE 1 -#elif ((__MODEL__) == 3) -# define LZO_MM_TINY 1 -#elif ((__MODEL__) == 4) -# define LZO_MM_XTINY 1 -#elif ((__MODEL__) == 5) -# define LZO_MM_XSMALL 1 -#else -# error "FIXME - MCS251 __MODEL__" -#endif -#elif (LZO_ARCH_MCS51) -#if !defined(__MODEL__) -# error "FIXME - MCS51 __MODEL__" -#elif ((__MODEL__) == 1) -# define LZO_MM_SMALL 1 -#elif ((__MODEL__) == 2) -# define LZO_MM_LARGE 1 -#elif ((__MODEL__) == 3) -# define LZO_MM_TINY 1 -#elif ((__MODEL__) == 4) -# define LZO_MM_XTINY 1 -#elif ((__MODEL__) == 5) -# define LZO_MM_XSMALL 1 -#else -# error "FIXME - MCS51 __MODEL__" -#endif -#elif (LZO_ARCH_CRAY_PVP) -# define LZO_MM_PVP 1 -#else -# define LZO_MM_FLAT 1 -#endif -#if (LZO_MM_COMPACT) -# define LZO_INFO_MM "compact" -#elif (LZO_MM_FLAT) -# define LZO_INFO_MM "flat" -#elif (LZO_MM_HUGE) -# define LZO_INFO_MM "huge" -#elif (LZO_MM_LARGE) -# define LZO_INFO_MM "large" -#elif (LZO_MM_MEDIUM) -# define LZO_INFO_MM "medium" -#elif (LZO_MM_PVP) -# define LZO_INFO_MM "pvp" -#elif (LZO_MM_SMALL) -# define LZO_INFO_MM "small" -#elif (LZO_MM_TINY) -# define LZO_INFO_MM "tiny" -#else -# error "unknown memory model" -#endif -#endif -#if defined(SIZEOF_SHORT) -# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) -#endif -#if defined(SIZEOF_INT) -# define LZO_SIZEOF_INT (SIZEOF_INT) -#endif -#if defined(SIZEOF_LONG) -# define LZO_SIZEOF_LONG (SIZEOF_LONG) -#endif -#if defined(SIZEOF_LONG_LONG) -# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) -#endif -#if defined(SIZEOF___INT16) -# define LZO_SIZEOF___INT16 (SIZEOF___INT16) -#endif -#if defined(SIZEOF___INT32) -# define LZO_SIZEOF___INT32 (SIZEOF___INT32) -#endif -#if defined(SIZEOF___INT64) -# define LZO_SIZEOF___INT64 (SIZEOF___INT64) -#endif -#if defined(SIZEOF_VOID_P) -# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) -#endif -#if defined(SIZEOF_SIZE_T) -# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) -#endif -#if defined(SIZEOF_PTRDIFF_T) -# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) -#endif -#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) -#if !defined(LZO_SIZEOF_SHORT) -# if (LZO_ARCH_CRAY_PVP) -# define LZO_SIZEOF_SHORT 8 -# elif (USHRT_MAX == LZO_0xffffL) -# define LZO_SIZEOF_SHORT 2 -# elif (__LZO_LSR(USHRT_MAX,7) == 1) -# define LZO_SIZEOF_SHORT 1 -# elif (__LZO_LSR(USHRT_MAX,15) == 1) -# define LZO_SIZEOF_SHORT 2 -# elif (__LZO_LSR(USHRT_MAX,31) == 1) -# define LZO_SIZEOF_SHORT 4 -# elif (__LZO_LSR(USHRT_MAX,63) == 1) -# define LZO_SIZEOF_SHORT 8 -# elif (__LZO_LSR(USHRT_MAX,127) == 1) -# define LZO_SIZEOF_SHORT 16 -# else -# error "LZO_SIZEOF_SHORT" -# endif -#endif -#if !defined(LZO_SIZEOF_INT) -# if (LZO_ARCH_CRAY_PVP) -# define LZO_SIZEOF_INT 8 -# elif (UINT_MAX == LZO_0xffffL) -# define LZO_SIZEOF_INT 2 -# elif (UINT_MAX == LZO_0xffffffffL) -# define LZO_SIZEOF_INT 4 -# elif (__LZO_LSR(UINT_MAX,7) == 1) -# define LZO_SIZEOF_INT 1 -# elif (__LZO_LSR(UINT_MAX,15) == 1) -# define LZO_SIZEOF_INT 2 -# elif (__LZO_LSR(UINT_MAX,31) == 1) -# define LZO_SIZEOF_INT 4 -# elif (__LZO_LSR(UINT_MAX,63) == 1) -# define LZO_SIZEOF_INT 8 -# elif (__LZO_LSR(UINT_MAX,127) == 1) -# define LZO_SIZEOF_INT 16 -# else -# error "LZO_SIZEOF_INT" -# endif -#endif -#if !defined(LZO_SIZEOF_LONG) -# if (ULONG_MAX == LZO_0xffffffffL) -# define LZO_SIZEOF_LONG 4 -# elif (__LZO_LSR(ULONG_MAX,7) == 1) -# define LZO_SIZEOF_LONG 1 -# elif (__LZO_LSR(ULONG_MAX,15) == 1) -# define LZO_SIZEOF_LONG 2 -# elif (__LZO_LSR(ULONG_MAX,31) == 1) -# define LZO_SIZEOF_LONG 4 -# elif (__LZO_LSR(ULONG_MAX,63) == 1) -# define LZO_SIZEOF_LONG 8 -# elif (__LZO_LSR(ULONG_MAX,127) == 1) -# define LZO_SIZEOF_LONG 16 -# else -# error "LZO_SIZEOF_LONG" -# endif -#endif -#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) -#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) -# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) -# if (LZO_CC_GNUC >= 0x030300ul) -# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) -# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG -# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) -# define LZO_SIZEOF_LONG_LONG 4 -# endif -# endif -# endif -#endif -#endif -#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) -#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) -#if (LZO_ARCH_I086 && LZO_CC_DMC) -#elif (LZO_CC_CILLY) && defined(__GNUC__) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define LZO_SIZEOF_LONG_LONG 8 -#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_OS_WIN64 || defined(_WIN64)) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) -# define LZO_SIZEOF___INT64 8 -#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) -# define LZO_SIZEOF___INT64 8 -#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) -# define LZO_SIZEOF_LONG_LONG 8 -#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) -#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -# define LZO_SIZEOF_LONG_LONG 8 -#endif -#endif -#endif -#if defined(__cplusplus) && defined(LZO_CC_GNUC) -# if (LZO_CC_GNUC < 0x020800ul) -# undef LZO_SIZEOF_LONG_LONG -# endif -#endif -#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) -# undef LZO_SIZEOF_LONG_LONG -#endif -#if !defined(LZO_SIZEOF_VOID_P) -#if (LZO_ARCH_I086) -# define __LZO_WORDSIZE 2 -# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) -# define LZO_SIZEOF_VOID_P 2 -# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) -# define LZO_SIZEOF_VOID_P 4 -# else -# error "LZO_MM" -# endif -#elif (LZO_ARCH_AVR || LZO_ARCH_Z80) -# define __LZO_WORDSIZE 1 -# define LZO_SIZEOF_VOID_P 2 -#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) -# define LZO_SIZEOF_VOID_P 2 -#elif (LZO_ARCH_H8300) -# if defined(__NORMAL_MODE__) -# define __LZO_WORDSIZE 4 -# define LZO_SIZEOF_VOID_P 2 -# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) -# define __LZO_WORDSIZE 4 -# define LZO_SIZEOF_VOID_P 4 -# else -# define __LZO_WORDSIZE 2 -# define LZO_SIZEOF_VOID_P 2 -# endif -# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT -# endif -#elif (LZO_ARCH_M16C) -# define __LZO_WORDSIZE 2 -# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) -# define LZO_SIZEOF_VOID_P 4 -# else -# define LZO_SIZEOF_VOID_P 2 -# endif -#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) -# define __LZO_WORDSIZE 8 -# define LZO_SIZEOF_VOID_P 4 -#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) -# define __LZO_WORDSIZE 8 -# define LZO_SIZEOF_VOID_P 8 -#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) -# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG -#elif (LZO_OS_OS400 || defined(__OS400__)) -# define __LZO_WORDSIZE LZO_SIZEOF_LONG -# define LZO_SIZEOF_VOID_P 16 -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG -#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) -# define LZO_SIZEOF_VOID_P 8 -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG -#elif (LZO_ARCH_SPU) -# if 0 -# define __LZO_WORDSIZE 16 -# endif -# define LZO_SIZEOF_VOID_P 4 -#else -# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG -#endif -#endif -#if !defined(LZO_WORDSIZE) -# if defined(__LZO_WORDSIZE) -# define LZO_WORDSIZE __LZO_WORDSIZE -# else -# define LZO_WORDSIZE LZO_SIZEOF_VOID_P -# endif -#endif -#if !defined(LZO_SIZEOF_SIZE_T) -#if (LZO_ARCH_I086 || LZO_ARCH_M16C) -# define LZO_SIZEOF_SIZE_T 2 -#else -# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P -#endif -#endif -#if !defined(LZO_SIZEOF_PTRDIFF_T) -#if (LZO_ARCH_I086) -# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P -# elif (LZO_MM_COMPACT || LZO_MM_LARGE) -# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) -# define LZO_SIZEOF_PTRDIFF_T 4 -# else -# define LZO_SIZEOF_PTRDIFF_T 2 -# endif -# else -# error "LZO_MM" -# endif -#else -# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T -#endif -#endif -#if defined(LZO_ABI_NEUTRAL_ENDIAN) -# undef LZO_ABI_BIG_ENDIAN -# undef LZO_ABI_LITTLE_ENDIAN -#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN) -#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) -# define LZO_ABI_BIG_ENDIAN 1 -#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) -# define LZO_ABI_LITTLE_ENDIAN 1 -#elif (LZO_ARCH_M68K || LZO_ARCH_S390) -# define LZO_ABI_BIG_ENDIAN 1 -#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) -# if (__LITTLE_ENDIAN__ == 1) -# define LZO_ABI_LITTLE_ENDIAN 1 -# else -# define LZO_ABI_BIG_ENDIAN 1 -# endif -#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) -# define LZO_ABI_BIG_ENDIAN 1 -#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) -# define LZO_ABI_LITTLE_ENDIAN 1 -#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) -# define LZO_ABI_BIG_ENDIAN 1 -#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) -# define LZO_ABI_LITTLE_ENDIAN 1 -#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) -# define LZO_ABI_BIG_ENDIAN 1 -#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) -# define LZO_ABI_LITTLE_ENDIAN 1 -#endif -#endif -#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN) -# error "this should not happen" -#endif -#if defined(LZO_ABI_BIG_ENDIAN) -# define LZO_INFO_ABI_ENDIAN "be" -#elif defined(LZO_ABI_LITTLE_ENDIAN) -# define LZO_INFO_ABI_ENDIAN "le" -#elif defined(LZO_ABI_NEUTRAL_ENDIAN) -# define LZO_INFO_ABI_ENDIAN "neutral" -#endif -#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) -# define LZO_ABI_I8LP16 1 -# define LZO_INFO_ABI_PM "i8lp16" -#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) -# define LZO_ABI_ILP16 1 -# define LZO_INFO_ABI_PM "ilp16" -#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) -# define LZO_ABI_ILP32 1 -# define LZO_INFO_ABI_PM "ilp32" -#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) -# define LZO_ABI_LLP64 1 -# define LZO_INFO_ABI_PM "llp64" -#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) -# define LZO_ABI_LP64 1 -# define LZO_INFO_ABI_PM "lp64" -#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) -# define LZO_ABI_ILP64 1 -# define LZO_INFO_ABI_PM "ilp64" -#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) -# define LZO_ABI_IP32L64 1 -# define LZO_INFO_ABI_PM "ip32l64" -#endif -#if !defined(__LZO_LIBC_OVERRIDE) -#if defined(LZO_LIBC_NAKED) -# define LZO_INFO_LIBC "naked" -#elif defined(LZO_LIBC_FREESTANDING) -# define LZO_INFO_LIBC "freestanding" -#elif defined(LZO_LIBC_MOSTLY_FREESTANDING) -# define LZO_INFO_LIBC "mfreestanding" -#elif defined(LZO_LIBC_ISOC90) -# define LZO_INFO_LIBC "isoc90" -#elif defined(LZO_LIBC_ISOC99) -# define LZO_INFO_LIBC "isoc99" -#elif defined(__dietlibc__) -# define LZO_LIBC_DIETLIBC 1 -# define LZO_INFO_LIBC "dietlibc" -#elif defined(_NEWLIB_VERSION) -# define LZO_LIBC_NEWLIB 1 -# define LZO_INFO_LIBC "newlib" -#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) -# if defined(__UCLIBC_SUBLEVEL__) -# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) -# else -# define LZO_LIBC_UCLIBC 0x00090bL -# endif -# define LZO_INFO_LIBC "uclibc" -#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) -# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) -# define LZO_INFO_LIBC "glibc" -#elif (LZO_CC_MWERKS) && defined(__MSL__) -# define LZO_LIBC_MSL __MSL__ -# define LZO_INFO_LIBC "msl" -#elif 1 && defined(__IAR_SYSTEMS_ICC__) -# define LZO_LIBC_ISOC90 1 -# define LZO_INFO_LIBC "isoc90" -#else -# define LZO_LIBC_DEFAULT 1 -# define LZO_INFO_LIBC "default" -#endif -#endif -#if !defined(__lzo_gnuc_extension__) -#if (LZO_CC_GNUC >= 0x020800ul) -# define __lzo_gnuc_extension__ __extension__ -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_gnuc_extension__ __extension__ -#else -# define __lzo_gnuc_extension__ -#endif -#endif -#if !defined(__lzo_ua_volatile) -# define __lzo_ua_volatile volatile -#endif -#if !defined(__lzo_alignof) -#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) -# define __lzo_alignof(e) __alignof__(e) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) -# define __lzo_alignof(e) __alignof__(e) -#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) -# define __lzo_alignof(e) __alignof(e) -#endif -#endif -#if defined(__lzo_alignof) -# define __lzo_HAVE_alignof 1 -#endif -#if !defined(__lzo_constructor) -#if (LZO_CC_GNUC >= 0x030400ul) -# define __lzo_constructor __attribute__((__constructor__,__used__)) -#elif (LZO_CC_GNUC >= 0x020700ul) -# define __lzo_constructor __attribute__((__constructor__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_constructor __attribute__((__constructor__)) -#endif -#endif -#if defined(__lzo_constructor) -# define __lzo_HAVE_constructor 1 -#endif -#if !defined(__lzo_destructor) -#if (LZO_CC_GNUC >= 0x030400ul) -# define __lzo_destructor __attribute__((__destructor__,__used__)) -#elif (LZO_CC_GNUC >= 0x020700ul) -# define __lzo_destructor __attribute__((__destructor__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_destructor __attribute__((__destructor__)) -#endif -#endif -#if defined(__lzo_destructor) -# define __lzo_HAVE_destructor 1 -#endif -#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor) -# error "this should not happen" -#endif -#if !defined(__lzo_inline) -#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) -#elif defined(__cplusplus) -# define __lzo_inline inline -#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) -# define __lzo_inline __inline -#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) -# define __lzo_inline __inline__ -#elif (LZO_CC_DMC) -# define __lzo_inline __inline -#elif (LZO_CC_INTELC) -# define __lzo_inline __inline -#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) -# define __lzo_inline __inline -#elif (LZO_CC_MSC && (_MSC_VER >= 900)) -# define __lzo_inline __inline -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -# define __lzo_inline inline -#endif -#endif -#if defined(__lzo_inline) -# define __lzo_HAVE_inline 1 -#else -# define __lzo_inline -#endif -#if !defined(__lzo_forceinline) -#if (LZO_CC_GNUC >= 0x030200ul) -# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) -# define __lzo_forceinline __forceinline -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) -# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) -# define __lzo_forceinline __forceinline -#endif -#endif -#if defined(__lzo_forceinline) -# define __lzo_HAVE_forceinline 1 -#else -# define __lzo_forceinline -#endif -#if !defined(__lzo_noinline) -#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) -# define __lzo_noinline __attribute__((__noinline__,__used__)) -#elif (LZO_CC_GNUC >= 0x030200ul) -# define __lzo_noinline __attribute__((__noinline__)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) -# define __lzo_noinline __declspec(noinline) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) -# define __lzo_noinline __attribute__((__noinline__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_noinline __attribute__((__noinline__)) -#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) -# define __lzo_noinline __declspec(noinline) -#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) -# if defined(__cplusplus) -# else -# define __lzo_noinline __declspec(noinline) -# endif -#endif -#endif -#if defined(__lzo_noinline) -# define __lzo_HAVE_noinline 1 -#else -# define __lzo_noinline -#endif -#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline) -# error "this should not happen" -#endif -#if !defined(__lzo_noreturn) -#if (LZO_CC_GNUC >= 0x020700ul) -# define __lzo_noreturn __attribute__((__noreturn__)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) -# define __lzo_noreturn __declspec(noreturn) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) -# define __lzo_noreturn __attribute__((__noreturn__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_noreturn __attribute__((__noreturn__)) -#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) -# define __lzo_noreturn __declspec(noreturn) -#endif -#endif -#if defined(__lzo_noreturn) -# define __lzo_HAVE_noreturn 1 -#else -# define __lzo_noreturn -#endif -#if !defined(__lzo_nothrow) -#if (LZO_CC_GNUC >= 0x030300ul) -# define __lzo_nothrow __attribute__((__nothrow__)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) -# define __lzo_nothrow __declspec(nothrow) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) -# define __lzo_nothrow __attribute__((__nothrow__)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_nothrow __attribute__((__nothrow__)) -#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) -# define __lzo_nothrow __declspec(nothrow) -#endif -#endif -#if defined(__lzo_nothrow) -# define __lzo_HAVE_nothrow 1 -#else -# define __lzo_nothrow -#endif -#if !defined(__lzo_restrict) -#if (LZO_CC_GNUC >= 0x030400ul) -# define __lzo_restrict __restrict__ -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) -# define __lzo_restrict __restrict__ -#elif (LZO_CC_LLVM) -# define __lzo_restrict __restrict__ -#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) -# define __lzo_restrict __restrict -#endif -#endif -#if defined(__lzo_restrict) -# define __lzo_HAVE_restrict 1 -#else -# define __lzo_restrict -#endif -#if !defined(__lzo_likely) && !defined(__lzo_unlikely) -#if (LZO_CC_GNUC >= 0x030200ul) -# define __lzo_likely(e) (__builtin_expect(!!(e),1)) -# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) -# define __lzo_likely(e) (__builtin_expect(!!(e),1)) -# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define __lzo_likely(e) (__builtin_expect(!!(e),1)) -# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -#endif -#endif -#if defined(__lzo_likely) -# define __lzo_HAVE_likely 1 -#else -# define __lzo_likely(e) (e) -#endif -#if defined(__lzo_unlikely) -# define __lzo_HAVE_unlikely 1 -#else -# define __lzo_unlikely(e) (e) -#endif -#if !defined(LZO_UNUSED) -# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) -# define LZO_UNUSED(var) ((void) &var) -# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) -# define LZO_UNUSED(var) if (&var) ; else -# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) -# define LZO_UNUSED(var) ((void) var) -# elif (LZO_CC_MSC && (_MSC_VER < 900)) -# define LZO_UNUSED(var) if (&var) ; else -# elif (LZO_CC_KEILC) -# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} -# elif (LZO_CC_PACIFICC) -# define LZO_UNUSED(var) ((void) sizeof(var)) -# elif (LZO_CC_WATCOMC) && defined(__cplusplus) -# define LZO_UNUSED(var) ((void) var) -# else -# define LZO_UNUSED(var) ((void) &var) -# endif -#endif -#if !defined(LZO_UNUSED_FUNC) -# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) -# define LZO_UNUSED_FUNC(func) ((void) func) -# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) -# define LZO_UNUSED_FUNC(func) if (func) ; else -# elif (LZO_CC_LLVM) -# define LZO_UNUSED_FUNC(func) ((void) &func) -# elif (LZO_CC_MSC && (_MSC_VER < 900)) -# define LZO_UNUSED_FUNC(func) if (func) ; else -# elif (LZO_CC_MSC) -# define LZO_UNUSED_FUNC(func) ((void) &func) -# elif (LZO_CC_KEILC || LZO_CC_PELLESC) -# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} -# else -# define LZO_UNUSED_FUNC(func) ((void) func) -# endif -#endif -#if !defined(LZO_UNUSED_LABEL) -# if (LZO_CC_WATCOMC) && defined(__cplusplus) -# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l -# elif (LZO_CC_INTELC || LZO_CC_WATCOMC) -# define LZO_UNUSED_LABEL(l) if (0) goto l -# else -# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l -# endif -#endif -#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) -# if 0 -# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var -# elif 0 && (LZO_CC_GNUC) -# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var -# else -# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init -# endif -#endif -#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) -# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) -# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; -# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) -# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; -# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) -# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; -# else -# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; -# endif -#endif -#if !defined(LZO_COMPILE_TIME_ASSERT) -# if (LZO_CC_AZTECC) -# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} -# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) -# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; -# elif (LZO_CC_MSC && (_MSC_VER < 900)) -# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; -# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) -# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; -# else -# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} -# endif -#endif -#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) -# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) -# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) -# define __lzo_cdecl __cdecl -# define __lzo_cdecl_atexit -# define __lzo_cdecl_main __cdecl -# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) -# define __lzo_cdecl_qsort __pascal -# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) -# define __lzo_cdecl_qsort _stdcall -# else -# define __lzo_cdecl_qsort __cdecl -# endif -# elif (LZO_CC_WATCOMC) -# define __lzo_cdecl __cdecl -# else -# define __lzo_cdecl __cdecl -# define __lzo_cdecl_atexit __cdecl -# define __lzo_cdecl_main __cdecl -# define __lzo_cdecl_qsort __cdecl -# endif -# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) -# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) -# define __lzo_cdecl_sighandler __pascal -# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) -# define __lzo_cdecl_sighandler _stdcall -# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) -# define __lzo_cdecl_sighandler __clrcall -# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) -# if defined(_DLL) -# define __lzo_cdecl_sighandler _far _cdecl _loadds -# elif defined(_MT) -# define __lzo_cdecl_sighandler _far _cdecl -# else -# define __lzo_cdecl_sighandler _cdecl -# endif -# else -# define __lzo_cdecl_sighandler __cdecl -# endif -#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) -# define __lzo_cdecl __cdecl -#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) -# define __lzo_cdecl cdecl -#endif -#if !defined(__lzo_cdecl) -# define __lzo_cdecl -#endif -#if !defined(__lzo_cdecl_atexit) -# define __lzo_cdecl_atexit -#endif -#if !defined(__lzo_cdecl_main) -# define __lzo_cdecl_main -#endif -#if !defined(__lzo_cdecl_qsort) -# define __lzo_cdecl_qsort -#endif -#if !defined(__lzo_cdecl_sighandler) -# define __lzo_cdecl_sighandler -#endif -#if !defined(__lzo_cdecl_va) -# define __lzo_cdecl_va __lzo_cdecl -#endif -#if !defined(LZO_CFG_NO_WINDOWS_H) -#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) -# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) -# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) -# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) -# else -# define LZO_HAVE_WINDOWS_H 1 -# endif -#endif -#endif -#if (LZO_ARCH_ALPHA) -# define LZO_OPT_AVOID_UINT_INDEX 1 -# define LZO_OPT_AVOID_SHORT 1 -# define LZO_OPT_AVOID_USHORT 1 -#elif (LZO_ARCH_AMD64) -# define LZO_OPT_AVOID_INT_INDEX 1 -# define LZO_OPT_AVOID_UINT_INDEX 1 -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -# define LZO_OPT_UNALIGNED64 1 -#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) -#elif (LZO_ARCH_ARM) -# define LZO_OPT_AVOID_SHORT 1 -# define LZO_OPT_AVOID_USHORT 1 -#elif (LZO_ARCH_CRIS) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -#elif (LZO_ARCH_I386) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -#elif (LZO_ARCH_IA64) -# define LZO_OPT_AVOID_INT_INDEX 1 -# define LZO_OPT_AVOID_UINT_INDEX 1 -# define LZO_OPT_PREFER_POSTINC 1 -#elif (LZO_ARCH_M68K) -# define LZO_OPT_PREFER_POSTINC 1 -# define LZO_OPT_PREFER_PREDEC 1 -# if defined(__mc68020__) && !defined(__mcoldfire__) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -# endif -#elif (LZO_ARCH_MIPS) -# define LZO_OPT_AVOID_UINT_INDEX 1 -#elif (LZO_ARCH_POWERPC) -# define LZO_OPT_PREFER_PREINC 1 -# define LZO_OPT_PREFER_PREDEC 1 -# if defined(LZO_ABI_BIG_ENDIAN) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -# endif -#elif (LZO_ARCH_S390) -# define LZO_OPT_UNALIGNED16 1 -# define LZO_OPT_UNALIGNED32 1 -# if (LZO_SIZEOF_SIZE_T == 8) -# define LZO_OPT_UNALIGNED64 1 -# endif -#elif (LZO_ARCH_SH) -# define LZO_OPT_PREFER_POSTINC 1 -# define LZO_OPT_PREFER_PREDEC 1 -#endif -#if !defined(LZO_CFG_NO_INLINE_ASM) -#if defined(LZO_CC_LLVM) -# define LZO_CFG_NO_INLINE_ASM 1 -#endif -#endif -#if !defined(LZO_CFG_NO_UNALIGNED) -#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC) -# define LZO_CFG_NO_UNALIGNED 1 -#endif -#endif -#if defined(LZO_CFG_NO_UNALIGNED) -# undef LZO_OPT_UNALIGNED16 -# undef LZO_OPT_UNALIGNED32 -# undef LZO_OPT_UNALIGNED64 -#endif -#if defined(LZO_CFG_NO_INLINE_ASM) -#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) -# define LZO_ASM_SYNTAX_MSC 1 -#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) -#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) -# define LZO_ASM_SYNTAX_GNUC 1 -#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) -# define LZO_ASM_SYNTAX_GNUC 1 -#endif -#if (LZO_ASM_SYNTAX_GNUC) -#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) -# define __LZO_ASM_CLOBBER "ax" -#elif (LZO_CC_INTELC) -# define __LZO_ASM_CLOBBER "memory" -#else -# define __LZO_ASM_CLOBBER "cc", "memory" -#endif -#endif -#if defined(__LZO_INFOSTR_MM) -#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) -# define __LZO_INFOSTR_MM "" -#elif defined(LZO_INFO_MM) -# define __LZO_INFOSTR_MM "." LZO_INFO_MM -#else -# define __LZO_INFOSTR_MM "" -#endif -#if defined(__LZO_INFOSTR_PM) -#elif defined(LZO_INFO_ABI_PM) -# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM -#else -# define __LZO_INFOSTR_PM "" -#endif -#if defined(__LZO_INFOSTR_ENDIAN) -#elif defined(LZO_INFO_ABI_ENDIAN) -# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN -#else -# define __LZO_INFOSTR_ENDIAN "" -#endif -#if defined(__LZO_INFOSTR_OSNAME) -#elif defined(LZO_INFO_OS_CONSOLE) -# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE -#elif defined(LZO_INFO_OS_POSIX) -# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX -#else -# define __LZO_INFOSTR_OSNAME LZO_INFO_OS -#endif -#if defined(__LZO_INFOSTR_LIBC) -#elif defined(LZO_INFO_LIBC) -# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC -#else -# define __LZO_INFOSTR_LIBC "" -#endif -#if defined(__LZO_INFOSTR_CCVER) -#elif defined(LZO_INFO_CCVER) -# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER -#else -# define __LZO_INFOSTR_CCVER "" -#endif -#define LZO_INFO_STRING \ - LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ - " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER - -#endif - -#endif - -#undef LZO_HAVE_CONFIG_H -#include "minilzo.h" - -#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2030) -# error "version mismatch in miniLZO source files" -#endif - -#ifdef MINILZO_HAVE_CONFIG_H -# define LZO_HAVE_CONFIG_H -#endif - -#ifndef __LZO_CONF_H -#define __LZO_CONF_H - -#if !defined(__LZO_IN_MINILZO) -#if defined(LZO_CFG_FREESTANDING) -# define LZO_LIBC_FREESTANDING 1 -# define LZO_OS_FREESTANDING 1 -# define ACC_LIBC_FREESTANDING 1 -# define ACC_OS_FREESTANDING 1 -#endif -#if defined(LZO_CFG_NO_UNALIGNED) -# define ACC_CFG_NO_UNALIGNED 1 -#endif -#if defined(LZO_ARCH_GENERIC) -# define ACC_ARCH_GENERIC 1 -#endif -#if defined(LZO_ABI_NEUTRAL_ENDIAN) -# define ACC_ABI_NEUTRAL_ENDIAN 1 -#endif -#if defined(LZO_HAVE_CONFIG_H) -# define ACC_CONFIG_NO_HEADER 1 -#endif -#if defined(LZO_CFG_EXTRA_CONFIG_HEADER) -# include LZO_CFG_EXTRA_CONFIG_HEADER -#endif -#if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED) -# error "include this file first" -#endif -#include "lzo/lzoconf.h" -#endif - -#if (LZO_VERSION < 0x02000) || !defined(__LZOCONF_H_INCLUDED) -# error "version mismatch" -#endif - -#if (LZO_CC_BORLANDC && LZO_ARCH_I086) -# pragma option -h -#endif - -#if (LZO_CC_MSC && (_MSC_VER >= 1000)) -# pragma warning(disable: 4127 4701) -#endif -#if (LZO_CC_MSC && (_MSC_VER >= 1300)) -# pragma warning(disable: 4820) -# pragma warning(disable: 4514 4710 4711) -#endif - -#if (LZO_CC_SUNPROC) -# pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED) -# pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP) -#endif - -#if defined(__LZO_MMODEL_HUGE) && (!LZO_HAVE_MM_HUGE_PTR) -# error "this should not happen - check defines for __huge" -#endif - -#if defined(__LZO_IN_MINILZO) || defined(LZO_CFG_FREESTANDING) -#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -# define ACC_WANT_ACC_INCD_H 1 -# define ACC_WANT_ACC_INCE_H 1 -# define ACC_WANT_ACC_INCI_H 1 -#elif 1 -# include -#else -# define ACC_WANT_ACC_INCD_H 1 -#endif - -#if (LZO_ARCH_I086) -# define ACC_MM_AHSHIFT LZO_MM_AHSHIFT -# define ACC_PTR_FP_OFF(x) (((const unsigned __far*)&(x))[0]) -# define ACC_PTR_FP_SEG(x) (((const unsigned __far*)&(x))[1]) -# define ACC_PTR_MK_FP(s,o) ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o))) -#endif - -#if !defined(lzo_uintptr_t) -# if defined(__LZO_MMODEL_HUGE) -# define lzo_uintptr_t unsigned long -# elif 1 && defined(LZO_OS_OS400) && (LZO_SIZEOF_VOID_P == 16) -# define __LZO_UINTPTR_T_IS_POINTER 1 - typedef char* lzo_uintptr_t; -# define lzo_uintptr_t lzo_uintptr_t -# elif (LZO_SIZEOF_SIZE_T == LZO_SIZEOF_VOID_P) -# define lzo_uintptr_t size_t -# elif (LZO_SIZEOF_LONG == LZO_SIZEOF_VOID_P) -# define lzo_uintptr_t unsigned long -# elif (LZO_SIZEOF_INT == LZO_SIZEOF_VOID_P) -# define lzo_uintptr_t unsigned int -# elif (LZO_SIZEOF_LONG_LONG == LZO_SIZEOF_VOID_P) -# define lzo_uintptr_t unsigned long long -# else -# define lzo_uintptr_t size_t -# endif -#endif -LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) - -#if 1 && !defined(LZO_CFG_FREESTANDING) -#if 1 && !defined(HAVE_STRING_H) -#define HAVE_STRING_H 1 -#endif -#if 1 && !defined(HAVE_MEMCMP) -#define HAVE_MEMCMP 1 -#endif -#if 1 && !defined(HAVE_MEMCPY) -#define HAVE_MEMCPY 1 -#endif -#if 1 && !defined(HAVE_MEMMOVE) -#define HAVE_MEMMOVE 1 -#endif -#if 1 && !defined(HAVE_MEMSET) -#define HAVE_MEMSET 1 -#endif -#endif - -#if 1 && defined(HAVE_STRING_H) -#include -#endif - -#if defined(LZO_CFG_FREESTANDING) -# undef HAVE_MEMCMP -# undef HAVE_MEMCPY -# undef HAVE_MEMMOVE -# undef HAVE_MEMSET -#endif - -#if !defined(HAVE_MEMCMP) -# undef memcmp -# define memcmp(a,b,c) lzo_memcmp(a,b,c) -#elif !defined(__LZO_MMODEL_HUGE) -# define lzo_memcmp(a,b,c) memcmp(a,b,c) -#endif -#if !defined(HAVE_MEMCPY) -# undef memcpy -# define memcpy(a,b,c) lzo_memcpy(a,b,c) -#elif !defined(__LZO_MMODEL_HUGE) -# define lzo_memcpy(a,b,c) memcpy(a,b,c) -#endif -#if !defined(HAVE_MEMMOVE) -# undef memmove -# define memmove(a,b,c) lzo_memmove(a,b,c) -#elif !defined(__LZO_MMODEL_HUGE) -# define lzo_memmove(a,b,c) memmove(a,b,c) -#endif -#if !defined(HAVE_MEMSET) -# undef memset -# define memset(a,b,c) lzo_memset(a,b,c) -#elif !defined(__LZO_MMODEL_HUGE) -# define lzo_memset(a,b,c) memset(a,b,c) -#endif - -#undef NDEBUG -#if defined(LZO_CFG_FREESTANDING) -# undef LZO_DEBUG -# define NDEBUG 1 -# undef assert -# define assert(e) ((void)0) -#else -# if !defined(LZO_DEBUG) -# define NDEBUG 1 -# endif -# include -#endif - -#if 0 && defined(__BOUNDS_CHECKING_ON) -# include -#else -# define BOUNDS_CHECKING_OFF_DURING(stmt) stmt -# define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr) -#endif - -#if !defined(__lzo_inline) -# define __lzo_inline -#endif -#if !defined(__lzo_forceinline) -# define __lzo_forceinline -#endif -#if !defined(__lzo_noinline) -# define __lzo_noinline -#endif - -#if 1 -# define LZO_BYTE(x) ((unsigned char) (x)) -#else -# define LZO_BYTE(x) ((unsigned char) ((x) & 0xff)) -#endif - -#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) -#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) -#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) -#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c)) - -#define lzo_sizeof(type) ((lzo_uint) (sizeof(type))) - -#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array)))) - -#define LZO_SIZE(bits) (1u << (bits)) -#define LZO_MASK(bits) (LZO_SIZE(bits) - 1) - -#define LZO_LSIZE(bits) (1ul << (bits)) -#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1) - -#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits)) -#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1) - -#if !defined(DMUL) -#if 0 - -# define DMUL(a,b) ((lzo_xint) ((lzo_uint32)(a) * (lzo_uint32)(b))) -#else -# define DMUL(a,b) ((lzo_xint) ((a) * (b))) -#endif -#endif - -#if 1 && !defined(LZO_CFG_NO_UNALIGNED) -#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386) -# if (LZO_SIZEOF_SHORT == 2) -# define LZO_UNALIGNED_OK_2 -# endif -# if (LZO_SIZEOF_INT == 4) -# define LZO_UNALIGNED_OK_4 -# endif -#endif -#endif - -#if defined(LZO_UNALIGNED_OK_2) - LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(short) == 2) -#endif -#if defined(LZO_UNALIGNED_OK_4) - LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) -#elif defined(LZO_ALIGNED_OK_4) - LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) -#endif - -#define MEMCPY8_DS(dest,src,len) \ - lzo_memcpy(dest,src,len); dest += len; src += len - -#define BZERO8_PTR(s,l,n) \ - lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n)) - -#define MEMCPY_DS(dest,src,len) \ - do *dest++ = *src++; while (--len > 0) - -__LZO_EXTERN_C int __lzo_init_done; -__LZO_EXTERN_C const char __lzo_copyright[]; -LZO_EXTERN(const lzo_bytep) lzo_copyright(void); - -#ifndef __LZO_PTR_H -#define __LZO_PTR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(lzo_uintptr_t) -# if defined(__LZO_MMODEL_HUGE) -# define lzo_uintptr_t unsigned long -# else -# define lzo_uintptr_t acc_uintptr_t -# ifdef __ACC_INTPTR_T_IS_POINTER -# define __LZO_UINTPTR_T_IS_POINTER 1 -# endif -# endif -#endif - -#if (LZO_ARCH_I086) -#define PTR(a) ((lzo_bytep) (a)) -#define PTR_ALIGNED_4(a) ((ACC_PTR_FP_OFF(a) & 3) == 0) -#define PTR_ALIGNED2_4(a,b) (((ACC_PTR_FP_OFF(a) | ACC_PTR_FP_OFF(b)) & 3) == 0) -#elif (LZO_MM_PVP) -#define PTR(a) ((lzo_bytep) (a)) -#define PTR_ALIGNED_8(a) ((((lzo_uintptr_t)(a)) >> 61) == 0) -#define PTR_ALIGNED2_8(a,b) ((((lzo_uintptr_t)(a)|(lzo_uintptr_t)(b)) >> 61) == 0) -#else -#define PTR(a) ((lzo_uintptr_t) (a)) -#define PTR_LINEAR(a) PTR(a) -#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0) -#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0) -#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0) -#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0) -#endif - -#define PTR_LT(a,b) (PTR(a) < PTR(b)) -#define PTR_GE(a,b) (PTR(a) >= PTR(b)) -#define PTR_DIFF(a,b) (PTR(a) - PTR(b)) -#define pd(a,b) ((lzo_uint) ((a)-(b))) - -LZO_EXTERN(lzo_uintptr_t) -__lzo_ptr_linear(const lzo_voidp ptr); - -typedef union -{ - char a_char; - unsigned char a_uchar; - short a_short; - unsigned short a_ushort; - int a_int; - unsigned int a_uint; - long a_long; - unsigned long a_ulong; - lzo_int a_lzo_int; - lzo_uint a_lzo_uint; - lzo_int32 a_lzo_int32; - lzo_uint32 a_lzo_uint32; - ptrdiff_t a_ptrdiff_t; - lzo_uintptr_t a_lzo_uintptr_t; - lzo_voidp a_lzo_voidp; - void * a_void_p; - lzo_bytep a_lzo_bytep; - lzo_bytepp a_lzo_bytepp; - lzo_uintp a_lzo_uintp; - lzo_uint * a_lzo_uint_p; - lzo_uint32p a_lzo_uint32p; - lzo_uint32 * a_lzo_uint32_p; - unsigned char * a_uchar_p; - char * a_char_p; -} -lzo_full_align_t; - -#ifdef __cplusplus -} -#endif - -#endif - -#define LZO_DETERMINISTIC - -#define LZO_DICT_USE_PTR -#if 0 && (LZO_ARCH_I086) -# undef LZO_DICT_USE_PTR -#endif - -#if defined(LZO_DICT_USE_PTR) -# define lzo_dict_t const lzo_bytep -# define lzo_dict_p lzo_dict_t __LZO_MMODEL * -#else -# define lzo_dict_t lzo_uint -# define lzo_dict_p lzo_dict_t __LZO_MMODEL * -#endif - -#endif - -#if !defined(MINILZO_CFG_SKIP_LZO_PTR) - -LZO_PUBLIC(lzo_uintptr_t) -__lzo_ptr_linear(const lzo_voidp ptr) -{ - lzo_uintptr_t p; - -#if (LZO_ARCH_I086) - p = (((lzo_uintptr_t)(ACC_PTR_FP_SEG(ptr))) << (16 - ACC_MM_AHSHIFT)) + (ACC_PTR_FP_OFF(ptr)); -#elif (LZO_MM_PVP) - p = (lzo_uintptr_t) (ptr); - p = (p << 3) | (p >> 61); -#else - p = (lzo_uintptr_t) PTR_LINEAR(ptr); -#endif - - return p; -} - -LZO_PUBLIC(unsigned) -__lzo_align_gap(const lzo_voidp ptr, lzo_uint size) -{ -#if defined(__LZO_UINTPTR_T_IS_POINTER) - size_t n = (size_t) ptr; - n = (((n + size - 1) / size) * size) - n; -#else - lzo_uintptr_t p, n; - p = __lzo_ptr_linear(ptr); - n = (((p + size - 1) / size) * size) - p; -#endif - - assert(size > 0); - assert((long)n >= 0); - assert(n <= size); - return (unsigned)n; -} - -#endif - -/* If you use the LZO library in a product, I would appreciate that you - * keep this copyright string in the executable of your product. - */ - -const char __lzo_copyright[] = -#if !defined(__LZO_IN_MINLZO) - LZO_VERSION_STRING; -#else - "\r\n\n" - "LZO data compression library.\n" - "$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Markus Franz Xaver Johannes Oberhumer\n" - "\n" - "http://www.oberhumer.com $\n\n" - "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n" - "$Built: " __DATE__ " " __TIME__ " $\n" - "$Info: " LZO_INFO_STRING " $\n"; -#endif - -LZO_PUBLIC(const lzo_bytep) -lzo_copyright(void) -{ -#if (LZO_OS_DOS16 && LZO_CC_TURBOC) - return (lzo_voidp) __lzo_copyright; -#else - return (const lzo_bytep) __lzo_copyright; -#endif -} - -LZO_PUBLIC(unsigned) -lzo_version(void) -{ - return LZO_VERSION; -} - -LZO_PUBLIC(const char *) -lzo_version_string(void) -{ - return LZO_VERSION_STRING; -} - -LZO_PUBLIC(const char *) -lzo_version_date(void) -{ - return LZO_VERSION_DATE; -} - -LZO_PUBLIC(const lzo_charp) -_lzo_version_string(void) -{ - return LZO_VERSION_STRING; -} - -LZO_PUBLIC(const lzo_charp) -_lzo_version_date(void) -{ - return LZO_VERSION_DATE; -} - -#define LZO_BASE 65521u -#define LZO_NMAX 5552 - -#define LZO_DO1(buf,i) s1 += buf[i]; s2 += s1 -#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1); -#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2); -#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4); -#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8); - -LZO_PUBLIC(lzo_uint32) -lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len) -{ - lzo_uint32 s1 = adler & 0xffff; - lzo_uint32 s2 = (adler >> 16) & 0xffff; - unsigned k; - - if (buf == NULL) - return 1; - - while (len > 0) - { - k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX; - len -= k; - if (k >= 16) do - { - LZO_DO16(buf,0); - buf += 16; - k -= 16; - } while (k >= 16); - if (k != 0) do - { - s1 += *buf++; - s2 += s1; - } while (--k > 0); - s1 %= LZO_BASE; - s2 %= LZO_BASE; - } - return (s2 << 16) | s1; -} - -#undef LZO_DO1 -#undef LZO_DO2 -#undef LZO_DO4 -#undef LZO_DO8 -#undef LZO_DO16 - -#if !defined(MINILZO_CFG_SKIP_LZO_STRING) -#undef lzo_memcmp -#undef lzo_memcpy -#undef lzo_memmove -#undef lzo_memset -#if !defined(__LZO_MMODEL_HUGE) -# undef LZO_HAVE_MM_HUGE_PTR -#endif -#define lzo_hsize_t lzo_uint -#define lzo_hvoid_p lzo_voidp -#define lzo_hbyte_p lzo_bytep -#define LZOLIB_PUBLIC(r,f) LZO_PUBLIC(r) f -#define lzo_hmemcmp lzo_memcmp -#define lzo_hmemcpy lzo_memcpy -#define lzo_hmemmove lzo_memmove -#define lzo_hmemset lzo_memset -#define __LZOLIB_HMEMCPY_CH_INCLUDED 1 -#if !defined(LZOLIB_PUBLIC) -# define LZOLIB_PUBLIC(r,f) r __LZOLIB_FUNCNAME(f) -#endif -LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len) -{ -#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCMP) - const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1; - const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2; - if __lzo_likely(len > 0) do - { - int d = *p1 - *p2; - if (d != 0) - return d; - p1++; p2++; - } while __lzo_likely(--len > 0); - return 0; -#else - return memcmp(s1, s2, len); -#endif -} -LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) -{ -#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCPY) - lzo_hbyte_p p1 = (lzo_hbyte_p) dest; - const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; - if (!(len > 0) || p1 == p2) - return dest; - do - *p1++ = *p2++; - while __lzo_likely(--len > 0); - return dest; -#else - return memcpy(dest, src, len); -#endif -} -LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) -{ -#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMMOVE) - lzo_hbyte_p p1 = (lzo_hbyte_p) dest; - const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; - if (!(len > 0) || p1 == p2) - return dest; - if (p1 < p2) - { - do - *p1++ = *p2++; - while __lzo_likely(--len > 0); - } - else - { - p1 += len; - p2 += len; - do - *--p1 = *--p2; - while __lzo_likely(--len > 0); - } - return dest; -#else - return memmove(dest, src, len); -#endif -} -LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len) -{ -#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMSET) - lzo_hbyte_p p = (lzo_hbyte_p) s; - if __lzo_likely(len > 0) do - *p++ = (unsigned char) c; - while __lzo_likely(--len > 0); - return s; -#else - return memset(s, c, len); -#endif -} -#undef LZOLIB_PUBLIC -#endif - -#if !defined(__LZO_IN_MINILZO) - -#define ACC_WANT_ACC_CHK_CH 1 -#undef ACCCHK_ASSERT - - ACCCHK_ASSERT_IS_SIGNED_T(lzo_int) - ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint) - - ACCCHK_ASSERT_IS_SIGNED_T(lzo_int32) - ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32) - ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0) - ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4) - -#if !defined(__LZO_UINTPTR_T_IS_POINTER) - ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t) -#endif - ACCCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) - - ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_xint) - ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint32)) - ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint)) - ACCCHK_ASSERT(sizeof(lzo_xint) == sizeof(lzo_uint32) || sizeof(lzo_xint) == sizeof(lzo_uint)) - -#endif -#undef ACCCHK_ASSERT - -LZO_PUBLIC(int) -_lzo_config_check(void) -{ - lzo_bool r = 1; - union { unsigned char c[2*sizeof(lzo_xint)]; lzo_xint l[2]; } u; - lzo_uintptr_t p; - -#if !defined(LZO_CFG_NO_CONFIG_CHECK) -#if defined(LZO_ABI_BIG_ENDIAN) - u.l[0] = u.l[1] = 0; u.c[sizeof(lzo_xint) - 1] = 128; - r &= (u.l[0] == 128); -#endif -#if defined(LZO_ABI_LITTLE_ENDIAN) - u.l[0] = u.l[1] = 0; u.c[0] = 128; - r &= (u.l[0] == 128); -#endif -#if defined(LZO_UNALIGNED_OK_2) - p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0]; - u.l[0] = u.l[1] = 0; - r &= ((* (const lzo_ushortp) (p+1)) == 0); -#endif -#if defined(LZO_UNALIGNED_OK_4) - p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0]; - u.l[0] = u.l[1] = 0; - r &= ((* (const lzo_uint32p) (p+1)) == 0); -#endif -#endif - - LZO_UNUSED(u); LZO_UNUSED(p); - return r == 1 ? LZO_E_OK : LZO_E_ERROR; -} - -int __lzo_init_done = 0; - -LZO_PUBLIC(int) -__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5, - int s6, int s7, int s8, int s9) -{ - int r; - -#if defined(__LZO_IN_MINILZO) -#elif (LZO_CC_MSC && ((_MSC_VER) < 700)) -#else -#define ACC_WANT_ACC_CHK_CH 1 -#undef ACCCHK_ASSERT -#define ACCCHK_ASSERT(expr) LZO_COMPILE_TIME_ASSERT(expr) -#endif -#undef ACCCHK_ASSERT - - __lzo_init_done = 1; - - if (v == 0) - return LZO_E_ERROR; - - r = (s1 == -1 || s1 == (int) sizeof(short)) && - (s2 == -1 || s2 == (int) sizeof(int)) && - (s3 == -1 || s3 == (int) sizeof(long)) && - (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) && - (s5 == -1 || s5 == (int) sizeof(lzo_uint)) && - (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) && - (s7 == -1 || s7 == (int) sizeof(char *)) && - (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) && - (s9 == -1 || s9 == (int) sizeof(lzo_callback_t)); - if (!r) - return LZO_E_ERROR; - - r = _lzo_config_check(); - if (r != LZO_E_OK) - return r; - - return r; -} - -#if !defined(__LZO_IN_MINILZO) - -#if (LZO_OS_WIN16 && LZO_CC_WATCOMC) && defined(__SW_BD) - -#if 0 -BOOL FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSegment, - WORD wHeapSize, LPSTR lpszCmdLine ) -#else -int __far __pascal LibMain ( int a, short b, short c, long d ) -#endif -{ - LZO_UNUSED(a); LZO_UNUSED(b); LZO_UNUSED(c); LZO_UNUSED(d); - return 1; -} - -#endif - -#endif - -#define do_compress _lzo1x_1_do_compress - -#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS) - -#define LZO_NEED_DICT_H -#define D_BITS 14 -#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) -#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) - -#ifndef __LZO_CONFIG1X_H -#define __LZO_CONFIG1X_H - -#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z) -# define LZO1X -#endif - -#if !defined(__LZO_IN_MINILZO) -#include "lzo/lzo1x.h" -#endif - -#define LZO_EOF_CODE -#undef LZO_DETERMINISTIC - -#define M1_MAX_OFFSET 0x0400 -#ifndef M2_MAX_OFFSET -#define M2_MAX_OFFSET 0x0800 -#endif -#define M3_MAX_OFFSET 0x4000 -#define M4_MAX_OFFSET 0xbfff - -#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) - -#define M1_MIN_LEN 2 -#define M1_MAX_LEN 2 -#define M2_MIN_LEN 3 -#ifndef M2_MAX_LEN -#define M2_MAX_LEN 8 -#endif -#define M3_MIN_LEN 3 -#define M3_MAX_LEN 33 -#define M4_MIN_LEN 3 -#define M4_MAX_LEN 9 - -#define M1_MARKER 0 -#define M2_MARKER 64 -#define M3_MARKER 32 -#define M4_MARKER 16 - -#ifndef MIN_LOOKAHEAD -#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) -#endif - -#if defined(LZO_NEED_DICT_H) - -#ifndef LZO_HASH -#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B -#endif -#define DL_MIN_LEN M2_MIN_LEN - -#ifndef __LZO_DICT_H -#define __LZO_DICT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(D_BITS) && defined(DBITS) -# define D_BITS DBITS -#endif -#if !defined(D_BITS) -# error "D_BITS is not defined" -#endif -#if (D_BITS < 16) -# define D_SIZE LZO_SIZE(D_BITS) -# define D_MASK LZO_MASK(D_BITS) -#else -# define D_SIZE LZO_USIZE(D_BITS) -# define D_MASK LZO_UMASK(D_BITS) -#endif -#define D_HIGH ((D_MASK >> 1) + 1) - -#if !defined(DD_BITS) -# define DD_BITS 0 -#endif -#define DD_SIZE LZO_SIZE(DD_BITS) -#define DD_MASK LZO_MASK(DD_BITS) - -#if !defined(DL_BITS) -# define DL_BITS (D_BITS - DD_BITS) -#endif -#if (DL_BITS < 16) -# define DL_SIZE LZO_SIZE(DL_BITS) -# define DL_MASK LZO_MASK(DL_BITS) -#else -# define DL_SIZE LZO_USIZE(DL_BITS) -# define DL_MASK LZO_UMASK(DL_BITS) -#endif - -#if (D_BITS != DL_BITS + DD_BITS) -# error "D_BITS does not match" -#endif -#if (D_BITS < 8 || D_BITS > 18) -# error "invalid D_BITS" -#endif -#if (DL_BITS < 8 || DL_BITS > 20) -# error "invalid DL_BITS" -#endif -#if (DD_BITS < 0 || DD_BITS > 6) -# error "invalid DD_BITS" -#endif - -#if !defined(DL_MIN_LEN) -# define DL_MIN_LEN 3 -#endif -#if !defined(DL_SHIFT) -# define DL_SHIFT ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN) -#endif - -#define LZO_HASH_GZIP 1 -#define LZO_HASH_GZIP_INCREMENTAL 2 -#define LZO_HASH_LZO_INCREMENTAL_A 3 -#define LZO_HASH_LZO_INCREMENTAL_B 4 - -#if !defined(LZO_HASH) -# error "choose a hashing strategy" -#endif - -#undef DM -#undef DX - -#if (DL_MIN_LEN == 3) -# define _DV2_A(p,shift1,shift2) \ - (((( (lzo_xint)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2]) -# define _DV2_B(p,shift1,shift2) \ - (((( (lzo_xint)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0]) -# define _DV3_B(p,shift1,shift2,shift3) \ - ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0]) -#elif (DL_MIN_LEN == 2) -# define _DV2_A(p,shift1,shift2) \ - (( (lzo_xint)(p[0]) << shift1) ^ p[1]) -# define _DV2_B(p,shift1,shift2) \ - (( (lzo_xint)(p[1]) << shift1) ^ p[2]) -#else -# error "invalid DL_MIN_LEN" -#endif -#define _DV_A(p,shift) _DV2_A(p,shift,shift) -#define _DV_B(p,shift) _DV2_B(p,shift,shift) -#define DA2(p,s1,s2) \ - (((((lzo_xint)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0]) -#define DS2(p,s1,s2) \ - (((((lzo_xint)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0]) -#define DX2(p,s1,s2) \ - (((((lzo_xint)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) -#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) -#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) -#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) -#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s))) -#define DM(v) DMS(v,0) - -#if (LZO_HASH == LZO_HASH_GZIP) -# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT)) - -#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL) -# define __LZO_HASH_INCREMENTAL -# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT) -# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2]) -# define _DINDEX(dv,p) (dv) -# define DVAL_LOOKAHEAD DL_MIN_LEN - -#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A) -# define __LZO_HASH_INCREMENTAL -# define DVAL_FIRST(dv,p) dv = _DV_A((p),5) -# define DVAL_NEXT(dv,p) \ - dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2]) -# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) -# define DVAL_LOOKAHEAD DL_MIN_LEN - -#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B) -# define __LZO_HASH_INCREMENTAL -# define DVAL_FIRST(dv,p) dv = _DV_B((p),5) -# define DVAL_NEXT(dv,p) \ - dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5))) -# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) -# define DVAL_LOOKAHEAD DL_MIN_LEN - -#else -# error "choose a hashing strategy" -#endif - -#ifndef DINDEX -#define DINDEX(dv,p) ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS) -#endif -#if !defined(DINDEX1) && defined(D_INDEX1) -#define DINDEX1 D_INDEX1 -#endif -#if !defined(DINDEX2) && defined(D_INDEX2) -#define DINDEX2 D_INDEX2 -#endif - -#if !defined(__LZO_HASH_INCREMENTAL) -# define DVAL_FIRST(dv,p) ((void) 0) -# define DVAL_NEXT(dv,p) ((void) 0) -# define DVAL_LOOKAHEAD 0 -#endif - -#if !defined(DVAL_ASSERT) -#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG) -static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) -{ - lzo_xint df; - DVAL_FIRST(df,(p)); - assert(DINDEX(dv,p) == DINDEX(df,p)); -} -#else -# define DVAL_ASSERT(dv,p) ((void) 0) -#endif -#endif - -#if defined(LZO_DICT_USE_PTR) -# define DENTRY(p,in) (p) -# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] -#else -# define DENTRY(p,in) ((lzo_uint) ((p)-(in))) -# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex] -#endif - -#if (DD_BITS == 0) - -# define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in) -# define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) -# define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in) - -#else - -# define UPDATE_D(dict,drun,dv,p,in) \ - dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK -# define UPDATE_I(dict,drun,index,p,in) \ - dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK -# define UPDATE_P(ptr,drun,p,in) \ - (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK - -#endif - -#if defined(LZO_DICT_USE_PTR) - -#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ - (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset) - -#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ - (BOUNDS_CHECKING_OFF_IN_EXPR(( \ - m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \ - PTR_LT(m_pos,in) || \ - (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) <= 0 || \ - m_off > max_offset ))) - -#else - -#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ - (m_off == 0 || \ - ((m_off = pd(ip, in) - m_off) > max_offset) || \ - (m_pos = (ip) - (m_off), 0) ) - -#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ - (pd(ip, in) <= m_off || \ - ((m_off = pd(ip, in) - m_off) > max_offset) || \ - (m_pos = (ip) - (m_off), 0) ) - -#endif - -#if defined(LZO_DETERMINISTIC) -# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET -#else -# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -#endif - -#define DO_COMPRESS lzo1x_1_compress - -static __lzo_noinline lzo_uint -do_compress ( const lzo_bytep in , lzo_uint in_len, - lzo_bytep out, lzo_uintp out_len, - lzo_voidp wrkmem ) -{ - register const lzo_bytep ip; - lzo_bytep op; - const lzo_bytep const in_end = in + in_len; - const lzo_bytep const ip_end = in + in_len - M2_MAX_LEN - 5; - const lzo_bytep ii; - lzo_dict_p const dict = (lzo_dict_p) wrkmem; - - op = out; - ip = in; - ii = ip; - - ip += 4; - for (;;) - { - register const lzo_bytep m_pos; - lzo_uint m_off; - lzo_uint m_len; - lzo_uint dindex; - - DINDEX1(dindex,ip); - GINDEX(m_pos,m_off,dict,dindex,in); - if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) - goto literal; -#if 1 - if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) - goto try_match; - DINDEX2(dindex,ip); -#endif - GINDEX(m_pos,m_off,dict,dindex,in); - if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) - goto literal; - if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) - goto try_match; - goto literal; - -try_match: -#if 1 && defined(LZO_UNALIGNED_OK_2) - if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) -#else - if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) -#endif - { - } - else - { - if __lzo_likely(m_pos[2] == ip[2]) - { -#if 0 - if (m_off <= M2_MAX_OFFSET) - goto match; - if (lit <= 3) - goto match; - if (lit == 3) - { - assert(op - 2 > out); op[-2] |= LZO_BYTE(3); - *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; - goto code_match; - } - if (m_pos[3] == ip[3]) -#endif - goto match; - } - else - { -#if 0 -#if 0 - if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) -#else - if (m_off <= M1_MAX_OFFSET && lit == 3) -#endif - { - register lzo_uint t; - - t = lit; - assert(op - 2 > out); op[-2] |= LZO_BYTE(t); - do *op++ = *ii++; while (--t > 0); - assert(ii == ip); - m_off -= 1; - *op++ = LZO_BYTE(M1_MARKER | ((m_off & 3) << 2)); - *op++ = LZO_BYTE(m_off >> 2); - ip += 2; - goto match_done; - } -#endif - } - } - -literal: - UPDATE_I(dict,0,dindex,ip,in); - ++ip; - if __lzo_unlikely(ip >= ip_end) - break; - continue; - -match: - UPDATE_I(dict,0,dindex,ip,in); - if (pd(ip,ii) > 0) - { - register lzo_uint t = pd(ip,ii); - - if (t <= 3) - { - assert(op - 2 > out); - op[-2] |= LZO_BYTE(t); - } - else if (t <= 18) - *op++ = LZO_BYTE(t - 3); - else - { - register lzo_uint tt = t - 18; - - *op++ = 0; - while (tt > 255) - { - tt -= 255; - *op++ = 0; - } - assert(tt > 0); - *op++ = LZO_BYTE(tt); - } - do *op++ = *ii++; while (--t > 0); - } - - assert(ii == ip); - ip += 3; - if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ || - m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ -#ifdef LZO1Y - || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ - || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ -#endif - ) - { - --ip; - m_len = pd(ip, ii); - assert(m_len >= 3); assert(m_len <= M2_MAX_LEN); - - if (m_off <= M2_MAX_OFFSET) - { - m_off -= 1; -#if defined(LZO1X) - *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); - *op++ = LZO_BYTE(m_off >> 3); -#elif defined(LZO1Y) - *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); - *op++ = LZO_BYTE(m_off >> 2); -#endif - } - else if (m_off <= M3_MAX_OFFSET) - { - m_off -= 1; - *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); - goto m3_m4_offset; - } - else -#if defined(LZO1X) - { - m_off -= 0x4000; - assert(m_off > 0); assert(m_off <= 0x7fff); - *op++ = LZO_BYTE(M4_MARKER | - ((m_off & 0x4000) >> 11) | (m_len - 2)); - goto m3_m4_offset; - } -#elif defined(LZO1Y) - goto m4_match; -#endif - } - else - { - { - const lzo_bytep end = in_end; - const lzo_bytep m = m_pos + M2_MAX_LEN + 1; - while (ip < end && *m == *ip) - m++, ip++; - m_len = pd(ip, ii); - } - assert(m_len > M2_MAX_LEN); - - if (m_off <= M3_MAX_OFFSET) - { - m_off -= 1; - if (m_len <= 33) - *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); - else - { - m_len -= 33; - *op++ = M3_MARKER | 0; - goto m3_m4_len; - } - } - else - { -#if defined(LZO1Y) -m4_match: -#endif - m_off -= 0x4000; - assert(m_off > 0); assert(m_off <= 0x7fff); - if (m_len <= M4_MAX_LEN) - *op++ = LZO_BYTE(M4_MARKER | - ((m_off & 0x4000) >> 11) | (m_len - 2)); - else - { - m_len -= M4_MAX_LEN; - *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11)); -m3_m4_len: - while (m_len > 255) - { - m_len -= 255; - *op++ = 0; - } - assert(m_len > 0); - *op++ = LZO_BYTE(m_len); - } - } - -m3_m4_offset: - *op++ = LZO_BYTE((m_off & 63) << 2); - *op++ = LZO_BYTE(m_off >> 6); - } - -#if 0 -match_done: -#endif - ii = ip; - if __lzo_unlikely(ip >= ip_end) - break; - } - - *out_len = pd(op, out); - return pd(in_end,ii); -} - -LZO_PUBLIC(int) -DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, - lzo_bytep out, lzo_uintp out_len, - lzo_voidp wrkmem ) -{ - lzo_bytep op = out; - lzo_uint t; - - if __lzo_unlikely(in_len <= M2_MAX_LEN + 5) - t = in_len; - else - { - t = do_compress(in,in_len,op,out_len,wrkmem); - op += *out_len; - } - - if (t > 0) - { - const lzo_bytep ii = in + in_len - t; - - if (op == out && t <= 238) - *op++ = LZO_BYTE(17 + t); - else if (t <= 3) - op[-2] |= LZO_BYTE(t); - else if (t <= 18) - *op++ = LZO_BYTE(t - 3); - else - { - lzo_uint tt = t - 18; - - *op++ = 0; - while (tt > 255) - { - tt -= 255; - *op++ = 0; - } - assert(tt > 0); - *op++ = LZO_BYTE(tt); - } - do *op++ = *ii++; while (--t > 0); - } - - *op++ = M4_MARKER | 1; - *op++ = 0; - *op++ = 0; - - *out_len = pd(op, out); - return LZO_E_OK; -} - -#endif - -#undef do_compress -#undef DO_COMPRESS -#undef LZO_HASH - -#undef LZO_TEST_OVERRUN -#undef DO_DECOMPRESS -#define DO_DECOMPRESS lzo1x_decompress - -#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS) - -#if defined(LZO_TEST_OVERRUN) -# if !defined(LZO_TEST_OVERRUN_INPUT) -# define LZO_TEST_OVERRUN_INPUT 2 -# endif -# if !defined(LZO_TEST_OVERRUN_OUTPUT) -# define LZO_TEST_OVERRUN_OUTPUT 2 -# endif -# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) -# define LZO_TEST_OVERRUN_LOOKBEHIND -# endif -#endif - -#undef TEST_IP -#undef TEST_OP -#undef TEST_LB -#undef TEST_LBO -#undef NEED_IP -#undef NEED_OP -#undef HAVE_TEST_IP -#undef HAVE_TEST_OP -#undef HAVE_NEED_IP -#undef HAVE_NEED_OP -#undef HAVE_ANY_IP -#undef HAVE_ANY_OP - -#if defined(LZO_TEST_OVERRUN_INPUT) -# if (LZO_TEST_OVERRUN_INPUT >= 1) -# define TEST_IP (ip < ip_end) -# endif -# if (LZO_TEST_OVERRUN_INPUT >= 2) -# define NEED_IP(x) \ - if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun -# endif -#endif - -#if defined(LZO_TEST_OVERRUN_OUTPUT) -# if (LZO_TEST_OVERRUN_OUTPUT >= 1) -# define TEST_OP (op <= op_end) -# endif -# if (LZO_TEST_OVERRUN_OUTPUT >= 2) -# undef TEST_OP -# define NEED_OP(x) \ - if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun -# endif -#endif - -#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) -# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun -# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun -#else -# define TEST_LB(m_pos) ((void) 0) -# define TEST_LBO(m_pos,o) ((void) 0) -#endif - -#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) -# define TEST_IP (ip < ip_end) -#endif - -#if defined(TEST_IP) -# define HAVE_TEST_IP -#else -# define TEST_IP 1 -#endif -#if defined(TEST_OP) -# define HAVE_TEST_OP -#else -# define TEST_OP 1 -#endif - -#if defined(NEED_IP) -# define HAVE_NEED_IP -#else -# define NEED_IP(x) ((void) 0) -#endif -#if defined(NEED_OP) -# define HAVE_NEED_OP -#else -# define NEED_OP(x) ((void) 0) -#endif - -#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) -# define HAVE_ANY_IP -#endif -#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) -# define HAVE_ANY_OP -#endif - -#undef __COPY4 -#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src) - -#undef COPY4 -#if defined(LZO_UNALIGNED_OK_4) -# define COPY4(dst,src) __COPY4(dst,src) -#elif defined(LZO_ALIGNED_OK_4) -# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src)) -#endif - -#if defined(DO_DECOMPRESS) -LZO_PUBLIC(int) -DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, - lzo_bytep out, lzo_uintp out_len, - lzo_voidp wrkmem ) -#endif -{ - register lzo_bytep op; - register const lzo_bytep ip; - register lzo_uint t; -#if defined(COPY_DICT) - lzo_uint m_off; - const lzo_bytep dict_end; -#else - register const lzo_bytep m_pos; -#endif - - const lzo_bytep const ip_end = in + in_len; -#if defined(HAVE_ANY_OP) - lzo_bytep const op_end = out + *out_len; -#endif -#if defined(LZO1Z) - lzo_uint last_m_off = 0; -#endif - - LZO_UNUSED(wrkmem); - -#if defined(COPY_DICT) - if (dict) - { - if (dict_len > M4_MAX_OFFSET) - { - dict += dict_len - M4_MAX_OFFSET; - dict_len = M4_MAX_OFFSET; - } - dict_end = dict + dict_len; - } - else - { - dict_len = 0; - dict_end = NULL; - } -#endif - - *out_len = 0; - - op = out; - ip = in; - - if (*ip > 17) - { - t = *ip++ - 17; - if (t < 4) - goto match_next; - assert(t > 0); NEED_OP(t); NEED_IP(t+1); - do *op++ = *ip++; while (--t > 0); - goto first_literal_run; - } - - while (TEST_IP && TEST_OP) - { - t = *ip++; - if (t >= 16) - goto match; - if (t == 0) - { - NEED_IP(1); - while (*ip == 0) - { - t += 255; - ip++; - NEED_IP(1); - } - t += 15 + *ip++; - } - assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) -#if !defined(LZO_UNALIGNED_OK_4) - if (PTR_ALIGNED2_4(op,ip)) - { -#endif - COPY4(op,ip); - op += 4; ip += 4; - if (--t > 0) - { - if (t >= 4) - { - do { - COPY4(op,ip); - op += 4; ip += 4; t -= 4; - } while (t >= 4); - if (t > 0) do *op++ = *ip++; while (--t > 0); - } - else - do *op++ = *ip++; while (--t > 0); - } -#if !defined(LZO_UNALIGNED_OK_4) - } - else -#endif -#endif -#if !defined(LZO_UNALIGNED_OK_4) - { - *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; - do *op++ = *ip++; while (--t > 0); - } -#endif - -first_literal_run: - - t = *ip++; - if (t >= 16) - goto match; -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); - last_m_off = m_off; -#else - m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); -#endif - NEED_OP(3); - t = 3; COPY_DICT(t,m_off) -#else -#if defined(LZO1Z) - t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); - m_pos = op - t; - last_m_off = t; -#else - m_pos = op - (1 + M2_MAX_OFFSET); - m_pos -= t >> 2; - m_pos -= *ip++ << 2; -#endif - TEST_LB(m_pos); NEED_OP(3); - *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; -#endif - goto match_done; - - do { -match: - if (t >= 64) - { -#if defined(COPY_DICT) -#if defined(LZO1X) - m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); - t = (t >> 5) - 1; -#elif defined(LZO1Y) - m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); - t = (t >> 4) - 3; -#elif defined(LZO1Z) - m_off = t & 0x1f; - if (m_off >= 0x1c) - m_off = last_m_off; - else - { - m_off = 1 + (m_off << 6) + (*ip++ >> 2); - last_m_off = m_off; - } - t = (t >> 5) - 1; -#endif -#else -#if defined(LZO1X) - m_pos = op - 1; - m_pos -= (t >> 2) & 7; - m_pos -= *ip++ << 3; - t = (t >> 5) - 1; -#elif defined(LZO1Y) - m_pos = op - 1; - m_pos -= (t >> 2) & 3; - m_pos -= *ip++ << 2; - t = (t >> 4) - 3; -#elif defined(LZO1Z) - { - lzo_uint off = t & 0x1f; - m_pos = op; - if (off >= 0x1c) - { - assert(last_m_off > 0); - m_pos -= last_m_off; - } - else - { - off = 1 + (off << 6) + (*ip++ >> 2); - m_pos -= off; - last_m_off = off; - } - } - t = (t >> 5) - 1; -#endif - TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); - goto copy_match; -#endif - } - else if (t >= 32) - { - t &= 31; - if (t == 0) - { - NEED_IP(1); - while (*ip == 0) - { - t += 255; - ip++; - NEED_IP(1); - } - t += 31 + *ip++; - } -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); - last_m_off = m_off; -#else - m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); -#endif -#else -#if defined(LZO1Z) - { - lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); - m_pos = op - off; - last_m_off = off; - } -#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos = op - 1; - m_pos -= (* (const lzo_ushortp) ip) >> 2; -#else - m_pos = op - 1; - m_pos -= (ip[0] >> 2) + (ip[1] << 6); -#endif -#endif - ip += 2; - } - else if (t >= 16) - { -#if defined(COPY_DICT) - m_off = (t & 8) << 11; -#else - m_pos = op; - m_pos -= (t & 8) << 11; -#endif - t &= 7; - if (t == 0) - { - NEED_IP(1); - while (*ip == 0) - { - t += 255; - ip++; - NEED_IP(1); - } - t += 7 + *ip++; - } -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off += (ip[0] << 6) + (ip[1] >> 2); -#else - m_off += (ip[0] >> 2) + (ip[1] << 6); -#endif - ip += 2; - if (m_off == 0) - goto eof_found; - m_off += 0x4000; -#if defined(LZO1Z) - last_m_off = m_off; -#endif -#else -#if defined(LZO1Z) - m_pos -= (ip[0] << 6) + (ip[1] >> 2); -#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos -= (* (const lzo_ushortp) ip) >> 2; -#else - m_pos -= (ip[0] >> 2) + (ip[1] << 6); -#endif - ip += 2; - if (m_pos == op) - goto eof_found; - m_pos -= 0x4000; -#if defined(LZO1Z) - last_m_off = pd((const lzo_bytep)op, m_pos); -#endif -#endif - } - else - { -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = 1 + (t << 6) + (*ip++ >> 2); - last_m_off = m_off; -#else - m_off = 1 + (t >> 2) + (*ip++ << 2); -#endif - NEED_OP(2); - t = 2; COPY_DICT(t,m_off) -#else -#if defined(LZO1Z) - t = 1 + (t << 6) + (*ip++ >> 2); - m_pos = op - t; - last_m_off = t; -#else - m_pos = op - 1; - m_pos -= t >> 2; - m_pos -= *ip++ << 2; -#endif - TEST_LB(m_pos); NEED_OP(2); - *op++ = *m_pos++; *op++ = *m_pos; -#endif - goto match_done; - } - -#if defined(COPY_DICT) - - NEED_OP(t+3-1); - t += 3-1; COPY_DICT(t,m_off) - -#else - - TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) -#if !defined(LZO_UNALIGNED_OK_4) - if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) - { - assert((op - m_pos) >= 4); -#else - if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) - { -#endif - COPY4(op,m_pos); - op += 4; m_pos += 4; t -= 4 - (3 - 1); - do { - COPY4(op,m_pos); - op += 4; m_pos += 4; t -= 4; - } while (t >= 4); - if (t > 0) do *op++ = *m_pos++; while (--t > 0); - } - else -#endif - { -copy_match: - *op++ = *m_pos++; *op++ = *m_pos++; - do *op++ = *m_pos++; while (--t > 0); - } - -#endif - -match_done: -#if defined(LZO1Z) - t = ip[-1] & 3; -#else - t = ip[-2] & 3; -#endif - if (t == 0) - break; - -match_next: - assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); -#if 0 - do *op++ = *ip++; while (--t > 0); -#else - *op++ = *ip++; - if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } -#endif - t = *ip++; - } while (TEST_IP && TEST_OP); - } - -#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) - *out_len = pd(op, out); - return LZO_E_EOF_NOT_FOUND; -#endif - -eof_found: - assert(t == 1); - *out_len = pd(op, out); - return (ip == ip_end ? LZO_E_OK : - (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); - -#if defined(HAVE_NEED_IP) -input_overrun: - *out_len = pd(op, out); - return LZO_E_INPUT_OVERRUN; -#endif - -#if defined(HAVE_NEED_OP) -output_overrun: - *out_len = pd(op, out); - return LZO_E_OUTPUT_OVERRUN; -#endif - -#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) -lookbehind_overrun: - *out_len = pd(op, out); - return LZO_E_LOOKBEHIND_OVERRUN; -#endif -} - -#endif - -#define LZO_TEST_OVERRUN -#undef DO_DECOMPRESS -#define DO_DECOMPRESS lzo1x_decompress_safe - -#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS_SAFE) - -#if defined(LZO_TEST_OVERRUN) -# if !defined(LZO_TEST_OVERRUN_INPUT) -# define LZO_TEST_OVERRUN_INPUT 2 -# endif -# if !defined(LZO_TEST_OVERRUN_OUTPUT) -# define LZO_TEST_OVERRUN_OUTPUT 2 -# endif -# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) -# define LZO_TEST_OVERRUN_LOOKBEHIND -# endif -#endif - -#undef TEST_IP -#undef TEST_OP -#undef TEST_LB -#undef TEST_LBO -#undef NEED_IP -#undef NEED_OP -#undef HAVE_TEST_IP -#undef HAVE_TEST_OP -#undef HAVE_NEED_IP -#undef HAVE_NEED_OP -#undef HAVE_ANY_IP -#undef HAVE_ANY_OP - -#if defined(LZO_TEST_OVERRUN_INPUT) -# if (LZO_TEST_OVERRUN_INPUT >= 1) -# define TEST_IP (ip < ip_end) -# endif -# if (LZO_TEST_OVERRUN_INPUT >= 2) -# define NEED_IP(x) \ - if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun -# endif -#endif - -#if defined(LZO_TEST_OVERRUN_OUTPUT) -# if (LZO_TEST_OVERRUN_OUTPUT >= 1) -# define TEST_OP (op <= op_end) -# endif -# if (LZO_TEST_OVERRUN_OUTPUT >= 2) -# undef TEST_OP -# define NEED_OP(x) \ - if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun -# endif -#endif - -#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) -# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun -# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun -#else -# define TEST_LB(m_pos) ((void) 0) -# define TEST_LBO(m_pos,o) ((void) 0) -#endif - -#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) -# define TEST_IP (ip < ip_end) -#endif - -#if defined(TEST_IP) -# define HAVE_TEST_IP -#else -# define TEST_IP 1 -#endif -#if defined(TEST_OP) -# define HAVE_TEST_OP -#else -# define TEST_OP 1 -#endif - -#if defined(NEED_IP) -# define HAVE_NEED_IP -#else -# define NEED_IP(x) ((void) 0) -#endif -#if defined(NEED_OP) -# define HAVE_NEED_OP -#else -# define NEED_OP(x) ((void) 0) -#endif - -#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) -# define HAVE_ANY_IP -#endif -#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) -# define HAVE_ANY_OP -#endif - -#undef __COPY4 -#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src) - -#undef COPY4 -#if defined(LZO_UNALIGNED_OK_4) -# define COPY4(dst,src) __COPY4(dst,src) -#elif defined(LZO_ALIGNED_OK_4) -# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src)) -#endif - -#if defined(DO_DECOMPRESS) -LZO_PUBLIC(int) -DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, - lzo_bytep out, lzo_uintp out_len, - lzo_voidp wrkmem ) -#endif -{ - register lzo_bytep op; - register const lzo_bytep ip; - register lzo_uint t; -#if defined(COPY_DICT) - lzo_uint m_off; - const lzo_bytep dict_end; -#else - register const lzo_bytep m_pos; -#endif - - const lzo_bytep const ip_end = in + in_len; -#if defined(HAVE_ANY_OP) - lzo_bytep const op_end = out + *out_len; -#endif -#if defined(LZO1Z) - lzo_uint last_m_off = 0; -#endif - - LZO_UNUSED(wrkmem); - -#if defined(COPY_DICT) - if (dict) - { - if (dict_len > M4_MAX_OFFSET) - { - dict += dict_len - M4_MAX_OFFSET; - dict_len = M4_MAX_OFFSET; - } - dict_end = dict + dict_len; - } - else - { - dict_len = 0; - dict_end = NULL; - } -#endif - - *out_len = 0; - - op = out; - ip = in; - - if (*ip > 17) - { - t = *ip++ - 17; - if (t < 4) - goto match_next; - assert(t > 0); NEED_OP(t); NEED_IP(t+1); - do *op++ = *ip++; while (--t > 0); - goto first_literal_run; - } - - while (TEST_IP && TEST_OP) - { - t = *ip++; - if (t >= 16) - goto match; - if (t == 0) - { - NEED_IP(1); - while (*ip == 0) - { - t += 255; - ip++; - NEED_IP(1); - } - t += 15 + *ip++; - } - assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) -#if !defined(LZO_UNALIGNED_OK_4) - if (PTR_ALIGNED2_4(op,ip)) - { -#endif - COPY4(op,ip); - op += 4; ip += 4; - if (--t > 0) - { - if (t >= 4) - { - do { - COPY4(op,ip); - op += 4; ip += 4; t -= 4; - } while (t >= 4); - if (t > 0) do *op++ = *ip++; while (--t > 0); - } - else - do *op++ = *ip++; while (--t > 0); - } -#if !defined(LZO_UNALIGNED_OK_4) - } - else -#endif -#endif -#if !defined(LZO_UNALIGNED_OK_4) - { - *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; - do *op++ = *ip++; while (--t > 0); - } -#endif - -first_literal_run: - - t = *ip++; - if (t >= 16) - goto match; -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); - last_m_off = m_off; -#else - m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); -#endif - NEED_OP(3); - t = 3; COPY_DICT(t,m_off) -#else -#if defined(LZO1Z) - t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); - m_pos = op - t; - last_m_off = t; -#else - m_pos = op - (1 + M2_MAX_OFFSET); - m_pos -= t >> 2; - m_pos -= *ip++ << 2; -#endif - TEST_LB(m_pos); NEED_OP(3); - *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; -#endif - goto match_done; - - do { -match: - if (t >= 64) - { -#if defined(COPY_DICT) -#if defined(LZO1X) - m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); - t = (t >> 5) - 1; -#elif defined(LZO1Y) - m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); - t = (t >> 4) - 3; -#elif defined(LZO1Z) - m_off = t & 0x1f; - if (m_off >= 0x1c) - m_off = last_m_off; - else - { - m_off = 1 + (m_off << 6) + (*ip++ >> 2); - last_m_off = m_off; - } - t = (t >> 5) - 1; -#endif -#else -#if defined(LZO1X) - m_pos = op - 1; - m_pos -= (t >> 2) & 7; - m_pos -= *ip++ << 3; - t = (t >> 5) - 1; -#elif defined(LZO1Y) - m_pos = op - 1; - m_pos -= (t >> 2) & 3; - m_pos -= *ip++ << 2; - t = (t >> 4) - 3; -#elif defined(LZO1Z) - { - lzo_uint off = t & 0x1f; - m_pos = op; - if (off >= 0x1c) - { - assert(last_m_off > 0); - m_pos -= last_m_off; - } - else - { - off = 1 + (off << 6) + (*ip++ >> 2); - m_pos -= off; - last_m_off = off; - } - } - t = (t >> 5) - 1; -#endif - TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); - goto copy_match; -#endif - } - else if (t >= 32) - { - t &= 31; - if (t == 0) - { - NEED_IP(1); - while (*ip == 0) - { - t += 255; - ip++; - NEED_IP(1); - } - t += 31 + *ip++; - } -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); - last_m_off = m_off; -#else - m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); -#endif -#else -#if defined(LZO1Z) - { - lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); - m_pos = op - off; - last_m_off = off; - } -#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos = op - 1; - m_pos -= (* (const lzo_ushortp) ip) >> 2; -#else - m_pos = op - 1; - m_pos -= (ip[0] >> 2) + (ip[1] << 6); -#endif -#endif - ip += 2; - } - else if (t >= 16) - { -#if defined(COPY_DICT) - m_off = (t & 8) << 11; -#else - m_pos = op; - m_pos -= (t & 8) << 11; -#endif - t &= 7; - if (t == 0) - { - NEED_IP(1); - while (*ip == 0) - { - t += 255; - ip++; - NEED_IP(1); - } - t += 7 + *ip++; - } -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off += (ip[0] << 6) + (ip[1] >> 2); -#else - m_off += (ip[0] >> 2) + (ip[1] << 6); -#endif - ip += 2; - if (m_off == 0) - goto eof_found; - m_off += 0x4000; -#if defined(LZO1Z) - last_m_off = m_off; -#endif -#else -#if defined(LZO1Z) - m_pos -= (ip[0] << 6) + (ip[1] >> 2); -#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos -= (* (const lzo_ushortp) ip) >> 2; -#else - m_pos -= (ip[0] >> 2) + (ip[1] << 6); -#endif - ip += 2; - if (m_pos == op) - goto eof_found; - m_pos -= 0x4000; -#if defined(LZO1Z) - last_m_off = pd((const lzo_bytep)op, m_pos); -#endif -#endif - } - else - { -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = 1 + (t << 6) + (*ip++ >> 2); - last_m_off = m_off; -#else - m_off = 1 + (t >> 2) + (*ip++ << 2); -#endif - NEED_OP(2); - t = 2; COPY_DICT(t,m_off) -#else -#if defined(LZO1Z) - t = 1 + (t << 6) + (*ip++ >> 2); - m_pos = op - t; - last_m_off = t; -#else - m_pos = op - 1; - m_pos -= t >> 2; - m_pos -= *ip++ << 2; -#endif - TEST_LB(m_pos); NEED_OP(2); - *op++ = *m_pos++; *op++ = *m_pos; -#endif - goto match_done; - } - -#if defined(COPY_DICT) - - NEED_OP(t+3-1); - t += 3-1; COPY_DICT(t,m_off) - -#else - - TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) -#if !defined(LZO_UNALIGNED_OK_4) - if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) - { - assert((op - m_pos) >= 4); -#else - if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) - { -#endif - COPY4(op,m_pos); - op += 4; m_pos += 4; t -= 4 - (3 - 1); - do { - COPY4(op,m_pos); - op += 4; m_pos += 4; t -= 4; - } while (t >= 4); - if (t > 0) do *op++ = *m_pos++; while (--t > 0); - } - else -#endif - { -copy_match: - *op++ = *m_pos++; *op++ = *m_pos++; - do *op++ = *m_pos++; while (--t > 0); - } - -#endif - -match_done: -#if defined(LZO1Z) - t = ip[-1] & 3; -#else - t = ip[-2] & 3; -#endif - if (t == 0) - break; - -match_next: - assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); -#if 0 - do *op++ = *ip++; while (--t > 0); -#else - *op++ = *ip++; - if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } -#endif - t = *ip++; - } while (TEST_IP && TEST_OP); - } - -#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) - *out_len = pd(op, out); - return LZO_E_EOF_NOT_FOUND; -#endif - -eof_found: - assert(t == 1); - *out_len = pd(op, out); - return (ip == ip_end ? LZO_E_OK : - (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); - -#if defined(HAVE_NEED_IP) -input_overrun: - *out_len = pd(op, out); - return LZO_E_INPUT_OVERRUN; -#endif - -#if defined(HAVE_NEED_OP) -output_overrun: - *out_len = pd(op, out); - return LZO_E_OUTPUT_OVERRUN; -#endif - -#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) -lookbehind_overrun: - *out_len = pd(op, out); - return LZO_E_LOOKBEHIND_OVERRUN; -#endif -} - -#endif - -/***** End of minilzo.c *****/ - diff --git a/n2n.7 b/n2n.7 new file mode 100644 index 0000000..df0f293 --- /dev/null +++ b/n2n.7 @@ -0,0 +1,132 @@ +.TH "n2n_v3" 7 "Sep 27, 2021" "version 3" "Background" +.SH NAME +n2n version 3 \- version 3 of the n2n decentralised peer-to-peer network overlay +VPN. +.SH DESCRIPTION +n2n is a peer-to-peer network overlay or VPN system that provides layer 2 over +layer 3 encapsulation with data transform capabilities such as encryption and +compression. This guide also discusses the differences of version 3 of n2n from +version 2. +.SH PROTOCOLS +n2n-3 basically uses the same set of messages to communicate with edges and +supernodes. However, due to slight packet format changes, the n2n-3 messages +are not compatible with n2n-2. There is no backward compatibility for n2n-2. +.SH ENCRYPTION +n2n-3 offers four different ciphers for payload encryption as well as optional +header encryption. Earlier versions of n2n-2 provided a mechanism using a key +schedule which has been removed in n2n-3. A basic user authentication scheme +relying on asymmetric cryptography has been added to n2n-3. + +n2n-3 provides the following ciphers to chose from for payload encryption; more +can be added as required: +.TP +.B (1) NULL +Data is encapsulated unchanged. Useful for testing and high-performance, low +sensitivity applications. +.TP +.B (2) TF-CTS +Twofish AES candidate in CTS mode. +.TP +.B (3) AES-CTS +AES in CTS mode with up to 256-bit key. +.TP +.B (4) CHACHA20 +ChaCha20, a well known stream cipher developped by Daniel J. Bernstein. +.TP +.B (5) SPECK-CTR +A fast block cipher developped by the NSA used as stream cipher in CTR mode. +.TP +Full Header Encyption +The optional full header encryption also encrypts packets' header which include +some administrative data. In addition, it adds replay protection. +.TP +User Password Authentication +n2n-3 implements an optional user-password authentication scheme. A key +generator assists in generating user's public keys to be stored at the +supernode side. +.SH COPMPRESSION +LZO for payload compression is an always available option at n2n-3. If compiled with +zstdlib support, ZSTD is at optional service as well. +.SH EXTENSIBILITY +n2n-3 decouples the data transform system from the core of the edge +operation. This allows for easier addition of new data transform +operations. n2n-3 reserves some standard transform identifiers (such as TwoFish +encryption) but allocates transform identifiers for user-defined +transforms. This allows anyone to add to n2n new private transforms without +breaking compatibility with the standard offering. +.SH FEDERATED SUPERNODES +n2n-3 incorporates the capability of multiple supernodes to be federated. +Federation acts transparently and balances the workload evenly among the +federated supernodes. Supernodes keep track of edges connected to different +supernodes and forward packets as required. This feature naturally supports +fail-over and this increases redundancy and resilience. +.P +Information on additional supernodes is propagated to all edges. In addition, +the n2n-3 edge implementation allows multiple supernodes to be specified on the +command line. Edges monitor the current supernode for responses to +REGISTER_SUPER as well as PING messages. After three responses from current +supernode are missed or when a better supernode in terms of significant lower workload +is found, the edge tries to connect to another supernode. It cycles through the list +f supernodes which over and over again is sorted according to reported workload. + +.SH MANAGEMENT CONSOLE +Edge and supernode in n2n-3 provide a UDP-based management console. Both listen +on the localhost address 127.0.0.1. Commands can be sent to the programs by +sending to the UDP socket. Responses are returned to the socket from which +commands were issued. This only works from the computer on which the programs +are running. Statistics can be retrieved and commands issued. The netcat utility +is all that is required; but more sophisticated tools could be built on the +interface. + +.SH SUPERNODE AUTHENTICATION +The supernode federation name serves as private key shared between the supernodes only. +The corresponding public key can be provided to the edges. + +.SH MESSAGE SUMMARY +The following message types work within n2n-3. +.TP +REGISTER_SUPER +Sent from an edge to its local supernode to register its MAC with the community. +Also, federated supernodes use this packet format to register to each other. +.TP +REGISTER_SUPER_ACK +Sent from a supernode to an edge to confirm registration. This also carries the +definition of the edge socket as seen at the supernode so NAT can be detected +and described. Furthermore, it carries information about additional federated +supernodes. +.TP +REGISTER_SUPER_NAK +Supernode refusing to register an edge. +.TP +PACKET +Encapsulated ethernet packets sent between edges. Supernodes forward or +broadcast these and edges send them direct in peer-to-peer mode. +.TP +REGISTER +A peer-to-peer mode registration request from one edge to another. Supernodes +forward these to facilitate NAT crossing introductions. +.TP +REGISTER_ACK +Complete peer-to-peer mode setup between two edges. These messages need to +travel direct between edges. +.TP +QUERY_PEER +Queries a supernode about another edge, especially its public socket in case of +no peer-to-peer communication can be established. Additionally, it serves as PING +to query supernodes about themselves. +.TP +PEER_INFO +Answers the QUERY_PEER; it also covers the special case of the PING query, internally +called PONG. +.SH AUTHORS +.TP +Richard Andrews andrews (at) ntop.org - main author of n2n-2 +.TP +Luca Deri +deri (at) ntop.org - code inherited from n2n-1 +.SH SEE ALSO +ifconfig(8) edge(8) supernode(1) +.br +the documentation contained in the source code +.br +the extensive documentation found in n2n's \fBdoc/\fR folder diff --git a/n2n.c b/n2n.c deleted file mode 100644 index db692da..0000000 --- a/n2n.c +++ /dev/null @@ -1,922 +0,0 @@ -/* - * (C) 2007-09 - Luca Deri - * Richard Andrews - * - * 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 - * - * Code contributions courtesy of: - * Richard Andrews - * Massimo Torquati - * - */ - -#include "n2n.h" - -#include "minilzo.h" - -#include - -#if defined(DEBUG) -# define PURGE_REGISTRATION_FREQUENCY 60 -# define REGISTRATION_TIMEOUT 120 -#else /* #if defined(DEBUG) */ -# define PURGE_REGISTRATION_FREQUENCY 60 -# define REGISTRATION_TIMEOUT (60*5) -#endif /* #if defined(DEBUG) */ - - -char broadcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -char multicast_addr[6] = { 0x01, 0x00, 0x05, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */ - -/* ************************************** */ - -static void print_header( const char * msg, const struct n2n_packet_header * hdr ) -{ - ipstr_t buf; - ipstr_t buf2; - - traceEvent(TRACE_INFO, "%s hdr: public_ip=(%d)%s:%d, private_ip=(%d)%s:%d", msg, - hdr->public_ip.family, - intoa(ntohl(hdr->public_ip.addr_type.v4_addr), buf, sizeof(buf)), - ntohs(hdr->public_ip.port), - hdr->private_ip.family, - intoa(ntohl(hdr->private_ip.addr_type.v4_addr), buf2, sizeof(buf2)), - ntohs(hdr->private_ip.port) - ); -} - -/* *********************************************** */ - -extern void sockaddr_in2peer_addr(struct sockaddr_in *in, struct peer_addr *out) { - out->family = (u_int8_t)in->sin_family; - out->port = in->sin_port; - out->addr_type.v4_addr = in->sin_addr.s_addr; -} - -/* *********************************************** */ - -extern void peer_addr2sockaddr_in(const struct peer_addr *in, struct sockaddr_in *out) { - out->sin_family = in->family; - out->sin_port = in->port; - out->sin_addr.s_addr = in->addr_type.v4_addr; -} - -/* ************************************** */ - -static -int marshall_peer_addr( u_int8_t * buf, size_t * offset, const struct peer_addr * s ) -{ - /* RA: I'm pretty sure that this is broken. There is no guarantee that the - * peer_addr structure is packed. This will always work between like hosts but - * is almost certainly broken between different host types. */ - memcpy( buf + *offset, s, sizeof(struct peer_addr)); - *offset += sizeof(struct peer_addr); - - return sizeof(struct peer_addr); /* bytes written */ -} - -/* ************************************** */ - -static -int marshall_uint32( u_int8_t * buf, size_t * offset, u_int32_t val ) -{ - buf[*offset + 0] = ((val >> 24) & 0xff); - buf[*offset + 1] = ((val >> 16) & 0xff); - buf[*offset + 2] = ((val >> 8) & 0xff); - buf[*offset + 3] = ((val ) & 0xff); - - *offset += 4; - return 4; -} - -/* ************************************** */ - -int marshall_n2n_packet_header( u_int8_t * buf, const struct n2n_packet_header * hdr ) -{ - size_t offset = 0; - - print_header( "Marshalling ", hdr ); - - *(buf+offset) = hdr->version; - ++offset; - - *(buf+offset) = hdr->msg_type; - ++offset; - - *(buf+offset) = hdr->ttl; - ++offset; - - *(buf+offset) = hdr->sent_by_supernode; - ++offset; - - memcpy( buf+offset, hdr->community_name, COMMUNITY_LEN ); - offset += COMMUNITY_LEN; - - memcpy( buf+offset, hdr->src_mac, 6 ); - offset += 6; - - memcpy( buf+offset, hdr->dst_mac, 6 ); - offset += 6; - - marshall_peer_addr( buf, &offset, &(hdr->public_ip) ); - marshall_peer_addr( buf, &offset, &(hdr->private_ip) ); - - *(buf+offset) = (hdr->pkt_type & 0xff); - ++offset; - - marshall_uint32( buf, &offset, hdr->sequence_id ); - marshall_uint32( buf, &offset, hdr->crc ); - - return offset; -} - -/* ************************************** */ - -static -int unmarshall_peer_addr( struct peer_addr * s, size_t * offset, - const u_int8_t * buf ) -{ - memcpy(s, buf + *offset, sizeof(struct peer_addr)); - *offset += sizeof(struct peer_addr); - return (sizeof(struct peer_addr)); /* bytes written */ -} - -/* ************************************** */ - -static -int unmarshall_uint32( u_int32_t * val, size_t * offset, const u_int8_t * buf ) -{ - *val = ( (buf[*offset + 0] & 0xff) << 24 ); - *val |= ( (buf[*offset + 1] & 0xff) << 16 ); - *val |= ( (buf[*offset + 2] & 0xff) << 8 ); - *val |= ( (buf[*offset + 3] & 0xff) ); - - *offset += 4; - return 4; -} - -/* ************************************** */ - -int unmarshall_n2n_packet_header( struct n2n_packet_header * hdr, const u_int8_t * buf ) -{ - size_t offset=0; - - hdr->version = *(buf + offset); - ++offset; - - hdr->msg_type = *(buf + offset); - ++offset; - - hdr->ttl = *(buf + offset); - ++offset; - - hdr->sent_by_supernode = *(buf + offset); - ++offset; - - memcpy( hdr->community_name, (buf + offset), COMMUNITY_LEN ); - offset += COMMUNITY_LEN; - - memcpy( hdr->src_mac, (buf + offset), 6 ); - offset += 6; - - memcpy( hdr->dst_mac, (buf + offset), 6 ); - offset += 6; - - unmarshall_peer_addr( &(hdr->public_ip), &offset, buf ); - unmarshall_peer_addr( &(hdr->private_ip), &offset, buf ); - - hdr->pkt_type = (*(buf + offset) & 0xff); /* Make sure only 8 bits are copied. */ - ++offset; - - unmarshall_uint32( &(hdr->sequence_id), &offset, buf ); - unmarshall_uint32( &(hdr->crc), &offset, buf ); - - print_header( "Unmarshalled ", hdr ); - - return offset; -} - -/* ************************************** */ - -SOCKET open_socket(int local_port, int udp_sock, int server_mode) { - SOCKET sock_fd; - struct sockaddr_in local_address; - int sockopt = 1; - - if((sock_fd = socket(PF_INET, udp_sock ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0) { - traceEvent(TRACE_ERROR, "Unable to create socket [%s][%d]\n", - strerror(errno), sock_fd); - return(-1); - } - -#ifndef WIN32 - /* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */ -#endif - - setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt)); - - memset(&local_address, 0, sizeof(local_address)); - local_address.sin_family = AF_INET; - local_address.sin_port = htons(local_port); - local_address.sin_addr.s_addr = INADDR_ANY; - if(bind(sock_fd, (struct sockaddr*) &local_address, sizeof(local_address)) == -1) { - traceEvent(TRACE_ERROR, "Bind error [%s]\n", strerror(errno)); - return(-1); - } - - if((!udp_sock) && server_mode) { - if(listen(sock_fd, 255) == -1) { - traceEvent(TRACE_ERROR, "Listen error [%s]\n", strerror(errno)); - return(-1); - } - } - - return(sock_fd); -} - -/* ************************************** */ - -int connect_socket(int sock_fd, struct peer_addr* _dest) { - char *http_header; - int len, rc; - struct sockaddr_in dest; - - peer_addr2sockaddr_in(_dest, &dest); - - /* FIX: add IPv6 support */ - rc = connect(sock_fd, (struct sockaddr*)&dest, sizeof(struct sockaddr_in)); - - if(rc == -1) { - traceEvent(TRACE_WARNING, "connect() error [%s]\n", strerror(errno)); - return(-1); - } - - /* Send dummy http header */ - http_header = "GET / HTTP/1.0\r\n\r\n"; - len = strlen(http_header); - rc = send(sock_fd, http_header, len, 0); - - return((rc == len) ? 0 : -1); -} - - -/* *********************************************** */ - -void send_packet(n2n_sock_info_t * sinfo, - char *packet, size_t *packet_len, - const struct peer_addr *remote_peer, u_int8_t compress_data) { - int data_sent_len; - - data_sent_len = unreliable_sendto(sinfo, - packet, packet_len, remote_peer, compress_data); - - if(data_sent_len != *packet_len) - traceEvent(TRACE_WARNING, - "sendto() [sent=%d][attempted_to_send=%d] [%s]\n", - data_sent_len, *packet_len, strerror(errno)); -} - -/* *********************************************** */ - -int traceLevel = 2 /* NORMAL */; -int useSyslog = 0, syslog_opened = 0; - -#define N2N_TRACE_DATESIZE 32 -void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...) { - va_list va_ap; - - if(eventTraceLevel <= traceLevel) { - char buf[2048]; - char out_buf[640]; - char theDate[N2N_TRACE_DATESIZE]; - char *extra_msg = ""; - time_t theTime = time(NULL); -#ifdef WIN32 - int i; -#endif - - /* We have two paths - one if we're logging, one if we aren't - * Note that the no-log case is those systems which don't support it (WIN32), - * those without the headers !defined(USE_SYSLOG) - * those where it's parametrically off... - */ - - memset(buf, 0, sizeof(buf)); - strftime(theDate, N2N_TRACE_DATESIZE, "%d/%b/%Y %H:%M:%S", localtime(&theTime)); - - va_start (va_ap, format); - vsnprintf(buf, sizeof(buf)-1, format, va_ap); - va_end(va_ap); - - if(eventTraceLevel == 0 /* TRACE_ERROR */) - extra_msg = "ERROR: "; - else if(eventTraceLevel == 1 /* TRACE_WARNING */) - extra_msg = "WARNING: "; - - while(buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; - -#ifndef WIN32 - if(useSyslog) { - if(!syslog_opened) { - openlog("n2n", LOG_PID, LOG_DAEMON); - syslog_opened = 1; - } - - snprintf(out_buf, sizeof(out_buf), "%s%s", extra_msg, buf); - syslog(LOG_INFO, out_buf); - } else { - snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, file, line, extra_msg, buf); - printf("%s\n", out_buf); - fflush(stdout); - } -#else - /* this is the WIN32 code */ - for(i=strlen(file)-1; i>0; i--) if(file[i] == '\\') { i++; break; }; - snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, &file[i], line, extra_msg, buf); - printf("%s\n", out_buf); - fflush(stdout); -#endif - } - -} - -/* *********************************************** */ - -/* addr should be in network order. Things are so much simpler that way. */ -char* intoa(u_int32_t /* host order */ addr, char* buf, u_short buf_len) { - char *cp, *retStr; - u_int byte; - int n; - - cp = &buf[buf_len]; - *--cp = '\0'; - - n = 4; - do { - byte = addr & 0xff; - *--cp = byte % 10 + '0'; - byte /= 10; - if (byte > 0) { - *--cp = byte % 10 + '0'; - byte /= 10; - if (byte > 0) - *--cp = byte + '0'; - } - *--cp = '.'; - addr >>= 8; - } while (--n > 0); - - /* Convert the string to lowercase */ - retStr = (char*)(cp+1); - - return(retStr); -} - -/* *********************************************** */ - -char* macaddr_str(const char *mac, char *buf, int buf_len) { - snprintf(buf, buf_len, "%02X:%02X:%02X:%02X:%02X:%02X", - mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF, - mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF); - return(buf); -} - -/* *********************************************** */ - -void fill_standard_header_fields(n2n_sock_info_t * sinfo, - struct n2n_packet_header *hdr, char *src_mac) { - socklen_t len = sizeof(hdr->private_ip); - memset(hdr, 0, N2N_PKT_HDR_SIZE); - hdr->version = N2N_PKT_VERSION; - hdr->crc = 0; // FIX - if(src_mac != NULL) memcpy(hdr->src_mac, src_mac, 6); - getsockname(sinfo->sock, (struct sockaddr*)&hdr->private_ip, &len); - hdr->public_ip.family = AF_INET; -} - -/* *********************************************** */ - -void send_ack(n2n_sock_info_t * sinfo, - u_int16_t last_rcvd_seq_id, - struct n2n_packet_header *header, - struct peer_addr *remote_peer, - char *src_mac) { - - /* marshalling double-checked. */ - struct n2n_packet_header hdr; - u_int8_t pkt[ N2N_PKT_HDR_SIZE ]; - size_t len = sizeof(hdr); - size_t len2; - int compress_data = N2N_COMPRESSION_ENABLED; - - fill_standard_header_fields(sinfo, &hdr, src_mac); - hdr.msg_type = MSG_TYPE_ACK_RESPONSE; - hdr.sequence_id = last_rcvd_seq_id; - memcpy(hdr.community_name, header->community_name, COMMUNITY_LEN); - - len2=marshall_n2n_packet_header( pkt, &hdr ); - assert( len2 == len ); - - send_packet(sinfo, (char*)pkt, &len, remote_peer, compress_data); -} - -/* *********************************************** */ - -u_int8_t is_multi_broadcast(char *dest_mac) { - return(((!memcmp(broadcast_addr, dest_mac, 6)) - || (!memcmp(multicast_addr, dest_mac, 3))) ? 1 : 0); -} - -/* *********************************************** */ - -/* http://www.faqs.org/rfcs/rfc908.html */ - -u_int receive_data(n2n_sock_info_t * sinfo, - char *packet, size_t packet_len, - struct peer_addr *from, u_int8_t *discarded_pkt, - char *tun_mac_addr, u_int8_t decompress_data, - struct n2n_packet_header *hdr) { - socklen_t fromlen = sizeof(struct sockaddr_in); - int len; - char *payload, *pkt_type; - macstr_t src_mac_buf; - macstr_t dst_mac_buf; - ipstr_t ip_buf; - ipstr_t from_ip_buf; - - if(sinfo->is_udp_socket) { - struct sockaddr_in _from; - len = recvfrom(sinfo->sock, packet, packet_len, 0, (struct sockaddr*)&_from, &fromlen); - sockaddr_in2peer_addr(&_from, from); - } else { - len = recv(sinfo->sock, packet, 4, 0); - if(len == 4) { - packet[4] = '\0'; - len = atoi(packet); - len = recv(sinfo->sock, packet, len, 0); - } else { - traceEvent(TRACE_WARNING, "Unable to receive n2n packet length"); - return(-1); - } - } - - unmarshall_n2n_packet_header(hdr, (u_int8_t *)packet); - - payload = &packet[N2N_PKT_HDR_SIZE]; - - if(len < 0) { -#ifdef WIN32 - if(WSAGetLastError() != WSAECONNRESET /* http://support.microsoft.com/kb/263823 */ ) { - traceEvent(TRACE_WARNING, "recvfrom returned %d [err=%d]", len, WSAGetLastError()); - } -#endif - return(0); - } else if(len > MIN_COMPRESSED_PKT_LEN) { -#define N2N_DECOMPRESS_BUFSIZE 2048 - char decompressed[N2N_DECOMPRESS_BUFSIZE]; - int rc; - lzo_uint decompressed_len=N2N_DECOMPRESS_BUFSIZE; - size_t insize = len-N2N_PKT_HDR_SIZE; - - if(decompress_data) { - rc = lzo1x_decompress_safe((u_char*)&packet[N2N_PKT_HDR_SIZE], - insize, - (u_char*)decompressed, &decompressed_len, NULL); - - if(rc == LZO_E_OK) - { - traceEvent(TRACE_INFO, "%u bytes decompressed into %u", insize, decompressed_len); - } - else - { - traceEvent(TRACE_WARNING, "Failed to decompress %u byte packet. LZO error=%d", insize, rc ); - return -1; - } - - if(packet_len > decompressed_len) { - memcpy(&packet[N2N_PKT_HDR_SIZE], decompressed, decompressed_len); - len = decompressed_len+N2N_PKT_HDR_SIZE; - } else { - traceEvent(TRACE_WARNING, "Uncompressed packet is too large [decompressed_len=%d]", - decompressed_len); - return(0); - } - } - - (*discarded_pkt) = 0; - - if(!hdr->sent_by_supernode) { - memcpy( &packet[offsetof(struct n2n_packet_header, public_ip)], from, sizeof(struct sockaddr_in) ); - } - - switch(hdr->pkt_type) { - case packet_unreliable_data: - pkt_type = "unreliable data"; - break; - case packet_reliable_data: - pkt_type = "reliable data"; - break; - case packet_ping: - pkt_type = "ping"; - break; - case packet_pong: - pkt_type = "pong"; - break; - default: - pkt_type = "???"; - } - - traceEvent(TRACE_INFO, "+++ Received %s packet [rcvd_from=%s:%d][msg_type=%s][seq_id=%d]", - pkt_type, - intoa(ntohl(from->addr_type.v4_addr), from_ip_buf, sizeof(from_ip_buf)), - ntohs(from->port), msg_type2str(hdr->msg_type), - hdr->sequence_id); - traceEvent(TRACE_INFO, " [src_mac=%s][dst_mac=%s][original_sender=%s:%d]", - macaddr_str(hdr->src_mac, src_mac_buf, sizeof(src_mac_buf)), - macaddr_str(hdr->dst_mac, dst_mac_buf, sizeof(dst_mac_buf)), - intoa(ntohl(hdr->public_ip.addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(hdr->public_ip.port)); - -#ifdef HANDLE_RETRANSMISSION - if((hdr->pkt_type == packet_reliable_data) - && (hdr->msg_type == MSG_TYPE_PACKET)) { - (*discarded_pkt) = handle_ack(sock_fd, is_udp_socket, hdr, - &payload[6], payload, from, tun_mac_addr); - } else - (*discarded_pkt) = 0; -#endif - } else - traceEvent(TRACE_WARNING, "Receive error [%s] or pkt too short [len=%d]\n", - strerror(errno), len); - - return(len); -} - -/* *********************************************** */ - -#if 0 -static u_int32_t queue_packet(struct send_hash_entry *scan, - char *packet, - u_int16_t packet_len) { - struct packet_list *pkt = (struct packet_list*)malloc(sizeof(struct packet_list)); - - if(pkt == NULL) { - traceEvent(TRACE_ERROR, "Not enough memory!"); - return(0); - } - - if((pkt->packet = (char*)malloc(packet_len)) == NULL) { - traceEvent(TRACE_ERROR, "Not enough memory!"); - return(0); - } - - memcpy(pkt->packet, packet, packet_len); - pkt->packet_len = packet_len; - pkt->seq_id = scan->last_seq_id; - pkt->next = scan->unacked_packet_list; - scan->unacked_packet_list = pkt; - scan->num_unacked_pkts++; - return(pkt->seq_id); -} -#endif - -/* *********************************************** */ - -/* Work-memory needed for compression. Allocate memory in units - * of `lzo_align_t' (instead of `char') to make sure it is properly aligned. - */ - -#define HEAP_ALLOC(var,size) \ - lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] - -static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS); - -/* ******************************************************* */ - -u_int send_data(n2n_sock_info_t * sinfo, - char *packet, size_t *packet_len, - const struct peer_addr *to, u_int8_t compress_data) { - char compressed[1650]; - int rc; - lzo_uint compressed_len=0; - struct sockaddr_in destsock; - - if(*packet_len < N2N_PKT_HDR_SIZE) { - traceEvent(TRACE_WARNING, "The packet about to be sent is too short [len=%d]\n", *packet_len); - return(-1); - } - - memcpy(compressed, packet, N2N_PKT_HDR_SIZE); - - peer_addr2sockaddr_in(to, &destsock); - - if(compress_data) { - rc = lzo1x_1_compress((u_char*)&packet[N2N_PKT_HDR_SIZE], - *packet_len - N2N_PKT_HDR_SIZE, - (u_char*)&compressed[N2N_PKT_HDR_SIZE], - &compressed_len, wrkmem); - - if ( 0 == compressed_len ) - { - traceEvent(TRACE_WARNING, "failed to compress %u bytes.", (*packet_len - N2N_PKT_HDR_SIZE) ); - return -1; - } - - compressed_len += N2N_PKT_HDR_SIZE; - - traceEvent(TRACE_INFO, "%u bytes compressed into %u", *packet_len, compressed_len); - /* *packet_len = compressed_len; */ - - if(sinfo->is_udp_socket) { - rc = sendto(sinfo->sock, compressed, compressed_len, 0, - (struct sockaddr*)&destsock, sizeof(struct sockaddr_in)); - } else { - char send_len[5]; - - /* 4 bytes packet length */ - snprintf(send_len, sizeof(send_len), "%04d", (int)compressed_len); - if((rc = send(sinfo->sock, send_len, 4, 0)) != 4) - return(-1); - if((rc = send(sinfo->sock, compressed, compressed_len, 0)) != compressed_len) { - traceEvent(TRACE_WARNING, "send error [%d][%s]", - errno, strerror(errno)); - } - } - } else { - compressed_len = *packet_len; - if(sinfo->is_udp_socket) - rc = sendto(sinfo->sock, packet, compressed_len, 0, - (struct sockaddr*)&destsock, sizeof(struct sockaddr_in)); - else { - char send_len[5]; - - /* 4 bytes packet length */ - snprintf(send_len, sizeof(send_len), "%04d", (int)compressed_len); - if((rc = send(sinfo->sock, send_len, 4, 0)) != 4) - return(-1); - rc = send(sinfo->sock, compressed, compressed_len, 0); - } - - if(rc == -1) { - ipstr_t ip_buf; - - traceEvent(TRACE_WARNING, "sendto() failed while attempting to send data to %s:%d", - intoa(ntohl(to->addr_type.v4_addr), ip_buf, sizeof(ip_buf)), - ntohs(to->port)); - } - } - - if ( rc >= 0) { - traceEvent(TRACE_INFO, "### Tx N2N Msg -> network"); - } - - if(rc == compressed_len) - return(*packet_len); /* fake just to avoid warnings */ - else - return(rc); -} - -/* *********************************************** */ - -u_int reliable_sendto(n2n_sock_info_t * sinfo, - char *packet, size_t *packet_len, - const struct peer_addr *to, u_int8_t compress_data) { - /* char *payload = &packet[N2N_PKT_HDR_SIZE]; */ - struct n2n_packet_header hdr_storage; - struct n2n_packet_header *hdr = &hdr_storage; - macstr_t src_mac_buf; - macstr_t dst_mac_buf; - - /* REVISIT: efficiency of unmarshal + re-marshal just to change a couple of bits. */ - unmarshall_n2n_packet_header( hdr, (u_int8_t *)packet ); - - /* hdr->sequence_id = (hdr->msg_type == MSG_TYPE_PACKET) ? mac2sequence((u_char*)payload, packet, *packet_len) : 0; */ - hdr->sequence_id = 0; - hdr->pkt_type = packet_reliable_data; - - traceEvent(TRACE_INFO, "Sent reliable packet [msg_type=%s][seq_id=%d][src_mac=%s][dst_mac=%s]", - msg_type2str(hdr->msg_type), hdr->sequence_id, - macaddr_str(&packet[6], src_mac_buf, sizeof(src_mac_buf)), - macaddr_str(packet, dst_mac_buf, sizeof(dst_mac_buf))); - - marshall_n2n_packet_header( (u_int8_t *)packet, hdr ); - - return(send_data(sinfo, packet, packet_len, to, compress_data)); -} - -/* *********************************************** */ - -/* unreliable_sendto is passed a fully marshalled, packet. Its purpose is to set - * the unreliable flags but leave the rest of the packet untouched. */ -u_int unreliable_sendto(n2n_sock_info_t * sinfo, - char *packet, size_t *packet_len, - const struct peer_addr *to, u_int8_t compress_data) { - struct n2n_packet_header hdr_storage; - struct n2n_packet_header *hdr = &hdr_storage; - macstr_t src_mac_buf; - macstr_t dst_mac_buf; - - /* REVISIT: efficiency of unmarshal + re-marshal just to change a couple of bits. */ - unmarshall_n2n_packet_header( hdr, (u_int8_t *)packet ); - - hdr->sequence_id = 0; /* Unreliable messages have 0 as sequence number */ - hdr->pkt_type = packet_unreliable_data; - - traceEvent(TRACE_INFO, "Sent unreliable packet [msg_type=%s][seq_id=%d][src_mac=%s][dst_mac=%s]", - msg_type2str(hdr->msg_type), hdr->sequence_id, - macaddr_str(hdr->src_mac, src_mac_buf, sizeof(src_mac_buf)), - macaddr_str(hdr->dst_mac, dst_mac_buf, sizeof(dst_mac_buf))); - - marshall_n2n_packet_header( (u_int8_t *)packet, hdr ); - - return(send_data(sinfo, packet, packet_len, to, compress_data)); -} - -/* *********************************************** */ - -char* msg_type2str(u_short msg_type) { - switch(msg_type) { - case MSG_TYPE_REGISTER: return("MSG_TYPE_REGISTER"); - case MSG_TYPE_DEREGISTER: return("MSG_TYPE_DEREGISTER"); - case MSG_TYPE_PACKET: return("MSG_TYPE_PACKET"); - case MSG_TYPE_REGISTER_ACK: return("MSG_TYPE_REGISTER_ACK"); - case MSG_TYPE_ACK_RESPONSE: return("MSG_TYPE_ACK_RESPONSE"); - } - - return("???"); -} - -/* *********************************************** */ - -void hexdump(char *buf, u_int len) { - u_int i; - - for(i=0; i 0) && ((i % 16) == 0)) printf("\n"); - printf("%02X ", buf[i] & 0xFF); - } - - printf("\n"); -} - -/* *********************************************** */ - -void print_n2n_version() { - printf("Welcome to n2n v.%s for %s\n" - "Built on %s\n" - "Copyright 2007-08 - http://www.ntop.org\n\n", - version, osName, buildDate); -} - - - - -/** Find the peer entry in list with mac_addr equal to mac. - * - * Does not modify the list. - * - * @return NULL if not found; otherwise pointer to peer entry. - */ -struct peer_info * find_peer_by_mac( struct peer_info * list, const char * mac ) -{ - while(list != NULL) - { - if( 0 == memcmp(mac, list->mac_addr, 6) ) - { - return list; - } - list = list->next; - } - - return NULL; -} - - -/** Return the number of elements in the list. - * - */ -size_t peer_list_size( const struct peer_info * list ) -{ - size_t retval=0; - - while ( list ) - { - ++retval; - list = list->next; - } - - return retval; -} - -/** Add new to the head of list. If list is NULL; create it. - * - * The item new is added to the head of the list. New is modified during - * insertion. list takes ownership of new. - */ -void peer_list_add( struct peer_info * * list, - struct peer_info * new ) -{ - new->next = *list; - new->last_seen = time(NULL); - *list = new; -} - - -size_t purge_expired_registrations( struct peer_info ** peer_list ) { - static time_t last_purge = 0; - time_t now = time(NULL); - size_t num_reg = 0; - - if((now - last_purge) < PURGE_REGISTRATION_FREQUENCY) return 0; - - traceEvent(TRACE_INFO, "Purging old registrations"); - - num_reg = purge_peer_list( peer_list, now-REGISTRATION_TIMEOUT ); - - last_purge = now; - traceEvent(TRACE_INFO, "Remove %ld registrations", num_reg); - - return num_reg; -} - -/** Purge old items from the peer_list and return the number of items that were removed. */ -size_t purge_peer_list( struct peer_info ** peer_list, - time_t purge_before ) -{ - struct peer_info *scan; - struct peer_info *prev; - size_t retval=0; - - scan = *peer_list; - prev = NULL; - while(scan != NULL) - { - if(scan->last_seen < purge_before) - { - struct peer_info *next = scan->next; - - if(prev == NULL) - { - *peer_list = next; - } - else - { - prev->next = next; - } - - ++retval; - free(scan); - scan = next; - } - else - { - prev = scan; - scan = scan->next; - } - } - - return retval; -} - -static u_int8_t hex2byte( const char * s ) -{ - char tmp[3]; - tmp[0]=s[0]; - tmp[1]=s[1]; - tmp[2]=0; /* NULL term */ - - return((u_int8_t)strtol( s, NULL, 16 )); -} - -extern int str2mac( u_int8_t * outmac /* 6 bytes */, const char * s ) -{ - size_t i; - - /* break it down as one case for the first "HH", the 5 x through loop for - * each ":HH" where HH is a two hex nibbles in ASCII. */ - - *outmac=hex2byte(s); - ++outmac; - s+=2; /* don't skip colon yet - helps generalise loop. */ - - for (i=1; i<6; ++i ) - { - s+=1; - *outmac=hex2byte(s); - ++outmac; - s+=2; - } - - return 0; /* ok */ -} diff --git a/n2n.h b/n2n.h deleted file mode 100644 index e5fa8e0..0000000 --- a/n2n.h +++ /dev/null @@ -1,299 +0,0 @@ -/* - * (C) 2007-09 - Luca Deri - * Richard Andrews - * - * 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 - * - * Code contributions courtesy of: - * Babak Farrokhi [FreeBSD port] - * -*/ - -#ifndef _N2N_H_ -#define _N2N_H_ - -/* - tunctl -t tun0 - tunctl -t tun1 - ifconfig tun0 1.2.3.4 up - ifconfig tun1 1.2.3.5 up - ./edge -d tun0 -l 2000 -r 127.0.0.1:3000 -c hello - ./edge -d tun1 -l 3000 -r 127.0.0.1:2000 -c hello - - - tunctl -u UID -t tunX -*/ - -#if defined(__APPLE__) && defined(__MACH__) -#define _DARWIN_ -#endif - -#ifdef WIN32 -#include "win32/n2n_win32.h" -#endif - -#include -#include -#include - -#ifndef WIN32 -#include -#endif - -#include -#include -#include - -#ifndef WIN32 -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include -#include -#endif - -#ifdef __FreeBSD__ -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define closesocket(a) close(a) -#endif - -#include -#ifdef WIN32 -#include "win32/getopt.h" -#else -#define _GNU_SOURCE -#include -#endif - -#include - -#ifdef WIN32 -#include "win32/wintap.h" -#endif - -#include "twofish.h" - -#ifndef WIN32 -typedef struct tuntap_dev { - int fd; - u_int8_t mac_addr[6]; - u_int32_t ip_addr, device_mask; - u_int mtu; -} tuntap_dev; - -#define SOCKET int -#endif /* #ifndef WIN32 */ - -#define QUICKLZ 1 -#define N2N_PKT_VERSION 1 - -#define MSG_TYPE_REGISTER 1 /* FIX invece di usare il sender del pacchetto scriverlo nel pacchetto stesso */ -#define MSG_TYPE_DEREGISTER 2 -#define MSG_TYPE_PACKET 3 -#define MSG_TYPE_REGISTER_ACK 4 -#define MSG_TYPE_ACK_RESPONSE 5 - -#define COMMUNITY_LEN 16 -#define MIN_COMPRESSED_PKT_LEN 32 - -/* Set N2N_COMPRESSION_ENABLED to 0 to disable lzo1x compression of ethernet - * frames. Doing this will break compatibility with the standard n2n packet - * format so do it only for experimentation. All edges must be built with the - * same value if they are to understand each other. */ -#define N2N_COMPRESSION_ENABLED 1 - -#define DEFAULT_MTU 1400 - -/* Maximum enum value is 255 due to marshalling into 1 byte */ -enum packet_type { - packet_unreliable_data = 0, /* no ACK needed */ - packet_reliable_data, /* needs ACK */ - packet_ping, - packet_pong -}; - -/* All information is always in network byte-order */ -struct peer_addr { - u_int8_t family; - u_int16_t port; - union { - u_int8_t v6_addr[16]; - u_int32_t v4_addr; - } addr_type; -}; - -struct n2n_packet_header { - u_int8_t version, msg_type, ttl, sent_by_supernode; - char community_name[COMMUNITY_LEN], src_mac[6], dst_mac[6]; - struct peer_addr public_ip, private_ip; - enum packet_type pkt_type; - u_int32_t sequence_id; - u_int32_t crc; // FIX - It needs to be handled for detcting forged packets -}; - -int marshall_n2n_packet_header( u_int8_t * buf, const struct n2n_packet_header * hdr ); -int unmarshall_n2n_packet_header( struct n2n_packet_header * hdr, const u_int8_t * buf ); - -#define N2N_PKT_HDR_SIZE (sizeof(struct n2n_packet_header)) - - -/** Common type used to hold stringified IP addresses. */ -typedef char ipstr_t[32]; - -/** Common type used to hold stringified MAC addresses. */ -typedef char macstr_t[32]; - -struct n2n_sock_info -{ - int sock; - char is_udp_socket /*= 1*/; -}; - -typedef struct n2n_sock_info n2n_sock_info_t; - -struct peer_info { - char community_name[16], mac_addr[6]; - struct peer_addr public_ip, private_ip; - time_t last_seen; - struct peer_info *next; - /* socket */ - n2n_sock_info_t sinfo; -}; - -struct n2n_edge; /* defined in edge.c */ -typedef struct n2n_edge n2n_edge_t; - - -/* ************************************** */ - -#if defined(DEBUG) -#define SOCKET_TIMEOUT_INTERVAL_SECS 5 -#define REGISTER_FREQUENCY 20 /* sec */ -#else /* #if defined(DEBUG) */ -#define SOCKET_TIMEOUT_INTERVAL_SECS 10 -#define REGISTER_FREQUENCY 60 /* sec */ -#endif /* #if defined(DEBUG) */ - -#define TRACE_ERROR 0, __FILE__, __LINE__ -#define TRACE_WARNING 1, __FILE__, __LINE__ -#define TRACE_NORMAL 2, __FILE__, __LINE__ -#define TRACE_INFO 3, __FILE__, __LINE__ - -/* ************************************** */ - -#define SUPERNODE_IP "127.0.0.1" -#define SUPERNODE_PORT 1234 - -/* ************************************** */ - -#ifndef max -#define max(a, b) ((a < b) ? b : a) -#endif - -#ifndef min -#define min(a, b) ((a > b) ? b : a) -#endif - -/* ************************************** */ - -/* Variables */ -// extern TWOFISH *tf; -extern int traceLevel; -extern char broadcast_addr[6]; -extern char multicast_addr[6]; - -/* Functions */ -extern void sockaddr_in2peer_addr(struct sockaddr_in *in, struct peer_addr *out); -extern void peer_addr2sockaddr_in(const struct peer_addr *in, struct sockaddr_in *out); -// extern int init_n2n(u_int8_t *encrypt_pwd, u_int32_t encrypt_pwd_len ); -// extern void term_n2n(); -extern void send_ack(n2n_sock_info_t * sinfo, - u_int16_t last_rcvd_seq_id, - struct n2n_packet_header *header, - struct peer_addr *remote_peer, - char *src_mac); - -extern void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...); -extern int tuntap_open(tuntap_dev *device, char *dev, char *device_ip, - char *device_mask, const char * device_mac, int mtu); -extern int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len); -extern int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len); -extern void tuntap_close(struct tuntap_dev *tuntap); - -extern SOCKET open_socket(int local_port, int udp_sock, int server_mode); -extern int connect_socket(int sock_fd, struct peer_addr* dest); - -extern void send_packet(n2n_sock_info_t * sinfo, - char *packet, size_t *packet_len, - const struct peer_addr *remote_peer, - u_int8_t compress_data); -extern char* intoa(u_int32_t addr, char* buf, u_short buf_len); -extern char* macaddr_str(const char *mac, char *buf, int buf_len); -extern int str2mac( u_int8_t * outmac /* 6 bytes */, const char * s ); -extern void fill_standard_header_fields(n2n_sock_info_t * eee, - struct n2n_packet_header *hdr, - char *src_mac); - -extern u_int receive_data(n2n_sock_info_t * sinfo, - char *packet, size_t packet_len, - struct peer_addr *from, u_int8_t *discarded_pkt, - char *tun_mac_addr, u_int8_t decompress_data, - struct n2n_packet_header *hdr); -extern u_int reliable_sendto(n2n_sock_info_t * sinfo, - char *packet, size_t *packet_len, - const struct peer_addr *from, u_int8_t compress_data); -extern u_int unreliable_sendto(n2n_sock_info_t * sinfo, - char *packet, size_t *packet_len, - const struct peer_addr *from, u_int8_t compress_data); -extern u_int send_data(n2n_sock_info_t * sinfo, - char *packet, size_t *packet_len, - const struct peer_addr *to, u_int8_t compress_data); -extern u_int8_t is_multi_broadcast(char *dest_mac); -extern char* msg_type2str(u_short msg_type); -extern void hexdump(char *buf, u_int len); - -void print_n2n_version(); - - -/* Operations on peer_info lists. */ -struct peer_info * find_peer_by_mac( struct peer_info * list, - const char * mac ); -void peer_list_add( struct peer_info * * list, - struct peer_info * new ); -size_t peer_list_size( const struct peer_info * list ); -size_t purge_peer_list( struct peer_info ** peer_list, - time_t purge_before ); -size_t purge_expired_registrations( struct peer_info ** peer_list ); - -/* version.c */ -extern char *version, *osName, *buildDate; - -#endif /* _N2N_H_ */ diff --git a/n2n.spec b/n2n.spec deleted file mode 100644 index 0e7892a..0000000 --- a/n2n.spec +++ /dev/null @@ -1,47 +0,0 @@ -Summary: N2N peer-to-peer virtual private network system. -Name: n2n -Version: 1.3 -Release: 1 -License: GPLv3 -Vendor: ntop.org -Group: None -URL: http://www.ntop.org/n2n -Source0: %{name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root - -%description -N2N is a peer-to-peer virtual private network system. N2N uses the universal -TUNTAP interface to create TAP network interfaces to an encrypted virtual -LAN. Members of a community share a common encryption key which allows echange -of data. The supernode is used for peer discovery and initial packet relay -before direct peer-to-peer exchange is established. -Once direct packet exchange is established, the supernode is not required. - -%prep - -%setup -q - -echo -e "\n *** Building ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION}-${RPM_PACKAGE_RELEASE} ***\n" - -%build -make - -%install -make PREFIX=${RPM_BUILD_ROOT}/usr install - -%clean -rm -rf $RPM_BUILD_ROOT - - -%files -%defattr(-,root,root,-) - /usr/bin/supernode - /usr/sbin/edge -%doc /usr/share/man/man1/supernode.1.gz -%doc /usr/share/man/man8/edge.8.gz - - -%changelog -* Sat May 3 2008 Richard Andrews - -- Initial build. - diff --git a/openwrt/kamikaze/Makefile b/openwrt/kamikaze/Makefile deleted file mode 100644 index ddcc7c1..0000000 --- a/openwrt/kamikaze/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -# -# Copyright (C) 2008 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. - - -include $(TOPDIR)/rules.mk - -PKG_BRANCH:=trunk -PKG_SOURCE_URL:=https://svn.ntop.org/svn/ntop/trunk/n2n -PKG_REV:=$(shell LC_ALL=C svn info ${PKG_SOURCE_URL} | sed -ne's/^Last Changed Rev: //p') - -PKG_NAME:=n2n -PKG_VERSION:=svn$(PKG_REV) -PKG_RELEASE:=1 - -PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.gz -PKG_SOURCE_PROTO:=svn -PKG_SOURCE_VERSION:=$(PKG_REV) - -PKG_BUILD_DEPENDS:= - -PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) -PKG_INSTALL_DIR:=$(PKG_BUILD_DIR) - - - -include $(INCLUDE_DIR)/package.mk - -define Package/n2n - SECTION:=net - CATEGORY:=Network - TITLE:=VPN tunneling daemon - URL:=http://www.ntop.org/n2n/ - SUBMENU:=VPN - DEPENDS:=libpthread -endef - - -define Build/Configure -endef - -define Build/Compile - $(MAKE) CC="$(TARGET_CC)" -C $(PKG_BUILD_DIR) -endef - - -define Package/n2n/install - $(INSTALL_DIR) $(1)/usr/sbin - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/edge $(1)/usr/sbin/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/supernode $(1)/usr/sbin/ -endef - -$(eval $(call BuildPackage,n2n)) diff --git a/packages/centos b/packages/centos new file mode 120000 index 0000000..7c88ef3 --- /dev/null +++ b/packages/centos @@ -0,0 +1 @@ +rpm \ No newline at end of file diff --git a/packages/debian/Makefile.in b/packages/debian/Makefile.in new file mode 100644 index 0000000..8b8b993 --- /dev/null +++ b/packages/debian/Makefile.in @@ -0,0 +1,41 @@ +# +# Change it according to your setup +# +N2N_HOME=$(PWD)/../.. +N2N_BUILD=${N2N_HOME}/packages/debian/n2n + +all: clean pkg + +pkg: + make -C ../../ + if test -e "${N2N_BUILD}"; then /bin/rm -fr ${N2N_BUILD}; fi + mkdir -p ${N2N_BUILD}/usr/sbin ${N2N_BUILD}/usr/share/man/man1 ${N2N_BUILD}/usr/share/man/man7 ${N2N_BUILD}/usr/share/man/man8 + mkdir -p ${N2N_BUILD}/usr/share/doc/n2n/examples + install -m755 ../../supernode ${N2N_BUILD}/usr/sbin/ + install -m755 ../../edge ${N2N_BUILD}/usr/sbin/ + install -m644 ../../edge.8.gz ${N2N_BUILD}/usr/share/man/man8/ + install -m644 ../../supernode.1.gz ${N2N_BUILD}/usr/share/man/man1/ + install -m644 ../../n2n.7.gz ${N2N_BUILD}/usr/share/man/man7/ + install -m644 ../../community.list ${N2N_BUILD}/usr/share/doc/n2n/examples/ + install -m644 ../../doc/*.md ${N2N_BUILD}/usr/share/doc/n2n/ + @/bin/rm -f ../n2n*.deb + dpkg-buildpackage -rfakeroot -d -us -uc -a@EXTN@ + -dpkg-sig --sign builder -k D1EB60BE ../n2n_*deb + @\rm -f ../n2n_*dsc ../n2n_*.gz ../n2n_*changes + @/bin/mv ../n2n_*deb . + @echo + @echo "Package built." + @/bin/ls n2n_*deb + @echo "-------------------------------" + -dpkg -I n2n_*deb + -dpkg --contents n2n_*deb + @echo "-------------------------------" + +distclean: + echo "dummy distclean" + +install: + echo "dummy install" + +clean: + rm -rf *~ *deb diff --git a/packages/debian/README b/packages/debian/README new file mode 100644 index 0000000..915a7c1 --- /dev/null +++ b/packages/debian/README @@ -0,0 +1,21 @@ +Prerequisites +------------- +apt-get install debhelper fakeroot dpkg-sig + +EdgeOS +------ +We need to replace BusyBox-implemented commands using full-fledged commands by doing +(see http://community.ubnt.com/t5/EdgeMAX/ubnt-debian-package-conflict/m-p/421325) + +curl -O http://ftp.us.debian.org/debian/pool/main/c/coreutils/coreutils_8.5-1_mips.deb +dpkg -i --force-all coreutils_8.5-1_mips.deb + +curl -O http://ftp.us.debian.org/debian/pool/main/t/tar/tar_1.23-3_mips.deb +dpkg -i --force-all tar_1.23-3_mips.deb + +wget http://ftp.us.debian.org/debian/pool/main/f/findutils/findutils_4.4.2-4_mips.deb +dpkg -i --force-all findutils_4.4.2-4_mips.deb + +wget http://ftp.us.debian.org/debian/pool/main/g/gzip/gzip_1.5-1.1_mips.deb +dpkg -i --force-all gzip_1.5-1.1_mips.deb + diff --git a/packages/debian/configure b/packages/debian/configure new file mode 100755 index 0000000..b1048d9 --- /dev/null +++ b/packages/debian/configure @@ -0,0 +1,2921 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for Makefile.in 1.0. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='Makefile.in' +PACKAGE_TARNAME='makefile-in' +PACKAGE_VERSION='1.0' +PACKAGE_STRING='Makefile.in 1.0' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_subst_vars='LTLIBOBJS +LIBOBJS +EXTRA_DEP +DATE +EXTN +N2N_VERSION +APP +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_edgex +' + ac_precious_vars='build_alias +host_alias +target_alias' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures Makefile.in 1.0 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/makefile-in] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of Makefile.in 1.0:";; + esac + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-edgex Build for Ubiquity-X + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +Makefile.in configure 1.0 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by Makefile.in $as_me 1.0, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +# Check whether --with-edgex was given. +if test "${with_edgex+set}" = set; then : + withval=$with_edgex; +fi + + +# NOTE: this file is not actually used. You need to edit configure as well! +N2N_VERSION=$(../../scripts/version.sh) + +DEBIAN_VERSION=`cat /etc/debian_version | grep "^8" | wc -l` + +EXTRA_DEP="" +if test $DEBIAN_VERSION = "0"; then +EXTRA_DEP=", libzstd1" +fi + +if test "${EXTN+set}" != set; then + MACHINE=`uname -m` + SHORT_MACHINE=`echo $MACHINE | cut -b1-3` + + if test $MACHINE = "x86_64"; then + EXTN="amd64" + else + if test $SHORT_MACHINE = "aar"; then + EXTN="arm64" + else + if test $SHORT_MACHINE = "arm"; then + EXTN="armhf" + else + if test $SHORT_MACHINE = "mip"; then + EXTN="mips" + else + EXTN="i386" + fi + fi + fi + fi +fi + +if test "${with_edgex+set}" = set; then + EXTN="mipsel" +fi + +APP=n2n +DATE=`date -R` + + + + + + + +ac_config_files="$ac_config_files debian/changelog" + +ac_config_files="$ac_config_files debian/files" + +ac_config_files="$ac_config_files debian/control" + +ac_config_files="$ac_config_files debian/rules" + +ac_config_files="$ac_config_files ../etc/systemd/system/edge.service" + +ac_config_files="$ac_config_files ../etc/systemd/system/edge@.service" + +ac_config_files="$ac_config_files ../etc/systemd/system/edge-ntopng@.service" + +ac_config_files="$ac_config_files ../etc/systemd/system/supernode.service" + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by Makefile.in $as_me 1.0, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +Makefile.in config.status 1.0 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "debian/changelog") CONFIG_FILES="$CONFIG_FILES debian/changelog" ;; + "debian/files") CONFIG_FILES="$CONFIG_FILES debian/files" ;; + "debian/control") CONFIG_FILES="$CONFIG_FILES debian/control" ;; + "debian/rules") CONFIG_FILES="$CONFIG_FILES debian/rules" ;; + "../etc/systemd/system/edge.service") CONFIG_FILES="$CONFIG_FILES ../etc/systemd/system/edge.service" ;; + "../etc/systemd/system/edge@.service") CONFIG_FILES="$CONFIG_FILES ../etc/systemd/system/edge@.service" ;; + "../etc/systemd/system/edge-ntopng@.service") CONFIG_FILES="$CONFIG_FILES ../etc/systemd/system/edge-ntopng@.service" ;; + "../etc/systemd/system/supernode.service") CONFIG_FILES="$CONFIG_FILES ../etc/systemd/system/supernode.service" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/packages/debian/configure.in b/packages/debian/configure.in new file mode 100644 index 0000000..e01e987 --- /dev/null +++ b/packages/debian/configure.in @@ -0,0 +1,60 @@ +AC_INIT([Makefile.in], 1.0) + +AC_ARG_WITH(edgex, [ --with-edgex Build for Ubiquity-X]) + +# NOTE: this file is not actually used. You need to edit configure as well! +N2N_VERSION=$(../../scripts/version.sh) + +DEBIAN_VERSION=`cat /etc/debian_version | grep "^8" | wc -l` + +EXTRA_DEP="" +if test $DEBIAN_VERSION = "0"; then +EXTRA_DEP=", libzstd1" +fi + +if test "${EXTN+set}" != set; then + MACHINE=`uname -m` + SHORT_MACHINE=`echo $MACHINE | cut -b1-3` + + if test $MACHINE = "x86_64"; then + EXTN="amd64" + else + if test $SHORT_MACHINE = "aar"; then + EXTN="arm64" + else + if test $SHORT_MACHINE = "arm"; then + EXTN="armhf" + else + if test $SHORT_MACHINE = "mip"; then + EXTN="mips" + else + EXTN="i386" + fi + fi + fi + fi +fi + +if test "${with_edgex+set}" = set; then + EXTN="mipsel" +fi + +APP=n2n +DATE=`date -R` + +AC_SUBST(APP) +AC_SUBST(N2N_VERSION) +AC_SUBST(EXTN) +AC_SUBST(DATE) +AC_SUBST(EXTRA_DEP) + +AC_CONFIG_FILES(debian/changelog) +AC_CONFIG_FILES(debian/files) +AC_CONFIG_FILES(debian/control) +AC_CONFIG_FILES(debian/rules) +AC_CONFIG_FILES(../etc/systemd/system/edge.service) +AC_CONFIG_FILES(../etc/systemd/system/edge@.service) +AC_CONFIG_FILES(../etc/systemd/system/edge-ntopng@.service) +AC_CONFIG_FILES(../etc/systemd/system/supernode.service) +AC_CONFIG_FILES(Makefile) +AC_OUTPUT diff --git a/packages/debian/debian/COPYRIGHT b/packages/debian/debian/COPYRIGHT new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/packages/debian/debian/COPYRIGHT @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/packages/debian/debian/README b/packages/debian/debian/README new file mode 100644 index 0000000..8d88f8d --- /dev/null +++ b/packages/debian/debian/README @@ -0,0 +1,2 @@ +This directory contains the files needed to build the package +named 'n2n' for the Debian GNU/Linux distribution. diff --git a/packages/debian/debian/changelog.in b/packages/debian/debian/changelog.in new file mode 100644 index 0000000..5669566 --- /dev/null +++ b/packages/debian/debian/changelog.in @@ -0,0 +1,4 @@ +@APP@ (@N2N_VERSION@) table; urgency=high + * Last packaged version + + -- Luca Deri @DATE@ diff --git a/debian/compat b/packages/debian/debian/compat similarity index 100% rename from debian/compat rename to packages/debian/debian/compat diff --git a/packages/debian/debian/conffiles b/packages/debian/debian/conffiles new file mode 100644 index 0000000..d467c8b --- /dev/null +++ b/packages/debian/debian/conffiles @@ -0,0 +1,2 @@ +/etc/n2n/edge.conf.sample +/etc/n2n/supernode.conf.sample diff --git a/packages/debian/debian/control.in b/packages/debian/debian/control.in new file mode 100644 index 0000000..7303119 --- /dev/null +++ b/packages/debian/debian/control.in @@ -0,0 +1,25 @@ +Source: n2n +Section: net +Priority: extra +Maintainer: Luca Deri +Standards-Version: 4.6.0 +Build-Depends: + +Package: n2n +Architecture: @EXTN@ +Suggests: uml-utilities +Depends: ${shlibs:Depends}, ${misc:Depends} @EXTRA_DEP@ +Conflicts: n2n (<< 2.1.0-1) +Replaces: n2n (<< 2.1.0-1) +Description: a layer-two peer-to-peer virtual private network (VPN) + n2n is a layer-two peer-to-peer virtual private network (VPN) which allows + users to exploit features typical of P2P applications at network instead of + application level. This means that users can gain native IP visibility (e.g. + two PCs belonging to the same n2n network can ping each other) and be + reachable with the same network IP address regardless of the network where + they currently belong. In a nutshell, as OpenVPN moved SSL from application + (e.g. used to implement the https protocol) to network protocol, n2n moves + P2P from application to network level. + . + Edge is the edge node daemon for n2n which creates a TAP interface to expose + the n2n virtual LAN. diff --git a/packages/debian/debian/dirs b/packages/debian/debian/dirs new file mode 100644 index 0000000..8a9632d --- /dev/null +++ b/packages/debian/debian/dirs @@ -0,0 +1,3 @@ +usr/sbin +etc/systemd +etc/init.d diff --git a/debian/docs b/packages/debian/debian/docs similarity index 100% rename from debian/docs rename to packages/debian/debian/docs diff --git a/packages/debian/debian/files.in b/packages/debian/debian/files.in new file mode 100644 index 0000000..510512c --- /dev/null +++ b/packages/debian/debian/files.in @@ -0,0 +1 @@ +n2n_@N2N_VERSION@_@EXTN@.deb free optional diff --git a/packages/debian/debian/n2n.substvars b/packages/debian/debian/n2n.substvars new file mode 100644 index 0000000..a595723 --- /dev/null +++ b/packages/debian/debian/n2n.substvars @@ -0,0 +1,2 @@ +misc:Depends=debconf (>= 0.5) | debconf-2.0 +misc:Pre-Depends= diff --git a/packages/debian/debian/postinst b/packages/debian/debian/postinst new file mode 100755 index 0000000..5de13e2 --- /dev/null +++ b/packages/debian/debian/postinst @@ -0,0 +1,56 @@ +#!/bin/sh -e + +case "$1" in + configure) + # continue below + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + exit 0 + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 0 + ;; +esac + +umask 022 + +if ! grep -q n2n /etc/group; then + echo 'Creating n2n group' + /usr/sbin/groupadd -r n2n +fi + +if ! /usr/bin/id -u n2n > /dev/null 2>&1; then + echo "Creating n2n user..." + /usr/sbin/useradd -M -N -g n2n -r -s /bin/false n2n +fi + +echo "Rebuilding ld cache..." +/sbin/ldconfig + +if [ -f /.dockerenv ]; then exit 0; fi + +# Start service after upgrade/install +systemctl daemon-reload +systemctl reset-failed + +# Enable edge +if systemctl -q is-active edge; then + # only restart edge if it's already running + echo "Restarting n2n edge..." + deb-systemd-invoke restart edge +fi + +# Restart specific services if already running +deb-systemd-invoke restart 'edge@*.service' 'edge-ntopng@*.service' + +# Enable supernode +if systemctl -q is-active supernode; then + # only restart supernode if it's already running + echo "Restarting n2n supernode..." + deb-systemd-invoke restart supernode +fi + +exit 0 diff --git a/packages/debian/debian/postrm b/packages/debian/debian/postrm new file mode 100644 index 0000000..ef799a3 --- /dev/null +++ b/packages/debian/debian/postrm @@ -0,0 +1,11 @@ +#!/bin/sh -e + +set -e + +#case "$1" in +# purge|remove) +# +# ;; +#esac + +exit 0 diff --git a/packages/debian/debian/preinst b/packages/debian/debian/preinst new file mode 100644 index 0000000..4e7a80d --- /dev/null +++ b/packages/debian/debian/preinst @@ -0,0 +1,31 @@ +#! /bin/sh +# preinst script for n2n +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `install' +# * `install' +# * `upgrade' +# * `abort-upgrade' + +case "$1" in + install|upgrade) + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 0 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + + +exit 0 diff --git a/packages/debian/debian/prerm b/packages/debian/debian/prerm new file mode 100755 index 0000000..9e4e53d --- /dev/null +++ b/packages/debian/debian/prerm @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +if [ -f /.dockerenv ]; then exit 0; fi + +. /usr/share/debconf/confmodule + +if [ "$1" = "remove" ]; then + deb-systemd-invoke stop edge.service 'edge@*.service' 'edge-ntopng@*.service' + deb-systemd-invoke disable edge.service 'edge@*.service' 'edge-ntopng@*.service' + deb-systemd-invoke stop supernode.service + deb-systemd-invoke disable supernode.service + systemctl daemon-reload + systemctl reset-failed +fi + +exit 0 diff --git a/packages/debian/debian/rules.in b/packages/debian/debian/rules.in new file mode 100755 index 0000000..4e879b9 --- /dev/null +++ b/packages/debian/debian/rules.in @@ -0,0 +1,59 @@ +#!/usr/bin/make -f + +# Uncomment this to turn on verbose mode. +# export DH_VERBOSE=1 + +# +# debian/compat +# We should use at least compatibility version 5 +# but this requires the whole building process +# to be remade and this is something we leave +# to when we will have more time +# http://www.tin.org/bin/man.cgi?section=7&topic=debhelper +# + +package=@APP@ + +build: build-stamp +build-stamp: + dh_testdir + +clean: + dh_testdir + dh_testroot + dh_clean + +install: build + dh_testdir + dh_testroot + dh_prep + dh_installdirs + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_prep + dh_installdirs + dh_installinit + dh_installdebconf + dh_installman + dh_strip + dh_compress + dh_fixperms + dh_installdeb + cp -r n2n debian + cp -r ../etc debian/n2n + find debian/n2n -name "*.in" -exec /bin/rm {} ';' + find debian/n2n -name "*~" -exec /bin/rm {} ';' + dh_link + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/packages/debian/debian/templates b/packages/debian/debian/templates new file mode 100644 index 0000000..4f35407 --- /dev/null +++ b/packages/debian/debian/templates @@ -0,0 +1,7 @@ +Template: n2n/license_expired_continue_installation +Type: boolean +Default: true +Description: Do you want to continue with the installation? + License found is not valid for the new package that is going to be installed. + . + Renew the maintenance to get a valid license for the new package or cancel the installation to continue using the current package. diff --git a/packages/etc/n2n/edge.conf.sample b/packages/etc/n2n/edge.conf.sample new file mode 100644 index 0000000..74d50a8 --- /dev/null +++ b/packages/etc/n2n/edge.conf.sample @@ -0,0 +1,41 @@ +# +# The configuration file is similar to the command line, with one option per line. An equal +# sign '=' should be used between key and value. Example: -c=mynetwork or --community=mynetwork +# This file contains a basic configuration example, please refer to the help (-h) for the full +# list of available options. +# +# -d|--tun-device +# Specifies the name of the TUN interface. +# +-d=n2n0 +# +# -c|--community +# Specifies the n2n community name the edge belongs to. +# +-c=mynetwork +# +# -k +# Sets the encryption key (ASCII). The environment variable N2N_KEY= can also be used. +# +-k=mypassword +# +# -m +# Specified the MAC address for the TAP interface (random otherwise). +# +# -m=DE:AD:BE:EF:99:99 +# +# -a +# Sets the interface address. For DHCP use '-r -a dhcp:0.0.0.0'. +# +-a=1.2.3.4 +# +# -p +# Sets the local UDP port to a fixed port. +# +-p=50001 +# +# -l|--supernode-list +# Specifies the supernode IP and port. +# +-l=7.8.9.0:7777 +# diff --git a/packages/etc/n2n/supernode.conf.sample b/packages/etc/n2n/supernode.conf.sample new file mode 100644 index 0000000..3575794 --- /dev/null +++ b/packages/etc/n2n/supernode.conf.sample @@ -0,0 +1,15 @@ +# +# The configuration file is similar to the command line, with one option per line. An equal +# sign '=' should be used between key and value. Example: -p=7777 +# This file contains a basic configuration example, please refer to the help (-h) for the full +# list of available options. +# +# -p +# Sets the UDP listening port. +# +-p=7777 +# +# -c +# Optionally specifies the allowed communities as listed in community.list file. +# +# -c=community.list diff --git a/packages/etc/systemd/system/edge-ntopng@.service.in b/packages/etc/systemd/system/edge-ntopng@.service.in new file mode 100644 index 0000000..5299d22 --- /dev/null +++ b/packages/etc/systemd/system/edge-ntopng@.service.in @@ -0,0 +1,16 @@ +[Unit] +Description=n2n edge process, on %I +After=network-online.target syslog.target +Wants=network-online.target +BindsTo=ntopng.service + +[Service] +Type=simple +ExecStartPre= +ExecStart=/usr/sbin/edge /etc/n2n/edge-%i.conf -f +Restart=on-abnormal +RestartSec=5 + +[Install] +WantedBy=ntopng.service +Alias= diff --git a/packages/etc/systemd/system/edge.service.in b/packages/etc/systemd/system/edge.service.in new file mode 100644 index 0000000..32f0d79 --- /dev/null +++ b/packages/etc/systemd/system/edge.service.in @@ -0,0 +1,15 @@ +[Unit] +Description=n2n edge process +After=network-online.target syslog.target nfw.target +Wants=network-online.target + +[Service] +Type=simple +ExecStartPre= +ExecStart=/usr/sbin/edge /etc/n2n/edge.conf -f +Restart=on-abnormal +RestartSec=5 + +[Install] +WantedBy=multi-user.target +Alias= diff --git a/packages/etc/systemd/system/edge@.service.in b/packages/etc/systemd/system/edge@.service.in new file mode 100644 index 0000000..d912345 --- /dev/null +++ b/packages/etc/systemd/system/edge@.service.in @@ -0,0 +1,15 @@ +[Unit] +Description=n2n edge process, on %I +After=network-online.target syslog.target nfw.target +Wants=network-online.target + +[Service] +Type=simple +ExecStartPre= +ExecStart=/usr/sbin/edge /etc/n2n/edge-%i.conf -f +Restart=on-abnormal +RestartSec=5 + +[Install] +WantedBy=multi-user.target +Alias= diff --git a/packages/etc/systemd/system/supernode.service.in b/packages/etc/systemd/system/supernode.service.in new file mode 100644 index 0000000..73e3d75 --- /dev/null +++ b/packages/etc/systemd/system/supernode.service.in @@ -0,0 +1,16 @@ +[Unit] +Description=n2n supernode process +After=network-online.target syslog.target +Wants=network-online.target + +[Service] +Type=simple +User=n2n +Group=n2n +ExecStart=/usr/sbin/supernode /etc/n2n/supernode.conf -f +Restart=on-abnormal +RestartSec=5 + +[Install] +WantedBy=multi-user.target +Alias= diff --git a/packages/openwrt/Makefile b/packages/openwrt/Makefile new file mode 100644 index 0000000..ce40d1c --- /dev/null +++ b/packages/openwrt/Makefile @@ -0,0 +1,100 @@ +# +# Copyright (C) 2021 - ntop.org and contributors +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=n2n +PKG_VERSION:=HEAD +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz + +# These are defaults for compiling without any environmental overrides +# (eg, the github action calculates the correct overrides for each build) +PKG_SOURCE_URL:=https://github.com/ntop/n2n +PKG_SOURCE_VERSION:=dev +PKG_MIRROR_HASH:=skip + +# Apply overrides from the build environment +ifdef N2N_PKG_SOURCE_URL + PKG_SOURCE_URL:=$(N2N_PKG_SOURCE_URL) +endif +ifdef N2N_PKG_SOURCE_VERSION + PKG_SOURCE_VERSION:=$(N2N_PKG_SOURCE_VERSION) +endif +ifdef N2N_PKG_VERSION + PKG_VERSION:=$(N2N_PKG_VERSION) +endif + +PKG_MAINTAINER:=Emanuele Faranda +PKG_LICENSE:=GPL3 + +# autogen fix +PKG_FIXUP:=autoreconf + +include $(INCLUDE_DIR)/package.mk + +define Package/n2n/Default + SECTION:=net + CATEGORY:=Network + TITLE:=N2N Peer-to-peer VPN + URL:=http://www.ntop.org/n2n + SUBMENU:=VPN + DEPENDS+=+libcap +endef + +define Package/n2n-edge + $(call Package/n2n/Default) + TITLE+= client (edge node) + DEPENDS+=+kmod-tun +endef + +define Package/n2n-supernode + $(call Package/n2n/Default) + TITLE+= server (supernode) +endef + +define Package/n2n-edge/description +The client node for the N2N infrastructure +endef + +define Package/n2n-supernode/description +The supernode for the N2N infrastructure +endef + +define Build/Configure + ( cd $(PKG_BUILD_DIR); \ + ./autogen.sh; \ + ./configure ) +endef + +define Package/n2n-edge/conffiles +/etc/n2n/edge.conf +endef + +define Package/n2n-edge/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/edge $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) $(PKG_BUILD_DIR)/packages/openwrt/etc/init.d/edge $(1)/etc/init.d/edge + $(INSTALL_DIR) $(1)/etc/n2n + $(INSTALL_CONF) $(PKG_BUILD_DIR)/packages/etc/n2n/edge.conf.sample $(1)/etc/n2n/edge.conf +endef + +define Package/n2n-supernode/conffiles +/etc/n2n/supernode.conf +endef + +define Package/n2n-supernode/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/supernode $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) $(PKG_BUILD_DIR)/packages/openwrt/etc/init.d/supernode $(1)/etc/init.d/supernode + $(INSTALL_DIR) $(1)/etc/n2n + $(INSTALL_CONF) $(PKG_BUILD_DIR)/packages/etc/n2n/supernode.conf.sample $(1)/etc/n2n/supernode.conf +endef + +$(eval $(call BuildPackage,n2n-edge)) +$(eval $(call BuildPackage,n2n-supernode)) diff --git a/packages/openwrt/README.md b/packages/openwrt/README.md new file mode 100644 index 0000000..65eac51 --- /dev/null +++ b/packages/openwrt/README.md @@ -0,0 +1,62 @@ +## Prerequisites + +This instructions explain how to build an OpenWRT .ipk package for n2n. + +You will either need to build a full OpenWRT buildchain (See the github +action for building openwrt.yml for some example steps) or have a working +cross-compiling build environment for the OpenWRT version installed into +your device. + +### Downloading a cross-compiling build environment + +This usually comes down to the following steps: + +1. Download and extract the SDK toolchain for your device. The toolchain + must match the *exact* OpenWRT version installed in your device. Toolchain + for official OpenWRT images can be downloaded from https://downloads.openwrt.org + +2. Build the toolchain: run `make menuconfig`, save the configuration, then + run `make` to build the cross compiling tools + +3. Download the feeds with `./scripts/feeds update -a` + +## Compilation + +These instructions are for building the current checked out version of the +n2n source (The generally used OpenWRT alternative is to download a tar.gz +file of a specific n2n version, but that is not as suitable for development +or local builds) + +You need both the openwrt repository and the n2n repository checked out +for this. In these instructions, we assume that `openwrt` is the directory +where your openwrt checkout is located and `n2n` is the directory for +the n2n repository. + +``` +git clone https://github.com/ntop/n2n n2n +N2N_PKG_VERSION=$(n2n/scripts/version.sh) +export N2N_PKG_VERSION + +cp -r n2n/packages/openwrt openwrt/package/n2n + +cd openwrt +make menuconfig # select Network -> VPN -> n2n-edge and n2n-supernode +make package/n2n/clean V=s +make package/n2n/prepare USE_SOURCE_DIR=../n2n V=s +make package/n2n/compile V=s +``` + +If everything went fine, two ipk will be generated, one for the n2n-edge +and the other for n2n-supernode. They can be found with `find . -name "n2n*.ipk"`, +copied to the target device, and installed with `opkg install`. + +The github action described in `.github/workflows/openwrt.yml` implements +an automated version of the above steps. + +## Configuration + +The edge node can be started with `/etc/init.d/edge start`. +Its configuration file is `/etc/n2n/edge.conf`. + +The supernode can be started with `/etc/init.d/supernode start`. +Its configuration file is `/etc/n2n/supernode.conf`. diff --git a/packages/openwrt/etc/init.d/edge b/packages/openwrt/etc/init.d/edge new file mode 100644 index 0000000..84e2b57 --- /dev/null +++ b/packages/openwrt/etc/init.d/edge @@ -0,0 +1,25 @@ +#!/bin/sh /etc/rc.common +START=90 +STOP=10 + +USE_PROCD=1 +PROG=/usr/bin/edge +CONFIGFILE=/etc/n2n/edge.conf + +start_service() { + procd_open_instance + procd_set_param command $PROG $CONFIGFILE + procd_set_param file $CONFIGFILE + procd_set_param respawn + procd_close_instance +} + +stop_service() +{ + service_stop $PROG +} + +service_triggers() +{ + procd_add_reload_trigger "edge" +} diff --git a/packages/openwrt/etc/init.d/supernode b/packages/openwrt/etc/init.d/supernode new file mode 100644 index 0000000..56aa81d --- /dev/null +++ b/packages/openwrt/etc/init.d/supernode @@ -0,0 +1,25 @@ +#!/bin/sh /etc/rc.common +START=90 +STOP=10 + +USE_PROCD=1 +PROG=/usr/bin/supernode +CONFIGFILE=/etc/n2n/supernode.conf + +start_service() { + procd_open_instance + procd_set_param command $PROG $CONFIGFILE + procd_set_param file $CONFIGFILE + procd_set_param respawn + procd_close_instance +} + +stop_service() +{ + service_stop $PROG +} + +service_triggers() +{ + procd_add_reload_trigger "supernode" +} diff --git a/packages/rpm/Makefile.in b/packages/rpm/Makefile.in new file mode 100644 index 0000000..a37c3d1 --- /dev/null +++ b/packages/rpm/Makefile.in @@ -0,0 +1,26 @@ +# +# Change it according to your setup +# +N2N_HOME=$(PWD)/../.. +N2N_BUILD=${N2N_HOME}/packages/debian/n2n +PLATFORM=@MACHINE@ +RPM_PKG=n2n-@N2N_VERSION_RPM@-1.$(PLATFORM).rpm + +all: clean pkg + +pkg: + rpmbuild -bb ./n2n.spec + -@@RPM_SIGN_CMD@ $(HOME)/rpmbuild/RPMS/$(PLATFORM)/$(RPM_PKG) + @echo "" + @echo "Package contents:" + @rpm -qpl $(HOME)/rpmbuild/RPMS/$(PLATFORM)/$(RPM_PKG) + @echo "The package is now available in $(HOME)/rpmbuild/RPMS/$(PLATFORM)/$(RPM_PKG)" + +distclean: + echo "dummy distclean" + +install: + echo "dummy install" + +clean: + rm -rf *~ *rpm diff --git a/packages/rpm/configure b/packages/rpm/configure new file mode 100755 index 0000000..dc8a37d --- /dev/null +++ b/packages/rpm/configure @@ -0,0 +1,2901 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for Makefile.in 1.0. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='Makefile.in' +PACKAGE_TARNAME='makefile-in' +PACKAGE_VERSION='1.0' +PACKAGE_STRING='Makefile.in 1.0' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_subst_vars='LTLIBOBJS +LIBOBJS +RPM_SIGN_CMD +DATE +EXTN +N2N_VERSION_RPM +MACHINE +APP +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +' + ac_precious_vars='build_alias +host_alias +target_alias' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures Makefile.in 1.0 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/makefile-in] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of Makefile.in 1.0:";; + esac + cat <<\_ACEOF + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +Makefile.in configure 1.0 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by Makefile.in $as_me 1.0, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# NOTE: this file is not actually used. You need to edit configure as well! +N2N_VERSION_RPM=$(../../scripts/version.sh |tr - _) + +MACHINE=`uname -m` +SHORT_MACHINE=`uname -m | cut -b1-3` + +if test $MACHINE = "x86_64"; then + EXTN="amd64" +else + if test $SHORT_MACHINE = "aar"; then + EXTN="arm64" + EXTRA_DEPS="" + else + if test $SHORT_MACHINE = "arm"; then + EXTN="armhf" + EXTRA_DEPS="" + else + if test $SHORT_MACHINE = "mip"; then + EXTN="mips" + EXTRA_DEPS="" + else + EXTN="i386" + fi + fi + fi +fi + +APP=n2n +DATE=`date -R` + +CENTOS_RELEASE=`cat /etc/centos-release | cut -d ' ' -f 3|cut -d '.' -f 1` +if test $CENTOS_RELEASE = "release"; then + CENTOS_RELEASE=`cat /etc/centos-release | cut -d ' ' -f 4|cut -d '.' -f 1` +fi + +RPM_SIGN_CMD="rpm --addsign" +if test "$CENTOS_RELEASE" -ne 8; then + RPM_SIGN_CMD="./rpm-sign.exp" +fi + + + + + + + + +ac_config_files="$ac_config_files n2n.spec" + +ac_config_files="$ac_config_files ../etc/systemd/system/edge.service" + +ac_config_files="$ac_config_files ../etc/systemd/system/edge@.service" + +ac_config_files="$ac_config_files ../etc/systemd/system/edge-ntopng@.service" + +ac_config_files="$ac_config_files ../etc/systemd/system/supernode.service" + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by Makefile.in $as_me 1.0, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +Makefile.in config.status 1.0 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "n2n.spec") CONFIG_FILES="$CONFIG_FILES n2n.spec" ;; + "../etc/systemd/system/edge.service") CONFIG_FILES="$CONFIG_FILES ../etc/systemd/system/edge.service" ;; + "../etc/systemd/system/edge@.service") CONFIG_FILES="$CONFIG_FILES ../etc/systemd/system/edge@.service" ;; + "../etc/systemd/system/edge-ntopng@.service") CONFIG_FILES="$CONFIG_FILES ../etc/systemd/system/edge-ntopng@.service" ;; + "../etc/systemd/system/supernode.service") CONFIG_FILES="$CONFIG_FILES ../etc/systemd/system/supernode.service" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/packages/rpm/configure.in b/packages/rpm/configure.in new file mode 100644 index 0000000..e65d3c0 --- /dev/null +++ b/packages/rpm/configure.in @@ -0,0 +1,56 @@ +AC_INIT([Makefile.in], 1.0) + +# NOTE: this file is not actually used. You need to edit configure as well! +N2N_VERSION_RPM=$(../../scripts/version.sh |tr - _) + +MACHINE=`uname -m` +SHORT_MACHINE=`uname -m | cut -b1-3` + +if test $MACHINE = "x86_64"; then + EXTN="amd64" +else + if test $SHORT_MACHINE = "aar"; then + EXTN="arm64" + EXTRA_DEPS="" + else + if test $SHORT_MACHINE = "arm"; then + EXTN="armhf" + EXTRA_DEPS="" + else + if test $SHORT_MACHINE = "mip"; then + EXTN="mips" + EXTRA_DEPS="" + else + EXTN="i386" + fi + fi + fi +fi + +APP=n2n +DATE=`date -R` + +CENTOS_RELEASE=`cat /etc/centos-release | cut -d ' ' -f 3|cut -d '.' -f 1` +if test $CENTOS_RELEASE = "release"; then + CENTOS_RELEASE=`cat /etc/centos-release | cut -d ' ' -f 4|cut -d '.' -f 1` +fi + +RPM_SIGN_CMD="rpm --addsign" +if test "$CENTOS_RELEASE" -ne 8; then + RPM_SIGN_CMD="./rpm-sign.exp" +fi + +AC_SUBST(APP) +AC_SUBST(MACHINE) +AC_SUBST(N2N_VERSION_RPM) +AC_SUBST(EXTN) +AC_SUBST(DATE) +AC_SUBST(RPM_SIGN_CMD) + +AC_CONFIG_FILES(n2n.spec) +AC_CONFIG_FILES(../etc/systemd/system/edge.service) +AC_CONFIG_FILES(../etc/systemd/system/edge@.service) +AC_CONFIG_FILES(../etc/systemd/system/edge-ntopng@.service) +AC_CONFIG_FILES(../etc/systemd/system/supernode.service) +AC_CONFIG_FILES(Makefile) +AC_OUTPUT diff --git a/packages/rpm/n2n.spec.in b/packages/rpm/n2n.spec.in new file mode 100644 index 0000000..7f4b847 --- /dev/null +++ b/packages/rpm/n2n.spec.in @@ -0,0 +1,107 @@ +Summary: n2n peer-to-peer VPN +Name: n2n +Version: @N2N_VERSION_RPM@ +Release: 1 +License: GPL +Group: Networking/Utilities +URL: http://www.ntop.org/ +Source: n2n-%{version}.tgz +Packager: Luca Deri +# Temporary location where the RPM will be built +BuildRoot: %{_tmppath}/%{name}-%{version}-root +Requires: libzstd + +# Make sure .build-id is not part of the package +%define _build_id_links none + +%description +n2n peer-to-peer VPN + +%prep + +%build + +mkdir -p $RPM_BUILD_ROOT/usr/sbin $RPM_BUILD_ROOT/usr/share/man/man1 $RPM_BUILD_ROOT/usr/share/man/man7 $RPM_BUILD_ROOT/usr/share/man/man8 +mkdir -p $RPM_BUILD_ROOT/etc/n2n +mkdir -p $RPM_BUILD_ROOT/usr/lib/systemd/system/ +cp $HOME/n2n/edge $RPM_BUILD_ROOT/usr/sbin +cp $HOME/n2n/supernode $RPM_BUILD_ROOT/usr/sbin +cp $HOME/n2n/n2n.7.gz $RPM_BUILD_ROOT/usr/share/man/man7 +cp $HOME/n2n/supernode.1.gz $RPM_BUILD_ROOT/usr/share/man/man1 +cp $HOME/n2n/edge.8.gz $RPM_BUILD_ROOT/usr/share/man/man8 +cp $HOME/n2n/packages/etc/systemd/system/*.service $RPM_BUILD_ROOT/usr/lib/systemd/system/ +cp $HOME/n2n/packages/etc/n2n/*.conf.sample $RPM_BUILD_ROOT/etc/n2n + +find $RPM_BUILD_ROOT -name ".git" | xargs /bin/rm -rf +find $RPM_BUILD_ROOT -name ".svn" | xargs /bin/rm -rf +find $RPM_BUILD_ROOT -name "*~" | xargs /bin/rm -f +# +DST=$RPM_BUILD_ROOT/usr/n2n +SRC=$RPM_BUILD_DIR/%{name}-%{version} +#mkdir -p $DST/conf +# Clean out our build directory +%clean +rm -fr $RPM_BUILD_ROOT + +%files +/usr/sbin/edge +/usr/sbin/supernode +/usr/share/man/man7/n2n.7.gz +/usr/share/man/man1/supernode.1.gz +/usr/share/man/man8/edge.8.gz +/usr/lib/systemd/system/edge.service +/usr/lib/systemd/system/edge@.service +/usr/lib/systemd/system/edge-ntopng@.service +/usr/lib/systemd/system/supernode.service +%config(noreplace) /etc/n2n/supernode.conf.sample +%config(noreplace) /etc/n2n/edge.conf.sample + +# Set the default attributes of all of the files specified to have an +# owner and group of root and to inherit the permissions of the file +# itself. +%defattr(-, root, root) + +%changelog +* Fri Aug 17 2018 Luca Deri 1.0 +- Current package version + +# Execution order: +# install: pre -> (copy) -> post +# upgrade: pre -> (copy) -> post -> preun (old) -> (delete old) -> postun (old) +# un-install: preun -> (delete) -> postun + +%pre + +if ! grep -q n2n /etc/group; then + echo 'Creating n2n group' + /usr/sbin/groupadd -r n2n +fi + +if ! /usr/bin/id -u n2n > /dev/null 2>&1; then + echo 'Creating n2n user' + /usr/sbin/useradd -M -N -g n2n -r -s /bin/false n2n +fi + +%post +if [ -f /bin/systemctl ]; then + if [ ! -f /.dockerenv ]; then + /bin/systemctl daemon-reload + # NOTE: do not enable any services during first installation + fi +fi + +%preun +if [ -f /bin/systemctl ]; then + if [ ! -f /.dockerenv ]; then + # possibly remove the installed services + %systemd_preun supernode.service edge.service 'edge-ntopng@*.service' 'edge@*.service' + fi +fi + +%postun +if [ -f /bin/systemctl ]; then + if [ ! -f /.dockerenv ]; then + # possibly restart the running services + %systemd_postun_with_restart supernode.service edge.service 'edge-ntopng@*.service' 'edge@*.service' + fi +fi diff --git a/packages/rpm/rpm-sign.exp b/packages/rpm/rpm-sign.exp new file mode 100755 index 0000000..7a0f88a --- /dev/null +++ b/packages/rpm/rpm-sign.exp @@ -0,0 +1,10 @@ +#!/usr/bin/expect -f + +### rpm-sign.exp -- Sign RPMs by sending the passphrase. + +spawn rpm --addsign {*}$argv + expect -exact "Enter pass phrase: " + send -- "\r" + expect eof + +## end of rpm-sign.exp diff --git a/packages/ubuntu b/packages/ubuntu new file mode 120000 index 0000000..b2f7fd3 --- /dev/null +++ b/packages/ubuntu @@ -0,0 +1 @@ +debian \ No newline at end of file diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..380fa3c --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,9 @@ +This directory contains executables that are not compiled. Some of these may +end up installed for use by end users, but many of them are for use during +development, builds and tests. + +Nothing in this directory should need compiling to use and they should be +written such that they do not need configuring (e.g: they might probe several +directories for their requirements) + +See the [Scripts Documentation](../docs/Scripts.md) for further details diff --git a/scripts/cmake_all.sh b/scripts/cmake_all.sh new file mode 100755 index 0000000..74c605b --- /dev/null +++ b/scripts/cmake_all.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# +# Well, cmake might be approximately the same as ./configure && make, but it +# never rolls off the fingers as easily +# + +if [ ! -f CMakeLists.txt ]; then + echo ERROR: run this script from the TOPDIR + exit 1 +fi + +OPTS="" +#OPTS+=" -DN2N_OPTION_USE_PTHREAD=ON" +#OPTS+=" -DN2N_OPTION_USE_OPENSSL=ON" +#OPTS+=" -DN2N_OPTION_USE_CAPLIB=ON" +#OPTS+=" -DN2N_OPTION_USE_PCAPLIB=ON" +#OPTS+=" -DN2N_OPTION_USE_ZSTD=ON" +#OPTS+=" -DN2N_OPTION_USE_PORTMAPPING=ON" + +#OPTS+=" -DOPENSSL_USE_STATIC_LIBS=true" + +set -e + +rm -rf build + +cmake -E make_directory build +cd build + +# Shell check wants me to use an array in this scenario. Bourne shell +# arrays are my line in the sand showing that a script should not be +# written in such a horrible language. Since it would be silly to rewrite +# a one-page wrapper script in python, we submit that this check is wrong. +# shellcheck disable=SC2086 +cmake .. $OPTS + +cmake --build . --config Release + +ctest diff --git a/scripts/hack_fakeautoconf.sh b/scripts/hack_fakeautoconf.sh new file mode 100755 index 0000000..a7f9203 --- /dev/null +++ b/scripts/hack_fakeautoconf.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# +# Specifically for windows, where installing autoconf looks suspiciously +# like boiling the ocean. + +sed \ + -e "s%@CC@%gcc%g" \ + -e "s%@AR@%ar%g" \ + -e "s%@CFLAGS@%$CFLAGS%g" \ + -e "s%@LDFLAGS@%$LDFLAGS%g" \ + -e "s%@N2N_LIBS@%$LDLIBS%g" \ + < Makefile.in > Makefile + +sed \ + -e "s%@ADDITIONAL_TOOLS@%%g" \ + < tools/Makefile.in > tools/Makefile + +cat <include/config.h +#define PACKAGE_VERSION "FIXME" +#define PACKAGE_OSNAME "FIXME" +EOF diff --git a/scripts/indent.sh b/scripts/indent.sh new file mode 100755 index 0000000..90d977a --- /dev/null +++ b/scripts/indent.sh @@ -0,0 +1,61 @@ +#!/bin/sh +# +# Given one or more input source files, run a re-indenter on them. + +help() { + echo "Usage: scripts/indent [-i] [file...]" + echo " -i modify file in place with reindent results" + echo "" + echo "By default, will output a diff and exitcode if changed are needed" + echo "If modifying files, no exit code or diff is output" + exit 1 +} + +[ -z "$1" ] && help +[ "$1" = "-h" ] && help +[ "$1" = "--help" ] && help + +INPLACE=0 +if [ "$1" = "-i" ]; then + shift + INPLACE=1 +fi + +## indentOneClang() { +## rm -f "$1.indent" +## clang-format "$1" >"$1.indent" +## if [ $? -ne 0 ]; then +## echo "Error while formatting \"$1\"" +## RESULT=1 +## return +## fi +## diff -u "$1" "$1.indent" +## if [ $? -ne 0 ]; then +## RESULT=1 +## fi +## } + +indentOne() { + IFILE="$1" + if [ "$INPLACE" -eq 0 ]; then + OFILE="$1.indent" + rm -f "$OFILE" + else + OFILE="$1" + fi + if ! uncrustify -c uncrustify.cfg -f "$IFILE" -o "$OFILE"; then + echo "Error while formatting \"$1\"" + RESULT=1 + return + fi + if ! diff -u "$IFILE" "$OFILE"; then + RESULT=1 + fi +} + +RESULT=0 +while [ -n "$1" ]; do + indentOne "$1" + shift +done +exit $RESULT diff --git a/scripts/mk_SRPM.sh b/scripts/mk_SRPM.sh deleted file mode 100755 index 2b1b374..0000000 --- a/scripts/mk_SRPM.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# This script makes a SRPM - a source RPM file which can be built into the -# appropriate distro specific RPM for any platform. -# -# To build the binary package: -# rpm -i n2n-.src.rpm -# rpmbuild -bb n2n.spec -# -# Look for the "Wrote:" line to see where the final RPM is. -# -# To run this script cd to the n2n directory and run it as follows -# scripts/mk_SRPMS.sh -# - -set -e - -set -x - -BASE=`pwd` - -TARFILE=`${BASE}/scripts/mk_tar.sh` - -test -f ${TARFILE} - -echo "Building SRPM" -# -ts means build source RPM from tarfile -rpmbuild -ts ${TARFILE} - -echo "Done" diff --git a/scripts/mk_deb.sh b/scripts/mk_deb.sh deleted file mode 100755 index 42d8691..0000000 --- a/scripts/mk_deb.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# This script makes a SRPM - a source RPM file which can be built into the -# appropriate distro specific RPM for any platform. -# -# To build the binary package: -# rpm -i n2n-.src.rpm -# rpmbuild -bb n2n.spec -# -# Look for the "Wrote:" line to see where the final RPM is. -# -# To run this script cd to the n2n directory and run it as follows -# scripts/mk_SRPMS.sh -# - -set -e - -set -x - -BASE=`pwd` - -TARFILE=`${BASE}/scripts/mk_tar.sh` -TEMPDIR="build_deb" - -test -f ${TARFILE} - -echo "Building .deb" - -if [ -d ${TEMPDIR} ]; then - echo "Removing ${TEMPDIR} directory" - rm -rf ${TEMPDIR} >&2 -fi - -mkdir ${TEMPDIR} - -pushd ${TEMPDIR} - -tar xzf ${TARFILE} #At original location - -cd n2n* - -dpkg-buildpackage -rfakeroot - -popd - -echo "Done" diff --git a/scripts/mk_tar.sh b/scripts/mk_tar.sh deleted file mode 100755 index 539a565..0000000 --- a/scripts/mk_tar.sh +++ /dev/null @@ -1,104 +0,0 @@ -#!/bin/bash - -# This script makes a SRPM - a source RPM file which can be built into the -# appropriate distro specific RPM for any platform. -# -# To build the binary package: -# rpm -i n2n-.src.rpm -# rpmbuild -bb n2n.spec -# -# Look for the "Wrote:" line to see where the final RPM is. -# -# To run this script cd to the n2n directory and run it as follows -# scripts/mk_SRPMS.sh -# - -set -e - -function exit_fail() -{ - echo "$1" - exit 1 -} - -PACKAGE="n2n" -PKG_VERSION="1.3" -PKG_AND_VERSION="${PACKAGE}-${PKG_VERSION}" - -TEMPDIR="tmp" - -SOURCE_MANIFEST=" -README -edge.c -lzoconf.h -lzodefs.h -Makefile -minilzo.c -minilzo.h -n2n.c -n2n.h -n2n.spec -supernode.c -tuntap_linux.c -tuntap_freebsd.c -tuntap_osx.c -twofish.c -twofish.h -edge.8 -supernode.1 -debian/changelog -debian/compat -debian/control -debian/copyright -debian/n2n.dirs -debian/n2n.docs -debian/n2n.install -debian/n2n.manpages -debian/README.Debian -debian/rules -" - -BASE=`pwd` - -for F in ${SOURCE_MANIFEST}; do - test -e $F || exit_fail "Cannot find $F. Maybe you're in the wrong directory. Please execute from n2n directory."; >&2 -done - -echo "Found critical files. Proceeding." >&2 - -if [ -d ${TEMPDIR} ]; then - echo "Removing ${TEMPDIR} directory" - rm -rf ${TEMPDIR} >&2 -fi - -mkdir ${TEMPDIR} >&2 - -pushd ${TEMPDIR} >&2 - -echo "Creating staging directory ${PWD}/${PKG_AND_VERSION}" >&2 - -if [ -d ${PKG_AND_VERSION} ] ; then - echo "Removing ${PKG_AND_VERSION} directory" - rm -rf ${PKG_AND_VERSION} >&2 -fi - -mkdir ${PKG_AND_VERSION} - -pushd ${BASE} >&2 - -echo "Copying in files" >&2 -for F in ${SOURCE_MANIFEST}; do - cp --parents -a $F ${TEMPDIR}/${PKG_AND_VERSION}/ -done - -popd >&2 - -TARFILE="${PKG_AND_VERSION}.tar.gz" -echo "Creating ${TARFILE}" >&2 -tar czf ${BASE}/${TARFILE} ${PKG_AND_VERSION} - -popd >&2 - -rm -rf ${TEMPDIR} >&2 - -echo ${BASE}/${TARFILE} diff --git a/scripts/munin/n2n_ b/scripts/munin/n2n_ new file mode 100755 index 0000000..fe8efd8 --- /dev/null +++ b/scripts/munin/n2n_ @@ -0,0 +1,324 @@ +#!/usr/bin/env perl +use warnings; +use strict; +# +# Requires +# libjson-perl +# + +# Magic Markers +# +#%# family=auto +#%# capabilities=autoconf suggest + +package JsonUDP; +use warnings; +use strict; + +use IO::Socket::INET; +use JSON; + +sub new { + my $class = shift; + my $port = shift || 5644; + my $self = {}; + bless($self, $class); + + $self->{sock} = IO::Socket::INET->new( + PeerAddr => '127.0.0.1', + PeerPort => $port, + Proto => 'udp', + ); + $self->{json} = JSON->new->utf8->relaxed->pretty->canonical; + $self->{tag} = 0; + $self->{debug} = 0; + return $self; +} + +sub _tx { + my $self = shift; + my $msgline = shift; + return $self->{sock}->send($msgline); +} + +sub _rx { + my $self = shift; + my $tag = shift; + + my $db = []; + my $error; + + while(1) { + my $jsontxt; + $self->{sock}->recv($jsontxt,1024); + if ($self->{debug}) { + print($jsontxt); + } + my $msg = $self->{json}->decode($jsontxt); + + # ignore packets not for us + if ($msg->{_tag} ne $tag) { + next; + } + + # Save most recent error for return + if ($msg->{_type} eq 'error') { + $error = $msg; + next; + } + + if ($msg->{_type} eq 'end') { + if ($error) { + # TODO: an error channel + return undef; + } + return $db; + } + + if ($msg->{_type} eq 'row') { + delete $msg->{_tag}; + delete $msg->{_type}; + push @$db, $msg; + next; + } + + # Ignore any unknown _type + } +} + +sub read { + my $self = shift; + my $cmdline = shift; + my $tag = $self->{tag}++; + + # TODO: + # Add a read cache + + $self->_tx(sprintf("r %i %s", $tag, $cmdline)); + return $self->_rx($tag); +} + +1; + +package main; +use warnings; +use strict; + +my $config = { + edge_pkts => { + p2p_tx_pkt => { + label => 'Peer to Peer tx rate', + type => 'DERIVE', + min => 0, + }, + p2p_rx_pkt => { + label => 'Peer to Peer rx rate', + type => 'DERIVE', + min => 0, + }, + super_tx_pkt => { + label => 'Peer to Supernode tx rate', + type => 'DERIVE', + min => 0, + }, + super_rx_pkt => { + label => 'Peer to Supernode rx rate', + type => 'DERIVE', + min => 0, + }, + super_broadcast_tx_pkt => { + label => 'Broadcast to Supernode tx rate', + type => 'DERIVE', + min => 0, + }, + super_broadcast_rx_pkt => { + label => 'Broadcast to Supernode rx rate', + type => 'DERIVE', + min => 0, + }, + transop_tx_pkt => { + label => 'Transform tx rate', + type => 'DERIVE', + min => 0, + }, + transop_rx_pkt => { + label => 'Transform rx rate', + type => 'DERIVE', + min => 0, + }, + }, + edge_counts => { + edges => { + label => 'Current known peers', + type => 'GAUGE', + }, + supernodes => { + label => 'Current known supernodes', + type => 'GAUGE', + }, + }, + supernode_pkts => { + errors_tx_pkt => { + label => 'Error rate', + type => 'DERIVE', + min => 0, + }, + reg_super_rx_pkt => { + label => 'Connect rate', + type => 'DERIVE', + min => 0, + }, + reg_super_nak => { + label => 'Connect error rate', + type => 'DERIVE', + min => 0, + }, + forward_tx_pkt => { + label => 'Packets forwarded rate', + type => 'DERIVE', + min => 0, + }, + broadcast_tx_pkt => { + label => 'Broadcast packet rate', + type => 'DERIVE', + min => 0, + }, + }, + supernode_counts => { + edges => { + label => 'Current known edges', + type => 'GAUGE', + }, + communities => { + label => 'Current known communities', + type => 'GAUGE', + }, + }, +}; + +my $fetchinfo = { + edge_pkts => { + port => 5644, + read => "packetstats", + }, + edge_counts => { + port => 5644, + count => [ + "edges", + "supernodes", + ], + }, + supernode_pkts => { + port => 5645, + read => "packetstats", + }, + supernode_counts => { + port => 5645, + count => [ + "edges", + "communities", + ], + }, +}; + +sub do_config { + my $rpc = shift; + my $name = shift; + + print("graph_title n2n $name status\n"); + print("graph_category network\n"); + my @names; + while (my ($fieldname, $field) = each(%{$config->{$name}})) { + push @names, $fieldname; + while (my ($key, $val) = each(%{$field})) { + print($fieldname.'.'.$key," ",$val,"\n"); + } + } + + # Ensure stable order + print("graph_order ", join(' ', sort(@names)), "\n"); +} + +sub do_fetch { + my $rpc = shift; + my $name = shift; + my $db; + + my $read_table = $fetchinfo->{$name}->{read}; + if (defined($read_table)) { + $db = $rpc->read($read_table); + for my $row (@$db) { + my $type = $row->{type}; + delete $row->{type}; + while (my ($key, $val) = each(%{$row})) { + my $metricname = $type."_".$key; + print($metricname,".value ",$val,"\n"); + } + } + } + + my $count_tables = $fetchinfo->{$name}->{count}; + if (defined($count_tables)) { + for my $table (@{$count_tables}) { + $db = $rpc->read($table); + print($table,".value ", scalar(@$db), "\n"); + } + } +} + +sub do_autoconf { + # quick check to see if this plugin should be enabled + if (`pgrep supernode`) { + print("yes\n"); + } elsif (`pgrep edge`) { + print("yes\n"); + } else { + print("no - neither edge nor supernode are running\n"); + } +} + +sub do_suggest { + my $ports = {}; + if (`pgrep supernode`) { + $ports->{5645}=1; + } + if (`pgrep edge`) { + $ports->{5644}=1; + } + + while (my ($name, $info) = each(%{$fetchinfo})) { + my $port = $info->{port}; + next if (!defined($port)); # this not a real fetchinfo + next if (!defined($ports->{$port})); # not linked to a running daemon + print($name,"\n"); + } +} + +my $subc = { + 'fetch' => \&do_fetch, + 'config' => \&do_config, + 'autoconf' => \&do_autoconf, + 'suggest' => \&do_suggest, +}; + +sub main() { + my $name = $ARGV[1] || $0; + $name =~ s%^.*/n2n_([^/]+)%$1%; + + my $port = $fetchinfo->{$name}->{port}; + my $rpc = JsonUDP->new($port); + + my $cmd = $ARGV[0]; + if (!defined($cmd)) { + $cmd = 'fetch'; + } + + my $func = $subc->{$cmd}; + if (!defined($func)) { + die("bad sub command"); + } + + return $func->($rpc, $name); +} +main(); + diff --git a/scripts/n2n-ctl b/scripts/n2n-ctl new file mode 100755 index 0000000..84b48cb --- /dev/null +++ b/scripts/n2n-ctl @@ -0,0 +1,301 @@ +#!/usr/bin/env python3 +# Licensed under GPLv3 +# +# Simple script to query the management interface of a running n2n edge node + +import argparse +import socket +import json +import collections + + +class JsonUDP(): + """encapsulate communication with the edge""" + + def __init__(self, port): + self.address = "127.0.0.1" + self.port = port + self.tag = 0 + self.key = None + self.debug = False + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.sock.settimeout(1) + + def _next_tag(self): + tagstr = str(self.tag) + self.tag = (self.tag + 1) % 1000 + return tagstr + + def _cmdstr(self, msgtype, cmdline): + """Create the full command string to send""" + tagstr = self._next_tag() + + options = [tagstr] + if self.key is not None: + options += ['1'] # Flags set for auth key field + options += [self.key] + optionsstr = ':'.join(options) + + return tagstr, ' '.join((msgtype, optionsstr, cmdline)) + + def _rx(self, tagstr): + """Wait for rx packets""" + + seen_begin = False + while not seen_begin: + # TODO: there are no timeouts with any of the recv calls + data, _ = self.sock.recvfrom(1024) + data = json.loads(data.decode('utf8')) + + # TODO: We assume the first packet we get will be tagged for us + assert(data['_tag'] == tagstr) + + if data['_type'] == 'error': + raise ValueError('Error: {}'.format(data['error'])) + + if data['_type'] == 'replacing': + # a signal that we have evicted an earlier subscribe + continue + + if data['_type'] == 'subscribe': + return True + + if data['_type'] == 'begin': + seen_begin = True + + # Ideally, we would confirm that this is our "begin", but that + # would need the cmd passed into this method, and that would + # probably require parsing the cmdline passed to us :-( + # assert(data['cmd'] == cmd) + + continue + + raise ValueError('Unknown data type {} from ' + 'edge'.format(data['_type'])) + + result = list() + error = None + + while True: + data, _ = self.sock.recvfrom(1024) + data = json.loads(data.decode('utf8')) + + if data['_tag'] != tagstr: + # this packet is not for us, ignore it + continue + + if data['_type'] == 'error': + # we still expect an end packet, so save the error + error = ValueError('Error: {}'.format(data['error'])) + continue + + if data['_type'] == 'end': + if error: + raise error + return result + + if data['_type'] != 'row': + raise ValueError('Unknown data type {} from ' + 'edge'.format(data['_type'])) + + # remove our boring metadata + del data['_tag'] + del data['_type'] + + if self.debug: + print(data) + + result.append(data) + + def _call(self, msgtype, cmdline): + """Perform a rpc call""" + tagstr, msgstr = self._cmdstr(msgtype, cmdline) + self.sock.sendto(msgstr.encode('utf8'), (self.address, self.port)) + return self._rx(tagstr) + + def read(self, cmdline): + return self._call('r', cmdline) + + def write(self, cmdline): + return self._call('w', cmdline) + + def sub(self, cmdline): + return self._call('s', cmdline) + + def readevent(self): + self.sock.settimeout(3600) + + data, _ = self.sock.recvfrom(1024) + data = json.loads(data.decode('utf8')) + # assert(data['_tag'] == tagstr) + assert(data['_type'] == 'event') + + del data['_tag'] + del data['_type'] + return data + + +def str_table(rows, columns, orderby): + """Given an array of dicts, do a simple table print""" + result = list() + widths = collections.defaultdict(lambda: 0) + + if len(rows) == 0: + # No data to show, be sure not to truncate the column headings + for col in columns: + widths[col] = len(col) + else: + for row in rows: + for col in columns: + if col in row: + widths[col] = max(widths[col], len(str(row[col]))) + + for col in columns: + if widths[col] == 0: + widths[col] = 1 + result += "{:{}.{}} ".format(col, widths[col], widths[col]) + result += "\n" + + if orderby is not None: + rows = sorted(rows, key=lambda row: row.get(orderby, 0)) + + for row in rows: + for col in columns: + if col in row: + data = row[col] + else: + data = '' + result += "{:{}} ".format(data, widths[col]) + result += "\n" + + return ''.join(result) + + +def subcmd_show_supernodes(rpc, args): + rows = rpc.read('supernodes') + columns = [ + 'version', + 'current', + 'macaddr', + 'sockaddr', + 'uptime', + ] + + return str_table(rows, columns, args.orderby) + + +def subcmd_show_edges(rpc, args): + rows = rpc.read('edges') + columns = [ + 'mode', + 'ip4addr', + 'macaddr', + 'sockaddr', + 'desc', + ] + + return str_table(rows, columns, args.orderby) + + +def subcmd_show_help(rpc, args): + result = 'Commands with pretty-printed output:\n\n' + for name, cmd in subcmds.items(): + result += "{:12} {}\n".format(name, cmd['help']) + + result += "\n" + result += "Possble remote commands:\n" + result += "(those without a pretty-printer will pass-through)\n\n" + rows = rpc.read('help') + for row in rows: + result += "{:12} {}\n".format(row['cmd'], row['help']) + return result + + +subcmds = { + 'help': { + 'func': subcmd_show_help, + 'help': 'Show available commands', + }, + 'supernodes': { + 'func': subcmd_show_supernodes, + 'help': 'Show the list of supernodes', + }, + 'edges': { + 'func': subcmd_show_edges, + 'help': 'Show the list of edges/peers', + }, +} + + +def subcmd_default(rpc, args): + """Just pass command through to edge""" + cmdline = ' '.join([args.cmd] + args.args) + if args.write: + rows = rpc.write(cmdline) + elif args.read: + rows = rpc.read(cmdline) + elif args.sub: + if not rpc.sub(cmdline): + raise ValueError('Could not subscribe') + while True: + event = rpc.readevent() + # FIXME: violates layering.. + print(json.dumps(event, sort_keys=True, indent=4)) + else: + raise ValueError('Unknown request type') + return json.dumps(rows, sort_keys=True, indent=4) + + +def main(): + ap = argparse.ArgumentParser( + description='Query the running local n2n edge') + ap.add_argument('-t', '--mgmtport', action='store', default=5644, + help='Management Port (default=5644)', type=int) + ap.add_argument('-k', '--key', action='store', + help='Password for mgmt commands') + ap.add_argument('-d', '--debug', action='store_true', + help='Also show raw internal data') + ap.add_argument('--raw', action='store_true', + help='Force cmd to avoid any pretty printing') + ap.add_argument('--orderby', action='store', + help='Hint to a pretty printer on how to sort') + + group = ap.add_mutually_exclusive_group() + group.add_argument('--read', action='store_true', + help='Make a read request (default)') + group.add_argument('--write', action='store_true', + help='Make a write request (only to non pretty' + 'printed cmds)') + group.add_argument('--sub', action='store_true', + help='Make a subscribe request') + + ap.add_argument('cmd', action='store', + help='Command to run (try "help" for list)') + ap.add_argument('args', action='store', nargs="*", + help='Optional args for the command') + + args = ap.parse_args() + + if not args.read and not args.write and not args.sub: + args.read = True + + if args.raw or (args.cmd not in subcmds): + func = subcmd_default + else: + func = subcmds[args.cmd]['func'] + + rpc = JsonUDP(args.mgmtport) + rpc.debug = args.debug + rpc.key = args.key + + try: + result = func(rpc, args) + except socket.timeout as e: + print(e) + exit(1) + + print(result) + + +if __name__ == '__main__': + main() diff --git a/scripts/n2n-gateway.sh b/scripts/n2n-gateway.sh new file mode 100755 index 0000000..0990d3a --- /dev/null +++ b/scripts/n2n-gateway.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# +# This is a sample script to route all the host traffic towards a remote +# gateway, which is reacheable via the n2n virtual interface. +# +# This assumes the n2n connection is already been established and the +# VPN gateway can be pinged by this host. +# + +####################################################### +# CONFIG +####################################################### + +# The IP address of the gateway through the n2n interface +N2N_GATEWAY="192.168.100.1" + +# The IP address of the supernode as configured in n2n +N2N_SUPERNODE="1.2.3.4" + +# The n2n interface name +N2N_INTERFACE="n2n0" + +# The DNS server to use. Must be a public DNS or a DNS located on the +# N2N virtual network, otherwise DNS query information will be leaked +# outside the VPN. +DNS_SERVER="8.8.8.8" + +####################################################### +# END CONFIG +####################################################### + +if [[ $UID -ne 0 ]]; then + echo "This script must be run as root" + exit 1 +fi + +if ! ip route get $N2N_GATEWAY | grep -q $N2N_INTERFACE ; then + echo "Cannot reach the gateway ($N2N_GATEWAY) via $N2N_INTERFACE. Is edge running?" + exit 1 +fi + +# Determine the current internet gateway +internet_gateway=$(ip route get 8.8.8.8 | head -n1 | awk '{ print $3 }') + +# Backup the DNS resolver configuration and use the specified server +cp /etc/resolv.conf /etc/resolv.conf.my_bak +echo "Using DNS server $DNS_SERVER" +echo "nameserver $DNS_SERVER" > /etc/resolv.conf + +# The public IP of the supernode must be reachable via the internet gateway +# Whereas all the other traffic will go through the new VPN gateway. +ip route add $N2N_SUPERNODE via "$internet_gateway" +ip route del default +echo "Forwarding traffic via $N2N_GATEWAY" +ip route add default via $N2N_GATEWAY + +function stopService { + echo "Deleting custom routes" + ip route del default + ip route del $N2N_SUPERNODE via "$internet_gateway" + + echo "Restoring original gateway $internet_gateway" + ip route add default via "$internet_gateway" + + echo "Restoring original DNS" + mv /etc/resolv.conf.my_bak /etc/resolv.conf + + exit 0 +} + +# setup signal handlers +trap "stopService" SIGHUP SIGINT SIGTERM + +# enter wait loop +echo "VPN is now up" +while :; do sleep 300; done diff --git a/scripts/n2n-httpd b/scripts/n2n-httpd new file mode 100755 index 0000000..a875047 --- /dev/null +++ b/scripts/n2n-httpd @@ -0,0 +1,472 @@ +#!/usr/bin/env python3 +# Licensed under GPLv3 +# +# Simple http server to allow user control of n2n edge nodes +# +# Currently only for demonstration +# - needs nicer looking html written +# - needs more json interfaces in edge +# +# Try it out with +# http://localhost:8080/ +# http://localhost:8080/edge/edges +# http://localhost:8080/edge/supernodes + +import argparse +import socket +import json +import socketserver +import http.server +import signal +import functools +import base64 + +from http import HTTPStatus + +import os +import sys +import importlib.machinery +import importlib.util + + +def import_filename(modulename, filename): + # look in the same dir as this script + pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)), + filename) + loader = importlib.machinery.SourceFileLoader(modulename, pathname) + spec = importlib.util.spec_from_loader(modulename, loader) + module = importlib.util.module_from_spec(spec) + + try: + loader.exec_module(module) + except FileNotFoundError: + print("Script {} not found".format(pathname), file=sys.stderr) + sys.exit(1) + return module + + +# We share the implementation of the RPC class with the n2n-ctl script. We +# cannot just import the module as 'n2n-ctl' has a dash in its name :-( +JsonUDP = import_filename('n2nctl', 'n2n-ctl').JsonUDP + + +pages = { + "/script.js": { + "content_type": "text/javascript", + "content": """ +var verbose=-1; + +function rows2verbose(id, unused, data) { + row0 = data[0] + verbose = row0['traceLevel'] + + let div = document.getElementById(id); + div.innerHTML=verbose +} + +function rows2keyvalue(id, keys, data) { + let s = "" + data.forEach((row) => { + keys.forEach((key) => { + if (key in row) { + s += "
" + key + "" + row[key]; + } + }); + }); + + s += "
" + let div = document.getElementById(id); + div.innerHTML=s +} + +function rows2keyvalueall(id, unused, data) { + let s = "" + data.forEach((row) => { + Object.keys(row).forEach((key) => { + s += "
" + key + "" + row[key]; + }); + }); + + s += "
" + let div = document.getElementById(id); + div.innerHTML=s +} + +function rows2table(id, columns, data) { + let s = "" + s += "" + columns.forEach((col) => { + s += "" + columns.forEach((col) => { + val = row[col] + if (typeof val === "undefined") { + val = '' + } + s += "
" + col + }); + data.forEach((row) => { + s += "
" + val + }); + }); + + s += "
" + let div = document.getElementById(id); + div.innerHTML=s +} + +function do_get(url, id, handler, handler_param) { + fetch(url) + .then(function (response) { + if (!response.ok) { + throw new Error('Fetch got ' + response.status) + } + return response.json(); + }) + .then(function (data) { + handler(id,handler_param,data); + + // update the timestamp on success + let now = Math.round(new Date().getTime() / 1000); + let time = document.getElementById('time'); + time.innerHTML=now; + }) + .catch(function (err) { + console.log('error: ' + err); + }); +} + +function do_post(url, body, id, handler, handler_param) { + fetch(url, {method:'POST', body: body}) + .then(function (response) { + if (!response.ok) { + throw new Error('Fetch got ' + response.status) + } + return response.json(); + }) + .then(function (data) { + handler(id,handler_param,data); + }) + .catch(function (err) { + console.log('error: ' + err); + }); +} + +function do_stop(tracelevel) { + // FIXME: uses global in script library + fetch(nodetype + '/stop', {method:'POST'}) +} + +function setverbose(tracelevel) { + if (tracelevel < 0) { + tracelevel = 0; + } + // FIXME: uses global in script library + do_post( + nodetype + '/verbose', tracelevel, 'verbose', + rows2verbose, null + ); +} + +function refresh_setup(interval) { + var timer = setInterval(refresh_job, interval); +} +""", + }, + "/": { + "content_type": "text/html; charset=utf-8", + "content": """ + + + n2n edge management + + + + + +
Last Updated: +
+
+ +
Logging Verbosity: + +
+
+ + +
+
+
+
+ Edges/Peers: +
+
+ Supernodes: +
+
+
+
+
+ + + + + +""", + }, + "/supernode.html": { + "content_type": "text/html; charset=utf-8", + "content": """ + + + n2n supernode management + + + + + +
Last Updated: +
+
+ +
Logging Verbosity: + +
+
+ + + +
+
+ Communities: +
+
+ Edges/Peers: +
+
+
+
+
+ + + + + +""", + }, +} + + +class SimpleHandler(http.server.BaseHTTPRequestHandler): + + def __init__(self, rpc, snrpc, *args, **kwargs): + self.rpc = rpc + self.snrpc = snrpc + super().__init__(*args, **kwargs) + + def log_request(self, code='-', size='-'): + # Dont spam the output + pass + + def _simplereply(self, number, message): + self.send_response(number) + self.end_headers() + self.wfile.write(message.encode('utf8')) + + def _replyjson(self, data): + self.send_response(HTTPStatus.OK) + self.send_header('Content-type', 'application/json') + self.end_headers() + self.wfile.write(json.dumps(data).encode('utf8')) + + def _replyunauth(self): + self.send_response(HTTPStatus.UNAUTHORIZED) + self.send_header('WWW-Authenticate', 'Basic realm="n2n"') + self.end_headers() + + def _extractauth(self, rpc): + # Avoid caching the key inside the object for all clients + rpc.key = None + + header = self.headers.get('Authorization') + if header is not None: + authtype, encoded = header.split(' ') + if authtype == 'Basic': + user, key = base64.b64decode(encoded).decode('utf8').split(':') + rpc.key = key + + if rpc.key is None: + rpc.key = rpc.defaultkey + + def _rpc(self, method, cmdline): + try: + data = method(cmdline) + except ValueError as e: + if str(e) == "Error: badauth": + self._replyunauth() + return + + self._simplereply(HTTPStatus.BAD_REQUEST, 'Bad Command') + return + except socket.timeout as e: + self._simplereply(HTTPStatus.REQUEST_TIMEOUT, str(e)) + return + + self._replyjson(data) + return + + def _rpc_read(self, rpc): + self._extractauth(rpc) + tail = self.path.split('/') + cmd = tail[2] + # if reads ever need args, could use more of the tail + + self._rpc(rpc.read, cmd) + + def _rpc_write(self, rpc): + self._extractauth(rpc) + content_length = int(self.headers['Content-Length']) + post_data = self.rfile.read(content_length).decode('utf8') + + tail = self.path.split('/') + cmd = tail[2] + cmdline = cmd + ' ' + post_data + + self._rpc(rpc.write, cmdline) + + def do_GET(self): + if self.path.startswith("/edge/"): + self._rpc_read(self.rpc) + return + + if self.path.startswith("/supernode/"): + self._rpc_read(self.snrpc) + return + + if self.path in pages: + page = pages[self.path] + + self.send_response(HTTPStatus.OK) + self.send_header('Content-type', page['content_type']) + self.end_headers() + self.wfile.write(page['content'].encode('utf8')) + return + + self._simplereply(HTTPStatus.NOT_FOUND, 'Not Found') + return + + def do_POST(self): + if self.path.startswith("/edge/"): + self._rpc_write(self.rpc) + return + + if self.path.startswith("/supernode/"): + self._rpc_write(self.snrpc) + return + + +def main(): + ap = argparse.ArgumentParser( + description='Control the running local n2n edge via http') + ap.add_argument('-t', '--mgmtport', action='store', default=5644, + help='Management Port (default=5644)', type=int) + ap.add_argument('--snmgmtport', action='store', default=5645, + help='Supernode Management Port (default=5645)', type=int) + ap.add_argument('-k', '--key', action='store', + help='Password for mgmt commands') + ap.add_argument('-d', '--debug', action='store_true', + help='Also show raw internal data') + ap.add_argument('port', action='store', + default=8080, type=int, nargs='?', + help='Serve requests on TCP port (default 8080)') + + args = ap.parse_args() + + rpc = JsonUDP(args.mgmtport) + rpc.debug = args.debug + rpc.defaultkey = args.key + + snrpc = JsonUDP(args.snmgmtport) + snrpc.debug = args.debug + snrpc.defaultkey = args.key + + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + socketserver.TCPServer.allow_reuse_address = True + handler = functools.partial(SimpleHandler, rpc, snrpc) + + httpd = socketserver.TCPServer(("", args.port), handler) + try: + httpd.serve_forever() + except KeyboardInterrupt: + return + + +if __name__ == '__main__': + main() diff --git a/scripts/test_harness.sh b/scripts/test_harness.sh new file mode 100755 index 0000000..2904305 --- /dev/null +++ b/scripts/test_harness.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# +# Run with the name of a test list file. +# +# This expects to find the tests in the tools dir or scripts dir and the +# expected results in the tests dir. + +# boilerplate so we can support whaky cmake dirs +[ -z "$TOPDIR" ] && TOPDIR="." +[ -z "$BINDIR" ] && BINDIR="." +export TOPDIR +export BINDIR + +if [ -z "$1" ]; then + echo need test list filename + exit 1 +fi +TESTLIST="$1" +LISTDIR=$(dirname "$TESTLIST") + +TESTS=$(sed -e "s/#.*//" "$TESTLIST") + +# Actually run the tests +for i in $TESTS; do + # Look in several places for the test program + if [ -e "$BINDIR/$i" ]; then + TEST="$BINDIR/$i" + elif [ -e "$BINDIR/tools/$i" ]; then + TEST="$BINDIR/tools/$i" + elif [ -e "$LISTDIR/../scripts/$i" ]; then + TEST="$LISTDIR/../scripts/$i" + else + echo "Could not find test $i" + exit 1 + fi + + if [ ! -e "$LISTDIR/$i.expected" ]; then + echo "Could not find testdata $LISTDIR/$i.expected" + exit 1 + fi + + echo "$TEST >$LISTDIR/$i.out" + set -e + "$TEST" >"$LISTDIR/$i.out" + cmp "$LISTDIR/$i.expected" "$LISTDIR/$i.out" + set +e +done diff --git a/scripts/test_integration_edge.sh b/scripts/test_integration_edge.sh new file mode 100755 index 0000000..93a5424 --- /dev/null +++ b/scripts/test_integration_edge.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# +# Do some quick tests via the Json API against the edge +# + +AUTH=n2n + +# boilerplate so we can support whaky cmake dirs +[ -z "$TOPDIR" ] && TOPDIR=. +[ -z "$BINDIR" ] && BINDIR=. + +docmd() { + echo "###" + "$@" + echo +} + +# start a supernode +docmd ${BINDIR}/supernode -v + +# Start the edge in the background +docmd sudo ${BINDIR}/edge -l localhost:7654 -c test >/dev/null +# TODO: +# - send edge messages to stderr? + +docmd ${TOPDIR}/scripts/n2n-ctl communities +docmd ${TOPDIR}/scripts/n2n-ctl packetstats +docmd ${TOPDIR}/scripts/n2n-ctl edges --raw + +# TODO: +# docmd ${TOPDIR}/scripts/n2n-ctl supernodes --raw +# - need fixed mac address +# - need to mask out: +# - version string +# - last_seen timestamp +# - uptime + +docmd ${TOPDIR}/scripts/n2n-ctl verbose +docmd ${TOPDIR}/scripts/n2n-ctl --write verbose 1 2>/dev/null +echo $? +docmd ${TOPDIR}/scripts/n2n-ctl -k $AUTH --write verbose 1 + +# looks strange, but we are querying the state of the "stop" verb +docmd ${TOPDIR}/scripts/n2n-ctl stop + +# stop them both +docmd ${TOPDIR}/scripts/n2n-ctl -k $AUTH --write stop +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 -k $AUTH --write stop + diff --git a/scripts/test_integration_supernode.sh b/scripts/test_integration_supernode.sh new file mode 100755 index 0000000..57f44bc --- /dev/null +++ b/scripts/test_integration_supernode.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Do some quick tests via the Json API against the supernode +# + +AUTH=n2n + +# boilerplate so we can support whaky cmake dirs +[ -z "$TOPDIR" ] && TOPDIR=. +[ -z "$BINDIR" ] && BINDIR=. + +docmd() { + echo "###" + "$@" + echo +} + +# start it running in the background +docmd ${BINDIR}/supernode -v + +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 communities +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 packetstats +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 edges --raw + +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 verbose +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 -k $AUTH --write verbose 1 + +# looks strange, but we are querying the state of the "stop" verb +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 stop + +# stop it +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 -k $AUTH --write stop + diff --git a/scripts/version.sh b/scripts/version.sh new file mode 100755 index 0000000..e551500 --- /dev/null +++ b/scripts/version.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# +# Output the current version number +# + +usage() { + echo "Usage: $0 [short|hash]" + echo + echo "Determine the correct version number for the current build" + exit 0 +} + +# We assume this script is in the TOPDIR/scripts directory and use that +# to find any other files we need +TOPDIR=$(dirname "$0")/.. + +VER_FILE_SHORT=$(cat "${TOPDIR}/VERSION") + +if [ -d "$TOPDIR/.git" ]; then + # If there is a .git directory in our TOPDIR, then this is assumed to be + # real git checkout + + cd "$TOPDIR" || exit 1 + + VER_GIT_SHORT=$(git describe --abbrev=0) + + if [ "$VER_FILE_SHORT" != "$VER_GIT_SHORT" ]; then + echo "Error: VERSION file does not match tag version ($VER_FILE_SHORT != $VER_GIT_SHORT)" + exit 1 + fi + + VER_SHORT="$VER_GIT_SHORT" + VER_HASH=$(git rev-parse --short HEAD) + VER=$(git describe --abbrev=7 --dirty) +else + # If there is no .git directory in our TOPDIR, we fall back on relying on + # the VERSION file + + VER_SHORT="$VER_FILE_SHORT" + VER_HASH="HEAD" + VER="$VER_FILE_SHORT" +fi + +case "$1" in + hash) + echo "$VER_HASH" + ;; + short) + echo "$VER_SHORT" + ;; + "") + echo "$VER" + ;; + *) + usage + ;; +esac diff --git a/src/aes.c b/src/aes.c new file mode 100644 index 0000000..35375bd --- /dev/null +++ b/src/aes.c @@ -0,0 +1,1313 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +#if defined (HAVE_OPENSSL_1_1) // openSSL 1.1 --------------------------------------------------------------------- + + +// get any erorr message out of openssl +// taken from https://en.wikibooks.org/wiki/OpenSSL/Error_handling +static char *openssl_err_as_string (void) { + + BIO *bio = BIO_new (BIO_s_mem ()); + ERR_print_errors (bio); + char *buf = NULL; + size_t len = BIO_get_mem_data (bio, &buf); + char *ret = (char *) calloc (1, 1 + len); + + if(ret) + memcpy (ret, buf, len); + + BIO_free (bio); + + return ret; +} + + +int aes_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, aes_context_t *ctx) { + + int evp_len; + int evp_ciphertext_len; + + if(1 == EVP_EncryptInit_ex(ctx->enc_ctx, ctx->cipher, NULL, ctx->key, iv)) { + if(1 == EVP_CIPHER_CTX_set_padding(ctx->enc_ctx, 0)) { + if(1 == EVP_EncryptUpdate(ctx->enc_ctx, out, &evp_len, in, in_len)) { + evp_ciphertext_len = evp_len; + if(1 == EVP_EncryptFinal_ex(ctx->enc_ctx, out + evp_len, &evp_len)) { + evp_ciphertext_len += evp_len; + if(evp_ciphertext_len != in_len) + traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl encryption: encrypted %u bytes where %u were expected", + evp_ciphertext_len, in_len); + } else + traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl final encryption: %s", + openssl_err_as_string()); + } else + traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl encrpytion: %s", + openssl_err_as_string()); + } else + traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl padding setup: %s", + openssl_err_as_string()); + } else + traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl init: %s", + openssl_err_as_string()); + + EVP_CIPHER_CTX_reset(ctx->enc_ctx); + + return 0; +} + + +int aes_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, aes_context_t *ctx) { + + int evp_len; + int evp_plaintext_len; + + if(1 == EVP_DecryptInit_ex(ctx->dec_ctx, ctx->cipher, NULL, ctx->key, iv)) { + if(1 == EVP_CIPHER_CTX_set_padding(ctx->dec_ctx, 0)) { + if(1 == EVP_DecryptUpdate(ctx->dec_ctx, out, &evp_len, in, in_len)) { + evp_plaintext_len = evp_len; + if(1 == EVP_DecryptFinal_ex(ctx->dec_ctx, out + evp_len, &evp_len)) { + evp_plaintext_len += evp_len; + if(evp_plaintext_len != in_len) + traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl decryption: decrypted %u bytes where %u were expected", + evp_plaintext_len, in_len); + } else + traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl final decryption: %s", + openssl_err_as_string()); + } else + traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl decrpytion: %s", + openssl_err_as_string()); + } else + traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl padding setup: %s", + openssl_err_as_string()); + } else + traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl init: %s", + openssl_err_as_string()); + + EVP_CIPHER_CTX_reset(ctx->dec_ctx); + + return 0; +} + + +int aes_ecb_decrypt (unsigned char *out, const unsigned char *in, aes_context_t *ctx) { + + AES_ecb_encrypt(in, out, &(ctx->ecb_dec_key), AES_DECRYPT); + + return 0; +} + + +int aes_init (const unsigned char *key, size_t key_size, aes_context_t **ctx) { + + // allocate context... + *ctx = (aes_context_t*) calloc(1, sizeof(aes_context_t)); + if(!(*ctx)) + return -1; + + // ...and fill her up: + + // initialize data structures + if(!((*ctx)->enc_ctx = EVP_CIPHER_CTX_new())) { + traceEvent(TRACE_ERROR, "aes_init openssl's evp_* encryption context creation failed: %s", + openssl_err_as_string()); + return -1; + } + + if(!((*ctx)->dec_ctx = EVP_CIPHER_CTX_new())) { + traceEvent(TRACE_ERROR, "aes_init openssl's evp_* decryption context creation failed: %s", + openssl_err_as_string()); + return -1; + } + + // check key size and make key size (given in bytes) dependant settings + switch(key_size) { + case AES128_KEY_BYTES: // 128 bit key size + (*ctx)->cipher = EVP_aes_128_cbc(); + break; + case AES192_KEY_BYTES: // 192 bit key size + (*ctx)->cipher = EVP_aes_192_cbc(); + break; + case AES256_KEY_BYTES: // 256 bit key size + (*ctx)->cipher = EVP_aes_256_cbc(); + break; + default: + traceEvent(TRACE_ERROR, "aes_init invalid key size %u\n", key_size); + return -1; + } + + // key materiel handling + memcpy((*ctx)->key, key, key_size); + AES_set_decrypt_key(key, key_size * 8, &((*ctx)->ecb_dec_key)); + + return 0; +} + + +#elif defined (__AES__) && defined (__SSE2__) // Intel's AES-NI --------------------------------------------------- + + +// inspired by https://gist.github.com/acapola/d5b940da024080dfaf5f +// furthered by the help of Sebastian Ramacher's implementation found at +// https://chromium.googlesource.com/external/github.com/dlitz/pycrypto/+/junk/master/src/AESNI.c +// modified along Intel's white paper on AES Instruction Set +// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf + + +static __m128i aes128_keyexpand(__m128i key, __m128i keygened, uint8_t shuf) { + + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + + // unfortunately, shuffle expects immediate argument, thus the not-so-stylish switch ... + // REVISIT: either macrorize this whole function (and perhaps the following one) or + // use shuffle_epi8 (which would require SSSE3 instead of SSE2) + switch(shuf) { + case 0x55: + keygened = _mm_shuffle_epi32(keygened, 0x55 ); + break; + case 0xaa: + keygened = _mm_shuffle_epi32(keygened, 0xaa ); + break; + case 0xff: + keygened = _mm_shuffle_epi32(keygened, 0xff ); + break; + default: + break; + } + + return _mm_xor_si128(key, keygened); +} + + +static __m128i aes192_keyexpand_2(__m128i key, __m128i key2) { + + key = _mm_shuffle_epi32(key, 0xff); + key2 = _mm_xor_si128(key2, _mm_slli_si128(key2, 4)); + + return _mm_xor_si128(key, key2); +} + + +#define KEYEXP128(K, I) aes128_keyexpand (K, _mm_aeskeygenassist_si128(K, I), 0xff) +#define KEYEXP192(K1, K2, I) aes128_keyexpand (K1, _mm_aeskeygenassist_si128(K2, I), 0x55) +#define KEYEXP192_2(K1, K2) aes192_keyexpand_2(K1, K2) +#define KEYEXP256(K1, K2, I) aes128_keyexpand (K1, _mm_aeskeygenassist_si128(K2, I), 0xff) +#define KEYEXP256_2(K1, K2) aes128_keyexpand (K1, _mm_aeskeygenassist_si128(K2, 0x00), 0xaa) + + +// key setup +static int aes_internal_key_setup (aes_context_t *ctx, const uint8_t *key, int key_bits) { + + // number of rounds + ctx->Nr = 6 + (key_bits / 32); + + // encryption keys + switch(key_bits) { + case 128: { + ctx->rk_enc[ 0] = _mm_loadu_si128((const __m128i*)key); + ctx->rk_enc[ 1] = KEYEXP128(ctx->rk_enc[0], 0x01); + ctx->rk_enc[ 2] = KEYEXP128(ctx->rk_enc[1], 0x02); + ctx->rk_enc[ 3] = KEYEXP128(ctx->rk_enc[2], 0x04); + ctx->rk_enc[ 4] = KEYEXP128(ctx->rk_enc[3], 0x08); + ctx->rk_enc[ 5] = KEYEXP128(ctx->rk_enc[4], 0x10); + ctx->rk_enc[ 6] = KEYEXP128(ctx->rk_enc[5], 0x20); + ctx->rk_enc[ 7] = KEYEXP128(ctx->rk_enc[6], 0x40); + ctx->rk_enc[ 8] = KEYEXP128(ctx->rk_enc[7], 0x80); + ctx->rk_enc[ 9] = KEYEXP128(ctx->rk_enc[8], 0x1B); + ctx->rk_enc[10] = KEYEXP128(ctx->rk_enc[9], 0x36); + break; + } + case 192: { + __m128i temp[2]; + ctx->rk_enc[ 0] = _mm_loadu_si128((const __m128i*) key); + + ctx->rk_enc[ 1] = _mm_loadu_si128((const __m128i*) (key+16)); + temp[0] = KEYEXP192(ctx->rk_enc[0], ctx->rk_enc[1], 0x01); + temp[1] = KEYEXP192_2(temp[0], ctx->rk_enc[1]); + ctx->rk_enc[ 1] = (__m128i)_mm_shuffle_pd((__m128d)ctx->rk_enc[1], (__m128d)temp[0], 0); + + ctx->rk_enc[ 2] = (__m128i)_mm_shuffle_pd((__m128d)temp[0], (__m128d)temp[1], 1); + ctx->rk_enc[ 3] = KEYEXP192(temp[0], temp[1], 0x02); + + ctx->rk_enc[ 4] = KEYEXP192_2(ctx->rk_enc[3], temp[1]); + temp[0] = KEYEXP192(ctx->rk_enc[3], ctx->rk_enc[4], 0x04); + temp[1] = KEYEXP192_2(temp[0], ctx->rk_enc[4]); + ctx->rk_enc[ 4] = (__m128i)_mm_shuffle_pd((__m128d)ctx->rk_enc[4], (__m128d)temp[0], 0); + + ctx->rk_enc[ 5] = (__m128i)_mm_shuffle_pd((__m128d)temp[0], (__m128d)temp[1], 1); + ctx->rk_enc[ 6] = KEYEXP192(temp[0], temp[1], 0x08); + + ctx->rk_enc[ 7] = KEYEXP192_2(ctx->rk_enc[6], temp[1]); + temp[0] = KEYEXP192(ctx->rk_enc[6], ctx->rk_enc[7], 0x10); + temp[1] = KEYEXP192_2(temp[0], ctx->rk_enc[7]); + ctx->rk_enc[ 7] = (__m128i)_mm_shuffle_pd((__m128d)ctx->rk_enc[7], (__m128d)temp[0], 0); + + ctx->rk_enc[ 8] = (__m128i)_mm_shuffle_pd((__m128d)temp[0], (__m128d)temp[1], 1); + ctx->rk_enc[ 9] = KEYEXP192(temp[0], temp[1], 0x20); + + ctx->rk_enc[10] = KEYEXP192_2(ctx->rk_enc[9], temp[1]); + temp[0] = KEYEXP192(ctx->rk_enc[9], ctx->rk_enc[10], 0x40); + temp[1] = KEYEXP192_2(temp[0], ctx->rk_enc[10]); + ctx->rk_enc[10] = (__m128i)_mm_shuffle_pd((__m128d)ctx->rk_enc[10], (__m128d) temp[0], 0); + + ctx->rk_enc[11] = (__m128i)_mm_shuffle_pd((__m128d)temp[0],(__m128d) temp[1], 1); + ctx->rk_enc[12] = KEYEXP192(temp[0], temp[1], 0x80); + break; + } + case 256: { + ctx->rk_enc[ 0] = _mm_loadu_si128((const __m128i*) key); + ctx->rk_enc[ 1] = _mm_loadu_si128((const __m128i*) (key+16)); + ctx->rk_enc[ 2] = KEYEXP256(ctx->rk_enc[0], ctx->rk_enc[1], 0x01); + ctx->rk_enc[ 3] = KEYEXP256_2(ctx->rk_enc[1], ctx->rk_enc[2]); + ctx->rk_enc[ 4] = KEYEXP256(ctx->rk_enc[2], ctx->rk_enc[3], 0x02); + ctx->rk_enc[ 5] = KEYEXP256_2(ctx->rk_enc[3], ctx->rk_enc[4]); + ctx->rk_enc[ 6] = KEYEXP256(ctx->rk_enc[4], ctx->rk_enc[5], 0x04); + ctx->rk_enc[ 7] = KEYEXP256_2(ctx->rk_enc[5], ctx->rk_enc[6]); + ctx->rk_enc[ 8] = KEYEXP256(ctx->rk_enc[6], ctx->rk_enc[7], 0x08); + ctx->rk_enc[ 9] = KEYEXP256_2(ctx->rk_enc[7], ctx->rk_enc[8]); + ctx->rk_enc[10] = KEYEXP256(ctx->rk_enc[8], ctx->rk_enc[9], 0x10); + ctx->rk_enc[11] = KEYEXP256_2(ctx->rk_enc[9], ctx->rk_enc[10]); + ctx->rk_enc[12] = KEYEXP256(ctx->rk_enc[10], ctx->rk_enc[11], 0x20); + ctx->rk_enc[13] = KEYEXP256_2(ctx->rk_enc[11], ctx->rk_enc[12]); + ctx->rk_enc[14] = KEYEXP256(ctx->rk_enc[12], ctx->rk_enc[13], 0x40); + break; + } + } + + // derive decryption keys + for(int i = 1; i < ctx->Nr; ++i) { + ctx->rk_dec[ctx->Nr - i] = _mm_aesimc_si128(ctx->rk_enc[i]); + } + ctx->rk_dec[ 0] = ctx->rk_enc[ctx->Nr]; + + return ctx->Nr; +} + + +static void aes_internal_encrypt (aes_context_t *ctx, const uint8_t pt[16], uint8_t ct[16]) { + + __m128i tmp = _mm_loadu_si128((__m128i*)pt); + + tmp = _mm_xor_si128 (tmp, ctx->rk_enc[ 0]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 1]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 2]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 3]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 4]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 5]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 6]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 7]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 8]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 9]); + if(ctx->Nr > 10) { + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[10]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[11]); + if(ctx->Nr > 12) { + tmp = _mm_aesenc_si128(tmp, ctx->rk_enc[12]); + tmp = _mm_aesenc_si128(tmp, ctx->rk_enc[13]); + } + } + tmp = _mm_aesenclast_si128 (tmp, ctx->rk_enc[ctx->Nr]); + + _mm_storeu_si128((__m128i*) ct, tmp); +} + + +static void aes_internal_decrypt (aes_context_t *ctx, const uint8_t ct[16], uint8_t pt[16]) { + + __m128i tmp = _mm_loadu_si128((__m128i*)ct); + + tmp = _mm_xor_si128 (tmp, ctx->rk_dec[ 0]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 1]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 2]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 3]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 4]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 5]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 6]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 7]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 8]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 9]); + if(ctx->Nr > 10) { + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[10]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[11]); + if(ctx->Nr > 12) { + tmp = _mm_aesdec_si128(tmp, ctx->rk_dec[12]); + tmp = _mm_aesdec_si128(tmp, ctx->rk_dec[13]); + } + } + tmp = _mm_aesdeclast_si128 (tmp, ctx->rk_enc[ 0]); + + _mm_storeu_si128((__m128i*) pt, tmp); +} + + +// public API + + +int aes_ecb_decrypt (unsigned char *out, const unsigned char *in, aes_context_t *ctx) { + + aes_internal_decrypt(ctx, in, out); + + return AES_BLOCK_SIZE; +} + + +// not used +int aes_ecb_encrypt (unsigned char *out, const unsigned char *in, aes_context_t *ctx) { + + aes_internal_encrypt(ctx, in, out); + + return AES_BLOCK_SIZE; +} + + +int aes_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, aes_context_t *ctx) { + + int n; /* number of blocks */ + int ret = (int)in_len & 15; /* remainder */ + + __m128i ivec = _mm_loadu_si128((__m128i*)iv); + + for(n = in_len / 16; n != 0; n--) { + __m128i tmp = _mm_loadu_si128((__m128i*)in); + in += 16; + tmp = _mm_xor_si128(tmp, ivec); + + tmp = _mm_xor_si128 (tmp, ctx->rk_enc[ 0]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 1]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 2]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 3]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 4]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 5]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 6]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 7]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 8]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[ 9]); + if(ctx->Nr > 10) { + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[10]); + tmp = _mm_aesenc_si128 (tmp, ctx->rk_enc[11]); + if(ctx->Nr > 12) { + tmp = _mm_aesenc_si128(tmp, ctx->rk_enc[12]); + tmp = _mm_aesenc_si128(tmp, ctx->rk_enc[13]); + } + } + tmp = _mm_aesenclast_si128 (tmp, ctx->rk_enc[ctx->Nr]); + + ivec = tmp; + + _mm_storeu_si128((__m128i*)out, tmp); + out += 16; + } + + return ret; +} + + +int aes_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, aes_context_t *ctx) { + + int n; /* number of blocks */ + int ret = (int)in_len & 15; /* remainder */ + + __m128i ivec = _mm_loadu_si128((__m128i*)iv); + + // 4 parallel rails of AES decryption to reduce data dependencies in x86's deep pipelines + for(n = in_len / 16; n > 3; n -=4) { + __m128i tmp1 = _mm_loadu_si128((__m128i*)in); in += 16; + __m128i tmp2 = _mm_loadu_si128((__m128i*)in); in += 16; + __m128i tmp3 = _mm_loadu_si128((__m128i*)in); in += 16; + __m128i tmp4 = _mm_loadu_si128((__m128i*)in); in += 16; + + __m128i old_in1 = tmp1; + __m128i old_in2 = tmp2; + __m128i old_in3 = tmp3; + __m128i old_in4 = tmp4; + + tmp1 = _mm_xor_si128 (tmp1, ctx->rk_dec[ 0]); tmp2 = _mm_xor_si128 (tmp2, ctx->rk_dec[ 0]); + tmp3 = _mm_xor_si128 (tmp3, ctx->rk_dec[ 0]); tmp4 = _mm_xor_si128 (tmp4, ctx->rk_dec[ 0]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 1]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 1]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[ 1]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[ 1]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 2]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 2]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[ 2]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[ 2]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 3]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 3]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[ 3]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[ 3]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 4]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 4]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[ 4]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[ 4]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 5]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 5]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[ 5]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[ 5]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 6]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 6]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[ 6]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[ 6]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 7]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 7]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[ 7]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[ 7]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 8]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 8]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[ 8]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[ 8]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 9]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 9]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[ 9]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[ 9]); + + if(ctx->Nr > 10) { + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[10]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[10]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[10]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[10]); + + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[11]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[11]); + tmp3 = _mm_aesdec_si128 (tmp3, ctx->rk_dec[11]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[11]); + + if(ctx->Nr > 12) { + tmp1 = _mm_aesdec_si128(tmp1, ctx->rk_dec[12]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[12]); + tmp3 = _mm_aesdec_si128(tmp3, ctx->rk_dec[12]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[12]); + + tmp1 = _mm_aesdec_si128(tmp1, ctx->rk_dec[13]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[13]); + tmp3 = _mm_aesdec_si128(tmp3, ctx->rk_dec[13]); tmp4 = _mm_aesdec_si128 (tmp4, ctx->rk_dec[13]); + } + } + tmp1 = _mm_aesdeclast_si128(tmp1, ctx->rk_enc[ 0]); tmp2 = _mm_aesdeclast_si128(tmp2, ctx->rk_enc[ 0]); + tmp3 = _mm_aesdeclast_si128(tmp3, ctx->rk_enc[ 0]); tmp4 = _mm_aesdeclast_si128(tmp4, ctx->rk_enc[ 0]); + + tmp1 = _mm_xor_si128 (tmp1, ivec); tmp2 = _mm_xor_si128 (tmp2, old_in1); + tmp3 = _mm_xor_si128 (tmp3, old_in2); tmp4 = _mm_xor_si128 (tmp4, old_in3); + + ivec = old_in4; + + _mm_storeu_si128((__m128i*) out, tmp1); out += 16; + _mm_storeu_si128((__m128i*) out, tmp2); out += 16; + _mm_storeu_si128((__m128i*) out, tmp3); out += 16; + _mm_storeu_si128((__m128i*) out, tmp4); out += 16; + } + // now: less than 4 blocks remaining + + // if 2 or 3 blocks remaining --> this code handles two of them + if(n > 1) { + n-= 2; + + __m128i tmp1 = _mm_loadu_si128((__m128i*)in); in += 16; + __m128i tmp2 = _mm_loadu_si128((__m128i*)in); in += 16; + + __m128i old_in1 = tmp1; + __m128i old_in2 = tmp2; + + tmp1 = _mm_xor_si128 (tmp1, ctx->rk_dec[ 0]); tmp2 = _mm_xor_si128 (tmp2, ctx->rk_dec[ 0]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 1]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 1]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 2]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 2]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 3]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 3]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 4]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 4]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 5]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 5]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 6]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 6]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 7]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 7]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 8]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 8]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[ 9]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[ 9]); + if(ctx->Nr > 10) { + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[10]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[10]); + tmp1 = _mm_aesdec_si128 (tmp1, ctx->rk_dec[11]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[11]); + if(ctx->Nr > 12) { + tmp1 = _mm_aesdec_si128(tmp1, ctx->rk_dec[12]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[12]); + tmp1 = _mm_aesdec_si128(tmp1, ctx->rk_dec[13]); tmp2 = _mm_aesdec_si128 (tmp2, ctx->rk_dec[13]); + } + } + tmp1 = _mm_aesdeclast_si128 (tmp1, ctx->rk_enc[ 0]); tmp2 = _mm_aesdeclast_si128(tmp2, ctx->rk_enc[ 0]); + + tmp1 = _mm_xor_si128 (tmp1, ivec); tmp2 = _mm_xor_si128 (tmp2, old_in1); + + ivec = old_in2; + + _mm_storeu_si128((__m128i*) out, tmp1); out += 16; + _mm_storeu_si128((__m128i*) out, tmp2); out += 16; + } + + // one block remaining + if(n) { + __m128i tmp = _mm_loadu_si128((__m128i*)in); + + tmp = _mm_xor_si128 (tmp, ctx->rk_dec[ 0]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 1]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 2]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 3]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 4]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 5]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 6]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 7]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 8]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[ 9]); + if(ctx->Nr > 10) { + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[10]); + tmp = _mm_aesdec_si128 (tmp, ctx->rk_dec[11]); + if(ctx->Nr > 12) { + tmp = _mm_aesdec_si128(tmp, ctx->rk_dec[12]); + tmp = _mm_aesdec_si128(tmp, ctx->rk_dec[13]); + } + } + tmp = _mm_aesdeclast_si128 (tmp, ctx->rk_enc[ 0]); + + tmp = _mm_xor_si128 (tmp, ivec); + + _mm_storeu_si128((__m128i*) out, tmp); + } + + return ret; +} + + +int aes_init (const unsigned char *key, size_t key_size, aes_context_t **ctx) { + + // allocate context... + *ctx = (aes_context_t*) calloc(1, sizeof(aes_context_t)); + if(!(*ctx)) + return -1; + // ...and fill her up: + + // initialize data structures + + // check key size and make key size (given in bytes) dependant settings + switch(key_size) { + case AES128_KEY_BYTES: // 128 bit key size + break; + case AES192_KEY_BYTES: // 192 bit key size + break; + case AES256_KEY_BYTES: // 256 bit key size + break; + default: + traceEvent(TRACE_ERROR, "aes_init invalid key size %u\n", key_size); + return -1; + } + + // key materiel handling + aes_internal_key_setup ( *ctx, key, 8 * key_size); + + return 0; +} + + +#else // plain C -------------------------------------------------------------------------- + + +// rijndael-alg-fst.c version 3.0 (December 2000) +// optimised ANSI C code for the Rijndael cipher (now AES) +// original authors: Vincent Rijmen +// Antoon Bosselaers +// Paulo Barreto +// +// was put in the public domain, taken (and modified) from +// https://fastcrypto.org/front/misc/rijndael-alg-fst.c + + +// Te0[x] = S [x].[02, 01, 01, 03]; +static const uint32_t Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU }; + +// Te1[x] = S [x].[03, 02, 01, 01]; +static const uint32_t Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U }; + +// Te2[x] = S [x].[01, 03, 02, 01]; +static const uint32_t Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U }; + +// Te3[x] = S [x].[01, 01, 03, 02]; +static const uint32_t Te3[256] = { + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU }; + +// Te4[x] = S [x].[01, 01, 01, 01]; +static const uint32_t Te4[256] = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U }; + +// Td0[x] = Si[x].[0e, 09, 0d, 0b]; +static const uint32_t Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U }; + +// Td1[x] = Si[x].[0b, 0e, 09, 0d]; +static const uint32_t Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U }; + +// Td2[x] = Si[x].[0d, 0b, 0e, 09]; +static const uint32_t Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U }; + +// Td3[x] = Si[x].[09, 0d, 0b, 0e]; +static const uint32_t Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U }; + +// Td4[x] = Si[x].[01, 01, 01, 01]; +static const uint32_t Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU }; + +// for 128-bit blocks, Rijndael never uses more than 10 rcon values +static const uint32_t rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000 }; + + +#define GETU32(p) (be32toh((*((uint32_t*)(p))))) +#define PUTU32(ct, st) { *((uint32_t*)(ct)) = htobe32((st)); } + +#define b0(x) ((uint8_t)(x)) +#define b1(x) ((uint8_t)((x) >> 8)) +#define b2(x) ((uint8_t)((x) >> 16)) +#define b3(x) ((uint8_t)((x) >> 24)) + +#define m0(x) ((x) & 0x000000ff) +#define m1(x) ((x) & 0x0000ff00) +#define m2(x) ((x) & 0x00ff0000) +#define m3(x) ((x) & 0xff000000) + + +// expand the cipher key into the encryption key schedule and +// return the number of rounds for the given cipher key size +static int aes_internal_key_setup_enc (uint32_t rk[/*4*(Nr + 1)*/], const uint8_t cipherKey[], int keyBits) { + + int i = 0; + uint32_t temp; + + rk[0] = GETU32(cipherKey ); + rk[1] = GETU32(cipherKey + 4); + rk[2] = GETU32(cipherKey + 8); + rk[3] = GETU32(cipherKey + 12); + if(keyBits == 128) { + for(;;) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[b2(temp)] & 0xff000000) ^ + (Te4[b1(temp)] & 0x00ff0000) ^ + (Te4[b0(temp)] & 0x0000ff00) ^ + (Te4[b3(temp)] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if(++i == 10) { + return 10; + } + rk += 4; + } + } + rk[4] = GETU32(cipherKey + 16); + rk[5] = GETU32(cipherKey + 20); + if(keyBits == 192) { + for(;;) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[b2(temp)] & 0xff000000) ^ + (Te4[b1(temp)] & 0x00ff0000) ^ + (Te4[b0(temp)] & 0x0000ff00) ^ + (Te4[b3(temp)] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if(++i == 8) { + return 12; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(cipherKey + 24); + rk[7] = GETU32(cipherKey + 28); + if(keyBits == 256) { + for(;;) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[b2(temp)] & 0xff000000) ^ + (Te4[b1(temp)] & 0x00ff0000) ^ + (Te4[b0(temp)] & 0x0000ff00) ^ + (Te4[b3(temp)] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if(++i == 7) { + return 14; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[b3(temp)] & 0xff000000) ^ + (Te4[b2(temp)] & 0x00ff0000) ^ + (Te4[b1(temp)] & 0x0000ff00) ^ + (Te4[b0(temp)] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + rk += 8; + } + } + + return 0; +} + + +#define INVMIXCOLRK(n) rk[n] = Td0[b0(Te4[b3(rk[n])])] ^ Td1[b0(Te4[b2(rk[n])])] ^ Td2[b0(Te4[b1(rk[n])])] ^ Td3[b0(Te4[b0(rk[n])])] + + +// expand the cipher key into the decryption key schedule and +// return the number of rounds for the given cipher key size +static int aes_internal_key_setup_dec (uint32_t rk[/*4*(Nr + 1)*/], const uint8_t cipherKey[], int keyBits) { + + int Nr, i, j; + uint32_t temp; + + // expand the cipher key + Nr = aes_internal_key_setup_enc(rk, cipherKey, keyBits); + // invert the order of the round keys + for(i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + + // apply the inverse MixColumn transform to all round keys but the first and the last + for(i = 1; i < Nr; i++) { + rk += 4; + INVMIXCOLRK(0); + INVMIXCOLRK(1); + INVMIXCOLRK(2); + INVMIXCOLRK(3); + } + + return Nr; +} + + +#define AES_ENC_ROUND(DST, SRC, round) \ + DST##0 = Te0[b3(SRC##0)] ^ Te1[b2(SRC##1)] ^ Te2[b1(SRC##2)] ^ Te3[b0(SRC##3)] ^ rk[4 * round + 0]; \ + DST##1 = Te0[b3(SRC##1)] ^ Te1[b2(SRC##2)] ^ Te2[b1(SRC##3)] ^ Te3[b0(SRC##0)] ^ rk[4 * round + 1]; \ + DST##2 = Te0[b3(SRC##2)] ^ Te1[b2(SRC##3)] ^ Te2[b1(SRC##0)] ^ Te3[b0(SRC##1)] ^ rk[4 * round + 2]; \ + DST##3 = Te0[b3(SRC##3)] ^ Te1[b2(SRC##0)] ^ Te2[b1(SRC##1)] ^ Te3[b0(SRC##2)] ^ rk[4 * round + 3]; + + +static void aes_internal_encrypt (const uint32_t rk[/*4*(Nr + 1)*/], int Nr, const uint8_t pt[16], uint8_t ct[16]) { + + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; + + // map byte array block to cipher state and add initial round key + s0 = GETU32(pt ) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; + + AES_ENC_ROUND(t, s, 1); + AES_ENC_ROUND(s, t, 2); + AES_ENC_ROUND(t, s, 3); + AES_ENC_ROUND(s, t, 4); + AES_ENC_ROUND(t, s, 5); + AES_ENC_ROUND(s, t, 6); + AES_ENC_ROUND(t, s, 7); + AES_ENC_ROUND(s, t, 8); + AES_ENC_ROUND(t, s, 9); + + if(Nr > 10) { + AES_ENC_ROUND(s, t, 10); + AES_ENC_ROUND(t, s, 11); + if(Nr > 12) { + AES_ENC_ROUND(s, t, 12); + AES_ENC_ROUND(t, s, 13); + } + } + + rk += Nr << 2; + // apply last round and map cipher state to byte array block + s0 = m3(Te4[b3(t0)]) ^ m2(Te4[b2(t1)]) ^ m1(Te4[b1(t2)]) ^ m0(Te4[b0(t3)]) ^ rk[0]; + PUTU32(ct , s0); + s1 = m3(Te4[b3(t1)]) ^ m2(Te4[b2(t2)]) ^ m1(Te4[b1(t3)]) ^ m0(Te4[b0(t0)]) ^ rk[1]; + PUTU32(ct + 4, s1); + s2 = m3(Te4[b3(t2)]) ^ m2(Te4[b2(t3)]) ^ m1(Te4[b1(t0)]) ^ m0(Te4[b0(t1)]) ^ rk[2]; + PUTU32(ct + 8, s2); + s3 = m3(Te4[b3(t3)]) ^ m2(Te4[b2(t0)]) ^ m1(Te4[b1(t1)]) ^ m0(Te4[b0(t2)]) ^ rk[3]; + PUTU32(ct + 12, s3); +} + + +#define AES_DEC_ROUND(DST, SRC, round) \ + DST##0 = Td0[b3(SRC##0)] ^ Td1[b2(SRC##3)] ^ Td2[b1(SRC##2)] ^ Td3[b0(SRC##1)] ^ rk[4 * round + 0]; \ + DST##1 = Td0[b3(SRC##1)] ^ Td1[b2(SRC##0)] ^ Td2[b1(SRC##3)] ^ Td3[b0(SRC##2)] ^ rk[4 * round + 1]; \ + DST##2 = Td0[b3(SRC##2)] ^ Td1[b2(SRC##1)] ^ Td2[b1(SRC##0)] ^ Td3[b0(SRC##3)] ^ rk[4 * round + 2]; \ + DST##3 = Td0[b3(SRC##3)] ^ Td1[b2(SRC##2)] ^ Td2[b1(SRC##1)] ^ Td3[b0(SRC##0)] ^ rk[4 * round + 3]; + + +static void aes_internal_decrypt (const uint32_t rk[/*4*(Nr + 1)*/], int Nr, const uint8_t ct[16], uint8_t pt[16]) { + + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; + + // map byte array block to cipher state and add initial round key + s0 = GETU32(ct ) ^ rk[0]; + s1 = GETU32(ct + 4) ^ rk[1]; + s2 = GETU32(ct + 8) ^ rk[2]; + s3 = GETU32(ct + 12) ^ rk[3]; + + AES_DEC_ROUND(t, s, 1); + AES_DEC_ROUND(s, t, 2); + AES_DEC_ROUND(t, s, 3); + AES_DEC_ROUND(s, t, 4); + AES_DEC_ROUND(t, s, 5); + AES_DEC_ROUND(s, t, 6); + AES_DEC_ROUND(t, s, 7); + AES_DEC_ROUND(s, t, 8); + AES_DEC_ROUND(t, s, 9); + + if(Nr > 10) { + AES_DEC_ROUND(s, t, 10); + AES_DEC_ROUND(t, s, 11); + if(Nr > 12) { + AES_DEC_ROUND(s, t, 12); + AES_DEC_ROUND(t, s, 13); + } + } + + rk += Nr << 2; + // apply last round and map cipher state to byte array block + s0 = m3(Td4[b3(t0)]) ^ m2(Td4[b2(t3)]) ^ m1(Td4[b1(t2)]) ^ m0(Td4[b0(t1)]) ^ rk[0]; + PUTU32(pt , s0); + s1 = m3(Td4[b3(t1)]) ^ m2(Td4[b2(t0)]) ^ m1(Td4[b1(t3)]) ^ m0(Td4[b0(t2)]) ^ rk[1]; + PUTU32(pt + 4, s1); + s2 = m3(Td4[b3(t2)]) ^ m2(Td4[b2(t1)]) ^ m1(Td4[b1(t0)]) ^ m0(Td4[b0(t3)]) ^ rk[2]; + PUTU32(pt + 8, s2); + s3 = m3(Td4[b3(t3)]) ^ m2(Td4[b2(t2)]) ^ m1(Td4[b1(t1)]) ^ m0(Td4[b0(t0)]) ^ rk[3]; + PUTU32(pt + 12, s3); +} + + +// public API + + +int aes_ecb_decrypt (unsigned char *out, const unsigned char *in, aes_context_t *ctx) { + + aes_internal_decrypt(ctx->dec_rk, ctx->Nr, in, out); + + return AES_BLOCK_SIZE; +} + + +// not used +int aes_ecb_encrypt (unsigned char *out, const unsigned char *in, aes_context_t *ctx) { + + aes_internal_encrypt(ctx->enc_rk, ctx->Nr, in, out); + + return AES_BLOCK_SIZE; +} + + +#define fix_xor(target, source) *(uint32_t*)&(target)[0] = *(uint32_t*)&(target)[0] ^ *(uint32_t*)&(source)[0]; *(uint32_t*)&(target)[4] = *(uint32_t*)&(target)[4] ^ *(uint32_t*)&(source)[4]; \ + *(uint32_t*)&(target)[8] = *(uint32_t*)&(target)[8] ^ *(uint32_t*)&(source)[8]; *(uint32_t*)&(target)[12] = *(uint32_t*)&(target)[12] ^ *(uint32_t*)&(source)[12]; + + +int aes_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, aes_context_t *ctx) { + + uint8_t tmp[AES_BLOCK_SIZE]; + size_t i; + size_t n; + + memcpy(tmp, iv, AES_BLOCK_SIZE); + + n = in_len / AES_BLOCK_SIZE; + for(i=0; i < n; i++) { + fix_xor(tmp, &in[i * AES_BLOCK_SIZE]); + aes_internal_encrypt(ctx->enc_rk, ctx->Nr, tmp, tmp); + memcpy(&out[i * AES_BLOCK_SIZE], tmp, AES_BLOCK_SIZE); + } + + return n * AES_BLOCK_SIZE; +} + + +int aes_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, aes_context_t *ctx) { + + uint8_t tmp[AES_BLOCK_SIZE]; + uint8_t old[AES_BLOCK_SIZE]; + size_t i; + size_t n; + + memcpy(tmp, iv, AES_BLOCK_SIZE); + + n = in_len / AES_BLOCK_SIZE; + for(i=0; i < n; i++) { + memcpy(old, &in[i * AES_BLOCK_SIZE], AES_BLOCK_SIZE); + aes_internal_decrypt(ctx->dec_rk, ctx->Nr, &in[i * AES_BLOCK_SIZE], &out[i * AES_BLOCK_SIZE]); + fix_xor(&out[i * AES_BLOCK_SIZE], tmp); + memcpy(tmp, old, AES_BLOCK_SIZE); + } + + return n * AES_BLOCK_SIZE; +} + + +int aes_init (const unsigned char *key, size_t key_size, aes_context_t **ctx) { + + // allocate context... + *ctx = (aes_context_t*) calloc(1, sizeof(aes_context_t)); + if(!(*ctx)) + return -1; + // ...and fill her up: + + // initialize data structures + + // check key size and make key size (given in bytes) dependant settings + switch(key_size) { + case AES128_KEY_BYTES: // 128 bit key size + break; + case AES192_KEY_BYTES: // 192 bit key size + break; + case AES256_KEY_BYTES: // 256 bit key size + break; + default: + traceEvent(TRACE_ERROR, "aes_init invalid key size %u\n", key_size); + return -1; + } + + // key materiel handling + (*ctx)->Nr = aes_internal_key_setup_enc((*ctx)->enc_rk/*[4*(Nr + 1)]*/, key, 8 * key_size); + aes_internal_key_setup_dec((*ctx)->dec_rk/*[4*(Nr + 1)]*/, key, 8 * key_size); + return 0; +} + + +#endif // openSSL 1.1, AES-NI, plain C ---------------------------------------------------------------------------- + + +int aes_deinit (aes_context_t *ctx) { + + if(ctx) free(ctx); + + return 0; +} diff --git a/src/auth.c b/src/auth.c new file mode 100644 index 0000000..2b898c9 --- /dev/null +++ b/src/auth.c @@ -0,0 +1,179 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + + +#include "auth.h" + + +// mapping six binary bits to printable ascii character +static uint8_t b2a[64] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, /* 0 ... 9, A ... F */ + 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* G ... V */ + 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, /* W ... Z, a ... l */ + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x2b, 0x2d }; /* m ... z, + , - */ + +// mapping ascii 0x30 ...0x7f back to 6 bit binary, invalids are mapped to 0xff +static uint8_t a2b[256] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0x3f, 0xff, 0xff, /* 0x20 ... 0x2f */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0x3e, 0xff, 0x3f, 0xff, /* 0x30 ... 0x3f */ + 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, /* 0x40 ... 0x4f */ + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 ... 0x5f */ + 0xff, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, /* 0x60 ... 0x6f */ + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff }; /* 0x70 ... 0x7f */ + + +int bin_to_ascii (char *out, uint8_t *in, size_t in_len) { + + // in buffer contains binary data of length in_len + + // out buffer is already allocated and of size ceiling(in_len * 8 / 6) + 1 + // out buffer will be filled with a string including trailing 0x00 + + size_t bit_count = 0; + size_t out_count = 0; + uint8_t buf1, buf2; + + for(bit_count = 0; bit_count < 8 * in_len; bit_count += 6) { + buf1 = in[bit_count / 8]; + buf1 <<= bit_count % 8; + + buf2 = ((bit_count + 6) < (8 * in_len)) ? in[bit_count / 8 + 1] : 0; + buf2 >>= 8 - (bit_count % 8); + + buf1 |= buf2; + buf1 >>= 2; + + out[out_count++] = b2a[buf1]; + } + out[out_count] = 0; + + return 0; +} + + +int ascii_to_bin (uint8_t *out, char *in) { + + // in buffer contains 0x00-terminated string to be decoded + + // out buffer will contain decoded binary data + // out buffer is already allocated and of size floor(strlen(in) * 6 / 8) + + size_t in_count, out_count, bit_count; + uint16_t buf = 0; + + bit_count = 0; + out_count = 0; + for(in_count = 0; in_count < strlen(in); in_count++) { + buf <<= 6; + + int ch = in[in_count]; + if((ch > 0x20) && (ch < 0x80)) { + if(a2b[ch] != 0xFF) { + buf |= a2b[ch - 0x20]; + } else { + traceEvent(TRACE_NORMAL, "ascii_to_bin encountered the unknown character '%c'", in[in_count]); + } + } else { + traceEvent(TRACE_WARNING, "ascii_to_bin encountered a completely out-of-range character"); + } + bit_count += 6; + + if(bit_count / 8) { + bit_count -= 8; + out[out_count++] = ((uint8_t)(buf >> bit_count)); + } + + } + + return 0; +} + + +int generate_private_key (n2n_private_public_key_t key, char *in) { + + // hash the 0-terminated string input twice to generate private key + + pearson_hash_256(key, (uint8_t *)in, strlen(in)); + pearson_hash_256(key, key, sizeof(n2n_private_public_key_t)); + + return 0; +} + + +int generate_public_key (n2n_private_public_key_t pub, n2n_private_public_key_t prv) { + + // generator point '9' on curve + static uint8_t gen[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }; + + curve25519(pub, prv, gen); + + return 0; +} + + +int generate_shared_secret (n2n_private_public_key_t shared, n2n_private_public_key_t prv, n2n_private_public_key_t pub) { + + curve25519(shared, prv, pub); + pearson_hash_256(shared, shared, sizeof(n2n_private_public_key_t)); + + return 0; +} + + +int bind_private_key_to_username (n2n_private_public_key_t prv, char *username) { + + uint8_t tmp[32]; + + pearson_hash_256(tmp, (uint8_t *)username, strlen(username)); + memxor(prv, tmp, sizeof(n2n_private_public_key_t)); + + return 0; +} + + +// calculate SPECK ( plain = HASH³(time), key = HASH³(comm) ^ HASH³(fed) ) +int calculate_dynamic_key (uint8_t out_key[N2N_AUTH_CHALLENGE_SIZE], + uint32_t key_time, n2n_community_t comm, n2n_community_t fed) { + + uint8_t key[N2N_AUTH_CHALLENGE_SIZE]; + uint8_t tmp[N2N_AUTH_CHALLENGE_SIZE]; + speck_context_t *ctx; + + // we know that N2N_AUTH_CHALLENGE_SIZE == 16, i.e. 128 bit that can take the hash value + pearson_hash_128(key, comm, sizeof(n2n_community_t)); + pearson_hash_128(key, key, N2N_AUTH_CHALLENGE_SIZE); + pearson_hash_128(key, key, N2N_AUTH_CHALLENGE_SIZE); + + pearson_hash_128(tmp, fed, sizeof(n2n_community_t)); + pearson_hash_128(tmp, tmp, N2N_AUTH_CHALLENGE_SIZE); + pearson_hash_128(tmp, tmp, N2N_AUTH_CHALLENGE_SIZE); + + memxor(key, tmp, N2N_AUTH_CHALLENGE_SIZE); + + ctx = (speck_context_t*)calloc(1, sizeof(speck_context_t)); + speck_init((speck_context_t**)&ctx, key, 128); + + pearson_hash_128(tmp, (uint8_t*)&key_time, sizeof(key_time)); + pearson_hash_128(tmp, tmp, N2N_AUTH_CHALLENGE_SIZE); + pearson_hash_128(out_key, tmp, N2N_AUTH_CHALLENGE_SIZE); + + speck_128_encrypt(out_key, ctx); + + free(ctx); + + return 0; +} diff --git a/src/cc20.c b/src/cc20.c new file mode 100644 index 0000000..168a423 --- /dev/null +++ b/src/cc20.c @@ -0,0 +1,421 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "cc20.h" + + +#if defined (HAVE_OPENSSL_1_1) // openSSL 1.1 --------------------------------------------------------------------- + + +// get any erorr message out of openssl +// taken from https://en.wikibooks.org/wiki/OpenSSL/Error_handling +static char *openssl_err_as_string (void) { + + BIO *bio = BIO_new(BIO_s_mem()); + ERR_print_errors(bio); + char *buf = NULL; + size_t len = BIO_get_mem_data(bio, &buf); + char *ret = (char *)calloc(1, 1 + len); + + if(ret) + memcpy(ret, buf, len); + + BIO_free(bio); + + return ret; +} + + +// encryption == decryption +int cc20_crypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, cc20_context_t *ctx) { + + int evp_len; + int evp_ciphertext_len; + + if(1 == EVP_EncryptInit_ex(ctx->ctx, ctx->cipher, NULL, ctx->key, iv)) { + if(1 == EVP_CIPHER_CTX_set_padding(ctx->ctx, 0)) { + if(1 == EVP_EncryptUpdate(ctx->ctx, out, &evp_len, in, in_len)) { + evp_ciphertext_len = evp_len; + if(1 == EVP_EncryptFinal_ex(ctx->ctx, out + evp_len, &evp_len)) { + evp_ciphertext_len += evp_len; + if(evp_ciphertext_len != in_len) + traceEvent(TRACE_ERROR, "cc20_crypt openssl encryption: encrypted %u bytes where %u were expected", + evp_ciphertext_len, in_len); + } else + traceEvent(TRACE_ERROR, "cc20_crypt openssl final encryption: %s", + openssl_err_as_string()); + } else + traceEvent(TRACE_ERROR, "cc20_encrypt openssl encrpytion: %s", + openssl_err_as_string()); + } else + traceEvent(TRACE_ERROR, "cc20_encrypt openssl padding setup: %s", + openssl_err_as_string()); + } else + traceEvent(TRACE_ERROR, "cc20_encrypt openssl init: %s", + openssl_err_as_string()); + + EVP_CIPHER_CTX_reset(ctx->ctx); + + return 0; +} + + +#elif defined (__SSE2__) // SSE2 --------------------------------------------------------------------------------- + + +// taken (and heavily modified and enhanced) from +// https://github.com/Ginurx/chacha20-c (public domain) + + +#define SL _mm_slli_epi32 +#define SR _mm_srli_epi32 +#define XOR _mm_xor_si128 +#define AND _mm_and_si128 +#define ADD _mm_add_epi32 +#define ROL(X,r) (XOR(SL(X,r),SR(X,(32-r)))) + +#define ONE _mm_setr_epi32(1, 0, 0, 0) +#define TWO _mm_setr_epi32(2, 0, 0, 0) + +#if defined (__SSSE3__) // --- SSSE3 + +#define L8 _mm_set_epi32(0x0e0d0c0fL, 0x0a09080bL, 0x06050407L, 0x02010003L) +#define L16 _mm_set_epi32(0x0d0c0f0eL, 0x09080b0aL, 0x05040706L, 0x01000302L) +#define ROL8(X) ( _mm_shuffle_epi8(X, L8)) /* SSSE 3 */ +#define ROL16(X) ( _mm_shuffle_epi8(X, L16)) /* SSSE 3 */ + +#else // --- regular SSE2 ---------- + +#define ROL8(X) ROL(X,8) +#define ROL16(X) ROL(X,16) + +#endif // -------------------------- + + +#define CC20_PERMUTE_ROWS(A,B,C,D) \ + B = _mm_shuffle_epi32(B, _MM_SHUFFLE(0, 3, 2, 1)); \ + C = _mm_shuffle_epi32(C, _MM_SHUFFLE(1, 0, 3, 2)); \ + D = _mm_shuffle_epi32(D, _MM_SHUFFLE(2, 1, 0, 3)) + +#define CC20_PERMUTE_ROWS_INV(A,B,C,D) \ + B = _mm_shuffle_epi32(B, _MM_SHUFFLE(2, 1, 0, 3)); \ + C = _mm_shuffle_epi32(C, _MM_SHUFFLE(1, 0, 3, 2)); \ + D = _mm_shuffle_epi32(D, _MM_SHUFFLE(0, 3, 2, 1)) + +#define CC20_ODD_ROUND(A,B,C,D) \ + /* odd round */ \ + A = ADD(A, B); D = ROL16(XOR(D, A)); \ + C = ADD(C, D); B = ROL(XOR(B, C), 12); \ + A = ADD(A, B); D = ROL8(XOR(D, A)); \ + C = ADD(C, D); B = ROL(XOR(B, C), 7) + +#define CC20_EVEN_ROUND(A,B,C,D) \ + CC20_PERMUTE_ROWS (A, B, C, D); \ + CC20_ODD_ROUND (A, B, C, D); \ + CC20_PERMUTE_ROWS_INV(A, B, C, D) + +#define CC20_DOUBLE_ROUND(A,B,C,D) \ + CC20_ODD_ROUND (A, B, C, D); \ + CC20_EVEN_ROUND(A, B, C, D) + +#define STOREXOR(O,I,X) \ + _mm_storeu_si128((__m128i*)O, \ + _mm_xor_si128(_mm_loadu_si128((__m128i*)I), X)); \ + I += 16; O += 16 \ + + +int cc20_crypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, cc20_context_t *ctx) { + + __m128i a, b, c, d, k0, k1, k2, k3, k4, k5, k6, k7; + + uint8_t *keystream8 = (uint8_t*)ctx->keystream32; + + const uint8_t *magic_constant = (uint8_t*)"expand 32-byte k"; + + a = _mm_loadu_si128((__m128i*)magic_constant); + b = _mm_loadu_si128((__m128i*)(ctx->key)); + c = _mm_loadu_si128( (__m128i*)((ctx->key)+16)); + d = _mm_loadu_si128((__m128i*)iv); + + while(in_len >= 128) { + k0 = a; k1 = b; k2 = c; k3 = d; + k4 = a; k5 = b; k6 = c; k7 = ADD(d, ONE); + + // 10 double rounds -- two in parallel to make better use of all 8 SSE registers + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); CC20_DOUBLE_ROUND(k4, k5, k6, k7); + + k0 = ADD(k0, a); k1 = ADD(k1, b); k2 = ADD(k2, c); k3 = ADD(k3, d); + k4 = ADD(k4, a); k5 = ADD(k5, b); k6 = ADD(k6, c); k7 = ADD(k7, d); k7 = ADD(k7, ONE); + + STOREXOR(out, in, k0); STOREXOR(out, in, k1); STOREXOR(out, in, k2); STOREXOR(out, in, k3); + STOREXOR(out, in, k4); STOREXOR(out, in, k5); STOREXOR(out, in, k6); STOREXOR(out, in, k7); + + // increment counter, make sure it is and stays little endian in memory + d = ADD(d, TWO); + + in_len -= 128; + } + + if(in_len >= 64) { + k0 = a; k1 = b; k2 = c; k3 = d; + + // 10 double rounds + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + + k0 = ADD(k0, a); k1 = ADD(k1, b); k2 = ADD(k2, c); k3 = ADD(k3, d); + + STOREXOR(out, in, k0); STOREXOR(out, in, k1); STOREXOR(out, in, k2); STOREXOR(out, in, k3); + + // increment counter, make sure it is and stays little endian in memory + d = ADD(d, ONE); + + in_len -= 64; + } + + if(in_len) { + k0 = a; k1 = b; k2 = c; k3 = d; + + // 10 double rounds + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + CC20_DOUBLE_ROUND(k0, k1, k2, k3); + + k0 = ADD(k0, a); k1 = ADD(k1, b); k2 = ADD(k2, c); k3 = ADD(k3, d); + + _mm_storeu_si128((__m128i*)&(ctx->keystream32[ 0]), k0); + _mm_storeu_si128((__m128i*)&(ctx->keystream32[ 4]), k1); + _mm_storeu_si128((__m128i*)&(ctx->keystream32[ 8]), k2); + _mm_storeu_si128((__m128i*)&(ctx->keystream32[12]), k3); + + // keep in mind that out and in got increased inside the last loop + // and point to current position now + while(in_len > 0) { + in_len--; + out[in_len] = in[in_len] ^ keystream8[in_len]; + } + } + + return(0); +} + + +#else // plain C -------------------------------------------------------------------------------------------------- + + +// taken (and modified) from https://github.com/Ginurx/chacha20-c (public domain) + + +static void cc20_init_block(cc20_context_t *ctx, const uint8_t nonce[]) { + + const uint8_t *magic_constant = (uint8_t*)"expand 32-byte k"; + + memcpy(&(ctx->state[ 0]), magic_constant, 16); + memcpy(&(ctx->state[ 4]), ctx->key, CC20_KEY_BYTES); + memcpy(&(ctx->state[12]), nonce, CC20_IV_SIZE); +} + + +#define ROL32(x,r) (((x)<<(r))|((x)>>(32-(r)))) + +#define CC20_QUARTERROUND(x, a, b, c, d) \ + x[a] += x[b]; x[d] = ROL32(x[d] ^ x[a], 16); \ + x[c] += x[d]; x[b] = ROL32(x[b] ^ x[c], 12); \ + x[a] += x[b]; x[d] = ROL32(x[d] ^ x[a], 8); \ + x[c] += x[d]; x[b] = ROL32(x[b] ^ x[c], 7) + +#define CC20_DOUBLE_ROUND(s) \ + /* odd round */ \ + CC20_QUARTERROUND(s, 0, 4, 8, 12); \ + CC20_QUARTERROUND(s, 1, 5, 9, 13); \ + CC20_QUARTERROUND(s, 2, 6, 10, 14); \ + CC20_QUARTERROUND(s, 3, 7, 11, 15); \ + /* even round */ \ + CC20_QUARTERROUND(s, 0, 5, 10, 15); \ + CC20_QUARTERROUND(s, 1, 6, 11, 12); \ + CC20_QUARTERROUND(s, 2, 7, 8, 13); \ + CC20_QUARTERROUND(s, 3, 4, 9, 14) + + +static void cc20_block_next(cc20_context_t *ctx) { + + uint32_t *counter = ctx->state + 12; + + ctx->keystream32[ 0] = ctx->state[ 0]; + ctx->keystream32[ 1] = ctx->state[ 1]; + ctx->keystream32[ 2] = ctx->state[ 2]; + ctx->keystream32[ 3] = ctx->state[ 3]; + ctx->keystream32[ 4] = ctx->state[ 4]; + ctx->keystream32[ 5] = ctx->state[ 5]; + ctx->keystream32[ 6] = ctx->state[ 6]; + ctx->keystream32[ 7] = ctx->state[ 7]; + ctx->keystream32[ 8] = ctx->state[ 8]; + ctx->keystream32[ 9] = ctx->state[ 9]; + ctx->keystream32[10] = ctx->state[10]; + ctx->keystream32[11] = ctx->state[11]; + ctx->keystream32[12] = ctx->state[12]; + ctx->keystream32[13] = ctx->state[13]; + ctx->keystream32[14] = ctx->state[14]; + ctx->keystream32[15] = ctx->state[15]; + + // 10 double rounds + CC20_DOUBLE_ROUND(ctx->keystream32); + CC20_DOUBLE_ROUND(ctx->keystream32); + CC20_DOUBLE_ROUND(ctx->keystream32); + CC20_DOUBLE_ROUND(ctx->keystream32); + CC20_DOUBLE_ROUND(ctx->keystream32); + CC20_DOUBLE_ROUND(ctx->keystream32); + CC20_DOUBLE_ROUND(ctx->keystream32); + CC20_DOUBLE_ROUND(ctx->keystream32); + CC20_DOUBLE_ROUND(ctx->keystream32); + CC20_DOUBLE_ROUND(ctx->keystream32); + + ctx->keystream32[ 0] += ctx->state[ 0]; + ctx->keystream32[ 1] += ctx->state[ 1]; + ctx->keystream32[ 2] += ctx->state[ 2]; + ctx->keystream32[ 3] += ctx->state[ 3]; + ctx->keystream32[ 4] += ctx->state[ 4]; + ctx->keystream32[ 5] += ctx->state[ 5]; + ctx->keystream32[ 6] += ctx->state[ 6]; + ctx->keystream32[ 7] += ctx->state[ 7]; + ctx->keystream32[ 8] += ctx->state[ 8]; + ctx->keystream32[ 9] += ctx->state[ 9]; + ctx->keystream32[10] += ctx->state[10]; + ctx->keystream32[11] += ctx->state[11]; + ctx->keystream32[12] += ctx->state[12]; + ctx->keystream32[13] += ctx->state[13]; + ctx->keystream32[14] += ctx->state[14]; + ctx->keystream32[15] += ctx->state[15]; + + // increment counter, make sure it is and stays little endian in memory + *counter = htole32(le32toh(*counter)+1); +} + + +static void cc20_init_context(cc20_context_t *ctx, const uint8_t *nonce) { + + cc20_init_block(ctx, nonce); +} + + +int cc20_crypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, cc20_context_t *ctx) { + + uint8_t *keystream8 = (uint8_t*)ctx->keystream32; + uint32_t * in_p = (uint32_t*)in; + uint32_t * out_p = (uint32_t*)out; + size_t tmp_len = in_len; + + cc20_init_context(ctx, iv); + + while(in_len >= 64) { + cc20_block_next(ctx); + + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 0]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 1]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 2]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 3]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 4]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 5]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 6]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 7]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 8]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[ 9]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[10]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[11]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[12]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[13]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[14]; in_p++; out_p++; + *(uint32_t*)out_p = *(uint32_t*)in_p ^ ctx->keystream32[15]; in_p++; out_p++; + + in_len -= 64; + } + + if(in_len > 0) { + cc20_block_next(ctx); + + tmp_len -= in_len; + while(in_len > 0) { + out[tmp_len] = in[tmp_len] ^ keystream8[tmp_len%64]; + tmp_len++; + in_len--; + } + } + + return(0); +} + + +#endif // openSSL 1.1, plain C ------------------------------------------------------------------------------------ + + +int cc20_init (const unsigned char *key, cc20_context_t **ctx) { + + // allocate context... + *ctx = (cc20_context_t*)calloc(1, sizeof(cc20_context_t)); + if(!(*ctx)) + return -1; +#if defined (HAVE_OPENSSL_1_1) + if(!((*ctx)->ctx = EVP_CIPHER_CTX_new())) { + traceEvent(TRACE_ERROR, "cc20_init openssl's evp_* encryption context creation failed: %s", + openssl_err_as_string()); + return -1; + } + + (*ctx)->cipher = EVP_chacha20(); +#endif + memcpy((*ctx)->key, key, CC20_KEY_BYTES); + + return 0; +} + + +int cc20_deinit (cc20_context_t *ctx) { + +#if defined (HAVE_OPENSSL_1_1) + if(ctx->ctx) EVP_CIPHER_CTX_free(ctx->ctx); +#endif + return 0; +} diff --git a/src/curve25519.c b/src/curve25519.c new file mode 100644 index 0000000..f8afe11 --- /dev/null +++ b/src/curve25519.c @@ -0,0 +1,356 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +/** + * version 20081011 + * Matthew Dempsky + * Public domain. + * Derived from public domain code by D. J. Bernstein. + * 20140216 tweak: Mask top bit of point input. + * + */ + + +static void add (unsigned int out[32], const unsigned int a[32], const unsigned int b[32]) { + + unsigned int j; + unsigned int u; + + u = 0; + for(j = 0; j < 31; ++j) { + u += a[j] + b[j]; + out[j] = u & 255; + u >>= 8; + } + u += a[31] + b[31]; + out[31] = u; +} + + +static void sub (unsigned int out[32], const unsigned int a[32], const unsigned int b[32]) { + + unsigned int j; + unsigned int u; + + u = 218; + for(j = 0; j < 31; ++j) { + u += a[j] + 65280 - b[j]; + out[j] = u & 255; + u >>= 8; + } + u += a[31] - b[31]; + out[31] = u; +} + + +static void squeeze (unsigned int a[32]) { + + unsigned int j; + unsigned int u; + + u = 0; + for(j = 0; j < 31; ++j) { + u += a[j]; + a[j] = u & 255; + u >>= 8; + } + u += a[31]; + a[31] = u & 127; + u = 19 * (u >> 7); + for(j = 0; j < 31; ++j) { + u += a[j]; + a[j] = u & 255; + u >>= 8; + } + u += a[31]; + a[31] = u; +} + + +static const unsigned int minusp[32] = { 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128 }; + + +static void freeze (unsigned int a[32]) { + + unsigned int aorig[32]; + unsigned int j; + unsigned int negative; + + for(j = 0; j < 32; ++j) + aorig[j] = a[j]; + add(a, a, minusp); + negative = -((a[31] >> 7) & 1); + for(j = 0; j < 32; ++j) + a[j] ^= negative & (aorig[j] ^ a[j]); +} + + +static void mult (unsigned int out[32], const unsigned int a[32], const unsigned int b[32]) { + + unsigned int i; + unsigned int j; + unsigned int u; + + for(i = 0; i < 32; ++i) { + u = 0; + for(j = 0; j <= i; ++j) + u += a[j] * b[i - j]; + for(j = i + 1; j < 32; ++j) + u += 38 * a[j] * b[i + 32 - j]; + out[i] = u; + } + squeeze(out); +} + + +static void mult121665 (unsigned int out[32], const unsigned int a[32]) { + + unsigned int j; + unsigned int u; + + u = 0; + for(j = 0; j < 31; ++j) { + u += 121665 * a[j]; + out[j] = u & 255; + u >>= 8; + } + u += 121665 * a[31]; + out[31] = u & 127; + u = 19 * (u >> 7); + for(j = 0; j < 31; ++j) { + u += out[j]; + out[j] = u & 255; + u >>= 8; + } + u += out[j]; + out[j] = u; +} + + +static void square (unsigned int out[32], const unsigned int a[32]) { + + unsigned int i; + unsigned int j; + unsigned int u; + + for(i = 0; i < 32; ++i) { + u = 0; + for(j = 0; j < i - j; ++j) + u += a[j] * a[i - j]; + for(j = i + 1; j < i + 32 - j; ++j) + u += 38 * a[j] * a[i + 32 - j]; + u *= 2; + if((i & 1) == 0) { + u += a[i / 2] * a[i / 2]; + u += 38 * a[i / 2 + 16] * a[i / 2 + 16]; + } + out[i] = u; + } + squeeze(out); +} + + +static void select (unsigned int p[64], unsigned int q[64], const unsigned int r[64], + const unsigned int s[64], unsigned int b) { + + unsigned int j; + unsigned int t; + unsigned int bminus1; + + bminus1 = b - 1; + for(j = 0; j < 64; ++j) { + t = bminus1 & (r[j] ^ s[j]); + p[j] = s[j] ^ t; + q[j] = r[j] ^ t; + } +} + + +static void mainloop (unsigned int work[64], const unsigned char e[32]) { + + unsigned int xzm1[64]; + unsigned int xzm[64]; + unsigned int xzmb[64]; + unsigned int xzm1b[64]; + unsigned int xznb[64]; + unsigned int xzn1b[64]; + unsigned int a0[64]; + unsigned int a1[64]; + unsigned int b0[64]; + unsigned int b1[64]; + unsigned int c1[64]; + unsigned int r[32]; + unsigned int s[32]; + unsigned int t[32]; + unsigned int u[32]; + unsigned int j; + unsigned int b; + int pos; + + for(j = 0; j < 32; ++j) + xzm1[j] = work[j]; + xzm1[32] = 1; + for(j = 33; j < 64; ++j) + xzm1[j] = 0; + + xzm[0] = 1; + for(j = 1; j < 64; ++j) + xzm[j] = 0; + + for(pos = 254; pos >= 0; --pos) { + b = e[pos / 8] >> (pos & 7); + b &= 1; + select(xzmb, xzm1b, xzm, xzm1, b); + add(a0, xzmb, xzmb + 32); + sub(a0 + 32, xzmb, xzmb + 32); + add (a1, xzm1b, xzm1b + 32); + sub(a1 + 32, xzm1b, xzm1b + 32); + square(b0, a0); + square(b0 + 32, a0 + 32); + mult(b1, a1, a0 + 32); + mult(b1 + 32, a1 + 32, a0); + add(c1, b1, b1 + 32); + sub(c1 + 32, b1, b1 + 32); + square(r, c1 + 32); + sub(s, b0, b0 + 32); + mult121665 (t, s); + add(u, t, b0); + mult(xznb, b0, b0 + 32); + mult(xznb + 32, s, u); + square(xzn1b, c1); + mult(xzn1b + 32, r, work); + select(xzm, xzm1, xznb, xzn1b, b); + } + + for(j = 0; j < 64; ++j) + work[j] = xzm[j]; +} + + +static void recip (unsigned int out[32], const unsigned int z[32]) { + + unsigned int z2[32]; + unsigned int z9[32]; + unsigned int z11[32]; + unsigned int z2_5_0[32]; + unsigned int z2_10_0[32]; + unsigned int z2_20_0[32]; + unsigned int z2_50_0[32]; + unsigned int z2_100_0[32]; + unsigned int t0[32]; + unsigned int t1[32]; + int i; + + /* 2 */ square(z2, z); + /* 4 */ square(t1, z2); + /* 8 */ square(t0, t1); + /* 9 */ mult(z9, t0, z); + /* 11 */ mult(z11, z9, z2); + /* 22 */ square(t0, z11); + /* 2^5 - 2^0 = 31 */ mult(z2_5_0, t0, z9); + + /* 2^6 - 2^1 */ square(t0, z2_5_0); + /* 2^7 - 2^2 */ square(t1, t0); + /* 2^8 - 2^3 */ square(t0, t1); + /* 2^9 - 2^4 */ square(t1, t0); + /* 2^10 - 2^5 */ square(t0, t1); + /* 2^10 - 2^0 */ mult(z2_10_0, t0, z2_5_0); + + /* 2^11 - 2^1 */ square(t0, z2_10_0); + /* 2^12 - 2^2 */ square(t1, t0); + /* 2^20 - 2^10 */ for(i = 2; i < 10; i += 2) { + square(t0, t1); + square(t1, t0); + } + /* 2^20 - 2^0 */ mult(z2_20_0, t1, z2_10_0); + + /* 2^21 - 2^1 */ square(t0, z2_20_0); + /* 2^22 - 2^2 */ square(t1, t0); + /* 2^40 - 2^20 */ for(i = 2; i < 20; i += 2) { + square(t0, t1); + square(t1, t0); + } + /* 2^40 - 2^0 */ mult(t0, t1, z2_20_0); + + /* 2^41 - 2^1 */ square(t1, t0); + /* 2^42 - 2^2 */ square(t0, t1); + /* 2^50 - 2^10 */ for(i = 2; i < 10; i += 2) { + square(t1, t0); + square(t0, t1); + } + /* 2^50 - 2^0 */ mult(z2_50_0, t0, z2_10_0); + + /* 2^51 - 2^1 */ square(t0, z2_50_0); + /* 2^52 - 2^2 */ square(t1, t0); + /* 2^100 - 2^50 */ for(i = 2; i < 50; i += 2) { + square(t0, t1); + square(t1, t0); + } + /* 2^100 - 2^0 */ mult(z2_100_0, t1, z2_50_0); + + /* 2^101 - 2^1 */ square(t1, z2_100_0); + /* 2^102 - 2^2 */ square(t0, t1); + /* 2^200 - 2^100 */ for(i = 2; i < 100; i += 2) { + square(t1, t0); + square(t0, t1); + } + /* 2^200 - 2^0 */ mult(t1, t0, z2_100_0); + + /* 2^201 - 2^1 */ square(t0, t1); + /* 2^202 - 2^2 */ square(t1, t0); + /* 2^250 - 2^50 */ for(i = 2; i < 50; i += 2) { + square(t0, t1); + square(t1, t0); + } + /* 2^250 - 2^0 */ mult(t0, t1, z2_50_0); + + /* 2^251 - 2^1 */ square(t1, t0); + /* 2^252 - 2^2 */ square(t0, t1); + /* 2^253 - 2^3 */ square(t1, t0); + /* 2^254 - 2^4 */ square(t0, t1); + /* 2^255 - 2^5 */ square(t1, t0); + /* 2^255 - 21 */ mult(out, t1, z11); +} + + +void curve25519 (unsigned char *q, const unsigned char *n, const unsigned char *p) { + + unsigned int work[96]; + unsigned char e[32]; + unsigned int i; + + for (i = 0; i < 32; ++i) + e[i] = n[i]; + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + + for (i = 0; i < 32; ++i) + work[i] = p[i]; + work[31] &= 127; + + mainloop(work, e); + recip(work + 32, work + 32); + mult(work + 64, work, work + 32); + freeze(work + 64); + + for(i = 0; i < 32; ++i) + q[i] = work[64 + i]; +} diff --git a/src/edge.c b/src/edge.c new file mode 100644 index 0000000..d2d6585 --- /dev/null +++ b/src/edge.c @@ -0,0 +1,1383 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" + +/* *************************************************** */ + +/** maximum length of command line arguments */ +#define MAX_CMDLINE_BUFFER_LENGTH 4096 + +/** maximum length of a line in the configuration file */ +#define MAX_CONFFILE_LINE_LENGTH 1024 + +/* ***************************************************** */ + +#ifdef HAVE_LIBCAP + +#include +#include +#include "network_traffic_filter.h" + +static cap_value_t cap_values[] = { + //CAP_NET_RAW, /* Use RAW and PACKET sockets */ + CAP_NET_ADMIN /* Needed to performs routes cleanup at exit */ +}; + +int num_cap = sizeof(cap_values)/sizeof(cap_value_t); +#endif + +// forward declaration for use in main() +void send_register_super (n2n_edge_t *eee); +void send_query_peer (n2n_edge_t *eee, const n2n_mac_t dst_mac); +int supernode_connect (n2n_edge_t *eee); +int supernode_disconnect (n2n_edge_t *eee); +int fetch_and_eventually_process_data (n2n_edge_t *eee, SOCKET sock, + uint8_t *pktbuf, uint16_t *expected, uint16_t *position, + time_t now); +int resolve_check (n2n_resolve_parameter_t *param, uint8_t resolution_request, time_t now); +int edge_init_routes (n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes); + +/* ***************************************************** */ + +/** Find the address and IP mode for the tuntap device. + * + * s is of the form: + * + * ["static"|"dhcp",":"] (|) [/] + * + * for example static:192.168.8.5/24 + * + * Fill the parts of the string into the fileds, ip_mode only if + * present. All strings are NULL terminated. + * + * return 0 on success and -1 on error + */ +static int scan_address (char * ip_addr, size_t addr_size, + char * netmask, size_t netmask_size, + char * ip_mode, size_t mode_size, + char * s) { + + int retval = -1; + char * start; + char * end; + int bitlen = N2N_EDGE_DEFAULT_CIDR_NM; + + if((NULL == s) || (NULL == ip_addr) || (NULL == netmask)) { + return -1; + } + + memset(ip_addr, 0, addr_size); + memset(netmask, 0, netmask_size); + + start = s; + end = strpbrk(s, ":"); + + if(end) { + // colon is present + if(ip_mode) { + memset(ip_mode, 0, mode_size); + strncpy(ip_mode, start, (size_t)MIN(end - start, mode_size - 1)); + } + start = end + 1; + } else { + // colon is not present + } + // start now points to first address character + retval = 0; // we have got an address + + end = strpbrk(start, "/"); + + if(!end) + // no slash present -- default end + end = s + strlen(s); + + strncpy(ip_addr, start, (size_t)MIN(end - start, addr_size - 1)); // ensure NULL term + + if(end) { + // slash is present + + // now, handle the sub-network address + sscanf(end + 1, "%u", &bitlen); + bitlen = htobe32(bitlen2mask(bitlen)); + inet_ntop(AF_INET, &bitlen, netmask, netmask_size); + } + + return retval; +} + +/* *************************************************** */ + +static void help (int level) { + + if(level == 0) return; /* no help required */ + + printf("\n"); + print_n2n_version(); + + if(level == 1) /* short help */ { + + printf(" basic usage: edge (see edge.conf)\n" + "\n" + " or edge " + " -c " + "\n " + " -l : " + "\n " + "[-a ] " + "\n " +#if defined(N2N_CAN_NAME_IFACE) + "[-d ] " + "\n " +#endif + "[-k ] " + "\n" + "\n -h shows a quick reference including all available options" + "\n --help gives a detailed parameter description" + "\n man files for n2n, edge, and superndode contain in-depth information" + "\n\n"); + + } else if(level == 2) /* quick reference */ { + + printf(" general usage: edge (see edge.conf)\n" + "\n" + " or edge " + " -c " + " -l " + "\n " + "[-p [:]] " + "\n " + +#ifdef __linux__ + "[-T ] " +#endif +#ifndef __APPLE__ + "[-D] " +#endif + "\n options for under- " + "[-i ] " + "[-L ] " + "\n lying connection " + "[-k ] " + "[-A] " + "[-H] " + "[-z] " + "\n " + "[-e ] [-S]" + "\n " + "[--select-rtt] " +#if defined(HAVE_MINIUPNP) || defined(HAVE_NATPMP) + "[--no-port-forwarding] " +#endif // HAVE_MINIUPNP || HAVE_NATPMP + "\n\n tap device and " + "[-a [static:|dhcp:][/]] " + "\n overlay network " + "[-m ] " +#if defined(N2N_CAN_NAME_IFACE) + "[-d ] " +#endif + "\n configuration " + "[-M ] " + "[-r] " + "[-E] " + "[-I ] " + "\n " + "[-J ] " + "[-P ] " + "[-R ] " +#ifdef WIN32 + "\n " + "[-x ] " +#endif + "\n\n local options " +#ifndef WIN32 + "[-f] " +#endif + "[-t ] " + "[--management-password ] " + "\n " + "[-v] " + "[-n ] " +#ifndef WIN32 + "\n " + "[-u ] " + "[-g ] " +#endif + "\n\n environment " + "N2N_KEY instead of [-k ]" + "\n variables " + "N2N_COMMUNITY instead of -c " + "\n " + "N2N_PASSWORD instead of [-J ]" + + "\n " + + "\n meaning of the " +#ifndef __APPLE__ + "[-D] enable PMTU discovery" +#endif + "\n flag options [-H] enable header encryption" + "\n [-r] enable packet forwarding through n2n community" + "\n [-E] accept multicast MAC addresses" + "\n [--select-rtt] select supernode by round trip time" + "\n [--select-mac] select supernode by MAC address" +#if defined(HAVE_MINIUPNP) || defined(HAVE_NATPMP) + "\n [--no-port-forwarding] disable UPnP/PMP port forwarding" +#endif // HAVE_MINIUPNP || HAVE_NATPMP +#ifndef WIN32 + "\n [-f] do not fork but run in foreground" +#endif + "\n [-v] make more verbose, repeat as required" + "\n " + + "\n -h shows this quick reference including all available options" + "\n --help gives a detailed parameter description" + "\n man files for n2n, edge, and superndode contain in-depth information" + "\n\n"); + + } else /* long help */ { + + printf(" general usage: edge (see edge.conf)\n" + "\n" + " or edge -c -l \n" + " [further optional command line parameters]\n\n" + ); + printf (" OPTIONS FOR THE UNDERLYING NETWORK CONNECTION\n"); + printf (" ---------------------------------------------\n\n"); + printf(" -c | n2n community name the edge belongs to\n"); + printf(" -l | supernode ip address or name, and port\n"); + printf(" -p [:] | fixed local UDP port and optionally bind to the\n" + " | sepcified local IP address only (any by default)\n"); +#ifdef __linux__ + printf(" -T | TOS for packets, e.g. 0x48 for SSH like priority\n"); +#endif +#ifndef __APPLE__ + printf(" -D | enable PMTU discovery, it can reduce fragmentation but\n" + " | causes connections to stall if not properly supported\n"); +#endif + printf(" -e | advertises the provided local IP address as preferred,\n" + " | useful if multicast peer detection is not available,\n" + " | '-e auto' tries IP address auto-detection\n"); + printf(" -S1 ... -S2 | do not connect p2p, always use the supernode,\n" + " | -S1 = via UDP" + +#ifdef N2N_HAVE_TCP + ", -S2 = via TCP" +#endif +"\n"); + printf(" -i | registration interval, for NAT hole punching (default\n" + " | %u seconds)\n", REGISTER_SUPER_INTERVAL_DFL); + printf(" -L | TTL for registration packet for NAT hole punching through\n" + " | supernode (default 0 for not set)\n"); + printf(" -k | encryption key (ASCII) - also N2N_KEY=\n"); + printf(" -A1 | disable payload encryption, do not use with key, defaults\n" + " | to AES then\n"); + printf(" -A2 ... -A5 | choose a cipher for payload encryption, requires a key,\n" + " | -A2 = Twofish, -A3 = AES (default if key provided),\n" + " | -A4 = ChaCha20, -A5 = Speck-CTR\n"); + printf(" -H | use header encryption, supernode needs fixed community\n"); + printf(" -z1 ... -z2 | compress outgoing data packets, -z1 = lzo1x,\n" + " | " +#ifdef HAVE_ZSTD + "-z2 = zstd, " +#endif + "disabled by default\n"); + printf("--select-rtt | supernode selection based on round trip time\n" + "--select-mac | supernode selection based on MAC address (default:\n" + " | by load)\n"); +#if defined(HAVE_MINIUPNP) || defined(HAVE_NATPMP) + printf("--no-port-... | disable UPnP/PMP port forwarding\n" + "...forwarding | \n"); +#endif // HAVE_MINIUPNP || HAVE_NATPMP + + printf ("\n"); + printf (" TAP DEVICE AND OVERLAY NETWORK CONFIGURATION\n"); + printf (" --------------------------------------------\n\n"); + printf(" -a [mode][/n] | interface address and optional CIDR subnet, default '/24',\n" + " | mode = [static|dhcp]:, for DHCP use '-r -a dhcp:0.0.0.0',\n" + " | edge draws IP address from supernode if no '-a ...' given\n"); + printf(" -m | fixed MAC address for the TAP interface, e.g.\n" + " | '-m 10:20:30:40:50:60', random otherwise\n"); +#if defined(N2N_CAN_NAME_IFACE) + printf(" -d | TAP device name\n"); +#endif + printf(" -M | specify n2n MTU of TAP interface, default %d\n", DEFAULT_MTU); + printf(" -r | enable packet forwarding through n2n community\n"); + printf(" -E | accept multicast MAC addresses, drop by default\n"); + printf(" -I | annotate the edge's description used for easier\n" + " | identification in management port output or username\n"); + printf(" -J | password for user-password edge authentication\n"); + printf(" -P | federation public key for user-password authentication\n"); + printf(" -R | drop or accept packets by rules, can be set multiple times\n"); + printf(" | rule format: 'src_ip/n:[s_port,e_port],...\n" + " | |on same| ...dst_ip/n:[s_port,e_port],...\n" + " | | line | ...TCP+/-,UDP+/-,ICMP+/-'\n"); +#ifdef WIN32 + printf(" -x | set TAP interface metric, defaults to 0 (auto),\n" + " | e.g. set to 1 for better multiplayer game detection\n"); +#endif + printf ("\n"); + printf (" LOCAL OPTIONS\n"); + printf (" -------------\n\n"); +#ifndef WIN32 + printf(" -f | do not fork and run as a daemon, rather run in foreground\n"); +#endif + printf(" -t | management UDP port, for multiple edges on a machine,\n" + " | defaults to %u\n", N2N_EDGE_MGMT_PORT); + printf(" --management_... | management port password, defaults to '%s'\n" + " ...password | \n", N2N_MGMT_PASSWORD); + printf(" -v | make more verbose, repeat as required\n"); + printf(" -n | route an IPv4 network via the gateway, use 0.0.0.0/0 for\n" + " | the default gateway, can be set multiple times\n"); +#ifndef WIN32 + printf(" -u | numeric user ID to use when privileges are dropped\n"); + printf(" -g | numeric group ID to use when privileges are dropped\n"); +#endif + printf ("\n"); + printf (" ENVIRONMENT VARIABLES\n"); + printf (" ---------------------\n\n"); + printf(" N2N_KEY | encryption key (ASCII), not with '-k ...'\n"); + printf(" N2N_COMMUNITY | community name (ASCII), overwritten by '-c ...'\n"); + printf(" N2N_PASSWORD | password (ASCII) for user-password authentication,\n" + " | overwritten by '-J ...'\n"); +#ifdef WIN32 + printf ("\n"); + printf (" AVAILABLE TAP ADAPTERS\n"); + printf (" ----------------------\n\n"); + win_print_available_adapters(); +#endif + printf ("\n" + "\n -h shows a quick reference including all available options" + "\n --help gives this detailed parameter description" + "\n man files for n2n, edge, and superndode contain in-depth information" + "\n\n"); + } + + exit(0); +} + +/* *************************************************** */ + +static void setPayloadCompression (n2n_edge_conf_t *conf, int compression) { + + /* even though 'compression' and 'conf->compression' share the same encoding scheme, + * a switch-statement under conditional compilation is used to sort out the + * unsupported optarguments */ + switch (compression) { + case 1: { + conf->compression = N2N_COMPRESSION_ID_LZO; + break; + } +#ifdef HAVE_ZSTD + case 2: { + conf->compression = N2N_COMPRESSION_ID_ZSTD; + break; + } +#endif + default: { + conf->compression = N2N_COMPRESSION_ID_NONE; + // internal comrpession scheme numbering differs from cli counting by one, hence plus one + // (internal: 0 == invalid, 1 == none, 2 == lzo, 3 == zstd) + traceEvent(TRACE_NORMAL, "the %s compression given by -z_ option is not supported in this version", compression_str(compression + 1)); + exit(1); // to make the user aware + } + } +} + +/* *************************************************** */ + +static void setPayloadEncryption (n2n_edge_conf_t *conf, int cipher) { + + /* even though 'cipher' and 'conf->transop_id' share the same encoding scheme, + * a switch-statement under conditional compilation is used to sort out the + * unsupported ciphers */ + switch (cipher) { + case 1: { + conf->transop_id = N2N_TRANSFORM_ID_NULL; + break; + } + + case 2: { + conf->transop_id = N2N_TRANSFORM_ID_TWOFISH; + break; + } + + case 3: { + conf->transop_id = N2N_TRANSFORM_ID_AES; + break; + } + + case 4: { + conf->transop_id = N2N_TRANSFORM_ID_CHACHA20; + break; + } + + case 5: { + conf->transop_id = N2N_TRANSFORM_ID_SPECK; + break; + } + + default: { + conf->transop_id = N2N_TRANSFORM_ID_INVAL; + traceEvent(TRACE_NORMAL, "the %s cipher given by -A_ option is not supported in this version", transop_str(cipher)); + exit(1); + } + } +} + +/* *************************************************** */ + +static int setOption (int optkey, char *optargument, n2n_tuntap_priv_config_t *ec, n2n_edge_conf_t *conf) { + + /* traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, optargument ? optargument : ""); */ + + switch(optkey) { + case 'a': /* IP address and mode of TUNTAP interface */ { + scan_address(ec->ip_addr, N2N_NETMASK_STR_SIZE, + ec->netmask, N2N_NETMASK_STR_SIZE, + ec->ip_mode, N2N_IF_MODE_SIZE, + optargument); + break; + } + + case 'c': /* community as a string */ { + strncpy((char *)conf->community_name, optargument, N2N_COMMUNITY_SIZE); + conf->community_name[N2N_COMMUNITY_SIZE - 1] = '\0'; + break; + } + + case 'E': /* multicast ethernet addresses accepted. */ { + conf->drop_multicast = 0; + traceEvent(TRACE_INFO, "enabling ethernet multicast traffic"); + break; + } + +#ifndef WIN32 + case 'u': /* unprivileged uid */ { + ec->userid = atoi(optargument); + break; + } + + case 'g': /* unprivileged uid */ { + ec->groupid = atoi(optargument); + break; + } +#endif + +#ifndef WIN32 + case 'f' : /* do not fork as daemon */ { + ec->daemon = 0; + break; + } +#endif /* #ifndef WIN32 */ + + case 'm' : /* TUNTAP MAC address */ { + strncpy(ec->device_mac, optargument, N2N_MACNAMSIZ); + ec->device_mac[N2N_MACNAMSIZ - 1] = '\0'; + break; + } + + case 'M' : /* TUNTAP MTU */ { + ec->mtu = atoi(optargument); + break; + } + +#ifndef __APPLE__ + case 'D' : /* enable PMTU discovery */ { + conf->disable_pmtu_discovery = 0; + break; + } +#endif + + case 'k': /* encrypt key */ { + if(conf->encrypt_key) free(conf->encrypt_key); + conf->encrypt_key = strdup(optargument); + traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", conf->encrypt_key); + break; + } + + case 'r': /* enable packet routing across n2n endpoints */ { + conf->allow_routing = 1; + break; + } + + case 'A': { + int cipher; + + if(optargument) { + cipher = atoi(optargument); + } else { + traceEvent(TRACE_WARNING, "the use of the solitary -A switch is deprecated and will not be supported in future versions, " + "please use -A3 instead to choose AES cipher for payload encryption"); + + cipher = N2N_TRANSFORM_ID_AES; // default, if '-A' only + } + + setPayloadEncryption(conf, cipher); + break; + } + + case 'H': /* indicate header encryption */ { + /* we cannot be sure if this gets parsed before the community name is set. + * so, only an indicator is set, action is taken later*/ + conf->header_encryption = HEADER_ENCRYPTION_ENABLED; + break; + } + + case 'z': { + int compression; + + if(optargument) { + compression = atoi(optargument); + } else { + traceEvent(TRACE_WARNING, "the use of the solitary -z switch is deprecated and will not be supported in future versions, " + "please use -z1 instead to choose LZO1X algorithm for payload compression"); + + compression = 1; // default, if '-z' only, equals -z1 + } + + setPayloadCompression(conf, compression); + break; + } + + case 'l': /* supernode-list */ { + if(optargument) { + if(edge_conf_add_supernode(conf, optargument) != 0) { + traceEvent(TRACE_WARNING, "failed to add supernode '%s'", optargument); + } + } + break; + } + + case 'i': /* supernode registration interval */ + conf->register_interval = atoi(optargument); + break; + + case 'L': /* supernode registration interval */ + conf->register_ttl = atoi(optarg); + break; + +#if defined(N2N_CAN_NAME_IFACE) + case 'd': /* TUNTAP name */ { + strncpy(ec->tuntap_dev_name, optargument, N2N_IFNAMSIZ); + ec->tuntap_dev_name[N2N_IFNAMSIZ - 1] = '\0'; + break; + } +#endif + case 'I': /* Device Description (hint) or username */ { + strncpy((char *)conf->dev_desc, optargument, N2N_DESC_SIZE); + conf->dev_desc[N2N_DESC_SIZE - 1] = '\0'; + break; + } + + case 'J': /* password for user-password authentication */ { + if(!conf->shared_secret) /* we could already have it from environment variable, see edge_init_conf_defaults() */ + conf->shared_secret = calloc(1, sizeof(n2n_private_public_key_t)); + if(conf->shared_secret) + generate_private_key(*(conf->shared_secret), optargument); + + // the hash of the username (-I) gets xored into this key later, + // we can't be sure to already have it at this point + // also, the complete shared secret will be calculated then as we + // might still be missing the federation public key as well + break; + } + + case 'P': /* federation public key for user-password authentication */ { + if(strlen(optargument) < ((N2N_PRIVATE_PUBLIC_KEY_SIZE * 8 + 5)/ 6 + 1)) { + conf->federation_public_key = calloc(1, sizeof(n2n_private_public_key_t)); + if(conf->federation_public_key) { + ascii_to_bin(*(conf->federation_public_key), optargument); + } + } else { + traceEvent(TRACE_WARNING, "public key too long"); + return 2; + } + break; + } + + case 'p': { + char* colon = strpbrk(optargument, ":"); + if(colon) { /*ip address:port */ + *colon = 0; + conf->bind_address = ntohl(inet_addr(optargument)); + conf->local_port = atoi(++colon); + + if(conf->bind_address == INADDR_NONE) { + traceEvent(TRACE_WARNING, "bad address to bind to, binding to any IP address"); + conf->bind_address = INADDR_ANY; + } + if(conf->local_port == 0) { + traceEvent(TRACE_WARNING, "bad local port format, using OS assigned port"); + } + } else { /* ip address or port only */ + char* dot = strpbrk(optargument, "."); + if(dot) { /* ip address only */ + conf->bind_address = ntohl(inet_addr(optargument)); + if(conf->bind_address == INADDR_NONE) { + traceEvent(TRACE_WARNING, "bad address to bind to, binding to any IP address"); + conf->bind_address = INADDR_ANY; + } + } else { /* port only */ + conf->local_port = atoi(optargument); + if(conf->local_port == 0) { + traceEvent(TRACE_WARNING, "bad local port format, using OS assigned port"); + } + } + } + break; + } + + case 'e': { + in_addr_t address_tmp; + + if(optargument) { + + if(!strcmp(optargument, "auto")) { + address_tmp = INADDR_ANY; + conf->preferred_sock_auto = 1; + } else { + address_tmp = inet_addr(optargument); + } + + memcpy(&(conf->preferred_sock.addr.v4), &(address_tmp), IPV4_SIZE); + + if(address_tmp == INADDR_NONE) { + traceEvent(TRACE_WARNING, "bad address for preferred local socket, skipping"); + conf->preferred_sock.family = AF_INVALID; + break; + } else { + conf->preferred_sock.family = AF_INET; + // port is set after parsing all cli parameters during supernode_connect() + } + + } + + break; + } + + case 't': { + conf->mgmt_port = atoi(optargument); + break; + } +#ifdef __linux__ + case 'T': { + if((optargument[0] == '0') && (optargument[1] == 'x')) + conf->tos = strtol(&optargument[2], NULL, 16); + else + conf->tos = atoi(optargument); + + break; + } +#endif + case 'n': { + char cidr_net[64], gateway[64]; + n2n_route_t route; + + if(sscanf(optargument, "%63[^/]/%hhd:%63s", cidr_net, &route.net_bitlen, gateway) != 3) { + traceEvent(TRACE_WARNING, "bad cidr/gateway format '%d'", optargument); + return 2; + } + + route.net_addr = inet_addr(cidr_net); + route.gateway = inet_addr(gateway); + + if((route.net_bitlen < 0) || (route.net_bitlen > 32)) { + traceEvent(TRACE_WARNING, "bad prefix '%d' in '%s'", route.net_bitlen, optargument); + return 2; + } + + if(route.net_addr == INADDR_NONE) { + traceEvent(TRACE_WARNING, "bad network '%s' in '%s'", cidr_net, optargument); + return 2; + } + + if(route.gateway == INADDR_NONE) { + traceEvent(TRACE_WARNING, "bad gateway '%s' in '%s'", gateway, optargument); + return 2; + } + + traceEvent(TRACE_NORMAL, "adding %s/%d via %s", cidr_net, route.net_bitlen, gateway); + + conf->routes = realloc(conf->routes, sizeof(struct n2n_route) * (conf->num_routes + 1)); + conf->routes[conf->num_routes] = route; + conf->num_routes++; + + break; + } + + case 'S': { + int solitude; + if(optargument) { + solitude = atoi(optargument); + } else { + traceEvent(TRACE_WARNING, "the use of the solitary -S switch is deprecated and will not be supported in future versions, " + "please use -S1 instead to choose supernode-only connection via UDP"); + + solitude = 1; + } + + // set the level + if(solitude >= 1) + conf->allow_p2p = 0; +#ifdef N2N_HAVE_TCP + if(solitude == 2) + conf->connect_tcp = 1; +#endif + break; + } + + case '[': /* round-trip-time-based supernode selection strategy */ { + // overwrites the default load-based strategy + conf->sn_selection_strategy = SN_SELECTION_STRATEGY_RTT; + + break; + } + + case ']': /* mac-address-based supernode selection strategy */ { + // overwrites the default load-based strategy + conf->sn_selection_strategy = SN_SELECTION_STRATEGY_MAC; + + break; + } + + case '{': /* password for management port */ { + conf->mgmt_password_hash = pearson_hash_64((uint8_t*)optargument, strlen(optargument)); + + break; + } + + case '}': /* disable port forwarding */ { + conf->port_forwarding = 0; + + break; + } + + case 'h': /* quick reference */ { + return 2; + } + + case '@': /* long help */ { + return 3; + } + + case 'v': /* verbose */ + setTraceLevel(getTraceLevel() + 1); + break; + + case 'R': /* network traffic filter */ { + filter_rule_t *new_rule = malloc(sizeof(filter_rule_t)); + memset(new_rule, 0, sizeof(filter_rule_t)); + + if(process_traffic_filter_rule_str(optargument, new_rule)) { + HASH_ADD(hh, conf->network_traffic_filter_rules, key, sizeof(filter_rule_key_t), new_rule); + } else { + free(new_rule); + traceEvent(TRACE_WARNING, "invalid filter rule: %s", optargument); + return 2; + } + break; + } +#ifdef WIN32 + case 'x': { + conf->metric = atoi(optargument); + ec->metric = atoi(optargument); + break; + } +#endif + default: { + traceEvent(TRACE_WARNING, "unknown option -%c", (char)optkey); + return 2; + } + } + + return 0; +} + +/* *********************************************** */ + + +static const struct option long_options[] = + { + { "community", required_argument, NULL, 'c' }, + { "supernode-list", required_argument, NULL, 'l' }, + { "tap-device", required_argument, NULL, 'd' }, + { "euid", required_argument, NULL, 'u' }, + { "egid", required_argument, NULL, 'g' }, + { "verbose", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, '@' }, /* internal special character '@' to identify long help case */ + { "select-rtt", no_argument, NULL, '[' }, /* '[' rtt selection strategy */ + { "select-mac", no_argument, NULL, ']' }, /* ']' mac selection strategy */ + { "management-password", required_argument, NULL, '{' }, /* '{' management port password */ + { "no-port-forwarding", no_argument, NULL, '}' }, /* '}' disable port forwarding */ + { NULL, 0, NULL, 0 } + }; + +/* *************************************************** */ + +/* read command line options */ +static int loadFromCLI (int argc, char *argv[], n2n_edge_conf_t *conf, n2n_tuntap_priv_config_t *ec) { + + u_char c; + + while ((c = getopt_long(argc, argv, + "k:a:c:Eu:g:m:M:s:d:l:p:fvhrt:i:I:J:P:S::DL:z::A::Hn:R:e:" +#ifdef __linux__ + "T:" +#endif +#ifdef WIN32 + "x:" +#endif + , + long_options, NULL)) != '?') { + + if(c == 255) break; + help(setOption(c, optarg, ec, conf)); + + } + + return 0; +} + +/* *************************************************** */ + +static char *trim (char *s) { + + char *end; + + while(isspace(s[0]) || (s[0] == '"') || (s[0] == '\'')) s++; + if(s[0] == 0) return s; + + end = &s[strlen(s) - 1]; + while(end > s + && (isspace(end[0])|| (end[0] == '"') || (end[0] == '\''))) + end--; + end[1] = 0; + + return s; +} + +/* *************************************************** */ + +/* parse the configuration file */ +static int loadFromFile (const char *path, n2n_edge_conf_t *conf, n2n_tuntap_priv_config_t *ec) { + + char buffer[4096], *line; + char *line_vec[3]; + int tmp; + + FILE *fd; + + fd = fopen(path, "r"); + + if(fd == NULL) { + traceEvent(TRACE_WARNING, "config file %s not found", path); + return -1; + } + + // we mess around with optind, better save it + tmp = optind; + + while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { + line = trim(line); + + if(strlen(line) < 2 || line[0] == '#') + continue; + + // executable, cannot be omitted, content can be anything + line_vec[0] = line; + // first token, e.g. `-p` or `-A3', eventually followed by a whitespace or '=' delimiter + line_vec[1] = strtok(line, "\t ="); + // separate parameter option, if present + line_vec[2] = strtok(NULL, ""); + if(line_vec[2]) + line_vec[2] = trim(line_vec[2]); + // not to duplicate the option parser code, call loadFromCLI and pretend we have no option read yet at all + optind = 0; + // if second token present (optional argument, not part of first), then announce 3 vector members + loadFromCLI(line_vec[2] ? 3 : 2, line_vec, conf, ec); + } + + fclose(fd); + optind = tmp; + + return 0; +} + +/* ************************************** */ + +#ifndef WIN32 +static void daemonize () { + int childpid; + + traceEvent(TRACE_NORMAL, "parent process is exiting (this is normal)"); + + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + + if((childpid = fork()) < 0) + traceEvent(TRACE_ERROR, "occurred while daemonizing (errno=%d)", + errno); + else { + if(!childpid) { /* child */ + int rc; + + //traceEvent(TRACE_NORMAL, "Bye bye: I'm becoming a daemon..."); + rc = chdir("/"); + if(rc != 0) + traceEvent(TRACE_ERROR, "error while moving to / directory"); + + setsid(); /* detach from the terminal */ + + fclose(stdin); + fclose(stdout); + /* fclose(stderr); */ + + /* + * clear any inherited file mode creation mask + */ + //umask(0); + + /* + * Use line buffered stdout + */ + /* setlinebuf (stdout); */ + setvbuf(stdout, (char *)NULL, _IOLBF, 0); + } else /* father */ + exit(0); + } +} +#endif + +/* *************************************************** */ + +static int keep_on_running; + +#if defined(__linux__) || defined(WIN32) +#ifdef WIN32 +BOOL WINAPI term_handler(DWORD sig) +#else + static void term_handler(int sig) +#endif +{ + static int called = 0; + + if(called) { + traceEvent(TRACE_NORMAL, "ok, I am leaving now"); + _exit(0); + } else { + traceEvent(TRACE_NORMAL, "shutting down..."); + called = 1; + } + + keep_on_running = 0; +#ifdef WIN32 + return(TRUE); +#endif +} +#endif /* defined(__linux__) || defined(WIN32) */ + +/* *************************************************** */ + +/** Entry point to program from kernel. */ +int main (int argc, char* argv[]) { + + int rc; + tuntap_dev tuntap; /* a tuntap device */ + n2n_edge_t *eee; /* single instance for this program */ + n2n_edge_conf_t conf; /* generic N2N edge config */ + n2n_tuntap_priv_config_t ec; /* config used for standalone program execution */ + uint8_t runlevel = 0; /* bootstrap: runlevel */ + uint8_t seek_answer = 1; /* expecting answer from supernode */ + time_t now, last_action = 0; /* timeout */ + macstr_t mac_buf; /* output mac address */ + fd_set socket_mask; /* for supernode answer */ + struct timeval wait_time; /* timeout for sn answer */ + peer_info_t *scan, *scan_tmp; /* supernode iteration */ + + uint16_t expected = sizeof(uint16_t); + uint16_t position = 0; + uint8_t pktbuf[N2N_SN_PKTBUF_SIZE + sizeof(uint16_t)]; /* buffer + prepended buffer length in case of tcp */ + + +#ifndef WIN32 + struct passwd *pw = NULL; +#endif +#ifdef HAVE_LIBCAP + cap_t caps; +#endif +#ifdef WIN32 + initWin32(); +#endif + + /* Defaults */ + edge_init_conf_defaults(&conf); + memset(&ec, 0, sizeof(ec)); + ec.mtu = DEFAULT_MTU; + ec.daemon = 1; /* By default run in daemon mode. */ + +#ifndef WIN32 + if(((pw = getpwnam("n2n")) != NULL) || + ((pw = getpwnam("nobody")) != NULL)) { + ec.userid = pw->pw_uid; + ec.groupid = pw->pw_gid; + } +#endif + +#ifdef WIN32 + ec.tuntap_dev_name[0] = '\0'; + ec.metric = 0; +#else + snprintf(ec.tuntap_dev_name, sizeof(ec.tuntap_dev_name), N2N_EDGE_DEFAULT_DEV_NAME); +#endif + snprintf(ec.netmask, sizeof(ec.netmask), N2N_EDGE_DEFAULT_NETMASK); + + if((argc >= 2) && (argv[1][0] != '-')) { + rc = loadFromFile(argv[1], &conf, &ec); + if(argc > 2) + rc = loadFromCLI(argc, argv, &conf, &ec); + } else if(argc > 1) + rc = loadFromCLI(argc, argv, &conf, &ec); + else + +#ifdef WIN32 + // load from current directory + rc = loadFromFile("edge.conf", &conf, &ec); +#else + rc = -1; +#endif + + // --- additional crypto setup; REVISIT: move to edge_init()? + // payload + if(conf.transop_id == N2N_TRANSFORM_ID_NULL) { + if(conf.encrypt_key) { + // make sure that AES is default cipher if key only (and no cipher) is specified + traceEvent(TRACE_WARNING, "switching to AES as key was provided"); + conf.transop_id = N2N_TRANSFORM_ID_AES; + } + } + // user auth + if(conf.shared_secret /* containing private key only so far*/) { + // if user-password auth and no federation public key provided, use default + if(!conf.federation_public_key) { + conf.federation_public_key = calloc(1, sizeof(n2n_private_public_key_t)); + if(conf.federation_public_key) { + traceEvent(TRACE_WARNING, "using default federation public key; FOR TESTING ONLY, usage of a custom federation name and key (-P) is highly recommended!"); + generate_private_key(*(conf.federation_public_key), &FEDERATION_NAME[1]); + generate_public_key(*(conf.federation_public_key), *(conf.federation_public_key)); + } + } + // calculate public key and shared secret + if(conf.federation_public_key) { + traceEvent(TRACE_NORMAL, "using username and password for edge authentication"); + bind_private_key_to_username(*(conf.shared_secret), (char *)conf.dev_desc); + conf.public_key = calloc(1, sizeof(n2n_private_public_key_t)); + if(conf.public_key) + generate_public_key(*conf.public_key, *(conf.shared_secret)); + generate_shared_secret(*(conf.shared_secret), *(conf.shared_secret), *(conf.federation_public_key)); + // prepare (first 128 bit) for use as key + conf.shared_secret_ctx = (he_context_t*)calloc(1, sizeof(speck_context_t)); + speck_init((speck_context_t**)&(conf.shared_secret_ctx), *(conf.shared_secret), 128); + } + // force header encryption + if(conf.header_encryption != HEADER_ENCRYPTION_ENABLED) { + traceEvent(TRACE_NORMAL, "enabling header encryption for edge authentication"); + conf.header_encryption = HEADER_ENCRYPTION_ENABLED; + } + } + + if(rc < 0) + help(1); /* short help */ + + if(edge_verify_conf(&conf) != 0) + help(1); /* short help */ + + traceEvent(TRACE_NORMAL, "starting n2n edge %s %s", PACKAGE_VERSION, PACKAGE_BUILDDATE); + +#if defined(HAVE_OPENSSL_1_1) + traceEvent(TRACE_NORMAL, "using %s", OpenSSL_version(0)); +#endif + + traceEvent(TRACE_NORMAL, "using compression: %s.", compression_str(conf.compression)); + traceEvent(TRACE_NORMAL, "using %s cipher.", transop_str(conf.transop_id)); + + /* Random seed */ + n2n_srand (n2n_seed()); + +#ifndef WIN32 + /* If running suid root then we need to setuid before using the force. */ + if(setuid(0) != 0) + traceEvent(TRACE_ERROR, "unable to become root [%u/%s]", errno, strerror(errno)); + /* setgid(0); */ +#endif + + if(conf.encrypt_key && !strcmp((char*)conf.community_name, conf.encrypt_key)) + traceEvent(TRACE_WARNING, "community and encryption key must differ, otherwise security will be compromised"); + + if((eee = edge_init(&conf, &rc)) == NULL) { + traceEvent(TRACE_ERROR, "failed in edge_init"); + exit(1); + } + + memcpy(&(eee->tuntap_priv_conf), &ec, sizeof(ec)); + + if((0 == strcmp("static", eee->tuntap_priv_conf.ip_mode)) || + ((eee->tuntap_priv_conf.ip_mode[0] == '\0') && (eee->tuntap_priv_conf.ip_addr[0] != '\0'))) { + traceEvent(TRACE_NORMAL, "use manually set IP address"); + eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_STATIC; + } else if(0 == strcmp("dhcp", eee->tuntap_priv_conf.ip_mode)) { + traceEvent(TRACE_NORMAL, "obtain IP from other edge DHCP services"); + eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_DHCP; + } else { + traceEvent(TRACE_NORMAL, "automatically assign IP address by supernode"); + eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; + } + + // mini main loop for bootstrap, not using main loop code because some of its mechanisms do not fit in here + // for the sake of quickly establishing connection. REVISIT when a more elegant way to re-use main loop code + // is found + + // find at least one supernode alive to faster establish connection + // exceptions: + if((HASH_COUNT(eee->conf.supernodes) <= 1) || (eee->conf.connect_tcp) || (eee->conf.shared_secret)) { + // skip the initial supernode ping + traceEvent(TRACE_DEBUG, "skip PING to supernode"); + runlevel = 2; + } + + eee->last_sup = 0; /* if it wasn't zero yet */ + eee->curr_sn = eee->conf.supernodes; + supernode_connect(eee); + while(runlevel < 5) { + + now = time(NULL); + + // we do not use switch-case because we also check for 'greater than' + + if(runlevel == 0) { /* PING to all known supernodes */ + last_action = now; + eee->sn_pong = 0; + // (re-)initialize the number of max concurrent pings (decreases by calling send_query_peer) + eee->conf.number_max_sn_pings = NUMBER_SN_PINGS_INITIAL; + send_query_peer(eee, null_mac); + traceEvent(TRACE_NORMAL, "send PING to supernodes"); + runlevel++; + } + + if(runlevel == 1) { /* PING has been sent to all known supernodes */ + if(eee->sn_pong) { + // first answer + eee->sn_pong = 0; + sn_selection_sort(&(eee->conf.supernodes)); + eee->curr_sn = eee->conf.supernodes; + supernode_connect(eee); + traceEvent(TRACE_NORMAL, "received first PONG from supernode [%s]", eee->curr_sn->ip_addr); + runlevel++; + } else if(last_action <= (now - BOOTSTRAP_TIMEOUT)) { + // timeout + runlevel--; + // skip waiting for answer to direcly go to send PING again + seek_answer = 0; + traceEvent(TRACE_DEBUG, "PONG timeout"); + } + } + + // by the way, have every later PONG cause the remaining (!) list to be sorted because the entries + // before have already been tried; as opposed to initial PONG, do not change curr_sn + if(runlevel > 1) { + if(eee->sn_pong) { + eee->sn_pong = 0; + if(eee->curr_sn->hh.next) { + sn_selection_sort((peer_info_t**)&(eee->curr_sn->hh.next)); + traceEvent(TRACE_DEBUG, "received additional PONG from supernode"); + // here, it is hard to detemine from which one, so no details to output + } + } + } + + if(runlevel == 2) { /* send REGISTER_SUPER to get auto ip address from a supernode */ + if(eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_SN_ASSIGN) { + last_action = now; + eee->sn_wait = 1; + send_register_super(eee); + runlevel++; + traceEvent(TRACE_NORMAL, "send REGISTER_SUPER to supernode [%s] asking for IP address", + eee->curr_sn->ip_addr); + } else { + runlevel += 2; /* skip waiting for TUNTAP IP address */ + traceEvent(TRACE_DEBUG, "skip auto IP address asignment"); + } + } + + if(runlevel == 3) { /* REGISTER_SUPER to get auto ip address from a sn has been sent */ + if(!eee->sn_wait) { /* TUNTAP IP address received */ + runlevel++; + traceEvent(TRACE_NORMAL, "received REGISTER_SUPER_ACK from supernode for IP address asignment"); + // it should be from curr_sn, but we can't determine definitely here, so no details to output + } else if(last_action <= (now - BOOTSTRAP_TIMEOUT)) { + // timeout, so try next supernode + if(eee->curr_sn->hh.next) + eee->curr_sn = eee->curr_sn->hh.next; + else + eee->curr_sn = eee->conf.supernodes; + supernode_connect(eee); + runlevel--; + // skip waiting for answer to direcly go to send REGISTER_SUPER again + seek_answer = 0; + traceEvent(TRACE_DEBUG, "REGISTER_SUPER_ACK timeout"); + } + } + + if(runlevel == 4) { /* configure the TUNTAP device, including routes */ + if(tuntap_open(&tuntap, eee->tuntap_priv_conf.tuntap_dev_name, eee->tuntap_priv_conf.ip_mode, + eee->tuntap_priv_conf.ip_addr, eee->tuntap_priv_conf.netmask, + eee->tuntap_priv_conf.device_mac, eee->tuntap_priv_conf.mtu +#ifdef WIN32 + , eee->tuntap_priv_conf.metric +#endif + ) < 0) + exit(1); + memcpy(&eee->device, &tuntap, sizeof(tuntap)); + traceEvent(TRACE_NORMAL, "created local tap device IP: %s, Mask: %s, MAC: %s", + eee->tuntap_priv_conf.ip_addr, + eee->tuntap_priv_conf.netmask, + macaddr_str(mac_buf, eee->device.mac_addr)); + // routes + if(edge_init_routes(eee, eee->conf.routes, eee->conf.num_routes) < 0) { + traceEvent(TRACE_ERROR, "routes setup failed"); + exit(1); + } + runlevel = 5; + // no more answers required + seek_answer = 0; + } + + // we usually wait for some answer, there however are exceptions when going back to a previous runlevel + if(seek_answer) { + FD_ZERO(&socket_mask); + FD_SET(eee->sock, &socket_mask); + wait_time.tv_sec = BOOTSTRAP_TIMEOUT; + wait_time.tv_usec = 0; + + if(select(eee->sock + 1, &socket_mask, NULL, NULL, &wait_time) > 0) { + if(FD_ISSET(eee->sock, &socket_mask)) { + + fetch_and_eventually_process_data (eee, eee->sock, + pktbuf, &expected, &position, + now); + } + } + } + seek_answer = 1; + + resolve_check(eee->resolve_parameter, 0 /* no intermediate resolution requirement at this point */, now); + } + // allow a higher number of pings for first regular round of ping + // to quicker get an inital 'supernode selection criterion overview' + eee->conf.number_max_sn_pings = NUMBER_SN_PINGS_INITIAL; + // shape supernode list; make current one the first on the list + HASH_ITER(hh, eee->conf.supernodes, scan, scan_tmp) { + if(scan == eee->curr_sn) + sn_selection_criterion_good(&(scan->selection_criterion)); + else + sn_selection_criterion_default(&(scan->selection_criterion)); + } + sn_selection_sort(&(eee->conf.supernodes)); + // do not immediately ping again, allow some time + eee->last_sweep = now - SWEEP_TIME + 2 * BOOTSTRAP_TIMEOUT; + eee->sn_wait = 1; + eee->last_register_req = 0; + +#ifndef WIN32 + if(eee->tuntap_priv_conf.daemon) { + setUseSyslog(1); /* traceEvent output now goes to syslog. */ + daemonize(); + } + +#ifdef HAVE_LIBCAP + /* Before dropping the privileges, retain capabilities to regain them in future. */ + caps = cap_get_proc(); + + cap_set_flag(caps, CAP_PERMITTED, num_cap, cap_values, CAP_SET); + cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET); + + if((cap_set_proc(caps) != 0) || (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0)) + traceEvent(TRACE_WARNING, "unable to retain permitted capabilities [%s]\n", strerror(errno)); +#else +#ifndef __APPLE__ + traceEvent(TRACE_WARNING, "n2n has not been compiled with libcap-dev; some commands may fail"); +#endif +#endif /* HAVE_LIBCAP */ + + if((eee->tuntap_priv_conf.userid != 0) || (eee->tuntap_priv_conf.groupid != 0)) { + traceEvent(TRACE_NORMAL, "dropping privileges to uid=%d, gid=%d", + (signed int)eee->tuntap_priv_conf.userid, (signed int)eee->tuntap_priv_conf.groupid); + + /* Finished with the need for root privileges. Drop to unprivileged user. */ + if((setgid(eee->tuntap_priv_conf.groupid) != 0) + || (setuid(eee->tuntap_priv_conf.userid) != 0)) { + traceEvent(TRACE_ERROR, "unable to drop privileges [%u/%s]", errno, strerror(errno)); + exit(1); + } + } + + if((getuid() == 0) || (getgid() == 0)) + traceEvent(TRACE_WARNING, "running as root is discouraged, check out the -u/-g options"); +#endif + +#ifdef __linux__ + signal(SIGPIPE, SIG_IGN); + signal(SIGTERM, term_handler); + signal(SIGINT, term_handler); +#endif +#ifdef WIN32 + SetConsoleCtrlHandler(term_handler, TRUE); +#endif + + keep_on_running = 1; + eee->keep_running = &keep_on_running; + traceEvent(TRACE_NORMAL, "edge started"); + rc = run_edge_loop(eee); + print_edge_stats(eee); + +#ifdef HAVE_LIBCAP + /* Before completing the cleanup, regain the capabilities as some + * cleanup tasks require them (e.g. routes cleanup). */ + cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET); + + if(cap_set_proc(caps) != 0) + traceEvent(TRACE_WARNING, "could not regain the capabilities [%s]\n", strerror(errno)); + + cap_free(caps); +#endif + + /* Cleanup */ + edge_term_conf(&eee->conf); + tuntap_close(&eee->device); + edge_term(eee); + +#ifdef WIN32 + destroyWin32(); +#endif + + return(rc); +} + +/* ************************************** */ diff --git a/src/edge_management.c b/src/edge_management.c new file mode 100644 index 0000000..1a472f0 --- /dev/null +++ b/src/edge_management.c @@ -0,0 +1,898 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" +#include "edge_utils_win32.h" + +typedef struct strbuf { + size_t size; + char str[]; +} strbuf_t; + +#define STRBUF_INIT(buf,p) do { \ + buf = (void *)p; \ + buf->size = sizeof(*p) - sizeof(size_t); \ +} while(0) + +enum n2n_mgmt_type { + N2N_MGMT_UNKNOWN = 0, + N2N_MGMT_READ = 1, + N2N_MGMT_WRITE = 2, + N2N_MGMT_SUB = 3, +}; + +/* + * Everything needed to reply to a request + */ +typedef struct mgmt_req { + n2n_edge_t *eee; + enum n2n_mgmt_type type; + char tag[10]; + struct sockaddr_in sender_sock; +} mgmt_req_t; + +/* + * Read/Write handlers are defined in this structure + */ +#define FLAG_WROK 1 +typedef struct mgmt_handler { + int flags; + char *cmd; + char *help; + void (*func)(mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv); +} mgmt_handler_t; + +/* + * Event topic names are defined in this structure + */ +typedef struct mgmt_events { + enum n2n_event_topic topic; + char *cmd; + char *help; +} mgmt_events_t; + +// Lookup the index of matching argv0 in a cmd list +// store index in "Result", or -1 for not found +#define lookup_handler(Result, list, argv0) do { \ + int nr_max = sizeof(list) / sizeof(list[0]); \ + for( Result=0; Result < nr_max; Result++ ) { \ + if(0 == strcmp(list[Result].cmd, argv0)) { \ + break; \ + } \ + } \ + if( Result >= nr_max ) { \ + Result = -1; \ + } \ +} while(0) + +ssize_t send_reply (mgmt_req_t *req, strbuf_t *buf, size_t msg_len) { + // TODO: better error handling (counters?) + return sendto(req->eee->udp_mgmt_sock, buf->str, msg_len, 0, + (struct sockaddr *) &req->sender_sock, sizeof(struct sockaddr_in)); +} + +size_t gen_json_1str (strbuf_t *buf, char *tag, char *_type, char *key, char *val) { + return snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"%s\"," + "\"%s\":\"%s\"}\n", + tag, + _type, + key, + val); +} + +size_t gen_json_1uint (strbuf_t *buf, char *tag, char *_type, char *key, unsigned int val) { + return snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"%s\"," + "\"%s\":%u}\n", + tag, + _type, + key, + val); +} + +static void send_json_1str (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, char *val) { + size_t msg_len = gen_json_1str(buf, req->tag, _type, key, val); + send_reply(req, buf, msg_len); +} + +static void send_json_1uint (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, unsigned int val) { + size_t msg_len = gen_json_1uint(buf, req->tag, _type, key, val); + send_reply(req, buf, msg_len); +} + +size_t event_debug (strbuf_t *buf, char *tag, int data0, void *data1) { + traceEvent(TRACE_DEBUG, "Unexpected call to event_debug"); + return 0; +} + +size_t event_test (strbuf_t *buf, char *tag, int data0, void *data1) { + size_t msg_len = gen_json_1str(buf, tag, "event", "test", (char *)data1); + return msg_len; +} + +size_t event_peer (strbuf_t *buf, char *tag, int data0, void *data1) { + int action = data0; + struct peer_info *peer = (struct peer_info *)data1; + + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + /* + * Just the peer_info bits that are needed for lookup (maccaddr) or + * firewall and routing (sockaddr) + * If needed, other details can be fetched via the edges method call. + */ + return snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"event\"," + "\"action\":%i," + "\"macaddr\":\"%s\"," + "\"sockaddr\":\"%s\"}\n", + tag, + action, + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock))); +} + +static void mgmt_error (mgmt_req_t *req, strbuf_t *buf, char *msg) { + send_json_1str(req, buf, "error", "error", msg); +} + +static void mgmt_stop (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + + if(req->type==N2N_MGMT_WRITE) { + *req->eee->keep_running = 0; + } + + send_json_1uint(req, buf, "row", "keep_running", *req->eee->keep_running); +} + +static void mgmt_verbose (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + + if(req->type==N2N_MGMT_WRITE) { + if(argv) { + setTraceLevel(strtoul(argv, NULL, 0)); + } + } + + send_json_1uint(req, buf, "row", "traceLevel", getTraceLevel()); +} + +static void mgmt_communities (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + + if(req->eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) { + mgmt_error(req, buf, "noaccess"); + return; + } + + send_json_1str(req, buf, "row", "community", (char *)req->eee->conf.community_name); +} + +static void mgmt_supernodes (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + size_t msg_len; + struct peer_info *peer, *tmpPeer; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + selection_criterion_str_t sel_buf; + + HASH_ITER(hh, req->eee->conf.supernodes, peer, tmpPeer) { + + /* + * TODO: + * The version string provided by the remote supernode could contain + * chars that make our JSON invalid. + * - do we care? + */ + + msg_len = snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"version\":\"%s\"," + "\"purgeable\":%i," + "\"current\":%i," + "\"macaddr\":\"%s\"," + "\"sockaddr\":\"%s\"," + "\"selection\":\"%s\"," + "\"last_seen\":%li," + "\"uptime\":%li}\n", + req->tag, + peer->version, + peer->purgeable, + (peer == req->eee->curr_sn) ? (req->eee->sn_wait ? 2 : 1 ) : 0, + is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + sn_selection_criterion_str(req->eee, sel_buf, peer), + peer->last_seen, + peer->uptime); + + send_reply(req, buf, msg_len); + } +} + +static void mgmt_edges_row (mgmt_req_t *req, strbuf_t *buf, struct peer_info *peer, char *mode) { + size_t msg_len; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + dec_ip_bit_str_t ip_bit_str = {'\0'}; + + msg_len = snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"mode\":\"%s\"," + "\"ip4addr\":\"%s\"," + "\"purgeable\":%i," + "\"local\":%i," + "\"macaddr\":\"%s\"," + "\"sockaddr\":\"%s\"," + "\"desc\":\"%s\"," + "\"last_p2p\":%li,\n" + "\"last_sent_query\":%li,\n" + "\"last_seen\":%li}\n", + req->tag, + mode, + (peer->dev_addr.net_addr == 0) ? "" : ip_subnet_to_str(ip_bit_str, &peer->dev_addr), + peer->purgeable, + peer->local, + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + peer->dev_desc, + peer->last_p2p, + peer->last_sent_query, + peer->last_seen); + + send_reply(req, buf, msg_len); +} + +static void mgmt_edges (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + struct peer_info *peer, *tmpPeer; + + // dump nodes with forwarding through supernodes + HASH_ITER(hh, req->eee->pending_peers, peer, tmpPeer) { + mgmt_edges_row(req, buf, peer, "pSp"); + } + + // dump peer-to-peer nodes + HASH_ITER(hh, req->eee->known_peers, peer, tmpPeer) { + mgmt_edges_row(req, buf, peer, "p2p"); + } +} + +static void mgmt_timestamps (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + size_t msg_len; + + msg_len = snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"start_time\":%lu," + "\"last_super\":%ld," + "\"last_p2p\":%ld}\n", + req->tag, + req->eee->start_time, + req->eee->last_sup, + req->eee->last_p2p); + + send_reply(req, buf, msg_len); +} + +static void mgmt_packetstats (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + size_t msg_len; + + msg_len = snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"type\":\"transop\"," + "\"tx_pkt\":%lu," + "\"rx_pkt\":%lu}\n", + req->tag, + req->eee->transop.tx_cnt, + req->eee->transop.rx_cnt); + + send_reply(req, buf, msg_len); + + msg_len = snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"type\":\"p2p\"," + "\"tx_pkt\":%u," + "\"rx_pkt\":%u}\n", + req->tag, + req->eee->stats.tx_p2p, + req->eee->stats.rx_p2p); + + send_reply(req, buf, msg_len); + + msg_len = snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"type\":\"super\"," + "\"tx_pkt\":%u," + "\"rx_pkt\":%u}\n", + req->tag, + req->eee->stats.tx_sup, + req->eee->stats.rx_sup); + + send_reply(req, buf, msg_len); + + msg_len = snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"type\":\"super_broadcast\"," + "\"tx_pkt\":%u," + "\"rx_pkt\":%u}\n", + req->tag, + req->eee->stats.tx_sup_broadcast, + req->eee->stats.rx_sup_broadcast); + + send_reply(req, buf, msg_len); +} + +static void mgmt_post_test (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + + send_json_1str(req, buf, "row", "sending", "test"); + mgmt_event_post(N2N_EVENT_TEST, -1, argv); +} + +static void mgmt_unimplemented (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + + mgmt_error(req, buf, "unimplemented"); +} + +// Forward define so we can include this in the mgmt_handlers[] table +static void mgmt_help (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv); +static void mgmt_help_events (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv); + +static const mgmt_handler_t mgmt_handlers[] = { + { .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reserved for supernode", .func = mgmt_unimplemented}, + + { .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop}, + { .cmd = "verbose", .flags = FLAG_WROK, .help = "Manage verbosity level", .func = mgmt_verbose}, + { .cmd = "communities", .help = "Show current community", .func = mgmt_communities}, + { .cmd = "edges", .help = "List current edges/peers", .func = mgmt_edges}, + { .cmd = "supernodes", .help = "List current supernodes", .func = mgmt_supernodes}, + { .cmd = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps}, + { .cmd = "packetstats", .help = "traffic counters", .func = mgmt_packetstats}, + { .cmd = "post.test", .help = "send a test event", .func = mgmt_post_test}, + { .cmd = "help", .flags = FLAG_WROK, .help = "Show JSON commands", .func = mgmt_help}, + { .cmd = "help.events", .help = "Show available Subscribe topics", .func = mgmt_help_events}, +}; + +/* Current subscriber for each event topic */ +static mgmt_req_t mgmt_event_subscribers[] = { + [N2N_EVENT_DEBUG] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, + [N2N_EVENT_TEST] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, + [N2N_EVENT_PEER] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, +}; + +/* Map topic number to function */ +static const size_t (*mgmt_events[])(strbuf_t *buf, char *tag, int data0, void *data1) = { + [N2N_EVENT_DEBUG] = event_debug, + [N2N_EVENT_TEST] = event_test, + [N2N_EVENT_PEER] = event_peer, +}; + +/* Allow help and subscriptions to use topic name */ +static const mgmt_events_t mgmt_event_names[] = { + { .cmd = "debug", .topic = N2N_EVENT_DEBUG, .help = "All events - for event debugging"}, + { .cmd = "test", .topic = N2N_EVENT_TEST, .help = "Used only by post.test"}, + { .cmd = "peer", .topic = N2N_EVENT_PEER, .help = "Changes to peer list"}, +}; + +void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1) { + mgmt_req_t *debug = &mgmt_event_subscribers[N2N_EVENT_DEBUG]; + mgmt_req_t *sub = &mgmt_event_subscribers[topic]; + + traceEvent(TRACE_DEBUG, "post topic=%i data0=%i", topic, data0); + + if( sub->type != N2N_MGMT_SUB && debug->type != N2N_MGMT_SUB) { + // If neither of this topic or the debug topic have a subscriber + // then we dont need to do any work + return; + } + + char buf_space[100]; + strbuf_t *buf; + STRBUF_INIT(buf, buf_space); + + char *tag; + if(sub->type == N2N_MGMT_SUB) { + tag = sub->tag; + } else { + tag = debug->tag; + } + + size_t msg_len = mgmt_events[topic](buf, tag, data0, data1); + + if(sub->type == N2N_MGMT_SUB) { + send_reply(sub, buf, msg_len); + } + if(debug->type == N2N_MGMT_SUB) { + send_reply(debug, buf, msg_len); + } +} + +static void mgmt_help_events (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + size_t msg_len; + + int i; + int nr_handlers = sizeof(mgmt_event_names) / sizeof(mgmt_events_t); + for( i=0; i < nr_handlers; i++ ) { + int topic = mgmt_event_names[i].topic; + mgmt_req_t *sub = &mgmt_event_subscribers[topic]; + char host[40]; + char serv[6]; + + if((sub->type != N2N_MGMT_SUB) || + getnameinfo((struct sockaddr *)&sub->sender_sock, sizeof(sub->sender_sock), + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + host[0] = '?'; + host[1] = 0; + serv[0] = '?'; + serv[1] = 0; + } + + // TODO: handle a topic with no subscribers more cleanly + + msg_len = snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"topic\":\"%s\"," + "\"tag\":\"%s\"," + "\"sockaddr\":\"%s:%s\"," + "\"help\":\"%s\"}\n", + req->tag, + mgmt_event_names[i].cmd, + sub->tag, + host, serv, + mgmt_event_names[i].help); + + send_reply(req, buf, msg_len); + } +} + +static void mgmt_help (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + size_t msg_len; + + /* + * Even though this command is readonly, we deliberately do not check + * the type - allowing help replies to both read and write requests + */ + + int i; + int nr_handlers = sizeof(mgmt_handlers) / sizeof(mgmt_handler_t); + for( i=0; i < nr_handlers; i++ ) { + msg_len = snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"cmd\":\"%s\"," + "\"help\":\"%s\"}\n", + req->tag, + mgmt_handlers[i].cmd, + mgmt_handlers[i].help); + + send_reply(req, buf, msg_len); + } +} + +/* + * Check if the user is authorised for this command. + * - this should be more configurable! + * - for the moment we use some simple heuristics: + * Reads are not dangerous, so they are simply allowed + * Writes are possibly dangerous, so they need a fake password + */ +static int mgmt_auth (mgmt_req_t *req, char *auth, char *argv0, char *argv) { + + if(auth) { + /* If we have an auth key, it must match */ + if(req->eee->conf.mgmt_password_hash == pearson_hash_64((uint8_t*)auth, strlen(auth))) { + return 1; + } + return 0; + } + /* if we dont have an auth key, we can still read */ + if(req->type == N2N_MGMT_READ) { + return 1; + } + + return 0; +} + +static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { + + strbuf_t *buf; + char cmdlinebuf[80]; + char *typechar; + char *options; + char *argv0; + char *argv; + char *flagstr; + int flags; + char *auth; + + /* Initialise the tag field until we extract it from the cmdline */ + req->tag[0] = '-'; + req->tag[1] = '1'; + req->tag[2] = '\0'; + + /* save a copy of the commandline before we reuse the udp_buf */ + strncpy(cmdlinebuf, udp_buf, sizeof(cmdlinebuf)-1); + cmdlinebuf[sizeof(cmdlinebuf)-1] = 0; + + traceEvent(TRACE_DEBUG, "mgmt json %s", cmdlinebuf); + + /* we reuse the buffer already on the stack for all our strings */ + STRBUF_INIT(buf, udp_buf); + + typechar = strtok(cmdlinebuf, " \r\n"); + if(!typechar) { + /* should not happen */ + mgmt_error(req, buf, "notype"); + return; + } + if(*typechar == 'r') { + req->type=N2N_MGMT_READ; + } else if(*typechar == 'w') { + req->type=N2N_MGMT_WRITE; + } else if(*typechar == 's') { + req->type=N2N_MGMT_SUB; + } else { + mgmt_error(req, buf, "badtype"); + return; + } + + /* Extract the tag to use in all reply packets */ + options = strtok(NULL, " \r\n"); + if(!options) { + mgmt_error(req, buf, "nooptions"); + return; + } + + argv0 = strtok(NULL, " \r\n"); + if(!argv0) { + mgmt_error(req, buf, "nocmd"); + return; + } + + /* + * The entire rest of the line is the argv. We apply no processing + * or arg separation so that the cmd can use it however it needs. + */ + argv = strtok(NULL, "\r\n"); + + /* + * There might be an auth token mixed in with the tag + */ + char *tagp = strtok(options, ":"); + strncpy(req->tag, tagp, sizeof(req->tag)-1); + req->tag[sizeof(req->tag)-1] = '\0'; + + flagstr = strtok(NULL, ":"); + if(flagstr) { + flags = strtoul(flagstr, NULL, 16); + } else { + flags = 0; + } + + /* Only 1 flag bit defined at the moment - "auth option present" */ + if(flags & 1) { + auth = strtok(NULL, ":"); + } else { + auth = NULL; + } + + if(!mgmt_auth(req, auth, argv0, argv)) { + mgmt_error(req, buf, "badauth"); + return; + } + + if(req->type == N2N_MGMT_SUB) { + int handler; + lookup_handler(handler, mgmt_event_names, argv0); + if(handler == -1) { + mgmt_error(req, buf, "unknowntopic"); + return; + } + + int topic = mgmt_event_names[handler].topic; + if(mgmt_event_subscribers[topic].type == N2N_MGMT_SUB) { + send_json_1str(&mgmt_event_subscribers[topic], buf, + "unsubscribed", "topic", argv0); + send_json_1str(req, buf, "replacing", "topic", argv0); + } + + memcpy(&mgmt_event_subscribers[topic], req, sizeof(*req)); + + send_json_1str(req, buf, "subscribe", "topic", argv0); + return; + } + + int handler; + lookup_handler(handler, mgmt_handlers, argv0); + if(handler == -1) { + mgmt_error(req, buf, "unknowncmd"); + return; + } + + if((req->type==N2N_MGMT_WRITE) && !(mgmt_handlers[handler].flags & FLAG_WROK)) { + mgmt_error(req, buf, "readonly"); + return; + } + + /* + * TODO: + * The tag provided by the requester could contain chars + * that make our JSON invalid. + * - do we care? + */ + send_json_1str(req, buf, "begin", "cmd", argv0); + + mgmt_handlers[handler].func(req, buf, argv0, argv); + + send_json_1str(req, buf, "end", "cmd", argv0); + return; +} + +/** Read a datagram from the management UDP socket and take appropriate + * action. */ +void readFromMgmtSocket (n2n_edge_t *eee) { + + char udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ + ssize_t recvlen; + /* ssize_t sendlen; */ + mgmt_req_t req; + socklen_t i; + size_t msg_len; + time_t now; + struct peer_info *peer, *tmpPeer; + macstr_t mac_buf; + char time_buf[10]; /* 9 digits + 1 terminating zero */ + char uptime_buf[11]; /* 10 digits + 1 terminating zero */ + /* dec_ip_bit_str_t ip_bit_str = {'\0'}; */ + /* dec_ip_str_t ip_str = {'\0'}; */ + in_addr_t net; + n2n_sock_str_t sockbuf; + uint32_t num_pending_peers = 0; + uint32_t num_known_peers = 0; + uint32_t num = 0; + selection_criterion_str_t sel_buf; + + req.eee = eee; + + now = time(NULL); + i = sizeof(req.sender_sock); + recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0 /*flags*/, + (struct sockaddr *) &req.sender_sock, (socklen_t *) &i); + + if(recvlen < 0) { + traceEvent(TRACE_WARNING, "mgmt recvfrom failed: %d - %s", errno, strerror(errno)); + return; /* failed to receive data from UDP */ + } + + /* avoid parsing any uninitialized junk from the stack */ + udp_buf[recvlen] = 0; + + if((0 == memcmp(udp_buf, "help", 4)) || (0 == memcmp(udp_buf, "?", 1))) { + strbuf_t *buf; + STRBUF_INIT(buf, &udp_buf); + msg_len = snprintf(buf->str, buf->size, + "Help for edge management console:\n" + "\tstop | Gracefully exit edge\n" + "\thelp | This help message\n" + "\t+verb | Increase verbosity of logging\n" + "\t-verb | Decrease verbosity of logging\n" + "\tr ... | start query with JSON reply\n" + "\tw ... | start update with JSON reply\n" + "\ts ... | subscribe to event channel JSON reply\n" + "\t | Display statistics\n\n"); + + send_reply(&req, buf, msg_len); + + return; + } + + if(0 == memcmp(udp_buf, "stop", 4)) { + traceEvent(TRACE_NORMAL, "stop command received"); + *eee->keep_running = 0; + return; + } + + if(0 == memcmp(udp_buf, "+verb", 5)) { + setTraceLevel(getTraceLevel() + 1); + + traceEvent(TRACE_NORMAL, "+verb traceLevel=%u", (unsigned int) getTraceLevel()); + + strbuf_t *buf; + STRBUF_INIT(buf, &udp_buf); + msg_len = snprintf(buf->str, buf->size, + "> +OK traceLevel=%u\n", (unsigned int) getTraceLevel()); + + send_reply(&req, buf, msg_len); + + return; + } + + if(0 == memcmp(udp_buf, "-verb", 5)) { + strbuf_t *buf; + STRBUF_INIT(buf, &udp_buf); + + if(getTraceLevel() > 0) { + setTraceLevel(getTraceLevel() - 1); + msg_len = snprintf(buf->str, buf->size, + "> -OK traceLevel=%u\n", getTraceLevel()); + } else { + msg_len = snprintf(buf->str, buf->size, + "> -NOK traceLevel=%u\n", getTraceLevel()); + } + + traceEvent(TRACE_NORMAL, "-verb traceLevel=%u", (unsigned int) getTraceLevel()); + + send_reply(&req, buf, msg_len); + return; + } + + if((udp_buf[0] >= 'a' && udp_buf[0] <= 'z') && (udp_buf[1] == ' ')) { + /* this is a JSON request */ + handleMgmtJson(&req, udp_buf, recvlen); + return; + } + + traceEvent(TRACE_DEBUG, "mgmt status requested"); + + msg_len = 0; + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "COMMUNITY '%s'\n\n", + (eee->conf.header_encryption == HEADER_ENCRYPTION_NONE) ? (char*)eee->conf.community_name : "-- header encrypted --"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + " ### | TAP | MAC | EDGE | HINT | LAST SEEN | UPTIME\n"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "=============================================================================================================\n"); + + // dump nodes with forwarding through supernodes + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "SUPERNODE FORWARD\n"); + num = 0; + HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) { + ++num_pending_peers; + net = htonl(peer->dev_addr.net_addr); + snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->last_seen)); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "%4u | %-15s | %-17s | %-21s | %-15s | %9s |\n", + ++num, + (peer->dev_addr.net_addr == 0) ? "" : inet_ntoa(*(struct in_addr *) &net), + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + peer->dev_desc, + (peer->last_seen) ? time_buf : ""); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)); + msg_len = 0; + } + + // dump peer-to-peer nodes + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "-------------------------------------------------------------------------------------------------------------\n"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "PEER TO PEER\n"); + num = 0; + HASH_ITER(hh, eee->known_peers, peer, tmpPeer) { + ++num_known_peers; + net = htonl(peer->dev_addr.net_addr); + snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->last_seen)); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "%4u | %-15s | %-17s | %-21s | %-15s | %9s |\n", + ++num, + (peer->dev_addr.net_addr == 0) ? "" : inet_ntoa(*(struct in_addr *) &net), + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + peer->dev_desc, + (peer->last_seen) ? time_buf : ""); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)); + msg_len = 0; + } + + // dump supernodes + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "-------------------------------------------------------------------------------------------------------------\n"); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "SUPERNODES\n"); + HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) { + net = htonl(peer->dev_addr.net_addr); + snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->last_seen)); + snprintf(uptime_buf, sizeof(uptime_buf), "%10u", (unsigned int)(peer->uptime)); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "%-19s %1s%1s | %-17s | %-21s | %-15s | %9s | %10s\n", + peer->version, + (peer->purgeable == SN_UNPURGEABLE) ? "l" : "", + (peer == eee->curr_sn) ? (eee->sn_wait ? "." : "*" ) : "", + is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + sn_selection_criterion_str(eee, sel_buf, peer), + (peer->last_seen) ? time_buf : "", + (peer->uptime) ? uptime_buf : ""); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)); + msg_len = 0; + } + + // further stats + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "=============================================================================================================\n"); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "uptime %lu | ", + time(NULL) - eee->start_time); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "pend_peers %u | ", + num_pending_peers); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "known_peers %u | ", + num_known_peers); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "transop %u,%u\n", + (unsigned int) eee->transop.tx_cnt, + (unsigned int) eee->transop.rx_cnt); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "super %u,%u | ", + (unsigned int) eee->stats.tx_sup, + (unsigned int) eee->stats.rx_sup); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "p2p %u,%u\n", + (unsigned int) eee->stats.tx_p2p, + (unsigned int) eee->stats.rx_p2p); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "last_super %ld sec ago | ", + (now - eee->last_sup)); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "last_p2p %ld sec ago\n", + (now - eee->last_p2p)); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "\nType \"help\" to see more commands.\n\n"); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)); +} diff --git a/src/edge_utils.c b/src/edge_utils.c new file mode 100644 index 0000000..42c1a6f --- /dev/null +++ b/src/edge_utils.c @@ -0,0 +1,3619 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" +#include "network_traffic_filter.h" +#include "edge_utils_win32.h" + + +/* ************************************** */ + +int resolve_create_thread (n2n_resolve_parameter_t **param, struct peer_info *sn_list); +int resolve_check (n2n_resolve_parameter_t *param, uint8_t resolution_request, time_t now); +int resolve_cancel_thread (n2n_resolve_parameter_t *param); + +#ifdef HAVE_PORT_FORWARDING +int port_map_create_thread (n2n_port_map_parameter_t **param, uint16_t mgmt_port); +int port_map_cancel_thread (n2n_port_map_parameter_t *param); +#endif + +static const char * supernode_ip (const n2n_edge_t * eee); +static void send_register (n2n_edge_t *eee, const n2n_sock_t *remote_peer, const n2n_mac_t peer_mac, n2n_cookie_t cookie); + +static void check_peer_registration_needed (n2n_edge_t *eee, + uint8_t from_supernode, + uint8_t via_multicast, + const n2n_mac_t mac, + const n2n_cookie_t cookie, + const n2n_ip_subnet_t *dev_addr, + const n2n_desc_t *dev_desc, + const n2n_sock_t *peer); + +static int edge_init_sockets (n2n_edge_t *eee); +int edge_init_routes (n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes); +static void edge_cleanup_routes (n2n_edge_t *eee); + +static void check_known_peer_sock_change (n2n_edge_t *eee, + uint8_t from_supernode, + uint8_t via_multicast, + const n2n_mac_t mac, + const n2n_ip_subnet_t *dev_addr, + const n2n_desc_t *dev_desc, + const n2n_sock_t *peer, + time_t when); + +/* ************************************** */ + +int edge_verify_conf (const n2n_edge_conf_t *conf) { + + if(conf->community_name[0] == 0) + return -1; + + // REVISIT: are the following two conditions equal? if so, remove one. but note that sn_num is used elsewhere + if(conf->sn_num == 0) + return -2; + + if(HASH_COUNT(conf->supernodes) == 0) + return -5; + + if(conf->register_interval < 1) + return -3; + + if(((conf->encrypt_key == NULL) && (conf->transop_id != N2N_TRANSFORM_ID_NULL)) || + ((conf->encrypt_key != NULL) && (conf->transop_id == N2N_TRANSFORM_ID_NULL))) + return -4; + + return 0; +} + + +/* ************************************** */ + +void edge_set_callbacks (n2n_edge_t *eee, const n2n_edge_callbacks_t *callbacks) { + + memcpy(&eee->cb, callbacks, sizeof(n2n_edge_callbacks_t)); +} + +/* ************************************** */ + +void edge_set_userdata (n2n_edge_t *eee, void *user_data) { + + eee->user_data = user_data; +} + +/* ************************************** */ + +void* edge_get_userdata (n2n_edge_t *eee) { + + return(eee->user_data); +} + +/* ************************************** */ + +int edge_get_n2n_socket (n2n_edge_t *eee) { + + return(eee->sock); +} + +/* ************************************** */ + +int edge_get_management_socket (n2n_edge_t *eee) { + + return(eee->udp_mgmt_sock); +} + +/* ************************************** */ + +const char* transop_str (enum n2n_transform tr) { + + switch(tr) { + case N2N_TRANSFORM_ID_NULL: return("null"); + case N2N_TRANSFORM_ID_TWOFISH: return("Twofish"); + case N2N_TRANSFORM_ID_AES: return("AES"); + case N2N_TRANSFORM_ID_CHACHA20:return("ChaCha20"); + case N2N_TRANSFORM_ID_SPECK: return("Speck"); + default: return("invalid"); + }; +} + +/* ************************************** */ + +const char* compression_str (uint8_t cmpr) { + + switch(cmpr) { + case N2N_COMPRESSION_ID_NONE: return("none"); + case N2N_COMPRESSION_ID_LZO: return("lzo1x"); + case N2N_COMPRESSION_ID_ZSTD: return("zstd"); + default: return("invalid"); + }; +} + +/* ************************************** */ + +/** Destination 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF is multicast ethernet. + */ +static int is_ethMulticast (const void * buf, size_t bufsize) { + + int retval = 0; + + /* Match 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF */ + if(bufsize >= sizeof(ether_hdr_t)) { + /* copy to aligned memory */ + ether_hdr_t eh; + memcpy(&eh, buf, sizeof(ether_hdr_t)); + + if((0x01 == eh.dhost[0]) && + (0x00 == eh.dhost[1]) && + (0x5E == eh.dhost[2]) && + (0 == (0x80 & eh.dhost[3]))) + retval = 1; /* This is an ethernet multicast packet [RFC1112]. */ + } + + return retval; +} + +/* ************************************** */ + +/** Destination MAC 33:33:0:00:00:00 - 33:33:FF:FF:FF:FF is reserved for IPv6 + * neighbour discovery. + */ +static int is_ip6_discovery (const void * buf, size_t bufsize) { + + int retval = 0; + + if(bufsize >= sizeof(ether_hdr_t)) { + /* copy to aligned memory */ + ether_hdr_t eh; + + memcpy(&eh, buf, sizeof(ether_hdr_t)); + + if((0x33 == eh.dhost[0]) && (0x33 == eh.dhost[1])) + retval = 1; /* This is an IPv6 multicast packet [RFC2464]. */ + } + + return retval; +} + + +/* ************************************** */ + + +// reset number of supernode connection attempts: try only once for already more realiable tcp connections +void reset_sup_attempts (n2n_edge_t *eee) { + + eee->sup_attempts = (eee->conf.connect_tcp) ? 1 : N2N_EDGE_SUP_ATTEMPTS; +} + + +// detect local IP address by probing a connection to the supernode +static int detect_local_ip_address (n2n_sock_t* out_sock, const n2n_edge_t* eee) { + + struct sockaddr_in local_sock; + struct sockaddr_in sn_sock; + socklen_t sock_len = sizeof(local_sock); + SOCKET probe_sock; + int ret = 0; + + out_sock->family = AF_INVALID; + + // always detetct local port even/especially if chosen by OS... + if((getsockname(eee->sock, (struct sockaddr *)&local_sock, &sock_len) == 0) + && (local_sock.sin_family == AF_INET) + && (sock_len == sizeof(local_sock))) + // remember the port number + out_sock->port = ntohs(local_sock.sin_port); + else + ret = -1; + + // probe for local IP address + probe_sock = socket(PF_INET, SOCK_DGRAM, 0); + // connecting the UDP socket makes getsockname read the local address it uses to connect (to the sn in this case); + // we cannot do it with the real (eee->sock) socket because socket does not accept any conenction from elsewhere then, + // e.g. from another edge instead of the supernode; as re-connecting to AF_UNSPEC might not work to release the socket + // on non-UNIXoids, we use a temporary socket + if((int)probe_sock >= 0) { + fill_sockaddr((struct sockaddr*)&sn_sock, sizeof(sn_sock), &eee->curr_sn->sock); + if(connect(probe_sock, (struct sockaddr *)&sn_sock, sizeof(sn_sock)) == 0) { + if((getsockname(probe_sock, (struct sockaddr *)&local_sock, &sock_len) == 0) + && (local_sock.sin_family == AF_INET) + && (sock_len == sizeof(local_sock))) { + memcpy(&(out_sock->addr.v4), &(local_sock.sin_addr.s_addr), IPV4_SIZE); + } else + ret = -4; + } else + ret = -3; + closesocket(probe_sock); + } else + ret = -2; + + out_sock->family = AF_INET; + + return ret; +} + + +// open socket, close it before if TCP +// in case of TCP, 'connect()' is required +int supernode_connect (n2n_edge_t *eee) { + + int sockopt; + struct sockaddr_in sn_sock; + n2n_sock_t local_sock; + n2n_sock_str_t sockbuf; + + if((eee->conf.connect_tcp) && (eee->sock >= 0)) { + closesocket(eee->sock); + eee->sock = -1; + } + + if(eee->sock < 0) { + + if(eee->conf.local_port > 0) + traceEvent(TRACE_NORMAL, "binding to local port %d", + (eee->conf.connect_tcp) ? 0 : eee->conf.local_port); + + eee->sock = open_socket((eee->conf.connect_tcp) ? 0 : eee->conf.local_port, + eee->conf.bind_address, + eee->conf.connect_tcp); + + if(eee->sock < 0) { + traceEvent(TRACE_ERROR, "failed to bind main UDP port %u", + (eee->conf.connect_tcp) ? 0 : eee->conf.local_port); + return -1; + } + + fill_sockaddr((struct sockaddr*)&sn_sock, sizeof(sn_sock), &eee->curr_sn->sock); + + // set tcp socket to O_NONBLOCK so connect does not hang + // requires checking the socket for readiness before sending and receving + if(eee->conf.connect_tcp) { +#ifdef WIN32 + u_long value = 1; + ioctlsocket(eee->sock, FIONBIO, &value); +#else + fcntl(eee->sock, F_SETFL, O_NONBLOCK); +#endif + if((connect(eee->sock, (struct sockaddr*)&(sn_sock), sizeof(struct sockaddr)) < 0) + && (errno != EINPROGRESS)) { + eee->sock = -1; + return -1; + } + } + + if(eee->conf.tos) { + /* https://www.tucny.com/Home/dscp-tos */ + sockopt = eee->conf.tos; + + if(setsockopt(eee->sock, IPPROTO_IP, IP_TOS, (char *)&sockopt, sizeof(sockopt)) == 0) + traceEvent(TRACE_INFO, "TOS set to 0x%x", eee->conf.tos); + else + traceEvent(TRACE_WARNING, "could not set TOS 0x%x[%d]: %s", eee->conf.tos, errno, strerror(errno)); + } +#ifdef IP_PMTUDISC_DO + sockopt = (eee->conf.disable_pmtu_discovery) ? IP_PMTUDISC_DONT : IP_PMTUDISC_DO; + + if(setsockopt(eee->sock, IPPROTO_IP, IP_MTU_DISCOVER, &sockopt, sizeof(sockopt)) < 0) + traceEvent(TRACE_WARNING, "could not %s PMTU discovery[%d]: %s", + (eee->conf.disable_pmtu_discovery) ? "disable" : "enable", errno, strerror(errno)); + else + traceEvent(TRACE_INFO, "PMTU discovery %s", (eee->conf.disable_pmtu_discovery) ? "disabled" : "enabled"); +#endif + + memset(&local_sock, 0, sizeof(n2n_sock_t)); + if(detect_local_ip_address(&local_sock, eee) == 0) { + // always overwrite local port even/especially if chosen by OS... + eee->conf.preferred_sock.port = local_sock.port; + // only if auto-detection mode, ... + if(eee->conf.preferred_sock_auto) { + // ... overwrite IP address, too (whole socket struct here) + memcpy(&eee->conf.preferred_sock, &local_sock, sizeof(n2n_sock_t)); + traceEvent(TRACE_INFO, "determined local socket [%s]", + sock_to_cstr(sockbuf, &local_sock)); + } + } + + if(eee->cb.sock_opened) + eee->cb.sock_opened(eee); + } + +#ifdef HAVE_PORT_FORWARDING + if(eee->conf.port_forwarding) + // REVISIT: replace with mgmt port notification to listener for mgmt port + // subscription support + n2n_chg_port_mapping(eee, eee->conf.preferred_sock.port); +#endif // HAVE_PORT_FORWARDING + return 0; +} + + +// always closes the socket +void supernode_disconnect (n2n_edge_t *eee) { + + if(eee->sock >= 0) { + closesocket(eee->sock); + eee->sock = -1; + } +} + + +/* ************************************** */ + +/** Initialise an edge to defaults. + * + * This also initialises the NULL transform operation opstruct. + */ +n2n_edge_t* edge_init (const n2n_edge_conf_t *conf, int *rv) { + + n2n_transform_t transop_id = conf->transop_id; + n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t)); + int rc = -1, i = 0; + struct peer_info *scan, *tmp; + uint8_t tmp_key[N2N_AUTH_CHALLENGE_SIZE]; + + if((rc = edge_verify_conf(conf)) != 0) { + traceEvent(TRACE_ERROR, "invalid configuration"); + goto edge_init_error; + } + + if(!eee) { + traceEvent(TRACE_ERROR, "cannot allocate memory"); + goto edge_init_error; + } + + + memcpy(&eee->conf, conf, sizeof(*conf)); + eee->curr_sn = eee->conf.supernodes; + eee->start_time = time(NULL); + + eee->known_peers = NULL; + eee->pending_peers = NULL; + reset_sup_attempts(eee); + + sn_selection_criterion_common_data_default(eee); + + pearson_hash_init(); + + // always initialize compression transforms so we can at least decompress + rc = n2n_transop_lzo_init(&eee->conf, &eee->transop_lzo); + if(rc) goto edge_init_error; /* error message is printed in lzo_init */ +#ifdef HAVE_ZSTD + rc = n2n_transop_zstd_init(&eee->conf, &eee->transop_zstd); + if(rc) goto edge_init_error; /* error message is printed in zstd_init */ +#endif + + traceEvent(TRACE_NORMAL, "number of supernodes in the list: %d\n", HASH_COUNT(eee->conf.supernodes)); + HASH_ITER(hh, eee->conf.supernodes, scan, tmp) { + traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (scan->ip_addr)); + i++; + } + + /* Set active transop */ + switch(transop_id) { + case N2N_TRANSFORM_ID_TWOFISH: + rc = n2n_transop_tf_init(&eee->conf, &eee->transop); + break; + + case N2N_TRANSFORM_ID_AES: + rc = n2n_transop_aes_init(&eee->conf, &eee->transop); + break; + + case N2N_TRANSFORM_ID_CHACHA20: + rc = n2n_transop_cc20_init(&eee->conf, &eee->transop); + break; + + case N2N_TRANSFORM_ID_SPECK: + rc = n2n_transop_speck_init(&eee->conf, &eee->transop); + break; + + default: + rc = n2n_transop_null_init(&eee->conf, &eee->transop); + } + + if((rc < 0) || (eee->transop.fwd == NULL) || (eee->transop.transform_id != transop_id)) { + traceEvent(TRACE_ERROR, "transop init failed"); + goto edge_init_error; + } + + // set the key schedule (context) for header encryption if enabled + if(conf->header_encryption == HEADER_ENCRYPTION_ENABLED) { + traceEvent(TRACE_NORMAL, "Header encryption is enabled."); + packet_header_setup_key((char *)(eee->conf.community_name), + &(eee->conf.header_encryption_ctx_static), + &(eee->conf.header_encryption_ctx_dynamic), + &(eee->conf.header_iv_ctx_static), + &(eee->conf.header_iv_ctx_dynamic)); + // in case of user/password auth, initialize a random dynamic key to prevent + // unintentional communication with only-header-encrypted community; will be + // overwritten by legit key later + if(conf->shared_secret) { + memrnd(tmp_key, N2N_AUTH_CHALLENGE_SIZE); + packet_header_change_dynamic_key(tmp_key, + &(eee->conf.header_encryption_ctx_dynamic), + &(eee->conf.header_iv_ctx_dynamic)); + } + } + + // setup authentication scheme + if(!conf->shared_secret) { + // id-based scheme + eee->conf.auth.scheme = n2n_auth_simple_id; + // random authentication token + memrnd(eee->conf.auth.token, N2N_AUTH_ID_TOKEN_SIZE); + eee->conf.auth.token_size = N2N_AUTH_ID_TOKEN_SIZE; + } else { + // user-password scheme + eee->conf.auth.scheme = n2n_auth_user_password; + // 'token' stores public key and the last random challenge being set upon sending REGISTER_SUPER + memcpy(eee->conf.auth.token, eee->conf.public_key, N2N_PRIVATE_PUBLIC_KEY_SIZE); + // random part of token (challenge) will be generated and filled in at each REGISTER_SUPER + eee->conf.auth.token_size = N2N_AUTH_PW_TOKEN_SIZE; + // make sure that only stream ciphers are being used + if((transop_id != N2N_TRANSFORM_ID_CHACHA20) + && (transop_id != N2N_TRANSFORM_ID_SPECK)) { + traceEvent(TRACE_ERROR, "user-password authentication requires ChaCha20 (-A4) or SPECK (-A5) to be used."); + goto edge_init_error; + } + } + + if(eee->transop.no_encryption) + traceEvent(TRACE_WARNING, "encryption is disabled in edge"); + + // first time calling edge_init_sockets needs -1 in the sockets for it does throw an error + // on trying to close them (open_sockets does so for also being able to RE-open the sockets + // if called in-between, see "Supernode not responding" in update_supernode_reg(...) + eee->sock = -1; + eee->udp_mgmt_sock = -1; +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + eee->udp_multicast_sock = -1; +#endif + if(edge_init_sockets(eee) < 0) { + traceEvent(TRACE_ERROR, "socket setup failed"); + goto edge_init_error; + } + + if(resolve_create_thread(&(eee->resolve_parameter), eee->conf.supernodes) == 0) { + traceEvent(TRACE_NORMAL, "successfully created resolver thread"); + } +#ifdef HAVE_PORT_FORWARDING + if(eee->conf.port_forwarding) + if(port_map_create_thread(&eee->port_map_parameter, eee->conf.mgmt_port) == 0) { + traceEvent(TRACE_NORMAL, "successfully created port mapping thread"); + } +#endif // HAVE_MINIUPNP || HAVE_NATPMP + eee->network_traffic_filter = create_network_traffic_filter(); + network_traffic_filter_add_rule(eee->network_traffic_filter, eee->conf.network_traffic_filter_rules); + + //edge_init_success: + *rv = 0; + return(eee); + +edge_init_error: + if(eee) + free(eee); + *rv = rc; + return(NULL); +} + +/* ************************************** */ + +static int find_and_remove_peer (struct peer_info **head, const n2n_mac_t mac) { + + struct peer_info *peer; + + HASH_FIND_PEER(*head, mac, peer); + if(peer) { + HASH_DEL(*head, peer); + free(peer); + return(1); + } + + return(0); +} + +/* ************************************** */ + +static uint32_t localhost_v4 = 0x7f000001; +static uint8_t localhost_v6[IPV6_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + +/* Exclude localhost as it may be received when an edge node runs + * in the same supernode host. + */ +static int is_valid_peer_sock (const n2n_sock_t *sock) { + + switch(sock->family) { + case AF_INET: { + uint32_t *a = (uint32_t*)sock->addr.v4; + + if(*a != htonl(localhost_v4)) + return(1); + } + break; + + case AF_INET6: + if(memcmp(sock->addr.v6, localhost_v6, IPV6_SIZE)) + return(1); + break; + } + + return(0); +} + +/* ***************************************************** */ + + +/*** + * + * For a given packet, find the apporopriate internal last valid time stamp for lookup + * and verify it (and also update, if applicable). + */ +static int find_peer_time_stamp_and_verify (n2n_edge_t * eee, + peer_info_t *sn, const n2n_mac_t mac, + uint64_t stamp, int allow_jitter) { + + uint64_t *previous_stamp = NULL; + + if(sn) { + // from supernode + previous_stamp = &(sn->last_valid_time_stamp); + } else { + // from (peer) edge + struct peer_info *peer; + HASH_FIND_PEER(eee->pending_peers, mac, peer); + if(!peer) { + HASH_FIND_PEER(eee->known_peers, mac, peer); + } + + if(peer) { + // time_stamp_verify_and_update allows the pointer a previous stamp to be NULL + // if it is a (so far) unknown peer + previous_stamp = &(peer->last_valid_time_stamp); + } + } + + // failure --> 0; success --> 1 + return time_stamp_verify_and_update(stamp, previous_stamp, allow_jitter); +} + + +/* ************************************** */ + +/*** + * + * Register over multicast in case there is a peer on the same network listening + */ +static void register_with_local_peers (n2n_edge_t * eee) { +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + if((eee->multicast_joined && eee->conf.allow_p2p) + && (eee->conf.preferred_sock.family == (uint8_t)AF_INVALID)) { + /* send registration to the local multicast group */ + traceEvent(TRACE_DEBUG, "registering with multicast group %s:%u", + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); + send_register(eee, &(eee->multicast_peer), NULL, N2N_MCAST_REG_COOKIE); + } +#else + traceEvent(TRACE_DEBUG, "multicast peers discovery is disabled, skipping"); +#endif +} + +/* ************************************** */ + +static struct peer_info* find_peer_by_sock (const n2n_sock_t *sock, struct peer_info *peer_list) { + + struct peer_info *scan, *tmp, *ret = NULL; + + HASH_ITER(hh, peer_list, scan, tmp) { + if(memcmp(&(scan->sock), sock, sizeof(n2n_sock_t)) == 0) { + ret = scan; + break; + } + } + + return ret; +} + +/* ************************************** */ + +/** Start the registration process. + * + * If the peer is already in pending_peers, ignore the request. + * If not in pending_peers, add it and send a REGISTER. + * + * If hdr is for a direct peer-to-peer packet, try to register back to sender + * even if the MAC is in pending_peers. This is because an incident direct + * packet indicates that peer-to-peer exchange should work so more aggressive + * registration can be permitted (once per incoming packet) as this should only + * last for a small number of packets.. + * + * Called from the main loop when Rx a packet for our device mac. + */ +static void register_with_new_peer (n2n_edge_t *eee, + uint8_t from_supernode, + uint8_t via_multicast, + const n2n_mac_t mac, + const n2n_ip_subnet_t *dev_addr, + const n2n_desc_t *dev_desc, + const n2n_sock_t *peer) { + + /* REVISIT: purge of pending_peers not yet done. */ + struct peer_info *scan; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + HASH_FIND_PEER(eee->pending_peers, mac, scan); + + /* NOTE: pending_peers are purged periodically with purge_expired_nodes */ + if(scan == NULL) { + scan = calloc(1, sizeof(struct peer_info)); + + memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); + scan->sock = *peer; + scan->timeout = eee->conf.register_interval; /* TODO: should correspond to the peer supernode registration timeout */ + scan->last_valid_time_stamp = initial_time_stamp(); + if(via_multicast) + scan->local = 1; + + HASH_ADD_PEER(eee->pending_peers, scan); + + traceEvent(TRACE_DEBUG, "new pending peer %s [%s]", + macaddr_str(mac_buf, scan->mac_addr), + sock_to_cstr(sockbuf, &(scan->sock))); + + traceEvent(TRACE_DEBUG, "pending peers list size=%u", + HASH_COUNT(eee->pending_peers)); + /* trace Sending REGISTER */ + if(from_supernode) { + /* UDP NAT hole punching through supernode. Send to peer first(punch local UDP hole) + * and then ask supernode to forward. Supernode then ask peer to ack. Some nat device + * drop and block ports with incoming UDP packet if out-come traffic does not exist. + * So we can alternatively set TTL so that the packet sent to peer never really reaches + * The register_ttl is basically nat level + 1. Set it to 1 means host like DMZ. + */ + if(eee->conf.register_ttl == 1) { + /* We are DMZ host or port is directly accessible. Just let peer to send back the ack */ +#ifndef WIN32 + } else if(eee->conf.register_ttl > 1) { + /* Setting register_ttl usually implies that the edge knows the internal net topology + * clearly, we can apply aggressive port prediction to support incoming Symmetric NAT + */ + int curTTL = 0; + socklen_t lenTTL = sizeof(int); + n2n_sock_t sock = scan->sock; + int alter = 16; /* TODO: set by command line or more reliable prediction method */ + + getsockopt(eee->sock, IPPROTO_IP, IP_TTL, (void *) (char *) &curTTL, &lenTTL); + setsockopt(eee->sock, IPPROTO_IP, IP_TTL, + (void *) (char *) &eee->conf.register_ttl, + sizeof(eee->conf.register_ttl)); + for(; alter > 0; alter--, sock.port++) { + send_register(eee, &sock, mac, N2N_PORT_REG_COOKIE); + } + setsockopt(eee->sock, IPPROTO_IP, IP_TTL, (void *) (char *) &curTTL, sizeof(curTTL)); +#endif + } else { /* eee->conf.register_ttl <= 0 */ + /* Normal STUN */ + send_register(eee, &(scan->sock), mac, N2N_REGULAR_REG_COOKIE); + } + send_register(eee, &(eee->curr_sn->sock), mac, N2N_FORWARDED_REG_COOKIE); + } else { + /* P2P register, send directly */ + send_register(eee, &(scan->sock), mac, N2N_REGULAR_REG_COOKIE); + } + register_with_local_peers(eee); + } else{ + scan->sock = *peer; + } + scan->last_seen = time(NULL); + if(dev_addr != NULL) { + memcpy(&(scan->dev_addr), dev_addr, sizeof(n2n_ip_subnet_t)); + } + if(dev_desc) memcpy(scan->dev_desc, dev_desc, N2N_DESC_SIZE); +} + + +/* ************************************** */ + +/** Update the last_seen time for this peer, or get registered. */ +static void check_peer_registration_needed (n2n_edge_t *eee, + uint8_t from_supernode, + uint8_t via_multicast, + const n2n_mac_t mac, + const n2n_cookie_t cookie, + const n2n_ip_subnet_t *dev_addr, + const n2n_desc_t *dev_desc, + const n2n_sock_t *peer) { + + struct peer_info *scan; + + HASH_FIND_PEER(eee->known_peers, mac, scan); + + /* If we were not able to find it by MAC, we try to find it by socket. */ + if(scan == NULL ) { + scan = find_peer_by_sock(peer, eee->known_peers); + + // MAC change + if(scan) { + HASH_DEL(eee->known_peers, scan); + memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); + HASH_ADD_PEER(eee->known_peers, scan); + // reset last_local_reg to allow re-registration + scan->last_cookie = N2N_NO_REG_COOKIE; + } + } + + if(scan == NULL) { + /* Not in known_peers - start the REGISTER process. */ + register_with_new_peer(eee, from_supernode, via_multicast, mac, dev_addr, dev_desc, peer); + } else { + /* Already in known_peers. */ + time_t now = time(NULL); + + if(!from_supernode) + scan->last_p2p = now; + + if(via_multicast) + scan->local = 1; + + if(((now - scan->last_seen) > 0 /* >= 1 sec */) + ||(cookie > scan->last_cookie)) { + /* Don't register too often */ + check_known_peer_sock_change(eee, from_supernode, via_multicast, mac, dev_addr, dev_desc, peer, now); + } + } +} + +/* ************************************** */ + + +/* Confirm that a pending peer is reachable directly via P2P. + * + * peer must be a pointer to an element of the pending_peers list. + */ +static void peer_set_p2p_confirmed (n2n_edge_t * eee, + const n2n_mac_t mac, + const n2n_cookie_t cookie, + const n2n_sock_t * peer, + time_t now) { + + struct peer_info *scan, *scan_tmp; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + HASH_FIND_PEER(eee->pending_peers, mac, scan); + if(scan == NULL) { + scan = find_peer_by_sock(peer, eee->pending_peers); + // in case of MAC change, reset last_local_reg to allow re-registration + if(scan) + scan->last_cookie = N2N_NO_REG_COOKIE; + } + + if(scan) { + HASH_DEL(eee->pending_peers, scan); + + scan_tmp = find_peer_by_sock(peer, eee->known_peers); + if(scan_tmp != NULL) { + HASH_DEL(eee->known_peers, scan_tmp); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan); + free(scan); + scan = scan_tmp; + memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); + // in case of MAC change, reset cookie to allow immediate re-registration + scan->last_cookie = N2N_NO_REG_COOKIE; + } else { + // update sock but ... + // ... ignore ACKs's (and their socks) from lower ranked inbound ways for a while + if(((now - scan->last_seen) > REGISTRATION_TIMEOUT / 4) + ||(cookie > scan->last_cookie)) { + scan->sock = *peer; + scan->last_cookie = cookie; + } + } + + HASH_ADD_PEER(eee->known_peers, scan); + scan->last_p2p = now; + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_ADD_P2P,scan); + + traceEvent(TRACE_DEBUG, "p2p connection established: %s [%s]", + macaddr_str(mac_buf, mac), + sock_to_cstr(sockbuf, peer)); + + traceEvent(TRACE_DEBUG, "new peer %s [%s]", + macaddr_str(mac_buf, scan->mac_addr), + sock_to_cstr(sockbuf, &(scan->sock))); + + traceEvent(TRACE_DEBUG, "pending peers list size=%u", + HASH_COUNT(eee->pending_peers)); + + traceEvent(TRACE_DEBUG, "known peers list size=%u", + HASH_COUNT(eee->known_peers)); + + scan->last_seen = now; + } else + traceEvent(TRACE_DEBUG, "failed to find sender in pending_peers"); +} + + +/* ************************************** */ + + +// provides the current / a new local auth token +static int get_local_auth (n2n_edge_t *eee, n2n_auth_t *auth) { + + switch(eee->conf.auth.scheme) { + case n2n_auth_simple_id: + memcpy(auth, &(eee->conf.auth), sizeof(n2n_auth_t)); + break; + case n2n_auth_user_password: + // start from the locally stored complete auth token (including type and size fields) + memcpy(auth, &(eee->conf.auth), sizeof(n2n_auth_t)); + + // the token data consists of + // 32 bytes public key + // 16 bytes random challenge + + // generate a new random auth challenge every time + memrnd(auth->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, N2N_AUTH_CHALLENGE_SIZE); + // store it in local auth token (for comparison later) + memcpy(eee->conf.auth.token + N2N_PRIVATE_PUBLIC_KEY_SIZE, auth->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, N2N_AUTH_CHALLENGE_SIZE); + // encrypt the challenge for transmission + speck_128_encrypt(auth->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, (speck_context_t*)eee->conf.shared_secret_ctx); + break; + default: + break; + } + + return 0; +} + + +// handles a returning (remote) auth token, takes action as required by auth scheme +static int handle_remote_auth (n2n_edge_t *eee, struct peer_info *peer, const n2n_auth_t *remote_auth) { + + uint8_t tmp_token[N2N_AUTH_MAX_TOKEN_SIZE]; + + switch(eee->conf.auth.scheme) { + case n2n_auth_simple_id: + // no action required + break; + case n2n_auth_user_password: + memcpy(tmp_token, remote_auth->token, N2N_AUTH_PW_TOKEN_SIZE); + + // the returning token data consists of + // 16 bytes double-encrypted challenge + // 16 bytes public key (second half) + // 16 bytes encrypted (original random challenge XOR shared secret XOR dynamic key) + + // decrypt double-encrypted received challenge (first half of public key field) + speck_128_decrypt(tmp_token, (speck_context_t*)eee->conf.shared_secret_ctx); + speck_128_decrypt(tmp_token, (speck_context_t*)eee->conf.shared_secret_ctx); + + // compare to original challenge + if(0 != memcmp(tmp_token, eee->conf.auth.token + N2N_PRIVATE_PUBLIC_KEY_SIZE, N2N_AUTH_CHALLENGE_SIZE)) + return -1; + + // decrypt the received challenge in which the dynamic key is wrapped + speck_128_decrypt(tmp_token + N2N_PRIVATE_PUBLIC_KEY_SIZE, (speck_context_t*)eee->conf.shared_secret_ctx); + // un-XOR the original challenge + memxor(tmp_token + N2N_PRIVATE_PUBLIC_KEY_SIZE, eee->conf.auth.token + N2N_PRIVATE_PUBLIC_KEY_SIZE, N2N_AUTH_CHALLENGE_SIZE); + // un-XOR the shared secret + memxor(tmp_token + N2N_PRIVATE_PUBLIC_KEY_SIZE, *(eee->conf.shared_secret), N2N_AUTH_CHALLENGE_SIZE); + // setup for use as dynamic key + packet_header_change_dynamic_key(tmp_token + N2N_PRIVATE_PUBLIC_KEY_SIZE, + &(eee->conf.header_encryption_ctx_dynamic), + &(eee->conf.header_iv_ctx_dynamic)); + break; + default: + break; + } + + return 0; +} + + +/* ************************************** */ + + +int is_empty_ip_address (const n2n_sock_t * sock) { + + const uint8_t * ptr = NULL; + size_t len = 0; + size_t i; + + if(AF_INET6 == sock->family) { + ptr = sock->addr.v6; + len = 16; + } else { + ptr = sock->addr.v4; + len = 4; + } + + for(i = 0; i < len; ++i) { + if(0 != ptr[i]) { + /* found a non-zero byte in address */ + return 0; + } + } + + return 1; +} + +/* ************************************** */ + + +/** Check if a known peer socket has changed and possibly register again. + */ +static void check_known_peer_sock_change (n2n_edge_t *eee, + uint8_t from_supernode, + uint8_t via_multicast, + const n2n_mac_t mac, + const n2n_ip_subnet_t *dev_addr, + const n2n_desc_t *dev_desc, + const n2n_sock_t *peer, + time_t when) { + + struct peer_info *scan; + n2n_sock_str_t sockbuf1; + n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */ + macstr_t mac_buf; + + if(is_empty_ip_address(peer)) + return; + + if(is_multi_broadcast(mac)) + return; + + /* Search the peer in known_peers */ + HASH_FIND_PEER(eee->known_peers, mac, scan); + + if(!scan) + /* Not in known_peers */ + return; + + if(!sock_equal(&(scan->sock), peer)) { + if(!from_supernode) { + /* This is a P2P packet */ + traceEvent(TRACE_NORMAL, "peer %s changed [%s] -> [%s]", + macaddr_str(mac_buf, scan->mac_addr), + sock_to_cstr(sockbuf1, &(scan->sock)), + sock_to_cstr(sockbuf2, peer)); + /* The peer has changed public socket. It can no longer be assumed to be reachable. */ + HASH_DEL(eee->known_peers, scan); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan); + free(scan); + + register_with_new_peer(eee, from_supernode, via_multicast, mac, dev_addr, dev_desc, peer); + } else { + /* Don't worry about what the supernode reports, it could be seeing a different socket. */ + } + } else + scan->last_seen = when; +} + +/* ************************************** */ + +/** Send a datagram to a socket file descriptor */ +static ssize_t sendto_fd (n2n_edge_t *eee, const void *buf, + size_t len, struct sockaddr_in *dest) { + + ssize_t sent = 0; + int rc = 1; + + // if required (tcp), wait until writeable as soket is set to O_NONBLOCK, could require + // some wait time directly after re-opening + if(eee->conf.connect_tcp) { + fd_set socket_mask; + struct timeval wait_time; + + FD_ZERO(&socket_mask); + FD_SET(eee->sock, &socket_mask); + wait_time.tv_sec = 0; + wait_time.tv_usec = 500000; + rc = select(eee->sock + 1, NULL, &socket_mask, NULL, &wait_time); + } + + if(rc > 0) { + + sent = sendto(eee->sock, buf, len, 0 /*flags*/, + (struct sockaddr *)dest, sizeof(struct sockaddr_in)); + + if((sent <= 0) && (errno)) { + char * c = strerror(errno); + // downgrade to TRACE_DEBUG in case of custom AF_INVALID, i.e. supernode not resolved yet + if(errno == EAFNOSUPPORT /* 93 */) { + traceEvent(TRACE_DEBUG, "sendto failed (%d) %s", errno, c); +#ifdef WIN32 + traceEvent(TRACE_DEBUG, "WSAGetLastError(): %u", WSAGetLastError()); +#endif + } else { + traceEvent(TRACE_WARNING, "sendto failed (%d) %s", errno, c); +#ifdef WIN32 + traceEvent(TRACE_WARNING, "WSAGetLastError(): %u", WSAGetLastError()); +#endif + } + + if(eee->conf.connect_tcp) { + supernode_disconnect(eee); + eee->sn_wait = 1; + traceEvent(TRACE_DEBUG, "disconnected supernode due to sendto() error"); + return -1; + } + } else { + traceEvent(TRACE_DEBUG, "sent=%d to ", (signed int)sent); + } + } else { + supernode_disconnect(eee); + eee->sn_wait = 1; + traceEvent(TRACE_DEBUG, "disconnected supernode due to select() timeout"); + return -1; + } + return sent; +} + + +/** Send a datagram to a socket defined by a n2n_sock_t */ +static ssize_t sendto_sock (n2n_edge_t *eee, const void * buf, + size_t len, const n2n_sock_t * dest) { + + struct sockaddr_in peer_addr; + ssize_t sent; + int value = 0; + + if(!dest->family) + // invalid socket + return 0; + + if(eee->sock < 0) + // invalid socket file descriptor, e.g. TCP unconnected has fd of '-1' + return 0; + + // network order socket + fill_sockaddr((struct sockaddr *) &peer_addr, sizeof(peer_addr), dest); + + // if the connection is tcp, i.e. not the regular sock... + if(eee->conf.connect_tcp) { + + setsockopt(eee->sock, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)); + value = 1; +#ifdef LINUX + setsockopt(eee->sock, IPPROTO_TCP, TCP_CORK, &value, sizeof(value)); +#endif + + // prepend packet length... + uint16_t pktsize16 = htobe16(len); + sent = sendto_fd(eee, (uint8_t*)&pktsize16, sizeof(pktsize16), &peer_addr); + + if(sent <= 0) + return -1; + // ...before sending the actual data + } + sent = sendto_fd(eee, buf, len, &peer_addr); + + // if the connection is tcp, i.e. not the regular sock... + if(eee->conf.connect_tcp) { + value = 1; /* value should still be set to 1 */ + setsockopt(eee->sock, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)); +#ifdef LINUX + value = 0; + setsockopt(eee->sock, IPPROTO_TCP, TCP_CORK, &value, sizeof(value)); +#endif + } + + return sent; +} + + +/* ************************************** */ + + +/* Bind eee->udp_multicast_sock to multicast group */ +static void check_join_multicast_group (n2n_edge_t *eee) { + +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + if((eee->conf.allow_p2p) + && (eee->conf.preferred_sock.family == (uint8_t)AF_INVALID)) { + if(!eee->multicast_joined) { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = inet_addr(N2N_MULTICAST_GROUP); +#ifdef WIN32 + dec_ip_str_t ip_addr; + get_best_interface_ip(eee, ip_addr); + mreq.imr_interface.s_addr = inet_addr(ip_addr); +#else + mreq.imr_interface.s_addr = htonl(INADDR_ANY); +#endif + + if(setsockopt(eee->udp_multicast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) { + traceEvent(TRACE_WARNING, "failed to bind to local multicast group %s:%u [errno %u]", + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT, errno); + +#ifdef WIN32 + traceEvent(TRACE_WARNING, "WSAGetLastError(): %u", WSAGetLastError()); +#endif + } else { + traceEvent(TRACE_NORMAL, "successfully joined multicast group %s:%u", + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); + eee->multicast_joined = 1; + } + } + } +#endif +} + +/* ************************************** */ + +/** Send a QUERY_PEER packet to the current supernode. */ +void send_query_peer (n2n_edge_t * eee, + const n2n_mac_t dst_mac) { + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + n2n_common_t cmn = {0}; + n2n_QUERY_PEER_t query = {0}; + struct peer_info *peer, *tmp; + int n_o_pings = 0; + int n_o_top_sn = 0; + int n_o_rest_sn = 0; + int n_o_skip_sn = 0; + + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_query_peer; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + + idx = 0; + encode_mac(query.srcMac, &idx, eee->device.mac_addr); + + idx = 0; + encode_mac(query.targetMac, &idx, dst_mac); + + idx = 0; + encode_QUERY_PEER(pktbuf, &idx, &cmn, &query); + + if(!is_null_mac(dst_mac)) { + + traceEvent(TRACE_DEBUG, "send QUERY_PEER to supernode"); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(pktbuf, idx, idx, + eee->conf.header_encryption_ctx_dynamic, eee->conf.header_iv_ctx_dynamic, + time_stamp()); + } + + sendto_sock(eee, pktbuf, idx, &(eee->curr_sn->sock)); + + } else { + traceEvent(TRACE_DEBUG, "send PING to supernodes"); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(pktbuf, idx, idx, + eee->conf.header_encryption_ctx_dynamic, eee->conf.header_iv_ctx_dynamic, + time_stamp()); + } + + n_o_pings = eee->conf.number_max_sn_pings; + eee->conf.number_max_sn_pings = NUMBER_SN_PINGS_REGULAR; + + // ping the 'floor(n/2)' top supernodes and 'ceiling(n/2)' of the remaining + n_o_top_sn = n_o_pings >> 1; + n_o_rest_sn = (n_o_pings + 1) >> 1; + + // skip a random number of supernodes between top and remaining + n_o_skip_sn = HASH_COUNT(eee->conf.supernodes) - n_o_pings; + n_o_skip_sn = (n_o_skip_sn < 0) ? 0 : n2n_rand_sqr(n_o_skip_sn); + HASH_ITER(hh, eee->conf.supernodes, peer, tmp) { + if(n_o_top_sn) { + n_o_top_sn--; + // fall through (send to top supernode) + } else if(n_o_skip_sn) { + n_o_skip_sn--; + // skip (do not send) + continue; + } else if(n_o_rest_sn) { + n_o_rest_sn--; + // fall through (send to remaining supernode) + } else { + // done with the remaining (do not send anymore) + break; + } + sendto_sock(eee, pktbuf, idx, &(peer->sock)); + } + } +} + +/* ******************************************************** */ + +/** Send a REGISTER_SUPER packet to the current supernode. */ +void send_register_super (n2n_edge_t *eee) { + + uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; + uint8_t hash_buf[16] = {0}; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_REGISTER_SUPER_t reg; + n2n_sock_str_t sockbuf; + + memset(&cmn, 0, sizeof(cmn)); + memset(®, 0, sizeof(reg)); + + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_register_super; + if(eee->conf.preferred_sock.family == (uint8_t)AF_INVALID) { + cmn.flags = 0; + } else { + cmn.flags = N2N_FLAGS_SOCKET; + memcpy(&(reg.sock), &(eee->conf.preferred_sock), sizeof(n2n_sock_t)); + } + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + + eee->curr_sn->last_cookie = n2n_rand(); + + reg.cookie = eee->curr_sn->last_cookie; + reg.dev_addr.net_addr = ntohl(eee->device.ip_addr); + reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask)); + memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE); + get_local_auth(eee, &(reg.auth)); + + idx = 0; + encode_mac(reg.edgeMac, &idx, eee->device.mac_addr); + + idx = 0; + encode_REGISTER_SUPER(pktbuf, &idx, &cmn, ®); + + traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to [%s]", + sock_to_cstr(sockbuf, &(eee->curr_sn->sock))); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(pktbuf, idx, idx, + eee->conf.header_encryption_ctx_static, eee->conf.header_iv_ctx_static, + time_stamp()); + + if(eee->conf.shared_secret) { + pearson_hash_128(hash_buf, pktbuf, idx); + speck_128_encrypt(hash_buf, (speck_context_t*)eee->conf.shared_secret_ctx); + encode_buf(pktbuf, &idx, hash_buf, N2N_REG_SUP_HASH_CHECK_LEN); + } + } + + /* sent = */ sendto_sock(eee, pktbuf, idx, &(eee->curr_sn->sock)); +} + + +static void send_unregister_super (n2n_edge_t *eee) { + + uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_UNREGISTER_SUPER_t unreg; + n2n_sock_str_t sockbuf; + + memset(&cmn, 0, sizeof(cmn)); + memset(&unreg, 0, sizeof(unreg)); + + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_unregister_super; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + get_local_auth(eee, &(unreg.auth)); + + idx = 0; + encode_mac(unreg.srcMac, &idx, eee->device.mac_addr); + + idx = 0; + encode_UNREGISTER_SUPER(pktbuf, &idx, &cmn, &unreg); + + traceEvent(TRACE_DEBUG, "send UNREGISTER_SUPER to [%s]", + sock_to_cstr(sockbuf, &(eee->curr_sn->sock))); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) + packet_header_encrypt(pktbuf, idx, idx, + eee->conf.header_encryption_ctx_dynamic, eee->conf.header_iv_ctx_dynamic, + time_stamp()); + + /* sent = */ sendto_sock(eee, pktbuf, idx, &(eee->curr_sn->sock)); + +} + + +static int sort_supernodes (n2n_edge_t *eee, time_t now) { + + struct peer_info *scan, *tmp; + + if(now - eee->last_sweep > SWEEP_TIME) { + // this routine gets periodically called + + if(!eee->sn_wait) { + // sort supernodes in ascending order of their selection_criterion fields + sn_selection_sort(&(eee->conf.supernodes)); + } + + if(eee->curr_sn != eee->conf.supernodes) { + // we have not been connected to the best/top one + send_unregister_super(eee); + eee->curr_sn = eee->conf.supernodes; + reset_sup_attempts(eee); + supernode_connect(eee); + + traceEvent(TRACE_INFO, "registering with supernode [%s][number of supernodes %d][attempts left %u]", + supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts); + + send_register_super(eee); + eee->last_register_req = now; + eee->sn_wait = 1; + } + + HASH_ITER(hh, eee->conf.supernodes, scan, tmp) { + if(scan == eee->curr_sn) + sn_selection_criterion_good(&(scan->selection_criterion)); + else + sn_selection_criterion_default(&(scan->selection_criterion)); + } + sn_selection_criterion_common_data_default(eee); + + // send PING to all the supernodes + if(!eee->conf.connect_tcp) + send_query_peer(eee, null_mac); + eee->last_sweep = now; + + // no answer yet (so far, unused in regular edge code; mainly used during bootstrap loading) + eee->sn_pong = 0; + } + + return 0; /* OK */ +} + +/** Send a REGISTER packet to another edge. */ +static void send_register (n2n_edge_t * eee, + const n2n_sock_t * remote_peer, + const n2n_mac_t peer_mac, + const n2n_cookie_t cookie) { + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_REGISTER_t reg; + n2n_sock_str_t sockbuf; + + if(!eee->conf.allow_p2p) { + traceEvent(TRACE_DEBUG, "skipping register as P2P is disabled"); + return; + } + + memset(&cmn, 0, sizeof(cmn)); + memset(®, 0, sizeof(reg)); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_register; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + + reg.cookie = cookie; + idx = 0; + encode_mac(reg.srcMac, &idx, eee->device.mac_addr); + + if(peer_mac) { + // can be NULL for multicast registrations + idx = 0; + encode_mac(reg.dstMac, &idx, peer_mac); + } + reg.dev_addr.net_addr = ntohl(eee->device.ip_addr); + reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask)); + memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE); + + idx = 0; + encode_REGISTER(pktbuf, &idx, &cmn, ®); + + traceEvent(TRACE_INFO, "send REGISTER to [%s]", + sock_to_cstr(sockbuf, remote_peer)); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) + packet_header_encrypt(pktbuf, idx, idx, + eee->conf.header_encryption_ctx_dynamic, eee->conf.header_iv_ctx_dynamic, + time_stamp()); + + /* sent = */ sendto_sock(eee, pktbuf, idx, remote_peer); +} + +/* ************************************** */ + +/** Send a REGISTER_ACK packet to a peer edge. */ +static void send_register_ack (n2n_edge_t * eee, + const n2n_sock_t * remote_peer, + const n2n_REGISTER_t * reg) { + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_REGISTER_ACK_t ack; + n2n_sock_str_t sockbuf; + + if(!eee->conf.allow_p2p) { + traceEvent(TRACE_DEBUG, "skipping register ACK as P2P is disabled"); + return; + } + + memset(&cmn, 0, sizeof(cmn)); + memset(&ack, 0, sizeof(reg)); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_register_ack; + cmn.flags = 0; + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + + memset(&ack, 0, sizeof(ack)); + ack.cookie = reg->cookie; + memcpy(ack.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); + memcpy(ack.dstMac, reg->srcMac, N2N_MAC_SIZE); + + idx = 0; + encode_REGISTER_ACK(pktbuf, &idx, &cmn, &ack); + + traceEvent(TRACE_INFO, "send REGISTER_ACK to [%s]", + sock_to_cstr(sockbuf, remote_peer)); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) + packet_header_encrypt(pktbuf, idx, idx, + eee->conf.header_encryption_ctx_dynamic, eee->conf.header_iv_ctx_dynamic, + time_stamp()); + + /* sent = */ sendto_sock(eee, pktbuf, idx, remote_peer); +} + +/* ************************************** */ + +static char gratuitous_arp[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* dest MAC */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* src MAC */ + 0x08, 0x06, /* ARP */ + 0x00, 0x01, /* ethernet */ + 0x08, 0x00, /* IP */ + 0x06, /* hw Size */ + 0x04, /* protocol Size */ + 0x00, 0x02, /* ARP reply */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* src MAC */ + 0x00, 0x00, 0x00, 0x00, /* src IP */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* target MAC */ + 0x00, 0x00, 0x00, 0x00 /* target IP */ +}; + +// build a gratuitous ARP packet */ +static int build_gratuitous_arp (n2n_edge_t * eee, char *buffer, uint16_t buffer_len) { + + if(buffer_len < sizeof(gratuitous_arp)) return(-1); + + memcpy(buffer, gratuitous_arp, sizeof(gratuitous_arp)); + memcpy(&buffer[6], eee->device.mac_addr, 6); + memcpy(&buffer[22], eee->device.mac_addr, 6); + memcpy(&buffer[28], &(eee->device.ip_addr), 4); + memcpy(&buffer[38], &(eee->device.ip_addr), 4); + + return(sizeof(gratuitous_arp)); +} + +/** Called from update_supernode_reg to periodically send gratuitous ARP + * broadcasts. */ +static void send_grat_arps (n2n_edge_t * eee) { + + uint8_t buffer[48]; + size_t len; + + traceEvent(TRACE_DEBUG, "sending gratuitous ARP..."); + len = build_gratuitous_arp(eee, (char*)buffer, sizeof(buffer)); + + edge_send_packet2net(eee, buffer, len); + edge_send_packet2net(eee, buffer, len); /* Two is better than one :-) */ +} + +/* ************************************** */ + +/** @brief Check to see if we should re-register with the supernode. + * + * This is frequently called by the main loop. + */ +void update_supernode_reg (n2n_edge_t * eee, time_t now) { + + struct peer_info *peer, *tmp_peer; + int cnt = 0; + int off = 0; + + if((eee->sn_wait && (now > (eee->last_register_req + (eee->conf.register_interval / 10)))) + ||(eee->sn_wait == 2)) /* immediately re-register in case of RE_REGISTER_SUPER */ { + /* fall through */ + traceEvent(TRACE_DEBUG, "update_supernode_reg: doing fast retry."); + } else if(now < (eee->last_register_req + eee->conf.register_interval)) + return; /* Too early */ + + // determine time offset to apply on last_register_req for + // all edges's next re-registration does not happen all at once + if(eee->sn_wait == 2) { + // remaining 1/4 is greater than 1/10 fast retry allowance; + // '%' might be expensive but does not happen all too often + off = n2n_rand() % ((eee->conf.register_interval * 3) / 4); + } + + check_join_multicast_group(eee); + + if(0 == eee->sup_attempts) { + /* Give up on that supernode and try the next one. */ + sn_selection_criterion_bad(&(eee->curr_sn->selection_criterion)); + sn_selection_sort(&(eee->conf.supernodes)); + eee->curr_sn = eee->conf.supernodes; + traceEvent(TRACE_WARNING, "supernode not responding, now trying [%s]", supernode_ip(eee)); + reset_sup_attempts(eee); + // trigger out-of-schedule DNS resolution + eee->resolution_request = 1; + + // in some multi-NATed scenarios communication gets stuck on losing connection to supernode + // closing and re-opening the socket allows for re-establishing communication + // this can only be done, if working on some unprivileged port and/or having sufficent + // privileges. as we are not able to check for sufficent privileges here, we only do it + // if port is sufficently high or unset. uncovered: privileged port and sufficent privileges + if((eee->conf.local_port == 0) || (eee->conf.local_port > 1024)) { + // do not explicitly disconnect every time as the condition described is rare, so ... + // ... check that there are no external peers (indicating a working socket) ... + HASH_ITER(hh, eee->known_peers, peer, tmp_peer) + if(!peer->local) { + cnt++; + break; + } + if(!cnt) { + // ... and then count the connection retries + (eee->close_socket_counter)++; + if(eee->close_socket_counter >= N2N_CLOSE_SOCKET_COUNTER_MAX) { + eee->close_socket_counter = 0; + supernode_disconnect(eee); + traceEvent(TRACE_DEBUG, "disconnected supernode"); + } + } + + traceEvent(TRACE_DEBUG, "reconnected to supernode"); + } + supernode_connect(eee); + + } else { + --(eee->sup_attempts); + } + +#ifndef HAVE_PTHREAD + if(supernode2sock(&(eee->curr_sn->sock), eee->curr_sn->ip_addr) == 0) { +#endif + traceEvent(TRACE_INFO, "registering with supernode [%s][number of supernodes %d][attempts left %u]", + supernode_ip(eee), HASH_COUNT(eee->conf.supernodes), (unsigned int)eee->sup_attempts); + + send_register_super(eee); +#ifndef HAVE_PTHREAD + } +#endif + + register_with_local_peers(eee); + + // if supernode repeatedly not responding (already waiting), safeguard the + // current known connections to peers by re-registering + if(eee->sn_wait == 1) + HASH_ITER(hh, eee->known_peers, peer, tmp_peer) + if((now - peer->last_seen) > REGISTER_SUPER_INTERVAL_DFL) + send_register(eee, &(peer->sock), peer->mac_addr, peer->last_cookie); + + eee->sn_wait = 1; + + eee->last_register_req = now - off; +} + +/* ************************************** */ + +/** Return the IP address of the current supernode in the ring. */ +static const char * supernode_ip (const n2n_edge_t * eee) { + + return (eee->curr_sn->ip_addr); +} + +/* ************************************** */ + +/** A PACKET has arrived containing an encapsulated ethernet datagram - usually + * encrypted. */ +static int handle_PACKET (n2n_edge_t * eee, + const uint8_t from_supernode, + const n2n_PACKET_t * pkt, + const n2n_sock_t * orig_sender, + uint8_t * payload, + size_t psize) { + + ssize_t data_sent_len; + uint8_t * eth_payload = NULL; + int retval = -1; + time_t now; + ether_hdr_t * eh; + ipstr_t ip_buf; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + now = time(NULL); + + traceEvent(TRACE_DEBUG, "handle_PACKET size %u transform %u", + (unsigned int)psize, (unsigned int)pkt->transform); + /* hexdump(payload, psize); */ + + if(from_supernode) { + if(is_multi_broadcast(pkt->dstMac)) + ++(eee->stats.rx_sup_broadcast); + + ++(eee->stats.rx_sup); + eee->last_sup = now; + } else { + ++(eee->stats.rx_p2p); + eee->last_p2p=now; + } + + /* Handle transform. */ + { + uint8_t decode_buf[N2N_PKT_BUF_SIZE]; + uint8_t deflate_buf[N2N_PKT_BUF_SIZE]; + size_t eth_size; + n2n_transform_t rx_transop_id; + uint8_t rx_compression_id; + + rx_transop_id = (n2n_transform_t)pkt->transform; + rx_compression_id = pkt->compression; + + if(rx_transop_id == eee->conf.transop_id) { + uint8_t is_multicast; + // decrypt + eth_payload = decode_buf; + eth_size = eee->transop.rev(&eee->transop, + eth_payload, N2N_PKT_BUF_SIZE, + payload, psize, pkt->srcMac); + ++(eee->transop.rx_cnt); /* stats */ + + /* decompress if necessary */ + size_t deflate_len; + + switch(rx_compression_id) { + case N2N_COMPRESSION_ID_NONE: + break; // continue afterwards + + case N2N_COMPRESSION_ID_LZO: + deflate_len = eee->transop_lzo.rev(&eee->transop_lzo, + deflate_buf, N2N_PKT_BUF_SIZE, + decode_buf, eth_size, pkt->srcMac); + break; + +#ifdef HAVE_ZSTD + case N2N_COMPRESSION_ID_ZSTD: + deflate_len = eee->transop_zstd.rev(&eee->transop_zstd, + deflate_buf, N2N_PKT_BUF_SIZE, + decode_buf, eth_size, pkt->srcMac); + break; +#endif + default: + traceEvent(TRACE_WARNING, "payload decompression failed: received packet indicating unsupported %s compression.", + compression_str(rx_compression_id)); + return(-1); // cannot handle it + } + + if(rx_compression_id != N2N_COMPRESSION_ID_NONE) { + traceEvent(TRACE_DEBUG, "payload decompression %s: deflated %u bytes to %u bytes", + compression_str(rx_compression_id), eth_size, (int)deflate_len); + eth_payload = deflate_buf; + eth_size = deflate_len; + } + eh = (ether_hdr_t*)eth_payload; + + is_multicast = (is_ip6_discovery(eth_payload, eth_size) || is_ethMulticast(eth_payload, eth_size)); + + if(eee->conf.drop_multicast && is_multicast) { + traceEvent(TRACE_INFO, "dropping RX multicast"); + return(-1); + } else if((!eee->conf.allow_routing) && (!is_multicast)) { + /* Check if it is a routed packet */ + + if((ntohs(eh->type) == 0x0800) && (eth_size >= ETH_FRAMESIZE + IP4_MIN_SIZE)) { + + uint32_t *dst = (uint32_t*)ð_payload[ETH_FRAMESIZE + IP4_DSTOFFSET]; + uint8_t *dst_mac = (uint8_t*)eth_payload; + + /* Note: all elements of the_ip are in network order */ + if(!memcmp(dst_mac, broadcast_mac, N2N_MAC_SIZE)) + traceEvent(TRACE_DEBUG, "RX broadcast packet destined to [%s]", + intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); + else if((*dst != eee->device.ip_addr)) { + /* This is a packet that needs to be routed */ + traceEvent(TRACE_INFO, "discarding routed packet destined to [%s]", + intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); + return(-1); + } else { + /* This packet is directed to us */ + /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ + } + } + } + + if(eee->network_traffic_filter->filter_packet_from_peer(eee->network_traffic_filter, eee, orig_sender, + eth_payload, eth_size) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "filtered packet of size %u", (unsigned int)eth_size); + return(0); + } + + if(eee->cb.packet_from_peer) { + uint16_t tmp_eth_size = eth_size; + if(eee->cb.packet_from_peer(eee, orig_sender, eth_payload, &tmp_eth_size) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "DROP packet of size %u", (unsigned int)eth_size); + return(0); + } + eth_size = tmp_eth_size; + } + + /* Write ethernet packet to tap device. */ + traceEvent(TRACE_DEBUG, "sending data of size %u to TAP", (unsigned int)eth_size); + data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size); + + if(data_sent_len == eth_size) { + retval = 0; + } + } else { + traceEvent(TRACE_WARNING, "invalid transop ID: expected %s (%u), got %s (%u) from %s [%s]", + transop_str(eee->conf.transop_id), eee->conf.transop_id, + transop_str(rx_transop_id), rx_transop_id, + macaddr_str(mac_buf, pkt->srcMac), + sock_to_cstr(sockbuf, orig_sender)); + } + } + + return retval; +} + +/* ************************************** */ + + +#if 0 +#ifndef WIN32 + +static char *get_ip_from_arp (dec_ip_str_t buf, const n2n_mac_t req_mac) { + + FILE *fd; + dec_ip_str_t ip_str = {'\0'}; + char dev_str[N2N_IFNAMSIZ] = {'\0'}; + macstr_t mac_str = {'\0'}; + n2n_mac_t mac = {'\0'}; + + strncpy(buf, "0.0.0.0", N2N_NETMASK_STR_SIZE - 1); + + if(is_null_mac(req_mac)) { + traceEvent(TRACE_DEBUG, "MAC address is null."); + return buf; + } + + if(!(fd = fopen("/proc/net/arp", "r"))) { + traceEvent(TRACE_WARNING, "could not open arp table: %d - %s", errno, strerror(errno)); + return buf; + } + + while(!feof(fd) && fgetc(fd) != '\n'); + while(!feof(fd) && (fscanf(fd, " %15[0-9.] %*s %*s %17[A-Fa-f0-9:] %*s %15s", ip_str, mac_str, dev_str) == 3)) { + str2mac(mac, mac_str); + if(0 == memcmp(mac, req_mac, sizeof(n2n_mac_t))) { + strncpy(buf, ip_str, N2N_NETMASK_STR_SIZE - 1); + break; + } + } + fclose(fd); + + return buf; +} + +#endif +#endif + +/* ************************************** */ + +static int check_query_peer_info (n2n_edge_t *eee, time_t now, n2n_mac_t mac) { + + struct peer_info *scan; + + HASH_FIND_PEER(eee->pending_peers, mac, scan); + + if(!scan) { + scan = calloc(1, sizeof(struct peer_info)); + + memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); + scan->timeout = eee->conf.register_interval; /* TODO: should correspond to the peer supernode registration timeout */ + scan->last_seen = now; /* Don't change this it marks the pending peer for removal. */ + scan->last_valid_time_stamp = initial_time_stamp(); + + HASH_ADD_PEER(eee->pending_peers, scan); + } + + if(now - scan->last_sent_query > eee->conf.register_interval) { + send_register(eee, &(eee->curr_sn->sock), mac, N2N_FORWARDED_REG_COOKIE); + send_query_peer(eee, scan->mac_addr); + scan->last_sent_query = now; + return(0); + } + + return(1); +} + +/* ************************************** */ + +/* @return 1 if destination is a peer, 0 if destination is supernode */ +static int find_peer_destination (n2n_edge_t * eee, + n2n_mac_t mac_address, + n2n_sock_t * destination) { + + struct peer_info *scan; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + int retval = 0; + time_t now = time(NULL); + + if(is_multi_broadcast(mac_address)) { + traceEvent(TRACE_DEBUG, "multicast or broadcast destination peer, using supernode"); + memcpy(destination, &(eee->curr_sn->sock), sizeof(struct sockaddr_in)); + return(0); + } + + traceEvent(TRACE_DEBUG, "searching destination socket for %s", + macaddr_str(mac_buf, mac_address)); + + HASH_FIND_PEER(eee->known_peers, mac_address, scan); + + if(scan && (scan->last_seen > 0)) { + if((now - scan->last_p2p) >= (scan->timeout / 2)) { + /* Too much time passed since we saw the peer, need to register again + * since the peer address may have changed. */ + traceEvent(TRACE_DEBUG, "refreshing idle known peer"); + HASH_DEL(eee->known_peers, scan); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan); + free(scan); + /* NOTE: registration will be performed upon the receival of the next response packet */ + } else { + /* Valid known peer found */ + memcpy(destination, &scan->sock, sizeof(n2n_sock_t)); + retval = 1; + } + } + + if(retval == 0) { + memcpy(destination, &(eee->curr_sn->sock), sizeof(struct sockaddr_in)); + traceEvent(TRACE_DEBUG, "p2p peer %s not found, using supernode", + macaddr_str(mac_buf, mac_address)); + + check_query_peer_info(eee, now, mac_address); + } + + traceEvent(TRACE_DEBUG, "found peer's socket %s [%s]", + macaddr_str(mac_buf, mac_address), + sock_to_cstr(sockbuf, destination)); + + return retval; +} + +/* ***************************************************** */ + +/** Send an ecapsulated ethernet PACKET to a destination edge or broadcast MAC + * address. */ +static int send_packet (n2n_edge_t * eee, + n2n_mac_t dstMac, + const uint8_t * pktbuf, + size_t pktlen) { + + int is_p2p; + /*ssize_t s; */ + n2n_sock_str_t sockbuf; + n2n_sock_t destination; + macstr_t mac_buf; + struct peer_info *peer, *tmp_peer; + + /* hexdump(pktbuf, pktlen); */ + + is_p2p = find_peer_destination(eee, dstMac, &destination); + + traceEvent(TRACE_INFO, "Tx PACKET of %u bytes to %s [%s]", + pktlen, macaddr_str(mac_buf, dstMac), + sock_to_cstr(sockbuf, &destination)); + + if(is_p2p) + ++(eee->stats.tx_p2p); + else + ++(eee->stats.tx_sup); + + if(is_multi_broadcast(dstMac)) { + ++(eee->stats.tx_sup_broadcast); + + // if no supernode around, foward the broadcast to all known peers + if(eee->sn_wait) { + HASH_ITER(hh, eee->known_peers, peer, tmp_peer) + /* s = */ sendto_sock(eee, pktbuf, pktlen, &peer->sock); + return 0; + } + // fall through otherwise + } + + /* s = */ sendto_sock(eee, pktbuf, pktlen, &destination); + + return 0; +} + +/* ************************************** */ + +/** A layer-2 packet was received at the tunnel and needs to be sent via UDP. */ +void edge_send_packet2net (n2n_edge_t * eee, + uint8_t *tap_pkt, size_t len) { + + ipstr_t ip_buf; + n2n_mac_t destMac; + n2n_common_t cmn; + n2n_PACKET_t pkt; + uint8_t *enc_src = tap_pkt; + size_t enc_len = len; + uint8_t compression_buf[N2N_PKT_BUF_SIZE]; + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx = 0; + n2n_transform_t tx_transop_idx = eee->transop.transform_id; + ether_hdr_t eh; + + /* tap_pkt is not aligned so we have to copy to aligned memory */ + memcpy(&eh, tap_pkt, sizeof(ether_hdr_t)); + + /* Discard IP packets that are not originated by this hosts */ + if(!(eee->conf.allow_routing)) { + if(ntohs(eh.type) == 0x0800) { + /* This is an IP packet from the local source address - not forwarded. */ + uint32_t *src = (uint32_t*)&tap_pkt[ETH_FRAMESIZE + IP4_SRCOFFSET]; + + /* Note: all elements of the_ip are in network order */ + if(*src != eee->device.ip_addr) { + /* This is a packet that needs to be routed */ + traceEvent(TRACE_INFO, "discarding routed packet destined to [%s]", + intoa(ntohl(*src), ip_buf, sizeof(ip_buf))); + return; + } else { + /* This packet is originated by us */ + /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ + } + } + } + + /* Optionally compress then apply transforms, eg encryption. */ + + /* Once processed, send to destination in PACKET */ + + memcpy(destMac, tap_pkt, N2N_MAC_SIZE); /* dest MAC is first in ethernet header */ + + memset(&cmn, 0, sizeof(cmn)); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_packet; + cmn.flags = 0; /* no options, not from supernode, no socket */ + memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); + + memset(&pkt, 0, sizeof(pkt)); + memcpy(pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); + memcpy(pkt.dstMac, destMac, N2N_MAC_SIZE); + + pkt.transform = tx_transop_idx; + + // compression needs to be tried before encode_PACKET is called for compression indication gets encoded there + pkt.compression = N2N_COMPRESSION_ID_NONE; + + if(eee->conf.compression) { + int32_t compression_len; + + switch(eee->conf.compression) { + case N2N_COMPRESSION_ID_LZO: + compression_len = eee->transop_lzo.fwd(&eee->transop_lzo, + compression_buf, sizeof(compression_buf), + tap_pkt, len, + pkt.dstMac); + + if((compression_len > 0) && (compression_len < len)) { + pkt.compression = N2N_COMPRESSION_ID_LZO; + } + break; + +#ifdef HAVE_ZSTD + case N2N_COMPRESSION_ID_ZSTD: + compression_len = eee->transop_zstd.fwd(&eee->transop_zstd, + compression_buf, sizeof(compression_buf), + tap_pkt, len, + pkt.dstMac); + + if((compression_len > 0) && (compression_len < len)) { + pkt.compression = N2N_COMPRESSION_ID_ZSTD; + } + break; +#endif + + default: + break; + } + + if(pkt.compression != N2N_COMPRESSION_ID_NONE) { + traceEvent(TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n", + compression_str(pkt.compression), len, compression_len); + enc_src = compression_buf; + enc_len = compression_len; + } + } + + idx = 0; + encode_PACKET(pktbuf, &idx, &cmn, &pkt); + + uint16_t headerIdx = idx; + + idx += eee->transop.fwd(&eee->transop, + pktbuf + idx, N2N_PKT_BUF_SIZE - idx, + enc_src, enc_len, pkt.dstMac); + + traceEvent(TRACE_DEBUG, "encode PACKET of %u bytes, %u bytes data, %u bytes overhead, transform %u", + (u_int)idx, (u_int)len, (u_int)(idx - len), tx_transop_idx); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) + // in case of user-password auth, also encrypt the iv of payload assuming ChaCha20 and SPECK having the same iv size + packet_header_encrypt(pktbuf, headerIdx + (NULL != eee->conf.shared_secret) * min(idx - headerIdx, N2N_SPECK_IVEC_SIZE), idx, + eee->conf.header_encryption_ctx_dynamic, eee->conf.header_iv_ctx_dynamic, + time_stamp()); + +#ifdef MTU_ASSERT_VALUE + { + const u_int eth_udp_overhead = ETH_FRAMESIZE + IP4_MIN_SIZE + UDP_SIZE; + + // MTU assertion which avoids fragmentation by N2N + assert(idx + eth_udp_overhead <= MTU_ASSERT_VALUE); + } +#endif + + eee->transop.tx_cnt++; /* stats */ + + send_packet(eee, destMac, pktbuf, idx); /* to peer or supernode */ +} + +/* ************************************** */ + +/** Read a single packet from the TAP interface, process it and write out the + * corresponding packet to the cooked socket. + */ +void edge_read_from_tap (n2n_edge_t * eee) { + + /* tun -> remote */ + uint8_t eth_pkt[N2N_PKT_BUF_SIZE]; + macstr_t mac_buf; + ssize_t len; + + len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE ); + if((len <= 0) || (len > N2N_PKT_BUF_SIZE)) { + traceEvent(TRACE_WARNING, "read()=%d [%d/%s]", + (signed int)len, errno, strerror(errno)); + traceEvent(TRACE_WARNING, "TAP I/O operation aborted, restart later."); + sleep(3); + tuntap_close(&(eee->device)); + tuntap_open(&(eee->device), eee->tuntap_priv_conf.tuntap_dev_name, eee->tuntap_priv_conf.ip_mode, eee->tuntap_priv_conf.ip_addr, + eee->tuntap_priv_conf.netmask, eee->tuntap_priv_conf.device_mac, eee->tuntap_priv_conf.mtu +#ifdef WIN32 + ,eee->tuntap_priv_conf.metric +#endif + ); + } else { + const uint8_t * mac = eth_pkt; + traceEvent(TRACE_DEBUG, "Rx TAP packet (%4d) for %s", + (signed int)len, macaddr_str(mac_buf, mac)); + + if(eee->conf.drop_multicast && + (is_ip6_discovery(eth_pkt, len) || + is_ethMulticast(eth_pkt, len))) { + traceEvent(TRACE_INFO, "dropping Tx multicast"); + } else { + if(!eee->last_sup) { + // drop packets before first registration with supernode + traceEvent(TRACE_DEBUG, "DROP packet before first registration with supernode"); + return; + } + + if(eee->network_traffic_filter) { + if(eee->network_traffic_filter->filter_packet_from_tap(eee->network_traffic_filter, eee, eth_pkt, + len) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "filtered packet of size %u", (unsigned int)len); + return; + } + } + + if(eee->cb.packet_from_tap) { + uint16_t tmp_len = len; + if(eee->cb.packet_from_tap(eee, eth_pkt, &tmp_len) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "DROP packet of size %u", (unsigned int)len); + return; + } + len = tmp_len; + } + + edge_send_packet2net(eee, eth_pkt, len); + } + } +} + + +/* ************************************** */ + + +/** handle a datagram from the main UDP socket to the internet. */ +void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const SOCKET in_sock, + uint8_t *udp_buf, size_t udp_size, time_t now) { + + n2n_common_t cmn; /* common fields in the packet header */ + n2n_sock_str_t sockbuf1; + n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */ + macstr_t mac_buf1; + macstr_t mac_buf2; + uint8_t hash_buf[16]; + size_t rem; + size_t idx; + size_t msg_type; + uint8_t from_supernode; + uint8_t via_multicast; + peer_info_t *sn = NULL; + n2n_sock_t sender; + n2n_sock_t * orig_sender = NULL; + uint32_t header_enc = 0; + uint64_t stamp = 0; + int skip_add = 0; + + /* REVISIT: when UDP/IPv6 is supported we will need a flag to indicate which + * IP transport version the packet arrived on. May need to UDP sockets. */ + + memset(&sender, 0, sizeof(n2n_sock_t)); + + if(eee->conf.connect_tcp) + // TCP expects that we know our comm partner and does not deliver the sender + memcpy(&sender, &(eee->curr_sn->sock), sizeof(struct sockaddr_in)); + else { + sender.family = AF_INET; /* UDP socket was opened PF_INET v4 */ + sender.port = ntohs(sender_sock->sin_port); + memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + } + /* The packet may not have an orig_sender socket spec. So default to last + * hop as sender. */ + orig_sender = &sender; + +#ifdef SKIP_MULTICAST_PEERS_DISCOVERY + via_multicast = 0; +#else + via_multicast = (in_sock == eee->udp_multicast_sock); +#endif + + traceEvent(TRACE_DEBUG, "Rx N2N_UDP of size %d from [%s]", + (signed int)udp_size, sock_to_cstr(sockbuf1, &sender)); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + // match with static (1) or dynamic (2) ctx? + // check dynamic first as it is identical to static in normal header encryption mode + if(packet_header_decrypt(udp_buf, udp_size, + (char *)eee->conf.community_name, + eee->conf.header_encryption_ctx_dynamic, eee->conf.header_iv_ctx_dynamic, + &stamp)) { + header_enc = 2; /* not accurate with normal header encryption but does not matter */ + } + if(!header_enc) { + // check static now (very likely to be REGISTER_SUPER_ACK, REGISTER_SUPER_NAK or invalid) + if(eee->conf.shared_secret) { + // hash the still encrypted packet to eventually be able to check it later (required for REGISTER_SUPER_ACK with user/pw auth) + pearson_hash_128(hash_buf, udp_buf, max(0, (int)udp_size - (int)N2N_REG_SUP_HASH_CHECK_LEN)); + } + header_enc = packet_header_decrypt(udp_buf, max(0, (int)udp_size - (int)N2N_REG_SUP_HASH_CHECK_LEN), + (char *)eee->conf.community_name, + eee->conf.header_encryption_ctx_static, eee->conf.header_iv_ctx_static, + &stamp); + } + if(!header_enc) { + traceEvent(TRACE_DEBUG, "failed to decrypt header"); + return; + } + // time stamp verification follows in the packet specific section as it requires to determine the + // sender from the hash list by its MAC, or the packet might be from the supernode, this all depends + // on packet type, path taken (via supernode) and packet structure (MAC is not always in the same place) + } + + rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */ + idx = 0; /* marches through packet header as parts are decoded. */ + if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) { + if(via_multicast) { + // from some other edge on local network, possibly header encrypted + traceEvent(TRACE_DEBUG, "dropped packet arriving via multicast due to error while decoding N2N_UDP"); + } else { + traceEvent(TRACE_INFO, "failed to decode common section in N2N_UDP"); + } + return; /* failed to decode packet */ + } + + msg_type = cmn.pc; /* packet code */ + + // special case for user/pw auth + // community's auth scheme and message type need to match the used key (dynamic) + if((eee->conf.shared_secret) + && (msg_type != MSG_TYPE_REGISTER_SUPER_ACK) + && (msg_type != MSG_TYPE_REGISTER_SUPER_NAK)) { + if(header_enc != 2) { + traceEvent(TRACE_INFO, "dropped packet encrypted with static key where dynamic key expected"); + return; + } + } + + // check if packet is from supernode and find the corresponding supernode in list + from_supernode = cmn.flags & N2N_FLAGS_FROM_SUPERNODE; + if(from_supernode) { + skip_add = SN_ADD_SKIP; + sn = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &sender, null_mac, &skip_add); + if(!sn) { + traceEvent(TRACE_DEBUG, "dropped incoming data from unknown supernode"); + return; + } + } + + if(0 == memcmp(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE)) { + switch(msg_type) { + case MSG_TYPE_PACKET: { + /* process PACKET - most frequent so first in list. */ + n2n_PACKET_t pkt; + + decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify(eee, sn, pkt.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped PACKET due to time stamp error"); + return; + } + } + + if(!eee->last_sup) { + // drop packets received before first registration with supernode + traceEvent(TRACE_DEBUG, "dropped PACKET recevied before first registration with supernode"); + return; + } + + if(!from_supernode) { + /* This is a P2P packet from the peer. We purge a pending + * registration towards the possibly nat-ted peer address as we now have + * a valid channel. We still use check_peer_registration_needed in + * handle_PACKET to double check this. + */ + traceEvent(TRACE_DEBUG, "[p2p] from %s", + macaddr_str(mac_buf1, pkt.srcMac)); + find_and_remove_peer(&eee->pending_peers, pkt.srcMac); + } else { + /* [PsP] : edge Peer->Supernode->edge Peer */ + + if(is_valid_peer_sock(&pkt.sock)) + orig_sender = &(pkt.sock); + + traceEvent(TRACE_DEBUG, "[pSp] from %s via [%s]", + macaddr_str(mac_buf1, pkt.srcMac), + sock_to_cstr(sockbuf1, &sender)); + } + + /* Update the sender in peer table entry */ + check_peer_registration_needed(eee, from_supernode, via_multicast, + pkt.srcMac, + // REVISIT: also consider PORT_REG_COOKIEs when implemented + from_supernode ? N2N_FORWARDED_REG_COOKIE : N2N_REGULAR_REG_COOKIE, + NULL, NULL, orig_sender); + + handle_PACKET(eee, from_supernode, &pkt, orig_sender, udp_buf + idx, udp_size - idx); + break; + } + + case MSG_TYPE_REGISTER: { + /* Another edge is registering with us */ + n2n_REGISTER_t reg; + + decode_REGISTER(®, &cmn, udp_buf, &rem, &idx); + + via_multicast &= is_null_mac(reg.dstMac); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify(eee, sn, reg.srcMac, stamp, + via_multicast ? TIME_STAMP_ALLOW_JITTER : TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped REGISTER due to time stamp error"); + return; + } + } + + if(is_valid_peer_sock(®.sock)) + orig_sender = &(reg.sock); + + if(via_multicast && !memcmp(reg.srcMac, eee->device.mac_addr, N2N_MAC_SIZE)) { + traceEvent(TRACE_DEBUG, "skipping REGISTER from self"); + break; + } + + if(!via_multicast && memcmp(reg.dstMac, eee->device.mac_addr, N2N_MAC_SIZE)) { + traceEvent(TRACE_DEBUG, "skipping REGISTER for other peer"); + break; + } + + if(!from_supernode) { + /* This is a P2P registration from the peer. We purge a pending + * registration towards the possibly nat-ted peer address as we now have + * a valid channel. We still use check_peer_registration_needed below + * to double check this. + */ + traceEvent(TRACE_INFO, "[p2p] Rx REGISTER from %s [%s]%s", + macaddr_str(mac_buf1, reg.srcMac), + sock_to_cstr(sockbuf1, &sender), + (reg.cookie & N2N_LOCAL_REG_COOKIE) ? " (local)" : ""); + find_and_remove_peer(&eee->pending_peers, reg.srcMac); + + /* NOTE: only ACK to peers */ + send_register_ack(eee, orig_sender, ®); + } else { + traceEvent(TRACE_INFO, "[pSp] Rx REGISTER from %s [%s] to %s via [%s]", + macaddr_str(mac_buf1, reg.srcMac), sock_to_cstr(sockbuf2, orig_sender), + macaddr_str(mac_buf2, reg.dstMac), sock_to_cstr(sockbuf1, &sender)); + } + + check_peer_registration_needed(eee, from_supernode, via_multicast, + reg.srcMac, reg.cookie, ®.dev_addr, (const n2n_desc_t*)®.dev_desc, orig_sender); + break; + } + + case MSG_TYPE_REGISTER_ACK: { + /* Peer edge is acknowledging our register request */ + n2n_REGISTER_ACK_t ra; + + decode_REGISTER_ACK(&ra, &cmn, udp_buf, &rem, &idx); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify(eee, sn, ra.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped REGISTER_ACK due to time stamp error"); + return; + } + } + + if(is_valid_peer_sock(&ra.sock)) + orig_sender = &(ra.sock); + + traceEvent(TRACE_INFO, "Rx REGISTER_ACK from %s [%s] to %s via [%s]%s", + macaddr_str(mac_buf1, ra.srcMac), + sock_to_cstr(sockbuf2, orig_sender), + macaddr_str(mac_buf2, ra.dstMac), + sock_to_cstr(sockbuf1, &sender), + (ra.cookie & N2N_LOCAL_REG_COOKIE) ? " (local)" : ""); + + peer_set_p2p_confirmed(eee, ra.srcMac, + ra.cookie, + &sender, now); + break; + } + + case MSG_TYPE_REGISTER_SUPER_ACK: { + in_addr_t net; + char * ip_str = NULL; + n2n_REGISTER_SUPER_ACK_t ra; + uint8_t tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; + char ip_tmp[N2N_EDGE_SN_HOST_SIZE]; + n2n_REGISTER_SUPER_ACK_payload_t *payload; + int i; + int skip_add; + + if(!(eee->sn_wait)) { + traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER_ACK with no outstanding REGISTER_SUPER"); + return; + } + + memset(&ra, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); + decode_REGISTER_SUPER_ACK(&ra, &cmn, udp_buf, &rem, &idx, tmpbuf); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify(eee, sn, ra.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped REGISTER_SUPER_ACK due to time stamp error"); + return; + } + } + + // hash check (user/pw auth only) + if(eee->conf.shared_secret) { + speck_128_encrypt(hash_buf, (speck_context_t*)eee->conf.shared_secret_ctx); + if(memcmp(hash_buf, udp_buf + udp_size - N2N_REG_SUP_HASH_CHECK_LEN /* length is has already been checked */, N2N_REG_SUP_HASH_CHECK_LEN)) { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong hash"); + return; + } + } + + if(ra.cookie != eee->curr_sn->last_cookie) { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old cookie"); + return; + } + + if(handle_remote_auth(eee, sn, &(ra.auth))) { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old response to challenge"); + if(eee->conf.shared_secret) { + traceEvent(TRACE_NORMAL, "Rx REGISTER_SUPER_ACK with wrong or old response to challenge, maybe indicating wrong federation public key (-P)"); + } + return; + } + + if(is_valid_peer_sock(&ra.sock)) + orig_sender = &(ra.sock); + + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK from %s [%s] (external %s) with %u attempts left", + macaddr_str(mac_buf1, ra.srcMac), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender), + (unsigned int)eee->sup_attempts); + + if(is_null_mac(eee->curr_sn->mac_addr)) { + HASH_DEL(eee->conf.supernodes, eee->curr_sn); + memcpy(&eee->curr_sn->mac_addr, ra.srcMac, N2N_MAC_SIZE); + HASH_ADD_PEER(eee->conf.supernodes, eee->curr_sn); + } + + payload = (n2n_REGISTER_SUPER_ACK_payload_t*)tmpbuf; + + // from here on, 'sn' gets used differently + for(i = 0; i < ra.num_sn; i++) { + skip_add = SN_ADD; + sn = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &(payload->sock), payload->mac, &skip_add); + + if(skip_add == SN_ADD_ADDED) { + sn->ip_addr = calloc(1, N2N_EDGE_SN_HOST_SIZE); + if(sn->ip_addr != NULL) { + inet_ntop(payload->sock.family, + (payload->sock.family == AF_INET) ? (void*)&(payload->sock.addr.v4) : (void*)&(payload->sock.addr.v6), + sn->ip_addr, N2N_EDGE_SN_HOST_SIZE - 1); + sprintf(ip_tmp, "%s:%u", (char*)sn->ip_addr, (uint16_t)(payload->sock.port)); + memcpy(sn->ip_addr, ip_tmp, sizeof(ip_tmp)); + } + sn_selection_criterion_default(&(sn->selection_criterion)); + sn->last_seen = 0; /* as opposed to payload handling in supernode */ + traceEvent(TRACE_NORMAL, "supernode '%s' added to the list of supernodes.", sn->ip_addr); + } + // shift to next payload entry + payload++; + } + + if(eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_SN_ASSIGN) { + if((ra.dev_addr.net_addr != 0) && (ra.dev_addr.net_bitlen != 0)) { + net = htonl(ra.dev_addr.net_addr); + if((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) { + strncpy(eee->tuntap_priv_conf.ip_addr, ip_str, N2N_NETMASK_STR_SIZE); + eee->tuntap_priv_conf.ip_addr[N2N_NETMASK_STR_SIZE - 1] = '\0'; + } + net = htonl(bitlen2mask(ra.dev_addr.net_bitlen)); + if((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) { + strncpy(eee->tuntap_priv_conf.netmask, ip_str, N2N_NETMASK_STR_SIZE); + eee->tuntap_priv_conf.netmask[N2N_NETMASK_STR_SIZE - 1] = '\0'; + } + } + } + + eee->sn_wait = 0; + reset_sup_attempts(eee); /* refresh because we got a response */ + + // update last_sup only on 'real' REGISTER_SUPER_ACKs, not on bootstrap ones (own MAC address + // still null_mac) this allows reliable in/out PACKET drop if not really registered with a supernode yet + if(!is_null_mac(eee->device.mac_addr)) { + if(!eee->last_sup) { + // indicates first successful connection between the edge and a supernode + traceEvent(TRACE_NORMAL, "[OK] edge <<< ================ >>> supernode"); + // send gratuitous ARP only upon first registration with supernode + send_grat_arps(eee); + } + eee->last_sup = now; + } + + // NOTE: the register_interval should be chosen by the edge node based on its NAT configuration. + // eee->conf.register_interval = ra.lifetime; + + if(eee->cb.sn_registration_updated && !is_null_mac(eee->device.mac_addr)) + eee->cb.sn_registration_updated(eee, now, &sender); + + break; + } + + case MSG_TYPE_REGISTER_SUPER_NAK: { + + n2n_REGISTER_SUPER_NAK_t nak; + + if(!(eee->sn_wait)) { + traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER_NAK with no outstanding REGISTER_SUPER"); + return; + } + + memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + decode_REGISTER_SUPER_NAK(&nak, &cmn, udp_buf, &rem, &idx); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify(eee, sn, nak.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped REGISTER_SUPER_NAK due to time stamp error"); + return; + } + } + + if(nak.cookie != eee->curr_sn->last_cookie) { + traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER_NAK with wrong or old cookie"); + return; + } + + // REVISIT: authenticate the NAK packet really originating from the supernode along the auth token. + // this must follow a different scheme because it needs to prove authenticity although the + // edge-provided credentials are wrong + + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_NAK"); + + if((memcmp(nak.srcMac, eee->device.mac_addr, sizeof(n2n_mac_t))) == 0) { + if(eee->conf.shared_secret) { + traceEvent(TRACE_ERROR, "authentication error, username or password not recognized by supernode"); + } else { + traceEvent(TRACE_ERROR, "authentication error, MAC or IP address already in use or not released yet by supernode"); + } + // REVISIT: the following portion is too harsh, repeated error warning should be sufficient until it eventually is resolved, + // preventing de-auth attacks + /* exit(1); this is too harsh, repeated error warning should be sufficient until it eventually is resolved, preventing de-auth attacks + } else { + HASH_FIND_PEER(eee->known_peers, nak.srcMac, peer); + if(peer != NULL) { + HASH_DEL(eee->known_peers, peer); + } + HASH_FIND_PEER(eee->pending_peers, nak.srcMac, scan); + if(scan != NULL) { + HASH_DEL(eee->pending_peers, scan); + } */ + } + break; + } + + case MSG_TYPE_PEER_INFO: { + + n2n_PEER_INFO_t pi; + struct peer_info * scan; + int skip_add; + + decode_PEER_INFO(&pi, &cmn, udp_buf, &rem, &idx); + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify(eee, sn, null_mac, stamp, TIME_STAMP_ALLOW_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped PEER_INFO due to time stamp error"); + return; + } + } + + if((cmn.flags & N2N_FLAGS_SOCKET) && !is_valid_peer_sock(&pi.sock)) { + traceEvent(TRACE_DEBUG, "skip invalid PEER_INFO from %s [%s]", + macaddr_str(mac_buf1, pi.mac), + sock_to_cstr(sockbuf1, &pi.sock)); + break; + } + + if(is_null_mac(pi.mac)) { + // PONG - answer to PING (QUERY_PEER_INFO with null mac) + skip_add = SN_ADD_SKIP; + scan = add_sn_to_list_by_mac_or_sock(&(eee->conf.supernodes), &sender, pi.srcMac, &skip_add); + if(scan != NULL) { + eee->sn_pong = 1; + scan->last_seen = now; + scan->uptime = pi.uptime; + memcpy(scan->version, pi.version, sizeof(n2n_version_t)); + /* The data type depends on the actual selection strategy that has been chosen. */ + SN_SELECTION_CRITERION_DATA_TYPE sn_sel_tmp = pi.load; + sn_selection_criterion_calculate(eee, scan, &sn_sel_tmp); + + traceEvent(TRACE_INFO, "Rx PONG from supernode %s version '%s'", + macaddr_str(mac_buf1, pi.srcMac), + pi.version); + + break; + } + } else { + // regular PEER_INFO + HASH_FIND_PEER(eee->pending_peers, pi.mac, scan); + if(!scan) + // just in case the remote edge has been upgraded by the REG/ACK mechanism in the meantime + HASH_FIND_PEER(eee->known_peers, pi.mac, scan); + + if(scan) { + scan->sock = pi.sock; + + traceEvent(TRACE_INFO, "Rx PEER_INFO %s can be found at [%s]", + macaddr_str(mac_buf1, pi.mac), + sock_to_cstr(sockbuf1, &pi.sock)); + + if(cmn.flags & N2N_FLAGS_SOCKET) { + scan->preferred_sock = pi.preferred_sock; + send_register(eee, &scan->preferred_sock, scan->mac_addr, N2N_LOCAL_REG_COOKIE); + + traceEvent(TRACE_INFO, "%s has preferred local socket at [%s]", + macaddr_str(mac_buf1, pi.mac), + sock_to_cstr(sockbuf1, &pi.preferred_sock)); + } + + send_register(eee, &scan->sock, scan->mac_addr, N2N_REGULAR_REG_COOKIE); + + } else { + traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s", + macaddr_str(mac_buf1, pi.mac)); + } + } + break; + } + + case MSG_TYPE_RE_REGISTER_SUPER: { + + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_peer_time_stamp_and_verify(eee, sn, null_mac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped RE_REGISTER due to time stamp error"); + return; + } + } + + // only accept in user/pw mode for immediate re-registration because the new + // key is required for continous traffic flow, in other modes edge will realize + // changes with regular recurring REGISTER_SUPER + if(!eee->conf.shared_secret) { + traceEvent(TRACE_DEBUG, "dropped RE_REGISTER_SUPER as not in user/pw auth mode"); + return; + } + + traceEvent(TRACE_INFO, "Rx RE_REGISTER_SUPER"); + + eee->sn_wait = 2; /* immediately */ + + break; + } + + default: + /* Not a known message type */ + traceEvent(TRACE_INFO, "unable to handle packet type %d: ignored", (signed int)msg_type); + return; + } /* switch(msg_type) */ + } else if(from_supernode) /* if(community match) */ + traceEvent(TRACE_INFO, "received packet with unknown community"); + else + traceEvent(TRACE_INFO, "ignoring packet with unknown community"); +} + + +/* ************************************** */ + + +int fetch_and_eventually_process_data (n2n_edge_t *eee, SOCKET sock, + uint8_t *pktbuf, uint16_t *expected, uint16_t *position, + time_t now) { + + ssize_t bread = 0; + + if((!eee->conf.connect_tcp) +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + || (sock == eee->udp_multicast_sock) +#endif + ) { + // udp + struct sockaddr_in sender_sock; + socklen_t i; + + i = sizeof(sender_sock); + bread = recvfrom(sock, pktbuf, N2N_PKT_BUF_SIZE, 0 /*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t *)&i); + + if((bread < 0) +#ifdef WIN32 + && (WSAGetLastError() != WSAECONNRESET) +#endif + ) { + /* For UDP bread of zero just means no data (unlike TCP). */ + /* The fd is no good now. Maybe we lost our interface. */ + traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno)); +#ifdef WIN32 + traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); +#endif + return -1; + } + + // we have a datagram to process... + if(bread > 0) { + // ...and the datagram has data (not just a header) + process_udp(eee, &sender_sock, sock, pktbuf, bread, now); + } + + } else { + // tcp + struct sockaddr_in sender_sock; + socklen_t i; + + i = sizeof(sender_sock); + bread = recvfrom(sock, + pktbuf + *position, *expected - *position, 0 /*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t *)&i); + if((bread <= 0) && (errno)) { + traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno)); +#ifdef WIN32 + traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); +#endif + supernode_disconnect(eee); + eee->sn_wait = 1; + traceEvent(TRACE_DEBUG, "disconnected supernode due to connection error"); + goto tcp_done; + } + *position = *position + bread; + + if(*position == *expected) { + if(*position == sizeof(uint16_t)) { + // the prepended length has been read, preparing for the packet + *expected = *expected + be16toh(*(uint16_t*)(pktbuf)); + if(*expected > N2N_PKT_BUF_SIZE) { + supernode_disconnect(eee); + eee->sn_wait = 1; + traceEvent(TRACE_DEBUG, "disconnected supernode due to too many bytes expected"); + goto tcp_done; + } + } else { + // full packet read, handle it + process_udp(eee, (struct sockaddr_in*)&sender_sock, sock, + pktbuf + sizeof(uint16_t), *position - sizeof(uint16_t), now); + // reset, await new prepended length + *expected = sizeof(uint16_t); + *position = 0; + } + } + } + tcp_done: + ; + + return 0; +} + + +void print_edge_stats (const n2n_edge_t *eee) { + + const struct n2n_edge_stats *s = &eee->stats; + + traceEvent(TRACE_NORMAL, "**********************************"); + traceEvent(TRACE_NORMAL, "Packet stats:"); + traceEvent(TRACE_NORMAL, " TX P2P: %u pkts", s->tx_p2p); + traceEvent(TRACE_NORMAL, " RX P2P: %u pkts", s->rx_p2p); + traceEvent(TRACE_NORMAL, " TX Supernode: %u pkts (%u broadcast)", s->tx_sup, s->tx_sup_broadcast); + traceEvent(TRACE_NORMAL, " RX Supernode: %u pkts (%u broadcast)", s->rx_sup, s->rx_sup_broadcast); + traceEvent(TRACE_NORMAL, "**********************************"); +} + + +/* ************************************** */ + + +int run_edge_loop (n2n_edge_t *eee) { + + size_t numPurged; + time_t lastIfaceCheck = 0; + time_t lastTransop = 0; + time_t last_purge_known = 0; + time_t last_purge_pending = 0; + + uint16_t expected = sizeof(uint16_t); + uint16_t position = 0; + uint8_t pktbuf[N2N_PKT_BUF_SIZE + sizeof(uint16_t)]; /* buffer + prepended buffer length in case of tcp */ + +#ifdef WIN32 + struct tunread_arg arg; + arg.eee = eee; + HANDLE tun_read_thread = startTunReadThread(&arg); +#endif + + *eee->keep_running = 1; + update_supernode_reg(eee, time(NULL)); + + /* Main loop + * + * select() is used to wait for input on either the TAP fd or the UDP/TCP + * socket. When input is present the data is read and processed by either + * readFromIPSocket() or edge_read_from_tap() + */ + + while(*eee->keep_running) { + + int rc, max_sock = 0; + fd_set socket_mask; + struct timeval wait_time; + time_t now; + + FD_ZERO(&socket_mask); + + FD_SET(eee->udp_mgmt_sock, &socket_mask); + max_sock = eee->udp_mgmt_sock; + + if(eee->sock >= 0) { + FD_SET(eee->sock, &socket_mask); + max_sock = max(eee->sock, eee->udp_mgmt_sock); + } +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + if((eee->conf.allow_p2p) + && (eee->conf.preferred_sock.family == (uint8_t)AF_INVALID)) { + FD_SET(eee->udp_multicast_sock, &socket_mask); + max_sock = max(eee->sock, eee->udp_multicast_sock); + } +#endif + +#ifndef WIN32 + FD_SET(eee->device.fd, &socket_mask); + max_sock = max(max_sock, eee->device.fd); +#endif + + wait_time.tv_sec = (eee->sn_wait) ? (SOCKET_TIMEOUT_INTERVAL_SECS / 10 + 1) : (SOCKET_TIMEOUT_INTERVAL_SECS); + wait_time.tv_usec = 0; + rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time); + now = time(NULL); + + // make sure ciphers are updated before the packet is treated + if((now - lastTransop) > TRANSOP_TICK_INTERVAL) { + lastTransop = now; + + eee->transop.tick(&eee->transop, now); + } + + if(rc > 0) { + // any or all of the FDs could have input; check them all + + // external + if(FD_ISSET(eee->sock, &socket_mask)) { + if(0 != fetch_and_eventually_process_data(eee, eee->sock, + pktbuf, &expected, &position, + now)) { + *eee->keep_running = 0; + break; + } + if(eee->conf.connect_tcp) { + if((expected >= N2N_PKT_BUF_SIZE) || (position >= N2N_PKT_BUF_SIZE)) { + // something went wrong, possibly even before + // e.g. connection failure/closure in the middle of transmission (between len & data) + supernode_disconnect(eee); + eee->sn_wait = 1; + + expected = sizeof(uint16_t); + position = 0; + } + } + } + +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + if(FD_ISSET(eee->udp_multicast_sock, &socket_mask)) { + if(0 != fetch_and_eventually_process_data(eee, eee->udp_multicast_sock, + pktbuf, &expected, &position, + now)) { + *eee->keep_running = 0; + break; + } + } +#endif + + if(FD_ISSET(eee->udp_mgmt_sock, &socket_mask)) { + // read from the management port socket + readFromMgmtSocket(eee); + + if(!(*eee->keep_running)) + break; + } + +#ifndef WIN32 + if(FD_ISSET(eee->device.fd, &socket_mask)) { + // read an ethernet frame from the TAP socket; write on the IP socket + edge_read_from_tap(eee); + } +#endif + } + + // finished processing select data + update_supernode_reg(eee, now); + + numPurged = 0; + // keep, i.e. do not purge, the known peers while no supernode supernode connection + if(!eee->sn_wait) + numPurged = purge_expired_nodes(&eee->known_peers, + eee->sock, NULL, + &last_purge_known, + PURGE_REGISTRATION_FREQUENCY, REGISTRATION_TIMEOUT); + numPurged += purge_expired_nodes(&eee->pending_peers, + eee->sock, NULL, + &last_purge_pending, + PURGE_REGISTRATION_FREQUENCY, REGISTRATION_TIMEOUT); + + if(numPurged > 0) { + traceEvent(TRACE_INFO, "%u peers removed. now: pending=%u, operational=%u", + numPurged, + HASH_COUNT(eee->pending_peers), + HASH_COUNT(eee->known_peers)); + } + + if((eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_DHCP) && + ((now - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) { + uint32_t old_ip = eee->device.ip_addr; + + traceEvent(TRACE_NORMAL, "re-checking dynamic IP address"); + tuntap_get_address(&(eee->device)); + lastIfaceCheck = now; + + if((old_ip != eee->device.ip_addr) && eee->cb.ip_address_changed) + eee->cb.ip_address_changed(eee, old_ip, eee->device.ip_addr); + } + + sort_supernodes(eee, now); + + eee->resolution_request = resolve_check(eee->resolve_parameter, eee->resolution_request, now); + + if(eee->cb.main_loop_period) + eee->cb.main_loop_period(eee, now); + + } /* while */ + + send_unregister_super(eee); + +#ifdef WIN32 + WaitForSingleObject(tun_read_thread, INFINITE); +#endif + + supernode_disconnect(eee); + + return 0; +} + +/* ************************************** */ + +/** Deinitialise the edge and deallocate any owned memory. */ +void edge_term (n2n_edge_t * eee) { + + resolve_cancel_thread(eee->resolve_parameter); +#ifdef HAVE_PORT_FORWARDING + if(eee->conf.port_forwarding) + port_map_cancel_thread(eee->port_map_parameter); +#endif // HAVE_MINIUPNP || HAVE_NATPMP + if(eee->sock >= 0) + closesocket(eee->sock); + + if(eee->udp_mgmt_sock >= 0) + closesocket(eee->udp_mgmt_sock); + +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + if(eee->udp_multicast_sock >= 0) + closesocket(eee->udp_multicast_sock); +#endif + + clear_peer_list(&eee->pending_peers); + clear_peer_list(&eee->known_peers); + + eee->transop.deinit(&eee->transop); + eee->transop_lzo.deinit(&eee->transop_lzo); +#ifdef HAVE_ZSTD + eee->transop_zstd.deinit(&eee->transop_zstd); +#endif + + edge_cleanup_routes(eee); + + destroy_network_traffic_filter(eee->network_traffic_filter); + + closeTraceFile(); + + free(eee); +} + +/* ************************************** */ + + +static int edge_init_sockets (n2n_edge_t *eee) { + + if(eee->udp_mgmt_sock >= 0) + closesocket(eee->udp_mgmt_sock); + +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + if(eee->udp_multicast_sock >= 0) + closesocket(eee->udp_multicast_sock); +#endif + + eee->udp_mgmt_sock = open_socket(eee->conf.mgmt_port, INADDR_LOOPBACK, 0 /* UDP */); + if(eee->udp_mgmt_sock < 0) { + traceEvent(TRACE_ERROR, "failed to bind management UDP port %u", eee->conf.mgmt_port); + return(-2); + } + +#ifndef SKIP_MULTICAST_PEERS_DISCOVERY + /* Populate the multicast group for local edge */ + eee->multicast_peer.family = AF_INET; + eee->multicast_peer.port = N2N_MULTICAST_PORT; + eee->multicast_peer.addr.v4[0] = 224; /* N2N_MULTICAST_GROUP */ + eee->multicast_peer.addr.v4[1] = 0; + eee->multicast_peer.addr.v4[2] = 0; + eee->multicast_peer.addr.v4[3] = 68; + + eee->udp_multicast_sock = open_socket(N2N_MULTICAST_PORT, INADDR_ANY, 0 /* UDP */); + if(eee->udp_multicast_sock < 0) + return(-3); + else { + u_int enable_reuse = 1; + + /* allow multiple sockets to use the same PORT number */ + setsockopt(eee->udp_multicast_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&enable_reuse, sizeof(enable_reuse)); +#ifdef SO_REUSEPORT /* no SO_REUSEPORT in Windows / old linux versions */ + setsockopt(eee->udp_multicast_sock, SOL_SOCKET, SO_REUSEPORT, &enable_reuse, sizeof(enable_reuse)); +#endif + } +#endif + + return(0); +} + +/* ************************************** */ + +#ifdef __linux__ + +static uint32_t get_gateway_ip () { + + FILE *fd; + char *token = NULL; + char *gateway_ip_str = NULL; + char buf[256]; + uint32_t gateway = 0; + + if(!(fd = fopen("/proc/net/route", "r"))) + return(0); + + while(fgets(buf, sizeof(buf), fd)) { + if(strtok(buf, "\t") && (token = strtok(NULL, "\t")) && (!strcmp(token, "00000000"))) { + token = strtok(NULL, "\t"); + + if(token) { + struct in_addr addr; + + addr.s_addr = strtoul(token, NULL, 16); + gateway_ip_str = inet_ntoa(addr); + + if(gateway_ip_str) { + gateway = addr.s_addr; + break; + } + } + } + } + + fclose(fd); + + return(gateway); +} + +static char* route_cmd_to_str (int cmd, const n2n_route_t *route, char *buf, size_t bufsize) { + + const char *cmd_str; + struct in_addr addr; + char netbuf[64], gwbuf[64]; + + switch(cmd) { + case RTM_NEWROUTE: + cmd_str = "Add"; + break; + + case RTM_DELROUTE: + cmd_str = "Delete"; + break; + + default: + cmd_str = "?"; + } + + addr.s_addr = route->net_addr; + inet_ntop(AF_INET, &addr, netbuf, sizeof(netbuf)); + addr.s_addr = route->gateway; + inet_ntop(AF_INET, &addr, gwbuf, sizeof(gwbuf)); + + snprintf(buf, bufsize, "%s %s/%d via %s", cmd_str, netbuf, route->net_bitlen, gwbuf); + + return(buf); +} + +/* Adapted from https://olegkutkov.me/2019/08/29/modifying-linux-network-routes-using-netlink/ */ +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + +/* Add new data to rtattr */ +static int rtattr_add (struct nlmsghdr *n, int maxlen, int type, const void *data, int alen) { + + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + traceEvent(TRACE_ERROR, "rtattr_add error: message exceeded bound of %d\n", maxlen); + return -1; + } + + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + + if(alen) + memcpy(RTA_DATA(rta), data, alen); + + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + + return 0; +} + +static int routectl (int cmd, int flags, n2n_route_t *route, int if_idx) { + + int rv = -1; + int rv2; + char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */ + char route_buf[256]; + struct iovec iov; + struct msghdr msg; + struct sockaddr_nl sa; + uint8_t read_reply = 1; + int nl_sock; + + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[4096]; + } nl_request; + + if((nl_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { + traceEvent(TRACE_ERROR, "netlink socket creation failed [%d]: %s", errno, strerror(errno)); + return(-1); + } + + /* Subscribe to route change events */ + iov.iov_base = nl_buf; + iov.iov_len = sizeof(nl_buf); + + memset(&sa, 0, sizeof(sa)); + sa.nl_family = PF_NETLINK; + sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY; + sa.nl_pid = getpid(); + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &sa; + msg.msg_namelen = sizeof(sa); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + /* Subscribe to route events */ + if(bind(nl_sock, (struct sockaddr*)&sa, sizeof(sa)) == -1) { + traceEvent(TRACE_ERROR, "netlink socket bind failed [%d]: %s", errno, strerror(errno)); + goto out; + } + + /* Initialize request structure */ + memset(&nl_request, 0, sizeof(nl_request)); + nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags; + nl_request.n.nlmsg_type = cmd; + nl_request.r.rtm_family = AF_INET; + nl_request.r.rtm_table = RT_TABLE_MAIN; + nl_request.r.rtm_scope = RT_SCOPE_NOWHERE; + + /* Set additional flags if NOT deleting route */ + if(cmd != RTM_DELROUTE) { + nl_request.r.rtm_protocol = RTPROT_BOOT; + nl_request.r.rtm_type = RTN_UNICAST; + } + + nl_request.r.rtm_family = AF_INET; + nl_request.r.rtm_dst_len = route->net_bitlen; + + /* Select scope, for simplicity we supports here only IPv6 and IPv4 */ + if(nl_request.r.rtm_family == AF_INET6) + nl_request.r.rtm_scope = RT_SCOPE_UNIVERSE; + else + nl_request.r.rtm_scope = RT_SCOPE_LINK; + + /* Set gateway */ + if(route->net_bitlen) { + if(rtattr_add(&nl_request.n, sizeof(nl_request), RTA_GATEWAY, &route->gateway, 4) < 0) + goto out; + + nl_request.r.rtm_scope = 0; + nl_request.r.rtm_family = AF_INET; + } + + /* Don't set destination and interface in case of default gateways */ + if(route->net_bitlen) { + /* Set destination network */ + if(rtattr_add(&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &route->net_addr, 4) < 0) + goto out; + + /* Set interface */ + if(if_idx > 0) { + if(rtattr_add(&nl_request.n, sizeof(nl_request), RTA_OIF, &if_idx, sizeof(int)) < 0) + goto out; + } + } + + /* Send message to the netlink */ + if((rv2 = send(nl_sock, &nl_request, sizeof(nl_request), 0)) != sizeof(nl_request)) { + traceEvent(TRACE_ERROR, "netlink send failed [%d]: %s", errno, strerror(errno)); + goto out; + } + + /* Wait for the route notification. Assume that the first reply we get is the correct one. */ + traceEvent(TRACE_DEBUG, "waiting for netlink response..."); + + while(read_reply) { + ssize_t len = recvmsg(nl_sock, &msg, 0); + struct nlmsghdr *nh; + + for(nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { + /* Stop after the first reply */ + read_reply = 0; + + if(nh->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = NLMSG_DATA(nh); + int errcode = err->error; + + if(errcode < 0) + errcode = -errcode; + + /* Ignore EEXIST as existing rules are ok */ + if(errcode != EEXIST) { + traceEvent(TRACE_ERROR, "[err=%d] route: %s", errcode, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf))); + goto out; + } + } + + if(nh->nlmsg_type == NLMSG_DONE) + break; + + if(nh->nlmsg_type == cmd) { + traceEvent(TRACE_DEBUG, "Found netlink reply"); + break; + } + } + } + + traceEvent(TRACE_DEBUG, route_cmd_to_str(cmd, route, route_buf, sizeof(route_buf))); + rv = 0; + +out: + close(nl_sock); + + return(rv); +} +#endif + +/* ************************************** */ + +#ifdef __linux__ + +static int edge_init_routes_linux (n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) { + int i; + for(i = 0; inet_addr == 0) && (route->net_bitlen == 0)) { + /* This is a default gateway rule. We need to: + * + * 1. Add a route to the supernode via the host internet gateway + * 2. Add the new default gateway route + * + * Instead of modifying the system default gateway, we use the trick + * of adding a route to the networks 0.0.0.0/1 and 128.0.0.0/1, thus + * covering the whole IPv4 range. Such routes in linux take precedence + * over the default gateway (0.0.0.0/0) since are more specific. + * This leaves the default gateway unchanged so that after n2n is + * stopped the cleanup is easier. + * See https://github.com/zerotier/ZeroTierOne/issues/178#issuecomment-204599227 + */ + n2n_sock_t sn; + n2n_route_t custom_route; + uint32_t *a; + + if(eee->sn_route_to_clean) { + traceEvent(TRACE_ERROR, "only one default gateway route allowed"); + return(-1); + } + + if(eee->conf.sn_num != 1) { + traceEvent(TRACE_ERROR, "only one supernode supported with routes"); + return(-1); + } + + if(supernode2sock(&sn, eee->conf.supernodes->ip_addr) < 0) + return(-1); + + if(sn.family != AF_INET) { + traceEvent(TRACE_ERROR, "only IPv4 routes supported"); + return(-1); + } + + a = (u_int32_t*)sn.addr.v4; + custom_route.net_addr = *a; + custom_route.net_bitlen = 32; + custom_route.gateway = get_gateway_ip(); + + if(!custom_route.gateway) { + traceEvent(TRACE_ERROR, "could not determine the gateway IP address"); + return(-1); + } + + /* ip route add supernode via internet_gateway */ + if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, -1) < 0) + return(-1); + + /* Save the route to delete it when n2n is stopped */ + eee->sn_route_to_clean = calloc(1, sizeof(n2n_route_t)); + + /* Store a copy of the rules into the runtime to delete it during shutdown */ + if(eee->sn_route_to_clean) + *eee->sn_route_to_clean = custom_route; + + /* ip route add 0.0.0.0/1 via n2n_gateway */ + custom_route.net_addr = 0; + custom_route.net_bitlen = 1; + custom_route.gateway = route->gateway; + + if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) + return(-1); + + /* ip route add 128.0.0.0/1 via n2n_gateway */ + custom_route.net_addr = 128; + custom_route.net_bitlen = 1; + custom_route.gateway = route->gateway; + + if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) + return(-1); + } else { + /* ip route add net via n2n_gateway */ + if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, route, eee->device.if_idx) < 0) + return(-1); + } + } + + return(0); +} +#endif + +/* ************************************** */ + +#ifdef WIN32 +static int edge_init_routes_win (n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes, uint8_t verb /* 0 = add, 1 = delete */) { + int i; + struct in_addr net_addr, gateway; + char c_net_addr[32]; + char c_gateway[32]; + char c_interface[32]; + char c_verb[32]; + char cmd[256]; + + for(i = 0; i < num_routes; i++) { + n2n_route_t *route = &routes[i]; + if((route->net_addr == 0) && (route->net_bitlen == 0)) { + // REVISIT: there might be a chance to get it working on Windows following the hints at + // https://docs.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipinterface_row + // + // " The DisableDefaultRoutes member of the MIB_IPINTERFACE_ROW structure can be used to disable + // using the default route on an interface. This member can be used as a security measure by + // VPN clients to restrict split tunneling when split tunneling is not required by the VPN client. + // A VPN client can call the SetIpInterfaceEntry function to set the DisableDefaultRoutes member + // to TRUE when required. A VPN client can query the current state of the DisableDefaultRoutes + // member by calling the GetIpInterfaceEntry function. " + traceEvent(TRACE_WARNING, "the 0.0.0.0/0 route settings are not supported on Windows"); + return(-1); + } else { + /* ip route add net via n2n_gateway */ + memcpy(&net_addr, &(route->net_addr), sizeof(net_addr)); + memcpy(&gateway, &(route->gateway), sizeof(gateway)); + _snprintf(c_net_addr, sizeof(c_net_addr), inet_ntoa(net_addr)); + _snprintf(c_gateway, sizeof(c_gateway), inet_ntoa(gateway)); + _snprintf(c_interface, sizeof(c_interface), "if %u", eee->device.if_idx); + _snprintf(c_verb, sizeof(c_verb), verb ? "delete" : "add"); + _snprintf(cmd, sizeof(cmd), "route %s %s/%d %s %s > nul", c_verb, c_net_addr, route->net_bitlen, c_gateway, c_interface); + traceEvent(TRACE_NORMAL, "ROUTE CMD = '%s'\n", cmd); + system(cmd); + } + } + + return (0); +} +#endif // WIN32 + +/* ************************************** */ + +/* Add the user-provided routes to the linux routing table. Network routes + * are bound to the n2n TAP device, so they are automatically removed when + * the TAP device is destroyed. */ +int edge_init_routes (n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) { +#ifdef __linux__ + return edge_init_routes_linux(eee, routes, num_routes); +#endif + +#ifdef WIN32 + return edge_init_routes_win(eee, routes, num_routes, 0 /* add */); +#endif + return 0; +} + +/* ************************************** */ + +static void edge_cleanup_routes (n2n_edge_t *eee) { +#ifdef __linux__ + if(eee->sn_route_to_clean) { + /* ip route del supernode via internet_gateway */ + routectl(RTM_DELROUTE, 0, eee->sn_route_to_clean, -1); + free(eee->sn_route_to_clean); + } +#endif + +#ifdef WIN32 + edge_init_routes_win(eee, eee->conf.routes, eee->conf.num_routes, 1 /* del */); +#endif + +} + +/* ************************************** */ + +void edge_init_conf_defaults (n2n_edge_conf_t *conf) { + + char *tmp_string; + + memset(conf, 0, sizeof(*conf)); + + conf->bind_address = INADDR_ANY; /* any address */ + conf->local_port = 0 /* any port */; + conf->preferred_sock.family = AF_INVALID; + conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */ + conf->transop_id = N2N_TRANSFORM_ID_NULL; + conf->header_encryption = HEADER_ENCRYPTION_NONE; + conf->compression = N2N_COMPRESSION_ID_NONE; + conf->drop_multicast = 1; + conf->allow_p2p = 1; + conf->disable_pmtu_discovery = 1; + conf->register_interval = REGISTER_SUPER_INTERVAL_DFL; + conf->tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; + /* reserve possible last char as null terminator. */ + gethostname((char*)conf->dev_desc, N2N_DESC_SIZE-1); + + if(getenv("N2N_KEY")) { + conf->encrypt_key = strdup(getenv("N2N_KEY")); + conf->transop_id = N2N_TRANSFORM_ID_AES; + } + if(getenv("N2N_COMMUNITY")) { + strncpy((char*)conf->community_name, getenv("N2N_COMMUNITY"), N2N_COMMUNITY_SIZE); + conf->community_name[N2N_COMMUNITY_SIZE - 1] = '\0'; + } + if(getenv("N2N_PASSWORD")) { + conf->shared_secret = calloc(1, sizeof(n2n_private_public_key_t)); + if(conf->shared_secret) + generate_private_key(*(conf->shared_secret), getenv("N2N_PASSWORD")); + } + + tmp_string = calloc(1, strlen(N2N_MGMT_PASSWORD) + 1); + if(tmp_string) { + strncpy((char*)tmp_string, N2N_MGMT_PASSWORD, strlen(N2N_MGMT_PASSWORD) + 1); + conf->mgmt_password_hash = pearson_hash_64((uint8_t*)tmp_string, strlen(N2N_MGMT_PASSWORD)); + free(tmp_string); + } + +#if defined(HAVE_MINIUPNP) || defined(HAVE_NATPMP) + conf->port_forwarding = 1; +#endif // HAVE_MINIUPNP || HAVE_NATPMP + + conf->sn_selection_strategy = SN_SELECTION_STRATEGY_LOAD; + conf->metric = 0; +} + +/* ************************************** */ + +void edge_term_conf (n2n_edge_conf_t *conf) { + + if(conf->routes) free(conf->routes); + if(conf->encrypt_key) free(conf->encrypt_key); + + if(conf->network_traffic_filter_rules) { + filter_rule_t *el = 0, *tmp = 0; + HASH_ITER(hh, conf->network_traffic_filter_rules, el, tmp) { + HASH_DEL(conf->network_traffic_filter_rules, el); + free(el); + } + } +} + +/* ************************************** */ + +const n2n_edge_conf_t* edge_get_conf (const n2n_edge_t *eee) { + + return(&eee->conf); +} + +/* ************************************** */ + +int edge_conf_add_supernode (n2n_edge_conf_t *conf, const char *ip_and_port) { + + struct peer_info *sn; + n2n_sock_t *sock; + int skip_add; + int rv = -1; + + sock = (n2n_sock_t*)calloc(1,sizeof(n2n_sock_t)); + rv = supernode2sock(sock, ip_and_port); + + if(rv < -2) { /* we accept resolver failure as it might resolve later */ + traceEvent(TRACE_WARNING, "invalid supernode parameter."); + free(sock); + return 1; + } + + skip_add = SN_ADD; + sn = add_sn_to_list_by_mac_or_sock(&(conf->supernodes), sock, null_mac, &skip_add); + + if(sn != NULL) { + sn->ip_addr = calloc(1, N2N_EDGE_SN_HOST_SIZE); + + if(sn->ip_addr != NULL) { + strncpy(sn->ip_addr, ip_and_port, N2N_EDGE_SN_HOST_SIZE - 1); + memcpy(&(sn->sock), sock, sizeof(n2n_sock_t)); + memcpy(sn->mac_addr, null_mac, sizeof(n2n_mac_t)); + sn->purgeable = SN_UNPURGEABLE; + } + } + + free(sock); + + traceEvent(TRACE_NORMAL, "adding supernode = %s", sn->ip_addr); + conf->sn_num++; + + return 0; +} + +/* ************************************** */ + +int quick_edge_init (char *device_name, char *community_name, + char *encrypt_key, char *device_mac, + char *local_ip_address, + char *supernode_ip_address_port, + int *keep_on_running) { + + tuntap_dev tuntap; + n2n_edge_t *eee; + n2n_edge_conf_t conf; + int rv; + + /* Setup the configuration */ + edge_init_conf_defaults(&conf); + conf.encrypt_key = encrypt_key; + conf.transop_id = N2N_TRANSFORM_ID_AES; + conf.compression = N2N_COMPRESSION_ID_NONE; + snprintf((char*)conf.community_name, sizeof(conf.community_name), "%s", community_name); + edge_conf_add_supernode(&conf, supernode_ip_address_port); + + /* Validate configuration */ + if(edge_verify_conf(&conf) != 0) + return(-1); + + /* Open the tuntap device */ + if(tuntap_open(&tuntap, device_name, "static", + local_ip_address, "255.255.255.0", + device_mac, DEFAULT_MTU +#ifdef WIN32 + , 0 +#endif + ) < 0) + return(-2); + + /* Init edge */ + if((eee = edge_init(&conf, &rv)) == NULL) + goto quick_edge_init_end; + + eee->keep_running = keep_on_running; + rv = run_edge_loop(eee); + edge_term(eee); + edge_term_conf(&conf); + +quick_edge_init_end: + tuntap_close(&tuntap); + return(rv); +} + +/* ************************************** */ diff --git a/src/edge_utils_win32.c b/src/edge_utils_win32.c new file mode 100644 index 0000000..a32e06c --- /dev/null +++ b/src/edge_utils_win32.c @@ -0,0 +1,111 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#ifdef WIN32 + +#include "edge_utils_win32.h" + +/* ************************************** */ + +static DWORD* tunReadThread (LPVOID lpArg) { + + struct tunread_arg *arg = (struct tunread_arg*)lpArg; + + while(*arg->eee->keep_running) { + edge_read_from_tap(arg->eee); + } + + return((DWORD*)NULL); +} + +/* ************************************** */ + +/** Start a second thread in Windows because TUNTAP interfaces do not expose + * file descriptors. */ +HANDLE startTunReadThread (struct tunread_arg *arg) { + + DWORD dwThreadId; + + return(CreateThread(NULL, /* security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE)tunReadThread, /* thread function */ + (void*)arg, /* argument to thread function */ + 0, /* thread creation flags */ + &dwThreadId)); /* thread id out */ +} + + + +int get_best_interface_ip (n2n_edge_t * eee, dec_ip_str_t ip_addr){ + DWORD interface_index = -1; + DWORD dwRetVal = 0; + PIP_ADAPTER_INFO pAdapterInfo = NULL, pAdapter = NULL; + macstr_t mac_buf; + ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO); + + dwRetVal = GetBestInterface(*(IPAddr*)(&eee->curr_sn->sock.addr.v4), &interface_index); + if(dwRetVal != NO_ERROR) return -1; + + pAdapterInfo = (PIP_ADAPTER_INFO)malloc(ulOutBufLen); + if(pAdapterInfo == NULL) { + traceEvent(TRACE_INFO, "Error allocating memory needed to call GetAdaptersInfo\n"); + return -1; + } + + dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen); + if(dwRetVal == ERROR_BUFFER_OVERFLOW) { + pAdapterInfo = (PIP_ADAPTER_INFO)realloc(pAdapterInfo, ulOutBufLen); + if(pAdapterInfo == NULL) { + traceEvent(TRACE_INFO, "Error allocating memory needed to call GetAdaptersInfo\n"); + return -1; + } + } + + dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen); +// hexdump((uint8_t*)pAdapterInfo, ulOutBufLen); + if(dwRetVal == NO_ERROR) { + for(pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next) { + if(pAdapter->Index != interface_index) continue; + + traceEvent(TRACE_DEBUG, "Adapter Index: %ld\n", pAdapter->Index); + traceEvent(TRACE_DEBUG, "Combo Index: %ld\n", pAdapter->ComboIndex); + traceEvent(TRACE_DEBUG, "Adapter Name: %s\n", pAdapter->AdapterName); + traceEvent(TRACE_DEBUG, "Adapter Desc: %s\n", pAdapter->Description); + traceEvent(TRACE_DEBUG, "Adapter Type: %u\n", pAdapter->Type); + macaddr_str(mac_buf, pAdapter->Address); + traceEvent(TRACE_DEBUG, "Adapter Addr: %s\n", mac_buf); + traceEvent(TRACE_DEBUG, "DHCP Enabled: %u\n", pAdapter->DhcpEnabled); + traceEvent(TRACE_DEBUG, "DHCP Server: %s\n", pAdapter->DhcpServer.IpAddress.String); + traceEvent(TRACE_DEBUG, "IP Address: %s\n", pAdapter->IpAddressList.IpAddress.String); + traceEvent(TRACE_DEBUG, "IP Mask: %s\n", pAdapter->IpAddressList.IpMask.String); + traceEvent(TRACE_DEBUG, "Gateway: %s\n", pAdapter->GatewayList.IpAddress.String); + strncpy(ip_addr, pAdapter->IpAddressList.IpAddress.String, sizeof(dec_ip_str_t)-1); + } + } else { + traceEvent(TRACE_WARNING, "GetAdaptersInfo failed with error: %d\n", dwRetVal); + } + if(pAdapterInfo != NULL) { + free(pAdapterInfo); + pAdapterInfo = NULL; + } + return 0; +} + + +#endif + diff --git a/src/example_edge_embed.c b/src/example_edge_embed.c new file mode 100644 index 0000000..76388b7 --- /dev/null +++ b/src/example_edge_embed.c @@ -0,0 +1,78 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" + +static int keep_running; + +int main() { + + n2n_edge_conf_t conf; + tuntap_dev tuntap; + n2n_edge_t *eee; + int rc; + + edge_init_conf_defaults(&conf); + conf.allow_p2p = 1; // Whether to allow peer-to-peer communication + conf.allow_routing = 1; // Whether to allow the edge to route packets to other edges + snprintf((char *)conf.community_name, sizeof(conf.community_name), "%s", "mycommunity"); // Community to connect to + conf.disable_pmtu_discovery = 1; // Whether to disable the path MTU discovery + conf.drop_multicast = 0; // Whether to disable multicast + conf.tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; // How to set the IP address + conf.encrypt_key = "mysecret"; // Secret to decrypt & encrypt with + conf.local_port = 0; // What port to use (0 = any port) + conf.mgmt_port = N2N_EDGE_MGMT_PORT; // Edge management port (5644 by default) + conf.register_interval = 1; // Interval for both UDP NAT hole punching and supernode registration + conf.register_ttl = 1; // Interval for UDP NAT hole punching through supernode + edge_conf_add_supernode(&conf, "localhost:1234"); // Supernode to connect to + conf.tos = 16; // Type of service for sent packets + conf.transop_id = N2N_TRANSFORM_ID_TWOFISH; // Use the twofish encryption + + if(edge_verify_conf(&conf) != 0) { + return -1; + } + + if(tuntap_open(&tuntap, + "edge0", // Name of the device to create + "static", // IP mode; static|dhcp + "10.0.0.1", // Set ip address + "255.255.255.0", // Netmask to use + "DE:AD:BE:EF:01:10", // Set mac address + DEFAULT_MTU // MTU to use +#ifdef WIN32 + , 0 +#endif + ) < 0) + { + return -1; + } + + eee = edge_init(&conf, &rc); + if(eee == NULL) { + exit(1); + } + + keep_running = 1; + eee->keep_running = &keep_running; + rc = run_edge_loop(eee); + + edge_term(eee); + tuntap_close(&tuntap); + + return rc; +} diff --git a/src/example_edge_embed_quick_edge_init.c b/src/example_edge_embed_quick_edge_init.c new file mode 100644 index 0000000..e96a765 --- /dev/null +++ b/src/example_edge_embed_quick_edge_init.c @@ -0,0 +1,55 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" + +/* + This tool demonstrates how to easily embed + n2n on an existing application + */ + +int main (int argc, char* argv[]) { + + char *device_name = (char*)"n2n0"; + char *network_name = (char*)"mynetwork"; + char *secret_key = (char*)"mysecret"; + char *my_mac_address = (char*)"DE:AD:BE:EF:01:10"; + char *my_ipv4_addr = (char*)"1.2.3.4"; + char *supernode = (char*)"7.8.9.10:1234"; + int keep_on_running = 1; + + /* Increase tracelevel to see what's happening */ + setTraceLevel(10); + + /* Random seed */ + n2n_srand(n2n_seed()); + + /* + NOTE + + As the function below won't end, you should + call it inside a separate thread + */ + return(quick_edge_init(device_name, + network_name, + secret_key, + my_mac_address, + my_ipv4_addr, + supernode, + &keep_on_running)); +} diff --git a/src/example_sn_embed.c b/src/example_sn_embed.c new file mode 100644 index 0000000..dc1ed18 --- /dev/null +++ b/src/example_sn_embed.c @@ -0,0 +1,51 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" + +static int keep_running; + +int main () { + + n2n_sn_t sss_node; + int rc; + + sn_init_defaults(&sss_node); + sss_node.daemon = 0; // Whether to daemonize + sss_node.lport = 1234; // Main UDP listen port + + sss_node.sock = open_socket(sss_node.lport, INADDR_ANY, 0 /* UDP */); + if(-1 == sss_node.sock) { + exit(-2); + } + + sss_node.mgmt_sock = open_socket(5645, INADDR_LOOPBACK, 0 /* UDP */); // Main UDP management port + if(-1 == sss_node.mgmt_sock) { + exit(-2); + } + + sn_init(&sss_node); + + keep_running = 1; + sss_node.keep_running = &keep_running; + rc = run_sn_loop(&sss_node); + + sn_term(&sss_node); + + return rc; +} diff --git a/src/header_encryption.c b/src/header_encryption.c new file mode 100644 index 0000000..5511557 --- /dev/null +++ b/src/header_encryption.c @@ -0,0 +1,170 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out) + + +int packet_header_decrypt (uint8_t packet[], uint16_t packet_len, + char *community_name, + he_context_t *ctx, he_context_t *ctx_iv, + uint64_t *stamp) { + + // try community name as possible key and check for magic bytes "n2__" + uint32_t magic = 0x6E320000; + uint32_t test_magic; + uint32_t checksum_high = 0; + + // check for magic + // so, as a first step, decrypt last 4 bytes from where originally the community name would be + speck_ctr((uint8_t*)&test_magic, &packet[16], 4, packet, (speck_context_t*)ctx); + test_magic = be32toh(test_magic); + + //extract header length (lower 2 bytes) + uint32_t header_len = test_magic - magic; + + if(header_len <= packet_len) { + // decrypt the complete header + speck_ctr(&packet[16], &packet[16], header_len - 16, packet, (speck_context_t*)ctx); + + // extract time stamp and un-xor actual checksum (calculated here) from it + // if payload was altered (different checksum than original), time stamp verification will fail + // use speck block cipher step (1 block == 128 bit == 16 bytes) + speck_128_decrypt(packet, (speck_context_t*)ctx_iv); + + // extract the required data + *stamp = be64toh(*(uint64_t*)&packet[4]); + checksum_high = be32toh(*(uint32_t*)packet); + + // restore original packet order before calculating checksum + memcpy(&packet[0], &packet[20], 4); + memcpy(&packet[4], community_name, N2N_COMMUNITY_SIZE); + uint64_t checksum = pearson_hash_64(packet, packet_len); + + if((checksum >> 32) != checksum_high) { + traceEvent(TRACE_DEBUG, "packet_header_decrypt dropped a packet with invalid checksum."); + + // unsuccessful + return 0; + } + + *stamp = *stamp ^ (checksum << 32); + + // successful + return 1; + } else { + + // unsuccessful + return 0; + } +} + + +int packet_header_encrypt (uint8_t packet[], uint16_t header_len, uint16_t packet_len, + he_context_t *ctx, he_context_t *ctx_iv, + uint64_t stamp) { + + uint32_t *p32 = (uint32_t*)packet; + uint64_t *p64 = (uint64_t*)packet; + uint64_t checksum = 0; + uint32_t magic = 0x6E320000; /* == ASCII "n2__" */ + magic += header_len; + + if(packet_len < 24) { + traceEvent(TRACE_DEBUG, "packet_header_encrypt dropped a packet too short to be valid."); + return -1; + } + // we trust in the caller assuring header_len <= packet_len + + checksum = pearson_hash_64(packet, packet_len); + + // re-order packet + p32[5] = p32[0]; + + // add time stamp, checksum, and random to form the pre-IV + p64[0] = htobe64(checksum); + + p32[1] = p32[1] ^ htobe32((uint32_t)(stamp >> 32)); + p32[2] = htobe32((uint32_t)stamp); + + p32[3] = n2n_rand(); + + // encrypt this pre-IV to IV + speck_128_encrypt(packet, (speck_context_t*)ctx_iv); + + // place IV plus magic in packet + p32[4] = htobe32(magic); + + // encrypt, starting from magic + speck_ctr(&packet[16], &packet[16], header_len - 16, packet, (speck_context_t*)ctx); + + return 0; +} + + +void packet_header_setup_key (const char *community_name, + he_context_t **ctx_static, he_context_t **ctx_dynamic, + he_context_t **ctx_iv_static, he_context_t **ctx_iv_dynamic) { + + uint8_t key[16]; + + // for REGISTER_SUPER, REGISTER_SUPER_ACK, REGISTER_SUPER_NAK only; + // for all other packets, same as static by default (changed by user/pw auth scheme + // calling packet_header_change_dynamic_key later) + + pearson_hash_128(key, (uint8_t*)community_name, N2N_COMMUNITY_SIZE); + + if(!*ctx_static) + *ctx_static = (he_context_t*)calloc(1, sizeof(speck_context_t)); + speck_init((speck_context_t**)ctx_static, key, 128); + + if(!*ctx_dynamic) + *ctx_dynamic = (he_context_t*)calloc(1, sizeof(speck_context_t)); + speck_init((speck_context_t**)ctx_dynamic, key, 128); + + // hash again and use as key for IV encryption + pearson_hash_128(key, key, sizeof(key)); + + if(!*ctx_iv_static) + *ctx_iv_static = (he_context_t*)calloc(1, sizeof(speck_context_t)); + speck_init((speck_context_t**)ctx_iv_static, key, 128); + + if(!*ctx_iv_dynamic) + *ctx_iv_dynamic = (he_context_t*)calloc(1, sizeof(speck_context_t)); + speck_init((speck_context_t**)ctx_iv_dynamic, key, 128); +} + + +void packet_header_change_dynamic_key (uint8_t *key_dynamic, + he_context_t **ctx_dynamic, he_context_t **ctx_iv_dynamic) { + + uint8_t key[16]; + pearson_hash_128(key, key_dynamic, N2N_AUTH_CHALLENGE_SIZE); + + // for REGISTER_SUPER, REGISTER_SUPER_ACK, REGISTER_SUPER_NAK only + // for all other packets, same as static by default (changed by user/pw auth scheme) + speck_init((speck_context_t**)ctx_dynamic, key, 128); + + // hash again and use as key for IV encryption + // REMOVE as soon as checksum and replay protection get their own fields + pearson_hash_128(key, key, sizeof(key)); + speck_init((speck_context_t**)ctx_iv_dynamic, key, 128); +} diff --git a/src/hexdump.c b/src/hexdump.c new file mode 100644 index 0000000..a9cbd00 --- /dev/null +++ b/src/hexdump.c @@ -0,0 +1,62 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include + +#include "n2n.h" +#include "hexdump.h" + +void fhexdump(unsigned int display_addr, void *in, int size, FILE *stream) { + uint8_t *p = in; + + while(size>0) { + int i; + + fprintf(stream, "%03x: ", display_addr); + + for (i = 0; i < 16; i++) { + if (i < size) { + fprintf(stream, "%02x", p[i]); + } else { + fprintf(stream, " "); + } + if (i==7) { + fprintf(stream, " "); + } else { + fprintf(stream, " "); + } + } + fprintf(stream, " |"); + + for (i = 0; i < 16; i++) { + if (i < size) { + char ch = p[i]; + if (ch>=0x20 && ch<=0x7e) { + fprintf(stream, "%c", ch); + } else { + fprintf(stream, " "); + } + } + } + fprintf(stream, "|\n"); + + size -= 16; + display_addr += 16; + p += 16; + } +} diff --git a/src/minilzo.c b/src/minilzo.c new file mode 100644 index 0000000..f4db433 --- /dev/null +++ b/src/minilzo.c @@ -0,0 +1,6383 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +/* minilzo.c -- mini subset of the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library 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 2 of + the License, or (at your option) any later version. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + +/* + * NOTE: + * the full LZO package can be found at + * http://www.oberhumer.com/opensource/lzo/ + */ + +#define __LZO_IN_MINILZO 1 + +#if defined(LZO_CFG_FREESTANDING) +# undef MINILZO_HAVE_CONFIG_H +# define LZO_LIBC_FREESTANDING 1 +# define LZO_OS_FREESTANDING 1 +#endif + +#ifdef MINILZO_HAVE_CONFIG_H +# include +#endif +#include +#include +#if defined(MINILZO_CFG_USE_INTERNAL_LZODEFS) + +#ifndef __LZODEFS_H_INCLUDED +#define __LZODEFS_H_INCLUDED 1 + +#if defined(__CYGWIN32__) && !defined(__CYGWIN__) +# define __CYGWIN__ __CYGWIN32__ +#endif +#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) +# define _ALL_SOURCE 1 +#endif +#if defined(__mips__) && defined(__R5900__) +# if !defined(__LONG_MAX__) +# define __LONG_MAX__ 9223372036854775807L +# endif +#endif +#if 0 +#elif !defined(__LZO_LANG_OVERRIDE) +#if (defined(__clang__) || defined(__GNUC__)) && defined(__ASSEMBLER__) +# if (__ASSEMBLER__+0) <= 0 +# error "__ASSEMBLER__" +# else +# define LZO_LANG_ASSEMBLER 1 +# endif +#elif defined(__cplusplus) +# if (__cplusplus+0) <= 0 +# error "__cplusplus" +# elif (__cplusplus < 199711L) +# define LZO_LANG_CXX 1 +# elif defined(_MSC_VER) && defined(_MSVC_LANG) && (_MSVC_LANG+0 >= 201402L) && 1 +# define LZO_LANG_CXX _MSVC_LANG +# else +# define LZO_LANG_CXX __cplusplus +# endif +# define LZO_LANG_CPLUSPLUS LZO_LANG_CXX +#else +# if defined(__STDC_VERSION__) && (__STDC_VERSION__+0 >= 199409L) +# define LZO_LANG_C __STDC_VERSION__ +# else +# define LZO_LANG_C 1 +# endif +#endif +#endif +#if !defined(LZO_CFG_NO_DISABLE_WUNDEF) +#if defined(__ARMCC_VERSION) +# pragma diag_suppress 193 +#elif defined(__clang__) && defined(__clang_minor__) +# pragma clang diagnostic ignored "-Wundef" +#elif defined(__INTEL_COMPILER) +# pragma warning(disable: 193) +#elif defined(__KEIL__) && defined(__C166__) +# pragma warning disable = 322 +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__PATHSCALE__) +# if ((__GNUC__-0) >= 5 || ((__GNUC__-0) == 4 && (__GNUC_MINOR__-0) >= 2)) +# pragma GCC diagnostic ignored "-Wundef" +# endif +#elif defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) +# if ((_MSC_VER-0) >= 1300) +# pragma warning(disable: 4668) +# endif +#endif +#endif +#if 0 && defined(__POCC__) && defined(_WIN32) +# if (__POCC__ >= 400) +# pragma warn(disable: 2216) +# endif +#endif +#if 0 && defined(__WATCOMC__) +# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) +# pragma warning 203 9 +# endif +#endif +#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) +# pragma option -h +#endif +#if !(LZO_CFG_NO_DISABLE_WCRTNONSTDC) +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#endif +#ifndef _CRT_NONSTDC_NO_WARNINGS +#define _CRT_NONSTDC_NO_WARNINGS 1 +#endif +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS 1 +#endif +#endif +#if 0 +#define LZO_0xffffUL 0xfffful +#define LZO_0xffffffffUL 0xfffffffful +#else +#define LZO_0xffffUL 65535ul +#define LZO_0xffffffffUL 4294967295ul +#endif +#define LZO_0xffffL LZO_0xffffUL +#define LZO_0xffffffffL LZO_0xffffffffUL +#if (LZO_0xffffL == LZO_0xffffffffL) +# error "your preprocessor is broken 1" +#endif +#if (16ul * 16384ul != 262144ul) +# error "your preprocessor is broken 2" +#endif +#if 0 +#if (32767 >= 4294967295ul) +# error "your preprocessor is broken 3" +#endif +#if (65535u >= 4294967295ul) +# error "your preprocessor is broken 4" +#endif +#endif +#if defined(__COUNTER__) +# ifndef LZO_CFG_USE_COUNTER +# define LZO_CFG_USE_COUNTER 1 +# endif +#else +# undef LZO_CFG_USE_COUNTER +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) +# if !defined(MSDOS) +# define MSDOS 1 +# endif +# if !defined(_MSDOS) +# define _MSDOS 1 +# endif +#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) +# if (__VERSION == 520) && (MB_LEN_MAX == 1) +# if !defined(__AZTEC_C__) +# define __AZTEC_C__ __VERSION +# endif +# if !defined(__DOS__) +# define __DOS__ 1 +# endif +# endif +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(_MSC_VER) && defined(M_I86HM) +# define ptrdiff_t long +# define _PTRDIFF_T_DEFINED 1 +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +# if defined(__AZTEC_C__) && defined(__DOS__) +# define __LZO_RENAME_A 1 +# elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define __LZO_RENAME_A 1 +# elif (_MSC_VER < 700) +# define __LZO_RENAME_B 1 +# endif +# elif defined(__TSC__) && defined(__OS2__) +# define __LZO_RENAME_A 1 +# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) +# define __LZO_RENAME_A 1 +# elif defined(__PACIFIC__) && defined(DOS) +# if !defined(__far) +# define __far far +# endif +# if !defined(__near) +# define __near near +# endif +# endif +# if defined(__LZO_RENAME_A) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__far) +# define __far far +# endif +# if !defined(__huge) +# define __huge huge +# endif +# if !defined(__near) +# define __near near +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# if !defined(__huge) +# define __huge huge +# endif +# elif defined(__LZO_RENAME_B) +# if !defined(__cdecl) +# define __cdecl _cdecl +# endif +# if !defined(__far) +# define __far _far +# endif +# if !defined(__huge) +# define __huge _huge +# endif +# if !defined(__near) +# define __near _near +# endif +# if !defined(__pascal) +# define __pascal _pascal +# endif +# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# endif +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__AZTEC_C__) && defined(__DOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +#elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# endif +# if (_MSC_VER < 700) +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# define LZO_BROKEN_SIZEOF 1 +# endif +#elif defined(__PACIFIC__) && defined(DOS) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#elif defined(__TURBOC__) && defined(__MSDOS__) +# if (__TURBOC__ < 0x0150) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# endif +# if (__TURBOC__ < 0x0200) +# define LZO_BROKEN_SIZEOF 1 +# endif +# if (__TURBOC__ < 0x0400) && defined(__cplusplus) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# endif +#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_SIZEOF 1 +#endif +#endif +#if defined(__WATCOMC__) && (__WATCOMC__ < 900) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#endif +#if defined(_CRAY) && defined(_CRAY1) +# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 +#endif +#define LZO_PP_STRINGIZE(x) #x +#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) +#define LZO_PP_CONCAT0() /*empty*/ +#define LZO_PP_CONCAT1(a) a +#define LZO_PP_CONCAT2(a,b) a ## b +#define LZO_PP_CONCAT3(a,b,c) a ## b ## c +#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_PP_CONCAT6(a,b,c,d,e,f) a ## b ## c ## d ## e ## f +#define LZO_PP_CONCAT7(a,b,c,d,e,f,g) a ## b ## c ## d ## e ## f ## g +#define LZO_PP_ECONCAT0() LZO_PP_CONCAT0() +#define LZO_PP_ECONCAT1(a) LZO_PP_CONCAT1(a) +#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) +#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) +#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) +#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) +#define LZO_PP_ECONCAT6(a,b,c,d,e,f) LZO_PP_CONCAT6(a,b,c,d,e,f) +#define LZO_PP_ECONCAT7(a,b,c,d,e,f,g) LZO_PP_CONCAT7(a,b,c,d,e,f,g) +#define LZO_PP_EMPTY /*empty*/ +#define LZO_PP_EMPTY0() /*empty*/ +#define LZO_PP_EMPTY1(a) /*empty*/ +#define LZO_PP_EMPTY2(a,b) /*empty*/ +#define LZO_PP_EMPTY3(a,b,c) /*empty*/ +#define LZO_PP_EMPTY4(a,b,c,d) /*empty*/ +#define LZO_PP_EMPTY5(a,b,c,d,e) /*empty*/ +#define LZO_PP_EMPTY6(a,b,c,d,e,f) /*empty*/ +#define LZO_PP_EMPTY7(a,b,c,d,e,f,g) /*empty*/ +#if 1 +#define LZO_CPP_STRINGIZE(x) #x +#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) +#define LZO_CPP_CONCAT2(a,b) a ## b +#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c +#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_CPP_CONCAT6(a,b,c,d,e,f) a ## b ## c ## d ## e ## f +#define LZO_CPP_CONCAT7(a,b,c,d,e,f,g) a ## b ## c ## d ## e ## f ## g +#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) +#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) +#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) +#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) +#define LZO_CPP_ECONCAT6(a,b,c,d,e,f) LZO_CPP_CONCAT6(a,b,c,d,e,f) +#define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g) +#endif +#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-((b)!=0))) - (o)) << 1) + (o)*((b)!=0)) +#if 1 && defined(__cplusplus) +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS 1 +# endif +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS 1 +# endif +#endif +#if defined(__cplusplus) +# define LZO_EXTERN_C extern "C" +# define LZO_EXTERN_C_BEGIN extern "C" { +# define LZO_EXTERN_C_END } +#else +# define LZO_EXTERN_C extern +# define LZO_EXTERN_C_BEGIN /*empty*/ +# define LZO_EXTERN_C_END /*empty*/ +#endif +#if !defined(__LZO_OS_OVERRIDE) +#if (LZO_OS_FREESTANDING) +# define LZO_INFO_OS "freestanding" +#elif (LZO_OS_EMBEDDED) +# define LZO_INFO_OS "embedded" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_OS_EMBEDDED 1 +# define LZO_INFO_OS "embedded" +#elif defined(__CYGWIN__) && defined(__GNUC__) +# define LZO_OS_CYGWIN 1 +# define LZO_INFO_OS "cygwin" +#elif defined(__EMX__) && defined(__GNUC__) +# define LZO_OS_EMX 1 +# define LZO_INFO_OS "emx" +#elif defined(__BEOS__) +# define LZO_OS_BEOS 1 +# define LZO_INFO_OS "beos" +#elif defined(__Lynx__) +# define LZO_OS_LYNXOS 1 +# define LZO_INFO_OS "lynxos" +#elif defined(__OS400__) +# define LZO_OS_OS400 1 +# define LZO_INFO_OS "os400" +#elif defined(__QNX__) +# define LZO_OS_QNX 1 +# define LZO_INFO_OS "qnx" +#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__BORLANDC__) && defined(__DPMI16__) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +#elif defined(__ZTC__) && defined(DOS386) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__OS2__) || defined(__OS2V2__) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_OS216 1 +# define LZO_INFO_OS "os216" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_OS2 1 +# define LZO_INFO_OS "os2" +# else +# error "check your limits.h header" +# endif +#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) +# define LZO_OS_WIN64 1 +# define LZO_INFO_OS "win64" +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__MWERKS__) && defined(__INTEL__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_WIN16 1 +# define LZO_INFO_OS "win16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# else +# error "check your limits.h header" +# endif +#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +# else +# error "check your limits.h header" +# endif +#elif defined(__WATCOMC__) +# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif defined(__NT__) && (__WATCOMC__ < 1100) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# elif defined(__linux__) || defined(__LINUX__) +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +# else +# error "please specify a target using the -bt compiler option" +# endif +#elif defined(__palmos__) +# define LZO_OS_PALMOS 1 +# define LZO_INFO_OS "palmos" +#elif defined(__TOS__) || defined(__atarist__) +# define LZO_OS_TOS 1 +# define LZO_INFO_OS "tos" +#elif defined(macintosh) && !defined(__arm__) && !defined(__i386__) && !defined(__ppc__) && !defined(__x64_64__) +# define LZO_OS_MACCLASSIC 1 +# define LZO_INFO_OS "macclassic" +#elif defined(__VMS) +# define LZO_OS_VMS 1 +# define LZO_INFO_OS "vms" +#elif (defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PS2 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "ps2" +#elif defined(__mips__) && defined(__psp__) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PSP 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "psp" +#else +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +#endif +#if (LZO_OS_POSIX) +# if defined(_AIX) || defined(__AIX__) || defined(__aix__) +# define LZO_OS_POSIX_AIX 1 +# define LZO_INFO_OS_POSIX "aix" +# elif defined(__FreeBSD__) +# define LZO_OS_POSIX_FREEBSD 1 +# define LZO_INFO_OS_POSIX "freebsd" +# elif defined(__hpux__) || defined(__hpux) +# define LZO_OS_POSIX_HPUX 1 +# define LZO_INFO_OS_POSIX "hpux" +# elif defined(__INTERIX) +# define LZO_OS_POSIX_INTERIX 1 +# define LZO_INFO_OS_POSIX "interix" +# elif defined(__IRIX__) || defined(__irix__) +# define LZO_OS_POSIX_IRIX 1 +# define LZO_INFO_OS_POSIX "irix" +# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) +# define LZO_OS_POSIX_LINUX 1 +# define LZO_INFO_OS_POSIX "linux" +# elif defined(__APPLE__) && defined(__MACH__) +# if ((__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__-0) >= 20000) +# define LZO_OS_POSIX_DARWIN 1040 +# define LZO_INFO_OS_POSIX "darwin_iphone" +# elif ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) >= 1040) +# define LZO_OS_POSIX_DARWIN __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ +# define LZO_INFO_OS_POSIX "darwin" +# else +# define LZO_OS_POSIX_DARWIN 1 +# define LZO_INFO_OS_POSIX "darwin" +# endif +# define LZO_OS_POSIX_MACOSX LZO_OS_POSIX_DARWIN +# elif defined(__minix__) || defined(__minix) +# define LZO_OS_POSIX_MINIX 1 +# define LZO_INFO_OS_POSIX "minix" +# elif defined(__NetBSD__) +# define LZO_OS_POSIX_NETBSD 1 +# define LZO_INFO_OS_POSIX "netbsd" +# elif defined(__OpenBSD__) +# define LZO_OS_POSIX_OPENBSD 1 +# define LZO_INFO_OS_POSIX "openbsd" +# elif defined(__osf__) +# define LZO_OS_POSIX_OSF 1 +# define LZO_INFO_OS_POSIX "osf" +# elif defined(__solaris__) || defined(__sun) +# if defined(__SVR4) || defined(__svr4__) +# define LZO_OS_POSIX_SOLARIS 1 +# define LZO_INFO_OS_POSIX "solaris" +# else +# define LZO_OS_POSIX_SUNOS 1 +# define LZO_INFO_OS_POSIX "sunos" +# endif +# elif defined(__ultrix__) || defined(__ultrix) +# define LZO_OS_POSIX_ULTRIX 1 +# define LZO_INFO_OS_POSIX "ultrix" +# elif defined(_UNICOS) +# define LZO_OS_POSIX_UNICOS 1 +# define LZO_INFO_OS_POSIX "unicos" +# else +# define LZO_OS_POSIX_UNKNOWN 1 +# define LZO_INFO_OS_POSIX "unknown" +# endif +#endif +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# if (UINT_MAX != LZO_0xffffL) +# error "unexpected configuration - check your compiler defines" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (UINT_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) +# define LZO_CC_CILLY 1 +# define LZO_INFO_CC "Cilly" +# if defined(__CILLY__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) +# define LZO_CC_SDCC 1 +# define LZO_INFO_CC "sdcc" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) +#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) +# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + (__PATHCC_MINOR__-0) * 0x100 + (__PATHCC_PATCHLEVEL__-0)) +# define LZO_INFO_CC "Pathscale C" +# define LZO_INFO_CCVER __PATHSCALE__ +# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# define LZO_CC_PATHSCALE_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# endif +#elif defined(__INTEL_COMPILER) && ((__INTEL_COMPILER-0) > 0) +# define LZO_CC_INTELC __INTEL_COMPILER +# define LZO_INFO_CC "Intel C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) +# if defined(_MSC_VER) && ((_MSC_VER-0) > 0) +# define LZO_CC_INTELC_MSC _MSC_VER +# elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# define LZO_CC_INTELC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# endif +#elif defined(__POCC__) && defined(_WIN32) +# define LZO_CC_PELLESC 1 +# define LZO_INFO_CC "Pelles C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) +#elif defined(__ARMCC_VERSION) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_ARMCC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# else +# define LZO_CC_ARMCC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100) +# endif +# define LZO_CC_ARMCC __ARMCC_VERSION +# define LZO_INFO_CC "ARM C Compiler" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__clang__) && defined(__c2__) && defined(__c2_version__) && defined(_MSC_VER) +# define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0)) +# define LZO_CC_CLANG_C2 _MSC_VER +# define LZO_CC_CLANG_VENDOR_MICROSOFT 1 +# define LZO_INFO_CC "clang/c2" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__c2_version__) +#elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__) +# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +# define LZO_CC_CLANG (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0)) +# else +# define LZO_CC_CLANG 0x010000L +# endif +# if defined(_MSC_VER) && ((_MSC_VER-0) > 0) +# define LZO_CC_CLANG_MSC _MSC_VER +# elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# endif +# if defined(__APPLE_CC__) +# define LZO_CC_CLANG_VENDOR_APPLE 1 +# define LZO_INFO_CC "clang/apple" +# else +# define LZO_CC_CLANG_VENDOR_LLVM 1 +# define LZO_INFO_CC "clang" +# endif +# if defined(__clang_version__) +# define LZO_INFO_CCVER __clang_version__ +# else +# define LZO_INFO_CCVER __VERSION__ +# endif +#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# else +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100) +# endif +# define LZO_CC_LLVM LZO_CC_LLVM_GNUC +# define LZO_INFO_CC "llvm-gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__ACK__) && defined(_ACK) +# define LZO_CC_ACK 1 +# define LZO_INFO_CC "Amsterdam Compiler Kit C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__ARMCC_VERSION) && !defined(__GNUC__) +# define LZO_CC_ARMCC __ARMCC_VERSION +# define LZO_CC_ARMCC_ARMCC __ARMCC_VERSION +# define LZO_INFO_CC "ARM C Compiler" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ARMCC_VERSION) +#elif defined(__AZTEC_C__) +# define LZO_CC_AZTECC 1 +# define LZO_INFO_CC "Aztec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__CODEGEARC__) +# define LZO_CC_CODEGEARC 1 +# define LZO_INFO_CC "CodeGear C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) +#elif defined(__BORLANDC__) +# define LZO_CC_BORLANDC 1 +# define LZO_INFO_CC "Borland C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) +#elif defined(_CRAYC) && defined(_RELEASE) +# define LZO_CC_CRAYC 1 +# define LZO_INFO_CC "Cray C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) +#elif defined(__DMC__) && defined(__SC__) +# define LZO_CC_DMC 1 +# define LZO_INFO_CC "Digital Mars C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) +#elif defined(__DECC) +# define LZO_CC_DECC 1 +# define LZO_INFO_CC "DEC C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) +#elif (defined(__ghs) || defined(__ghs__)) && defined(__GHS_VERSION_NUMBER) && ((__GHS_VERSION_NUMBER-0) > 0) +# define LZO_CC_GHS 1 +# define LZO_INFO_CC "Green Hills C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__GHS_VERSION_NUMBER) +# if defined(_MSC_VER) && ((_MSC_VER-0) > 0) +# define LZO_CC_GHS_MSC _MSC_VER +# elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# define LZO_CC_GHS_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# endif +#elif defined(__HIGHC__) +# define LZO_CC_HIGHC 1 +# define LZO_INFO_CC "MetaWare High C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__HP_aCC) && ((__HP_aCC-0) > 0) +# define LZO_CC_HPACC __HP_aCC +# define LZO_INFO_CC "HP aCC" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__HP_aCC) +#elif defined(__IAR_SYSTEMS_ICC__) +# define LZO_CC_IARC 1 +# define LZO_INFO_CC "IAR C" +# if defined(__VER__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__IBMC__) && ((__IBMC__-0) > 0) +# define LZO_CC_IBMC __IBMC__ +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) +#elif defined(__IBMCPP__) && ((__IBMCPP__-0) > 0) +# define LZO_CC_IBMC __IBMCPP__ +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMCPP__) +#elif defined(__KEIL__) && defined(__C166__) +# define LZO_CC_KEILC 1 +# define LZO_INFO_CC "Keil C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) +#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) +# define LZO_CC_LCCWIN32 1 +# define LZO_INFO_CC "lcc-win32" +# define LZO_INFO_CCVER "unknown" +#elif defined(__LCC__) +# define LZO_CC_LCC 1 +# define LZO_INFO_CC "lcc" +# if defined(__LCC_VERSION__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__MWERKS__) && ((__MWERKS__-0) > 0) +# define LZO_CC_MWERKS __MWERKS__ +# define LZO_INFO_CC "Metrowerks C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) +#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) +# define LZO_CC_NDPC 1 +# define LZO_INFO_CC "Microway NDP C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PACIFIC__) +# define LZO_CC_PACIFICC 1 +# define LZO_INFO_CC "Pacific C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) +#elif defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define LZO_CC_PGI (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100 + (__PGIC_PATCHLEVEL__-0)) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PGIC__) "." LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) "." LZO_PP_MACRO_EXPAND(__PGIC_PATCHLEVEL__) +# else +# define LZO_CC_PGI (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PGIC__) "." LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) ".0" +# endif +# define LZO_INFO_CC "Portland Group PGI C" +#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) +# define LZO_CC_PGI 1 +# define LZO_INFO_CC "Portland Group PGI C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PUREC__) && defined(__TOS__) +# define LZO_CC_PUREC 1 +# define LZO_INFO_CC "Pure C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) +#elif defined(__SC__) && defined(__ZTC__) +# define LZO_CC_SYMANTECC 1 +# define LZO_INFO_CC "Symantec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) +#elif defined(__SUNPRO_C) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_C-0) > 0) +# define LZO_CC_SUNPROC __SUNPRO_C +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__SUNPRO_CC) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_CC-0) > 0) +# define LZO_CC_SUNPROC __SUNPRO_CC +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__TINYC__) +# define LZO_CC_TINYC 1 +# define LZO_INFO_CC "Tiny C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) +#elif defined(__TSC__) +# define LZO_CC_TOPSPEEDC 1 +# define LZO_INFO_CC "TopSpeed C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) +#elif defined(__WATCOMC__) +# define LZO_CC_WATCOMC 1 +# define LZO_INFO_CC "Watcom C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) +#elif defined(__TURBOC__) +# define LZO_CC_TURBOC 1 +# define LZO_INFO_CC "Turbo C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) +#elif defined(__ZTC__) +# define LZO_CC_ZORTECHC 1 +# define LZO_INFO_CC "Zortech C" +# if ((__ZTC__-0) == 0x310) +# define LZO_INFO_CCVER "0x310" +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) +# endif +#elif defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0)) +# elif defined(__GNUC_MINOR__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100) +# else +# define LZO_CC_GNUC (__GNUC__ * 0x10000L) +# endif +# define LZO_INFO_CC "gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(_MSC_VER) && ((_MSC_VER-0) > 0) +# define LZO_CC_MSC _MSC_VER +# define LZO_INFO_CC "Microsoft C" +# if defined(_MSC_FULL_VER) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) +# endif +#else +# define LZO_CC_UNKNOWN 1 +# define LZO_INFO_CC "unknown" +# define LZO_INFO_CCVER "unknown" +#endif +#if (LZO_CC_GNUC) && defined(__OPEN64__) +# if defined(__OPENCC__) && defined(__OPENCC_MINOR__) && defined(__OPENCC_PATCHLEVEL__) +# define LZO_CC_OPEN64 (__OPENCC__ * 0x10000L + (__OPENCC_MINOR__-0) * 0x100 + (__OPENCC_PATCHLEVEL__-0)) +# define LZO_CC_OPEN64_GNUC LZO_CC_GNUC +# endif +#endif +#if (LZO_CC_GNUC) && defined(__PCC__) +# if defined(__PCC__) && defined(__PCC_MINOR__) && defined(__PCC_MINORMINOR__) +# define LZO_CC_PCC (__PCC__ * 0x10000L + (__PCC_MINOR__-0) * 0x100 + (__PCC_MINORMINOR__-0)) +# define LZO_CC_PCC_GNUC LZO_CC_GNUC +# endif +#endif +#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) +# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" +#endif +#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) +# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) +# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) +# define LZO_ARCH_CRAY_MPP 1 +# elif defined(_CRAY1) +# define LZO_ARCH_CRAY_PVP 1 +# endif +# endif +#endif +#if !defined(__LZO_ARCH_OVERRIDE) +#if (LZO_ARCH_GENERIC) +# define LZO_INFO_ARCH "generic" +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086 1 +# define LZO_INFO_ARCH "i086" +#elif defined(__aarch64__) || defined(_M_ARM64) +# define LZO_ARCH_ARM64 1 +# define LZO_INFO_ARCH "arm64" +#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) +# define LZO_ARCH_AMD64 1 +# define LZO_INFO_ARCH "amd64" +#elif defined(__arm__) || defined(_M_ARM) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) +# define LZO_ARCH_AVR 1 +# define LZO_INFO_ARCH "avr" +#elif defined(__avr32__) || defined(__AVR32__) +# define LZO_ARCH_AVR32 1 +# define LZO_INFO_ARCH "avr32" +#elif defined(__bfin__) +# define LZO_ARCH_BLACKFIN 1 +# define LZO_INFO_ARCH "blackfin" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) +# define LZO_ARCH_C166 1 +# define LZO_INFO_ARCH "c166" +#elif defined(__cris__) +# define LZO_ARCH_CRIS 1 +# define LZO_INFO_ARCH "cris" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) +# define LZO_ARCH_EZ80 1 +# define LZO_INFO_ARCH "ez80" +#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_ARCH_H8300 1 +# define LZO_INFO_ARCH "h8300" +#elif defined(__hppa__) || defined(__hppa) +# define LZO_ARCH_HPPA 1 +# define LZO_INFO_ARCH "hppa" +#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_CC_ZORTECHC && defined(__I86__)) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) +# define LZO_ARCH_IA64 1 +# define LZO_INFO_ARCH "ia64" +#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__m32r__) +# define LZO_ARCH_M32R 1 +# define LZO_INFO_ARCH "m32r" +#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) +# define LZO_ARCH_M68K 1 +# define LZO_INFO_ARCH "m68k" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) +# define LZO_ARCH_MCS251 1 +# define LZO_INFO_ARCH "mcs251" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) +# define LZO_ARCH_MIPS 1 +# define LZO_INFO_ARCH "mips" +#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__powerpc64__) || defined(__powerpc64) || defined(__ppc64__) || defined(__PPC64__) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__powerpc64le__) || defined(__powerpc64le) || defined(__ppc64le__) || defined(__PPC64LE__) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__riscv) +# define LZO_ARCH_RISCV 1 +# define LZO_INFO_ARCH "riscv" +#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) +# define LZO_ARCH_S390 1 +# define LZO_INFO_ARCH "s390" +#elif defined(__sh__) || defined(_M_SH) +# define LZO_ARCH_SH 1 +# define LZO_INFO_ARCH "sh" +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) +# define LZO_ARCH_SPARC 1 +# define LZO_INFO_ARCH "sparc" +#elif defined(__SPU__) +# define LZO_ARCH_SPU 1 +# define LZO_INFO_ARCH "spu" +#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) +# define LZO_ARCH_Z80 1 +# define LZO_INFO_ARCH "z80" +#elif (LZO_ARCH_CRAY_PVP) +# if defined(_CRAYSV1) +# define LZO_ARCH_CRAY_SV1 1 +# define LZO_INFO_ARCH "cray_sv1" +# elif (_ADDR64) +# define LZO_ARCH_CRAY_T90 1 +# define LZO_INFO_ARCH "cray_t90" +# elif (_ADDR32) +# define LZO_ARCH_CRAY_YMP 1 +# define LZO_INFO_ARCH "cray_ymp" +# else +# define LZO_ARCH_CRAY_XMP 1 +# define LZO_INFO_ARCH "cray_xmp" +# endif +#else +# define LZO_ARCH_UNKNOWN 1 +# define LZO_INFO_ARCH "unknown" +#endif +#endif +#if !defined(LZO_ARCH_ARM_THUMB2) +#if (LZO_ARCH_ARM) +# if defined(__thumb__) || defined(__thumb) || defined(_M_THUMB) +# if defined(__thumb2__) +# define LZO_ARCH_ARM_THUMB2 1 +# elif 1 && defined(__TARGET_ARCH_THUMB) && ((__TARGET_ARCH_THUMB)+0 >= 4) +# define LZO_ARCH_ARM_THUMB2 1 +# elif 1 && defined(_MSC_VER) && defined(_M_THUMB) && ((_M_THUMB)+0 >= 7) +# define LZO_ARCH_ARM_THUMB2 1 +# endif +# endif +#endif +#endif +#if (LZO_ARCH_ARM_THUMB2) +# undef LZO_INFO_ARCH +# define LZO_INFO_ARCH "arm_thumb2" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) +# error "FIXME - missing define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) +# error "FIXME - missing LZO_OS_WIN32 define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) +# error "FIXME - missing LZO_OS_WIN64 define for CPU architecture" +#endif +#if (LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) +# define LZO_ARCH_I086PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) +# define LZO_ARCH_I086PM 1 +#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) +# define LZO_ARCH_I086PM 1 +#endif +#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64) +# define LZO_ARCH_X64 1 +#elif (!LZO_ARCH_AMD64 && LZO_ARCH_X64) && defined(__LZO_ARCH_OVERRIDE) +# define LZO_ARCH_AMD64 1 +#endif +#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64) +# define LZO_ARCH_AARCH64 1 +#elif (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64) && defined(__LZO_ARCH_OVERRIDE) +# define LZO_ARCH_ARM64 1 +#endif +#if (LZO_ARCH_I386 && !LZO_ARCH_X86) +# define LZO_ARCH_X86 1 +#elif (!LZO_ARCH_I386 && LZO_ARCH_X86) && defined(__LZO_ARCH_OVERRIDE) +# define LZO_ARCH_I386 1 +#endif +#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64) || (!LZO_ARCH_AMD64 && LZO_ARCH_X64) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64) || (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_I086PM && !LZO_ARCH_I086) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_I086) +# if (UINT_MAX != LZO_0xffffL) +# error "unexpected configuration - check your compiler defines" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if (LZO_ARCH_I386) +# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) +# error "unexpected configuration - check your compiler defines" +# endif +# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) +# error "unexpected configuration - check your compiler defines" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if (LZO_ARCH_AMD64 || LZO_ARCH_I386) +# if !defined(LZO_TARGET_FEATURE_SSE2) +# if defined(__SSE2__) +# define LZO_TARGET_FEATURE_SSE2 1 +# elif defined(_MSC_VER) && (defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) +# define LZO_TARGET_FEATURE_SSE2 1 +# elif (LZO_CC_INTELC_MSC || LZO_CC_MSC) && defined(_M_AMD64) +# define LZO_TARGET_FEATURE_SSE2 1 +# endif +# endif +# if !defined(LZO_TARGET_FEATURE_SSSE3) +# if (LZO_TARGET_FEATURE_SSE2) +# if defined(__SSSE3__) +# define LZO_TARGET_FEATURE_SSSE3 1 +# elif defined(_MSC_VER) && defined(__AVX__) +# define LZO_TARGET_FEATURE_SSSE3 1 +# endif +# endif +# endif +# if !defined(LZO_TARGET_FEATURE_SSE4_2) +# if (LZO_TARGET_FEATURE_SSSE3) +# if defined(__SSE4_2__) +# define LZO_TARGET_FEATURE_SSE4_2 1 +# endif +# endif +# endif +# if !defined(LZO_TARGET_FEATURE_AVX) +# if (LZO_TARGET_FEATURE_SSSE3) +# if defined(__AVX__) +# define LZO_TARGET_FEATURE_AVX 1 +# endif +# endif +# endif +# if !defined(LZO_TARGET_FEATURE_AVX2) +# if (LZO_TARGET_FEATURE_AVX) +# if defined(__AVX2__) +# define LZO_TARGET_FEATURE_AVX2 1 +# endif +# endif +# endif +#endif +#if (LZO_TARGET_FEATURE_SSSE3 && !(LZO_TARGET_FEATURE_SSE2)) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_TARGET_FEATURE_SSE4_2 && !(LZO_TARGET_FEATURE_SSSE3)) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_TARGET_FEATURE_AVX && !(LZO_TARGET_FEATURE_SSSE3)) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_TARGET_FEATURE_AVX2 && !(LZO_TARGET_FEATURE_AVX)) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ARCH_ARM) +# if !defined(LZO_TARGET_FEATURE_NEON) +# if defined(__ARM_NEON) && ((__ARM_NEON)+0) +# define LZO_TARGET_FEATURE_NEON 1 +# elif 1 && defined(__ARM_NEON__) && ((__ARM_NEON__)+0) +# define LZO_TARGET_FEATURE_NEON 1 +# elif 1 && defined(__TARGET_FEATURE_NEON) && ((__TARGET_FEATURE_NEON)+0) +# define LZO_TARGET_FEATURE_NEON 1 +# endif +# endif +#elif (LZO_ARCH_ARM64) +# if !defined(LZO_TARGET_FEATURE_NEON) +# if 1 +# define LZO_TARGET_FEATURE_NEON 1 +# endif +# endif +#endif +#if 0 +#elif !defined(__LZO_MM_OVERRIDE) +#if (LZO_ARCH_I086) +#if (UINT_MAX != LZO_0xffffL) +# error "unexpected configuration - check your compiler defines" +#endif +#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) +# define LZO_MM_TINY 1 +#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) +# define LZO_MM_HUGE 1 +#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) +# define LZO_MM_SMALL 1 +#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) +# define LZO_MM_MEDIUM 1 +#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) +# define LZO_MM_COMPACT 1 +#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) +# define LZO_MM_LARGE 1 +#elif (LZO_CC_AZTECC) +# if defined(_LARGE_CODE) && defined(_LARGE_DATA) +# define LZO_MM_LARGE 1 +# elif defined(_LARGE_CODE) +# define LZO_MM_MEDIUM 1 +# elif defined(_LARGE_DATA) +# define LZO_MM_COMPACT 1 +# else +# define LZO_MM_SMALL 1 +# endif +#elif (LZO_CC_ZORTECHC && defined(__VCM__)) +# define LZO_MM_LARGE 1 +#else +# error "unknown LZO_ARCH_I086 memory model" +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +#define LZO_HAVE_MM_HUGE_PTR 1 +#define LZO_HAVE_MM_HUGE_ARRAY 1 +#if (LZO_MM_TINY) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) +# undef LZO_HAVE_MM_HUGE_PTR +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_MSC && defined(_QC)) +# undef LZO_HAVE_MM_HUGE_ARRAY +# if (_MSC_VER < 600) +# undef LZO_HAVE_MM_HUGE_PTR +# endif +#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) +# if (LZO_OS_DOS16) +# error "unexpected configuration - check your compiler defines" +# elif (LZO_CC_ZORTECHC) +# else +# error "unexpected configuration - check your compiler defines" +# endif +#endif +#if defined(__cplusplus) +extern "C" { +#endif +#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) +# define LZO_MM_AHSHIFT 12 +#elif (LZO_CC_WATCOMC) + extern unsigned char _HShift; +# define LZO_MM_AHSHIFT ((unsigned) _HShift) +#else +# error "FIXME - implement LZO_MM_AHSHIFT" +#endif +#if defined(__cplusplus) +} +#endif +#endif +#elif (LZO_ARCH_C166) +#if !defined(__MODEL__) +# error "FIXME - LZO_ARCH_C166 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - LZO_ARCH_C166 __MODEL__" +#endif +#elif (LZO_ARCH_MCS251) +#if !defined(__MODEL__) +# error "FIXME - LZO_ARCH_MCS251 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - LZO_ARCH_MCS251 __MODEL__" +#endif +#elif (LZO_ARCH_MCS51) +#if !defined(__MODEL__) +# error "FIXME - LZO_ARCH_MCS51 __MODEL__" +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - LZO_ARCH_MCS51 __MODEL__" +#endif +#elif (LZO_ARCH_CRAY_PVP) +# define LZO_MM_PVP 1 +#else +# define LZO_MM_FLAT 1 +#endif +#if (LZO_MM_COMPACT) +# define LZO_INFO_MM "compact" +#elif (LZO_MM_FLAT) +# define LZO_INFO_MM "flat" +#elif (LZO_MM_HUGE) +# define LZO_INFO_MM "huge" +#elif (LZO_MM_LARGE) +# define LZO_INFO_MM "large" +#elif (LZO_MM_MEDIUM) +# define LZO_INFO_MM "medium" +#elif (LZO_MM_PVP) +# define LZO_INFO_MM "pvp" +#elif (LZO_MM_SMALL) +# define LZO_INFO_MM "small" +#elif (LZO_MM_TINY) +# define LZO_INFO_MM "tiny" +#else +# error "unknown memory model" +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +#if (LZO_CC_GNUC >= 0x020800ul) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_IBMC >= 600) +# define __lzo_gnuc_extension__ __extension__ +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +# define __lzo_gnuc_extension__ /*empty*/ +#endif +#if !defined(lzo_has_builtin) +#if (LZO_CC_CLANG) && defined(__has_builtin) +# define lzo_has_builtin __has_builtin +#endif +#endif +#if !defined(lzo_has_builtin) +# define lzo_has_builtin(x) 0 +#endif +#if !defined(lzo_has_attribute) +#if (LZO_CC_CLANG) && defined(__has_attribute) +# define lzo_has_attribute __has_attribute +#endif +#endif +#if !defined(lzo_has_attribute) +# define lzo_has_attribute(x) 0 +#endif +#if !defined(lzo_has_declspec_attribute) +#if (LZO_CC_CLANG) && defined(__has_declspec_attribute) +# define lzo_has_declspec_attribute __has_declspec_attribute +#endif +#endif +#if !defined(lzo_has_declspec_attribute) +# define lzo_has_declspec_attribute(x) 0 +#endif +#if !defined(lzo_has_feature) +#if (LZO_CC_CLANG) && defined(__has_feature) +# define lzo_has_feature __has_feature +#endif +#endif +#if !defined(lzo_has_feature) +# define lzo_has_feature(x) 0 +#endif +#if !defined(lzo_has_extension) +#if (LZO_CC_CLANG) && defined(__has_extension) +# define lzo_has_extension __has_extension +#elif (LZO_CC_CLANG) && defined(__has_feature) +# define lzo_has_extension __has_feature +#endif +#endif +#if !defined(lzo_has_extension) +# define lzo_has_extension(x) 0 +#endif +#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0 +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) +# define LZO_CFG_USE_NEW_STYLE_CASTS 0 +# elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1200)) +# define LZO_CFG_USE_NEW_STYLE_CASTS 0 +# else +# define LZO_CFG_USE_NEW_STYLE_CASTS 1 +# endif +#endif +#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_CFG_USE_NEW_STYLE_CASTS 0 +#endif +#if !defined(__cplusplus) +# if defined(LZO_CFG_USE_NEW_STYLE_CASTS) +# undef LZO_CFG_USE_NEW_STYLE_CASTS +# endif +# define LZO_CFG_USE_NEW_STYLE_CASTS 0 +#endif +#if !defined(LZO_REINTERPRET_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_REINTERPRET_CAST(t,e) (reinterpret_cast (e)) +# endif +#endif +#if !defined(LZO_REINTERPRET_CAST) +# define LZO_REINTERPRET_CAST(t,e) ((t) (e)) +#endif +#if !defined(LZO_STATIC_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_STATIC_CAST(t,e) (static_cast (e)) +# endif +#endif +#if !defined(LZO_STATIC_CAST) +# define LZO_STATIC_CAST(t,e) ((t) (e)) +#endif +#if !defined(LZO_STATIC_CAST2) +# define LZO_STATIC_CAST2(t1,t2,e) LZO_STATIC_CAST(t1, LZO_STATIC_CAST(t2, e)) +#endif +#if !defined(LZO_UNCONST_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_UNCONST_CAST(t,e) (const_cast (e)) +# elif (LZO_HAVE_MM_HUGE_PTR) +# define LZO_UNCONST_CAST(t,e) ((t) (e)) +# elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((lzo_uintptr_t) ((const void *) (e))))) +# endif +#endif +#if !defined(LZO_UNCONST_CAST) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((const void *) (e)))) +#endif +#if !defined(LZO_UNCONST_VOLATILE_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_UNCONST_VOLATILE_CAST(t,e) (const_cast (e)) +# elif (LZO_HAVE_MM_HUGE_PTR) +# define LZO_UNCONST_VOLATILE_CAST(t,e) ((t) (e)) +# elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_VOLATILE_CAST(t,e) ((t) ((volatile void *) ((lzo_uintptr_t) ((volatile const void *) (e))))) +# endif +#endif +#if !defined(LZO_UNCONST_VOLATILE_CAST) +# define LZO_UNCONST_VOLATILE_CAST(t,e) ((t) ((volatile void *) ((volatile const void *) (e)))) +#endif +#if !defined(LZO_UNVOLATILE_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_UNVOLATILE_CAST(t,e) (const_cast (e)) +# elif (LZO_HAVE_MM_HUGE_PTR) +# define LZO_UNVOLATILE_CAST(t,e) ((t) (e)) +# elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNVOLATILE_CAST(t,e) ((t) ((void *) ((lzo_uintptr_t) ((volatile void *) (e))))) +# endif +#endif +#if !defined(LZO_UNVOLATILE_CAST) +# define LZO_UNVOLATILE_CAST(t,e) ((t) ((void *) ((volatile void *) (e)))) +#endif +#if !defined(LZO_UNVOLATILE_CONST_CAST) +# if (LZO_CFG_USE_NEW_STYLE_CASTS) +# define LZO_UNVOLATILE_CONST_CAST(t,e) (const_cast (e)) +# elif (LZO_HAVE_MM_HUGE_PTR) +# define LZO_UNVOLATILE_CONST_CAST(t,e) ((t) (e)) +# elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNVOLATILE_CONST_CAST(t,e) ((t) ((const void *) ((lzo_uintptr_t) ((volatile const void *) (e))))) +# endif +#endif +#if !defined(LZO_UNVOLATILE_CONST_CAST) +# define LZO_UNVOLATILE_CONST_CAST(t,e) ((t) ((const void *) ((volatile const void *) (e)))) +#endif +#if !defined(LZO_PCAST) +# if (LZO_HAVE_MM_HUGE_PTR) +# define LZO_PCAST(t,e) ((t) (e)) +# endif +#endif +#if !defined(LZO_PCAST) +# define LZO_PCAST(t,e) LZO_STATIC_CAST(t, LZO_STATIC_CAST(void *, e)) +#endif +#if !defined(LZO_CCAST) +# if (LZO_HAVE_MM_HUGE_PTR) +# define LZO_CCAST(t,e) ((t) (e)) +# endif +#endif +#if !defined(LZO_CCAST) +# define LZO_CCAST(t,e) LZO_STATIC_CAST(t, LZO_STATIC_CAST(const void *, e)) +#endif +#if !defined(LZO_ICONV) +# define LZO_ICONV(t,e) LZO_STATIC_CAST(t, e) +#endif +#if !defined(LZO_ICAST) +# define LZO_ICAST(t,e) LZO_STATIC_CAST(t, e) +#endif +#if !defined(LZO_ITRUNC) +# define LZO_ITRUNC(t,e) LZO_STATIC_CAST(t, e) +#endif +#if !defined(__lzo_cte) +# if (LZO_CC_MSC || LZO_CC_WATCOMC) +# define __lzo_cte(e) ((void)0,(e)) +# elif 1 +# define __lzo_cte(e) ((void)0,(e)) +# endif +#endif +#if !defined(__lzo_cte) +# define __lzo_cte(e) (e) +#endif +#if !defined(LZO_BLOCK_BEGIN) +# define LZO_BLOCK_BEGIN do { +# define LZO_BLOCK_END } while __lzo_cte(0) +#endif +#if !defined(LZO_UNUSED) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030200ul)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNUSED(var) ((void) var) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_KEILC) +# define LZO_UNUSED(var) {extern int lzo_unused__[1-2*!(sizeof(var)>0)]; (void)lzo_unused__;} +# elif (LZO_CC_PACIFICC) +# define LZO_UNUSED(var) ((void) sizeof(var)) +# elif (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED(var) ((void) var) +# else +# define LZO_UNUSED(var) ((void) &var) +# endif +#endif +#if !defined(LZO_UNUSED_RESULT) +# define LZO_UNUSED_RESULT(var) LZO_UNUSED(var) +#endif +#if !defined(LZO_UNUSED_FUNC) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED_FUNC(func) ((void) func) +# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_MSC) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_KEILC || LZO_CC_PELLESC) +# define LZO_UNUSED_FUNC(func) {extern int lzo_unused__[1-2*!(sizeof((int)func)>0)]; (void)lzo_unused__;} +# else +# define LZO_UNUSED_FUNC(func) ((void) func) +# endif +#endif +#if !defined(LZO_UNUSED_LABEL) +# if (LZO_CC_CLANG >= 0x020800ul) +# define LZO_UNUSED_LABEL(l) (__lzo_gnuc_extension__ ((void) ((const void *) &&l))) +# elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) +# define LZO_UNUSED_LABEL(l) if __lzo_cte(0) goto l +# else +# define LZO_UNUSED_LABEL(l) switch (0) case 1:goto l +# endif +#endif +#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) +# if 0 +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var +# elif 0 && (LZO_CC_GNUC) +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var +# else +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init +# endif +#endif +#if !defined(__lzo_inline) +#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) +#elif defined(__cplusplus) +# define __lzo_inline inline +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L) +# define __lzo_inline inline +#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) +# define __lzo_inline __inline +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_inline __inline__ +#elif (LZO_CC_DMC) +# define __lzo_inline __inline +#elif (LZO_CC_GHS) +# define __lzo_inline __inline__ +#elif (LZO_CC_IBMC >= 600) +# define __lzo_inline __inline__ +#elif (LZO_CC_INTELC) +# define __lzo_inline __inline +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) +# define __lzo_inline __inline +#elif (LZO_CC_MSC && (_MSC_VER >= 900)) +# define __lzo_inline __inline +#elif (LZO_CC_SUNPROC >= 0x5100) +# define __lzo_inline __inline__ +#endif +#endif +#if defined(__lzo_inline) +# ifndef __lzo_HAVE_inline +# define __lzo_HAVE_inline 1 +# endif +#else +# define __lzo_inline /*empty*/ +#endif +#if !defined(__lzo_forceinline) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_IBMC >= 700) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800)) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_PGI >= 0x0d0a00ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_SUNPROC >= 0x5100) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#endif +#endif +#if defined(__lzo_forceinline) +# ifndef __lzo_HAVE_forceinline +# define __lzo_HAVE_forceinline 1 +# endif +#else +# define __lzo_forceinline __lzo_inline +#endif +#if !defined(__lzo_noinline) +#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) +# define __lzo_noinline __attribute__((__noinline__,__used__)) +#elif (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_IBMC >= 700) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800)) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) +# if defined(__cplusplus) +# else +# define __lzo_noinline __declspec(noinline) +# endif +#elif (LZO_CC_PGI >= 0x0d0a00ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_SUNPROC >= 0x5100) +# define __lzo_noinline __attribute__((__noinline__)) +#endif +#endif +#if defined(__lzo_noinline) +# ifndef __lzo_HAVE_noinline +# define __lzo_HAVE_noinline 1 +# endif +#else +# define __lzo_noinline /*empty*/ +#endif +#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) +# error "unexpected configuration - check your compiler defines" +#endif +#if !defined(__lzo_static_inline) +#if (LZO_CC_IBMC) +# define __lzo_static_inline __lzo_gnuc_extension__ static __lzo_inline +#endif +#endif +#if !defined(__lzo_static_inline) +# define __lzo_static_inline static __lzo_inline +#endif +#if !defined(__lzo_static_forceinline) +#if (LZO_CC_IBMC) +# define __lzo_static_forceinline __lzo_gnuc_extension__ static __lzo_forceinline +#endif +#endif +#if !defined(__lzo_static_forceinline) +# define __lzo_static_forceinline static __lzo_forceinline +#endif +#if !defined(__lzo_static_noinline) +#if (LZO_CC_IBMC) +# define __lzo_static_noinline __lzo_gnuc_extension__ static __lzo_noinline +#endif +#endif +#if !defined(__lzo_static_noinline) +# define __lzo_static_noinline static __lzo_noinline +#endif +#if !defined(__lzo_c99_extern_inline) +#if defined(__GNUC_GNU_INLINE__) +# define __lzo_c99_extern_inline __lzo_inline +#elif defined(__GNUC_STDC_INLINE__) +# define __lzo_c99_extern_inline extern __lzo_inline +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L) +# define __lzo_c99_extern_inline extern __lzo_inline +#endif +#if !defined(__lzo_c99_extern_inline) && (__lzo_HAVE_inline) +# define __lzo_c99_extern_inline __lzo_inline +#endif +#endif +#if defined(__lzo_c99_extern_inline) +# ifndef __lzo_HAVE_c99_extern_inline +# define __lzo_HAVE_c99_extern_inline 1 +# endif +#else +# define __lzo_c99_extern_inline /*empty*/ +#endif +#if !defined(__lzo_may_alias) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_may_alias __attribute__((__may_alias__)) +#elif (LZO_CC_CLANG >= 0x020900ul) +# define __lzo_may_alias __attribute__((__may_alias__)) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1210)) && 0 +# define __lzo_may_alias __attribute__((__may_alias__)) +#elif (LZO_CC_PGI >= 0x0d0a00ul) && 0 +# define __lzo_may_alias __attribute__((__may_alias__)) +#endif +#endif +#if defined(__lzo_may_alias) +# ifndef __lzo_HAVE_may_alias +# define __lzo_HAVE_may_alias 1 +# endif +#else +# define __lzo_may_alias /*empty*/ +#endif +#if !defined(__lzo_noreturn) +#if (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_IBMC >= 700) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600)) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_PGI >= 0x0d0a00ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#endif +#endif +#if defined(__lzo_noreturn) +# ifndef __lzo_HAVE_noreturn +# define __lzo_HAVE_noreturn 1 +# endif +#else +# define __lzo_noreturn /*empty*/ +#endif +#if !defined(__lzo_nothrow) +#if (LZO_CC_GNUC >= 0x030300ul) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 900)) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#endif +#endif +#if defined(__lzo_nothrow) +# ifndef __lzo_HAVE_nothrow +# define __lzo_HAVE_nothrow 1 +# endif +#else +# define __lzo_nothrow /*empty*/ +#endif +#if !defined(__lzo_restrict) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_IBMC >= 800) && !defined(__cplusplus) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_IBMC >= 1210) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600)) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600)) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) +# define __lzo_restrict __restrict +#elif (LZO_CC_PGI >= 0x0d0a00ul) +# define __lzo_restrict __restrict__ +#endif +#endif +#if defined(__lzo_restrict) +# ifndef __lzo_HAVE_restrict +# define __lzo_HAVE_restrict 1 +# endif +#else +# define __lzo_restrict /*empty*/ +#endif +#if !defined(__lzo_alignof) +#if (LZO_CC_ARMCC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_GHS) && !defined(__cplusplus) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_IBMC >= 600) +# define __lzo_alignof(e) (__lzo_gnuc_extension__ __alignof__(e)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_alignof(e) __alignof(e) +#elif (LZO_CC_SUNPROC >= 0x5100) +# define __lzo_alignof(e) __alignof__(e) +#endif +#endif +#if defined(__lzo_alignof) +# ifndef __lzo_HAVE_alignof +# define __lzo_HAVE_alignof 1 +# endif +#endif +#if !defined(__lzo_struct_packed) +#if (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul)) +#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul)) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus) +#elif (LZO_CC_GNUC >= 0x030400ul) && !(LZO_CC_PCC_GNUC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) +# define __lzo_struct_packed(s) struct s { +# define __lzo_struct_packed_end() } __attribute__((__gcc_struct__,__packed__)); +# define __lzo_struct_packed_ma_end() } __lzo_may_alias __attribute__((__gcc_struct__,__packed__)); +#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_struct_packed(s) struct s { +# define __lzo_struct_packed_end() } __attribute__((__packed__)); +# define __lzo_struct_packed_ma_end() } __lzo_may_alias __attribute__((__packed__)); +#elif (LZO_CC_IBMC >= 700) +# define __lzo_struct_packed(s) __lzo_gnuc_extension__ struct s { +# define __lzo_struct_packed_end() } __attribute__((__packed__)); +# define __lzo_struct_packed_ma_end() } __lzo_may_alias __attribute__((__packed__)); +#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_struct_packed(s) __pragma(pack(push,1)) struct s { +# define __lzo_struct_packed_end() } __pragma(pack(pop)); +#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900)) +# define __lzo_struct_packed(s) _Packed struct s { +# define __lzo_struct_packed_end() }; +#endif +#endif +#if defined(__lzo_struct_packed) && !defined(__lzo_struct_packed_ma) +# define __lzo_struct_packed_ma(s) __lzo_struct_packed(s) +#endif +#if defined(__lzo_struct_packed_end) && !defined(__lzo_struct_packed_ma_end) +# define __lzo_struct_packed_ma_end() __lzo_struct_packed_end() +#endif +#if !defined(__lzo_byte_struct) +#if defined(__lzo_struct_packed) +# define __lzo_byte_struct(s,n) __lzo_struct_packed(s) unsigned char a[n]; __lzo_struct_packed_end() +# define __lzo_byte_struct_ma(s,n) __lzo_struct_packed_ma(s) unsigned char a[n]; __lzo_struct_packed_ma_end() +#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_PGI || (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_byte_struct(s,n) struct s { unsigned char a[n]; } __attribute__((__packed__)); +# define __lzo_byte_struct_ma(s,n) struct s { unsigned char a[n]; } __lzo_may_alias __attribute__((__packed__)); +#endif +#endif +#if defined(__lzo_byte_struct) && !defined(__lzo_byte_struct_ma) +# define __lzo_byte_struct_ma(s,n) __lzo_byte_struct(s,n) +#endif +#if !defined(__lzo_struct_align16) && (__lzo_HAVE_alignof) +#if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul)) +#elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_CILLY || LZO_CC_PCC) +#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_struct_align16(s) struct __declspec(align(16)) s { +# define __lzo_struct_align16_end() }; +# define __lzo_struct_align32(s) struct __declspec(align(32)) s { +# define __lzo_struct_align32_end() }; +# define __lzo_struct_align64(s) struct __declspec(align(64)) s { +# define __lzo_struct_align64_end() }; +#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || (LZO_CC_IBMC >= 700) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_struct_align16(s) struct s { +# define __lzo_struct_align16_end() } __attribute__((__aligned__(16))); +# define __lzo_struct_align32(s) struct s { +# define __lzo_struct_align32_end() } __attribute__((__aligned__(32))); +# define __lzo_struct_align64(s) struct s { +# define __lzo_struct_align64_end() } __attribute__((__aligned__(64))); +#endif +#endif +#if !defined(__lzo_union_um) +#if (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul)) +#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER < 810)) +#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul)) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus) +#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_union_am(s) union s { +# define __lzo_union_am_end() } __lzo_may_alias; +# define __lzo_union_um(s) union s { +# define __lzo_union_um_end() } __lzo_may_alias __attribute__((__packed__)); +#elif (LZO_CC_IBMC >= 700) +# define __lzo_union_am(s) __lzo_gnuc_extension__ union s { +# define __lzo_union_am_end() } __lzo_may_alias; +# define __lzo_union_um(s) __lzo_gnuc_extension__ union s { +# define __lzo_union_um_end() } __lzo_may_alias __attribute__((__packed__)); +#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_union_um(s) __pragma(pack(push,1)) union s { +# define __lzo_union_um_end() } __pragma(pack(pop)); +#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900)) +# define __lzo_union_um(s) _Packed union s { +# define __lzo_union_um_end() }; +#endif +#endif +#if !defined(__lzo_union_am) +# define __lzo_union_am(s) union s { +# define __lzo_union_am_end() }; +#endif +#if !defined(__lzo_constructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_constructor __attribute__((__constructor__)) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800)) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_constructor __attribute__((__constructor__)) +#endif +#endif +#if defined(__lzo_constructor) +# ifndef __lzo_HAVE_constructor +# define __lzo_HAVE_constructor 1 +# endif +#endif +#if !defined(__lzo_destructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_destructor __attribute__((__destructor__)) +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800)) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_destructor __attribute__((__destructor__)) +#endif +#endif +#if defined(__lzo_destructor) +# ifndef __lzo_HAVE_destructor +# define __lzo_HAVE_destructor 1 +# endif +#endif +#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) +# error "unexpected configuration - check your compiler defines" +#endif +#if !defined(__lzo_likely) && !defined(__lzo_unlikely) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_IBMC >= 1010) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_CLANG && LZO_CC_CLANG_C2) +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#endif +#endif +#if defined(__lzo_likely) +# ifndef __lzo_HAVE_likely +# define __lzo_HAVE_likely 1 +# endif +#else +# define __lzo_likely(e) (e) +#endif +#if defined(__lzo_very_likely) +# ifndef __lzo_HAVE_very_likely +# define __lzo_HAVE_very_likely 1 +# endif +#else +# define __lzo_very_likely(e) __lzo_likely(e) +#endif +#if defined(__lzo_unlikely) +# ifndef __lzo_HAVE_unlikely +# define __lzo_HAVE_unlikely 1 +# endif +#else +# define __lzo_unlikely(e) (e) +#endif +#if defined(__lzo_very_unlikely) +# ifndef __lzo_HAVE_very_unlikely +# define __lzo_HAVE_very_unlikely 1 +# endif +#else +# define __lzo_very_unlikely(e) __lzo_unlikely(e) +#endif +#if !defined(__lzo_loop_forever) +# if (LZO_CC_IBMC) +# define __lzo_loop_forever() LZO_BLOCK_BEGIN for (;;) { ; } LZO_BLOCK_END +# else +# define __lzo_loop_forever() do { ; } while __lzo_cte(1) +# endif +#endif +#if !defined(__lzo_unreachable) +#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul)) && lzo_has_builtin(__builtin_unreachable) +# define __lzo_unreachable() __builtin_unreachable(); +#elif (LZO_CC_GNUC >= 0x040500ul) +# define __lzo_unreachable() __builtin_unreachable(); +#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1300)) && 1 +# define __lzo_unreachable() __builtin_unreachable(); +#endif +#endif +#if defined(__lzo_unreachable) +# ifndef __lzo_HAVE_unreachable +# define __lzo_HAVE_unreachable 1 +# endif +#else +# if 0 +# define __lzo_unreachable() ((void)0); +# else +# define __lzo_unreachable() __lzo_loop_forever(); +# endif +#endif +#if !defined(lzo_unused_funcs_impl) +# if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define lzo_unused_funcs_impl(r,f) static r __attribute__((__unused__)) f +# elif 1 && (LZO_CC_BORLANDC || LZO_CC_GNUC) +# define lzo_unused_funcs_impl(r,f) static r f +# else +# define lzo_unused_funcs_impl(r,f) __lzo_static_forceinline r f +# endif +#endif +#ifndef __LZO_CTA_NAME +#if (LZO_CFG_USE_COUNTER) +# define __LZO_CTA_NAME(a) LZO_PP_ECONCAT2(a,__COUNTER__) +#else +# define __LZO_CTA_NAME(a) LZO_PP_ECONCAT2(a,__LINE__) +#endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) +# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1u-2*!(e)]; LZO_EXTERN_C_END +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END +# elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020900ul)) && defined(__cplusplus) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN int __LZO_CTA_NAME(lzo_cta_f__)(int [1-2*!(e)]); LZO_EXTERN_C_END +# elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__)); LZO_EXTERN_C_END +# else +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-2*!(e)]; LZO_EXTERN_C_END +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT) +# if (LZO_CC_AZTECC) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];} +# elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030000ul)) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));} +# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__) +# define LZO_COMPILE_TIME_ASSERT(e) {(void) (0/!!(e));} +# elif (LZO_CC_GNUC >= 0x040700ul) && (LZO_CFG_USE_COUNTER) && defined(__cplusplus) +# define LZO_COMPILE_TIME_ASSERT(e) {enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__));} +# elif (LZO_CC_GNUC >= 0x040700ul) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));} +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# else +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];} +# endif +#endif +#if (LZO_LANG_ASSEMBLER) +# undef LZO_COMPILE_TIME_ASSERT_HEADER +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) /*empty*/ +#else +LZO_COMPILE_TIME_ASSERT_HEADER(1 == 1) +#if defined(__cplusplus) +extern "C" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) } +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3) +#endif +#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit /*empty*/ +# define __lzo_cdecl_main __cdecl +# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_qsort __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_qsort _stdcall +# else +# define __lzo_cdecl_qsort __cdecl +# endif +# elif (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +# else +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit __cdecl +# define __lzo_cdecl_main __cdecl +# define __lzo_cdecl_qsort __cdecl +# endif +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) +# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_sighandler __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_sighandler _stdcall +# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) +# define __lzo_cdecl_sighandler __clrcall +# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) +# if defined(_DLL) +# define __lzo_cdecl_sighandler _far _cdecl _loadds +# elif defined(_MT) +# define __lzo_cdecl_sighandler _far _cdecl +# else +# define __lzo_cdecl_sighandler _cdecl +# endif +# else +# define __lzo_cdecl_sighandler __cdecl +# endif +#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) +# define __lzo_cdecl cdecl +#endif +#if !defined(__lzo_cdecl) +# define __lzo_cdecl /*empty*/ +#endif +#if !defined(__lzo_cdecl_atexit) +# define __lzo_cdecl_atexit /*empty*/ +#endif +#if !defined(__lzo_cdecl_main) +# define __lzo_cdecl_main /*empty*/ +#endif +#if !defined(__lzo_cdecl_qsort) +# define __lzo_cdecl_qsort /*empty*/ +#endif +#if !defined(__lzo_cdecl_sighandler) +# define __lzo_cdecl_sighandler /*empty*/ +#endif +#if !defined(__lzo_cdecl_va) +# define __lzo_cdecl_va __lzo_cdecl +#endif +#if !(LZO_CFG_NO_WINDOWS_H) +#if !defined(LZO_HAVE_WINDOWS_H) +#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +# elif ((LZO_OS_WIN32 && defined(__PW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul))) +# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) +# else +# define LZO_HAVE_WINDOWS_H 1 +# endif +#endif +#endif +#endif +#define LZO_SIZEOF_CHAR 1 +#ifndef LZO_SIZEOF_SHORT +#if defined(SIZEOF_SHORT) +# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +#elif defined(__SIZEOF_SHORT__) +# define LZO_SIZEOF_SHORT (__SIZEOF_SHORT__) +#endif +#endif +#ifndef LZO_SIZEOF_INT +#if defined(SIZEOF_INT) +# define LZO_SIZEOF_INT (SIZEOF_INT) +#elif defined(__SIZEOF_INT__) +# define LZO_SIZEOF_INT (__SIZEOF_INT__) +#endif +#endif +#ifndef LZO_SIZEOF_LONG +#if defined(SIZEOF_LONG) +# define LZO_SIZEOF_LONG (SIZEOF_LONG) +#elif defined(__SIZEOF_LONG__) +# define LZO_SIZEOF_LONG (__SIZEOF_LONG__) +#endif +#endif +#ifndef LZO_SIZEOF_LONG_LONG +#if defined(SIZEOF_LONG_LONG) +# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) +#elif defined(__SIZEOF_LONG_LONG__) +# define LZO_SIZEOF_LONG_LONG (__SIZEOF_LONG_LONG__) +#endif +#endif +#ifndef LZO_SIZEOF___INT16 +#if defined(SIZEOF___INT16) +# define LZO_SIZEOF___INT16 (SIZEOF___INT16) +#endif +#endif +#ifndef LZO_SIZEOF___INT32 +#if defined(SIZEOF___INT32) +# define LZO_SIZEOF___INT32 (SIZEOF___INT32) +#endif +#endif +#ifndef LZO_SIZEOF___INT64 +#if defined(SIZEOF___INT64) +# define LZO_SIZEOF___INT64 (SIZEOF___INT64) +#endif +#endif +#ifndef LZO_SIZEOF_VOID_P +#if defined(SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) +#elif defined(__SIZEOF_POINTER__) +# define LZO_SIZEOF_VOID_P (__SIZEOF_POINTER__) +#endif +#endif +#ifndef LZO_SIZEOF_SIZE_T +#if defined(SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) +#elif defined(__SIZEOF_SIZE_T__) +# define LZO_SIZEOF_SIZE_T (__SIZEOF_SIZE_T__) +#endif +#endif +#ifndef LZO_SIZEOF_PTRDIFF_T +#if defined(SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) +#elif defined(__SIZEOF_PTRDIFF_T__) +# define LZO_SIZEOF_PTRDIFF_T (__SIZEOF_PTRDIFF_T__) +#endif +#endif +#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) +#if !defined(LZO_SIZEOF_SHORT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_SHORT 8 +# elif (USHRT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,7) == 1) +# define LZO_SIZEOF_SHORT 1 +# elif (__LZO_LSR(USHRT_MAX,15) == 1) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,31) == 1) +# define LZO_SIZEOF_SHORT 4 +# elif (__LZO_LSR(USHRT_MAX,63) == 1) +# define LZO_SIZEOF_SHORT 8 +# elif (__LZO_LSR(USHRT_MAX,127) == 1) +# define LZO_SIZEOF_SHORT 16 +# else +# error "LZO_SIZEOF_SHORT" +# endif +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SHORT == sizeof(short)) +#if !defined(LZO_SIZEOF_INT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_INT 8 +# elif (UINT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_INT 2 +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,7) == 1) +# define LZO_SIZEOF_INT 1 +# elif (__LZO_LSR(UINT_MAX,15) == 1) +# define LZO_SIZEOF_INT 2 +# elif (__LZO_LSR(UINT_MAX,31) == 1) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,63) == 1) +# define LZO_SIZEOF_INT 8 +# elif (__LZO_LSR(UINT_MAX,127) == 1) +# define LZO_SIZEOF_INT 16 +# else +# error "LZO_SIZEOF_INT" +# endif +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_INT == sizeof(int)) +#if !defined(LZO_SIZEOF_LONG) +# if (ULONG_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,7) == 1) +# define LZO_SIZEOF_LONG 1 +# elif (__LZO_LSR(ULONG_MAX,15) == 1) +# define LZO_SIZEOF_LONG 2 +# elif (__LZO_LSR(ULONG_MAX,31) == 1) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,39) == 1) +# define LZO_SIZEOF_LONG 5 +# elif (__LZO_LSR(ULONG_MAX,63) == 1) +# define LZO_SIZEOF_LONG 8 +# elif (__LZO_LSR(ULONG_MAX,127) == 1) +# define LZO_SIZEOF_LONG 16 +# else +# error "LZO_SIZEOF_LONG" +# endif +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long)) +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) +# if (LZO_CC_GNUC >= 0x030300ul) +# if ((__LONG_MAX__-0) == (__LONG_LONG_MAX__-0)) +# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG +# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) +# define LZO_SIZEOF_LONG_LONG 4 +# endif +# endif +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +#if (LZO_ARCH_I086 && LZO_CC_DMC) +#elif (LZO_CC_CILLY) && defined(__GNUC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_SIZEOF_LONG_LONG 8 +#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_OS_WIN64 || defined(_WIN64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_CC_GHS && defined(__LLONG_BIT) && ((__LLONG_BIT-0) == 64)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && ((_INTEGRAL_MAX_BITS-0) == 64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (defined(__vms) || defined(__VMS)) && ((__INITIAL_POINTER_SIZE-0) == 64) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) +#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define LZO_SIZEOF_LONG_LONG 8 +#endif +#endif +#endif +#if defined(__cplusplus) && (LZO_CC_GNUC) +# if (LZO_CC_GNUC < 0x020800ul) +# undef LZO_SIZEOF_LONG_LONG +# endif +#endif +#if (LZO_CFG_NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#elif defined(__NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#elif defined(_NO_LONGLONG) +# undef LZO_SIZEOF_LONG_LONG +#endif +#if !defined(LZO_WORDSIZE) +#if (LZO_ARCH_ALPHA) +# define LZO_WORDSIZE 8 +#elif (LZO_ARCH_AMD64) +# define LZO_WORDSIZE 8 +#elif (LZO_ARCH_ARM64) +# define LZO_WORDSIZE 8 +#elif (LZO_ARCH_AVR) +# define LZO_WORDSIZE 1 +#elif (LZO_ARCH_H8300) +# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_WORDSIZE 4 +# else +# define LZO_WORDSIZE 2 +# endif +#elif (LZO_ARCH_I086) +# define LZO_WORDSIZE 2 +#elif (LZO_ARCH_IA64) +# define LZO_WORDSIZE 8 +#elif (LZO_ARCH_M16C) +# define LZO_WORDSIZE 2 +#elif (LZO_ARCH_SPU) +# define LZO_WORDSIZE 4 +#elif (LZO_ARCH_Z80) +# define LZO_WORDSIZE 1 +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_WORDSIZE 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) +# define LZO_WORDSIZE 8 +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_WORDSIZE 8 +#endif +#endif +#if !defined(LZO_SIZEOF_VOID_P) +#if defined(__ILP32__) || defined(__ILP32) || defined(_ILP32) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) == 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4) +# define LZO_SIZEOF_VOID_P 4 +#elif defined(__ILP64__) || defined(__ILP64) || defined(_ILP64) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) == 8) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8) +# define LZO_SIZEOF_VOID_P 8 +#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4) +# define LZO_SIZEOF_VOID_P 8 +#elif defined(__LP64__) || defined(__LP64) || defined(_LP64) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8) +# define LZO_SIZEOF_VOID_P 8 +#elif (LZO_ARCH_AVR) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_H8300) +# if defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) + LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 4) +# if defined(__NORMAL_MODE__) +# define LZO_SIZEOF_VOID_P 2 +# else +# define LZO_SIZEOF_VOID_P 4 +# endif +# else + LZO_COMPILE_TIME_ASSERT_HEADER(LZO_WORDSIZE == 2) +# define LZO_SIZEOF_VOID_P 2 +# endif +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT +# endif +#elif (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) +# define LZO_SIZEOF_VOID_P 2 +# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) +# define LZO_SIZEOF_VOID_P 4 +# else +# error "invalid LZO_ARCH_I086 memory model" +# endif +#elif (LZO_ARCH_M16C) +# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) +# define LZO_SIZEOF_VOID_P 4 +# else +# define LZO_SIZEOF_VOID_P 2 +# endif +#elif (LZO_ARCH_SPU) +# define LZO_SIZEOF_VOID_P 4 +#elif (LZO_ARCH_Z80) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_SIZEOF_VOID_P 4 +#elif (LZO_OS_OS400 || defined(__OS400__)) +# if defined(__LLP64_IFC__) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +# else +# define LZO_SIZEOF_VOID_P 16 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +# endif +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#endif +#endif +#if !defined(LZO_SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_VOID_P == sizeof(void *)) +#if !defined(LZO_SIZEOF_SIZE_T) +#if (LZO_ARCH_I086 || LZO_ARCH_M16C) +# define LZO_SIZEOF_SIZE_T 2 +#endif +#endif +#if !defined(LZO_SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P +#endif +#if defined(offsetof) +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SIZE_T == sizeof(size_t)) +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +#if (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P +# elif (LZO_MM_COMPACT || LZO_MM_LARGE) +# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) +# define LZO_SIZEOF_PTRDIFF_T 4 +# else +# define LZO_SIZEOF_PTRDIFF_T 2 +# endif +# else +# error "invalid LZO_ARCH_I086 memory model" +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T +#endif +#if defined(offsetof) +LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)) +#endif +#if !defined(LZO_WORDSIZE) +# define LZO_WORDSIZE LZO_SIZEOF_VOID_P +#endif +#if (LZO_ABI_NEUTRAL_ENDIAN) +# undef LZO_ABI_BIG_ENDIAN +# undef LZO_ABI_LITTLE_ENDIAN +#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) +# define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430 || LZO_ARCH_RISCV) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) +# if (__LITTLE_ENDIAN__ == 1) +# define LZO_ABI_LITTLE_ENDIAN 1 +# else +# define LZO_ABI_BIG_ENDIAN 1 +# endif +#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(_MSC_VER) && defined(_WIN32) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC) +# if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) +# error "unexpected configuration - check your compiler defines" +# elif defined(__BIG_ENDIAN) +# define LZO_ABI_BIG_ENDIAN 1 +# else +# define LZO_ABI_LITTLE_ENDIAN 1 +# endif +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM64) && defined(__ARM_BIG_ENDIAN) && ((__ARM_BIG_ENDIAN)+0) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM64) && defined(_MSC_VER) && defined(_WIN32) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#endif +#endif +#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) +# error "unexpected configuration - check your compiler defines" +#endif +#if (LZO_ABI_BIG_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "be" +#elif (LZO_ABI_LITTLE_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "le" +#elif (LZO_ABI_NEUTRAL_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "neutral" +#endif +#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_I8LP16 1 +# define LZO_INFO_ABI_PM "i8lp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_ILP16 1 +# define LZO_INFO_ABI_PM "ilp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_LP32 1 +# define LZO_INFO_ABI_PM "lp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_ILP32 1 +# define LZO_INFO_ABI_PM "ilp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) +# define LZO_ABI_LLP64 1 +# define LZO_INFO_ABI_PM "llp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_LP64 1 +# define LZO_INFO_ABI_PM "lp64" +#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_ILP64 1 +# define LZO_INFO_ABI_PM "ilp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_IP32L64 1 +# define LZO_INFO_ABI_PM "ip32l64" +#endif +#if (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_VOID_P == 4 && LZO_WORDSIZE == 8) +# define LZO_ABI_IP32W64 1 +# ifndef LZO_INFO_ABI_PM +# define LZO_INFO_ABI_PM "ip32w64" +# endif +#endif +#if 0 +#elif !defined(__LZO_LIBC_OVERRIDE) +#if (LZO_LIBC_NAKED) +# define LZO_INFO_LIBC "naked" +#elif (LZO_LIBC_FREESTANDING) +# define LZO_INFO_LIBC "freestanding" +#elif (LZO_LIBC_MOSTLY_FREESTANDING) +# define LZO_INFO_LIBC "mfreestanding" +#elif (LZO_LIBC_ISOC90) +# define LZO_INFO_LIBC "isoc90" +#elif (LZO_LIBC_ISOC99) +# define LZO_INFO_LIBC "isoc99" +#elif (LZO_CC_ARMCC_ARMCC) && defined(__ARMCLIB_VERSION) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#elif defined(__dietlibc__) +# define LZO_LIBC_DIETLIBC 1 +# define LZO_INFO_LIBC "dietlibc" +#elif defined(_NEWLIB_VERSION) +# define LZO_LIBC_NEWLIB 1 +# define LZO_INFO_LIBC "newlib" +#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) +# if defined(__UCLIBC_SUBLEVEL__) +# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + (__UCLIBC_MINOR__-0) * 0x100 + (__UCLIBC_SUBLEVEL__-0)) +# else +# define LZO_LIBC_UCLIBC 0x00090bL +# endif +# define LZO_INFO_LIBC "uc" "libc" +#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) +# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + (__GLIBC_MINOR__-0) * 0x100) +# define LZO_INFO_LIBC "glibc" +#elif (LZO_CC_MWERKS) && defined(__MSL__) +# define LZO_LIBC_MSL __MSL__ +# define LZO_INFO_LIBC "msl" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#else +# define LZO_LIBC_DEFAULT 1 +# define LZO_INFO_LIBC "default" +#endif +#endif +#if (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +# define LZO_ASM_SYNTAX_MSC 1 +#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) +#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_CC_GNUC) +# define LZO_ASM_SYNTAX_GNUC 1 +#endif +#if (LZO_ASM_SYNTAX_GNUC) +#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) +# define __LZO_ASM_CLOBBER "ax" +# define __LZO_ASM_CLOBBER_LIST_CC /*empty*/ +# define __LZO_ASM_CLOBBER_LIST_CC_MEMORY /*empty*/ +# define __LZO_ASM_CLOBBER_LIST_EMPTY /*empty*/ +#elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1000)) +# define __LZO_ASM_CLOBBER "memory" +# define __LZO_ASM_CLOBBER_LIST_CC /*empty*/ +# define __LZO_ASM_CLOBBER_LIST_CC_MEMORY : "memory" +# define __LZO_ASM_CLOBBER_LIST_EMPTY /*empty*/ +#else +# define __LZO_ASM_CLOBBER "cc", "memory" +# define __LZO_ASM_CLOBBER_LIST_CC : "cc" +# define __LZO_ASM_CLOBBER_LIST_CC_MEMORY : "cc", "memory" +# define __LZO_ASM_CLOBBER_LIST_EMPTY /*empty*/ +#endif +#endif +#if (LZO_ARCH_ALPHA) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_AMD64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_ARM) +# if defined(__ARM_FEATURE_UNALIGNED) +# if ((__ARM_FEATURE_UNALIGNED)+0) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# endif +# elif 1 && (LZO_ARCH_ARM_THUMB2) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# elif 1 && defined(__ARM_ARCH) && ((__ARM_ARCH)+0 >= 7) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 7) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# elif 1 && defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM)+0 >= 6) && (defined(__TARGET_PROFILE_A) || defined(__TARGET_PROFILE_R)) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# elif 1 && defined(_MSC_VER) && defined(_M_ARM) && ((_M_ARM)+0 >= 7) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# endif +#elif (LZO_ARCH_ARM64) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_CRIS) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_I386) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_IA64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_PREFER_POSTINC 1 +#elif (LZO_ARCH_M68K) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(__mc68020__) && !defined(__mcoldfire__) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# endif +#elif (LZO_ARCH_MIPS) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_POWERPC) +# define LZO_OPT_PREFER_PREINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if (LZO_ABI_BIG_ENDIAN) || (LZO_WORDSIZE == 8) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# if (LZO_WORDSIZE == 8) +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +# endif +# endif +#elif (LZO_ARCH_RISCV) +# define LZO_OPT_AVOID_UINT_INDEX 1 +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# if (LZO_WORDSIZE == 8) +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +# endif +#elif (LZO_ARCH_S390) +# ifndef LZO_OPT_UNALIGNED16 +# define LZO_OPT_UNALIGNED16 1 +# endif +# ifndef LZO_OPT_UNALIGNED32 +# define LZO_OPT_UNALIGNED32 1 +# endif +# if (LZO_WORDSIZE == 8) +# ifndef LZO_OPT_UNALIGNED64 +# define LZO_OPT_UNALIGNED64 1 +# endif +# endif +#elif (LZO_ARCH_SH) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +#endif +#ifndef LZO_CFG_NO_INLINE_ASM +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) +# define LZO_CFG_NO_INLINE_ASM 1 +#elif (LZO_CC_LLVM) +# define LZO_CFG_NO_INLINE_ASM 1 +#endif +#endif +#if (LZO_CFG_NO_INLINE_ASM) +# undef LZO_ASM_SYNTAX_MSC +# undef LZO_ASM_SYNTAX_GNUC +# undef __LZO_ASM_CLOBBER +# undef __LZO_ASM_CLOBBER_LIST_CC +# undef __LZO_ASM_CLOBBER_LIST_CC_MEMORY +# undef __LZO_ASM_CLOBBER_LIST_EMPTY +#endif +#ifndef LZO_CFG_NO_UNALIGNED +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) +# define LZO_CFG_NO_UNALIGNED 1 +#endif +#endif +#if (LZO_CFG_NO_UNALIGNED) +# undef LZO_OPT_UNALIGNED16 +# undef LZO_OPT_UNALIGNED32 +# undef LZO_OPT_UNALIGNED64 +#endif +#if defined(__LZO_INFOSTR_MM) +#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) +# define __LZO_INFOSTR_MM "" +#elif defined(LZO_INFO_MM) +# define __LZO_INFOSTR_MM "." LZO_INFO_MM +#else +# define __LZO_INFOSTR_MM "" +#endif +#if defined(__LZO_INFOSTR_PM) +#elif defined(LZO_INFO_ABI_PM) +# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM +#else +# define __LZO_INFOSTR_PM "" +#endif +#if defined(__LZO_INFOSTR_ENDIAN) +#elif defined(LZO_INFO_ABI_ENDIAN) +# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN +#else +# define __LZO_INFOSTR_ENDIAN "" +#endif +#if defined(__LZO_INFOSTR_OSNAME) +#elif defined(LZO_INFO_OS_CONSOLE) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE +#elif defined(LZO_INFO_OS_POSIX) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX +#else +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS +#endif +#if defined(__LZO_INFOSTR_LIBC) +#elif defined(LZO_INFO_LIBC) +# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC +#else +# define __LZO_INFOSTR_LIBC "" +#endif +#if defined(__LZO_INFOSTR_CCVER) +#elif defined(LZO_INFO_CCVER) +# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER +#else +# define __LZO_INFOSTR_CCVER "" +#endif +#define LZO_INFO_STRING \ + LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ + " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER +#if !(LZO_CFG_SKIP_LZO_TYPES) +#if (!(LZO_SIZEOF_SHORT+0 > 0 && LZO_SIZEOF_INT+0 > 0 && LZO_SIZEOF_LONG+0 > 0)) +# error "missing defines for sizes" +#endif +#if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0)) +# error "missing defines for sizes" +#endif +#define LZO_TYPEOF_CHAR 1u +#define LZO_TYPEOF_SHORT 2u +#define LZO_TYPEOF_INT 3u +#define LZO_TYPEOF_LONG 4u +#define LZO_TYPEOF_LONG_LONG 5u +#define LZO_TYPEOF___INT8 17u +#define LZO_TYPEOF___INT16 18u +#define LZO_TYPEOF___INT32 19u +#define LZO_TYPEOF___INT64 20u +#define LZO_TYPEOF___INT128 21u +#define LZO_TYPEOF___INT256 22u +#define LZO_TYPEOF___MODE_QI 33u +#define LZO_TYPEOF___MODE_HI 34u +#define LZO_TYPEOF___MODE_SI 35u +#define LZO_TYPEOF___MODE_DI 36u +#define LZO_TYPEOF___MODE_TI 37u +#define LZO_TYPEOF_CHAR_P 129u +#if !defined(lzo_llong_t) +#if (LZO_SIZEOF_LONG_LONG+0 > 0) +# if !(LZO_LANG_ASSEMBLER) + __lzo_gnuc_extension__ typedef long long lzo_llong_t__; + __lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__; +# endif +# define lzo_llong_t lzo_llong_t__ +# define lzo_ullong_t lzo_ullong_t__ +#endif +#endif +#if !defined(lzo_int16e_t) +#if (LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) && (LZO_SIZEOF_SHORT != 2) +# undef LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T +#endif +#if (LZO_SIZEOF_LONG == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) +# define lzo_int16e_t long +# define lzo_uint16e_t unsigned long +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG +#elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT) +# define lzo_int16e_t int +# define lzo_uint16e_t unsigned int +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_SHORT == 2) +# define lzo_int16e_t short int +# define lzo_uint16e_t unsigned short int +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_SHORT +#elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) +# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__))); + typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__))); +# endif +# define lzo_int16e_t lzo_int16e_hi_t__ +# define lzo_uint16e_t lzo_uint16e_hi_t__ +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI +#elif (LZO_SIZEOF___INT16 == 2) +# define lzo_int16e_t __int16 +# define lzo_uint16e_t unsigned __int16 +# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16 +#else +#endif +#endif +#if defined(lzo_int16e_t) +# define LZO_SIZEOF_LZO_INT16E_T 2 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == 2) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T) +#endif +#if !defined(lzo_int32e_t) +#if (LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) && (LZO_SIZEOF_INT != 4) +# undef LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T +#endif +#if (LZO_SIZEOF_LONG == 4) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT32E_T == LZO_TYPEOF_INT) +# define lzo_int32e_t long int +# define lzo_uint32e_t unsigned long int +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG +#elif (LZO_SIZEOF_INT == 4) +# define lzo_int32e_t int +# define lzo_uint32e_t unsigned int +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_SHORT == 4) +# define lzo_int32e_t short int +# define lzo_uint32e_t unsigned short int +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_SHORT +#elif (LZO_SIZEOF_LONG_LONG == 4) +# define lzo_int32e_t lzo_llong_t +# define lzo_uint32e_t lzo_ullong_t +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG_LONG +#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L) +# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); + typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); +# endif +# define lzo_int32e_t lzo_int32e_si_t__ +# define lzo_uint32e_t lzo_uint32e_si_t__ +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI +#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L) +# if !(LZO_LANG_ASSEMBLER) + typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__))); + typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__))); +# endif +# define lzo_int32e_t lzo_int32e_si_t__ +# define lzo_uint32e_t lzo_uint32e_si_t__ +# define LZO_INT32_C(c) (c##LL) +# define LZO_UINT32_C(c) (c##ULL) +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI +#elif (LZO_SIZEOF___INT32 == 4) +# define lzo_int32e_t __int32 +# define lzo_uint32e_t unsigned __int32 +# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32 +#else +#endif +#endif +#if defined(lzo_int32e_t) +# define LZO_SIZEOF_LZO_INT32E_T 4 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == LZO_SIZEOF_LZO_INT32E_T) +#endif +#if !defined(lzo_int64e_t) +#if (LZO_SIZEOF___INT64 == 8) +# if (LZO_CC_BORLANDC) && !defined(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T) +# define LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T LZO_TYPEOF___INT64 +# endif +#endif +#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && (LZO_SIZEOF_LONG_LONG != 8) +# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T +#endif +#if (LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) && (LZO_SIZEOF___INT64 != 8) +# undef LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T +#endif +#if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) +# define lzo_int64e_t int +# define lzo_uint64e_t unsigned int +# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) +# define lzo_int64e_t long int +# define lzo_uint64e_t unsigned long int +# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG +#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64) +# define lzo_int64e_t lzo_llong_t +# define lzo_uint64e_t lzo_ullong_t +# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_LONG_LONG +# if (LZO_CC_BORLANDC) +# define LZO_INT64_C(c) ((c) + 0ll) +# define LZO_UINT64_C(c) ((c) + 0ull) +# elif 0 +# define LZO_INT64_C(c) (__lzo_gnuc_extension__ (c##LL)) +# define LZO_UINT64_C(c) (__lzo_gnuc_extension__ (c##ULL)) +# else +# define LZO_INT64_C(c) (c##LL) +# define LZO_UINT64_C(c) (c##ULL) +# endif +#elif (LZO_SIZEOF___INT64 == 8) +# define lzo_int64e_t __int64 +# define lzo_uint64e_t unsigned __int64 +# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF___INT64 +# if (LZO_CC_BORLANDC) +# define LZO_INT64_C(c) ((c) + 0i64) +# define LZO_UINT64_C(c) ((c) + 0ui64) +# else +# define LZO_INT64_C(c) (c##i64) +# define LZO_UINT64_C(c) (c##ui64) +# endif +#else +#endif +#endif +#if defined(lzo_int64e_t) +# define LZO_SIZEOF_LZO_INT64E_T 8 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T) +#endif +#if !defined(lzo_int32l_t) +#if defined(lzo_int32e_t) +# define lzo_int32l_t lzo_int32e_t +# define lzo_uint32l_t lzo_uint32e_t +# define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LZO_INT32E_T +# define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T +#elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) +# define lzo_int32l_t int +# define lzo_uint32l_t unsigned int +# define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT +# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT +#elif (LZO_SIZEOF_LONG >= 4) +# define lzo_int32l_t long int +# define lzo_uint32l_t unsigned long int +# define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_LONG +# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_LONG +#else +# error "lzo_int32l_t" +#endif +#endif +#if 1 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) >= 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) == LZO_SIZEOF_LZO_INT32L_T) +#endif +#if !defined(lzo_int64l_t) +#if defined(lzo_int64e_t) +# define lzo_int64l_t lzo_int64e_t +# define lzo_uint64l_t lzo_uint64e_t +# define LZO_SIZEOF_LZO_INT64L_T LZO_SIZEOF_LZO_INT64E_T +# define LZO_TYPEOF_LZO_INT64L_T LZO_TYPEOF_LZO_INT64E_T +#else +#endif +#endif +#if defined(lzo_int64l_t) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) >= 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) == LZO_SIZEOF_LZO_INT64L_T) +#endif +#if !defined(lzo_int32f_t) +#if (LZO_SIZEOF_SIZE_T >= 8) +# define lzo_int32f_t lzo_int64l_t +# define lzo_uint32f_t lzo_uint64l_t +# define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT64L_T +# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT64L_T +#else +# define lzo_int32f_t lzo_int32l_t +# define lzo_uint32f_t lzo_uint32l_t +# define LZO_SIZEOF_LZO_INT32F_T LZO_SIZEOF_LZO_INT32L_T +# define LZO_TYPEOF_LZO_INT32F_T LZO_TYPEOF_LZO_INT32L_T +#endif +#endif +#if 1 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) >= 4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) == LZO_SIZEOF_LZO_INT32F_T) +#endif +#if !defined(lzo_int64f_t) +#if defined(lzo_int64l_t) +# define lzo_int64f_t lzo_int64l_t +# define lzo_uint64f_t lzo_uint64l_t +# define LZO_SIZEOF_LZO_INT64F_T LZO_SIZEOF_LZO_INT64L_T +# define LZO_TYPEOF_LZO_INT64F_T LZO_TYPEOF_LZO_INT64L_T +#else +#endif +#endif +#if defined(lzo_int64f_t) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) >= 8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) == LZO_SIZEOF_LZO_INT64F_T) +#endif +#if !defined(lzo_intptr_t) +#if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16)) +# define __LZO_INTPTR_T_IS_POINTER 1 +# if !(LZO_LANG_ASSEMBLER) + typedef char * lzo_intptr_t; + typedef char * lzo_uintptr_t; +# endif +# define lzo_intptr_t lzo_intptr_t +# define lzo_uintptr_t lzo_uintptr_t +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_VOID_P +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_CHAR_P +#elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4)) +# if !(LZO_LANG_ASSEMBLER) + typedef __w64 int lzo_intptr_t; + typedef __w64 unsigned int lzo_uintptr_t; +# endif +# define lzo_intptr_t lzo_intptr_t +# define lzo_uintptr_t lzo_uintptr_t +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P) +# define lzo_intptr_t short +# define lzo_uintptr_t unsigned short +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_SHORT +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT +#elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG) +# define lzo_intptr_t int +# define lzo_uintptr_t unsigned int +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT +#elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P) +# define lzo_intptr_t long +# define lzo_uintptr_t unsigned long +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LONG +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LONG +#elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P) +# define lzo_intptr_t lzo_int64l_t +# define lzo_uintptr_t lzo_uint64l_t +# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_LZO_INT64L_T +# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_LZO_INT64L_T +#else +# error "lzo_intptr_t" +#endif +#endif +#if 1 + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) >= sizeof(void *)) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) == sizeof(lzo_uintptr_t)) +#endif +#if !defined(lzo_word_t) +#if defined(LZO_WORDSIZE) && (LZO_WORDSIZE+0 > 0) +#if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER) +# define lzo_word_t lzo_uintptr_t +# define lzo_sword_t lzo_intptr_t +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LZO_INTPTR_T +#elif (LZO_WORDSIZE == LZO_SIZEOF_LONG) +# define lzo_word_t unsigned long +# define lzo_sword_t long +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG +#elif (LZO_WORDSIZE == LZO_SIZEOF_INT) +# define lzo_word_t unsigned int +# define lzo_sword_t int +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT +#elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT) +# define lzo_word_t unsigned short +# define lzo_sword_t short +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_SHORT +#elif (LZO_WORDSIZE == 1) +# define lzo_word_t unsigned char +# define lzo_sword_t signed char +# define LZO_SIZEOF_LZO_WORD_T 1 +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_CHAR +#elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T) +# define lzo_word_t lzo_uint64l_t +# define lzo_sword_t lzo_int64l_t +# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T +# define LZO_TYPEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T +#elif (LZO_ARCH_SPU) && (LZO_CC_GNUC) +#if 0 +# if !(LZO_LANG_ASSEMBLER) + typedef unsigned lzo_word_t __attribute__((__mode__(__V16QI__))); + typedef int lzo_sword_t __attribute__((__mode__(__V16QI__))); +# endif +# define lzo_word_t lzo_word_t +# define lzo_sword_t lzo_sword_t +# define LZO_SIZEOF_LZO_WORD_T 16 +# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF___MODE_V16QI +#endif +#else +# error "lzo_word_t" +#endif +#endif +#endif +#if 1 && defined(lzo_word_t) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_word_t) == LZO_WORDSIZE) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_sword_t) == LZO_WORDSIZE) +#endif +#if 1 +#define lzo_int8_t signed char +#define lzo_uint8_t unsigned char +#define LZO_SIZEOF_LZO_INT8_T 1 +#define LZO_TYPEOF_LZO_INT8_T LZO_TYPEOF_CHAR +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t)) +#endif +#if defined(lzo_int16e_t) +#define lzo_int16_t lzo_int16e_t +#define lzo_uint16_t lzo_uint16e_t +#define LZO_SIZEOF_LZO_INT16_T LZO_SIZEOF_LZO_INT16E_T +#define LZO_TYPEOF_LZO_INT16_T LZO_TYPEOF_LZO_INT16E_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t)) +#endif +#if defined(lzo_int32e_t) +#define lzo_int32_t lzo_int32e_t +#define lzo_uint32_t lzo_uint32e_t +#define LZO_SIZEOF_LZO_INT32_T LZO_SIZEOF_LZO_INT32E_T +#define LZO_TYPEOF_LZO_INT32_T LZO_TYPEOF_LZO_INT32E_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t)) +#endif +#if defined(lzo_int64e_t) +#define lzo_int64_t lzo_int64e_t +#define lzo_uint64_t lzo_uint64e_t +#define LZO_SIZEOF_LZO_INT64_T LZO_SIZEOF_LZO_INT64E_T +#define LZO_TYPEOF_LZO_INT64_T LZO_TYPEOF_LZO_INT64E_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t)) +#endif +#if 1 +#define lzo_int_least32_t lzo_int32l_t +#define lzo_uint_least32_t lzo_uint32l_t +#define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T +#define LZO_TYPEOF_LZO_INT_LEAST32_T LZO_TYPEOF_LZO_INT32L_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t)) +#endif +#if defined(lzo_int64l_t) +#define lzo_int_least64_t lzo_int64l_t +#define lzo_uint_least64_t lzo_uint64l_t +#define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T +#define LZO_TYPEOF_LZO_INT_LEAST64_T LZO_TYPEOF_LZO_INT64L_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t)) +#endif +#if 1 +#define lzo_int_fast32_t lzo_int32f_t +#define lzo_uint_fast32_t lzo_uint32f_t +#define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T +#define LZO_TYPEOF_LZO_INT_FAST32_T LZO_TYPEOF_LZO_INT32F_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t)) +#endif +#if defined(lzo_int64f_t) +#define lzo_int_fast64_t lzo_int64f_t +#define lzo_uint_fast64_t lzo_uint64f_t +#define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T +#define LZO_TYPEOF_LZO_INT_FAST64_T LZO_TYPEOF_LZO_INT64F_T +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t)) +#endif +#if !defined(LZO_INT16_C) +# if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 2) +# define LZO_INT16_C(c) ((c) + 0) +# define LZO_UINT16_C(c) ((c) + 0U) +# elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 2) +# define LZO_INT16_C(c) ((c) + 0L) +# define LZO_UINT16_C(c) ((c) + 0UL) +# elif (LZO_SIZEOF_INT >= 2) +# define LZO_INT16_C(c) (c) +# define LZO_UINT16_C(c) (c##U) +# elif (LZO_SIZEOF_LONG >= 2) +# define LZO_INT16_C(c) (c##L) +# define LZO_UINT16_C(c) (c##UL) +# else +# error "LZO_INT16_C" +# endif +#endif +#if !defined(LZO_INT32_C) +# if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 4) +# define LZO_INT32_C(c) ((c) + 0) +# define LZO_UINT32_C(c) ((c) + 0U) +# elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 4) +# define LZO_INT32_C(c) ((c) + 0L) +# define LZO_UINT32_C(c) ((c) + 0UL) +# elif (LZO_SIZEOF_INT >= 4) +# define LZO_INT32_C(c) (c) +# define LZO_UINT32_C(c) (c##U) +# elif (LZO_SIZEOF_LONG >= 4) +# define LZO_INT32_C(c) (c##L) +# define LZO_UINT32_C(c) (c##UL) +# elif (LZO_SIZEOF_LONG_LONG >= 4) +# define LZO_INT32_C(c) (c##LL) +# define LZO_UINT32_C(c) (c##ULL) +# else +# error "LZO_INT32_C" +# endif +#endif +#if !defined(LZO_INT64_C) && defined(lzo_int64l_t) +# if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 8) +# define LZO_INT64_C(c) ((c) + 0) +# define LZO_UINT64_C(c) ((c) + 0U) +# elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 8) +# define LZO_INT64_C(c) ((c) + 0L) +# define LZO_UINT64_C(c) ((c) + 0UL) +# elif (LZO_SIZEOF_INT >= 8) +# define LZO_INT64_C(c) (c) +# define LZO_UINT64_C(c) (c##U) +# elif (LZO_SIZEOF_LONG >= 8) +# define LZO_INT64_C(c) (c##L) +# define LZO_UINT64_C(c) (c##UL) +# else +# error "LZO_INT64_C" +# endif +#endif +#endif + +#endif + +#endif + +#undef LZO_HAVE_CONFIG_H +#include "minilzo.h" + +#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x20a0) +# error "version mismatch in miniLZO source files" +#endif + +#ifdef MINILZO_HAVE_CONFIG_H +# define LZO_HAVE_CONFIG_H 1 +#endif + +#ifndef __LZO_CONF_H +#define __LZO_CONF_H 1 + +#if !defined(__LZO_IN_MINILZO) +#if defined(LZO_CFG_FREESTANDING) && (LZO_CFG_FREESTANDING) +# define LZO_LIBC_FREESTANDING 1 +# define LZO_OS_FREESTANDING 1 +#endif +#if defined(LZO_CFG_EXTRA_CONFIG_HEADER) +# include LZO_CFG_EXTRA_CONFIG_HEADER +#endif +#if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED) +# error "include this file first" +#endif +#if defined(LZO_CFG_BUILD_DLL) && (LZO_CFG_BUILD_DLL+0) && !defined(__LZO_EXPORT1) && !defined(__LZO_EXPORT2) && 0 +#ifndef __LZODEFS_H_INCLUDED +#if defined(LZO_HAVE_CONFIG_H) +# include +#endif +#include +#include +#include +#endif +#endif +#include +#if defined(LZO_CFG_EXTRA_CONFIG_HEADER2) +# include LZO_CFG_EXTRA_CONFIG_HEADER2 +#endif +#endif + +#if !defined(__LZOCONF_H_INCLUDED) || (LZO_VERSION+0 != 0x20a0) +# error "version mismatch" +#endif + +#if (LZO_CC_MSC && (_MSC_VER >= 1000 && _MSC_VER < 1100)) +# pragma warning(disable: 4702) +#endif +#if (LZO_CC_MSC && (_MSC_VER >= 1000)) +# pragma warning(disable: 4127 4701) +# pragma warning(disable: 4514 4710 4711) +#endif +#if (LZO_CC_MSC && (_MSC_VER >= 1300)) +# pragma warning(disable: 4820) +#endif +#if (LZO_CC_MSC && (_MSC_VER >= 1800)) +# pragma warning(disable: 4746) +#endif +#if (LZO_CC_INTELC && (__INTEL_COMPILER >= 900)) +# pragma warning(disable: 1684) +#endif + +#if (LZO_CC_SUNPROC) +#if !defined(__cplusplus) +# pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED) +# pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP) +# pragma error_messages(off,E_STATEMENT_NOT_REACHED) +#endif +#endif + +#if !defined(__LZO_NOEXPORT1) +# define __LZO_NOEXPORT1 /*empty*/ +#endif +#if !defined(__LZO_NOEXPORT2) +# define __LZO_NOEXPORT2 /*empty*/ +#endif + +#if 1 +# define LZO_PUBLIC_DECL(r) LZO_EXTERN(r) +#endif +#if 1 +# define LZO_PUBLIC_IMPL(r) LZO_PUBLIC(r) +#endif +#if !defined(LZO_LOCAL_DECL) +# define LZO_LOCAL_DECL(r) __LZO_EXTERN_C LZO_LOCAL_IMPL(r) +#endif +#if !defined(LZO_LOCAL_IMPL) +# define LZO_LOCAL_IMPL(r) __LZO_NOEXPORT1 r __LZO_NOEXPORT2 __LZO_CDECL +#endif +#if 1 +# define LZO_STATIC_DECL(r) LZO_PRIVATE(r) +#endif +#if 1 +# define LZO_STATIC_IMPL(r) LZO_PRIVATE(r) +#endif + +#if defined(__LZO_IN_MINILZO) || (LZO_CFG_FREESTANDING) +#elif 1 +# include +#else +# define LZO_WANT_ACC_INCD_H 1 +#endif +#if defined(LZO_HAVE_CONFIG_H) +# define LZO_CFG_NO_CONFIG_HEADER 1 +#endif + +#if 1 && !defined(LZO_CFG_FREESTANDING) +#if 1 && !defined(HAVE_STRING_H) +#define HAVE_STRING_H 1 +#endif +#if 1 && !defined(HAVE_MEMCMP) +#define HAVE_MEMCMP 1 +#endif +#if 1 && !defined(HAVE_MEMCPY) +#define HAVE_MEMCPY 1 +#endif +#if 1 && !defined(HAVE_MEMMOVE) +#define HAVE_MEMMOVE 1 +#endif +#if 1 && !defined(HAVE_MEMSET) +#define HAVE_MEMSET 1 +#endif +#endif + +#if 1 && defined(HAVE_STRING_H) +#include +#endif + +#if 1 || defined(lzo_int8_t) || defined(lzo_uint8_t) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint8_t) == 1) +#endif +#if 1 || defined(lzo_int16_t) || defined(lzo_uint16_t) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint16_t) == 2) +#endif +#if 1 || defined(lzo_int32_t) || defined(lzo_uint32_t) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32_t) == 4) +#endif +#if defined(lzo_int64_t) || defined(lzo_uint64_t) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64_t) == 8) +#endif + +#if (LZO_CFG_FREESTANDING) +# undef HAVE_MEMCMP +# undef HAVE_MEMCPY +# undef HAVE_MEMMOVE +# undef HAVE_MEMSET +#endif + +#if !(HAVE_MEMCMP) +# undef memcmp +# define memcmp(a,b,c) lzo_memcmp(a,b,c) +#else +# undef lzo_memcmp +# define lzo_memcmp(a,b,c) memcmp(a,b,c) +#endif +#if !(HAVE_MEMCPY) +# undef memcpy +# define memcpy(a,b,c) lzo_memcpy(a,b,c) +#else +# undef lzo_memcpy +# define lzo_memcpy(a,b,c) memcpy(a,b,c) +#endif +#if !(HAVE_MEMMOVE) +# undef memmove +# define memmove(a,b,c) lzo_memmove(a,b,c) +#else +# undef lzo_memmove +# define lzo_memmove(a,b,c) memmove(a,b,c) +#endif +#if !(HAVE_MEMSET) +# undef memset +# define memset(a,b,c) lzo_memset(a,b,c) +#else +# undef lzo_memset +# define lzo_memset(a,b,c) memset(a,b,c) +#endif + +#undef NDEBUG +#if (LZO_CFG_FREESTANDING) +# undef LZO_DEBUG +# define NDEBUG 1 +# undef assert +# define assert(e) ((void)0) +#else +# if !defined(LZO_DEBUG) +# define NDEBUG 1 +# endif +# include +#endif + +#if 0 && defined(__BOUNDS_CHECKING_ON) +# include +#else +# define BOUNDS_CHECKING_OFF_DURING(stmt) stmt +# define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr) +#endif + +#if (LZO_CFG_PGO) +# undef __lzo_likely +# undef __lzo_unlikely +# define __lzo_likely(e) (e) +# define __lzo_unlikely(e) (e) +#endif + +#undef _ +#undef __ +#undef ___ +#undef ____ +#undef _p0 +#undef _p1 +#undef _p2 +#undef _p3 +#undef _p4 +#undef _s0 +#undef _s1 +#undef _s2 +#undef _s3 +#undef _s4 +#undef _ww + +#if 1 +# define LZO_BYTE(x) ((unsigned char) (x)) +#else +# define LZO_BYTE(x) ((unsigned char) ((x) & 0xff)) +#endif + +#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) +#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) +#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c)) + +#define lzo_sizeof(type) ((lzo_uint) (sizeof(type))) + +#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array)))) + +#define LZO_SIZE(bits) (1u << (bits)) +#define LZO_MASK(bits) (LZO_SIZE(bits) - 1) + +#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits)) +#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1) + +#if !defined(DMUL) +#if 0 + +# define DMUL(a,b) ((lzo_xint) ((lzo_uint32_t)(a) * (lzo_uint32_t)(b))) +#else +# define DMUL(a,b) ((lzo_xint) ((a) * (b))) +#endif +#endif + +#ifndef __LZO_FUNC_H +#define __LZO_FUNC_H 1 + +#if !defined(LZO_BITOPS_USE_ASM_BITSCAN) && !defined(LZO_BITOPS_USE_GNUC_BITSCAN) && !defined(LZO_BITOPS_USE_MSC_BITSCAN) +#if 1 && (LZO_ARCH_AMD64) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_ASM_SYNTAX_GNUC) +#define LZO_BITOPS_USE_ASM_BITSCAN 1 +#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_LLVM && (!defined(__llvm_tools_version__) || (__llvm_tools_version__+0 >= 0x010500ul)))) +#define LZO_BITOPS_USE_GNUC_BITSCAN 1 +#elif (LZO_OS_WIN32 || LZO_OS_WIN64) && ((LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 1010)) || (LZO_CC_MSC && (_MSC_VER >= 1400))) +#define LZO_BITOPS_USE_MSC_BITSCAN 1 +#if (LZO_CC_MSC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) +#include +#endif +#if (LZO_CC_MSC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) +#pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) +#endif +#if (LZO_CC_MSC) && (LZO_ARCH_AMD64) +#pragma intrinsic(_BitScanReverse64) +#pragma intrinsic(_BitScanForward64) +#endif +#endif +#endif + +__lzo_static_forceinline unsigned lzo_bitops_ctlz32_func(lzo_uint32_t v) +{ +#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) + unsigned long r; (void) _BitScanReverse(&r, v); return (unsigned) r ^ 31; +#define lzo_bitops_ctlz32(v) lzo_bitops_ctlz32_func(v) +#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) && (LZO_ASM_SYNTAX_GNUC) + lzo_uint32_t r; + __asm__("bsr %1,%0" : "=r" (r) : "rm" (v) __LZO_ASM_CLOBBER_LIST_CC); + return (unsigned) r ^ 31; +#define lzo_bitops_ctlz32(v) lzo_bitops_ctlz32_func(v) +#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_INT == 4) + unsigned r; r = (unsigned) __builtin_clz(v); return r; +#define lzo_bitops_ctlz32(v) ((unsigned) __builtin_clz(v)) +#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG == 8) && (LZO_WORDSIZE >= 8) + unsigned r; r = (unsigned) __builtin_clzl(v); return r ^ 32; +#define lzo_bitops_ctlz32(v) (((unsigned) __builtin_clzl(v)) ^ 32) +#else + LZO_UNUSED(v); return 0; +#endif +} + +#if defined(lzo_uint64_t) +__lzo_static_forceinline unsigned lzo_bitops_ctlz64_func(lzo_uint64_t v) +{ +#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64) + unsigned long r; (void) _BitScanReverse64(&r, v); return (unsigned) r ^ 63; +#define lzo_bitops_ctlz64(v) lzo_bitops_ctlz64_func(v) +#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64) && (LZO_ASM_SYNTAX_GNUC) + lzo_uint64_t r; + __asm__("bsr %1,%0" : "=r" (r) : "rm" (v) __LZO_ASM_CLOBBER_LIST_CC); + return (unsigned) r ^ 63; +#define lzo_bitops_ctlz64(v) lzo_bitops_ctlz64_func(v) +#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG == 8) && (LZO_WORDSIZE >= 8) + unsigned r; r = (unsigned) __builtin_clzl(v); return r; +#define lzo_bitops_ctlz64(v) ((unsigned) __builtin_clzl(v)) +#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG_LONG == 8) && (LZO_WORDSIZE >= 8) + unsigned r; r = (unsigned) __builtin_clzll(v); return r; +#define lzo_bitops_ctlz64(v) ((unsigned) __builtin_clzll(v)) +#else + LZO_UNUSED(v); return 0; +#endif +} +#endif + +__lzo_static_forceinline unsigned lzo_bitops_cttz32_func(lzo_uint32_t v) +{ +#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) + unsigned long r; (void) _BitScanForward(&r, v); return (unsigned) r; +#define lzo_bitops_cttz32(v) lzo_bitops_cttz32_func(v) +#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) && (LZO_ASM_SYNTAX_GNUC) + lzo_uint32_t r; + __asm__("bsf %1,%0" : "=r" (r) : "rm" (v) __LZO_ASM_CLOBBER_LIST_CC); + return (unsigned) r; +#define lzo_bitops_cttz32(v) lzo_bitops_cttz32_func(v) +#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_INT >= 4) + unsigned r; r = (unsigned) __builtin_ctz(v); return r; +#define lzo_bitops_cttz32(v) ((unsigned) __builtin_ctz(v)) +#else + LZO_UNUSED(v); return 0; +#endif +} + +#if defined(lzo_uint64_t) +__lzo_static_forceinline unsigned lzo_bitops_cttz64_func(lzo_uint64_t v) +{ +#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64) + unsigned long r; (void) _BitScanForward64(&r, v); return (unsigned) r; +#define lzo_bitops_cttz64(v) lzo_bitops_cttz64_func(v) +#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64) && (LZO_ASM_SYNTAX_GNUC) + lzo_uint64_t r; + __asm__("bsf %1,%0" : "=r" (r) : "rm" (v) __LZO_ASM_CLOBBER_LIST_CC); + return (unsigned) r; +#define lzo_bitops_cttz64(v) lzo_bitops_cttz64_func(v) +#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG >= 8) && (LZO_WORDSIZE >= 8) + unsigned r; r = (unsigned) __builtin_ctzl(v); return r; +#define lzo_bitops_cttz64(v) ((unsigned) __builtin_ctzl(v)) +#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG_LONG >= 8) && (LZO_WORDSIZE >= 8) + unsigned r; r = (unsigned) __builtin_ctzll(v); return r; +#define lzo_bitops_cttz64(v) ((unsigned) __builtin_ctzll(v)) +#else + LZO_UNUSED(v); return 0; +#endif +} +#endif + +lzo_unused_funcs_impl(void, lzo_bitops_unused_funcs)(void) +{ + LZO_UNUSED_FUNC(lzo_bitops_unused_funcs); + LZO_UNUSED_FUNC(lzo_bitops_ctlz32_func); + LZO_UNUSED_FUNC(lzo_bitops_cttz32_func); +#if defined(lzo_uint64_t) + LZO_UNUSED_FUNC(lzo_bitops_ctlz64_func); + LZO_UNUSED_FUNC(lzo_bitops_cttz64_func); +#endif +} + +#if defined(__lzo_alignof) && !(LZO_CFG_NO_UNALIGNED) +#if !defined(lzo_memops_tcheck__) && 0 +#define lzo_memops_tcheck__(t,a,b) ((void)0, sizeof(t) == (a) && __lzo_alignof(t) == (b)) +#endif +#endif +#ifndef lzo_memops_TU0p +#define lzo_memops_TU0p void __LZO_MMODEL * +#endif +#ifndef lzo_memops_TU1p +#define lzo_memops_TU1p unsigned char __LZO_MMODEL * +#endif +#ifndef lzo_memops_TU2p +#if (LZO_OPT_UNALIGNED16) +typedef lzo_uint16_t __lzo_may_alias lzo_memops_TU2; +#define lzo_memops_TU2p volatile lzo_memops_TU2 * +#elif defined(__lzo_byte_struct) +__lzo_byte_struct(lzo_memops_TU2_struct,2) +typedef struct lzo_memops_TU2_struct lzo_memops_TU2; +#else +struct lzo_memops_TU2_struct { unsigned char a[2]; } __lzo_may_alias; +typedef struct lzo_memops_TU2_struct lzo_memops_TU2; +#endif +#ifndef lzo_memops_TU2p +#define lzo_memops_TU2p lzo_memops_TU2 * +#endif +#endif +#ifndef lzo_memops_TU4p +#if (LZO_OPT_UNALIGNED32) +typedef lzo_uint32_t __lzo_may_alias lzo_memops_TU4; +#define lzo_memops_TU4p volatile lzo_memops_TU4 __LZO_MMODEL * +#elif defined(__lzo_byte_struct) +__lzo_byte_struct(lzo_memops_TU4_struct,4) +typedef struct lzo_memops_TU4_struct lzo_memops_TU4; +#else +struct lzo_memops_TU4_struct { unsigned char a[4]; } __lzo_may_alias; +typedef struct lzo_memops_TU4_struct lzo_memops_TU4; +#endif +#ifndef lzo_memops_TU4p +#define lzo_memops_TU4p lzo_memops_TU4 __LZO_MMODEL * +#endif +#endif +#ifndef lzo_memops_TU8p +#if (LZO_OPT_UNALIGNED64) +typedef lzo_uint64_t __lzo_may_alias lzo_memops_TU8; +#define lzo_memops_TU8p volatile lzo_memops_TU8 __LZO_MMODEL * +#elif defined(__lzo_byte_struct) +__lzo_byte_struct(lzo_memops_TU8_struct,8) +typedef struct lzo_memops_TU8_struct lzo_memops_TU8; +#else +struct lzo_memops_TU8_struct { unsigned char a[8]; } __lzo_may_alias; +typedef struct lzo_memops_TU8_struct lzo_memops_TU8; +#endif +#ifndef lzo_memops_TU8p +#define lzo_memops_TU8p lzo_memops_TU8 __LZO_MMODEL * +#endif +#endif +#ifndef lzo_memops_set_TU1p +#define lzo_memops_set_TU1p volatile lzo_memops_TU1p +#endif +#ifndef lzo_memops_move_TU1p +#define lzo_memops_move_TU1p lzo_memops_TU1p +#endif +#define LZO_MEMOPS_SET1(dd,cc) \ + LZO_BLOCK_BEGIN \ + lzo_memops_set_TU1p d__1 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \ + d__1[0] = LZO_BYTE(cc); \ + LZO_BLOCK_END +#define LZO_MEMOPS_SET2(dd,cc) \ + LZO_BLOCK_BEGIN \ + lzo_memops_set_TU1p d__2 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \ + d__2[0] = LZO_BYTE(cc); d__2[1] = LZO_BYTE(cc); \ + LZO_BLOCK_END +#define LZO_MEMOPS_SET3(dd,cc) \ + LZO_BLOCK_BEGIN \ + lzo_memops_set_TU1p d__3 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \ + d__3[0] = LZO_BYTE(cc); d__3[1] = LZO_BYTE(cc); d__3[2] = LZO_BYTE(cc); \ + LZO_BLOCK_END +#define LZO_MEMOPS_SET4(dd,cc) \ + LZO_BLOCK_BEGIN \ + lzo_memops_set_TU1p d__4 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \ + d__4[0] = LZO_BYTE(cc); d__4[1] = LZO_BYTE(cc); d__4[2] = LZO_BYTE(cc); d__4[3] = LZO_BYTE(cc); \ + LZO_BLOCK_END +#define LZO_MEMOPS_MOVE1(dd,ss) \ + LZO_BLOCK_BEGIN \ + lzo_memops_move_TU1p d__1 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \ + const lzo_memops_move_TU1p s__1 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \ + d__1[0] = s__1[0]; \ + LZO_BLOCK_END +#define LZO_MEMOPS_MOVE2(dd,ss) \ + LZO_BLOCK_BEGIN \ + lzo_memops_move_TU1p d__2 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \ + const lzo_memops_move_TU1p s__2 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \ + d__2[0] = s__2[0]; d__2[1] = s__2[1]; \ + LZO_BLOCK_END +#define LZO_MEMOPS_MOVE3(dd,ss) \ + LZO_BLOCK_BEGIN \ + lzo_memops_move_TU1p d__3 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \ + const lzo_memops_move_TU1p s__3 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \ + d__3[0] = s__3[0]; d__3[1] = s__3[1]; d__3[2] = s__3[2]; \ + LZO_BLOCK_END +#define LZO_MEMOPS_MOVE4(dd,ss) \ + LZO_BLOCK_BEGIN \ + lzo_memops_move_TU1p d__4 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \ + const lzo_memops_move_TU1p s__4 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \ + d__4[0] = s__4[0]; d__4[1] = s__4[1]; d__4[2] = s__4[2]; d__4[3] = s__4[3]; \ + LZO_BLOCK_END +#define LZO_MEMOPS_MOVE8(dd,ss) \ + LZO_BLOCK_BEGIN \ + lzo_memops_move_TU1p d__8 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \ + const lzo_memops_move_TU1p s__8 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \ + d__8[0] = s__8[0]; d__8[1] = s__8[1]; d__8[2] = s__8[2]; d__8[3] = s__8[3]; \ + d__8[4] = s__8[4]; d__8[5] = s__8[5]; d__8[6] = s__8[6]; d__8[7] = s__8[7]; \ + LZO_BLOCK_END +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU1p)0)==1) +#define LZO_MEMOPS_COPY1(dd,ss) LZO_MEMOPS_MOVE1(dd,ss) +#if (LZO_OPT_UNALIGNED16) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2) +#define LZO_MEMOPS_COPY2(dd,ss) \ + * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss) +#elif defined(lzo_memops_tcheck__) +#define LZO_MEMOPS_COPY2(dd,ss) \ + LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU2,2,1)) { \ + * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss); \ + } else { LZO_MEMOPS_MOVE2(dd,ss); } LZO_BLOCK_END +#else +#define LZO_MEMOPS_COPY2(dd,ss) LZO_MEMOPS_MOVE2(dd,ss) +#endif +#if (LZO_OPT_UNALIGNED32) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4) +#define LZO_MEMOPS_COPY4(dd,ss) \ + * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss) +#elif defined(lzo_memops_tcheck__) +#define LZO_MEMOPS_COPY4(dd,ss) \ + LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU4,4,1)) { \ + * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss); \ + } else { LZO_MEMOPS_MOVE4(dd,ss); } LZO_BLOCK_END +#else +#define LZO_MEMOPS_COPY4(dd,ss) LZO_MEMOPS_MOVE4(dd,ss) +#endif +#if (LZO_WORDSIZE != 8) +#define LZO_MEMOPS_COPY8(dd,ss) \ + LZO_BLOCK_BEGIN LZO_MEMOPS_COPY4(dd,ss); LZO_MEMOPS_COPY4((lzo_memops_TU1p)(lzo_memops_TU0p)(dd)+4,(const lzo_memops_TU1p)(const lzo_memops_TU0p)(ss)+4); LZO_BLOCK_END +#else +#if (LZO_OPT_UNALIGNED64) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU8p)0)==8) +#define LZO_MEMOPS_COPY8(dd,ss) \ + * (lzo_memops_TU8p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss) +#elif (LZO_OPT_UNALIGNED32) +#define LZO_MEMOPS_COPY8(dd,ss) \ + LZO_BLOCK_BEGIN LZO_MEMOPS_COPY4(dd,ss); LZO_MEMOPS_COPY4((lzo_memops_TU1p)(lzo_memops_TU0p)(dd)+4,(const lzo_memops_TU1p)(const lzo_memops_TU0p)(ss)+4); LZO_BLOCK_END +#elif defined(lzo_memops_tcheck__) +#define LZO_MEMOPS_COPY8(dd,ss) \ + LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU8,8,1)) { \ + * (lzo_memops_TU8p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss); \ + } else { LZO_MEMOPS_MOVE8(dd,ss); } LZO_BLOCK_END +#else +#define LZO_MEMOPS_COPY8(dd,ss) LZO_MEMOPS_MOVE8(dd,ss) +#endif +#endif +#define LZO_MEMOPS_COPYN(dd,ss,nn) \ + LZO_BLOCK_BEGIN \ + lzo_memops_TU1p d__n = (lzo_memops_TU1p) (lzo_memops_TU0p) (dd); \ + const lzo_memops_TU1p s__n = (const lzo_memops_TU1p) (const lzo_memops_TU0p) (ss); \ + lzo_uint n__n = (nn); \ + while ((void)0, n__n >= 8) { LZO_MEMOPS_COPY8(d__n, s__n); d__n += 8; s__n += 8; n__n -= 8; } \ + if ((void)0, n__n >= 4) { LZO_MEMOPS_COPY4(d__n, s__n); d__n += 4; s__n += 4; n__n -= 4; } \ + if ((void)0, n__n > 0) do { *d__n++ = *s__n++; } while (--n__n > 0); \ + LZO_BLOCK_END + +__lzo_static_forceinline lzo_uint16_t lzo_memops_get_le16(const lzo_voidp ss) +{ + lzo_uint16_t v; +#if (LZO_ABI_LITTLE_ENDIAN) + LZO_MEMOPS_COPY2(&v, ss); +#elif (LZO_OPT_UNALIGNED16 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC) + const lzo_memops_TU2p s = (const lzo_memops_TU2p) ss; + unsigned long vv; + __asm__("lhbrx %0,0,%1" : "=r" (vv) : "r" (s), "m" (*s)); + v = (lzo_uint16_t) vv; +#else + const lzo_memops_TU1p s = (const lzo_memops_TU1p) ss; + v = (lzo_uint16_t) (((lzo_uint16_t)s[0]) | ((lzo_uint16_t)s[1] << 8)); +#endif + return v; +} +#if (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN) +#define LZO_MEMOPS_GET_LE16(ss) (* (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)) +#else +#define LZO_MEMOPS_GET_LE16(ss) lzo_memops_get_le16(ss) +#endif + +__lzo_static_forceinline lzo_uint32_t lzo_memops_get_le32(const lzo_voidp ss) +{ + lzo_uint32_t v; +#if (LZO_ABI_LITTLE_ENDIAN) + LZO_MEMOPS_COPY4(&v, ss); +#elif (LZO_OPT_UNALIGNED32 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC) + const lzo_memops_TU4p s = (const lzo_memops_TU4p) ss; + unsigned long vv; + __asm__("lwbrx %0,0,%1" : "=r" (vv) : "r" (s), "m" (*s)); + v = (lzo_uint32_t) vv; +#else + const lzo_memops_TU1p s = (const lzo_memops_TU1p) ss; + v = (lzo_uint32_t) (((lzo_uint32_t)s[0]) | ((lzo_uint32_t)s[1] << 8) | ((lzo_uint32_t)s[2] << 16) | ((lzo_uint32_t)s[3] << 24)); +#endif + return v; +} +#if (LZO_OPT_UNALIGNED32) && (LZO_ABI_LITTLE_ENDIAN) +#define LZO_MEMOPS_GET_LE32(ss) (* (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)) +#else +#define LZO_MEMOPS_GET_LE32(ss) lzo_memops_get_le32(ss) +#endif + +#if (LZO_OPT_UNALIGNED64) && (LZO_ABI_LITTLE_ENDIAN) +#define LZO_MEMOPS_GET_LE64(ss) (* (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)) +#endif + +__lzo_static_forceinline lzo_uint16_t lzo_memops_get_ne16(const lzo_voidp ss) +{ + lzo_uint16_t v; + LZO_MEMOPS_COPY2(&v, ss); + return v; +} +#if (LZO_OPT_UNALIGNED16) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2) +#define LZO_MEMOPS_GET_NE16(ss) (* (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)) +#else +#define LZO_MEMOPS_GET_NE16(ss) lzo_memops_get_ne16(ss) +#endif + +__lzo_static_forceinline lzo_uint32_t lzo_memops_get_ne32(const lzo_voidp ss) +{ + lzo_uint32_t v; + LZO_MEMOPS_COPY4(&v, ss); + return v; +} +#if (LZO_OPT_UNALIGNED32) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4) +#define LZO_MEMOPS_GET_NE32(ss) (* (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)) +#else +#define LZO_MEMOPS_GET_NE32(ss) lzo_memops_get_ne32(ss) +#endif + +#if (LZO_OPT_UNALIGNED64) +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU8p)0)==8) +#define LZO_MEMOPS_GET_NE64(ss) (* (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)) +#endif + +__lzo_static_forceinline void lzo_memops_put_le16(lzo_voidp dd, lzo_uint16_t vv) +{ +#if (LZO_ABI_LITTLE_ENDIAN) + LZO_MEMOPS_COPY2(dd, &vv); +#elif (LZO_OPT_UNALIGNED16 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC) + lzo_memops_TU2p d = (lzo_memops_TU2p) dd; + unsigned long v = vv; + __asm__("sthbrx %2,0,%1" : "=m" (*d) : "r" (d), "r" (v)); +#else + lzo_memops_TU1p d = (lzo_memops_TU1p) dd; + d[0] = LZO_BYTE((vv ) & 0xff); + d[1] = LZO_BYTE((vv >> 8) & 0xff); +#endif +} +#if (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN) +#define LZO_MEMOPS_PUT_LE16(dd,vv) (* (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = (vv)) +#else +#define LZO_MEMOPS_PUT_LE16(dd,vv) lzo_memops_put_le16(dd,vv) +#endif + +__lzo_static_forceinline void lzo_memops_put_le32(lzo_voidp dd, lzo_uint32_t vv) +{ +#if (LZO_ABI_LITTLE_ENDIAN) + LZO_MEMOPS_COPY4(dd, &vv); +#elif (LZO_OPT_UNALIGNED32 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC) + lzo_memops_TU4p d = (lzo_memops_TU4p) dd; + unsigned long v = vv; + __asm__("stwbrx %2,0,%1" : "=m" (*d) : "r" (d), "r" (v)); +#else + lzo_memops_TU1p d = (lzo_memops_TU1p) dd; + d[0] = LZO_BYTE((vv ) & 0xff); + d[1] = LZO_BYTE((vv >> 8) & 0xff); + d[2] = LZO_BYTE((vv >> 16) & 0xff); + d[3] = LZO_BYTE((vv >> 24) & 0xff); +#endif +} +#if (LZO_OPT_UNALIGNED32) && (LZO_ABI_LITTLE_ENDIAN) +#define LZO_MEMOPS_PUT_LE32(dd,vv) (* (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = (vv)) +#else +#define LZO_MEMOPS_PUT_LE32(dd,vv) lzo_memops_put_le32(dd,vv) +#endif + +__lzo_static_forceinline void lzo_memops_put_ne16(lzo_voidp dd, lzo_uint16_t vv) +{ + LZO_MEMOPS_COPY2(dd, &vv); +} +#if (LZO_OPT_UNALIGNED16) +#define LZO_MEMOPS_PUT_NE16(dd,vv) (* (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = (vv)) +#else +#define LZO_MEMOPS_PUT_NE16(dd,vv) lzo_memops_put_ne16(dd,vv) +#endif + +__lzo_static_forceinline void lzo_memops_put_ne32(lzo_voidp dd, lzo_uint32_t vv) +{ + LZO_MEMOPS_COPY4(dd, &vv); +} +#if (LZO_OPT_UNALIGNED32) +#define LZO_MEMOPS_PUT_NE32(dd,vv) (* (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = (vv)) +#else +#define LZO_MEMOPS_PUT_NE32(dd,vv) lzo_memops_put_ne32(dd,vv) +#endif + +lzo_unused_funcs_impl(void, lzo_memops_unused_funcs)(void) +{ + LZO_UNUSED_FUNC(lzo_memops_unused_funcs); + LZO_UNUSED_FUNC(lzo_memops_get_le16); + LZO_UNUSED_FUNC(lzo_memops_get_le32); + LZO_UNUSED_FUNC(lzo_memops_get_ne16); + LZO_UNUSED_FUNC(lzo_memops_get_ne32); + LZO_UNUSED_FUNC(lzo_memops_put_le16); + LZO_UNUSED_FUNC(lzo_memops_put_le32); + LZO_UNUSED_FUNC(lzo_memops_put_ne16); + LZO_UNUSED_FUNC(lzo_memops_put_ne32); +} + +#endif + +#ifndef UA_SET1 +#define UA_SET1 LZO_MEMOPS_SET1 +#endif +#ifndef UA_SET2 +#define UA_SET2 LZO_MEMOPS_SET2 +#endif +#ifndef UA_SET3 +#define UA_SET3 LZO_MEMOPS_SET3 +#endif +#ifndef UA_SET4 +#define UA_SET4 LZO_MEMOPS_SET4 +#endif +#ifndef UA_MOVE1 +#define UA_MOVE1 LZO_MEMOPS_MOVE1 +#endif +#ifndef UA_MOVE2 +#define UA_MOVE2 LZO_MEMOPS_MOVE2 +#endif +#ifndef UA_MOVE3 +#define UA_MOVE3 LZO_MEMOPS_MOVE3 +#endif +#ifndef UA_MOVE4 +#define UA_MOVE4 LZO_MEMOPS_MOVE4 +#endif +#ifndef UA_MOVE8 +#define UA_MOVE8 LZO_MEMOPS_MOVE8 +#endif +#ifndef UA_COPY1 +#define UA_COPY1 LZO_MEMOPS_COPY1 +#endif +#ifndef UA_COPY2 +#define UA_COPY2 LZO_MEMOPS_COPY2 +#endif +#ifndef UA_COPY3 +#define UA_COPY3 LZO_MEMOPS_COPY3 +#endif +#ifndef UA_COPY4 +#define UA_COPY4 LZO_MEMOPS_COPY4 +#endif +#ifndef UA_COPY8 +#define UA_COPY8 LZO_MEMOPS_COPY8 +#endif +#ifndef UA_COPYN +#define UA_COPYN LZO_MEMOPS_COPYN +#endif +#ifndef UA_COPYN_X +#define UA_COPYN_X LZO_MEMOPS_COPYN +#endif +#ifndef UA_GET_LE16 +#define UA_GET_LE16 LZO_MEMOPS_GET_LE16 +#endif +#ifndef UA_GET_LE32 +#define UA_GET_LE32 LZO_MEMOPS_GET_LE32 +#endif +#ifdef LZO_MEMOPS_GET_LE64 +#ifndef UA_GET_LE64 +#define UA_GET_LE64 LZO_MEMOPS_GET_LE64 +#endif +#endif +#ifndef UA_GET_NE16 +#define UA_GET_NE16 LZO_MEMOPS_GET_NE16 +#endif +#ifndef UA_GET_NE32 +#define UA_GET_NE32 LZO_MEMOPS_GET_NE32 +#endif +#ifdef LZO_MEMOPS_GET_NE64 +#ifndef UA_GET_NE64 +#define UA_GET_NE64 LZO_MEMOPS_GET_NE64 +#endif +#endif +#ifndef UA_PUT_LE16 +#define UA_PUT_LE16 LZO_MEMOPS_PUT_LE16 +#endif +#ifndef UA_PUT_LE32 +#define UA_PUT_LE32 LZO_MEMOPS_PUT_LE32 +#endif +#ifndef UA_PUT_NE16 +#define UA_PUT_NE16 LZO_MEMOPS_PUT_NE16 +#endif +#ifndef UA_PUT_NE32 +#define UA_PUT_NE32 LZO_MEMOPS_PUT_NE32 +#endif + +#define MEMCPY8_DS(dest,src,len) \ + lzo_memcpy(dest,src,len); dest += len; src += len + +#define BZERO8_PTR(s,l,n) \ + lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n)) + +#define MEMCPY_DS(dest,src,len) \ + do *dest++ = *src++; while (--len > 0) + +LZO_EXTERN(const lzo_bytep) lzo_copyright(void); + +#ifndef __LZO_PTR_H +#define __LZO_PTR_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if (LZO_ARCH_I086) +#error "LZO_ARCH_I086 is unsupported" +#elif (LZO_MM_PVP) +#error "LZO_MM_PVP is unsupported" +#else +#define PTR(a) ((lzo_uintptr_t) (a)) +#define PTR_LINEAR(a) PTR(a) +#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0) +#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0) +#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0) +#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0) +#endif + +#define PTR_LT(a,b) (PTR(a) < PTR(b)) +#define PTR_GE(a,b) (PTR(a) >= PTR(b)) +#define PTR_DIFF(a,b) (PTR(a) - PTR(b)) +#define pd(a,b) ((lzo_uint) ((a)-(b))) + +LZO_EXTERN(lzo_uintptr_t) +__lzo_ptr_linear(const lzo_voidp ptr); + +typedef union +{ + char a_char; + unsigned char a_uchar; + short a_short; + unsigned short a_ushort; + int a_int; + unsigned int a_uint; + long a_long; + unsigned long a_ulong; + lzo_int a_lzo_int; + lzo_uint a_lzo_uint; + lzo_xint a_lzo_xint; + lzo_int16_t a_lzo_int16_t; + lzo_uint16_t a_lzo_uint16_t; + lzo_int32_t a_lzo_int32_t; + lzo_uint32_t a_lzo_uint32_t; +#if defined(lzo_uint64_t) + lzo_int64_t a_lzo_int64_t; + lzo_uint64_t a_lzo_uint64_t; +#endif + size_t a_size_t; + ptrdiff_t a_ptrdiff_t; + lzo_uintptr_t a_lzo_uintptr_t; + void * a_void_p; + char * a_char_p; + unsigned char * a_uchar_p; + const void * a_c_void_p; + const char * a_c_char_p; + const unsigned char * a_c_uchar_p; + lzo_voidp a_lzo_voidp; + lzo_bytep a_lzo_bytep; + const lzo_voidp a_c_lzo_voidp; + const lzo_bytep a_c_lzo_bytep; +} +lzo_full_align_t; + +#ifdef __cplusplus +} +#endif + +#endif + +#ifndef LZO_DETERMINISTIC +#define LZO_DETERMINISTIC 1 +#endif + +#ifndef LZO_DICT_USE_PTR +#define LZO_DICT_USE_PTR 1 +#endif + +#if (LZO_DICT_USE_PTR) +# define lzo_dict_t const lzo_bytep +# define lzo_dict_p lzo_dict_t * +#else +# define lzo_dict_t lzo_uint +# define lzo_dict_p lzo_dict_t * +#endif + +#endif + +#if !defined(MINILZO_CFG_SKIP_LZO_PTR) + +LZO_PUBLIC(lzo_uintptr_t) +__lzo_ptr_linear(const lzo_voidp ptr) +{ + lzo_uintptr_t p; + +#if (LZO_ARCH_I086) +#error "LZO_ARCH_I086 is unsupported" +#elif (LZO_MM_PVP) +#error "LZO_MM_PVP is unsupported" +#else + p = (lzo_uintptr_t) PTR_LINEAR(ptr); +#endif + + return p; +} + +LZO_PUBLIC(unsigned) +__lzo_align_gap(const lzo_voidp ptr, lzo_uint size) +{ +#if (__LZO_UINTPTR_T_IS_POINTER) +#error "__LZO_UINTPTR_T_IS_POINTER is unsupported" +#else + lzo_uintptr_t p, n; + if (size < 2) return 0; + p = __lzo_ptr_linear(ptr); +#if 0 + n = (((p + size - 1) / size) * size) - p; +#else + if ((size & (size - 1)) != 0) + return 0; + n = size; n = ((p + n - 1) & ~(n - 1)) - p; +#endif +#endif + assert((long)n >= 0); + assert(n <= size); + return (unsigned)n; +} + +#endif +#if !defined(MINILZO_CFG_SKIP_LZO_UTIL) + +/* If you use the LZO library in a product, I would appreciate that you + * keep this copyright string in the executable of your product. + */ + +static const char lzo_copyright_[] = +#if !defined(__LZO_IN_MINLZO) + LZO_VERSION_STRING; +#else + "\r\n\n" + "LZO data compression library.\n" + "$Copyright: LZO Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer\n" + "\n" + "http://www.oberhumer.com $\n\n" + "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n" + "$Info: " LZO_INFO_STRING " $\n"; +#endif +static const char lzo_version_string_[] = LZO_VERSION_STRING; +static const char lzo_version_date_[] = LZO_VERSION_DATE; + +LZO_PUBLIC(const lzo_bytep) +lzo_copyright(void) +{ + return (const lzo_bytep) lzo_copyright_; +} + +LZO_PUBLIC(unsigned) +lzo_version(void) +{ + return LZO_VERSION; +} + +LZO_PUBLIC(const char *) +lzo_version_string(void) +{ + return lzo_version_string_; +} + +LZO_PUBLIC(const char *) +lzo_version_date(void) +{ + return lzo_version_date_; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_string(void) +{ + return lzo_version_string_; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_date(void) +{ + return lzo_version_date_; +} + +#define LZO_BASE 65521u +#define LZO_NMAX 5552 + +#define LZO_DO1(buf,i) s1 += buf[i]; s2 += s1 +#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1) +#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2) +#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4) +#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8) + +LZO_PUBLIC(lzo_uint32_t) +lzo_adler32(lzo_uint32_t adler, const lzo_bytep buf, lzo_uint len) +{ + lzo_uint32_t s1 = adler & 0xffff; + lzo_uint32_t s2 = (adler >> 16) & 0xffff; + unsigned k; + + if (buf == NULL) + return 1; + + while (len > 0) + { + k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX; + len -= k; + if (k >= 16) do + { + LZO_DO16(buf,0); + buf += 16; + k -= 16; + } while (k >= 16); + if (k != 0) do + { + s1 += *buf++; + s2 += s1; + } while (--k > 0); + s1 %= LZO_BASE; + s2 %= LZO_BASE; + } + return (s2 << 16) | s1; +} + +#undef LZO_DO1 +#undef LZO_DO2 +#undef LZO_DO4 +#undef LZO_DO8 +#undef LZO_DO16 + +#endif +#if !defined(MINILZO_CFG_SKIP_LZO_STRING) +#undef lzo_memcmp +#undef lzo_memcpy +#undef lzo_memmove +#undef lzo_memset +#if !defined(__LZO_MMODEL_HUGE) +# undef LZO_HAVE_MM_HUGE_PTR +#endif +#define lzo_hsize_t lzo_uint +#define lzo_hvoid_p lzo_voidp +#define lzo_hbyte_p lzo_bytep +#define LZOLIB_PUBLIC(r,f) LZO_PUBLIC(r) f +#define lzo_hmemcmp lzo_memcmp +#define lzo_hmemcpy lzo_memcpy +#define lzo_hmemmove lzo_memmove +#define lzo_hmemset lzo_memset +#define __LZOLIB_HMEMCPY_CH_INCLUDED 1 +#if !defined(LZOLIB_PUBLIC) +# define LZOLIB_PUBLIC(r,f) r __LZOLIB_FUNCNAME(f) +#endif +LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP) + const lzo_hbyte_p p1 = LZO_STATIC_CAST(const lzo_hbyte_p, s1); + const lzo_hbyte_p p2 = LZO_STATIC_CAST(const lzo_hbyte_p, s2); + if __lzo_likely(len > 0) do + { + int d = *p1 - *p2; + if (d != 0) + return d; + p1++; p2++; + } while __lzo_likely(--len > 0); + return 0; +#else + return memcmp(s1, s2, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY) + lzo_hbyte_p p1 = LZO_STATIC_CAST(lzo_hbyte_p, dest); + const lzo_hbyte_p p2 = LZO_STATIC_CAST(const lzo_hbyte_p, src); + if (!(len > 0) || p1 == p2) + return dest; + do + *p1++ = *p2++; + while __lzo_likely(--len > 0); + return dest; +#else + return memcpy(dest, src, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE) + lzo_hbyte_p p1 = LZO_STATIC_CAST(lzo_hbyte_p, dest); + const lzo_hbyte_p p2 = LZO_STATIC_CAST(const lzo_hbyte_p, src); + if (!(len > 0) || p1 == p2) + return dest; + if (p1 < p2) + { + do + *p1++ = *p2++; + while __lzo_likely(--len > 0); + } + else + { + p1 += len; + p2 += len; + do + *--p1 = *--p2; + while __lzo_likely(--len > 0); + } + return dest; +#else + return memmove(dest, src, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int cc, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET) + lzo_hbyte_p p = LZO_STATIC_CAST(lzo_hbyte_p, s); + unsigned char c = LZO_ITRUNC(unsigned char, cc); + if __lzo_likely(len > 0) do + *p++ = c; + while __lzo_likely(--len > 0); + return s; +#else + return memset(s, cc, len); +#endif +} +#undef LZOLIB_PUBLIC +#endif +#if !defined(MINILZO_CFG_SKIP_LZO_INIT) + +#if !defined(__LZO_IN_MINILZO) + +#define LZO_WANT_ACC_CHK_CH 1 +#undef LZOCHK_ASSERT + + LZOCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0) + LZOCHK_ASSERT_IS_SIGNED_T(lzo_int) + LZOCHK_ASSERT_IS_UNSIGNED_T(lzo_uint) +#if !(__LZO_UINTPTR_T_IS_POINTER) + LZOCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t) +#endif + LZOCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) + LZOCHK_ASSERT_IS_UNSIGNED_T(lzo_xint) + +#endif +#undef LZOCHK_ASSERT + +union lzo_config_check_union { + lzo_uint a[2]; + unsigned char b[2*LZO_MAX(8,sizeof(lzo_uint))]; +#if defined(lzo_uint64_t) + lzo_uint64_t c[2]; +#endif +}; + +#if 0 +#define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off))) +#else +static __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off) +{ + return (lzo_voidp) ((lzo_bytep) ptr + off); +} +#endif + +LZO_PUBLIC(int) +_lzo_config_check(void) +{ +#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030100ul && LZO_CC_CLANG < 0x030300ul)) +# if 0 + volatile +# endif +#endif + union lzo_config_check_union u; + lzo_voidp p; + unsigned r = 1; + + u.a[0] = u.a[1] = 0; + p = u2p(&u, 0); + r &= ((* (lzo_bytep) p) == 0); +#if !(LZO_CFG_NO_CONFIG_CHECK) +#if (LZO_ABI_BIG_ENDIAN) + u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128; + p = u2p(&u, 0); + r &= ((* (lzo_uintp) p) == 128); +#endif +#if (LZO_ABI_LITTLE_ENDIAN) + u.a[0] = u.a[1] = 0; u.b[0] = 128; + p = u2p(&u, 0); + r &= ((* (lzo_uintp) p) == 128); +#endif + u.a[0] = u.a[1] = 0; + u.b[0] = 1; u.b[3] = 2; + p = u2p(&u, 1); + r &= UA_GET_NE16(p) == 0; + r &= UA_GET_LE16(p) == 0; + u.b[1] = 128; + r &= UA_GET_LE16(p) == 128; + u.b[2] = 129; + r &= UA_GET_LE16(p) == LZO_UINT16_C(0x8180); +#if (LZO_ABI_BIG_ENDIAN) + r &= UA_GET_NE16(p) == LZO_UINT16_C(0x8081); +#endif +#if (LZO_ABI_LITTLE_ENDIAN) + r &= UA_GET_NE16(p) == LZO_UINT16_C(0x8180); +#endif + u.a[0] = u.a[1] = 0; + u.b[0] = 3; u.b[5] = 4; + p = u2p(&u, 1); + r &= UA_GET_NE32(p) == 0; + r &= UA_GET_LE32(p) == 0; + u.b[1] = 128; + r &= UA_GET_LE32(p) == 128; + u.b[2] = 129; u.b[3] = 130; u.b[4] = 131; + r &= UA_GET_LE32(p) == LZO_UINT32_C(0x83828180); +#if (LZO_ABI_BIG_ENDIAN) + r &= UA_GET_NE32(p) == LZO_UINT32_C(0x80818283); +#endif +#if (LZO_ABI_LITTLE_ENDIAN) + r &= UA_GET_NE32(p) == LZO_UINT32_C(0x83828180); +#endif +#if defined(UA_GET_NE64) + u.c[0] = u.c[1] = 0; + u.b[0] = 5; u.b[9] = 6; + p = u2p(&u, 1); + u.c[0] = u.c[1] = 0; + r &= UA_GET_NE64(p) == 0; +#if defined(UA_GET_LE64) + r &= UA_GET_LE64(p) == 0; + u.b[1] = 128; + r &= UA_GET_LE64(p) == 128; +#endif +#endif +#if defined(lzo_bitops_ctlz32) + { unsigned i = 0; lzo_uint32_t v; + for (v = 1; v != 0 && r == 1; v <<= 1, i++) { + r &= lzo_bitops_ctlz32(v) == 31 - i; + r &= lzo_bitops_ctlz32_func(v) == 31 - i; + }} +#endif +#if defined(lzo_bitops_ctlz64) + { unsigned i = 0; lzo_uint64_t v; + for (v = 1; v != 0 && r == 1; v <<= 1, i++) { + r &= lzo_bitops_ctlz64(v) == 63 - i; + r &= lzo_bitops_ctlz64_func(v) == 63 - i; + }} +#endif +#if defined(lzo_bitops_cttz32) + { unsigned i = 0; lzo_uint32_t v; + for (v = 1; v != 0 && r == 1; v <<= 1, i++) { + r &= lzo_bitops_cttz32(v) == i; + r &= lzo_bitops_cttz32_func(v) == i; + }} +#endif +#if defined(lzo_bitops_cttz64) + { unsigned i = 0; lzo_uint64_t v; + for (v = 1; v != 0 && r == 1; v <<= 1, i++) { + r &= lzo_bitops_cttz64(v) == i; + r &= lzo_bitops_cttz64_func(v) == i; + }} +#endif +#endif + LZO_UNUSED_FUNC(lzo_bitops_unused_funcs); + + return r == 1 ? LZO_E_OK : LZO_E_ERROR; +} + +LZO_PUBLIC(int) +__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5, + int s6, int s7, int s8, int s9) +{ + int r; + +#if defined(__LZO_IN_MINILZO) +#elif (LZO_CC_MSC && ((_MSC_VER) < 700)) +#else +#define LZO_WANT_ACC_CHK_CH 1 +#undef LZOCHK_ASSERT +#define LZOCHK_ASSERT(expr) LZO_COMPILE_TIME_ASSERT(expr) +#endif +#undef LZOCHK_ASSERT + + if (v == 0) + return LZO_E_ERROR; + + r = (s1 == -1 || s1 == (int) sizeof(short)) && + (s2 == -1 || s2 == (int) sizeof(int)) && + (s3 == -1 || s3 == (int) sizeof(long)) && + (s4 == -1 || s4 == (int) sizeof(lzo_uint32_t)) && + (s5 == -1 || s5 == (int) sizeof(lzo_uint)) && + (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) && + (s7 == -1 || s7 == (int) sizeof(char *)) && + (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) && + (s9 == -1 || s9 == (int) sizeof(lzo_callback_t)); + if (!r) + return LZO_E_ERROR; + + r = _lzo_config_check(); + if (r != LZO_E_OK) + return r; + + return r; +} + +#if !defined(__LZO_IN_MINILZO) + +#if (LZO_OS_WIN16 && LZO_CC_WATCOMC) && defined(__SW_BD) + +#if 0 +BOOL FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSegment, + WORD wHeapSize, LPSTR lpszCmdLine ) +#else +int __far __pascal LibMain ( int a, short b, short c, long d ) +#endif +{ + LZO_UNUSED(a); LZO_UNUSED(b); LZO_UNUSED(c); LZO_UNUSED(d); + return 1; +} + +#endif + +#endif + +#endif + +#define LZO1X 1 +#define LZO_EOF_CODE 1 +#define M2_MAX_OFFSET 0x0800 + +#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS) + +#if 1 && defined(UA_GET_LE32) +#undef LZO_DICT_USE_PTR +#define LZO_DICT_USE_PTR 0 +#undef lzo_dict_t +#define lzo_dict_t lzo_uint16_t +#endif + +#define LZO_NEED_DICT_H 1 +#ifndef D_BITS +#define D_BITS 14 +#endif +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) +#if 1 +#define DINDEX(dv,p) DM(((DMUL(0x1824429d,dv)) >> (32-D_BITS))) +#else +#define DINDEX(dv,p) DM((dv) + ((dv) >> (32-D_BITS))) +#endif + +#ifndef __LZO_CONFIG1X_H +#define __LZO_CONFIG1X_H 1 + +#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z) +# define LZO1X 1 +#endif + +#if !defined(__LZO_IN_MINILZO) +#include +#endif + +#ifndef LZO_EOF_CODE +#define LZO_EOF_CODE 1 +#endif +#undef LZO_DETERMINISTIC + +#define M1_MAX_OFFSET 0x0400 +#ifndef M2_MAX_OFFSET +#define M2_MAX_OFFSET 0x0800 +#endif +#define M3_MAX_OFFSET 0x4000 +#define M4_MAX_OFFSET 0xbfff + +#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) + +#define M1_MIN_LEN 2 +#define M1_MAX_LEN 2 +#define M2_MIN_LEN 3 +#ifndef M2_MAX_LEN +#define M2_MAX_LEN 8 +#endif +#define M3_MIN_LEN 3 +#define M3_MAX_LEN 33 +#define M4_MIN_LEN 3 +#define M4_MAX_LEN 9 + +#define M1_MARKER 0 +#define M2_MARKER 64 +#define M3_MARKER 32 +#define M4_MARKER 16 + +#ifndef MIN_LOOKAHEAD +#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) +#endif + +#if defined(LZO_NEED_DICT_H) + +#ifndef LZO_HASH +#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B +#endif +#define DL_MIN_LEN M2_MIN_LEN + +#ifndef __LZO_DICT_H +#define __LZO_DICT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(D_BITS) && defined(DBITS) +# define D_BITS DBITS +#endif +#if !defined(D_BITS) +# error "D_BITS is not defined" +#endif +#if (D_BITS < 16) +# define D_SIZE LZO_SIZE(D_BITS) +# define D_MASK LZO_MASK(D_BITS) +#else +# define D_SIZE LZO_USIZE(D_BITS) +# define D_MASK LZO_UMASK(D_BITS) +#endif +#define D_HIGH ((D_MASK >> 1) + 1) + +#if !defined(DD_BITS) +# define DD_BITS 0 +#endif +#define DD_SIZE LZO_SIZE(DD_BITS) +#define DD_MASK LZO_MASK(DD_BITS) + +#if !defined(DL_BITS) +# define DL_BITS (D_BITS - DD_BITS) +#endif +#if (DL_BITS < 16) +# define DL_SIZE LZO_SIZE(DL_BITS) +# define DL_MASK LZO_MASK(DL_BITS) +#else +# define DL_SIZE LZO_USIZE(DL_BITS) +# define DL_MASK LZO_UMASK(DL_BITS) +#endif + +#if (D_BITS != DL_BITS + DD_BITS) +# error "D_BITS does not match" +#endif +#if (D_BITS < 6 || D_BITS > 18) +# error "invalid D_BITS" +#endif +#if (DL_BITS < 6 || DL_BITS > 20) +# error "invalid DL_BITS" +#endif +#if (DD_BITS < 0 || DD_BITS > 6) +# error "invalid DD_BITS" +#endif + +#if !defined(DL_MIN_LEN) +# define DL_MIN_LEN 3 +#endif +#if !defined(DL_SHIFT) +# define DL_SHIFT ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN) +#endif + +#define LZO_HASH_GZIP 1 +#define LZO_HASH_GZIP_INCREMENTAL 2 +#define LZO_HASH_LZO_INCREMENTAL_A 3 +#define LZO_HASH_LZO_INCREMENTAL_B 4 + +#if !defined(LZO_HASH) +# error "choose a hashing strategy" +#endif + +#undef DM +#undef DX + +#if (DL_MIN_LEN == 3) +# define _DV2_A(p,shift1,shift2) \ + (((( (lzo_xint)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2]) +# define _DV2_B(p,shift1,shift2) \ + (((( (lzo_xint)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0]) +# define _DV3_B(p,shift1,shift2,shift3) \ + ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0]) +#elif (DL_MIN_LEN == 2) +# define _DV2_A(p,shift1,shift2) \ + (( (lzo_xint)(p[0]) << shift1) ^ p[1]) +# define _DV2_B(p,shift1,shift2) \ + (( (lzo_xint)(p[1]) << shift1) ^ p[2]) +#else +# error "invalid DL_MIN_LEN" +#endif +#define _DV_A(p,shift) _DV2_A(p,shift,shift) +#define _DV_B(p,shift) _DV2_B(p,shift,shift) +#define DA2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0]) +#define DS2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0]) +#define DX2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) +#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) +#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) +#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) +#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s))) +#define DM(v) DMS(v,0) + +#if (LZO_HASH == LZO_HASH_GZIP) +# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT)) + +#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL) +# define __LZO_HASH_INCREMENTAL 1 +# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT) +# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2]) +# define _DINDEX(dv,p) (dv) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A) +# define __LZO_HASH_INCREMENTAL 1 +# define DVAL_FIRST(dv,p) dv = _DV_A((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2]) +# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B) +# define __LZO_HASH_INCREMENTAL 1 +# define DVAL_FIRST(dv,p) dv = _DV_B((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5))) +# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#else +# error "choose a hashing strategy" +#endif + +#ifndef DINDEX +#define DINDEX(dv,p) ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS) +#endif +#if !defined(DINDEX1) && defined(D_INDEX1) +#define DINDEX1 D_INDEX1 +#endif +#if !defined(DINDEX2) && defined(D_INDEX2) +#define DINDEX2 D_INDEX2 +#endif + +#if !defined(__LZO_HASH_INCREMENTAL) +# define DVAL_FIRST(dv,p) ((void) 0) +# define DVAL_NEXT(dv,p) ((void) 0) +# define DVAL_LOOKAHEAD 0 +#endif + +#if !defined(DVAL_ASSERT) +#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG) +#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +static void __attribute__((__unused__)) +#else +static void +#endif +DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) +{ + lzo_xint df; + DVAL_FIRST(df,(p)); + assert(DINDEX(dv,p) == DINDEX(df,p)); +} +#else +# define DVAL_ASSERT(dv,p) ((void) 0) +#endif +#endif + +#if (LZO_DICT_USE_PTR) +# define DENTRY(p,in) (p) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] +#else +# define DENTRY(p,in) ((lzo_dict_t) pd(p, in)) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex] +#endif + +#if (DD_BITS == 0) + +# define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in) +# define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) +# define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in) + +#else + +# define UPDATE_D(dict,drun,dv,p,in) \ + dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_I(dict,drun,index,p,in) \ + dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_P(ptr,drun,p,in) \ + (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK + +#endif + +#if (LZO_DICT_USE_PTR) + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + (BOUNDS_CHECKING_OFF_IN_EXPR(( \ + m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \ + PTR_LT(m_pos,in) || \ + (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) == 0 || \ + m_off > max_offset ))) + +#else + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_off == 0 || \ + ((m_off = pd(ip, in) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + (pd(ip, in) <= m_off || \ + ((m_off = pd(ip, in) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#endif + +#if (LZO_DETERMINISTIC) +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET +#else +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +#endif + +#define LZO_DETERMINISTIC !(LZO_DICT_USE_PTR) + +#ifndef DO_COMPRESS +#define DO_COMPRESS lzo1x_1_compress +#endif + +#if 1 && defined(DO_COMPRESS) && !defined(do_compress) +# define do_compress LZO_PP_ECONCAT2(DO_COMPRESS,_core) +#endif + +static __lzo_noinline lzo_uint +do_compress ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_uint ti, lzo_voidp wrkmem) +{ + const lzo_bytep ip; + lzo_bytep op; + const lzo_bytep const in_end = in + in_len; + const lzo_bytep const ip_end = in + in_len - 20; + const lzo_bytep ii; + lzo_dict_p const dict = (lzo_dict_p) wrkmem; + + op = out; + ip = in; + ii = ip; + + ip += ti < 4 ? 4 - ti : 0; + for (;;) + { + const lzo_bytep m_pos; +#if !(LZO_DETERMINISTIC) + LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0); + lzo_uint m_len; + lzo_uint dindex; +next: + if __lzo_unlikely(ip >= ip_end) + break; + DINDEX1(dindex,ip); + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; +#if 1 + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + DINDEX2(dindex,ip); +#endif + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + goto literal; + +try_match: +#if (LZO_OPT_UNALIGNED32) + if (UA_GET_NE32(m_pos) != UA_GET_NE32(ip)) +#else + if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3]) +#endif + { +literal: + UPDATE_I(dict,0,dindex,ip,in); + ip += 1 + ((ip - ii) >> 5); + continue; + } + UPDATE_I(dict,0,dindex,ip,in); +#else + lzo_uint m_off; + lzo_uint m_len; + { + lzo_uint32_t dv; + lzo_uint dindex; +literal: + ip += 1 + ((ip - ii) >> 5); +next: + if __lzo_unlikely(ip >= ip_end) + break; + dv = UA_GET_LE32(ip); + dindex = DINDEX(dv,ip); + GINDEX(m_off,m_pos,in+dict,dindex,in); + UPDATE_I(dict,0,dindex,ip,in); + if __lzo_unlikely(dv != UA_GET_LE32(m_pos)) + goto literal; + } +#endif + + ii -= ti; ti = 0; + { + lzo_uint t = pd(ip,ii); + if (t != 0) + { + if (t <= 3) + { + op[-2] = LZO_BYTE(op[-2] | t); +#if (LZO_OPT_UNALIGNED32) + UA_COPY4(op, ii); + op += t; +#else + { do *op++ = *ii++; while (--t > 0); } +#endif + } +#if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64) + else if (t <= 16) + { + *op++ = LZO_BYTE(t - 3); + UA_COPY8(op, ii); + UA_COPY8(op+8, ii+8); + op += t; + } +#endif + else + { + if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + lzo_uint tt = t - 18; + *op++ = 0; + while __lzo_unlikely(tt > 255) + { + tt -= 255; + UA_SET1(op, 0); + op++; + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } +#if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64) + do { + UA_COPY8(op, ii); + UA_COPY8(op+8, ii+8); + op += 16; ii += 16; t -= 16; + } while (t >= 16); if (t > 0) +#endif + { do *op++ = *ii++; while (--t > 0); } + } + } + } + m_len = 4; + { +#if (LZO_OPT_UNALIGNED64) + lzo_uint64_t v; + v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len); + if __lzo_unlikely(v == 0) { + do { + m_len += 8; + v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len); + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (v == 0); + } +#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz64) + m_len += lzo_bitops_ctlz64(v) / CHAR_BIT; +#elif (LZO_ABI_BIG_ENDIAN) + if ((v >> (64 - CHAR_BIT)) == 0) do { + v <<= CHAR_BIT; + m_len += 1; + } while ((v >> (64 - CHAR_BIT)) == 0); +#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz64) + m_len += lzo_bitops_cttz64(v) / CHAR_BIT; +#elif (LZO_ABI_LITTLE_ENDIAN) + if ((v & UCHAR_MAX) == 0) do { + v >>= CHAR_BIT; + m_len += 1; + } while ((v & UCHAR_MAX) == 0); +#else + if (ip[m_len] == m_pos[m_len]) do { + m_len += 1; + } while (ip[m_len] == m_pos[m_len]); +#endif +#elif (LZO_OPT_UNALIGNED32) + lzo_uint32_t v; + v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len); + if __lzo_unlikely(v == 0) { + do { + m_len += 4; + v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len); + if (v != 0) + break; + m_len += 4; + v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len); + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (v == 0); + } +#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz32) + m_len += lzo_bitops_ctlz32(v) / CHAR_BIT; +#elif (LZO_ABI_BIG_ENDIAN) + if ((v >> (32 - CHAR_BIT)) == 0) do { + v <<= CHAR_BIT; + m_len += 1; + } while ((v >> (32 - CHAR_BIT)) == 0); +#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz32) + m_len += lzo_bitops_cttz32(v) / CHAR_BIT; +#elif (LZO_ABI_LITTLE_ENDIAN) + if ((v & UCHAR_MAX) == 0) do { + v >>= CHAR_BIT; + m_len += 1; + } while ((v & UCHAR_MAX) == 0); +#else + if (ip[m_len] == m_pos[m_len]) do { + m_len += 1; + } while (ip[m_len] == m_pos[m_len]); +#endif +#else + if __lzo_unlikely(ip[m_len] == m_pos[m_len]) { + do { + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (ip[m_len] == m_pos[m_len]); + } +#endif + } +m_len_done: + m_off = pd(ip,m_pos); + ip += m_len; + ii = ip; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) + { + m_off -= 1; +#if defined(LZO1X) + *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = LZO_BYTE(m_off >> 3); +#elif defined(LZO1Y) + *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); + *op++ = LZO_BYTE(m_off >> 2); +#endif + } + else if (m_off <= M3_MAX_OFFSET) + { + m_off -= 1; + if (m_len <= M3_MAX_LEN) + *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); + else + { + m_len -= M3_MAX_LEN; + *op++ = M3_MARKER | 0; + while __lzo_unlikely(m_len > 255) + { + m_len -= 255; + UA_SET1(op, 0); + op++; + } + *op++ = LZO_BYTE(m_len); + } + *op++ = LZO_BYTE(m_off << 2); + *op++ = LZO_BYTE(m_off >> 6); + } + else + { + m_off -= 0x4000; + if (m_len <= M4_MAX_LEN) + *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2)); + else + { + m_len -= M4_MAX_LEN; + *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8)); + while __lzo_unlikely(m_len > 255) + { + m_len -= 255; + UA_SET1(op, 0); + op++; + } + *op++ = LZO_BYTE(m_len); + } + *op++ = LZO_BYTE(m_off << 2); + *op++ = LZO_BYTE(m_off >> 6); + } + goto next; + } + + *out_len = pd(op, out); + return pd(in_end,ii-ti); +} + +LZO_PUBLIC(int) +DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +{ + const lzo_bytep ip = in; + lzo_bytep op = out; + lzo_uint l = in_len; + lzo_uint t = 0; + + while (l > 20) + { + lzo_uint ll = l; + lzo_uintptr_t ll_end; +#if 0 || (LZO_DETERMINISTIC) + ll = LZO_MIN(ll, 49152); +#endif + ll_end = (lzo_uintptr_t)ip + ll; + if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll) + break; +#if (LZO_DETERMINISTIC) + lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t)); +#endif + t = do_compress(ip,ll,op,out_len,t,wrkmem); + ip += ll; + op += *out_len; + l -= ll; + } + t += l; + + if (t > 0) + { + const lzo_bytep ii = in + in_len - t; + + if (op == out && t <= 238) + *op++ = LZO_BYTE(17 + t); + else if (t <= 3) + op[-2] = LZO_BYTE(op[-2] | t); + else if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + lzo_uint tt = t - 18; + + *op++ = 0; + while (tt > 255) + { + tt -= 255; + UA_SET1(op, 0); + op++; + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } + UA_COPYN(op, ii, t); + op += t; + } + + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = pd(op, out); + return LZO_E_OK; +} + +#endif + +#undef do_compress +#undef DO_COMPRESS +#undef LZO_HASH + +#undef LZO_TEST_OVERRUN +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress + +#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS) + +#if defined(LZO_TEST_OVERRUN) +# if !defined(LZO_TEST_OVERRUN_INPUT) +# define LZO_TEST_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_OUTPUT) +# define LZO_TEST_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define LZO_TEST_OVERRUN_LOOKBEHIND 1 +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_IP_AND_TEST_OP +#undef TEST_LB +#undef TEST_LBO +#undef NEED_IP +#undef NEED_OP +#undef TEST_IV +#undef TEST_OV +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_OVERRUN_INPUT) +# if (LZO_TEST_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# define TEST_IV(x) if ((x) > (lzo_uint)0 - (511)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_OUTPUT) +# if (LZO_TEST_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# define TEST_OV(x) if ((x) > (lzo_uint)0 - (511)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op)) goto lookbehind_overrun +# define TEST_LBO(m_pos,o) if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op-(o))) goto lookbehind_overrun +#else +# define TEST_LB(m_pos) ((void) 0) +# define TEST_LBO(m_pos,o) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP 1 +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP 1 +#else +# define TEST_OP 1 +#endif + +#if defined(HAVE_TEST_IP) && defined(HAVE_TEST_OP) +# define TEST_IP_AND_TEST_OP (TEST_IP && TEST_OP) +#elif defined(HAVE_TEST_IP) +# define TEST_IP_AND_TEST_OP TEST_IP +#elif defined(HAVE_TEST_OP) +# define TEST_IP_AND_TEST_OP TEST_OP +#else +# define TEST_IP_AND_TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP 1 +#else +# define NEED_IP(x) ((void) 0) +# define TEST_IV(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP 1 +#else +# define NEED_OP(x) ((void) 0) +# define TEST_OV(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP 1 +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP 1 +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + lzo_bytep op; + const lzo_bytep ip; + lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_bytep dict_end; +#else + const lzo_bytep m_pos; +#endif + + const lzo_bytep const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_bytep const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + NEED_IP(1); + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+3); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + for (;;) + { + NEED_IP(3); + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + while (*ip == 0) + { + t += 255; + ip++; + TEST_IV(t); + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+6); +#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32) + t += 3; + if (t >= 8) do + { + UA_COPY8(op,ip); + op += 8; ip += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY4(op,ip); + op += 4; ip += 4; t -= 4; + } + if (t > 0) + { + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } + } +#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4) +#if !(LZO_OPT_UNALIGNED32) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + UA_COPY4(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + UA_COPY4(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !(LZO_OPT_UNALIGNED32) + } + else +#endif +#endif +#if !(LZO_OPT_UNALIGNED32) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + for (;;) { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + while (*ip == 0) + { + t += 255; + ip++; + TEST_OV(t); + NEED_IP(1); + } + t += 31 + *ip++; + NEED_IP(2); + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= UA_GET_LE16(ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + while (*ip == 0) + { + t += 255; + ip++; + TEST_OV(t); + NEED_IP(1); + } + t += 7 + *ip++; + NEED_IP(2); + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN) + m_pos -= UA_GET_LE16(ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const lzo_bytep)op, m_pos); +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32) + if (op - m_pos >= 8) + { + t += (3 - 1); + if (t >= 8) do + { + UA_COPY8(op,m_pos); + op += 8; m_pos += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } + if (t > 0) + { + *op++ = m_pos[0]; + if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } + } + } + else +#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4) +#if !(LZO_OPT_UNALIGNED32) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + UA_COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + UA_COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+3); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } +#endif + t = *ip++; + } + } + +eof_found: + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +#endif + +#define LZO_TEST_OVERRUN 1 +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress_safe + +#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS_SAFE) + +#if defined(LZO_TEST_OVERRUN) +# if !defined(LZO_TEST_OVERRUN_INPUT) +# define LZO_TEST_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_OUTPUT) +# define LZO_TEST_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define LZO_TEST_OVERRUN_LOOKBEHIND 1 +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_IP_AND_TEST_OP +#undef TEST_LB +#undef TEST_LBO +#undef NEED_IP +#undef NEED_OP +#undef TEST_IV +#undef TEST_OV +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_OVERRUN_INPUT) +# if (LZO_TEST_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# define TEST_IV(x) if ((x) > (lzo_uint)0 - (511)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_OUTPUT) +# if (LZO_TEST_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# define TEST_OV(x) if ((x) > (lzo_uint)0 - (511)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op)) goto lookbehind_overrun +# define TEST_LBO(m_pos,o) if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op-(o))) goto lookbehind_overrun +#else +# define TEST_LB(m_pos) ((void) 0) +# define TEST_LBO(m_pos,o) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP 1 +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP 1 +#else +# define TEST_OP 1 +#endif + +#if defined(HAVE_TEST_IP) && defined(HAVE_TEST_OP) +# define TEST_IP_AND_TEST_OP (TEST_IP && TEST_OP) +#elif defined(HAVE_TEST_IP) +# define TEST_IP_AND_TEST_OP TEST_IP +#elif defined(HAVE_TEST_OP) +# define TEST_IP_AND_TEST_OP TEST_OP +#else +# define TEST_IP_AND_TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP 1 +#else +# define NEED_IP(x) ((void) 0) +# define TEST_IV(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP 1 +#else +# define NEED_OP(x) ((void) 0) +# define TEST_OV(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP 1 +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP 1 +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + lzo_bytep op; + const lzo_bytep ip; + lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_bytep dict_end; +#else + const lzo_bytep m_pos; +#endif + + const lzo_bytep const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_bytep const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + NEED_IP(1); + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+3); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + for (;;) + { + NEED_IP(3); + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + while (*ip == 0) + { + t += 255; + ip++; + TEST_IV(t); + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+6); +#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32) + t += 3; + if (t >= 8) do + { + UA_COPY8(op,ip); + op += 8; ip += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY4(op,ip); + op += 4; ip += 4; t -= 4; + } + if (t > 0) + { + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } + } +#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4) +#if !(LZO_OPT_UNALIGNED32) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + UA_COPY4(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + UA_COPY4(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !(LZO_OPT_UNALIGNED32) + } + else +#endif +#endif +#if !(LZO_OPT_UNALIGNED32) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + for (;;) { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + while (*ip == 0) + { + t += 255; + ip++; + TEST_OV(t); + NEED_IP(1); + } + t += 31 + *ip++; + NEED_IP(2); + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= UA_GET_LE16(ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + while (*ip == 0) + { + t += 255; + ip++; + TEST_OV(t); + NEED_IP(1); + } + t += 7 + *ip++; + NEED_IP(2); + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN) + m_pos -= UA_GET_LE16(ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const lzo_bytep)op, m_pos); +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32) + if (op - m_pos >= 8) + { + t += (3 - 1); + if (t >= 8) do + { + UA_COPY8(op,m_pos); + op += 8; m_pos += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } + if (t > 0) + { + *op++ = m_pos[0]; + if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } + } + } + else +#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4) +#if !(LZO_OPT_UNALIGNED32) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + UA_COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + UA_COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+3); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } +#endif + t = *ip++; + } + } + +eof_found: + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +#endif + +/***** End of minilzo.c *****/ diff --git a/src/n2n.c b/src/n2n.c new file mode 100644 index 0000000..f81de09 --- /dev/null +++ b/src/n2n.c @@ -0,0 +1,948 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" + +#include "sn_selection.h" + +#include "minilzo.h" + +#include + + + +/* ************************************** */ + +SOCKET open_socket (int local_port, in_addr_t address, int type /* 0 = UDP, TCP otherwise */) { + + SOCKET sock_fd; + struct sockaddr_in local_address; + int sockopt; + + if((int)(sock_fd = socket(PF_INET, ((type == 0) ? SOCK_DGRAM : SOCK_STREAM) , 0)) < 0) { + traceEvent(TRACE_ERROR, "Unable to create socket [%s][%d]\n", + strerror(errno), sock_fd); + return(-1); + } + +#ifndef WIN32 + /* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */ +#endif + + sockopt = 1; + setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt)); + + memset(&local_address, 0, sizeof(local_address)); + local_address.sin_family = AF_INET; + local_address.sin_port = htons(local_port); + local_address.sin_addr.s_addr = htonl(address); + + if(bind(sock_fd,(struct sockaddr*) &local_address, sizeof(local_address)) == -1) { + traceEvent(TRACE_ERROR, "Bind error on local port %u [%s]\n", local_port, strerror(errno)); + return(-1); + } + + return(sock_fd); +} + + +static int traceLevel = 2 /* NORMAL */; +static int useSyslog = 0, syslog_opened = 0; +static FILE *traceFile = NULL; + +int getTraceLevel () { + + return(traceLevel); +} + +void setTraceLevel (int level) { + + traceLevel = level; +} + +void setUseSyslog (int use_syslog) { + + useSyslog = use_syslog; +} + +void setTraceFile (FILE *f) { + + traceFile = f; +} + +void closeTraceFile () { + + if((traceFile != NULL) && (traceFile != stdout)) { + fclose(traceFile); + } +#ifndef WIN32 + if(useSyslog && syslog_opened) { + closelog(); + syslog_opened = 0; + } +#endif +} + +#define N2N_TRACE_DATESIZE 32 +void traceEvent (int eventTraceLevel, char* file, int line, char * format, ...) { + + va_list va_ap; + + if(traceFile == NULL) { + traceFile = stdout; + } + + if(eventTraceLevel <= traceLevel) { + char buf[1024]; + char out_buf[1280]; + char theDate[N2N_TRACE_DATESIZE]; + char *extra_msg = ""; + time_t theTime = time(NULL); + int i; + + /* We have two paths - one if we're logging, one if we aren't + * Note that the no-log case is those systems which don't support it(WIN32), + * those without the headers !defined(USE_SYSLOG) + * those where it's parametrically off... + */ + + memset(buf, 0, sizeof(buf)); + strftime(theDate, N2N_TRACE_DATESIZE, "%d/%b/%Y %H:%M:%S", localtime(&theTime)); + + va_start(va_ap, format); + vsnprintf(buf, sizeof(buf) - 1, format, va_ap); + va_end(va_ap); + + if(eventTraceLevel == 0 /* TRACE_ERROR */) { + extra_msg = "ERROR: "; + } else if(eventTraceLevel == 1 /* TRACE_WARNING */) { + extra_msg = "WARNING: "; + } + + while(buf[strlen(buf) - 1] == '\n') { + buf[strlen(buf) - 1] = '\0'; + } + +#ifndef WIN32 + if(useSyslog) { + if(!syslog_opened) { + openlog("n2n", LOG_PID, LOG_DAEMON); + syslog_opened = 1; + } + + snprintf(out_buf, sizeof(out_buf), "%s%s", extra_msg, buf); + syslog(LOG_INFO, "%s", out_buf); + } else { +#endif + for(i = strlen(file) - 1; i > 0; i--) { + if((file[i] == '/') || (file[i] == '\\')) { + i++; + break; + } + } + snprintf(out_buf, sizeof(out_buf), "%s [%s:%d] %s%s", theDate, &file[i], line, extra_msg, buf); + fprintf(traceFile, "%s\n", out_buf); + fflush(traceFile); +#ifndef WIN32 + } +#endif + } + +} + +/* *********************************************** */ + +/* addr should be in network order. Things are so much simpler that way. */ +char* intoa (uint32_t /* host order */ addr, char* buf, uint16_t buf_len) { + + char *cp, *retStr; + uint8_t byteval; + int n; + + cp = &buf[buf_len]; + *--cp = '\0'; + + n = 4; + do { + byteval = addr & 0xff; + *--cp = byteval % 10 + '0'; + byteval /= 10; + if(byteval > 0) { + *--cp = byteval % 10 + '0'; + byteval /= 10; + if(byteval > 0) { + *--cp = byteval + '0'; + } + } + *--cp = '.'; + addr >>= 8; + } while(--n > 0); + + /* Convert the string to lowercase */ + retStr = (char*)(cp + 1); + + return(retStr); +} + + +/** Convert subnet prefix bit length to host order subnet mask. */ +uint32_t bitlen2mask (uint8_t bitlen) { + + uint8_t i; + uint32_t mask = 0; + + for (i = 1; i <= bitlen; ++i) { + mask |= 1 << (32 - i); + } + + return mask; +} + + +/** Convert host order subnet mask to subnet prefix bit length. */ +uint8_t mask2bitlen (uint32_t mask) { + + uint8_t i, bitlen = 0; + + for (i = 0; i < 32; ++i) { + if((mask << i) & 0x80000000) { + ++bitlen; + } else { + break; + } + } + + return bitlen; +} + + +/* *********************************************** */ + +char * macaddr_str (macstr_t buf, + const n2n_mac_t mac) { + + snprintf(buf, N2N_MACSTR_SIZE, "%02X:%02X:%02X:%02X:%02X:%02X", + mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF, + mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF); + + return(buf); +} + +/* *********************************************** */ + +/** Resolve the supernode IP address. + * + */ +int supernode2sock (n2n_sock_t *sn, const n2n_sn_name_t addrIn) { + + n2n_sn_name_t addr; + char *supernode_host; + char *supernode_port; + int rv = 0; + int nameerr; + const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL}; + struct addrinfo * ainfo = NULL; + struct sockaddr_in * saddr; + + sn->family = AF_INVALID; + + memcpy(addr, addrIn, N2N_EDGE_SN_HOST_SIZE); + supernode_host = strtok(addr, ":"); + + if(supernode_host) { + supernode_port = strtok(NULL, ":"); + if(supernode_port) { + sn->port = atoi(supernode_port); + nameerr = getaddrinfo(supernode_host, NULL, &aihints, &ainfo); + if(0 == nameerr) { + /* ainfo s the head of a linked list if non-NULL. */ + if(ainfo && (PF_INET == ainfo->ai_family)) { + /* It is definitely and IPv4 address -> sockaddr_in */ + saddr = (struct sockaddr_in *)ainfo->ai_addr; + memcpy(sn->addr.v4, &(saddr->sin_addr.s_addr), IPV4_SIZE); + sn->family = AF_INET; + traceEvent(TRACE_INFO, "supernode2sock successfully resolves supernode IPv4 address for %s", supernode_host); + rv = 0; + } else { + /* Should only return IPv4 addresses due to aihints. */ + traceEvent(TRACE_WARNING, "supernode2sock fails to resolve supernode IPv4 address for %s", supernode_host); + rv = -1; + } + freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */ + } else { + traceEvent(TRACE_WARNING, "supernode2sock fails to resolve supernode host %s, %d: %s", supernode_host, nameerr, gai_strerror(nameerr)); + rv = -2; + } + } else { + traceEvent(TRACE_WARNING, "supernode2sock sees malformed supernode parameter (-l ) %s", addrIn); + rv = -3; + } + } else { + traceEvent(TRACE_WARNING, "supernode2sock sees malformed supernode parameter (-l ) %s", + addrIn); + rv = -4; + } + + ainfo = NULL; + + return rv; +} + + +#ifdef HAVE_PTHREAD +N2N_THREAD_RETURN_DATATYPE resolve_thread(N2N_THREAD_PARAMETER_DATATYPE p) { + + n2n_resolve_parameter_t *param = (n2n_resolve_parameter_t*)p; + n2n_resolve_ip_sock_t *entry, *tmp_entry; + time_t rep_time = N2N_RESOLVE_INTERVAL / 10; + time_t now; + + while(1) { + sleep(N2N_RESOLVE_INTERVAL / 60); /* wake up in-between to check for signaled requests */ + + // what's the time? + now = time(NULL); + + // lock access + pthread_mutex_lock(¶m->access); + + // is it time to resolve yet? + if(((param->request)) || ((now - param->last_resolved) > rep_time)) { + HASH_ITER(hh, param->list, entry, tmp_entry) { + // resolve + entry->error_code = supernode2sock(&entry->sock, entry->org_ip); + // if socket changed and no error + if(!sock_equal(&entry->sock, entry->org_sock) + && (!entry->error_code)) { + // flag the change + param->changed = 1; + } + } + param->last_resolved = now; + + // any request fulfilled + param->request = 0; + + // determine next resolver repetition (shorter time if resolver errors occured) + rep_time = N2N_RESOLVE_INTERVAL; + HASH_ITER(hh, param->list, entry, tmp_entry) { + if(entry->error_code) { + rep_time = N2N_RESOLVE_INTERVAL / 10; + break; + } + } + } + + // unlock access + pthread_mutex_unlock(¶m->access); + } +} +#endif + + +int resolve_create_thread (n2n_resolve_parameter_t **param, struct peer_info *sn_list) { + +#ifdef HAVE_PTHREAD + struct peer_info *sn, *tmp_sn; + n2n_resolve_ip_sock_t *entry; + int ret; + + // create parameter structure + *param = (n2n_resolve_parameter_t*)calloc(1, sizeof(n2n_resolve_parameter_t)); + if(*param) { + HASH_ITER(hh, sn_list, sn, tmp_sn) { + // create entries for those peers that come with ip_addr string (from command-line) + if(sn->ip_addr) { + entry = (n2n_resolve_ip_sock_t*)calloc(1, sizeof(n2n_resolve_ip_sock_t)); + if(entry) { + entry->org_ip = sn->ip_addr; + entry->org_sock = &(sn->sock); + memcpy(&(entry->sock), &(sn->sock), sizeof(n2n_sock_t)); + HASH_ADD(hh, (*param)->list, org_ip, sizeof(char*), entry); + } else + traceEvent(TRACE_WARNING, "resolve_create_thread was unable to add list entry for supernode '%s'", sn->ip_addr); + } + } + (*param)->check_interval = N2N_RESOLVE_CHECK_INTERVAL; + } else { + traceEvent(TRACE_WARNING, "resolve_create_thread was unable to create list of supernodes"); + return -1; + } + + // create thread + ret = pthread_create(&((*param)->id), NULL, resolve_thread, (void *)*param); + if(ret) { + traceEvent(TRACE_WARNING, "resolve_create_thread failed to create resolver thread with error number %d", ret); + return -1; + } + + pthread_mutex_init(&((*param)->access), NULL); + + return 0; +#else + return -1; +#endif +} + + +void resolve_cancel_thread (n2n_resolve_parameter_t *param) { + +#ifdef HAVE_PTHREAD + pthread_cancel(param->id); + free(param); +#endif +} + + +uint8_t resolve_check (n2n_resolve_parameter_t *param, uint8_t requires_resolution, time_t now) { + + uint8_t ret = requires_resolution; /* if trylock fails, it still requires resolution */ + +#ifdef HAVE_PTHREAD + n2n_resolve_ip_sock_t *entry, *tmp_entry; + n2n_sock_str_t sock_buf; + + if(NULL == param) + return ret; + + // check_interval and last_check do not need to be guarded by the mutex because + // their values get changed and evaluated only here + + if((now - param->last_checked > param->check_interval) || (requires_resolution)) { + // try to lock access + if(pthread_mutex_trylock(¶m->access) == 0) { + // any changes? + if(param->changed) { + // reset flag + param->changed = 0; + // unselectively copy all socks (even those with error code, that would be the old one because + // sockets do not get overwritten in case of error in resolve_thread) from list to supernode list + HASH_ITER(hh, param->list, entry, tmp_entry) { + memcpy(entry->org_sock, &entry->sock, sizeof(n2n_sock_t)); + traceEvent(TRACE_INFO, "resolve_check renews ip address of supernode '%s' to %s", + entry->org_ip, sock_to_cstr(sock_buf, &(entry->sock))); + } + } + + // let the resolver thread know eventual difficulties in reaching the supernode + if(requires_resolution) { + param->request = 1; + ret = 0; + } + + param->last_checked = now; + + // next appointment + if(param->request) + // earlier if resolver still working on fulfilling a request + param->check_interval = N2N_RESOLVE_CHECK_INTERVAL / 10; + else + param->check_interval = N2N_RESOLVE_CHECK_INTERVAL; + + // unlock access + pthread_mutex_unlock(¶m->access); + } + } +#endif + + return ret; +} + + +/* ************************************** */ + + +struct peer_info* add_sn_to_list_by_mac_or_sock (struct peer_info **sn_list, n2n_sock_t *sock, const n2n_mac_t mac, int *skip_add) { + + struct peer_info *scan, *tmp, *peer = NULL; + + if(!is_null_mac(mac)) { /* not zero MAC */ + HASH_FIND_PEER(*sn_list, mac, peer); + } + + if(peer == NULL) { /* zero MAC, search by socket */ + HASH_ITER(hh, *sn_list, scan, tmp) { + if(memcmp(&(scan->sock), sock, sizeof(n2n_sock_t)) == 0) { + // update mac if appropriate, needs to be deleted first because it is key to the hash list + if(!is_null_mac(mac)) { + HASH_DEL(*sn_list, scan); + memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); + HASH_ADD_PEER(*sn_list, scan); + } + peer = scan; + break; + } + } + + if((peer == NULL) && (*skip_add == SN_ADD)) { + peer = (struct peer_info*)calloc(1, sizeof(struct peer_info)); + if(peer) { + sn_selection_criterion_default(&(peer->selection_criterion)); + peer->last_valid_time_stamp = initial_time_stamp(); + memcpy(&(peer->sock), sock, sizeof(n2n_sock_t)); + memcpy(peer->mac_addr, mac, sizeof(n2n_mac_t)); + HASH_ADD_PEER(*sn_list, peer); + *skip_add = SN_ADD_ADDED; + } + } + } + + return peer; +} + +/* ************************************************ */ + + +/* http://www.faqs.org/rfcs/rfc908.html */ +uint8_t is_multi_broadcast (const n2n_mac_t dest_mac) { + + int is_broadcast = (memcmp(broadcast_mac, dest_mac, N2N_MAC_SIZE) == 0); + int is_multicast = (memcmp(multicast_mac, dest_mac, 3) == 0) && !(dest_mac[3] >> 7); + int is_ipv6_multicast = (memcmp(ipv6_multicast_mac, dest_mac, 2) == 0); + + return is_broadcast || is_multicast || is_ipv6_multicast; +} + + +uint8_t is_broadcast (const n2n_mac_t dest_mac) { + + int is_broadcast = (memcmp(broadcast_mac, dest_mac, N2N_MAC_SIZE) == 0); + + return is_broadcast; +} + + +uint8_t is_null_mac (const n2n_mac_t dest_mac) { + + int is_null_mac = (memcmp(null_mac, dest_mac, N2N_MAC_SIZE) == 0); + + return is_null_mac; +} + + +/* *********************************************** */ + +char* msg_type2str (uint16_t msg_type) { + + switch(msg_type) { + case MSG_TYPE_REGISTER: return("MSG_TYPE_REGISTER"); + case MSG_TYPE_DEREGISTER: return("MSG_TYPE_DEREGISTER"); + case MSG_TYPE_PACKET: return("MSG_TYPE_PACKET"); + case MSG_TYPE_REGISTER_ACK: return("MSG_TYPE_REGISTER_ACK"); + case MSG_TYPE_REGISTER_SUPER: return("MSG_TYPE_REGISTER_SUPER"); + case MSG_TYPE_REGISTER_SUPER_ACK: return("MSG_TYPE_REGISTER_SUPER_ACK"); + case MSG_TYPE_REGISTER_SUPER_NAK: return("MSG_TYPE_REGISTER_SUPER_NAK"); + case MSG_TYPE_FEDERATION: return("MSG_TYPE_FEDERATION"); + default: return("???"); + } + + return("???"); +} + +/* *********************************************** */ + +void hexdump (const uint8_t *buf, size_t len) { + + size_t i; + + if(0 == len) { + return; + } + + printf("-----------------------------------------------\n"); + for(i = 0; i < len; i++) { + if((i > 0) && ((i % 16) == 0)) { + printf("\n"); + } + printf("%02X ", buf[i] & 0xFF); + } + printf("\n"); + printf("-----------------------------------------------\n"); +} + + +/* *********************************************** */ + +void print_n2n_version () { + + printf("Welcome to n2n v.%s for %s\n" + "Built on %s\n" + "Copyright 2007-2022 - ntop.org and contributors\n\n", + PACKAGE_VERSION, PACKAGE_OSNAME, PACKAGE_BUILDDATE); +} + +/* *********************************************** */ + +size_t purge_expired_nodes (struct peer_info **peer_list, + SOCKET socket_not_to_close, + n2n_tcp_connection_t **tcp_connections, + time_t *p_last_purge, + int frequency, int timeout) { + + time_t now = time(NULL); + size_t num_reg = 0; + + if((now - (*p_last_purge)) < frequency) { + return 0; + } + + traceEvent(TRACE_DEBUG, "Purging old registrations"); + + num_reg = purge_peer_list(peer_list, socket_not_to_close, tcp_connections, now - timeout); + + (*p_last_purge) = now; + traceEvent(TRACE_DEBUG, "Remove %ld registrations", num_reg); + + return num_reg; +} + +/** Purge old items from the peer_list, eventually close the related socket, and + * return the number of items that were removed. */ +size_t purge_peer_list (struct peer_info **peer_list, + SOCKET socket_not_to_close, + n2n_tcp_connection_t **tcp_connections, + time_t purge_before) { + + struct peer_info *scan, *tmp; + n2n_tcp_connection_t *conn; + size_t retval = 0; + + HASH_ITER(hh, *peer_list, scan, tmp) { + if((scan->purgeable == SN_PURGEABLE) && (scan->last_seen < purge_before)) { + if((scan->socket_fd >=0) && (scan->socket_fd != socket_not_to_close)) { + if(tcp_connections) { + HASH_FIND_INT(*tcp_connections, &scan->socket_fd, conn); + if(conn) { + HASH_DEL(*tcp_connections, conn); + free(conn); + } + shutdown(scan->socket_fd, SHUT_RDWR); + closesocket(scan->socket_fd); + } + } + HASH_DEL(*peer_list, scan); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_PURGE,scan); + /* FIXME: generates events for more than just p2p */ + retval++; + free(scan); + } + } + + return retval; +} + +/** Purge all items from the peer_list and return the number of items that were removed. */ +size_t clear_peer_list (struct peer_info ** peer_list) { + + struct peer_info *scan, *tmp; + size_t retval = 0; + + HASH_ITER(hh, *peer_list, scan, tmp) { + HASH_DEL(*peer_list, scan); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_CLEAR,scan); + /* FIXME: generates events for more than just p2p */ + retval++; + free(scan); + } + + return retval; +} + +static uint8_t hex2byte (const char * s) { + + char tmp[3]; + tmp[0] = s[0]; + tmp[1] = s[1]; + tmp[2] = 0; /* NULL term */ + + return((uint8_t)strtol(tmp, NULL, 16)); +} + +extern int str2mac (uint8_t * outmac /* 6 bytes */, const char * s) { + + size_t i; + + /* break it down as one case for the first "HH", the 5 x through loop for + * each ":HH" where HH is a two hex nibbles in ASCII. */ + + *outmac = hex2byte(s); + ++outmac; + s += 2; /* don't skip colon yet - helps generalise loop. */ + + for(i = 1; i < 6; ++i) { + s += 1; + *outmac = hex2byte(s); + ++outmac; + s += 2; + } + + return 0; /* ok */ +} + +extern char * sock_to_cstr (n2n_sock_str_t out, + const n2n_sock_t * sock) { + + if(NULL == out) { + return NULL; + } + memset(out, 0, N2N_SOCKBUF_SIZE); + + if(AF_INET6 == sock->family) { + /* INET6 not written yet */ + snprintf(out, N2N_SOCKBUF_SIZE, "XXXX:%hu", sock->port); + return out; + } else { + const uint8_t * a = sock->addr.v4; + + snprintf(out, N2N_SOCKBUF_SIZE, "%hu.%hu.%hu.%hu:%hu", + (unsigned short)(a[0] & 0xff), + (unsigned short)(a[1] & 0xff), + (unsigned short)(a[2] & 0xff), + (unsigned short)(a[3] & 0xff), + (unsigned short)sock->port); + return out; + } +} + +char *ip_subnet_to_str (dec_ip_bit_str_t buf, const n2n_ip_subnet_t *ipaddr) { + + snprintf(buf, sizeof(dec_ip_bit_str_t), "%hhu.%hhu.%hhu.%hhu/%hhu", + (uint8_t) ((ipaddr->net_addr >> 24) & 0xFF), + (uint8_t) ((ipaddr->net_addr >> 16) & 0xFF), + (uint8_t) ((ipaddr->net_addr >> 8) & 0xFF), + (uint8_t) (ipaddr->net_addr & 0xFF), + ipaddr->net_bitlen); + + return buf; +} + + +/* @return 1 if the two sockets are equivalent. */ +int sock_equal (const n2n_sock_t * a, + const n2n_sock_t * b) { + + if(a->port != b->port) { + return(0); + } + + if(a->family != b->family) { + return(0); + } + + switch(a->family) { + case AF_INET: + if(memcmp(a->addr.v4, b->addr.v4, IPV4_SIZE)) { + return(0); + } + break; + + default: + if(memcmp(a->addr.v6, b->addr.v6, IPV6_SIZE)) { + return(0); + } + break; + } + + /* equal */ + return(1); +} + + +/* *********************************************** */ + +// fills a specified memory area with random numbers +int memrnd (uint8_t *address, size_t len) { + + for(; len >= 4; len -= 4) { + *(uint32_t*)address = n2n_rand(); + address += 4; + } + + for(; len > 0; len--) { + *address = n2n_rand(); + address++; + } + + return 0; +} + + +// exclusive-ors a specified memory area with another +int memxor (uint8_t *destination, const uint8_t *source, size_t len) { + + for(; len >= 4; len -= 4) { + *(uint32_t*)destination ^= *(uint32_t*)source; + source += 4; + destination += 4; + } + + for(; len > 0; len--) { + *destination ^= *source; + source++; + destination++; + } + + return 0; +} + +/* *********************************************** */ + +#if defined(WIN32) +int gettimeofday (struct timeval *tp, void *tzp) { + + time_t clock; + struct tm tm; + SYSTEMTIME wtm; + + GetLocalTime(&wtm); + tm.tm_year = wtm.wYear - 1900; + tm.tm_mon = wtm.wMonth - 1; + tm.tm_mday = wtm.wDay; + tm.tm_hour = wtm.wHour; + tm.tm_min = wtm.wMinute; + tm.tm_sec = wtm.wSecond; + tm.tm_isdst = -1; + clock = mktime(&tm); + tp->tv_sec = clock; + tp->tv_usec = wtm.wMilliseconds * 1000; + + return 0; +} +#endif + + +// stores the previously issued time stamp +static uint64_t previously_issued_time_stamp = 0; + + +// returns a time stamp for use with replay protection (branchless code) +// +// depending on the self-detected accuracy, it has the following format +// +// MMMMMMMMCCCCCCCF or +// +// MMMMMMMMSSSSSCCF +// +// with M being the 32-bit second time stamp +// S the 20-bit sub-second (microsecond) time stamp part, if applicable +// C a counter (8 bit or 24 bit) reset to 0 with every MMMMMMMM(SSSSS) turn-over +// F a 4-bit flag field with +// ...c being the accuracy indicator (if set, only counter and no sub-second accuracy) +// +uint64_t time_stamp (void) { + + struct timeval tod; + uint64_t micro_seconds; + uint64_t co, mask_lo, mask_hi, hi_unchanged, counter, new_co; + + gettimeofday(&tod, NULL); + + // (roughly) calculate the microseconds since 1970, leftbound + micro_seconds = ((uint64_t)(tod.tv_sec) << 32) + ((uint64_t)tod.tv_usec << 12); + // more exact but more costly due to the multiplication: + // micro_seconds = ((uint64_t)(tod.tv_sec) * 1000000ULL + tod.tv_usec) << 12; + + // extract "counter only" flag (lowest bit) + co = (previously_issued_time_stamp << 63) >> 63; + // set mask accordingly + mask_lo = -co; + mask_lo >>= 32; + // either 0x00000000FFFFFFFF (if co flag set) or 0x0000000000000000 (if co flag not set) + + mask_lo |= (~mask_lo) >> 52; + // either 0x00000000FFFFFFFF (unchanged) or 0x0000000000000FFF (lowest 12 bit set) + + mask_hi = ~mask_lo; + + hi_unchanged = ((previously_issued_time_stamp & mask_hi) == (micro_seconds & mask_hi)); + // 0 if upper bits unchanged (compared to previous stamp), 1 otherwise + + // read counter and shift right for flags + counter = (previously_issued_time_stamp & mask_lo) >> 4; + + counter += hi_unchanged; + counter &= -hi_unchanged; + // either counter++ if upper part of timestamp unchanged, 0 otherwise + + // back to time stamp format + counter <<= 4; + + // set new co flag if counter overflows while upper bits unchanged or if it was set before + new_co = (((counter & mask_lo) == 0) & hi_unchanged) | co; + + // in case co flag changed, masks need to be recalculated + mask_lo = -new_co; + mask_lo >>= 32; + mask_lo |= (~mask_lo) >> 52; + mask_hi = ~mask_lo; + + // assemble new timestamp + micro_seconds &= mask_hi; + micro_seconds |= counter; + micro_seconds |= new_co; + + previously_issued_time_stamp = micro_seconds; + + return micro_seconds; +} + + +// returns an initial time stamp for use with replay protection +uint64_t initial_time_stamp (void) { + + return time_stamp() - TIME_STAMP_FRAME; +} + + +// checks if a provided time stamp is consistent with current time and previously valid time stamps +// and, in case of validity, updates the "last valid time stamp" +int time_stamp_verify_and_update (uint64_t stamp, uint64_t *previous_stamp, int allow_jitter) { + + int64_t diff; /* do not change to unsigned */ + uint64_t co; /* counter only mode (for sub-seconds) */ + + co = (stamp << 63) >> 63; + + // is it around current time (+/- allowed deviation TIME_STAMP_FRAME)? + diff = stamp - time_stamp(); + // abs() + diff = (diff < 0 ? -diff : diff); + if(diff >= TIME_STAMP_FRAME) { + traceEvent(TRACE_DEBUG, "time_stamp_verify_and_update found a timestamp out of allowed frame."); + return 0; // failure + } + + // if applicable: is it higher than previous time stamp (including allowed deviation of TIME_STAMP_JITTER)? + if(NULL != previous_stamp) { + diff = stamp - *previous_stamp; + if(allow_jitter) { + // 8 times higher jitter allowed for counter-only flagged timestamps ( ~ 1.25 sec with 160 ms default jitter) + diff += TIME_STAMP_JITTER << (co << 3); + } + + if(diff <= 0) { + traceEvent(TRACE_DEBUG, "time_stamp_verify_and_update found a timestamp too old compared to previous."); + return 0; // failure + } + // for not allowing to exploit the allowed TIME_STAMP_JITTER to "turn the clock backwards", + // set the higher of the values + *previous_stamp = (stamp > *previous_stamp ? stamp : *previous_stamp); + } + + return 1; // success +} diff --git a/src/n2n_port_mapping.c b/src/n2n_port_mapping.c new file mode 100644 index 0000000..29fbc6f --- /dev/null +++ b/src/n2n_port_mapping.c @@ -0,0 +1,640 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +// This file contains code taken from MiniUPnPc and natpmp found at +// https://github.com/miniupnp/miniupnp/ or +// https://github.com/miniupnp/natpmp/ respectively +// both as of October 2021 + + +/** + * MiniUPnPc + * Copyright (c) 2005-2021, Thomas BERNARD + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include "n2n.h" + +#ifdef HAVE_PORT_FORWARDING + +#ifdef HAVE_MINIUPNP + + +#if 0 /* unused code */ +/* protofix() checks if protocol is "UDP" or "TCP" + * returns NULL if not */ +static const char *protofix (const char *proto) { + + int i, b; + const char proto_tcp[4] = {'T', 'C', 'P', 0}; + const char proto_udp[4] = {'U', 'D', 'P', 0}; + + for(i = 0, b = 1; i < 4; i++) + b = b && ((proto[i] == proto_tcp[i]) || (proto[i] == (proto_tcp[i] | 32))); + if(b) + return proto; + for(i = 0, b = 1; i < 4; i++) + b = b && ((proto[i] == proto_udp[i]) || (proto[i] == (proto_udp[i] | 32))); + if(b) + return proto; + + return NULL; +} +#endif // unused code + + +static int n2n_UPNP_GetValidIGD (struct UPNPUrls *urls, struct IGDdatas *data, char *lanaddr, char *externaladdr) { + + struct UPNPDev *devlist = NULL; + struct UPNPDev *device = NULL; + int delay = 2000; + const char *multicastif = NULL; + const char *minissdpdpath = NULL; + int localport = UPNP_LOCAL_PORT_ANY; + int ipv6 = 0; + unsigned char ttl = 2; /* defaulting to 2 */ + int error = 0; + int ret = 0; + + devlist = upnpDiscover(delay, multicastif, minissdpdpath, localport, ipv6, ttl, &error); + if((error != UPNPDISCOVER_SUCCESS) || (devlist == NULL) ) { + traceEvent(TRACE_WARNING, "no IGD UPnP device found on the network"); + return -1; + } + + traceEvent(TRACE_INFO, "list of UPnP devices found on the network:"); + for(device = devlist; device; device = device->pNext) { + traceEvent(TRACE_INFO, " desc: %s", device->descURL); + traceEvent(TRACE_INFO, " st: %s", device->st); + traceEvent(TRACE_INFO, " usn: %s", device->usn); + } + + ret = UPNP_GetValidIGD(devlist, urls, data, lanaddr, N2N_NETMASK_STR_SIZE); + if(ret == 0) { + traceEvent(TRACE_WARNING, "UPnP get valid IGD failed, code %d (%s)", ret, strupnperror(ret)); + freeUPNPDevlist(devlist); + devlist = NULL; + return -1; + } + freeUPNPDevlist(devlist); + devlist = NULL; + traceEvent(TRACE_INFO, "UPnP found valid IGD: %s", urls->controlURL); + + ret = UPNP_GetExternalIPAddress(urls->controlURL, + data->first.servicetype, + externaladdr); + if(ret != UPNPCOMMAND_SUCCESS) { + traceEvent(TRACE_WARNING, "UPnP get external ip address failed, code %d (%s)", ret, strupnperror(ret)); + } + + return 0; +} + + +#if 0 /* unused code */ +static int n2n_upnp_get_port_mapping (struct UPNPUrls *urls, const struct IGDdatas *data, const uint16_t port, const char *proto, + char *lanaddr, char *lanport, char *description, char *enabled, char *duration) { + + int errorcode = 0; + // struct UPNPUrls urls; + // struct IGDdatas data; + // char lanaddr[N2N_NETMASK_STR_SIZE] = {'\0'}; + // char lanport[6] = {'\0'}; + // char externaladdr[N2N_NETMASK_STR_SIZE] = {'\0'}; + char externalport[6] = {'\0'}; + // char description[64] = {'\0'}; + // char enabled[16] = {'\0'}; + // char duration[16] = {'\0'}; + int ret = 0; + + proto = protofix(proto); + if(!proto) { + traceEvent(TRACE_ERROR, "invalid protocol"); + errorcode = -1; + goto end; + } + + snprintf(externalport, sizeof(externalport), "%d", port); + + ret = UPNP_GetSpecificPortMappingEntry(urls->controlURL, + data->first.servicetype, + externalport, proto, NULL, + lanaddr, lanport, description, + enabled, duration); + if(ret != UPNPCOMMAND_SUCCESS) { + traceEvent(TRACE_WARNING, "UPNP_GetSpecificPortMappingEntry() failed, code %d (%s)", ret, strupnperror(ret)); + errorcode = -1; + goto end; + } + +end: + FreeUPNPUrls(urls); + + return errorcode; +} +#endif // unused code + + +static int n2n_upnp_set_port_mapping (const uint16_t port) { + + int errorcode = 0; + struct UPNPUrls urls; + struct IGDdatas data; + char lanaddr[N2N_NETMASK_STR_SIZE] = {'\0'}; + char lanport[6] = {'\0'}; + char externaladdr[N2N_NETMASK_STR_SIZE] = {'\0'}; + char externalport[6] = {'\0'}; + int ret = 0; + + if(port == 0) { + traceEvent(TRACE_ERROR, "invalid port"); + errorcode = -1; + return errorcode; + } + snprintf(lanport, sizeof(lanport), "%d", port); + memcpy(externalport, lanport, sizeof(externalport)); + + ret = n2n_UPNP_GetValidIGD(&urls, &data, lanaddr, externaladdr); + if(ret != 0) { + errorcode = -1; + return errorcode; + } + + // TCP port + ret = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, + externalport, lanport, lanaddr, "n2n-vpn", + "TCP", NULL, "0"); + if(ret != UPNPCOMMAND_SUCCESS) { + traceEvent(TRACE_WARNING, "UPnP local TCP port %s mapping failed, code %d (%s)", lanport, ret, strupnperror(ret)); + errorcode = -1; + } else + traceEvent(TRACE_NORMAL, "UPnP added TCP port mapping: %s:%s -> %s:%s", externaladdr, externalport, lanaddr, lanport); + + // UDP port + ret = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, + externalport, lanport, lanaddr, "n2n-vpn", + "UDP", NULL, "0"); + if(ret != UPNPCOMMAND_SUCCESS) { + traceEvent(TRACE_WARNING, "UPnP local UDP port %s mapping failed, code %d (%s)", lanport, ret, strupnperror(ret)); + errorcode = -1; + } else + traceEvent(TRACE_NORMAL, "UPnP added UDP port mapping: %s:%s -> %s:%s", externaladdr, externalport, lanaddr, lanport); + + FreeUPNPUrls(&urls); + + return errorcode; +} + + +static int n2n_upnp_del_port_mapping (const uint16_t port) { + + int errorcode = 0; + struct UPNPUrls urls; + struct IGDdatas data; + char lanaddr[N2N_NETMASK_STR_SIZE] = {'\0'}; + // char lanport[6] = {'\0'}; + char externaladdr[N2N_NETMASK_STR_SIZE] = {'\0'}; + char externalport[6] = {'\0'}; + int ret = 0; + + if(port == 0) { + traceEvent(TRACE_ERROR, "invalid port"); + errorcode = -1; + return errorcode; + } + snprintf(externalport, sizeof(externalport), "%d", port); + + ret = n2n_UPNP_GetValidIGD(&urls, &data, lanaddr, externaladdr); + if(ret != 0) { + errorcode = -1; + return errorcode; + } + + // TCP port + ret = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, externalport, "TCP", NULL); + if(ret != UPNPCOMMAND_SUCCESS) { + traceEvent(TRACE_WARNING, "UPnP failed to delete TCP port mapping for %s:%s, code %d (%s)", externaladdr, externalport, ret, strupnperror(ret)); + errorcode = -1; + } else + traceEvent(TRACE_NORMAL, "UPnP deleted TCP port mapping for %s:%s", externaladdr, externalport); + + // UDP port + ret = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, externalport, "UDP", NULL); + if(ret != UPNPCOMMAND_SUCCESS) { + traceEvent(TRACE_WARNING, "UPnP failed to delete UDP port mapping for %s:%s, code %d (%s)", externaladdr, externalport, ret, strupnperror(ret)); + errorcode = -1; + } else + traceEvent(TRACE_NORMAL, "UPnP deleted UDP port mapping for %s:%s", externaladdr, externalport); + + FreeUPNPUrls(&urls); + + return errorcode; +} + +#endif // HAVE_MINIUPNP + + +// ---------------------------------------------------------------------------------------------------- + + +#ifdef HAVE_NATPMP + +static int n2n_natpmp_initialization (natpmp_t *natpmp, char *lanaddr, char *externaladdr) { + + int errorcode = 0; + natpmpresp_t response; + int ret = 0; + int forcegw = 0; + in_addr_t gateway = 0; + struct in_addr gateway_in_use; + struct timeval timeout; + fd_set fds; + + ret = initnatpmp(natpmp, forcegw, gateway); + if(ret != 0) { + traceEvent(TRACE_WARNING, "NAT-PMP failed to initialize, code %d", ret); + errorcode = -1; + return errorcode; + } + gateway_in_use.s_addr = natpmp->gateway; + traceEvent(TRACE_INFO, "NAT-PMP using gateway: %s", inet_ntoa(gateway_in_use)); + + ret = sendpublicaddressrequest(natpmp); + if(ret != 2) { + traceEvent(TRACE_WARNING, "NAT-PMP get external ip address failed, code %d", ret); + closenatpmp(natpmp); + errorcode = -1; + return errorcode; + } + + do + { + FD_ZERO(&fds); + FD_SET(natpmp->s, &fds); + getnatpmprequesttimeout(natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + ret = readnatpmpresponseorretry(natpmp, &response); + traceEvent(TRACE_INFO, "NAT-PMP read response returned %d (%s)", ret, ret == 0 ? "OK" : (ret == NATPMP_TRYAGAIN ? "TRY AGAIN" : "FAILED")); + } while (ret == NATPMP_TRYAGAIN); + + if(response.type != NATPMP_RESPTYPE_PUBLICADDRESS) { + traceEvent(TRACE_WARNING, "NAT-PMP invalid response type %u", response.type); + closenatpmp(natpmp); + errorcode = -1; + return errorcode; + } + snprintf(externaladdr, N2N_NETMASK_STR_SIZE, "%s", inet_ntoa(response.pnu.publicaddress.addr)); + snprintf(lanaddr, N2N_NETMASK_STR_SIZE, "localhost"); + + return errorcode; +} + + +static int n2n_natpmp_port_mapping_request (natpmp_t *natpmp, + const uint16_t port, + const int protocol /* NATPMP_PROTOCOL_TCP or NATPMP_PROTOCOL_UDP */, + const int method /* set:1 del:0 */) { + + int errorcode = 0; + natpmpresp_t response; + int ret = 0; + uint16_t lanport = 0; + uint16_t externalport = 0; + struct timeval timeout; + fd_set fds; + + if(port == 0) { + traceEvent(TRACE_ERROR, "invalid port"); + errorcode = -1; + return errorcode; + } + lanport = port; + externalport = port; + + ret = sendnewportmappingrequest(natpmp, protocol, lanport, externalport, (method ? 31104000 /* lifetime 360 days*/ : 0)); + if(ret != 12) { + traceEvent(TRACE_WARNING, "NAT-PMP new port mapping request failed, code %d", ret); + errorcode = -1; + return errorcode; + } + + do + { + FD_ZERO(&fds); + FD_SET(natpmp->s, &fds); + getnatpmprequesttimeout(natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + ret = readnatpmpresponseorretry(natpmp, &response); + traceEvent(TRACE_INFO, "NAT-PMP read response returned %d (%s)", ret, ret == 0 ? "OK" : (ret == NATPMP_TRYAGAIN ? "TRY AGAIN" : "FAILED")); + } while (ret == NATPMP_TRYAGAIN); + + if(!((response.type == NATPMP_RESPTYPE_TCPPORTMAPPING) || (response.type == NATPMP_RESPTYPE_UDPPORTMAPPING))) { + traceEvent(TRACE_WARNING, "NAT-PMP invalid response type %u", response.type); + errorcode = -1; + return errorcode; + } + + return errorcode; +} + + +static int n2n_natpmp_set_port_mapping (const uint16_t port) { + + int errorcode = 0; + natpmp_t natpmp; + int ret = 0; + char lanaddr[N2N_NETMASK_STR_SIZE] = {'\0'}; + uint16_t lanport = 0; + char externaladdr[N2N_NETMASK_STR_SIZE] = {'\0'}; + uint16_t externalport = 0; + + lanport = port; + externalport = port; + + ret = n2n_natpmp_initialization(&natpmp, lanaddr, externaladdr); + if(ret != 0) { + errorcode = -1; + return errorcode; + } + + // TCP port + ret = n2n_natpmp_port_mapping_request(&natpmp, port, NATPMP_PROTOCOL_TCP, 1); + if(ret != 0) { + traceEvent(TRACE_WARNING, "NAT-PMP local TCP port %hu mapping failed", lanport); + errorcode = -1; + } else + traceEvent(TRACE_NORMAL, "NAT-PMP added TCP port mapping: %s:%hu -> %s:%hu", externaladdr, externalport, lanaddr, lanport); + + // UDP port + ret = n2n_natpmp_port_mapping_request(&natpmp, port, NATPMP_PROTOCOL_UDP, 1); + if(ret != 0) { + traceEvent(TRACE_WARNING, "NAT-PMP local UDP port %hu mapping failed", lanport); + errorcode = -1; + } else + traceEvent(TRACE_NORMAL, "NAT-PMP added UDP port mapping: %s:%hu -> %s:%hu", externaladdr, externalport, lanaddr, lanport); + + closenatpmp(&natpmp); + + return errorcode; +} + + +static int n2n_natpmp_del_port_mapping (const uint16_t port) { + + int errorcode = 0; + natpmp_t natpmp; + int ret = 0; + char lanaddr[N2N_NETMASK_STR_SIZE] = {'\0'}; + // uint16_t lanport = 0; + char externaladdr[N2N_NETMASK_STR_SIZE] = {'\0'}; + uint16_t externalport = 0; + + // lanport = port; + externalport = port; + + ret = n2n_natpmp_initialization(&natpmp, lanaddr, externaladdr); + if(ret != 0) { + errorcode = -1; + return errorcode; + } + + // TCP port + ret = n2n_natpmp_port_mapping_request(&natpmp, port, NATPMP_PROTOCOL_TCP, 0); + if(ret != 0) { + traceEvent(TRACE_WARNING, "NAT-PMP failed to delete TCP port mapping for %s:%hu", externaladdr, externalport); + errorcode = -1; + } else + traceEvent(TRACE_NORMAL, "NAT-PMP deleted TCP port mapping for %s:%hu", externaladdr, externalport); + + // UDP port + ret = n2n_natpmp_port_mapping_request(&natpmp, port, NATPMP_PROTOCOL_UDP, 0); + if(ret != 0) { + traceEvent(TRACE_WARNING, "NAT-PMP failed to delete UDP port mapping for %s:%hu", externaladdr, externalport); + errorcode = -1; + } else + traceEvent(TRACE_NORMAL, "NAT-PMP deleted UDP port mapping for %s:%hu", externaladdr, externalport); + + closenatpmp(&natpmp); + + return errorcode; +} + +#endif // HAVE_NATPMP + + +// ---------------------------------------------------------------------------------------------------- + +static void n2n_set_port_mapping (const uint16_t port) { + +#ifdef HAVE_NATPMP + // since the NAT-PMP protocol is more concise than UPnP, NAT-PMP is preferred. + if(n2n_natpmp_set_port_mapping(port)) +#endif // HAVE_NATPMP + { +#ifdef HAVE_MINIUPNP + n2n_upnp_set_port_mapping(port); +#endif // HAVE_MINIUPNP + } +} + + +static void n2n_del_port_mapping (const uint16_t port) { + +#ifdef HAVE_NATPMP + if(n2n_natpmp_del_port_mapping(port)) +#endif // HAVE_NATPMP + { +#ifdef HAVE_MINIUPNP + n2n_upnp_del_port_mapping(port); +#endif // HAVE_MINIUPNP + } +} + + +// static +// ---------------------------------------------------------------------------------------------------- +// public + + +#ifdef HAVE_PTHREAD /* future management port subscriptions will deprecate the following temporary code */ +void n2n_chg_port_mapping (struct n2n_edge *eee, uint16_t port) { + // write a port change request to param struct, it will be handled in the thread + pthread_mutex_lock(&eee->port_map_parameter->access); + eee->port_map_parameter->new_port = port; + pthread_mutex_unlock(&eee->port_map_parameter->access); + +} +#else +#error "enabling port mapping requires enabling pthread" +#endif + + +N2N_THREAD_RETURN_DATATYPE port_map_thread(N2N_THREAD_PARAMETER_DATATYPE p) { + +#ifdef HAVE_PTHREAD /* future management port subscriptions will deprecate the following temporary code */ + n2n_port_map_parameter_t *param = (n2n_port_map_parameter_t*)p; + + while(1) { + sleep(2); + pthread_mutex_lock(¶m->access); + if(param->mapped_port != param->new_port) { + if(param->mapped_port) + n2n_del_port_mapping(param->mapped_port); + if(param->new_port) + n2n_set_port_mapping(param->new_port); + param->mapped_port = param->new_port; + } + pthread_mutex_unlock(¶m->access); + } +#endif + +#if 0 /* to be used with future management port subscriptions */ + n2n_port_map_parameter_t *param = (n2n_port_map_parameter_t*)p; + SOCKET socket_fd; + fd_set socket_mask; + struct timeval wait_time; + int ret = 0; + char udp_buf[N2N_PKT_BUF_SIZE]; + ssize_t msg_len; + uint32_t addr_tmp = htonl(INADDR_LOOPBACK); + n2n_sock_t sock_tmp; + struct sockaddr_in sock; + socklen_t sock_len; + + // open a new socket ... + socket_fd = open_socket(0 /* no specific port */, INADDR_LOOPBACK, 0 /* UDP */); + if(socket_fd < 0) { + traceEvent(TRACE_ERROR, "port_map_thread failed to open a socket to management port"); + return 0; + } + // ... and connect to local mgmt port + sock_tmp.family = AF_INET; + memcpy(&sock_tmp.addr.v4, &addr_tmp, IPV4_SIZE); + sock_tmp.port = param->mgmt_port; + sock_len = sizeof(sock); + fill_sockaddr((struct sockaddr*)&sock, sock_len, &sock_tmp); + connect(socket_fd, (struct sockaddr*)&sock, sock_len); + + // prepare a subscription request in 'udp_buf' of length 'msg_len' + // !!! dummy + udp_buf[0] = '\n'; + msg_len = 1; + send(socket_fd, udp_buf, msg_len, 0 /*flags*/); + // note: 'msg_len' and 'sock' get re-used hereafter + + while(1) { + FD_ZERO(&socket_mask); + FD_SET(socket_fd, &socket_mask); + + wait_time.tv_sec = SOCKET_TIMEOUT_INTERVAL_SECS; + wait_time.tv_usec = 0; + + ret = select(socket_fd + 1, &socket_mask, NULL, NULL, &wait_time); + + if(ret > 0) { + if(FD_ISSET(socket_fd, &socket_mask)) { + // get the data + sock_len = sizeof(sock); + msg_len = recv(socket_fd, udp_buf, N2N_PKT_BUF_SIZE, 0 /*flags*/); + + // check message format, first message could be the still buffered answer to the subscription request + // !!! + if(1 /* !!! correct message format */) { + // delete an eventually previous port mapping + if(param->mapped_port) + n2n_del_port_mapping(param->mapped_port); + // extract port from message and set accordingly if valid + param->mapped_port = 0; // !!! + if(param->mapped_port) + n2n_set_port_mapping(param->mapped_port); + } + } + } + } +#endif + + return 0; /* should never happen */ +} + + +int port_map_create_thread (n2n_port_map_parameter_t **param, uint16_t mgmt_port) { + +#ifdef HAVE_PTHREAD + int ret; + + // create parameter structure + *param = (n2n_port_map_parameter_t*)calloc(1, sizeof(n2n_port_map_parameter_t)); + if(*param) { + // initialize + (*param)->mgmt_port = mgmt_port; + } else { + traceEvent(TRACE_WARNING, "port_map_create_thread was unable to create parameter structure"); + return -1; + } + + // create thread + ret = pthread_create(&((*param)->id), NULL, port_map_thread, (void *)*param); + if(ret) { + traceEvent(TRACE_WARNING, "port_map_create_thread failed to create port mapping thread with error number %d", ret); + return -1; + } + + return 0; +#else + return -1; +#endif +} + + +void port_map_cancel_thread (n2n_port_map_parameter_t *param) { + +#ifdef HAVE_PTHREAD + pthread_cancel(param->id); + if(param->mapped_port) + n2n_del_port_mapping(param->mapped_port); + free(param); +#endif +} + +#endif // HAVE_PORT_FORWARDING diff --git a/src/n2n_regex.c b/src/n2n_regex.c new file mode 100644 index 0000000..6539451 --- /dev/null +++ b/src/n2n_regex.c @@ -0,0 +1,486 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +// taken from https://github.com/kokke/tiny-regex-c +// under Unlicense as of August 4, 2020 + +/* + * + * Mini regex-module inspired by Rob Pike's regex code described in: + * + * http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html + * + * + * + * Supports: + * --------- + * '.' Dot, matches any character + * '^' Start anchor, matches beginning of string -- NOTE: currently disabled (checking for full matches anyway) + * '$' End anchor, matches end of string -- NOTE: currently disabled (checking for full matches anyway) + * '*' Asterisk, match zero or more (greedy) + * '+' Plus, match one or more (greedy) + * '?' Question, match zero or one (non-greedy) + * '[abc]' Character class, match if one of {'a', 'b', 'c'} + * '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} -- NOTE: feature is currently broken! + * '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z } + * '\s' Whitespace, \t \f \r \n \v and spaces + * '\S' Non-whitespace + * '\w' Alphanumeric, [a-zA-Z0-9_] + * '\W' Non-alphanumeric + * '\d' Digits, [0-9] + * '\D' Non-digits + * + * + */ + + +#include "n2n.h" +#include "n2n_regex.h" + +/* Definitions: */ + +#define MAX_REGEXP_OBJECTS 30 /* Max number of regex symbols in expression. */ +#define MAX_CHAR_CLASS_LEN 40 /* Max length of character-class buffer in. */ + + +enum { UNUSED, DOT, BEGIN, END, QUESTIONMARK, STAR, PLUS, CHAR_TYPE, CHAR_CLASS, INV_CHAR_CLASS, DIGIT, NOT_DIGIT, ALPHA, NOT_ALPHA, WHITESPACE, NOT_WHITESPACE, /* BRANCH */ }; + +typedef struct regex_t { + unsigned char type; /* CHAR_TYPE, STAR, etc. */ + union { + unsigned char ch; /* the character itself */ + unsigned char* ccl; /* OR a pointer to characters in class */ + }; +} regex_t; + + + +/* Private function declarations: */ +static int matchpattern (regex_t* pattern, const char* text, int* matchlength); +static int matchcharclass (char c, const char* str); +static int matchstar (regex_t p, regex_t* pattern, const char* text, int* matchlength); +static int matchplus (regex_t p, regex_t* pattern, const char* text, int* matchlength); +static int matchone (regex_t p, char c); +static int matchdigit (char c); +static int matchalpha (char c); +static int matchwhitespace (char c); +static int matchmetachar (char c, const char* str); +static int matchrange (char c, const char* str); +static int matchdot (char c); +static int ismetachar (char c); + + + +/* Public functions: */ +int re_match (const char* pattern, const char* text, int* matchlength) { + + re_t re_p; /* pointer to (to be created) copy of compiled regex */ + int ret = -1; + + re_p = re_compile (pattern); + ret = re_matchp(re_p, text, matchlength); + free(re_p); + + return(ret); +} + +int re_matchp (re_t pattern, const char* text, int* matchlength) { + + *matchlength = 0; + + if(pattern != 0) { + if(pattern[0].type == BEGIN) { + return ((matchpattern(&pattern[1], text, matchlength)) ? 0 : -1); + } else { + int idx = -1; + + do { + idx += 1; + + if(matchpattern(pattern, text, matchlength)) { + if(text[0] == '\0') { + return -1; + } + return idx; + } + } while(*text++ != '\0'); + } + } + + return -1; +} + +re_t re_compile (const char* pattern) { + + /* The sizes of the two static arrays below substantiates the static RAM usage of this module. + MAX_REGEXP_OBJECTS is the max number of symbols in the expression. + MAX_CHAR_CLASS_LEN determines the size of buffer for chars in all char-classes in the expression. */ + static regex_t re_compiled[MAX_REGEXP_OBJECTS]; + re_t re_p; /* pointer to (to be created) copy of compiled regex in re_compiled */ + + static unsigned char ccl_buf[MAX_CHAR_CLASS_LEN]; + int ccl_bufidx = 1; + + char c; /* current char in pattern */ + int i = 0; /* index into pattern */ + int j = 0; /* index into re_compiled */ + + while(pattern[i] != '\0' && (j + 1 < MAX_REGEXP_OBJECTS)) { + c = pattern[i]; + + switch(c) { + /* Meta-characters: */ + // case '^': { re_compiled[j].type = BEGIN; } break; <-- disabled (always full matches) + // case '$': { re_compiled[j].type = END; } break; <-- disabled (always full matches) + case '.': { re_compiled[j].type = DOT; } break; + case '*': { re_compiled[j].type = STAR; } break; + case '+': { re_compiled[j].type = PLUS; } break; + case '?': { re_compiled[j].type = QUESTIONMARK; } break; + /* case '|': { re_compiled[j].type = BRANCH; } break; <-- not working properly */ + + /* Escaped character-classes (\s \w ...): */ + case '\\': { + if(pattern[i + 1] != '\0') { + /* Skip the escape-char '\\' */ + i += 1; + /* ... and check the next */ + switch(pattern[i]) { + /* Meta-character: */ + case 'd': { re_compiled[j].type = DIGIT; } break; + case 'D': { re_compiled[j].type = NOT_DIGIT; } break; + case 'w': { re_compiled[j].type = ALPHA; } break; + case 'W': { re_compiled[j].type = NOT_ALPHA; } break; + case 's': { re_compiled[j].type = WHITESPACE; } break; + case 'S': { re_compiled[j].type = NOT_WHITESPACE; } break; + + /* Escaped character, e.g. '.' */ + default: { + re_compiled[j].type = CHAR_TYPE; + re_compiled[j].ch = pattern[i]; + } break; + } + } + /* '\\' as last char in pattern -> invalid regular expression. */ + /* + else + { + re_compiled[j].type = CHAR_TYPE; + re_compiled[j].ch = pattern[i]; + } + */ + } break; + + /* Character class: */ + case '[': { + /* Remember where the char-buffer starts. */ + int buf_begin = ccl_bufidx; + + /* Look-ahead to determine if negated */ + if(pattern[i+1] == '^') { + re_compiled[j].type = INV_CHAR_CLASS; + i += 1; /* Increment i to avoid including '^' in the char-buffer */ + } else { + re_compiled[j].type = CHAR_CLASS; + } + + /* Copy characters inside [..] to buffer */ + while((pattern[++i] != ']') + && (pattern[i] != '\0')) /* Missing ] */ + { + if(pattern[i] == '\\') { + if(ccl_bufidx >= MAX_CHAR_CLASS_LEN - 1) { + //fputs("exceeded internal buffer!\n", stderr); + return 0; + } + ccl_buf[ccl_bufidx++] = pattern[i++]; + } else if(ccl_bufidx >= MAX_CHAR_CLASS_LEN) { + //fputs("exceeded internal buffer!\n", stderr); + return 0; + } + ccl_buf[ccl_bufidx++] = pattern[i]; + } + if(ccl_bufidx >= MAX_CHAR_CLASS_LEN) { + /* Catches cases such as [00000000000000000000000000000000000000][ */ + //fputs("exceeded internal buffer!\n", stderr); + return 0; + } + /* Null-terminate string end */ + ccl_buf[ccl_bufidx++] = 0; + re_compiled[j].ccl = &ccl_buf[buf_begin]; + } break; + + /* Other characters: */ + default: { + re_compiled[j].type = CHAR_TYPE; + re_compiled[j].ch = c; + } break; + } + i += 1; + j += 1; + } + /* 'UNUSED' is a sentinel used to indicate end-of-pattern */ + re_compiled[j].type = UNUSED; + + re_p = (re_t)calloc(1, sizeof(re_compiled)); + memcpy (re_p, re_compiled, sizeof(re_compiled)); + + return (re_t) re_p; +} + +void re_print (regex_t* pattern) { + + const char* types[] = { "UNUSED", "DOT", "BEGIN", "END", "QUESTIONMARK", "STAR", "PLUS", "CHAR_TYPE", "CHAR_CLASS", "INV_CHAR_CLASS", "DIGIT", "NOT_DIGIT", "ALPHA", "NOT_ALPHA", "WHITESPACE" , "NOT_WHITESPACE", /* "BRANCH" */ }; + int i; + int j; + char c; + + for(i = 0; i < MAX_REGEXP_OBJECTS; ++i) { + if(pattern[i].type == UNUSED) { + break; + } + + printf("type: %s", types[pattern[i].type]); + if((pattern[i].type == CHAR_CLASS) || (pattern[i].type == INV_CHAR_CLASS)) { + printf(" ["); + for(j = 0; j < MAX_CHAR_CLASS_LEN; ++j) { + c = pattern[i].ccl[j]; + if((c == '\0') || (c == ']')) { + break; + } + printf("%c", c); + } + printf("]"); + } else if(pattern[i].type == CHAR_TYPE) { + printf(" '%c'", pattern[i].ch); + } + printf("\n"); + } +} + + + +/* Private functions: */ +static int matchdigit (char c) { + + return ((c >= '0') && (c <= '9')); +} + +static int matchalpha (char c) { + + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); +} + +static int matchwhitespace (char c) { + + return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\f') || (c == '\v')); +} + +static int matchalphanum (char c) { + + return ((c == '_') || matchalpha(c) || matchdigit(c)); +} + +static int matchrange (char c, const char* str) { + + return ((c != '-') && (str[0] != '\0') && (str[0] != '-') && + (str[1] == '-') && (str[1] != '\0') && + (str[2] != '\0') && ((c >= str[0]) && (c <= str[2]))); +} + +static int matchdot (char c) { + + return ((c != '\n') && (c != '\r')); +} + +static int ismetachar (char c) { + + return ((c == 's') || (c == 'S') || (c == 'w') || (c == 'W') || (c == 'd') || (c == 'D')); +} + +static int matchmetachar (char c, const char* str) { + + switch(str[0]) { + case 'd': return matchdigit(c); + case 'D': return !matchdigit(c); + case 'w': return matchalphanum(c); + case 'W': return !matchalphanum(c); + case 's': return matchwhitespace(c); + case 'S': return !matchwhitespace(c); + default: return (c == str[0]); + } +} + +static int matchcharclass (char c, const char* str) { + + do { + if(matchrange(c, str)) { + return 1; + } else if(str[0] == '\\') { + /* Escape-char: increment str-ptr and match on next char */ + str += 1; + if(matchmetachar(c, str)) { + return 1; + } else if((c == str[0]) && !ismetachar(c)) { + return 1; + } + } else if(c == str[0]) { + if(c == '-') { + return ((str[-1] == '\0') || (str[1] == '\0')); + } else { + return 1; + } + } + } while(*str++ != '\0'); + + return 0; +} + +static int matchone (regex_t p, char c) { + + switch(p.type) { + case DOT: return matchdot(c); + case CHAR_CLASS: return matchcharclass(c, (const char*)p.ccl); + case INV_CHAR_CLASS: return !matchcharclass(c, (const char*)p.ccl); + case DIGIT: return matchdigit(c); + case NOT_DIGIT: return !matchdigit(c); + case ALPHA: return matchalphanum(c); + case NOT_ALPHA: return !matchalphanum(c); + case WHITESPACE: return matchwhitespace(c); + case NOT_WHITESPACE: return !matchwhitespace(c); + default: return (p.ch == c); + } +} + +static int matchstar (regex_t p, regex_t* pattern, const char* text, int* matchlength) { + + int prelen = *matchlength; + const char* prepoint = text; + + while((text[0] != '\0') && matchone(p, *text)) { + text++; + (*matchlength)++; + } + + while(text >= prepoint) { + if(matchpattern(pattern, text--, matchlength)) { + return 1; + } + (*matchlength)--; + } + + *matchlength = prelen; + + return 0; +} + +static int matchplus (regex_t p, regex_t* pattern, const char* text, int* matchlength) { + + const char* prepoint = text; + + while((text[0] != '\0') && matchone(p, *text)) { + text++; + (*matchlength)++; + } + + while(text > prepoint) { + if(matchpattern(pattern, text--, matchlength)) { + return 1; + } + (*matchlength)--; + } + + return 0; +} + +static int matchquestion (regex_t p, regex_t* pattern, const char* text, int* matchlength) { + + if(p.type == UNUSED) { + return 1; + } + + if(matchpattern(pattern, text, matchlength)) { + return 1; + } + + if(*text && matchone(p, *text++)) { + if(matchpattern(pattern, text, matchlength)) { + (*matchlength)++; + return 1; + } + } + + return 0; +} + + +#if 0 + +/* Recursive matching */ +static int matchpattern (regex_t* pattern, const char* text, int *matchlength) { + + int pre = *matchlength; + + if((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK)) { + return matchquestion(pattern[1], &pattern[2], text, matchlength); + } else if(pattern[1].type == STAR) { + return matchstar(pattern[0], &pattern[2], text, matchlength); + } else if(pattern[1].type == PLUS) { + return matchplus(pattern[0], &pattern[2], text, matchlength); + } else if((pattern[0].type == END) && pattern[1].type == UNUSED) { + return text[0] == '\0'; + } else if((text[0] != '\0') && matchone(pattern[0], text[0])) { + (*matchlength)++; + return matchpattern(&pattern[1], text+1); + } else { + *matchlength = pre; + return 0; + } +} + +#else + +/* Iterative matching */ +static int matchpattern (regex_t* pattern, const char* text, int* matchlength) { + + int pre = *matchlength; + + do { + if((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK)) { + return matchquestion(pattern[0], &pattern[2], text, matchlength); + } else if(pattern[1].type == STAR) { + return matchstar(pattern[0], &pattern[2], text, matchlength); + } else if(pattern[1].type == PLUS) { + return matchplus(pattern[0], &pattern[2], text, matchlength); + } else if((pattern[0].type == END) && pattern[1].type == UNUSED) { + return (text[0] == '\0'); + } +/* Branching is not working properly + else if (pattern[1].type == BRANCH) + { + return (matchpattern(pattern, text) || matchpattern(&pattern[2], text)); + } +*/ + (*matchlength)++; + } while((text[0] != '\0') && matchone(*pattern++, *text++)); + + *matchlength = pre; + + return 0; +} + +#endif diff --git a/src/network_traffic_filter.c b/src/network_traffic_filter.c new file mode 100644 index 0000000..dfdb54d --- /dev/null +++ b/src/network_traffic_filter.c @@ -0,0 +1,783 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" +#include "network_traffic_filter.h" +#include "uthash.h" + +// cache that hit less than 10 while 10000 package processed will be delete; +#define CLEAR_CACHE_EVERY_X_COUNT 10000 +#define CLAER_CACHE_ACTIVE_COUNT 10 + +/* for [-Wmissing-declarations] */ +const char* get_filter_packet_proto_name (filter_packet_proto proto); + +const char* get_filter_packet_proto_name (filter_packet_proto proto) { + + switch(proto) { + case FPP_ARP: + return "ARP"; + case FPP_TCP: + return "TCP"; + case FPP_UDP: + return "UDP"; + case FPP_ICMP: + return "ICMP"; + case FPP_IGMP: + return "IGMP"; + default: + return "UNKNOWN_PROTO"; + } +} + + +/* for [-Wmissing-declarations] */ +const char* get_filter_packet_info_log_string (packet_address_proto_info_t* info); + +const char* get_filter_packet_info_log_string (packet_address_proto_info_t* info) { + + static char buf[1024] = {0}; + + switch(info->proto) { + case FPP_ARP: + case FPP_ICMP: + case FPP_IGMP: + return get_filter_packet_proto_name(info->proto); + case FPP_TCP: + case FPP_UDP: { + struct in_addr src, dst; + + src.s_addr = info->src_ip; + dst.s_addr = info->dst_ip; + const char* proto = get_filter_packet_proto_name(info->proto); + char src_ip[64] = {0}; + char dst_ip[64] = {0}; + strcpy(src_ip, inet_ntoa(src)); + strcpy(dst_ip, inet_ntoa(dst)); + sprintf(buf, "%s\t%s:%d->%s:%d", proto, src_ip, info->src_port, dst_ip, info->dst_port); + return buf; + } + default: + return "UNKNOWN_PROTO"; + } +} + +/* for [-Wmissing-declarations] */ +void collect_packet_info (packet_address_proto_info_t* out_info, unsigned char *buffer, int size); + +void collect_packet_info (packet_address_proto_info_t* out_info, unsigned char *buffer, int size) { + + ether_hdr_t *hdr_ether = (ether_hdr_t*)buffer; + uint16_t ether_type = ntohs(hdr_ether->type); + struct n2n_iphdr *hdr_ip = NULL; + struct n2n_tcphdr *hdr_tcp = NULL; + struct n2n_udphdr *udp_hdr = NULL; + + memset(out_info, 0, sizeof(packet_address_proto_info_t)); + + switch(ether_type) { + case 0x0800: { + buffer += sizeof(ether_hdr_t); + size -= sizeof(ether_hdr_t); + if(size <= 0) { + return; + } + hdr_ip = (struct n2n_iphdr*)buffer; + + switch(hdr_ip->version) { + case 4: { + out_info->src_ip = hdr_ip->saddr; + out_info->dst_ip = hdr_ip->daddr; + switch(hdr_ip->protocol) { + case 0x01: + out_info->proto = FPP_ICMP; + break; + case 0x02: + out_info->proto = FPP_IGMP; + break; + case 0x06: { + out_info->proto = FPP_TCP; + buffer += hdr_ip->ihl * 4; + size -= hdr_ip->ihl * 4; + if(size <= 0) { + return; + } + hdr_tcp = (struct n2n_tcphdr*)buffer; + out_info->src_port = ntohs(hdr_tcp->source); + out_info->dst_port = ntohs(hdr_tcp->dest); + break; + } + case 0x11: { + out_info->proto = FPP_UDP; + buffer += hdr_ip->ihl * 4; + size -= hdr_ip->ihl * 4; + if(size <= 0) { + return; + } + udp_hdr = (struct n2n_udphdr*)buffer; + out_info->src_port = ntohs(udp_hdr->source); + out_info->dst_port = ntohs(udp_hdr->dest); + break; + } + default: + out_info->proto = FPP_UNKNOWN; + }; + break; + } + case 6: { + // TODO: IPV6 Not Support + out_info->proto = FPP_UNKNOWN; + break; + } + default: + out_info->proto = FPP_UNKNOWN; + } + break; + } + case 0x0806: + out_info->proto = FPP_ARP; + break; + case 0x86DD: + out_info->proto = FPP_UNKNOWN; + break; + default: + traceEvent(TRACE_DEBUG, "collect_packet_info stumbled across the unknown ether type 0x%04X", ether_type); + }; +} + +/* for [-Wmissing-declarations] */ +const char* get_filter_rule_info_log_string (filter_rule_t* rule); + +const char* get_filter_rule_info_log_string (filter_rule_t* rule) { + + static char buf[1024] = {0}; + char* print_start = buf; + char src_net[64] = {0}; + char dst_net[64] = {0}; + struct in_addr src, dst; + + src.s_addr = rule->key.src_net_cidr; + dst.s_addr = rule->key.dst_net_cidr; + strcpy(src_net, inet_ntoa(src)); + strcpy(dst_net, inet_ntoa(dst)); + print_start += sprintf(print_start, "%s/%d:[%d,%d],%s/%d:[%d,%d]", + src_net, rule->key.src_net_bit_len, + rule->key.src_port_range.start_port, rule->key.src_port_range.end_port, + dst_net, rule->key.dst_net_bit_len, + rule->key.dst_port_range.start_port, rule->key.dst_port_range.end_port +#if 0 + , + rule->bool_accept_tcp ? '+' : '-', rule->bool_accept_udp ? '+' : '-', rule->bool_accept_icmp ? '+' : '-' +#endif + ); + if(rule->key.bool_tcp_configured) { + print_start += sprintf(print_start, ",TCP%c", rule->bool_accept_tcp ? '+' : '-'); + } + + if(rule->key.bool_udp_configured) { + print_start += sprintf(print_start, ",UDP%c", rule->bool_accept_udp ? '+' : '-'); + } + + if(rule->key.bool_icmp_configured) { + print_start += sprintf(print_start, ",ICMP%c", rule->bool_accept_icmp ? '+' : '-'); + } + + return buf; +} + + + +/* for [-Wmissing-declarations] */ +uint8_t march_cidr_and_address (in_addr_t network, uint8_t net_bitlen, in_addr_t ip_addr); + +uint8_t march_cidr_and_address (in_addr_t network, uint8_t net_bitlen, in_addr_t ip_addr) { + + in_addr_t mask = 0, ip_addr_network = 0; + + network = ntohl(network); + ip_addr = ntohl(ip_addr); + uint32_t mask1 = net_bitlen != 0 ? ((~mask) << (32u-net_bitlen)) : 0; + ip_addr_network = ip_addr & mask1; + if(network == ip_addr_network) { + return net_bitlen + 1; // march 0.0.0.0/0 still march success, that case return 1 + } else { + return 0; + } +} + +/* for [-Wmissing-declarations] */ +uint8_t march_rule_and_cache_key (filter_rule_key_t *rule_key, packet_address_proto_info_t *pkt_addr_info); + +// if ports march, compare cidr. if cidr ok, return sum of src&dst cidr net_bitlen. means always select larger net_bitlen record when multi record is marched. +uint8_t march_rule_and_cache_key (filter_rule_key_t *rule_key, packet_address_proto_info_t *pkt_addr_info) { + + // march failed if proto is not configured at the rule. + switch(pkt_addr_info->proto) { + case FPP_ICMP: + if(!rule_key->bool_icmp_configured) { + return 0; + } + break; + case FPP_UDP: + if(!rule_key->bool_udp_configured) { + return 0; + } + break; + case FPP_TCP: + if(!rule_key->bool_tcp_configured) { + return 0; + } + break; + default: + return 0; + } + + // ignore ports for ICMP proto. + if(pkt_addr_info->proto == FPP_ICMP || (rule_key->src_port_range.start_port <= pkt_addr_info->src_port + && pkt_addr_info->src_port <= rule_key->src_port_range.end_port + && rule_key->dst_port_range.start_port <= pkt_addr_info->dst_port + && pkt_addr_info->dst_port <= rule_key->dst_port_range.end_port)) { + uint8_t march_src_score = march_cidr_and_address(rule_key->src_net_cidr, rule_key->src_net_bit_len, pkt_addr_info->src_ip); + uint8_t march_dst_score = march_cidr_and_address(rule_key->dst_net_cidr, rule_key->dst_net_bit_len, pkt_addr_info->dst_ip); + if((march_src_score > 0) && (march_dst_score > 0)) { + return march_src_score + march_dst_score; + } + } + + return(0); +} + +/* for [-Wmissing-declarations] */ +filter_rule_t* get_filter_rule (filter_rule_t **rules, packet_address_proto_info_t *pkt_addr_info); + +filter_rule_t* get_filter_rule (filter_rule_t **rules, packet_address_proto_info_t *pkt_addr_info) { + + filter_rule_t *item = 0, *tmp = 0, *marched_rule = 0; + int march_score = 0; + + HASH_ITER(hh, *rules, item, tmp) { + /* ... it is safe to delete and free s here */ + uint8_t cur_march_score = march_rule_and_cache_key(&(item->key), pkt_addr_info); + if(cur_march_score > march_score) { + marched_rule = item; + march_score = cur_march_score; + } + } + + return marched_rule; +} + + +/* for [-Wmissing-declarations] */ +void update_and_clear_cache_if_need (network_traffic_filter_t *filter); + +void update_and_clear_cache_if_need (network_traffic_filter_t *filter) { + + if(++(filter->work_count_scene_last_clear) > CLEAR_CACHE_EVERY_X_COUNT) { + filter_rule_pair_cache_t *item = NULL, *tmp = NULL; + HASH_ITER(hh, filter->connections_rule_cache, item, tmp) { + /* ... it is safe to delete and free s here */ + if(item->active_count < CLAER_CACHE_ACTIVE_COUNT) { + traceEvent(TRACE_DEBUG, "### DELETE filter cache %s", get_filter_packet_info_log_string(&item->key)); + HASH_DEL(filter->connections_rule_cache, item); + free(item); + } else { + item->active_count = 0; + } + } + filter->work_count_scene_last_clear = 0; + } +} + +/* for [-Wmissing-declarations] */ +filter_rule_pair_cache_t* get_or_create_filter_rule_cache (network_traffic_filter_t *filter, packet_address_proto_info_t *pkt_addr_info); + +filter_rule_pair_cache_t* get_or_create_filter_rule_cache (network_traffic_filter_t *filter, packet_address_proto_info_t *pkt_addr_info) { + + filter_rule_pair_cache_t* rule_cache_find_result = 0; + HASH_FIND(hh, filter->connections_rule_cache, pkt_addr_info, sizeof(packet_address_proto_info_t), rule_cache_find_result); + if(!rule_cache_find_result) { + filter_rule_t* rule = get_filter_rule(&filter->rules, pkt_addr_info); + if(!rule) { + return NULL; + } + + rule_cache_find_result = malloc(sizeof(filter_rule_pair_cache_t)); + memset(rule_cache_find_result, 0, sizeof(filter_rule_pair_cache_t)); + rule_cache_find_result->key = *pkt_addr_info; + switch(rule_cache_find_result->key.proto) { + case FPP_ICMP: + rule_cache_find_result->bool_allow_traffic = rule->bool_accept_icmp; + break; + case FPP_UDP: + rule_cache_find_result->bool_allow_traffic = rule->bool_accept_udp; + break; + case FPP_TCP: + rule_cache_find_result->bool_allow_traffic = rule->bool_accept_tcp; + break; + default: + traceEvent(TRACE_WARNING, "### Generate filter rule cache failed!"); + return NULL; + } + traceEvent(TRACE_DEBUG, "### ADD filter cache %s", get_filter_packet_info_log_string(&rule_cache_find_result->key)); + HASH_ADD(hh, filter->connections_rule_cache, key, sizeof(packet_address_proto_info_t), rule_cache_find_result); + } + ++(rule_cache_find_result->active_count); + update_and_clear_cache_if_need(filter); + + return rule_cache_find_result; +} + +/* for [-Wmissing-declarations] */ +n2n_verdict filter_packet_from_peer (network_traffic_filter_t *filter, n2n_edge_t *eee, const n2n_sock_t *peer, uint8_t *payload, uint16_t payload_size); + +n2n_verdict filter_packet_from_peer (network_traffic_filter_t *filter, n2n_edge_t *eee, const n2n_sock_t *peer, uint8_t *payload, uint16_t payload_size) { + + filter_rule_pair_cache_t *cur_pkt_rule = 0; + packet_address_proto_info_t pkt_info; + + collect_packet_info(&pkt_info, payload, payload_size); + cur_pkt_rule = get_or_create_filter_rule_cache(filter, &pkt_info); + if(cur_pkt_rule && !cur_pkt_rule->bool_allow_traffic) { + traceEvent(TRACE_DEBUG, "### DROP %s", get_filter_packet_info_log_string(&pkt_info)); + return N2N_DROP; + } + + return N2N_ACCEPT; +} + +/* for [-Wmissing-declarations] */ +n2n_verdict filter_packet_from_tap (network_traffic_filter_t *filter, n2n_edge_t *eee, uint8_t *payload, uint16_t payload_size); + +n2n_verdict filter_packet_from_tap (network_traffic_filter_t *filter, n2n_edge_t *eee, uint8_t *payload, uint16_t payload_size) { + + filter_rule_pair_cache_t *cur_pkt_rule = 0; + packet_address_proto_info_t pkt_info; + + collect_packet_info(&pkt_info, payload, payload_size); + cur_pkt_rule = get_or_create_filter_rule_cache(filter, &pkt_info); + if(cur_pkt_rule && !cur_pkt_rule->bool_allow_traffic) { + traceEvent(TRACE_DEBUG, "### DROP %s", get_filter_packet_info_log_string(&pkt_info)); + return N2N_DROP; + } + + return N2N_ACCEPT; +} + +/* for [-Wmissing-declarations] */ +network_traffic_filter_t *create_network_traffic_filter (); + +network_traffic_filter_t *create_network_traffic_filter () { + + network_traffic_filter_t *filter = malloc(sizeof(network_traffic_filter_t)); + + memset(filter, 0, sizeof(network_traffic_filter_t)); + filter->filter_packet_from_peer = filter_packet_from_peer; + filter->filter_packet_from_tap = filter_packet_from_tap; + + return filter; +} + +/* for [-Wmissing-declarations] */ +void destroy_network_traffic_filter (network_traffic_filter_t *filter); + +void destroy_network_traffic_filter (network_traffic_filter_t *filter) { + + filter_rule_t *el = 0, *tmp = 0; + filter_rule_pair_cache_t* el1 = 0, * tmp1 = 0; + + HASH_ITER(hh, filter->rules, el, tmp) { + HASH_DEL(filter->rules, el); + free(el); + } + + HASH_ITER(hh, filter->connections_rule_cache, el1, tmp1) { + HASH_DEL(filter->connections_rule_cache, el1); + free(el); + } + + free(filter); +} + +/* for [-Wmissing-declarations] */ +void network_traffic_filter_add_rule (network_traffic_filter_t* filter, filter_rule_t* rules); + +void network_traffic_filter_add_rule (network_traffic_filter_t* filter, filter_rule_t* rules) { + + filter_rule_t *item = NULL, *tmp = NULL; + + HASH_ITER(hh, rules, item, tmp) { + filter_rule_t *new_rule = malloc(sizeof(filter_rule_t)); + memcpy(new_rule, item, sizeof(filter_rule_t)); + HASH_ADD(hh, filter->rules, key, sizeof(filter_rule_key_t), new_rule); + traceEvent(TRACE_NORMAL, "### ADD network traffic filter %s", get_filter_rule_info_log_string(new_rule)); + } +} + +/* for [-Wmissing-declarations] */ +in_addr_t get_int32_addr_from_ip_string (const char* begin, const char* next_pos_of_last_char); + +in_addr_t get_int32_addr_from_ip_string (const char* begin, const char* next_pos_of_last_char) { + + char buf[16] = {0}; + + if((next_pos_of_last_char - begin) > 15) { + traceEvent(TRACE_WARNING, "Internal Error"); + return -1; + } + memcpy(buf, begin, (next_pos_of_last_char - begin)); + + return inet_addr(buf); +} + +/* for [-Wmissing-declarations] */ +int get_int32_from_number_string (const char* begin, const char* next_pos_of_last_char); + +int get_int32_from_number_string (const char* begin, const char* next_pos_of_last_char) { + + char buf[6] = {0}; + + if((next_pos_of_last_char - begin) > 5 ) { // max is 65535, 5 char + traceEvent(TRACE_WARNING, "Internal Error"); + return 0; + } + memcpy(buf, begin, (next_pos_of_last_char - begin)); + + return atoi(buf); +} + +/* for [-Wmissing-declarations] */ +void process_traffic_filter_proto (const char* begin, const char* next_pos_of_last_char, filter_rule_t *rule_struct); + +void process_traffic_filter_proto (const char* begin, const char* next_pos_of_last_char, filter_rule_t *rule_struct) { + + char buf[6] = {0}; + + if((next_pos_of_last_char - begin) > 5 ) { // max length str is "ICMP+", 5 char + traceEvent(TRACE_WARNING, "Internal Error"); + } + memcpy(buf, begin, (next_pos_of_last_char - begin)); + + if(strstr(buf, "TCP")) { + rule_struct->key.bool_tcp_configured = 1; + rule_struct->bool_accept_tcp = buf[3] == '+'; + } else if(strstr(buf, "UDP")) { + rule_struct->key.bool_udp_configured = 1; + rule_struct->bool_accept_udp = buf[3] == '+'; + } else if(strstr(buf, "ICMP")) { + rule_struct->key.bool_icmp_configured = 1; + rule_struct->bool_accept_icmp = buf[4] == '+'; + } else { + traceEvent(TRACE_WARNING, "Invalid Proto : %s", buf); + } +} + +typedef enum { + FPS_SRC_NET = 1, + FPS_SRC_NET_BIT_LEN, + FPS_SRC_PORT_SINGLE, + FPS_SRC_PORT_RANGE, + FPS_SRC_PORT_START, + FPS_SRC_PORT_END, + FPS_DST_NET, + FPS_DST_NET_BIT_LEN, + FPS_DST_PORT_SINGLE, + FPS_DST_PORT_RANGE, + FPS_DST_PORT_START, + FPS_DST_PORT_END, + FPS_PROTO +} filter_process_stage; + +/* for [-Wmissing-declarations] */ +uint8_t process_traffic_filter_rule_str (const char *rule_str, filter_rule_t *rule_struct); + +uint8_t process_traffic_filter_rule_str (const char *rule_str, filter_rule_t *rule_struct) { + + const char *cur_pos = rule_str, *stage_begin_pos = rule_str; + filter_process_stage stage = FPS_SRC_NET; + + while(1) { + switch(stage) { + case FPS_SRC_NET: { + if((*cur_pos >= '0' && *cur_pos <= '9') || *cur_pos == '.') { + ; // Normal FPS_SRC_NET, next char + } else if(*cur_pos == '/') { + // FPS_SRC_NET finish, next is FPS_SRC_NET_BIT_LEN + rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + stage = FPS_SRC_NET_BIT_LEN; + } else if(*cur_pos == ':') { + // FPS_SRC_NET finish, ignore FPS_SRC_NET_BIT_LEN(default 32), next is one of FPS_SRC_PORT_RANGE/FPS_SRC_PORT_SINGLE + rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + rule_struct->key.src_net_bit_len = 32; + stage_begin_pos = cur_pos + 1; + if(*(cur_pos + 1) == '[') { + stage = FPS_SRC_PORT_RANGE; + } else { + stage = FPS_SRC_PORT_SINGLE; + } + } else if(*cur_pos == ',') { + // FPS_SRC_NET finish, ignore FPS_SRC_NET_BIT_LEN(default 32), ignore FPS_SRC_PORT(default all), + // next is FPS_DST_NET + rule_struct->key.src_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + rule_struct->key.src_net_bit_len = 32; + rule_struct->key.src_port_range.start_port = 0; + rule_struct->key.src_port_range.end_port = 65535; + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_NET; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_NET_BIT_LEN: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_SRC_NET_BIT_LEN, next char + } else if(*cur_pos == ':') { + // FPS_SRC_NET_BIT_LEN finish, next is one of FPS_SRC_PORT_RANGE/FPS_SRC_PORT_SINGLE + rule_struct->key.src_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + if(*(cur_pos + 1) == '[') { + stage = FPS_SRC_PORT_RANGE; + } else { + stage = FPS_SRC_PORT_SINGLE; + } + } else if(*cur_pos == ',') { + // FPS_SRC_NET_BIT_LEN finish, ignore FPS_SRC_PORT(default all), next is FPS_DST_NET + rule_struct->key.src_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);; + rule_struct->key.src_port_range.start_port = 0; + rule_struct->key.src_port_range.end_port = 65535; + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_NET; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_PORT_SINGLE: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_SRC_PORT_SINGLE, next char + } else if(*cur_pos == ',') { + // FPS_SRC_PORT_SINGLE finish, next is FPS_DST_NET + rule_struct->key.src_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + rule_struct->key.src_port_range.end_port = rule_struct->key.src_port_range.start_port; + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_NET; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_PORT_RANGE: { + if(*cur_pos == '[') { + stage_begin_pos = cur_pos + 1; + stage = FPS_SRC_PORT_START; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_PORT_START: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_SRC_PORT_START, next char + } else if(*cur_pos == ',') { + // FPS_SRC_PORT_START finish, next is FPS_SRC_PORT_END + rule_struct->key.src_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + stage = FPS_SRC_PORT_END; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_SRC_PORT_END: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_SRC_PORT_END, next char + } else if((*cur_pos == ']') && (*(cur_pos + 1) == ',')) { + // FPS_SRC_PORT_END finish, next is FPS_DST_NET + rule_struct->key.src_port_range.end_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 2; + stage = FPS_DST_NET; + ++cur_pos; //skip next char ',' + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_DST_NET: { + if((*cur_pos >= '0' && *cur_pos <= '9') || *cur_pos == '.') { + ; // Normal FPS_DST_NET, next char + } else if(*cur_pos == '/') { + // FPS_DST_NET finish, next is FPS_DST_NET_BIT_LEN + rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_NET_BIT_LEN; + } else if(*cur_pos == ':') { + // FPS_DST_NET finish, ignore FPS_DST_NET_BIT_LEN(default 32), next is one of FPS_DST_PORT_RANGE/FPS_DST_PORT_SINGLE + rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + rule_struct->key.dst_net_bit_len = 32; + stage_begin_pos = cur_pos + 1; + if(*(cur_pos + 1) == '[') { + stage = FPS_DST_PORT_RANGE; + } else { + stage = FPS_DST_PORT_SINGLE; + } + } else if((*cur_pos == ',') || (*cur_pos == 0)) { + // FPS_DST_NET finish, ignore FPS_DST_NET_BIT_LEN(default 32), ignore FPS_DST_PORT(default all), + // next is FPS_PROTO + rule_struct->key.dst_net_cidr = get_int32_addr_from_ip_string(stage_begin_pos, cur_pos); + rule_struct->key.dst_net_bit_len = 32; + rule_struct->key.dst_port_range.start_port = 0; + rule_struct->key.dst_port_range.end_port = 65535; + stage_begin_pos = cur_pos + 1; + stage = FPS_PROTO; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_DST_NET_BIT_LEN: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_DST_NET_BIT_LEN, next char + } else if(*cur_pos == ':') { + // FPS_DST_NET_BIT_LEN finish, next is one of FPS_DST_PORT_RANGE/FPS_DST_PORT_SINGLE + rule_struct->key.dst_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + if(*(cur_pos + 1) == '[') { + stage = FPS_DST_PORT_RANGE; + } else { + stage = FPS_DST_PORT_SINGLE; + } + } else if((*cur_pos == ',') || (*cur_pos == 0)) { + // FPS_DST_NET_BIT_LEN finish, ignore FPS_DST_PORT(default all), next is FPS_PROTO + rule_struct->key.dst_net_bit_len = get_int32_from_number_string(stage_begin_pos, cur_pos);; + rule_struct->key.dst_port_range.start_port = 0; + rule_struct->key.dst_port_range.end_port = 65535; + stage_begin_pos = cur_pos + 1; + stage = FPS_PROTO; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_DST_PORT_SINGLE: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_DST_PORT_SINGLE, next char + } else if((*cur_pos == ',') || (*cur_pos == 0)) { + // FPS_DST_PORT_SINGLE finish, next is FPS_PROTO + rule_struct->key.dst_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + rule_struct->key.dst_port_range.end_port = rule_struct->key.dst_port_range.start_port; + stage_begin_pos = cur_pos + 1; + stage = FPS_PROTO; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_DST_PORT_RANGE: { + if(*cur_pos == '[') { + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_PORT_START; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_DST_PORT_START: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_DST_PORT_START, next char + } else if(*cur_pos == ',') { + // FPS_DST_PORT_START finish, next is FPS_DST_PORT_END + rule_struct->key.dst_port_range.start_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage_begin_pos = cur_pos + 1; + stage = FPS_DST_PORT_END; + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_DST_PORT_END: { + if((*cur_pos >= '0') && (*cur_pos <= '9')) { + ; // Normal FPS_DST_PORT_END, next char + } else if(*cur_pos == ']') { + // FPS_DST_PORT_END finish, next is FPS_PROTO + rule_struct->key.dst_port_range.end_port = get_int32_from_number_string(stage_begin_pos, cur_pos); + stage = FPS_PROTO; + if(*(cur_pos + 1) == ',') { + stage_begin_pos = cur_pos + 2; + ++cur_pos; //skip next char ',' + } else if(*(cur_pos + 1) != 0) { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + } else { + traceEvent(TRACE_WARNING, "process filter rule with error char %c at pos %d", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + + case FPS_PROTO: { + if((*cur_pos != '-') && (*cur_pos != '+') && (*cur_pos != ',')) { + ; // Normal FPS_PROTO. next char + } else if(*cur_pos != ',') { + process_traffic_filter_proto(stage_begin_pos, cur_pos + 1, rule_struct); + if(*(cur_pos+1) == 0) { // end of whole rule string + break; + } else { // new proto info, and skip next char ',' + stage_begin_pos = cur_pos + 2; + ++cur_pos; + } + } else { + traceEvent(TRACE_WARNING, "Internal Error: ',' should skiped", *cur_pos, cur_pos - rule_str); + return 0; + } + break; + } + } + + if(0 == *cur_pos) { + break; + } + ++cur_pos; + } + + return 1; +} diff --git a/src/pearson.c b/src/pearson.c new file mode 100644 index 0000000..4852b43 --- /dev/null +++ b/src/pearson.c @@ -0,0 +1,224 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +// taken from https://github.com/Logan007/pearsonB +// this is free and unencumbered software released into the public domain + + +#include "pearson.h" + + +// Christopher Wellons' triple32 from https://github.com/skeeto/hash-prospector +// published under The Unlicense +#define permute32(in) \ + in ^= in >> 17; \ + in *= 0xed5ad4bb; \ + in ^= in >> 11; \ + in *= 0xac4c1b51; \ + in ^= in >> 15; \ + in *= 0x31848bab; \ + in ^= in >> 14 + +// David Stafford's Mix13 from http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html +// the author clarified via eMail that this of his work is released to the public domain +#define permute64(in) \ + in ^= (in >> 30); \ + in *= 0xbf58476d1ce4e5b9; \ + in ^= (in >> 27); \ + in *= 0x94d049bb133111eb; \ + in ^= (in >> 31) + +#define dec1(in) \ + in-- + +#define dec2(in) \ + dec1(in); \ + dec1(in) + +#define dec3(in) \ + dec2(in); \ + dec1(in) + +#define dec4(in) \ + dec3(in); \ + dec1(in) + +#define hash_round(hash, in, part) \ + hash##part ^= in; \ + dec##part(hash##part); \ + permute64(hash##part) + + +void pearson_hash_256 (uint8_t *out, const uint8_t *in, size_t len) { + + uint64_t *current; + current = (uint64_t*)in; + uint64_t org_len = len; + uint64_t hash1 = 0; + uint64_t hash2 = 0; + uint64_t hash3 = 0; + uint64_t hash4 = 0; + + while (len > 7) { + // digest words little endian first + hash_round(hash, le64toh(*current), 1); + hash_round(hash, le64toh(*current), 2); + hash_round(hash, le64toh(*current), 3); + hash_round(hash, le64toh(*current), 4); + + current++; + len-=8; + } + + // handle the rest + hash1 = ~hash1; + hash2 = ~hash2; + hash3 = ~hash3; + hash4 = ~hash4; + + while(len) { + // byte-wise, no endianess + hash_round(hash, *(uint8_t*)current, 1); + hash_round(hash, *(uint8_t*)current, 2); + hash_round(hash, *(uint8_t*)current, 3); + hash_round(hash, *(uint8_t*)current, 4); + + current = (uint64_t*)((uint8_t*)current + 1); + len--; + } + + // digest length + hash1 = ~hash1; + hash2 = ~hash2; + hash3 = ~hash3; + hash4 = ~hash4; + + hash_round(hash, org_len, 1); + hash_round(hash, org_len, 2); + hash_round(hash, org_len, 3); + hash_round(hash, org_len, 4); + + // hash string is stored big endian, the natural way to read + uint64_t *o; + o = (uint64_t*)out; + *o = htobe64(hash4); + o++; + *o = htobe64(hash3); + o++; + *o = htobe64(hash2); + o++; + *o = htobe64(hash1); +} + + +void pearson_hash_128 (uint8_t *out, const uint8_t *in, size_t len) { + + uint64_t *current; + current = (uint64_t*)in; + uint64_t org_len = len; + uint64_t hash1 = 0; + uint64_t hash2 = 0; + + while (len > 7) { + // digest words little endian first + hash_round(hash, le64toh(*current), 1); + hash_round(hash, le64toh(*current), 2); + + current++; + len-=8; + } + + // handle the rest + hash1 = ~hash1; + hash2 = ~hash2; + + while(len) { + // byte-wise, no endianess + hash_round(hash, *(uint8_t*)current, 1); + hash_round(hash, *(uint8_t*)current, 2); + + current = (uint64_t*)((uint8_t*)current + 1); + len--; + } + + // digest length + hash1 = ~hash1; + hash2 = ~hash2; + + hash_round(hash, org_len, 1); + hash_round(hash, org_len, 2); + + // hash string is stored big endian, the natural way to read + uint64_t *o; + o = (uint64_t*)out; + *o = htobe64(hash2); + o++; + *o = htobe64(hash1); +} + + +uint64_t pearson_hash_64 (const uint8_t *in, size_t len) { + + uint64_t *current; + current = (uint64_t*)in; + uint64_t org_len = len; + uint64_t hash1 = 0; + + while(len > 7) { + // digest words little endian first + hash_round(hash, le64toh(*current), 1); + + current++; + len-=8; + } + + // handle the rest + hash1 = ~hash1; + while(len) { + // byte-wise, no endianess + hash_round(hash, *(uint8_t*)current, 1); + + current = (uint64_t*)((uint8_t*)current + 1); + len--; + } + + // digest length + hash1 = ~hash1; + hash_round(hash, org_len, 1); + + // caller is responsible for storing it big endian to memory (if ever) + return hash1; +} + + +uint32_t pearson_hash_32 (const uint8_t *in, size_t len) { + + return pearson_hash_64(in, len); +} + + +uint16_t pearson_hash_16 (const uint8_t *in, size_t len) { + + return pearson_hash_64(in, len); +} + + +void pearson_hash_init(void) { + +} diff --git a/src/random_numbers.c b/src/random_numbers.c new file mode 100644 index 0000000..e874031 --- /dev/null +++ b/src/random_numbers.c @@ -0,0 +1,244 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "random_numbers.h" + + +// the following code offers an alterate pseudo random number generator +// namely XORSHIFT128+ to use instead of C's rand() +// its performance is on par with C's rand() + + +// the state must be seeded in a way that it is not all zero, choose some +// arbitrary defaults (in this case: taken from splitmix64) +static rn_generator_state_t rn_current_state = { + .a = 0x9E3779B97F4A7C15, + .b = 0xBF58476D1CE4E5B9 +}; + + +// used for mixing the initializing seed +static uint64_t splitmix64 (splitmix64_state_t *state) { + + uint64_t result = state->s; + + state->s = result + 0x9E3779B97F4A7C15; + + result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9; + result = (result ^ (result >> 27)) * 0x94D049BB133111EB; + + return result ^ (result >> 31); +} + + +int n2n_srand (uint64_t seed) { + + uint8_t i; + splitmix64_state_t smstate = { seed }; + + rn_current_state.a = 0; + rn_current_state.b = 0; + + rn_current_state.a = splitmix64 (&smstate); + rn_current_state.b = splitmix64 (&smstate); + + // the following lines could be deleted as soon as it is formally prooved that + // there is no seed leading to (a == b == 0). until then, just to be safe: + if((rn_current_state.a == 0) && (rn_current_state.b == 0)) { + rn_current_state.a = 0x9E3779B97F4A7C15; + rn_current_state.b = 0xBF58476D1CE4E5B9; + } + + // stabilize in unlikely case of weak state with only a few bits set + for(i = 0; i < 32; i++) + n2n_rand(); + + return 0; +} + + +// the following code of xorshift128p was taken from +// https://en.wikipedia.org/wiki/Xorshift as of July, 2019 +// and thus is considered public domain +uint64_t n2n_rand (void) { + + uint64_t t = rn_current_state.a; + uint64_t const s = rn_current_state.b; + + rn_current_state.a = s; + t ^= t << 23; + t ^= t >> 17; + t ^= s ^ (s >> 26); + rn_current_state.b = t; + + return t + s; +} + + +// the following code tries to gather some entropy from several sources +// for use as seed. Note, that this code does not set the random generator +// state yet, a call to n2n_srand (n2n_seed()) would do +uint64_t n2n_seed (void) { + + uint64_t seed = 0; /* this could even go uninitialized */ + uint64_t ret = 0; /* this could even go uninitialized */ + size_t i = 0; + +#ifdef SYS_getrandom + int rc = -1; + for(i = 0; (i < RND_RETRIES) && (rc != sizeof(seed)); i++) { + rc = syscall (SYS_getrandom, &seed, sizeof(seed), GRND_NONBLOCK); + // if successful, rc should contain the requested number of random bytes + if(rc != sizeof(seed)) { + if (errno != EAGAIN) { + traceEvent(TRACE_ERROR, "n2n_seed faced error errno=%u from getrandom syscall.", errno); + break; + } + } + } + + // if we still see an EAGAIN error here, we must have run out of retries + if(errno == EAGAIN) { + traceEvent(TRACE_ERROR, "n2n_seed saw getrandom syscall indicate not being able to provide enough entropy yet."); + } +#endif + + // as we want randomness, it does no harm to add up even uninitialized values or + // erroneously arbitrary values returned from the syscall for the first time + ret += seed; + + // __RDRND__ is set only if architecturual feature is set, e.g. compiled with -march=native +#ifdef __RDRND__ + for(i = 0; i < RND_RETRIES; i++) { + if(_rdrand64_step((unsigned long long*)&seed)) { + // success! + // from now on, we keep this inside the loop because in case of failure + // and with unchanged values, we do not want to double the previous value + ret += seed; + break; + } + // continue loop to try again otherwise + } + if(i == RND_RETRIES) { + traceEvent(TRACE_ERROR, "n2n_seed was not able to get a hardware generated random number from RDRND."); + } +#endif + + // __RDSEED__ ist set only if architecturual feature is set, e.g. compile with -march=native +#ifdef __RDSEED__ +#if __GNUC__ > 4 + for(i = 0; i < RND_RETRIES; i++) { + if(_rdseed64_step((unsigned long long*)&seed)) { + // success! + ret += seed; + break; + } + // continue loop to try again otherwise + } + if(i == RND_RETRIES) { + traceEvent(TRACE_ERROR, "n2n_seed was not able to get a hardware generated random number from RDSEED."); + } +#endif +#endif + +#ifdef WIN32 + HCRYPTPROV crypto_provider; + CryptAcquireContext (&crypto_provider, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + CryptGenRandom (crypto_provider, 8, &seed); + CryptReleaseContext (crypto_provider, 0); + ret += seed; +#endif + + seed = time(NULL); /* UTC in seconds */ + ret += seed; + + seed = clock(); /* ticks since program start */ + seed *= 18444244737; + ret += seed; + + return ret; +} + +// an integer squrare root approximation +// from https://stackoverflow.com/a/1100591 +static int ftbl[33] = { + 0, 1, 1, 2, 2, 4, 5, 8, 11, 16, 22, 32, 45, 64, 90, + 128, 181 ,256 ,362, 512, 724, 1024, 1448, 2048, 2896, + 4096, 5792, 8192, 11585, 16384, 23170, 32768, 46340 }; + + +static int ftbl2[32] = { + 32768, 33276, 33776, 34269, 34755, 35235, 35708, 36174, + 36635, 37090, 37540, 37984, 38423, 38858, 39287, 39712, + 40132, 40548, 40960, 41367, 41771, 42170, 42566, 42959, + 43347, 43733, 44115, 44493, 44869, 45241, 45611, 45977 }; + + +static int i_sqrt (int val) { + + int cnt = 0; + int t = val; + + while(t) { + cnt++; + t>>=1; + } + + if(6 >= cnt) + t = (val << (6-cnt)); + else + t = (val >> (cnt-6)); + + return (ftbl[cnt] * ftbl2[t & 31]) >> 15; +} + + +static int32_t int_sqrt (int val) { + + int ret; + + ret = i_sqrt (val); + ret += i_sqrt (val - ret * ret) / 16; + + return ret; +} + + +// returns a random number from [0, max_n] with higher probability towards the borders +uint32_t n2n_rand_sqr (uint32_t max_n) { + + uint32_t raw_max = 0; + uint32_t raw_rnd = 0; + int32_t ret = 0; + + raw_max = (max_n+2) * (max_n+2); + raw_rnd = n2n_rand() % (raw_max); + + ret = int_sqrt(raw_rnd) / 2; + ret = (raw_rnd & 1) ? ret : -ret; + ret = max_n / 2 + ret; + + if(ret < 0) + ret = 0; + if (ret > max_n) + ret = max_n; + + return ret; +} diff --git a/src/sn_management.c b/src/sn_management.c new file mode 100644 index 0000000..44dc4c6 --- /dev/null +++ b/src/sn_management.c @@ -0,0 +1,607 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +/* + * This file has a large amount of duplication with the edge_management.c + * code. In the fullness of time, they should both be merged + */ + +#include "n2n.h" +#include "edge_utils_win32.h" + +int load_allowed_sn_community (n2n_sn_t *sss); /* defined in sn_utils.c */ + +enum n2n_mgmt_type { + N2N_MGMT_READ = 0, + N2N_MGMT_WRITE = 1, +}; + +#define FLAG_WROK 1 +typedef struct mgmt_handler { + int flags; + char *cmd; + char *help; + void (*func)(n2n_sn_t *sss, char *udp_buf, struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); +} mgmt_handler_t; + +static void mgmt_error (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, char *tag, char *msg) { + size_t msg_len; + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"error\"," + "\"error\":\"%s\"}\n", + tag, + msg); + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); +} + +static void mgmt_stop (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { + size_t msg_len; + + if(type==N2N_MGMT_WRITE) { + *sss->keep_running = 0; + } + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"keep_running\":%u}\n", + tag, + *sss->keep_running); + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); +} + +static void mgmt_verbose (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { + size_t msg_len; + + if(type==N2N_MGMT_WRITE) { + if(argv) { + setTraceLevel(strtoul(argv, NULL, 0)); + } + } + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"traceLevel\":%u}\n", + tag, + getTraceLevel()); + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); +} + +static void mgmt_reload_communities (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { + size_t msg_len; + + if(type!=N2N_MGMT_WRITE) { + mgmt_error(sss, udp_buf, sender_sock, tag, "writeonly"); + return; + } + + if(!sss->community_file) { + mgmt_error(sss, udp_buf, sender_sock, tag, "nofile"); + return; + } + + int ok = load_allowed_sn_community(sss); + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"ok\":%i}\n", + tag, + ok); + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); +} + +static void mgmt_timestamps (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { + size_t msg_len; + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"start_time\":%lu," + "\"last_fwd\":%ld," + "\"last_reg_super\":%ld}\n", + tag, + sss->start_time, + sss->stats.last_fwd, + sss->stats.last_reg_super); + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); +} + +static void mgmt_packetstats (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { + size_t msg_len; + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"type\":\"forward\"," + "\"tx_pkt\":%lu}\n", + tag, + sss->stats.fwd); + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"type\":\"broadcast\"," + "\"tx_pkt\":%lu}\n", + tag, + sss->stats.broadcast); + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"type\":\"reg_super\"," + "\"rx_pkt\":%lu," + "\"nak\":%lu}\n", + tag, + sss->stats.reg_super, + sss->stats.reg_super_nak); + + /* Note: reg_super_nak is not currently incremented anywhere */ + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + + /* Generic errors when trying to sendto() */ + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"type\":\"errors\"," + "\"tx_pkt\":%lu}\n", + tag, + sss->stats.errors); + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + +} + +static void mgmt_communities (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { + size_t msg_len; + struct sn_community *community, *tmp; + dec_ip_bit_str_t ip_bit_str = {'\0'}; + + HASH_ITER(hh, sss->communities, community, tmp) { + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"community\":\"%s\"," + "\"purgeable\":%i," + "\"is_federation\":%i," + "\"ip4addr\":\"%s\"}\n", + tag, + (community->is_federation) ? "-/-" : community->community, + community->purgeable, + community->is_federation, + (community->auto_ip_net.net_addr == 0) ? "" : ip_subnet_to_str(ip_bit_str, &community->auto_ip_net)); + + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + } +} + +static void mgmt_edges (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { + size_t msg_len; + struct sn_community *community, *tmp; + struct peer_info *peer, *tmpPeer; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + dec_ip_bit_str_t ip_bit_str = {'\0'}; + + HASH_ITER(hh, sss->communities, community, tmp) { + HASH_ITER(hh, community->edges, peer, tmpPeer) { + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"community\":\"%s\"," + "\"ip4addr\":\"%s\"," + "\"purgeable\":%i," + "\"macaddr\":\"%s\"," + "\"sockaddr\":\"%s\"," + "\"proto\":\"%s\"," + "\"desc\":\"%s\"," + "\"last_seen\":%li}\n", + tag, + (community->is_federation) ? "-/-" : community->community, + (peer->dev_addr.net_addr == 0) ? "" : ip_subnet_to_str(ip_bit_str, &peer->dev_addr), + peer->purgeable, + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + ((peer->socket_fd >= 0) && (peer->socket_fd != sss->sock)) ? "TCP" : "UDP", + peer->dev_desc, + peer->last_seen); + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + } + } +} + +static void mgmt_unimplemented (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { + mgmt_error(sss, udp_buf, sender_sock, tag, "unimplemented"); +} + +static void mgmt_help (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); + +mgmt_handler_t mgmt_handlers[] = { + { .cmd = "supernodes", .help = "Reserved for edge", .func = mgmt_unimplemented}, + + { .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop}, + { .cmd = "verbose", .flags = FLAG_WROK, .help = "Manage verbosity level", .func = mgmt_verbose}, + { .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reloads communities and user's public keys", .func = mgmt_reload_communities}, + { .cmd = "communities", .help = "List current communities", .func = mgmt_communities}, + { .cmd = "edges", .help = "List current edges/peers", .func = mgmt_edges}, + { .cmd = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps}, + { .cmd = "packetstats", .help = "Traffic statistics", .func = mgmt_packetstats}, + { .cmd = "help", .flags = FLAG_WROK, .help = "Show JSON commands", .func = mgmt_help}, + { .cmd = NULL }, +}; + +static void mgmt_help (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { + size_t msg_len; + mgmt_handler_t *handler; + + /* + * Even though this command is readonly, we deliberately do not check + * the type - allowing help replies to both read and write requests + */ + + for( handler=mgmt_handlers; handler->cmd; handler++ ) { + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"cmd\":\"%s\"," + "\"help\":\"%s\"}\n", + tag, + handler->cmd, + handler->help); + + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + } +} + +/* + * Check if the user is authorised for this command. + * - this should be more configurable! + * - for the moment we use some simple heuristics: + * Reads are not dangerous, so they are simply allowed + * Writes are possibly dangerous, so they need a fake password + */ +static int mgmt_auth (n2n_sn_t *sss, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *auth, char *argv0, char *argv) { + + if(auth) { + /* If we have an auth key, it must match */ + if(sss->mgmt_password_hash == pearson_hash_64((uint8_t*)auth, strlen(auth))) { + return 1; + } + return 0; + } + /* if we dont have an auth key, we can still read */ + if(type == N2N_MGMT_READ) { + return 1; + } + + return 0; +} + +static void handleMgmtJson (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock) { + + char cmdlinebuf[80]; + enum n2n_mgmt_type type; + char *typechar; + char *options; + char *argv0; + char *argv; + char *tag; + char *flagstr; + int flags; + char *auth; + mgmt_handler_t *handler; + size_t msg_len; + + /* save a copy of the commandline before we reuse the udp_buf */ + strncpy(cmdlinebuf, udp_buf, sizeof(cmdlinebuf)-1); + cmdlinebuf[sizeof(cmdlinebuf)-1] = 0; + + traceEvent(TRACE_DEBUG, "mgmt json %s", cmdlinebuf); + + typechar = strtok(cmdlinebuf, " \r\n"); + if(!typechar) { + /* should not happen */ + mgmt_error(sss, udp_buf, sender_sock, "-1", "notype"); + return; + } + if(*typechar == 'r') { + type=N2N_MGMT_READ; + } else if(*typechar == 'w') { + type=N2N_MGMT_WRITE; + } else { + /* dunno how we got here */ + mgmt_error(sss, udp_buf, sender_sock, "-1", "badtype"); + return; + } + + /* Extract the tag to use in all reply packets */ + options = strtok(NULL, " \r\n"); + if(!options) { + mgmt_error(sss, udp_buf, sender_sock, "-1", "nooptions"); + return; + } + + argv0 = strtok(NULL, " \r\n"); + if(!argv0) { + mgmt_error(sss, udp_buf, sender_sock, "-1", "nocmd"); + return; + } + + /* + * The entire rest of the line is the argv. We apply no processing + * or arg separation so that the cmd can use it however it needs. + */ + argv = strtok(NULL, "\r\n"); + + /* + * There might be an auth token mixed in with the tag + */ + tag = strtok(options, ":"); + flagstr = strtok(NULL, ":"); + if(flagstr) { + flags = strtoul(flagstr, NULL, 16); + } else { + flags = 0; + } + + /* Only 1 flag bit defined at the moment - "auth option present" */ + if(flags & 1) { + auth = strtok(NULL, ":"); + } else { + auth = NULL; + } + + if(!mgmt_auth(sss, sender_sock, type, auth, argv0, argv)) { + mgmt_error(sss, udp_buf, sender_sock, tag, "badauth"); + return; + } + + for( handler=mgmt_handlers; handler->cmd; handler++ ) { + if(0 == strcmp(handler->cmd, argv0)) { + break; + } + } + if(!handler->cmd) { + mgmt_error(sss, udp_buf, sender_sock, tag, "unknowncmd"); + return; + } + + if((type==N2N_MGMT_WRITE) && !(handler->flags & FLAG_WROK)) { + mgmt_error(sss, udp_buf, sender_sock, tag, "readonly"); + return; + } + + /* + * TODO: + * The tag provided by the requester could contain chars + * that make our JSON invalid. + * - do we care? + */ + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{\"_tag\":\"%s\",\"_type\":\"begin\",\"cmd\":\"%s\"}\n", tag, argv0); + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + + handler->func(sss, udp_buf, sender_sock, type, tag, argv0, argv); + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{\"_tag\":\"%s\",\"_type\":\"end\"}\n", tag); + sendto(sss->mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + return; +} + +static int sendto_mgmt (n2n_sn_t *sss, + const struct sockaddr_in *sender_sock, + const uint8_t *mgmt_buf, + size_t mgmt_size) { + + ssize_t r = sendto(sss->mgmt_sock, (void *)mgmt_buf, mgmt_size, 0 /*flags*/, + (struct sockaddr *)sender_sock, sizeof (struct sockaddr_in)); + + if(r <= 0) { + ++(sss->stats.errors); + traceEvent(TRACE_ERROR, "sendto_mgmt : sendto failed. %s", strerror(errno)); + return -1; + } + + return 0; +} + +int process_mgmt (n2n_sn_t *sss, + const struct sockaddr_in *sender_sock, + char *mgmt_buf, + size_t mgmt_size, + time_t now) { + + char resbuf[N2N_SN_PKTBUF_SIZE]; + size_t ressize = 0; + uint32_t num_edges = 0; + uint32_t num_comm = 0; + uint32_t num = 0; + struct sn_community *community, *tmp; + struct peer_info *peer, *tmpPeer; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + char time_buf[10]; /* 9 digits + 1 terminating zero */ + dec_ip_bit_str_t ip_bit_str = {'\0'}; + + traceEvent(TRACE_DEBUG, "process_mgmt"); + + /* avoid parsing any uninitialized junk from the stack */ + mgmt_buf[mgmt_size] = 0; + + // process input, if any + if((0 == memcmp(mgmt_buf, "help", 4)) || (0 == memcmp(mgmt_buf, "?", 1))) { + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "Help for supernode management console:\n" + "\thelp | This help message\n" + "\treload_communities | Reloads communities and user's public keys\n" + "\t | Display status and statistics\n"); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + return 0; /* no status output afterwards */ + } + + if(0 == memcmp(mgmt_buf, "reload_communities", 18)) { + if(!sss->community_file) { + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "No community file provided (-c command line option)\n"); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + return 0; /* no status output afterwards */ + } + traceEvent(TRACE_NORMAL, "'reload_communities' command"); + + if(load_allowed_sn_community(sss)) { + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "Error while re-loading community file (not found or no valid content)\n"); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + return 0; /* no status output afterwards */ + } + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "OK.\n"); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + return 0; /* no status output afterwards */ + } + + if((mgmt_buf[0] == 'r' || mgmt_buf[0] == 'w') && (mgmt_buf[1] == ' ')) { + /* this is a JSON request */ + handleMgmtJson(sss, mgmt_buf, *sender_sock); + return 0; + } + + // output current status + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + " ### | TAP | MAC | EDGE | HINT | LAST SEEN\n"); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "========================================================================================================\n"); + HASH_ITER(hh, sss->communities, community, tmp) { + if(num_comm) + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "--------------------------------------------------------------------------------------------------------\n"); + num_comm++; + num_edges += HASH_COUNT(community->edges); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "%s '%s'\n", + (community->is_federation) ? "FEDERATION" : ((community->purgeable == COMMUNITY_UNPURGEABLE) ? "FIXED NAME COMMUNITY" : "COMMUNITY"), + (community->is_federation) ? "-/-" : community->community); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + ressize = 0; + + num = 0; + HASH_ITER(hh, community->edges, peer, tmpPeer) { + sprintf(time_buf, "%9u", (unsigned int)(now - peer->last_seen)); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "%4u | %-19s | %-17s | %-21s %-3s | %-15s | %9s\n", + ++num, + (peer->dev_addr.net_addr == 0) ? ((peer->purgeable == SN_UNPURGEABLE) ? "-l" : "") : ip_subnet_to_str(ip_bit_str, &peer->dev_addr), + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + ((peer->socket_fd >= 0) && (peer->socket_fd != sss->sock)) ? "TCP" : "", + peer->dev_desc, + (peer->last_seen) ? time_buf : ""); + + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + ressize = 0; + } + } + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "========================================================================================================\n"); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "uptime %lu | ", (now - sss->start_time)); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "edges %u | ", + num_edges); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "reg_sup %u | ", + (unsigned int) sss->stats.reg_super); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "reg_nak %u | ", + (unsigned int) sss->stats.reg_super_nak); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "errors %u \n", + (unsigned int) sss->stats.errors); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "fwd %u | ", + (unsigned int) sss->stats.fwd); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "broadcast %u | ", + (unsigned int) sss->stats.broadcast); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "cur_cmnts %u\n", HASH_COUNT(sss->communities)); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "last_fwd %lu sec ago | ", + (long unsigned int) (now - sss->stats.last_fwd)); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "last reg %lu sec ago\n\n", + (long unsigned int) (now - sss->stats.last_reg_super)); + + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + + return 0; +} diff --git a/src/sn_selection.c b/src/sn_selection.c new file mode 100644 index 0000000..0c865ee --- /dev/null +++ b/src/sn_selection.c @@ -0,0 +1,254 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +static SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_common_read (n2n_edge_t *eee); +static int sn_selection_criterion_sort (peer_info_t *a, peer_info_t *b); + + +/* Initialize selection_criterion field in peer_info structure*/ +int sn_selection_criterion_init (peer_info_t *peer) { + + if(peer != NULL) { + sn_selection_criterion_default(&(peer->selection_criterion)); + } + + return 0; /* OK */ +} + + +/* Set selection_criterion field to default value according to selected strategy. */ +int sn_selection_criterion_default (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion) { + + *selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(UINT64_MAX >> 1) - 1; + + return 0; /* OK */ +} + + +/* Set selection_criterion field to 'bad' value (worse than default) according to selected strategy. */ +int sn_selection_criterion_bad (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion) { + + *selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(UINT64_MAX >> 1); + + return 0; /* OK */ +} + +/* Set selection_criterion field to 'good' value (better than default) according to selected strategy. */ +int sn_selection_criterion_good (SN_SELECTION_CRITERION_DATA_TYPE *selection_criterion) { + + *selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(UINT64_MAX >> 1) - 2; + + return 0; /* OK */ +} + + +/* Take data from PEER_INFO payload and transform them into a selection_criterion. + * This function is highly dependant of the chosen selection criterion. + */ +int sn_selection_criterion_calculate (n2n_edge_t *eee, peer_info_t *peer, SN_SELECTION_CRITERION_DATA_TYPE *data) { + + SN_SELECTION_CRITERION_DATA_TYPE common_data; + int sum = 0; + + common_data = sn_selection_criterion_common_read(eee); + + switch(eee->conf.sn_selection_strategy) { + + case SN_SELECTION_STRATEGY_LOAD: { + peer->selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)(be32toh(*data) + common_data); + + /* Mitigation of the real supernode load in order to see less oscillations. + * Edges jump from a supernode to another back and forth due to purging. + * Because this behavior has a cost of switching, the real load is mitigated with a stickyness factor. + * This factor is dynamically calculated basing on network size and prevent that unnecessary switching */ + if(peer == eee->curr_sn) { + sum = HASH_COUNT(eee->known_peers) + HASH_COUNT(eee->pending_peers); + peer->selection_criterion = peer->selection_criterion * sum / (sum + 1); + } + break; + } + + case SN_SELECTION_STRATEGY_RTT: { + peer->selection_criterion = (SN_SELECTION_CRITERION_DATA_TYPE)((uint32_t)time_stamp() >> 22) - common_data; + break; + } + + case SN_SELECTION_STRATEGY_MAC: { + peer->selection_criterion = 0; + memcpy(&peer->selection_criterion, /* leftbound, don't mess with pointer arithmetics */ + peer->mac_addr, + N2N_MAC_SIZE); + peer->selection_criterion = be64toh(peer->selection_criterion); + peer->selection_criterion >>= (sizeof(peer->selection_criterion) - N2N_MAC_SIZE) * 8; /* rightbound */ + break; + } + + default: { + // this should never happen + traceEvent(TRACE_ERROR, "selection_criterion unknown selection strategy configuration"); + break; + } + } + + return 0; /* OK */ +} + + +/* Set sn_selection_criterion_common_data field to default value. */ +int sn_selection_criterion_common_data_default (n2n_edge_t *eee) { + + switch(eee->conf.sn_selection_strategy) { + + case SN_SELECTION_STRATEGY_LOAD: { + SN_SELECTION_CRITERION_DATA_TYPE tmp = 0; + + tmp = HASH_COUNT(eee->pending_peers); + if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + tmp *= 2; + } + eee->sn_selection_criterion_common_data = tmp / HASH_COUNT(eee->conf.supernodes); + break; + } + + case SN_SELECTION_STRATEGY_RTT: { + eee->sn_selection_criterion_common_data = (SN_SELECTION_CRITERION_DATA_TYPE)((uint32_t)time_stamp() >> 22); + break; + } + + case SN_SELECTION_STRATEGY_MAC: { + eee->sn_selection_criterion_common_data = 0; + break; + } + + default: { + // this should never happen + traceEvent(TRACE_ERROR, "selection_criterion unknown selection strategy configuration"); + break; + } + } + + return 0; /* OK */ +} + + +/* Return the value of sn_selection_criterion_common_data field. */ +static SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_common_read (n2n_edge_t *eee) { + + return eee->sn_selection_criterion_common_data; +} + + +/* Function that compare two selection_criterion fields and sorts them in ascending order. */ +static int sn_selection_criterion_sort (peer_info_t *a, peer_info_t *b) { + + int ret = 0; + + // comparison function for sorting supernodes in ascending order of their selection_criterion. + if(a->selection_criterion > b->selection_criterion) + ret = 1; + else if(a->selection_criterion < b->selection_criterion) + ret = -1; + + return ret; +} + + +/* Function that sorts peer_list using sn_selection_criterion_sort. */ +int sn_selection_sort (peer_info_t **peer_list) { + + HASH_SORT(*peer_list, sn_selection_criterion_sort); + + return 0; /* OK */ +} + + +/* Function that gathers requested data on a supernode. + * it remains unaffected by selection strategy because it refers to edge behaviour only + */ +SN_SELECTION_CRITERION_DATA_TYPE sn_selection_criterion_gather_data (n2n_sn_t *sss) { + + SN_SELECTION_CRITERION_DATA_TYPE data = 0, tmp = 0; + struct sn_community *comm, *tmp_comm; + + HASH_ITER(hh, sss->communities, comm, tmp_comm) { + // number of nodes in the community + the community itself + tmp = HASH_COUNT(comm->edges) + 1; + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + // double-count encrypted communities (and their nodes): they exert more load on supernode + tmp *= 2; + } + data += tmp; + } + + return htobe64(data); +} + + +/* Convert selection_criterion field in a string for management port output. */ +extern char * sn_selection_criterion_str (n2n_edge_t *eee, selection_criterion_str_t out, peer_info_t *peer) { + + int chars = 0; + + + if(NULL == out) { + return NULL; + } + memset(out, 0, SN_SELECTION_CRITERION_BUF_SIZE); + + // keep off the super-big values (used for "bad" or "good" or "undetermined" supernodes, + // easier to sort to the end of the list). + // Alternatively, typecast to (int16_t) and check for greater or equal zero + if(peer->selection_criterion < (UINT64_MAX >> 2)) { + + switch(eee->conf.sn_selection_strategy) { + + case SN_SELECTION_STRATEGY_LOAD: { + chars = snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE, "load = %8ld", peer->selection_criterion); + break; + } + + case SN_SELECTION_STRATEGY_RTT: { + chars = snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE, "rtt = %6ld ms", peer->selection_criterion); + break; + } + + case SN_SELECTION_STRATEGY_MAC: { + chars = snprintf(out, SN_SELECTION_CRITERION_BUF_SIZE, "%s", ((int64_t)peer->selection_criterion > 0 ? + ((peer == eee->curr_sn) ? "active" : "standby") : "")); + break; + } + + default: { + // this should never happen + traceEvent(TRACE_ERROR, "selection_criterion unknown selection strategy configuration"); + break; + } + } + + // this test is to make "-Wformat-truncation" less sad + if(chars > SN_SELECTION_CRITERION_BUF_SIZE) { + traceEvent(TRACE_ERROR, "selection_criterion buffer overflow"); + } + } + + return out; +} diff --git a/src/sn_utils.c b/src/sn_utils.c new file mode 100644 index 0000000..f325c26 --- /dev/null +++ b/src/sn_utils.c @@ -0,0 +1,2772 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include "n2n.h" + +#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out) + +int resolve_create_thread (n2n_resolve_parameter_t **param, struct peer_info *sn_list); +int resolve_check (n2n_resolve_parameter_t *param, uint8_t resolution_request, time_t now); +int resolve_cancel_thread (n2n_resolve_parameter_t *param); + + +static ssize_t sendto_peer (n2n_sn_t *sss, + const struct peer_info *peer, + const uint8_t *pktbuf, + size_t pktsize); + +static uint16_t reg_lifetime (n2n_sn_t *sss); + +static int update_edge (n2n_sn_t *sss, + const n2n_common_t* cmn, + const n2n_REGISTER_SUPER_t* reg, + struct sn_community *comm, + const n2n_sock_t *sender_sock, + const SOCKET socket_fd, + n2n_auth_t *answer_auth, + int skip_add, + time_t now); + +static int re_register_and_purge_supernodes (n2n_sn_t *sss, + struct sn_community *comm, + time_t *p_last_re_reg_and_purge, + time_t now, + uint8_t forced); + +static int purge_expired_communities (n2n_sn_t *sss, + time_t* p_last_purge, + time_t now); + +static int sort_communities (n2n_sn_t *sss, + time_t* p_last_sort, + time_t now); + +int process_mgmt (n2n_sn_t *sss, + const struct sockaddr_in *sender_sock, + char *mgmt_buf, + size_t mgmt_size, + time_t now); + +static int process_udp (n2n_sn_t *sss, + const struct sockaddr_in *sender_sock, + const SOCKET socket_fd, + uint8_t *udp_buf, + size_t udp_size, + time_t now); + + +/* ************************************** */ + + +void close_tcp_connection (n2n_sn_t *sss, n2n_tcp_connection_t *conn) { + + struct sn_community *comm, *tmp_comm; + struct peer_info *edge, *tmp_edge; + + if(!conn) + return; + + // find peer by file descriptor + HASH_ITER(hh, sss->communities, comm, tmp_comm) { + HASH_ITER(hh, comm->edges, edge, tmp_edge) { + if(edge->socket_fd == conn->socket_fd) { + // remove peer + HASH_DEL(comm->edges, edge); + free(edge); + goto close_conn; /* break - level 2 */ + } + } + } + + close_conn: + // close the connection + shutdown(conn->socket_fd, SHUT_RDWR); + closesocket(conn->socket_fd); + // forget about the connection, will be deleted later + conn->inactive = 1; +} + + +/* *************************************************** */ + + +// generate shared secrets for user authentication; can be done only after +// federation name is known (-F) and community list completely read (-c) +void calculate_shared_secrets (n2n_sn_t *sss) { + + struct sn_community *comm, *tmp_comm; + sn_user_t *user, *tmp_user; + + traceEvent(TRACE_INFO, "started shared secrets calculation for edge authentication"); + + generate_private_key(sss->private_key, sss->federation->community + 1); /* skip '*' federation leading character */ + HASH_ITER(hh, sss->communities, comm, tmp_comm) { + if(comm->is_federation) { + continue; + } + HASH_ITER(hh, comm->allowed_users, user, tmp_user) { + // calculate common shared secret (ECDH) + generate_shared_secret(user->shared_secret, sss->private_key, user->public_key); + // prepare for use as key + user->shared_secret_ctx = (he_context_t*)calloc(1, sizeof(speck_context_t)); + speck_init((speck_context_t**)&user->shared_secret_ctx, user->shared_secret, 128); + } + } + + traceEvent(TRACE_NORMAL, "calculated shared secrets for edge authentication"); +} + + +// calculate dynamic keys +void calculate_dynamic_keys (n2n_sn_t *sss) { + + struct sn_community *comm, *tmp_comm = NULL; + + traceEvent(TRACE_INFO, "calculating dynamic keys"); + HASH_ITER(hh, sss->communities, comm, tmp_comm) { + // skip federation + if(comm->is_federation) { + continue; + } + + // calculate dynamic keys if this is a user/pw auth'ed community + if(comm->allowed_users) { + calculate_dynamic_key(comm->dynamic_key, /* destination */ + sss->dynamic_key_time, /* time - same for all */ + (uint8_t *)comm->community, /* community name */ + (uint8_t *)sss->federation->community); /* federation name */ + packet_header_change_dynamic_key(comm->dynamic_key, + &(comm->header_encryption_ctx_dynamic), + &(comm->header_iv_ctx_dynamic)); + traceEvent(TRACE_DEBUG, "calculated dynamic key for community '%s'", comm->community); + } + } +} + + +// send RE_REGISTER_SUPER to all edges from user/pw auth'ed communites +void send_re_register_super (n2n_sn_t *sss) { + + struct sn_community *comm, *tmp_comm = NULL; + struct peer_info *edge, *tmp_edge = NULL; + n2n_common_t cmn; + uint8_t rereg_buf[N2N_SN_PKTBUF_SIZE]; + size_t encx = 0; + n2n_sock_str_t sockbuf; + + HASH_ITER(hh, sss->communities, comm, tmp_comm) { + if(comm->is_federation) { + continue; + } + + // send RE_REGISTER_SUPER to edges if this is a user/pw auth community + if(comm->allowed_users) { + // prepare + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_re_register_super; + cmn.flags = N2N_FLAGS_FROM_SUPERNODE; + memcpy(cmn.community, comm->community, N2N_COMMUNITY_SIZE); + + HASH_ITER(hh, comm->edges, edge, tmp_edge) { + // encode + encx = 0; + encode_common(rereg_buf, &encx, &cmn); + + // send + traceEvent(TRACE_DEBUG, "send RE_REGISTER_SUPER to %s", + sock_to_cstr(sockbuf, &(edge->sock))); + + packet_header_encrypt(rereg_buf, encx, encx, + comm->header_encryption_ctx_dynamic, comm->header_iv_ctx_dynamic, + time_stamp()); + + /* sent = */ sendto_peer(sss, edge, rereg_buf, encx); + } + } + } +} + + +/** Load the list of allowed communities. Existing/previous ones will be removed, + * return 0 on success, -1 if file not found, -2 if no valid entries found + */ +int load_allowed_sn_community (n2n_sn_t *sss) { + + char buffer[4096], *line, *cmn_str, net_str[20], format[20]; + + sn_user_t *user, *tmp_user; + n2n_desc_t username; + n2n_private_public_key_t public_key; + char ascii_public_key[(N2N_PRIVATE_PUBLIC_KEY_SIZE * 8 + 5) / 6 + 1]; + + dec_ip_str_t ip_str = {'\0'}; + uint8_t bitlen; + in_addr_t net; + uint32_t mask; + FILE *fd = fopen(sss->community_file, "r"); + + struct sn_community *comm, *tmp_comm, *last_added_comm = NULL; + struct peer_info *edge, *tmp_edge; + node_supernode_association_t *assoc, *tmp_assoc; + n2n_tcp_connection_t *conn; + time_t any_time = 0; + + uint32_t num_communities = 0; + + struct sn_community_regular_expression *re, *tmp_re; + uint32_t num_regex = 0; + int has_net; + + if(fd == NULL) { + traceEvent(TRACE_WARNING, "File %s not found", sss->community_file); + return -1; + } + + // reset data structures ------------------------------ + + // send RE_REGISTER_SUPER to all edges from user/pw auth communites, this is safe because + // follow-up REGISTER_SUPER cannot be handled before this function ends + send_re_register_super(sss); + + // remove communities (not: federation) + HASH_ITER(hh, sss->communities, comm, tmp_comm) { + if(comm->is_federation) { + continue; + } + + // remove all edges from community + HASH_ITER(hh, comm->edges, edge, tmp_edge) { + // remove all edge associations (with other supernodes) + HASH_ITER(hh, comm->assoc, assoc, tmp_assoc) { + HASH_DEL(comm->assoc, assoc); + free(assoc); + } + + // close TCP connections, if any (also causes reconnect) + // and delete edge from list + if((edge->socket_fd != sss->sock) && (edge->socket_fd >= 0)) { + HASH_FIND_INT(sss->tcp_connections, &(edge->socket_fd), conn); + close_tcp_connection(sss, conn); /* also deletes the edge */ + } else { + HASH_DEL(comm->edges, edge); + free(edge); + } + } + + // remove allowed users from community + HASH_ITER(hh, comm->allowed_users, user, tmp_user) { + free(user->shared_secret_ctx); + HASH_DEL(comm->allowed_users, user); + free(user); + } + + // remove community + HASH_DEL(sss->communities, comm); + if(NULL != comm->header_encryption_ctx_static) { + // remove header encryption keys + free(comm->header_encryption_ctx_static); + free(comm->header_iv_ctx_static); + free(comm->header_encryption_ctx_dynamic); + free(comm->header_iv_ctx_dynamic); + } + free(comm); + } + + // remove all regular expressions for allowed communities + HASH_ITER(hh, sss->rules, re, tmp_re) { + HASH_DEL(sss->rules, re); + free(re); + } + + // prepare reading data ------------------------------- + + // new key_time for all communities, requires dynamic keys to be recalculated (see further below), + // and edges to re-register (see above) and ... + sss->dynamic_key_time = time(NULL); + // ... federated supernodes to re-register + re_register_and_purge_supernodes(sss, sss->federation, &any_time, any_time, 1 /* forced */); + + // format definition for possible user-key entries + sprintf(format, "%c %%%ds %%%lds", N2N_USER_KEY_LINE_STARTER, N2N_DESC_SIZE - 1, sizeof(ascii_public_key)-1); + + while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { + int len = strlen(line); + + if((len < 2) || line[0] == '#') { + continue; + } + + len--; + while(len > 0) { + if((line[len] == '\n') || (line[len] == '\r')) { + line[len] = '\0'; + len--; + } else { + break; + } + } + // the loop above does not always determine correct 'len' + len = strlen(line); + + // user-key line for edge authentication? + if(line[0] == N2N_USER_KEY_LINE_STARTER) { /* special first character */ + if(sscanf(line, format, username, ascii_public_key) == 2) { /* correct format */ + if(last_added_comm) { /* is there a valid community to add users to */ + user = (sn_user_t*)calloc(1, sizeof(sn_user_t)); + if(user) { + // username + memcpy(user->name, username, sizeof(username)); + // public key + ascii_to_bin(public_key, ascii_public_key); + memcpy(user->public_key, public_key, sizeof(public_key)); + // common shared secret will be calculated later + // add to list + HASH_ADD(hh, last_added_comm->allowed_users, public_key, sizeof(n2n_private_public_key_t), user); + traceEvent(TRACE_INFO, "added user '%s' with public key '%s' to community '%s'", + user->name, ascii_public_key, last_added_comm->community); + // enable header encryption + last_added_comm->header_encryption = HEADER_ENCRYPTION_ENABLED; + packet_header_setup_key(last_added_comm->community, + &(last_added_comm->header_encryption_ctx_static), + &(last_added_comm->header_encryption_ctx_dynamic), + &(last_added_comm->header_iv_ctx_static), + &(last_added_comm->header_iv_ctx_dynamic)); + // dynamic key setup follows at a later point in code + } + continue; + } + } + } + + // --- community name or regular expression + + // cut off any IP sub-network upfront + cmn_str = (char*)calloc(len + 1, sizeof(char)); + has_net = (sscanf(line, "%s %s", cmn_str, net_str) == 2); + + // if it contains typical characters... + if(NULL != strpbrk(cmn_str, ".*+?[]\\")) { + // ...it is treated as regular expression + re = (struct sn_community_regular_expression*)calloc(1, sizeof(struct sn_community_regular_expression)); + if(re) { + re->rule = re_compile(cmn_str); + HASH_ADD_PTR(sss->rules, rule, re); + num_regex++; + traceEvent(TRACE_INFO, "added regular expression for allowed communities '%s'", cmn_str); + free(cmn_str); + last_added_comm = NULL; + continue; + } + } + + comm = (struct sn_community*)calloc(1,sizeof(struct sn_community)); + + if(comm != NULL) { + comm_init(comm, cmn_str); + /* loaded from file, this community is unpurgeable */ + comm->purgeable = COMMUNITY_UNPURGEABLE; + /* we do not know if header encryption is used in this community, + * first packet will show. just in case, setup the key. */ + comm->header_encryption = HEADER_ENCRYPTION_UNKNOWN; + packet_header_setup_key(comm->community, + &(comm->header_encryption_ctx_static), + &(comm->header_encryption_ctx_dynamic), + &(comm->header_iv_ctx_static), + &(comm->header_iv_ctx_dynamic)); + HASH_ADD_STR(sss->communities, community, comm); + last_added_comm = comm; + + num_communities++; + traceEvent(TRACE_INFO, "added allowed community '%s' [total: %u]", + (char*)comm->community, num_communities); + + // check for sub-network address + if(has_net) { + if(sscanf(net_str, "%15[^/]/%hhu", ip_str, &bitlen) != 2) { + traceEvent(TRACE_WARNING, "bad net/bit format '%s' for community '%c', ignoring; see comments inside community.list file", + net_str, cmn_str); + has_net = 0; + } + net = inet_addr(ip_str); + mask = bitlen2mask(bitlen); + if((net == (in_addr_t)(-1)) || (net == INADDR_NONE) || (net == INADDR_ANY) + || ((ntohl(net) & ~mask) != 0)) { + traceEvent(TRACE_WARNING, "bad network '%s/%u' in '%s' for community '%s', ignoring", + ip_str, bitlen, net_str, cmn_str); + has_net = 0; + } + if((bitlen > 30) || (bitlen == 0)) { + traceEvent(TRACE_WARNING, "bad prefix '%hhu' in '%s' for community '%s', ignoring", + bitlen, net_str, cmn_str); + has_net = 0; + } + } + if(has_net) { + comm->auto_ip_net.net_addr = ntohl(net); + comm->auto_ip_net.net_bitlen = bitlen; + traceEvent(TRACE_INFO, "assigned sub-network %s/%u to community '%s'", + inet_ntoa(*(struct in_addr *) &net), + comm->auto_ip_net.net_bitlen, + comm->community); + } else { + assign_one_ip_subnet(sss, comm); + } + } + free(cmn_str); + } + + fclose(fd); + + if((num_regex + num_communities) == 0) { + traceEvent(TRACE_WARNING, "file %s does not contain any valid community names or regular expressions", sss->community_file); + return -2; + } + + traceEvent(TRACE_NORMAL, "loaded %u fixed-name communities from %s", + num_communities, sss->community_file); + + traceEvent(TRACE_NORMAL, "loaded %u regular expressions for community name matching from %s", + num_regex, sss->community_file); + + // calculate allowed user's shared secrets (shared with federation) + calculate_shared_secrets(sss); + + // calculcate communties' dynamic keys + calculate_dynamic_keys(sss); + + // no new communities will be allowed + sss->lock_communities = 1; + + return 0; +} + + +/* *************************************************** */ + + +/** Send a datagram to a file descriptor socket. + * + * @return -1 on error otherwise number of bytes sent + */ +static ssize_t sendto_fd (n2n_sn_t *sss, + SOCKET socket_fd, + const struct sockaddr *socket, + const uint8_t *pktbuf, + size_t pktsize) { + + ssize_t sent = 0; + n2n_tcp_connection_t *conn; + + sent = sendto(socket_fd, (void *)pktbuf, pktsize, 0 /* flags */, + socket, sizeof(struct sockaddr_in)); + + if((sent <= 0) && (errno)) { + char * c = strerror(errno); + traceEvent(TRACE_ERROR, "sendto failed (%d) %s", errno, c); +#ifdef WIN32 + traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); +#endif + // if the erroneous connection is tcp, i.e. not the regular sock... + if((socket_fd >= 0) && (socket_fd != sss->sock)) { + // ...forget about the corresponding peer and the connection + HASH_FIND_INT(sss->tcp_connections, &socket_fd, conn); + close_tcp_connection(sss, conn); + return -1; + } + } else { + traceEvent(TRACE_DEBUG, "sendto sent=%d to ", (signed int)sent); + } + + return sent; +} + + +/** Send a datagram to a network order socket of type struct sockaddr. + * + * @return -1 on error otherwise number of bytes sent + */ +static ssize_t sendto_sock(n2n_sn_t *sss, + SOCKET socket_fd, + const struct sockaddr *socket, + const uint8_t *pktbuf, + size_t pktsize) { + + ssize_t sent = 0; + int value = 0; + + // if the connection is tcp, i.e. not the regular sock... + if((socket_fd >= 0) && (socket_fd != sss->sock)) { + + setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)); + value = 1; +#ifdef LINUX + setsockopt(socket_fd, IPPROTO_TCP, TCP_CORK, &value, sizeof(value)); +#endif + + // prepend packet length... + uint16_t pktsize16 = htobe16(pktsize); + sent = sendto_fd(sss, socket_fd, socket, (uint8_t*)&pktsize16, sizeof(pktsize16)); + + if(sent <= 0) + return -1; + // ...before sending the actual data + } + + sent = sendto_fd(sss, socket_fd, socket, pktbuf, pktsize); + + // if the connection is tcp, i.e. not the regular sock... + if((socket_fd >= 0) && (socket_fd != sss->sock)) { + value = 1; /* value should still be set to 1 */ + setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)); +#ifdef LINUX + value = 0; + setsockopt(socket_fd, IPPROTO_TCP, TCP_CORK, &value, sizeof(value)); +#endif + } + + return sent; +} + + +/** Send a datagram to a peer whose destination socket is embodied in its sock field of type n2n_sock_t. + * It calls sendto_sock to do the final send. + * + * @return -1 on error otherwise number of bytes sent + */ +static ssize_t sendto_peer (n2n_sn_t *sss, + const struct peer_info *peer, + const uint8_t *pktbuf, + size_t pktsize) { + + n2n_sock_str_t sockbuf; + + if(AF_INET == peer->sock.family) { + + // network order socket + struct sockaddr_in socket; + fill_sockaddr((struct sockaddr *)&socket, sizeof(socket), &(peer->sock)); + + traceEvent(TRACE_DEBUG, "sent %lu bytes to [%s]", + pktsize, + sock_to_cstr(sockbuf, &(peer->sock))); + + return sendto_sock(sss, + (peer->socket_fd >= 0) ? peer->socket_fd : sss->sock, + (const struct sockaddr*)&socket, pktbuf, pktsize); + } else { + /* AF_INET6 not implemented */ + errno = EAFNOSUPPORT; + return -1; + } +} + + +/** Try and broadcast a message to all edges in the community. + * + * This will send the exact same datagram to zero or more edges registered to + * the supernode. + */ +static int try_broadcast (n2n_sn_t * sss, + const struct sn_community *comm, + const n2n_common_t * cmn, + const n2n_mac_t srcMac, + uint8_t from_supernode, + const uint8_t * pktbuf, + size_t pktsize, + time_t now) { + + struct peer_info *scan, *tmp; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + traceEvent(TRACE_DEBUG, "try_broadcast"); + + /* We have to make sure that a broadcast reaches the other supernodes and edges + * connected to them. try_broadcast needs a from_supernode parameter: if set, + * do forward to edges of community only. If unset, forward to all locally known + * nodes of community AND all supernodes associated with the community */ + + if (!from_supernode) { + HASH_ITER(hh, sss->federation->edges, scan, tmp) { + int data_sent_len; + + // only forward to active supernodes + if(scan->last_seen + LAST_SEEN_SN_INACTIVE > now) { + + data_sent_len = sendto_peer(sss, scan, pktbuf, pktsize); + + if(data_sent_len != pktsize) { + ++(sss->stats.errors); + traceEvent(TRACE_WARNING, "multicast %lu to supernode [%s] %s failed %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr), + strerror(errno)); + } else { + ++(sss->stats.broadcast); + traceEvent(TRACE_DEBUG, "multicast %lu to supernode [%s] %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr)); + } + } + } + } + + if(comm) { + HASH_ITER(hh, comm->edges, scan, tmp) { + if(memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0) { + /* REVISIT: exclude if the destination socket is where the packet came from. */ + int data_sent_len; + + data_sent_len = sendto_peer(sss, scan, pktbuf, pktsize); + + if(data_sent_len != pktsize) { + ++(sss->stats.errors); + traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr), + strerror(errno)); + } else { + ++(sss->stats.broadcast); + traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr)); + } + } + } + } + + return 0; +} + + +static int try_forward (n2n_sn_t * sss, + const struct sn_community *comm, + const n2n_common_t * cmn, + const n2n_mac_t dstMac, + uint8_t from_supernode, + const uint8_t * pktbuf, + size_t pktsize, + time_t now) { + + struct peer_info * scan; + node_supernode_association_t *assoc; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + HASH_FIND_PEER(comm->edges, dstMac, scan); + + if(NULL != scan) { + int data_sent_len; + data_sent_len = sendto_peer(sss, scan, pktbuf, pktsize); + + if(data_sent_len == pktsize) { + ++(sss->stats.fwd); + traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr)); + } else { + ++(sss->stats.errors); + traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)", + pktsize, + sock_to_cstr(sockbuf, &(scan->sock)), + macaddr_str(mac_buf, scan->mac_addr), + errno, strerror(errno)); + return -1; + } + } else { + if(!from_supernode) { + // check if target edge is associated with a certain supernode + HASH_FIND(hh, comm->assoc, dstMac, sizeof(n2n_mac_t), assoc); + if(assoc) { + traceEvent(TRACE_DEBUG, "found mac address associated with a known supernode, forwarding packet to that supernode"); + sendto_sock(sss, sss->sock, + (const struct sockaddr*)&(assoc->sock), + pktbuf, pktsize); + } else { + // forwarding packet to all federated supernodes + traceEvent(TRACE_DEBUG, "unknown mac address, broadcasting packet to all federated supernodes"); + try_broadcast(sss, NULL, cmn, sss->mac_addr, from_supernode, pktbuf, pktsize, now); + } + } else { + traceEvent(TRACE_DEBUG, "unknown mac address in packet from a supernode, dropping the packet"); + /* Not a known MAC so drop. */ + return -2; + } + } + + return 0; +} + + +/** Initialise some fields of the community structure **/ +int comm_init (struct sn_community *comm, char *cmn) { + + strncpy((char*)comm->community, cmn, N2N_COMMUNITY_SIZE); + comm->community[N2N_COMMUNITY_SIZE - 1] = '\0'; + comm->is_federation = IS_NO_FEDERATION; + + return 0; /* OK */ +} + + +/** Initialise the supernode structure */ +int sn_init_defaults (n2n_sn_t *sss) { + + char *tmp_string; + +#ifdef WIN32 + initWin32(); +#endif + + pearson_hash_init(); + + memset(sss, 0, sizeof(n2n_sn_t)); + + strncpy(sss->version, PACKAGE_VERSION, sizeof(n2n_version_t)); + sss->version[sizeof(n2n_version_t) - 1] = '\0'; + sss->daemon = 1; /* By defult run as a daemon. */ + sss->lport = N2N_SN_LPORT_DEFAULT; + sss->mport = N2N_SN_MGMT_PORT; + sss->sock = -1; + sss->mgmt_sock = -1; + sss->min_auto_ip_net.net_addr = inet_addr(N2N_SN_MIN_AUTO_IP_NET_DEFAULT); + sss->min_auto_ip_net.net_addr = ntohl(sss->min_auto_ip_net.net_addr); + sss->min_auto_ip_net.net_bitlen = N2N_SN_AUTO_IP_NET_BIT_DEFAULT; + sss->max_auto_ip_net.net_addr = inet_addr(N2N_SN_MAX_AUTO_IP_NET_DEFAULT); + sss->max_auto_ip_net.net_addr = ntohl(sss->max_auto_ip_net.net_addr); + sss->max_auto_ip_net.net_bitlen = N2N_SN_AUTO_IP_NET_BIT_DEFAULT; + + sss->federation = (struct sn_community *)calloc(1, sizeof(struct sn_community)); + /* Initialize the federation */ + if(sss->federation) { + if(getenv("N2N_FEDERATION")) + snprintf(sss->federation->community, N2N_COMMUNITY_SIZE - 1 ,"*%s", getenv("N2N_FEDERATION")); + else + strncpy(sss->federation->community, (char*)FEDERATION_NAME, N2N_COMMUNITY_SIZE); + sss->federation->community[N2N_COMMUNITY_SIZE - 1] = '\0'; + /* enable the flag for federation */ + sss->federation->is_federation = IS_FEDERATION; + sss->federation->purgeable = COMMUNITY_UNPURGEABLE; + /* header encryption enabled by default */ + sss->federation->header_encryption = HEADER_ENCRYPTION_ENABLED; + /*setup the encryption key */ + packet_header_setup_key(sss->federation->community, + &(sss->federation->header_encryption_ctx_static), + &(sss->federation->header_encryption_ctx_dynamic), + &(sss->federation->header_iv_ctx_static), + &(sss->federation->header_iv_ctx_dynamic)); + sss->federation->edges = NULL; + } + + n2n_srand(n2n_seed()); + + /* Random auth token */ + sss->auth.scheme = n2n_auth_simple_id; + memrnd(sss->auth.token, N2N_AUTH_ID_TOKEN_SIZE); + sss->auth.token_size = N2N_AUTH_ID_TOKEN_SIZE; + + /* Random MAC address */ + memrnd(sss->mac_addr, N2N_MAC_SIZE); + sss->mac_addr[0] &= ~0x01; /* Clear multicast bit */ + sss->mac_addr[0] |= 0x02; /* Set locally-assigned bit */ + + tmp_string = calloc(1, strlen(N2N_MGMT_PASSWORD) + 1); + if(tmp_string) { + strncpy((char*)tmp_string, N2N_MGMT_PASSWORD, strlen(N2N_MGMT_PASSWORD) + 1); + sss->mgmt_password_hash = pearson_hash_64((uint8_t*)tmp_string, strlen(N2N_MGMT_PASSWORD)); + free(tmp_string); + } + + return 0; /* OK */ +} + + +/** Initialise the supernode */ +void sn_init (n2n_sn_t *sss) { + + if(resolve_create_thread(&(sss->resolve_parameter), sss->federation->edges) == 0) { + traceEvent(TRACE_NORMAL, "successfully created resolver thread"); + } +} + + +/** Deinitialise the supernode structure and deallocate any memory owned by + * it. */ +void sn_term (n2n_sn_t *sss) { + + struct sn_community *community, *tmp; + struct sn_community_regular_expression *re, *tmp_re; + n2n_tcp_connection_t *conn, *tmp_conn; + node_supernode_association_t *assoc, *tmp_assoc; + + resolve_cancel_thread(sss->resolve_parameter); + + if(sss->sock >= 0) { + closesocket(sss->sock); + } + sss->sock = -1; + + HASH_ITER(hh, sss->tcp_connections, conn, tmp_conn) { + shutdown(conn->socket_fd, SHUT_RDWR); + closesocket(conn->socket_fd); + HASH_DEL(sss->tcp_connections, conn); + free(conn); + } + + if(sss->tcp_sock >= 0) { + shutdown(sss->tcp_sock, SHUT_RDWR); + closesocket(sss->tcp_sock); + } + sss->tcp_sock = -1; + + if(sss->mgmt_sock >= 0) { + closesocket(sss->mgmt_sock); + } + sss->mgmt_sock = -1; + + HASH_ITER(hh, sss->communities, community, tmp) { + clear_peer_list(&community->edges); + if(NULL != community->header_encryption_ctx_static) { + free(community->header_encryption_ctx_static); + free(community->header_encryption_ctx_dynamic); + } + // remove all associations + HASH_ITER(hh, community->assoc, assoc, tmp_assoc) { + HASH_DEL(community->assoc, assoc); + free(assoc); + } + HASH_DEL(sss->communities, community); + free(community); + } + + HASH_ITER(hh, sss->rules, re, tmp_re) { + HASH_DEL(sss->rules, re); + if (NULL != re->rule) { + free(re->rule); + } + free(re); + } + + if(sss->community_file) + free(sss->community_file); +#ifdef WIN32 + destroyWin32(); +#endif +} + +void update_node_supernode_association (struct sn_community *comm, + n2n_mac_t *edgeMac, const struct sockaddr_in *sender_sock, + time_t now) { + + node_supernode_association_t *assoc; + + HASH_FIND(hh, comm->assoc, edgeMac, sizeof(n2n_mac_t), assoc); + if(!assoc) { + // create a new association + assoc = (node_supernode_association_t*)malloc(sizeof(node_supernode_association_t)); + if(assoc) { + memcpy(&(assoc->mac), edgeMac, sizeof(n2n_mac_t)); + memcpy((struct sockaddr_in*)&(assoc->sock), sender_sock, sizeof(struct sockaddr_in)); + assoc->last_seen = now; + HASH_ADD(hh, comm->assoc, mac, sizeof(n2n_mac_t), assoc); + } else { + // already there, update socket and time only + memcpy((struct sockaddr_in*)&(assoc->sock), sender_sock, sizeof(struct sockaddr_in)); + assoc->last_seen = now; + } + } +} + + +/** Determine the appropriate lifetime for new registrations. + * + * If the supernode has been put into a pre-shutdown phase then this lifetime + * should not allow registrations to continue beyond the shutdown point. + */ +static uint16_t reg_lifetime (n2n_sn_t *sss) { + + /* NOTE: UDP firewalls usually have a 30 seconds timeout */ + return 15; +} + + +/** Verifies authentication tokens from known edges. + * + * It is called by update_edge and during UNREGISTER_SUPER handling + * to verify the stored auth token. + */ +static int auth_edge (const n2n_auth_t *present, const n2n_auth_t *presented, n2n_auth_t *answer, struct sn_community *community) { + + sn_user_t *user = NULL; + + if(present->scheme == n2n_auth_none) { + // n2n_auth_none scheme (set at supernode if cli option '-M') + // if required, zero_token answer (not for NAK) + if(answer) + memset(answer, 0, sizeof(n2n_auth_t)); + // 0 == (always) successful + return 0; + } + + if((present->scheme == n2n_auth_simple_id) && (presented->scheme == n2n_auth_simple_id)) { + // n2n_auth_simple_id scheme: if required, zero_token answer (not for NAK) + if(answer) + memset(answer, 0, sizeof(n2n_auth_t)); + + // 0 = success (tokens are equal) + return (memcmp(present, presented, sizeof(n2n_auth_t))); + } + + if((present->scheme == n2n_auth_user_password) && (presented->scheme == n2n_auth_user_password)) { + // check if submitted public key is in list of allowed users + HASH_FIND(hh, community->allowed_users, &presented->token, sizeof(n2n_private_public_key_t), user); + if(user) { + if(answer) { + memcpy(answer, presented, sizeof(n2n_auth_t)); + + // return a double-encrypted challenge (just encrypt again) in the (first half of) public key field so edge can verify + memcpy(answer->token, answer->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, N2N_AUTH_CHALLENGE_SIZE); + speck_128_encrypt(answer->token, (speck_context_t*)user->shared_secret_ctx); + + // decrypt the challenge using user's shared secret + speck_128_decrypt(answer->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, (speck_context_t*)user->shared_secret_ctx); + // xor-in the community dynamic key + memxor(answer->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, community->dynamic_key, N2N_AUTH_CHALLENGE_SIZE); + // xor-in the user's shared secret + memxor(answer->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, user->shared_secret, N2N_AUTH_CHALLENGE_SIZE); + // encrypt it using user's shared secret + speck_128_encrypt(answer->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, (speck_context_t*)user->shared_secret_ctx); + // user in list? success! (we will see if edge can handle the key for further com) + } + return 0; + } + } + + // if not successful earlier: failure + return -1; +} + + +// provides the current / a new local auth token +// REVISIT: behavior should depend on some local auth scheme setting (to be implemented) +static int get_local_auth (n2n_sn_t *sss, n2n_auth_t *auth) { + + // n2n_auth_simple_id scheme + memcpy(auth, &(sss->auth), sizeof(n2n_auth_t)); + + return 0; +} + + +// handles an incoming (remote) auth token from a so far unknown edge, +// takes action as required by auth scheme, and +// could provide an answer auth token for use in REGISTER_SUPER_ACK +static int handle_remote_auth (n2n_sn_t *sss, const n2n_auth_t *remote_auth, + n2n_auth_t *answer_auth, + struct sn_community *community) { + + sn_user_t *user = NULL; + + if((NULL == community->allowed_users) != (remote_auth->scheme != n2n_auth_user_password)) { + // received token's scheme does not match expected scheme + return -1; + } + + switch(remote_auth->scheme) { + // we do not handle n2n_auth_none because the edge always edge always uses either id or user/password + // auth_none is sn-internal only (skipping MAC/IP address spoofing protection) + case n2n_auth_none: + case n2n_auth_simple_id: + // zero_token answer + memset(answer_auth, 0, sizeof(n2n_auth_t)); + return 0; + case n2n_auth_user_password: + // check if submitted public key is in list of allowed users + HASH_FIND(hh, community->allowed_users, &remote_auth->token, sizeof(n2n_private_public_key_t), user); + if(user) { + memcpy(answer_auth, remote_auth, sizeof(n2n_auth_t)); + + // return a double-encrypted challenge (just encrypt again) in the (first half of) public key field so edge can verify + memcpy(answer_auth->token, answer_auth->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, N2N_AUTH_CHALLENGE_SIZE); + speck_128_encrypt(answer_auth->token, (speck_context_t*)user->shared_secret_ctx); + + // wrap dynamic key for transmission + // decrypt the challenge using user's shared secret + speck_128_decrypt(answer_auth->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, (speck_context_t*)user->shared_secret_ctx); + // xor-in the community dynamic key + memxor(answer_auth->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, community->dynamic_key, N2N_AUTH_CHALLENGE_SIZE); + // xor-in the user's shared secret + memxor(answer_auth->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, user->shared_secret, N2N_AUTH_CHALLENGE_SIZE); + // encrypt it using user's shared secret + speck_128_encrypt(answer_auth->token + N2N_PRIVATE_PUBLIC_KEY_SIZE, (speck_context_t*)user->shared_secret_ctx); + return 0; + } + break; + default: + break; + } + + // if not successful earlier: failure + return -1; +} + + +/** Update the edge table with the details of the edge which contacted the + * supernode. */ +static int update_edge (n2n_sn_t *sss, + const n2n_common_t* cmn, + const n2n_REGISTER_SUPER_t* reg, + struct sn_community *comm, + const n2n_sock_t *sender_sock, + const SOCKET socket_fd, + n2n_auth_t *answer_auth, + int skip_add, + time_t now) { + + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + struct peer_info *scan, *iter, *tmp; + int ret; + + traceEvent(TRACE_DEBUG, "update_edge for %s [%s]", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); + + HASH_FIND_PEER(comm->edges, reg->edgeMac, scan); + + // if unknown, make sure it is also not known by IP address + if(NULL == scan) { + HASH_ITER(hh,comm->edges,iter,tmp) { + if(iter->dev_addr.net_addr == reg->dev_addr.net_addr) { + scan = iter; + HASH_DEL(comm->edges, scan); + memcpy(scan->mac_addr, reg->edgeMac, sizeof(n2n_mac_t)); + HASH_ADD_PEER(comm->edges, scan); + break; + } + } + } + + if(NULL == scan) { + /* Not known */ + if(handle_remote_auth(sss, &(reg->auth), answer_auth, comm) == 0) { + if(skip_add == SN_ADD) { + scan = (struct peer_info *) calloc(1, sizeof(struct peer_info)); /* deallocated in purge_expired_nodes */ + memcpy(&(scan->mac_addr), reg->edgeMac, sizeof(n2n_mac_t)); + scan->dev_addr.net_addr = reg->dev_addr.net_addr; + scan->dev_addr.net_bitlen = reg->dev_addr.net_bitlen; + memcpy((char*)scan->dev_desc, reg->dev_desc, N2N_DESC_SIZE); + memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); + scan->socket_fd = socket_fd; + scan->last_cookie = reg->cookie; + scan->last_valid_time_stamp = initial_time_stamp(); + // eventually, store edge's preferred local socket from REGISTER_SUPER + if(cmn->flags & N2N_FLAGS_SOCKET) + memcpy(&scan->preferred_sock, ®->sock, sizeof(n2n_sock_t)); + else + scan->preferred_sock.family = AF_INVALID; + + // store the submitted auth token + memcpy(&(scan->auth), &(reg->auth), sizeof(n2n_auth_t)); + // manually set to type 'auth_none' if cli option disables MAC/IP address spoofing protection + // for id based auth communities. This will be obsolete when handling public keys only (v4.0?) + if((reg->auth.scheme == n2n_auth_simple_id) && (sss->override_spoofing_protection)) + scan->auth.scheme = n2n_auth_none; + + HASH_ADD_PEER(comm->edges, scan); + + traceEvent(TRACE_INFO, "created edge %s ==> %s", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); + } + ret = update_edge_new_sn; + } else { + traceEvent(TRACE_INFO, "authentication failed"); + ret = update_edge_auth_fail; + } + } else { + /* Known */ + if(auth_edge(&(scan->auth), &(reg->auth), answer_auth, comm) == 0) { + if(!sock_equal(sender_sock, &(scan->sock))) { + memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); + scan->socket_fd = socket_fd; + scan->last_cookie = reg->cookie; + // eventually, update edge's preferred local socket from REGISTER_SUPER + if(cmn->flags & N2N_FLAGS_SOCKET) + memcpy(&scan->preferred_sock, ®->sock, sizeof(n2n_sock_t)); + else + scan->preferred_sock.family = AF_INVALID; + + traceEvent(TRACE_INFO, "updated edge %s ==> %s", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); + ret = update_edge_sock_change; + } else { + scan->last_cookie = reg->cookie; + + traceEvent(TRACE_DEBUG, "edge unchanged %s ==> %s", + macaddr_str(mac_buf, reg->edgeMac), + sock_to_cstr(sockbuf, sender_sock)); + + ret = update_edge_no_change; + } + } else { + traceEvent(TRACE_INFO, "authentication failed"); + ret = update_edge_auth_fail; + } + } + + if((scan != NULL) && (ret != update_edge_auth_fail)) { + scan->last_seen = now; + } + + return ret; +} + + +/** checks if a certain ip address is still available, i.e. not used by any other edge of a given community */ +static int ip_addr_available (struct sn_community *comm, n2n_ip_subnet_t *ip_addr) { + + int success = 1; + struct peer_info *peer, *tmp_peer; + + // prerequisite: list of peers is sorted according to peer's tap ip address + HASH_ITER(hh, comm->edges, peer, tmp_peer) { + if(peer->dev_addr.net_addr > ip_addr->net_addr) { + break; + } + if(peer->dev_addr.net_addr == ip_addr->net_addr) { + success = 0; + break; + } + } + + return success; +} + + +static signed int peer_tap_ip_sort (struct peer_info *a, struct peer_info *b) { + + uint32_t a_host_id = a->dev_addr.net_addr & (~bitlen2mask(a->dev_addr.net_bitlen)); + uint32_t b_host_id = b->dev_addr.net_addr & (~bitlen2mask(b->dev_addr.net_bitlen)); + + return ((signed int)a_host_id - (signed int)b_host_id); +} + + +/** The IP address assigned to the edge by the auto ip address function of sn. */ +static int assign_one_ip_addr (struct sn_community *comm, n2n_desc_t dev_desc, n2n_ip_subnet_t *ip_addr) { + + uint32_t tmp, success, net_id, mask, max_host, host_id = 1; + dec_ip_bit_str_t ip_bit_str = {'\0'}; + + mask = bitlen2mask(comm->auto_ip_net.net_bitlen); + net_id = comm->auto_ip_net.net_addr & mask; + max_host = ~mask; + + // sorting is a prerequisite for more efficient availabilitiy check + HASH_SORT(comm->edges, peer_tap_ip_sort); + + // first proposal derived from hash of mac address + tmp = pearson_hash_32(dev_desc, sizeof(n2n_desc_t)) & max_host; + if(tmp == 0) tmp++; /* avoid 0 host */ + if(tmp == max_host) tmp--; /* avoid broadcast address */ + tmp |= net_id; + + // candidate + ip_addr->net_bitlen = comm->auto_ip_net.net_bitlen; + + // check for availability starting from proposal, then downwards, ... + for(host_id = tmp; host_id > net_id; host_id--) { + ip_addr->net_addr = host_id; + success = ip_addr_available(comm, ip_addr); + if(success) { + break; + } + } + // ... then upwards + if(!success) { + for(host_id = tmp + 1; host_id < (net_id + max_host); host_id++) { + ip_addr->net_addr = host_id; + success = ip_addr_available(comm, ip_addr); + if(success) { + break; + } + } + } + + if(success) { + traceEvent(TRACE_INFO, "assign IP %s to tap adapter of edge", ip_subnet_to_str(ip_bit_str, ip_addr)); + return 0; + } else { + traceEvent(TRACE_WARNING, "no assignable IP to edge tap adapter"); + return -1; + } +} + + +/** checks if a certain sub-network is still available, i.e. does not cut any other community's sub-network */ +int subnet_available (n2n_sn_t *sss, + struct sn_community *comm, + uint32_t net_id, + uint32_t mask) { + + struct sn_community *cmn, *tmpCmn; + int success = 1; + + HASH_ITER(hh, sss->communities, cmn, tmpCmn) { + if(cmn == comm) { + continue; + } + if(cmn->is_federation == IS_FEDERATION) { + continue; + } + if((net_id <= (cmn->auto_ip_net.net_addr + ~bitlen2mask(cmn->auto_ip_net.net_bitlen))) + &&(net_id + ~mask >= cmn->auto_ip_net.net_addr)) { + success = 0; + break; + } + } + + return success; +} + + +/** The IP address range (subnet) assigned to the community by the auto ip address function of sn. */ +int assign_one_ip_subnet (n2n_sn_t *sss, + struct sn_community *comm) { + + uint32_t net_id, net_id_i, mask, net_increment; + uint32_t no_subnets; + uint8_t success; + in_addr_t net; + + mask = bitlen2mask(sss->min_auto_ip_net.net_bitlen); + // number of possible sub-networks + no_subnets = (sss->max_auto_ip_net.net_addr - sss->min_auto_ip_net.net_addr); + no_subnets >>= (32 - sss->min_auto_ip_net.net_bitlen); + no_subnets += 1; + + // proposal for sub-network to choose + net_id = pearson_hash_32((const uint8_t *)comm->community, N2N_COMMUNITY_SIZE) % no_subnets; + net_id = sss->min_auto_ip_net.net_addr + (net_id << (32 - sss->min_auto_ip_net.net_bitlen)); + + // check for availability starting from net_id, then downwards, ... + net_increment = (~mask+1); + for(net_id_i = net_id; net_id_i >= sss->min_auto_ip_net.net_addr; net_id_i -= net_increment) { + success = subnet_available(sss, comm, net_id_i, mask); + if(success) { + break; + } + } + // ... then upwards + if(!success) { + for(net_id_i = net_id + net_increment; net_id_i <= sss->max_auto_ip_net.net_addr; net_id_i += net_increment) { + success = subnet_available(sss, comm, net_id_i, mask); + if(success) { + break; + } + } + } + + if(success) { + comm->auto_ip_net.net_addr = net_id_i; + comm->auto_ip_net.net_bitlen = sss->min_auto_ip_net.net_bitlen; + net = htonl(comm->auto_ip_net.net_addr); + traceEvent(TRACE_INFO, "assigned sub-network %s/%u to community '%s'", + inet_ntoa(*(struct in_addr *) &net), + comm->auto_ip_net.net_bitlen, + comm->community); + return 0; + } else { + comm->auto_ip_net.net_addr = 0; + comm->auto_ip_net.net_bitlen = 0; + traceEvent(TRACE_WARNING, "no assignable sub-network left for community '%s'", + comm->community); + return -1; + } +} + + +/*** + * + * For a given packet, find the apporopriate internal last valid time stamp for lookup + * and verify it (and also update, if applicable). + */ +static int find_edge_time_stamp_and_verify (struct peer_info * edges, + peer_info_t *sn, n2n_mac_t mac, + uint64_t stamp, int allow_jitter) { + + uint64_t *previous_stamp = NULL; + + if(sn) { + previous_stamp = &(sn->last_valid_time_stamp); + } else { + struct peer_info *edge; + HASH_FIND_PEER(edges, mac, edge); + + if(edge) { + // time_stamp_verify_and_update allows the pointer a previous stamp to be NULL + // if it is a (so far) unknown edge + previous_stamp = &(edge->last_valid_time_stamp); + } + } + + // failure --> 0; success --> 1 + return time_stamp_verify_and_update(stamp, previous_stamp, allow_jitter); +} + + +static int re_register_and_purge_supernodes (n2n_sn_t *sss, struct sn_community *comm, time_t *p_last_re_reg_and_purge, time_t now, uint8_t forced) { + + time_t time; + struct peer_info *peer, *tmp; + + if(!forced) { + if((now - (*p_last_re_reg_and_purge)) < RE_REG_AND_PURGE_FREQUENCY) { + return 0; + } + + // purge long-time-not-seen supernodes + purge_expired_nodes(&(comm->edges), sss->sock, &sss->tcp_connections, p_last_re_reg_and_purge, + RE_REG_AND_PURGE_FREQUENCY, LAST_SEEN_SN_INACTIVE); + } + + if(comm != NULL) { + HASH_ITER(hh,comm->edges,peer,tmp) { + + time = now - peer->last_seen; + + if(!forced) { + if(time <= LAST_SEEN_SN_ACTIVE) { + continue; + } + } + + /* re-register (send REGISTER_SUPER) */ + uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0}; + size_t idx; + /* ssize_t sent; */ + n2n_common_t cmn; + n2n_REGISTER_SUPER_t reg; + n2n_sock_str_t sockbuf; + + memset(&cmn, 0, sizeof(cmn)); + memset(®, 0, sizeof(reg)); + + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_register_super; + cmn.flags = N2N_FLAGS_FROM_SUPERNODE; + memcpy(cmn.community, comm->community, N2N_COMMUNITY_SIZE); + + reg.cookie = n2n_rand(); + peer->last_cookie = reg.cookie; + + reg.dev_addr.net_addr = ntohl(peer->dev_addr.net_addr); + reg.dev_addr.net_bitlen = mask2bitlen(ntohl(peer->dev_addr.net_bitlen)); + get_local_auth(sss, &(reg.auth)); + + reg.key_time = sss->dynamic_key_time; + + idx = 0; + encode_mac(reg.edgeMac, &idx, sss->mac_addr); + + idx = 0; + encode_REGISTER_SUPER(pktbuf, &idx, &cmn, ®); + + traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s", + sock_to_cstr(sockbuf, &(peer->sock))); + + packet_header_encrypt(pktbuf, idx, idx, + comm->header_encryption_ctx_static, comm->header_iv_ctx_static, + time_stamp()); + + /* sent = */ sendto_peer(sss, peer, pktbuf, idx); + } + } + + return 0; /* OK */ +} + + +static int purge_expired_communities (n2n_sn_t *sss, + time_t* p_last_purge, + time_t now) { + + struct sn_community *comm, *tmp_comm; + node_supernode_association_t *assoc, *tmp_assoc; + size_t num_reg = 0; + size_t num_assoc = 0; + + if((now - (*p_last_purge)) < PURGE_REGISTRATION_FREQUENCY) { + return 0; + } + + traceEvent(TRACE_DEBUG, "purging old communities and edges"); + + HASH_ITER(hh, sss->communities, comm, tmp_comm) { + // federation is taken care of in re_register_and_purge_supernodes() + if(comm->is_federation == IS_FEDERATION) + continue; + + // purge the community's local peers + num_reg += purge_peer_list(&comm->edges, sss->sock, &sss->tcp_connections, now - REGISTRATION_TIMEOUT); + + // purge the community's associated peers (connected to other supernodes) + HASH_ITER(hh, comm->assoc, assoc, tmp_assoc) { + if(comm->assoc->last_seen < (now - 3 * REGISTRATION_TIMEOUT)) { + HASH_DEL(comm->assoc, assoc); + free(assoc); + num_assoc++; + } + } + + if((comm->edges == NULL) && (comm->purgeable == COMMUNITY_PURGEABLE)) { + traceEvent(TRACE_INFO, "purging idle community %s", comm->community); + if(NULL != comm->header_encryption_ctx_static) { + /* this should not happen as 'purgeable' and thus only communities w/o encrypted header here */ + free(comm->header_encryption_ctx_static); + free(comm->header_iv_ctx_static); + free(comm->header_encryption_ctx_dynamic); + free(comm->header_iv_ctx_dynamic); + } + // remove all associations + HASH_ITER(hh, comm->assoc, assoc, tmp_assoc) { + HASH_DEL(comm->assoc, assoc); + free(assoc); + } + HASH_DEL(sss->communities, comm); + free(comm); + } + } + (*p_last_purge) = now; + + traceEvent(TRACE_DEBUG, "purge_expired_communities removed %ld locally registered edges and %ld remotely associated edges", + num_reg, num_assoc); + + return 0; +} + + +static int number_enc_packets_sort (struct sn_community *a, struct sn_community *b) { + + // comparison function for sorting communities in descending order of their + // number_enc_packets-fields + return (b->number_enc_packets - a->number_enc_packets); +} + + +static int sort_communities (n2n_sn_t *sss, + time_t* p_last_sort, + time_t now) { + + struct sn_community *comm, *tmp; + + if((now - (*p_last_sort)) < SORT_COMMUNITIES_INTERVAL) { + return 0; + } + + // this routine gets periodically called as defined in SORT_COMMUNITIES_INTERVAL + // it sorts the communities in descending order of their number_enc_packets-fields... + HASH_SORT(sss->communities, number_enc_packets_sort); + + // ... and afterward resets the number_enc__packets-fields to zero + // (other models could reset it to half of their value to respect history) + HASH_ITER(hh, sss->communities, comm, tmp) { + comm->number_enc_packets = 0; + } + + (*p_last_sort) = now; + + return 0; +} + + +/** Examine a datagram and determine what to do with it. + * + */ +static int process_udp (n2n_sn_t * sss, + const struct sockaddr_in *sender_sock, + const SOCKET socket_fd, + uint8_t * udp_buf, + size_t udp_size, + time_t now) { + + n2n_common_t cmn; /* common fields in the packet header */ + size_t rem; + size_t idx; + size_t msg_type; + uint8_t from_supernode; + peer_info_t *sn = NULL; + n2n_sock_t sender; + macstr_t mac_buf; + macstr_t mac_buf2; + n2n_sock_str_t sockbuf; + char buf[32]; + uint8_t hash_buf[16] = {0}; /* always size of 16 (max) despite the actual value of N2N_REG_SUP_HASH_CHECK_LEN (<= 16) */ + + struct sn_community *comm, *tmp; + uint32_t header_enc = 0; /* 1 == encrypted by static key, 2 == encrypted by dynamic key */ + uint64_t stamp; + int skip_add; + time_t any_time = 0; + + traceEvent(TRACE_DEBUG, "processing incoming UDP packet [len: %lu][sender: %s:%u]", + udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)), + ntohs(sender_sock->sin_port)); + + /* check if header is unencrypted. the following check is around 99.99962 percent reliable. + * it heavily relies on the structure of packet's common part + * changes to wire.c:encode/decode_common need to go together with this code */ + if(udp_size < 24) { + traceEvent(TRACE_DEBUG, "dropped a packet too short to be valid"); + return -1; + } + if((udp_buf[23] == (uint8_t)0x00) // null terminated community name + && (udp_buf[00] == N2N_PKT_VERSION) // correct packet version + && ((be16toh(*(uint16_t*)&(udp_buf[02])) & N2N_FLAGS_TYPE_MASK) <= MSG_TYPE_MAX_TYPE) // message type + && ( be16toh(*(uint16_t*)&(udp_buf[02])) < N2N_FLAGS_OPTIONS) // flags + ) { + /* most probably unencrypted */ + /* make sure, no downgrading happens here and no unencrypted packets can be + * injected in a community which definitely deals with encrypted headers */ + HASH_FIND_COMMUNITY(sss->communities, (char *)&udp_buf[04], comm); + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + traceEvent(TRACE_DEBUG, "dropped a packet with unencrypted header " + "addressed to community '%s' which uses encrypted headers", + comm->community); + return -1; + } + if(comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) { + traceEvent(TRACE_INFO, "locked community '%s' to " + "unencrypted headers", comm->community); + /* set 'no encryption' in case it is not set yet */ + comm->header_encryption = HEADER_ENCRYPTION_NONE; + comm->header_encryption_ctx_static = NULL; + comm->header_encryption_ctx_dynamic = NULL; + } + } + } else { + /* most probably encrypted */ + /* cycle through the known communities (as keys) to eventually decrypt */ + HASH_ITER(hh, sss->communities, comm, tmp) { + /* skip the definitely unencrypted communities */ + if(comm->header_encryption == HEADER_ENCRYPTION_NONE) { + continue; + } + + // match with static (1) or dynamic (2) ctx? + // check dynamic first as it is identical to static in normal header encryption mode + if(packet_header_decrypt(udp_buf, udp_size, + comm->community, + comm->header_encryption_ctx_dynamic, comm->header_iv_ctx_dynamic, + &stamp)) { + header_enc = 2; + } + if(!header_enc) { + pearson_hash_128(hash_buf, udp_buf, max(0, (int)udp_size - (int)N2N_REG_SUP_HASH_CHECK_LEN)); + header_enc = packet_header_decrypt(udp_buf, max(0, (int)udp_size - (int)N2N_REG_SUP_HASH_CHECK_LEN), comm->community, + comm->header_encryption_ctx_static, comm->header_iv_ctx_static, &stamp); + } + + if(header_enc) { + // time stamp verification follows in the packet specific section as it requires to determine the + // sender from the hash list by its MAC, this all depends on packet type and packet structure + // (MAC is not always in the same place) + + if(comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) { + traceEvent(TRACE_INFO, "locked community '%s' to " + "encrypted headers", comm->community); + /* set 'encrypted' in case it is not set yet */ + comm->header_encryption = HEADER_ENCRYPTION_ENABLED; + } + // count the number of encrypted packets for sorting the communities from time to time + // for the HASH_ITER a few lines above gets faster for the more busy communities + (comm->number_enc_packets)++; + // no need to test further communities + break; + } + } + if(!header_enc) { + // no matching key/community + traceEvent(TRACE_DEBUG, "dropped a packet with seemingly encrypted header " + "for which no matching community which uses encrypted headers was found"); + return -1; + } + } + + /* Use decode_common() to determine the kind of packet then process it: + * + * REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK + * + * REGISTER, REGISTER_ACK and PACKET messages are forwarded to their + * destination edge. If the destination is not known then PACKETs are + * broadcast. + */ + + rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */ + idx = 0; /* marches through packet header as parts are decoded. */ + + if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) { + traceEvent(TRACE_ERROR, "failed to decode common section"); + return -1; /* failed to decode packet */ + } + + msg_type = cmn.pc; /* packet code */ + + // special case for user/pw auth + // community's auth scheme and message type need to match the used key (dynamic) + if(comm) { + if((comm->allowed_users) + && (msg_type != MSG_TYPE_REGISTER_SUPER) + && (msg_type != MSG_TYPE_REGISTER_SUPER_ACK) + && (msg_type != MSG_TYPE_REGISTER_SUPER_NAK)) { + if(header_enc != 2) { + traceEvent(TRACE_WARNING, "dropped packet encrypted with static key where expecting dynamic key"); + return -1; + } + } + } + + /* REVISIT: when UDP/IPv6 is supported we will need a flag to indicate which + * IP transport version the packet arrived on. May need to UDP sockets. */ + memset(&sender, 0, sizeof(n2n_sock_t)); + sender.family = AF_INET; /* UDP socket was opened PF_INET v4 */ + sender.port = ntohs(sender_sock->sin_port); + memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + from_supernode = cmn.flags & N2N_FLAGS_FROM_SUPERNODE; + if(from_supernode) { + skip_add = SN_ADD_SKIP; + sn = add_sn_to_list_by_mac_or_sock (&(sss->federation->edges), &sender, null_mac, &skip_add); + // only REGISTER_SUPER allowed from unknown supernodes + if((!sn) && (msg_type != MSG_TYPE_REGISTER_SUPER)) { + traceEvent(TRACE_DEBUG, "dropped incoming data from unknown supernode"); + return -1; + } + } + + if(cmn.ttl < 1) { + traceEvent(TRACE_WARNING, "expired TTL"); + return 0; /* Don't process further */ + } + + --(cmn.ttl); /* The value copied into all forwarded packets. */ + + switch(msg_type) { + case MSG_TYPE_PACKET: { + /* PACKET from one edge to another edge via supernode. */ + + /* pkt will be modified in place and recoded to an output of potentially + * different size due to addition of the socket.*/ + n2n_PACKET_t pkt; + n2n_common_t cmn2; + uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx = 0; + int unicast; /* non-zero if unicast */ + uint8_t * rec_buf; /* either udp_buf or encbuf */ + + if(!comm) { + traceEvent(TRACE_DEBUG, "PACKET with unknown community %s", cmn.community); + return -1; + } + + sss->stats.last_fwd = now; + decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); + + // already checked for valid comm + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, sn, pkt.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped PACKET due to time stamp error"); + return -1; + } + } + + unicast = (0 == is_multi_broadcast(pkt.dstMac)); + + traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s", + (unicast ? "unicast" : "multicast"), + macaddr_str(mac_buf, pkt.srcMac), + macaddr_str(mac_buf2, pkt.dstMac), + (from_supernode ? "from sn" : "local")); + + if(!from_supernode) { + memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); + + /* We are going to add socket even if it was not there before */ + cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + + pkt.sock.family = AF_INET; + pkt.sock.port = ntohs(sender_sock->sin_port); + memcpy(pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + rec_buf = encbuf; + /* Re-encode the header. */ + encode_PACKET(encbuf, &encx, &cmn2, &pkt); + + uint16_t oldEncx = encx; + + /* Copy the original payload unchanged */ + encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx)); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + // in case of user-password auth, also encrypt the iv of payload assuming ChaCha20 and SPECK having the same iv size + packet_header_encrypt(rec_buf, oldEncx + (NULL != comm->allowed_users) * min(encx - oldEncx, N2N_SPECK_IVEC_SIZE), encx, + comm->header_encryption_ctx_dynamic, comm->header_iv_ctx_dynamic, + time_stamp()); + } + } else { + /* Already from a supernode. Nothing to modify, just pass to + * destination. */ + + traceEvent(TRACE_DEBUG, "Rx PACKET fwd unmodified"); + + rec_buf = udp_buf; + encx = udp_size; + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + // in case of user-password auth, also encrypt the iv of payload assuming ChaCha20 and SPECK having the same iv size + packet_header_encrypt(rec_buf, idx + (NULL != comm->allowed_users) * min(encx - idx, N2N_SPECK_IVEC_SIZE), encx, + comm->header_encryption_ctx_dynamic, comm->header_iv_ctx_dynamic, + time_stamp()); + } + } + + /* Common section to forward the final product. */ + if(unicast) { + try_forward(sss, comm, &cmn, pkt.dstMac, from_supernode, rec_buf, encx, now); + } else { + try_broadcast(sss, comm, &cmn, pkt.srcMac, from_supernode, rec_buf, encx, now); + } + break; + } + + case MSG_TYPE_REGISTER: { + /* Forwarding a REGISTER from one edge to the next */ + + n2n_REGISTER_t reg; + n2n_common_t cmn2; + uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx = 0; + int unicast; /* non-zero if unicast */ + uint8_t * rec_buf; /* either udp_buf or encbuf */ + + if(!comm) { + traceEvent(TRACE_DEBUG, "REGISTER from unknown community %s", cmn.community); + return -1; + } + + sss->stats.last_fwd = now; + decode_REGISTER(®, &cmn, udp_buf, &rem, &idx); + + // already checked for valid comm + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, sn, reg.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped REGISTER due to time stamp error"); + return -1; + } + } + + unicast = (0 == is_multi_broadcast(reg.dstMac)); + + if(unicast) { + traceEvent(TRACE_DEBUG, "Rx REGISTER %s -> %s %s", + macaddr_str(mac_buf, reg.srcMac), + macaddr_str(mac_buf2, reg.dstMac), + ((cmn.flags & N2N_FLAGS_FROM_SUPERNODE) ? "from sn" : "local")); + + if(0 == (cmn.flags & N2N_FLAGS_FROM_SUPERNODE)) { + memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); + + /* We are going to add socket even if it was not there before */ + cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + + reg.sock.family = AF_INET; + reg.sock.port = ntohs(sender_sock->sin_port); + memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + /* Re-encode the header. */ + encode_REGISTER(encbuf, &encx, &cmn2, ®); + + rec_buf = encbuf; + } else { + /* Already from a supernode. Nothing to modify, just pass to + * destination. */ + + rec_buf = udp_buf; + encx = udp_size; + } + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(rec_buf, encx, encx, + comm->header_encryption_ctx_dynamic, comm->header_iv_ctx_dynamic, + time_stamp()); + } + try_forward(sss, comm, &cmn, reg.dstMac, from_supernode, rec_buf, encx, now); /* unicast only */ + } else { + traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination"); + } + break; + } + + case MSG_TYPE_REGISTER_ACK: { + traceEvent(TRACE_DEBUG, "Rx REGISTER_ACK (not implemented) should not be via supernode"); + break; + } + + case MSG_TYPE_REGISTER_SUPER: { + n2n_REGISTER_SUPER_t reg; + n2n_REGISTER_SUPER_ACK_t ack; + n2n_REGISTER_SUPER_NAK_t nak; + n2n_common_t cmn2; + uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; + uint8_t payload_buf[REG_SUPER_ACK_PAYLOAD_SPACE]; + n2n_REGISTER_SUPER_ACK_payload_t *payload; + size_t encx = 0; + struct sn_community_regular_expression *re, *tmp_re; + struct peer_info *peer, *tmp_peer, *p; + int8_t allowed_match = -1; + uint8_t match = 0; + int match_length = 0; + n2n_ip_subnet_t ipaddr; + int num = 0; + int skip; + int ret_value; + sn_user_t *user = NULL; + + memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); + memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + + /* Edge/supernode requesting registration with us. */ + sss->stats.last_reg_super=now; + ++(sss->stats.reg_super); + decode_REGISTER_SUPER(®, &cmn, udp_buf, &rem, &idx); + + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, sn, reg.edgeMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped REGISTER_SUPER due to time stamp error"); + return -1; + } + } + } + + /* + Before we move any further, we need to check if the requested + community is allowed by the supernode. In case it is not we do + not report any message back to the edge to hide the supernode + existance (better from the security standpoint) + */ + + if(!comm && sss->lock_communities) { + HASH_ITER(hh, sss->rules, re, tmp_re) { + allowed_match = re_matchp(re->rule, (const char *)cmn.community, &match_length); + + if((allowed_match != -1) + && (match_length == strlen((const char *)cmn.community)) // --- only full matches allowed (remove, if also partial matches wanted) + && (allowed_match == 0)) { // --- only full matches allowed (remove, if also partial matches wanted) + match = 1; + break; + } + } + if(match != 1) { + traceEvent(TRACE_INFO, "discarded registration with unallowed community '%s'", + (char*)cmn.community); + return -1; + } + } + + if(!comm && (!sss->lock_communities || (match == 1))) { + comm = (struct sn_community*)calloc(1, sizeof(struct sn_community)); + + if(comm) { + comm_init(comm, (char *)cmn.community); + /* new communities introduced by REGISTERs could not have had encrypted header... */ + comm->header_encryption = HEADER_ENCRYPTION_NONE; + comm->header_encryption_ctx_static = NULL; + comm->header_encryption_ctx_dynamic = NULL; + /* ... and also are purgeable during periodic purge */ + comm->purgeable = COMMUNITY_PURGEABLE; + comm->number_enc_packets = 0; + HASH_ADD_STR(sss->communities, community, comm); + + traceEvent(TRACE_INFO, "new community: %s", comm->community); + assign_one_ip_subnet(sss, comm); + } + } + + if(!comm) { + traceEvent(TRACE_INFO, "discarded registration with unallowed community '%s'", + (char*)cmn.community); + return -1; + } + + // hash check (user/pw auth only) + if(comm->allowed_users) { + // check if submitted public key is in list of allowed users + HASH_FIND(hh, comm->allowed_users, ®.auth.token, sizeof(n2n_private_public_key_t), user); + if(user) { + speck_128_encrypt(hash_buf, (speck_context_t*)user->shared_secret_ctx); + if(memcmp(hash_buf, udp_buf + udp_size - N2N_REG_SUP_HASH_CHECK_LEN /* length has already been checked */, N2N_REG_SUP_HASH_CHECK_LEN)) { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER with wrong hash"); + return -1; + } + } else { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER from unknown user"); + // continue and let auth check do the rest (otherwise, no NAK is sent) + } + } + + if(!memcmp(reg.edgeMac, sss->mac_addr, sizeof(n2n_mac_t))) { + traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER from self, ignoring"); + return -1; + } + + cmn2.ttl = N2N_DEFAULT_TTL; + cmn2.pc = n2n_register_super_ack; + cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); + + ack.cookie = reg.cookie; + memcpy(ack.srcMac, sss->mac_addr, sizeof(n2n_mac_t)); + + if(comm->is_federation != IS_FEDERATION) { /* alternatively, do not send zero tap ip address in federation REGISTER_SUPER */ + if((reg.dev_addr.net_addr == 0) || (reg.dev_addr.net_addr == 0xFFFFFFFF) || (reg.dev_addr.net_bitlen == 0) || + ((reg.dev_addr.net_addr & 0xFFFF0000) == 0xA9FE0000 /* 169.254.0.0 */)) { + memset(&ipaddr, 0, sizeof(n2n_ip_subnet_t)); + assign_one_ip_addr(comm, reg.dev_desc, &ipaddr); + ack.dev_addr.net_addr = ipaddr.net_addr; + ack.dev_addr.net_bitlen = ipaddr.net_bitlen; + } + } + + ack.lifetime = reg_lifetime(sss); + + ack.sock.family = AF_INET; + ack.sock.port = ntohs(sender_sock->sin_port); + memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + /* Add sender's data to federation (or update it) */ + if(comm->is_federation == IS_FEDERATION) { + skip_add = SN_ADD; + p = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &(ack.sock), reg.edgeMac, &skip_add); + p->last_seen = now; + // communication with other supernodes happens via standard udp port + p->socket_fd = sss->sock; + } + + /* Skip random numbers of supernodes before payload assembling, calculating an appropriate random_number. + * That way, all supernodes have a chance to be propagated with REGISTER_SUPER_ACK. */ + skip = HASH_COUNT(sss->federation->edges) - (int)(REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE / REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE); + skip = (skip < 0) ? 0 : n2n_rand_sqr(skip); + + /* Assembling supernode list for REGISTER_SUPER_ACK payload */ + payload = (n2n_REGISTER_SUPER_ACK_payload_t*)payload_buf; + HASH_ITER(hh, sss->federation->edges, peer, tmp_peer) { + if(skip) { + skip--; + continue; + } + if(peer->sock.family == (uint8_t)AF_INVALID) + continue; /* do not add unresolved supernodes to payload */ + if(memcmp(&(peer->sock), &(ack.sock), sizeof(n2n_sock_t)) == 0) continue; /* a supernode doesn't add itself to the payload */ + if((now - peer->last_seen) >= LAST_SEEN_SN_NEW) continue; /* skip long-time-not-seen supernodes. + * We need to allow for a little extra time because supernodes sometimes exceed + * their SN_ACTIVE time before they get re-registred to. */ + if(((++num)*REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE) > REG_SUPER_ACK_PAYLOAD_SPACE) break; /* no more space available in REGISTER_SUPER_ACK payload */ + memcpy(&(payload->sock), &(peer->sock), sizeof(n2n_sock_t)); + memcpy(payload->mac, peer->mac_addr, sizeof(n2n_mac_t)); + // shift to next payload entry + payload++; + } + ack.num_sn = num; + + traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]", + macaddr_str(mac_buf, reg.edgeMac), + sock_to_cstr(sockbuf, &(ack.sock))); + + // check authentication + ret_value = update_edge_no_change; + if(comm->is_federation != IS_FEDERATION) { /* REVISIT: auth among supernodes is not implemented yet */ + if(cmn.flags & N2N_FLAGS_FROM_SUPERNODE) { + ret_value = update_edge(sss, &cmn, ®, comm, &(ack.sock), socket_fd, &(ack.auth), SN_ADD_SKIP, now); + } else { + // do not add in case of null mac (edge asking for ip address) + ret_value = update_edge(sss, &cmn, ®, comm, &(ack.sock), socket_fd, &(ack.auth), is_null_mac(reg.edgeMac) ? SN_ADD_SKIP : SN_ADD, now); + } + } + + if(ret_value == update_edge_auth_fail) { + // send REGISTER_SUPER_NAK + cmn2.pc = n2n_register_super_nak; + nak.cookie = reg.cookie; + memcpy(nak.srcMac, reg.edgeMac, sizeof(n2n_mac_t)); + + encode_REGISTER_SUPER_NAK(ackbuf, &encx, &cmn2, &nak); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(ackbuf, encx, encx, + comm->header_encryption_ctx_static, comm->header_iv_ctx_static, + time_stamp()); + // if user-password-auth + if(comm->allowed_users) { + encode_buf(ackbuf, &encx, hash_buf /* no matter what content */, N2N_REG_SUP_HASH_CHECK_LEN); + } + } + sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, ackbuf, encx); + + traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_NAK for %s", + macaddr_str(mac_buf, reg.edgeMac)); + } else { + // if this is not already from a supernode ... + // and not from federation, ... + if((!(cmn.flags & N2N_FLAGS_FROM_SUPERNODE)) || (!(cmn.flags & N2N_FLAGS_SOCKET))) { + // ... forward to all other supernodes (note try_broadcast()'s behavior with + // NULL comm and from_supernode parameter) + // exception: do not forward auto ip draw + if(!is_null_mac(reg.edgeMac)) { + reg.sock.family = AF_INET; + reg.sock.port = ntohs(sender_sock->sin_port); + memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + cmn2.pc = n2n_register_super; + encode_REGISTER_SUPER(ackbuf, &encx, &cmn2, ®); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(ackbuf, encx, encx, + comm->header_encryption_ctx_static, comm->header_iv_ctx_static, + time_stamp()); + // if user-password-auth + if(comm->allowed_users) { + // append an encrypted packet hash + pearson_hash_128(hash_buf, ackbuf, encx); + // same 'user' as above + speck_128_encrypt(hash_buf, (speck_context_t*)user->shared_secret_ctx); + encode_buf(ackbuf, &encx, hash_buf, N2N_REG_SUP_HASH_CHECK_LEN); + } + } + + try_broadcast(sss, NULL, &cmn, reg.edgeMac, from_supernode, ackbuf, encx, now); + } + + // dynamic key time handling if appropriate + ack.key_time = 0; + if(comm->is_federation == IS_FEDERATION) { + if(reg.key_time > sss->dynamic_key_time) { + traceEvent(TRACE_DEBUG, "setting new key time"); + // have all edges re_register (using old dynamic key) + send_re_register_super(sss); + // set new key time + sss->dynamic_key_time = reg.key_time; + // calculate new dynamic keys for all communities + calculate_dynamic_keys(sss); + // force re-register with all supernodes + re_register_and_purge_supernodes(sss, sss->federation, &any_time, now, 1 /* forced */); + } + ack.key_time = sss->dynamic_key_time; + } + + // send REGISTER_SUPER_ACK + encx = 0; + cmn2.pc = n2n_register_super_ack; + + encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack, payload_buf); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(ackbuf, encx, encx, + comm->header_encryption_ctx_static, comm->header_iv_ctx_static, + time_stamp()); + // if user-password-auth + if(comm->allowed_users) { + // append an encrypted packet hash + pearson_hash_128(hash_buf, ackbuf, encx); + // same 'user' as above + speck_128_encrypt(hash_buf, (speck_context_t*)user->shared_secret_ctx); + encode_buf(ackbuf, &encx, hash_buf, N2N_REG_SUP_HASH_CHECK_LEN); + } + } + + sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, ackbuf, encx); + + traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]", + macaddr_str(mac_buf, reg.edgeMac), + sock_to_cstr(sockbuf, &(ack.sock))); + } else { + // this is an edge with valid authentication registering with another supernode, so ... + // 1- ... associate it with that other supernode + update_node_supernode_association(comm, &(reg.edgeMac), sender_sock, now); + // 2- ... we can delete it from regular list if present (can happen) + HASH_FIND_PEER(comm->edges, reg.edgeMac, peer); + if(peer != NULL) { + if((peer->socket_fd != sss->sock) && (peer->socket_fd >= 0)) { + n2n_tcp_connection_t *conn; + HASH_FIND_INT(sss->tcp_connections, &(peer->socket_fd), conn); + close_tcp_connection(sss, conn); /* also deletes the peer */ + } else { + HASH_DEL(comm->edges, peer); + free(peer); + } + } + } + } + + break; + } + + case MSG_TYPE_UNREGISTER_SUPER: { + n2n_UNREGISTER_SUPER_t unreg; + struct peer_info *peer; + int auth; + + + memset(&unreg, 0, sizeof(n2n_UNREGISTER_SUPER_t)); + + if(!comm) { + traceEvent(TRACE_DEBUG, "dropped UNREGISTER_SUPER with unknown community %s", cmn.community); + return -1; + } + + if((from_supernode == 1) || (comm->is_federation == IS_FEDERATION)) { + traceEvent(TRACE_DEBUG, "dropped UNREGISTER_SUPER: should not come from a supernode or federation."); + return -1; + } + + decode_UNREGISTER_SUPER(&unreg, &cmn, udp_buf, &rem, &idx); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, sn, unreg.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped UNREGISTER_SUPER due to time stamp error"); + return -1; + } + } + + traceEvent(TRACE_DEBUG, "Rx UNREGISTER_SUPER from %s", + macaddr_str(mac_buf, unreg.srcMac)); + + HASH_FIND_PEER(comm->edges, unreg.srcMac, peer); + if(peer != NULL) { + if((auth = auth_edge(&(peer->auth), &unreg.auth, NULL, comm)) == 0) { + if((peer->socket_fd != sss->sock) && (peer->socket_fd >= 0)) { + n2n_tcp_connection_t *conn; + HASH_FIND_INT(sss->tcp_connections, &(peer->socket_fd), conn); + close_tcp_connection(sss, conn); /* also deletes the peer */ + } else { + HASH_DEL(comm->edges, peer); + free(peer); + } + } + } + break; + } + + case MSG_TYPE_REGISTER_SUPER_ACK: { + n2n_REGISTER_SUPER_ACK_t ack; + struct peer_info *scan, *tmp; + n2n_sock_str_t sockbuf1; + n2n_sock_str_t sockbuf2; + macstr_t mac_buf1; + n2n_sock_t sender; + n2n_sock_t *orig_sender; + int i; + uint8_t dec_tmpbuf[REG_SUPER_ACK_PAYLOAD_SPACE]; + n2n_REGISTER_SUPER_ACK_payload_t *payload; + + memset(&sender, 0, sizeof(n2n_sock_t)); + sender.family = AF_INET; + sender.port = ntohs(sender_sock->sin_port); + memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + orig_sender = &sender; + + memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); + + if(!comm) { + traceEvent(TRACE_DEBUG, "REGISTER_SUPER_ACK with unknown community %s", cmn.community); + return -1; + } + + if((from_supernode == 0) || (comm->is_federation == IS_NO_FEDERATION)) { + traceEvent(TRACE_DEBUG, "dropped REGISTER_SUPER_ACK, should not come from an edge or regular community"); + return -1; + } + + decode_REGISTER_SUPER_ACK(&ack, &cmn, udp_buf, &rem, &idx, dec_tmpbuf); + orig_sender = &(ack.sock); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, sn, ack.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped REGISTER_SUPER_ACK due to time stamp error"); + return -1; + } + } + + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK from MAC %s [%s] (external %s)", + macaddr_str(mac_buf1, ack.srcMac), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender)); + + skip_add = SN_ADD_SKIP; + scan = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &sender, ack.srcMac, &skip_add); + if(scan != NULL) { + scan->last_seen = now; + } else { + traceEvent(TRACE_DEBUG, "dropped REGISTER_SUPER_ACK due to an unknown supernode"); + break; + } + + if(ack.cookie == scan->last_cookie) { + + payload = (n2n_REGISTER_SUPER_ACK_payload_t *)dec_tmpbuf; + for(i = 0; i < ack.num_sn; i++) { + skip_add = SN_ADD; + tmp = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), &(payload->sock), payload->mac, &skip_add); + // other supernodes communicate via standard udp socket + tmp->socket_fd = sss->sock; + + if(skip_add == SN_ADD_ADDED) { + tmp->last_seen = now - LAST_SEEN_SN_NEW; + } + + // shift to next payload entry + payload++; + } + + if(ack.key_time > sss->dynamic_key_time) { + traceEvent(TRACE_DEBUG, "setting new key time"); + // have all edges re_register (using old dynamic key) + send_re_register_super(sss); + // set new key time + sss->dynamic_key_time = ack.key_time; + // calculate new dynamic keys for all communities + calculate_dynamic_keys(sss); + // force re-register with all supernodes + re_register_and_purge_supernodes(sss, sss->federation, &any_time, now, 1 /* forced */); + } + + } else { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old cookie"); + } + break; + } + + case MSG_TYPE_REGISTER_SUPER_NAK: { + n2n_REGISTER_SUPER_NAK_t nak; + uint8_t nakbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx = 0; + struct peer_info *peer; + n2n_sock_str_t sockbuf; + macstr_t mac_buf; + n2n_sock_t sender; + + memset(&sender, 0, sizeof(n2n_sock_t)); + sender.family = AF_INET; + sender.port = ntohs(sender_sock->sin_port); + memcpy(&(sender.addr.v4), &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + + memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + + if(!comm) { + traceEvent(TRACE_DEBUG, "REGISTER_SUPER_NAK with unknown community %s", cmn.community); + return -1; + } + + decode_REGISTER_SUPER_NAK(&nak, &cmn, udp_buf, &rem, &idx); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, sn, nak.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "process_udp dropped REGISTER_SUPER_NAK due to time stamp error"); + return -1; + } + } + + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_NAK from %s [%s]", + macaddr_str(mac_buf, nak.srcMac), + sock_to_cstr(sockbuf, &sender)); + + HASH_FIND_PEER(comm->edges, nak.srcMac, peer); + if(comm->is_federation == IS_NO_FEDERATION) { + if(peer != NULL) { + // this is a NAK for one of the edges conencted to this supernode, forward, + // i.e. re-assemble (memcpy from udpbuf to nakbuf could be sufficient as well) + + // use incoming cmn (with already decreased TTL) + // NAK (cookie, srcMac, auth) remains unchanged + + encode_REGISTER_SUPER_NAK(nakbuf, &encx, &cmn, &nak); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(nakbuf, encx, encx, + comm->header_encryption_ctx_static, comm->header_iv_ctx_static, + time_stamp()); + // if user-password-auth + if(comm->allowed_users) { + encode_buf(nakbuf, &encx, hash_buf /* no matter what content */, N2N_REG_SUP_HASH_CHECK_LEN); + } + } + + sendto_peer(sss, peer, nakbuf, encx); + + if((peer->socket_fd != sss->sock) && (peer->socket_fd >= 0)) { + n2n_tcp_connection_t *conn; + HASH_FIND_INT(sss->tcp_connections, &(peer->socket_fd), conn); + close_tcp_connection(sss, conn); /* also deletes the peer */ + } else { + HASH_DEL(comm->edges, peer); + free(peer); + } + } + } + break; + } + + case MSG_TYPE_QUERY_PEER: { + n2n_QUERY_PEER_t query; + uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx = 0; + n2n_common_t cmn2; + n2n_PEER_INFO_t pi; + struct sn_community_regular_expression *re, *tmp_re; + int8_t allowed_match = -1; + uint8_t match = 0; + int match_length = 0; + + if(!comm && sss->lock_communities) { + HASH_ITER(hh, sss->rules, re, tmp_re) { + allowed_match = re_matchp(re->rule, (const char *)cmn.community, &match_length); + + if((allowed_match != -1) + && (match_length == strlen((const char *)cmn.community)) // --- only full matches allowed (remove, if also partial matches wanted) + && (allowed_match == 0)) { // --- only full matches allowed (remove, if also partial matches wanted) + match = 1; + break; + } + } + if(match != 1) { + traceEvent(TRACE_DEBUG, "QUERY_PEER from unknown community %s", cmn.community); + return -1; + } + } + + if(!comm && sss->lock_communities && (match == 0)) { + traceEvent(TRACE_DEBUG, "QUERY_PEER from not allowed community %s", cmn.community); + return -1; + } + + decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx ); + + // to answer a PING, it is sufficient if the provided communtiy would be a valid one, there does not + // neccessarily need to be a comm entry present, e.g. because there locally are no edges of the + // community connected (several supernodes in a federation setup) + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, sn, query.srcMac, stamp, TIME_STAMP_ALLOW_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped QUERY_PEER due to time stamp error"); + return -1; + } + } + } + + if(is_null_mac(query.targetMac)) { + traceEvent(TRACE_DEBUG, "Rx PING from %s", + macaddr_str(mac_buf, query.srcMac)); + + cmn2.ttl = N2N_DEFAULT_TTL; + cmn2.pc = n2n_peer_info; + cmn2.flags = N2N_FLAGS_FROM_SUPERNODE; + memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); + + pi.aflags = 0; + memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t)); + memcpy(pi.srcMac, sss->mac_addr, sizeof(n2n_mac_t)); + pi.sock.family = AF_INET; + pi.sock.port = ntohs(sender_sock->sin_port); + memcpy(pi.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE); + pi.load = sn_selection_criterion_gather_data(sss); + + snprintf(pi.version, sizeof(pi.version), "%s", sss->version); + pi.uptime = now - sss->start_time; + + encode_PEER_INFO(encbuf, &encx, &cmn2, &pi); + + if(comm) { + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(encbuf, encx, encx, comm->header_encryption_ctx_dynamic, + comm->header_iv_ctx_dynamic, + time_stamp()); + } + } + + sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, encbuf, encx); + + traceEvent(TRACE_DEBUG, "Tx PONG to %s", + macaddr_str(mac_buf, query.srcMac)); + + } else { + traceEvent(TRACE_DEBUG, "Rx QUERY_PEER from %s for %s", + macaddr_str(mac_buf, query.srcMac), + macaddr_str(mac_buf2, query.targetMac)); + + struct peer_info *scan; + + // as opposed to the special case 'PING', proper QUERY_PEER processing requires a locally actually present community entry + if(!comm) { + traceEvent(TRACE_DEBUG, "QUERY_PEER with unknown community %s", cmn.community); + return -1; + } + + HASH_FIND_PEER(comm->edges, query.targetMac, scan); + if(scan) { + cmn2.ttl = N2N_DEFAULT_TTL; + cmn2.pc = n2n_peer_info; + cmn2.flags = N2N_FLAGS_FROM_SUPERNODE; + memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); + + pi.aflags = 0; + memcpy(pi.srcMac, query.srcMac, sizeof(n2n_mac_t)); + memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t)); + pi.sock = scan->sock; + if(scan->preferred_sock.family != (uint8_t)AF_INVALID) { + cmn2.flags |= N2N_FLAGS_SOCKET; + pi.preferred_sock = scan->preferred_sock; + } + + encode_PEER_INFO(encbuf, &encx, &cmn2, &pi); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(encbuf, encx, encx, comm->header_encryption_ctx_dynamic, + comm->header_iv_ctx_dynamic, + time_stamp()); + } + // back to sender, be it edge or supernode (which will forward to edge) + sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, encbuf, encx); + + traceEvent(TRACE_DEBUG, "Tx PEER_INFO to %s", + macaddr_str(mac_buf, query.srcMac)); + + } else { + + if(from_supernode) { + traceEvent(TRACE_DEBUG, "QUERY_PEER on unknown edge from supernode %s, dropping the packet", + macaddr_str(mac_buf, query.srcMac)); + } else { + traceEvent(TRACE_DEBUG, "QUERY_PEER from unknown edge %s, forwarding to all other supernodes", + macaddr_str(mac_buf, query.srcMac)); + + memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); + cmn2.flags |= N2N_FLAGS_FROM_SUPERNODE; + + encode_QUERY_PEER(encbuf, &encx, &cmn2, &query); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(encbuf, encx, encx, comm->header_encryption_ctx_dynamic, + comm->header_iv_ctx_dynamic, + time_stamp()); + } + + try_broadcast(sss, NULL, &cmn, query.srcMac, from_supernode, encbuf, encx, now); + } + } + } + break; + } + + case MSG_TYPE_PEER_INFO: { + n2n_PEER_INFO_t pi; + uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx = 0; + struct peer_info *peer; + + if(!comm) { + traceEvent(TRACE_DEBUG, "PEER_INFO with unknown community %s", cmn.community); + return -1; + } + + decode_PEER_INFO(&pi, &cmn, udp_buf, &rem, &idx); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + if(!find_edge_time_stamp_and_verify(comm->edges, sn, pi.srcMac, stamp, TIME_STAMP_NO_JITTER)) { + traceEvent(TRACE_DEBUG, "dropped PEER_INFO due to time stamp error"); + return -1; + } + } + + traceEvent(TRACE_INFO, "Rx PEER_INFO from %s [%s]", + macaddr_str(mac_buf, pi.srcMac), + sock_to_cstr(sockbuf, &sender)); + + HASH_FIND_PEER(comm->edges, pi.srcMac, peer); + if(peer != NULL) { + if((comm->is_federation == IS_NO_FEDERATION) && (!is_null_mac(pi.srcMac))) { + // snoop on the information to use for supernode forwarding (do not wait until first remote REGISTER_SUPER) + update_node_supernode_association(comm, &(pi.mac), sender_sock, now); + + // this is a PEER_INFO for one of the edges conencted to this supernode, forward, + // i.e. re-assemble (memcpy of udpbuf to encbuf could be sufficient as well) + + // use incoming cmn (with already decreased TTL) + // PEER_INFO remains unchanged + + encode_PEER_INFO(encbuf, &encx, &cmn, &pi); + + if(comm->header_encryption == HEADER_ENCRYPTION_ENABLED) { + packet_header_encrypt(encbuf, encx, encx, + comm->header_encryption_ctx_dynamic, comm->header_iv_ctx_dynamic, + time_stamp()); + } + + sendto_peer(sss, peer, encbuf, encx); + } + } + break; + } + + default: + /* Not a known message type */ + traceEvent(TRACE_WARNING, "unable to handle packet type %d: ignored", (signed int)msg_type); + } /* switch(msg_type) */ + + return 0; +} + + +/** Long lived processing entry point. Split out from main to simply + * daemonisation on some platforms. */ +int run_sn_loop (n2n_sn_t *sss) { + + uint8_t pktbuf[N2N_SN_PKTBUF_SIZE]; + time_t last_purge_edges = 0; + time_t last_sort_communities = 0; + time_t last_re_reg_and_purge = 0; + + sss->start_time = time(NULL); + + while(*sss->keep_running) { + int rc; + ssize_t bread; + int max_sock; + fd_set socket_mask; + n2n_tcp_connection_t *conn, *tmp_conn; + +#ifdef N2N_HAVE_TCP + SOCKET tmp_sock; + n2n_sock_str_t sockbuf; +#endif + struct timeval wait_time; + time_t before, now = 0; + + FD_ZERO(&socket_mask); + + FD_SET(sss->sock, &socket_mask); +#ifdef N2N_HAVE_TCP + FD_SET(sss->tcp_sock, &socket_mask); +#endif + FD_SET(sss->mgmt_sock, &socket_mask); + + max_sock = MAX(MAX(sss->sock, sss->mgmt_sock), sss->tcp_sock); + +#ifdef N2N_HAVE_TCP + // add the tcp connections' sockets + HASH_ITER(hh, sss->tcp_connections, conn, tmp_conn) { + //socket descriptor + FD_SET(conn->socket_fd, &socket_mask); + if(conn->socket_fd > max_sock) + max_sock = conn->socket_fd; + } +#endif + + wait_time.tv_sec = 10; + wait_time.tv_usec = 0; + + before = time(NULL); + + rc = select(max_sock + 1, &socket_mask, NULL, NULL, &wait_time); + + now = time(NULL); + + if(rc > 0) { + + // external udp + if(FD_ISSET(sss->sock, &socket_mask)) { + struct sockaddr_in sender_sock; + socklen_t i; + + i = sizeof(sender_sock); + bread = recvfrom(sss->sock, (void *)pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t *)&i); + + if((bread < 0) +#ifdef WIN32 + && (WSAGetLastError() != WSAECONNRESET) +#endif + ) { + /* For UDP bread of zero just means no data (unlike TCP). */ + /* The fd is no good now. Maybe we lost our interface. */ + traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno)); +#ifdef WIN32 + traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); +#endif + *sss->keep_running = 0; + break; + } + + // we have a datagram to process... + if(bread > 0) { + // ...and the datagram has data (not just a header) + process_udp(sss, &sender_sock, sss->sock, pktbuf, bread, now); + } + } + +#ifdef N2N_HAVE_TCP + // the so far known tcp connections + + // beware: current conn and other items of the connection list may be found + // due for deletion while processing packets. Even OTHER connections, e.g. if + // forwarding to another edge node fails. connections due for deletion will + // not immediately be deleted but marked 'inactive' for later deletion + HASH_ITER(hh, sss->tcp_connections, conn, tmp_conn) { + // do not process entries that have been marked inactive, those will be deleted + // immediately after this loop + if(conn->inactive) + continue; + + if(FD_ISSET(conn->socket_fd, &socket_mask)) { + + struct sockaddr_in sender_sock; + socklen_t i; + + i = sizeof(sender_sock); + bread = recvfrom(conn->socket_fd, + conn->buffer + conn->position, conn->expected - conn->position, 0 /*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t *)&i); + + if(bread <= 0) { + traceEvent(TRACE_INFO, "closing tcp connection to [%s]", sock_to_cstr(sockbuf, (n2n_sock_t*)&sender_sock)); + traceEvent(TRACE_DEBUG, "recvfrom() returns %d and sees errno %d (%s)", bread, errno, strerror(errno)); +#ifdef WIN32 + traceEvent(TRACE_DEBUG, "WSAGetLastError(): %u", WSAGetLastError()); +#endif + close_tcp_connection(sss, conn); + continue; + } + conn->position += bread; + + if(conn->position == conn->expected) { + if(conn->position == sizeof(uint16_t)) { + // the prepended length has been read, preparing for the packet + conn->expected += be16toh(*(uint16_t*)(conn->buffer)); + if(conn->expected > N2N_SN_PKTBUF_SIZE) { + traceEvent(TRACE_INFO, "closing tcp connection to [%s]", sock_to_cstr(sockbuf, (n2n_sock_t*)&sender_sock)); + traceEvent(TRACE_DEBUG, "too many bytes in tcp packet expected"); + close_tcp_connection(sss, conn); + continue; + } + } else { + // full packet read, handle it + process_udp(sss, (struct sockaddr_in*)&(conn->sock), conn->socket_fd, + conn->buffer + sizeof(uint16_t), conn->position - sizeof(uint16_t), now); + + // reset, await new prepended length + conn->expected = sizeof(uint16_t); + conn->position = 0; + } + } + } + } + + // remove inactive / already closed tcp connections from list + HASH_ITER(hh, sss->tcp_connections, conn, tmp_conn) { + if(conn->inactive) { + HASH_DEL(sss->tcp_connections, conn); + free(conn); + } + } + + // accept new incoming tcp connection + if(FD_ISSET(sss->tcp_sock, &socket_mask)) { + struct sockaddr_in sender_sock; + socklen_t i; + + i = sizeof(sender_sock); + if((HASH_COUNT(sss->tcp_connections) + 4) < FD_SETSIZE) { + tmp_sock = accept(sss->tcp_sock, (struct sockaddr *)&sender_sock, (socklen_t *)&i); + if(tmp_sock >= 0) { + conn = (n2n_tcp_connection_t*)malloc(sizeof(n2n_tcp_connection_t)); + if(conn) { + conn->socket_fd = tmp_sock; + memcpy(&(conn->sock), &sender_sock, sizeof(struct sockaddr_in)); + conn->inactive = 0; + conn->expected = sizeof(uint16_t); + conn->position = 0; + HASH_ADD_INT(sss->tcp_connections, socket_fd, conn); + traceEvent(TRACE_INFO, "accepted incoming TCP connection from [%s]", + sock_to_cstr(sockbuf, (n2n_sock_t*)&sender_sock)); + } + } + } else { + // no space to store the socket for a new connection, close immediately + traceEvent(TRACE_DEBUG, "denied incoming TCP connection from [%s] due to max connections limit hit", + sock_to_cstr(sockbuf, (n2n_sock_t*)&sender_sock)); + } + } +#endif /* N2N_HAVE_TCP */ + + // handle management port input + if(FD_ISSET(sss->mgmt_sock, &socket_mask)) { + struct sockaddr_in sender_sock; + size_t i; + + i = sizeof(sender_sock); + bread = recvfrom(sss->mgmt_sock, (void *)pktbuf, N2N_SN_PKTBUF_SIZE, 0 /*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t *)&i); + + if(bread <= 0) { + traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno)); + *sss->keep_running = 0; + break; + } + + // we have a datagram to process + process_mgmt(sss, &sender_sock, (char *)pktbuf, bread, now); + } + + } else { + if(((now - before) < wait_time.tv_sec) && (*sss->keep_running)){ + // this is no real timeout, something went wrong with one of the tcp connections (probably) + // close them all, edges will re-open if they detect closure + traceEvent(TRACE_DEBUG, "falsly claimed timeout, assuming issue with tcp connection, closing them all"); + HASH_ITER(hh, sss->tcp_connections, conn, tmp_conn) + close_tcp_connection(sss, conn); + } else + traceEvent(TRACE_DEBUG, "timeout"); + } + + re_register_and_purge_supernodes(sss, sss->federation, &last_re_reg_and_purge, now, 0 /* not forced */); + purge_expired_communities(sss, &last_purge_edges, now); + sort_communities(sss, &last_sort_communities, now); + resolve_check(sss->resolve_parameter, 0 /* presumably, no special resolution requirement */, now); + } /* while */ + + sn_term(sss); + + return 0; +} diff --git a/src/speck.c b/src/speck.c new file mode 100644 index 0000000..4c43003 --- /dev/null +++ b/src/speck.c @@ -0,0 +1,1026 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +// cipher SPECK -- 128 bit block size -- 128 and 256 bit key size -- CTR mode +// taken from (and modified: removed pure crypto-stream generation and seperated key expansion) +// https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/ + + +#include "speck.h" + + +#if defined (__AVX512F__) // AVX512 support ---------------------------------------------------------------------- + + +#define LCS(x,r) (((x)<>(64-r))) +#define RCS(x,r) (((x)>>r)|((x)<<(64-r))) + +#define SET _mm512_set_epi64 +#define XOR _mm512_xor_si512 +#define ADD _mm512_add_epi64 +#define AND _mm512_and_si512 +#define ROL(X,r) (_mm512_rol_epi64(X,r)) +#define ROR(X,r) (_mm512_ror_epi64(X,r)) + +#define _q8 SET(0x7LL,0x3LL,0x6LL,0x2LL,0x5LL,0x1LL,0x4LL,0x0LL) +#define _eight SET(0x8LL,0x8LL,0x8LL,0x8LL,0x8LL,0x8LL,0x8LL,0x8LL) + +#define SET1(X,c) (X=SET(c,c,c,c,c,c,c,c)) +#define SET8(X,c) (X=SET(c,c,c,c,c,c,c,c), X=ADD(X,_q8)) + +#define LOW _mm512_unpacklo_epi64 +#define HIGH _mm512_unpackhi_epi64 +#define LD(ip) (_mm512_load_epi64(((void *)(ip)))) +#define ST(ip,X) _mm512_storeu_si512((void *)(ip),X) +#define STORE(out,X,Y) (ST(out,LOW(Y,X)), ST(out+64,HIGH(Y,X))) +#define XOR_STORE(in,out,X,Y) (ST(out,XOR(LD(in),LOW(Y,X))), ST(out+64,XOR(LD(in+64),HIGH(Y,X)))) + +#define Rx8(X,Y,k) (X[0]=XOR(ADD(ROR(X[0],8),Y[0]),k), \ + Y[0]=XOR(ROL(Y[0],3),X[0])) +#define Rx16(X,Y,k) (X[0]=XOR(ADD(ROR(X[0],8),Y[0]),k), X[1]=XOR(ADD(ROR(X[1],8),Y[1]),k), \ + Y[0]=XOR(ROL(Y[0],3),X[0]), Y[1]=XOR(ROL(Y[1],3),X[1])) +#define Rx24(X,Y,k) (X[0]=XOR(ADD(ROR(X[0],8),Y[0]),k), X[1]=XOR(ADD(ROR(X[1],8),Y[1]),k), X[2]=XOR(ADD(ROR(X[2],8),Y[2]),k), \ + Y[0]=XOR(ROL(Y[0],3),X[0]), Y[1]=XOR(ROL(Y[1],3),X[1]), Y[2]=XOR(ROL(Y[2],3),X[2])) +#define Rx32(X,Y,k) (X[0]=XOR(ADD(ROR(X[0],8),Y[0]),k), X[1]=XOR(ADD(ROR(X[1],8),Y[1]),k), \ + X[2]=XOR(ADD(ROR(X[2],8),Y[2]),k), X[3]=XOR(ADD(ROR(X[3],8),Y[3]),k), \ + Y[0]=XOR(ROL(Y[0],3),X[0]), Y[1]=XOR(ROL(Y[1],3),X[1]), \ + Y[2]=XOR(ROL(Y[2],3),X[2]), Y[3]=XOR(ROL(Y[3],3),X[3])) + +#define Rx1(x,y,k) (x[0]=RCS(x[0],8), x[0]+=y[0], x[0]^=k, y[0]=LCS(y[0],3), y[0]^=x[0]) +#define Rx1b(x,y,k) (x=RCS(x,8), x+=y, x^=k, y=LCS(y,3), y^=x) +#define Rx2(x,y,k) (x[0]=RCS(x[0],8), x[1]=RCS(x[1],8), x[0]+=y[0], x[1]+=y[1], \ + x[0]^=k, x[1]^=k, y[0]=LCS(y[0],3), y[1]=LCS(y[1],3), y[0]^=x[0], y[1]^=x[1]) + +#define Encrypt_128(X,Y,k,n) (Rx##n(X,Y,k[0]), Rx##n(X,Y,k[1]), Rx##n(X,Y,k[2]), Rx##n(X,Y,k[3]), Rx##n(X,Y,k[4]), Rx##n(X,Y,k[5]), Rx##n(X,Y,k[6]), Rx##n(X,Y,k[7]), \ + Rx##n(X,Y,k[8]), Rx##n(X,Y,k[9]), Rx##n(X,Y,k[10]), Rx##n(X,Y,k[11]), Rx##n(X,Y,k[12]), Rx##n(X,Y,k[13]), Rx##n(X,Y,k[14]), Rx##n(X,Y,k[15]), \ + Rx##n(X,Y,k[16]), Rx##n(X,Y,k[17]), Rx##n(X,Y,k[18]), Rx##n(X,Y,k[19]), Rx##n(X,Y,k[20]), Rx##n(X,Y,k[21]), Rx##n(X,Y,k[22]), Rx##n(X,Y,k[23]), \ + Rx##n(X,Y,k[24]), Rx##n(X,Y,k[25]), Rx##n(X,Y,k[26]), Rx##n(X,Y,k[27]), Rx##n(X,Y,k[28]), Rx##n(X,Y,k[29]), Rx##n(X,Y,k[30]), Rx##n(X,Y,k[31])) + +#define Encrypt_256(X,Y,k,n) (Encrypt_128(X,Y,k,n), \ + Rx##n(X,Y,k[32]), Rx##n(X,Y,k[33])) + +#define RK(X,Y,k,key,i) (SET1(k[i],Y), key[i]=Y, X=RCS(X,8), X+=Y, X^=i, Y=LCS(Y,3), Y^=X) + +#define EK(A,B,C,D,k,key) (RK(B,A,k,key,0), RK(C,A,k,key,1), RK(D,A,k,key,2), RK(B,A,k,key,3), RK(C,A,k,key,4), RK(D,A,k,key,5), RK(B,A,k,key,6), \ + RK(C,A,k,key,7), RK(D,A,k,key,8), RK(B,A,k,key,9), RK(C,A,k,key,10), RK(D,A,k,key,11), RK(B,A,k,key,12), RK(C,A,k,key,13), \ + RK(D,A,k,key,14), RK(B,A,k,key,15), RK(C,A,k,key,16), RK(D,A,k,key,17), RK(B,A,k,key,18), RK(C,A,k,key,19), RK(D,A,k,key,20), \ + RK(B,A,k,key,21), RK(C,A,k,key,22), RK(D,A,k,key,23), RK(B,A,k,key,24), RK(C,A,k,key,25), RK(D,A,k,key,26), RK(B,A,k,key,27), \ + RK(C,A,k,key,28), RK(D,A,k,key,29), RK(B,A,k,key,30), RK(C,A,k,key,31), RK(D,A,k,key,32), RK(B,A,k,key,33)) + +#define Encrypt_Dispatcher(keysize) \ + u64 x[2], y[2]; \ + u512 X[4], Y[4]; \ + unsigned char block1024[128]; \ + \ + if(numbytes == 16) { \ + x[0] = nonce[1]; y[0] = nonce[0]; nonce[0]++; \ + Encrypt_##keysize(x, y, ctx->key, 1); \ + ((u64 *)out)[1] = x[0]; ((u64 *)out)[0] = y[0]; \ + return 0; \ + } \ + \ + if(numbytes == 32) { \ + x[0] = nonce[1]; y[0] = nonce[0]; nonce[0]++; \ + x[1] = nonce[1]; y[1] = nonce[0]; nonce[0]++; \ + Encrypt_##keysize(x, y, ctx->key, 2); \ + ((u64 *)out)[1] = x[0] ^ ((u64 *)in)[1]; ((u64 *)out)[0] = y[0] ^ ((u64 *)in)[0]; \ + ((u64 *)out)[3] = x[1] ^ ((u64 *)in)[3]; ((u64 *)out)[2] = y[1] ^ ((u64 *)in)[2]; \ + return 0; \ + } \ + \ + if(numbytes == 64) { \ + SET1(X[0], nonce[1]); \ + SET8(Y[0], nonce[0]); \ + Encrypt_##keysize(X, Y, ctx->rk, 8); \ + nonce[0] += (numbytes >> 4); \ + memcpy(block1024, in, 64); \ + XOR_STORE(block1024, block1024, X[0], Y[0]); \ + memcpy(out, block1024, 64); \ + return 0; \ + } \ + \ + SET1(X[0], nonce[1]); SET8(Y[0], nonce[0]); \ + \ + if(numbytes == 128) \ + Encrypt_##keysize(X, Y, ctx->rk, 8); \ + else { \ + X[1] = X[0]; \ + Y[1] = ADD(Y[0], _eight); \ + if(numbytes == 256) \ + Encrypt_##keysize(X, Y, ctx->rk, 16); \ + else { \ + X[2] = X[0]; \ + Y[2] = ADD(Y[1], _eight); \ + if(numbytes == 384) \ + Encrypt_##keysize(X, Y, ctx->rk, 24); \ + else { \ + X[3] = X[0]; \ + Y[3] = ADD(Y[2], _eight); \ + Encrypt_##keysize(X, Y, ctx->rk, 32); \ + } \ + } \ + } \ + \ + nonce[0] += (numbytes >> 4); \ + \ + XOR_STORE(in, out, X[0], Y[0]); \ + if (numbytes >= 256) \ + XOR_STORE(in + 128, out + 128, X[1], Y[1]); \ + if(numbytes >= 384) \ + XOR_STORE(in + 256, out + 256, X[2], Y[2]); \ + if(numbytes >= 512) \ + XOR_STORE(in + 384, out + 384, X[3], Y[3]); \ + \ + return 0 + + +static int speck_encrypt_xor(unsigned char *out, const unsigned char *in, u64 nonce[], speck_context_t *ctx, int numbytes) { + + if(ctx->keysize == 256) { + Encrypt_Dispatcher(256); + } else { + Encrypt_Dispatcher(128); + } +} + + +static int internal_speck_ctr(unsigned char *out, const unsigned char *in, unsigned long long inlen, + const unsigned char *n, speck_context_t *ctx) { + + int i; + u64 nonce[2]; + unsigned char block[16]; + u64 * const block64 = (u64 *)block; + + if (!inlen) + return 0; + + nonce[0] = ((u64 *)n)[0]; + nonce[1] = ((u64 *)n)[1]; + + while(inlen >= 512) { + speck_encrypt_xor(out, in, nonce, ctx, 512); + in += 512; inlen -= 512; out += 512; + } + + if(inlen >= 384) { + speck_encrypt_xor(out, in, nonce, ctx, 384); + in += 384; inlen -= 384; out += 384; + } + + if(inlen >= 256) { + speck_encrypt_xor(out, in, nonce, ctx, 256); + in += 256; inlen -= 256; out += 256; + } + + if(inlen >= 128) { + speck_encrypt_xor(out, in, nonce, ctx, 128); + in += 128; inlen -= 128; out += 128; + } + + if(inlen >= 64) { + speck_encrypt_xor(out, in, nonce, ctx, 64); + in += 64; inlen -= 64; out += 64; + } + + if(inlen >= 32) { + speck_encrypt_xor(out, in, nonce, ctx, 32); + in += 32; inlen -= 32; out += 32; + } + + if(inlen >= 16) { + speck_encrypt_xor(block, in, nonce, ctx, 16); + ((u64 *)out)[0] = block64[0] ^ ((u64 *)in)[0]; + ((u64 *)out)[1] = block64[1] ^ ((u64 *)in)[1]; + in += 16; inlen -= 16; out += 16; + } + + if(inlen > 0) { + speck_encrypt_xor(block, in, nonce, ctx, 16); + for(i = 0; i < inlen; i++) + out[i] = block[i] ^ in[i]; + } + + return 0; +} + + +static int speck_expand_key (speck_context_t *ctx, const unsigned char *k, int keysize) { + + u64 K[4]; + size_t i; + + for(i = 0; i < (keysize >> 6); i++) + K[i] = ((u64 *)k)[i]; + + // 128 bit has only two keys A and B thus replacing both C and D with B then + if(keysize == 128) { + EK(K[0], K[1], K[1], K[1], ctx->rk, ctx->key); + } else { + EK(K[0], K[1], K[2], K[3], ctx->rk, ctx->key); + } + + ctx->keysize = keysize; + + return 0; +} + + +#elif defined (__AVX2__) // AVX2 support ------------------------------------------------------------------------- + + +#define LCS(x,r) (((x)<>(64-r))) +#define RCS(x,r) (((x)>>r)|((x)<<(64-r))) + +#define XOR _mm256_xor_si256 +#define AND _mm256_and_si256 +#define ADD _mm256_add_epi64 +#define SL _mm256_slli_epi64 +#define SR _mm256_srli_epi64 + +#define _q SET(0x3,0x1,0x2,0x0) +#define _four SET(0x4,0x4,0x4,0x4) + +#define SET _mm256_set_epi64x +#define SET1(X,c) (X=SET(c,c,c,c)) +#define SET4(X,c) (X=SET(c,c,c,c), X=ADD(X,_q)) + +#define LOW _mm256_unpacklo_epi64 +#define HIGH _mm256_unpackhi_epi64 +#define LD(ip) _mm256_loadu_si256((__m256i *)(ip)) +#define ST(ip,X) _mm256_storeu_si256((__m256i *)(ip),X) +#define STORE(out,X,Y) (ST(out,LOW(Y,X)), ST(out+32,HIGH(Y,X))) +#define STORE_ALT(out,X,Y) (ST(out,LOW(X,Y)), ST(out+32,HIGH(X,Y))) +#define XOR_STORE(in,out,X,Y) (ST(out,XOR(LD(in),LOW(Y,X))), ST(out+32,XOR(LD(in+32),HIGH(Y,X)))) +#define XOR_STORE_ALT(in,out,X,Y) (ST(out,XOR(LD(in),LOW(X,Y))), ST(out+32,XOR(LD(in+32),HIGH(X,Y)))) + +#define SHFL _mm256_shuffle_epi8 +#define R8 SET(0x080f0e0d0c0b0a09LL,0x0007060504030201LL,0x080f0e0d0c0b0a09LL,0x0007060504030201LL) +#define L8 SET(0x0e0d0c0b0a09080fLL,0x0605040302010007LL,0x0e0d0c0b0a09080fLL,0x0605040302010007LL) +#define ROL8(X) (SHFL(X,L8)) +#define ROR8(X) (SHFL(X,R8)) +#define ROL(X,r) (XOR(SL(X,r),SR(X,(64-r)))) +#define ROR(X,r) (XOR(SR(X,r),SL(X,(64-r)))) + +#define R(X,Y,k) (X=XOR(ADD(ROR8(X),Y),k), Y=XOR(ROL(Y,3),X)) + +#define Rx4(X,Y,k) (R(X[0],Y[0],k)) +#define Rx8(X,Y,k) (R(X[0],Y[0],k), R(X[1],Y[1],k)) +#define Rx12(X,Y,k) (R(X[0],Y[0],k), R(X[1],Y[1],k), R(X[2],Y[2],k)) +#define Rx16(X,Y,k) (X[0]=ROR8(X[0]), X[0]=ADD(X[0],Y[0]), X[1]=ROR8(X[1]), X[1]=ADD(X[1],Y[1]), \ + X[2]=ROR8(X[2]), X[2]=ADD(X[2],Y[2]), X[3]=ROR8(X[3]), X[3]=ADD(X[3],Y[3]), \ + X[0]=XOR(X[0],k), X[1]=XOR(X[1],k), X[2]=XOR(X[2],k), X[3]=XOR(X[3],k), \ + Z[0]=Y[0], Z[1]=Y[1], Z[2]=Y[2], Z[3]=Y[3], \ + Z[0]=SL(Z[0],3), Y[0]=SR(Y[0],61), Z[1]=SL(Z[1],3), Y[1]=SR(Y[1],61), \ + Z[2]=SL(Z[2],3), Y[2]=SR(Y[2],61), Z[3]=SL(Z[3],3), Y[3]=SR(Y[3],61), \ + Y[0]=XOR(Y[0],Z[0]), Y[1]=XOR(Y[1],Z[1]), Y[2]=XOR(Y[2],Z[2]), Y[3]=XOR(Y[3],Z[3]), \ + Y[0]=XOR(X[0],Y[0]), Y[1]=XOR(X[1],Y[1]), Y[2]=XOR(X[2],Y[2]), Y[3]=XOR(X[3],Y[3])) + +#define Rx1(x,y,k) (x[0]=RCS(x[0],8), x[0]+=y[0], x[0]^=k, y[0]=LCS(y[0],3), y[0]^=x[0]) +#define Rx1b(x,y,k) (x=RCS(x,8), x+=y, x^=k, y=LCS(y,3), y^=x) +#define Rx2(x,y,k) (x[0]=RCS(x[0],8), x[1]=RCS(x[1],8), x[0]+=y[0], x[1]+=y[1], \ + x[0]^=k, x[1]^=k, y[0]=LCS(y[0],3), y[1]=LCS(y[1],3), y[0]^=x[0], y[1]^=x[1]) + +#define Encrypt_128(X,Y,k,n) (Rx##n(X,Y,k[0]), Rx##n(X,Y,k[1]), Rx##n(X,Y,k[2]), Rx##n(X,Y,k[3]), Rx##n(X,Y,k[4]), Rx##n(X,Y,k[5]), Rx##n(X,Y,k[6]), Rx##n(X,Y,k[7]), \ + Rx##n(X,Y,k[8]), Rx##n(X,Y,k[9]), Rx##n(X,Y,k[10]), Rx##n(X,Y,k[11]), Rx##n(X,Y,k[12]), Rx##n(X,Y,k[13]), Rx##n(X,Y,k[14]), Rx##n(X,Y,k[15]), \ + Rx##n(X,Y,k[16]), Rx##n(X,Y,k[17]), Rx##n(X,Y,k[18]), Rx##n(X,Y,k[19]), Rx##n(X,Y,k[20]), Rx##n(X,Y,k[21]), Rx##n(X,Y,k[22]), Rx##n(X,Y,k[23]), \ + Rx##n(X,Y,k[24]), Rx##n(X,Y,k[25]), Rx##n(X,Y,k[26]), Rx##n(X,Y,k[27]), Rx##n(X,Y,k[28]), Rx##n(X,Y,k[29]), Rx##n(X,Y,k[30]), Rx##n(X,Y,k[31])) + +#define Encrypt_256(X,Y,k,n) (Encrypt_128(X,Y,k,n), \ + Rx##n(X,Y,k[32]), Rx##n(X,Y,k[33])) + +#define RK(X,Y,k,key,i) (SET1(k[i],Y), key[i]=Y, X=RCS(X,8), X+=Y, X^=i, Y=LCS(Y,3), Y^=X) + +#define EK(A,B,C,D,k,key) (RK(B,A,k,key,0), RK(C,A,k,key,1), RK(D,A,k,key,2), RK(B,A,k,key,3), RK(C,A,k,key,4), RK(D,A,k,key,5), RK(B,A,k,key,6), \ + RK(C,A,k,key,7), RK(D,A,k,key,8), RK(B,A,k,key,9), RK(C,A,k,key,10), RK(D,A,k,key,11), RK(B,A,k,key,12), RK(C,A,k,key,13), \ + RK(D,A,k,key,14), RK(B,A,k,key,15), RK(C,A,k,key,16), RK(D,A,k,key,17), RK(B,A,k,key,18), RK(C,A,k,key,19), RK(D,A,k,key,20), \ + RK(B,A,k,key,21), RK(C,A,k,key,22), RK(D,A,k,key,23), RK(B,A,k,key,24), RK(C,A,k,key,25), RK(D,A,k,key,26), RK(B,A,k,key,27), \ + RK(C,A,k,key,28), RK(D,A,k,key,29), RK(B,A,k,key,30), RK(C,A,k,key,31), RK(D,A,k,key,32), RK(B,A,k,key,33)) + +#define Encrypt_Dispatcher(keysize) \ + u64 x[2], y[2]; \ + u256 X[4], Y[4], Z[4]; \ + \ + if(numbytes == 16) { \ + x[0] = nonce[1]; y[0] = nonce[0]; nonce[0]++; \ + Encrypt_##keysize(x, y, ctx->key, 1); \ + ((u64 *)out)[1] = x[0]; ((u64 *)out)[0] = y[0]; \ + return 0; \ + } \ + \ + if(numbytes == 32) { \ + x[0] = nonce[1]; y[0] = nonce[0]; nonce[0]++; \ + x[1] = nonce[1]; y[1] = nonce[0]; nonce[0]++; \ + Encrypt_##keysize(x , y, ctx->key, 2); \ + ((u64 *)out)[1] = x[0] ^ ((u64 *)in)[1]; ((u64 *)out)[0] = y[0] ^ ((u64 *)in)[0]; \ + ((u64 *)out)[3] = x[1] ^ ((u64 *)in)[3]; ((u64 *)out)[2] = y[1] ^ ((u64 *)in)[2]; \ + return 0; \ + } \ + \ + SET1(X[0], nonce[1]); SET4(Y[0], nonce[0]); \ + \ + if(numbytes == 64) \ + Encrypt_##keysize(X, Y, ctx->rk, 4); \ + else { \ + X[1] = X[0]; \ + Y[1] = ADD(Y[0], _four); \ + if(numbytes == 128) \ + Encrypt_##keysize(X, Y, ctx->rk, 8); \ + else { \ + X[2] = X[0]; \ + Y[2] = ADD(Y[1], _four); \ + if(numbytes == 192) \ + Encrypt_##keysize(X, Y, ctx->rk, 12); \ + else { \ + X[3] = X[0]; \ + Y[3] = ADD(Y[2], _four); \ + Encrypt_##keysize(X, Y, ctx->rk, 16); \ + } \ + } \ + } \ + \ + nonce[0] += (numbytes >> 4); \ + \ + XOR_STORE(in, out, X[0], Y[0]); \ + if (numbytes >= 128) \ + XOR_STORE(in + 64, out + 64, X[1], Y[1]); \ + if(numbytes >= 192) \ + XOR_STORE(in + 128, out + 128, X[2], Y[2]); \ + if(numbytes >= 256) \ + XOR_STORE(in + 192, out + 192, X[3], Y[3]); \ + \ + return 0 + + +static int speck_encrypt_xor(unsigned char *out, const unsigned char *in, u64 nonce[], speck_context_t *ctx, int numbytes) { + + if(ctx->keysize == 256) { + Encrypt_Dispatcher(256); + } else { + Encrypt_Dispatcher(128); + } +} + + +static int internal_speck_ctr(unsigned char *out, const unsigned char *in, unsigned long long inlen, + const unsigned char *n, speck_context_t *ctx) { + + int i; + u64 nonce[2]; + unsigned char block[16]; + u64 * const block64 = (u64 *)block; + + if (!inlen) + return 0; + + nonce[0] = ((u64 *)n)[0]; + nonce[1] = ((u64 *)n)[1]; + + while(inlen >= 256) { + speck_encrypt_xor(out, in, nonce, ctx, 256); + in += 256; inlen -= 256; out += 256; + } + + if(inlen >= 192) { + speck_encrypt_xor(out, in, nonce, ctx, 192); + in += 192; inlen -= 192; out += 192; + } + + if(inlen >= 128) { + speck_encrypt_xor(out, in, nonce, ctx, 128); + in += 128; inlen -= 128; out += 128; + } + + if(inlen >= 64) { + speck_encrypt_xor(out, in, nonce, ctx, 64); + in += 64; inlen -= 64; out += 64; + } + + if(inlen >= 32) { + speck_encrypt_xor(out, in, nonce, ctx, 32); + in += 32; inlen -= 32; out += 32; + } + + if(inlen >= 16) { + speck_encrypt_xor(block, in, nonce, ctx, 16); + ((u64 *)out)[0] = block64[0] ^ ((u64 *)in)[0]; + ((u64 *)out)[1] = block64[1] ^ ((u64 *)in)[1]; + in += 16; inlen -= 16; out += 16; + } + + if(inlen > 0) { + speck_encrypt_xor(block, in, nonce, ctx, 16); + for(i = 0; i < inlen; i++) + out[i] = block[i] ^ in[i]; + } + + return 0; +} + + +static int speck_expand_key (speck_context_t *ctx, const unsigned char *k, int keysize) { + + u64 K[4]; + size_t i; + + for(i = 0; i < (keysize >> 6); i++) + K[i] = ((u64 *)k)[i]; + + // 128 bit has only two keys A and B thus replacing both C and D with B then + if(keysize == 128) { + EK(K[0], K[1], K[1], K[1], ctx->rk, ctx->key); + } else { + EK(K[0], K[1], K[2], K[3], ctx->rk, ctx->key); + } + + ctx->keysize = keysize; + + return 0; +} + + +#elif defined (__SSE2__) // SSE support --------------------------------------------------------------------------- + + +#define LCS(x,r) (((x)<>(64-r))) +#define RCS(x,r) (((x)>>r)|((x)<<(64-r))) + +#define XOR _mm_xor_si128 +#define AND _mm_and_si128 +#define ADD _mm_add_epi64 +#define SL _mm_slli_epi64 +#define SR _mm_srli_epi64 + +#define _q SET(0x1,0x0) +#define _two SET(0x2,0x2) + +#define SET _mm_set_epi64x +#define SET1(X,c) (X=SET(c,c)) +#define SET2(X,c) (X=SET(c,c), X=ADD(X,_q)) + +#define LOW _mm_unpacklo_epi64 +#define HIGH _mm_unpackhi_epi64 +#define LD(ip) _mm_loadu_si128((__m128i *)(ip)) +#define ST(ip,X) _mm_storeu_si128((__m128i *)(ip),X) +#define STORE(out,X,Y) (ST(out,LOW(Y,X)), ST(out+16,HIGH(Y,X))) +#define STORE_ALT(out,X,Y) (ST(out,LOW(X,Y)), ST(out+16,HIGH(X,Y))) +#define XOR_STORE(in,out,X,Y) (ST(out,XOR(LD(in),LOW(Y,X))), ST(out+16,XOR(LD(in+16),HIGH(Y,X)))) +#define XOR_STORE_ALT(in,out,X,Y) (ST(out,XOR(LD(in),LOW(X,Y))), ST(out+16,XOR(LD(in+16),HIGH(X,Y)))) + +#define ROL(X,r) (XOR(SL(X,r),SR(X,(64-r)))) +#define ROR(X,r) (XOR(SR(X,r),SL(X,(64-r)))) + +#if defined (__SSSE3__) // even SSSE3 ------------------------------- +#define SHFL _mm_shuffle_epi8 +#define R8 _mm_set_epi64x(0x080f0e0d0c0b0a09LL,0x0007060504030201LL) +#define L8 _mm_set_epi64x(0x0e0d0c0b0a09080fLL,0x0605040302010007LL) +#define ROL8(X) (SHFL(X,L8)) +#define ROR8(X) (SHFL(X,R8)) +#else // regular SSE2 ------------------------------------------------ +#define ROL8(X) (ROL(X,8)) +#define ROR8(X) (ROR(X,8)) +#endif // SSS3 vs. SSE2 ---------------------------------------------- + +#define R(X,Y,k) (X=XOR(ADD(ROR8(X),Y),k), Y=XOR(ROL(Y,3),X)) + +#define Rx2(X,Y,k) (R(X[0],Y[0],k)) +#define Rx4(X,Y,k) (R(X[0],Y[0],k), R(X[1],Y[1],k)) +#define Rx6(X,Y,k) (R(X[0],Y[0],k), R(X[1],Y[1],k), R(X[2],Y[2],k)) +#define Rx8(X,Y,k) (X[0]=ROR8(X[0]), X[0]=ADD(X[0],Y[0]), X[1]=ROR8(X[1]), X[1]=ADD(X[1],Y[1]), \ + X[2]=ROR8(X[2]), X[2]=ADD(X[2],Y[2]), X[3]=ROR8(X[3]), X[3]=ADD(X[3],Y[3]), \ + X[0]=XOR(X[0],k), X[1]=XOR(X[1],k), X[2]=XOR(X[2],k), X[3]=XOR(X[3],k), \ + Z[0]=Y[0], Z[1]=Y[1], Z[2]=Y[2], Z[3]=Y[3], \ + Z[0]=SL(Z[0],3), Y[0]=SR(Y[0],61), Z[1]=SL(Z[1],3), Y[1]=SR(Y[1],61), \ + Z[2]=SL(Z[2],3), Y[2]=SR(Y[2],61), Z[3]=SL(Z[3],3), Y[3]=SR(Y[3],61), \ + Y[0]=XOR(Y[0],Z[0]), Y[1]=XOR(Y[1],Z[1]), Y[2]=XOR(Y[2],Z[2]), Y[3]=XOR(Y[3],Z[3]), \ + Y[0]=XOR(X[0],Y[0]), Y[1]=XOR(X[1],Y[1]), Y[2]=XOR(X[2],Y[2]), Y[3]=XOR(X[3],Y[3])) + +#define Rx1(x,y,k) (x[0]=RCS(x[0],8), x[0]+=y[0], x[0]^=k, y[0]=LCS(y[0],3), y[0]^=x[0]) +#define Rx1b(x,y,k) (x=RCS(x,8), x+=y, x^=k, y=LCS(y,3), y^=x) + +#define Encrypt_128(X,Y,k,n) (Rx##n(X,Y,k[0]), Rx##n(X,Y,k[1]), Rx##n(X,Y,k[2]), Rx##n(X,Y,k[3]), Rx##n(X,Y,k[4]), Rx##n(X,Y,k[5]), Rx##n(X,Y,k[6]), Rx##n(X,Y,k[7]), \ + Rx##n(X,Y,k[8]), Rx##n(X,Y,k[9]), Rx##n(X,Y,k[10]), Rx##n(X,Y,k[11]), Rx##n(X,Y,k[12]), Rx##n(X,Y,k[13]), Rx##n(X,Y,k[14]), Rx##n(X,Y,k[15]), \ + Rx##n(X,Y,k[16]), Rx##n(X,Y,k[17]), Rx##n(X,Y,k[18]), Rx##n(X,Y,k[19]), Rx##n(X,Y,k[20]), Rx##n(X,Y,k[21]), Rx##n(X,Y,k[22]), Rx##n(X,Y,k[23]), \ + Rx##n(X,Y,k[24]), Rx##n(X,Y,k[25]), Rx##n(X,Y,k[26]), Rx##n(X,Y,k[27]), Rx##n(X,Y,k[28]), Rx##n(X,Y,k[29]), Rx##n(X,Y,k[30]), Rx##n(X,Y,k[31])) + +#define Encrypt_256(X,Y,k,n) (Encrypt_128(X,Y,k,n), \ + Rx##n(X,Y,k[32]), Rx##n(X,Y,k[33])) + +#define RK(X,Y,k,key,i) (SET1(k[i],Y), key[i]=Y, X=RCS(X,8), X+=Y, X^=i, Y=LCS(Y,3), Y^=X) + +#define EK(A,B,C,D,k,key) (RK(B,A,k,key,0), RK(C,A,k,key,1), RK(D,A,k,key,2), RK(B,A,k,key,3), RK(C,A,k,key,4), RK(D,A,k,key,5), RK(B,A,k,key,6), \ + RK(C,A,k,key,7), RK(D,A,k,key,8), RK(B,A,k,key,9), RK(C,A,k,key,10), RK(D,A,k,key,11), RK(B,A,k,key,12), RK(C,A,k,key,13), \ + RK(D,A,k,key,14), RK(B,A,k,key,15), RK(C,A,k,key,16), RK(D,A,k,key,17), RK(B,A,k,key,18), RK(C,A,k,key,19), RK(D,A,k,key,20), \ + RK(B,A,k,key,21), RK(C,A,k,key,22), RK(D,A,k,key,23), RK(B,A,k,key,24), RK(C,A,k,key,25), RK(D,A,k,key,26), RK(B,A,k,key,27), \ + RK(C,A,k,key,28), RK(D,A,k,key,29), RK(B,A,k,key,30), RK(C,A,k,key,31), RK(D,A,k,key,32), RK(B,A,k,key,33)) + +#define Encrypt_Dispatcher(keysize) \ + u64 x[2], y[2]; \ + u128 X[4], Y[4], Z[4]; \ + \ + if(numbytes == 16) { \ + x[0] = nonce[1]; y[0] = nonce[0]; nonce[0]++; \ + Encrypt_##keysize(x, y, ctx.key, 1); \ + ((u64 *)out)[1] = x[0]; ((u64 *)out)[0] = y[0]; \ + return 0; \ + } \ + \ + SET1(X[0], nonce[1]); SET2(Y[0], nonce[0]); \ + \ + if(numbytes == 32) \ + Encrypt_##keysize(X, Y, ctx.rk, 2); \ + else { \ + X[1] = X[0]; Y[1] = ADD(Y[0], _two); \ + if(numbytes == 64) \ + Encrypt_##keysize(X, Y, ctx.rk, 4); \ + else { \ + X[2] = X[0]; Y[2] = ADD(Y[1], _two); \ + if(numbytes == 96) \ + Encrypt_##keysize(X, Y, ctx.rk, 6); \ + else { \ + X[3] = X[0]; Y[3] = ADD(Y[2], _two); \ + Encrypt_##keysize(X, Y, ctx.rk, 8); \ + } \ + } \ + } \ + \ + nonce[0] += (numbytes >> 4); \ + \ + XOR_STORE(in, out, X[0], Y[0]); \ + if(numbytes >= 64) \ + XOR_STORE(in + 32, out + 32, X[1], Y[1]); \ + if(numbytes >= 96) \ + XOR_STORE(in + 64, out + 64, X[2], Y[2]); \ + if(numbytes >= 128) \ + XOR_STORE(in + 96, out + 96, X[3], Y[3]); \ + \ + return 0 + + +// attention: ctx is provided by value as it is faster in this case, astonishingly +static int speck_encrypt_xor (unsigned char *out, const unsigned char *in, u64 nonce[], const speck_context_t ctx, int numbytes) { + + if(ctx.keysize == 256) { + Encrypt_Dispatcher(256); + } else { + Encrypt_Dispatcher(128); + } +} + + +// attention: ctx is provided by value as it is faster in this case, astonishingly +static int internal_speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen, + const unsigned char *n, const speck_context_t ctx) { + + int i; + u64 nonce[2]; + unsigned char block[16]; + u64 * const block64 = (u64 *)block; + + if(!inlen) + return 0; + + nonce[0] = ((u64 *)n)[0]; + nonce[1] = ((u64 *)n)[1]; + + while(inlen >= 128) { + speck_encrypt_xor(out, in, nonce, ctx, 128); + in += 128; inlen -= 128; out += 128; + } + + if(inlen >= 96) { + speck_encrypt_xor(out, in, nonce, ctx, 96); + in += 96; inlen -= 96; out += 96; + } + + if(inlen >= 64) { + speck_encrypt_xor(out, in, nonce, ctx, 64); + in += 64; inlen -= 64; out += 64; + } + + if(inlen >= 32) { + speck_encrypt_xor(out, in, nonce, ctx, 32); + in += 32; inlen -= 32; out += 32; + } + + if(inlen >= 16) { + speck_encrypt_xor(block, in, nonce, ctx, 16); + ((u64 *)out)[0] = block64[0] ^ ((u64 *)in)[0]; + ((u64 *)out)[1] = block64[1] ^ ((u64 *)in)[1]; + in += 16; inlen -= 16; out += 16; + } + + if(inlen > 0) { + speck_encrypt_xor (block, in, nonce, ctx, 16); + for(i = 0; i < inlen; i++) + out[i] = block[i] ^ in[i]; + } + + return 0; +} + + +static int speck_expand_key (speck_context_t *ctx, const unsigned char *k, int keysize) { + + u64 K[4]; + size_t i; + + for(i = 0; i < (keysize >> 6 ); i++) + K[i] = ((u64 *)k)[i]; + + // 128 bit has only two keys A and B thus replacing both C and D with B then + if(keysize == 128) { + EK(K[0], K[1], K[1], K[1], ctx->rk, ctx->key); + } else { + EK(K[0], K[1], K[2], K[3], ctx->rk, ctx->key); + } + + ctx->keysize = keysize; + + return 0; +} + + +#elif defined (__ARM_NEON) && defined (SPECK_ARM_NEON) // NEON support --------------------------------------- + + +#define LCS(x,r) (((x)<>(64-r))) +#define RCS(x,r) (((x)>>r)|((x)<<(64-r))) + +#define XOR veorq_u64 +#define AND vandq_u64 +#define ADD vaddq_u64 +#define SL vshlq_n_u64 +#define SR vshrq_n_u64 + +#define SET(a,b) vcombine_u64((uint64x1_t)(a),(uint64x1_t)(b)) +#define SET1(X,c) (X=SET(c,c)) +#define SET2(X,c) (SET1(X,c), X=ADD(X,SET(0x1ll,0x0ll)),c+=2) + +#define LOW(Z) vgetq_lane_u64(Z,0) +#define HIGH(Z) vgetq_lane_u64(Z,1) +#define STORE(ip,X,Y) (((u64 *)(ip))[0]=HIGH(Y), ((u64 *)(ip))[1]=HIGH(X), ((u64 *)(ip))[2]=LOW(Y), ((u64 *)(ip))[3]=LOW(X)) +#define XOR_STORE(in,out,X,Y) (Y=XOR(Y,SET(((u64 *)(in))[2],((u64 *)(in))[0])), X=XOR(X,SET(((u64 *)(in))[3],((u64 *)(in))[1])), STORE(out,X,Y)) + +#define ROR(X,r) vsriq_n_u64(SL(X,(64-r)),X,r) +#define ROL(X,r) ROR(X,(64-r)) + +#define tableR vcreate_u8(0x0007060504030201LL) +#define tableL vcreate_u8(0x0605040302010007LL) +#define ROR8(X) SET(vtbl1_u8((uint8x8_t)vget_low_u64(X),tableR), vtbl1_u8((uint8x8_t)vget_high_u64(X),tableR)) +#define ROL8(X) SET(vtbl1_u8((uint8x8_t)vget_low_u64(X),tableL), vtbl1_u8((uint8x8_t)vget_high_u64(X),tableL)) + +#define R(X,Y,k) (X=XOR(ADD(ROR8(X),Y),k), Y=XOR(ROL(Y,3),X)) + +#define Rx2(X,Y,k) (R(X[0],Y[0],k)) +#define Rx4(X,Y,k) (R(X[0],Y[0],k), R(X[1],Y[1],k)) +#define Rx6(X,Y,k) (R(X[0],Y[0],k), R(X[1],Y[1],k), R(X[2],Y[2],k)) +#define Rx8(X,Y,k) (X[0]=ROR8(X[0]), X[0]=ADD(X[0],Y[0]), X[0]=XOR(X[0],k), X[1]=ROR8(X[1]), X[1]=ADD(X[1],Y[1]), X[1]=XOR(X[1],k), \ + X[2]=ROR8(X[2]), X[2]=ADD(X[2],Y[2]), X[2]=XOR(X[2],k), X[3]=ROR8(X[3]), X[3]=ADD(X[3],Y[3]), X[3]=XOR(X[3],k), \ + Z[0]=SL(Y[0],3), Z[1]=SL(Y[1],3), Z[2]=SL(Y[2],3), Z[3]=SL(Y[3],3), \ + Y[0]=SR(Y[0],61), Y[1]=SR(Y[1],61), Y[2]=SR(Y[2],61), Y[3]=SR(Y[3],61), \ + Y[0]=XOR(Y[0],Z[0]), Y[1]=XOR(Y[1],Z[1]), Y[2]=XOR(Y[2],Z[2]), Y[3]=XOR(Y[3],Z[3]), \ + Y[0]=XOR(X[0],Y[0]), Y[1]=XOR(X[1],Y[1]), Y[2]=XOR(X[2],Y[2]), Y[3]=XOR(X[3],Y[3])) + +#define Rx1(x,y,k) (x[0]=RCS(x[0],8), x[0]+=y[0], x[0]^=k, y[0]=LCS(y[0],3), y[0]^=x[0]) +#define Rx1b(x,y,k) (x=RCS(x,8), x+=y, x^=k, y=LCS(y,3), y^=x) + +#define Encrypt_128(X,Y,k,n) (Rx##n(X,Y,k[0]), Rx##n(X,Y,k[1]), Rx##n(X,Y,k[2]), Rx##n(X,Y,k[3]), Rx##n(X,Y,k[4]), Rx##n(X,Y,k[5]), Rx##n(X,Y,k[6]), Rx##n(X,Y,k[7]), \ + Rx##n(X,Y,k[8]), Rx##n(X,Y,k[9]), Rx##n(X,Y,k[10]), Rx##n(X,Y,k[11]), Rx##n(X,Y,k[12]), Rx##n(X,Y,k[13]), Rx##n(X,Y,k[14]), Rx##n(X,Y,k[15]), \ + Rx##n(X,Y,k[16]), Rx##n(X,Y,k[17]), Rx##n(X,Y,k[18]), Rx##n(X,Y,k[19]), Rx##n(X,Y,k[20]), Rx##n(X,Y,k[21]), Rx##n(X,Y,k[22]), Rx##n(X,Y,k[23]), \ + Rx##n(X,Y,k[24]), Rx##n(X,Y,k[25]), Rx##n(X,Y,k[26]), Rx##n(X,Y,k[27]), Rx##n(X,Y,k[28]), Rx##n(X,Y,k[29]), Rx##n(X,Y,k[30]), Rx##n(X,Y,k[31])) + +#define Encrypt_256(X,Y,k,n) (Encrypt_128(X,Y,k,n), \ + Rx##n(X,Y,k[32]), Rx##n(X,Y,k[33])) + +#define RK(X,Y,k,key,i) (SET1(k[i],Y), key[i]=Y, X=RCS(X,8), X+=Y, X^=i, Y=LCS(Y,3), Y^=X) + +#define EK(A,B,C,D,k,key) (RK(B,A,k,key,0), RK(C,A,k,key,1), RK(D,A,k,key,2), RK(B,A,k,key,3), RK(C,A,k,key,4), RK(D,A,k,key,5), RK(B,A,k,key,6), \ + RK(C,A,k,key,7), RK(D,A,k,key,8), RK(B,A,k,key,9), RK(C,A,k,key,10), RK(D,A,k,key,11), RK(B,A,k,key,12), RK(C,A,k,key,13), \ + RK(D,A,k,key,14), RK(B,A,k,key,15), RK(C,A,k,key,16), RK(D,A,k,key,17), RK(B,A,k,key,18), RK(C,A,k,key,19), RK(D,A,k,key,20), \ + RK(B,A,k,key,21), RK(C,A,k,key,22), RK(D,A,k,key,23), RK(B,A,k,key,24), RK(C,A,k,key,25), RK(D,A,k,key,26), RK(B,A,k,key,27), \ + RK(C,A,k,key,28), RK(D,A,k,key,29), RK(B,A,k,key,30), RK(C,A,k,key,31), RK(D,A,k,key,32), RK(B,A,k,key,33)) + +#define Encrypt_Dispatcher(keysize) \ + u64 x[2], y[2]; \ + u128 X[4], Y[4], Z[4]; \ + \ + if(numbytes == 16) { \ + x[0] = nonce[1]; y[0]=nonce[0]; nonce[0]++; \ + Encrypt_##keysize(x, y, ctx->key, 1); \ + ((u64 *)out)[1] = x[0]; ((u64 *)out)[0] = y[0]; \ + return 0; \ + } \ + \ + SET1(X[0], nonce[1]); SET2(Y[0], nonce[0]); \ + \ + if(numbytes == 32) \ + Encrypt_##keysize(X, Y, ctx->rk, 2); \ + else { \ + X[1] = X[0]; SET2(Y[1], nonce[0]); \ + if(numbytes == 64) \ + Encrypt_##keysize(X, Y, ctx->rk, 4); \ + else { \ + X[2] = X[0]; SET2(Y[2], nonce[0]); \ + if(numbytes == 96) \ + Encrypt_##keysize(X, Y, ctx->rk, 6); \ + else { \ + X[3] = X[0]; SET2(Y[3], nonce[0]); \ + Encrypt_##keysize(X, Y, ctx->rk, 8); \ + } \ + } \ + } \ + \ + XOR_STORE(in, out, X[0], Y[0]); \ + if(numbytes >= 64) \ + XOR_STORE(in + 32, out + 32, X[1], Y[1]); \ + if(numbytes >= 96) \ + XOR_STORE(in + 64, out + 64, X[2], Y[2]); \ + if(numbytes >= 128) \ + XOR_STORE(in + 96, out + 96, X[3], Y[3]); \ + \ + return 0 + + +static int speck_encrypt_xor (unsigned char *out, const unsigned char *in, u64 nonce[], speck_context_t *ctx, int numbytes) { + + if(ctx->keysize == 256) { + Encrypt_Dispatcher(256); + } else { + Encrypt_Dispatcher(128); + } +} + + +static int internal_speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen, + const unsigned char *n, speck_context_t *ctx) { + + int i; + u64 nonce[2]; + unsigned char block[16]; + u64 *const block64 = (u64 *)block; + + if(!inlen) + return 0; + + nonce[0] = ((u64 *)n)[0]; + nonce[1] = ((u64 *)n)[1]; + + while(inlen >= 128) { + speck_encrypt_xor(out, in, nonce, ctx, 128); + in += 128; inlen -= 128; out += 128; + } + + if(inlen >= 96) { + speck_encrypt_xor(out, in, nonce, ctx, 96); + in += 96; inlen -= 96; out += 96; + } + + if(inlen >= 64) { + speck_encrypt_xor(out, in, nonce, ctx, 64); + in += 64; inlen -= 64; out += 64; + } + + if(inlen >= 32) { + speck_encrypt_xor(out, in, nonce, ctx, 32); + in += 32; inlen -= 32; out += 32; + } + + if(inlen >= 16) { + speck_encrypt_xor(block, in, nonce, ctx, 16); + ((u64 *)out)[0] = block64[0] ^ ((u64 *)in)[0]; + ((u64 *)out)[1] = block64[1] ^ ((u64 *)in)[1]; + in += 16; inlen -= 16; out += 16; + } + + if(inlen > 0) { + speck_encrypt_xor(block, in, nonce, ctx, 16); + for(i = 0; i < inlen; i++) + out[i] = block[i] ^ in[i]; + } + + return 0; +} + + +static int speck_expand_key (speck_context_t *ctx, const unsigned char *k, int keysize) { + + u64 K[4]; + size_t i; + + for(i = 0; i < (keysize >> 6); i++) + K[i] = ((u64 *)k)[i]; + + // 128 bit has only two keys A and B thus replacing both C and D with B then + if(keysize == 128) { + EK(K[0], K[1], K[1], K[1], ctx->rk, ctx->key); + } else { + EK(K[0], K[1], K[2], K[3], ctx->rk, ctx->key); + } + + ctx->keysize = keysize; + + return 0; +} + + +#else // plain C ---------------------------------------------------------------------------------------- + + +#define ROR(x,r) (((x)>>(r))|((x)<<(64-(r)))) +#define ROL(x,r) (((x)<<(r))|((x)>>(64-(r)))) +#define R(x,y,k) (x=ROR(x,8), x+=y, x^=k, y=ROL(y,3), y^=x) + + +static int speck_encrypt (u64 *u, u64 *v, speck_context_t *ctx, int numrounds) { + + u64 i, x = *u, y = *v; + + for(i = 0; i < numrounds; i++) + R(x, y, ctx->key[i]); + *u = x; *v = y; + + return 0; +} + + +static int internal_speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen, + const unsigned char *n, speck_context_t *ctx) { + + u64 i, nonce[2], x, y, t; + unsigned char *block = malloc(16); + int numrounds = (ctx->keysize == 256)?34:32; + + if(!inlen) { + free(block); + return 0; + } + nonce[0] = htole64( ((u64*)n)[0] ); + nonce[1] = htole64( ((u64*)n)[1] ); + + t=0; + while(inlen >= 16) { + x = nonce[1]; y = nonce[0]; nonce[0]++; + speck_encrypt(&x, &y, ctx, numrounds); + ((u64 *)out)[1+t] = htole64(x ^ ((u64 *)in)[1+t]); + ((u64 *)out)[0+t] = htole64(y ^ ((u64 *)in)[0+t]); + t += 2; + inlen -= 16; + } + + if(inlen > 0) { + x = nonce[1]; y = nonce[0]; + speck_encrypt(&x, &y, ctx, numrounds); + ((u64 *)block)[1] = htole64(x); ((u64 *)block)[0] = htole64(y); + for(i = 0; i < inlen; i++) + out[i + 8*t] = block[i] ^ in[i + 8*t]; + } + + free(block); + + return 0; +} + + +static int speck_expand_key (speck_context_t *ctx, const unsigned char *k, int keysize) { + + u64 K[4]; + u64 i; + + for(i = 0; i < (keysize >> 6); i++) + K[i] = htole64( ((u64 *)k)[i] ); + + for(i = 0; i < 33; i += 3) { + ctx->key[i ] = K[0]; + R(K[1], K[0], i ); + + if(keysize == 256) { + ctx->key[i+1] = K[0]; + R(K[2], K[0], i + 1); + ctx->key[i+2] = K[0]; + R(K[3], K[0], i + 2); + } else { + // counter the i += 3 to make the loop go one by one in this case + // we can afford the unused 31 and 32 + i -= 2; + } + } + ctx->key[33] = K[0]; + + ctx->keysize = keysize; + + return 1; +} + + +#endif // AVX, SSE, NEON, plain C ------------------------------------------------------------------------ + + +// this functions wraps the call to internal_speck_ctr functions which have slightly different +// signature -- ctx by value for SSE with SPECK_CTX_BYVAL defined in speck.h, by name otherwise +int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen, + const unsigned char *n, speck_context_t *ctx) { + + return internal_speck_ctr(out, in, inlen, n, +#if defined (SPECK_CTX_BYVAL) + *ctx); +#else + ctx); +#endif +} + + +// create context loaded with round keys ready for use, key size either 128 or 256 (bits) +int speck_init (speck_context_t **ctx, const unsigned char *k, int keysize) { + +#if defined (SPECK_ALIGNED_CTX) + *ctx = (speck_context_t*)_mm_malloc(sizeof(speck_context_t), SPECK_ALIGNED_CTX); +#else + *ctx = (speck_context_t*)calloc(1, sizeof(speck_context_t)); +#endif + if(!(*ctx)) { + return -1; + } + + return speck_expand_key(*ctx, k, keysize); +} + + +int speck_deinit (speck_context_t *ctx) { + + if(ctx) { +#if defined (SPECK_ALIGNED_CTX) + _mm_free(ctx); +#else + free(ctx); +#endif + } + + return 0; +} + + +// ---------------------------------------------------------------------------------------------------------------- + + +// cipher SPECK -- 128 bit block size -- 128 bit key size -- ECB mode (decrypt only) +// follows endianess rules as used in official implementation guide and NOT as in original 2013 cipher presentation +// used for IV in header encryption (one block) and challenge encryption (user/password) +// for now: just plain C -- probably no need for AVX, SSE, NEON + + +#define ROTL64(x,r) (((x)<<(r))|((x)>>(64-(r)))) +#define ROTR64(x,r) (((x)>>(r))|((x)<<(64-(r)))) +#define DR128(x,y,k) (y^=x, y=ROTR64(y,3), x^=k, x-=y, x=ROTL64(x,8)) +#define ER128(x,y,k) (x=(ROTR64(x,8)+y)^k, y=ROTL64(y,3)^x) + +int speck_128_decrypt (unsigned char *inout, speck_context_t *ctx) { + + u64 x, y; + int i; + + x = le64toh( *(u64*)&inout[8] ); + y = le64toh( *(u64*)&inout[0] ); + + for(i = 31; i >= 0; i--) + DR128(x, y, ctx->key[i]); + + ((u64*)inout)[1] = htole64(x); + ((u64*)inout)[0] = htole64(y); + + return 0; +} + + +int speck_128_encrypt (unsigned char *inout, speck_context_t *ctx) { + + u64 x, y; + int i; + + x = le64toh( *(u64*)&inout[8] ); + y = le64toh( *(u64*)&inout[0] ); + + for(i = 0; i < 32; i++) + ER128(x, y, ctx->key[i]); + + ((u64*)inout)[1] = htole64(x); + ((u64*)inout)[0] = htole64(y); + + return 0; +} diff --git a/src/supernode.c b/src/supernode.c new file mode 100644 index 0000000..848f74c --- /dev/null +++ b/src/supernode.c @@ -0,0 +1,693 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +/* Supernode for n2n-2.x */ + +#include "n2n.h" +#include "header_encryption.h" + +#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out) + +static n2n_sn_t sss_node; + +void close_tcp_connection (n2n_sn_t *sss, n2n_tcp_connection_t *conn); +void calculate_shared_secrets (n2n_sn_t *sss); +int load_allowed_sn_community (n2n_sn_t *sss); +int resolve_create_thread (n2n_resolve_parameter_t **param, struct peer_info *sn_list); + + +/** Help message to print if the command line arguments are not valid. */ +static void help (int level) { + + if(level == 0) /* no help required */ + return; + + printf("\n"); + print_n2n_version(); + + if(level == 1) /* short help */ { + + printf(" basic usage: supernode (see supernode.conf)\n" + "\n" + " or supernode " + "[optional parameters, at least one] " + "\n " + "\n technically, all parameters are optional, but the supernode executable" + "\n requires at least one parameter to run, .e.g. -v or -f, as otherwise this" + "\n short help text is displayed" + "\n\n -h shows a quick reference including all available options" + "\n --help gives a detailed parameter description" + "\n man files for n2n, edge, and superndode contain in-depth information" + "\n\n"); + + } else if(level == 2) /* quick reference */ { + + printf(" general usage: supernode (see supernode.conf)\n" + "\n" + " or supernode " + "[-p ] " + "\n " + "[-F ] " + "\n options for under- " + "[-l ] " + "\n lying connection " +#ifdef SN_MANUAL_MAC + "[-m ] " +#endif + "[-M] " + "[-V ] " + "\n\n overlay network " + "[-c ] " + "\n configuration " + "[-a -/] " + "\n\n local options " +#if defined(N2N_HAVE_DAEMON) + "[-f] " +#endif + "[-t ] " + "\n " + "[--management-password ] " + "[-v] " +#ifndef WIN32 + "\n " + "[-u ]" + "[-g ]" +#endif + "\n\n meaning of the " + "[-M] disable MAC and IP address spoofing protection" + "\n flag options " +#if defined(N2N_HAVE_DAEMON) + "[-f] do not fork but run in foreground" + "\n " +#endif + "[-v] make more verbose, repeat as required" + "\n " + "\n technically, all parameters are optional, but the supernode executable" + "\n requires at least one parameter to run, .e.g. -v or -f, as otherwise a" + "\n short help text is displayed" + "\n\n -h shows this quick reference including all available options" + "\n --help gives a detailed parameter description" + "\n man files for n2n, edge, and superndode contain in-depth information" + "\n\n"); + + } else /* long help */ { + + printf(" general usage: supernode (see supernode.conf)\n" + "\n" + " or supernode [optional parameters, at least one]\n\n" + ); + printf (" OPTIONS FOR THE UNDERLYING NETWORK CONNECTION\n"); + printf (" ---------------------------------------------\n\n"); + printf(" -p | fixed local UDP port, defaults to %u\n", N2N_SN_LPORT_DEFAULT); + printf(" -F | name of the supernode's federation, defaults to\n" + " | '%s'\n", (char *)FEDERATION_NAME); + printf(" -l | ip address or name, and port of known supernode\n"); +#ifdef SN_MANUAL_MAC + printf(" -m | fixed MAC address for the supernode, e.g.\n" + " | '-m 10:20:30:40:50:60', random otherwise\n"); +#endif + printf(" -M | disable MAC and IP address spoofing protection for all\n" + " | non-username-password-authenticating communities\n"); + printf(" -V | sends a custom supernode version string of max 19 letters \n" + " | length to edges, visible in their management port output\n"); + printf ("\n"); + printf (" TAP DEVICE AND OVERLAY NETWORK CONFIGURATION\n"); + printf (" --------------------------------------------\n\n"); + printf(" -c | file containing the allowed communities\n"); + printf(" -a | subnet range for auto ip address service, e.g.\n" + " | '-a 192.168.0.0-192.168.255.0/24', defaults\n" + " | to '10.128.255.0-10.255.255.0/24'\n"); + printf ("\n"); + printf (" LOCAL OPTIONS\n"); + printf (" -------------\n\n"); +#if defined(N2N_HAVE_DAEMON) + printf(" -f | do not fork and run as a daemon, rather run in foreground\n"); +#endif + printf(" -t | management UDP port, for multiple supernodes on a machine,\n" + " | defaults to %u\n", N2N_SN_MGMT_PORT); + printf(" --management_... | management port password, defaults to '%s'\n" + " ...password | \n", N2N_MGMT_PASSWORD); + printf(" -v | make more verbose, repeat as required\n"); +#ifndef WIN32 + printf(" -u | numeric user ID to use when privileges are dropped\n"); + printf(" -g | numeric group ID to use when privileges are dropped\n"); +#endif + printf("\n technically, all parameters are optional, but the supernode executable" + "\n requires at least one parameter to run, .e.g. -v or -f, as otherwise a" + "\n short help text is displayed" + "\n\n -h shows a quick reference including all available options" + "\n --help gives this detailed parameter description" + "\n man files for n2n, edge, and superndode contain in-depth information" + "\n\n"); + } + + exit(0); +} + + +/* *************************************************** */ + +static int setOption (int optkey, char *_optarg, n2n_sn_t *sss) { + + //traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, _optarg ? _optarg : ""); + + switch(optkey) { + case 'p': /* local-port */ + sss->lport = atoi(_optarg); + + if(sss->lport == 0) + traceEvent(TRACE_WARNING, "bad local port format, defaulting to %u", N2N_SN_LPORT_DEFAULT); + // default is made sure in sn_init() + + break; + + case 't': /* mgmt-port */ + sss->mport = atoi(_optarg); + + if(sss->mport == 0) + traceEvent(TRACE_WARNING, "bad management port format, defaulting to %u", N2N_SN_MGMT_PORT); + // default is made sure in sn_init() + + break; + + case 'l': { /* supernode:port */ + n2n_sock_t *socket; + struct peer_info *anchor_sn; + size_t length; + int rv = -1; + int skip_add; + char *double_column = strchr(_optarg, ':'); + + length = strlen(_optarg); + if(length >= N2N_EDGE_SN_HOST_SIZE) { + traceEvent(TRACE_WARNING, "size of -l argument too long: %zu; maximum size is %d", length, N2N_EDGE_SN_HOST_SIZE); + return 1; + } + + if(!double_column) { + traceEvent(TRACE_WARNING, "invalid -l format, missing port"); + return 1; + } + + socket = (n2n_sock_t *)calloc(1, sizeof(n2n_sock_t)); + rv = supernode2sock(socket, _optarg); + + if(rv < -2) { /* we accept resolver failure as it might resolve later */ + traceEvent(TRACE_WARNING, "invalid supernode parameter"); + free(socket); + return 1; + } + + if(sss->federation != NULL) { + skip_add = SN_ADD; + anchor_sn = add_sn_to_list_by_mac_or_sock(&(sss->federation->edges), socket, null_mac, &skip_add); + + if(anchor_sn != NULL) { + anchor_sn->ip_addr = calloc(1, N2N_EDGE_SN_HOST_SIZE); + if(anchor_sn->ip_addr) { + strncpy(anchor_sn->ip_addr, _optarg, N2N_EDGE_SN_HOST_SIZE - 1); + memcpy(&(anchor_sn->sock), socket, sizeof(n2n_sock_t)); + memcpy(anchor_sn->mac_addr, null_mac, sizeof(n2n_mac_t)); + anchor_sn->purgeable = SN_UNPURGEABLE; + anchor_sn->last_valid_time_stamp = initial_time_stamp(); + } + } + } + + free(socket); + break; + } + + case 'a': { + dec_ip_str_t ip_min_str = {'\0'}; + dec_ip_str_t ip_max_str = {'\0'}; + in_addr_t net_min, net_max; + uint8_t bitlen; + uint32_t mask; + + if(sscanf(_optarg, "%15[^\\-]-%15[^/]/%hhu", ip_min_str, ip_max_str, &bitlen) != 3) { + traceEvent(TRACE_WARNING, "bad net-net/bit format '%s'.", _optarg); + return 2; + } + + net_min = inet_addr(ip_min_str); + net_max = inet_addr(ip_max_str); + mask = bitlen2mask(bitlen); + if((net_min == (in_addr_t)(-1)) || (net_min == INADDR_NONE) || (net_min == INADDR_ANY) + || (net_max == (in_addr_t)(-1)) || (net_max == INADDR_NONE) || (net_max == INADDR_ANY) + || (ntohl(net_min) > ntohl(net_max)) + || ((ntohl(net_min) & ~mask) != 0) || ((ntohl(net_max) & ~mask) != 0)) { + traceEvent(TRACE_WARNING, "bad network range '%s...%s/%u' in '%s', defaulting to '%s...%s/%d'", + ip_min_str, ip_max_str, bitlen, _optarg, + N2N_SN_MIN_AUTO_IP_NET_DEFAULT, N2N_SN_MAX_AUTO_IP_NET_DEFAULT, N2N_SN_AUTO_IP_NET_BIT_DEFAULT); + return 2; + } + + if((bitlen > 30) || (bitlen == 0)) { + traceEvent(TRACE_WARNING, "bad prefix '%hhu' in '%s', defaulting to '%s...%s/%d'", + bitlen, _optarg, + N2N_SN_MIN_AUTO_IP_NET_DEFAULT, N2N_SN_MAX_AUTO_IP_NET_DEFAULT, N2N_SN_AUTO_IP_NET_BIT_DEFAULT); + return 2; + } + + traceEvent(TRACE_NORMAL, "the network range for community ip address service is '%s...%s/%hhu'", ip_min_str, ip_max_str, bitlen); + + sss->min_auto_ip_net.net_addr = ntohl(net_min); + sss->min_auto_ip_net.net_bitlen = bitlen; + sss->max_auto_ip_net.net_addr = ntohl(net_max); + sss->max_auto_ip_net.net_bitlen = bitlen; + + break; + } +#ifndef WIN32 + case 'u': /* unprivileged uid */ + sss->userid = atoi(_optarg); + break; + + case 'g': /* unprivileged uid */ + sss->groupid = atoi(_optarg); + break; +#endif + case 'F': { /* federation name */ + snprintf(sss->federation->community, N2N_COMMUNITY_SIZE - 1 ,"*%s", _optarg); + sss->federation->community[N2N_COMMUNITY_SIZE - 1] = '\0'; + break; + } +#ifdef SN_MANUAL_MAC + case 'm': {/* MAC address */ + str2mac(sss->mac_addr, _optarg); + + // clear multicast bit + sss->mac_addr[0] &= ~0x01; + // set locally-assigned bit + sss->mac_addr[0] |= 0x02; + + break; + } +#endif + case 'M': /* override spoofing protection */ + sss->override_spoofing_protection = 1; + break; + + case 'V': /* version text */ + strncpy(sss->version, _optarg, sizeof(n2n_version_t)); + sss->version[sizeof(n2n_version_t) - 1] = '\0'; + break; + case 'c': /* community file */ + sss->community_file = calloc(1, strlen(_optarg) + 1); + if(sss->community_file) + strcpy(sss->community_file, _optarg); + break; + + case ']': /* password for management port */ { + sss->mgmt_password_hash = pearson_hash_64((uint8_t*)_optarg, strlen(_optarg)); + + break; + } +#if defined(N2N_HAVE_DAEMON) + case 'f': /* foreground */ + sss->daemon = 0; + break; +#endif + case 'h': /* quick reference */ + return 2; + + case '@': /* long help */ + return 3; + + case 'v': /* verbose */ + setTraceLevel(getTraceLevel() + 1); + break; + + default: + traceEvent(TRACE_WARNING, "unknown option -%c:", (char) optkey); + return 2; + } + + return 0; +} + + +/* *********************************************** */ + +static const struct option long_options[] = { + {"communities", required_argument, NULL, 'c'}, +#if defined(N2N_HAVE_DAEMON) + {"foreground", no_argument, NULL, 'f'}, +#endif + {"local-port", required_argument, NULL, 'p'}, + {"mgmt-port", required_argument, NULL, 't'}, + {"autoip", required_argument, NULL, 'a'}, + {"verbose", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, '@'}, /* special character '@' to identify long help case */ + {"management-password", required_argument, NULL, ']' }, /* ']' management port password */ + {NULL, 0, NULL, 0} +}; + +/* *************************************************** */ + +/* read command line options */ +static int loadFromCLI (int argc, char * const argv[], n2n_sn_t *sss) { + + u_char c; + + while((c = getopt_long(argc, argv, + "p:l:t:a:c:F:vhMV:" +#ifdef SN_MANUAL_MAC + "m:" +#endif +#if defined(N2N_HAVE_DAEMON) + "f" +#endif +#ifndef WIN32 + "u:g:" +#endif + , + long_options, NULL)) != '?') { + if(c == 255) { + break; + } + help(setOption(c, optarg, sss)); + } + + return 0; +} + +/* *************************************************** */ + +static char *trim (char *s) { + + char *end; + + while(isspace(s[0]) || (s[0] == '"') || (s[0] == '\'')) { + s++; + } + + if(s[0] == 0) { + return s; + } + + end = &s[strlen(s) - 1]; + while(end > s && (isspace(end[0])|| (end[0] == '"') || (end[0] == '\''))) { + end--; + } + end[1] = 0; + + return s; +} + +/* *************************************************** */ + +/* parse the configuration file */ +static int loadFromFile (const char *path, n2n_sn_t *sss) { + + char buffer[4096], *line; + char *line_vec[3]; + int tmp; + + FILE *fd; + + fd = fopen(path, "r"); + + if(fd == NULL) { + traceEvent(TRACE_WARNING, "config file %s not found", path); + return -1; + } + + // we mess around with optind, better save it + tmp = optind; + + while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { + line = trim(line); + + if(strlen(line) < 2 || line[0] == '#') { + continue; + } + + // executable, cannot be omitted, content can be anything + line_vec[0] = line; + // first token, e.g. `-p`, eventually followed by a whitespace or '=' delimiter + line_vec[1] = strtok(line, "\t ="); + // separate parameter option, if present + line_vec[2] = strtok(NULL, "\t "); + + // not to duplicate the option parser code, call loadFromCLI and pretend we have no option read yet + optind = 0; + // if separate second token present (optional argument, not part of first), then announce 3 vector members + loadFromCLI(line_vec[2] ? 3 : 2, line_vec, sss); + } + + fclose(fd); + optind = tmp; + + return 0; +} + +/* *************************************************** */ + +/* Add the federation to the communities list of a supernode */ +static int add_federation_to_communities (n2n_sn_t *sss) { + + uint32_t num_communities = 0; + + if(sss->federation != NULL) { + HASH_ADD_STR(sss->communities, community, sss->federation); + + num_communities = HASH_COUNT(sss->communities); + + traceEvent(TRACE_INFO, "added federation '%s' to the list of communities [total: %u]", + (char*)sss->federation->community, num_communities); + } + + return 0; +} + +/* *************************************************** */ + +#ifdef __linux__ +static void dump_registrations (int signo) { + + struct sn_community *comm, *ctmp; + struct peer_info *list, *tmp; + char buf[32]; + time_t now = time(NULL); + u_int num = 0; + + traceEvent(TRACE_NORMAL, "===================================="); + + HASH_ITER(hh, sss_node.communities, comm, ctmp) { + traceEvent(TRACE_NORMAL, "dumping community: %s", comm->community); + + HASH_ITER(hh, comm->edges, list, tmp) { + if(list->sock.family == AF_INET) { + traceEvent(TRACE_NORMAL, "[id: %u][MAC: %s][edge: %u.%u.%u.%u:%u][last seen: %u sec ago]", + ++num, macaddr_str(buf, list->mac_addr), + list->sock.addr.v4[0], list->sock.addr.v4[1], list->sock.addr.v4[2], list->sock.addr.v4[3], + list->sock.port, + now - list->last_seen); + } else { + traceEvent(TRACE_NORMAL, "[id: %u][MAC: %s][edge: IPv6:%u][last seen: %u sec ago]", + ++num, macaddr_str(buf, list->mac_addr), list->sock.port, + now - list->last_seen); + } + } + } + + traceEvent(TRACE_NORMAL, "===================================="); +} +#endif + +/* *************************************************** */ + +static int keep_running; + +#if defined(__linux__) || defined(WIN32) +#ifdef WIN32 +BOOL WINAPI term_handler (DWORD sig) +#else + static void term_handler(int sig) +#endif +{ + static int called = 0; + + if(called) { + traceEvent(TRACE_NORMAL, "ok, I am leaving now"); + _exit(0); + } else { + traceEvent(TRACE_NORMAL, "shutting down..."); + called = 1; + } + + keep_running = 0; +#ifdef WIN32 + return(TRUE); +#endif +} +#endif /* defined(__linux__) || defined(WIN32) */ + +/* *************************************************** */ + +/** Main program entry point from kernel. */ +int main (int argc, char * const argv[]) { + + int rc; +#ifndef WIN32 + struct passwd *pw = NULL; +#endif + struct peer_info *scan, *tmp; + + + sn_init_defaults(&sss_node); + add_federation_to_communities(&sss_node); + + if((argc >= 2) && (argv[1][0] != '-')) { + rc = loadFromFile(argv[1], &sss_node); + if(argc > 2) { + rc = loadFromCLI(argc, argv, &sss_node); + } + } else if(argc > 1) { + rc = loadFromCLI(argc, argv, &sss_node); + } else + +#ifdef WIN32 + // load from current directory + rc = loadFromFile("supernode.conf", &sss_node); +#else + rc = -1; +#endif + + if(rc < 0) { + help(1); /* short help */ + } + + if(sss_node.community_file) + load_allowed_sn_community(&sss_node); + +#if defined(N2N_HAVE_DAEMON) + if(sss_node.daemon) { + setUseSyslog(1); /* traceEvent output now goes to syslog. */ + + if(-1 == daemon(0, 0)) { + traceEvent(TRACE_ERROR, "failed to become daemon"); + exit(-5); + } + } +#endif /* #if defined(N2N_HAVE_DAEMON) */ + + // warn on default federation name + if(!strcmp(sss_node.federation->community, FEDERATION_NAME)) { + traceEvent(TRACE_WARNING, "using default federation name; FOR TESTING ONLY, usage of a custom federation name (-F) is highly recommended!"); + } + + if(sss_node.override_spoofing_protection) { + traceEvent(TRACE_WARNING, "disabled MAC and IP address spoofing protection; FOR TESTING ONLY, usage of user-password authentication (-I, -J, -P) recommended instead!"); + } + + calculate_shared_secrets(&sss_node); + + traceEvent(TRACE_DEBUG, "traceLevel is %d", getTraceLevel()); + + sss_node.sock = open_socket(sss_node.lport, INADDR_ANY, 0 /* UDP */); + if(-1 == sss_node.sock) { + traceEvent(TRACE_ERROR, "failed to open main socket. %s", strerror(errno)); + exit(-2); + } else { + traceEvent(TRACE_NORMAL, "supernode is listening on UDP %u (main)", sss_node.lport); + } + +#ifdef N2N_HAVE_TCP + sss_node.tcp_sock = open_socket(sss_node.lport, INADDR_ANY, 1 /* TCP */); + if(-1 == sss_node.tcp_sock) { + traceEvent(TRACE_ERROR, "failed to open auxiliary TCP socket, %s", strerror(errno)); + exit(-2); + } else { + traceEvent(TRACE_NORMAL, "supernode opened TCP %u (aux)", sss_node.lport); + } + + if(-1 == listen(sss_node.tcp_sock, N2N_TCP_BACKLOG_QUEUE_SIZE)) { + traceEvent(TRACE_ERROR, "failed to listen on auxiliary TCP socket, %s", strerror(errno)); + exit(-2); + } else { + traceEvent(TRACE_NORMAL, "supernode is listening on TCP %u (aux)", sss_node.lport); + } +#endif + + sss_node.mgmt_sock = open_socket(sss_node.mport, INADDR_LOOPBACK, 0 /* UDP */); + if(-1 == sss_node.mgmt_sock) { + traceEvent(TRACE_ERROR, "failed to open management socket, %s", strerror(errno)); + exit(-2); + } else { + traceEvent(TRACE_NORMAL, "supernode is listening on UDP %u (management)", sss_node.mport); + } + + HASH_ITER(hh, sss_node.federation->edges, scan, tmp) + scan->socket_fd = sss_node.sock; + +#ifndef WIN32 + /* + * If no uid/gid is specified on the commandline, use the uid/gid of the + * first found out of user "n2n" or "nobody" + */ + if(((pw = getpwnam ("n2n")) != NULL) || ((pw = getpwnam ("nobody")) != NULL)) { + /* + * If the uid/gid is not set from the CLI, set it from getpwnam + * otherwise reset it to zero + * (TODO: this looks wrong) + */ + sss_node.userid = sss_node.userid == 0 ? pw->pw_uid : 0; + sss_node.groupid = sss_node.groupid == 0 ? pw->pw_gid : 0; + } + + /* + * If we have a non-zero requested uid/gid, attempt to switch to use + * those + */ + if((sss_node.userid != 0) || (sss_node.groupid != 0)) { + traceEvent(TRACE_NORMAL, "dropping privileges to uid=%d, gid=%d", + (signed int)sss_node.userid, (signed int)sss_node.groupid); + + /* Finished with the need for root privileges. Drop to unprivileged user. */ + if((setgid(sss_node.groupid) != 0) + || (setuid(sss_node.userid) != 0)) { + traceEvent(TRACE_ERROR, "unable to drop privileges [%u/%s]", errno, strerror(errno)); + } + } + + if((getuid() == 0) || (getgid() == 0)) { + traceEvent(TRACE_WARNING, "running as root is discouraged, check out the -u/-g options"); + } +#endif + + sn_init(&sss_node); + + traceEvent(TRACE_NORMAL, "supernode started"); + +#ifdef __linux__ + signal(SIGPIPE, SIG_IGN); + signal(SIGTERM, term_handler); + signal(SIGINT, term_handler); + signal(SIGHUP, dump_registrations); +#endif +#ifdef WIN32 + SetConsoleCtrlHandler(term_handler, TRUE); +#endif + + keep_running = 1; + sss_node.keep_running = &keep_running; + return run_sn_loop(&sss_node); +} diff --git a/src/tf.c b/src/tf.c new file mode 100644 index 0000000..793c527 --- /dev/null +++ b/src/tf.c @@ -0,0 +1,619 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +// taken (and modified) from github/fudanchii/twofish as of August 2020 +// which itself is a modified copy of Andrew T. Csillag's implementation +// published on github/drewcsillag/twofish + + +/** + * The MIT License (MIT) + * + * Copyright (c) 2015 Andrew T. Csillag + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "tf.h" + + +const uint8_t RS[4][8] = { { 0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, }, + { 0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5, }, + { 0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19, }, + { 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03 } }; + +const uint8_t Q0[] = { 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, + 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, + 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, + 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, + 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, + 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, + 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, + 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, + 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, + 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, + 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0 }; + +const uint8_t Q1[] = { 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, + 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, + 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, + 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, + 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, + 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, + 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, + 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, + 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, + 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, + 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 }; + +const uint8_t mult5B[] = { 0x00, 0x5B, 0xB6, 0xED, 0x05, 0x5E, 0xB3, 0xE8, 0x0A, 0x51, 0xBC, 0xE7, 0x0F, 0x54, 0xB9, 0xE2, + 0x14, 0x4F, 0xA2, 0xF9, 0x11, 0x4A, 0xA7, 0xFC, 0x1E, 0x45, 0xA8, 0xF3, 0x1B, 0x40, 0xAD, 0xF6, + 0x28, 0x73, 0x9E, 0xC5, 0x2D, 0x76, 0x9B, 0xC0, 0x22, 0x79, 0x94, 0xCF, 0x27, 0x7C, 0x91, 0xCA, + 0x3C, 0x67, 0x8A, 0xD1, 0x39, 0x62, 0x8F, 0xD4, 0x36, 0x6D, 0x80, 0xDB, 0x33, 0x68, 0x85, 0xDE, + 0x50, 0x0B, 0xE6, 0xBD, 0x55, 0x0E, 0xE3, 0xB8, 0x5A, 0x01, 0xEC, 0xB7, 0x5F, 0x04, 0xE9, 0xB2, + 0x44, 0x1F, 0xF2, 0xA9, 0x41, 0x1A, 0xF7, 0xAC, 0x4E, 0x15, 0xF8, 0xA3, 0x4B, 0x10, 0xFD, 0xA6, + 0x78, 0x23, 0xCE, 0x95, 0x7D, 0x26, 0xCB, 0x90, 0x72, 0x29, 0xC4, 0x9F, 0x77, 0x2C, 0xC1, 0x9A, + 0x6C, 0x37, 0xDA, 0x81, 0x69, 0x32, 0xDF, 0x84, 0x66, 0x3D, 0xD0, 0x8B, 0x63, 0x38, 0xD5, 0x8E, + 0xA0, 0xFB, 0x16, 0x4D, 0xA5, 0xFE, 0x13, 0x48, 0xAA, 0xF1, 0x1C, 0x47, 0xAF, 0xF4, 0x19, 0x42, + 0xB4, 0xEF, 0x02, 0x59, 0xB1, 0xEA, 0x07, 0x5C, 0xBE, 0xE5, 0x08, 0x53, 0xBB, 0xE0, 0x0D, 0x56, + 0x88, 0xD3, 0x3E, 0x65, 0x8D, 0xD6, 0x3B, 0x60, 0x82, 0xD9, 0x34, 0x6F, 0x87, 0xDC, 0x31, 0x6A, + 0x9C, 0xC7, 0x2A, 0x71, 0x99, 0xC2, 0x2F, 0x74, 0x96, 0xCD, 0x20, 0x7B, 0x93, 0xC8, 0x25, 0x7E, + 0xF0, 0xAB, 0x46, 0x1D, 0xF5, 0xAE, 0x43, 0x18, 0xFA, 0xA1, 0x4C, 0x17, 0xFF, 0xA4, 0x49, 0x12, + 0xE4, 0xBF, 0x52, 0x09, 0xE1, 0xBA, 0x57, 0x0C, 0xEE, 0xB5, 0x58, 0x03, 0xEB, 0xB0, 0x5D, 0x06, + 0xD8, 0x83, 0x6E, 0x35, 0xDD, 0x86, 0x6B, 0x30, 0xD2, 0x89, 0x64, 0x3F, 0xD7, 0x8C, 0x61, 0x3A, + 0xCC, 0x97, 0x7A, 0x21, 0xC9, 0x92, 0x7F, 0x24, 0xC6, 0x9D, 0x70, 0x2B, 0xC3, 0x98, 0x75, 0x2E }; + +const uint8_t multEF[] = { 0x00, 0xEF, 0xB7, 0x58, 0x07, 0xE8, 0xB0, 0x5F, 0x0E, 0xE1, 0xB9, 0x56, 0x09, 0xE6, 0xBE, 0x51, + 0x1C, 0xF3, 0xAB, 0x44, 0x1B, 0xF4, 0xAC, 0x43, 0x12, 0xFD, 0xA5, 0x4A, 0x15, 0xFA, 0xA2, 0x4D, + 0x38, 0xD7, 0x8F, 0x60, 0x3F, 0xD0, 0x88, 0x67, 0x36, 0xD9, 0x81, 0x6E, 0x31, 0xDE, 0x86, 0x69, + 0x24, 0xCB, 0x93, 0x7C, 0x23, 0xCC, 0x94, 0x7B, 0x2A, 0xC5, 0x9D, 0x72, 0x2D, 0xC2, 0x9A, 0x75, + 0x70, 0x9F, 0xC7, 0x28, 0x77, 0x98, 0xC0, 0x2F, 0x7E, 0x91, 0xC9, 0x26, 0x79, 0x96, 0xCE, 0x21, + 0x6C, 0x83, 0xDB, 0x34, 0x6B, 0x84, 0xDC, 0x33, 0x62, 0x8D, 0xD5, 0x3A, 0x65, 0x8A, 0xD2, 0x3D, + 0x48, 0xA7, 0xFF, 0x10, 0x4F, 0xA0, 0xF8, 0x17, 0x46, 0xA9, 0xF1, 0x1E, 0x41, 0xAE, 0xF6, 0x19, + 0x54, 0xBB, 0xE3, 0x0C, 0x53, 0xBC, 0xE4, 0x0B, 0x5A, 0xB5, 0xED, 0x02, 0x5D, 0xB2, 0xEA, 0x05, + 0xE0, 0x0F, 0x57, 0xB8, 0xE7, 0x08, 0x50, 0xBF, 0xEE, 0x01, 0x59, 0xB6, 0xE9, 0x06, 0x5E, 0xB1, + 0xFC, 0x13, 0x4B, 0xA4, 0xFB, 0x14, 0x4C, 0xA3, 0xF2, 0x1D, 0x45, 0xAA, 0xF5, 0x1A, 0x42, 0xAD, + 0xD8, 0x37, 0x6F, 0x80, 0xDF, 0x30, 0x68, 0x87, 0xD6, 0x39, 0x61, 0x8E, 0xD1, 0x3E, 0x66, 0x89, + 0xC4, 0x2B, 0x73, 0x9C, 0xC3, 0x2C, 0x74, 0x9B, 0xCA, 0x25, 0x7D, 0x92, 0xCD, 0x22, 0x7A, 0x95, + 0x90, 0x7F, 0x27, 0xC8, 0x97, 0x78, 0x20, 0xCF, 0x9E, 0x71, 0x29, 0xC6, 0x99, 0x76, 0x2E, 0xC1, + 0x8C, 0x63, 0x3B, 0xD4, 0x8B, 0x64, 0x3C, 0xD3, 0x82, 0x6D, 0x35, 0xDA, 0x85, 0x6A, 0x32, 0xDD, + 0xA8, 0x47, 0x1F, 0xF0, 0xAF, 0x40, 0x18, 0xF7, 0xA6, 0x49, 0x11, 0xFE, 0xA1, 0x4E, 0x16, 0xF9, + 0xB4, 0x5B, 0x03, 0xEC, 0xB3, 0x5C, 0x04, 0xEB, 0xBA, 0x55, 0x0D, 0xE2, 0xBD, 0x52, 0x0A, 0xE5 }; + + +#define RS_MOD 0x14D +#define RHO 0x01010101L + +#define ROL(x,n) (((x) << ((n) & 0x1F)) | ((x) >> (32-((n) & 0x1F)))) +#define ROR(x,n) (((x) >> ((n) & 0x1F)) | ((x) << (32-((n) & 0x1F)))) + +#define _b(x, N) (((x) >> (N*8)) & 0xFF) + +#define b0(x) ((uint8_t)(x)) +#define b1(x) ((uint8_t)((x) >> 8)) +#define b2(x) ((uint8_t)((x) >> 16)) +#define b3(x) ((uint8_t)((x) >> 24)) + +#define U8ARRAY_TO_U32(r) ((r[0] << 24) ^ (r[1] << 16) ^ (r[2] << 8) ^ r[3]) +#define U8S_TO_U32(r0, r1, r2, r3) ((r0 << 24) ^ (r1 << 16) ^ (r2 << 8) ^ r3) + + +// multiply two polynomials represented as u32's, actually called with bytes +uint32_t polyMult(uint32_t a, uint32_t b) { + + uint32_t t=0; + + while(a) { + if(a & 1) + t^=b; + b <<= 1; + a >>= 1; + } + + return t; +} + + +// take the polynomial t and return the t % modulus in GF(256) +uint32_t gfMod(uint32_t t, uint32_t modulus) { + + int i; + uint32_t tt; + + modulus <<= 7; + for(i = 0; i < 8; i++) { + tt = t ^ modulus; + if(tt < t) + t = tt; + modulus >>= 1; + } + + return t; +} + + +// multiply a and b and return the modulus +#define gfMult(a, b, modulus) gfMod(polyMult(a, b), modulus) + + +// return a u32 containing the result of multiplying the RS Code matrix by the sd matrix +uint32_t RSMatrixMultiply(uint8_t sd[8]) { + + int j, k; + uint8_t t; + uint8_t result[4]; + + for(j = 0; j < 4; j++) { + t = 0; + for(k = 0; k < 8; k++) { + t ^= gfMult(RS[j][k], sd[k], RS_MOD); + } + result[3-j] = t; + } + + return U8ARRAY_TO_U32(result); +} + + +// the Zero-keyed h function (used by the key setup routine) +uint32_t h(uint32_t X, uint32_t L[4], int k) { + + uint8_t y0, y1, y2, y3; + uint8_t z0, z1, z2, z3; + + y0 = b0(X); + y1 = b1(X); + y2 = b2(X); + y3 = b3(X); + + switch(k) { + case 4: + y0 = Q1[y0] ^ b0(L[3]); + y1 = Q0[y1] ^ b1(L[3]); + y2 = Q0[y2] ^ b2(L[3]); + y3 = Q1[y3] ^ b3(L[3]); + case 3: + y0 = Q1[y0] ^ b0(L[2]); + y1 = Q1[y1] ^ b1(L[2]); + y2 = Q0[y2] ^ b2(L[2]); + y3 = Q0[y3] ^ b3(L[2]); + case 2: + y0 = Q1[ Q0 [ Q0[y0] ^ b0(L[1]) ] ^ b0(L[0]) ]; + y1 = Q0[ Q0 [ Q1[y1] ^ b1(L[1]) ] ^ b1(L[0]) ]; + y2 = Q1[ Q1 [ Q0[y2] ^ b2(L[1]) ] ^ b2(L[0]) ]; + y3 = Q0[ Q1 [ Q1[y3] ^ b3(L[1]) ] ^ b3(L[0]) ]; + } + + // inline the MDS matrix multiply + z0 = multEF[y0] ^ y1 ^ multEF[y2] ^ mult5B[y3]; + z1 = multEF[y0] ^ mult5B[y1] ^ y2 ^ multEF[y3]; + z2 = mult5B[y0] ^ multEF[y1] ^ multEF[y2] ^ y3; + z3 = y0 ^ multEF[y1] ^ mult5B[y2] ^ mult5B[y3]; + + return U8S_TO_U32(z0, z1, z2, z3); +} + + +// given the Sbox keys, create the fully keyed QF +void fullKey(uint32_t L[4], int k, uint32_t QF[4][256]) { + + uint8_t y0, y1, y2, y3; + int i; + + // for all input values to the Q permutations + for(i = 0; i < 256; i++) { + // run the Q permutations + y0 = i; y1 = i; y2 = i; y3 = i; + switch(k) { + case 4: + y0 = Q1[y0] ^ b0(L[3]); + y1 = Q0[y1] ^ b1(L[3]); + y2 = Q0[y2] ^ b2(L[3]); + y3 = Q1[y3] ^ b3(L[3]); + case 3: + y0 = Q1[y0] ^ b0(L[2]); + y1 = Q1[y1] ^ b1(L[2]); + y2 = Q0[y2] ^ b2(L[2]); + y3 = Q0[y3] ^ b3(L[2]); + case 2: + y0 = Q1[ Q0 [ Q0[y0] ^ b0(L[1]) ] ^ b0(L[0]) ]; + y1 = Q0[ Q0 [ Q1[y1] ^ b1(L[1]) ] ^ b1(L[0]) ]; + y2 = Q1[ Q1 [ Q0[y2] ^ b2(L[1]) ] ^ b2(L[0]) ]; + y3 = Q0[ Q1 [ Q1[y3] ^ b3(L[1]) ] ^ b3(L[0]) ]; + } + + // now do the partial MDS matrix multiplies + QF[0][i] = ((multEF[y0] << 24) + | (multEF[y0] << 16) + | (mult5B[y0] << 8) + | y0); + QF[1][i] = ((y1 << 24) + | (mult5B[y1] << 16) + | (multEF[y1] << 8) + | multEF[y1]); + QF[2][i] = ((multEF[y2] << 24) + | (y2 << 16) + | (multEF[y2] << 8) + | mult5B[y2]); + QF[3][i] = ((mult5B[y3] << 24) + | (multEF[y3] << 16) + | (y3 << 8) + | mult5B[y3]); + } +} + +// ---------------------------------------------------------------------------------------------------------------- + + +// fully keyed h (aka g) function +#define fkh(X) (ctx->QF[0][b0(X)]^ctx->QF[1][b1(X)]^ctx->QF[2][b2(X)]^ctx->QF[3][b3(X)]) + + +// ---------------------------------------------------------------------------------------------------------------- + + +// one encryption round +#define ENC_ROUND(R0, R1, R2, R3, round) \ + T0 = fkh(R0); \ + T1 = fkh(ROL(R1, 8)); \ + R2 = ROR(R2 ^ (T1 + T0 + ctx->K[2*round+8]), 1); \ + R3 = ROL(R3, 1) ^ (2*T1 + T0 + ctx->K[2*round+9]); + + +void twofish_internal_encrypt(uint8_t PT[16], tf_context_t *ctx) { + + uint32_t R0, R1, R2, R3; + uint32_t T0, T1; + + // load/byteswap/whiten input + R3 = ctx->K[3] ^ le32toh(((uint32_t*)PT)[3]); + R2 = ctx->K[2] ^ le32toh(((uint32_t*)PT)[2]); + R1 = ctx->K[1] ^ le32toh(((uint32_t*)PT)[1]); + R0 = ctx->K[0] ^ le32toh(((uint32_t*)PT)[0]); + + ENC_ROUND(R0, R1, R2, R3, 0); + ENC_ROUND(R2, R3, R0, R1, 1); + ENC_ROUND(R0, R1, R2, R3, 2); + ENC_ROUND(R2, R3, R0, R1, 3); + ENC_ROUND(R0, R1, R2, R3, 4); + ENC_ROUND(R2, R3, R0, R1, 5); + ENC_ROUND(R0, R1, R2, R3, 6); + ENC_ROUND(R2, R3, R0, R1, 7); + ENC_ROUND(R0, R1, R2, R3, 8); + ENC_ROUND(R2, R3, R0, R1, 9); + ENC_ROUND(R0, R1, R2, R3, 10); + ENC_ROUND(R2, R3, R0, R1, 11); + ENC_ROUND(R0, R1, R2, R3, 12); + ENC_ROUND(R2, R3, R0, R1, 13); + ENC_ROUND(R0, R1, R2, R3, 14); + ENC_ROUND(R2, R3, R0, R1, 15); + + // whiten/byteswap/store output + ((uint32_t*)PT)[3] = htole32(R1 ^ ctx->K[7]); + ((uint32_t*)PT)[2] = htole32(R0 ^ ctx->K[6]); + ((uint32_t*)PT)[1] = htole32(R3 ^ ctx->K[5]); + ((uint32_t*)PT)[0] = htole32(R2 ^ ctx->K[4]); +} + + +// ---------------------------------------------------------------------------------------------------------------- + + +// one decryption round +#define DEC_ROUND(R0, R1, R2, R3, round) \ + T0 = fkh(R0); \ + T1 = fkh(ROL(R1, 8)); \ + R2 = ROL(R2, 1) ^ (T0 + T1 + ctx->K[2*round+8]); \ + R3 = ROR(R3 ^ (T0 + 2*T1 + ctx->K[2*round+9]), 1); + + +void twofish_internal_decrypt(uint8_t PT[16], const uint8_t CT[16], tf_context_t *ctx) { + + uint32_t T0, T1; + uint32_t R0, R1, R2, R3; + + // load/byteswap/whiten input + R3 = ctx->K[7] ^ le32toh(((uint32_t*)CT)[3]); + R2 = ctx->K[6] ^ le32toh(((uint32_t*)CT)[2]); + R1 = ctx->K[5] ^ le32toh(((uint32_t*)CT)[1]); + R0 = ctx->K[4] ^ le32toh(((uint32_t*)CT)[0]); + + DEC_ROUND(R0, R1, R2, R3, 15); + DEC_ROUND(R2, R3, R0, R1, 14); + DEC_ROUND(R0, R1, R2, R3, 13); + DEC_ROUND(R2, R3, R0, R1, 12); + DEC_ROUND(R0, R1, R2, R3, 11); + DEC_ROUND(R2, R3, R0, R1, 10); + DEC_ROUND(R0, R1, R2, R3, 9); + DEC_ROUND(R2, R3, R0, R1, 8); + DEC_ROUND(R0, R1, R2, R3, 7); + DEC_ROUND(R2, R3, R0, R1, 6); + DEC_ROUND(R0, R1, R2, R3, 5); + DEC_ROUND(R2, R3, R0, R1, 4); + DEC_ROUND(R0, R1, R2, R3, 3); + DEC_ROUND(R2, R3, R0, R1, 2); + DEC_ROUND(R0, R1, R2, R3, 1); + DEC_ROUND(R2, R3, R0, R1, 0); + + // whiten/byteswap/store output + ((uint32_t*)PT)[3] = htole32(R1 ^ ctx->K[3]); + ((uint32_t*)PT)[2] = htole32(R0 ^ ctx->K[2]); + ((uint32_t*)PT)[1] = htole32(R3 ^ ctx->K[1]); + ((uint32_t*)PT)[0] = htole32(R2 ^ ctx->K[0]); +} + + +// ------------------------------------------------------------------------------------- + + +// the key schedule routine +void keySched(const uint8_t M[], int N, uint32_t **S, uint32_t K[40], int *k) { + + uint32_t Mo[4], Me[4]; + int i, j; + uint8_t vector[8]; + uint32_t A, B; + + *k = (N + 63) / 64; + *S = (uint32_t*)malloc(sizeof(uint32_t) * (*k)); + + for(i = 0; i < *k; i++) { + Me[i] = le32toh(((uint32_t*)M)[2*i]); + Mo[i] = le32toh(((uint32_t*)M)[2*i+1]); + } + + for(i = 0; i < *k; i++) { + for(j = 0; j < 4; j++) + vector[j] = _b(Me[i], j); + for(j = 0; j < 4; j++) + vector[j+4] = _b(Mo[i], j); + (*S)[(*k)-i-1] = RSMatrixMultiply(vector); + } + + for(i = 0; i < 20; i++) { + A = h(2*i*RHO, Me, *k); + B = ROL(h(2*i*RHO + RHO, Mo, *k), 8); + K[2*i] = A+B; + K[2*i+1] = ROL(A + 2*B, 9); + } +} + + +// ---------------------------------------------------------------------------------------------------------------- + + +#define fix_xor(target, source) *(uint32_t*)&(target)[0] = *(uint32_t*)&(target)[0] ^ *(uint32_t*)&(source)[0]; *(uint32_t*)&(target)[4] = *(uint32_t*)&(target)[4] ^ *(uint32_t*)&(source)[4]; \ + *(uint32_t*)&(target)[8] = *(uint32_t*)&(target)[8] ^ *(uint32_t*)&(source)[8]; *(uint32_t*)&(target)[12] = *(uint32_t*)&(target)[12] ^ *(uint32_t*)&(source)[12]; + +// ---------------------------------------------------------------------------------------------------------------- + + +// public API + + +int tf_ecb_decrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx) { + + twofish_internal_decrypt(out, in, ctx); + + return TF_BLOCK_SIZE; +} + + +// not used +int tf_ecb_encrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx) { + + memcpy(out, in, TF_BLOCK_SIZE); + twofish_internal_encrypt(out, ctx); + + return TF_BLOCK_SIZE; +} + + +int tf_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, tf_context_t *ctx) { + + uint8_t tmp[TF_BLOCK_SIZE]; + size_t i; + size_t n; + + memcpy(tmp, iv, TF_BLOCK_SIZE); + + n = in_len / TF_BLOCK_SIZE; + for(i = 0; i < n; i++) { + fix_xor(tmp, &in[i * TF_BLOCK_SIZE]); + twofish_internal_encrypt(tmp, ctx); + memcpy(&out[i * TF_BLOCK_SIZE], tmp, TF_BLOCK_SIZE); + } + + return n * TF_BLOCK_SIZE; +} + + +int tf_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, tf_context_t *ctx) { + + int n; /* number of blocks */ + /* int ret = (int)in_len & 15; remainder, unused*/ + + uint8_t ivec[TF_BLOCK_SIZE]; /* the ivec/old handling might be optimized if we */ + uint8_t old[TF_BLOCK_SIZE]; /* can be sure that in != out */ + + memcpy(ivec, iv, TF_BLOCK_SIZE); + + // 3 parallel rails of twofish decryption + for(n = in_len / TF_BLOCK_SIZE; n > 2; n -=3) { + memcpy(old, in + 2 * TF_BLOCK_SIZE, TF_BLOCK_SIZE); + + uint32_t T0, T1; + uint32_t Q0, Q1, Q2, Q3, R0, R1, R2, R3, S0, S1, S2, S3; + + // load/byteswap/whiten input/iv + Q3 = ctx->K[7] ^ le32toh(((uint32_t*)in)[3]); + Q2 = ctx->K[6] ^ le32toh(((uint32_t*)in)[2]); + Q1 = ctx->K[5] ^ le32toh(((uint32_t*)in)[1]); + Q0 = ctx->K[4] ^ le32toh(((uint32_t*)in)[0]); + + R3 = ctx->K[7] ^ le32toh(((uint32_t*)in)[7]); + R2 = ctx->K[6] ^ le32toh(((uint32_t*)in)[6]); + R1 = ctx->K[5] ^ le32toh(((uint32_t*)in)[5]); + R0 = ctx->K[4] ^ le32toh(((uint32_t*)in)[4]); + + S3 = ctx->K[7] ^ le32toh(((uint32_t*)in)[11]); + S2 = ctx->K[6] ^ le32toh(((uint32_t*)in)[10]); + S1 = ctx->K[5] ^ le32toh(((uint32_t*)in)[9]); + S0 = ctx->K[4] ^ le32toh(((uint32_t*)in)[8]); + + DEC_ROUND(Q0, Q1, Q2, Q3, 15); DEC_ROUND(R0, R1, R2, R3, 15); DEC_ROUND(S0, S1, S2, S3, 15); + DEC_ROUND(Q2, Q3, Q0, Q1, 14); DEC_ROUND(R2, R3, R0, R1, 14); DEC_ROUND(S2, S3, S0, S1, 14); + DEC_ROUND(Q0, Q1, Q2, Q3, 13); DEC_ROUND(R0, R1, R2, R3, 13); DEC_ROUND(S0, S1, S2, S3, 13); + DEC_ROUND(Q2, Q3, Q0, Q1, 12); DEC_ROUND(R2, R3, R0, R1, 12); DEC_ROUND(S2, S3, S0, S1, 12); + DEC_ROUND(Q0, Q1, Q2, Q3, 11); DEC_ROUND(R0, R1, R2, R3, 11); DEC_ROUND(S0, S1, S2, S3, 11); + DEC_ROUND(Q2, Q3, Q0, Q1, 10); DEC_ROUND(R2, R3, R0, R1, 10); DEC_ROUND(S2, S3, S0, S1, 10); + DEC_ROUND(Q0, Q1, Q2, Q3, 9); DEC_ROUND(R0, R1, R2, R3, 9); DEC_ROUND(S0, S1, S2, S3, 9); + DEC_ROUND(Q2, Q3, Q0, Q1, 8); DEC_ROUND(R2, R3, R0, R1, 8); DEC_ROUND(S2, S3, S0, S1, 8); + DEC_ROUND(Q0, Q1, Q2, Q3, 7); DEC_ROUND(R0, R1, R2, R3, 7); DEC_ROUND(S0, S1, S2, S3, 7); + DEC_ROUND(Q2, Q3, Q0, Q1, 6); DEC_ROUND(R2, R3, R0, R1, 6); DEC_ROUND(S2, S3, S0, S1, 6); + DEC_ROUND(Q0, Q1, Q2, Q3, 5); DEC_ROUND(R0, R1, R2, R3, 5); DEC_ROUND(S0, S1, S2, S3, 5); + DEC_ROUND(Q2, Q3, Q0, Q1, 4); DEC_ROUND(R2, R3, R0, R1, 4); DEC_ROUND(S2, S3, S0, S1, 4); + DEC_ROUND(Q0, Q1, Q2, Q3, 3); DEC_ROUND(R0, R1, R2, R3, 3); DEC_ROUND(S0, S1, S2, S3, 3); + DEC_ROUND(Q2, Q3, Q0, Q1, 2); DEC_ROUND(R2, R3, R0, R1, 2); DEC_ROUND(S2, S3, S0, S1, 2); + DEC_ROUND(Q0, Q1, Q2, Q3, 1); DEC_ROUND(R0, R1, R2, R3, 1); DEC_ROUND(S0, S1, S2, S3, 1); + DEC_ROUND(Q2, Q3, Q0, Q1, 0); DEC_ROUND(R2, R3, R0, R1, 0); DEC_ROUND(S2, S3, S0, S1, 0); + + // whiten/byteswap/store output/iv + ((uint32_t*)out)[11] = htole32(S1 ^ ctx->K[3] ^ ((uint32_t*)in)[7]); + ((uint32_t*)out)[10] = htole32(S0 ^ ctx->K[2] ^ ((uint32_t*)in)[6]); + ((uint32_t*)out)[9] = htole32(S3 ^ ctx->K[1] ^ ((uint32_t*)in)[5]); + ((uint32_t*)out)[8] = htole32(S2 ^ ctx->K[0] ^ ((uint32_t*)in)[4]); + + ((uint32_t*)out)[7] = htole32(R1 ^ ctx->K[3] ^ ((uint32_t*)in)[3]); + ((uint32_t*)out)[6] = htole32(R0 ^ ctx->K[2] ^ ((uint32_t*)in)[2]); + ((uint32_t*)out)[5] = htole32(R3 ^ ctx->K[1] ^ ((uint32_t*)in)[1]); + ((uint32_t*)out)[4] = htole32(R2 ^ ctx->K[0] ^ ((uint32_t*)in)[0]); + + ((uint32_t*)out)[3] = htole32(Q1 ^ ctx->K[3] ^ ((uint32_t*)ivec)[3]); + ((uint32_t*)out)[2] = htole32(Q0 ^ ctx->K[2] ^ ((uint32_t*)ivec)[2]); + ((uint32_t*)out)[1] = htole32(Q3 ^ ctx->K[1] ^ ((uint32_t*)ivec)[1]); + ((uint32_t*)out)[0] = htole32(Q2 ^ ctx->K[0] ^ ((uint32_t*)ivec)[0]); + + in += 3 * TF_BLOCK_SIZE; out += 3 * TF_BLOCK_SIZE; + + memcpy(ivec, old, TF_BLOCK_SIZE); + } + + // handle the two or less remaining block on a single rail + for(; n != 0; n--) { + uint32_t T0, T1; + uint32_t Q0, Q1, Q2, Q3; + + memcpy(old, in, TF_BLOCK_SIZE); + + // load/byteswap/whiten input + Q3 = ctx->K[7] ^ le32toh(((uint32_t*)in)[3]); + Q2 = ctx->K[6] ^ le32toh(((uint32_t*)in)[2]); + Q1 = ctx->K[5] ^ le32toh(((uint32_t*)in)[1]); + Q0 = ctx->K[4] ^ le32toh(((uint32_t*)in)[0]); + + DEC_ROUND(Q0, Q1, Q2, Q3, 15); + DEC_ROUND(Q2, Q3, Q0, Q1, 14); + DEC_ROUND(Q0, Q1, Q2, Q3, 13); + DEC_ROUND(Q2, Q3, Q0, Q1, 12); + DEC_ROUND(Q0, Q1, Q2, Q3, 11); + DEC_ROUND(Q2, Q3, Q0, Q1, 10); + DEC_ROUND(Q0, Q1, Q2, Q3, 9); + DEC_ROUND(Q2, Q3, Q0, Q1, 8); + DEC_ROUND(Q0, Q1, Q2, Q3, 7); + DEC_ROUND(Q2, Q3, Q0, Q1, 6); + DEC_ROUND(Q0, Q1, Q2, Q3, 5); + DEC_ROUND(Q2, Q3, Q0, Q1, 4); + DEC_ROUND(Q0, Q1, Q2, Q3, 3); + DEC_ROUND(Q2, Q3, Q0, Q1, 2); + DEC_ROUND(Q0, Q1, Q2, Q3, 1); + DEC_ROUND(Q2, Q3, Q0, Q1, 0); + + // load/byteswap/whiten output/iv + ((uint32_t*)out)[3] = htole32(Q1 ^ ctx->K[3] ^ ((uint32_t*)ivec)[3]); + ((uint32_t*)out)[2] = htole32(Q0 ^ ctx->K[2] ^ ((uint32_t*)ivec)[2]); + ((uint32_t*)out)[1] = htole32(Q3 ^ ctx->K[1] ^ ((uint32_t*)ivec)[1]); + ((uint32_t*)out)[0] = htole32(Q2 ^ ctx->K[0] ^ ((uint32_t*)ivec)[0]); + + in += TF_BLOCK_SIZE; out+= TF_BLOCK_SIZE; + + memcpy(ivec, old, TF_BLOCK_SIZE); + } + + return n * TF_BLOCK_SIZE; +} + + +// by definition twofish can only accept key up to 256 bit +// we wont do any checking here and will assume user already +// know about it. twofish is undefined for key larger than 256 bit +int tf_init (const unsigned char *key, size_t key_size, tf_context_t **ctx) { + + int k; + uint32_t *S; + + *ctx = calloc(1, sizeof(tf_context_t)); + if(!(*ctx)) { + return -1; + } + + (*ctx)->N = key_size; + keySched(key, key_size, &S, (*ctx)->K, &k); + fullKey(S, k, (*ctx)->QF); + free(S); /* allocated in keySched(...) */ + + return 0; +} + + +int tf_deinit (tf_context_t *ctx) { + + if(ctx) free(ctx); + + return 0; +} diff --git a/src/transform_aes.c b/src/transform_aes.c new file mode 100644 index 0000000..d147287 --- /dev/null +++ b/src/transform_aes.c @@ -0,0 +1,246 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +// size of random value prepended to plaintext defaults to AES BLOCK_SIZE; +// gradually abandoning security, lower values could be chosen; +// however, minimum transmission size with cipher text stealing scheme is one +// block; as network packets should be longer anyway, only low level programmer +// might encounter an issue with lower values here +#define AES_PREAMBLE_SIZE (AES_BLOCK_SIZE) + + +// cts/cbc mode is being used with random value prepended to plaintext +// instead of iv so, actual iv is aes_null_iv +const uint8_t aes_null_iv[AES_IV_SIZE] = { 0 }; + +typedef struct transop_aes { + aes_context_t *ctx; +} transop_aes_t; + + +static int transop_deinit_aes (n2n_trans_op_t *arg) { + + transop_aes_t *priv = (transop_aes_t *)arg->priv; + + if(priv->ctx) + aes_deinit(priv->ctx); + + if(priv) + free(priv); + + return 0; +} + + +// the aes packet format consists of +// +// - a random AES_PREAMBLE_SIZE-sized value prepended to plaintext +// encrypted together with the... +// - ... payload data +// +// [VV|DDDDDDDDDDDDDDDDDDDDD] +// | <---- encrypted ----> | +// +static int transop_encode_aes (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + transop_aes_t *priv = (transop_aes_t *)arg->priv; + + // the assembly buffer is a source for encrypting data + // the whole contents of assembly are encrypted + uint8_t assembly[N2N_PKT_BUF_SIZE]; + size_t idx = 0; + int padded_len; + uint8_t padding; + uint8_t buf[AES_BLOCK_SIZE]; + + if(in_len <= N2N_PKT_BUF_SIZE) { + if((in_len + AES_PREAMBLE_SIZE + AES_BLOCK_SIZE) <= out_len) { + traceEvent(TRACE_DEBUG, "transop_encode_aes %lu bytes plaintext", in_len); + + // full block sized random value (128 bit) + encode_uint64(assembly, &idx, n2n_rand()); + encode_uint64(assembly, &idx, n2n_rand()); + + // adjust for maybe differently chosen AES_PREAMBLE_SIZE + idx = AES_PREAMBLE_SIZE; + + // the plaintext data + encode_buf(assembly, &idx, inbuf, in_len); + + // round up to next whole AES block size + padded_len = (((idx - 1) / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; + padding = (padded_len-idx); + + // pad the following bytes with zero, fixed length (AES_BLOCK_SIZE) seems to compile + // to slightly faster code than run-time dependant 'padding' + memset(assembly + idx, 0, AES_BLOCK_SIZE); + + aes_cbc_encrypt(outbuf, assembly, padded_len, aes_null_iv, priv->ctx); + + if(padding) { + // exchange last two cipher blocks + memcpy(buf, outbuf+padded_len - AES_BLOCK_SIZE, AES_BLOCK_SIZE); + memcpy(outbuf + padded_len - AES_BLOCK_SIZE, outbuf + padded_len - 2 * AES_BLOCK_SIZE, AES_BLOCK_SIZE); + memcpy(outbuf + padded_len - 2 * AES_BLOCK_SIZE, buf, AES_BLOCK_SIZE); + } + } else + traceEvent(TRACE_ERROR, "transop_encode_aes outbuf too small"); + } else + traceEvent(TRACE_ERROR, "transop_encode_aes inbuf too big to encrypt"); + + return idx; +} + + +// see transop_encode_aes for packet format +static int transop_decode_aes (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + transop_aes_t *priv = (transop_aes_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE]; + + uint8_t rest; + size_t penultimate_block; + uint8_t buf[AES_BLOCK_SIZE]; + int len = -1; + + if(((in_len - AES_PREAMBLE_SIZE) <= N2N_PKT_BUF_SIZE) /* cipher text fits in assembly */ + && (in_len >= AES_PREAMBLE_SIZE) /* has at least random number */ + && (in_len >= AES_BLOCK_SIZE)) { /* minimum size requirement for cipher text stealing */ + traceEvent(TRACE_DEBUG, "transop_decode_aes %lu bytes ciphertext", in_len); + + rest = in_len % AES_BLOCK_SIZE; + if(rest) { /* cipher text stealing */ + penultimate_block = ((in_len / AES_BLOCK_SIZE) - 1) * AES_BLOCK_SIZE; + + // everything normal up to penultimate block + memcpy(assembly, inbuf, penultimate_block); + + // prepare new penultimate block in buf + aes_ecb_decrypt(buf, inbuf + penultimate_block, priv->ctx); + memcpy(buf, inbuf + in_len - rest, rest); + + // former penultimate block becomes new ultimate block + memcpy(assembly + penultimate_block + AES_BLOCK_SIZE, inbuf + penultimate_block, AES_BLOCK_SIZE); + + // write new penultimate block from buf + memcpy(assembly + penultimate_block, buf, AES_BLOCK_SIZE); + + // regular cbc decryption of the re-arranged ciphertext + aes_cbc_decrypt(assembly, assembly, in_len + AES_BLOCK_SIZE - rest, aes_null_iv, priv->ctx); + + // check for expected zero padding and give a warning otherwise + if(memcmp(assembly + in_len, aes_null_iv, AES_BLOCK_SIZE - rest)) { + traceEvent(TRACE_WARNING, "transop_decode_aes payload decryption failed with unexpected cipher text stealing padding"); + return -1; + } + } else { + // regular cbc decryption on multiple block-sized payload + aes_cbc_decrypt(assembly, inbuf, in_len, aes_null_iv, priv->ctx); + } + len = in_len - AES_PREAMBLE_SIZE; + memcpy(outbuf, assembly + AES_PREAMBLE_SIZE, len); + } else + traceEvent(TRACE_ERROR, "transop_decode_aes inbuf wrong size (%ul) to decrypt", in_len); + + return len; +} + + +static int setup_aes_key (transop_aes_t *priv, const uint8_t *password, ssize_t password_len) { + + unsigned char key_mat[32]; /* maximum aes key length, equals hash length */ + unsigned char *key; + size_t key_size; + + // let the user choose the degree of encryption: + // long input passwords will pick AES192 or AES256 with more robust but expensive encryption + + // the input password always gets hashed to make a more unpredictable use of the key space + // just think of usually reset MSB of ASCII coded password bytes + pearson_hash_256(key_mat, password, password_len); + + // the length-dependant scheme for key setup was discussed on github: + // https://github.com/ntop/n2n/issues/101 -- as no iv encryption required + // anymore, the key-size trigger values were roughly halved + if(password_len >= 33) { + key_size = AES256_KEY_BYTES; /* 256 bit */ + } else if(password_len >= 23) { + key_size = AES192_KEY_BYTES; /* 192 bit */ + } else { + key_size = AES128_KEY_BYTES; /* 128 bit */ + } + + // and use the last key-sized part of the hash as aes key + key = key_mat + sizeof(key_mat) - key_size; + + // setup the key and have corresponding context created + if(aes_init (key, key_size, &(priv->ctx))) { + traceEvent(TRACE_ERROR, "setup_aes_key %u-bit key setup unsuccessful", key_size * 8); + return -1; + } + traceEvent(TRACE_DEBUG, "setup_aes_key %u-bit key setup completed", key_size * 8); + + return 0; +} + + +static void transop_tick_aes (n2n_trans_op_t *arg, time_t now) { + + // no tick action +} + + +// AES initialization function +int n2n_transop_aes_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) { + + transop_aes_t *priv; + const u_char *encrypt_key = (const u_char *)conf->encrypt_key; + size_t encrypt_key_len = strlen(conf->encrypt_key); + + memset(ttt, 0, sizeof(*ttt)); + ttt->transform_id = N2N_TRANSFORM_ID_AES; + + ttt->tick = transop_tick_aes; + ttt->deinit = transop_deinit_aes; + ttt->fwd = transop_encode_aes; + ttt->rev = transop_decode_aes; + + priv = (transop_aes_t*)calloc(1, sizeof(transop_aes_t)); + if(!priv) { + traceEvent(TRACE_ERROR, "n2n_transop_aes_init cannot allocate transop_aes_t memory"); + return -1; + } + ttt->priv = priv; + + // setup the cipher and key + return setup_aes_key(priv, encrypt_key, encrypt_key_len); +} diff --git a/src/transform_cc20.c b/src/transform_cc20.c new file mode 100644 index 0000000..5cf9eb4 --- /dev/null +++ b/src/transform_cc20.c @@ -0,0 +1,170 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +// ChaCha20 plaintext preamble +#define CC20_PREAMBLE_SIZE (CC20_IV_SIZE) + + +typedef struct transop_cc20 { + cc20_context_t *ctx; +} transop_cc20_t; + + +static int transop_deinit_cc20 (n2n_trans_op_t *arg) { + + transop_cc20_t *priv = (transop_cc20_t *)arg->priv; + + if(priv->ctx) + cc20_deinit(priv->ctx); + + if(priv) + free(priv); + + return 0; +} + + +// the ChaCha20 packet format consists of +// +// - a 128-bit random iv +// - encrypted payload +// +// [IIII|DDDDDDDDDDDDDDDDDDDDD] +// |<---- encrypted ---->| +// +static int transop_encode_cc20 (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + int len = -1; + transop_cc20_t *priv = (transop_cc20_t *)arg->priv; + + if(in_len <= N2N_PKT_BUF_SIZE) { + if((in_len + CC20_PREAMBLE_SIZE) <= out_len) { + size_t idx = 0; + + traceEvent(TRACE_DEBUG, "encode_cc20 %lu bytes", in_len); + + // full iv sized random value (128 bit) + encode_uint64(outbuf, &idx, n2n_rand()); + encode_uint64(outbuf, &idx, n2n_rand()); + + len = in_len; + cc20_crypt(outbuf + CC20_PREAMBLE_SIZE, + inbuf, + in_len, + outbuf, /* iv */ + priv->ctx); + + // size of datacarried in UDP + len += CC20_PREAMBLE_SIZE; + } else + traceEvent(TRACE_ERROR, "encode_cc20 outbuf too small."); + } else + traceEvent(TRACE_ERROR, "encode_cc20 inbuf too big to encrypt."); + + return len; +} + + +// see transop_encode_cc20 for packet format +static int transop_decode_cc20 (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + int len = 0; + transop_cc20_t *priv = (transop_cc20_t *)arg->priv; + + if(((in_len - CC20_PREAMBLE_SIZE) <= N2N_PKT_BUF_SIZE) /* cipher text fits in assembly */ + && (in_len >= CC20_PREAMBLE_SIZE)) { /* has at least iv */ + + traceEvent(TRACE_DEBUG, "decode_cc20 %lu bytes", in_len); + + len = (in_len - CC20_PREAMBLE_SIZE); + + cc20_crypt(outbuf, + inbuf + CC20_PREAMBLE_SIZE, + in_len, + inbuf, /* iv */ + priv->ctx); + } else + traceEvent(TRACE_ERROR, "decode_cc20 inbuf wrong size (%ul) to decrypt.", in_len); + + return len; +} + + +static int setup_cc20_key (transop_cc20_t *priv, const uint8_t *password, ssize_t password_len) { + + uint8_t key_mat[CC20_KEY_BYTES]; + + // the input key always gets hashed to make a more unpredictable and more complete use of the key space + pearson_hash_256(key_mat, password, password_len); + + if(cc20_init(key_mat, &(priv->ctx))) { + traceEvent(TRACE_ERROR, "setup_cc20_key setup unsuccessful"); + return -1; + } + + traceEvent(TRACE_DEBUG, "setup_cc20_key completed"); + + return 0; +} + + +static void transop_tick_cc20 (n2n_trans_op_t *arg, time_t now) { + + // no tick action +} + + +// ChaCha20 initialization function +int n2n_transop_cc20_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) { + + transop_cc20_t *priv; + const u_char *encrypt_key = (const u_char *)conf->encrypt_key; + size_t encrypt_key_len = strlen(conf->encrypt_key); + + memset(ttt, 0, sizeof(*ttt)); + ttt->transform_id = N2N_TRANSFORM_ID_CHACHA20; + + ttt->tick = transop_tick_cc20; + ttt->deinit = transop_deinit_cc20; + ttt->fwd = transop_encode_cc20; + ttt->rev = transop_decode_cc20; + + priv = (transop_cc20_t*)calloc(1, sizeof(transop_cc20_t)); + if(!priv) { + traceEvent(TRACE_ERROR, "cannot allocate transop_cc20_t memory"); + return -1; + } + ttt->priv = priv; + + // setup the cipher and key + return setup_cc20_key(priv, encrypt_key, encrypt_key_len); +} diff --git a/src/transform_lzo.c b/src/transform_lzo.c new file mode 100644 index 0000000..69a1eff --- /dev/null +++ b/src/transform_lzo.c @@ -0,0 +1,133 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +/* heap allocation for compression as per lzo example doc */ +#define HEAP_ALLOC(var,size) lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] + + +typedef struct transop_lzo { + HEAP_ALLOC(wrkmem, LZO1X_1_MEM_COMPRESS); +} transop_lzo_t; + + +static int transop_deinit_lzo (n2n_trans_op_t *arg) { + + transop_lzo_t *priv = (transop_lzo_t *)arg->priv; + + if(priv) + free(priv); + + return 0; +} + + +// returns compressed packet length +// returns 0 if error occured, the caller would have to use +// original, i.e. uncompressed data then +static int transop_encode_lzo (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + transop_lzo_t *priv = (transop_lzo_t *)arg->priv; + lzo_uint compression_len = 0; + + if(in_len > N2N_PKT_BUF_SIZE) { + traceEvent(TRACE_ERROR, "encode_lzo inbuf wrong size (%ul) to compress", in_len); + return 0; + } + + if(out_len < in_len + in_len / 16 + 64 + 3) { + traceEvent(TRACE_ERROR, "encode_lzo outbuf too small (%ul) to compress inbuf (%ul)", + out_len, in_len); + return 0; + } + + if(lzo1x_1_compress(inbuf, in_len, outbuf, &compression_len, priv->wrkmem) != LZO_E_OK) { + traceEvent(TRACE_ERROR, "encode_lzo compression error"); + compression_len = 0; + } + + return compression_len; +} + + +static int transop_decode_lzo (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + lzo_uint deflated_len = N2N_PKT_BUF_SIZE; + + if(in_len > N2N_PKT_BUF_SIZE) { + traceEvent(TRACE_ERROR, "decode_lzo inbuf wrong size (%ul) to decompress", in_len); + return 0; + } + + lzo1x_decompress(inbuf, in_len, outbuf, &deflated_len, NULL); + + if(deflated_len > N2N_PKT_BUF_SIZE) { + traceEvent(TRACE_ERROR, "decode_lzo outbuf wrong size (%ul) decompressed", deflated_len); + return 0; + } + + return deflated_len; +} + + +static void transop_tick_lzo (n2n_trans_op_t *arg, time_t now) { + + // no tick action +} + + +// lzo initialization function +int n2n_transop_lzo_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) { + + transop_lzo_t *priv; + + memset(ttt, 0, sizeof(*ttt)); + ttt->transform_id = N2N_COMPRESSION_ID_LZO; + + ttt->tick = transop_tick_lzo; + ttt->deinit = transop_deinit_lzo; + ttt->fwd = transop_encode_lzo; + ttt->rev = transop_decode_lzo; + + priv = (transop_lzo_t*)calloc(1, sizeof(transop_lzo_t)); + if(!priv) { + traceEvent(TRACE_ERROR, "lzo_init cannot allocate transop_lzo memory"); + return -1; + } + ttt->priv = priv; + + if(lzo_init() != LZO_E_OK) { + traceEvent(TRACE_ERROR, "lzo_init cannot init lzo compression"); + return -1; + } + + return 0; +} diff --git a/src/transform_null.c b/src/transform_null.c new file mode 100644 index 0000000..cc3cbf3 --- /dev/null +++ b/src/transform_null.c @@ -0,0 +1,91 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +static int transop_deinit_null (n2n_trans_op_t *arg ) { + + // nothing to deallocate, nothing to release + + return 0; +} + + +static int transop_encode_null (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + int retval = -1; + + traceEvent(TRACE_DEBUG, "encode_null %lu", in_len); + if(out_len >= in_len) { + memcpy(outbuf, inbuf, in_len); + retval = in_len; + } else { + traceEvent(TRACE_DEBUG, "encode_null %lu too big for packet buffer", in_len); + } + + return retval; +} + + +static int transop_decode_null (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + int retval = -1; + + traceEvent(TRACE_DEBUG, "decode_null %lu", in_len); + if(out_len >= in_len) { + memcpy(outbuf, inbuf, in_len); + retval = in_len; + } else { + traceEvent(TRACE_DEBUG, "decode_null %lu too big for packet buffer", in_len); + } + + return retval; +} + + +static void transop_tick_null (n2n_trans_op_t *arg, time_t now) { + + // no tick action +} + + +int n2n_transop_null_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) { + + memset(ttt, 0, sizeof(n2n_trans_op_t)); + + ttt->transform_id = N2N_TRANSFORM_ID_NULL; + ttt->no_encryption = 1; + ttt->deinit = transop_deinit_null; + ttt->tick = transop_tick_null; + ttt->fwd = transop_encode_null; + ttt->rev = transop_decode_null; + + return 0; +} diff --git a/src/transform_speck.c b/src/transform_speck.c new file mode 100644 index 0000000..1778eb7 --- /dev/null +++ b/src/transform_speck.c @@ -0,0 +1,174 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +// Speck plaintext preamble +#define TRANSOP_SPECK_PREAMBLE_SIZE (N2N_SPECK_IVEC_SIZE) + + +typedef struct transop_speck { + speck_context_t *ctx; /* the round keys for payload encryption & decryption */ +} transop_speck_t; + + +static int transop_deinit_speck (n2n_trans_op_t *arg) { + + transop_speck_t *priv = (transop_speck_t *)arg->priv; + + if(priv->ctx) + speck_deinit(priv->ctx); + + if(priv) + free(priv); + + return 0; +} + + +// the Speck packet format consists of +// +// - a 128-bit random iv +// - encrypted payload +// +// [IIII|DDDDDDDDDDDDDDDDDDDDD] +// |<---- encrypted ---->| +// +static int transop_encode_speck (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + int len = -1; + transop_speck_t *priv = (transop_speck_t *)arg->priv; + + if(in_len <= N2N_PKT_BUF_SIZE) { + if((in_len + TRANSOP_SPECK_PREAMBLE_SIZE) <= out_len) { + size_t idx = 0; + + traceEvent(TRACE_DEBUG, "encode_speck %lu bytes", in_len); + + // generate and encode the iv + encode_uint64(outbuf, &idx, n2n_rand()); + encode_uint64(outbuf, &idx, n2n_rand()); + + // encrypt the payload and write the ciphertext after the iv + // len is set to the length of the cipher plain text to be encrpyted + // which is (in this case) identical to original packet lentgh + len = in_len; + speck_ctr (outbuf + TRANSOP_SPECK_PREAMBLE_SIZE, /* output starts right after the iv */ + inbuf, /* input */ + in_len, /* len */ + outbuf, /* iv, already encoded in outbuf, speck does not change it */ + priv->ctx); /* ctx already setup with round keys */ + + traceEvent(TRACE_DEBUG, "encode_speck: encrypted %u bytes.\n", in_len); + + // size of data carried in UDP + len += TRANSOP_SPECK_PREAMBLE_SIZE; + } else + traceEvent(TRACE_ERROR, "encode_speck outbuf too small."); + } else + traceEvent(TRACE_ERROR, "encode_speck inbuf too big to encrypt."); + + return len; +} + + +// see transop_encode_speck for packet format +static int transop_decode_speck (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + int len = 0; + transop_speck_t *priv = (transop_speck_t *)arg->priv; + + if(((in_len - TRANSOP_SPECK_PREAMBLE_SIZE) <= N2N_PKT_BUF_SIZE) /* cipher text fits in buffer */ + && (in_len >= TRANSOP_SPECK_PREAMBLE_SIZE)) { /* has at least iv */ + + traceEvent(TRACE_DEBUG, "decode_speck %lu bytes", in_len); + + len = (in_len - TRANSOP_SPECK_PREAMBLE_SIZE); + speck_ctr (outbuf, /* output */ + inbuf + TRANSOP_SPECK_PREAMBLE_SIZE, /* encrypted data starts right after preamble (iv) */ + len, /* len */ + inbuf, /* iv can be found at input's beginning */ + priv->ctx); /* ctx already setup with round keys */ + + traceEvent(TRACE_DEBUG, "decode_speck decrypted %u bytes.\n", len); + } else + traceEvent(TRACE_ERROR, "decode_speck inbuf wrong size (%ul) to decrypt.", in_len); + + return len; +} + + +static int setup_speck_key (transop_speck_t *priv, const uint8_t *key, ssize_t key_size) { + + uint8_t key_mat_buf[32]; + + // the input key always gets hashed to make a more unpredictable and more complete use of the key space + pearson_hash_256(key_mat_buf, key, key_size); + + // expand the key material to the context (= round keys), 256 bit keysize + speck_init(&(priv->ctx), key_mat_buf, 256); + + traceEvent(TRACE_DEBUG, "setup_speck_key completed\n"); + + return 0; +} + + +static void transop_tick_speck (n2n_trans_op_t *arg, time_t now) { + + // no tick action +} + + +// Speck initialization function +int n2n_transop_speck_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) { + + transop_speck_t *priv; + const u_char *encrypt_key = (const u_char *)conf->encrypt_key; + size_t encrypt_key_len = strlen(conf->encrypt_key); + + memset(ttt, 0, sizeof(*ttt)); + ttt->transform_id = N2N_TRANSFORM_ID_SPECK; + + ttt->tick = transop_tick_speck; + ttt->deinit = transop_deinit_speck; + ttt->fwd = transop_encode_speck; + ttt->rev = transop_decode_speck; + + priv = (transop_speck_t*)calloc(1, sizeof(transop_speck_t)); + if(!priv) { + traceEvent(TRACE_ERROR, "n2n_transop_speck_init cannot allocate transop_speck_t memory"); + return -1; + } + ttt->priv = priv; + + // setup the cipher and key + return setup_speck_key(priv, encrypt_key, encrypt_key_len); +} diff --git a/src/transform_tf.c b/src/transform_tf.c new file mode 100644 index 0000000..4368d03 --- /dev/null +++ b/src/transform_tf.c @@ -0,0 +1,232 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +// size of random value prepended to plaintext defaults to TF_BLOCK_SIZE; +// gradually abandoning security, lower values could be chosen; +// however, minimum transmission size with cipher text stealing scheme is one +// block; as network packets should be longer anyway, only low level programmer +// might encounter an issue with lower values here +#define TF_PREAMBLE_SIZE (TF_BLOCK_SIZE) + + +// cbc mode is being used with random value prepended to plaintext +// instead of iv so, actual iv is tf_null_iv +const uint8_t tf_null_iv[TF_IV_SIZE] = { 0 }; + +typedef struct transop_tf { + tf_context_t *ctx; +} transop_tf_t; + + +static int transop_deinit_tf (n2n_trans_op_t *arg) { + + transop_tf_t *priv = (transop_tf_t *)arg->priv; + + if(priv->ctx) + tf_deinit(priv->ctx); + + if(priv) + free(priv); + + return 0; +} + + +// the Twofish packet format consists of +// +// - a random TF_PREAMBLE_SIZE-sized value prepended to plaintext +// encrypted together with the... +// - ... payload data +// +// [VV|DDDDDDDDDDDDDDDDDDDDD] +// | <---- encrypted ----> | +// +static int transop_encode_tf (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + transop_tf_t *priv = (transop_tf_t *)arg->priv; + + // the assembly buffer is a source for encrypting data + // the whole contents of assembly are encrypted + uint8_t assembly[N2N_PKT_BUF_SIZE]; + size_t idx = 0; + int padded_len; + uint8_t padding; + uint8_t buf[TF_BLOCK_SIZE]; + + if(in_len <= N2N_PKT_BUF_SIZE) { + if((in_len + TF_PREAMBLE_SIZE + TF_BLOCK_SIZE) <= out_len) { + traceEvent(TRACE_DEBUG, "transop_encode_tf %lu bytes plaintext", in_len); + + // full block sized random value (128 bit) + encode_uint64(assembly, &idx, n2n_rand()); + encode_uint64(assembly, &idx, n2n_rand()); + + // adjust for maybe differently chosen TF_PREAMBLE_SIZE + idx = TF_PREAMBLE_SIZE; + + // the plaintext data + encode_buf(assembly, &idx, inbuf, in_len); + + // round up to next whole TF block size + padded_len = (((idx - 1) / TF_BLOCK_SIZE) + 1) * TF_BLOCK_SIZE; + padding = (padded_len-idx); + + // pad the following bytes with zero, fixed length (TF_BLOCK_SIZE) seems to compile + // to slightly faster code than run-time dependant 'padding' + memset(assembly + idx, 0, TF_BLOCK_SIZE); + tf_cbc_encrypt(outbuf, assembly, padded_len, tf_null_iv, priv->ctx); + + if(padding) { + // exchange last two cipher blocks + memcpy(buf, outbuf + padded_len - TF_BLOCK_SIZE, TF_BLOCK_SIZE); + memcpy(outbuf + padded_len - TF_BLOCK_SIZE, outbuf + padded_len - 2 * TF_BLOCK_SIZE, TF_BLOCK_SIZE); + memcpy(outbuf + padded_len - 2 * TF_BLOCK_SIZE, buf, TF_BLOCK_SIZE); + } + } else + traceEvent(TRACE_ERROR, "transop_encode_tf outbuf too small"); + } else + traceEvent(TRACE_ERROR, "transop_encode_tf inbuf too big to encrypt"); + + return idx; +} + + +// see transop_encode_tf for packet format +static int transop_decode_tf (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + + transop_tf_t *priv = (transop_tf_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE]; + + uint8_t rest; + size_t penultimate_block; + uint8_t buf[TF_BLOCK_SIZE]; + int len = -1; + + if(((in_len - TF_PREAMBLE_SIZE) <= N2N_PKT_BUF_SIZE) /* cipher text fits in assembly */ + && (in_len >= TF_PREAMBLE_SIZE) /* has at least random number */ + && (in_len >= TF_BLOCK_SIZE)) { /* minimum size requirement for cipher text stealing */ + + traceEvent(TRACE_DEBUG, "transop_decode_tf %lu bytes ciphertext", in_len); + + rest = in_len % TF_BLOCK_SIZE; + if(rest) { /* cipher text stealing */ + penultimate_block = ((in_len / TF_BLOCK_SIZE) - 1) * TF_BLOCK_SIZE; + + // everything normal up to penultimate block + memcpy(assembly, inbuf, penultimate_block); + + // prepare new penultimate block in buf + tf_ecb_decrypt(buf, inbuf + penultimate_block, priv->ctx); + memcpy(buf, inbuf + in_len - rest, rest); + + // former penultimate block becomes new ultimate block + memcpy(assembly + penultimate_block + TF_BLOCK_SIZE, inbuf + penultimate_block, TF_BLOCK_SIZE); + + // write new penultimate block from buf + memcpy(assembly + penultimate_block, buf, TF_BLOCK_SIZE); + + // regular cbc decryption of the re-arranged ciphertext + tf_cbc_decrypt(assembly, assembly, in_len + TF_BLOCK_SIZE - rest, tf_null_iv, priv->ctx); + + // check for expected zero padding and give a warning otherwise + if(memcmp(assembly + in_len, tf_null_iv, TF_BLOCK_SIZE - rest)) { + traceEvent(TRACE_WARNING, "transop_decode_tf payload decryption failed with unexpected cipher text stealing padding"); + return -1; + } + } else { + // regular cbc decryption on multiple block-sized payload + tf_cbc_decrypt(assembly, inbuf, in_len, tf_null_iv, priv->ctx); + } + len = in_len - TF_PREAMBLE_SIZE; + memcpy(outbuf, assembly + TF_PREAMBLE_SIZE, len); + } else + traceEvent(TRACE_ERROR, "transop_decode_tf inbuf wrong size (%ul) to decrypt", in_len); + + return len; +} + + +static int setup_tf_key (transop_tf_t *priv, const uint8_t *password, ssize_t password_len) { + + unsigned char key[32]; /* tf key length, equals hash length */ + size_t key_size; + + // the input password always gets hashed to make a more unpredictable use of the key space + // just think of usually reset MSB of ASCII coded password bytes + pearson_hash_256(key, password, password_len); + + key_size = 32; /* 256 bit */ + + // setup the key and have corresponding context created + if(tf_init(key, key_size * 8, &(priv->ctx))) { + traceEvent(TRACE_ERROR, "setup_tf_key %u-bit key setup unsuccessful", key_size * 8); + return -1; + } + + traceEvent(TRACE_DEBUG, "setup_tf_key %u-bit key setup completed", key_size * 8); + + return 0; +} + + +static void transop_tick_tf (n2n_trans_op_t *arg, time_t now) { + + // no tick action +} + + +// Twofish initialization function +int n2n_transop_tf_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) { + + transop_tf_t *priv; + const u_char *encrypt_key = (const u_char *)conf->encrypt_key; + size_t encrypt_key_len = strlen(conf->encrypt_key); + + memset(ttt, 0, sizeof(*ttt)); + ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH; + + ttt->tick = transop_tick_tf; + ttt->deinit = transop_deinit_tf; + ttt->fwd = transop_encode_tf; + ttt->rev = transop_decode_tf; + + priv = (transop_tf_t*)calloc(1, sizeof(transop_tf_t)); + if(!priv) { + traceEvent(TRACE_ERROR, "n2n_transop_tf_cbc_init cannot allocate transop_tf_t memory"); + return -1; + } + ttt->priv = priv; + + // setup the cipher and key + return setup_tf_key(priv, encrypt_key, encrypt_key_len); +} diff --git a/src/transform_zstd.c b/src/transform_zstd.c new file mode 100644 index 0000000..c39ec3b --- /dev/null +++ b/src/transform_zstd.c @@ -0,0 +1,148 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +#ifdef HAVE_ZSTD + + +typedef struct transop_zstd { + // no local data +} transop_zstd_t; + + +static int transop_deinit_zstd (n2n_trans_op_t *arg) { + + transop_zstd_t *priv = (transop_zstd_t *)arg->priv; + + if(priv) + free(priv); + + return 0; +} + + +// returns compressed packet length +// returns 0 if error occured, the caller would have to use +// original, i.e. uncompressed data then +static int transop_encode_zstd (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + /* transop_zstd_t *priv = (transop_zstd_t *)arg->priv; */ + int32_t compression_len = 0; + + if(in_len > N2N_PKT_BUF_SIZE) { + traceEvent(TRACE_ERROR, "encode_zstd inbuf wrong size (%ul) to compress", in_len); + return 0; + } + + if(out_len < in_len + 128) { // 128 leaves enough room, + // for exact size call + // ZSTD_compressBound(in_len) + // which is slower + traceEvent(TRACE_ERROR, "encode_zstd outbuf too small (%ul) to compress inbuf (%ul)", + out_len, in_len); + return 0; + } + + compression_len = ZSTD_compress(outbuf, out_len, inbuf, in_len, ZSTD_COMPRESSION_LEVEL); + if(ZSTD_isError(compression_len)) { + traceEvent(TRACE_ERROR, "payload compression failed with zstd error '%s'", + ZSTD_getErrorName(compression_len)); + // we do no return the error code to the caller, just return 0 len + // so, any further specific error handling would have to happen right here + compression_len = 0; + } + + return compression_len; +} + + +static int transop_decode_zstd (n2n_trans_op_t *arg, + uint8_t *outbuf, + size_t out_len, + const uint8_t *inbuf, + size_t in_len, + const uint8_t *peer_mac) { + + int32_t deflated_len = 0; + + if(in_len > N2N_PKT_BUF_SIZE) { + traceEvent(TRACE_ERROR, "decode_zstd inbuf wrong size (%ul) to decompress", in_len); + return 0; + } + + deflated_len = ZSTD_decompress(outbuf, out_len, inbuf, in_len); + + if(ZSTD_isError(deflated_len)) { + traceEvent(TRACE_WARNING, "payload decompression failed with zstd error '%s'", + ZSTD_getErrorName(deflated_len)); + return 0; // cannot help it + } + + // we should have noticed by memory break or ZSTD complaining about a too small of an out_len + if(deflated_len > N2N_PKT_BUF_SIZE) { + traceEvent(TRACE_ERROR, "decode_zstd outbuf wrong size (%ul) decompressed", deflated_len); + return 0; + } + + return deflated_len; +} + + +static void transop_tick_zstd (n2n_trans_op_t *arg, time_t now) { + + // no tick action +} + + +// zstd initialization function +int n2n_transop_zstd_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) { + + transop_zstd_t *priv; + + memset(ttt, 0, sizeof(*ttt)); + ttt->transform_id = N2N_COMPRESSION_ID_ZSTD; + + ttt->tick = transop_tick_zstd; + ttt->deinit = transop_deinit_zstd; + ttt->fwd = transop_encode_zstd; + ttt->rev = transop_decode_zstd; + + priv = (transop_zstd_t*)calloc(1, sizeof(transop_zstd_t)); + if(!priv) { + traceEvent(TRACE_ERROR, "zstd_init cannot allocate transop_zstd memory"); + return -1; + } + ttt->priv = priv; + + // zstd does not require initialization + // if it requires one day, this is the place to do it and eventually throw an error + // (see 'transform_lzo.c') + + return 0; +} + + +#endif // HAVE_ZSTD diff --git a/src/tuntap_freebsd.c b/src/tuntap_freebsd.c new file mode 100644 index 0000000..6501659 --- /dev/null +++ b/src/tuntap_freebsd.c @@ -0,0 +1,136 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +#ifdef __FreeBSD__ + + +#define N2N_FREEBSD_TAPDEVICE_SIZE 32 + + +void tuntap_close (tuntap_dev *device); + + +int tuntap_open (tuntap_dev *device /* ignored */, + char *dev, + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu) { + + int i; + char tap_device[N2N_FREEBSD_TAPDEVICE_SIZE]; + + for(i = 0; i < 255; i++) { + snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i); + + device->fd = open(tap_device, O_RDWR); + if(device->fd > 0) { + traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device); + break; + } + } + + if(device->fd < 0) { + traceEvent(TRACE_ERROR, "Unable to open tap device"); + return -1; + } else { + char buf[256]; + FILE *fd; + + device->ip_addr = inet_addr(device_ip); + + if(device_mac && device_mac[0] != '\0') { + // FIXME - this is not tested, might be wrong syntax for OS X + + // set the hw address before bringing the if up + snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s", i, device_mac); + system(buf); + } + + snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up", i, device_ip, device_mask, mtu); + system(buf); + + traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)", i, device_ip, device_mask); + + // read MAC address + snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i); + // traceEvent(TRACE_INFO, "%s", buf); + + fd = popen(buf, "r"); + if(fd < 0) { + tuntap_close(device); + return -1; + } else { + int a, b, c, d, e, f; + + buf[0] = 0; + fgets(buf, sizeof(buf), fd); + pclose(fd); + + if(buf[0] == '\0') { + traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address"); + exit(0); + } + + traceEvent(TRACE_NORMAL, "Interface tap%d mac %s", i, buf); + if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) { + device->mac_addr[0] = a, device->mac_addr[1] = b; + device->mac_addr[2] = c, device->mac_addr[3] = d; + device->mac_addr[4] = e, device->mac_addr[5] = f; + } + } + } + + + // read_mac(dev, device->mac_addr); + + return device->fd; +} + + +int tuntap_read (struct tuntap_dev *tuntap, unsigned char *buf, int len) { + + return read(tuntap->fd, buf, len); +} + + +int tuntap_write (struct tuntap_dev *tuntap, unsigned char *buf, int len) { + + return write(tuntap->fd, buf, len); +} + + +void tuntap_close (struct tuntap_dev *tuntap) { + + close(tuntap->fd); +} + + +// fill out the ip_addr value from the interface, called to pick up dynamic address changes +void tuntap_get_address (struct tuntap_dev *tuntap) { + + // no action +} + + +#endif /* #ifdef __FreeBSD__ */ diff --git a/src/tuntap_linux.c b/src/tuntap_linux.c new file mode 100644 index 0000000..b110e9c --- /dev/null +++ b/src/tuntap_linux.c @@ -0,0 +1,281 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#ifdef __linux__ + + +#include "n2n.h" + + +static int setup_ifname (int fd, const char *ifname, const char *ipaddr, + const char *netmask, uint8_t *mac, int mtu) { + + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + memcpy(ifr.ifr_hwaddr.sa_data, mac, 6); + + if(ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) { + traceEvent(TRACE_ERROR, "ioctl(SIOCSIFHWADDR) failed [%d]: %s", errno, strerror(errno)); + return -1; + } + + ifr.ifr_addr.sa_family = AF_INET; + + // interface address + inet_pton(AF_INET, ipaddr, &((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr); + if(ioctl(fd, SIOCSIFADDR, &ifr) == -1) { + traceEvent(TRACE_ERROR, "ioctl(SIOCSIFADDR) failed [%d]: %s", errno, strerror(errno)); + return -2; + } + + // netmask + if(netmask && (((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr.s_addr != 0)) { + inet_pton(AF_INET, netmask, &((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr); + if(ioctl(fd, SIOCSIFNETMASK, &ifr) == -1) { + traceEvent(TRACE_ERROR, "ioctl(SIOCSIFNETMASK, %s) failed [%d]: %s", netmask, errno, strerror(errno)); + return -3; + } + } + + // MTU + ifr.ifr_mtu = mtu; + if(ioctl(fd, SIOCSIFMTU, &ifr) == -1) { + traceEvent(TRACE_ERROR, "ioctl(SIOCSIFMTU) failed [%d]: %s", errno, strerror(errno)); + return -4; + } + + // set up and running + if(ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { + traceEvent(TRACE_ERROR, "ioctl(SIOCGIFFLAGS) failed [%d]: %s", errno, strerror(errno)); + return -5; + } + + ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); + + if(ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { + traceEvent(TRACE_ERROR, "ioctl(SIOCSIFFLAGS) failed [%d]: %s", errno, strerror(errno)); + return -6; + } + + return 0; +} + + +/** @brief Open and configure the TAP device for packet read/write. + * + * This routine creates the interface via the tuntap driver and then + * configures it. + * + * @param device - [inout] a device info holder object + * @param dev - user-defined name for the new iface, + * if NULL system will assign a name + * @param device_ip - address of iface + * @param device_mask - netmask for device_ip + * @param mtu - MTU for device_ip + * + * @return - negative value on error + * - non-negative file-descriptor on success + */ +int tuntap_open (tuntap_dev *device, + char *dev, /* user-definable interface name, eg. edge0 */ + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu) { + + char *tuntap_device = "/dev/net/tun"; + int ioctl_fd; + struct ifreq ifr; + int rc; + int nl_fd; + char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */ + struct iovec iov; + struct sockaddr_nl sa; + int up_and_running = 0; + struct msghdr msg; + + device->fd = open(tuntap_device, O_RDWR); + if(device->fd < 0) { + traceEvent(TRACE_ERROR, "tuntap open() error: %s[%d]. Is the tun kernel module loaded?\n", strerror(errno), errno); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + + // want a TAP device for layer 2 frames + ifr.ifr_flags = IFF_TAP|IFF_NO_PI; + + strncpy(ifr.ifr_name, dev, IFNAMSIZ-1); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + rc = ioctl(device->fd, TUNSETIFF, (void *)&ifr); + + if(rc < 0) { + traceEvent(TRACE_ERROR, "tuntap ioctl(TUNSETIFF, IFF_TAP) error: %s[%d]\n", strerror(errno), rc); + close(device->fd); + return -1; + } + + // store the device name for later reuse + strncpy(device->dev_name, ifr.ifr_name, MIN(IFNAMSIZ, N2N_IFNAMSIZ)); + + if(device_mac && device_mac[0]) { + // use the user-provided MAC + str2mac(device->mac_addr, device_mac); + } else { + // set an explicit random MAC to know the exact MAC in use, manually + // reading the MAC address is not safe as it may change internally + // also after the TAP interface UP status has been notified + + memrnd(device->mac_addr, N2N_MAC_SIZE); + + // clear multicast bit + device->mac_addr[0] &= ~0x01; + + // set locally-assigned bit + device->mac_addr[0] |= 0x02; + } + + // initialize netlink socket + if((nl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { + traceEvent(TRACE_ERROR, "netlink socket creation failed [%d]: %s", errno, strerror(errno)); + return -1; + } + + iov.iov_base = nl_buf; + iov.iov_len = sizeof(nl_buf); + + memset(&sa, 0, sizeof(sa)); + sa.nl_family = PF_NETLINK; + sa.nl_groups = RTMGRP_LINK; + sa.nl_pid = getpid(); + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &sa; + msg.msg_namelen = sizeof(sa); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + // subscribe to interface events + if(bind(nl_fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) { + traceEvent(TRACE_ERROR, "netlink socket bind failed [%d]: %s", errno, strerror(errno)); + return -1; + } + + if((ioctl_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { + traceEvent(TRACE_ERROR, "socket creation failed [%d]: %s", errno, strerror(errno)); + close(nl_fd); + return -1; + } + + if(setup_ifname(ioctl_fd, device->dev_name, device_ip, device_mask, device->mac_addr, mtu) < 0) { + close(nl_fd); + close(ioctl_fd); + close(device->fd); + return -1; + } + + close(ioctl_fd); + + // wait for the up and running notification + traceEvent(TRACE_INFO, "Waiting for TAP interface to be up and running..."); + + while(!up_and_running) { + ssize_t len = recvmsg(nl_fd, &msg, 0); + struct nlmsghdr *nh; + + for(nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { + if(nh->nlmsg_type == NLMSG_ERROR) { + traceEvent(TRACE_DEBUG, "nh->nlmsg_type == NLMSG_ERROR"); + break; + } + + if(nh->nlmsg_type == NLMSG_DONE) + break; + + if(nh->nlmsg_type == NETLINK_GENERIC) { + struct ifinfomsg *ifi = NLMSG_DATA(nh); + + // NOTE: skipping interface name check, assuming it's our TAP + if((ifi->ifi_flags & IFF_UP) && (ifi->ifi_flags & IFF_RUNNING)) { + up_and_running = 1; + traceEvent(TRACE_INFO, "Interface is up and running"); + break; + } + } + } + } + + close(nl_fd); + + device->ip_addr = inet_addr(device_ip); + device->device_mask = inet_addr(device_mask); + device->if_idx = if_nametoindex(dev); + + return device->fd; +} + + +int tuntap_read (struct tuntap_dev *tuntap, unsigned char *buf, int len) { + + return read(tuntap->fd, buf, len); +} + + +int tuntap_write (struct tuntap_dev *tuntap, unsigned char *buf, int len) { + + return write(tuntap->fd, buf, len); +} + + +void tuntap_close (struct tuntap_dev *tuntap) { + + close(tuntap->fd); +} + + +// fill out the ip_addr value from the interface, called to pick up dynamic address changes +void tuntap_get_address (struct tuntap_dev *tuntap) { + + struct ifreq ifr; + int fd; + + if((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { + traceEvent(TRACE_ERROR, "socket creation failed [%d]: %s", errno, strerror(errno)); + return; + } + + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, tuntap->dev_name, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + + if(ioctl(fd, SIOCGIFADDR, &ifr) != -1) + tuntap->ip_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + + close(fd); +} + + +#endif /* #ifdef __linux__ */ diff --git a/src/tuntap_netbsd.c b/src/tuntap_netbsd.c new file mode 100644 index 0000000..4302897 --- /dev/null +++ b/src/tuntap_netbsd.c @@ -0,0 +1,148 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +#ifdef __NetBSD__ + + +#include +#include +#include + + +#define N2N_NETBSD_TAPDEVICE_SIZE 32 + + +void tun_close (tuntap_dev *device); + + +int tuntap_open (tuntap_dev *device /* ignored */, + char *dev, + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu) { + + char tap_device[N2N_NETBSD_TAPDEVICE_SIZE]; + struct ifreq req; + + if(dev) { + snprintf(tap_device, sizeof(tap_device), "/dev/%s", dev); + device->fd = open(tap_device, O_RDWR); + snprintf(tap_device, sizeof(tap_device), "%s", dev); + } else { + device->fd = open("/dev/tap", O_RDWR); + if(device->fd >= 0) { + if(ioctl(device->fd, TAPGIFNAME, &req) == -1) { + traceEvent(TRACE_ERROR, "Unable to obtain name of tap device (%s)", strerror(errno)); + close(device->fd); + return -1; + } else { + snprintf(tap_device, sizeof(tap_device), req.ifr_name); + } + } + } + + if(device->fd < 0) { + traceEvent(TRACE_ERROR, "Unable to open tap device (%s)", strerror(errno)); + return -1; + } else { + char cmd[256]; + FILE *fd; + + traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device); + + device->ip_addr = inet_addr(device_ip); + + if(device_mac && device_mac[0] != '\0') { + // set the hw address before bringing the if up + snprintf(cmd, sizeof(cmd), "ifconfig %s link %s active", tap_device, device_mac); + system(cmd); + } + + snprintf(cmd, sizeof(cmd), "ifconfig %s %s netmask %s mtu %d up", tap_device, device_ip, device_mask, mtu); + system(cmd); + + traceEvent(TRACE_NORMAL, "Interface %s up and running (%s/%s)", tap_device, device_ip, device_mask); + + // read MAC address + snprintf(cmd, sizeof(cmd), "ifconfig %s |grep address|cut -c 11-28", tap_device); + // traceEvent(TRACE_INFO, "%s", cmd); + + fd = popen(cmd, "r"); + if(fd < 0) { + tun_close(device); + return -1; + } else { + int a, b, c, d, e, f; + char buf[256]; + + buf[0] = 0; + fgets(buf, sizeof(buf), fd); + pclose(fd); + + if(buf[0] == '\0') { + traceEvent(TRACE_ERROR, "Unable to read %s interface MAC address [%s]", tap_device, cmd); + exit(0); + } + + traceEvent(TRACE_NORMAL, "Interface %s mac %s", tap_device, buf); + if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) { + device->mac_addr[0] = a, device->mac_addr[1] = b; + device->mac_addr[2] = c, device->mac_addr[3] = d; + device->mac_addr[4] = e, device->mac_addr[5] = f; + } + } + } + + // read_mac(dev, device->mac_addr); + + return(device->fd); +} + + +int tuntap_read (struct tuntap_dev *tuntap, unsigned char *buf, int len) { + + return(read(tuntap->fd, buf, len)); +} + + +int tuntap_write (struct tuntap_dev *tuntap, unsigned char *buf, int len) { + + return(write(tuntap->fd, buf, len)); +} + + +void tuntap_close (struct tuntap_dev *tuntap) { + + close(tuntap->fd); +} + + +// fill out the ip_addr value from the interface, called to pick up dynamic address changes +void tuntap_get_address (struct tuntap_dev *tuntap) { + + // no action +} + + +#endif /* #ifdef __NetBSD__ */ diff --git a/src/tuntap_osx.c b/src/tuntap_osx.c new file mode 100644 index 0000000..6d4092d --- /dev/null +++ b/src/tuntap_osx.c @@ -0,0 +1,134 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +#include "n2n.h" + + +#ifdef __APPLE__ + + +#define N2N_OSX_TAPDEVICE_SIZE 32 + + +void tun_close (tuntap_dev *device); + + +int tuntap_open (tuntap_dev *device /* ignored */, + char *dev, + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu) { + + int i; + char tap_device[N2N_OSX_TAPDEVICE_SIZE]; + + for(i = 0; i < 255; i++) { + snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i); + + device->fd = open(tap_device, O_RDWR); + if(device->fd > 0) { + traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device); + break; + } + } + + if(device->fd < 0) { + traceEvent(TRACE_ERROR, "Unable to open any tap devices /dev/tap0 through /dev/tap254. Is this user properly authorized to access those descriptors?"); + traceEvent(TRACE_ERROR, "Please read https://github.com/ntop/n2n/blob/dev/doc/Building.md"); + return -1; + } else { + char buf[256]; + FILE *fd; + + device->ip_addr = inet_addr(device_ip); + + if(device_mac && device_mac[0] != '\0') { + // FIXME - this is not tested. might be wrong syntax for OS X + // set the hw address before bringing the if up + snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s", i, device_mac); + system(buf); + } + + snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up", i, device_ip, device_mask, mtu); + system(buf); + + traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)", i, device_ip, device_mask); + + // read MAC address + snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i); + // traceEvent(TRACE_INFO, "%s", buf); + + fd = popen(buf, "r"); + if(fd < 0) { + tuntap_close(device); + return -1; + } else { + int a, b, c, d, e, f; + + buf[0] = 0; + fgets(buf, sizeof(buf), fd); + pclose(fd); + + if(buf[0] == '\0') { + traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address"); + exit(0); + } + + traceEvent(TRACE_NORMAL, "Interface tap%d [MTU %d] mac %s", i, mtu, buf); + if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) { + device->mac_addr[0] = a, device->mac_addr[1] = b; + device->mac_addr[2] = c, device->mac_addr[3] = d; + device->mac_addr[4] = e, device->mac_addr[5] = f; + } + } + } + + // read_mac(dev, device->mac_addr); + + return(device->fd); +} + + +int tuntap_read (struct tuntap_dev *tuntap, unsigned char *buf, int len) { + + return(read(tuntap->fd, buf, len)); +} + + +int tuntap_write (struct tuntap_dev *tuntap, unsigned char *buf, int len) { + + return(write(tuntap->fd, buf, len)); +} + + +void tuntap_close (struct tuntap_dev *tuntap) { + + close(tuntap->fd); +} + +// fill out the ip_addr value from the interface, called to pick up dynamic address changes +void tuntap_get_address (struct tuntap_dev *tuntap) { + + // no action +} + + +#endif /* __APPLE__ */ diff --git a/src/wire.c b/src/wire.c new file mode 100644 index 0000000..4eb6576 --- /dev/null +++ b/src/wire.c @@ -0,0 +1,727 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +/** Routines for encoding and decoding n2n packets on the wire. + * + * encode_X(base,idx,v) prototypes are inspired by the erlang internal + * encoding model. Passing the start of a buffer in base and a pointer to an + * integer (initially set to zero). Each encode routine increases idx by the + * amount written and returns the amount written. In this way complex sequences + * of encodings can be represented cleanly. See encode_register() for an + * example. + */ + +#include "n2n.h" + + +int encode_uint8 (uint8_t * base, + size_t * idx, + const uint8_t v) { + + *(base + (*idx)) = (v & 0xff); + ++(*idx); + + return 1; +} + +int decode_uint8 (uint8_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx) { + + if(*rem < 1) { + return 0; + } + + *out = ( base[*idx] & 0xff ); + ++(*idx); + --(*rem); + + return 1; +} + +int encode_uint16 (uint8_t * base, + size_t * idx, + const uint16_t v) { + + *(base + (*idx)) = ( v >> 8) & 0xff; + *(base + (1 + *idx)) = ( v & 0xff ); + *idx += 2; + + return 2; +} + +int decode_uint16 (uint16_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx) { + + if(*rem < 2) { + return 0; + } + + *out = ( base[*idx] & 0xff ) << 8; + *out |= ( base[1 + *idx] & 0xff ); + *idx += 2; + *rem -= 2; + + return 2; +} + +int encode_uint32 (uint8_t * base, + size_t * idx, + const uint32_t v) { + + *(base + (0 + *idx)) = ( v >> 24) & 0xff; + *(base + (1 + *idx)) = ( v >> 16) & 0xff; + *(base + (2 + *idx)) = ( v >> 8) & 0xff; + *(base + (3 + *idx)) = ( v & 0xff ); + *idx += 4; + + return 4; +} + +int decode_uint32 (uint32_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx) { + + if(*rem < 4) { + return 0; + } + + *out = ( base[0 + *idx] & 0xff ) << 24; + *out |= ( base[1 + *idx] & 0xff ) << 16; + *out |= ( base[2 + *idx] & 0xff ) << 8; + *out |= ( base[3 + *idx] & 0xff ); + *idx += 4; + *rem -= 4; + + return 4; +} + +int encode_uint64 (uint8_t * base, + size_t * idx, + const uint64_t v) { + + *(uint64_t*)(base + *idx) = htobe64(v); + *idx += 8; + + return 8; +} + +int decode_uint64 (uint64_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx) { + + if(*rem < 8) { + return 0; + } + + *out = be64toh(*(uint64_t*)base + *idx); + *idx += 8; + *rem -= 8; + + return 8; +} + +int encode_buf (uint8_t * base, + size_t * idx, + const void * p, + size_t s) { + + memcpy((base + (*idx)), p, s); + *idx += s; + + return s; +} + +/* Copy from base to out of size bufsize */ +int decode_buf (uint8_t * out, + size_t bufsize, + const uint8_t * base, + size_t * rem, + size_t * idx) { + + if(*rem < bufsize) { + return 0; + } + + memcpy(out, (base + *idx), bufsize); + *idx += bufsize; + *rem -= bufsize; + + return bufsize; +} + + +int encode_mac (uint8_t * base, /* n2n_mac_t is typedefed array type which is always passed by reference */ + size_t * idx, + const n2n_mac_t m) { + + return encode_buf(base, idx, m, N2N_MAC_SIZE); +} + +int decode_mac (n2n_mac_t out, + const uint8_t * base, + size_t * rem, + size_t * idx) { + + return decode_buf(out, N2N_MAC_SIZE, base, rem, idx); +} + +int encode_cookie (uint8_t * base, + size_t * idx, + const n2n_cookie_t c) { + + return encode_uint32(base, idx, c); +} + +int decode_cookie (n2n_cookie_t * out, /* cookies are typedef'd as uint32_t which needs to correspond to this code */ + const uint8_t * base, + size_t * rem, + size_t * idx) { + + return decode_uint32(out, base, rem, idx); +} + + +int encode_common (uint8_t * base, + size_t * idx, + const n2n_common_t * common) { + + uint16_t flags = 0; + + encode_uint8(base, idx, N2N_PKT_VERSION); + encode_uint8(base, idx, common->ttl); + + flags = common->pc & N2N_FLAGS_TYPE_MASK; + flags |= common->flags & N2N_FLAGS_BITS_MASK; + + encode_uint16(base, idx, flags); + encode_buf(base, idx, common->community, N2N_COMMUNITY_SIZE); + + return -1; +} + +int decode_common (n2n_common_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx) { + + size_t idx0 = *idx; + uint8_t dummy = 0; + + decode_uint8(&dummy, base, rem, idx); + + if(N2N_PKT_VERSION != dummy) { + return -1; + } + + decode_uint8(&(out->ttl), base, rem, idx); + decode_uint16(&(out->flags), base, rem, idx); + out->pc = (out->flags & N2N_FLAGS_TYPE_MASK); + out->flags &= N2N_FLAGS_BITS_MASK; + + decode_buf(out->community, N2N_COMMUNITY_SIZE, base, rem, idx); + + return (*idx - idx0); +} + + +int encode_sock (uint8_t * base, + size_t * idx, + const n2n_sock_t * sock) { + + int retval = 0; + uint16_t f; + + switch(sock->family) { + case AF_INET: { + f = 0; + retval += encode_uint16(base, idx, f); + retval += encode_uint16(base, idx, sock->port); + retval += encode_buf(base, idx, sock->addr.v4, IPV4_SIZE); + break; + } + + case AF_INET6: { + f = 0x8000; + retval += encode_uint16(base, idx, f); + retval += encode_uint16(base, idx, sock->port); + retval += encode_buf(base, idx, sock->addr.v6, IPV6_SIZE); + break; + } + + default: + retval = -1; + } + + return retval; +} + + +int decode_sock (n2n_sock_t * sock, + const uint8_t * base, + size_t * rem, + size_t * idx) { + + size_t * idx0 = idx; + uint16_t f = 0; + + decode_uint16(&f, base, rem, idx); + + if(f & 0x8000) { + + /* IPv6 */ + sock->family = AF_INET6; + decode_uint16(&(sock->port), base, rem, idx); + decode_buf(sock->addr.v6, IPV6_SIZE, base, rem, idx); + } else { + /* IPv4 */ + sock->family = AF_INET; + decode_uint16(&(sock->port), base, rem, idx); + memset(sock->addr.v6, 0, IPV6_SIZE); /* so memcmp() works for equality. */ + decode_buf(sock->addr.v4, IPV4_SIZE, base, rem, idx); + } + + return (idx - idx0); +} + + +int encode_REGISTER (uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_REGISTER_t *reg) { + + int retval = 0; + + retval += encode_common(base, idx, common); + retval += encode_cookie(base, idx, reg->cookie); + retval += encode_mac(base, idx, reg->srcMac); + retval += encode_mac(base, idx, reg->dstMac); + if(common->flags & N2N_FLAGS_SOCKET) { + retval += encode_sock(base, idx, &(reg->sock)); + } + retval += encode_uint32(base, idx, reg->dev_addr.net_addr); + retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); + retval += encode_buf(base, idx, reg->dev_desc, N2N_DESC_SIZE); + + return retval; +} + + +int decode_REGISTER (n2n_REGISTER_t *reg, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx) { + + size_t retval = 0; + memset(reg, 0, sizeof(n2n_REGISTER_t)); + + retval += decode_cookie(®->cookie, base, rem, idx); + retval += decode_mac(reg->srcMac, base, rem, idx); + retval += decode_mac(reg->dstMac, base, rem, idx); + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&(reg->sock), base, rem, idx); + } + retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); + retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); + retval += decode_buf(reg->dev_desc, N2N_DESC_SIZE, base, rem, idx); + + return retval; +} + + +int encode_REGISTER_SUPER (uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_REGISTER_SUPER_t *reg) { + + int retval = 0; + + retval += encode_common(base, idx, common); + retval += encode_cookie(base, idx, reg->cookie); + retval += encode_mac(base, idx, reg->edgeMac); + if(common->flags & N2N_FLAGS_SOCKET) { + retval += encode_sock(base, idx, &(reg->sock)); + } + retval += encode_uint32(base, idx, reg->dev_addr.net_addr); + retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); + retval += encode_buf(base, idx, reg->dev_desc, N2N_DESC_SIZE); + retval += encode_uint16(base, idx, reg->auth.scheme); + retval += encode_uint16(base, idx, reg->auth.token_size); + retval += encode_buf(base, idx, reg->auth.token, reg->auth.token_size); + retval += encode_uint32(base, idx, reg->key_time); + + return retval; +} + + +int decode_REGISTER_SUPER (n2n_REGISTER_SUPER_t *reg, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx) { + + size_t retval = 0; + memset(reg, 0, sizeof(n2n_REGISTER_SUPER_t)); + + retval += decode_cookie(®->cookie, base, rem, idx); + retval += decode_mac(reg->edgeMac, base, rem, idx); + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&(reg->sock), base, rem, idx); + } + retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); + retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); + retval += decode_buf(reg->dev_desc, N2N_DESC_SIZE, base, rem, idx); + retval += decode_uint16(&(reg->auth.scheme), base, rem, idx); + retval += decode_uint16(&(reg->auth.token_size), base, rem, idx); + retval += decode_buf(reg->auth.token, reg->auth.token_size, base, rem, idx); + retval += decode_uint32(&(reg->key_time), base, rem, idx); + + return retval; +} + + +int encode_UNREGISTER_SUPER (uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_UNREGISTER_SUPER_t *unreg) { + + int retval = 0; + + retval += encode_common(base, idx, common); + retval += encode_uint16(base, idx, unreg->auth.scheme); + retval += encode_uint16(base, idx, unreg->auth.token_size); + retval += encode_buf(base, idx, unreg->auth.token, unreg->auth.token_size); + retval += encode_mac(base, idx, unreg->srcMac); + + return retval; +} + + +int decode_UNREGISTER_SUPER (n2n_UNREGISTER_SUPER_t *unreg, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx) { + + size_t retval = 0; + memset(unreg, 0, sizeof(n2n_UNREGISTER_SUPER_t)); + + retval += decode_uint16(&(unreg->auth.scheme), base, rem, idx); + retval += decode_uint16(&(unreg->auth.token_size), base, rem, idx); + retval += decode_buf(unreg->auth.token, unreg->auth.token_size, base, rem, idx); + retval += decode_mac(unreg->srcMac, base, rem, idx); + + return retval; +} + + +int encode_REGISTER_ACK (uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_REGISTER_ACK_t *reg) { + + int retval = 0; + + retval += encode_common(base, idx, common); + retval += encode_cookie(base, idx, reg->cookie); + retval += encode_mac(base, idx, reg->dstMac); + retval += encode_mac(base, idx, reg->srcMac); + + /* The socket in REGISTER_ACK is the socket from which the REGISTER + * arrived. This is sent back to the sender so it knows what its public + * socket is. */ + if(common->flags & N2N_FLAGS_SOCKET) { + retval += encode_sock(base, idx, &(reg->sock)); + } + + return retval; +} + + +int decode_REGISTER_ACK (n2n_REGISTER_ACK_t *reg, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx) { + + size_t retval = 0; + memset(reg, 0, sizeof(n2n_REGISTER_ACK_t)); + + retval += decode_cookie(®->cookie, base, rem, idx); + retval += decode_mac(reg->dstMac, base, rem, idx); + retval += decode_mac(reg->srcMac, base, rem, idx); + + /* The socket in REGISTER_ACK is the socket from which the REGISTER + * arrived. This is sent back to the sender so it knows what its public + * socket is. */ + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&(reg->sock), base, rem, idx); + } + + return retval; +} + + +int encode_REGISTER_SUPER_ACK (uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_REGISTER_SUPER_ACK_t *reg, + uint8_t *tmpbuf) { + + int retval = 0; + + retval += encode_common(base, idx, common); + retval += encode_cookie(base, idx, reg->cookie); + retval += encode_mac(base, idx, reg->srcMac); + retval += encode_uint32(base, idx, reg->dev_addr.net_addr); + retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); + retval += encode_uint16(base, idx, reg->lifetime); + + retval += encode_sock(base, idx, &(reg->sock)); + + retval += encode_uint16(base, idx, reg->auth.scheme); + retval += encode_uint16(base, idx, reg->auth.token_size); + retval += encode_buf(base, idx, reg->auth.token, reg->auth.token_size); + + retval += encode_uint8(base, idx, reg->num_sn); + retval += encode_buf(base, idx, tmpbuf, (reg->num_sn*REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE)); + + retval += encode_uint32(base, idx, reg->key_time); + + return retval; +} + + +int decode_REGISTER_SUPER_ACK (n2n_REGISTER_SUPER_ACK_t *reg, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx, + uint8_t *tmpbuf) { + + size_t retval = 0; + memset(reg, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); + + retval += decode_cookie(®->cookie, base, rem, idx); + retval += decode_mac(reg->srcMac, base, rem, idx); + retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); + retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); + retval += decode_uint16(&(reg->lifetime), base, rem, idx); + + /* Socket is mandatory in this message type */ + retval += decode_sock(&(reg->sock), base, rem, idx); + + retval += decode_uint16(&(reg->auth.scheme), base, rem, idx); + retval += decode_uint16(&(reg->auth.token_size), base, rem, idx); + retval += decode_buf(reg->auth.token, reg->auth.token_size, base, rem, idx); + + /* Following the edge socket are an array of backup supernodes. */ + retval += decode_uint8(&(reg->num_sn), base, rem, idx); + retval += decode_buf(tmpbuf, (reg->num_sn * REG_SUPER_ACK_PAYLOAD_ENTRY_SIZE), base, rem, idx); + + retval += decode_uint32(&(reg->key_time), base, rem, idx); + + return retval; +} + + +int encode_REGISTER_SUPER_NAK (uint8_t *base, + size_t *idx, + const n2n_common_t *common, + const n2n_REGISTER_SUPER_NAK_t *nak) { + + int retval = 0; + + retval += encode_common(base, idx, common); + retval += encode_cookie(base, idx, nak->cookie); + retval += encode_mac(base, idx, nak->srcMac); + + retval += encode_uint16(base, idx, nak->auth.scheme); + retval += encode_uint16(base, idx, nak->auth.token_size); + retval += encode_buf(base, idx, nak->auth.token, nak->auth.token_size); + + return retval; +} + + +int decode_REGISTER_SUPER_NAK (n2n_REGISTER_SUPER_NAK_t *nak, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx) { + + size_t retval = 0; + memset(nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); + + retval += decode_cookie(&nak->cookie, base, rem, idx); + retval += decode_mac(nak->srcMac, base, rem, idx); + + retval += decode_uint16(&(nak->auth.scheme), base, rem, idx); + retval += decode_uint16(&(nak->auth.token_size), base, rem, idx); + retval += decode_buf(nak->auth.token, nak->auth.token_size, base, rem, idx); + + return retval; +} + + +int fill_sockaddr (struct sockaddr * addr, + size_t addrlen, + const n2n_sock_t * sock) { + + int retval = -1; + + if(AF_INET == sock->family) { + if(addrlen >= sizeof(struct sockaddr_in)) { + struct sockaddr_in * si = (struct sockaddr_in *)addr; + si->sin_family = sock->family; + si->sin_port = htons(sock->port); + memcpy(&(si->sin_addr.s_addr), sock->addr.v4, IPV4_SIZE); + retval = 0; + } + } + + return retval; +} + + +int encode_PACKET (uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_PACKET_t * pkt) { + + int retval = 0; + + retval += encode_common(base, idx, common); + retval += encode_mac(base, idx, pkt->srcMac); + retval += encode_mac(base, idx, pkt->dstMac); + if(common->flags & N2N_FLAGS_SOCKET) { + retval += encode_sock(base, idx, &(pkt->sock)); + } + retval += encode_uint8(base, idx, pkt->compression); + retval += encode_uint8(base, idx, pkt->transform); + + return retval; +} + + +int decode_PACKET (n2n_PACKET_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx) { + + size_t retval = 0; + memset(pkt, 0, sizeof(n2n_PACKET_t)); + + retval += decode_mac(pkt->srcMac, base, rem, idx); + retval += decode_mac(pkt->dstMac, base, rem, idx); + + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&(pkt->sock), base, rem, idx); + } + + retval += decode_uint8(&(pkt->compression), base, rem, idx); + retval += decode_uint8(&(pkt->transform), base, rem, idx); + + return retval; +} + + +int encode_PEER_INFO (uint8_t *base, + size_t *idx, + const n2n_common_t *cmn, + const n2n_PEER_INFO_t *pkt) { + + int retval = 0; + + retval += encode_common(base, idx, cmn); + retval += encode_uint16(base, idx, pkt->aflags); + retval += encode_mac(base, idx, pkt->srcMac); + retval += encode_mac(base, idx, pkt->mac); + retval += encode_sock(base, idx, &pkt->sock); + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += encode_sock(base, idx, &pkt->preferred_sock); + } + retval += encode_uint32(base, idx, (uint32_t)pkt->load); + retval += encode_uint32(base, idx, (uint32_t)pkt->uptime); + retval += encode_buf(base, idx, pkt->version, sizeof(n2n_version_t)); + + return retval; +} + + +int decode_PEER_INFO (n2n_PEER_INFO_t *pkt, + const n2n_common_t *cmn, /* info on how to interpret it */ + const uint8_t *base, + size_t *rem, + size_t *idx) { + + size_t retval = 0; + memset(pkt, 0, sizeof(n2n_PEER_INFO_t)); + + retval += decode_uint16(&(pkt->aflags), base, rem, idx); + retval += decode_mac(pkt->srcMac, base, rem, idx); + retval += decode_mac(pkt->mac, base, rem, idx); + retval += decode_sock(&pkt->sock, base, rem, idx); + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&pkt->preferred_sock, base, rem, idx); + } + retval += decode_uint32(&pkt->load, base, rem, idx); + retval += decode_uint32((uint32_t*)&pkt->uptime, base, rem, idx); + retval += decode_buf((uint8_t*)pkt->version, sizeof(n2n_version_t), base, rem, idx); + + return retval; +} + + +int encode_QUERY_PEER (uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_QUERY_PEER_t * pkt) { + + int retval = 0; + + retval += encode_common(base, idx, common); + retval += encode_mac(base, idx, pkt->srcMac); + retval += encode_mac(base, idx, pkt->targetMac); + retval += encode_uint16(base, idx, pkt->aflags); + + return retval; +} + +int decode_QUERY_PEER (n2n_QUERY_PEER_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx) { + + size_t retval = 0; + memset(pkt, 0, sizeof(n2n_QUERY_PEER_t)); + + retval += decode_mac(pkt->srcMac, base, rem, idx); + retval += decode_mac(pkt->targetMac, base, rem, idx); + retval += decode_uint16(&(pkt->aflags), base, rem, idx); + + return retval; +} diff --git a/supernode.1 b/supernode.1 index 863c498..742b826 100644 --- a/supernode.1 +++ b/supernode.1 @@ -1,8 +1,12 @@ -.TH supernode 1 "Jan 3, 2009" "revision 3679" "USER COMMANDS" +.TH supernode 1 "Jul 16, 2021" "version 3" "USER COMMANDS" .SH NAME supernode \- n2n supernode daemon .SH SYNOPSIS -.B supernode \-l [\-v] +.B supernode + +.br +.B supernode +[OPTION]... .SH DESCRIPTION N2N is a peer-to-peer VPN system. Supernode is a node introduction registry, broadcast conduit and packet relay node for the n2n system. On startup supernode @@ -16,20 +20,105 @@ Supernode can service a number of n2n communities concurrently. Traffic does not cross between communities. .PP All logging goes to stdout. -.SH OPTIONS +.PP +The config file is similar to the command line, with one option per line. +Lines starting with a "#" are ignored. +An equal sign ('=') should be used between key and value. Example: -p=7777 +.SH OPTIONS FOR THE UNDERLYING NETWORK CONNECTION .TP -\-l -listen on the given UDP port +\fB\-p \fR<\fIlocal_port\fR>, \fB\-\-local-port\fR=<\fIlocal_port\fR> +listen on this fixed local UDP port, defaults to 7654 .TP -\-v +\fB\-F \fR<\fIfed_name\fR> +name of the supernode's federation, defaults to '*Federation' (see also N2N_FEDERATION in ENVIRONMENT) +.TP +\fB\-l \fR<\fIhost:port\fR> +ip address or name, and port of known supernode +.TP +\fB\-m \fR<\fImac_address\fR> +fixed MAC address for the supernode, e.g. + '-m 10:20:30:40:50:60', random otherwise +.TP +\fB\-M\fR +disable MAC and IP address spoofing protection for all +non-username-password-authenticating communities +.TP +\fB\-V \fR<\fIversion_string\fR> +modify the supernode version string which is distributed to the +edges and shown at their management port output, up to 19 characters +.TP +.SH TAP DEVICE AND OVERLAY NETWORK CONFIGURATION +.TP +\fB\-c \fR<\fIpath\fR>, \fB\-\-communities\fR=<\fIpath\fR> +file containing the allowed communities and any User / Password based authentication +details (See ALLOWED COMMUNITIES FILE section) +.TP +\fB\-a \fR<\fInet-net/n\fR>, \fB\-\-autoip\fR= +subnet range for auto ip address service, +.br +e.g. '-a 192.168.0.0-192.168.255.0/24', +.br +defaults to '10.128.255.0-10.255.255.0/24' +.SH LOCAL OPTIONS +.TP +\fB\-f\fR, \fB\-\-foreground\fR +disable daemon mode (UNIX) and run in foreground. +.TP +\fB\-t \fR<\fIport\fR>, \fB\-\-mgmt-port\fR=<\fIport\fR> +management UDP port, for multiple supernodes on a machine, defaults to 5645 +.TP +\fB\-\-management-password \fR<\fIpassword\fR> +sets the password for access to JSON API at the management port, defaults to 'n2n'. The password +has to be provided for relevant access to JSON API at the management port. +.TP +\fB\-v\fR, \fB\-\-verbose\fR use verbose logging +.TP +\fB\-u \fR<\fIUID\fR> +numeric user ID to use when privileges are dropped +.TP +\fB\-g \fR<\fIGID\fR> +numeric group ID to use when privileges are dropped +.TP +\fB-h\fR +shows a quick reference including all available options +.TP +\fB\-\-help\fR +shows detailed parameter description + +.SH ALLOWED COMMUNITIES FILE +This file is a plain text file. +Comments are introduced with a hash at the beginning of the line. +A line that begins with an asterisk is a user authentication definition and adds an allowed user to the most recently defined community. +Allowed communities can be specified with a regular expression. +.PP +Example community file: +.PP +.nf +.RS +# List of allowed communities +mynetwork +netleo +* logan nHWum+r42k1qDXdIeH-WFKeylK5UyLStRzxofRNAgpG +* sister HwHpPrdMft+38tFDDiunUds6927t0+zhCMMkQdJafcC +.RE +.fi +.PP +More details on creating the allowed communities file are found in the Communities.md and Authentication.md documentation included with this package. +.SH ENVIRONMENT +.TP +.B N2N_FEDERATION +set the federation name so it is not visible at the command line .SH EXAMPLES .TP -.B supernode -l 7654 -v +.B supernode -p 7654 -v Start supernode listening on UDP port 7654 with verbose output. +.TP +.B echo | nc -w1 -u 127.0.0.1 5645 +Shows the management status of a running supernode. .PP .SH RESTART -When suprenode restarts it loses all registration information from associated +When supernode restarts it loses all registration information from associated edge nodes. It can take up to five minutes for the edge nodes to re-register and normal traffic flow to resume. .SH EXIT STATUS @@ -38,3 +127,7 @@ supernode is a daemon and any exit is an error Luca Deri ( deri (at) ntop.org ), Richard Andrews ( andrews (at) ntop.org ), Don Bindner .SH SEE ALSO ifconfig(8) edge(8) +.br +the documentation contained in the source code +.br +the extensive documentation found in n2n's \fBdoc/\fR folder diff --git a/supernode.c b/supernode.c deleted file mode 100644 index ff41927..0000000 --- a/supernode.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * (C) 2007-09 - Luca Deri - * Richard Andrews - * - * 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 - * -*/ - -#include "n2n.h" - -struct tx_stats -{ - size_t pkts; - size_t errors; -}; - - -/* *********************************************** */ - -static void help() { - print_n2n_version(); - printf("supernode -l [-v] [-h]\n"); - exit(0); -} - -/* *********************************************** */ - -static struct peer_info *known_peers = NULL; -static struct tx_stats supernode_stats = {0,0}; - -/* *********************************************** */ - -/** Turn a REGISTER request around and send a REGISTER_ACK packet back to the - * sender. - * - * This needs to be done for all incoming REGISTER packets to keep firewalls - * open - */ -static void send_register_ack( n2n_sock_info_t * sinfo, - const struct peer_addr *destination_peer, - const struct n2n_packet_header * reqhdr ) -{ - struct n2n_packet_header hdr; - u_int8_t pkt[N2N_PKT_HDR_SIZE]; - size_t len = sizeof(hdr); - - fill_standard_header_fields(sinfo, &hdr, NULL /* zero src MAC */ ); - hdr.sent_by_supernode = 1; - hdr.msg_type = MSG_TYPE_REGISTER_ACK; - memcpy( hdr.community_name, reqhdr->community_name, COMMUNITY_LEN); - memcpy( hdr.dst_mac, reqhdr->src_mac, 6); /* turn it around */ - /* leave IP sockets unfilled. */ - - marshall_n2n_packet_header( pkt, &hdr ); - send_packet(sinfo, (char *)pkt, &len, destination_peer, N2N_COMPRESSION_ENABLED); -} - -static void register_peer(struct n2n_packet_header *hdr, - struct peer_addr *sender, - n2n_sock_info_t * sinfo) { - struct peer_info *scan = known_peers; - ipstr_t buf, buf1; - macstr_t mac_buf; - - send_register_ack( sinfo, sender, hdr ); /* keep firewalls open */ - - while(scan != NULL) { - if((strcmp(scan->community_name, hdr->community_name) == 0) - && (memcmp(&scan->mac_addr, hdr->src_mac, 6) == 0)) { - - scan->last_seen = time(NULL); - if ( ( 0 != memcmp(&scan->public_ip, sender, sizeof(struct peer_addr)) ) || - ( 0 != memcmp(&scan->private_ip, &hdr->private_ip, sizeof(struct peer_addr)) ) ) - { - /* Something is actually different. */ - memcpy(&scan->public_ip, sender, sizeof(struct peer_addr)); - memcpy(&scan->private_ip, &hdr->private_ip, sizeof(struct peer_addr)); - - /* Overwrite existing peer */ - traceEvent(TRACE_NORMAL, "Re-registered node [public_ip=(%d)%s:%hd][private_ip=%s:%hd][mac=%s][community=%s]", - scan->public_ip.family, - intoa(ntohl(scan->public_ip.addr_type.v4_addr), buf, sizeof(buf)), - ntohs(scan->public_ip.port), - intoa(ntohl(scan->private_ip.addr_type.v4_addr), buf1, sizeof(buf1)), - ntohs(scan->private_ip.port), - macaddr_str(scan->mac_addr, mac_buf, sizeof(mac_buf)), - scan->community_name); - } - - return; /* Found the registration entry so stop. */ - } - - scan = scan->next; - } - - /* FIX mettere un limite alla lista dei peer */ - - scan = (struct peer_info*)calloc(1, sizeof(struct peer_info)); - memcpy(scan->community_name, hdr->community_name, COMMUNITY_LEN); - memcpy(&scan->public_ip, sender, sizeof(struct peer_addr)); - memcpy(&scan->private_ip, &hdr->private_ip, sizeof(struct peer_addr)); - memcpy(&scan->mac_addr, hdr->src_mac, 6); - scan->last_seen = time(NULL); // FIX aggiungere un timeout - scan->next = known_peers; - scan->sinfo = *sinfo; - known_peers = scan; - - traceEvent(TRACE_NORMAL, "Registered new node [public_ip=(%d)%s:%d][private_ip=%s:%d][mac=%s][community=%s]", - scan->public_ip.family, - intoa(ntohl(scan->public_ip.addr_type.v4_addr), buf, sizeof(buf)), - ntohs(scan->public_ip.port), - intoa(ntohl(scan->private_ip.addr_type.v4_addr), buf1, sizeof(buf1)), - ntohs(scan->private_ip.port), - macaddr_str(scan->mac_addr, mac_buf, sizeof(mac_buf)), - scan->community_name); -} - -/* *********************************************** */ - -static void deregister_peer(struct n2n_packet_header *hdr, - struct peer_addr *sender) { - struct peer_info *scan = known_peers, *prev = NULL; - ipstr_t buf, buf1; - - while(scan != NULL) { - if((strcmp(scan->community_name, hdr->community_name) == 0) - && (memcmp(&scan->mac_addr, hdr->src_mac, 6) == 0)) { - /* Overwrite existing peer */ - if(prev == NULL) - known_peers = scan->next; - else - prev->next = scan->next; - - traceEvent(TRACE_INFO, "Degistered node [public_ip=%s:%hd][private_ip=%s:%hd]", - intoa(ntohl(scan->public_ip.addr_type.v4_addr), buf, sizeof(buf)), - ntohs(scan->public_ip.port), - intoa(ntohl(scan->private_ip.addr_type.v4_addr), buf1, sizeof(buf1)), - ntohs(scan->private_ip.port)); - - free(scan); - return; - } - - scan = scan->next; - } - - traceEvent(TRACE_WARNING, "Unable to delete specified peer [%s:%hd]", - intoa(ntohl(sender->addr_type.v4_addr), buf, sizeof(buf)), - ntohs(sender->port)); -} - -/* *********************************************** */ - -/* *********************************************** */ - -static const struct option long_options[] = { - { "community", required_argument, NULL, 'c' }, - { "listening-port", required_argument, NULL, 'l' }, - { "help" , no_argument, NULL, 'h' }, - { "verbose", no_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } -}; - -/* *********************************************** */ - - -/** Forward a L2 packet to every edge registered for the community of the - * originator. - * - * @return number of copies of the packet sent - */ -static size_t broadcast_packet(char *packet, u_int packet_len, - struct peer_addr *sender, - n2n_sock_info_t * sinfo, - struct n2n_packet_header *hdr ) -{ - size_t numsent=0; - struct peer_info *scan; - - scan = known_peers; - while(scan != NULL) { - if((strcmp(scan->community_name, hdr->community_name) == 0) - && (memcmp(sender, &scan->public_ip, sizeof(struct peer_addr)) /* No L3 self-send */) ) - { - int data_sent_len; - size_t len = packet_len; - - data_sent_len = send_data( &(scan->sinfo), packet, &len, &scan->public_ip, 0); - - if(data_sent_len != len) - { - ++(supernode_stats.errors); - traceEvent(TRACE_WARNING, "sendto() [sent=%d][attempted_to_send=%d] [%s]\n", - data_sent_len, len, strerror(errno)); - } - else - { - ipstr_t buf; - ipstr_t buf1; - - ++numsent; - ++(supernode_stats.pkts); - traceEvent(TRACE_INFO, "Sent multicast message to remote node [%s:%hd][mac=%s]", - intoa(ntohl(scan->public_ip.addr_type.v4_addr), buf, sizeof(buf)), - ntohs(scan->public_ip.port), - macaddr_str(scan->mac_addr, buf1, sizeof(buf1))); - } - } - - scan = scan->next; - } /* while */ - - - return numsent; -} - - -/** Forward a L2 packet. This may involve a broadcast operation. - * - * Rules are as follows: - * - * 1. If the dest MAC is a multicast address, broadcast to all edges in the - * community. - * - * 2. If the dest MAC is known forward to the destination edge only. - * Else broadcast to all edges in the community. - * - * @return number of copies of the packet sent - */ -static size_t forward_packet(char *packet, u_int packet_len, - struct peer_addr *sender, - n2n_sock_info_t * sinfo, - struct n2n_packet_header *hdr ) -{ - size_t numsent=0; - u_int8_t is_dst_broad_multi_cast; - struct peer_info *scan; - - ipstr_t buf; - ipstr_t buf1; - - hdr->ttl++; /* FIX discard packets with a high TTL */ - is_dst_broad_multi_cast = is_multi_broadcast(hdr->dst_mac); - - /* Put the original packet sender (public) address */ - memcpy(&hdr->public_ip, sender, sizeof(struct peer_addr)); - hdr->sent_by_supernode = 1; - - marshall_n2n_packet_header( (u_int8_t *)packet, hdr ); - - - if ( is_dst_broad_multi_cast ) - { - traceEvent(TRACE_INFO, "Broadcasting. Multicast address [mac=%s]", - macaddr_str(hdr->dst_mac, buf, sizeof(buf))); - - numsent = broadcast_packet( packet, packet_len, sender, sinfo, hdr ); - } - else - { - scan = find_peer_by_mac( known_peers, hdr->dst_mac ); - if ( scan ) - { - int data_sent_len; - size_t len = packet_len; - - data_sent_len = send_data( &(scan->sinfo), packet, &len, &scan->public_ip, 0); - - if(data_sent_len != len) - { - ++(supernode_stats.errors); - traceEvent(TRACE_WARNING, "sendto() [sent=%d][attempted_to_send=%d] [%s]\n", - data_sent_len, len, strerror(errno)); - } - else { - ++(supernode_stats.pkts); - traceEvent(TRACE_INFO, "Sent message to remote node [%s:%hd][mac=%s]", - intoa(ntohl(scan->public_ip.addr_type.v4_addr), buf, sizeof(buf)), - ntohs(scan->public_ip.port), - macaddr_str(scan->mac_addr, buf1, sizeof(buf1))); - } - - numsent = 1; - } - else - { - traceEvent(TRACE_INFO, "Broadcasting because unknown dest [mac=%s]", - macaddr_str(hdr->dst_mac, buf, sizeof(buf))); - numsent = broadcast_packet( packet, packet_len, sender, sinfo, hdr ); - } - } - - return numsent; -} - -static void handle_packet(char *packet, u_int packet_len, - struct peer_addr *sender, - n2n_sock_info_t * sinfo) { - ipstr_t buf; - - traceEvent(TRACE_INFO, "Received message from node [%s:%hd]", - intoa(ntohl(sender->addr_type.v4_addr), buf, sizeof(buf)), - ntohs(sender->port)); - - if(packet_len < N2N_PKT_HDR_SIZE) - traceEvent(TRACE_WARNING, "Received packet too short [len=%d]\n", packet_len); - else { - struct n2n_packet_header hdr_storage; - struct n2n_packet_header *hdr = &hdr_storage; - - unmarshall_n2n_packet_header( hdr, (u_int8_t *)packet ); - - if(hdr->version != N2N_PKT_VERSION) { - traceEvent(TRACE_WARNING, - "Received packet with unknown protocol version (%d): discarded\n", - hdr->version); - return; - } - - if(hdr->msg_type == MSG_TYPE_REGISTER) - { - register_peer(hdr, sender, sinfo); - } - else if(hdr->msg_type == MSG_TYPE_DEREGISTER) { - deregister_peer(hdr, sender); - } else if(hdr->msg_type == MSG_TYPE_PACKET) { - forward_packet( packet, packet_len, sender, sinfo, hdr ); - } else { - traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored\n", - hdr->msg_type); - } - } -} - -/* *********************************************** */ - -static -#ifdef WIN32 -DWORD tcpReadThread(LPVOID lpArg) -#else - void* tcpReadThread(void *lpArg) -#endif -{ - n2n_sock_info_t sinfo; - char c[1600]; - int new_line = 0; - - sinfo.sock=(int)lpArg; - sinfo.is_udp_socket=0; /* TCP in this case */ - - traceEvent(TRACE_NORMAL, "Handling sock_fd %d", sinfo.sock); - - while(1) { - int rc; - - if((rc = recv(sinfo.sock, c, 2, 0)) > 0) { - if((c[0] == '\r') && (c[1] == '\n')) { - if(!new_line) - new_line = 1; - else - break; /* Double \r\n\r\n, the http header is over */ - } else - printf("%c%c [%d][%d] ", c[0], c[1], c[0], c[1]); fflush(stdout); - } else { - traceEvent(TRACE_NORMAL, "recv() error [rc=%d][%s]", rc, strerror(errno)); - break; - } - } - - /* Beginning of n2n protocol over TCP */ - c[5] = 0; - - while(1) { - int rc; - - // FIX: add select - if((rc = recv(sinfo.sock, c, 4, 0)) == 4) { - int len = atoi(c); - socklen_t from_len = sizeof(struct sockaddr_in ); - struct sockaddr_in from; - - /* Check packet length */ - if((len <= 0) || (len >= 1600)) break; - rc = recvfrom(sinfo.sock, c, len, 0, (struct sockaddr*)&from, &from_len); - - if((rc <= 0) || (rc != len)) - break; - else { - struct peer_addr _from; - - sockaddr_in2peer_addr(&from, &_from); - handle_packet(c, len, &_from, &sinfo); - } - } else - break; - } - - closesocket(sinfo.sock); -#ifdef WIN32 - return(0); -#else - return(NULL); -#endif -} - - -/* *********************************************** */ - -static void startTcpReadThread(int sock_fd) { -#ifdef WIN32 - HANDLE hThread; - DWORD dwThreadId; - - hThread = CreateThread(NULL, /* no security attributes */ - 0, /* use default stack size */ - (LPTHREAD_START_ROUTINE)tcpReadThread, /* thread function */ - (void*)sock_fd, /* argument to thread function */ - 0, /* use default creation flags */ - &dwThreadId); /* returns the thread identifier */ -#else - int rc; - pthread_t threadId; - - rc = pthread_create(&threadId, NULL, tcpReadThread, (void*)sock_fd); -#endif -} - -/* *********************************************** */ - -int main(int argc, char* argv[]) { - int opt, local_port = 0; - n2n_sock_info_t udp_sinfo; - n2n_sock_info_t tcp_sinfo; - -#ifdef WIN32 - initWin32(); -#endif - - optarg = NULL; - while((opt = getopt_long(argc, argv, "l:vh", long_options, NULL)) != EOF) { - switch (opt) { - case 'l': /* local-port */ - local_port = atoi(optarg); - break; - case 'h': /* help */ - help(); - break; - case 'v': /* verbose */ - traceLevel = 3; - break; - } - } - - if(!(local_port)) - help(); - - udp_sinfo.is_udp_socket=1; - udp_sinfo.sock = open_socket(local_port, 1, 0); - if(udp_sinfo.sock < 0) return(-1); - - tcp_sinfo.is_udp_socket=0; - tcp_sinfo.sock = open_socket(local_port, 0, 1); - if(tcp_sinfo.sock < 0) return(-1); - - traceEvent(TRACE_NORMAL, "Supernode ready: listening on port %d [TCP/UDP]", local_port); - - while(1) { - int rc, max_sock; - fd_set socket_mask; - struct timeval wait_time; - - FD_ZERO(&socket_mask); - max_sock = max(udp_sinfo.sock, tcp_sinfo.sock); - FD_SET(udp_sinfo.sock, &socket_mask); - FD_SET(tcp_sinfo.sock, &socket_mask); - - wait_time.tv_sec = 10; wait_time.tv_usec = 0; - rc = select(max_sock+1, &socket_mask, NULL, NULL, &wait_time); - - if(rc > 0) { - if(FD_ISSET(udp_sinfo.sock, &socket_mask)) { - char packet[2048]; - size_t len; - struct peer_addr sender; - u_int8_t discarded_pkt; - struct n2n_packet_header hdr; - - len = receive_data( &udp_sinfo, packet, sizeof(packet), &sender, &discarded_pkt, NULL, 0, &hdr); - - if(len <= 0) - traceEvent(TRACE_WARNING, "recvfrom()=%d [%s]\n", len, strerror(errno)); - else { - handle_packet(packet, len, &sender, &udp_sinfo); - } - } else if(FD_ISSET(tcp_sinfo.sock, &socket_mask)) { - struct sockaddr from; - int from_len = sizeof(from); - int new_sock = accept(tcp_sinfo.sock, (struct sockaddr*)&from, - (socklen_t*)&from_len); - - if(new_sock < 0) { - traceEvent(TRACE_WARNING, "TCP connection accept() failed [%s]\n", strerror(errno)); - } else { - startTcpReadThread(new_sock); - } - } - } - - purge_expired_registrations( &known_peers ); - } /* while */ - - closesocket(udp_sinfo.sock); - closesocket(tcp_sinfo.sock); - - return(0); -} diff --git a/tests/test_integration_edge.sh.expected b/tests/test_integration_edge.sh.expected new file mode 100644 index 0000000..f8a009f --- /dev/null +++ b/tests/test_integration_edge.sh.expected @@ -0,0 +1,74 @@ +### + +### +[ + { + "community": "test" + } +] + +### +[ + { + "rx_pkt": 0, + "tx_pkt": 2, + "type": "transop" + }, + { + "rx_pkt": 0, + "tx_pkt": 0, + "type": "p2p" + }, + { + "rx_pkt": 0, + "tx_pkt": 2, + "type": "super" + }, + { + "rx_pkt": 0, + "tx_pkt": 2, + "type": "super_broadcast" + } +] + +### +[] + +### +[ + { + "traceLevel": 2 + } +] + +### + +0 +### +[ + { + "traceLevel": 1 + } +] + +### +[ + { + "keep_running": 1 + } +] + +### +[ + { + "keep_running": 0 + } +] + +### +[ + { + "keep_running": 0 + } +] + diff --git a/tests/test_integration_supernode.sh.expected b/tests/test_integration_supernode.sh.expected new file mode 100644 index 0000000..b1d2a78 --- /dev/null +++ b/tests/test_integration_supernode.sh.expected @@ -0,0 +1,64 @@ +### + +### +[ + { + "community": "-/-", + "ip4addr": "", + "is_federation": 1, + "purgeable": 0 + } +] + +### +[ + { + "tx_pkt": 0, + "type": "forward" + }, + { + "tx_pkt": 0, + "type": "broadcast" + }, + { + "nak": 0, + "rx_pkt": 0, + "type": "reg_super" + }, + { + "tx_pkt": 0, + "type": "errors" + } +] + +### +[] + +### +[ + { + "traceLevel": 3 + } +] + +### +[ + { + "traceLevel": 1 + } +] + +### +[ + { + "keep_running": 1 + } +] + +### +[ + { + "keep_running": 0 + } +] + diff --git a/tests/tests-auth.expected b/tests/tests-auth.expected new file mode 100644 index 0000000..51f6637 --- /dev/null +++ b/tests/tests-auth.expected @@ -0,0 +1,31 @@ +bin_to_ascii: input size = 0x10 +000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +bin_to_ascii: output: 00420mG51WS82GeB30qE3m + +ascii_to_bin: input = 00420mG51WS82GeB30qE3m +ascii_to_bin: output: +000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | | + +generate_private_key: input = 00420mG51WS82GeB30qE3m +generate_private_key: output: +000: a4 f4 b5 1c 8a 0a 09 f9 7e 98 22 ca 8a cc b3 f9 | ~ " | +010: 4d 5a 0d 02 0b 9d 08 ea 03 9b 46 41 8e 3c 0d 49 |MZ FA < I| + +generate_public_key: input: +000: a4 f4 b5 1c 8a 0a 09 f9 7e 98 22 ca 8a cc b3 f9 | ~ " | +010: 4d 5a 0d 02 0b 9d 08 ea 03 9b 46 41 8e 3c 0d 49 |MZ FA < I| +generate_public_key: output: +000: ca 58 61 6f f9 25 d0 cd 1d a5 62 48 a0 15 5e ad | Xao % bH ^ | +010: a9 f3 5c 10 5f 20 b6 42 b0 a9 7c 1e 0e d7 e9 4b | \ _ B | K| + +generate_shared_secret: input: prv +000: a4 f4 b5 1c 8a 0a 09 f9 7e 98 22 ca 8a cc b3 f9 | ~ " | +010: 4d 5a 0d 02 0b 9d 08 ea 03 9b 46 41 8e 3c 0d 49 |MZ FA < I| +generate_shared_secret: input: pub +000: ca 58 61 6f f9 25 d0 cd 1d a5 62 48 a0 15 5e ad | Xao % bH ^ | +010: a9 f3 5c 10 5f 20 b6 42 b0 a9 7c 1e 0e d7 e9 4b | \ _ B | K| +generate_shared_secret: output: +000: 5d 94 7b 0b db 54 e8 70 8a 09 b0 db 6f 0b 0d 31 |] { T p o 1| +010: 1b b8 5f ba 57 74 34 bd 3b c5 c4 6c d5 ae a4 84 | _ Wt4 ; l | + diff --git a/tests/tests-compress.expected b/tests/tests-compress.expected new file mode 100644 index 0000000..6360547 --- /dev/null +++ b/tests/tests-compress.expected @@ -0,0 +1,44 @@ +original: input size = 0x200 +000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +010: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +020: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +030: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +040: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +050: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +060: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +070: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +080: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +090: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0a0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0b0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0c0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0d0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0e0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0f0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +100: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +110: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +120: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +130: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +140: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +150: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +160: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +170: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +180: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +190: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1a0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1b0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1c0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1d0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1e0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1f0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | + +lzo1x: output size = 0x2f +000: 0d 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e | | +010: 0f 20 00 bc 3c 00 00 02 0c 0d 0e 0f 00 01 02 03 | < | +020: 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 11 00 00 | | + +zstd: output size = 0x21 +000: 28 b5 2f fd 60 00 01 bd 00 00 80 00 01 02 03 04 |( / ` | +010: 05 06 07 08 09 0a 0b 0c 0d 0e 0f 01 00 da 47 9d | G | +020: 4b |K| + diff --git a/tests/tests-elliptic.expected b/tests/tests-elliptic.expected new file mode 100644 index 0000000..c60ce1b --- /dev/null +++ b/tests/tests-elliptic.expected @@ -0,0 +1,11 @@ +environment: input +000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | | +010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 | | +environment: key +000: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 |UUUUUUUUUUUUUUUU| +010: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 |UUUUUUUUUUUUUUUU| + +curve25519: output +000: 7f 42 1b f9 34 5a 59 84 4a 30 bc 53 64 74 fa 7c | B 4ZY J0 Sdt || +010: 15 81 77 a4 4d 34 6d 2f 8b c1 8c 05 d6 a9 44 54 | w M4m/ DT| + diff --git a/tests/tests-hashing.expected b/tests/tests-hashing.expected new file mode 100644 index 0000000..ed2eac0 --- /dev/null +++ b/tests/tests-hashing.expected @@ -0,0 +1,47 @@ +environment: input size = 0x200 +000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +010: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +020: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +030: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +040: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +050: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +060: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +070: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +080: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +090: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0a0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0b0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0c0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0d0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0e0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0f0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +100: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +110: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +120: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +130: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +140: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +150: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +160: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +170: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +180: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +190: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1a0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1b0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1c0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1d0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1e0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1f0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | + +pearson_hash_256: output: +000: 40 09 5c ca 28 6b fb 93 4c 4a f7 c0 79 a8 04 5a |@ \ (k LJ y Z| +010: b5 3d cf b3 a7 ed 18 56 b2 d9 8f a8 2e a1 08 be | = V . | + +pearson_hash_128: output: +000: b5 3d cf b3 a7 ed 18 56 b2 d9 8f a8 2e a1 08 be | = V . | + +pearson_hash_64: output = 0xb2d98fa82ea108be + +pearson_hash_32: output = 0x2ea108be + +pearson_hash_16: output = 0x8be + diff --git a/tests/tests-transform.expected b/tests/tests-transform.expected new file mode 100644 index 0000000..adafb4e --- /dev/null +++ b/tests/tests-transform.expected @@ -0,0 +1,240 @@ +environment: community_name = "abc123def456" +environment: encrypt_key = "SoMEVer!S$cUREPassWORD" +environment: input size = 0x200 +000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +010: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +020: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +030: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +040: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +050: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +060: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +070: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +080: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +090: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0a0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0b0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0c0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0d0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0e0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +0f0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +100: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +110: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +120: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +130: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +140: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +150: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +160: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +170: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +180: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +190: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1a0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1b0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1c0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1d0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1e0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | +1f0: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | | + +null: output size = 0x226 +000: 03 02 00 03 61 62 63 31 32 33 64 65 66 34 35 36 | abc123def456| +010: 00 00 00 00 00 00 00 00 00 01 02 03 04 05 00 01 | | +020: 02 03 04 05 00 00 00 01 02 03 04 05 06 07 08 09 | | +030: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +040: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +050: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +060: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +070: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +080: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +090: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +0a0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +0b0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +0c0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +0d0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +0e0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +0f0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +100: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +110: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +120: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +130: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +140: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +150: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +160: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +170: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +180: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +190: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +1a0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +1b0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +1c0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +1d0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +1e0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +1f0: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +200: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +210: 0a 0b 0c 0d 0e 0f 00 01 02 03 04 05 06 07 08 09 | | +220: 0a 0b 0c 0d 0e 0f | | + +tf: output size = 0x236 +000: 03 02 00 03 61 62 63 31 32 33 64 65 66 34 35 36 | abc123def456| +010: 00 00 00 00 00 00 00 00 00 01 02 03 04 05 00 01 | | +020: 02 03 04 05 00 00 69 54 ba b7 b9 00 7e 1f 4e 43 | iT ~ NC| +030: 6b 6e c0 b7 5a bb e1 6a 7d 8b f6 41 9e fb 7e c1 |kn Z j} A ~ | +040: a8 6c 67 6b c7 27 17 32 9b 89 f2 5d 1d 67 49 de | lgk ' 2 ] gI | +050: ab 5c d4 b7 a1 97 99 76 7d 90 8d 2c 7c 0d 65 66 | \ v} ,| ef| +060: d5 7f 1a 3b bf 0c 52 b3 42 0d c8 c8 0d 62 8e 4b | ; R B b K| +070: 98 7b bc 0d 9c db bf 61 dc 9d 9f 44 a4 fc 8d 1a | { a D | +080: 70 f0 14 87 89 0e 4a b8 7e 66 72 7a 04 6e 9b 17 |p J ~frz n | +090: e1 2c 06 ce 52 04 2a a0 0f 7f 76 f4 5c c5 e2 09 | , R * v \ | +0a0: f6 35 ff ad 87 ab 72 5a 6f bc 61 78 f6 3c 48 e2 | 5 rZo ax | +1a0: a7 fc d2 83 5b 61 b1 e0 fd 28 d1 ec 65 a2 cf 6c | [a ( e l| +1b0: ef 3b ad cc 75 e3 f9 71 0f 90 71 a6 bc 1a d5 17 | ; u q q | +1c0: 65 64 3e 0c d2 c8 de bd 1f d5 af 84 fc fe aa bd |ed> | +1d0: c5 88 13 af 09 ee 8c c0 38 49 79 09 a7 7a 01 48 | 8Iy z H| +1e0: 2e 3e 9a 38 1b c6 b8 c0 a9 4e 61 0f 19 2a 95 84 |.> 8 Na * | +1f0: 3b 53 1c db 9a ec af 8f 2d af 73 d5 cc 71 bd 42 |;S - s q B| +200: 4f e2 70 ca 45 b6 44 18 54 fe 6b 23 31 ba f4 b1 |O p E D T k#1 | +210: 02 a1 26 4f f1 a9 c0 78 e6 3b 11 9e d6 3c 61 e5 | &O x ; e 9 | +150: c2 4c 3d 3e 73 a7 15 fc 28 6c a6 e5 8b 16 bd c9 | L=>s (l | +160: e2 c9 5e d9 64 8e bc f5 92 a4 e5 74 04 cb 9c 90 | ^ d t | +170: 0c 10 28 5f 30 10 61 b7 44 50 b1 f9 3e 21 a1 41 | (_0 a DP >! A| +180: c2 e2 a5 e9 f7 33 16 52 32 61 d1 a3 c5 0b 61 d4 | 3 R2a a | +190: 53 0f 65 a8 d9 e1 fb e1 9b 1b 61 16 d1 75 0a 4b |S e a u K| +1a0: 9a 9f d1 f3 4e f6 ca b2 a2 24 50 8b 10 4d 45 54 | N $P MET| +1b0: 3d e1 c2 8f 07 52 67 52 7e d1 7f 99 3c 4e de eb |= RgR~ g|[2 6. | +080: 74 50 9f a3 de 38 4e c7 ca 6b 35 7c 1b 4e 39 ea |tP 8N k5| N9 | +090: 5f e2 8a 80 d9 58 6e 14 32 bf 8e e9 a2 b0 19 8a |_ Xn 2 | +0a0: e1 1d da fa 3f 4a b7 1c 03 e0 e3 17 85 54 84 c8 | ?J T | +0b0: 3e 90 8e 85 5b e7 12 3d 73 9e b9 ef 7e 48 c0 55 |> [ =s ~H U| +0c0: 59 28 29 f4 d1 12 62 b3 b3 db 65 0a 6c 8c 44 be |Y() b e l D | +0d0: e2 76 49 e6 b6 4a 9e 7e 9c 49 c9 10 d3 dc 85 33 | vI J ~ I 3| +0e0: fe eb a5 dc 5e 18 cf dc 9a 99 da bc 5c 9f c1 ff | ^ \ | +0f0: 9c 92 3b a9 9d d6 5d 03 f4 f3 5e a9 52 21 d2 d0 | ; ] ^ R! | +100: 8b 4e 8a b6 06 af 4e 34 98 e2 bc 9b c2 f1 9d 72 | N N4 r| +110: f8 0f f3 d5 83 34 7d 47 fe bf 6c 1d c2 d3 89 a4 | 4}G l | +120: ff 5b 76 3c cb 9b 4d 09 a6 3a a2 2f 0b 8d 7a 34 | [v< M : / z4| +130: 12 d5 73 c4 bc ba 13 76 e7 69 50 6d 50 ab 76 b5 | s v iPmP v | +140: a6 fb b4 fb c7 98 3d ac ce e1 e1 98 97 9f 24 98 | = $ | +150: 90 82 61 00 38 57 b0 36 7d 55 a7 70 9c ee 51 26 | a 8W 6}U p Q&| +160: 47 02 4f b5 fe cc 2c e0 07 c6 7b 04 6d a1 89 dc |G O , { m | +170: e8 98 71 fd 27 54 d1 f1 2d 0b 3e 64 ef 02 74 71 | q 'T - >d tq| +180: db f5 b1 84 87 6d c9 37 c5 c3 3a de ea 1b 53 d3 | m 7 : S | +190: f1 ed 8f 24 2d 74 a3 77 23 20 9b 75 c3 f2 ef 4a | $-t w# u J| +1a0: 75 ec d3 86 59 11 c5 fc b0 ed 79 b0 8e a8 03 c8 |u Y y | +1b0: 3e 05 db b0 65 62 53 e5 ef e7 95 88 ce 62 89 7a |> ebS b z| +1c0: 9d 3c bc ea a4 3a f6 df 1d 10 8a a3 80 7c 3b 80 | < : |; | +1d0: be 0a 27 76 2b bc 7d 02 98 bf b7 5e 4a 4c 53 df | 'v+ } ^JLS | +1e0: 57 ff 67 7e 33 6a 00 4c ff d6 c0 ff 3f 1c 24 f7 |W g~3j L ? $ | +1f0: fb fd 3b d2 4f 18 e3 9d 62 5b 9b 15 68 13 44 d8 | ; O b[ h D | +200: 71 79 9d b1 ab 2f bd f3 44 6b 77 96 b8 44 bc 90 |qy / Dkw D | +210: 1f 74 db d2 73 7d 5d 44 f7 a6 92 4e fa 24 e3 92 | t s}]D N $ | +220: c8 34 c7 1d 16 8b f5 80 d9 15 48 24 12 16 14 76 | 4 H$ v| +230: 15 5f d0 dc 1e 9c | _ | + +speck: output size = 0x236 +000: 03 02 00 03 61 62 63 31 32 33 64 65 66 34 35 36 | abc123def456| +010: 00 00 00 00 00 00 00 00 00 01 02 03 04 05 00 01 | | +020: 02 03 04 05 00 00 69 c2 17 4a ab 55 f3 8d 44 17 | i J U D | +030: 2c 31 09 b5 b0 2f 0c 87 f2 05 13 59 34 49 72 45 |,1 / Y4IrE| +040: 2c 79 51 cf 39 f5 ce 0e b9 fc c8 41 31 08 e9 a5 |,yQ 9 A1 | +050: 54 3c aa 77 aa 29 10 41 4a 16 4b e9 89 8f 92 7b |T< w ) AJ K {| +060: 29 b3 0b 4b 84 92 2a 3a fe bd c0 50 75 fc a4 7e |) K *: Pu ~| +070: 4e 20 2e 3b 53 eb d1 37 43 35 b6 5e 55 a6 5e 0e |N .;S 7C5 ^U ^ | +080: e3 05 db 07 5f a8 74 4d 9f 41 ed 5f 44 93 98 9b | _ tM A _D | +090: fb 48 3c 9c 36 8b a6 71 ed ee f4 e6 10 21 b1 b5 | H< 6 q ! | +0a0: f4 b7 28 db d5 5d 43 3d 4b 8d 1a 33 cf c5 54 09 | ( ]C=K 3 T | +0b0: b6 9d f5 f2 27 2f e7 be dd 4c 3c 5c c8 71 ca 71 | '/ L<\ q q| +0c0: 8c 47 37 21 6c ad 3f d6 9a 99 ab 18 fc d8 1b c7 | G7!l ? | +0d0: 72 c2 7d fb 57 8c 97 4f 77 4c 6c 94 4a ab f4 94 |r } W OwLl J | +0e0: d8 e3 02 e2 b9 bf 12 47 fb 53 aa b8 4a 93 38 c6 | G S J 8 | +0f0: bb 8b 27 8b d6 db f3 e4 e3 43 7e 7f 83 cf c9 df | ' C~ | +100: e5 71 b9 80 9c ad 38 e5 10 aa 99 ad e1 0d 34 6f | q 8 4o| +110: de 7e ff 29 cc fe b5 89 49 a9 a1 b5 9e 9f be 5e | ~ ) I ^| +120: e6 d2 74 2c 57 91 86 40 02 a0 7b 6b 42 6e b0 63 | t,W @ {kBn c| +130: 0e 04 19 7c f0 e5 ff 3d db de e3 c5 fc 70 18 7d | | = p }| +140: 06 33 7e 6a bb 46 3b 94 28 85 87 51 9f 6e 95 22 | 3~j F; ( Q n "| +150: 99 b4 34 bd 29 94 3a a8 a4 ff 5b 19 53 69 cb e5 | 4 ) : [ Si | +160: a6 0c 41 c5 22 89 82 a7 a5 f3 f3 49 ed 5d ce f3 | A " I ] | +170: a7 ee 77 dd a9 aa 26 5b 85 ec b1 6e f4 33 a0 b8 | w &[ n 3 | +180: 93 2a 80 6f 3f 5f 0a ff 1b 72 14 5d 4f 1a cc 74 | * o?_ r ]O t| +190: 69 01 da 81 7d 89 4b 0f 68 fe c6 c5 ae 39 86 1d |i } K h 9 | +1a0: ab e3 c7 35 2e 5d a8 3d 56 3e 26 52 74 72 5b f2 | 5.] =V>&Rtr[ | +1b0: 41 1a 7a 04 d9 d0 65 fe 92 c4 b9 be 75 e5 9e e1 |A z e u | +1c0: 8e 52 f4 27 98 44 61 26 7f 6b 96 0c c4 6a a6 6b | R ' Da& k j k| +1d0: 36 66 81 a1 f6 dd ab 2a a7 63 e5 7f 63 67 79 08 |6f * c cgy | +1e0: ba 7b bb 11 12 9c 14 b2 a4 2b 56 66 14 c1 54 c6 | { +Vf T | +1f0: 96 f0 e4 68 8a 5c 11 b6 27 af 61 ef ab 47 9e 7f | h \ ' a G | +200: 76 0e 39 c3 fb 88 94 29 7c 9e 96 9b e5 e1 6b ae |v 9 )| k | +210: 87 03 a4 86 a2 1f 91 cf 90 1c 11 08 57 bc c7 90 | W | +220: 0b c1 51 2e 28 a6 58 96 e2 e7 f2 20 c6 ac 06 05 | Q.( X | +230: 39 75 4a 56 cf f8 |9uJV | + +lzo: output size = 0x55 +000: 03 02 00 03 61 62 63 31 32 33 64 65 66 34 35 36 | abc123def456| +010: 00 00 00 00 00 00 00 00 00 01 02 03 04 05 00 01 | | +020: 02 03 04 05 00 00 0d 00 01 02 03 04 05 06 07 08 | | +030: 09 0a 0b 0c 0d 0e 0f 20 00 bc 3c 00 00 02 0c 0d | < | +040: 0e 0f 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d | | +050: 0e 0f 11 00 00 | | + +zstd: output size = 0x47 +000: 03 02 00 03 61 62 63 31 32 33 64 65 66 34 35 36 | abc123def456| +010: 00 00 00 00 00 00 00 00 00 01 02 03 04 05 00 01 | | +020: 02 03 04 05 00 00 28 b5 2f fd 60 00 01 bd 00 00 | ( / ` | +030: 80 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e | | +040: 0f 01 00 da 47 9d 4b | G K| + diff --git a/tests/tests-wire.expected b/tests/tests-wire.expected new file mode 100644 index 0000000..e4ba9de --- /dev/null +++ b/tests/tests-wire.expected @@ -0,0 +1,51 @@ +environment: common.ttl = 2 +environment: common.flags = 0 +environment: common.community = "abc123def456z" + +REGISTER: common.pc = 1 +REGISTER: reg.cookie = 0 +REGISTER: reg.srcMac[] = 0:1:2:3:4:5 +REGISTER: reg.dstMac[] = 10:11:12:13:14:15 +REGISTER: reg.dev_addr.net_addr = 0x20212223 +REGISTER: reg.dev_addr.net_bitlen = 25 +REGISTER: reg.dev_desc = "Dummy_Dev_Desc" + +REGISTER: output retval = 0x24 +REGISTER: output idx = 0x3d +000: 03 02 00 01 61 62 63 31 32 33 64 65 66 34 35 36 | abc123def456| +010: 7a 00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 |z | +020: 04 05 10 11 12 13 14 15 20 21 22 23 19 44 75 6d | !"# Dum| +030: 6d 79 5f 44 65 76 5f 44 65 73 63 00 00 |my_Dev_Desc | + +REGISTER_SUPER: common.pc = 5 +REGISTER_SUPER: reg.cookie = 0 +REGISTER_SUPER: reg.edgeMac[] = 20:21:22:23:24:25 +REGISTER_SUPER: reg.dev_addr.net_addr = 0x20212223 +REGISTER_SUPER: reg.dev_addr.net_bitlen = 25 +REGISTER_SUPER: reg.dev_desc = "Dummy_Dev_Desc" +REGISTER_SUPER: reg.auth.scheme = 1 +REGISTER_SUPER: reg.auth.token_size = 16 +REGISTER_SUPER: reg.auth.token[0] = 0xfe +REGISTER_SUPER: reg.key_time = 600 + +REGISTER_SUPER: output retval = 0x36 +REGISTER_SUPER: output idx = 0x4f +000: 03 02 00 05 61 62 63 31 32 33 64 65 66 34 35 36 | abc123def456| +010: 7a 00 00 00 00 00 00 00 00 00 00 00 20 21 22 23 |z !"#| +020: 24 25 20 21 22 23 19 44 75 6d 6d 79 5f 44 65 76 |$% !"# Dummy_Dev| +030: 5f 44 65 73 63 00 00 00 01 00 10 fe 00 00 00 fd |_Desc | +040: 00 00 00 fc 00 00 00 00 00 00 fb 00 00 02 58 | X| + +UNREGISTER_SUPER: common.pc = 6 +UNREGISTER_SUPER: unreg.auth.scheme = 1 +UNREGISTER_SUPER: unreg.auth.token_size = 16 +UNREGISTER_SUPER: unreg.auth.token[0] = 0xfe +UNREGISTER_SUPER: unreg.srcMac[] = 30:31:32:33:34:35 + +UNREGISTER_SUPER: output retval = 0x19 +UNREGISTER_SUPER: output idx = 0x32 +000: 03 02 00 06 61 62 63 31 32 33 64 65 66 34 35 36 | abc123def456| +010: 7a 00 00 00 00 00 00 00 00 01 00 10 fe 00 00 00 |z | +020: fd 00 00 00 fc 00 00 00 00 00 00 fb 30 31 32 33 | 0123| +030: 34 35 |45| + diff --git a/tests/tests_integration.list b/tests/tests_integration.list new file mode 100644 index 0000000..ff7ffcc --- /dev/null +++ b/tests/tests_integration.list @@ -0,0 +1,5 @@ +# +# The integration tests + +test_integration_supernode.sh +test_integration_edge.sh diff --git a/tests/tests_units.list b/tests/tests_units.list new file mode 100644 index 0000000..6491c1b --- /dev/null +++ b/tests/tests_units.list @@ -0,0 +1,9 @@ +# +# The unit tests + +tests-auth +tests-compress +tests-elliptic +tests-hashing +tests-transform +tests-wire diff --git a/tools/Makefile.in b/tools/Makefile.in new file mode 100644 index 0000000..4241c15 --- /dev/null +++ b/tools/Makefile.in @@ -0,0 +1,43 @@ +# +# This is not a standalone makefile, it must be called from the toplevel +# makefile to inherit the correct environment + +DEBUG?=-g3 + +HEADERS=$(wildcard include/*.h) +CFLAGS+=-I../include +ifeq ($(CONFIG_TARGET),mingw) +CFLAGS+=-I../win32 +endif +CFLAGS+=$(DEBUG) +LDFLAGS+=-L.. + +N2N_LIB=../libn2n.a + +TOOLS=n2n-benchmark n2n-keygen +TOOLS+=@ADDITIONAL_TOOLS@ + +TESTS=tests-compress tests-elliptic tests-hashing tests-transform +TESTS+=tests-wire +TESTS+=tests-auth + +.PHONY: all clean install +all: $(TOOLS) $(TESTS) + +n2n-benchmark.o: $(N2N_LIB) $(HEADERS) ../Makefile Makefile +n2n-keygen.o: $(N2N_LIB) $(HEADERS) ../Makefile Makefile + +n2n-decode: n2n-decode.c $(N2N_LIB) $(HEADERS) ../Makefile Makefile + $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDLIBS) -lpcap -o $@ + +# See comments in the topdir Makefile about how to generate coverage +# data. +gcov: + gcov $(TOOLS) $(TESTS) + +clean: + rm -rf $(TOOLS) *.o *.dSYM *~ + rm -f $(TESTS) *.gcno *.gcda + +install: $(TOOLS) + $(INSTALL_PROG) $(TOOLS) $(SBINDIR)/ diff --git a/tools/n2n-benchmark.c b/tools/n2n-benchmark.c new file mode 100644 index 0000000..b4a3c95 --- /dev/null +++ b/tools/n2n-benchmark.c @@ -0,0 +1,281 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + +#ifndef _MSC_VER +/* MinGW has undefined function gettimeofday() warnings without this header + * but Visual C++ doesnt even have the header */ +#include +#endif + +#include "n2n.h" + +#define DURATION 2.5 // test duration per algorithm +#define PACKETS_BEFORE_GETTIME 2047 // do not check time after every packet but after (2 ^ n - 1) + + +uint8_t PKT_CONTENT[DEFAULT_MTU]; + +/* Prototypes */ +static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c ); +static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2n_edge_conf_t *conf, uint8_t *pktbuf); +static void run_hashing_benchmark(void); +static void run_ecc_benchmark(void); + + +int main(int argc, char * argv[]) { + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t i; + + n2n_trans_op_t transop_null, transop_tf; + n2n_trans_op_t transop_aes; + n2n_trans_op_t transop_cc20; + n2n_trans_op_t transop_lzo; +#ifdef HAVE_ZSTD + n2n_trans_op_t transop_zstd; +#endif + + n2n_trans_op_t transop_speck; + n2n_edge_conf_t conf; + + print_n2n_version(); + + /* Init configuration */ + edge_init_conf_defaults(&conf); + + strncpy((char*)conf.community_name, "abc123def456", sizeof(conf.community_name)); + conf.encrypt_key = "SoMEVer!S$cUREPassWORD"; + + pearson_hash_init(); + + /* Init transops */ + n2n_transop_null_init(&conf, &transop_null); + n2n_transop_tf_init(&conf, &transop_tf); + n2n_transop_aes_init(&conf, &transop_aes); + n2n_transop_cc20_init(&conf, &transop_cc20); + n2n_transop_speck_init(&conf, &transop_speck); + n2n_transop_lzo_init(&conf, &transop_lzo); +#ifdef HAVE_ZSTD + n2n_transop_zstd_init(&conf, &transop_zstd); +#endif + + /* Setup packet content */ + for (i = 0; i < sizeof(PKT_CONTENT) / sizeof(PKT_CONTENT[0]); i++) { + PKT_CONTENT[i] = i & 0x0f; + } + + /* Run the tests */ + run_transop_benchmark("null", &transop_null, &conf, pktbuf); + run_transop_benchmark("tf", &transop_tf, &conf, pktbuf); + run_transop_benchmark("aes", &transop_aes, &conf, pktbuf); + run_transop_benchmark("cc20", &transop_cc20, &conf, pktbuf); + run_transop_benchmark("speck", &transop_speck, &conf, pktbuf); + run_transop_benchmark("lzo1x", &transop_lzo, &conf, pktbuf); +#ifdef HAVE_ZSTD + run_transop_benchmark("zstd", &transop_zstd, &conf, pktbuf); +#endif + + run_ecc_benchmark(); + + run_hashing_benchmark(); + + /* Cleanup */ + transop_null.deinit(&transop_null); + transop_tf.deinit(&transop_tf); + transop_aes.deinit(&transop_aes); + transop_cc20.deinit(&transop_cc20); + transop_speck.deinit(&transop_speck); + transop_lzo.deinit(&transop_lzo); +#ifdef HAVE_ZSTD + transop_zstd.deinit(&transop_zstd); +#endif + return 0; +} + +// --- hashing benchmark ------------------------------------------------------------------ + +static void run_hashing_benchmark(void) { + const float target_sec = DURATION; + struct timeval t1; + struct timeval t2; + ssize_t nw; + ssize_t target_usec = target_sec * 1e6; + ssize_t tdiff = 0; // microseconds + size_t num_packets = 0; + + uint64_t hash; + + printf("(%s)\t%s\t%.1f sec\t(%u bytes)", + "prs64", "hash", target_sec, (unsigned int)sizeof(PKT_CONTENT)); + fflush(stdout); + + gettimeofday( &t1, NULL ); + nw = 8; + + while(tdiff < target_usec) { + hash = pearson_hash_64(PKT_CONTENT, sizeof(PKT_CONTENT)); + hash++; // clever compiler finds out that we do no use the variable + num_packets++; + if (!(num_packets & PACKETS_BEFORE_GETTIME)) { + gettimeofday( &t2, NULL ); + tdiff = ((t2.tv_sec - t1.tv_sec) * 1000000) + (t2.tv_usec - t1.tv_usec); + } + } + + float mpps = num_packets / (tdiff / 1e6) / 1e6; + + printf(" ---> (%u bytes)\t%12u packets\t%8.1f Kpps\t%8.1f MB/s\n", + (unsigned int)nw, (unsigned int)num_packets, mpps * 1e3, mpps * sizeof(PKT_CONTENT)); + printf("\n"); +} + +// --- ecc benchmark ---------------------------------------------------------------------- + +static void run_ecc_benchmark(void) { + const float target_sec = DURATION; + struct timeval t1; + struct timeval t2; + ssize_t nw; + ssize_t target_usec = target_sec * 1e6; + ssize_t tdiff = 0; // microseconds + size_t num_packets = 0; + + unsigned char b[32]; + unsigned char k[32]; + + memset(b, 0x00, 31); + b[31] = 9; + + memset(k, 0x55, 32); + + printf("[%s]\t%s\t%.1f sec\t(%u bytes) ", + "curve", "25519", target_sec, 32); + fflush(stdout); + + gettimeofday( &t1, NULL ); + nw = 32; + + while(tdiff < target_usec) { + curve25519(b, k, b); + num_packets++; + gettimeofday( &t2, NULL ); + tdiff = ((t2.tv_sec - t1.tv_sec) * 1000000) + (t2.tv_usec - t1.tv_usec); + } + + float mpps = num_packets / (tdiff / 1e6) / 1e6; + + printf(" ---> (%u bytes)\t%12u ops\t%8.1f Kops/s\n", + (unsigned int)nw, (unsigned int)num_packets, mpps * 1e3); + printf("\n"); +} + +// --- transop benchmark ------------------------------------------------------------------ + +static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2n_edge_conf_t *conf, uint8_t *pktbuf) { + n2n_common_t cmn; + n2n_PACKET_t pkt; + n2n_mac_t mac_buf; + uint8_t decodebuf[N2N_PKT_BUF_SIZE]; + const float target_sec = DURATION; + struct timeval t1; + struct timeval t2; + size_t idx; + size_t rem; + size_t nw; + ssize_t target_usec = target_sec * 1e6; + ssize_t tdiff; // microseconds + size_t num_packets; + float mpps; + + // encryption + printf("[%s]\t%s\t%.1f sec\t(%u bytes)", + op_name, "encrypt" , target_sec, (unsigned int)sizeof(PKT_CONTENT)); + fflush(stdout); + memset(mac_buf, 0, sizeof(mac_buf)); + num_packets = 0; + tdiff = 0; + gettimeofday( &t1, NULL ); + while(tdiff < target_usec) { + nw = do_encode_packet( pktbuf, N2N_PKT_BUF_SIZE, conf->community_name); + nw += op_fn->fwd(op_fn, + pktbuf+nw, N2N_PKT_BUF_SIZE-nw, + PKT_CONTENT, sizeof(PKT_CONTENT), mac_buf); + num_packets++; + if (!(num_packets & PACKETS_BEFORE_GETTIME)) { + gettimeofday( &t2, NULL ); + tdiff = ((t2.tv_sec - t1.tv_sec) * 1000000) + (t2.tv_usec - t1.tv_usec); + } + } + mpps = num_packets / (tdiff / 1e6) / 1e6; + printf(" ---> (%u bytes)\t%12u packets\t%8.1f Kpps\t%8.1f MB/s\n", + (unsigned int)nw, (unsigned int)num_packets, mpps * 1e3, mpps * sizeof(PKT_CONTENT)); + + // decrpytion + printf("\t%s\t%.1f sec\t(%u bytes)", + "decrypt" , target_sec, (unsigned int)sizeof(PKT_CONTENT)); + fflush(stdout); + num_packets = 0; + tdiff = 0; + gettimeofday( &t1, NULL ); + while(tdiff < target_usec) { + idx=0; + rem=nw; + decode_common( &cmn, pktbuf, &rem, &idx); + decode_PACKET( &pkt, &cmn, pktbuf, &rem, &idx ); + op_fn->rev(op_fn, decodebuf, N2N_PKT_BUF_SIZE, pktbuf+idx, rem, 0); + num_packets++; + if (!(num_packets & PACKETS_BEFORE_GETTIME)) { + gettimeofday( &t2, NULL ); + tdiff = ((t2.tv_sec - t1.tv_sec) * 1000000) + (t2.tv_usec - t1.tv_usec); + } + } + mpps = num_packets / (tdiff / 1e6) / 1e6; + printf(" <--- (%u bytes)\t%12u packets\t%8.1f Kpps\t%8.1f MB/s\n", + (unsigned int)nw, (unsigned int)num_packets, mpps * 1e3, mpps * sizeof(PKT_CONTENT)); + if(memcmp(decodebuf, PKT_CONTENT, sizeof(PKT_CONTENT)) != 0) + printf("\tpayload decryption failed!\n"); + printf("\n"); +} + + +static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c ) +{ + n2n_mac_t destMac={0,1,2,3,4,5}; + n2n_common_t cmn; + n2n_PACKET_t pkt; + size_t idx; + + + memset( &cmn, 0, sizeof(cmn) ); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_packet; + cmn.flags=0; /* no options, not from supernode, no socket */ + memcpy( cmn.community, c, N2N_COMMUNITY_SIZE ); + + memset( &pkt, 0, sizeof(pkt) ); + memcpy( pkt.srcMac, destMac, N2N_MAC_SIZE); + memcpy( pkt.dstMac, destMac, N2N_MAC_SIZE); + + pkt.sock.family=0; /* do not encode sock */ + + idx=0; + encode_PACKET( pktbuf, &idx, &cmn, &pkt ); + traceEvent( TRACE_DEBUG, "encoded PACKET header of size=%u", (unsigned int)idx ); + + return idx; +} diff --git a/tools/n2n-decode.c b/tools/n2n-decode.c new file mode 100644 index 0000000..94b14d6 --- /dev/null +++ b/tools/n2n-decode.c @@ -0,0 +1,371 @@ +/** + * (C) 2019-22 - ntop.org and contributors + * + * 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 see + * + */ + +#include +#include "n2n.h" + +#define SNAPLEN 1500 +#define TIMEOUT 200 + +/* *************************************************** */ + +static int aes_mode = 0; +static int running = 1; +static char *ifname = NULL; +static n2n_edge_conf_t conf; +static n2n_trans_op_t transop; +static pcap_t *handle; +static pcap_dumper_t *dumper; + +/* *************************************************** */ + +static void help() { + fprintf(stderr, "n2n-decode -i ifname -k key -c community [-B bpf] [-w fname] [-v]" +#ifdef N2N_HAVE_AES + " [-A]" +#endif + "\n"); + fprintf(stderr, "-i | Specify the capture interface name.\n"); + fprintf(stderr, "-c | Specify the community.\n"); + fprintf(stderr, "-k | Specify the encryption key.\n"); +#ifdef N2N_HAVE_AES + fprintf(stderr, "-A | Use AES decryption (default=use twofish).\n"); +#endif + fprintf(stderr, "-B | Use set a BPF filter for the capture.\n"); + fprintf(stderr, "-w | Write decoded PCAP to file.\n"); + fprintf(stderr, "-v | Increase verbosity level.\n"); + + exit(0); +} + +/* *************************************************** */ + +#ifdef WIN32 +BOOL WINAPI term_handler(DWORD sig) +#else +static void term_handler(int sig) +#endif +{ + static int called = 0; + + if(called) { + traceEvent(TRACE_NORMAL, "Ok I am leaving now"); + _exit(0); + } else { + traceEvent(TRACE_NORMAL, "Shutting down..."); + called = 1; + } + + running = 0; +#ifdef WIN32 + return(TRUE); +#endif +} + +/* *************************************************** */ + +static void write_packet(const u_char *packet, struct pcap_pkthdr *hdr) { + pcap_dump((unsigned char*)dumper, hdr, packet); + pcap_dump_flush(dumper); +} + +/* *************************************************** */ + +static int decode_encrypted_packet(const u_char *packet, struct pcap_pkthdr *header, + n2n_PACKET_t *pkt, int encrypted_offset) { + uint8_t decoded_packet[encrypted_offset + N2N_PKT_BUF_SIZE]; + int decoded_eth_size; + int transop_shift; + + switch(pkt->transform) { + case N2N_TRANSFORM_ID_NULL: + /* Not encrypted, dump it */ + write_packet(packet, header); + break; + case N2N_TRANSFORM_ID_TWOFISH: + if(aes_mode) { + traceEvent(TRACE_INFO, "Skipping twofish encrypted packet"); + return(-1); + } + break; + case N2N_TRANSFORM_ID_AES: + if(!aes_mode) { + traceEvent(TRACE_INFO, "Skipping AES encrypted packet"); + return(-1); + } + break; + default: + traceEvent(TRACE_INFO, "Skipping unknown transform packet: %d", pkt->transform); + return(-2); + } + + decoded_eth_size = transop.rev(&transop, decoded_packet+encrypted_offset, N2N_PKT_BUF_SIZE, packet + encrypted_offset, + header->caplen - encrypted_offset, pkt->srcMac); + + transop_shift = (header->caplen - encrypted_offset) - decoded_eth_size; + + if(transop_shift >= 0) { + int transform_id_offset = encrypted_offset - 2; + + /* Copy the initial part of the packet */ + memcpy(decoded_packet, packet, encrypted_offset); + + /* Change the packet transform to NULL as there is now plaintext data */ + *((u_int16_t*)(decoded_packet + transform_id_offset)) = htons(N2N_TRANSFORM_ID_NULL); + + // TODO fix IP and UDP chechsums + write_packet(decoded_packet, header); + return(0); + } + + traceEvent(TRACE_INFO, "Something was wrong in the decoding"); + return(-3); +} + +/* *************************************************** */ + +#define ETH_SIZE 14 +#define UDP_SIZE 8 +#define MIN_IP_SIZE 20 +#define MIN_LEN (ETH_SIZE + UDP_SIZE + MIN_IP_SIZE + sizeof(n2n_common_t)) + +static int run_packet_loop() { + struct pcap_pkthdr header; + const u_char *packet; + + traceEvent(TRACE_NORMAL, "Capturing packets on %s...", ifname); + + while(running) { + n2n_common_t common; + n2n_PACKET_t pkt; + uint ipsize, common_offset; + size_t idx, rem; + + memset(&common, 0, sizeof(common)); + memset(&pkt, 0, sizeof(pkt)); + + packet = pcap_next(handle, &header); + + if(!packet) + continue; + + if(header.caplen < MIN_LEN) { + traceEvent(TRACE_INFO, "Skipping packet too small: size=%d", header.caplen); + continue; + } + + if(ntohs(*(uint16_t*)(packet + 12)) != 0x0800) { + traceEvent(TRACE_INFO, "Skipping non IPv4 packet"); + continue; + } + + if(packet[ETH_SIZE + 9] != IPPROTO_UDP) { + traceEvent(TRACE_INFO, "Skipping non UDP packet"); + continue; + } + + ipsize = (packet[ETH_SIZE] & 0x0F) * 4; + common_offset = ETH_SIZE + ipsize + UDP_SIZE; + + idx = common_offset; + rem = header.caplen - idx; + + if(decode_common(&common, packet, &rem, &idx) == -1) { + traceEvent(TRACE_INFO, "Skipping packet, decode common failed"); + continue; + } + + if(strncmp((char*)conf.community_name, (char*)common.community, N2N_COMMUNITY_SIZE) != 0) { + traceEvent(TRACE_INFO, "Skipping packet with non-matching community"); + continue; + } + + switch(common.pc) { + case n2n_ping: + case n2n_register: + case n2n_deregister: + case n2n_register_ack: + case n2n_register_super: + case n2n_register_super_ack: + case n2n_register_super_nak: + case n2n_federation: + case n2n_peer_info: + case n2n_query_peer: + write_packet(packet, &header); + break; + case n2n_packet: + decode_PACKET(&pkt, &common, packet, &rem, &idx); + decode_encrypted_packet(packet, &header, &pkt, idx); + break; + default: + traceEvent(TRACE_INFO, "Skipping packet with unknown type: %d", common.pc); + continue; + } + } + + return(0); +} + +/* *************************************************** */ + +int main(int argc, char* argv[]) { + u_char c; + struct bpf_program fcode; + char *bpf_filter = NULL, *out_fname = NULL; + char errbuf[PCAP_ERRBUF_SIZE]; + int rv = 0; + FILE *outf = stdout; + + /* Trace to stderr to leave stdout for the PCAP dump if "-w -" is used */ + setTraceFile(stderr); + + /* Init configuration */ + edge_init_conf_defaults(&conf); + + while((c = getopt(argc, argv, + "k:i:B:w:c:v" +#ifdef N2N_HAVE_AES + "A" +#endif + )) != '?') { + if(c == 255) break; + + switch(c) { + case 'c': + strncpy((char*)conf.community_name, optarg, sizeof(conf.community_name)-1); + break; + case 'i': + ifname = strdup(optarg); + break; + case 'k': + conf.encrypt_key = strdup(optarg); + break; + case 'B': + bpf_filter = strdup(optarg); + break; +#ifdef N2N_HAVE_AES + case 'A': + aes_mode = 1; + break; +#endif + case 'w': + if(strcmp(optarg, "-") != 0) + out_fname = strdup(optarg); + break; + case 'v': /* verbose */ + setTraceLevel(getTraceLevel() + 1); + break; + default: + help(); + } + } + + if((ifname == NULL) || (conf.encrypt_key == NULL) || (conf.community_name[0] == '\0')) + help(); + +#ifdef N2N_HAVE_AES + if(aes_mode) + n2n_transop_aes_init(&conf, &transop); + else +#endif + n2n_transop_tf_init(&conf, &transop); + + if((handle = pcap_create(ifname, errbuf)) == NULL) { + traceEvent(TRACE_ERROR, "Cannot open device %s: %s", ifname, errbuf); + return(1); + } + + if((pcap_set_timeout(handle, TIMEOUT) != 0) || + (pcap_set_snaplen(handle, SNAPLEN) != 0)) { + traceEvent(TRACE_ERROR, "Error while setting timeout/snaplen"); + return(1); + } + +#ifdef HAVE_PCAP_IMMEDIATE_MODE + /* The timeout is not honored unless immediate mode is set. + * See https://github.com/mfontanini/libtins/issues/180 */ + if(pcap_set_immediate_mode(handle, 1) != 0) { + traceEvent(TRACE_ERROR, "Could not set PCAP immediate mode"); + return(1); + } +#endif + + if(pcap_activate(handle) != 0) { + traceEvent(TRACE_ERROR, "pcap_activate failed: %s", pcap_geterr(handle)); + } + + if(pcap_datalink(handle) != DLT_EN10MB) { + traceEvent(TRACE_ERROR, "Device %s doesn't provide Ethernet headers - not supported", ifname); + return(2); + } + + if(bpf_filter) { + bpf_u_int32 net, mask; + + if(pcap_lookupnet(ifname, &net, &mask, errbuf) == -1) { + traceEvent(TRACE_WARNING, "Couldn't get netmask for device %s: %s", ifname, errbuf); + net = 0; + mask = 0; + } + + if((pcap_compile(handle, &fcode, bpf_filter, 1, net) < 0) + || (pcap_setfilter(handle, &fcode) < 0)) { + traceEvent(TRACE_ERROR, "Could not set BPF filter: %s", pcap_geterr(handle)); + return(3); + } + } + + if(out_fname) { + outf = fopen(out_fname, "wb"); + + if(outf == NULL) { + traceEvent(TRACE_ERROR, "Could not open %s for write[%d]: %s", errno, strerror(errno)); + return(4); + } + } + + dumper = pcap_dump_fopen(handle, outf); + + if(dumper == NULL) { + traceEvent(TRACE_ERROR, "Could dump file: %s", pcap_geterr(handle)); + return(5); + } + +#ifdef WIN32 + SetConsoleCtrlHandler(term_handler, TRUE); +#else + signal(SIGTERM, term_handler); + signal(SIGINT, term_handler); +#endif + + rv = run_packet_loop(); + + /* Cleanup */ + pcap_close(handle); + + if(conf.encrypt_key) free(conf.encrypt_key); + if(bpf_filter) free(bpf_filter); + if(ifname) free(ifname); + + if(out_fname) { + fclose(outf); + free(out_fname); + } + + return(rv); +} diff --git a/tools/n2n-keygen.c b/tools/n2n-keygen.c new file mode 100644 index 0000000..3ce25f9 --- /dev/null +++ b/tools/n2n-keygen.c @@ -0,0 +1,76 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + + +#include "n2n.h" + + +int main(int argc, char * argv[]) { + + n2n_private_public_key_t prv; /* 32 bytes private key */ + n2n_private_public_key_t bin; /* 32 bytes public key binary output buffer */ + char asc[44]; /* 43 bytes + 0-terminator ascii string output */ + uint8_t fed = 0; + + // exactly two parameters required + if(argc != 3) { + // error message to stderr to not interfere with batch usage + fprintf(stderr, "\n" + "n2n-keygen tool\n\n" + " usage: n2n-keygen \n\n" + " or n2n-keygen -F \n\n" + " outputs a line to insert at supernode's community file for user-and-\n" + " password authentication or a command line parameter with the public\n" + " federation key for use at edge's command line, please refer to the\n" + " doc/Authentication.md document or the man pages for more details\n\n"); + return 1; + } + + // federation mode? + if(strcmp(argv[1], "-F") == 0) + fed = 1; + + // derive private key from username and password: + // hash username once, hash password twice (so password is bound + // to username but username and password are not interchangeable), + // finally xor the result + // in federation mode: only hash federation name, twice + generate_private_key(prv, argv[2]); + + // hash user name only if required + if(!fed) { + bind_private_key_to_username(prv, argv[1]); + } + + // calculate the public key into binary output buffer + generate_public_key(bin, prv); + + // clear out the private key + memset(prv, 0, sizeof(prv)); + + // convert binary output to 6-bit-ascii string output + bin_to_ascii(asc, bin, sizeof(bin)); + + // output + if(fed) + fprintf(stdout, "-P %s\n", asc); + else + fprintf(stdout, "%c %s %s\n", N2N_USER_KEY_LINE_STARTER, argv[1], asc); + + return 0; +} diff --git a/tools/tests-auth.c b/tools/tests-auth.c new file mode 100644 index 0000000..232df6e --- /dev/null +++ b/tools/tests-auth.c @@ -0,0 +1,128 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + +#include + +#include "n2n.h" +#include "hexdump.h" + + +uint8_t PKT_CONTENT1[]={ + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, +}; + +char *PKT_CONTENT2 = "00420mG51WS82GeB30qE3m"; + +void test_bin_to_ascii (void *buf, unsigned int bufsize) { + char *test_name = "bin_to_ascii"; + char out[32]; + + printf("%s: input size = 0x%x\n", test_name, bufsize); + fhexdump(0, buf, bufsize, stdout); + + bin_to_ascii(out, buf, bufsize); + + printf("%s: output: %s\n", test_name, out); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_ascii_to_bin (char *buf) { + char *test_name = "ascii_to_bin"; + uint8_t out[32]; + memset(out, 0, sizeof(out)); + + printf("%s: input = %s\n", test_name, buf); + + ascii_to_bin(out, buf); + // TODO: + // - it would be nice if the function returned the bufsize, + // - or took an allocation size as input + + printf("%s: output:\n", test_name); + fhexdump(0, out, sizeof(out), stdout); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_generate_private_key (char *in, n2n_private_public_key_t prv) { + char *test_name = "generate_private_key"; + + printf("%s: input = %s\n", test_name, in); + + generate_private_key(prv, in); + + printf("%s: output:\n", test_name); + fhexdump(0, prv, sizeof(n2n_private_public_key_t), stdout); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_generate_public_key (n2n_private_public_key_t prv, n2n_private_public_key_t pub) { + char *test_name = "generate_public_key"; + + printf("%s: input:\n", test_name); + fhexdump(0, prv, sizeof(n2n_private_public_key_t), stdout); + + generate_public_key(pub, prv); + + printf("%s: output:\n", test_name); + fhexdump(0, pub, sizeof(n2n_private_public_key_t), stdout); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_generate_shared_secret (n2n_private_public_key_t prv, n2n_private_public_key_t pub) { + char *test_name = "generate_shared_secret"; + n2n_private_public_key_t out; + + printf("%s: input: prv\n", test_name); + fhexdump(0, prv, sizeof(n2n_private_public_key_t), stdout); + printf("%s: input: pub\n", test_name); + fhexdump(0, pub, sizeof(n2n_private_public_key_t), stdout); + + generate_shared_secret(out, prv, pub); + + printf("%s: output:\n", test_name); + fhexdump(0, out, sizeof(out), stdout); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +int main (int argc, char * argv[]) { + + test_bin_to_ascii(PKT_CONTENT1, sizeof(PKT_CONTENT1)); + test_ascii_to_bin(PKT_CONTENT2); + + n2n_private_public_key_t prv; + memset(prv, 0, sizeof(prv)); + n2n_private_public_key_t pub; + memset(pub, 0, sizeof(pub)); + + test_generate_private_key(PKT_CONTENT2, prv); + test_generate_public_key(prv, pub); + test_generate_shared_secret(prv, pub); + + return 0; +} + diff --git a/tools/tests-compress.c b/tools/tests-compress.c new file mode 100644 index 0000000..dded8bc --- /dev/null +++ b/tools/tests-compress.c @@ -0,0 +1,165 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + +#include + +#include + +#include "n2n.h" +#include "hexdump.h" + +/* heap allocation for compression as per lzo example doc */ +#define HEAP_ALLOC(var,size) lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] +static HEAP_ALLOC(wrkmem, LZO1X_1_MEM_COMPRESS); + + +uint8_t PKT_CONTENT[]={ + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 +}; + +static void init_compression_for_benchmark (void) { + + if(lzo_init() != LZO_E_OK) { + traceEvent(TRACE_ERROR, "LZO compression init error"); + exit(1); + } + +#ifdef N2N_HAVE_ZSTD + // zstd does not require initialization. if it were required, this would be a good place +#endif +} + + +static void deinit_compression_for_benchmark (void) { + + // lzo1x does not require de-initialization. if it were required, this would be a good place + +#ifdef N2N_HAVE_ZSTD + // zstd does not require de-initialization. if it were required, this would be a good place +#endif +} + +void test_lzo1x () { + char *test_name = "lzo1x"; + uint8_t compression_buffer[N2N_PKT_BUF_SIZE]; // size allows enough of a reserve required for compression + lzo_uint compression_len = sizeof(compression_buffer); + + if(lzo1x_1_compress(PKT_CONTENT, sizeof(PKT_CONTENT), compression_buffer, &compression_len, wrkmem) != LZO_E_OK) { + fprintf(stderr, "%s: compression error\n", test_name); + exit(1); + } + + assert(compression_len == 47); + + printf("%s: output size = 0x%" PRIx64 "\n", test_name, compression_len); + fhexdump(0, compression_buffer, compression_len, stdout); + + uint8_t deflation_buffer[N2N_PKT_BUF_SIZE]; + lzo_uint deflated_len; + lzo1x_decompress(compression_buffer, compression_len, deflation_buffer, &deflated_len, NULL); + + assert(deflated_len == sizeof(PKT_CONTENT)); + if(memcmp(PKT_CONTENT, deflation_buffer, deflated_len)!=0) { + fprintf(stderr, "%s: round-trip buffer mismatch\n", test_name); + exit(1); + } + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_zstd () { + char *test_name = "zstd"; + +#ifdef N2N_HAVE_ZSTD + uint8_t compression_buffer[N2N_PKT_BUF_SIZE]; // size allows enough of a reserve required for compression + lzo_uint compression_len = sizeof(compression_buffer); + + compression_len = N2N_PKT_BUF_SIZE; + compression_len = ZSTD_compress(compression_buffer, compression_len, PKT_CONTENT, sizeof(PKT_CONTENT), ZSTD_COMPRESSION_LEVEL); + if(ZSTD_isError(compression_len)) { + fprintf(stderr, "%s: compression error\n", test_name); + exit(1); + } + + assert(compression_len == 33); + + printf("%s: output size = 0x%" PRIx64 "\n", test_name, compression_len); + fhexdump(0, compression_buffer, compression_len, stdout); + + uint8_t deflation_buffer[N2N_PKT_BUF_SIZE]; + int64_t deflated_len = sizeof(deflation_buffer); + deflated_len = (int32_t)ZSTD_decompress(deflation_buffer, deflated_len, compression_buffer, compression_len); + if(ZSTD_isError(deflated_len)) { + fprintf(stderr, "%s: decompression error '%s'\n", + test_name, ZSTD_getErrorName(deflated_len)); + exit(1); + } + + assert(deflated_len == sizeof(PKT_CONTENT)); + if(memcmp(PKT_CONTENT, deflation_buffer, deflated_len)!=0) { + fprintf(stderr, "%s: round-trip buffer mismatch\n", test_name); + exit(1); + } + + fprintf(stderr, "%s: tested\n", test_name); +#else + // FIXME - output dummy data to the stdout for easy comparison + printf("zstd: output size = 0x21\n"); + printf("000: 28 b5 2f fd 60 00 01 bd 00 00 80 00 01 02 03 04 |( / ` |\n"); + printf("010: 05 06 07 08 09 0a 0b 0c 0d 0e 0f 01 00 da 47 9d | G |\n"); + printf("020: 4b |K|\n"); + + fprintf(stderr, "%s: not compiled - dummy data output\n", test_name); +#endif + printf("\n"); +} + + +int main (int argc, char * argv[]) { + + /* Also for compression (init moved here for ciphers get run before in case of lzo init error) */ + init_compression_for_benchmark(); + + printf("%s: input size = 0x%" PRIx64 "\n", "original", sizeof(PKT_CONTENT)); + fhexdump(0, PKT_CONTENT, sizeof(PKT_CONTENT), stdout); + printf("\n"); + + test_lzo1x(); + test_zstd(); + + deinit_compression_for_benchmark(); + + return 0; +} + diff --git a/tools/tests-elliptic.c b/tools/tests-elliptic.c new file mode 100644 index 0000000..eb96365 --- /dev/null +++ b/tools/tests-elliptic.c @@ -0,0 +1,56 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + +#include "n2n.h" +#include "hexdump.h" + +void test_curve25519 (unsigned char *pkt_input, unsigned char *key) { + char *test_name = "curve25519"; + unsigned char pkt_output[32]; + + curve25519(pkt_output, key, pkt_input); + + printf("%s: output\n", test_name); + fhexdump(0, pkt_output, sizeof(pkt_output), stdout); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +int main (int argc, char * argv[]) { + char *test_name = "environment"; + + unsigned char key[32]; + unsigned char pkt_input[32]; + + memset(pkt_input, 0, 31); + pkt_input[31] = 9; + + memset(key, 0x55, 32); + + printf("%s: input\n", test_name); + fhexdump(0, pkt_input, sizeof(pkt_input), stdout); + printf("%s: key\n", test_name); + fhexdump(0, key, sizeof(key), stdout); + printf("\n"); + + test_curve25519(pkt_input, key); + + return 0; +} + diff --git a/tools/tests-hashing.c b/tools/tests-hashing.c new file mode 100644 index 0000000..dbbbbb8 --- /dev/null +++ b/tools/tests-hashing.c @@ -0,0 +1,119 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + +#include + +#include "n2n.h" +#include "hexdump.h" + + +uint8_t PKT_CONTENT[]={ + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 +}; + +void test_pearson_16 (void *buf, unsigned int bufsize) { + char *test_name = "pearson_hash_16"; + + uint16_t hash = pearson_hash_16(buf, bufsize); + + printf("%s: output = 0x%" PRIx16 "\n", test_name, hash); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_pearson_32 (void *buf, unsigned int bufsize) { + char *test_name = "pearson_hash_32"; + + uint32_t hash = pearson_hash_32(buf, bufsize); + + printf("%s: output = 0x%" PRIx32 "\n", test_name, hash); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_pearson_64 (void *buf, unsigned int bufsize) { + char *test_name = "pearson_hash_64"; + + uint64_t hash = pearson_hash_64(buf, bufsize); + + printf("%s: output = 0x%" PRIx64 "\n", test_name, hash); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_pearson_128 (void *buf, unsigned int bufsize) { + char *test_name = "pearson_hash_128"; + + uint8_t hash[16]; + pearson_hash_128(hash, buf, bufsize); + + printf("%s: output:\n", test_name); + fhexdump(0, hash, sizeof(hash), stdout); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_pearson_256 (void *buf, unsigned int bufsize) { + char *test_name = "pearson_hash_256"; + + uint8_t hash[32]; + pearson_hash_256(hash, buf, bufsize); + + printf("%s: output:\n", test_name); + fhexdump(0, hash, sizeof(hash), stdout); + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +int main (int argc, char * argv[]) { + pearson_hash_init(); + + char *test_name = "environment"; + printf("%s: input size = 0x%" PRIx64 "\n", test_name, sizeof(PKT_CONTENT)); + fhexdump(0, PKT_CONTENT, sizeof(PKT_CONTENT), stdout); + printf("\n"); + + test_pearson_256(PKT_CONTENT, sizeof(PKT_CONTENT)); + test_pearson_128(PKT_CONTENT, sizeof(PKT_CONTENT)); + test_pearson_64(PKT_CONTENT, sizeof(PKT_CONTENT)); + test_pearson_32(PKT_CONTENT, sizeof(PKT_CONTENT)); + test_pearson_16(PKT_CONTENT, sizeof(PKT_CONTENT)); + + return 0; +} + diff --git a/tools/tests-transform.c b/tools/tests-transform.c new file mode 100644 index 0000000..11f0deb --- /dev/null +++ b/tools/tests-transform.c @@ -0,0 +1,191 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + +#include + +#include "n2n.h" +#include "hexdump.h" + +#define DURATION 2.5 // test duration per algorithm +#define PACKETS_BEFORE_GETTIME 2047 // do not check time after every packet but after (2 ^ n - 1) + + +uint8_t PKT_CONTENT[]={ + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 +}; + +/* Prototypes */ +static ssize_t do_encode_packet ( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c ); +static void run_transop_benchmark (const char *op_name, n2n_trans_op_t *op_fn, n2n_edge_conf_t *conf, uint8_t *pktbuf); + + +int main (int argc, char * argv[]) { + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + n2n_trans_op_t transop_null, transop_tf; + n2n_trans_op_t transop_aes; + n2n_trans_op_t transop_cc20; + n2n_trans_op_t transop_speck; + n2n_trans_op_t transop_lzo; +#ifdef HAVE_ZSTD + n2n_trans_op_t transop_zstd; +#endif + n2n_edge_conf_t conf; + + /* Init configuration */ + edge_init_conf_defaults(&conf); + strncpy((char *)conf.community_name, "abc123def456", sizeof(conf.community_name)); + conf.encrypt_key = "SoMEVer!S$cUREPassWORD"; + + char *test_name = "environment"; + printf("%s: community_name = \"%s\"\n", test_name, conf.community_name); + printf("%s: encrypt_key = \"%s\"\n", test_name, conf.encrypt_key); + printf("%s: input size = 0x%" PRIx64 "\n", test_name, sizeof(PKT_CONTENT)); + fhexdump(0, PKT_CONTENT, sizeof(PKT_CONTENT), stdout); + printf("\n"); + + /* Init transopts */ + n2n_transop_null_init(&conf, &transop_null); + n2n_transop_tf_init(&conf, &transop_tf); + n2n_transop_aes_init(&conf, &transop_aes); + n2n_transop_cc20_init(&conf, &transop_cc20); + n2n_transop_speck_init(&conf, &transop_speck); + n2n_transop_lzo_init(&conf, &transop_lzo); +#ifdef HAVE_ZSTD + n2n_transop_zstd_init(&conf, &transop_zstd); +#endif + + /* Run the tests */ + /* FIXME: interop tests are pretty useless without the expected encrypted buffer data */ + run_transop_benchmark("null", &transop_null, &conf, pktbuf); + run_transop_benchmark("tf", &transop_tf, &conf, pktbuf); + run_transop_benchmark("aes", &transop_aes, &conf, pktbuf); + run_transop_benchmark("cc20", &transop_cc20, &conf, pktbuf); + run_transop_benchmark("speck", &transop_speck, &conf, pktbuf); + run_transop_benchmark("lzo", &transop_lzo, &conf, pktbuf); +#ifdef HAVE_ZSTD + run_transop_benchmark("zstd", &transop_zstd, &conf, pktbuf); +#else + // FIXME - output dummy data to the stdout for easy comparison + printf("zstd: output size = 0x47\n"); + printf("000: 03 02 00 03 61 62 63 31 32 33 64 65 66 34 35 36 | abc123def456|\n"); + printf("010: 00 00 00 00 00 00 00 00 00 01 02 03 04 05 00 01 | |\n"); + printf("020: 02 03 04 05 00 00 28 b5 2f fd 60 00 01 bd 00 00 | ( / ` |\n"); + printf("030: 80 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e | |\n"); + printf("040: 0f 01 00 da 47 9d 4b | G K|\n"); + + fprintf(stderr, "%s: not compiled - dummy data output\n", "zstd"); + printf("\n"); +#endif + + /* Cleanup */ + transop_null.deinit(&transop_null); + transop_tf.deinit(&transop_tf); + transop_aes.deinit(&transop_aes); + transop_cc20.deinit(&transop_cc20); + transop_speck.deinit(&transop_speck); + transop_lzo.deinit(&transop_lzo); +#ifdef HAVE_ZSTD + transop_zstd.deinit(&transop_zstd); +#endif + + return 0; +} + +// --- transop benchmark ------------------------------------------------------------------ + +static void run_transop_benchmark (const char *op_name, n2n_trans_op_t *op_fn, n2n_edge_conf_t *conf, uint8_t *pktbuf) { + n2n_common_t cmn; + n2n_PACKET_t pkt; + n2n_mac_t mac_buf; + uint8_t decodebuf[N2N_PKT_BUF_SIZE]; + size_t idx; + size_t rem; + size_t nw; + + // encryption + memset(mac_buf, 0, sizeof(mac_buf)); + + nw = do_encode_packet( pktbuf, N2N_PKT_BUF_SIZE, conf->community_name); + nw += op_fn->fwd(op_fn, + pktbuf+nw, N2N_PKT_BUF_SIZE-nw, + PKT_CONTENT, sizeof(PKT_CONTENT), mac_buf); + + printf("%s: output size = 0x%" PRIx64 "\n", op_name, nw); + fhexdump(0, pktbuf, nw, stdout); + + // decrpytion + idx=0; + rem=nw; + decode_common( &cmn, pktbuf, &rem, &idx); + decode_PACKET( &pkt, &cmn, pktbuf, &rem, &idx ); + op_fn->rev(op_fn, decodebuf, sizeof(decodebuf), pktbuf+idx, rem, 0); + + if(memcmp(decodebuf, PKT_CONTENT, sizeof(PKT_CONTENT)) != 0) { + fprintf(stderr, "%s: round-trip buffer mismatch\n", op_name); + exit(1); + } + + fprintf(stderr, "%s: tested\n", op_name); + printf("\n"); +} + + +static ssize_t do_encode_packet ( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c ) +{ + // FIXME: this is a parameter of the test environment + n2n_mac_t destMac={0,1,2,3,4,5}; + + n2n_common_t cmn; + n2n_PACKET_t pkt; + size_t idx; + + + memset( &cmn, 0, sizeof(cmn) ); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_packet; + cmn.flags=0; /* no options, not from supernode, no socket */ + memcpy( cmn.community, c, N2N_COMMUNITY_SIZE ); + + memset( &pkt, 0, sizeof(pkt) ); + memcpy( pkt.srcMac, destMac, N2N_MAC_SIZE); + memcpy( pkt.dstMac, destMac, N2N_MAC_SIZE); + + pkt.sock.family=0; /* do not encode sock */ + + idx=0; + encode_PACKET( pktbuf, &idx, &cmn, &pkt ); + traceEvent( TRACE_DEBUG, "encoded PACKET header of size=%u", (unsigned int)idx ); + + return idx; +} diff --git a/tools/tests-wire.c b/tools/tests-wire.c new file mode 100644 index 0000000..e194f72 --- /dev/null +++ b/tools/tests-wire.c @@ -0,0 +1,201 @@ +/* + * (C) 2007-22 - ntop.org and contributors + * + * 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 + * + */ + +#include + +#include "n2n.h" +#include "hexdump.h" + +void init_ip_subnet (n2n_ip_subnet_t * d) { + d->net_addr = 0x20212223; + d->net_bitlen = 25; +} + +void print_ip_subnet (char *test_name, char *field, n2n_ip_subnet_t * d) { + printf("%s: %s.net_addr = 0x%08x\n", + test_name, field, d->net_addr); + printf("%s: %s.net_bitlen = %i\n", + test_name, field, d->net_bitlen); +} + +void init_mac (n2n_mac_t mac, const uint8_t o0, const uint8_t o1, + const uint8_t o2, const uint8_t o3, + const uint8_t o4, const uint8_t o5) { + mac[0] = o0; + mac[1] = o1; + mac[2] = o2; + mac[3] = o3; + mac[4] = o4; + mac[5] = o5; +} + +void print_mac (char *test_name, char *field, n2n_mac_t mac) { + printf("%s: %s[] = %x:%x:%x:%x:%x:%x\n", + test_name, field, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +void init_auth (n2n_auth_t *auth) { + auth->scheme = n2n_auth_simple_id; + auth->token_size = 16; + auth->token[0] = 0xfe; + auth->token[4] = 0xfd; + auth->token[8] = 0xfc; + auth->token[15] = 0xfb; +} + +void print_auth (char *test_name, char *field, n2n_auth_t *auth) { + printf("%s: %s.scheme = %i\n", test_name, field, auth->scheme); + printf("%s: %s.token_size = %i\n", test_name, field, auth->token_size); + printf("%s: %s.token[0] = 0x%02x\n", test_name, field, auth->token[0]); +} + +void init_common (n2n_common_t *common, char *community) { + memset( common, 0, sizeof(*common) ); + common->ttl = N2N_DEFAULT_TTL; + common->flags = 0; + strncpy( (char *)common->community, community, N2N_COMMUNITY_SIZE); + common->community[N2N_COMMUNITY_SIZE - 1] = '\0'; +} + +void print_common (char *test_name, n2n_common_t *common) { + printf("%s: common.ttl = %i\n", test_name, common->ttl); + printf("%s: common.flags = %i\n", test_name, common->flags); + printf("%s: common.community = \"%s\"\n", test_name, common->community); +} + +void test_REGISTER (n2n_common_t *common) { + char *test_name = "REGISTER"; + + common->pc = n2n_register; + printf("%s: common.pc = %i\n", test_name, common->pc); + + n2n_REGISTER_t reg; + memset( ®, 0, sizeof(reg) ); + init_mac( reg.srcMac, 0,1,2,3,4,5); + init_mac( reg.dstMac, 0x10,0x11,0x12,0x13,0x14,0x15); + init_ip_subnet(®.dev_addr); + strcpy( (char *)reg.dev_desc, "Dummy_Dev_Desc" ); + + printf("%s: reg.cookie = %i\n", test_name, reg.cookie); + print_mac(test_name, "reg.srcMac", reg.srcMac); + print_mac(test_name, "reg.dstMac", reg.dstMac); + // TODO: print reg.sock + print_ip_subnet(test_name, "reg.dev_addr", ®.dev_addr); + printf("%s: reg.dev_desc = \"%s\"\n", test_name, reg.dev_desc); + printf("\n"); + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx = 0; + size_t retval = encode_REGISTER( pktbuf, &idx, common, ®); + + printf("%s: output retval = 0x%" PRIx64 "\n", test_name, retval); + printf("%s: output idx = 0x%" PRIx64 "\n", test_name, idx); + fhexdump(0, pktbuf, idx, stdout); + + // TODO: decode_REGISTER() and print + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_REGISTER_SUPER (n2n_common_t *common) { + char *test_name = "REGISTER_SUPER"; + + common->pc = n2n_register_super; + printf("%s: common.pc = %i\n", test_name, common->pc); + + n2n_REGISTER_SUPER_t reg; + memset( ®, 0, sizeof(reg) ); + init_mac( reg.edgeMac, 0x20,0x21,0x22,0x23,0x24,0x25); + // n2n_sock_t sock + init_ip_subnet(®.dev_addr); + strcpy( (char *)reg.dev_desc, "Dummy_Dev_Desc" ); + init_auth(®.auth); + reg.key_time = 600; + + + printf("%s: reg.cookie = %i\n", test_name, reg.cookie); + print_mac(test_name, "reg.edgeMac", reg.edgeMac); + // TODO: print reg.sock + print_ip_subnet(test_name, "reg.dev_addr", ®.dev_addr); + printf("%s: reg.dev_desc = \"%s\"\n", test_name, reg.dev_desc); + print_auth(test_name, "reg.auth", ®.auth); + printf("%s: reg.key_time = %" PRIi32 "\n", test_name, reg.key_time); + printf("\n"); + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx = 0; + size_t retval = encode_REGISTER_SUPER( pktbuf, &idx, common, ®); + + printf("%s: output retval = 0x%" PRIx64 "\n", test_name, retval); + printf("%s: output idx = 0x%" PRIx64 "\n", test_name, idx); + fhexdump(0, pktbuf, idx, stdout); + + // TODO: decode_REGISTER_SUPER() and print + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +void test_UNREGISTER_SUPER (n2n_common_t *common) { + char *test_name = "UNREGISTER_SUPER"; + + common->pc = n2n_unregister_super; + printf("%s: common.pc = %i\n", test_name, common->pc); + + n2n_UNREGISTER_SUPER_t unreg; + memset( &unreg, 0, sizeof(unreg) ); + init_auth(&unreg.auth); + init_mac( unreg.srcMac, 0x30,0x31,0x32,0x33,0x34,0x35); + + + print_auth(test_name, "unreg.auth", &unreg.auth); + print_mac(test_name, "unreg.srcMac", unreg.srcMac); + printf("\n"); + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx = 0; + size_t retval = encode_UNREGISTER_SUPER( pktbuf, &idx, common, &unreg); + + printf("%s: output retval = 0x%" PRIx64 "\n", test_name, retval); + printf("%s: output idx = 0x%" PRIx64 "\n", test_name, idx); + fhexdump(0, pktbuf, idx, stdout); + + // TODO: decode_UNREGISTER_SUPER() and print + + fprintf(stderr, "%s: tested\n", test_name); + printf("\n"); +} + +int main (int argc, char * argv[]) { + char *test_name = "environment"; + + n2n_common_t common; + init_common( &common, "abc123def456z" ); + print_common( test_name, &common ); + printf("\n"); + + test_REGISTER(&common); + test_REGISTER_SUPER(&common); + test_UNREGISTER_SUPER(&common); + // TODO: add more wire tests + + return 0; +} + diff --git a/tuntap_freebsd.c b/tuntap_freebsd.c deleted file mode 100644 index 95308be..0000000 --- a/tuntap_freebsd.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * (C) 2007-09 - Luca Deri - * - * 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 see - */ - -#include "n2n.h" - -#ifdef __FreeBSD__ - -void tun_close(tuntap_dev *device); - -/* ********************************** */ - -#define N2N_FREEBSD_TAPDEVICE_SIZE 32 -int tuntap_open(tuntap_dev *device /* ignored */, - char *dev, - char *device_ip, - char *device_mask, - const char * device_mac, - int mtu) { - int i; - char tap_device[N2N_FREEBSD_TAPDEVICE_SIZE]; - - for (i = 0; i < 255; i++) { - snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i); - - device->fd = open(tap_device, O_RDWR); - if(device->fd > 0) { - traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device); - break; - } - } - - if(device->fd < 0) { - traceEvent(TRACE_ERROR, "Unable to open tap device"); - return(-1); - } else { - char buf[256]; - FILE *fd; - - device->ip_addr = inet_addr(device_ip); - - if ( device_mac ) - { - /* FIXME - This is not tested. Might be wrong syntax for OS X */ - - /* Set the hw address before bringing the if up. */ - snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s", - i, device_mac); - system(buf); - } - - snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up", - i, device_ip, device_mask, mtu); - system(buf); - - traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)", - i, device_ip, device_mask); - - /* Read MAC address */ - - snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i); - /* traceEvent(TRACE_INFO, "%s", buf); */ - - fd = popen(buf, "r"); - if(fd < 0) { - tun_close(device); - return(-1); - } else { - int a, b, c, d, e, f; - - buf[0] = 0; - fgets(buf, sizeof(buf), fd); - pclose(fd); - - if(buf[0] == '\0') { - traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address"); - exit(0); - } - - traceEvent(TRACE_NORMAL, "Interface tap%d mac %s", i, buf); - if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) { - device->mac_addr[0] = a, device->mac_addr[1] = b; - device->mac_addr[2] = c, device->mac_addr[3] = d; - device->mac_addr[4] = e, device->mac_addr[5] = f; - } - } - } - - - /* read_mac(dev, device->mac_addr); */ - return(device->fd); -} - -/* ********************************** */ - -int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) { - return(read(tuntap->fd, buf, len)); -} - -/* ********************************** */ - -int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) { - return(write(tuntap->fd, buf, len)); -} - -/* ********************************** */ - -void tuntap_close(struct tuntap_dev *tuntap) { - close(tuntap->fd); -} - -#endif diff --git a/tuntap_linux.c b/tuntap_linux.c deleted file mode 100644 index a1d20fb..0000000 --- a/tuntap_linux.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * (C) 2007-09 - Luca Deri - * - * 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 -*/ - -#include "n2n.h" - -#ifdef __linux__ - -static void read_mac(char *ifname, char *mac_addr) { - int _sock, res; - struct ifreq ifr; - macstr_t mac_addr_buf; - - memset (&ifr,0,sizeof(struct ifreq)); - - /* Dummy socket, just to make ioctls with */ - _sock=socket(PF_INET, SOCK_DGRAM, 0); - strcpy(ifr.ifr_name, ifname); - res = ioctl(_sock,SIOCGIFHWADDR,&ifr); - if (res<0) { - perror ("Get hw addr"); - } else - memcpy(mac_addr, ifr.ifr_ifru.ifru_hwaddr.sa_data, 6); - - traceEvent(TRACE_NORMAL, "Interface %s has MAC %s", - ifname, - macaddr_str(mac_addr, mac_addr_buf, sizeof(mac_addr_buf))); - close(_sock); -} - -/* ********************************** */ - -/** @brief Open and configure the TAP device for packet read/write. - * - * This routine creates the interface via the tuntap driver then uses ifconfig - * to configure address/mask and MTU. - * - * @param device - [inout] a device info holder object - * @param dev - user-defined name for the new iface, - * if NULL system will assign a name - * @param device_ip - address of iface - * @param device_mask - netmask for device_ip - * @param mtu - MTU for device_ip - * - * @return - negative value on error - * - non-negative file-descriptor on success - */ -int tuntap_open(tuntap_dev *device, - char *dev, /* user-definable interface name, eg. edge0 */ - char *device_ip, - char *device_mask, - const char * device_mac, - int mtu) { - char *tuntap_device = "/dev/net/tun"; -#define N2N_LINUX_SYSTEMCMD_SIZE 128 - char buf[N2N_LINUX_SYSTEMCMD_SIZE]; - struct ifreq ifr; - int rc; - - device->fd = open(tuntap_device, O_RDWR); - if(device->fd < 0) { - printf("ERROR: ioctl() [%s][%d]\n", strerror(errno), errno); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP|IFF_NO_PI; /* Want a TAP device for layer 2 frames. */ - strncpy(ifr.ifr_name, dev, IFNAMSIZ); - rc = ioctl(device->fd, TUNSETIFF, (void *)&ifr); - - if(rc < 0) { - traceEvent(TRACE_ERROR, "ioctl() [%s][%d]\n", strerror(errno), rc); - close(device->fd); - return -1; - } - - if ( device_mac ) - { - /* Set the hw address before bringing the if up. */ - snprintf(buf, sizeof(buf), "/sbin/ifconfig %s hw ether %s", - ifr.ifr_name, device_mac ); - system(buf); - traceEvent(TRACE_INFO, "Setting MAC: %s", buf); - } - - snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s netmask %s mtu %d up", - ifr.ifr_name, device_ip, device_mask, mtu); - system(buf); - traceEvent(TRACE_INFO, "Bringing up: %s", buf); - - device->ip_addr = inet_addr(device_ip); - device->device_mask = inet_addr(device_mask); - read_mac(dev, (char*)device->mac_addr); - return(device->fd); -} - -int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) { - return(read(tuntap->fd, buf, len)); -} - -int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) { - return(write(tuntap->fd, buf, len)); -} - -void tuntap_close(struct tuntap_dev *tuntap) { - close(tuntap->fd); -} - -#endif /* #ifdef __linux__ */ diff --git a/tuntap_osx.c b/tuntap_osx.c deleted file mode 100644 index c0c4c08..0000000 --- a/tuntap_osx.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * (C) 2007-09 - Luca Deri - * - * 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 see - */ - -#include "n2n.h" - -#ifdef _DARWIN_ - -void tun_close(tuntap_dev *device); - -/* ********************************** */ - -#define N2N_OSX_TAPDEVICE_SIZE 32 -int tuntap_open(tuntap_dev *device /* ignored */, - char *dev, - char *device_ip, - char *device_mask, - const char * device_mac, - int mtu) { - int i; - char tap_device[N2N_OSX_TAPDEVICE_SIZE]; - - for (i = 0; i < 255; i++) { - snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i); - - device->fd = open(tap_device, O_RDWR); - if(device->fd > 0) { - traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device); - break; - } - } - - if(device->fd < 0) { - traceEvent(TRACE_ERROR, "Unable to open tap device"); - return(-1); - } else { - char buf[256]; - FILE *fd; - - device->ip_addr = inet_addr(device_ip); - - if ( device_mac ) - { - /* FIXME - This is not tested. Might be wrong syntax for OS X */ - - /* Set the hw address before bringing the if up. */ - snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s", - i, device_mac); - system(buf); - } - - snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up", - i, device_ip, device_mask, mtu); - system(buf); - - traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)", - i, device_ip, device_mask); - - /* Read MAC address */ - - snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i); - /* traceEvent(TRACE_INFO, "%s", buf); */ - - fd = popen(buf, "r"); - if(fd < 0) { - tun_close(device); - return(-1); - } else { - int a, b, c, d, e, f; - - buf[0] = 0; - fgets(buf, sizeof(buf), fd); - pclose(fd); - - if(buf[0] == '\0') { - traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address"); - exit(0); - } - - traceEvent(TRACE_NORMAL, "Interface tap%d [MTU %d] mac %s", i, mtu, buf); - if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) { - device->mac_addr[0] = a, device->mac_addr[1] = b; - device->mac_addr[2] = c, device->mac_addr[3] = d; - device->mac_addr[4] = e, device->mac_addr[5] = f; - } - } - } - - - /* read_mac(dev, device->mac_addr); */ - return(device->fd); -} - -/* ********************************** */ - -int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) { - return(read(tuntap->fd, buf, len)); -} - -/* ********************************** */ - -int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) { - return(write(tuntap->fd, buf, len)); -} - -/* ********************************** */ - -void tuntap_close(struct tuntap_dev *tuntap) { - close(tuntap->fd); -} - -#endif diff --git a/twofish.c b/twofish.c deleted file mode 100644 index 73a1a8e..0000000 --- a/twofish.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* $Id: twofish.c,v 2.0 2002/08/11 22:32:25 fknobbe Exp $ - * - * - * Copyright (C) 1997-2000 The Cryptix Foundation Limited. - * Copyright (C) 2000 Farm9. - * Copyright (C) 2001 Frank Knobbe. - * All rights reserved. - * - * For Cryptix code: - * Use, modification, copying and distribution of this software is subject - * the terms and conditions of the Cryptix General Licence. You should have - * received a copy of the Cryptix General Licence along with this library; - * if not, you can download a copy from http://www.cryptix.org/ . - * - * For Farm9: - * --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and - * ciphertext stealing technique, added AsciiTwofish class for easy encryption - * decryption of text strings - * - * Frank Knobbe : - * --- April 2001, converted from C++ to C, prefixed global variables - * with TwoFish, substituted some defines, changed functions to make use of - * variables supplied in a struct, modified and added routines for modular calls. - * Cleaned up the code so that defines are used instead of fixed 16's and 32's. - * Created two general purpose crypt routines for one block and multiple block - * encryption using Joh's CBC code. - * Added crypt routines that use a header (with a magic and data length). - * (Basically a major rewrite). - * - * Note: Routines labeled _TwoFish are private and should not be used - * (or with extreme caution). - * - */ - -#ifndef __TWOFISH_LIBRARY_SOURCE__ -#define __TWOFISH_LIBRARY_SOURCE__ - -#include -#include -#include -#include -#include -#include "twofish.h" - - -bool TwoFish_srand=TRUE; /* if TRUE, first call of TwoFishInit will seed rand(); */ -/* of TwoFishInit */ - -/* Fixed 8x8 permutation S-boxes */ -static const u_int8_t TwoFish_P[2][256] = - { - { /* p0 */ - 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, - 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, - 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, - 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, - 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, - 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, - 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, - 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, - 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, - 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, - 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, - 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, - 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, - 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, - 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, - 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, - 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, - 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, - 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, - 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, - 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, - 0x4A, 0x5E, 0xC1, 0xE0 - }, - { /* p1 */ - 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, - 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, - 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, - 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, - 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, - 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, - 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, - 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, - 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, - 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, - 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, - 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, - 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, - 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, - 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, - 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, - 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, - 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, - 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, - 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, - 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, - 0x55, 0x09, 0xBE, 0x91 - } - }; - -static bool TwoFish_MDSready=FALSE; -static u_int32_t TwoFish_MDS[4][256]; /* TwoFish_MDS matrix */ - - -#define TwoFish_LFSR1(x) (((x)>>1)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/2:0)) -#define TwoFish_LFSR2(x) (((x)>>2)^(((x)&0x02)?TwoFish_MDS_GF_FDBK/2:0)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/4:0)) - -#define TwoFish_Mx_1(x) ((u_int32_t)(x)) /* force result to dword so << will work */ -#define TwoFish_Mx_X(x) ((u_int32_t)((x)^TwoFish_LFSR2(x))) /* 5B */ -#define TwoFish_Mx_Y(x) ((u_int32_t)((x)^TwoFish_LFSR1(x)^TwoFish_LFSR2(x))) /* EF */ -#define TwoFish_RS_rem(x) { u_int8_t b=(u_int8_t)(x>>24); u_int32_t g2=((b<<1)^((b&0x80)?TwoFish_RS_GF_FDBK:0))&0xFF; u_int32_t g3=((b>>1)&0x7F)^((b&1)?TwoFish_RS_GF_FDBK>>1:0)^g2; x=(x<<8)^(g3<<24)^(g2<<16)^(g3<<8)^b; } - -/*#define TwoFish__b(x,N) (((u_int8_t *)&x)[((N)&3)^TwoFish_ADDR_XOR])*/ /* pick bytes out of a dword */ - -#define TwoFish_b0(x) TwoFish__b(x,0) /* extract LSB of u_int32_t */ -#define TwoFish_b1(x) TwoFish__b(x,1) -#define TwoFish_b2(x) TwoFish__b(x,2) -#define TwoFish_b3(x) TwoFish__b(x,3) /* extract MSB of u_int32_t */ - -u_int8_t TwoFish__b(u_int32_t x,int n) -{ n&=3; - while(n-->0) - x>>=8; - return (u_int8_t)x; -} - - -/* TwoFish Initialization - * - * This routine generates a global data structure for use with TwoFish, - * initializes important values (such as subkeys, sBoxes), generates subkeys - * and precomputes the MDS matrix if not already done. - * - * Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!') - * - * Output: Pointer to TWOFISH structure. This data structure contains key dependent data. - * This pointer is used with all other crypt functions. - */ - -TWOFISH *TwoFishInit(const u_int8_t *userkey, u_int32_t keysize) -{ TWOFISH *tfdata; - int i,x,m; - u_int8_t tkey[TwoFish_KEY_LENGTH+40]; - - memset( tkey, 0, TwoFish_KEY_LENGTH+40 ); - tfdata=(TWOFISH *)malloc(sizeof(TWOFISH)); /* allocate the TwoFish structure */ - if(tfdata!=NULL) - { - - /* Changes here prevented a dangerous random key segment for keys of length < TwoFish_KEY_LENGTH */ - if(keysize > 0) - { - memcpy( tkey, userkey, keysize ); /* The rest will be zeros */ - } - else - { - memcpy( tkey, TwoFish_DEFAULT_PW, TwoFish_DEFAULT_PW_LEN ); /* if no key defined, use default password */ - } - - /* This loop is awful - surely a loop on memcpy() would be clearer and more efficient */ - for(i=0,x=0,m=keysize;ikey[i]=tkey[x++]; /* fill the whole keyspace with repeating key. */ - if(x==m) - x=0; - } - - if(!TwoFish_MDSready) - _TwoFish_PrecomputeMDSmatrix(); /* "Wake Up, Neo" */ - _TwoFish_MakeSubKeys(tfdata); /* generate subkeys */ - _TwoFish_ResetCBC(tfdata); /* reset the CBC */ - tfdata->output=NULL; /* nothing to output yet */ - tfdata->dontflush=FALSE; /* reset decrypt skip block flag */ - if(TwoFish_srand) - { - TwoFish_srand=FALSE; - /* REVISIT: BbMaj7 : Should choose something with less predictability - * particularly for embedded targets with no real-time clock. */ - srand((unsigned int)time(NULL)); - } - } - return tfdata; /* return the data pointer */ -} - - -void TwoFishDestroy(TWOFISH *tfdata) -{ if(tfdata!=NULL) - free(tfdata); -} - - -/* en/decryption with CBC mode */ -u_int32_t _TwoFish_CryptRawCBC(u_int8_t *in,u_int8_t *out,u_int32_t len,bool decrypt,TWOFISH *tfdata) -{ u_int32_t rl; - - rl=len; /* remember how much data to crypt. */ - while(len>TwoFish_BLOCK_SIZE) /* and now we process block by block. */ - { _TwoFish_BlockCrypt(in,out,TwoFish_BLOCK_SIZE,decrypt,tfdata); /* de/encrypt it. */ - in+=TwoFish_BLOCK_SIZE; /* adjust pointers. */ - out+=TwoFish_BLOCK_SIZE; - len-=TwoFish_BLOCK_SIZE; - } - if(len>0) /* if we have less than a block left... */ - _TwoFish_BlockCrypt(in,out,len,decrypt,tfdata); /* ...then we de/encrypt that too. */ - if(tfdata->qBlockDefined && !tfdata->dontflush) /* in case len was exactly one block... */ - _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); /* ...we need to write the... */ - /* ...remaining bytes of the buffer */ - return rl; -} - -/* en/decryption on one block only */ -u_int32_t _TwoFish_CryptRaw16(u_int8_t *in,u_int8_t *out,u_int32_t len,bool decrypt,TWOFISH *tfdata) -{ /* qBlockPlain already zero'ed through ResetCBC */ - memcpy(tfdata->qBlockPlain,in,len); /* toss the data into it. */ - _TwoFish_BlockCrypt16(tfdata->qBlockPlain,tfdata->qBlockCrypt,decrypt,tfdata); /* encrypt just that block without CBC. */ - memcpy(out,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE); /* and return what we got */ - return TwoFish_BLOCK_SIZE; -} - -/* en/decryption without reset of CBC and output assignment */ -u_int32_t _TwoFish_CryptRaw(u_int8_t *in,u_int8_t *out,u_int32_t len,bool decrypt,TWOFISH *tfdata) -{ - if(in!=NULL && out!=NULL && len>0 && tfdata!=NULL) /* if we have valid data, then... */ - { if(len>TwoFish_BLOCK_SIZE) /* ...check if we have more than one block. */ - return _TwoFish_CryptRawCBC(in,out,len,decrypt,tfdata); /* if so, use the CBC routines... */ - else - return _TwoFish_CryptRaw16(in,out,len,decrypt,tfdata); /* ...otherwise just do one block. */ - } - return 0; -} - - -/* TwoFish Raw Encryption - * - * Does not use header, but does use CBC (if more than one block has to be encrypted). - * - * Input: Pointer to the buffer of the plaintext to be encrypted. - * Pointer to the buffer receiving the ciphertext. - * The length of the plaintext buffer. - * The TwoFish structure. - * - * Output: The amount of bytes encrypted if successful, otherwise 0. - */ - -u_int32_t TwoFishEncryptRaw(u_int8_t *in, - u_int8_t *out, - u_int32_t len, - TWOFISH *tfdata) -{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */ - tfdata->output=out; /* output straight into output buffer. */ - return _TwoFish_CryptRaw(in,out,len,FALSE,tfdata); /* and go for it. */ -} - -/* TwoFish Raw Decryption - * - * Does not use header, but does use CBC (if more than one block has to be decrypted). - * - * Input: Pointer to the buffer of the ciphertext to be decrypted. - * Pointer to the buffer receiving the plaintext. - * The length of the ciphertext buffer (at least one cipher block). - * The TwoFish structure. - * - * Output: The amount of bytes decrypted if successful, otherwise 0. - */ - -u_int32_t TwoFishDecryptRaw(u_int8_t *in, - u_int8_t *out, - u_int32_t len, - TWOFISH *tfdata) -{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */ - tfdata->output=out; /* output straight into output buffer. */ - return _TwoFish_CryptRaw(in,out,len,TRUE,tfdata); /* and go for it. */ -} - -/* TwoFish Free - * - * Free's the allocated buffer. - * - * Input: Pointer to the TwoFish structure - * - * Output: (none) - */ - -void TwoFishFree(TWOFISH *tfdata) -{ if(tfdata->output!=NULL) /* if a valid buffer is present... */ - { free(tfdata->output); /* ...then we free it for you... */ - tfdata->output=NULL; /* ...and mark as such. */ - } -} - -/* TwoFish Set Output - * - * If you want to allocate the output buffer yourself, - * then you can set it with this function. - * - * Input: Pointer to your output buffer - * Pointer to the TwoFish structure - * - * Output: (none) - */ - -void TwoFishSetOutput(u_int8_t *outp,TWOFISH *tfdata) -{ tfdata->output=outp; /* (do we really need a function for this?) */ -} - -/* TwoFish Alloc - * - * Allocates enough memory for the output buffer that would be required - * - * Input: Length of the plaintext. - * Boolean flag for BinHex Output. - * Pointer to the TwoFish structure. - * - * Output: Returns a pointer to the memory allocated. - */ - -void *TwoFishAlloc(u_int32_t len,bool binhex,bool decrypt,TWOFISH *tfdata) -{ - /* TwoFishFree(tfdata); */ /* (don't for now) discard whatever was allocated earlier. */ - if(decrypt) /* if decrypting... */ - { if(binhex) /* ...and input is binhex encoded... */ - len/=2; /* ...use half as much for output. */ - len-=TwoFish_BLOCK_SIZE; /* Also, subtract the size of the header. */ - } - else - { len+=TwoFish_BLOCK_SIZE; /* the size is just increased by the header... */ - if(binhex) - len*=2; /* ...and doubled if output is to be binhexed. */ - } - tfdata->output=malloc(len+TwoFish_BLOCK_SIZE);/* grab some memory...plus some extra (it's running over somewhere, crashes without extra padding) */ - - return tfdata->output; /* ...and return to caller. */ -} - -/* bin2hex and hex2bin conversion */ -void _TwoFish_BinHex(u_int8_t *buf,u_int32_t len,bool bintohex) -{ u_int8_t *pi,*po,c; - - if(bintohex) - { for(pi=buf+len-1,po=buf+(2*len)-1;len>0;pi--,po--,len--) /* let's start from the end of the bin block. */ - { c=*pi; /* grab value. */ - c&=15; /* use lower 4 bits. */ - if(c>9) /* convert to ascii. */ - c+=('a'-10); - else - c+='0'; - *po--=c; /* set the lower nibble. */ - c=*pi; /* grab value again. */ - c>>=4; /* right shift 4 bits. */ - c&=15; /* make sure we only have 4 bits. */ - if(c>9) /* convert to ascii. */ - c+=('a'-10); - else - c+='0'; - *po=c; /* set the higher nibble. */ - } /* and keep going. */ - } - else - { for(pi=buf,po=buf;len>0;pi++,po++,len-=2) /* let's start from the beginning of the hex block. */ - { c=tolower(*pi++)-'0'; /* grab higher nibble. */ - if(c>9) /* convert to value. */ - c-=('0'-9); - *po=c<<4; /* left shit 4 bits. */ - c=tolower(*pi)-'0'; /* grab lower nibble. */ - if(c>9) /* convert to value. */ - c-=('0'-9); - *po|=c; /* and add to value. */ - } - } -} - - -/* TwoFish Encryption - * - * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, - * this routine will alloc the memory. In addition, it will include a small 'header' - * containing the magic and some salt. That way the decrypt routine can check if the - * packet got decrypted successfully, and return 0 instead of garbage. - * - * Input: Pointer to the buffer of the plaintext to be encrypted. - * Pointer to the pointer to the buffer receiving the ciphertext. - * The pointer either points to user allocated output buffer space, or to NULL, in which case - * this routine will set the pointer to the buffer allocated through the struct. - * The length of the plaintext buffer. - * Can be -1 if the input is a null terminated string, in which case we'll count for you. - * Boolean flag for BinHex Output (if used, output will be twice as large as input). - * Note: BinHex conversion overwrites (converts) input buffer! - * The TwoFish structure. - * - * Output: The amount of bytes encrypted if successful, otherwise 0. - */ - -u_int32_t TwoFishEncrypt(u_int8_t *in, - u_int8_t **out, - signed long len, - bool binhex, - TWOFISH *tfdata) -{ u_int32_t ilen,olen; - - -#if 0 -/* This is so broken it doesn't deserve to live. */ - if(len== -1) /* if we got -1 for len, we'll assume IN is a... */ - ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */ - else - ilen=len; /* ...otherwise we trust you supply a correct length. */ -#endif - - ilen = len; - - if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */ - { if(*out==NULL) /* if OUT points to a NULL pointer... */ - *out=TwoFishAlloc(ilen,binhex,FALSE,tfdata); /* ...we'll (re-)allocate buffer space. */ - if(*out!=NULL) - { tfdata->output=*out; /* set output buffer. */ - tfdata->header.salt=rand()*65536+rand(); /* toss in some salt. */ - tfdata->header.length[0]= (u_int8_t)(ilen); - tfdata->header.length[1]= (u_int8_t)(ilen>>8); - tfdata->header.length[2]= (u_int8_t)(ilen>>16); - tfdata->header.length[3]= (u_int8_t)(ilen>>24); - memcpy(tfdata->header.magic,TwoFish_MAGIC,TwoFish_MAGIC_LEN); /* set the magic. */ - olen=TwoFish_BLOCK_SIZE; /* set output counter. */ - _TwoFish_ResetCBC(tfdata); /* reset the CBC flag */ - _TwoFish_BlockCrypt((u_int8_t *)&(tfdata->header),*out,olen,FALSE,tfdata); /* encrypt first block (without flush on 16 byte boundary). */ - olen+=_TwoFish_CryptRawCBC(in,*out+TwoFish_BLOCK_SIZE,ilen,FALSE,tfdata); /* and encrypt the rest (we do not reset the CBC flag). */ - if(binhex) /* if binhex... */ - { _TwoFish_BinHex(*out,olen,TRUE); /* ...convert output to binhex... */ - olen*=2; /* ...and size twice as large. */ - } - tfdata->output=*out; - return olen; - } - } - return 0; -} - -/* TwoFish Decryption - * - * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, - * this routine will alloc the memory. In addition, it will check the small 'header' - * containing the magic. If magic does not match we return 0. Otherwise we return the - * amount of bytes decrypted (should be the same as the length in the header). - * - * Input: Pointer to the buffer of the ciphertext to be decrypted. - * Pointer to the pointer to the buffer receiving the plaintext. - * The pointer either points to user allocated output buffer space, or to NULL, in which case - * this routine will set the pointer to the buffer allocated through the struct. - * The length of the ciphertext buffer. - * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you. - * Boolean flag for BinHex Input (if used, plaintext will be half as large as input). - * Note: BinHex conversion overwrites (converts) input buffer! - * The TwoFish structure. - * - * Output: The amount of bytes decrypted if successful, otherwise 0. - */ - -u_int32_t TwoFishDecrypt(u_int8_t *in, - u_int8_t **out, - signed long len, - bool binhex, - TWOFISH *tfdata) -{ u_int32_t ilen,elen,olen; - const u_int8_t cmagic[TwoFish_MAGIC_LEN]=TwoFish_MAGIC; - u_int8_t *tbuf; - - - -#if 0 -/* This is so broken it doesn't deserve to live. */ - if(len== -1) /* if we got -1 for len, we'll assume IN is a... */ - ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */ - else - ilen=len; /* ...otherwise we trust you supply a correct length. */ -#endif - - ilen = len; - - if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */ - { if(*out==NULL) /* if OUT points to a NULL pointer... */ - *out=TwoFishAlloc(ilen,binhex,TRUE,tfdata); /* ...we'll (re-)allocate buffer space. */ - if(*out!=NULL) - { if(binhex) /* if binhex... */ - { _TwoFish_BinHex(in,ilen,FALSE); /* ...convert input to values... */ - ilen/=2; /* ...and size half as much. */ - } - _TwoFish_ResetCBC(tfdata); /* reset the CBC flag. */ - - tbuf=(u_int8_t *)malloc(ilen+TwoFish_BLOCK_SIZE); /* get memory for data and header. */ - if(tbuf==NULL) - return 0; - tfdata->output=tbuf; /* set output to temp buffer. */ - - olen=_TwoFish_CryptRawCBC(in,tbuf,ilen,TRUE,tfdata)-TwoFish_BLOCK_SIZE; /* decrypt the whole thing. */ - memcpy(&(tfdata->header),tbuf,TwoFish_BLOCK_SIZE); /* copy first block into header. */ - tfdata->output=*out; - for(elen=0;elenheader.magic[elen]!=cmagic[elen]) - break; - if(elen==TwoFish_MAGIC_LEN) /* if magic matches then... */ - { elen=(tfdata->header.length[0]) | - (tfdata->header.length[1])<<8 | - (tfdata->header.length[2])<<16 | - (tfdata->header.length[3])<<24; /* .. we know how much to expect. */ - if(elen>olen) /* adjust if necessary. */ - elen=olen; - memcpy(*out,tbuf+TwoFish_BLOCK_SIZE,elen); /* copy data into intended output. */ - free(tbuf); - return elen; - } - free(tbuf); - } - } - return 0; -} - -void _TwoFish_PrecomputeMDSmatrix(void) /* precompute the TwoFish_MDS matrix */ -{ u_int32_t m1[2]; - u_int32_t mX[2]; - u_int32_t mY[2]; - u_int32_t i, j; - - for (i = 0; i < 256; i++) - { j = TwoFish_P[0][i] & 0xFF; /* compute all the matrix elements */ - m1[0] = j; - mX[0] = TwoFish_Mx_X( j ) & 0xFF; - mY[0] = TwoFish_Mx_Y( j ) & 0xFF; - - j = TwoFish_P[1][i] & 0xFF; - m1[1] = j; - mX[1] = TwoFish_Mx_X( j ) & 0xFF; - mY[1] = TwoFish_Mx_Y( j ) & 0xFF; - - TwoFish_MDS[0][i] = m1[TwoFish_P_00] | /* fill matrix w/ above elements */ - mX[TwoFish_P_00] << 8 | - mY[TwoFish_P_00] << 16 | - mY[TwoFish_P_00] << 24; - TwoFish_MDS[1][i] = mY[TwoFish_P_10] | - mY[TwoFish_P_10] << 8 | - mX[TwoFish_P_10] << 16 | - m1[TwoFish_P_10] << 24; - TwoFish_MDS[2][i] = mX[TwoFish_P_20] | - mY[TwoFish_P_20] << 8 | - m1[TwoFish_P_20] << 16 | - mY[TwoFish_P_20] << 24; - TwoFish_MDS[3][i] = mX[TwoFish_P_30] | - m1[TwoFish_P_30] << 8 | - mY[TwoFish_P_30] << 16 | - mX[TwoFish_P_30] << 24; - } - TwoFish_MDSready=TRUE; -} - - -void _TwoFish_MakeSubKeys(TWOFISH *tfdata) /* Expand a user-supplied key material into a session key. */ -{ u_int32_t k64Cnt = TwoFish_KEY_LENGTH / 8; - u_int32_t k32e[4]; /* even 32-bit entities */ - u_int32_t k32o[4]; /* odd 32-bit entities */ - u_int32_t sBoxKey[4]; - u_int32_t offset,i,j; - u_int32_t A, B, q=0; - u_int32_t k0,k1,k2,k3; - u_int32_t b0,b1,b2,b3; - - /* split user key material into even and odd 32-bit entities and */ - /* compute S-box keys using (12, 8) Reed-Solomon code over GF(256) */ - - - for (offset=0,i=0,j=k64Cnt-1;i<4 && offsetkey[offset++]; - k32e[i]|= tfdata->key[offset++]<<8; - k32e[i]|= tfdata->key[offset++]<<16; - k32e[i]|= tfdata->key[offset++]<<24; - k32o[i] = tfdata->key[offset++]; - k32o[i]|= tfdata->key[offset++]<<8; - k32o[i]|= tfdata->key[offset++]<<16; - k32o[i]|= tfdata->key[offset++]<<24; - sBoxKey[j] = _TwoFish_RS_MDS_Encode( k32e[i], k32o[i] ); /* reverse order */ - } - - /* compute the round decryption subkeys for PHT. these same subkeys */ - /* will be used in encryption but will be applied in reverse order. */ - i=0; - while(i < TwoFish_TOTAL_SUBKEYS) - { A = _TwoFish_F32( k64Cnt, q, k32e ); /* A uses even key entities */ - q += TwoFish_SK_BUMP; - - B = _TwoFish_F32( k64Cnt, q, k32o ); /* B uses odd key entities */ - q += TwoFish_SK_BUMP; - - B = B << 8 | B >> 24; - - A += B; - tfdata->subKeys[i++] = A; /* combine with a PHT */ - - A += B; - tfdata->subKeys[i++] = A << TwoFish_SK_ROTL | A >> (32-TwoFish_SK_ROTL); - } - - /* fully expand the table for speed */ - k0 = sBoxKey[0]; - k1 = sBoxKey[1]; - k2 = sBoxKey[2]; - k3 = sBoxKey[3]; - - for (i = 0; i < 256; i++) - { b0 = b1 = b2 = b3 = i; - switch (k64Cnt & 3) - { case 1: /* 64-bit keys */ - tfdata->sBox[ 2*i ] = TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0]) ^ TwoFish_b0(k0)]; - tfdata->sBox[ 2*i+1] = TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1]) ^ TwoFish_b1(k0)]; - tfdata->sBox[0x200+2*i ] = TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2]) ^ TwoFish_b2(k0)]; - tfdata->sBox[0x200+2*i+1] = TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3]) ^ TwoFish_b3(k0)]; - break; - case 0: /* 256-bit keys (same as 4) */ - b0 = (TwoFish_P[TwoFish_P_04][b0]) ^ TwoFish_b0(k3); - b1 = (TwoFish_P[TwoFish_P_14][b1]) ^ TwoFish_b1(k3); - b2 = (TwoFish_P[TwoFish_P_24][b2]) ^ TwoFish_b2(k3); - b3 = (TwoFish_P[TwoFish_P_34][b3]) ^ TwoFish_b3(k3); - case 3: /* 192-bit keys */ - b0 = (TwoFish_P[TwoFish_P_03][b0]) ^ TwoFish_b0(k2); - b1 = (TwoFish_P[TwoFish_P_13][b1]) ^ TwoFish_b1(k2); - b2 = (TwoFish_P[TwoFish_P_23][b2]) ^ TwoFish_b2(k2); - b3 = (TwoFish_P[TwoFish_P_33][b3]) ^ TwoFish_b3(k2); - case 2: /* 128-bit keys */ - tfdata->sBox[ 2*i ]= - TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0]) ^ - TwoFish_b0(k1)]) ^ TwoFish_b0(k0)]; - - tfdata->sBox[ 2*i+1]= - TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1]) ^ - TwoFish_b1(k1)]) ^ TwoFish_b1(k0)]; - - tfdata->sBox[0x200+2*i ]= - TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2]) ^ - TwoFish_b2(k1)]) ^ TwoFish_b2(k0)]; - - tfdata->sBox[0x200+2*i+1]= - TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3]) ^ - TwoFish_b3(k1)]) ^ TwoFish_b3(k0)]; - } - } -} - - -/** - * Encrypt or decrypt exactly one block of plaintext in CBC mode. - * Use "ciphertext stealing" technique described on pg. 196 - * of "Applied Cryptography" to encrypt the final partial - * (i.e. <16 byte) block if necessary. - * - * jojo: the "ciphertext stealing" requires we read ahead and have - * special handling for the last two blocks. Because of this, the - * output from the TwoFish algorithm is handled internally here. - * It would be better to have a higher level handle this as well as - * CBC mode. Unfortunately, I've mixed the two together, which is - * pretty crappy... The Java version separates these out correctly. - * - * fknobbe: I have reduced the CBC mode to work on memory buffer only. - * Higher routines should use an intermediate buffer and handle - * their output seperately (mainly so the data can be flushed - * in one chunk, not seperate 16 byte blocks...) - * - * @param in The plaintext. - * @param out The ciphertext - * @param size how much to encrypt - * @param tfdata: Pointer to the global data structure containing session keys. - * @return none - */ -void _TwoFish_BlockCrypt(u_int8_t *in,u_int8_t *out,u_int32_t size,int decrypt,TWOFISH *tfdata) -{ u_int8_t PnMinusOne[TwoFish_BLOCK_SIZE]; - u_int8_t CnMinusOne[TwoFish_BLOCK_SIZE]; - u_int8_t CBCplusCprime[TwoFish_BLOCK_SIZE]; - u_int8_t Pn[TwoFish_BLOCK_SIZE]; - u_int8_t *p,*pout; - u_int32_t i; - - /* here is where we implement CBC mode and cipher block stealing */ - if(size==TwoFish_BLOCK_SIZE) - { /* if we are encrypting, CBC means we XOR the plain text block with the */ - /* previous cipher text block before encrypting */ - if(!decrypt && tfdata->qBlockDefined) - { for(p=in,i=0;iqBlockCrypt[i]; /* FK: I'm copying the xor'ed input into Pn... */ - } - else - memcpy(Pn,in,TwoFish_BLOCK_SIZE); /* FK: same here. we work of Pn all the time. */ - - /* TwoFish block level encryption or decryption */ - _TwoFish_BlockCrypt16(Pn,out,decrypt,tfdata); - - /* if we are decrypting, CBC means we XOR the result of the decryption */ - /* with the previous cipher text block to get the resulting plain text */ - if(decrypt && tfdata->qBlockDefined) - { for (p=out,i=0;iqBlockPlain[i]; - } - - /* save the input and output blocks, since CBC needs these for XOR */ - /* operations */ - _TwoFish_qBlockPush(Pn,out,tfdata); - } - else - { /* cipher block stealing, we are at Pn, */ - /* but since Cn-1 must now be replaced with CnC' */ - /* we pop it off, and recalculate Cn-1 */ - - if(decrypt) - { /* We are on an odd block, and had to do cipher block stealing, */ - /* so the PnMinusOne has to be derived differently. */ - - /* First we decrypt it into CBC and C' */ - _TwoFish_qBlockPop(CnMinusOne,PnMinusOne,tfdata); - _TwoFish_BlockCrypt16(CnMinusOne,CBCplusCprime,decrypt,tfdata); - - /* we then xor the first few bytes with the "in" bytes (Cn) */ - /* to recover Pn, which we put in out */ - for(p=in,pout=out,i=0;iprevCipher[i]; - - /* So at this point, out has PnMinusOne */ - _TwoFish_qBlockPush(CnMinusOne,PnMinusOne,tfdata); - _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); - _TwoFish_FlushOutput(out,size,tfdata); - } - else - { _TwoFish_qBlockPop(PnMinusOne,CnMinusOne,tfdata); - memset(Pn,0,TwoFish_BLOCK_SIZE); - memcpy(Pn,in,size); - for(i=0;iqBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); - _TwoFish_FlushOutput(CnMinusOne,size,tfdata); /* old Cn-1 becomes new partial Cn */ - } - tfdata->qBlockDefined=FALSE; - } -} - -void _TwoFish_qBlockPush(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata) -{ if(tfdata->qBlockDefined) - _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); - memcpy(tfdata->prevCipher,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE); - memcpy(tfdata->qBlockPlain,p,TwoFish_BLOCK_SIZE); - memcpy(tfdata->qBlockCrypt,c,TwoFish_BLOCK_SIZE); - tfdata->qBlockDefined=TRUE; -} - -void _TwoFish_qBlockPop(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata) -{ memcpy(p,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE ); - memcpy(c,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE ); - tfdata->qBlockDefined=FALSE; -} - -/* Reset's the CBC flag and zero's PrevCipher (through qBlockPlain) (important) */ -void _TwoFish_ResetCBC(TWOFISH *tfdata) -{ tfdata->qBlockDefined=FALSE; - memset(tfdata->qBlockPlain,0,TwoFish_BLOCK_SIZE); -} - -void _TwoFish_FlushOutput(u_int8_t *b,u_int32_t len,TWOFISH *tfdata) -{ u_int32_t i; - - for(i=0;idontflush;i++) - *tfdata->output++ = *b++; - tfdata->dontflush=FALSE; -} - -void _TwoFish_BlockCrypt16(u_int8_t *in,u_int8_t *out,bool decrypt,TWOFISH *tfdata) -{ u_int32_t x0,x1,x2,x3; - u_int32_t k,t0,t1,R; - - - x0=*in++; - x0|=(*in++ << 8 ); - x0|=(*in++ << 16); - x0|=(*in++ << 24); - x1=*in++; - x1|=(*in++ << 8 ); - x1|=(*in++ << 16); - x1|=(*in++ << 24); - x2=*in++; - x2|=(*in++ << 8 ); - x2|=(*in++ << 16); - x2|=(*in++ << 24); - x3=*in++; - x3|=(*in++ << 8 ); - x3|=(*in++ << 16); - x3|=(*in++ << 24); - - if(decrypt) - { x0 ^= tfdata->subKeys[4]; /* swap input and output whitening keys when decrypting */ - x1 ^= tfdata->subKeys[5]; - x2 ^= tfdata->subKeys[6]; - x3 ^= tfdata->subKeys[7]; - - k = 7+(TwoFish_ROUNDS*2); - for (R = 0; R < TwoFish_ROUNDS; R += 2) - { t0 = _TwoFish_Fe320( tfdata->sBox, x0); - t1 = _TwoFish_Fe323( tfdata->sBox, x1); - x3 ^= t0 + (t1<<1) + tfdata->subKeys[k--]; - x3 = x3 >> 1 | x3 << 31; - x2 = x2 << 1 | x2 >> 31; - x2 ^= t0 + t1 + tfdata->subKeys[k--]; - - t0 = _TwoFish_Fe320( tfdata->sBox, x2); - t1 = _TwoFish_Fe323( tfdata->sBox, x3); - x1 ^= t0 + (t1<<1) + tfdata->subKeys[k--]; - x1 = x1 >> 1 | x1 << 31; - x0 = x0 << 1 | x0 >> 31; - x0 ^= t0 + t1 + tfdata->subKeys[k--]; - } - - x2 ^= tfdata->subKeys[0]; - x3 ^= tfdata->subKeys[1]; - x0 ^= tfdata->subKeys[2]; - x1 ^= tfdata->subKeys[3]; - } - else - { x0 ^= tfdata->subKeys[0]; - x1 ^= tfdata->subKeys[1]; - x2 ^= tfdata->subKeys[2]; - x3 ^= tfdata->subKeys[3]; - - k = 8; - for (R = 0; R < TwoFish_ROUNDS; R += 2) - { t0 = _TwoFish_Fe320( tfdata->sBox, x0); - t1 = _TwoFish_Fe323( tfdata->sBox, x1); - x2 ^= t0 + t1 + tfdata->subKeys[k++]; - x2 = x2 >> 1 | x2 << 31; - x3 = x3 << 1 | x3 >> 31; - x3 ^= t0 + (t1<<1) + tfdata->subKeys[k++]; - - t0 = _TwoFish_Fe320( tfdata->sBox, x2); - t1 = _TwoFish_Fe323( tfdata->sBox, x3); - x0 ^= t0 + t1 + tfdata->subKeys[k++]; - x0 = x0 >> 1 | x0 << 31; - x1 = x1 << 1 | x1 >> 31; - x1 ^= t0 + (t1<<1) + tfdata->subKeys[k++]; - } - - x2 ^= tfdata->subKeys[4]; - x3 ^= tfdata->subKeys[5]; - x0 ^= tfdata->subKeys[6]; - x1 ^= tfdata->subKeys[7]; - } - - *out++ = (u_int8_t)(x2 ); - *out++ = (u_int8_t)(x2 >> 8); - *out++ = (u_int8_t)(x2 >> 16); - *out++ = (u_int8_t)(x2 >> 24); - - *out++ = (u_int8_t)(x3 ); - *out++ = (u_int8_t)(x3 >> 8); - *out++ = (u_int8_t)(x3 >> 16); - *out++ = (u_int8_t)(x3 >> 24); - - *out++ = (u_int8_t)(x0 ); - *out++ = (u_int8_t)(x0 >> 8); - *out++ = (u_int8_t)(x0 >> 16); - *out++ = (u_int8_t)(x0 >> 24); - - *out++ = (u_int8_t)(x1 ); - *out++ = (u_int8_t)(x1 >> 8); - *out++ = (u_int8_t)(x1 >> 16); - *out++ = (u_int8_t)(x1 >> 24); -} - -/** - * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box - * 32-bit entity from two key material 32-bit entities. - * - * @param k0 1st 32-bit entity. - * @param k1 2nd 32-bit entity. - * @return Remainder polynomial generated using RS code - */ -u_int32_t _TwoFish_RS_MDS_Encode(u_int32_t k0,u_int32_t k1) -{ u_int32_t i,r; - - for(r=k1,i=0;i<4;i++) /* shift 1 byte at a time */ - TwoFish_RS_rem(r); - r ^= k0; - for(i=0;i<4;i++) - TwoFish_RS_rem(r); - - return r; -} - -u_int32_t _TwoFish_F32(u_int32_t k64Cnt,u_int32_t x,u_int32_t *k32) -{ u_int8_t b0,b1,b2,b3; - u_int32_t k0,k1,k2,k3,result = 0; - - b0=TwoFish_b0(x); - b1=TwoFish_b1(x); - b2=TwoFish_b2(x); - b3=TwoFish_b3(x); - k0=k32[0]; - k1=k32[1]; - k2=k32[2]; - k3=k32[3]; - - switch (k64Cnt & 3) - { case 1: /* 64-bit keys */ - result = - TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0] & 0xFF) ^ TwoFish_b0(k0)] ^ - TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1] & 0xFF) ^ TwoFish_b1(k0)] ^ - TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2] & 0xFF) ^ TwoFish_b2(k0)] ^ - TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3] & 0xFF) ^ TwoFish_b3(k0)]; - break; - case 0: /* 256-bit keys (same as 4) */ - b0 = (TwoFish_P[TwoFish_P_04][b0] & 0xFF) ^ TwoFish_b0(k3); - b1 = (TwoFish_P[TwoFish_P_14][b1] & 0xFF) ^ TwoFish_b1(k3); - b2 = (TwoFish_P[TwoFish_P_24][b2] & 0xFF) ^ TwoFish_b2(k3); - b3 = (TwoFish_P[TwoFish_P_34][b3] & 0xFF) ^ TwoFish_b3(k3); - - case 3: /* 192-bit keys */ - b0 = (TwoFish_P[TwoFish_P_03][b0] & 0xFF) ^ TwoFish_b0(k2); - b1 = (TwoFish_P[TwoFish_P_13][b1] & 0xFF) ^ TwoFish_b1(k2); - b2 = (TwoFish_P[TwoFish_P_23][b2] & 0xFF) ^ TwoFish_b2(k2); - b3 = (TwoFish_P[TwoFish_P_33][b3] & 0xFF) ^ TwoFish_b3(k2); - case 2: /* 128-bit keys (optimize for this case) */ - result = - TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0] & 0xFF) ^ TwoFish_b0(k1)] & 0xFF) ^ TwoFish_b0(k0)] ^ - TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1] & 0xFF) ^ TwoFish_b1(k1)] & 0xFF) ^ TwoFish_b1(k0)] ^ - TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2] & 0xFF) ^ TwoFish_b2(k1)] & 0xFF) ^ TwoFish_b2(k0)] ^ - TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3] & 0xFF) ^ TwoFish_b3(k1)] & 0xFF) ^ TwoFish_b3(k0)]; - break; - } - return result; -} - -u_int32_t _TwoFish_Fe320(u_int32_t *lsBox,u_int32_t x) -{ return lsBox[ TwoFish_b0(x)<<1 ]^ - lsBox[ ((TwoFish_b1(x)<<1)|1)]^ - lsBox[0x200+ (TwoFish_b2(x)<<1) ]^ - lsBox[0x200+((TwoFish_b3(x)<<1)|1)]; -} - -u_int32_t _TwoFish_Fe323(u_int32_t *lsBox,u_int32_t x) -{ return lsBox[ (TwoFish_b3(x)<<1) ]^ - lsBox[ ((TwoFish_b0(x)<<1)|1)]^ - lsBox[0x200+ (TwoFish_b1(x)<<1) ]^ - lsBox[0x200+((TwoFish_b2(x)<<1)|1)]; -} - -u_int32_t _TwoFish_Fe32(u_int32_t *lsBox,u_int32_t x,u_int32_t R) -{ return lsBox[ 2*TwoFish__b(x,R ) ]^ - lsBox[ 2*TwoFish__b(x,R+1)+1]^ - lsBox[0x200+2*TwoFish__b(x,R+2) ]^ - lsBox[0x200+2*TwoFish__b(x,R+3)+1]; -} - - -#endif - -/* ******************************************* */ -#if defined TWOFISH_UNIT_TEST -#include - -#define TEST_DATA_SIZE 327 - -int main(int argc, char* argv[]) -{ - int i; - int n; - - char outbuf[4096]; - char * outp = outbuf; - - u_int8_t key[] = { 0xfc, 0x77, 0x1a, 0xda, 0xaa }; - TWOFISH *tfa = TwoFishInit( key, 5 ); - TWOFISH *tfb = TwoFishInit( key, 5 ); - - u_int8_t out[2048], out2[2048]; - u_int8_t in[TEST_DATA_SIZE]; - - for ( i=0; i: - * --- April 2001, converted from C++ to C, prefixed global variables - * with TwoFish, substituted some defines, changed functions to make use of - * variables supplied in a struct, modified and added routines for modular calls. - * Cleaned up the code so that defines are used instead of fixed 16's and 32's. - * Created two general purpose crypt routines for one block and multiple block - * encryption using Joh's CBC code. - * Added crypt routines that use a header (with a magic and data length). - * (Basically a major rewrite). - * - * Note: Routines labeled _TwoFish are private and should not be used - * (or with extreme caution). - * - */ - -#ifndef __TWOFISH_LIBRARY_HEADER__ -#define __TWOFISH_LIBRARY_HEADER__ - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE !FALSE -#endif -#ifndef bool -#define bool int -#endif - -#ifdef WIN32 -#include "win32/n2n_win32.h" -#endif - -/* Constants */ - -#define TwoFish_DEFAULT_PW "SnortHas2FishEncryptionRoutines!" /* default password (not more than 32 chars) */ -#define TwoFish_DEFAULT_PW_LEN 32 -#define TwoFish_MAGIC "TwoFish" /* to indentify a successful decryption */ - -enum -{ TwoFish_KEY_SIZE = 256, /* Valid values: 64, 128, 192, 256 */ - /* User 256, other key sizes have not been tested. */ - /* (But should work. I substitutes as much as */ - /* I could with this define.) */ - TwoFish_ROUNDS = 16, - TwoFish_BLOCK_SIZE = 16, /* bytes in a data-block */ - TwoFish_KEY_LENGTH = TwoFish_KEY_SIZE/8, /* 32= 256-bit key */ - TwoFish_TOTAL_SUBKEYS = 4+4+2*TwoFish_ROUNDS, - TwoFish_MAGIC_LEN = TwoFish_BLOCK_SIZE-8, - TwoFish_SK_BUMP = 0x01010101, - TwoFish_SK_ROTL = 9, - TwoFish_P_00 = 1, - TwoFish_P_01 = 0, - TwoFish_P_02 = 0, - TwoFish_P_03 = TwoFish_P_01 ^ 1, - TwoFish_P_04 = 1, - TwoFish_P_10 = 0, - TwoFish_P_11 = 0, - TwoFish_P_12 = 1, - TwoFish_P_13 = TwoFish_P_11 ^ 1, - TwoFish_P_14 = 0, - TwoFish_P_20 = 1, - TwoFish_P_21 = 1, - TwoFish_P_22 = 0, - TwoFish_P_23 = TwoFish_P_21 ^ 1, - TwoFish_P_24 = 0, - TwoFish_P_30 = 0, - TwoFish_P_31 = 1, - TwoFish_P_32 = 1, - TwoFish_P_33 = TwoFish_P_31 ^ 1, - TwoFish_P_34 = 1, - TwoFish_GF256_FDBK = 0x169, - TwoFish_GF256_FDBK_2 = 0x169 / 2, - TwoFish_GF256_FDBK_4 = 0x169 / 4, - TwoFish_RS_GF_FDBK = 0x14D, /* field generator */ - TwoFish_MDS_GF_FDBK = 0x169 /* primitive polynomial for GF(256) */ -}; - - -/* Global data structure for callers */ - -typedef struct -{ - u_int32_t sBox[4 * 256]; /* Key dependent S-box */ - u_int32_t subKeys[TwoFish_TOTAL_SUBKEYS]; /* Subkeys */ - u_int8_t key[TwoFish_KEY_LENGTH]; /* Encryption Key */ - u_int8_t *output; /* Pointer to output buffer */ - u_int8_t qBlockPlain[TwoFish_BLOCK_SIZE]; /* Used by CBC */ - u_int8_t qBlockCrypt[TwoFish_BLOCK_SIZE]; - u_int8_t prevCipher[TwoFish_BLOCK_SIZE]; - struct /* Header for crypt functions. Has to be at least one block long. */ - { u_int32_t salt; /* Random salt in first block (will salt the rest through CBC) */ - u_int8_t length[4]; /* The amount of data following the header */ - u_int8_t magic[TwoFish_MAGIC_LEN]; /* Magic to identify successful decryption */ - } header; - bool qBlockDefined; - bool dontflush; -} TWOFISH; - -#ifndef __TWOFISH_LIBRARY_SOURCE__ - -extern bool TwoFish_srand; /* if set to TRUE (default), first call of TwoFishInit will seed rand(); */ - /* call of TwoFishInit */ -#endif - - -/**** Public Functions ****/ - -/* TwoFish Initialization - * - * This routine generates a global data structure for use with TwoFish, - * initializes important values (such as subkeys, sBoxes), generates subkeys - * and precomputes the MDS matrix if not already done. - * - * Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!') - * - * Output: Pointer to TWOFISH structure. This data structure contains key dependent data. - * This pointer is used with all other crypt functions. - */ -TWOFISH *TwoFishInit(const u_int8_t *userkey, u_int32_t keysize ); - - -/* TwoFish Destroy - * - * Nothing else but a free... - * - * Input: Pointer to the TwoFish structure. - * - */ -void TwoFishDestroy(TWOFISH *tfdata); - - -/* TwoFish Alloc - * - * Allocates enough memory for the output buffer as required. - * - * Input: Length of the plaintext. - * Boolean flag for BinHex Output. - * Pointer to the TwoFish structure. - * - * Output: Returns a pointer to the memory allocated. - */ -void *TwoFishAlloc(u_int32_t len,bool binhex,bool decrypt,TWOFISH *tfdata); - - -/* TwoFish Free - * - * Free's the allocated buffer. - * - * Input: Pointer to the TwoFish structure - * - * Output: (none) - */ -void TwoFishFree(TWOFISH *tfdata); - - -/* TwoFish Set Output - * - * If you want to allocate the output buffer yourself, - * then you can set it with this function. - * - * Input: Pointer to your output buffer - * Pointer to the TwoFish structure - * - * Output: (none) - */ -void TwoFishSetOutput(u_int8_t *outp,TWOFISH *tfdata); - - -/* TwoFish Raw Encryption - * - * Does not use header, but does use CBC (if more than one block has to be encrypted). - * - * Input: Pointer to the buffer of the plaintext to be encrypted. - * Pointer to the buffer receiving the ciphertext. - * The length of the plaintext buffer. - * The TwoFish structure. - * - * Output: The amount of bytes encrypted if successful, otherwise 0. - */ -u_int32_t TwoFishEncryptRaw(u_int8_t *in,u_int8_t *out,u_int32_t len,TWOFISH *tfdata); - -/* TwoFish Raw Decryption - * - * Does not use header, but does use CBC (if more than one block has to be decrypted). - * - * Input: Pointer to the buffer of the ciphertext to be decrypted. - * Pointer to the buffer receiving the plaintext. - * The length of the ciphertext buffer (at least one cipher block). - * The TwoFish structure. - * - * Output: The amount of bytes decrypted if successful, otherwise 0. - */ -u_int32_t TwoFishDecryptRaw(u_int8_t *in,u_int8_t *out,u_int32_t len,TWOFISH *tfdata); - - -/* TwoFish Encryption - * - * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, - * this routine will alloc the memory. In addition, it will include a small 'header' - * containing the magic and some salt. That way the decrypt routine can check if the - * packet got decrypted successfully, and return 0 instead of garbage. - * - * Input: Pointer to the buffer of the plaintext to be encrypted. - * Pointer to the pointer to the buffer receiving the ciphertext. - * The pointer either points to user allocated output buffer space, or to NULL, in which case - * this routine will set the pointer to the buffer allocated through the struct. - * The length of the plaintext buffer. - * Can be -1 if the input is a null terminated string, in which case we'll count for you. - * Boolean flag for BinHex Output (if used, output will be twice as large as input). - * Note: BinHex conversion overwrites (converts) input buffer! - * The TwoFish structure. - * - * Output: The amount of bytes encrypted if successful, otherwise 0. - */ -u_int32_t TwoFishEncrypt(u_int8_t *in,u_int8_t **out,signed long len,bool binhex,TWOFISH *tfdata); - - -/* TwoFish Decryption - * - * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, - * this routine will alloc the memory. In addition, it will check the small 'header' - * containing the magic. If magic does not match we return 0. Otherwise we return the - * amount of bytes decrypted (should be the same as the length in the header). - * - * Input: Pointer to the buffer of the ciphertext to be decrypted. - * Pointer to the pointer to the buffer receiving the plaintext. - * The pointer either points to user allocated output buffer space, or to NULL, in which case - * this routine will set the pointer to the buffer allocated through the struct. - * The length of the ciphertext buffer. - * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you. - * Boolean flag for BinHex Input (if used, plaintext will be half as large as input). - * Note: BinHex conversion overwrites (converts) input buffer! - * The TwoFish structure. - * - * Output: The amount of bytes decrypted if successful, otherwise 0. - */ -u_int32_t TwoFishDecrypt(u_int8_t *in,u_int8_t **out,signed long len,bool binhex,TWOFISH *tfdata); - - -/**** Private Functions ****/ - -u_int8_t TwoFish__b(u_int32_t x,int n); -void _TwoFish_BinHex(u_int8_t *buf,u_int32_t len,bool bintohex); -u_int32_t _TwoFish_CryptRawCBC(u_int8_t *in,u_int8_t *out,u_int32_t len,bool decrypt,TWOFISH *tfdata); -u_int32_t _TwoFish_CryptRaw16(u_int8_t *in,u_int8_t *out,u_int32_t len,bool decrypt,TWOFISH *tfdata); -u_int32_t _TwoFish_CryptRaw(u_int8_t *in,u_int8_t *out,u_int32_t len,bool decrypt,TWOFISH *tfdata); -void _TwoFish_PrecomputeMDSmatrix(void); -void _TwoFish_MakeSubKeys(TWOFISH *tfdata); -void _TwoFish_qBlockPush(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata); -void _TwoFish_qBlockPop(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata); -void _TwoFish_ResetCBC(TWOFISH *tfdata); -void _TwoFish_FlushOutput(u_int8_t *b,u_int32_t len,TWOFISH *tfdata); -void _TwoFish_BlockCrypt(u_int8_t *in,u_int8_t *out,u_int32_t size,int decrypt,TWOFISH *tfdata); -void _TwoFish_BlockCrypt16(u_int8_t *in,u_int8_t *out,bool decrypt,TWOFISH *tfdata); -u_int32_t _TwoFish_RS_MDS_Encode(u_int32_t k0,u_int32_t k1); -u_int32_t _TwoFish_F32(u_int32_t k64Cnt,u_int32_t x,u_int32_t *k32); -u_int32_t _TwoFish_Fe320(u_int32_t *lsBox,u_int32_t x); -u_int32_t _TwoFish_Fe323(u_int32_t *lsBox,u_int32_t x); -u_int32_t _TwoFish_Fe32(u_int32_t *lsBox,u_int32_t x,u_int32_t R); - - -#endif diff --git a/uncrustify.cfg b/uncrustify.cfg new file mode 100644 index 0000000..baef9cd --- /dev/null +++ b/uncrustify.cfg @@ -0,0 +1,34 @@ +# Initial rules taken from a quick discussion +# (See https://github.com/ntop/n2n/commit/00159d0d012c6836fd972af1748833eeaf50fa22#commitcomment-57137247) + +# 4 space indention (never use tabs) +indent_columns = 4 +indent_with_tabs = 0 +indent_switch_case = 4 + +# space between name and bracket during function define +sp_func_def_paren = force +sp_func_proto_paren = force + +# no space between name and bracket during call +sp_func_call_paren = remove + +# no space after if and while +sp_before_sparen = remove +#sp_while_paren_open = remove # only in newer uncrustify + +# block-braces as seen above +nl_if_brace = remove +nl_brace_else = remove +nl_elseif_brace = remove +nl_else_brace = remove +#nl_before_opening_brace_func_class_def = remove # only in newer uncrustify +nl_for_brace = remove +nl_while_brace = remove + +# multi-line parameters with indentation under the opening bracket +# looks like this is the default, but might be the following: +#indent_func_call_param = false ? + +# Want to keep var definition alignment +#align_keep_extra_space = true diff --git a/win32/CMakeLists.txt b/win32/CMakeLists.txt new file mode 100644 index 0000000..2e96b18 --- /dev/null +++ b/win32/CMakeLists.txt @@ -0,0 +1,5 @@ +add_library(n2n_win32 + getopt1.c + getopt.c + wintap.c) +target_link_libraries(n2n_win32 PUBLIC ws2_32.lib) diff --git a/win32/DotNet/n2n.sln b/win32/DotNet/n2n.sln new file mode 100644 index 0000000..c8cfda1 --- /dev/null +++ b/win32/DotNet/n2n.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "edge", "n2n.vcproj", "{4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "supernode", "supernode.vcproj", "{BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Debug|Win32.ActiveCfg = Debug|Win32 + {4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Debug|Win32.Build.0 = Debug|Win32 + {4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Release|Win32.ActiveCfg = Release|Win32 + {4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Release|Win32.Build.0 = Release|Win32 + {BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Debug|Win32.ActiveCfg = Debug|Win32 + {BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Debug|Win32.Build.0 = Debug|Win32 + {BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Release|Win32.ActiveCfg = Release|Win32 + {BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/win32/DotNet/n2n.suo b/win32/DotNet/n2n.suo new file mode 100644 index 0000000..aae212b Binary files /dev/null and b/win32/DotNet/n2n.suo differ diff --git a/win32/DotNet/n2n.vcproj b/win32/DotNet/n2n.vcproj new file mode 100644 index 0000000..650e694 --- /dev/null +++ b/win32/DotNet/n2n.vcproj @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/DotNet/supernode.vcproj b/win32/DotNet/supernode.vcproj new file mode 100644 index 0000000..c54e95b --- /dev/null +++ b/win32/DotNet/supernode.vcproj @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/Makefile b/win32/Makefile new file mode 100644 index 0000000..3ffda93 --- /dev/null +++ b/win32/Makefile @@ -0,0 +1,19 @@ +# +# This is not a standalone makefile, it must be called from the toplevel +# makefile to inherit the correct environment + +CFLAGS+=-I../include +LDFLAGS+=-L.. + +.PHONY: all clean install + +all: n2n_win32.a + +n2n_win32.a: getopt1.o getopt.o wintap.o + $(AR) rcs $@ $+ + +clean: + rm -rf n2n_win32.a *.o *.gcno *.gcda + +install: + true diff --git a/win32/getopt.c b/win32/getopt.c new file mode 100644 index 0000000..f34b53a --- /dev/null +++ b/win32/getopt.c @@ -0,0 +1,1092 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 + Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include +#ifdef WIN32 +#include +#endif + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT<_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +#ifndef DARWIN +char *optarg; +#endif + + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +#ifndef DARWIN +int optind = 1; +#endif + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +#ifndef DARWIN +#ifdef WIN32 +int opterr = 0; +#else +int opterr = 1; +#endif +#endif + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ +#ifndef DARWIN +int optopt = '?'; +#endif + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +#ifndef WIN32 +# if HAVE_STRING_H +# include +# else +# include +# endif +#endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int print_errors = opterr; + if (optstring[0] == ':') + print_errors = 0; + + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (print_errors) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt____ (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ + diff --git a/win32/getopt.h b/win32/getopt.h new file mode 100644 index 0000000..bc7f256 --- /dev/null +++ b/win32/getopt.h @@ -0,0 +1,187 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +# if defined __STDC__ && __STDC__ + const char *name; +# else + char *name; +# endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +#if defined __STDC__ && __STDC__ +# ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int __argc, char *const *__argv, const char *__shortopts); +# else /* not __GNU_LIBRARY__ */ +extern int getopt (); +# endif /* __GNU_LIBRARY__ */ + +# ifndef __need_getopt +extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, + const struct option *__longopts, int *__longind); +extern int getopt_long_only (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only); +# endif +#else /* not __STDC__ */ +extern int getopt (); +# ifndef __need_getopt +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +# endif +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/win32/getopt1.c b/win32/getopt1.c new file mode 100644 index 0000000..8742b08 --- /dev/null +++ b/win32/getopt1.c @@ -0,0 +1,207 @@ +/** + * (C) 2007-22 - ntop.org and contributors + * + * 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 see + * + */ + + +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/win32/n2n_win32.h b/win32/n2n_win32.h new file mode 100644 index 0000000..e1a0104 --- /dev/null +++ b/win32/n2n_win32.h @@ -0,0 +1,132 @@ +/* + + (C) 2007-22 - Luca Deri + +*/ + +#ifndef _N2N_WIN32_H_ +#define _N2N_WIN32_H_ + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#define WIN32_LEAN_AND_MEAN + +#if defined(__MINGW32__) +/* should be defined here and before winsock gets included */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x501 //Otherwise the linker doesnt find getaddrinfo +#endif /* #ifndef _WIN32_WINNT */ +#include +#endif /* #if defined(__MINGW32__) */ + + +#include +#include +#include +#include +#if defined(_MSC_VER) +#include +#pragma comment(lib,"Iphlpapi.lib") +#endif +#include +#include +#include + + +#include "wintap.h" + +#undef EAFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define MAX(a,b) (a > b ? a : b) +#define MIN(a,b) (a < b ? a : b) + +#define snprintf _snprintf +#define strdup _strdup + +#define socklen_t int + + +/* ************************************* */ + +struct ip { +#if BYTE_ORDER == LITTLE_ENDIAN + u_char ip_hl:4, /* header length */ + ip_v:4; /* version */ +#else + u_char ip_v:4, /* version */ + ip_hl:4; /* header length */ +#endif + u_char ip_tos; /* type of service */ + short ip_len; /* total length */ + u_short ip_id; /* identification */ + short ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_char ip_ttl; /* time to live */ + u_char ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +}; + + +/* ************************************* */ + + +typedef struct tuntap_dev { + HANDLE device_handle; + char *device_name; + char *ifName; + int if_idx; + OVERLAPPED overlap_read, overlap_write; + n2n_mac_t mac_addr; + uint32_t ip_addr; + uint32_t device_mask; + unsigned int mtu; + unsigned int metric; + unsigned int metric_original; +} tuntap_dev; + + +/* ************************************* */ + + +#define index(a, b) strchr(a, b) +#define sleep(x) Sleep(x * 1000) + + +/* ************************************* */ + + +#define HAVE_PTHREAD +#define pthread_t HANDLE +#define pthread_mutex_t HANDLE + +#define pthread_create(p_thread_handle, attr, thread_func, p_param) \ + (*p_thread_handle = CreateThread(0 /* default security flags */, 0 /*default stack*/, \ + thread_func, p_param, 0 /* default creation flags */, \ + NULL) == 0) + +#define pthread_cancel(p_thread_handle) \ + TerminateThread(p_thread_handle, 0) + +#define pthread_mutex_init(p_mutex_handle, attr) \ + *p_mutex_handle = CreateMutex(NULL /*default security flags */, \ + FALSE /* initially not owned */, NULL /* unnamed */) + +#define pthread_mutex_lock(mutex) \ + WaitForSingleObject(*mutex, INFINITE) + +#define pthread_mutex_trylock(mutex) \ + WaitForSingleObject(*mutex, NULL) + +#define pthread_mutex_unlock(mutex) \ + ReleaseMutex(*mutex) + + +/* ************************************* */ + + +#endif diff --git a/win32/version-msvc.c b/win32/version-msvc.c new file mode 100644 index 0000000..92cce06 --- /dev/null +++ b/win32/version-msvc.c @@ -0,0 +1,3 @@ +const char * n2n_sw_version = "2.0.0"; +const char * n2n_sw_osName = "Win32"; +const char * n2n_sw_buildDate = __DATE__ " " __TIME__; diff --git a/win32/winconfig.h b/win32/winconfig.h new file mode 100644 index 0000000..aa9794a --- /dev/null +++ b/win32/winconfig.h @@ -0,0 +1,11 @@ +/* winconfig.h. Win32 replacement for file generated from config.h.in by configure. */ + +/* OS name */ +#ifndef PACKAGE_OSNAME +#define PACKAGE_OSNAME "windows" +#endif + +/* Define to the version of this package. */ +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION N2N_VERSION +#endif diff --git a/win32/wintap.c b/win32/wintap.c new file mode 100644 index 0000000..0777a59 --- /dev/null +++ b/win32/wintap.c @@ -0,0 +1,517 @@ +/* + (C) 2007-22 - Luca Deri +*/ + +#include "n2n.h" +#include "n2n_win32.h" + +/* ***************************************************** */ + +void initWin32() { + WSADATA wsaData; + int err; + + err = WSAStartup(MAKEWORD(2, 2), &wsaData ); + if( err != 0 ) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + printf("FATAL ERROR: unable to initialise Winsock 2.x."); + exit(EXIT_FAILURE); + } +} + + +void destroyWin32() { + WSACleanup(); +} + +struct win_adapter_info { + HANDLE handle; + char adapterid[1024]; + char adaptername[1024]; +}; + +/* ***************************************************** */ + +static HANDLE open_tap_device(const char *adapterid) { + char tapname[1024]; + _snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid); + + return(CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, + 0, /* Don't let other processes share or open + the resource until the handle's been closed */ + 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0)); +} + +/* ***************************************************** */ + +static void iterate_win_network_adapters( + int (*callback)(struct win_adapter_info*, struct tuntap_dev *), + void *userdata) { + HKEY key, key2; + char regpath[1024]; + long len, rc; + int found = 0; + int err, i; + struct win_adapter_info adapter; + + /* Open registry and look for network adapters */ + if((rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key))) { + printf("Unable to read registry: [rc=%d]\n", rc); + exit(EXIT_FAILURE); + /* MSVC Note: If you keep getting rc=2 errors, make sure you set: + Project -> Properties -> Configuration Properties -> General -> Character set + to: "Use Multi-Byte Character Set" + */ + } + + for (i = 0; ; i++) { + len = sizeof(adapter.adapterid); + if(RegEnumKeyEx(key, i, (LPTSTR)adapter.adapterid, &len, 0, 0, 0, NULL)) + break; + + /* Find out more about this adapter */ + + _snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapter.adapterid); + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)regpath, 0, KEY_READ, &key2)) + continue; + + len = sizeof(adapter.adaptername); + err = RegQueryValueEx(key2, "Name", 0, 0, adapter.adaptername, &len); + + RegCloseKey(key2); + + if(err) + continue; + + + adapter.handle = open_tap_device(adapter.adapterid); + + if(adapter.handle != INVALID_HANDLE_VALUE) { + /* Valid device, use the callback */ + if(!callback(&adapter, userdata)) + break; + else + CloseHandle(adapter.handle); + /* continue */ + } + } + + RegCloseKey(key); +} + +/* ***************************************************** */ + +static int print_adapter_callback(struct win_adapter_info *adapter, struct tuntap_dev *device) { + printf(" %s - %s\n", adapter->adapterid, adapter->adaptername); + + /* continue */ + return(1); +} + +void win_print_available_adapters() { + iterate_win_network_adapters(print_adapter_callback, NULL); +} + +/* ***************************************************** */ + +static int lookup_adapter_info_reg(const char *target_adapter, char *regpath, size_t regpath_size) { + HKEY key, key2; + long len, rc; + char index[16]; + int err, i; + char adapter_name[N2N_IFNAMSIZ]; + int rv = 0; + + if((rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_INFO_KEY, 0, KEY_READ, &key))) { + printf("Unable to read registry: %s, [rc=%d]\n", ADAPTER_INFO_KEY, rc); + exit(EXIT_FAILURE); + } + + for(i = 0; ; i++) { + len = sizeof(index); + if(RegEnumKeyEx(key, i, (LPTSTR)index, &len, 0, 0, 0, NULL)) + break; + + _snprintf(regpath, regpath_size, "%s\\%s", ADAPTER_INFO_KEY, index); + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)regpath, 0, KEY_READ, &key2)) + continue; + + len = sizeof(adapter_name); + err = RegQueryValueEx(key2, "NetCfgInstanceId", 0, 0, adapter_name, &len); + + RegCloseKey(key2); + + if(err) + continue; + + if(!strcmp(adapter_name, target_adapter)) { + rv = 1; + break; + } + } + + RegCloseKey(key); + return(rv); +} + +/* ***************************************************** */ + +static void set_interface_mac(struct tuntap_dev *device, const char *mac_str) { + char cmd[256]; + char mac_buf[18]; + char adapter_info_reg[1024]; + + uint64_t mac = 0; + uint8_t *ptr = (uint8_t*)&mac; + + if(strlen(mac_str) != 17) { + printf("Invalid MAC: %s\n", mac_str); + exit(EXIT_FAILURE); + } + + /* Remove the colons */ + for(int i=0; i<6; i++) { + mac_buf[i*2] = mac_str[2*i + i]; + mac_buf[i*2+1] = mac_str[2*i + i + 1]; + } + mac_buf[12] = '\0'; + + if(!lookup_adapter_info_reg(device->device_name, adapter_info_reg, sizeof(adapter_info_reg))) { + printf("Could not determine adapter MAC registry key\n"); + exit(EXIT_FAILURE); + } + + _snprintf(cmd, sizeof(cmd), + "reg add HKEY_LOCAL_MACHINE\\%s /v MAC /d %s /f > nul", adapter_info_reg, mac_buf); + system(cmd); + + /* Put down then up again to apply */ + CloseHandle(device->device_handle); + _snprintf(cmd, sizeof(cmd), "netsh interface set interface \"%s\" disabled > nul", device->ifName); + system(cmd); + _snprintf(cmd, sizeof(cmd), "netsh interface set interface \"%s\" enabled > nul", device->ifName); + system(cmd); + + device->device_handle = open_tap_device(device->device_name); + if(device->device_handle == INVALID_HANDLE_VALUE) { + printf("Reopening TAP device \"%s\" failed\n", device->device_name); + exit(EXIT_FAILURE); + } +} + +/* ***************************************************** */ + +static int choose_adapter_callback(struct win_adapter_info *adapter, struct tuntap_dev *device) { + if(device->device_name) { + /* A device name filter was set, name must match */ + if(strcmp(device->device_name, adapter->adapterid) && + strcmp(device->device_name, adapter->adaptername)) { + /* Not found, continue */ + return(1); + } + } /* otherwise just pick the first available adapter */ + + /* Adapter found, break */ + device->device_handle = adapter->handle; + if(device->device_name) free(device->device_name); + device->device_name = _strdup(adapter->adapterid); + device->ifName = _strdup(adapter->adaptername); + return(0); +} + +/* ***************************************************** */ + +int open_wintap(struct tuntap_dev *device, + const char * devname, + const char * address_mode, /* "static" or "dhcp" */ + char *device_ip, + char *device_mask, + const char *device_mac, + int mtu, + int metric) { + + char cmd[256]; + DWORD len; + ULONG status = TRUE; + + memset(device, 0, sizeof(struct tuntap_dev)); + device->device_handle = INVALID_HANDLE_VALUE; + device->device_name = devname[0] ? _strdup(devname) : NULL; + device->ifName = NULL; + device->ip_addr = inet_addr(device_ip); + + iterate_win_network_adapters(choose_adapter_callback, device); + + if(device->device_handle == INVALID_HANDLE_VALUE) { + if(!devname[0]) + printf("No Windows tap devices found, did you run tapinstall.exe?\n"); + else + printf("Cannot find tap device \"%s\"\n", devname); + return -1; + } + + /* ************************************** */ + + /* interface index, required for routing */ + + ULONG buffer_len = 0; + IP_ADAPTER_INFO *buffer; + + // get required buffer size and allocate buffer + GetAdaptersInfo(NULL, &buffer_len); + buffer = malloc(buffer_len); + + // find device by name and get its index + if(buffer && !GetAdaptersInfo(buffer, &buffer_len)) { + IP_ADAPTER_INFO *i; + for(i = buffer; i != NULL; i = i->Next) { + if(!strcmp(device->device_name, i->AdapterName)) { + device->if_idx = i->Index; + break; + } + } + } + + free(buffer); + + /* ************************************** */ + + if(device_mac[0]) + set_interface_mac(device, device_mac); + + /* Get MAC address from tap device->device_name */ + + if(!DeviceIoControl(device->device_handle, TAP_IOCTL_GET_MAC, + device->mac_addr, sizeof(device->mac_addr), + device->mac_addr, sizeof(device->mac_addr), &len, 0)) { + printf("Could not get MAC address from Windows tap %s (%s)\n", + device->device_name, device->ifName); + return -1; + } + + device->mtu = mtu; + + printf("Open device [name=%s][ip=%s][ifName=%s][MTU=%d][mac=%02X:%02X:%02X:%02X:%02X:%02X]\n", + device->device_name, device_ip, device->ifName, device->mtu, + device->mac_addr[0] & 0xFF, + device->mac_addr[1] & 0xFF, + device->mac_addr[2] & 0xFF, + device->mac_addr[3] & 0xFF, + device->mac_addr[4] & 0xFF, + device->mac_addr[5] & 0xFF); + + /* ****************** */ + + if ( 0 == strcmp("dhcp", address_mode) ) + { + _snprintf(cmd, sizeof(cmd), + "netsh interface ip set address \"%s\" dhcp > nul", + device->ifName); + } + else + { + _snprintf(cmd, sizeof(cmd), + "netsh interface ip set address \"%s\" static %s %s > nul", + device->ifName, device_ip, device_mask); + } + + if(system(cmd) == 0) { + device->ip_addr = inet_addr(device_ip); + device->device_mask = inet_addr(device_mask); + } else + printf("WARNING: Unable to set device %s IP address [%s]\n", + device->ifName, cmd); + + /* ****************** */ + + /* MTU */ + + _snprintf(cmd, sizeof(cmd), + "netsh interface ipv4 set subinterface \"%s\" mtu=%d store=persistent > nul", + device->ifName, mtu); + + if(system(cmd) != 0) + printf("WARNING: Unable to set device %s parameters MTU=%d store=persistent [%s]\n", + device->ifName, mtu, cmd); + + /* ****************** */ + + /* metric */ + + PMIB_IPINTERFACE_ROW Row; + + if(metric) { /* try to change only if a value has been given, otherwise leave with default or as set before */ + // find & store original metric + Row = calloc(1, sizeof(MIB_IPINTERFACE_ROW)); + InitializeIpInterfaceEntry(Row); + Row->InterfaceIndex = device->if_idx; + Row->Family = AF_INET; + GetIpInterfaceEntry(Row); + + device->metric_original = Row->Metric; + device->metric = metric; + + // set new value + Row->Metric = metric; + + // store + Row->SitePrefixLength = 0; /* if not set to zero, following function call fails... */ + SetIpInterfaceEntry(Row); + + free(Row); + } + + /* ****************** */ + + + /* set driver media status to 'connected' (i.e. set the interface up) */ + if (!DeviceIoControl (device->device_handle, TAP_IOCTL_SET_MEDIA_STATUS, + &status, sizeof (status), + &status, sizeof (status), &len, NULL)) + printf("WARNING: Unable to enable TAP adapter\n"); + + /* + * Initialize overlapped structures + */ + device->overlap_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + device->overlap_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!device->overlap_read.hEvent || !device->overlap_write.hEvent) { + return -1; + } + + return(0); +} + +/* ************************************************ */ + +int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) +{ + DWORD read_size, last_err; + + ResetEvent(tuntap->overlap_read.hEvent); + if (ReadFile(tuntap->device_handle, buf, len, &read_size, &tuntap->overlap_read)) { + //printf("tun_read(len=%d)\n", read_size); + return read_size; + } + switch (last_err = GetLastError()) { + case ERROR_IO_PENDING: + WaitForSingleObject(tuntap->overlap_read.hEvent, INFINITE); + GetOverlappedResult(tuntap->device_handle, &tuntap->overlap_read, &read_size, FALSE); + return read_size; + break; + default: + printf("GetLastError() returned %d\n", last_err); + break; + } + + return -1; +} +/* ************************************************ */ + +int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) +{ + DWORD write_size; + + //printf("tun_write(len=%d)\n", len); + + ResetEvent(tuntap->overlap_write.hEvent); + if (WriteFile(tuntap->device_handle, + buf, + len, + &write_size, + &tuntap->overlap_write)) { + //printf("DONE tun_write(len=%d)\n", write_size); + return write_size; + } + switch (GetLastError()) { + case ERROR_IO_PENDING: + WaitForSingleObject(tuntap->overlap_write.hEvent, INFINITE); + GetOverlappedResult(tuntap->device_handle, &tuntap->overlap_write, + &write_size, FALSE); + return write_size; + break; + default: + break; + } + + return -1; +} + +/* ************************************************ */ + +int tuntap_open(struct tuntap_dev *device, + char *dev, + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu, + int metric) { + return(open_wintap(device, dev, address_mode, device_ip, device_mask, device_mac, mtu, metric)); +} + +/* ************************************************ */ + +void tuntap_close(struct tuntap_dev *tuntap) { + + PMIB_IPINTERFACE_ROW Row; + + if(tuntap->metric) { /* only required if a value has been given (and thus stored) */ + // find device entry + Row = calloc(1, sizeof(MIB_IPINTERFACE_ROW)); + InitializeIpInterfaceEntry(Row); + Row->InterfaceIndex = tuntap->if_idx; + Row->Family = AF_INET; + GetIpInterfaceEntry(Row); + + // restore original value + Row->Metric = tuntap->metric_original; + + // store + Row->SitePrefixLength = 0; /* if not set to zero, following function call fails... */ + SetIpInterfaceEntry(Row); + + free(Row); + } + + CloseHandle(tuntap->device_handle); +} + +/* Fill out the ip_addr value from the interface. Called to pick up dynamic + * address changes. */ +void tuntap_get_address(struct tuntap_dev *tuntap) +{ +} + +/* ************************************************ */ + +#if 0 +int main(int argc, char* argv[]) { + struct tuntap_dev tuntap; + int i; + int mtu = 1400; + + printf("Welcome to n2n\n"); + initWin32(); + open_wintap(&tuntap, "static", "1.2.3.20", "255.255.255.0", mtu, 0); + + for(i=0; i<10; i++) { + u_char buf[MTU]; + int rc; + + rc = tun_read(&tuntap, buf, sizeof(buf)); + buf[0]=2; + buf[1]=3; + buf[2]=4; + + printf("tun_read returned %d\n", rc); + rc = tun_write(&tuntap, buf, rc); + printf("tun_write returned %d\n", rc); + } + // rc = tun_open (device->device_name, IF_MODE_TUN); + WSACleanup (); + return(0); +} + +#endif diff --git a/win32/wintap.h b/win32/wintap.h new file mode 100644 index 0000000..ff46ddc --- /dev/null +++ b/win32/wintap.h @@ -0,0 +1,72 @@ +/* + (C) 2007-22 - Luca Deri +*/ + +#ifndef _WINTAP_H_ +#define _WINTAP_H_ + +#undef UNICODE +#undef _UNICODE +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include + + + +//=============================================== +// This file is included both by OpenVPN and +// the TAP-Win32 driver and contains definitions +// common to both. +//=============================================== + +//============= +// TAP IOCTLs +//============= + +#define TAP_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) + +//================= +// Registry keys +//================= + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" +#define ADAPTER_INFO_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +//====================== +// Filesystem prefixes +//====================== + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define SYSDEVICEDIR "\\Device\\" +#define USERDEVICEDIR "\\DosDevices\\Global\\" +#define TAPSUFFIX ".tap" + +//========================================================= +// TAP_COMPONENT_ID -- This string defines the TAP driver +// type -- different component IDs can reside in the system +// simultaneously. +//========================================================= + +#define TAP_COMPONENT_ID "tap0801" + +extern void initWin32(); +extern void destroyWin32(); +extern void win_print_available_adapters(); + +#endif diff --git a/wireshark/README.md b/wireshark/README.md new file mode 100644 index 0000000..4c0b6fd --- /dev/null +++ b/wireshark/README.md @@ -0,0 +1,9 @@ +Wireshark Lua plugin to dissect n2n traffic. + +Quick load: + +``` + wireshark -X lua_script:n2n.lua +``` + +NOTE: the dissector only decodes traffic on UDP port 50001. In order to decode n2n traffic on another UDP port you can use the "Decode As..." function of wireshark. diff --git a/wireshark/n2n.lua b/wireshark/n2n.lua new file mode 100644 index 0000000..ff45341 --- /dev/null +++ b/wireshark/n2n.lua @@ -0,0 +1,316 @@ +-- (C) 2019 - ntop.org and contributors + +n2n = Proto("n2n", "n2n Protocol") + +-- ############################################# + +PKT_TYPE_PING = 0 +PKT_TYPE_REGISTER = 1 +PKT_TYPE_DEREGISTER = 2 +PKT_TYPE_PACKET = 3 +PKT_TYPE_REGISTER_ACK = 4 +PKT_TYPE_REGISTER_SUPER = 5 +PKT_TYPE_REGISTER_SUPER_ACK = 6 +PKT_TYPE_REGISTER_SUPER_NAK = 7 +PKT_TYPE_FEDERATION = 8 +PKT_TYPE_PEER_INFO = 9 +PKT_TYPE_QUERY_PEER = 10 + +PKT_TRANSFORM_NULL = 1 +PKT_TRANSFORM_TWOFISH = 2 +PKT_TRANSFORM_AESCBC = 3 + +FLAG_FROM_SUPERNODE = 0x0020 +FLAG_SOCKET = 0x0040 +FLAG_OPTIONS = 0x0080 + +SOCKET_FAMILY_AF_INET = 0x0000 +SOCKET_FAMILY_AF_INET6 = 0x8000 + +-- ############################################# + +version = ProtoField.uint8("n2n.version", "version", base.DEC) +ttl = ProtoField.uint8("n2n.ttl", "ttl", base.DEC) + +packet_type_mask = 0x001f +pkt_type_2_str = { + [PKT_TYPE_PING] = "ping", + [PKT_TYPE_REGISTER] = "register", + [PKT_TYPE_DEREGISTER] = "deregister", + [PKT_TYPE_PACKET] = "packet", + [PKT_TYPE_REGISTER_ACK] = "register_ack", + [PKT_TYPE_REGISTER_SUPER] = "register_super", + [PKT_TYPE_REGISTER_SUPER_ACK] = "register_super_ack", + [PKT_TYPE_REGISTER_SUPER_NAK] = "register_super_nak", + [PKT_TYPE_FEDERATION] = "federation", + [PKT_TYPE_PEER_INFO] = "peer_info", + [PKT_TYPE_QUERY_PEER] = "query_peer", +} +packet_type = ProtoField.uint8("n2n.packet_type", "packetType", base.HEX, pkt_type_2_str, packet_type_mask) + +flags_mask = 0xffe0 +flags = ProtoField.uint16("n2n.flags", "Flags", base.HEX, nil, flags_mask) +from_supernode_flag = ProtoField.uint16("n2n.flags.from_supernode", "from_supernode", base.BOOLEAN, nil, FLAG_FROM_SUPERNODE) +socket_flag = ProtoField.uint16("n2n.flags.socket", "socket", base.BOOLEAN, nil, FLAG_SOCKET) +options_flag = ProtoField.uint16("n2n.flags.options", "options", base.BOOLEAN, nil, FLAG_OPTIONS) +community = ProtoField.string("n2n.community", "Community", base.ASCII) + +-- ############################################# + +src_mac = ProtoField.ether("n2n.src_mac", "Source") +dst_mac = ProtoField.ether("n2n.dst_mac", "Destination") +socket_info = ProtoField.none("n2n.socket", "Socket Info") +socket_family = ProtoField.uint16("n2n.socket.family", "Family", base.HEX, { + [0] = "AF_INET", +}) +socket_port = ProtoField.uint16("n2n.socket.port", "Port") +socket_ipv4 = ProtoField.ipv4("n2n.socket.ipv4", "IPv4") +socket_ipv6 = ProtoField.ipv6("n2n.socket.ipv6", "IPv6") + +-- ############################################# + +peer_info_field = ProtoField.none("n2n.peer_info", "PeerInfo") +peer_info_flags = ProtoField.uint16("n2n.peer_info.flags", "Flags") +peer_info_mac = ProtoField.ether("n2n.peer_info.query_mac", "Query") + +query_peer_field = ProtoField.none("n2n.query_peer", "QueryPeer") + +-- ############################################# + + + +packet_field = ProtoField.none("n2n.packet", "Packet") +packet_transform = ProtoField.uint16("n2n.packet.transform", "Transform", base.HEX, { + [PKT_TRANSFORM_NULL] = "Plaintext", + [PKT_TRANSFORM_TWOFISH] = "TwoFish", + [PKT_TRANSFORM_AESCBC] = "AES CBC", +}) +packet_payload = ProtoField.bytes("n2n.packet.payload", "Payload") + +-- ############################################# + +register_field = ProtoField.none("n2n.register", "Register") +register_cookie = ProtoField.uint32("n2n.register.cookie", "Cookie", base.HEX) + +register_ack_field = ProtoField.none("n2n.register_ack", "RegisterACK") +register_ack_cookie = ProtoField.uint32("n2n.register_ack.cookie", "Cookie", base.HEX) + +register_super_field = ProtoField.none("n2n.register_super", "RegisterSuper") +register_super_cookie = ProtoField.uint32("n2n.register_super.cookie", "Cookie", base.HEX) +register_super_auth_schema = ProtoField.uint16("n2n.register_super.auth.schema", "AuthSchema", base.HEX) +register_super_auth_data = ProtoField.uint16("n2n.register_super.auth.data", "AuthData", base.HEX) + +register_super_ack_field = ProtoField.none("n2n.register_super_ack", "RegisterSuperACK") +register_super_ack_cookie = ProtoField.uint32("n2n.register_super_ack.cookie", "Cookie", base.HEX) +register_super_ack_lifetime = ProtoField.uint16("n2n.register_super_ack.lifetime", "Registration Lifetime", base.DEC) +register_super_ack_num_sn = ProtoField.uint8("n2n.register_super_ack.num_sn", "Num Supernodes", base.DEC) + +-- ############################################# + +n2n.fields = { + version, ttl, packet_type, + flags, from_supernode_flag, socket_flag, options_flag, + community, + + -- Generic + src_mac, dst_mac, + socket_info, socket_family, socket_port, socket_ipv4, socket_ipv6, + + -- PKT_TYPE_REGISTER + register_field, register_cookie, + -- PKT_TYPE_PACKET + packet_field, packet_transform, packet_payload, + -- PKT_TYPE_REGISTER_ACK + register_ack_field, register_ack_cookie, + -- PKT_TYPE_REGISTER_SUPER + register_super_field, register_super_cookie, register_super_auth_schema, register_super_auth_data, + -- PKT_TYPE_REGISTER_SUPER_ACK + register_super_ack_field, register_super_ack_cookie, register_super_ack_lifetime, register_super_ack_num_sn, + -- PKT_TYPE_PEER_INFO + peer_info_field, peer_info_flags, peer_info_mac, + -- PKT_TYPE_QUERY_PEER + query_peer_field, +} + +-- ############################################# + +function dissect_socket(subtree, buffer, offset) + local sock_baselen = 4 + local sock_protolen = 0 + buffer = buffer(offset) + local sock_family = bit.band(buffer(0,4):uint(), 0xFFFF0000) + + if(sock_family == SOCKET_FAMILY_AF_INET) then + sock_protolen = 4 + elseif(sock_family == SOCKET_FAMILY_AF_INET6) then + sock_protolen = 16 + end + + local totlen = sock_baselen + sock_protolen + local socktree = subtree:add(socket_info, buffer(0, totlen)) + + socktree:add(socket_family, buffer(0, 2)) + socktree:add(socket_port, buffer(2, 2)) + + if(sock_family == SOCKET_FAMILY_AF_INET) then + socktree:add(socket_ipv4, buffer(4, sock_protolen)) + elseif(sock_family == SOCKET_FAMILY_AF_INET6) then + socktree:add(socket_ipv6, buffer(4, sock_protolen)) + end + + return offset+totlen, socktree +end + +-- ############################################# + +function dissect_register(subtree, buffer, flags) + local regtree = subtree:add(register_field, buffer) + + regtree:add(register_cookie, buffer(0,4)) + regtree:add(src_mac, buffer(4,6)) + regtree:add(dst_mac, buffer(10,6)) + + if(bit.band(flags, FLAG_SOCKET) == FLAG_SOCKET) then + dissect_socket(regtree, buffer, 16) + end + + return regtree +end + +-- ############################################# + +function dissect_register_ack(subtree, buffer, flags) + local regtree = subtree:add(register_ack_field, buffer) + + regtree:add(register_ack_cookie, buffer(0,4)) + regtree:add(src_mac, buffer(4,6)) + regtree:add(dst_mac, buffer(10,6)) + + return regtree +end + +-- ############################################# + +function dissect_packet(subtree, buffer, flags, pinfo) + local pktree = subtree:add(packet_field, buffer) + + pktree:add(src_mac, buffer(0,6)) + pktree:add(dst_mac, buffer(6,6)) + + if(bit.band(flags, FLAG_SOCKET) == FLAG_SOCKET) then + idx = dissect_socket(pktree, buffer, 12) + else + idx = 12 + end + + pktree:add(packet_transform, buffer(idx,2)) + local payload = pktree:add(packet_payload, buffer(idx+2)) + local transform = buffer(idx,2):uint() + + -- Can only dissect unencrypted data + if(transform == PKT_TRANSFORM_NULL) then + Dissector.get("eth_withoutfcs"):call(buffer(idx+2):tvb(), pinfo, payload) + end + + return pktree +end + +-- ############################################# + +function dissect_register_super(subtree, buffer, flags) + local regtree = subtree:add(register_super_field, buffer) + + regtree:add(register_super_cookie, buffer(0,4)) + regtree:add(src_mac, buffer(4,6)) + regtree:add(register_super_auth_schema, buffer(10,2)) + regtree:add(register_super_auth_data, buffer(12,2)) + + return regtree +end + +-- ############################################# + +function dissect_register_super_ack(subtree, buffer, flags) + local regtree = subtree:add(register_super_ack_field, buffer) + + regtree:add(register_super_ack_cookie, buffer(0,4)) + regtree:add(dst_mac, buffer(4,6)) + regtree:add(register_super_ack_lifetime, buffer(10,2)) + local idx = dissect_socket(regtree, buffer, 12) + regtree:add(register_super_ack_num_sn, buffer(idx, 1)) + + return regtree +end + +-- ############################################# + +function dissect_peer_info(subtree, buffer, flags) + local peertree = subtree:add(peer_info_field, buffer) + + peertree:add(peer_info_flags, buffer(0,2)) + peertree:add(peer_info_mac, buffer(2,6)) + dissect_socket(peertree, buffer, 8) + + return peertree +end + +-- ############################################# + +function dissect_query_peer(subtree, buffer, flags) + local peertree = subtree:add(query_peer_field, buffer) + + peertree:add(src_mac, buffer(0,6)) + peertree:add(dst_mac, buffer(6,6)) + + return peertree +end + +-- ############################################# + +function n2n.dissector(buffer, pinfo, tree) + local length = buffer:len() + if length < 20 then return end + + pinfo.cols.protocol = n2n.name + + local pkt_type = bit.band(buffer(2,2):uint(), packet_type_mask) + local subtree = tree:add(n2n, buffer(), string.format("n2n Protocol, Type: %s", pkt_type_2_str[pkt_type] or "Unknown")) + + -- Common + subtree:add(version, buffer(0,1)) + subtree:add(ttl, buffer(1,1)) + subtree:add(packet_type, buffer(2,2)) + local flags_buffer = buffer(2,2) + local flags_tree = subtree:add(flags, flags_buffer) + subtree:add(community, buffer(4,16)) + + -- Flags + flags_tree:add(from_supernode_flag, flags_buffer) + flags_tree:add(socket_flag, flags_buffer) + flags_tree:add(options_flag, flags_buffer) + + -- Packet specific + local flags = bit.band(buffer(2,2):uint(), flags_mask) + local typebuf = buffer(20) + + if(pkt_type == PKT_TYPE_REGISTER) then + dissect_register(subtree, typebuf, flags) + elseif(pkt_type == PKT_TYPE_REGISTER) then + dissect_register_ack(subtree, typebuf, flags) + elseif(pkt_type == PKT_TYPE_PACKET) then + dissect_packet(subtree, typebuf, flags, pinfo) + elseif(pkt_type == PKT_TYPE_REGISTER_SUPER) then + dissect_register_super(subtree, typebuf, flags) + elseif(pkt_type == PKT_TYPE_REGISTER_SUPER_ACK) then + dissect_register_super_ack(subtree, typebuf, flags) + elseif(pkt_type == PKT_TYPE_PEER_INFO) then + dissect_peer_info(subtree, typebuf, flags) + elseif(pkt_type == PKT_TYPE_QUERY_PEER) then + dissect_query_peer(subtree, typebuf, flags) + end +end + +-- ############################################# + +local udp_port = DissectorTable.get("udp.port") +udp_port:add(50001, n2n)