diff --git a/.github/workflows/action-lint.yml b/.github/workflows/action-lint.yml new file mode 100644 index 0000000..f5cde26 --- /dev/null +++ b/.github/workflows/action-lint.yml @@ -0,0 +1,35 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Fabrício Barros Cabral +# SPDX-License-Identifier: MIT +--- +name: action-lint +'on': + push: + branches: + - main + - master + pull_request: + branches: + - main + - master +defaults: + run: + shell: bash -xeuo pipefail {0} +permissions: + contents: read +jobs: + action-lint: + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Download and installs actionlint + # yamllint disable rule:line-length + run: | + curl -sS -L --retry 3 -o /tmp/download-actionlint.bash \ + https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash + bash /tmp/download-actionlint.bash latest /tmp + # yamllint enable rule:line-length + - name: Check workflow files + run: /tmp/actionlint -color diff --git a/.github/workflows/action-security.yml b/.github/workflows/action-security.yml new file mode 100644 index 0000000..97c0ab5 --- /dev/null +++ b/.github/workflows/action-security.yml @@ -0,0 +1,48 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Fabrício Barros Cabral +# SPDX-License-Identifier: MIT +--- +name: action-security +'on': + push: + branches: + - main + - master + pull_request: + branches: + - main + - master +defaults: + run: + shell: bash -xeuo pipefail {0} +jobs: + action-security: + runs-on: ubuntu-24.04 + permissions: + security-events: write + contents: read + actions: read + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Download and installs zizmor + run: | + site="https://github.com/zizmorcore/zizmor/releases/latest/download" + file="zizmor-x86_64-unknown-linux-gnu.tar.gz" + curl -sS -L --retry 3 -o /tmp/${file} ${site}/${file} + mkdir /tmp/as + tar xfz /tmp/${file} -C /tmp/as --no-same-owner --no-same-permissions + chmod +x /tmp/as/zizmor + - name: Check security in workflow files + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + /tmp/as/zizmor .github/workflows --config .github/zizmor.yml + - name: Stop pipeline if issues are found + run: | + if grep -q "error" zizmor.log; then + echo "Zizmor found some security issues:" + cat zizmor.log + exit 1 + fi diff --git a/.github/workflows/action-update.yml b/.github/workflows/action-update.yml new file mode 100644 index 0000000..d2d8997 --- /dev/null +++ b/.github/workflows/action-update.yml @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Fabrício Barros Cabral +# SPDX-License-Identifier: MIT +--- +name: action-update +'on': + schedule: + - cron: '0 2 * * *' + workflow_dispatch: +defaults: + run: + shell: bash -xeuo pipefail {0} +permissions: + contents: read +jobs: + action-update: + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Setup node.js + uses: actions/setup-node@v5 + with: + node-version: '22' + - name: Run renovate + uses: renovatebot/github-action@7876d7a812254599d262d62b6b2c2706018258a2 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/c-cpp-build.yml b/.github/workflows/c-cpp-build.yml new file mode 100644 index 0000000..63ac4f7 --- /dev/null +++ b/.github/workflows/c-cpp-build.yml @@ -0,0 +1,204 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Fabrício Barros Cabral +# SPDX-License-Identifier: MIT +--- +name: c-cpp-build +'on': + push: + branches: + - main + - master + pull_request: + branches: + - main + - master +defaults: + run: + shell: bash -xeuo pipefail {0} +permissions: + contents: read +jobs: + c-cpp-linux-build: + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Configure apt cache + uses: actions/cache@v4 + with: + path: /var/cache/apt/archives + key: ${{ runner.os }}-apt-${{ hashFiles('**/apt-packages.txt') }} + restore-keys: ${{ runner.os }}-apt- + - name: Install dependencies + run: | + sudo apt-get update + if [ -s apt-packages.txt ]; then + xargs -a apt-packages.txt sudo apt-get install \ + -y --no-install-recommends + fi + - name: Configure and build + run: | + [ -x ./autogen.sh ] && ./autogen.sh + [ -x ./configure ] && ./configure + [ -s Makefile ] || { + echo "I couldn't find an autogen.sh, configure, or Makefile." + echo "Please check your files." + exit 1 + } + make + - name: Get properties from configure.ac + id: props + # yamllint disable rule:line-length + run: | + name="$(sed -n 's/AC_INIT(\[\([^]]*\)\],.*/\1/p' configure.ac)" + echo "name=${name}" >> "${GITHUB_OUTPUT}" + version="$(sed -n 's/AC_INIT(\[[^]]*\], \[\([^]]*\)\], \[[^]]*\])/\1/p' configure.ac)" + echo "version=${version}" >> "${GITHUB_OUTPUT}" + # yamllint enable rule:line-length + - name: Create source package + run: | + make dist + - name: Create Linux binary package + run: | + make binary-dist + - name: Prepare packages to distribution + env: + NAME: ${{ steps.props.outputs.name }} + VERSION: ${{ steps.props.outputs.version }} + run: | + # Sanitize variables for security purposes + safe_name="$(echo "${NAME}" | tr -cd '[:alnum:]._-' )" + safe_version="$(echo "${VERSION}" | tr -cd '[:alnum:]._-' )" + + # Check if variables are empty + [ -z "$safe_name" ] && { echo "Invalid name"; exit 1; } + [ -z "$safe_version" ] && { echo "Invalid version"; exit 1; } + + # Check if files exists + src="${safe_name}-${safe_version}.tar.gz" + bin="${safe_name}-${safe_version}-bin.tar.gz" + [ -f "$src" ] || { echo "File '${src}' not found"; exit 1; } + [ -f "$bin" ] || { echo "File '${bin}' not found"; exit 1; } + + # Move files + mkdir -p dist + mv "${src}" dist/ + mv "${bin}" "dist/${safe_name}-${safe_version}-linux.tar.gz" + c-cpp-macos-build: + runs-on: macos-15 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Install dependencies + run: | + brew update + if [ -s brew-packages.txt ]; then + xargs brew install < brew-packages.txt + fi + - name: Configure and build + run: | + [ -x ./autogen.sh ] && ./autogen.sh + [ -x ./configure ] && ./configure + [ -s Makefile ] || { + echo "I couldn't find an autogen.sh, configure, or Makefile." + echo "Please check your files." + exit 1 + } + make + - name: Get properties from configure.ac + id: props + # yamllint disable rule:line-length + run: | + name="$(sed -n 's/AC_INIT(\[\([^]]*\)\],.*/\1/p' configure.ac)" + echo "name=${name}" >> "${GITHUB_OUTPUT}" + version="$(sed -n 's/AC_INIT(\[[^]]*\], \[\([^]]*\)\], \[[^]]*\])/\1/p' configure.ac)" + echo "version=${version}" >> "${GITHUB_OUTPUT}" + # yamllint enable rule:line-length + - name: Create macOS binary package + run: | + make binary-dist + - name: Prepare package to distribution + env: + NAME: ${{ steps.props.outputs.name }} + VERSION: ${{ steps.props.outputs.version }} + run: | + # Sanitize variables for security purposes + safe_name="$(echo "${NAME}" | tr -cd '[:alnum:]._-' )" + safe_version="$(echo "${VERSION}" | tr -cd '[:alnum:]._-' )" + + # Check if variables are empty + [ -z "$safe_name" ] && { echo "Invalid name"; exit 1; } + [ -z "$safe_version" ] && { echo "Invalid version"; exit 1; } + + # Check if file exist + bin="${safe_name}-${safe_version}-bin.tar.gz" + [ -f "$bin" ] || { echo "File '${bin}' not found"; exit 1; } + + # Move file + mkdir -p dist + mv "${bin}" dist/"${safe_name}-${safe_version}-macos.tar.gz" + c-cpp-windows-build: + runs-on: windows-2025 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Install and setup MSYS2 with MinGW64 + uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 + with: + msystem: MINGW64 + update: true + install: >- + base-devel + autoconf + automake + libtool + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-make + mingw-w64-x86_64-pkgconf + mingw-w64-x86_64-libpcap + mingw-w64-x86_64-tcl + - name: Configure and build + shell: msys2 {0} + run: | + [ -x ./autogen.sh ] && ./autogen.sh + [ -x ./configure ] && ./configure --host=x86_64-w64-mingw64 + [ -s Makefile ] || { + echo "I couldn't find an autogen.sh, configure, or Makefile." + echo "Please check your files." + exit 1 + } + make + - name: Get properties from configure.ac + id: props + # yamllint disable rule:line-length + run: | + name="$(sed -n 's/AC_INIT(\[\([^]]*\)\],.*/\1/p' configure.ac)" + echo "name=${name}" >> "${GITHUB_OUTPUT}" + version="$(sed -n 's/AC_INIT(\[[^]]*\], \[\([^]]*\)\], \[[^]]*\])/\1/p' configure.ac)" + echo "version=${version}" >> "${GITHUB_OUTPUT}" + # yamllint enable rule:line-length + - name: Create source package + run: | + make dist + - name: Create Windows binary package + run: | + make binary-dist + - name: Prepare packages to distribution + env: + NAME: ${{ steps.props.outputs.name }} + VERSION: ${{ steps.props.outputs.version }} + # yamllint disable rule:line-length + run: | + md dist + move "${NAME}-${VERSION}-bin.zip" "dist/${NAME}-${VERSION}-windows.zip" + # yamllint enable rule:line-length + - name: Upload Windows artifacts + uses: actions/upload-artifact@v4 + with: + name: windows-dist + path: dist/*.zip diff --git a/.github/workflows/c-cpp-release.yml b/.github/workflows/c-cpp-release.yml new file mode 100644 index 0000000..907e11e --- /dev/null +++ b/.github/workflows/c-cpp-release.yml @@ -0,0 +1,161 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Fabrício Barros Cabral +# SPDX-License-Identifier: MIT +--- +name: c-cpp-release +'on': + push: + tags: + - '[0-9]*.[0-9]*.[0-9]*' +defaults: + run: + shell: bash -xeuo pipefail {0} +permissions: + contents: read +jobs: + c-cpp-linux-build: + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Install dependencies + run: | + sudo apt-get update + if [ -s apt-packages.txt ]; then + xargs -a apt-packages.txt sudo apt-get install \ + -y --no-install-recommends + fi + - name: Configure and build + run: | + [ -x ./autogen.sh ] && ./autogen.sh + [ -x ./configure ] && ./configure + [ -s Makefile ] || { + echo "I couldn't find an autogen.sh, configure, or Makefile." + echo "Please check your files." + exit 1 + } + make + - name: Get properties from configure.ac + id: props + # yamllint disable rule:line-length + run: | + name="$(sed -n 's/AC_INIT(\[\([^]]*\)\],.*/\1/p' configure.ac)" + echo "name=${name}" >> "${GITHUB_OUTPUT}" + version="$(sed -n 's/AC_INIT(\[[^]]*\], \[\([^]]*\)\], \[[^]]*\])/\1/p' configure.ac)" + echo "version=${version}" >> "${GITHUB_OUTPUT}" + # yamllint enable rule:line-length + - name: Create source package + run: | + make dist + - name: Create Linux binary package + run: | + make binary-dist + - name: Prepare packages to distribution + env: + NAME: ${{ steps.props.outputs.name }} + VERSION: ${{ steps.props.outputs.version }} + run: | + # Sanitize variables for security purposes + safe_name="$(echo "${NAME}" | tr -cd '[:alnum:]._-' )" + safe_version="$(echo "${VERSION}" | tr -cd '[:alnum:]._-' )" + + # Check if variables are empty + [ -z "$safe_name" ] && { echo "Invalid name"; exit 1; } + [ -z "$safe_version" ] && { echo "Invalid version"; exit 1; } + + # Check if files exists + src="${safe_name}-${safe_version}.tar.gz" + bin="${safe_name}-${safe_version}-bin.tar.gz" + [ -f "$src" ] || { echo "File '${src}' not found"; exit 1; } + [ -f "$bin" ] || { echo "File '${bin}' not found"; exit 1; } + + # Move files + mkdir -p dist + mv "${src}" dist/ + mv "${bin}" "dist/${safe_name}-${safe_version}-linux.tar.gz" + c-cpp-macos-build: + runs-on: macos-15 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Install dependencies + run: | + brew update + if [ -s brew-packages.txt ]; then + xargs brew install < brew-packages.txt + fi + - name: Configure and build + run: | + [ -x ./autogen.sh ] && ./autogen.sh + [ -x ./configure ] && ./configure + [ -s Makefile ] || { + echo "I couldn't find an autogen.sh, configure, or Makefile." + echo "Please check your files." + exit 1 + } + make + - name: Get properties from configure.ac + id: props + # yamllint disable rule:line-length + run: | + name="$(sed -n 's/AC_INIT(\[\([^]]*\)\],.*/\1/p' configure.ac)" + echo "name=${name}" >> "${GITHUB_OUTPUT}" + version="$(sed -n 's/AC_INIT(\[[^]]*\], \[\([^]]*\)\], \[[^]]*\])/\1/p' configure.ac)" + echo "version=${version}" >> "${GITHUB_OUTPUT}" + # yamllint enable rule:line-length + - name: Create macOS binary package + run: | + make binary-dist + - name: Prepare package to distribution + env: + NAME: ${{ steps.props.outputs.name }} + VERSION: ${{ steps.props.outputs.version }} + run: | + # Sanitize variables for security purposes + safe_name="$(echo "${NAME}" | tr -cd '[:alnum:]._-' )" + safe_version="$(echo "${VERSION}" | tr -cd '[:alnum:]._-' )" + + # Check if variables are empty + [ -z "$safe_name" ] && { echo "Invalid name"; exit 1; } + [ -z "$safe_version" ] && { echo "Invalid version"; exit 1; } + + # Check if file exist + bin="${safe_name}-${safe_version}-bin.tar.gz" + [ -f "$bin" ] || { echo "File '${bin}' not found"; exit 1; } + + # Move file + mkdir -p "dist" + mv "${bin}" dist/"${safe_name}-${safe_version}-macos.tar.gz" + c-cpp-release: + runs-on: ubuntu-24.04 + needs: [c-cpp-linux-build, c-cpp-macos-build] + permissions: + contents: write + steps: + - name: Download Linux artifacts + uses: actions/download-artifact@v5 + with: + name: linux-dist + path: dist + - name: Download macOS artifacts + uses: actions/download-artifact@v5 + with: + name: macos-dist + path: dist + - name: Set release tag + id: tag + run: | + # Detects which tag triggered the build + echo "tag=${GITHUB_REF##*/}" >> "${GITHUB_OUTPUT}" + - name: Release artifacts + # yamllint disable-line rule:line-length + uses: softprops/action-gh-release@fbadcc90e88ecface60a0a0d123795b784ceb239 + with: + tag_name: ${{ steps.tag.outputs.tag }} + files: dist/*.tar.gz + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/markdown-lint.yml b/.github/workflows/markdown-lint.yml new file mode 100644 index 0000000..660b6b0 --- /dev/null +++ b/.github/workflows/markdown-lint.yml @@ -0,0 +1,35 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Fabrício Barros Cabral +# SPDX-License-Identifier: MIT +--- +name: markdown-lint +'on': + push: + branches: + - main + - master + pull_request: + branches: + - main + - master +defaults: + run: + shell: bash -xeuo pipefail {0} +permissions: + contents: read +concurrency: + group: markdown-lint-${{ github.ref }} + cancel-in-progress: true +jobs: + markdown-lint: + timeout-minutes: 15 + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Lint Markdown files + # yamllint disable-line rule:line-length + uses: DavidAnson/markdownlint-cli2-action@0a509faff138d7a586d9ee1fea0f5fefbddb7946 + with: + globs: '**/*.md' diff --git a/.github/workflows/spell-lint.yml b/.github/workflows/spell-lint.yml new file mode 100644 index 0000000..3f51fbe --- /dev/null +++ b/.github/workflows/spell-lint.yml @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Fabrício Barros Cabral +# SPDX-License-Identifier: MIT +--- +name: spell-lint +'on': + push: + branches: + - main + - master + pull_request: + branches: + - main + - master +defaults: + run: + shell: bash -xeuo pipefail {0} +permissions: + contents: read +jobs: + spell-lint: + timeout-minutes: 15 + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Check files for typos (spell checker) + uses: crate-ci/typos@85f62a8a84f939ae994ab3763f01a0296d61a7ee diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml new file mode 100644 index 0000000..bd7cc73 --- /dev/null +++ b/.github/workflows/yaml-lint.yml @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Fabrício Barros Cabral +# SPDX-License-Identifier: MIT +--- +name: yaml-lint +'on': + push: + branches: + - main + - master + pull_request: + branches: + - main + - master +defaults: + run: + shell: bash -xeuo pipefail {0} +permissions: + contents: read +jobs: + yaml-lint: + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Lint YAML files + uses: ibiqlik/action-yamllint@b74a2626a991d676b6ec243a6458ff86cccf2d2d diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 0000000..bf41986 --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: Copyright (C) 2025 Fabrício Barros Cabral +# SPDX-License-Identifier: MIT +--- +rules: + forbidden-uses: + config: + deny: + - actions/checkout@v1 diff --git a/.gitignore b/.gitignore index 5ac1006..e27e983 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,21 @@ hping3 *.swp Makefile -byteorder -byteorder.h -systype.h +aclocal.m4 +autom4te.cache/ +config.h +config.h.in~ +config.log +config.status +configure~ +libtool +src/.deps/ +src/libars.a +stamp-h1 +.vscode/ +Makefile.in +build/ +config.h.in +configure +m4/ +src/Makefile.in diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..07866b0 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,18 @@ +# Files to put into source package +EXTRA_DIST = src/*.h BUGS CHANGES KNOWN-BUGS img/* lib/* RFCs/* docs/* + +SUBDIRS = src +ACLOCAL_AMFLAGS = -Im4 + +BIN_DISTDIR = $(PACKAGE_NAME)-$(PACKAGE_VERSION) + +.PHONY: install-bin-local binary-dist + +install-bin-local: + $(MAKE) -C src install-bin-local + +binary-dist: + $(MAKE) install-bin-local + @ABS_DISTDIR=$$(pwd)/$(BIN_DISTDIR); \ + tar cvfz $(PACKAGE_NAME)-$(PACKAGE_VERSION)-bin.tar.gz -C $$ABS_DISTDIR .; \ + rm -rf $$ABS_DISTDIR diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index 5cccbdd..0000000 --- a/Makefile.in +++ /dev/null @@ -1,92 +0,0 @@ -# $smu-mark$ -# $name: Makefile.in$ -# $author: Salvatore Sanfilippo 'antirez'$ -# $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ -# $license: This software is under GPL version 2 of license$ -# $date: Sun Jul 25 17:56:15 MET DST 1999$ -# $rev: 3$ - -CC= gcc -AR=/usr/bin/ar -RANLIB=/usr/bin/ranlib -CCOPT= -O2 -Wall @PCAP_INCLUDE@ @TCL_INC@ @USE_TCL@ -DEBUG= -g -#uncomment the following if you need libpcap based build under linux -#(not raccomanded) -COMPILE_TIME= -INSTALL_MANPATH=@MANPATH@ -@PCAP@ - -ARSOBJ = ars.o apd.o split.o rapd.o - -OBJ= main.o getifname.o getlhs.o \ - parseoptions.o datafiller.o \ - datahandler.o gethostname.o \ - binding.o getusec.o opensockraw.o \ - logicmp.o waitpacket.o resolve.o \ - sendip.o sendicmp.o sendudp.o \ - sendtcp.o cksum.o statistics.o \ - usage.o version.o antigetopt.o \ - sockopt.o listen.o \ - sendhcmp.o memstr.o rtt.o \ - relid.o sendip_handler.o \ - libpcap_stuff.o memlockall.o memunlockall.o \ - memlock.o memunlock.o ip_opt_build.o \ - display_ipopt.o sendrawip.o signal.o send.o \ - strlcpy.o arsglue.o random.o scan.o \ - hstring.o script.o interface.o \ - adbuf.o hex.o apdutils.o sbignum.o \ - sbignum-tables.o $(ARSOBJ) - -all: .depend hping3 - -dep: .depend -.depend: - @echo Making dependences - @$(CC) -MM *.c > .depend - -libars.a: $(ARSOBJ) - $(AR) rc $@ $^ - $(RANLIB) $@ - -hping3: byteorder.h $(OBJ) - $(CC) -o hping3 $(CCOPT) $(DEBUG) $(OBJ) -L/usr/local/lib $(PCAP) @SOLARISLIB@ @TCL_LIB@ - @echo - ./hping3 -v - @echo "use \`make strip' to strip hping3 binary" - @echo "use \`make install' to install hping3" - -hping3-static: byteorder.h $(OBJ) - $(CC) -static -o hping3-static $(CCOPT) $(DEBUG) $(OBJ) -L/usr/local/lib $(PCAP) @SOLARISLIB@ @TCL_LIB@ -ldl - -byteorder.h: - ./configure - -.c.o: - $(CC) -c $(CCOPT) $(DEBUG) $(COMPILE_TIME) $< - -clean: - rm -rf hping3 *.o libars.a - -distclean: - rm -rf hping3 *.o byteorder byteorder.h systype.h Makefile libars.a .depend - -install: hping3 - cp -f hping3 /usr/sbin/ - chmod 755 /usr/sbin/hping3 - ln -s /usr/sbin/hping3 /usr/sbin/hping - ln -s /usr/sbin/hping3 /usr/sbin/hping2 - @if [ -d ${INSTALL_MANPATH}/man8 ]; then \ - cp ./docs/hping3.8 ${INSTALL_MANPATH}/man8; \ - chmod 644 ${INSTALL_MANPATH}/man8/hping3.8; \ - else \ - echo "@@@@@@ WARNING @@@@@@"; \ - echo "Can't install the man page: ${INSTALL_MANPATH}/man8 does not exist"; \ - fi - -strip: hping3 - @ls -l ./hping3 - strip hping3 - @ls -l ./hping3 - -include .depend diff --git a/adbuf.c b/adbuf.c deleted file mode 100644 index bb55ab0..0000000 --- a/adbuf.c +++ /dev/null @@ -1,375 +0,0 @@ -/* adbuf.c - dynamic buffers support - * - * Copyright(C) 2001-2003 Salvatore Sanfilippo - * All rights reserved. - * - * ----------------------------------------------------------------------------- - * Design principles: - * - * - This library is little and probably not so flexible nor - * full-featured. The goal is to have something of useful - * enough to build stuff like mysql queries without to care - * about allocation, but with very simple code so that security - * auditing is quite simple. - * - security is more important than speed in this context, so there - * is some redundant and useless check to prevent that some unsane use - * become a security problem. - * - while the library is binary-safe the buffers are implicitly - * nul termined. Even an empty buffer just initialized points - * to an empty nul termined string. This prevents problems passing - * strings that the user never nul-termined to functions that - * expects nul-termined strings. - * - memory is more important than speed in this context, so we do often - * realloc to change the buffer size even if not required. - * This should protect about strange usage patterns that may result - * in a lot of memory allocated. - * - * ----------------------------------------------------------------------------- - * Security auditing history: - * format is SECAUDIT(date)(time spent in seconds)(audited part) - * - * SECAUDIT(Dec 18 2001)(3600)(all) - * SECAUDIT(Aug 19 2003)(600)(adbuf_printf) - * - * After the last security auditing the code changed, so a new - * auditing is needed as fast as possible. - * Remember to audit adbuf.h too. - * - * ----------------------------------------------------------------------------- - * CHANGES - * - * 18 Aug 2003 - Changes section just created. - * 19 Aug 2003 - Added adbuf_printf(). - * - * ----------------------------------------------------------------------------- - * HISTORY OF SECURITY VULNERABILITIES - * - * - Nothing discovered for now. - * - * ----------------------------------------------------------------------------- - * TODO - * - * - adbuf_slice(), with Python-like semantics - * - adbuf_split(), similar to the TCL split command - * - minimal documentation - */ - -/* $Id: adbuf.c,v 1.1.1.1 2003/08/31 17:24:00 antirez Exp $ */ - -#include -#include -#include -#include -#include - -#include "adbuf.h" - -/* initialize a new buffer. The new empty buffer will - * appear as an empty nul terminated string to functions - * that expects a string */ -int adbuf_init(struct adbuf *b) -{ - b->buf = malloc(1); - /* note that if the allocation fails b->buf is set to NULL - * so it's safe to call adbuf_free() after a failed initialization */ - if (b->buf == NULL) - return 1; - b->buf[0] = '\0'; - b->size = 1; - b->left = 1; - return 0; -} - -/* free a buffer */ -void adbuf_free(struct adbuf *b) -{ - if (b->buf) { /* not really needed with sane libC */ - free(b->buf); - b->buf = NULL; - } -} - -/* reset the buffer */ -int adbuf_reset(struct adbuf *b) -{ - adbuf_free(b); - return adbuf_init(b); -} - -/* add data to the buffer 'b'. return 0 on success, 1 on out of memory. - * len = 0 and data = NULL is valid */ -int adbuf_add(struct adbuf *b, void *data, size_t len) -{ - if (adbuf_ptr(b) == NULL) - return 1; /* bad buffer in input */ - if (len == 0) - return 0; /* nothing to add */ - if ((len+1) > b->left) { /* need one more byte to add a nul term */ - size_t newsz = b->size + len + ADBUF_INCR; - void *t = realloc(b->buf, newsz); - - if (t == NULL) - return 1; /* out of memory */ - b->buf = t; - b->left += len + ADBUF_INCR; - b->size = newsz; - } - memcpy(b->buf + adbuf_used(b), data, len); - b->buf[adbuf_used(b)+len] = '\0'; /* always nul term */ - b->left -= len; - return 0; -} - -/* adbuf_addchar() is like adbuf_add() when {len} = 1, but sligthly - * optmized to add just one byte */ -int adbuf_addchar(struct adbuf *b, int c) -{ - if (adbuf_ptr(b) == NULL) - return 1; /* bad buffer in input */ - if (b->left >= 2) { - unsigned char *p = (unsigned char*) b->buf + adbuf_used(b); - - *p = c; - *(p+1) = '\0'; - b->left -= 1; - return 0; - } else { - unsigned char t[1]; - - t[0] = c; - return adbuf_add(b, &t, 1); - } - return 0; /* unreached */ -} - -/* add the given nul terminated string */ -int adbuf_strcat(struct adbuf *b, char *string) -{ - return adbuf_add(b, string, strlen(string)); -} - -/* concatenate the buffer b to the buffer a */ -int adbuf_cat(struct adbuf *a, struct adbuf *b) -{ - return adbuf_add(a, b->buf, adbuf_used(b)); -} - -/* cut the buffer to 'count' bytes on the right. If the used buffer is - * already smaller than 'count' no operation is performed. - * The function preserves the nul term. - * On success zero is returned. The function returns 1 on out of memory */ -int adbuf_cut(struct adbuf *b, size_t count) -{ - char *t; - - if (adbuf_ptr(b) == NULL) - return 1; /* bad buffer in input */ - if (count >= adbuf_used(b)) - return 0; - count++; /* preserve space for the nul term */ - t = realloc(b->buf, count); - if (t == NULL) - return 1; /* out of memory */ - t[count-1] = '\0'; - b->buf = t; - b->size = count; - b->left = 1; /* the nul term is conceptually free space */ - return 0; -} - -/* discard count characters on the left */ -int adbuf_ltrim(struct adbuf *b, size_t count) -{ - char *t; - size_t newlen; - - if (adbuf_ptr(b) == NULL) - return 1; /* bad buffer in input */ - if (count == 0) /* nothing to trim */ - return 0; - /* to discard all the buffer on the left is just - * the same as to reset the buffer */ - if (count >= adbuf_used(b)) - return adbuf_reset(b); - newlen = adbuf_used(b)-count; - t = malloc(newlen+1); /* add one byte for the nul term */ - if (t == NULL) - return 1; /* out of memory */ - memcpy(t, adbuf_ptr(b)+count, newlen); - t[newlen] = '\0'; - free(b->buf); - b->buf = t; - b->size = newlen+1; - b->left = 1; - return 0; -} - -/* discard count caracters on the right */ -int adbuf_rtrim(struct adbuf *b, size_t count) -{ - return adbuf_cut(b, adbuf_used(b)-count); -} - -#define ADBUF_ITOABUFSZ 32 /* ok for 64bit integers and more */ - -/* add the string rappresentation of the long integer l */ -int adbuf_add_long(struct adbuf *b, long l) -{ - int n = 0; - char s[ADBUF_ITOABUFSZ]; - char *p = s+ADBUF_ITOABUFSZ-1; - - *p-- = '\0'; - if (l < 0) { - n = 1; - l = -l; - } - while(p > s) { - *p-- = '0' + (l % 10); - l /= 10; - if (l == 0) - break; - } - if (n) - *p-- = '-'; - p++; - return adbuf_strcat(b, p); -} - -/* the same as adbuf_add_long() but with unsigned integers */ -int adbuf_add_ulong(struct adbuf *b, unsigned long l) -{ - char s[ADBUF_ITOABUFSZ]; - char *p = s+ADBUF_ITOABUFSZ-1; - *p-- = '\0'; - while(p >= s) { - *p-- = '0' + (l % 10); - l /= 10; - if (l == 0) - break; - } - p++; - return adbuf_strcat(b, p); -} - -/* clone the buffer src in the buffer dst. - * The buffers will be indipendent */ -int adbuf_clone(struct adbuf *src, struct adbuf *dst) -{ - if (adbuf_ptr(src) == NULL) - return 1; /* bad buffer in input */ - if (adbuf_init(dst)) - return 1; /* out of memory */ - return adbuf_add(dst, adbuf_ptr(src), adbuf_used(src)); -} - -/* Concat to the buffer using printf-like format. - * Note that while this function try to detect - * non-C99 vsnprintf() behaviour, it can be - * unsafe with some vsnprintf() implementation. - * - * On Linux with glibc >= 2.1, and recent *BSDs, and - * in any other system with a C99-wise vsprintf(), it is sane. - * On Linux with glibc < 2.1 it should be still secure, - * but the behaviour is different (unable to handle strings - * with more than ADBUF_PRINTF_BUFSZ chars). - * On other non-C99 systems be prepared to random results. */ -#define ADBUF_PRINTF_BUFSZ 1024 -int adbuf_printf(struct adbuf *dst, const char *fmt, ...) -{ - char buf[ADBUF_PRINTF_BUFSZ]; - int retval; - va_list ap; - - va_start(ap, fmt); - retval = vsnprintf(buf, ADBUF_PRINTF_BUFSZ, fmt, ap); - buf[ADBUF_PRINTF_BUFSZ-1] = '\0'; - va_end(ap); - - if (retval <= -1) { /* pre-C99 vsnprintf() behaviour */ - /* We just append the output without to care - * about a too slow buffer. This isn't a security - * issue, but the semantics of adbuf_printf() changes - * on this systems. */ - return adbuf_add(dst, buf, strlen(buf)); - } - if (retval >= ADBUF_PRINTF_BUFSZ) { /* PRINTF_BUFSZ wasn't enough */ - /* Use dynamic allocation */ - char *dynbuf; - int newretval; - - if ((dynbuf = malloc(retval+1)) == NULL) - return 1; /* Out of memory */ - va_start(ap, fmt); - newretval = vsnprintf(dynbuf, retval+1, fmt, ap); - dynbuf[retval] = '\0'; - va_end(ap); - - /* If we can trust the return value, we can avoid - * strlen() */ - if (newretval == retval) { - int rv; - rv = adbuf_add(dst, dynbuf, retval); - free(dynbuf); - return rv; - } else { /* On strange results we are more prudent */ - int rv; - rv = adbuf_add(dst, dynbuf, strlen(dynbuf)); - free(dynbuf); - return rv; - } - } else { /* The simple case */ - return adbuf_add(dst, buf, retval); - } -} - -#ifdef TEST_MAIN - -#include - -int main(void) -{ - struct adbuf b, bb; - int add = 0, i; - - adbuf_init(&b); - for(i = 0; i < 6; i++) - adbuf_strcat(&b, ".,;-+*#*+-;,."); - while(adbuf_used(&b) > 0) { - for (i = 0; i < add; i++) printf(" "); - printf("%s\n", adbuf_ptr(&b)); - adbuf_rtrim(&b, 1); - adbuf_ltrim(&b, 1); - add++; - } - adbuf_free(&b); - adbuf_init(&b); - for (i = 0; i < 6000; i++) { - char c; - for (c = 'A'; c <= 'Z'; c++) - adbuf_addchar(&b, c); - } - adbuf_rtrim(&b, adbuf_used(&b)-500); - printf("%s\n", adbuf_ptr(&b)); - adbuf_free(&b); - adbuf_init(&b); - adbuf_strcat(&b, "adbuf_printf with small output: "); - adbuf_printf(&b, "%d %04x", 123456789, 123456789); - printf("%s\n", adbuf_ptr(&b)); - adbuf_reset(&b); - for (i = 0; i < 1024; i++) { - adbuf_addchar(&b, 'X'); - } - adbuf_init(&bb); - adbuf_printf(&bb, "%s---%s", - adbuf_ptr(&b), adbuf_ptr(&b)); - adbuf_free(&b); - printf("bif printf test... "); - if (strlen(adbuf_ptr(&bb)) == (1024*2)+3) - printf("PASSED\n"); - else - printf("FALIED!!!\n"); - adbuf_free(&bb); - return 0; -} -#endif /* TEST_MAIN */ diff --git a/antigetopt.c b/antigetopt.c deleted file mode 100644 index 892c23e..0000000 --- a/antigetopt.c +++ /dev/null @@ -1,297 +0,0 @@ -/* antigetopt -- a getopt replacement - * Copyright(C) 2001 Salvatore Sanfilippo - * This software is released under the GPL license - * see the COPYING file for more information */ - -/* $Id: antigetopt.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -/* TODO: - * argument list sanity check */ - -#include -#include -#include - -#include "antigetopt.h" - -/* global vars */ -char *ago_optarg = NULL; -char *ago_optname = NULL; -char ago_optchar = '\0'; - -/* static vars */ -static struct ago_exception { - int (*tester)(void); - char *msg; -} ago_exceptions[3] = { - { NULL, NULL }, - { NULL, NULL }, - { NULL, NULL } -}; - -static int ago_exception_bits[] = { AGO_EXCEPT0, AGO_EXCEPT1, AGO_EXCEPT2 }; - -/* static functions */ -static struct ago_optlist -*ago_lookup(struct ago_optlist *list, char *arg, int *islong, int *amb); -static int strinitcmp(char *a, char *b); - -/*----------------------------- implementation ------------------------------ */ - -int antigetopt(int argc, char **argv, struct ago_optlist *list) -{ - static char **save_argv = NULL; - static char *chain = NULL; - static int endoptions = 0; - struct ago_optlist *opt; - int islong; - - /* Reset */ - if (argv == NULL) { - save_argv = NULL; - chain = NULL; - endoptions = 0; - return AGO_RESET; - } else { - if (save_argv == NULL) { - save_argv = argv+1; /* skips the argv[0] */ - /* XXX: argument list sanity check */ - } - } - -chain_start: - if (chain) { - if (*chain == '\0') - chain = NULL; - else { - if ((opt = ago_lookup(list, chain, &islong, NULL)) - == NULL) - return AGO_UNKNOWN; - if (!(opt->ao_flags & AGO_NOARG)) { - /* the if expression maybe false if the - * argument is optional */ - if (chain[1] == '\0' && *save_argv) - ago_optarg = *save_argv++; - /* while it is mandatory for the NEEDARG type */ - else if (opt->ao_flags & AGO_NEEDARG) - return AGO_REQARG; - } - chain++; - return opt->ao_id; - } - } - - argv = save_argv; - - /* handle the "--" special option */ - if (*argv && strcmp(*argv, "--") == 0) { - endoptions = 1; - argv++; - save_argv++; - } - - while(*argv) { - /* The option must start with '-' */ - if (!endoptions && argv[0][0] == '-' && argv[0][1] != '\0') { - int amb; - - /* note: ago_lookup also sets ago_optname */ - if ((opt = ago_lookup(list, argv[0], &islong, &amb)) - == NULL) - return amb ? AGO_AMBIG : AGO_UNKNOWN; - - /* handle the collapsed short options */ - if (!islong && argv[0][2] != '\0') { - chain = argv[0]+1; - save_argv++; - goto chain_start; - } - - /* if the option require or may have an argument */ - ago_optarg = NULL; - /* If the argument is needed we get the next argv[] - * element without care about what it contains */ - if (opt->ao_flags & AGO_NEEDARG) { - if (argv[1] == NULL) - return AGO_REQARG; - ago_optarg = argv[1]; - argv++; - } - /* If the argument is optional we only recognize it - * as argument if it does not starts with '-' */ - else if (opt->ao_flags & AGO_OPTARG) { - if (argv[1] && argv[1][0] != '-') { - ago_optarg = argv[1]; - argv++; - } - } - save_argv = argv+1; - return opt->ao_id; - } else { - save_argv = argv+1; - ago_optarg = argv[0]; - ago_optchar = '\0'; - ago_optname = NULL; - return AGO_ALONE; - } - } - return AGO_EOF; -} - -#define UNK_SHORT_ERRSTRING "invalid option -- %c\n" -#define UNK_LONG_ERRSTRING "unrecognized option `--%s'\n" -#define ARG_SHORT_ERRSTRING "option requires an argument -- %c\n" -#define ARG_LONG_ERRSTRING "option `--%s' requires an argument\n" -#define AMB_ERRSTRING "option `--%s' is ambiguos\n" -#define IERR_ERRSTRING "internal error. ago_gnu_error() called with " \ - "a bad error code (%d)\n" -void ago_gnu_error(char *pname, int error) -{ - if (pname) - fprintf(stderr, "%s: ", pname); - switch(error) { - case AGO_UNKNOWN: - if (ago_optname) - fprintf(stderr, UNK_LONG_ERRSTRING, - ago_optname); - else - fprintf(stderr, UNK_SHORT_ERRSTRING, - ago_optchar); - break; - case AGO_REQARG: - if (ago_optname) - fprintf(stderr, ARG_LONG_ERRSTRING, - ago_optname); - else - fprintf(stderr, ARG_SHORT_ERRSTRING, - ago_optchar); - break; - case AGO_AMBIG: - fprintf(stderr, AMB_ERRSTRING, ago_optname); - break; - default: - fprintf(stderr, IERR_ERRSTRING, error); - break; - } -} - -int ago_set_exception(int except_nr, int (*tester)(void), char *msg) -{ - if (tester == NULL || msg == NULL || except_nr < 0 || except_nr >= 3) - return -1; - ago_exceptions[except_nr].tester = tester; - ago_exceptions[except_nr].msg = msg; - return 0; -} - -/*-------------------------- static functions ------------------------------- */ - -struct ago_optlist -*ago_lookup(struct ago_optlist *list, char *arg, int *islong, int *amb) -{ - int i; - - /* ago_lookup can be receive as `arg' a pointer to a - * long argument, like --option, a pointer to a short - * argument like -O, or just a pointer to a char sequence - * in the case of collapsed short arguments like -abcde. */ - - /* Clear the 'ambiguos' flag, used to report the caller - * an ambiguos option abbreviation error */ - if (amb) *amb = 0; - - if (*arg == '-') /* skips the first - if any */ - arg++; - - switch(*arg) { - case '\0': - return NULL; - case '-': - *islong = 1; - arg++; /* skip the last - */ - break; - default: - *islong = 0; - break; - } - - /* search the argument in the list */ - if (*islong) { - int retval; - struct ago_optlist *last = NULL; - - while(!(list->ao_flags & AGO_ENDOFLIST)) { - ago_optname = arg; - ago_optchar = '\0'; - if ((retval = strinitcmp(arg, list->ao_long)) != 0) { - switch(retval) { - case 1: - if (last) { - if (amb) *amb = 1; - return NULL; - } - last = list; - break; - case 2: - goto ok; - } - } - list++; - } - if (last) { - ago_optname = last->ao_long; - list = last; - goto ok; - } - } else { - ago_optchar = *arg; - ago_optname = NULL; - while(!(list->ao_flags & AGO_ENDOFLIST)) { - if (*arg == list->ao_short) - goto ok; - list++; - } - } - return NULL; -ok: - /* handle the exceptions if any */ - for (i = 0; i < 3; i++) { - if ((list->ao_flags & ago_exception_bits[i]) && - ago_exceptions[i].tester) - { - if (ago_exceptions[i].tester()) { - if (ago_optname) { - fprintf(stderr, "%s `--%s'\n", - ago_exceptions[i].msg, - ago_optname); - } else { - fprintf(stderr, "%s `-%c'\n", - ago_exceptions[i].msg, - ago_optchar); - } - exit(1); - } - } - } - return list; -} - -/* Given two strings this function returns: - * 1, if the strings are the same for the len of the first string (abc, abcde) - * 2, if the strings are exactly the same: (abcd, abcd) - * otherwise zero is returned (abcde, abcd) ... (djf, 293492) */ -int strinitcmp(char *a, char *b) -{ - if (!a || !b) - return 0; - while (*a && *b) { - if (*a != *b) - return 0; - a++; b++; - } - if (*a) - return 0; - if (*a == *b) - return 2; - return 1; -} diff --git a/antigetopt.h b/antigetopt.h deleted file mode 100644 index 72bc8e9..0000000 --- a/antigetopt.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __ANTIGETOPT_H -#define __ANTIGETOPT_H - -/* special return codes */ -enum { AGO_EOF=4000, AGO_ALONE, AGO_UNKNOWN, AGO_REQARG, AGO_RESET, AGO_AMBIG }; - -/* option flags */ -#define AGO_NOARG (1<<0) /* no argument */ -#define AGO_NEEDARG (1<<1) /* required argument */ -#define AGO_OPTARG (1<<2) /* optional argument */ -#define AGO_EXCEPT0 (1<<3) /* exception #0 */ -#define AGO_EXCEPT1 (1<<4) /* exception #1 */ -#define AGO_EXCEPT2 (1<<5) /* exception #3 */ -#define AGO_ENDOFLIST (1<<15) /* end of argument list marker */ - -/* option list null term */ -#define AGO_LIST_TERM {'\0',NULL,0,AGO_ENDOFLIST} - -/* The structure that defines an argument */ -struct ago_optlist { - char ao_short; - char *ao_long; - int ao_id; - int ao_flags; -}; - -extern char *ago_optarg; -extern char *ago_optname; -extern char ago_optchar; - -int antigetopt(int argc, char **argv, struct ago_optlist *list); -void ago_gnu_error(char *pname, int error); -int ago_set_exception(int except_nr, int (*tester)(void), char *msg); - -#endif /* __ANTIGETOPT_H */ diff --git a/apd.c b/apd.c deleted file mode 100644 index 66584fa..0000000 --- a/apd.c +++ /dev/null @@ -1,1037 +0,0 @@ -/* Copyright (C) 2000,2001 Salvatore Sanfilippo - * See the LICENSE file for more information. - * - * ARS Packet Description System. - * - * Please, prefix all the function with ars_d_ */ - -/* $Id: apd.c,v 1.3 2003/09/07 11:21:18 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ars.h" -#include "hstring.h" -#include "hex.h" - -/* FIXME: parsing should use dynamic buffers to use less memory. - * For now we support MTU up to 3000 */ -#define ARS_MAX_TSIZE (3000*4) -char *ars_d_parser(char *t, char *next, size_t size) -{ - int i = 0; - - if (size == 0 || next == NULL || *t == '\0') - return NULL; - size--; /* space for nul term */ - while (1) { - /* no space for the next char */ - if (i == size) { - next[i] = '\0'; - return t; - } - switch(*t) { - case '\0': - case '(': - case ')': - case ',': - case '=': - case '+': - if (i == 0) { - next[i] = *t; - next[i+1] = '\0'; - return t+1; - } else { - next[i] = '\0'; - return t; - } - default: - next[i++] = *t++; - break; - } - } - return NULL; /* unreached */ -} - -/* states */ -#define ARS_G_LAYER 0 -#define ARS_G_FIELD_OR_CBRACE 1 -#define ARS_G_VALUE 2 -#define ARS_G_OBRACE_OR_PLUS 3 -#define ARS_G_CBRACE 4 -#define ARS_G_COMMA_OR_CBRACE 5 -#define ARS_G_LEN_OR_PLUS 6 -#define ARS_G_PLUS 7 -#define ARS_G_EQUAL 8 - -struct ars_d_keyword_info { - char *ki_keyword; - int ki_opt; - void *(*ki_add) (struct ars_packet *pkt, int opt); - int (*ki_set) (struct ars_packet *pkt, int layer, char *f, char *v); -}; - -#define ARS_DKINFO_SIZE 64 - -/* If the user specify a layer number of -1 with *set functions, the - * last layer is selected */ -#define ARS_DEF_LAYER \ -do { \ - if (layer == ARS_LAST_LAYER) \ - layer = pkt->p_layer_nr - 1; \ - if (ars_valid_layer(layer) != -ARS_OK) \ - return -ARS_INVALID; \ -} while(0) - -#define BOGUS_SET_F(x) \ - int (x)(struct ars_packet *pkt, int layer, char *f, char *v) { return 0; } - -int ars_d_set_ip(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_udp(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_tcp(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_icmp(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_data(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_ipopt_rr(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_ipopt_ts(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_ipopt_sid(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_ipopt_sec(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_ipopt_dumb(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_tcpopt_mss(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_tcpopt_wscale(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_tcpopt_sack(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_tcpopt_echo(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_tcpopt_dumb(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_igrp(struct ars_packet *pkt, int layer, char *f, char *v); -int ars_d_set_igrpentry(struct ars_packet *pkt, int layer, char *f, char *v); -BOGUS_SET_F(ars_d_set_tcpopt_ts) - -struct ars_d_keyword_info ars_dkinfo[ARS_DKINFO_SIZE] = { - /* KEYWORD OPT ADD function SET function * - * --------------------------------------------------------- */ - {"ip", 0, ars_add_iphdr, ars_d_set_ip}, - {"ip.eol", ARS_IPOPT_EOL, ars_add_ipopt, ars_d_set_ipopt_dumb}, - {"ip.nop", ARS_IPOPT_NOP, ars_add_ipopt, ars_d_set_ipopt_dumb}, - {"ip.sec", ARS_IPOPT_SEC, ars_add_ipopt, ars_d_set_ipopt_sec}, - {"ip.sid", ARS_IPOPT_SID, ars_add_ipopt, ars_d_set_ipopt_sid}, - {"ip.lsrr", ARS_IPOPT_LSRR, ars_add_ipopt, ars_d_set_ipopt_rr}, - {"ip.ssrr", ARS_IPOPT_SSRR, ars_add_ipopt, ars_d_set_ipopt_rr}, - {"ip.rr", ARS_IPOPT_RR, ars_add_ipopt, ars_d_set_ipopt_rr}, - {"ip.ts", ARS_IPOPT_TIMESTAMP, ars_add_ipopt, ars_d_set_ipopt_ts}, - {"udp", 0, ars_add_udphdr, ars_d_set_udp}, - {"tcp", 0, ars_add_tcphdr, ars_d_set_tcp}, - {"tcp.eol", ARS_TCPOPT_EOL, ars_add_tcpopt, ars_d_set_tcpopt_dumb}, - {"tcp.nop", ARS_TCPOPT_NOP, ars_add_tcpopt, ars_d_set_tcpopt_dumb}, - {"tcp.mss", ARS_TCPOPT_MAXSEG, ars_add_tcpopt, ars_d_set_tcpopt_mss}, - {"tcp.wscale", ARS_TCPOPT_WINDOW, ars_add_tcpopt, ars_d_set_tcpopt_wscale}, - {"tcp.sackperm", ARS_TCPOPT_SACK_PERM, ars_add_tcpopt, ars_d_set_tcpopt_dumb}, - {"tcp.sack", ARS_TCPOPT_SACK, ars_add_tcpopt, ars_d_set_tcpopt_sack}, - {"tcp.echo", ARS_TCPOPT_ECHOREQUEST, ars_add_tcpopt, ars_d_set_tcpopt_echo}, - {"tcp.echoreply", ARS_TCPOPT_ECHOREPLY, ars_add_tcpopt, ars_d_set_tcpopt_echo}, - {"tcp.ts", ARS_TCPOPT_TIMESTAMP, ars_add_tcpopt, ars_d_set_tcpopt_ts}, - {"icmp", 0, ars_add_icmphdr, ars_d_set_icmp}, - {"igrp", 0, ars_add_igrphdr, ars_d_set_igrp}, - {"igrp.entry", 0, ars_add_igrpentry, ars_d_set_igrpentry}, - {"data", 0, ars_add_data, ars_d_set_data}, - {NULL, 0, NULL, NULL} /* nul term */ -}; - -struct ars_d_keyword_info *ars_get_keyword_by_name(char *name) -{ - struct ars_d_keyword_info *k = ars_dkinfo; - - while (k->ki_keyword) { - if (strcasecmp(k->ki_keyword, name) == 0) - return k; - k++; - } - return NULL; -} - -int ars_d_setlayer_size(struct ars_packet *pkt, int layer, char *size) -{ - size_t newsize; - - ARS_DEF_LAYER; - newsize = ars_atou(size); - if (newsize < 1 || newsize > pkt->p_layer[layer].l_size) { - ars_set_error(pkt, "Invalid layer size in description"); - return -ARS_INVALID; - } - pkt->p_layer[layer].l_size = newsize; - - __D(printf("Setting the layer to size %s\n", size);) - return -ARS_OK; -} - -int ars_d_set_ip(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_iphdr *ip; - - ARS_DEF_LAYER; - ip = pkt->p_layer[layer].l_data; - - if (strcasecmp(f, "saddr") == 0) { - return ars_resolve(pkt, &ip->saddr, v); - } else if (strcasecmp(f, "daddr") == 0) { - return ars_resolve(pkt, &ip->daddr, v); - } else if (strcasecmp(f, "ihl") == 0) { - ip->ihl = ars_atou(v); - pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_HDRLEN; - } else if (strcasecmp(f, "ver") == 0) { - ip->version = ars_atou(v); - pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_VERSION; - } else if (strcasecmp(f, "tos") == 0) { - ip->tos = ars_atou(v); - } else if (strcasecmp(f, "totlen") == 0) { - ip->tot_len = htons(ars_atou(v)); - pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_TOTLEN; - } else if (strcasecmp(f, "id") == 0) { - ip->id = htons(ars_atou(v)); - } else if (strcasecmp(f, "fragoff") == 0) { - ip->frag_off = ip->frag_off & 0xE000; - ip->frag_off |= htons(ars_atou(v) >> 3); - } else if (strcasecmp(f, "mf") == 0) { - if (ars_atou(v) == 0) - ip->frag_off &= htons(~ARS_IP_MF); - else - ip->frag_off |= htons(ARS_IP_MF); - } else if (strcasecmp(f, "df") == 0) { - if (ars_atou(v) == 0) - ip->frag_off &= htons(~ARS_IP_DF); - else - ip->frag_off |= htons(ARS_IP_DF); - } else if (strcasecmp(f, "rf") == 0) { - if (ars_atou(v) == 0) - ip->frag_off &= htons((u_int16_t)~ARS_IP_RF); - else - ip->frag_off |= htons(ARS_IP_RF); - } else if (strcasecmp(f, "ttl") == 0) { - ip->ttl = ars_atou(v); - } else if (strcasecmp(f, "proto") == 0) { - if (!strcasecmp(v, "icmp")) { - ip->protocol = ARS_IPPROTO_ICMP; - } else if (!strcasecmp(v, "udp")) { - ip->protocol = ARS_IPPROTO_UDP; - } else if (!strcasecmp(v, "tcp")) { - ip->protocol = ARS_IPPROTO_TCP; - } else { - ip->protocol = ars_atou(v); - } - pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_PROTOCOL; - } else if (strcasecmp(f, "cksum") == 0) { - ip->check = htons(ars_atou(v)); - pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_CKSUM; - } else { - ars_set_error(pkt, "Invalid field for IP layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -/* Note: for all the variable-length ip options the allocated layer data - * length is always as big as possible (40 bytes), so set_ipopt_rr() and - * other similar functions don't need to check if there is enough room. - * Of course functions shoult still check to not overflow over the 40 - * bytes, but this makes very little sense. */ -#define IPOPTRR_MAX_ENTRIES 9 -int ars_d_set_ipopt_rr(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_ipopt *ipopt; - - ARS_DEF_LAYER; - ipopt = pkt->p_layer[layer].l_data; - - if (strcasecmp(f, "optlen") == 0) { - ipopt->len = ars_atou(v); - } else if (strcasecmp(f, "ptr") == 0) { - ipopt->un.rr.ptr = ars_atou(v); - pkt->p_layer[layer].l_flags |= ARS_TAKE_IPOPT_PTR; - } else if (strcasecmp(f, "data") == 0) { - char *addrv[IPOPTRR_MAX_ENTRIES]; - int vlen = strlen(v), num, i; - char *vcopy = alloca(vlen+1); - unsigned char *data = pkt->p_layer[layer].l_data; - - memcpy(vcopy, v, vlen+1); - num = strftok("/", vcopy, addrv, IPOPTRR_MAX_ENTRIES); - for (i = 0; i < num; i++) { - __u32 addr; - int err; - - err = ars_resolve(pkt, &addr, addrv[i]); - if (err != -ARS_OK) - return err; - memcpy(data+3+(i*4), &addr, 4); - } - if (ARS_DONTTAKE(pkt->p_layer[layer].l_flags, - ARS_TAKE_IPOPT_PTR)) - { - /* For the record route option the default ptr - * is at the end of the specified entries */ - if (ipopt->kind == ARS_IPOPT_RR) { - ipopt->un.rr.ptr = 4+(num*4); - } else { - /* For SSRR and LSRR is set at the start - * if not otherwise specified. */ - ipopt->un.rr.ptr = 4; - } - } - } else { - ars_set_error(pkt, "Invalid field for IP.RR layer: '%s'", f); - return -ARS_INVALID; - } - - return -ARS_OK; -} - -#define IPOPTTS_MAX_ENTRIES 9 -int ars_d_set_ipopt_ts(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_ipopt *ipopt; - int flags, overflow; - - ARS_DEF_LAYER; - ipopt = pkt->p_layer[layer].l_data; - overflow = (ipopt->un.ts.flags & 0xF0) >> 4; - flags = ipopt->un.ts.flags & 0xF; - - if (strcasecmp(f, "optlen") == 0) { - ipopt->len = ars_atou(v); - } else if (strcasecmp(f, "ptr") == 0) { - ipopt->un.rr.ptr = ars_atou(v); - pkt->p_layer[layer].l_flags |= ARS_TAKE_IPOPT_PTR; - } else if (strcasecmp(f, "flags") == 0) { - if (strisnum(v)) { - flags = ars_atou(v) & 0xF; - } else { - if (!strcasecmp(v, "tsonly")) - flags = ARS_IPOPT_TS_TSONLY; - else if (!strcasecmp(v, "tsandaddr")) - flags = ARS_IPOPT_TS_TSANDADDR; - else if (!strcasecmp(v, "prespec")) - flags = ARS_IPOPT_TS_PRESPEC; - else { - ars_set_error(pkt, "Invalid symbol for ip.ts flags: '%s' (use: tsonly, tsandaddr, prespec or a numerical value)", v); - return -ARS_INVALID; - } - } - ipopt->un.ts.flags = ((overflow&0xF)<<4)|(flags&0xF); - } else if (strcasecmp(f, "overflow") == 0) { - overflow = ars_atou(v) & 0xF; - ipopt->un.ts.flags = ((overflow&0xF)<<4)|(flags&0xF); - } else if (strcasecmp(f, "data") == 0) { - char *addrv[IPOPTTS_MAX_ENTRIES]; - int vlen = strlen(v), num, i; - char *vcopy = alloca(vlen+1); - unsigned char *data = pkt->p_layer[layer].l_data; - - memcpy(vcopy, v, vlen+1); - num = strftok("/", vcopy, addrv, IPOPTTS_MAX_ENTRIES); - for (i = 0; i < num; i++) { - __u32 addr, ts; - int err; - char *p; - - p = strchr(addrv[i], '@'); - if (p) { - if (flags == ARS_IPOPT_TS_TSONLY) { - ars_set_error(pkt, "Gateway specified but ip.ts flags set to 'tsonly'. (Try flags=tsandaddr,data=...)"); - return -ARS_INVALID; - } - *p = '\0'; - p++; - err = ars_resolve(pkt, &addr, p); - if (err != -ARS_OK) - return err; - ts = ars_atou(addrv[i]); - ts = htonl(ts); - if (i < 4) { - memcpy(data+4+(i*8), &addr, 4); - memcpy(data+8+(i*8), &ts, 4); - }; - } else { - if (flags == ARS_IPOPT_TS_TSANDADDR || - flags == ARS_IPOPT_TS_PRESPEC) { - ars_set_error(pkt, "Gateway not specified in data for ip.ts, but flags set to 'tsandaddr' or 'prespec'. (Try flags=tsonly)"); - return -ARS_INVALID; - } - ts = ars_atou(addrv[i]); - ts = htonl(ts); - memcpy(data+4+(i*4), &ts, 4); - } - } - if (ARS_DONTTAKE(pkt->p_layer[layer].l_flags, - ARS_TAKE_IPOPT_PTR)) - { - if (flags == ARS_IPOPT_TS_TSANDADDR || - flags == ARS_IPOPT_TS_PRESPEC) { - ipopt->un.rr.ptr = 5+(num*8); - } else { - ipopt->un.rr.ptr = 5+(num*4); - } - } - } else { - ars_set_error(pkt, "Invalid field for IP.TS layer: '%s'", f); - return -ARS_INVALID; - } - - return -ARS_OK; -} - -int ars_d_set_ipopt_sid(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_ipopt *ipopt; - - ARS_DEF_LAYER; - ipopt = pkt->p_layer[layer].l_data; - if (strcasecmp(f, "optlen") == 0) { - ipopt->len = ars_atou(v); - } else if (strcasecmp(f, "sid") == 0) { - ipopt->un.sid.id = ars_atou(v); - } else { - ars_set_error(pkt, "Invalid field for IP.SID layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_d_set_ipopt_sec(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_ipopt *ipopt; - - ARS_DEF_LAYER; - ipopt = pkt->p_layer[layer].l_data; - if (strcasecmp(f, "optlen") == 0) { - ipopt->len = ars_atou(v); - } else if (strcasecmp(f, "seclev") == 0) { - ipopt->un.sec.s = ars_atou(v); - } else if (strcasecmp(f, "comp") == 0) { - ipopt->un.sec.c = ars_atou(v); - } else if (strcasecmp(f, "hrest") == 0) { - if (strlen(v) != 4) { - ars_set_error(pkt, "Invalid ip.sec hrest field value of '%s'(should be four hex digits, like this: ...,hrest=252A,...)", v); - return -ARS_INVALID; - } - if (hextobin(&ipopt->un.sec.h, v, 4)) { - ars_set_error(pkt, "Invalid hex value for ip.sec hex: '%s'", v); - return -ARS_INVALID; - } - } else if (strcasecmp(f, "tcc") == 0) { - if (strlen(v) != 6) { - ars_set_error(pkt, "Invalid ip.sec tcc field value of '%s'(should be six hex digits, like this: ...,tcc=252A27,...)", v); - return -ARS_INVALID; - } - if (hextobin(&ipopt->un.sec.h, v, 6)) { - ars_set_error(pkt, "Invalid hex value for ip.sec hex: '%s'", v); - return -ARS_INVALID; - } - } else { - ars_set_error(pkt, "Invalid field for IP.SEC layer: '%s'", f); - return -ARS_INVALID; - } - - return -ARS_OK; -} - -int ars_d_set_ipopt_dumb(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_ipopt *ipopt; - - ARS_DEF_LAYER; - ipopt = pkt->p_layer[layer].l_data; - if (strcasecmp(f, "optlen") == 0) { - ipopt->len = ars_atou(v); - } else { - ars_set_error(pkt, "Invalid field for IP.? layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_d_set_udp(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_udphdr *udp; - - ARS_DEF_LAYER; - udp = pkt->p_layer[layer].l_data; - - if (strcasecmp(f, "sport") == 0) { - udp->uh_sport = htons(ars_atou(v)); - } else if (strcasecmp(f, "dport") == 0) { - udp->uh_dport = htons(ars_atou(v)); - } else if (strcasecmp(f, "len") == 0) { - udp->uh_ulen = htons(ars_atou(v)); - pkt->p_layer[layer].l_flags |= ARS_TAKE_UDP_LEN; - } else if (strcasecmp(f, "cksum") == 0) { - udp->uh_sum = htons(ars_atou(v)); - pkt->p_layer[layer].l_flags |= ARS_TAKE_UDP_CKSUM; - } else { - ars_set_error(pkt, "Invalid field for UDP layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_d_set_tcp(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_tcphdr *tcp; - - ARS_DEF_LAYER; - tcp = pkt->p_layer[layer].l_data; - - if (strcasecmp(f, "sport") == 0) { - tcp->th_sport = htons(ars_atou(v)); - } else if (strcasecmp(f, "dport") == 0) { - tcp->th_dport = htons(ars_atou(v)); - } else if (strcasecmp(f, "seq") == 0) { - tcp->th_seq = htonl(ars_atou(v)); - } else if (strcasecmp(f, "ack") == 0) { - tcp->th_ack = htonl(ars_atou(v)); - } else if (strcasecmp(f, "x2") == 0) { - tcp->th_x2 = ars_atou(v); - } else if (strcasecmp(f, "off") == 0) { - tcp->th_off = ars_atou(v); - pkt->p_layer[layer].l_flags |= ARS_TAKE_TCP_HDRLEN; - } else if (strcasecmp(f, "flags") == 0) { - tcp->th_flags = 0; - if (strchr(v, 'f') || strchr(v, 'F')) - tcp->th_flags |= ARS_TCP_TH_FIN; - if (strchr(v, 's') || strchr(v, 'S')) - tcp->th_flags |= ARS_TCP_TH_SYN; - if (strchr(v, 'r') || strchr(v, 'R')) - tcp->th_flags |= ARS_TCP_TH_RST; - if (strchr(v, 'p') || strchr(v, 'P')) - tcp->th_flags |= ARS_TCP_TH_PUSH; - if (strchr(v, 'a') || strchr(v, 'A')) - tcp->th_flags |= ARS_TCP_TH_ACK; - if (strchr(v, 'u') || strchr(v, 'U')) - tcp->th_flags |= ARS_TCP_TH_URG; - if (strchr(v, 'x') || strchr(v, 'X')) - tcp->th_flags |= ARS_TCP_TH_X; - if (strchr(v, 'y') || strchr(v, 'Y')) - tcp->th_flags |= ARS_TCP_TH_Y; - } else if (strcasecmp(f, "win") == 0) { - tcp->th_win = htons(ars_atou(v)); - } else if (strcasecmp(f, "cksum") == 0) { - tcp->th_sum = htons(ars_atou(v)); - pkt->p_layer[layer].l_flags |= ARS_TAKE_TCP_CKSUM; - } else if (strcasecmp(f, "urp") == 0) { - tcp->th_urp = htons(ars_atou(v)); - } else { - ars_set_error(pkt, "Invalid field for TCP layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_d_set_tcpopt_mss(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_tcpopt *tcpopt; - - ARS_DEF_LAYER; - tcpopt = pkt->p_layer[layer].l_data; - if (strcasecmp(f, "optlen") == 0) { - tcpopt->len = ars_atou(v); - } else if (strcasecmp(f, "size") == 0) { - tcpopt->un.mss.size = htons(ars_atou(v)); - } else { - ars_set_error(pkt, "Invalid field for TCP.MSS layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_d_set_tcpopt_wscale(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_tcpopt *tcpopt; - - ARS_DEF_LAYER; - tcpopt = pkt->p_layer[layer].l_data; - if (strcasecmp(f, "optlen") == 0) { - tcpopt->len = ars_atou(v); - } else if (strcasecmp(f, "shift") == 0) { - tcpopt->un.win.shift = htons(ars_atou(v)); - } else { - ars_set_error(pkt, "Invalid field for TCP.WSCALE layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -#define TCPOPTSACK_MAX_ENTRIES 4 -int ars_d_set_tcpopt_sack(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_tcpopt *tcpopt; - - ARS_DEF_LAYER; - tcpopt = pkt->p_layer[layer].l_data; - if (strcasecmp(f, "optlen") == 0) { - tcpopt->len = ars_atou(v); - } else if (strcasecmp(f, "blocks") == 0) { - char *bv[TCPOPTSACK_MAX_ENTRIES]; - int vlen = strlen(v), num, i; - char *vcopy = alloca(vlen+1); - unsigned char *data = pkt->p_layer[layer].l_data; - - memcpy(vcopy, v, vlen+1); - num = strftok("/", vcopy, bv, TCPOPTSACK_MAX_ENTRIES); - for (i = 0; i < num; i++) { - char *p; - __u32 s_origin, s_len; - - p = strchr(bv[i], '-'); - if (!p) { - ars_set_error(pkt, "Invalid syntax for tcp.sack blocks: '%s' (try ...tcp.sack(blocks=123342-10/12653-50/0-0/0-0)... )"); - return -ARS_INVALID; - } - *p = '\0'; - p++; - s_origin = htonl(ars_atou(bv[i])); - s_len = htonl(ars_atou(p)); - memcpy(data+2+(i*8), &s_origin, 4); - memcpy(data+6+(i*8), &s_len, 4); - } - } else { - ars_set_error(pkt, "Invalid field for TCP.SACK layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_d_set_tcpopt_dumb(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_tcpopt *tcpopt; - - ARS_DEF_LAYER; - tcpopt = pkt->p_layer[layer].l_data; - if (strcasecmp(f, "optlen") == 0) { - tcpopt->len = ars_atou(v); - } else { - ars_set_error(pkt, "Invalid field for TCP.? layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_d_set_tcpopt_echo(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_tcpopt *tcpopt; - - ARS_DEF_LAYER; - tcpopt = pkt->p_layer[layer].l_data; - if (strcasecmp(f, "optlen") == 0) { - tcpopt->len = ars_atou(v); - } else if (strcasecmp(f, "info") == 0) { - u_int32_t info = htonl(ars_atou(v)); - memcpy(tcpopt->un.echo.info, &info, 4); - } else { - ars_set_error(pkt, "Invalid field for TCP.ECHO layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_d_set_icmp(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_icmphdr *icmp; - - ARS_DEF_LAYER; - icmp = pkt->p_layer[layer].l_data; - - if (strcasecmp(f, "type") == 0) { - icmp->type = ars_atou(v); - } else if (strcasecmp(f, "code") == 0) { - icmp->code = ars_atou(v); - } else if (strcasecmp(f, "cksum") == 0) { - icmp->checksum = htons(ars_atou(v)); - pkt->p_layer[layer].l_flags |= ARS_TAKE_ICMP_CKSUM; - } else if (strcasecmp(f, "id") == 0) { - icmp->un.echo.id = htons(ars_atou(v)); - } else if (strcasecmp(f, "seq") == 0) { - icmp->un.echo.sequence = htons(ars_atou(v)); - } else if (strcasecmp(f, "gw") == 0) { - return ars_resolve(pkt, &icmp->un.gateway, v); - } else if (strcasecmp(f, "unused") == 0) { - icmp->un.gateway = htonl(ars_atou(v)); - } else { - ars_set_error(pkt, "Invalid field for ICMP layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_d_set_igrp(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_igrphdr *igrp; - - ARS_DEF_LAYER; - igrp = pkt->p_layer[layer].l_data; - - if (strcasecmp(f, "version") == 0) { - igrp->version = ars_atou(v); - } else if (strcasecmp(f, "opcode") == 0) { - if (strcasecmp(v, "update") == 0) - igrp->opcode = ARS_IGRP_OPCODE_UPDATE; - else if (strcasecmp(v, "request") == 0) - igrp->opcode = ARS_IGRP_OPCODE_REQUEST; - else - igrp->opcode = ars_atou(v); - } else if (strcasecmp(f, "cksum") == 0) { - igrp->checksum = htons(ars_atou(v)); - pkt->p_layer[layer].l_flags |= ARS_TAKE_IGRP_CKSUM; - } else if (strcasecmp(f, "edition") == 0) { - igrp->edition = ars_atou(v); - } else if (strcasecmp(f, "autosys") == 0) { - igrp->autosys = htons(ars_atou(v)); - } else if (strcasecmp(f, "interior") == 0) { - igrp->interior = htons(ars_atou(v)); - } else if (strcasecmp(f, "system") == 0) { - igrp->system= htons(ars_atou(v)); - } else if (strcasecmp(f, "exterior") == 0) { - igrp->exterior = htons(ars_atou(v)); - } else { - ars_set_error(pkt, "Invalid field for IGRP layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -static int igrp_set_dest(unsigned char *d, char *v) -{ - int l = strlen(v); - char *vcopy = alloca(l+1); - char *f0, *f1, *f2; - - memcpy(vcopy, v, l+1); - f0 = vcopy; - if ((f1 = strchr(f0, '.')) == NULL) - return 1; - *f1++ = '\0'; - if ((f2 = strchr(f1, '.')) == NULL) - return 1; - *f2++ = '\0'; - if (!strisnum(f0) || !strisnum(f1) || !strisnum(f2)) - return 1; - d[0] = ars_atou(f0); - d[1] = ars_atou(f1); - d[2] = ars_atou(f2); - return 0; -} - -static void igrp_set_uint24(void *d, char *v) -{ - __u32 t; - unsigned char *x; - - t = htonl(ars_atou(v)); - x = (unsigned char*) &t; - memcpy(d, x+1, 3); -} - -int ars_d_set_igrpentry(struct ars_packet *pkt, int layer, char *f, char *v) -{ - struct ars_igrpentry *entry; - - ARS_DEF_LAYER; - entry = pkt->p_layer[layer].l_data; - - if (strcasecmp(f, "dest") == 0) { - if (igrp_set_dest(entry->destination, v)) { - ars_set_error(pkt, "Invalid IGRP entry 'dest' field value: '%s'\n", v); - return -ARS_INVALID; - } - } else if (strcasecmp(f, "delay") == 0) { - igrp_set_uint24(entry->delay, v); - } else if (strcasecmp(f, "bandwidth") == 0) { - igrp_set_uint24(entry->bandwidth, v); - } else if (strcasecmp(f, "mtu") == 0) { - __u16 mtu = htons(ars_atou(v)); - memcpy(entry->mtu, &mtu, 2); - } else if (strcasecmp(f, "reliability") == 0) { - entry->reliability = ars_atou(v); - } else if (strcasecmp(f, "load") == 0) { - entry->load = ars_atou(v); - } else if (strcasecmp(f, "hopcount") == 0) { - entry->hopcount = ars_atou(v); - } else { - ars_set_error(pkt, "Invalid field for IGRP.ENTRY layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -int ars_push_data(struct ars_packet *pkt, int layer, void *data, size_t size) -{ - char *p; - int old_size; - - ARS_DEF_LAYER; - old_size = pkt->p_layer[layer].l_size; - p = realloc(pkt->p_layer[layer].l_data, old_size + size); - if (p == NULL) - return -ARS_NOMEM; - memcpy(p+old_size, data, size); - pkt->p_layer[layer].l_data = p; - pkt->p_layer[layer].l_size += size; - return ARS_OK; -} - -static int hextab[256]; -static int hextab_initialized = 0; -static char *hexdig = "0123456789abcdef"; - -static char *ars_decode_hex(struct ars_packet *pkt, char *s, int *blen) -{ - int len = strlen(s), i; - unsigned char *d, *saved; - - if (len%2) { - ars_set_error(pkt, "Odd length of 'hex' data"); - return NULL; - } - *blen = len/2; - if (!hextab_initialized) { - memset(hextab, 255, 255); - for (i = 0; i < 16; i++) - hextab[(int)hexdig[i]] = i; - } - if ((d = malloc(*blen)) == NULL) { - ars_set_error(pkt, "Out of memory decoding 'hex' data"); - return NULL; - } - saved = d; - while(*s) { - int x0, x1; - - x0 = hextab[tolower(*s)]; - x1 = hextab[tolower(*(s+1))]; - if (x0 == 255 || x1 == 255) { - ars_set_error(pkt, "Wrong byte for 'hex' data: '%c%c'", - *s, *(s+1)); - free(saved); - return NULL; - } - *d++ = (x0 << 4) | x1; - s += 2; - } - return (char*)saved; -} - -static char *ars_decode_string(struct ars_packet *pkt, char *s, int *blen) -{ - int l = strlen(s), i; - int bl = 0; - unsigned char *d, *saved; - - if (!hextab_initialized) { - memset(hextab, -1, 255); - for (i = 0; i < 16; i++) - hextab[(int)hexdig[i]] = i; - } - if ((d = malloc(l)) == NULL) { - ars_set_error(pkt, "Out of memory decoding 'str' data"); - return NULL; - } - saved = d; - while(*s) { - if (*s == '\\' && *(s+1) && *(s+2)) { - *d++ = (hextab[(int)*(s+1)] << 4) + hextab[(int)*(s+2)]; - s += 3; - } else { - *d++ = *s++; - } - bl++; - } - *blen = bl; - return (char*)saved; -} - -#define ARS_DATA_BUF_SIZE 4096 -int ars_d_set_data(struct ars_packet *pkt, int layer, char *f, char *v) -{ - ARS_DEF_LAYER; - if (strcasecmp(f, "file") == 0) { - int fd, n_read; - unsigned char buffer[ARS_DATA_BUF_SIZE]; - - if ((fd = open(v, O_RDONLY)) == -1) { - ars_set_error(pkt, "Can't open the DATA file '%s': %s", - v, strerror(errno)); - return -ARS_ERROR; - } - if ((n_read = read(fd, buffer, ARS_DATA_BUF_SIZE)) == -1) { - close(fd); - ars_set_error(pkt, "Can't read DATA from file: %s", strerror(errno)); - return -ARS_ERROR; - } - close(fd); - if (n_read == 0) - return -ARS_OK; - return ars_push_data(pkt, layer, buffer, n_read); - } else if (strcasecmp(f, "str") == 0) { - char *binary; - int err, blen; - - binary = ars_decode_string(pkt, v, &blen); - if (binary == NULL) - return -ARS_ERROR; - err = ars_push_data(pkt, layer, binary, blen); - free(binary); - return err; - } else if (strcasecmp(f, "hex") == 0) { - char *binary; - int err, blen; - - binary = ars_decode_hex(pkt, v, &blen); - if (binary == NULL) - return -ARS_ERROR; - err = ars_push_data(pkt, layer, binary, blen); - free(binary); - } else if (strcasecmp(f, "uint32") == 0) { - int err; - __u32 t, nt; - t = ars_atou(v); - nt = htonl(t); - err = ars_push_data(pkt, layer, (char*)&nt, 4); - return err; - } else if (strcasecmp(f, "uint24") == 0) { - int err; - __u32 t, nt; - unsigned char *x = (unsigned char*) &nt; - t = ars_atou(v); - nt = htonl(t); - err = ars_push_data(pkt, layer, x+1, 3); - return err; - } else if (strcasecmp(f, "uint16") == 0) { - int err; - __u16 t, nt; - t = ars_atou(v); - nt = htons(t); - err = ars_push_data(pkt, layer, (char*)&nt, 2); - return err; - } else if (strcasecmp(f, "uint8") == 0) { - int err; - __u8 t; - t = ars_atou(v); - err = ars_push_data(pkt, layer, (char*)&t, 1); - return err; - } else { - ars_set_error(pkt, "Invalid field for DATA layer: '%s'", f); - return -ARS_INVALID; - } - return -ARS_OK; -} - -/* A Finite state machine to build the packet using the description */ -int ars_d_build(struct ars_packet *pkt, char *t) -{ - struct ars_d_keyword_info *k = NULL; - char next[ARS_MAX_TSIZE]; - char field[ARS_MAX_TSIZE]; - int state = ARS_G_LAYER; - int error; - void *p; - - while ((t = ars_d_parser(t, next, ARS_MAX_TSIZE)) != NULL) { - switch(state) { - case ARS_G_LAYER: - k = ars_get_keyword_by_name(next); - if (k == NULL) { - ars_set_error(pkt, "Unknown keyword: '%s'", next); - return -ARS_INVALID; - } - __D(printf("Adding a new layer (%s)\n", next);) - p = k->ki_add(pkt, k->ki_opt); - if (p == NULL) - return -ARS_INVALID; - state = ARS_G_OBRACE_OR_PLUS; - break; - case ARS_G_FIELD_OR_CBRACE: - if (next[0] == ')' && next[1] == '\0') { - state = ARS_G_LEN_OR_PLUS; - } else { - strncpy(field, next, ARS_MAX_TSIZE); - state = ARS_G_EQUAL; - } - break; - case ARS_G_VALUE: - if (k->ki_set == NULL) { - ars_set_error(pkt, "Field specified for" - "a layer that doesn't support fields"); - return -ARS_INVALID; - } - error = k->ki_set(pkt, ARS_LAST_LAYER, field, next); - if (error != -ARS_OK) - return error; - state = ARS_G_COMMA_OR_CBRACE; - break; - case ARS_G_OBRACE_OR_PLUS: - if (next[0] == '(' && next[1] == '\0') { - state = ARS_G_FIELD_OR_CBRACE; - break; - } else if (next[0] == '+' && next[1] == '\0') { - state = ARS_G_LAYER; - break; - } else { - ars_set_error(pkt, "Missing brace or plus"); - return -ARS_INVALID; - } - break; - case ARS_G_CBRACE: - if (next[0] != ')' || next[1] != '\0') { - ars_set_error(pkt, "Missing closed brace"); - return -ARS_INVALID; - } - state = ARS_G_LEN_OR_PLUS; - break; - case ARS_G_COMMA_OR_CBRACE: - if (next[0] == ')' && next[1] == '\0') { - state = ARS_G_LEN_OR_PLUS; - break; - } else if (next[0] == ',' && next[1] == '\0') { - state = ARS_G_FIELD_OR_CBRACE; - break; - } else { - ars_set_error(pkt, "Missing brace or comma"); - return -ARS_INVALID; - } - break; - case ARS_G_LEN_OR_PLUS: - if (next[0] == '+' && next[1] == '\0') { - state = ARS_G_LAYER; - break; - } - error = ars_d_setlayer_size(pkt, ARS_LAST_LAYER, next); - if (error != -ARS_OK) - return error; - state = ARS_G_PLUS; - break; - case ARS_G_PLUS: - if (next[0] != '+' || next[1] != '\0') { - ars_set_error(pkt, "Missing plus"); - return -ARS_INVALID; - } - state = ARS_G_LAYER; - break; - case ARS_G_EQUAL: - if (next[0] != '=' || next[1] != '\0') { - ars_set_error(pkt, "Missing equal"); - return -ARS_INVALID; - } - state = ARS_G_VALUE; - break; - } - } - if (state != ARS_G_LEN_OR_PLUS && state != ARS_G_PLUS && - state != ARS_G_OBRACE_OR_PLUS) { - ars_set_error(pkt, "Packet description truncated"); - return -ARS_INVALID; - } - return -ARS_OK; -} diff --git a/apt-packages.txt b/apt-packages.txt new file mode 100644 index 0000000..599427f --- /dev/null +++ b/apt-packages.txt @@ -0,0 +1,7 @@ +build-essential +autoconf +automake +libtool +pkg-config +libpcap-dev +tcl-dev diff --git a/ars.c b/ars.c deleted file mode 100644 index 2b95b32..0000000 --- a/ars.c +++ /dev/null @@ -1,989 +0,0 @@ -/* Copyright (C) 2000,2001 Salvatore Sanfilippo - * See the LICENSE file for more information. - * - * TODO: - * o Functions to add addresses and timestamps for some IP and TCP option - * o IGMP support - * o DNS support - * o ARS add_build_layer() facility and Co., read the PROPOSAL file. - */ - -/* $Id: ars.c,v 1.3 2004/04/14 12:30:18 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ars.h" - -/* prototypes */ -int ars_compiler_ip(struct ars_packet *pkt, int layer); -int ars_compiler_ipopt(struct ars_packet *pkt, int layer); -int ars_compiler_tcp(struct ars_packet *pkt, int layer); -int ars_compiler_tcpopt(struct ars_packet *pkt, int layer); -int ars_compiler_udp(struct ars_packet *pkt, int layer); -int ars_compiler_icmp(struct ars_packet *pkt, int layer); -int ars_compiler_igrp(struct ars_packet *pkt, int layer); -int ars_compiler_abort(struct ars_packet *pkt, int layer) { return 0; } - -/* Initialize a packets context: - * must be called before to work with the packet's layers */ -int ars_init(struct ars_packet *pkt) -{ - int j; - - pkt->p_error = NULL; - pkt->p_layer_nr = 0; - pkt->p_options = 0; - for (j = 0; j < ARS_MAX_LAYER; j++) { - pkt->p_layer[j].l_size = 0; - pkt->p_layer[j].l_flags = 0; - pkt->p_layer[j].l_type = ARS_TYPE_NULL; - pkt->p_layer[j].l_data = NULL; - pkt->p_layer[j].l_packet = pkt; - } - for (j = 0; j < ARS_TYPE_SIZE; j++) - pkt->p_default[j] = NULL; - return -ARS_OK; -} - -/* Destroy (free the allocated memory) a packet context */ -int ars_destroy(struct ars_packet *pkt) -{ - int j; - - free(pkt->p_error); - for (j = 0; j < ARS_MAX_LAYER; j++) { - if (pkt->p_layer[j].l_type != ARS_TYPE_NULL && - pkt->p_layer[j].l_data != NULL) - free(pkt->p_layer[j].l_data); - } - return ars_init(pkt); /* Re-initialize it */ -} - -/* THe out of memory message must be statically allocated */ -char *ars_error_nomem = "Out of memory"; - -/* Set the error description */ -int ars_set_error(struct ars_packet *pkt, const char *fmt, ...) -{ - va_list ap; - char buf[ARS_ERR_BUFSZ]; - - if (pkt == NULL) - return -ARS_OK; - - va_start(ap, fmt); - vsnprintf(buf, ARS_ERR_BUFSZ, fmt, ap); - buf[ARS_ERR_BUFSZ-1] = '\0'; - va_end(ap); - free(pkt->p_error); /* p_error is initialized to NULL */ - if ((pkt->p_error = strdup(buf)) == NULL) { - /* To put the error description for the -KO_NOMEM - * error we needs a statically allocated error message: - * Note that all other functions don't need to report - * a statically allocated error message for -KO_NOMEM - * it will be auto-selected if strdup() returns NULL */ - pkt->p_error = ars_error_nomem; - } - return -ARS_OK; /* report anyway success */ -} - -/* Set the default for a layer */ -int ars_set_default(struct ars_packet *pkt, int layer_type, void *def) -{ - pkt->p_default[layer_type] = def; - return -ARS_OK; -} - -/* return nonzero if the packet is full */ -int ars_nospace(struct ars_packet *pkt) -{ - return (pkt->p_layer_nr == ARS_MAX_LAYER); -} - -/* Check if the layer number is valid */ -int ars_valid_layer(int layer) -{ - if (layer < 0 || layer >= ARS_MAX_LAYER) - return -ARS_INVALID; - return -ARS_OK; -} - -/* Add an a generic layer */ -int ars_add_generic(struct ars_packet *pkt, size_t size, int type) -{ - int layer; - - if (ars_nospace(pkt)) { - ars_set_error(pkt, "No space for the next layer"); - return -ARS_NOSPACE; - } - layer = pkt->p_layer_nr; - /* You may want to create a 0 len layer and then realloc */ - if (size != 0) { - pkt->p_layer[layer].l_data = malloc(size); - if (pkt->p_layer[layer].l_data == NULL) { - ars_set_error(pkt, "Out of memory adding a new layer"); - return -ARS_NOMEM; - } - memset(pkt->p_layer[layer].l_data, 0, size); - /* Copy the default if any */ - if (pkt->p_default[type] != NULL) { - memcpy(pkt->p_layer[layer].l_data, - pkt->p_default[type], size); - } - } - pkt->p_layer[layer].l_type = type; - pkt->p_layer[layer].l_size = size; - return -ARS_OK; -} - -/* Add an IP layer */ -void *ars_add_iphdr(struct ars_packet *pkt, int unused) -{ - int retval; - - retval = ars_add_generic(pkt, sizeof(struct ars_iphdr), ARS_TYPE_IP); - if (retval != -ARS_OK) - return NULL; - pkt->p_layer_nr++; - return pkt->p_layer[pkt->p_layer_nr-1].l_data; -} - -/* Add on IP option */ -void *ars_add_ipopt(struct ars_packet *pkt, int option) -{ - int retval; - struct ars_ipopt *ipopt; - int opt_len; - - switch(option) { - case ARS_IPOPT_END: - case ARS_IPOPT_NOOP: - opt_len = 1; - break; - case ARS_IPOPT_SEC: - opt_len = 11; - break; - case ARS_IPOPT_SID: - opt_len = 4; - break; - case ARS_IPOPT_LSRR: - case ARS_IPOPT_SSRR: - case ARS_IPOPT_RR: - case ARS_IPOPT_TIMESTAMP: - /* We allocate the max (40 bytes) but the real layer size - * may be modified by ars_ipopt_set*() functions */ - opt_len = 40; - break; - default: - return NULL; /* Unsupported option */ - break; - } - - retval = ars_add_generic(pkt, opt_len, ARS_TYPE_IPOPT); - if (retval != -ARS_OK) - return NULL; - ipopt = pkt->p_layer[pkt->p_layer_nr].l_data; - pkt->p_layer_nr++; - - ipopt->kind = option; - /* END and NOOP hasn't the length byte */ - if (option == ARS_IPOPT_END || option == ARS_IPOPT_NOOP) - return ipopt; - ipopt->len = opt_len; /* the default, can be modified inside switch() */ - /* Perform some special operation for some option */ - switch(option) { - case ARS_IPOPT_LSRR: /* ars_ipopt_setls() will change some field */ - case ARS_IPOPT_SSRR: /* ars_ipopt_setss() will change some field */ - case ARS_IPOPT_RR: /* ars_ipopt_setrr() will change some field */ - /* RFC 791 needs the roomlen - 3 octects, so the gateways - * can compare len and ptr to check for room. - * Try to break this to stress lame TCP/IP implementation */ - ipopt->len = opt_len - 2 - 3; - ipopt->un.rr.ptr = 4; - break; - case ARS_IPOPT_TIMESTAMP: - ipopt->len = opt_len - 2 - 4; - ipopt->un.ts.ptr = 5; - ipopt->un.ts.flags = ARS_IPOPT_TS_TSONLY; /* default */ - break; - } - return ipopt; -} - -/* Add a UDP layer */ -void *ars_add_udphdr(struct ars_packet *pkt, int unused) -{ - int retval; - - retval = ars_add_generic(pkt, sizeof(struct ars_udphdr), ARS_TYPE_UDP); - if (retval != -ARS_OK) - return NULL; - pkt->p_layer_nr++; - return pkt->p_layer[pkt->p_layer_nr-1].l_data; -} - -/* Add a TCP layer */ -void *ars_add_tcphdr(struct ars_packet *pkt, int unused) -{ - int retval; - - retval = ars_add_generic(pkt, sizeof(struct ars_tcphdr), ARS_TYPE_TCP); - if (retval != -ARS_OK) - return NULL; - pkt->p_layer_nr++; - return pkt->p_layer[pkt->p_layer_nr-1].l_data; -} - -/* Add TCP options */ -void *ars_add_tcpopt(struct ars_packet *pkt, int option) -{ - int retval; - struct ars_tcpopt *tcpopt; - int opt_len; - - switch(option) { - case ARS_TCPOPT_NOP: - case ARS_TCPOPT_EOL: - opt_len = 1; - break; - case ARS_TCPOPT_MAXSEG: - opt_len = 4; - break; - case ARS_TCPOPT_WINDOW: - opt_len = 3; - break; - case ARS_TCPOPT_SACK_PERM: - opt_len = 2; - break; - case ARS_TCPOPT_SACK: - opt_len = 8*4+2; - break; - case ARS_TCPOPT_ECHOREQUEST: - case ARS_TCPOPT_ECHOREPLY: - opt_len = 6; - break; - case ARS_TCPOPT_TIMESTAMP: - opt_len = 10; - break; - default: - return NULL; /* Unsupported option */ - break; - } - - retval = ars_add_generic(pkt, opt_len, ARS_TYPE_TCPOPT); - if (retval != -ARS_OK) - return NULL; - tcpopt = pkt->p_layer[pkt->p_layer_nr].l_data; - pkt->p_layer_nr++; - - tcpopt->kind = option; - /* EOL and NOP lacks the len field */ - if (option != ARS_TCPOPT_EOL && option != ARS_TCPOPT_NOP) - tcpopt->len = opt_len; - - /* Perform some special operation for the option */ - switch(option) { - case ARS_TCPOPT_ECHOREQUEST: - case ARS_TCPOPT_ECHOREPLY: - memset(tcpopt->un.echo.info, 0, 4); - break; - case ARS_TCPOPT_TIMESTAMP: - memset(tcpopt->un.timestamp.tsval, 0, 4); - memset(tcpopt->un.timestamp.tsecr, 0, 4); - break; - } - return tcpopt; -} - -/* Add an ICMP layer */ -void *ars_add_icmphdr(struct ars_packet *pkt, int unused) -{ - int retval; - struct ars_icmphdr *icmp; - - retval = ars_add_generic(pkt, sizeof(struct ars_icmphdr),ARS_TYPE_ICMP); - if (retval != -ARS_OK) - return NULL; - icmp = pkt->p_layer[pkt->p_layer_nr].l_data; - icmp->type = ARS_ICMP_ECHO; - icmp->code = 0; - pkt->p_layer_nr++; - return (struct ars_icmphdr*) pkt->p_layer[pkt->p_layer_nr-1].l_data; -} - -/* Add an IGRP layer */ -void *ars_add_igrphdr(struct ars_packet *pkt, int unused) -{ - int retval; - struct ars_igrphdr *igrp; - - retval = ars_add_generic(pkt, sizeof(struct ars_igrphdr),ARS_TYPE_IGRP); - if (retval != -ARS_OK) - return NULL; - igrp = pkt->p_layer[pkt->p_layer_nr].l_data; - igrp->opcode = ARS_IGRP_OPCODE_REQUEST; - igrp->version = 1; - igrp->edition = 0; - igrp->autosys = 0; - igrp->interior = 0; - igrp->system = 0; - igrp->exterior = 0; - pkt->p_layer_nr++; - return pkt->p_layer[pkt->p_layer_nr-1].l_data; -} - -/* Add an IGRP entry */ -void *ars_add_igrpentry(struct ars_packet *pkt, int unused) -{ - int retval; - - retval = ars_add_generic(pkt, sizeof(struct ars_igrpentry),ARS_TYPE_IGRPENTRY); - if (retval != -ARS_OK) - return NULL; - pkt->p_layer_nr++; - return pkt->p_layer[pkt->p_layer_nr-1].l_data; -} - -/* Add data, for IP-RAW, TCP, UDP, and so on */ -void *ars_add_data(struct ars_packet *pkt, int size) -{ - int retval; - static void *ptr = "zzappt"; /* we can't return NULL for size == 0 */ - - if (size < 0) { - ars_set_error(pkt, "Tryed to add a DATA layer with size < 0"); - return NULL; - } - retval = ars_add_generic(pkt, size, ARS_TYPE_DATA); - if (retval != -ARS_OK) - return NULL; - pkt->p_layer_nr++; - if (size > 0) - return pkt->p_layer[pkt->p_layer_nr-1].l_data; - else - return ptr; -} - -/* Remove a layer */ -int ars_remove_layer(struct ars_packet *pkt, int layer) -{ - if (layer == ARS_LAST_LAYER) - layer = pkt->p_layer_nr -1; - if (ars_valid_layer(layer) != -ARS_OK) - return -ARS_INVALID; - - free(pkt->p_layer[layer].l_data); /* No problem if it's NULL */ - pkt->p_layer[layer].l_type = ARS_TYPE_NULL; - pkt->p_layer[layer].l_size = 0; - pkt->p_layer[layer].l_flags = 0; - pkt->p_layer[layer].l_data = NULL; - pkt->p_layer[layer].l_packet = pkt; - return -ARS_OK; -} - -/* Return the sum of the size of the specifed layer and of all the - * following layers */ -size_t ars_relative_size(struct ars_packet *pkt, int layer_nr) -{ - int j = layer_nr, rel_size = 0; - - while (j < ARS_MAX_LAYER && pkt->p_layer[j].l_type != ARS_TYPE_NULL) { - rel_size += pkt->p_layer[j].l_size; - j++; - } - return rel_size; -} - -/* Just a short cut for ars_relative_size(), to get the total size */ -size_t ars_packet_size(struct ars_packet *pkt) -{ - return ars_relative_size(pkt, 0); -} - -/* from R. Stevens's Network Programming */ -u_int16_t ars_cksum(void *vbuf, size_t nbytes) -{ - u_int16_t *buf = (u_int16_t*) vbuf; - u_int32_t sum; - u_int16_t oddbyte; - - sum = 0; - while (nbytes > 1) { - sum += *buf++; - nbytes -= 2; - } - if (nbytes == 1) { - oddbyte = 0; - *((u_int16_t *) &oddbyte) = *(u_int16_t *) buf; - sum += oddbyte; - } - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - return (u_int16_t) ~sum; -} - -/* Multiple buffers checksum facility */ -u_int16_t ars_multi_cksum(struct mc_context *c, int op, void *vbuf, - size_t nbytes) -{ - u_int16_t *buf = (u_int16_t*) vbuf; - u_int32_t sum; - u_int16_t oddbyte; - void *tmp; - - if (op == ARS_MC_INIT) { - c->oddbyte_flag = 0; - c->old = 0; - return -ARS_OK; - } else if (op == ARS_MC_UPDATE) { - if (c->oddbyte_flag) { - u_int8_t *x = (u_int8_t*)&oddbyte; - oddbyte = 0; - *((u_int16_t *) &oddbyte) = c->oddbyte << 8; - *((u_int16_t *) &oddbyte) |= *(u_int16_t *) buf; - oddbyte = (x[0] << 8) | x[1]; /* fix endianess */ - c->old += oddbyte; - nbytes--; - c->oddbyte_flag = 0; - /* We need to stay aligned -- bad slowdown, fix? */ - tmp = alloca(nbytes); - memcpy(tmp, vbuf+1, nbytes); - buf = tmp; - } - sum = c->old; - while (nbytes > 1) { - sum += *buf++; - nbytes -= 2; - } - c->old = sum; - if (nbytes == 1) { - c->oddbyte = *(u_int16_t*) buf; - c->oddbyte_flag++; - } - return -ARS_OK; - } else if (op == ARS_MC_FINAL) { - sum = c->old; - if (c->oddbyte_flag == 1) { - oddbyte = 0; - *((u_int16_t *) &oddbyte) = c->oddbyte; - sum += oddbyte; - } - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - return (u_int16_t) ~sum; - } else { - assert("else reached in ars_multi_cksum()" == ""); - } - return 0; /* unreached, here to prevent warnings */ -} - -/* The ARS compiler table is just a function pointers array: - * For example to select the right function to compile an IP - * layer use: ars_compiler[ARS_TYPE_IP](pkt, layer); - * You can, of course, add your protocols and compilers: - * - * WARNING: take it syncronized with ars.h ARS_TYPE_* defines - */ -struct ars_layer_info ars_linfo[ARS_TYPE_SIZE] = { -/* NAME COMPILER ID * - * ---- -------- -- */ -{ "NULL", ars_compiler_abort, NULL, 0 }, -{ "IP", ars_compiler_ip, ars_rapd_ip, 1 }, -{ "IPOPT", ars_compiler_ipopt, ars_rapd_ipopt, 2 }, -{ "ICMP", ars_compiler_icmp, ars_rapd_icmp, 3 }, -{ "UDP", ars_compiler_udp, ars_rapd_udp, 4 }, -{ "TCP", ars_compiler_tcp, ars_rapd_tcp, 5 }, -{ "TCPOPT", ars_compiler_tcpopt, ars_rapd_tcpopt, 6 }, -{ "IGRP", ars_compiler_igrp, ars_rapd_igrp, 7 }, -{ "IGRPENTRY", NULL, ars_rapd_igrpentry, 8 }, -{ NULL, NULL, NULL, 9 }, -{ NULL, NULL, NULL, 10 }, -{ NULL, NULL, NULL, 11 }, -{ NULL, NULL, NULL, 12 }, -{ NULL, NULL, NULL, 13 }, -{ NULL, NULL, NULL, 14 }, -{ NULL, NULL, NULL, 15 }, -{ NULL, NULL, NULL, 16 }, -{ NULL, NULL, NULL, 17 }, -{ NULL, NULL, NULL, 18 }, -{ NULL, NULL, NULL, 19 }, -{ NULL, NULL, NULL, 20 }, -{ NULL, NULL, NULL, 21 }, -{ NULL, NULL, NULL, 22 }, -{ NULL, NULL, NULL, 23 }, -{ NULL, NULL, NULL, 24 }, -{ NULL, NULL, NULL, 25 }, -{ NULL, NULL, NULL, 26 }, -{ NULL, NULL, NULL, 27 }, -{ NULL, NULL, NULL, 28 }, -{ NULL, NULL, NULL, 29 }, -{ NULL, NULL, NULL, 30 }, -{ "DATA", NULL, ars_rapd_data, 31 } -}; - -/* This function call the right compiler for all the layers of the packet: - * A compiler just set the protocol fields like the checksum, len, and so on - * accordly to the following layers. - * Note that the layers are compiled from the last to the first, to ensure - * that the checksum and other dependences are sane. */ -int ars_compile(struct ars_packet *pkt) -{ - int j, err; - - for (j = pkt->p_layer_nr - 1; j >= 0; j--) { - __D(printf("Compiling layer %d\n", j);) - /* Skip NULL compilers */ - if (ars_linfo[pkt->p_layer[j].l_type].li_compiler != NULL) { - /* Call the compiler */ - err = ars_linfo[pkt->p_layer[j].l_type].li_compiler(pkt, j); - if (err != -ARS_OK) - return err; - } - } - return -ARS_OK; -} - -/* The IP compiler: probably the more complex, but still simple */ -int ars_compiler_ip(struct ars_packet *pkt, int layer) -{ - struct ars_iphdr *ip = pkt->p_layer[layer].l_data; - int j = layer, err; - int flags = pkt->p_layer[layer].l_flags; - int ipoptlen = 0; - struct mc_context mc; /* multi-buffer checksum context */ - - /* IP version */ - if (ARS_DONTTAKE(flags, ARS_TAKE_IP_VERSION)) - ip->version = 4; - /* IP header len */ - if (ARS_DONTTAKE(flags, ARS_TAKE_IP_HDRLEN)) { - ip->ihl = (ARS_IPHDR_SIZE >> 2); - /* Add IP options len */ - for (j = layer+1; j < ARS_MAX_LAYER; j++) { - if (pkt->p_layer[j].l_type != ARS_TYPE_IPOPT) - break; - ipoptlen += pkt->p_layer[j].l_size; - } - ip->ihl += ipoptlen >> 2; - } - /* IP tot len */ - if (ARS_DONTTAKE(flags, ARS_TAKE_IP_TOTLEN)) - ip->tot_len = htons(ars_relative_size(pkt, layer)); - /* IP protocol field */ - if (ARS_DONTTAKE(flags, ARS_TAKE_IP_PROTOCOL)) { - ip->protocol = ARS_IPPROTO_RAW; /* This is the default */ - while (j < ARS_MAX_LAYER) { - if (pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) { - j++; - continue; - } - switch(pkt->p_layer[j].l_type) { - case ARS_TYPE_IP: - ip->protocol = ARS_IPPROTO_IPIP; - break; - case ARS_TYPE_ICMP: - ip->protocol = ARS_IPPROTO_ICMP; - break; - case ARS_TYPE_UDP: - ip->protocol = ARS_IPPROTO_UDP; - break; - case ARS_TYPE_TCP: - ip->protocol = ARS_IPPROTO_TCP; - break; - case ARS_TYPE_IGRP: - ip->protocol = ARS_IPPROTO_IGRP; - break; - } - break; - } - } - /* We always calculate the IP checksum, since the kernel - * do it only for the first IP header in the datagram */ - if (ARS_DONTTAKE(flags, ARS_TAKE_IP_CKSUM)) { - ip->check = 0; - ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); - err = ars_multi_cksum(&mc, ARS_MC_UPDATE, ip, ARS_IPHDR_SIZE); - if (err != -ARS_OK) - return err; - for (j = layer+1; j < ARS_MAX_LAYER; j++) { - if (pkt->p_layer[j].l_type != ARS_TYPE_IPOPT) - break; - err = ars_multi_cksum(&mc, ARS_MC_UPDATE, - pkt->p_layer[j].l_data, - pkt->p_layer[j].l_size); - if (err != -ARS_OK) - return err; - } - ip->check = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); - } - return -ARS_OK; -} - -/* The ip options compiler: do just option padding with NOP options */ -int ars_compiler_ipopt(struct ars_packet *pkt, int layer) -{ - int j, opt_size; - - /* Padding is needed only in the last IP option */ - if (layer != ARS_MAX_LAYER-1 && - pkt->p_layer[layer+1].l_type == ARS_TYPE_IPOPT) - return ARS_OK; - - /* Search the layer of the relative first IP option */ - j = layer - 1; /* We know that 'layer' is an IP option */ - while (j < ARS_MAX_LAYER && j >= 0 && - pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) - j--; - j++; - __D(printf("First IP OPTION layer is %d\n", j);) - opt_size = ars_relative_size(pkt, j) - ars_relative_size(pkt, layer+1); - __D(printf("IP OPTION size %d\n", opt_size);) - if (opt_size % 4) { - int padding = 4 - (opt_size % 4); - unsigned char *t; - int cur_size = pkt->p_layer[layer].l_size; - - __D(printf("IP OPTION at layer %d needs %d bytes " - "of padding\n", layer, padding);) - t = realloc(pkt->p_layer[layer].l_data, cur_size + padding); - if (t == NULL) { - ars_set_error(pkt, "Out of memory padding IP options"); - return -ARS_NOMEM; - } - memset(t+cur_size, ARS_IPOPT_NOP, padding); - __D(printf("The last IP OPTION length was: %d\n", cur_size);) - pkt->p_layer[layer].l_data = t; - pkt->p_layer[layer].l_size += padding; - __D(printf("After padding it is: %d\n", pkt->p_layer[layer].l_size);) - } - return -ARS_OK; -} - -/* Compute the UDP and TCP checksum using the pseudoheader. - * Note that this functions automatically care about TCP/UDP data. - * FIXME: this doesn't work when the IP source address is 0.0.0.0 */ -int ars_udptcp_cksum(struct ars_packet *pkt, int layer, u_int16_t *sum) -{ - struct ars_iphdr *ip; - struct ars_pseudohdr pseudo; - struct mc_context mc; /* multi-buffer checksum context */ - int j = layer - 1, err; - - /* search the first IP layer on the left: - * it returns an error if between the IP and - * the TCP layer there aren't just IPOPT layers: - * even with malformed packets this does not - * makes sense. */ - while (j > 0 && pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) - j--; - if (pkt->p_layer[j].l_type != ARS_TYPE_IP) { - ars_set_error(pkt, "TCP/UDP checksum requested, but IP header " - "not found"); - return -ARS_INVALID; - } - ip = pkt->p_layer[j].l_data; - memset(&pseudo, 0, sizeof(pseudo)); /* actually not needed */ - /* Copy the src and dst IP address */ - memcpy(&pseudo.saddr, &ip->saddr, 4); - memcpy(&pseudo.daddr, &ip->daddr, 4); - pseudo.protocol = (pkt->p_layer[layer].l_type == ARS_TYPE_TCP) - ? ARS_IPPROTO_TCP : ARS_IPPROTO_UDP; - pseudo.lenght = htons(ars_relative_size(pkt, layer)); - - /* Finally do the checksum */ - ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); - err = ars_multi_cksum(&mc, ARS_MC_UPDATE, &pseudo, sizeof(pseudo)); - if (err != -ARS_OK) - return err; - for (j = layer; j < ARS_MAX_LAYER; j++) { - if (pkt->p_layer[j].l_type == ARS_TYPE_NULL) - break; - err = ars_multi_cksum(&mc, ARS_MC_UPDATE, - pkt->p_layer[j].l_data, - pkt->p_layer[j].l_size); - if (err != -ARS_OK) - return err; - } - *sum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); - return -ARS_OK; -} - -/* The tcp compiler */ -int ars_compiler_tcp(struct ars_packet *pkt, int layer) -{ - struct ars_tcphdr *tcp = pkt->p_layer[layer].l_data; - int j, err, tcpoptlen = 0; - int flags = pkt->p_layer[layer].l_flags; - - if (ARS_DONTTAKE(flags, ARS_TAKE_TCP_HDRLEN)) { - tcp->th_off = ARS_TCPHDR_SIZE >> 2; - /* Add the len of the options */ - for (j = layer+1; j < ARS_MAX_LAYER; j++) { - if (pkt->p_layer[j].l_type != ARS_TYPE_TCPOPT) - break; - tcpoptlen += pkt->p_layer[j].l_size; - } - tcp->th_off += tcpoptlen >> 2; - } - if (ARS_DONTTAKE(flags, ARS_TAKE_TCP_CKSUM)) { - tcp->th_sum = 0; - err = ars_udptcp_cksum(pkt, layer, &tcp->th_sum); - if (err != -ARS_OK) - return err; - } - return -ARS_OK; -} - -/* The tcp options compiler: do just option padding with NOP options */ -int ars_compiler_tcpopt(struct ars_packet *pkt, int layer) -{ - int j, opt_size; - - /* Padding is needed only in the last TCP option */ - if (layer != ARS_MAX_LAYER-1 && - pkt->p_layer[layer+1].l_type == ARS_TYPE_TCPOPT) - return ARS_OK; - - /* Search the layer of the relative first TCP option */ - j = layer - 1; /* We know that 'layer' is a tcp option */ - while (j < ARS_MAX_LAYER && j >= 0 && - pkt->p_layer[j].l_type == ARS_TYPE_TCPOPT) - j--; - j++; - __D(printf("First TCP OPTION layer is %d\n", j);) - opt_size = ars_relative_size(pkt, j) - ars_relative_size(pkt, layer+1); - __D(printf("TCP OPTION size %d\n", opt_size);) - if (opt_size % 4) { - int padding = 4 - (opt_size % 4); - unsigned char *t; - int cur_size = pkt->p_layer[layer].l_size; - - __D(printf("TCP OPTION at layer %d needs %d bytes " - "of padding\n", layer, padding);) - t = realloc(pkt->p_layer[layer].l_data, cur_size + padding); - if (t == NULL) { - ars_set_error(pkt, "Out of memory padding TCP options"); - return -ARS_NOMEM; - } - memset(t+cur_size, ARS_TCPOPT_NOP, padding); - pkt->p_layer[layer].l_size += padding; - } - return -ARS_OK; -} - -/* The udp compiler, very simple */ -int ars_compiler_udp(struct ars_packet *pkt, int layer) -{ - struct ars_udphdr *udp = pkt->p_layer[layer].l_data; - int err; - int flags = pkt->p_layer[layer].l_flags; - - if (ARS_DONTTAKE(flags, ARS_TAKE_UDP_LEN)) - udp->uh_ulen = htons(ars_relative_size(pkt, layer)); - - if (ARS_DONTTAKE(flags, ARS_TAKE_UDP_CKSUM)) { - udp->uh_sum = 0; - err = ars_udptcp_cksum(pkt, layer, &udp->uh_sum); - if (err != -ARS_OK) - return err; - } - return -ARS_OK; -} - -/* The icmp compiler, just compute the checksum */ -int ars_compiler_icmp(struct ars_packet *pkt, int layer) -{ - struct ars_icmphdr *icmp = pkt->p_layer[layer].l_data; - struct mc_context mc; /* multi-buffer checksum context */ - int err, j; - int flags = pkt->p_layer[layer].l_flags; - - if (ARS_DONTTAKE(flags, ARS_TAKE_ICMP_CKSUM)) { - icmp->checksum = 0; - ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); - for (j = layer; j < ARS_MAX_LAYER; j++) { - if (pkt->p_layer[j].l_type == ARS_TYPE_NULL) - break; - err = ars_multi_cksum(&mc, ARS_MC_UPDATE, - pkt->p_layer[j].l_data, - pkt->p_layer[j].l_size); - if (err != -ARS_OK) - return err; - } - icmp->checksum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); - } - return -ARS_OK; -} - -/* The igrp compiler, just compute the checksum */ -int ars_compiler_igrp(struct ars_packet *pkt, int layer) -{ - struct ars_igrphdr *igrp = pkt->p_layer[layer].l_data; - struct mc_context mc; /* multi-buffer checksum context */ - int err, j; - int flags = pkt->p_layer[layer].l_flags; - - if (ARS_DONTTAKE(flags, ARS_TAKE_IGRP_CKSUM)) { - igrp->checksum = 0; - ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); - for (j = layer; j < ARS_MAX_LAYER; j++) { - if (pkt->p_layer[j].l_type == ARS_TYPE_NULL) - break; - err = ars_multi_cksum(&mc, ARS_MC_UPDATE, - pkt->p_layer[j].l_data, - pkt->p_layer[j].l_size); - if (err != -ARS_OK) - return err; - } - igrp->checksum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); - } - return -ARS_OK; -} - -/* Open a raw socket, ready for IP header creation and broadcast addresses */ -int ars_open_rawsocket(struct ars_packet *pkt) -{ - int s; - const int one = 1; - - if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) { - ars_set_error(pkt, "Can't open the raw socket"); - return -ARS_ERROR; - } - if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&one, - sizeof(one)) == -1 || - setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*)&one, - sizeof(one)) == -1) - { - close(s); - ars_set_error(pkt, "Can't set socket options"); - return -ARS_ERROR; - } - return s; -} - -/* Create the packets using the layers. This function is often called - * after the layers compilation. Note that since the packet created - * is sane the strange-rawsocket-behaviour of some *BSD will not - * be able to send this packet. Use the function ars_bsd_fix() to fix it. - * WARNING: The packets returned is malloc()ated, free it */ -int ars_build_packet(struct ars_packet *pkt, unsigned char **packet, size_t *size) -{ - size_t tot_size, offset = 0; - int j = 0; - - if ((tot_size = ars_packet_size(pkt)) == 0) { - ars_set_error(pkt, "Total size 0 building the packet"); - return -ARS_INVALID; - } - if ((*packet = malloc(tot_size)) == NULL) { - ars_set_error(pkt, "Out of memory building the packet"); - return -ARS_NOMEM; - } - while (j < ARS_MAX_LAYER && pkt->p_layer[j].l_type != ARS_TYPE_NULL) { - memcpy((*packet)+offset, pkt->p_layer[j].l_data, - pkt->p_layer[j].l_size); - offset += pkt->p_layer[j].l_size; - j++; - } - *size = tot_size; - return -ARS_OK; -} - -/* FreeBSD and NetBSD have a strange raw socket layer :( - * Call this function anyway to increase portability - * since it does not perform any operation if the - * system isn't FreeBSD or NetBSD. */ -int ars_bsd_fix(struct ars_packet *pkt, unsigned char *packet, size_t size) -{ - struct ars_iphdr *ip; - - if (pkt->p_layer[0].l_type != ARS_TYPE_IP || - size < sizeof(struct ars_iphdr)) { - ars_set_error(pkt, "BSD fix requested, but layer 0 not IP"); - return -ARS_INVALID; - } - ip = (struct ars_iphdr*) packet; -#if defined OSTYPE_DARWIN || defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD || defined OSTYPE_BSDI - ip->tot_len = ntohs(ip->tot_len); - ip->frag_off = ntohs(ip->frag_off); -#endif - return -ARS_OK; -} - -/* Set the flags for some layer: if layer == -1 the last layer will be used */ -int ars_set_flags(struct ars_packet *pkt, int layer, int flags) -{ - if (layer == ARS_LAST_LAYER) - layer = pkt->p_layer_nr - 1; - if (layer < 0 || layer >= ARS_MAX_LAYER) { - ars_set_error(pkt, "Invalid layer setting layer flags"); - return -ARS_INVALID; - } - pkt->p_layer[layer].l_flags = flags; - return -ARS_OK; -} - -/* Build, fix, and send the packet */ -int ars_send(int s, struct ars_packet *pkt, struct sockaddr *sa, socklen_t slen) -{ - struct sockaddr_in sain; - struct sockaddr *_sa = sa; - unsigned char *packet; - size_t size; - int error; - - /* Perform the socket address completion if sa == NULL */ - if (sa == NULL) { - struct ars_iphdr *ip; - - memset(&sain, 0, sizeof(sain)); - sain.sin_family = AF_INET; - /* The first layer MUST be IP if the user requested - * the socket address completion */ - if (pkt->p_layer[0].l_type != ARS_TYPE_IP) { - ars_set_error(pkt, "socket address completion" - "requested, but layer 0 isn't IP"); - return -ARS_ERROR; - } - ip = (struct ars_iphdr*) pkt->p_layer[0].l_data; - memcpy(&sain.sin_addr.s_addr, &ip->daddr, 4); - _sa = (struct sockaddr*) &sain; - slen = sizeof(sain); - } - if ((error = ars_build_packet(pkt, &packet, &size)) != ARS_OK) - return error; - if ((error = ars_bsd_fix(pkt, packet, size)) != ARS_OK) - return error; - error = sendto(s, packet, size, 0, _sa, slen); - free(packet); - return (error != -1) ? -ARS_OK : -ARS_ERROR; -} - -/* Resolve an hostname and write to 'dest' the IP */ -int ars_resolve(struct ars_packet *pkt, u_int32_t *dest, char *hostname) -{ - struct sockaddr_in sa; - - if (inet_aton(hostname, &sa.sin_addr) == 0) { - struct hostent *he; - he = gethostbyname(hostname); - if (he == NULL) { - ars_set_error(pkt, "Can't resolve the hostname"); - return -ARS_ERROR; - } - sa.sin_addr.s_addr = ((struct in_addr*) he->h_addr)->s_addr; - } - memcpy(dest, &sa.sin_addr.s_addr, sizeof(u_int32_t)); - return -ARS_OK; -} diff --git a/ars.h b/ars.h deleted file mode 100644 index ba460fe..0000000 --- a/ars.h +++ /dev/null @@ -1,531 +0,0 @@ -/* Copyright (C) 2000,2001 Salvatore Sanfilippo - * See the LICENSE file for more information. */ - -/* $Id: ars.h,v 1.4 2004/06/04 07:22:38 antirez Exp $ */ - -#ifndef _ARS_H -#define _ARS_H - -/* define before including sys/socket.h */ -#if defined(__APPLE__) && !defined(_BSD_SOCKLEN_T_) -#define _BSD_SOCKLEN_T_ int -#endif - -#include -#include -#include -#include -#include "systype.h" -#include "in.h" -#include "byteorder.h" -#include "adbuf.h" -#include "fixtypes.h" - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - - -#ifndef MIN -#define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - -#ifndef MAX -#define MAX(x,y) ((x)>(y)?(x):(y)) -#endif - -#ifdef DEBUG -#define __D(x) x -#else -#define __D(x) do { } while (0); -#endif - -#ifndef __u8 -#define __u8 u_int8_t -#define __u16 u_int16_t -#define __u32 u_int32_t -#endif - -/* error codes */ -#define ARS_OK 0 -#define ARS_ERROR 1 -#define ARS_NOSPACE 2 -#define ARS_NOMEM 3 -#define ARS_INVALID 4 - -/* Headers size */ -#define ARS_ICMPHDR_SIZE sizeof(struct ars_icmphdr) -#define ARS_UDPHDR_SIZE sizeof(struct ars_udphdr) -#define ARS_TCPHDR_SIZE sizeof(struct ars_tcphdr) -#define ARS_IPHDR_SIZE sizeof(struct ars_iphdr) -#define ARS_PSEUDOHDR_SIZE sizeof(struct pseudohdr) -#define ARS_IGRPHDR_SIZE sizeof(struct ars_igrphdr) -#define ARS_IGRPENTRY_SIZE sizeof(struct ars_igrpentry) - -/* IP defines */ -#define ARS_MAX_IP_SIZE 65535 - -#define ARS_IP_MF ((unsigned short)0x2000) /* more fragments */ -#define ARS_IP_DF ((unsigned short)0x4000) /* dont fragment */ -#define ARS_IP_RF ((unsigned short)0x8000) /* reserved fragment flag */ - -#define ARS_IPOPT_COPY 0x80 -#define ARS_IPOPT_CLASS_MASK 0x60 -#define ARS_IPOPT_NUMBER_MASK 0x1f - -#define ARS_IPOPT_COPIED(o) ((o)&ARS_IPOPT_COPY) -#define ARS_IPOPT_CLASS(o) ((o)&ARS_IPOPT_CLASS_MASK) -#define ARS_IPOPT_NUMBER(o) ((o)&ARS_IPOPT_NUMBER_MASK) - -#define ARS_IPOPT_CONTROL 0x00 -#define ARS_IPOPT_RESERVED1 0x20 -#define ARS_IPOPT_MEASUREMENT 0x40 -#define ARS_IPOPT_RESERVED2 0x60 - -#define ARS_IPOPT_END (0 |ARS_IPOPT_CONTROL) -#define ARS_IPOPT_NOOP (1 |ARS_IPOPT_CONTROL) -#define ARS_IPOPT_SEC (2 |ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) -#define ARS_IPOPT_LSRR (3 |ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) -#define ARS_IPOPT_TIMESTAMP (4 |ARS_IPOPT_MEASUREMENT) -#define ARS_IPOPT_RR (7 |ARS_IPOPT_CONTROL) -#define ARS_IPOPT_SID (8 |ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) -#define ARS_IPOPT_SSRR (9 |ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) -#define ARS_IPOPT_RA (20|ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) - -#define ARS_IPOPT_OPTVAL 0 -#define ARS_IPOPT_OLEN 1 -#define ARS_IPOPT_OFFSET 2 -#define ARS_IPOPT_MINOFF 4 -#define ARS_MAX_IPOPTLEN 40 -#define ARS_IPOPT_NOP ARS_IPOPT_NOOP -#define ARS_IPOPT_EOL ARS_IPOPT_END -#define ARS_IPOPT_TS ARS_IPOPT_TIMESTAMP - -#define ARS_IPOPT_TS_TSONLY 0 /* timestamps only */ -#define ARS_IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ -#define ARS_IPOPT_TS_PRESPEC 3 /* specified modules only */ - -/* IPV4 and IPV6 string rappresentation len */ -#define ARS_INET_ADDRSTRLEN 16 -#define ARS_INET6_ADDRSTRLEN 46 - -/* TCP */ -#define ARS_TCPOPT_EOL 0 -#define ARS_TCPOPT_NOP 1 -#define ARS_TCPOPT_MAXSEG 2 -#define ARS_TCPOPT_WINDOW 3 -#define ARS_TCPOPT_SACK_PERM 4 -#define ARS_TCPOPT_SACK 5 -#define ARS_TCPOPT_ECHOREQUEST 6 -#define ARS_TCPOPT_ECHOREPLY 7 -#define ARS_TCPOPT_TIMESTAMP 8 - -#define ARS_TCP_TH_FIN 0x01 -#define ARS_TCP_TH_SYN 0x02 -#define ARS_TCP_TH_RST 0x04 -#define ARS_TCP_TH_PUSH 0x08 -#define ARS_TCP_TH_ACK 0x10 -#define ARS_TCP_TH_URG 0x20 -#define ARS_TCP_TH_X 0x40 /* X tcp flag */ -#define ARS_TCP_TH_Y 0x80 /* Y tcp flag */ - -/* ICMP TYPE */ -#define ARS_ICMP_ECHOREPLY 0 /* Echo Reply */ -#define ARS_ICMP_DEST_UNREACH 3 /* Destination Unreachable */ -#define ARS_ICMP_SOURCE_QUENCH 4 /* Source Quench */ -#define ARS_ICMP_REDIRECT 5 /* Redirect (change route) */ -#define ARS_ICMP_ECHO 8 /* Echo Request */ -#define ARS_ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ -#define ARS_ICMP_PARAMETERPROB 12 /* Parameter Problem */ -#define ARS_ICMP_TIMESTAMP 13 /* Timestamp Request */ -#define ARS_ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ -#define ARS_ICMP_INFO_REQUEST 15 /* Information Request */ -#define ARS_ICMP_INFO_REPLY 16 /* Information Reply */ -#define ARS_ICMP_ADDRESS 17 /* Address Mask Request */ -#define ARS_ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ - -/* Codes for UNREACHABLE */ -#define ARS_ICMP_UNR_NET 0 /* Network Unreachable */ -#define ARS_ICMP_UNR_HOST 1 /* Host Unreachable */ -#define ARS_ICMP_UNR_PROT 2 /* Protocol Unreachable */ -#define ARS_ICMP_UNR_PORT 3 /* Port Unreachable */ -#define ARS_ICMP_UNR_FRAG_NEEDED 4 /* Fragmentation Needed,DF set*/ -#define ARS_ICMP_UNR_SR_FAILED 5 /* Source Route failed */ -#define ARS_ICMP_UNR_UNK_NET 6 -#define ARS_ICMP_UNR_UNK_HOST 7 -#define ARS_ICMP_UNR_ISOLATED_HOST 8 -#define ARS_ICMP_UNR_NET_ANO 9 -#define ARS_ICMP_UNR_HOST_ANO 10 -#define ARS_ICMP_UNR_NET_UNR_TOS 11 -#define ARS_ICMP_UNR_HOST_UNR_TOS 12 -#define ARS_ICMP_UNR_PKT_FILTERED 13 /* Packet filtered */ -#define ARS_ICMP_UNR_PREC_VIOLATION 14 /* Precedence violation */ -#define ARS_ICMP_UNR_PREC_CUTOFF 15 /* Precedence cut off */ -#define ARS_NR_ICMP_UNREACH 15 /* Instead of hardcoded immediate value */ - -/* Codes for REDIRECT */ -#define ARS_ICMP_REDIR_NET 0 /* Redirect Net */ -#define ARS_ICMP_REDIR_HOST 1 /* Redirect Host */ -#define ARS_ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ -#define ARS_ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ - -/* Codes for TIME_EXCEEDED */ -#define ARS_ICMP_EXC_TTL 0 /* TTL count exceeded */ -#define ARS_ICMP_EXC_FRAGTIME 1 /* TTL exceeded reassembling */ - -/* IGRP defines */ -#define ARS_IGRP_OPCODE_UPDATE 1 -#define ARS_IGRP_OPCODE_REQUEST 2 - -/* The IP header structure */ -struct ars_iphdr { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 ihl:4, - version:4; -#elif defined (__BIG_ENDIAN_BITFIELD) - __u8 version:4, - ihl:4; -#else -#error "Please, edit Makefile and add -DBYTE_ORDER_(BIG|LITTLE)_ENDIAN" -#endif - __u8 tos; - __u16 tot_len; - __u16 id; - __u16 frag_off; - __u8 ttl; - __u8 protocol; - __u16 check; - __u32 saddr; - __u32 daddr; -}; - -/* The IP options structure */ -struct ars_ipopt { - u_int8_t kind; - u_int8_t len; - union { - struct { - u_int16_t s; - u_int16_t c; - u_int16_t h; - u_int8_t tcc[3]; - } sec; /* security */ - struct { - u_int8_t ptr; - u_int8_t data[37]; - } src; /* loose and strict source routing */ - struct { - u_int8_t ptr; - u_int8_t data[37]; - } rr; /* record route */ - struct { - u_int16_t id; - } sid; /* stream id */ - struct { - u_int8_t ptr; - u_int8_t flags; - u_int8_t data[36]; - } ts; /* timestamp */ - } un; -}; - -/* The UDP header structure */ -struct ars_udphdr { - __u16 uh_sport; /* source port */ - __u16 uh_dport; /* destination port */ - __u16 uh_ulen; /* udp length */ - __u16 uh_sum; /* udp checksum */ -}; - -/* The TCP header structure */ -struct ars_tcphdr { - __u16 th_sport; /* source port */ - __u16 th_dport; /* destination port */ - __u32 th_seq; /* sequence number */ - __u32 th_ack; /* acknowledgement number */ -#if defined (__LITTLE_ENDIAN_BITFIELD) - __u8 th_x2:4, /* (unused) */ - th_off:4; /* data offset */ -#elif defined (__BIG_ENDIAN_BITFIELD) - __u8 th_off:4, /* data offset */ - th_x2:4; /* (unused) */ -#else -#error "Please, edit Makefile and add -DBYTE_ORDER_(BIG|LITTLE)_ENDIAN" -#endif - __u8 th_flags; - __u16 th_win; /* window */ - __u16 th_sum; /* checksum */ - __u16 th_urp; /* urgent pointer */ -}; - -/* The TCP options structure */ -struct ars_tcpopt { - u_int8_t kind; - u_int8_t len; - union { - struct { - u_int16_t size; - } mss; - struct { - u_int8_t shift; - } win; - struct { - u_int8_t origin[4]; - u_int8_t size[4]; - } sack[4]; /* max 4 SACK blocks in 40 bytes of space */ - struct { - u_int8_t info[4]; - } echo; - struct { - u_int8_t tsval[4]; - u_int8_t tsecr[4]; - } timestamp; - } un; -}; - -/* The ICMP header structure */ -struct ars_icmphdr -{ - __u8 type; - __u8 code; - __u16 checksum; - union - { - struct - { - __u16 id; - __u16 sequence; - } echo; /* called echo since it's the most used */ - __u32 gateway; - } un; -}; - -/* TCP/UDP pseudo header used to compute the checksum */ -struct ars_pseudohdr -{ - __u32 saddr; - __u32 daddr; - __u8 zero; - __u8 protocol; - __u16 lenght; -}; - -/* The IGRP header structure */ -struct ars_igrphdr { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 opcode:4, - version:4; -#elif defined (__BIG_ENDIAN_BITFIELD) - __u8 version:4, - opcode:4; -#else -#error "Please, edit Makefile and add -DBYTE_ORDER_(BIG|LITTLE)_ENDIAN" -#endif - __u8 edition; - __u16 autosys; - __u16 interior; - __u16 system; - __u16 exterior; - __u16 checksum; -}; - -/* The IGRP entry */ -struct ars_igrpentry { - __u8 destination[3]; - __u8 delay[3]; - __u8 bandwidth[3]; - __u8 mtu[2]; - __u8 reliability; - __u8 load; - __u8 hopcount; -}; - -struct ars_packet; /* forward declaration */ - -/* ARS layer */ -struct ars_layer { - int l_type; - int l_size; - int l_flags; - void *l_data; - struct ars_packet *l_packet; -}; - -#define ARS_MAX_LAYER 256 -#define ARS_ERR_BUFSZ 1024 - -/* Types */ -#define ARS_TYPE_SIZE 32 -#define ARS_TYPE_NULL 0 -#define ARS_TYPE_IP 1 -#define ARS_TYPE_IPOPT 2 -#define ARS_TYPE_ICMP 3 -#define ARS_TYPE_UDP 4 -#define ARS_TYPE_TCP 5 -#define ARS_TYPE_TCPOPT 6 -#define ARS_TYPE_IGRP 7 -#define ARS_TYPE_IGRPENTRY 8 -#define ARS_TYPE_DATA 31 - -/* ARS packet context */ -struct ars_packet { - char *p_error; - int p_layer_nr; - struct ars_layer p_layer[ARS_MAX_LAYER]; - void *p_default[ARS_TYPE_SIZE]; - int p_options; - int aux; /* Auxiliar variable for data exchange between functions */ - int aux_ipproto; /* This hold the ip->proto field seen in the last - IP datagram so that when the IP options processing - is done, the split-machine can continue with - the right state. */ -}; - -/* Facility to check for flags */ -#define ARS_TAKE(f,x) (f & x) -#define ARS_DONTTAKE(f, x) (!(f & x)) -#define ARS_TAKE_NONE 0 - -/* IP layer flags */ -#define ARS_TAKE_IP_VERSION (1 << 0) -#define ARS_TAKE_IP_HDRLEN (1 << 1) -#define ARS_TAKE_IP_TOTLEN (1 << 2) -#define ARS_TAKE_IP_PROTOCOL (1 << 3) -#define ARS_TAKE_IP_CKSUM (1 << 4) - -/* IP options layers flags */ -#define ARS_TAKE_IPOPT_PTR (1 << 0) /* for RR, LSRR, SSRR */ - -/* ICMP layer flags */ -#define ARS_TAKE_ICMP_CKSUM (1 << 0) - -/* UDP layer flags */ -#define ARS_TAKE_UDP_CKSUM (1 << 0) -#define ARS_TAKE_UDP_LEN (1 << 1) - -/* TCP layer flags */ -#define ARS_TAKE_TCP_HDRLEN (1 << 0) -#define ARS_TAKE_TCP_CKSUM (1 << 1) - -/* IGRP layer flags */ -#define ARS_TAKE_IGRP_CKSUM (1 << 0) - -/* Some function that acts on layer switch to the last layer with this */ -#define ARS_LAST_LAYER -1 - -/* Structure and defines needed to calculate the internet-like checksum - * when the data is splitted in more not adjacent buffers */ -#define ARS_MC_INIT 0 -#define ARS_MC_UPDATE 1 -#define ARS_MC_FINAL 2 - -struct mc_context { - u_int32_t oddbyte_flag; - u_int32_t old; - u_int8_t oddbyte; - u_int8_t pad; -}; - -/* ARS layer info structure */ -struct ars_layer_info { - char *li_name; /* NULL = unused slot */ - int (*li_compiler) (struct ars_packet *pkt, int layer); /* NULL = NOP */ - int (*li_rapd) (struct adbuf *dest, struct ars_packet *pkt, int layer); - int layer_id; -}; - -/* ARS layer info table */ -extern struct ars_layer_info ars_linfo[ARS_TYPE_SIZE]; - -/* ARS interface managment structure and defines */ -#define ARS_IF_UP (1 << 0) -#define ARS_IF_LOOP (1 << 1) -#define ARS_IF_IPV4 (1 << 2) -#define ARS_IF_IPV6 (1 << 3) -#define ARS_IF_MISCONF (1 << 4) - -#define ARS_IF_MAX_IFACE 16 -#define ARS_IF_NAME_SIZE 32 - -/* iface type are obtained using libpcap to avoid efforts duplication */ -struct ars_iface { - char if_name[ARS_IF_NAME_SIZE]; - int if_mtu; - int if_flags; - char if_ipv4addr[ARS_INET_ADDRSTRLEN]; - char if_ipv6addr[ARS_INET6_ADDRSTRLEN]; -}; - -/* Flags for packet splitting */ -#define ARS_SPLIT_FTRUNC (1 << 0) -#define ARS_SPLIT_FBADCKSUM (1 << 1) - -/* Ars packet options */ -#define ARS_OPT_RAPD_HEXDATA (1 << 0) /* Use hex format for RAPD data */ - -/* More macros */ -#define ars_atou(x) strtoul(x, (char **) NULL, 0) -#define ars_set_option(pkt,opt) do { (pkt)->p_options |= (opt); } while(0) -#define ars_clear_option(pkt,opt) do { (pkt)->p_options &= ~(opt); } while(0) -#define ars_test_option(pkt,opt) ((pkt)->p_options & (opt)) - -/* Prototypes */ -int ars_init(struct ars_packet *pkt); -int ars_destroy(struct ars_packet *pkt); -int ars_nospace(struct ars_packet *pkt); -int ars_add_generic(struct ars_packet *pkt, size_t size, int type); -void *ars_add_iphdr(struct ars_packet *pkt, int unused); -void *ars_add_ipopt(struct ars_packet *pkt, int option); -void *ars_add_udphdr(struct ars_packet *pkt, int unused); -void *ars_add_tcphdr(struct ars_packet *pkt, int unused); -void *ars_add_tcpopt(struct ars_packet *pkt, int option); -void *ars_add_icmphdr(struct ars_packet *pkt, int unused); -void *ars_add_igrphdr(struct ars_packet *pkt, int unused); -void *ars_add_igrpentry(struct ars_packet *pkt, int unused); -void *ars_add_data(struct ars_packet *pkt, int size); -size_t ars_relative_size(struct ars_packet *pkt, int layer_nr); -size_t ars_packet_size(struct ars_packet *pkt); -u_int16_t ars_cksum(void *vbuf, size_t nbytes); -u_int16_t ars_multi_cksum(struct mc_context *c, int op, void *vbuf, size_t nbytes); -int ars_compile(struct ars_packet *pkt); -int ars_udptcp_cksum(struct ars_packet *pkt, int layer, u_int16_t *sum); -int ars_open_rawsocket(struct ars_packet *pkt); -int ars_build_packet(struct ars_packet *pkt, unsigned char **packet, size_t *size); -int ars_bsd_fix(struct ars_packet *pkt, unsigned char *packet, size_t size); -int ars_set_flags(struct ars_packet *pkt, int layer, int flags); -int ars_send(int s, struct ars_packet *pkt, struct sockaddr *sa, socklen_t slen); -int ars_resolve(struct ars_packet *pkt, u_int32_t *dest, char *hostname); -int ars_set_error(struct ars_packet *pkt, const char *fmt, ...); -int ars_d_build(struct ars_packet *pkt, char *t); -int ars_valid_layer(int layer); -int ars_get_iface_list(struct ars_iface *iface, size_t *isize); -int ars_get_iface(char *name, struct ars_iface *i); -int ars_valid_layer(int layer); -int ars_remove_layer(struct ars_packet *pkt, int layer); - -/* split.c prototypes */ -int ars_seems_ip(struct ars_iphdr *ip, size_t size); -int ars_guess_ipoff(void *packet, size_t size, int *lhs); -int ars_check_ip_cksum(struct ars_iphdr *ip); -int ars_check_icmp_cksum(struct ars_icmphdr *icmp, size_t size); -int ars_split_packet(void *packet, size_t size, int ipoff, struct ars_packet *pkt); - -/* reverse apd */ -int ars_d_from_ars(char *dest, size_t len, struct ars_packet *pkt); -int ars_rapd_ip(struct adbuf *dest, struct ars_packet *pkt, int layer); -int ars_rapd_ipopt(struct adbuf *dest, struct ars_packet *pkt, int layer); -int ars_rapd_icmp(struct adbuf *dest, struct ars_packet *pkt, int layer); -int ars_rapd_udp(struct adbuf *dest, struct ars_packet *pkt, int layer); -int ars_rapd_tcp(struct adbuf *dest, struct ars_packet *pkt, int layer); -int ars_rapd_tcpopt(struct adbuf *dest, struct ars_packet *pkt, int layer); -int ars_rapd_igrp(struct adbuf *dest, struct ars_packet *pkt, int layer); -int ars_rapd_igrpentry(struct adbuf *dest, struct ars_packet *pkt, int layer); -int ars_rapd_data(struct adbuf *dest, struct ars_packet *pkt, int layer); - -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ - !defined(__bsdi__) && !defined(__APPLE__) -size_t strlcpy(char *dst, const char *src, size_t siz); -#endif - -#endif /* _ARS_H */ diff --git a/arsglue.c b/arsglue.c deleted file mode 100644 index 9f05816..0000000 --- a/arsglue.c +++ /dev/null @@ -1,34 +0,0 @@ -/* Glue between hping and the ars engine */ - -/* $Id: arsglue.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include -#include "ars.h" - -/* Send the APD described packet {s} */ -void hping_ars_send(char *apd) -{ - struct ars_packet p; - int s; - - ars_init(&p); - s = ars_open_rawsocket(&p); - if (s == -ARS_ERROR) { - perror("Opening raw socket"); - exit(1); - } - if (ars_d_build(&p, apd) != -ARS_OK) { - fprintf(stderr, "APD error: %s\n", p.p_error); - exit(1); - } - if (ars_compile(&p) != -ARS_OK) { - fprintf(stderr, "APD error compiling: %s\n", p.p_error); - exit(1); - } - if (ars_send(s, &p, NULL, 0) != -ARS_OK) { - perror("Sending the packet"); - exit(1); - } - exit(0); -} diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..9d27ba6 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,61 @@ +#!/bin/bash +set -e + +OS=$(uname | tr '[:upper:]' '[:lower:]') + +# macOS uses glibtoolize +if [ "$OS" = "darwin" ]; then + LIBTOOLIZE=glibtoolize +else + LIBTOOLIZE=libtoolize +fi + +clean() { + echo -n "Cleaning created files... " + rm -rf autom4te.cache aclocal.m4 Makefile.in src/Makefile.in m4/* \ + src/.deps src/.libs configure configure~ config.status \ + config.log libtool Makefile src/Makefile src/*.o src/.depend .depend \ + config.h.in* config.h stamp-h1 src/hping3 src/libars.a build \ + hping3*.tar.gz + echo "done." +} + +dist() { + echo -n "Cleaning temporary files... " + rm -rf autom4te.cache aclocal.m4 src/.deps src/.libs config.status \ + config.log libtool Makefile src/Makefile src/*.o src/.depend .depend \ + config.h.in~ configure~ config.h stamp-h1 src/hping3 src/libars.a \ + hping3*.tar.gz + echo "done." +} + +build() { + echo "Creating configure and support files... " + # Create config.h.in + autoheader + # Create libtool files + $LIBTOOLIZE --force --copy + # Create aclocal macros + aclocal + # Create configure + autoconf + # Create Makefile.in + automake --add-missing --copy + echo "done." +} + +case "$1" in + clean) + clean + ;; + build) + build + ;; + dist) + dist + ;; + *) + clean + build + ;; +esac diff --git a/binding.c b/binding.c deleted file mode 100644 index 338da17..0000000 --- a/binding.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * $smu-mark$ - * $name: binding.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:46 MET 1999$ - * $rev: 11$ - */ - -/* $Id: binding.c,v 1.2 2003/09/01 00:15:22 antirez Exp $ */ - -#include -#include -#include -#include - -#include "hping2.h" -#include "globals.h" - -void inc_destparm(int sid) -{ - static long sec = 0; - static long usec = 0; - int *p; - int errno_save = errno; - - switch (ctrlzbind) { - case BIND_DPORT: - p = &dst_port; - break; - case BIND_TTL: - p = &src_ttl; - break; - default: - printf("error binding ctrl+z\n"); - /* errno = errno_save; */ - return; - } - - if ( (time(NULL) == sec) && ((get_usec() - usec) < 200000) ) { - if (*p > 0) - (*p)-=2; - if (*p < 0) - *p=0; - } else - (*p)++; - - printf("\b\b\b\b\b\b\b\b\b"); - printf("%d: ", *p); - fflush(stdout); - - sec = time(NULL); - usec = get_usec(); - signal(SIGTSTP, inc_destparm); - errno = errno_save; -} diff --git a/brew-packages.txt b/brew-packages.txt new file mode 100644 index 0000000..7d4454e --- /dev/null +++ b/brew-packages.txt @@ -0,0 +1,5 @@ +autoconf +automake +libtool +libpcap +tcl-tk diff --git a/byteorder.c b/byteorder.c deleted file mode 100644 index 06f9d06..0000000 --- a/byteorder.c +++ /dev/null @@ -1,80 +0,0 @@ -#if 0 -# -# Compile with: -# $sh byteorder.c -# -cc byteorder.c -o byteorder || exit 1 -echo successfully compiled -exit -#endif /* 0 */ - -/* Coypright (C) 1999-2003 Salvatore Sanfilippo */ - -/* - * 0.1 first version - * 0.2 add Strchr, so it's possibile remove string.h - * 0.3 more portable thx to Pancrazio De Mauro 'TrantIT'!!! - * 0.4 better debug output - */ - -/* $Id: byteorder.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include - -char *Strchr(char *s, char c) -{ - while(*s) - if (*s++ == c) - return s; - - return (char*) 0; -} - -int main(int argc, char **argv) -{ - unsigned int test = 1; - unsigned char *x; - int macro = 0, debug = 0, help = 0, j; - - for (j = 1; j < argc; j++) { - if (Strchr(argv[j], 'm')) macro = 1; - if (Strchr(argv[j], 'd')) debug = 1; - if (Strchr(argv[j], 'h')) help = 1; - } - - if (help) { - printf( "-m macro output\n" - "-d debug\n" - "-h help\n"); - return 0; - } - - x = (unsigned char*) &test; - - if (*x == 0x00) { - if (macro) - printf("__BIG_ENDIAN_BITFIELD\n"); - else - printf("big endian\n"); - } - else if (*x == 0x01) { - if (macro) - printf("__LITTLE_ENDIAN_BITFIELD\n"); - else - printf("little endian\n"); - } else { - printf("\nWARNING!!! byteorder exception\n\n"); - debug = 1; - } - - if (debug) { - printf("sizeof(unsigned int) = %d\n", - (int)sizeof(unsigned int)); - printf("unsigned int test = 1;\n"); - printf("in memory as: "); - for (j = 0; j < sizeof(unsigned int); j++) - printf("%02x ", x[j]); - printf("\n"); - } - return 0; -} diff --git a/choco-packages.txt b/choco-packages.txt new file mode 100644 index 0000000..e2f070d --- /dev/null +++ b/choco-packages.txt @@ -0,0 +1 @@ +msys2 diff --git a/cksum.c b/cksum.c deleted file mode 100644 index 305c703..0000000 --- a/cksum.c +++ /dev/null @@ -1,30 +0,0 @@ -/* $Id: cksum.c,v 1.3 2004/04/14 12:30:18 antirez Exp $ */ - -#include "hping2.h" /* only for arch semi-indipendent data types */ -#include "globals.h" - -/* - * from R. Stevens's Network Programming - */ -__u16 cksum(__u16 *buf, int nbytes) -{ - __u32 sum; - - sum = 0; - while (nbytes > 1) { - sum += *buf++; - nbytes -= 2; - } - - if (nbytes == 1) { - sum += *((__u8*)buf); - } - - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - - /* return a bad checksum with --badcksum option */ - if (opt_badcksum) sum ^= 0x5555; - - return (__u16) ~sum; -} diff --git a/configure b/configure deleted file mode 100755 index dab04ab..0000000 --- a/configure +++ /dev/null @@ -1,166 +0,0 @@ -#!/bin/sh - -show_help() -{ - echo configure help: - echo "--help show this help" - echo "--no-tcl disable TCL scripting support" - echo " even if uid != euid" -} - -if [ "$1" = "--help" ]; then - show_help - exit 0 -fi - -CC=${CC:=cc} - -echo build byteorder.c... -$CC byteorder.c -o byteorder || exit 1 - -INSTALL_MANPATH=`echo $MANPATH|cut -f1 -d:` -if [ "$INSTALL_MANPATH" = "" ]; then - INSTALL_MANPATH="/usr/local/man" -fi -BYTEORDER=`./byteorder -m` - -echo create byteorder.h... -cat > byteorder.h <> byteorder.h -echo \#define $BYTEORDER >> byteorder.h -echo \#endif /\* $BYTEORDER \*/ >> byteorder.h -cat >> byteorder.h < Found Tclsh in: $TCLSH" - fi - fi - done -done -if [ -f $TCLSH ] -then - TCL_VER=`echo puts \\$tcl_version | $TCLSH -` - USE_TCL='-DUSE_TCL' - TCL_LIB="-ltcl${TCL_VER}" - if [ -e /usr/include/tcl${TCL_VER} ] - then - TCL_INC="-I/usr/include/tcl${TCL_VER}" - elif [ -e /usr/include/tcl.h ] - then - TCL_INC="" - elif [ -e /usr/local/include/tcl${TCL_VER} ] - then - TCL_INC="-I/usr/local/include/tcl${TCL_VER}" - else - USE_TCL="" - TCL_LIB="" - echo "==> WARNING: no Tcl header files found!" - fi -fi -if [ -n $USE_TCL ] -then - LIBPOSTFIX=`ls -1 /usr/local/lib/ /usr/lib | grep 'libtcl[0-9]' | grep so | sed -e 's/\.so.*//g' -e 's/libtcl//g' | sort -r | head -1` - TCL_LIB="-ltcl${LIBPOSTFIX} -lm -lpthread" -fi - -# -# configurable stuff -# -PCAP="PCAP=-lpcap" -PCAP_INCLUDE="" - -for ARG in $*; do - case "$ARG" in - *"--no-tcl") - USE_TCL="" - TCL_VER="" - TCL_INC="" - TCL_LIB="" - ;; - esac -done - -echo -------------------------------------- -echo system type: $CONFIGOSTYPE -echo -echo "LIBPCAP : $PCAP" -echo "PCAP_INCLUDE : $PCAP_INCLUDE" -echo "MANPATH : $INSTALL_MANPATH" -echo "USE_TCL : $USE_TCL" -echo "TCL_VER : $TCL_VER" -echo "TCL_INC : $TCL_INC" -echo "LIBTCL : $TCL_LIB" -echo "TCLSH : $TCLSH" -echo -echo "(to modify try configure --help)" -echo -------------------------------------- - -echo creating Makefile... -sed -e "s^@PCAP@^$PCAP^g" \ - -e "s^@PCAP_INCLUDE@^$PCAP_INCLUDE^g" \ - -e "s^@MANPATH@^$INSTALL_MANPATH^g" \ - -e "s^@SOLARISLIB@^$SOLARISLIB^g" \ - -e "s^@USE_TCL@^$USE_TCL^g" \ - -e "s^@TCL_INC@^$TCL_INC^g" \ - -e "s^@TCL_VER@^$TCL_VER^g" \ - -e "s^@TCL_LIB@^$TCL_LIB^g" \ - Makefile - -# -# -# - -cat > systype.h <> systype.h -cat >> systype.h < .depend - -echo now you can try \`make\' diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..8cf08f9 --- /dev/null +++ b/configure.ac @@ -0,0 +1,121 @@ +AC_PREREQ([2.69]) +AC_INIT([hping3], [3.0.0], [antirez@invece.org]) +AC_CONFIG_AUX_DIR([build]) +AC_CONFIG_MACRO_DIRS([m4]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) + +AC_PROG_CC +AM_PROG_AR +LT_INIT + +# Export this info to Makefile +AC_SUBST([PACKAGE_NAME]) +AC_SUBST([PACKAGE_VERSION]) + +# To detect endianess +AC_C_BIGENDIAN([WORDS_BIGENDIAN]) + +# Detect host system +AC_CANONICAL_HOST + +AC_MSG_NOTICE([Checking target operating system...]) + +case "$host_os" in + linux*) + CFLAGS="$CFLAGS -DOSTYPE_LINUX" + AC_MSG_NOTICE([Detected Linux OS]) + ;; + darwin*) + CFLAGS="$CFLAGS -DOSTYPE_DARWIN" + AC_MSG_NOTICE([Detected macOS]) + ;; + freebsd*) + CFLAGS="$CFLAGS -DOSTYPE_FREEBSD" + AC_MSG_NOTICE([Detected FreeBSD]) + ;; + netbsd*) + CFLAGS="$CFLAGS -DOSTYPE_NETBSD" + AC_MSG_NOTICE([Detected NetBSD]) + ;; + openbsd*) + CFLAGS="$CFLAGS -DOSTYPE_OPENBSD" + AC_MSG_NOTICE([Detected OpenBSD]) + ;; + mingw* | cygwin* | msys*) + CFLAGS="$CFLAGS -DOSTYPE_WINDOWS" + LIBS="$LIBS -lws2_32" + AC_MSG_NOTICE([Detected Windows (MinGW/Cygwin)]) + ;; + *) + AC_MSG_WARN([Unknown OS type: $host_os]) + os_type=UNKNOWN + ;; +esac + +# Add dirs to PKG_CONFIG_PATH +AC_DEFUN([ADD_TO_PKG_CONFIG_PATH], +[ + for dir in $@; do + if test -d "$dir"; then + case ":$PKG_CONFIG_PATH:" in + *":$dir:"*) ;; + *) PKG_CONFIG_PATH="$dir:$PKG_CONFIG_PATH" ;; + esac + fi + done + if test -n "$PKG_CONFIG_PATH"; then + export PKG_CONFIG_PATH + fi +]) + +# Detect Homebrew or MSYS2 pkg-config paths +AC_MSG_NOTICE([Detecting pkg-config paths...]) +case "$host_os" in + darwin*) + case "$host_cpu" in + x86_64) + ADD_TO_PKG_CONFIG_PATH([/usr/local/lib/pkgconfig]) + ;; + aarch64) + ADD_TO_PKG_CONFIG_PATH([/opt/homebrew/opt/libpcap/lib/pkgconfig]) + ADD_TO_PKG_CONFIG_PATH([/opt/homebrew/opt/tcl-tk/lib/pkgconfig]) + ;; + esac + ;; + mingw* | cygwin* | msys*) + ADD_TO_PKG_CONFIG_PATH([/mingw64/lib/pkgconfig]) + ;; +esac + +# Show PKG_CONFIG_PATH variable +AC_MSG_NOTICE([PKG_CONFIG_PATH=$PKG_CONFIG_PATH]) + +# Detect dependencies using pkg-config +PKG_CHECK_MODULES([PCAP], [libpcap >= 1.0], + [AC_MSG_NOTICE([Found libpcap: $PCAP_CFLAGS $PCAP_LIBS])], + [AC_MSG_ERROR([libpcap >= 1.0 not found. Please, install it.])]) + +PKG_CHECK_MODULES([TCL], [tcl >= 8.6], + [AC_MSG_NOTICE([Found Tcl: $TCL_CFLAGS $TCL_LIBS])], + [AC_MSG_ERROR([Tcl >= 8.6 not found. Please, install it.])]) + +# Check if Tcl has specific functions +AC_CHECK_LIB([tcl], [Tcl_CreateInterp], [have_tcl=yes], [have_tcl=no]) +if test "$have_tcl" = yes; then + AC_DEFINE([USE_TCL], [1], [Define if Tcl has been found]) + CFLAGS="$CFLAGS -DUSE_TCL" +fi + +# Create config.h +AC_CONFIG_HEADERS([config.h]) + +# Export variables to Makefile +AC_SUBST([PCAP_CFLAGS]) +AC_SUBST([PCAP_LIBS]) +AC_SUBST([TCL_CFLAGS]) +AC_SUBST([TCL_LIBS]) +AC_SUBST([LIBS]) + +# Output final Makefiles +AC_CONFIG_FILES([Makefile src/Makefile]) +AC_OUTPUT diff --git a/datafiller.c b/datafiller.c deleted file mode 100644 index 0c49012..0000000 --- a/datafiller.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * $smu-mark$ - * $name: datafiller.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:47 MET 1999$ - * $rev: 8$ - */ - -/* $Id: datafiller.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include /* memset */ - -#include "hping2.h" -#include "globals.h" - -void datafiller(char *p, int size) -{ - static int fd = 0; - int readed, diff; - - if (!fd) { - fd = open(datafilename, O_RDONLY); - if (fd == -1) { - perror("[datafiller] open()"); - fd = 0; /* will retry to open the file for - * the next packet */ - memset(p, 'X', size); - return; - } - } - - if (p == NULL && fd != -1) { /* seek operation */ - /* size-1 because packet with id 1 start from 0 */ - lseek(fd, (data_size-signlen)*(size-1), SEEK_SET); - return; - } - -restart: /* if EOF occurs, after rewind, restart */ - - readed = read(fd, p, size); - if (readed == size) - return; - else if (readed == -1) { - perror("[datafiller] read()"); - close(fd); - fd = 0; /* will retry to open the file for the next packet */ - memset(p, 'X', size); - return; - } - else if (readed < size && opt_end == FALSE) { - lseek(fd, 0, SEEK_SET); - if (readed == 0) - goto restart; - } - else if (readed < size && opt_end == TRUE) { - fprintf(stderr, "EOF reached, wait some second than press " - "ctrl+c\n"); - eof_reached = TRUE; - } else { - printf("[datafiller.c INTERNAL ERROR] readed = %d - " - "opt_end == %d\n", readed, opt_end); - exit(1); - } - diff = size - readed; - memset(p+readed, '\0', diff); /* padding */ - lseek(fd, 0, SEEK_SET); - return; -} diff --git a/datahandler.c b/datahandler.c deleted file mode 100644 index be1b24e..0000000 --- a/datahandler.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * $smu-mark$ - * $name: datahandler.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:47 MET 1999$ - * $rev: 8$ - */ - -/* $Id: datahandler.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include - -#include "hping2.h" -#include "globals.h" - -void data_handler(char *data, int data_size) -{ - if (opt_listenmode) { /* send an HCMP */ - memcpy(data, rsign, signlen); /* ok, write own reverse sign */ - data+=signlen; - data_size-=signlen; - memcpy(data, hcmphdr_p, data_size); - return; /* done */ - } - - if (opt_sign) { - memcpy(data, sign, signlen); /* lenght pre-checked */ - data+=signlen; - data_size-=signlen; - } - - if (data_size == 0) - return; /* there is not space left */ - - if (opt_datafromfile) - datafiller(data, data_size); - else - memset(data, 'X', data_size); -} diff --git a/gentables.c b/gentables.c index 3ed19e9..d44b142 100644 --- a/gentables.c +++ b/gentables.c @@ -2,7 +2,7 @@ #include #include -#include "sbignum.h" +#include "src/sbignum.h" static char *cset = "0123456789abcdefghijklmnopqrstuvwxyz"; @@ -17,188 +17,187 @@ static unsigned long lexp(unsigned long b, int e); static int nbits(unsigned char x); static double logbn(double base, double n); -#define EFL 16 /* elements for line */ +#define EFL 16 /* elements for line */ int main(int argc, char **argv) { - int hdr = argc-1; - argv = argv; - - if (hdr) { - printf( "#ifndef _SBN_TABLES_H\n" - "#define _SBN_TABLES_H\n" - "\n" - "#include \n\n"); - } else { - printf( "#include \"tables.h\"\n" - "#include \"sbignum.h\"\n\n"); - } - gen_cset(hdr); - gen_rcset(hdr); - gen_bitstable(hdr); - gen_basetable(hdr); - gen_basepowtable(hdr); - if (hdr) { - printf("\n#endif /* _SBN_TABLES_H */\n"); - } - return 0; + (void)argv; + int hdr = argc-1; + if (hdr) { + printf( "#ifndef _SBN_TABLES_H\n" + "#define _SBN_TABLES_H\n" + "\n" + "#include \n\n"); + } else { + printf( "#include \"tables.h\"\n" + "#include \"sbignum.h\"\n\n"); + } + gen_cset(hdr); + gen_rcset(hdr); + gen_bitstable(hdr); + gen_basetable(hdr); + gen_basepowtable(hdr); + if (hdr) { + printf("\n#endif /* _SBN_TABLES_H */\n"); + } + return 0; } void gen_cset(int hdr) { - if (hdr) { - printf("extern char *cset;\n"); - return; - } - printf("/* maps a number to a char */\n"); - printf("char *cset = \"%s\";\n\n", cset); + if (hdr) { + printf("extern char *cset;\n"); + return; + } + printf("/* maps a number to a char */\n"); + printf("char *cset = \"%s\";\n\n", cset); } void gen_rcset(int hdr) { - int i; - - if (hdr) { - printf("extern int8_t r_cset[256];\n"); - return; - } - printf("/* maps a char to a number */\n"); - printf("int8_t r_cset[256] = {\n"); - for (i = 0; i < 256; i++) { - char *p; - p = strchr(cset, i); - if (!(i%EFL)) - printf("\t"); - if (!p || !i) { - printf("-1, "); - } else { - printf("%2d, ", p-cset); - } - if (!((i+1) % EFL)) - printf("\n"); - } - printf("};\n\n"); + int i; + + if (hdr) { + printf("extern int8_t r_cset[256];\n"); + return; + } + printf("/* maps a char to a number */\n"); + printf("int8_t r_cset[256] = {\n"); + for (i = 0; i < 256; i++) { + char *p; + p = strchr(cset, i); + if (!(i%EFL)) + printf("\t"); + if (!p || !i) { + printf("-1, "); + } else { + printf("%2ld, ", p-cset); + } + if (!((i+1) % EFL)) + printf("\n"); + } + printf("};\n\n"); } int nbits(unsigned char x) { - int i = 8; - int bits = 0; - do { - bits += x & 1; - x >>= 1; - } while(--i); - return bits; + int i = 8; + int bits = 0; + do { + bits += x & 1; + x >>= 1; + } while(--i); + return bits; } void gen_bitstable(int hdr) { - int i; - - if (hdr) { - printf("extern int8_t bitstable[256];\n"); - return; - } - printf("/* bitstable[n] is the number of set bits\n" - " * in the number 'n' */\n"); - printf("int8_t bitstable[256] = {\n"); - for (i = 0; i < 256; i++) { - if (!(i%EFL)) - printf("\t"); - printf("%d, ", nbits(i)); - if (!((i+1) % EFL)) - printf("\n"); - } - printf("};\n\n"); + int i; + + if (hdr) { + printf("extern int8_t bitstable[256];\n"); + return; + } + printf("/* bitstable[n] is the number of set bits\n" + " * in the number 'n' */\n"); + printf("int8_t bitstable[256] = {\n"); + for (i = 0; i < 256; i++) { + if (!(i%EFL)) + printf("\t"); + printf("%d, ", nbits(i)); + if (!((i+1) % EFL)) + printf("\n"); + } + printf("};\n\n"); } double logbn(double base, double n) { - return log(n)/log(base); + return log(n)/log(base); } void _gen_basetable(int bytes, double base) { - int i; - - printf("#if ATOMBYTES == %d\n", bytes); - printf("double basetable[%d] = {\n", SBN_MAXBASE+1); - for (i = 0; i <= SBN_MAXBASE; i++) { - if (i < 2) { - printf("\t0, /* unused */\n"); - continue; - } - printf("\t%f, /* (log of %d in base %.0f) */\n", - logbn(i, base), i, base); - } - printf("};\n#endif\n\n"); + int i; + + printf("#if ATOMBYTES == %d\n", bytes); + printf("double basetable[%d] = {\n", SBN_MAXBASE+1); + for (i = 0; i <= SBN_MAXBASE; i++) { + if (i < 2) { + printf("\t0, /* unused */\n"); + continue; + } + printf("\t%f, /* (log of %d in base %.0f) */\n", + logbn(i, base), i, base); + } + printf("};\n#endif\n\n"); } -#define BT_8BITBASE 256U -#define BT_16BITBASE 65536U -#define BT_32BITBASE 4294967296U +#define BT_8BITBASE 256U +#define BT_16BITBASE 65536U +#define BT_32BITBASE 4294967296U void gen_basetable(int hdr) { - if (hdr) { - printf("extern double basetable[%d];\n", SBN_MAXBASE+1); - return; - } - printf("/* basetable[b] = number of digits needed to convert\n" - " * an mpz atom in base 'b' */\n"); - _gen_basetable(1, BT_8BITBASE); - _gen_basetable(2, BT_16BITBASE); - _gen_basetable(4, BT_32BITBASE); + if (hdr) { + printf("extern double basetable[%d];\n", SBN_MAXBASE+1); + return; + } + printf("/* basetable[b] = number of digits needed to convert\n" + " * an mpz atom in base 'b' */\n"); + _gen_basetable(1, BT_8BITBASE); + _gen_basetable(2, BT_16BITBASE); + _gen_basetable(4, BT_32BITBASE); } /* return b^e */ unsigned long lexp(unsigned long b, int e) { - unsigned long p = b; - if (!e) return 1; - while(--e) - p *= b; - return p; + unsigned long p = b; + if (!e) return 1; + while(--e) + p *= b; + return p; } void _gen_basepowtable(int bytes, double base) { - int i; - - base--; - printf("#if ATOMBYTES == %d\n", bytes); - printf("struct sbn_basepow basepowtable[%d] = {\n", SBN_MAXBASE+1); - for (i = 0; i <= SBN_MAXBASE; i++) { - unsigned long bexp; - unsigned long bpow; - if (i < 2) { - printf("\t{0,0}, /* unused */\n"); - continue; - } - bexp = (unsigned long) floor(logbn(i, base)); - bpow = lexp(i, bexp); - printf("\t{%luU, %luU}, /* floor(log of %d in base %.0f) */\n", - bpow, bexp, i, base); - } - printf("};\n#endif\n\n"); + int i; + + base--; + printf("#if ATOMBYTES == %d\n", bytes); + printf("struct sbn_basepow basepowtable[%d] = {\n", SBN_MAXBASE+1); + for (i = 0; i <= SBN_MAXBASE; i++) { + unsigned long bexp; + unsigned long bpow; + if (i < 2) { + printf("\t{0,0}, /* unused */\n"); + continue; + } + bexp = (unsigned long) floor(logbn(i, base)); + bpow = lexp(i, bexp); + printf("\t{%luU, %luU}, /* floor(log of %d in base %.0f) */\n", + bpow, bexp, i, base); + } + printf("};\n#endif\n\n"); } void gen_basepowtable(int hdr) { - if (hdr) { - printf( "struct sbn_basepow {\n" - " unsigned long maxpow;\n" - " unsigned long maxexp;\n" - "};\n"); - printf("extern struct sbn_basepow basepowtable[%d];\n", - SBN_MAXBASE+1); - return; - } - printf( - "/* basepowtable[b] = the first column is the biggest power of 'b'\n" - " * that fits in mpz_atom_t, the second column is the exponent\n" - " * 'e' so that b^e = the value of the first column */\n"); - _gen_basepowtable(1, BT_8BITBASE); - _gen_basepowtable(2, BT_16BITBASE); - _gen_basepowtable(4, BT_32BITBASE); + if (hdr) { + printf( "struct sbn_basepow {\n" + " unsigned long maxpow;\n" + " unsigned long maxexp;\n" + "};\n"); + printf("extern struct sbn_basepow basepowtable[%d];\n", + SBN_MAXBASE+1); + return; + } + printf( + "/* basepowtable[b] = the first column is the biggest power of 'b'\n" + " * that fits in mpz_atom_t, the second column is the exponent\n" + " * 'e' so that b^e = the value of the first column */\n"); + _gen_basepowtable(1, BT_8BITBASE); + _gen_basepowtable(2, BT_16BITBASE); + _gen_basepowtable(4, BT_32BITBASE); } diff --git a/gentables.sh b/gentables.sh index cc2d758..017dd18 100755 --- a/gentables.sh +++ b/gentables.sh @@ -4,6 +4,6 @@ CC=${CC:=cc} CCOPT="-Wall -W -O2" $CC gentables.c -o gentables $CCOPT -./gentables > tables.c -./gentables h > tables.h -echo Tables generated +./gentables > src/tables.c +./gentables h > src/tables.h +echo Tables generated! diff --git a/gethostname.c b/gethostname.c deleted file mode 100644 index 97015ef..0000000 --- a/gethostname.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * $smu-mark$ - * $name: gethostname.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:47 MET 1999$ - * $rev: 8$ - */ - -/* $Id: gethostname.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include - -char *get_hostname(char* addr) -{ - static char answer[1024]; - static char lastreq[1024] = {'\0'}; /* last request */ - struct hostent *he; - struct in_addr naddr; - static char *last_answerp = NULL; - - printf(" get hostname..."); fflush(stdout); - printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" - " " - "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - - if (!strcmp(addr, lastreq)) - return last_answerp; - - strncpy(lastreq, addr, 1024); - inet_aton(addr, &naddr); - he = gethostbyaddr((char*)&naddr, 4, AF_INET); - - if (he == NULL) { - last_answerp = NULL; - return NULL; - } - - strncpy(answer, he->h_name, 1024); - last_answerp = answer; - - return answer; -} - diff --git a/getifname.c b/getifname.c deleted file mode 100644 index 86b387f..0000000 --- a/getifname.c +++ /dev/null @@ -1,355 +0,0 @@ -/* getifname.c -- network interface handling - * Copyright(C) 1999,2000,2001 Salvatore Sanfilippo - * Copyright(C) 2001 by Nicolas Jombart - * This code is under the GPL license */ - -/* BSD support thanks to Nicolas Jombart */ - -/* $Id: getifname.c,v 1.3 2003/10/22 10:41:00 antirez Exp $ */ - -#include /* perror */ -#include -#include -#include -#include -#include /* struct sockaddr_in */ -#include /* inet_ntoa */ -#include -#include /* close */ -#include - -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ - defined(__bsdi__) || defined(__APPLE__) -#include -#include -#endif /* defined(__*BSD__) */ - -#include "hping2.h" -#include "globals.h" - -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ - !defined(__linux__) && !defined(__sun__) && !defined(__bsdi__) && \ - !defined(__APPLE__) -#error Sorry, interface code not implemented. -#endif - -#ifdef __sun__ -#include -#include -#include -#endif - -#if (defined OSTYPE_LINUX) || (defined __sun__) -int get_if_name(void) -{ - int fd; - struct ifconf ifc; - struct ifreq ibuf[16], - ifr, - *ifrp, - *ifend; - struct sockaddr_in sa; - struct sockaddr_in output_if_addr; - int known_output_if = 0; - - /* Try to get the output interface address according to - * the OS routing table */ - if (ifname[0] == '\0') { - if (get_output_if(&remote, &output_if_addr) == 0) { - known_output_if = 1; - if (opt_debug) - printf("DEBUG: Output interface address: %s\n", - inet_ntoa(sa.sin_addr)); - } else { - fprintf(stderr, "Warning: Unable to guess the output " - "interface\n"); - } - } - - if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - perror("[get_if_name] socket(AF_INET, SOCK_DGRAM, 0)"); - return -1; - } - - memset(ibuf, 0, sizeof(struct ifreq)*16); - ifc.ifc_len = sizeof ibuf; - ifc.ifc_buf = (caddr_t) ibuf; - - /* gets interfaces list */ - if ( ioctl(fd, SIOCGIFCONF, (char*)&ifc) == -1 || - ifc.ifc_len < sizeof(struct ifreq) ) { - perror("[get_if_name] ioctl(SIOCGIFCONF)"); - close(fd); - return -1; - } - - /* ifrp points to buffer and ifend points to buffer's end */ - ifrp = ibuf; - ifend = (struct ifreq*) ((char*)ibuf + ifc.ifc_len); - - for (; ifrp < ifend; ifrp++) { - strlcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name)); - - if ( ioctl(fd, SIOCGIFFLAGS, (char*)&ifr) == -1) { - if (opt_debug) - perror("DEBUG: [get_if_name] ioctl(SIOCGIFFLAGS)"); - continue; - } - - if (opt_debug) - printf("DEBUG: if %s: ", ifr.ifr_name); - - /* Down interface? */ - if ( !(ifr.ifr_flags & IFF_UP) ) - { - if (opt_debug) - printf("DOWN\n"); - continue; - } - - if (known_output_if) { - /* Get the interface address */ - if (ioctl(fd, SIOCGIFADDR, (char*)&ifr) == -1) { - perror("[get_if_name] ioctl(SIOCGIFADDR)"); - continue; - } - /* Copy it */ - memcpy(&sa, &ifr.ifr_addr, - sizeof(struct sockaddr_in)); - /* Check if it is what we are locking for */ - if (sa.sin_addr.s_addr != - output_if_addr.sin_addr.s_addr) { - if (opt_debug) - printf("The address doesn't match\n"); - continue; - } - } else if (ifname[0] != '\0' && !strstr(ifr.ifr_name, ifname)) { - if (opt_debug) - printf("Don't Match (but seems to be UP)\n"); - continue; - } - - if (opt_debug) - printf("OK\n"); - - /* interface found, save if name */ - strlcpy(ifname, ifr.ifr_name, 1024); - - /* get if address */ - if ( ioctl(fd, SIOCGIFADDR, (char*)&ifr) == -1) { - perror("DEBUG: [get_if_name] ioctl(SIOCGIFADDR)"); - exit(1); - } - - /* save if address */ - memcpy(&sa, &ifr.ifr_addr, - sizeof(struct sockaddr_in)); - strlcpy(ifstraddr, inet_ntoa(sa.sin_addr), 1024); - - /* get if mtu */ - if ( ioctl(fd, SIOCGIFMTU, (char*)&ifr) == -1) { - perror("Warning: [get_if_name] ioctl(SIOCGIFMTU)"); - fprintf(stderr, "Using a fixed MTU of 1500\n"); - h_if_mtu = 1500; - } - else - { -#ifdef __sun__ - /* somehow solaris is braidamaged in wrt ifr_mtu */ - h_if_mtu = ifr.ifr_metric; -#else - h_if_mtu = ifr.ifr_mtu; -#endif - } - close(fd); - return 0; - } - /* interface not found, use 'lo' */ - strlcpy(ifname, "lo", 1024); - strlcpy(ifstraddr, "127.0.0.1", 1024); - h_if_mtu = 1500; - - close(fd); - return 0; -} - -#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ - defined(__bsdi__) || defined(__APPLE__) - -/* return interface informations : - - from the specified (-I) interface - - from the routing table - - or at least from the first UP interface found -*/ -int get_if_name(void) -{ - /* variable declarations */ - struct ifaddrs *ifap, *ifa; - char current_if_name[24]; - char saved_ifname[24]; - struct sockaddr_in output_if_addr; -#ifdef __NetBSD__ - int s; - struct ifreq ifr; -#endif /* __NetBSD__ */ - - if (getifaddrs(&ifap) < 0) - perror("getifaddrs"); - - saved_ifname[0] = 0; - - /* lookup desired interface */ - if(ifname[0] == 0) { - /* find gateway interface from kernel */ - if (get_output_if(&remote, &output_if_addr) == 0) { - if (opt_debug) - printf("DEBUG: Output interface address: %s\n", - inet_ntoa(output_if_addr.sin_addr)); - /* Put something in saved_ifname in order to tell - that the output adress is known */ - saved_ifname[0] = 'X'; saved_ifname[1] = 0; - } else { - fprintf(stderr, "Warning: Unable to guess the output " - "interface\n"); - } - } - else { - /* use the forced interface name */ - strlcpy(saved_ifname,ifname,24); - } - - /* get interface information */ - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - - if (opt_debug) printf("\n DEBUG: if %s: ", ifa->ifa_name); - - /* print if the data structure is null or not */ - if (ifa->ifa_data) { - if(opt_debug) printf("DEBUG: (struct DATA) "); } - else - if(opt_debug) printf("DEBUG: (struct DATA is NULL) "); - - if (!(ifa->ifa_flags & IFF_UP)) { /* if down */ - if (opt_debug) - printf("DEBUG: DOWN"); - continue; - } - - if ((ifa->ifa_flags & IFF_LOOPBACK)&& - (strncmp(saved_ifname,"lo0",3))) { /* if loopback */ - if (opt_debug) - printf("DEBUG: LOOPBACK, SKIPPED"); - continue; - } - - if (ifa->ifa_addr->sa_family == AF_LINK) { - if (opt_debug) - printf("DEBUG: AF_LINK "); - strlcpy(ifname,ifa->ifa_name,1024); - strlcpy(current_if_name,ifa->ifa_name,24); - -/* I don't know why NetBSD behavior is not the same */ -#ifdef __NetBSD__ - memset( &ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name)); - if( sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len ) - memcpy(&ifr.ifr_addr, ifa->ifa_addr, - ifa->ifa_addr->sa_len); - if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - perror("[get_if_name] socket"); - return -1; - } - if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) h_if_mtu = 0; - else h_if_mtu = ifr.ifr_mtu; - close(s); -#else - if( ifa->ifa_data ) - h_if_mtu = ((struct if_data *)ifa->ifa_data)->ifi_mtu; - else { - h_if_mtu = 1500; - fprintf(stderr, "Warning: fixing MTU to 1500 !\n"); - } -#endif /* __NetBSD__ */ - continue; - } - - if (ifa->ifa_addr->sa_family == AF_INET6) { - if (opt_debug) - printf("AF_INET6 "); - continue; - } - - if (ifa->ifa_addr->sa_family == AF_INET) { - if (opt_debug) - printf("AF_INET "); - - if(strncmp(ifa->ifa_name,current_if_name,24)) - continue; /* error */ - - if(opt_debug) printf("OK\n"); - - strlcpy(ifstraddr, - inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr), - 1024); - - if( (saved_ifname[0] == 0) || - (!strncmp(ifa->ifa_name, saved_ifname, 24)) || - (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == - output_if_addr.sin_addr.s_addr) ) - break; /* asked if found or first UP interface */ - } - - /* interface not found, use hardcoded 'lo' */ - strlcpy(ifname, "lo0", 1024); - strlcpy(ifstraddr, "127.0.0.1", 1024); - h_if_mtu = 1500; - } - - freeifaddrs(ifap); - return 0; -} - -#endif /* __*BSD__ */ - -/* Try to obtain the IP address of the output interface according - * to the OS routing table. Derived from R.Stevens */ -int get_output_if(struct sockaddr_in *dest, struct sockaddr_in *ifip) -{ - socklen_t len; - int sock_rt, on=1; - struct sockaddr_in iface_out; - - memset(&iface_out, 0, sizeof(iface_out)); - sock_rt = socket(AF_INET, SOCK_DGRAM, 0 ); - - dest->sin_port = htons(11111); - if (setsockopt(sock_rt, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) - == -1) { - if (opt_debug) - perror("DEBUG: [get_output_if] setsockopt(SOL_SOCKET, " - "SO_BROADCAST"); - close(sock_rt); - return -1; - } - - if (connect(sock_rt, (struct sockaddr*)dest, sizeof(struct sockaddr_in)) - == -1 ) { - if (opt_debug) - perror("DEBUG: [get_output_if] connect"); - close(sock_rt); - return -1; - } - - len = sizeof(iface_out); - if (getsockname(sock_rt, (struct sockaddr *)&iface_out, &len) == -1 ) { - if (opt_debug) - perror("DEBUG: [get_output_if] getsockname"); - close(sock_rt); - return -1; - } - close(sock_rt); - if (iface_out.sin_addr.s_addr == 0) - return 1; - memcpy(ifip, &iface_out, sizeof(struct sockaddr_in)); - return 0; -} diff --git a/getlhs.c b/getlhs.c deleted file mode 100644 index 7fadc2e..0000000 --- a/getlhs.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * $smu-mark$ - * $name: getlhs.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:47 MET 1999$ - * $rev: 8$ - */ - -/* $Id: getlhs.c,v 1.5 2004/04/09 23:38:56 antirez Exp $ */ - -#include - -#include "hping2.h" -#include "globals.h" - - -int dltype_to_lhs(int dltype) -{ - int lhs; - - switch(dltype) { - case DLT_EN10MB: -#ifdef DLT_IEEE802 - case DLT_IEEE802: -#endif - lhs = 14; - break; - case DLT_SLIP: - case DLT_SLIP_BSDOS: - lhs = 16; - break; - case DLT_PPP: - case DLT_NULL: -#ifdef DLT_PPP_SERIAL - case DLT_PPP_SERIAL: -#endif -#ifdef DLT_LOOP - case DLT_LOOP: -#endif - lhs = 4; - break; - case DLT_PPP_BSDOS: - lhs = 24; - break; - case DLT_FDDI: - lhs = 13; - break; - case DLT_RAW: - lhs = 0; - break; -#ifdef DLT_IEE802_11 - case DLT_IEEE802_11: - lhs = 14; - break; -#endif - case DLT_ATM_RFC1483: -#ifdef DLT_CIP - case DLT_CIP: -#endif -#ifdef DLT_ATM_CLIP - case DLT_ATM_CLIP: -#endif - lhs = 8; - break; -#ifdef DLT_C_HDLC - case DLT_C_HDLC: - lhs = 4; - break; -#endif -#ifdef DLT_LINUX_SLL - case DLT_LINUX_SLL: -#endif -#ifdef DLT_LANE8023 - case DLT_LANE8023: -#endif - lhs = 16; - break; - default: - return -1; - break; - } - return lhs; -} - -int get_linkhdr_size(char *ifname) -{ - int dltype = pcap_datalink(pcapfp); - - if (opt_debug) - printf("DEBUG: dltype is %d\n", dltype); - - linkhdr_size = dltype_to_lhs(dltype); - return linkhdr_size; -} diff --git a/globals.h b/globals.h deleted file mode 100644 index 48b3d09..0000000 --- a/globals.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * $smu-mark$ - * $name: globals.h$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:47 MET 1999$ - * $rev: 9$ - */ - -/* $Id: globals.h,v 1.3 2004/06/18 09:53:11 antirez Exp $ */ - -#ifndef _GLOBALS_H -#define _GLOBALS_H - -extern float - rtt_min, - rtt_max, - rtt_avg; - -extern unsigned int - tcp_th_flags, - linkhdr_size, - h_if_mtu, - virtual_mtu, - ip_frag_offset, - signlen, - lsr_length, - ssr_length, - ip_tos, - set_seqnum, - tcp_seqnum, - set_ack, - ip_header_length, - tcp_ack; - -extern unsigned short int - data_size; - -extern int opt_debug, - sockpacket, - sockraw, - sent_pkt, - recv_pkt, - out_of_sequence_pkt, - sending_wait, - opt_rawipmode, - opt_icmpmode, - opt_udpmode, - opt_scanmode, - opt_listenmode, - opt_waitinusec, - opt_numeric, - opt_gethost, - opt_quiet, - opt_relid, - opt_fragment, - opt_df, - opt_mf, - opt_debug, - opt_verbose, - opt_winid_order, - opt_keepstill, - opt_datafromfile, - opt_hexdump, - opt_contdump, - opt_sign, - opt_safe, - opt_end, - opt_traceroute, - opt_seqnum, - opt_incdport, - opt_force_incdport, - opt_icmptype, - opt_icmpcode, - opt_rroute, - opt_tcpexitcode, - opt_badcksum, - opt_tr_keep_ttl, - opt_tcp_timestamp, - opt_clock_skew, - cs_window, - cs_window_shift, - cs_vector_len, - opt_tr_stop, - opt_tr_no_rtt, - opt_rand_dest, - opt_rand_source, - opt_lsrr, - opt_ssrr, - opt_beep, - opt_flood, - tcp_exitcode, - src_ttl, - src_id, - base_dst_port, - dst_port, - src_port, - initsport, - sequence, - src_winsize, - src_thoff, - count, - ctrlzbind, - delaytable_index, - eof_reached, - icmp_ip_version, - icmp_ip_ihl, - icmp_ip_tos, - icmp_ip_tot_len, - icmp_ip_id, - icmp_ip_srcport, - icmp_ip_dstport, - opt_force_icmp, - icmp_ip_protocol, - icmp_cksum, - raw_ip_protocol; - -extern unsigned char lsr[255], - ssr[255]; - -extern char ifname[1024], - ifstraddr[1024], - datafilename[1024], - targetname[1024], - targetstraddr[1024], - spoofaddr[1024], - icmp_ip_srcip[1024], - icmp_ip_dstip[1024], - icmp_gwip[1024], - sign[1024], - rsign[1024], - ip_opt[40], - ip_optlen, - *opt_scanports; - -extern struct sockaddr_in icmp_ip_src, icmp_ip_dst, icmp_gw, local, remote; -extern struct itimerval usec_delay; -extern volatile struct delaytable_element delaytable[TABLESIZE]; -extern struct hcmphdr *hcmphdr_p; - -#include -extern pcap_t *pcapfp; -extern char errbuf[PCAP_ERRBUF_SIZE]; -extern struct pcap_pkthdr hdr; - -#endif /* _GLOBALS_H */ diff --git a/hping2.h b/hping2.h deleted file mode 100644 index 27cb0ff..0000000 --- a/hping2.h +++ /dev/null @@ -1,434 +0,0 @@ -/* - * $smu-mark$ - * $name: hping2.h$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:48 MET 1999$ - * $rev: 9$ - */ - -/* $Id: hping2.h,v 1.4 2004/06/04 07:22:38 antirez Exp $ */ - -#ifndef _HPING2_H -#define _HPING2_H - -#include -#include -#include -#include -#include "byteorder.h" -#include "systype.h" -#include "fixtypes.h" - -/* types */ -#ifndef __u8 -#define __u8 u_int8_t -#endif /* __u8 */ -#ifndef __u16 -#define __u16 u_int16_t -#endif /* __u16 */ -#ifndef __u32 -#define __u32 u_int32_t -#endif /* __u32 */ - -#ifndef __uint8_t -#define __uint8_t u_int8_t -#endif /* __uint8_t */ -#ifndef __uint16_t -#define __uint16_t u_int16_t -#endif /* __uint16_t */ -#ifndef __uint32_t -#define __uint32_t u_int32_t -#endif /* __uint32_t */ - -#include "hcmp.h" /* Hping Control Message Protocol */ - -/* protocols header size */ -#ifndef ICMPHDR_SIZE -#define ICMPHDR_SIZE sizeof(struct myicmphdr) -#endif -#ifndef UDPHDR_SIZE -#define UDPHDR_SIZE sizeof(struct myudphdr) -#endif -#ifndef TCPHDR_SIZE -#define TCPHDR_SIZE sizeof(struct mytcphdr) -#endif -#ifndef IPHDR_SIZE -#define IPHDR_SIZE sizeof(struct myiphdr) -#endif - -/* wait X seconds after reached to sent packets in oreder to display replies */ -#define COUNTREACHED_TIMEOUT 1 - -/* requests status table stuffs */ -/* Warning, TABLESIZE 0 == floating point exception */ -#define TABLESIZE 400 -#define S_SENT 0 -#define S_RECV 1 - -/* usefull defines */ -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif -#ifndef PF_PACKET -#define PF_PACKET 17 /* kernel 2.[12].* with 2.0.* kernel headers? */ -#endif -#ifndef ETH_P_IP -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ -#endif -#ifndef ABS -#define ABS(x) (((x)>0) ? (x) : -(x)) -#endif - -/* header size of some physical layer type */ -#define PPPHDR_SIZE_LINUX 0 -#define PPPHDR_SIZE_FREEBSD 4 -#define PPPHDR_SIZE_OPENBSD 4 -#define PPPHDR_SIZE_NETBSD 4 -#define PPPHDR_SIZE_BSDI 4 -#define ETHHDR_SIZE 14 -#define LOHDR_SIZE 14 -#define WLANHDR_SIZE 14 -#define TRHDR_SIZE 20 - -/* packet size (physical header size + ip header + tcp header + 0 data bytes) */ -#ifndef IP_MAX_SIZE -#define IP_MAX_SIZE 65535 -#endif - -/* absolute offsets */ -#define ABS_OFFSETIP linkhdr_size -#define ABS_OFFSETTCP ( linkhdr_size + IPHDR_SIZE ) -#define ABS_OFFSETICMP ( linkhdr_size + IPHDR_SIZE ) -#define ABS_OFFSETUDP ( linkhdr_size + IPHDR_SIZE ) - -/* defaults and misc */ -#define DEFAULT_SENDINGWAIT 1 /* wait 1 sec. between sending each packets */ -#define DEFAULT_DPORT 0 /* default dest. port */ -#define DEFAULT_INITSPORT -1 /* default initial source port: -1 means random */ -#define DEFAULT_COUNT -1 /* default packets count: -1 means forever */ -#define DEFAULT_TTL 64 /* default ip->ttl value */ -#define DEFAULT_SRCWINSIZE 512 /* default tcp windows size */ -#define DEFAULT_VIRTUAL_MTU 16 /* tiny fragments */ -#define DEFAULT_ICMP_TYPE 8 /* echo request */ -#define DEFAULT_ICMP_CODE 0 /* icmp-type relative */ -#define DEFAULT_ICMP_IP_VERSION 4 -#define DEFAULT_ICMP_IP_IHL (IPHDR_SIZE >> 2) -#define DEFAULT_ICMP_IP_TOS 0 -#define DEFAULT_ICMP_IP_TOT_LEN 0 /* computed by send_icmp_*() */ -#define DEFAULT_ICMP_IP_ID 0 /* rand */ -#define DEFAULT_ICMP_CKSUM -1 /* -1 means compute the cksum */ -#define DEFAULT_ICMP_IP_PROTOCOL 6 /* TCP */ -#define DEFAULT_RAW_IP_PROTOCOL 6 /* TCP */ -#define DEFAULT_TRACEROUTE_TTL 1 - -#define BIND_NONE 0 /* no bind */ -#define BIND_DPORT 1 /* bind destination port */ -#define BIND_TTL 2 /* bind ip->ttl */ -#define DEFAULT_BIND BIND_DPORT - -#define DEFAULT_CS_WINDOW 300 -#define DEFAULT_CS_WINDOW_SHIFT 5 -#define DEFAULT_CS_VECTOR_LEN 10 - -/* fragmentation defines */ -#define MF ((unsigned short)0x2000) /* more fragments */ -#define DF ((unsigned short)0x4000) /* dont fragment */ -#define NF ((unsigned short)0x0000) /* no more fragments */ - -/* ip options defines */ -#define IPOPT_COPY 0x80 -#define IPOPT_CLASS_MASK 0x60 -#define IPOPT_NUMBER_MASK 0x1f - -#define IPOPT_COPIED(o) ((o)&IPOPT_COPY) -#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK) -#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK) - -#define IPOPT_CONTROL 0x00 -#define IPOPT_RESERVED1 0x20 -#define IPOPT_MEASUREMENT 0x40 -#define IPOPT_RESERVED2 0x60 - -#define IPOPT_END (0 |IPOPT_CONTROL) -#define IPOPT_NOOP (1 |IPOPT_CONTROL) -#define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT) -#define IPOPT_RR (7 |IPOPT_CONTROL) -#define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_RA (20|IPOPT_CONTROL|IPOPT_COPY) - -#define IPOPT_OPTVAL 0 -#define IPOPT_OLEN 1 -#define IPOPT_OFFSET 2 -#define IPOPT_MINOFF 4 -#define MAX_IPOPTLEN 40 -#define IPOPT_NOP IPOPT_NOOP -#define IPOPT_EOL IPOPT_END -#define IPOPT_TS IPOPT_TIMESTAMP - -#define IPOPT_TS_TSONLY 0 /* timestamps only */ -#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ -#define IPOPT_TS_PRESPEC 3 /* specified modules only */ - -/* tcp flags */ -#ifndef TH_FIN -#define TH_FIN 0x01 -#endif -#ifndef TH_SYN -#define TH_SYN 0x02 -#endif -#ifndef TH_RST -#define TH_RST 0x04 -#endif -#ifndef TH_PUSH -#define TH_PUSH 0x08 -#endif -#ifndef TH_ACK -#define TH_ACK 0x10 -#endif -#ifndef TH_URG -#define TH_URG 0x20 -#endif -#ifndef TH_X -#define TH_X 0x40 /* X tcp flag */ -#endif -#ifndef TH_Y -#define TH_Y 0x80 /* Y tcp flag */ -#endif - -/* ICMP TYPE */ -#define ICMP_ECHOREPLY 0 /* Echo Reply */ -#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ -#define ICMP_SOURCE_QUENCH 4 /* Source Quench */ -#define ICMP_REDIRECT 5 /* Redirect (change route) */ -#define ICMP_ECHO 8 /* Echo Request */ -#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ -#define ICMP_PARAMETERPROB 12 /* Parameter Problem */ -#define ICMP_TIMESTAMP 13 /* Timestamp Request */ -#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ -#define ICMP_INFO_REQUEST 15 /* Information Request */ -#define ICMP_INFO_REPLY 16 /* Information Reply */ -#define ICMP_ADDRESS 17 /* Address Mask Request */ -#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ - -/* Codes for UNREACHABLE */ -#define ICMP_NET_UNREACH 0 /* Network Unreachable */ -#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ -#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ -#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ -#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ -#define ICMP_SR_FAILED 5 /* Source Route failed */ -#define ICMP_NET_UNKNOWN 6 -#define ICMP_HOST_UNKNOWN 7 -#define ICMP_HOST_ISOLATED 8 -#define ICMP_NET_ANO 9 -#define ICMP_HOST_ANO 10 -#define ICMP_NET_UNR_TOS 11 -#define ICMP_HOST_UNR_TOS 12 -#define ICMP_PKT_FILTERED 13 /* Packet filtered */ -#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ -#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ -#define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */ - -/* Codes for REDIRECT */ -#define ICMP_REDIR_NET 0 /* Redirect Net */ -#define ICMP_REDIR_HOST 1 /* Redirect Host */ -#define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ -#define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ - -/* Codes for TIME_EXCEEDED */ -#define ICMP_EXC_TTL 0 /* TTL count exceeded */ -#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ - -/* - * IP header - */ -struct myiphdr { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 ihl:4, - version:4; -#elif defined (__BIG_ENDIAN_BITFIELD) - __u8 version:4, - ihl:4; -#else -#error "Please, edit Makefile and add -D__(LITTLE|BIG)_ENDIAN_BITFIEND" -#endif - __u8 tos; - __u16 tot_len; - __u16 id; - __u16 frag_off; - __u8 ttl; - __u8 protocol; - __u16 check; - __u32 saddr; - __u32 daddr; -}; - -/* - * UDP header - */ -struct myudphdr { - __u16 uh_sport; /* source port */ - __u16 uh_dport; /* destination port */ - __u16 uh_ulen; /* udp length */ - __u16 uh_sum; /* udp checksum */ -}; - -/* - * TCP header. - * Per RFC 793, September, 1981. - */ -struct mytcphdr { - __u16 th_sport; /* source port */ - __u16 th_dport; /* destination port */ - __u32 th_seq; /* sequence number */ - __u32 th_ack; /* acknowledgement number */ -#if defined (__LITTLE_ENDIAN_BITFIELD) - __u8 th_x2:4, /* (unused) */ - th_off:4; /* data offset */ -#elif defined (__BIG_ENDIAN_BITFIELD) - __u8 th_off:4, /* data offset */ - th_x2:4; /* (unused) */ -#else -#error "Please, edit Makefile and add -D__(LITTLE|BIG)_ENDIAN_BITFIEND" -#endif - __u8 th_flags; - __u16 th_win; /* window */ - __u16 th_sum; /* checksum */ - __u16 th_urp; /* urgent pointer */ -}; - -/* - * ICMP header - */ -struct myicmphdr -{ - __u8 type; - __u8 code; - __u16 checksum; - union - { - struct - { - __u16 id; - __u16 sequence; - } echo; - __u32 gateway; - } un; -}; - -struct icmp_tstamp_data { - __u32 orig; - __u32 recv; - __u32 tran; -}; - -/* - * UDP/TCP pseudo header - * for cksum computing - */ -struct pseudohdr -{ - __u32 saddr; - __u32 daddr; - __u8 zero; - __u8 protocol; - __u16 lenght; -}; - -#define PSEUDOHDR_SIZE sizeof(struct pseudohdr) - -/* - * hping replies delay table - */ -struct delaytable_element { - int seq; - int src; - time_t sec; - time_t usec; - int status; -}; - -volatile struct delaytable_element delaytable[TABLESIZE]; - -/* protos */ -void nop(void); /* nop */ -int parse_options(int, char**); /* option parser */ -int get_if_name(void); /* get interface (see source) */ -int get_output_if(struct sockaddr_in *dest, struct sockaddr_in *ifip); -int dltype_to_lhs(int dltype); -int get_linkhdr_size(char*); /* get link layer hdr size */ -int open_sockpacket(void); /* open SOCK_PACKET socket */ -int open_sockpacket_ifindex(int ifindex); -int close_sockpacket(int); /* close SOCK_PACKET socket */ -int open_sockraw(void); /* open raw socket */ -void send_packet (int signal_id); -void send_rawip (void); -void send_tcp(void); -void send_udp(void); -void send_icmp(void); -void send_hcmp(__u8 type, __u32 arg); /* send hcmp packets */ -void send_ip (char*, char*, char*, unsigned int, int, unsigned short, - char*, char); -void send_ip_handler(char *packet, unsigned int size); /* fragmentation - handler */ -void wait_packet(void); /* handle incoming packets */ -void print_statistics(int); -void show_usage(void); -void show_version(void); -int resolve_addr(struct sockaddr * addr, char *hostname); /* resolver */ -void resolve(struct sockaddr*, char*); /* resolver, exit on err. */ -void log_icmp_unreach(char*, unsigned short);/* ICMP unreachable logger */ -void log_icmp_timeexc(char*, unsigned short);/* ICMP time exceeded logger */ -time_t get_usec(void); /* return current usec */ -time_t milliseconds(void); /* ms from UT midnight */ -long long mstime(void); /* ms from 1 Jan 1970 */ -#define get_midnight_ut_ms milliseconds /* backward compatibilty */ -__u16 cksum(__u16 *buf, int nwords); /* compute 16bit checksum */ -void inc_destparm(int sid); /* inc dst port or ttl */ -char *get_hostname(char*); /* get host from addr */ -void datafiller(char *p, int size); /* fill data from file */ -void data_handler(char *data, int data_size);/* handle data filling */ -void socket_broadcast(int sd); /* set SO_BROADCAST option */ -void socket_iphdrincl(int sd); /* set SO_IPHDRINCL option */ -void listenmain(void); /* main for listen mode */ -char *memstr(char *haystack, char *needle, int size); /* memstr */ -void tos_help(void); /* show the TOS help */ -int rtt(int *seqp, int recvport, float *ms_delay); /* compute round trip time */ -int relativize_id(int seqnum, int *ip_id); /* compute relative id */ -int if_promisc_on(int s); /* promisc. mode ON */ -int if_promisc_off(int s); /* promisc. mode OFF */ -int open_pcap(void); /* open libpcap socket */ -int close_pcap(void); /* close libpcap socket */ -int pcap_recv(char *, unsigned int); /* libpcap api wrapper */ -int memlock(char *addr, size_t size); /* disable paging */ -int memunlock(char *addr, size_t size); /* enable paging */ -int memlockall(void); /* disable paging (all pages) */ -int memunlockall(void); /* enable paging (all pages) */ -unsigned char ip_opt_build(char *ip_opt); /* build ip options */ -void display_ipopt(char* buf); /* display ip options */ -void icmp_help(void); /* show the ICMP help */ -void route_help(void); /* show the route help */ -void (*Signal(int signo, void (*func)(int)))(int); -void delaytable_add(int seq, int src, time_t sec, time_t usec, int status); -int read_packet(void *packet, int size); -void scanmain(void); -void hping_script(int argc, char **argv); -u_int32_t hp_rand(void); -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ - !defined(__bsdi__) && !defined(__APPLE__) -size_t strlcpy(char *dst, const char *src, size_t siz); -#endif - -/* ARS glue */ -void hping_ars_send(char *s); - -#endif /* _HPING2_H */ diff --git a/hstring.c b/hstring.c deleted file mode 100644 index 9c0c254..0000000 --- a/hstring.c +++ /dev/null @@ -1,82 +0,0 @@ -/* hstring.c - Random string-related functions for hping. - * Copyright(C) 2003 Salvatore Sanfilippo - * All rights reserved */ - -/* $Id: hstring.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include -#include - -/* return 1 if the string looks like an integer number - * otherwise 0 is returned. - * - * this function is equivalent to this regexp: - * [:space:]*-{0,1}[0-9]+[:space:]* - * in english: - * (0-inf spaces)(zero or one -)(1-inf digits)(0-inf spaces) - */ -int strisnum(char *s) -{ - int digits = 0; /* used to return false if there aren't digits */ - - while(isspace(*s)) - s++; /* skip initial spaces */ - if (*s == '-') /* negative number? */ - s++; - while(*s) { - if (isspace(*s)) { /* skip spaces in the tail */ - while(isspace(*s)) - s++; - if (*s) return 0; /* but don't allow other tail chars */ - return digits ? 1 : 0; - } - if (!isdigit(*s)) - return 0; - s++; - digits++; - } - return digits ? 1 : 0; -} - -/* function similar to strtok() more convenient when we know the - * max number of tokens, to tokenize with a single call. - * Unlike strtok(), strftok() is thread safe. - * - * ARGS: - * 'sep' is a string that contains all the delimiter characters - * 'str' is the string to tokenize, that will be modified - * 'tptrs' is an array of char* poiters that will contain the token pointers - * 'nptrs' is the length of the 'tptrs' array. - * - * RETURN VALUE: - * The number of extracted tokens is returned. - */ -size_t strftok(char *sep, char *str, char **tptrs, size_t nptrs) -{ - size_t seplen = strlen(sep); - size_t i, j = 0; - int inside = 0; - - while(*str) { - for(i = 0; i < seplen; i++) { - if (sep[i] == *str) - break; - } - if (i == seplen) { /* no match */ - if (!inside) { - tptrs[j++] = str; - inside = 1; - } - } else { /* match */ - if (inside) { - *str = '\0'; - if (j == nptrs) - return j; - inside = 0; - } - } - str++; - } - return j; -} diff --git a/if_promisc.c b/if_promisc.c deleted file mode 100644 index e80e932..0000000 --- a/if_promisc.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * $smu-mark$ - * $name: if_promisc.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:48 MET 1999$ - * $rev: 2$ - */ - -/* $Id: if_promisc.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include - -#include "hping2.h" -#include "globals.h" - -int if_promisc_on(int s) -{ - struct ifreq ifr; - - strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - if ( ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { - perror("[if_prommisc_on] ioctl(SIOCGIFFLAGS)"); - return -1; - } - - if (!(ifr.ifr_flags & IFF_PROMISC)) { - ifr.ifr_flags |= IFF_PROMISC; - if ( ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { - perror("[if_promisc_on] ioctl(SIOCSIFFLAGS)"); - return -1; - } - } - return 0; -} - -int if_promisc_off(int s) -{ - struct ifreq ifr; - - strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - if ( ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { - perror("[if_promisc_off] ioctl(SIOCGIFFLAGS)"); - return -1; - } - - if (ifr.ifr_flags & IFF_PROMISC) { - ifr.ifr_flags ^= IFF_PROMISC; - if ( ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { - perror("[if_promisc_off] ioctl(SIOCSIFFLAGS)"); - return -1; - } - } - return 0; -} diff --git a/in.h b/in.h deleted file mode 100644 index e4661f1..0000000 --- a/in.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 2000,2001 Salvatore Sanfilippo */ - -#ifndef ARS_IPPROTO_IP - -#define ARS_IPPROTO_IP 0 /* Dummy protocol for TCP. */ -#define ARS_IPPROTO_HOPOPTS 0 /* IPv6 Hop-by-Hop options. */ -#define ARS_IPPROTO_ICMP 1 /* Internet Control Message Protocol. */ -#define ARS_IPPROTO_IGMP 2 /* Internet Group Management Protocol. */ -#define ARS_IPPROTO_IPIP 4 /* IPIP tunnels (older KA9Q tunnels use 94).*/ -#define ARS_IPPROTO_TCP 6 /* Transmission Control Protocol. */ -#define ARS_IPPROTO_EGP 8 /* Exterior Gateway Protocol. */ -#define ARS_IPPROTO_IGRP 9 /* Cisco(R)'s IGRP Routing Portocol. */ -#define ARS_IPPROTO_PUP 12 /* PUP protocol. */ -#define ARS_IPPROTO_UDP 17 /* User Datagram Protocol. */ -#define ARS_IPPROTO_IDP 22 /* XNS IDP protocol. */ -#define ARS_IPPROTO_TP 29 /* SO Transport Protocol Class 4. */ -#define ARS_IPPROTO_IPV6 41 /* IPv6 header. */ -#define ARS_IPPROTO_ROUTING 43 /* IPv6 routing header. */ -#define ARS_IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header. */ -#define ARS_IPPROTO_RSVP 46 /* Reservation Protocol. */ -#define ARS_IPPROTO_GRE 47 /* General Routing Encapsulation. */ -#define ARS_IPPROTO_ESP 50 /* encapsulating security payload. */ -#define ARS_IPPROTO_AH 51 /* authentication header. */ -#define ARS_IPPROTO_ICMPV6 58 /* ICMPv6. */ -#define ARS_IPPROTO_NONE 59 /* IPv6 no next header. */ -#define ARS_IPPROTO_DSTOPTS 60 /* IPv6 destination options. */ -#define ARS_IPPROTO_MTP 92 /* Multicast Transport Protocol. */ -#define ARS_IPPROTO_ENCAP 98 /* Encapsulation Header. */ -#define ARS_IPPROTO_PIM 103 /* Protocol Independent Multicast. */ -#define ARS_IPPROTO_COMP 108 /* Compression Header Protocol. */ -#define ARS_IPPROTO_RAW 255 /* Raw IP packets. */ - -#endif diff --git a/interface.c b/interface.c deleted file mode 100644 index 029e68b..0000000 --- a/interface.c +++ /dev/null @@ -1,323 +0,0 @@ -/* interfaces.c -- that's getifname.c redone with a decent API. - * This fils is for now used for the TCL bindings but it - * should replace getifname.c at some time. - * - * Note that most of the code comes from getifname.c, so the - * old copyright still apply: - * - * Copyright(C) 1999,2000,2001 Salvatore Sanfilippo - * Copyright(C) 2001 by Nicolas Jombart - * This code is under the GPL license - * - * What changes is the API design that's now sane, the changes - * are Copyright(C) 2003 Salvatore Sanfilippo. - */ - -/* $Id: interface.c,v 1.7 2003/09/08 15:32:40 antirez Exp $ */ - -#ifdef USE_TCL - -#include /* perror */ -#include -#include -#include -#include -#include /* struct sockaddr_in */ -#include /* inet_ntoa */ -#include -#include /* close */ - -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ - defined(__bsdi__) || defined(__APPLE__) -#include -#include -#include -#include -#endif /* defined(__*BSD__) */ - -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ - !defined(__linux__) && !defined(__sun__) && !defined(__bsdi__) && \ - !defined(__APPLE__) -#error Sorry, interface code not implemented. -#endif - -#ifdef __sun__ -#include -#include -#include -#endif - -#include "hping2.h" -#include "globals.h" -#include "interface.h" - -/* This function fill the hpingif structures array poited by 'i', - * able to hold up to 'ilen' elements, with details about - * all the interfaces present in the system, with the UP flag set. - * - * The function returns the number of active interfaces found, - * regardless to 'ilen'. So if the returned value is > ilen - * the provided structures array was not enough to hold all - * the interfaces. - * - * On error -1 is returned, and errno set. */ -#if (defined OSTYPE_LINUX) || (defined __sun__) -int hping_get_interfaces(struct hpingif *hif, int ilen) -{ - int fd, found = 0, i; - struct ifconf ifc; - struct ifreq ibuf[HPING_IFACE_MAX], ifr; - - /* We need a socket to perform the ioctl()s */ - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd == -1) - return -1; - /* Setup the request structure */ - memset(ibuf, 0, sizeof(struct ifreq)*HPING_IFACE_MAX); - ifc.ifc_len = sizeof ibuf; - ifc.ifc_buf = (caddr_t) ibuf; - /* Get a list of interfaces */ - if (ioctl(fd, SIOCGIFCONF, (char*)&ifc) == -1 || - ifc.ifc_len < sizeof(struct ifreq)) - { - close(fd); - return -1; - } - /* Walk the interfaces list, searching for UP interfaces */ - for (i = 0; i < (ifc.ifc_len/sizeof(struct ifreq)); i++) { - struct ifreq *this = ibuf+i; - in_addr_t ifaddr, ifbaddr = 0; - struct sockaddr_in *sain; - int ifloopback, ifmtu, ifptp, ifpromisc, ifbroadcast, ifindex, ifnolink = 0; - - memset(&ifr, 0, sizeof(ifr)); - /* It seems we can avoid to call the ioctl against - * a bogus device with little efforts */ - if (!this->ifr_name[0]) - continue; - strlcpy(ifr.ifr_name, this->ifr_name, HPING_IFNAME_LEN); - /* Get the interface's flags */ - if (ioctl(fd, SIOCGIFFLAGS, (char*)&ifr) == -1) { - /* oops.. failed, continue with the next */ - continue; - } - /* If it's DOWN we are not intersted */ - if (!(ifr.ifr_flags & IFF_UP)) - continue; - ifloopback = (ifr.ifr_flags & IFF_LOOPBACK) != 0; - ifptp = (ifr.ifr_flags & IFF_POINTOPOINT) != 0; - ifpromisc = (ifr.ifr_flags & IFF_PROMISC) != 0; - ifbroadcast = (ifr.ifr_flags & IFF_BROADCAST) != 0; -#ifdef __sun__ - ifindex = -1; -#else - /* Get the interface index */ - if (ioctl(fd, SIOCGIFINDEX, (char*)&ifr) == -1) { - /* oops.. failed, continue with the next */ - continue; - } - ifindex = ifr.ifr_ifindex; -#endif - /* Get the interface address */ - if (ioctl(fd, SIOCGIFADDR, (char*)&ifr) == -1) { - /* oops.. failed, continue with the next */ - continue; - } - sain = (struct sockaddr_in*) &ifr.ifr_addr; - ifaddr = sain->sin_addr.s_addr; - /* Get the interface broadcast address */ - if (ifbroadcast) { - if (ioctl(fd, SIOCGIFBRDADDR, (char*)&ifr) == -1) { - /* oops.. failed, continue with the next */ - continue; - } - sain = (struct sockaddr_in*) &ifr.ifr_broadaddr; - ifbaddr = sain->sin_addr.s_addr; - } - /* Get the interface MTU */ - if (ioctl(fd, SIOCGIFMTU, (char*)&ifr) == -1) { - /* Failed... we wan't consider it fatal */ - ifmtu = 1500; - } - else - { -#ifdef __sun__ - /* somehow solaris is braidamaged in wrt ifr_mtu */ - ifmtu = ifr.ifr_metric; -#else - ifmtu = ifr.ifr_mtu; -#endif - } -#ifdef __linux__ - /* Get the interface link status using MII */ - { - struct mii_data *mii = (struct mii_data*)&ifr.ifr_data; - if (ioctl(fd, SIOCGMIIPHY, (char*)&ifr) != -1) { - int bmsr; - - mii->reg_num = MII_BMSR; - if (ioctl(fd, SIOCGMIIREG, (char*)&ifr) != -1) { - bmsr = mii->val_out; - ifnolink = !(bmsr & MII_BMSR_LINK_VALID); - } - } - } -#endif - /* Finally populate an hpingif entry if there is room */ - if (!ilen) - continue; - strlcpy(hif[found].hif_name, this->ifr_name, HPING_IFNAME_LEN); - hif[found].hif_mtu = ifmtu; - hif[found].hif_loopback = ifloopback; - hif[found].hif_ptp = ifptp; - hif[found].hif_broadcast = ifbroadcast; - hif[found].hif_promisc = ifpromisc; - hif[found].hif_addr[0] = ifaddr; - hif[found].hif_baddr[0] = ifbaddr; - hif[found].hif_naddr = 1; - hif[found].hif_nolink = ifnolink; - /* if_index should be set to -1 if the OS isn't Linux */ - hif[found].hif_index = ifindex; - found++; - ilen--; - } - close(fd); - return found; -} -#endif - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ - defined(__bsdi__) || defined(__APPLE__) -/* I wish getifaddrs() API on linux... -- SS */ -int hping_get_interfaces(struct hpingif *hif, int ilen) -{ - int found = 0; - struct ifaddrs *ifap, *ifa; - struct if_data *ifdata; - int ifloopback, ifptp, ifpromisc, ifbroadcast, ifnolink; - - /* Get the interfaces list */ - if (getifaddrs(&ifap) == -1) - return -1; - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - struct ifaddrs *ift; - struct sockaddr_in *sa, *ba; - int naddr = 0; - /* Not interested in DOWN interfaces */ - if (!(ifa->ifa_flags & IFF_UP)) - continue; - ifloopback = (ifa->ifa_flags & IFF_LOOPBACK) != 0; - ifptp = (ifa->ifa_flags & IFF_POINTOPOINT) != 0; - ifpromisc = (ifa->ifa_flags & IFF_PROMISC) != 0; - ifbroadcast = (ifa->ifa_flags & IFF_BROADCAST) != 0; - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - /* Now search for the AF_INET entry with the same name */ - ift = ifa->ifa_next; - for (; ift; ift = ift->ifa_next) { - if (ift->ifa_addr->sa_family == AF_INET && - ift->ifa_addr && - !strcmp(ifa->ifa_name, ift->ifa_name)) - { - sa = (struct sockaddr_in*) ift->ifa_addr; - ba = (struct sockaddr_in*) ift->ifa_broadaddr; - if (naddr < HPING_IFADDR_MAX) { - hif[found].hif_addr[naddr] = - sa->sin_addr.s_addr; - hif[found].hif_baddr[naddr] = - ba->sin_addr.s_addr; - naddr++; - } - } - } - if (!naddr) - continue; - /* Read the media status */ - { - struct ifmediareq ifmr; - int s = -1; - memset(&ifmr, 0, sizeof(ifmr)); - strncpy(ifmr.ifm_name, ifa->ifa_name, sizeof(ifmr.ifm_name)); - ifnolink = 0; - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s != -1 && - ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) != -1) - { - if (ifmr.ifm_status & IFM_AVALID) { - if (!(ifmr.ifm_status & IFM_ACTIVE)) - ifnolink = 1; - } - } - if (s != -1) - close(s); - } - /* Add the new entry and cotinue */ - ifdata = (struct if_data*) ifa->ifa_data; - strlcpy(hif[found].hif_name, ifa->ifa_name, HPING_IFNAME_LEN); - hif[found].hif_broadcast = ifbroadcast; - hif[found].hif_mtu = ifdata->ifi_mtu; - hif[found].hif_loopback = ifloopback; - hif[found].hif_ptp = ifptp; - hif[found].hif_promisc = ifpromisc; - hif[found].hif_naddr = naddr; - hif[found].hif_nolink = ifnolink; - /* if_index should be set to -1 if the OS isn't Linux */ - hif[found].hif_index = -1; - found++; - ilen--; - if (!ilen) - break; - } - freeifaddrs(ifap); - return found; -} -#endif /* __*BSD__ */ - -/* ------------------------------- test main -------------------------------- */ -#ifdef TESTMAIN -int main(void) -{ - struct hpingif ifaces[16]; - int found, i, j; - - found = hping_get_interfaces(ifaces, 16); - printf("Found %d active interfaces:\n", found); - printf("%-10.10s %-16.16s %-10.10s %-10.10s\n", - "NAME", "ADDR", "MTU", "INDEX"); - for (i = 0; i < found; i++) { - struct in_addr ia; - printf("%-10.10s %-10d %-10d", - ifaces[i].hif_name, - ifaces[i].hif_mtu, - ifaces[i].hif_index); - printf("("); - for (j = 0; j < ifaces[i].hif_naddr; j++) { - ia.s_addr = ifaces[i].hif_addr[j]; - printf("%-16.16s ", inet_ntoa(ia)); - } - printf(")"); - if (ifaces[i].hif_broadcast) { - printf("("); - for (j = 0; j < ifaces[i].hif_naddr; j++) { - ia.s_addr = ifaces[i].hif_baddr[j]; - printf("%-16.16s ", inet_ntoa(ia)); - } - printf(")"); - } - if (ifaces[i].hif_loopback) - printf(" LOOPBACK"); - if (ifaces[i].hif_ptp) - printf(" POINTOPOINT"); - if (ifaces[i].hif_promisc) - printf(" PROMISC"); - if (ifaces[i].hif_broadcast) - printf(" BROADCAST"); - if (ifaces[i].hif_nolink) - printf(" NOLINK"); - printf("\n"); - } - return 0; -} -#endif - -#endif /* USE_TCL */ diff --git a/interface.h b/interface.h deleted file mode 100644 index 269de23..0000000 --- a/interface.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef __HPING_INTERFACE_H -#define __HPING_INTERFACE_H - -#ifndef _LINUX_MII_H -#define _LINUX_MII_H - -/* network interface ioctl's for MII commands */ -#ifndef SIOCGMIIPHY -#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Read from current PHY */ -#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read any PHY register */ -#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write any PHY register */ -#define SIOCGPARAMS (SIOCDEVPRIVATE+3) /* Read operational parameters */ -#define SIOCSPARAMS (SIOCDEVPRIVATE+4) /* Set operational parameters */ -#endif - -/* This data structure is used for all the MII ioctl's */ -struct mii_data { - __u16 phy_id; - __u16 reg_num; - __u16 val_in; - __u16 val_out; -}; - -/* Basic Mode Control Register */ -#define MII_BMCR 0x00 -#define MII_BMCR_RESET 0x8000 -#define MII_BMCR_LOOPBACK 0x4000 -#define MII_BMCR_100MBIT 0x2000 -#define MII_BMCR_AN_ENA 0x1000 -#define MII_BMCR_ISOLATE 0x0400 -#define MII_BMCR_RESTART 0x0200 -#define MII_BMCR_DUPLEX 0x0100 -#define MII_BMCR_COLTEST 0x0080 - -/* Basic Mode Status Register */ -#define MII_BMSR 0x01 -#define MII_BMSR_CAP_MASK 0xf800 -#define MII_BMSR_100BASET4 0x8000 -#define MII_BMSR_100BASETX_FD 0x4000 -#define MII_BMSR_100BASETX_HD 0x2000 -#define MII_BMSR_10BASET_FD 0x1000 -#define MII_BMSR_10BASET_HD 0x0800 -#define MII_BMSR_NO_PREAMBLE 0x0040 -#define MII_BMSR_AN_COMPLETE 0x0020 -#define MII_BMSR_REMOTE_FAULT 0x0010 -#define MII_BMSR_AN_ABLE 0x0008 -#define MII_BMSR_LINK_VALID 0x0004 -#define MII_BMSR_JABBER 0x0002 -#define MII_BMSR_EXT_CAP 0x0001 - -#define MII_PHY_ID1 0x02 -#define MII_PHY_ID2 0x03 - -/* Auto-Negotiation Advertisement Register */ -#define MII_ANAR 0x04 -/* Auto-Negotiation Link Partner Ability Register */ -#define MII_ANLPAR 0x05 -#define MII_AN_NEXT_PAGE 0x8000 -#define MII_AN_ACK 0x4000 -#define MII_AN_REMOTE_FAULT 0x2000 -#define MII_AN_ABILITY_MASK 0x07e0 -#define MII_AN_FLOW_CONTROL 0x0400 -#define MII_AN_100BASET4 0x0200 -#define MII_AN_100BASETX_FD 0x0100 -#define MII_AN_100BASETX_HD 0x0080 -#define MII_AN_10BASET_FD 0x0040 -#define MII_AN_10BASET_HD 0x0020 -#define MII_AN_PROT_MASK 0x001f -#define MII_AN_PROT_802_3 0x0001 - -/* Auto-Negotiation Expansion Register */ -#define MII_ANER 0x06 -#define MII_ANER_MULT_FAULT 0x0010 -#define MII_ANER_LP_NP_ABLE 0x0008 -#define MII_ANER_NP_ABLE 0x0004 -#define MII_ANER_PAGE_RX 0x0002 -#define MII_ANER_LP_AN_ABLE 0x0001 - -#endif /* _LINUX_MII_H */ - -#define HPING_IFNAME_LEN 24 -#define HPING_IFACE_MAX 64 -#define HPING_IFADDR_MAX 16 - -/* hping interface rappresentation */ -struct hpingif { - char hif_name[HPING_IFNAME_LEN]; - in_addr_t hif_addr[HPING_IFADDR_MAX]; /* ipv4 addresses */ - in_addr_t hif_baddr[HPING_IFADDR_MAX]; /* ipv4 broadcast addresses */ - int hif_naddr; - int hif_loopback; - int hif_ptp; - int hif_promisc; - int hif_broadcast; - int hif_nolink; /* only set with MII-capable devices */ - int hif_mtu; - int hif_index; /* only useful for linux sockpacket version */ -}; - -int hping_get_interfaces(struct hpingif *hif, int ilen); - -#endif diff --git a/listen.c b/listen.c deleted file mode 100644 index 2a73c43..0000000 --- a/listen.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * $smu-mark$ - * $name: listen.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:48 MET 1999$ - * $rev: 8$ - */ - -/* $Id: listen.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include - -#include "hping2.h" /* hping2.h includes hcmp.h */ -#include "globals.h" - -void listenmain(void) -{ - int size, ip_size; - int stdoutFD = fileno(stdout); - char packet[IP_MAX_SIZE+linkhdr_size]; - char *p, *ip_packet; - struct myiphdr ip; - __u16 id; - static __u16 exp_id; /* expected id */ - - exp_id = 1; - - while(1) { - size = read_packet(packet, IP_MAX_SIZE+linkhdr_size); - switch(size) { - case 0: - continue; - case -1: - exit(1); - } - - /* Skip truncated packets */ - if (size < linkhdr_size+IPHDR_SIZE) - continue; - ip_packet = packet + linkhdr_size; - - /* copy the ip header so it will be aligned */ - memcpy(&ip, ip_packet, sizeof(ip)); - id = ntohs(ip.id); - ip_size = ntohs(ip.tot_len); - if (size-linkhdr_size > ip_size) - size = ip_size; - else - size -= linkhdr_size; - - if ((p = memstr(ip_packet, sign, size))) { - if (opt_verbose) - fprintf(stderr, "packet %d received\n", id); - - if (opt_safe) { - if (id == exp_id) - exp_id++; - else { - if (opt_verbose) - fprintf(stderr, "packet not in sequence (id %d) received\n", id); - send_hcmp(HCMP_RESTART, exp_id); - if (opt_verbose) - fprintf(stderr, "HCMP restart from %d sent\n", exp_id); - continue; /* discard this packet */ - } - } - - p+=strlen(sign); - write(stdoutFD, p, size-(p-ip_packet)); - } - } -} diff --git a/logicmp.c b/logicmp.c deleted file mode 100644 index d75488c..0000000 --- a/logicmp.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * $smu-mark$ - * $name: logicmp.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:48 MET 1999$ - * $rev: 8$ - */ - -/* $Id: logicmp.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include /* this should be not needed, but ip_icmp.h lacks it */ - -#include "hping2.h" -#include "globals.h" - -void log_icmp_timeexc(char *src_addr, unsigned short icmp_code) -{ - switch(icmp_code) { - case ICMP_EXC_TTL: - printf("TTL 0 during transit from ip=%s", src_addr); - break; - case ICMP_EXC_FRAGTIME: - printf("TTL 0 during reassembly from ip=%s", src_addr); - break; - } - if (opt_gethost) { - char *hostn; - - fflush(stdout); - hostn = get_hostname(src_addr); - printf("name=%s", (hostn) ? hostn : "UNKNOWN"); - } - putchar('\n'); -} - -void log_icmp_unreach(char *src_addr, unsigned short icmp_code) -{ - static char* icmp_unreach_msg[]={ - "Network Unreachable from", /* code 0 */ - "Host Unreachable from", /* code 1 */ - "Protocol Unreachable from", /* code 2 */ - "Port Unreachable from", /* code 3 */ - "Fragmentation Needed/DF set from", /* code 4 */ - "Source Route failed from", /* code 5 */ - NULL, /* code 6 */ - NULL, /* code 7 */ - NULL, /* code 8 */ - NULL, /* code 9 */ - NULL, /* code 10 */ - NULL, /* code 11 */ - NULL, /* code 12 */ - "Packet filtered from", /* code 13 */ - "Precedence violation from", /* code 14 */ - "precedence cut off from" /* code 15 */ - }; - - if (icmp_unreach_msg[icmp_code] != NULL) - printf("ICMP %s ip=%s", icmp_unreach_msg[icmp_code], src_addr); - else - printf("ICMP Unreachable type=%d from ip=%s", - icmp_code, src_addr); - - if (opt_gethost) { - char *hostn; - - fflush(stdout); - hostn = get_hostname(src_addr); - printf("name=%s", (hostn) ? hostn : "UNKNOWN"); - } - putchar('\n'); -} diff --git a/m4/.keep b/m4/.keep new file mode 100644 index 0000000..e69de29 diff --git a/main.c b/main.c deleted file mode 100644 index 3aedd86..0000000 --- a/main.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * $smu-mark$ - * $name: main.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:48 MET 1999$ - * $rev: 8$ - */ - -/* - * hping official page at http://www.kyuzz.org/antirez - * Covered by GPL version 2, Read the COPYING file for more information - */ - -/* $Id: main.c,v 1.4 2004/06/18 09:53:11 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hping2.h" - -/* globals */ -unsigned int - tcp_th_flags = 0, - linkhdr_size, /* physical layer header size */ - ip_tos = 0, - set_seqnum = FALSE, - tcp_seqnum = FALSE, - set_ack, - h_if_mtu, - virtual_mtu = DEFAULT_VIRTUAL_MTU, - ip_frag_offset = 0, - signlen, - lsr_length = 0, - ssr_length = 0, - tcp_ack; - - -unsigned short int - data_size = 0; - -float - rtt_min = 0, - rtt_max = 0, - rtt_avg = 0; - -int - sockpacket, - sockraw, - sent_pkt = 0, - recv_pkt = 0, - out_of_sequence_pkt = 0, - sending_wait = DEFAULT_SENDINGWAIT, /* see DEFAULT_SENDINGWAIT */ - opt_rawipmode = FALSE, - opt_icmpmode = FALSE, - opt_udpmode = FALSE, - opt_scanmode = FALSE, - opt_listenmode = FALSE, - opt_waitinusec = FALSE, - opt_numeric = FALSE, - opt_gethost = TRUE, - opt_quiet = FALSE, - opt_relid = FALSE, - opt_fragment = FALSE, - opt_df = FALSE, - opt_mf = FALSE, - opt_debug = FALSE, - opt_verbose = FALSE, - opt_winid_order = FALSE, - opt_keepstill = FALSE, - opt_datafromfile= FALSE, - opt_hexdump = FALSE, - opt_contdump = FALSE, - opt_sign = FALSE, - opt_safe = FALSE, - opt_end = FALSE, - opt_traceroute = FALSE, - opt_seqnum = FALSE, - opt_incdport = FALSE, - opt_force_incdport = FALSE, - opt_icmptype = DEFAULT_ICMP_TYPE, - opt_icmpcode = DEFAULT_ICMP_CODE, - opt_rroute = FALSE, - opt_tcpexitcode = FALSE, - opt_badcksum = FALSE, - opt_tr_keep_ttl = FALSE, - opt_tcp_timestamp = FALSE, - opt_clock_skew = FALSE, - cs_window = DEFAULT_CS_WINDOW, - cs_window_shift = DEFAULT_CS_WINDOW_SHIFT, - cs_vector_len = DEFAULT_CS_VECTOR_LEN, - opt_tr_stop = FALSE, - opt_tr_no_rtt = FALSE, - opt_rand_dest = FALSE, - opt_rand_source = FALSE, - opt_lsrr = FALSE, - opt_ssrr = FALSE, - opt_cplt_rte = FALSE, - opt_beep = FALSE, - opt_flood = FALSE, - tcp_exitcode = 0, - src_ttl = DEFAULT_TTL, - src_id = -1, /* random */ - base_dst_port = DEFAULT_DPORT, - dst_port = DEFAULT_DPORT, - src_port, - sequence = 0, - initsport = DEFAULT_INITSPORT, - src_winsize = DEFAULT_SRCWINSIZE, - src_thoff = (TCPHDR_SIZE >> 2), - count = DEFAULT_COUNT, - ctrlzbind = DEFAULT_BIND, - delaytable_index= 0, - eof_reached = FALSE, - icmp_ip_version = DEFAULT_ICMP_IP_VERSION, - icmp_ip_ihl = DEFAULT_ICMP_IP_IHL, - icmp_ip_tos = DEFAULT_ICMP_IP_TOS, - icmp_ip_tot_len = DEFAULT_ICMP_IP_TOT_LEN, - icmp_ip_id = DEFAULT_ICMP_IP_ID, - icmp_ip_protocol= DEFAULT_ICMP_IP_PROTOCOL, - icmp_ip_srcport = DEFAULT_DPORT, - icmp_ip_dstport = DEFAULT_DPORT, - opt_force_icmp = FALSE, - icmp_cksum = DEFAULT_ICMP_CKSUM, - raw_ip_protocol = DEFAULT_RAW_IP_PROTOCOL; - -char - datafilename [1024], - targetname [1024], - targetstraddr [1024], - ifname [1024] = {'\0'}, - ifstraddr [1024], - spoofaddr [1024], - icmp_ip_srcip [1024], - icmp_ip_dstip [1024], - icmp_gwip [1024], - sign [1024], - rsign [1024], /* reverse sign (hping -> gniph) */ - ip_opt [40], - *opt_scanports = ""; - -unsigned char - lsr [255] = {0}, - ssr [255] = {0}; - -unsigned - ip_optlen = 0; - -struct sockaddr_in - icmp_ip_src, - icmp_ip_dst, - icmp_gw, - local, - remote; - -struct itimerval usec_delay; -volatile struct delaytable_element delaytable[TABLESIZE]; - -struct hcmphdr *hcmphdr_p; /* global pointer used by send_hcmp to transfer - hcmp headers to data_handler */ - -pcap_t *pcapfp; -char errbuf[PCAP_ERRBUF_SIZE]; -struct pcap_pkthdr hdr; - -/* main */ -int main(int argc, char **argv) -{ - char setflags[1024] = {'\0'}; - int c, hdr_size; - - /* Check for the scripting mode */ - if (argc == 1 || (argc > 1 && !strcmp(argv[1], "exec"))) { -#ifdef USE_TCL - if (argc != 1) { - argv++; - argc--; - } - hping_script(argc, argv); - exit(0); /* unreached */ -#else - fprintf(stderr, "Sorry, this hping binary was compiled " - "without TCL scripting support\n"); - exit(1); -#endif - } - - if (parse_options(argc, argv) == -1) { - printf("hping2: missing host argument\n" - "Try `hping2 --help' for more information.\n"); - exit(1); - } - - /* reverse sign */ - if (opt_sign || opt_listenmode) { - char *src = sign+strlen(sign)-1; /* last char before '\0' */ - char *dst = rsign; - - while(src>=sign) - *dst++ = *src--; - *dst = '\0'; - if (opt_debug) - printf("DEBUG: reverse sign: %s\n", rsign); - } - - /* get target address before interface processing */ - if ((!opt_listenmode && !opt_safe) && !opt_rand_dest) - resolve((struct sockaddr*)&remote, targetname); - - if (opt_rand_dest) { - strlcpy(targetstraddr, targetname, sizeof(targetstraddr)); - } else { - strlcpy(targetstraddr, inet_ntoa(remote.sin_addr), - sizeof(targetstraddr)); - } - - /* get interface's name and address */ - if ( get_if_name() == -1 ) { - printf("[main] no such device\n"); - exit(1); - } - - if (opt_verbose || opt_debug) { - printf("using %s, addr: %s, MTU: %d\n", - ifname, ifstraddr, h_if_mtu); - } - - /* open raw socket */ - sockraw = open_sockraw(); - if (sockraw == -1) { - printf("[main] can't open raw socket\n"); - exit(1); - } - - /* set SO_BROADCAST option */ - socket_broadcast(sockraw); - /* set SO_IPHDRINCL option */ - socket_iphdrincl(sockraw); - - /* open sock packet or libpcap socket */ - if (open_pcap() == -1) { - printf("[main] open_pcap failed\n"); - exit(1); - } - - /* get physical layer header size */ - if ( get_linkhdr_size(ifname) == -1 ) { - printf("[main] physical layer header size unknown\n"); - exit(1); - } - - if (spoofaddr[0] == '\0') - resolve((struct sockaddr*)&local, ifstraddr); - else - resolve((struct sockaddr*)&local, spoofaddr); - - if (icmp_ip_srcip[0] == '\0') - resolve((struct sockaddr*)&icmp_ip_src, "1.2.3.4"); - else - resolve((struct sockaddr*)&icmp_ip_src, icmp_ip_srcip); - - if (icmp_ip_dstip[0] == '\0') - resolve((struct sockaddr*)&icmp_ip_dst, "5.6.7.8"); - else - resolve((struct sockaddr*)&icmp_ip_dst, icmp_ip_dstip); - - if (icmp_gwip[0] == '\0') - resolve((struct sockaddr*)&icmp_gw, "0.0.0.0"); - else - resolve((struct sockaddr*)&icmp_gw, icmp_gwip); - - srand(time(NULL)); - - /* set initial source port */ - if (initsport == -1) - initsport = src_port = 1024 + (rand() % 2000); - else - src_port = initsport; - - for (c = 0; c < TABLESIZE; c++) - delaytable[c].seq = -1; - - /* use SIGALRM to send packets like ping do */ - Signal(SIGALRM, send_packet); - - /* binding */ - if (ctrlzbind != BIND_NONE) Signal(SIGTSTP, inc_destparm); - Signal(SIGINT, print_statistics); - Signal(SIGTERM, print_statistics); - - /* if we are in listemode enter in listenmain() else */ - /* print HPING... bla bla bla and enter in wait_packet() */ - if (opt_listenmode) { - fprintf(stderr, "hping2 listen mode\n"); - - /* memory protection */ - if (memlockall() == -1) { - perror("[main] memlockall()"); - fprintf(stderr, "Warning: can't disable memory paging!\n"); - } else if (opt_verbose || opt_debug) { - printf("Memory paging disabled\n"); - } - listenmain(); - /* UNREACHED */ - } - - /* Scan mode */ - if (opt_scanmode) { - fprintf(stderr, "Scanning %s (%s), port %s\n", - targetname, targetstraddr, opt_scanports); - scanmain(); - /* UNREACHED */ - } - - if (opt_rawipmode) { - strcat(setflags, "raw IP mode"); - hdr_size = IPHDR_SIZE; - } else if (opt_icmpmode) { - strcat(setflags, "icmp mode"); - hdr_size = IPHDR_SIZE + ICMPHDR_SIZE; - } else if (opt_udpmode) { - strcat(setflags, "udp mode"); - hdr_size = IPHDR_SIZE + UDPHDR_SIZE; - } else { - if (tcp_th_flags & TH_RST) strcat(setflags, "R"); - if (tcp_th_flags & TH_SYN) strcat(setflags, "S"); - if (tcp_th_flags & TH_ACK) strcat(setflags, "A"); - if (tcp_th_flags & TH_FIN) strcat(setflags, "F"); - if (tcp_th_flags & TH_PUSH) strcat(setflags, "P"); - if (tcp_th_flags & TH_URG) strcat(setflags, "U"); - if (tcp_th_flags & TH_X) strcat(setflags, "X"); - if (tcp_th_flags & TH_Y) strcat(setflags, "Y"); - if (setflags[0] == '\0') strcat(setflags, "NO FLAGS are"); - hdr_size = IPHDR_SIZE + TCPHDR_SIZE; - } - - printf("HPING %s (%s %s): %s set, %d headers + %d data bytes\n", - targetname, - ifname, - targetstraddr, - setflags, - hdr_size, - data_size); - - /* memory protection */ - if (opt_datafromfile || opt_sign) { - if (memlockall() == -1) { - perror("[main] memlockall()"); - fprintf(stderr, - "Warning: can't disable memory paging!\n"); - } else if (opt_verbose || opt_debug) { - printf("Memory paging disabled\n"); - } - } - - /* start packet sending */ - kill(getpid(), SIGALRM); - - /* flood mode? */ - if (opt_flood) { - fprintf(stderr, - "hping in flood mode, no replies will be shown\n"); - while (1) { - send_packet(0); - } - } - - /* main loop */ - while(1) - wait_packet(); - - return 0; -} diff --git a/parseoptions.c b/parseoptions.c deleted file mode 100644 index e55f67a..0000000 --- a/parseoptions.c +++ /dev/null @@ -1,692 +0,0 @@ -/* parseoptions.c -- options handling - * Copyright(C) 1999-2001 Salvatore Sanfilippo - * Under GPL, see the COPYING file for more information about - * the license. */ - -/* $Id: parseoptions.c,v 1.2 2004/06/18 09:53:11 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "antigetopt.h" - -#include "hping2.h" -#include "globals.h" - -enum { OPT_COUNT, OPT_INTERVAL, OPT_NUMERIC, OPT_QUIET, OPT_INTERFACE, - OPT_HELP, OPT_VERSION, OPT_DESTPORT, OPT_BASEPORT, OPT_TTL, OPT_ID, - OPT_WIN, OPT_SPOOF, OPT_FIN, OPT_SYN, OPT_RST, OPT_PUSH, OPT_ACK, - OPT_URG, OPT_XMAS, OPT_YMAS, OPT_FRAG, OPT_MOREFRAG, OPT_DONTFRAG, - OPT_FRAGOFF, OPT_TCPOFF, OPT_REL, OPT_DATA, OPT_RAWIP, OPT_ICMP, - OPT_UDP, OPT_BIND, OPT_UNBIND, OPT_DEBUG, OPT_VERBOSE, OPT_WINID, - OPT_KEEP, OPT_FILE, OPT_DUMP, OPT_PRINT, OPT_SIGN, OPT_LISTEN, - OPT_SAFE, OPT_TRACEROUTE, OPT_TOS, OPT_MTU, OPT_SEQNUM, OPT_BADCKSUM, - OPT_SETSEQ, OPT_SETACK, OPT_ICMPTYPE, OPT_ICMPCODE, OPT_END, - OPT_RROUTE, OPT_IPPROTO, OPT_ICMP_IPVER, OPT_ICMP_IPHLEN, - OPT_ICMP_IPLEN, OPT_ICMP_IPID, OPT_ICMP_IPPROTO, OPT_ICMP_CKSUM, - OPT_ICMP_TS, OPT_ICMP_ADDR, OPT_TCPEXITCODE, OPT_FAST, OPT_TR_KEEP_TTL, - OPT_TCP_TIMESTAMP, OPT_TR_STOP, OPT_TR_NO_RTT, OPT_ICMP_HELP, - OPT_RAND_DEST, OPT_RAND_SOURCE, OPT_LSRR, OPT_SSRR, OPT_ROUTE_HELP, - OPT_ICMP_IPSRC, OPT_ICMP_IPDST, OPT_ICMP_SRCPORT, OPT_ICMP_DSTPORT, - OPT_ICMP_GW, OPT_FORCE_ICMP, OPT_APD_SEND, OPT_SCAN, OPT_FASTER, - OPT_BEEP, OPT_FLOOD, OPT_CLOCK_SKEW, OPT_CS_WINDOW, OPT_CS_WINDOW_SHIFT, - OPT_CS_VECTOR_LEN }; - -static struct ago_optlist hping_optlist[] = { - { 'c', "count", OPT_COUNT, AGO_NEEDARG }, - { 'i', "interval", OPT_INTERVAL, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'n', "numeric", OPT_NUMERIC, AGO_NOARG }, - { 'q', "quiet", OPT_QUIET, AGO_NOARG }, - { 'I', "interface", OPT_INTERFACE, AGO_NEEDARG }, - { 'h', "help", OPT_HELP, AGO_NOARG }, - { 'v', "version", OPT_VERSION, AGO_NOARG }, - { 'p', "destport", OPT_DESTPORT, AGO_NEEDARG|AGO_EXCEPT0 }, - { 's', "baseport", OPT_BASEPORT, AGO_NEEDARG|AGO_EXCEPT0 }, - { 't', "ttl", OPT_TTL, AGO_NEEDARG }, - { 'N', "id", OPT_ID, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'w', "win", OPT_WIN, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'a', "spoof", OPT_SPOOF, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'F', "fin", OPT_FIN, AGO_NOARG|AGO_EXCEPT0 }, - { 'S', "syn", OPT_SYN, AGO_NOARG|AGO_EXCEPT0 }, - { 'R', "rst", OPT_RST, AGO_NOARG|AGO_EXCEPT0 }, - { 'P', "push", OPT_PUSH, AGO_NOARG|AGO_EXCEPT0 }, - { 'A', "ack", OPT_ACK, AGO_NOARG|AGO_EXCEPT0 }, - { 'U', "urg", OPT_URG, AGO_NOARG|AGO_EXCEPT0 }, - { 'X', "xmas", OPT_XMAS, AGO_NOARG|AGO_EXCEPT0 }, - { 'Y', "ymas", OPT_YMAS, AGO_NOARG|AGO_EXCEPT0 }, - { 'f', "frag", OPT_FRAG, AGO_NOARG|AGO_EXCEPT0 }, - { 'x', "morefrag", OPT_MOREFRAG, AGO_NOARG|AGO_EXCEPT0 }, - { 'y', "dontfrag", OPT_DONTFRAG, AGO_NOARG }, - { 'g', "fragoff", OPT_FRAGOFF, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'O', "tcpoff", OPT_TCPOFF, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'r', "rel", OPT_REL, AGO_NOARG }, - { 'd', "data", OPT_DATA, AGO_NEEDARG|AGO_EXCEPT0 }, - { '0', "rawip", OPT_RAWIP, AGO_NOARG|AGO_EXCEPT0 }, - { '1', "icmp", OPT_ICMP, AGO_NOARG }, - { '2', "udp", OPT_UDP, AGO_NOARG }, - { '8', "scan", OPT_SCAN, AGO_NEEDARG }, - { 'z', "bind", OPT_BIND, AGO_NOARG }, - { 'Z', "unbind", OPT_UNBIND, AGO_NOARG }, - { 'D', "debug", OPT_DEBUG, AGO_NOARG }, - { 'V', "verbose", OPT_VERBOSE, AGO_NOARG }, - { 'W', "winid", OPT_WINID, AGO_NOARG }, - { 'k', "keep", OPT_KEEP, AGO_NOARG }, - { 'E', "file", OPT_FILE, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'j', "dump", OPT_DUMP, AGO_NOARG|AGO_EXCEPT0 }, - { 'J', "print", OPT_PRINT, AGO_NOARG|AGO_EXCEPT0 }, - { 'e', "sign", OPT_SIGN, AGO_NEEDARG|AGO_EXCEPT0 }, - { '9', "listen", OPT_LISTEN, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'B', "safe", OPT_SAFE, AGO_NOARG|AGO_EXCEPT0 }, - { 'T', "traceroute", OPT_TRACEROUTE, AGO_NOARG }, - { 'o', "tos", OPT_TOS, AGO_NEEDARG }, - { 'm', "mtu", OPT_MTU, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'Q', "seqnum", OPT_SEQNUM, AGO_NOARG|AGO_EXCEPT0 }, - { 'b', "badcksum", OPT_BADCKSUM, AGO_NOARG|AGO_EXCEPT0 }, - { 'M', "setseq", OPT_SETSEQ, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'L', "setack", OPT_SETACK, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'C', "icmptype", OPT_ICMPTYPE, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'K', "icmpcode", OPT_ICMPCODE, AGO_NEEDARG|AGO_EXCEPT0 }, - { 'u', "end", OPT_END, AGO_NOARG|AGO_EXCEPT0 }, - { 'G', "rroute", OPT_RROUTE, AGO_NOARG }, - { 'H', "ipproto", OPT_IPPROTO, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-help", OPT_ICMP_HELP, AGO_NOARG }, - { '\0', "icmp-ipver", OPT_ICMP_IPVER, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-iphlen", OPT_ICMP_IPHLEN, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-iplen", OPT_ICMP_IPLEN, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-ipid", OPT_ICMP_IPID, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-ipproto", OPT_ICMP_IPPROTO, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-cksum", OPT_ICMP_CKSUM, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-ts", OPT_ICMP_TS, AGO_NOARG }, - { '\0', "icmp-addr", OPT_ICMP_ADDR, AGO_NOARG }, - { '\0', "tcpexitcode", OPT_TCPEXITCODE, AGO_NOARG }, - { '\0', "fast", OPT_FAST, AGO_NOARG|AGO_EXCEPT0 }, - { '\0', "faster", OPT_FASTER, AGO_NOARG|AGO_EXCEPT0 }, - { '\0', "tr-keep-ttl", OPT_TR_KEEP_TTL, AGO_NOARG }, - { '\0', "tcp-timestamp",OPT_TCP_TIMESTAMP, AGO_NOARG }, - { '\0', "tr-stop", OPT_TR_STOP, AGO_NOARG }, - { '\0', "tr-no-rtt", OPT_TR_NO_RTT, AGO_NOARG }, - { '\0', "rand-dest", OPT_RAND_DEST, AGO_NOARG }, - { '\0', "rand-source", OPT_RAND_SOURCE, AGO_NOARG }, - { '\0', "lsrr", OPT_LSRR, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "ssrr", OPT_SSRR, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "route-help", OPT_ROUTE_HELP, AGO_NOARG }, - { '\0', "apd-send", OPT_APD_SEND, AGO_NEEDARG }, - { '\0', "icmp-ipsrc", OPT_ICMP_IPSRC, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-ipdst", OPT_ICMP_IPDST, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-gw", OPT_ICMP_GW, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-srcport", OPT_ICMP_SRCPORT, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "icmp-dstport", OPT_ICMP_DSTPORT, AGO_NEEDARG|AGO_EXCEPT0 }, - { '\0', "force-icmp", OPT_FORCE_ICMP, AGO_NOARG }, - { '\0', "beep", OPT_BEEP, AGO_NOARG }, - { '\0', "flood", OPT_FLOOD, AGO_NOARG }, - { '\0', "clock-skew", OPT_CLOCK_SKEW, AGO_NOARG }, - { '\0', "clock-skew-win", OPT_CS_WINDOW, AGO_NEEDARG}, - { '\0', "clock-skew-win-shift", OPT_CS_WINDOW_SHIFT, AGO_NEEDARG}, - { '\0', "clock-skew-packets-per-sample", OPT_CS_VECTOR_LEN,AGO_NEEDARG}, - AGO_LIST_TERM -}; - -/* The following var is turned to 1 if the -i option is used. - * This allows to assign a different delay default value if - * the scanning mode is selected. */ -static int delay_changed = 0; - -static int suidtester(void) -{ - return (getuid() != geteuid()); -} - -void fail_parse_route(void) -{ - fprintf(stderr, "RECTUM\n"); - exit(1); -} - -void parse_route(unsigned char *route, unsigned int *route_len, char *str) -{ - struct in_addr ip; - unsigned int i = 0; - unsigned int j; - unsigned int n = 0; - unsigned int route_ptr = 256; - char c; - - route += 3; - while (str[i] != '\0') - { - for (j = i; isalnum(str[j]) || str[j] == '.'; j++); - switch(c = str[j]) - { - case '\0': - case '/': - if (n >= 62) - { - fprintf(stderr, "too long route\n"); - fail_parse_route(); - } - str[j] = '\0'; - if (inet_aton(str+i, &ip)) - { - memcpy(route+4*n, &ip.s_addr, 4); - n++; - if (c == '/') - str[j++] = '/'; - break; - } - fprintf(stderr, "invalid IP adress in route\n"); - fail_parse_route(); - case ':': - if ((!i) && j && j < 4) - { - sscanf(str, "%u:%n", &route_ptr, &i); - if (i == ++j) - { - if (route_ptr < 256) - break; - } - } - default: - fail_parse_route(); - } - i = j; - } - if (route_ptr == 256) - route[-1] = (unsigned char) ( n ? 8 : 4 ); - else - route[-1] = (unsigned char) route_ptr; - *route_len = 4*n + 3; - route[-2] = (unsigned char) *route_len; -} - -int parse_options(int argc, char **argv) -{ - int src_ttl_set = 0; - int targethost_set = 0; - int o; - - if (argc < 2) - return -1; - - ago_set_exception(0, suidtester, "Option disabled when setuid"); - - while ((o = antigetopt(argc, argv, hping_optlist)) != AGO_EOF) { - switch(o) { - case AGO_UNKNOWN: - case AGO_REQARG: - case AGO_AMBIG: - ago_gnu_error("hping", o); - fprintf(stderr, "Try hping --help\n"); - exit(1); - case AGO_ALONE: - if (targethost_set == 1) { - fprintf(stderr, "hping: you must specify only " - "one target host at a time\n"); - exit(1); - } else { - strlcpy(targetname, ago_optarg, 1024); - targethost_set = 1; - } - break; - case OPT_COUNT: - count = strtol(ago_optarg, NULL, 0); - break; - case OPT_INTERVAL: - delay_changed = 1; - if (*ago_optarg == 'u') { - opt_waitinusec = TRUE; - usec_delay.it_value.tv_sec = - usec_delay.it_interval.tv_sec = 0; - usec_delay.it_value.tv_usec = - usec_delay.it_interval.tv_usec = - atol(ago_optarg+1); - } - else - sending_wait = strtol(ago_optarg, NULL, 0); - break; - case OPT_NUMERIC: - opt_numeric = TRUE; - break; - case OPT_QUIET: - opt_quiet = TRUE; - break; - case OPT_INTERFACE: - strlcpy (ifname, ago_optarg, 1024); - break; - case OPT_HELP: - show_usage(); - break; - case OPT_VERSION: - show_version(); - break; - case OPT_DESTPORT: - if (*ago_optarg == '+') - { - opt_incdport = TRUE; - ago_optarg++; - } - if (*ago_optarg == '+') - { - opt_force_incdport = TRUE; - ago_optarg++; - } - base_dst_port = dst_port = strtol(ago_optarg, NULL, 0); - break; - case OPT_BASEPORT: - initsport = strtol(ago_optarg, NULL, 0); - break; - case OPT_TTL: - src_ttl = strtol(ago_optarg, NULL, 0); - src_ttl_set = 1; - break; - case OPT_ID: - src_id = strtol(ago_optarg, NULL, 0); - break; - case OPT_WIN: - src_winsize = strtol(ago_optarg, NULL, 0); - break; - case OPT_SPOOF: - strlcpy (spoofaddr, ago_optarg, 1024); - break; - case OPT_FIN: - tcp_th_flags |= TH_FIN; - break; - case OPT_SYN: - tcp_th_flags |= TH_SYN; - break; - case OPT_RST: - tcp_th_flags |= TH_RST; - break; - case OPT_PUSH: - tcp_th_flags |= TH_PUSH; - break; - case OPT_ACK: - tcp_th_flags |= TH_ACK; - break; - case OPT_URG: - tcp_th_flags |= TH_URG; - break; - case OPT_XMAS: - tcp_th_flags |= TH_X; - break; - case OPT_YMAS: - tcp_th_flags |= TH_Y; - break; - case OPT_FRAG: - opt_fragment = TRUE; - break; - case OPT_MOREFRAG: - opt_mf = TRUE; - break; - case OPT_DONTFRAG: - opt_df = TRUE; - break; - case OPT_FRAGOFF: - ip_frag_offset = strtol(ago_optarg, NULL, 0); - break; - case OPT_TCPOFF: - src_thoff = strtol(ago_optarg, NULL, 0); - break; - case OPT_REL: - opt_relid = TRUE; - break; - case OPT_DATA: - data_size = strtol(ago_optarg, NULL, 0); - break; - case OPT_RAWIP: - opt_rawipmode = TRUE; - break; - case OPT_ICMP: - opt_icmpmode = TRUE; - break; - case OPT_ICMP_TS: - opt_icmpmode = TRUE; - opt_icmptype = 13; - break; - case OPT_ICMP_ADDR: - opt_icmpmode = TRUE; - opt_icmptype = 17; - break; - case OPT_UDP: - opt_udpmode = TRUE; - break; - case OPT_SCAN: - opt_scanmode = TRUE; - opt_scanports = strdup(ago_optarg); - break; - case OPT_LISTEN: - opt_listenmode = TRUE; - strlcpy(sign, ago_optarg, 1024); - signlen = strlen(ago_optarg); - break; - case OPT_IPPROTO: - raw_ip_protocol = strtol(ago_optarg, NULL, 0); - break; - case OPT_ICMPTYPE: - opt_icmpmode= TRUE; - opt_icmptype = strtol(ago_optarg, NULL, 0); - break; - case OPT_ICMPCODE: - opt_icmpmode= TRUE; - opt_icmpcode = strtol(ago_optarg, NULL, 0); - break; - case OPT_BIND: - ctrlzbind = BIND_TTL; - break; - case OPT_UNBIND: - ctrlzbind = BIND_NONE; - break; - case OPT_DEBUG: - opt_debug = TRUE; - break; - case OPT_VERBOSE: - opt_verbose = TRUE; - break; - case OPT_WINID: - opt_winid_order = TRUE; - break; - case OPT_KEEP: - opt_keepstill = TRUE; - break; - case OPT_FILE: - opt_datafromfile = TRUE; - strlcpy(datafilename, ago_optarg, 1024); - break; - case OPT_DUMP: - opt_hexdump = TRUE; - break; - case OPT_PRINT: - opt_contdump = TRUE; - break; - case OPT_SIGN: - opt_sign = TRUE; - strlcpy(sign, ago_optarg, 1024); - signlen = strlen(ago_optarg); - break; - case OPT_SAFE: - opt_safe = TRUE; - break; - case OPT_END: - opt_end = TRUE; - break; - case OPT_TRACEROUTE: - opt_traceroute = TRUE; - break; - case OPT_TOS: - if (!strcmp(ago_optarg, "help")) - tos_help(); - else - { - static unsigned int tos_tmp = 0; - - sscanf(ago_optarg, "%2x", &tos_tmp); - ip_tos |= tos_tmp; /* OR tos */ - } - break; - case OPT_MTU: - virtual_mtu = strtol(ago_optarg, NULL, 0); - opt_fragment = TRUE; - if(virtual_mtu > 65535) { - virtual_mtu = 65535; - printf("Specified MTU too high, " - "fixed to 65535.\n"); - } - break; - case OPT_SEQNUM: - opt_seqnum = TRUE; - break; - case OPT_BADCKSUM: - opt_badcksum = TRUE; - break; - case OPT_SETSEQ: - set_seqnum = TRUE; - tcp_seqnum = strtoul(ago_optarg, NULL, 0); - break; - case OPT_SETACK: - set_ack = TRUE; - tcp_ack = strtoul(ago_optarg, NULL, 0); - break; - case OPT_RROUTE: - opt_rroute = TRUE; - break; - case OPT_ICMP_HELP: - icmp_help(); /* ICMP options help */ - break; - case OPT_ICMP_IPVER: - icmp_ip_version = strtol(ago_optarg, NULL, 0); - break; - case OPT_ICMP_IPHLEN: - icmp_ip_ihl = strtol(ago_optarg, NULL, 0); - break; - case OPT_ICMP_IPLEN: - icmp_ip_tot_len = strtol(ago_optarg, NULL, 0); - break; - case OPT_ICMP_IPID: - icmp_ip_id = strtol(ago_optarg, NULL, 0); - break; - case OPT_ICMP_IPPROTO: - icmp_ip_protocol = strtol(ago_optarg, NULL, 0); - break; - case OPT_ICMP_IPSRC: - strlcpy (icmp_ip_srcip, ago_optarg, 1024); - break; - case OPT_ICMP_IPDST: - strlcpy (icmp_ip_dstip, ago_optarg, 1024); - break; - case OPT_ICMP_GW: - strlcpy (icmp_gwip, ago_optarg, 1024); - break; - case OPT_ICMP_SRCPORT: - icmp_ip_srcport = strtol(ago_optarg, NULL, 0); - break; - case OPT_ICMP_DSTPORT: - icmp_ip_dstport = strtol(ago_optarg, NULL, 0); - break; - case OPT_FORCE_ICMP: - opt_force_icmp = TRUE; - break; - case OPT_ICMP_CKSUM: - icmp_cksum = strtol(ago_optarg, NULL, 0); - break; - case OPT_TCPEXITCODE: - opt_tcpexitcode = TRUE; - break; - case OPT_FAST: - delay_changed = 1; - opt_waitinusec = TRUE; - usec_delay.it_value.tv_sec = - usec_delay.it_interval.tv_sec = 0; - usec_delay.it_value.tv_usec = - usec_delay.it_interval.tv_usec = 100000; - break; - case OPT_FASTER: - delay_changed = 1; - opt_waitinusec = TRUE; - usec_delay.it_value.tv_sec = - usec_delay.it_interval.tv_sec = 0; - usec_delay.it_value.tv_usec = - usec_delay.it_interval.tv_usec = 1; - case OPT_TR_KEEP_TTL: - opt_tr_keep_ttl = TRUE; - break; - case OPT_TCP_TIMESTAMP: - opt_tcp_timestamp = TRUE; - break; - case OPT_TR_STOP: - opt_tr_stop = TRUE; - break; - case OPT_TR_NO_RTT: - opt_tr_no_rtt = TRUE; - break; - case OPT_RAND_DEST: - opt_rand_dest = TRUE; - break; - case OPT_RAND_SOURCE: - opt_rand_source = TRUE; - break; - case OPT_LSRR: - opt_lsrr = TRUE; - parse_route(lsr, &lsr_length, ago_optarg); - if (lsr[0]) - printf("Warning: erasing previously given " - "loose source route"); - lsr[0] = 131; - break; - case OPT_SSRR: - opt_ssrr = TRUE; - parse_route(ssr, &ssr_length, ago_optarg); - if (ssr[0]) - printf("Warning: erasing previously given " - "strong source route"); - ssr[0] = 137; - break; - case OPT_ROUTE_HELP: - route_help(); - break; - case OPT_APD_SEND: - hping_ars_send(ago_optarg); - break; - case OPT_BEEP: - opt_beep = TRUE; - break; - case OPT_FLOOD: - opt_flood = TRUE; - break; - case OPT_CLOCK_SKEW: - opt_tcp_timestamp = TRUE; - opt_clock_skew = TRUE; - break; - case OPT_CS_WINDOW: - cs_window = strtol(ago_optarg, NULL, 0); - if (cs_window < 30) { - fprintf(stderr, - "clock skew window can't be < 30 sec.\n"); - exit(1); - } - break; - case OPT_CS_WINDOW_SHIFT: - cs_window_shift = strtol(ago_optarg, NULL, 0); - if (cs_window_shift < 1) { - fprintf(stderr, - "clock skew window shift can't be < 1\n"); - exit(1); - } - break; - case OPT_CS_VECTOR_LEN: - cs_vector_len = strtol(ago_optarg, NULL, 0); - if (cs_vector_len < 1) { - fprintf(stderr, - "clock skew packets per sample can't be < 1\n"); - exit(1); - } - break; - } - } - - /* missing target host? */ - if (targethost_set == 0 && opt_listenmode && opt_safe) - { - printf( - "you must specify a target host if you require safe protocol\n" - "because hping needs a target for HCMP packets\n"); - exit(1); - } - - if (targethost_set == 0 && !opt_listenmode) return -1; - - if (opt_numeric == TRUE) opt_gethost = FALSE; - - /* some error condition */ - if (data_size+IPHDR_SIZE+TCPHDR_SIZE > 65535) { - printf("Option error: sorry, data size must be <= %lu\n", - (unsigned long)(65535-IPHDR_SIZE+TCPHDR_SIZE)); - exit(1); - } - else if (count <= 0 && count != -1) { - printf("Option error: count must > 0\n"); - exit(1); - } - else if (sending_wait < 0) { - printf("Option error: bad timing interval\n"); - exit(1); - } - else if (opt_waitinusec == TRUE && usec_delay.it_value.tv_usec < 0) - { - printf("Option error: bad timing interval\n"); - exit(1); - } - else if (opt_datafromfile == TRUE && data_size == 0) - { - printf("Option error: -E option useless without -d\n"); - exit(1); - } - else if (opt_sign && data_size && signlen > data_size) - { - printf( - "Option error: signature (%d bytes) is larger than data size\n" - "check -d option, don't specify -d to let hping compute it\n", signlen); - exit(1); - } - else if ((opt_sign || opt_listenmode) && signlen > 1024) - { - printf("Option error: signature too big\n"); - exit(1); - } - else if (opt_safe == TRUE && src_id != -1) - { - printf("Option error: sorry, you can't set id and " - "use safe protocol at some time\n"); - exit(1); - } - else if (opt_safe == TRUE && opt_datafromfile == FALSE && - opt_listenmode == FALSE) - { - printf("Option error: sorry, safe protocol is useless " - "without 'data from file' option\n"); - exit(1); - } - else if (opt_safe == TRUE && opt_sign == FALSE && - opt_listenmode == FALSE) - { - printf("Option error: sorry, safe protocol require you " - "sign your packets, see --sign | -e option\n"); - exit(1); - } else if (opt_rand_dest == TRUE && ifname[0] == '\0') { - printf("Option error: you need to specify an interface " - "when the --rand-dest option is enabled\n"); - exit(1); - } - - /* dependences */ - if (opt_safe == TRUE) - src_id = 1; - - if (opt_traceroute == TRUE && ctrlzbind == BIND_DPORT) - ctrlzbind = BIND_TTL; - - if (opt_traceroute == TRUE && src_ttl_set == 0) - src_ttl = DEFAULT_TRACEROUTE_TTL; - - /* set the data size to the signature len if the no data size - * was specified */ - if (opt_sign && !data_size) - data_size = signlen; - - /* If scan mode is on, and the -i option was not used, - * set the default delay to zero, that's send packets - * as fast as possible. */ - if (opt_scanmode && !delay_changed) { - opt_waitinusec = TRUE; - usec_delay.it_value.tv_sec = - usec_delay.it_interval.tv_sec = 0; - usec_delay.it_value.tv_usec = - usec_delay.it_interval.tv_usec = 0; - } - - return 1; -} diff --git a/random.c b/random.c deleted file mode 100644 index 455ff8e..0000000 --- a/random.c +++ /dev/null @@ -1,84 +0,0 @@ -/* rc4-based pseudo-random number generator for hping. - * Copyright (C) 2003 Salvatore Sanfilippo - * This software is released under the GPL license - * All rights reserved */ - -/* $Id: random.c,v 1.3 2004/06/04 07:22:38 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include "fixtypes.h" - -u_int32_t hp_rand(void); - -/* The rc4 sbox */ -static unsigned char rc4_sbox[256]; -/* This flags is used to initialize the sbox the first time, - * without an explicit intialization step outside this file. */ -static int rc4_seedflag = 0; - -/* Initialize the sbox with pseudo random data */ -static void hp_rand_init(void) -{ - int i, fd; - - /* Strong sbox initialization */ - fd = open("/dev/urandom", O_RDONLY); - if (fd != -1) { - read(fd, rc4_sbox, 256); - close(fd); - } - /* Weaker sbox initialization */ - for (i = 0; i < 256; i++) { - struct timeval tv; - gettimeofday(&tv, NULL); - if (i&1) - rc4_sbox[i] ^= (tv.tv_usec >> (i&0xF)) & 0xFF; - else - rc4_sbox[i] ^= (tv.tv_sec >> (i&0xF)) & 0xFF; - } - rc4_seedflag = 1; -} - -#if 0 -/* Re-seed the generator with user-provided bytes. Not used for now. */ -static void hp_rand_seed(void *seed, size_t len) -{ - int i; - - if (len > 256) len = 256; - memcpy(rc4_sbox, seed, len); - /* discard the first 256 bytes of output after the reseed */ - for (i = 0; i < 32; i++) - (void) hp_rand(); -} -#endif - -/* Generates a 32bit random number using an RC4-like algorithm */ -u_int32_t hp_rand(void) -{ - u_int32_t r = 0; - unsigned char *rc = (unsigned char*) &r; - static unsigned int i = 0, j = 0; - unsigned int si, sj, x; - - /* initialization, only needed the first time */ - if (!rc4_seedflag) - hp_rand_init(); - /* generates 4 bytes of pseudo-random data using RC4 */ - for (x = 0; x < 4; x++) { - i = (i+1) & 0xff; - si = rc4_sbox[i]; - j = (j + si) & 0xff; - sj = rc4_sbox[j]; - rc4_sbox[i] = sj; - rc4_sbox[j] = si; - *rc++ = rc4_sbox[(si+sj)&0xff]; - } - return r; -} - diff --git a/rapd.c b/rapd.c deleted file mode 100644 index ed42e93..0000000 --- a/rapd.c +++ /dev/null @@ -1,440 +0,0 @@ -/* rapd.c -- Reverse APD, from ARS packet to APD string description. - * Copyright (C) 2003 Salvatore Sanfilippo - * All rights reserved. */ - -/* $Id: rapd.c,v 1.7 2004/04/10 00:45:11 antirez Exp $ */ - -#include -#include -#include - -#include "ars.h" - -void trimlastchar(char *s) -{ - int len = strlen(s); - s[len-1] = '\0'; -} - -int ars_d_from_ars(char *dest, size_t len, struct ars_packet *pkt) -{ - int j, err; - struct adbuf buf; - - if (len <= 0) - return -ARS_OK; - if (adbuf_init(&buf)) - return -ARS_NOMEM; - for (j = 0; j < pkt->p_layer_nr; j++) { - __D(printf("ReverseAPD-ing layer %d\n", j);) - /* Skip NULL compilers */ - if (ars_linfo[pkt->p_layer[j].l_type].li_rapd != NULL) { - /* Call the layer to string converter */ - err = ars_linfo[pkt->p_layer[j].l_type].li_rapd(&buf, pkt, j); - if (err != -ARS_OK) { - adbuf_free(&buf); - return err; - } - } - } - adbuf_rtrim(&buf, 1); - strlcpy(dest, adbuf_ptr(&buf), len); - adbuf_free(&buf); - return -ARS_OK; -} - -/* layer rapd methods */ -int ars_rapd_ip(struct adbuf *dest, struct ars_packet *pkt, int layer) -{ - struct ars_iphdr *ip = pkt->p_layer[layer].l_data; - struct ars_iphdr *defip = pkt->p_default[pkt->p_layer[layer].l_type]; - adbuf_printf(dest, "ip("); - if (!defip || ip->ihl != defip->ihl) - adbuf_printf(dest, "ihl=0x%1x,", ip->ihl); - if (!defip || ip->version != defip->version) - adbuf_printf(dest, "ver=0x%1x,", ip->version); - if (!defip || ip->tos != defip->tos) - adbuf_printf(dest, "tos=0x%02x,", ip->tos); - adbuf_printf(dest, "totlen=%u,", ntohs(ip->tot_len)); - if (!defip || ip->id != defip->id) - adbuf_printf(dest, "id=%u,", ntohs(ip->id)); - adbuf_printf(dest, "fragoff=%u,", - (ntohs(ip->frag_off) & 0x1FFF) << 3); - if (!defip || - (ip->frag_off & ARS_IP_MF) != (defip->frag_off & ARS_IP_MF)) - adbuf_printf(dest, "mf=%d,", - (htons(ip->frag_off) & ARS_IP_MF) != 0); - if (!defip || - (ip->frag_off & ARS_IP_DF) != (defip->frag_off & ARS_IP_DF)) - adbuf_printf(dest, "df=%d,", - (htons(ip->frag_off) & ARS_IP_DF) != 0); - if (!defip || - (ip->frag_off & ARS_IP_RF) != (defip->frag_off & ARS_IP_RF)) - adbuf_printf(dest, "rf=%d,", - (htons(ip->frag_off) & ARS_IP_RF) != 0); - if (!defip || ip->ttl != defip->ttl) - adbuf_printf(dest, "ttl=%u,", ip->ttl); - /* TODO: the 'proto' field may not be added if the protocl - * that follows this layer looks as specified. */ - adbuf_printf(dest, "proto=%u,", ip->protocol); - adbuf_printf(dest, "cksum=0x%04x,", ip->check); - { - unsigned char *x = (unsigned char*) &ip->saddr; - adbuf_printf(dest, "saddr=%u.%u.%u.%u,", - x[0], x[1], x[2], x[3]); - x = (unsigned char*) &ip->daddr; - adbuf_printf(dest, "daddr=%u.%u.%u.%u", - x[0], x[1], x[2], x[3]); - } - adbuf_printf(dest, ")+"); - return -ARS_OK; -} - -int ars_rapd_ipopt(struct adbuf *dest, struct ars_packet *pkt, int layer) -{ - struct ars_ipopt ipopt; - int len = pkt->p_layer[layer].l_size; - unsigned char *optp = pkt->p_layer[layer].l_data; - int optlen, i; - - /* ip options may not be naturally aligned */ - memcpy(&ipopt, pkt->p_layer[layer].l_data, len); - optlen = ipopt.len; - - switch(ipopt.kind) { - case ARS_IPOPT_EOL: - adbuf_printf(dest, "ip.eol()+"); - break; - case ARS_IPOPT_NOP: - adbuf_printf(dest, "ip.nop()+"); - break; - case ARS_IPOPT_RR: - case ARS_IPOPT_LSRR: - case ARS_IPOPT_SSRR: - { - int ptr = 4; - char *optname = ""; - - switch(ipopt.kind) { - case ARS_IPOPT_RR: optname="rr"; break; - case ARS_IPOPT_LSRR: optname="lsrr"; break; - case ARS_IPOPT_SSRR: optname="ssrr"; break; - } - adbuf_printf(dest, "ip.%s(ptr=%u,data=", - optname, ipopt.un.rr.ptr); - while(1) { - unsigned char *x; - - if (ptr > 37 || - ptr > (optlen-3)) - break; - x = optp + ptr - 1; - adbuf_printf(dest, "%u.%u.%u.%u/", - x[0],x[1],x[2],x[3]); - ptr += 4; - } - if (ptr > 4) - adbuf_rtrim(dest, 1); - adbuf_printf(dest, ")+"); - } - break; - case ARS_IPOPT_TIMESTAMP: - { - int ptr = 5; - int overflow = (ipopt.un.ts.flags & 0xF0)>>4; - int flags = ipopt.un.ts.flags & 0xF; - char *strflags; - adbuf_printf(dest, "ip.ts(ptr=%u,", ipopt.un.ts.ptr); - switch(flags) { - case ARS_IPOPT_TS_TSONLY: strflags="tsonly"; break; - case ARS_IPOPT_TS_TSANDADDR: strflags="tsandaddr"; break; - case ARS_IPOPT_TS_PRESPEC: strflags="prespec"; break; - default: strflags=NULL; break; - } - if (strflags) { - adbuf_printf(dest, "flags=%s,", strflags); - } else { - adbuf_printf(dest, "flags=%u,", flags); - } - adbuf_printf(dest, "overflow=%u,data=", overflow); - while(1) { - unsigned char *x; - __u32 ts; - - if (ptr > 37 || - ptr > (optlen-4)) - break; - if (flags != ARS_IPOPT_TS_TSANDADDR && - flags != ARS_IPOPT_TS_PRESPEC) { - memcpy(&ts, optp+ptr-1, 4); - ts = ntohl(ts); - adbuf_printf(dest, "%u/", ts); - ptr += 4; - } else { - x = optp + ptr - 1; - memcpy(&ts, x+4, 4); - adbuf_printf(dest, "%u@%u.%u.%u.%u/", - ts,x[0],x[1],x[2],x[3]); - ptr += 8; - } - } - if (ptr > 5) - adbuf_rtrim(dest, 1); - adbuf_printf(dest, ")+"); - } - break; - default: - adbuf_printf(dest, "ip.unknown(hex="); - for (i = 0; i < optlen; i++) { - adbuf_printf(dest, "0x%02x", optp[i]); - } - adbuf_printf(dest, ")+"); - break; - } - return -ARS_OK; -} - -int ars_rapd_icmp(struct adbuf *dest, struct ars_packet *pkt, int layer) -{ - struct ars_icmphdr *icmp = pkt->p_layer[layer].l_data; - - adbuf_printf(dest, "icmp("); - adbuf_printf(dest, "type=%u,", icmp->type); - adbuf_printf(dest, "code=%u,", icmp->code); - if (icmp->type == ARS_ICMP_DEST_UNREACH || - icmp->type == ARS_ICMP_TIME_EXCEEDED || - icmp->type == ARS_ICMP_PARAMETERPROB || - icmp->type == ARS_ICMP_SOURCE_QUENCH) - { - adbuf_printf(dest, "unused=%lu,", (unsigned long) - ntohl(icmp->un.gateway)); - } - if (icmp->type == ARS_ICMP_ECHOREPLY || - icmp->type == ARS_ICMP_ECHO || - icmp->type == ARS_ICMP_TIMESTAMP || - icmp->type == ARS_ICMP_TIMESTAMPREPLY || - icmp->type == ARS_ICMP_INFO_REQUEST || - icmp->type == ARS_ICMP_INFO_REPLY) - { - adbuf_printf(dest, "id=%u,", ntohs(icmp->un.echo.id)); - adbuf_printf(dest, "seq=%u,", ntohs(icmp->un.echo.sequence)); - } - if (icmp->type == ARS_ICMP_REDIRECT) { - unsigned char x[4]; - memcpy(x, &icmp->un.gateway, 4); - adbuf_printf(dest, "gw=%u.%u.%u.%u,", - x[0], x[1], x[2], x[3]); - } - adbuf_rtrim(dest, 1); - adbuf_printf(dest, ")+"); - return -ARS_OK; -} - -int ars_rapd_udp(struct adbuf *dest, struct ars_packet *pkt, int layer) -{ - struct ars_udphdr *udp = pkt->p_layer[layer].l_data; - //struct ars_udphdr *defudp = pkt->p_default[pkt->p_layer[layer].l_type]; - adbuf_printf(dest, "udp("); - adbuf_printf(dest, "sport=%u,", ntohs(udp->uh_sport)); - adbuf_printf(dest, "dport=%u,", ntohs(udp->uh_dport)); - adbuf_printf(dest, "len=%u,", ntohs(udp->uh_ulen)); - adbuf_printf(dest, "cksum=0x%04x", ntohs(udp->uh_sum)); - adbuf_printf(dest, ")+"); - return -ARS_OK; -} - -int ars_rapd_tcp(struct adbuf *dest, struct ars_packet *pkt, int layer) -{ - struct ars_tcphdr *tcp = pkt->p_layer[layer].l_data; - struct ars_tcphdr *deftcp = pkt->p_default[pkt->p_layer[layer].l_type]; - adbuf_printf(dest, "tcp("); - adbuf_printf(dest, "sport=%u,", ntohs(tcp->th_sport)); - adbuf_printf(dest, "dport=%u,", ntohs(tcp->th_dport)); - adbuf_printf(dest, "seq=%lu,", ntohl(tcp->th_seq)); - adbuf_printf(dest, "ack=%lu,", ntohl(tcp->th_ack)); - if (!deftcp || tcp->th_x2 != deftcp->th_x2) - adbuf_printf(dest, "x2=0x%1x,", tcp->th_x2); - if (!deftcp || tcp->th_off != deftcp->th_off) - adbuf_printf(dest, "off=%u,", tcp->th_off); - adbuf_printf(dest, "flags="); - if (tcp->th_flags & ARS_TCP_TH_FIN) adbuf_printf(dest, "f"); - if (tcp->th_flags & ARS_TCP_TH_SYN) adbuf_printf(dest, "s"); - if (tcp->th_flags & ARS_TCP_TH_RST) adbuf_printf(dest, "r"); - if (tcp->th_flags & ARS_TCP_TH_PUSH) adbuf_printf(dest, "p"); - if (tcp->th_flags & ARS_TCP_TH_ACK) adbuf_printf(dest, "a"); - if (tcp->th_flags & ARS_TCP_TH_URG) adbuf_printf(dest, "u"); - if (tcp->th_flags & ARS_TCP_TH_X) adbuf_printf(dest, "x"); - if (tcp->th_flags & ARS_TCP_TH_Y) adbuf_printf(dest, "y"); - adbuf_printf(dest, ","); - adbuf_printf(dest, "win=%u,", ntohs(tcp->th_win)); - adbuf_printf(dest, "cksum=0x%04x,", ntohs(tcp->th_sum)); - if (!deftcp || tcp->th_urp != deftcp->th_urp) - adbuf_printf(dest, "urp=%u,", ntohs(tcp->th_urp)); - adbuf_rtrim(dest, 1); - adbuf_printf(dest, ")+"); - return -ARS_OK; -} - -int ars_rapd_tcpopt(struct adbuf *dest, struct ars_packet *pkt, int layer) -{ - struct ars_tcpopt tcpopt; - int len = pkt->p_layer[layer].l_size; - unsigned char *optp = pkt->p_layer[layer].l_data; - int optlen, i; - - /* tcp options may not be naturally aligned */ - memcpy(&tcpopt, pkt->p_layer[layer].l_data, len); - optlen = tcpopt.len; - - switch(tcpopt.kind) { - case ARS_TCPOPT_EOL: - adbuf_printf(dest, "tcp.eol()+"); - break; - case ARS_TCPOPT_NOP: - adbuf_printf(dest, "tcp.nop()+"); - break; - case ARS_TCPOPT_MAXSEG: - adbuf_printf(dest, "tcp.mss(size=%u)+", - ntohs(tcpopt.un.mss.size)); - break; - case ARS_TCPOPT_WINDOW: - adbuf_printf(dest, "tcp.wscale(shift=%u)+", - tcpopt.un.win.shift); - break; - case ARS_TCPOPT_SACK_PERM: - adbuf_printf(dest, "tcp.sackperm()+"); - break; - case ARS_TCPOPT_SACK: - adbuf_printf(dest, "tcp.sack(blocks="); - { - int blocks = (optlen-2)/8; - for (i = 0; i < blocks; i++) { - u_int32_t s_orig, s_size; - - memcpy(&s_orig, tcpopt.un.sack[i].origin, 4); - memcpy(&s_size, tcpopt.un.sack[i].size, 4); - adbuf_printf(dest, "%lu-%lu", - ntohl(s_orig), - ntohl(s_size)); - if ((i+1) != blocks) - adbuf_addchar(dest, '/'); - } - } - adbuf_printf(dest, ")+"); - break; - case ARS_TCPOPT_ECHOREQUEST: - { - __u32 info; - memcpy(&info, tcpopt.un.echo.info, 4); - adbuf_printf(dest, "tcp.echoreq(info=%lu)+", - (unsigned long) ntohl(info)); - } - break; - case ARS_TCPOPT_ECHOREPLY: - { - __u32 info; - memcpy(&info, tcpopt.un.echo.info, 4); - adbuf_printf(dest, "tcp.echoreply(info=%lu)+", - (unsigned long) ntohl(info)); - } - break; - case ARS_TCPOPT_TIMESTAMP: - { - __u32 tsval, tsecr; - memcpy(&tsval, tcpopt.un.timestamp.tsval, 4); - memcpy(&tsecr, tcpopt.un.timestamp.tsecr, 4); - adbuf_printf(dest, "tcp.timestamp(val=%lu,ecr=%lu)+", - (unsigned long) ntohl(tsval), - (unsigned long) ntohl(tsecr)); - } - break; - default: - adbuf_printf(dest, "tcp.unknown(hex="); - for (i = 0; i < optlen; i++) { - adbuf_printf(dest, "%02x", optp[i]); - } - adbuf_printf(dest, ")+"); - break; - } - return -ARS_OK; -} - -int ars_rapd_igrp(struct adbuf *dest, struct ars_packet *pkt, int layer) -{ - struct ars_igrphdr *igrp = pkt->p_layer[layer].l_data; - - adbuf_printf(dest, "igrp("); - adbuf_printf(dest, "version=%u,", igrp->version); - if (igrp->opcode == ARS_IGRP_OPCODE_UPDATE) { - adbuf_printf(dest, "opcode=update,", igrp->opcode); - } else if (igrp->opcode == ARS_IGRP_OPCODE_REQUEST) { - adbuf_printf(dest, "opcode=request,", igrp->opcode); - } else { - adbuf_printf(dest, "opcode=%u,", igrp->opcode); - } - adbuf_printf(dest, "edition=%u,", igrp->edition); - adbuf_printf(dest, "autosys=%u,", htons(igrp->autosys)); - adbuf_printf(dest, "interior=%u,", htons(igrp->interior)); - adbuf_printf(dest, "system=%u,", htons(igrp->system)); - adbuf_printf(dest, "exterior=%u,", htons(igrp->exterior)); - adbuf_printf(dest, "cksum=0x%04x", ntohs(igrp->checksum)); - adbuf_printf(dest, ")+"); - return -ARS_OK; -} - -static u_int32_t get_net_int24(void *ptr) -{ - unsigned char *x = (unsigned char*)ptr; - u_int32_t u; - - u = x[0] <<16 | x[1] << 8 | x[2]; - return u; -} - -int ars_rapd_igrpentry(struct adbuf *dest, struct ars_packet *pkt, int layer) -{ - struct ars_igrpentry *entry = pkt->p_layer[layer].l_data; - unsigned char *x = (unsigned char*) entry->destination; - - adbuf_printf(dest, "igrp.entry("); - adbuf_printf(dest, "dest=%u.%u.%u,", x[0], x[1], x[2]); - adbuf_printf(dest, "delay=%u,", get_net_int24(entry->delay)); - adbuf_printf(dest, "bandwidth=%u,", get_net_int24(entry->bandwidth)); - adbuf_printf(dest, "mtu=%u,", entry->mtu[0] << 8 | entry->mtu[1]); - adbuf_printf(dest, "reliability=%u,", entry->reliability); - adbuf_printf(dest, "load=%u,", entry->load); - adbuf_printf(dest, "hopcount=%u", entry->hopcount); - adbuf_printf(dest, ")+"); - return -ARS_OK; -} - -int ars_rapd_data(struct adbuf *dest, struct ars_packet *pkt, int layer) -{ - unsigned char *data = pkt->p_layer[layer].l_data; - int dlen = pkt->p_layer[layer].l_size, i; - - if (ars_test_option(pkt, ARS_OPT_RAPD_HEXDATA)) { - adbuf_printf(dest, "data(hex="); - for (i = 0; i < dlen; i++) { - adbuf_printf(dest, "%02x", data[i]); - } - adbuf_printf(dest, ")+"); - } else { - adbuf_printf(dest, "data(str="); - for (i = 0; i < dlen; i++) { - /* escape non-printable chars and chars - * having special meanings in APD packets. */ - if (isgraph(data[i]) && - data[i] != '(' && - data[i] != ')' && - data[i] != '+' && - data[i] != ',' && - data[i] != '=') - adbuf_printf(dest, "%c", data[i]); - else - adbuf_printf(dest, "\\%02x", data[i]); - } - adbuf_printf(dest, ")+"); - } - return 0; -} diff --git a/relid.c b/relid.c deleted file mode 100644 index 91076c2..0000000 --- a/relid.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * $smu-mark$ - * $name: relid.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:49 MET 1999$ - * $rev: 3$ - */ - -/* FIXME: maybe it's better to avoid division per seq_diff and - at least add an option to switch on/off this feature */ - -/* $Id: relid.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include "hping2.h" -#include "globals.h" - -int relativize_id(int seqnum, int *ip_id) -{ - int seq_diff, backup_id; - static int last_seq = 0, last_id = -1; - - backup_id = *ip_id; - - if (last_id == -1) { - last_id = *ip_id; - last_seq = seqnum; - } - else - { - if ( (seq_diff=(seqnum-last_seq)) > 0) - { - if (last_id > *ip_id) /* rew */ - *ip_id = ((65535-last_id) - + *ip_id)/seq_diff; - else - *ip_id = (*ip_id-last_id) - /seq_diff; - last_id = backup_id; - last_seq = seqnum; - return TRUE; - } else { - out_of_sequence_pkt++; - } - } - return FALSE; -} diff --git a/rtt.c b/rtt.c deleted file mode 100644 index e06343d..0000000 --- a/rtt.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * $smu-mark$ - * $name: rtt.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:49 MET 1999$ - * $rev: 3$ - */ - -/* $Id: rtt.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include - -#include "hping2.h" -#include "globals.h" - -void minavgmax(float ms_delay) -{ - static int avg_counter = 0; - - if (rtt_min == 0 || ms_delay < rtt_min) - rtt_min = ms_delay; - if (rtt_max == 0 || ms_delay > rtt_max) - rtt_max = ms_delay; - avg_counter++; - rtt_avg = (rtt_avg*(avg_counter-1)/avg_counter)+(ms_delay/avg_counter); -} - -int rtt(int *seqp, int recvport, float *ms_delay) -{ - long sec_delay = 0, usec_delay = 0; - int i, tablepos = -1, status; - - if (*seqp != 0) { - for (i = 0; i < TABLESIZE; i++) - if (delaytable[i].seq == *seqp) { - tablepos = i; - break; - } - } else { - for (i=0; i - * All rights reserved. - * - * This code and the documentation is released under the GPL license - * version 2 of the license. You can get a copy of the license at - * http://www.gnu.org/licenses/gpl.html - * A copy of the license is distributed with this code, - * see the file COPYING. */ - -/* History of important bugs: - * - * 28 Feb 2002: Bad casting in low-level subtraction generated bad results - * for particular pairs of numbers. It was a bit hard to - * discover the real origin of the bug since all started - * with a strange behaviour of the Fermat little theorem. - * This was since the modular reduction uses the low-level - * subtraction to perform its work. Of course now it's fixed. - * - * 12 Sep 2003: Fixed a memory leak in mpz_tostr(). - */ - -#include -#include -#include -#include -#include - -#include "sbignum.h" -#include "sbignum-tables.h" - -/* All the function with the _raw suffix don't care about the sign - * and works if the last operand, that's specified as a mpz_atom_t pointer - * and a u_int32_t length is stored in statically allocated memory, while - * higher level functions expect operands declared as mpz_t and initialized - * with mpz_init(). */ - -/* Macros and functions starting with the '_' character are usually not - * exported faster versions of normal functions, that do some unsane assumption - * like there is enough memory to store the result and so on. - * They are used to build more complex functions */ - -/* --------------------------- Low level functions -------------------------- */ - -/* For the actual list of supported functions see sbignum.h */ - -/* inititialization/allocation */ -static int mpz_zero_realloc(mpz_ptr z, u_int32_t i); -static void mpz_zero(mpz_ptr z); -/* shifting */ -static int mpz_lshiftword(mpz_ptr r, u_int32_t i); -static int mpz_rshiftword(mpz_ptr r, u_int32_t i); -/* comparision */ -static int32_t mpz_cmpabsi_raw(mpz_ptr a, mpz_atom_t *d, u_int32_t l); -static int32_t mpz_cmpabs(mpz_ptr a, mpz_ptr b); -/* addition */ -static int mpz_addi_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l); -/* subtraction */ -static int mpz_subi_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l); -/* multiplication */ -static int mpz_muli_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l); -/* division */ -static int mpz_divi_qr_raw(mpz_ptr q, mpz_ptr r, mpz_ptr z, mpz_atom_t *d, - u_int32_t l); -static int mpz_divi_r_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l); -/* number theoretic functions */ -static int mpz_gcd_raw(mpz_ptr g, mpz_ptr a, mpz_atom_t *b, u_int32_t l); -/* to/from mpz conversions */ -static int mpz_tostr(mpz_ptr z, u_int32_t b, void *s, size_t l); -/* random numbers */ -static void sbn_rand_init(void); - -/* ================================== MPZ =================================== */ - -#define MAX(a,b) ((a)>(b)?(a):(b)) -#define MIN(a,b) ((a)<(b)?(a):(b)) - -/* 32bit integer to mpz conversion */ -#if ATOMBYTES == 4 -#define u32tompz(t,u,l) \ - mpz_atom_t t[1]; \ - u_int32_t l = 0; \ - t[0] = u; \ - if (t[0]) l = 1 -#elif ATOMBYTES == 2 -#define u32tompz(t,u,l) \ - mpz_atom_t t[2]; \ - u_int32_t l = 0; \ - t[0] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ - t[1] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ - if (t[1]) l = 1; \ - else if (t[0]) l = 2 -#elif ATOMBYTES == 1 -#define u32tompz(t,u,l) \ - mpz_atom_t t[4]; \ - u_int32_t l = 0; \ - t[0] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ - t[1] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ - t[2] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ - t[3] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ - if (t[3]) l = 4; \ - else if (t[2]) l = 3; \ - else if (t[1]) l = 2; \ - else if (t[0]) l = 1 -#endif - -/* shift/andmask needed to division and modulo operation for ATOMBITS: - * a / ATOMBITS == A >> DIVATOMBITS_SHIFT - * a % ATOMBITS == A & MODATOMBITS_MASK */ -#if ATOMBYTES == 4 -#define DIVATOMBITS_SHIFT 5 -#elif ATOMBYTES == 2 -#define DIVATOMBITS_SHIFT 4 -#elif ATOMBYTES == 1 -#define DIVATOMBITS_SHIFT 3 -#endif -#define MODATOMBITS_MASK ((1<l = l; \ - (mpz)->a = l; \ - (mpz)->s = 0; \ - (mpz)->d = t; \ -} while(0) - -/* Raw inizialization of mpz_t elements */ -#define _mpz_raw_init(z, d, l, a, s) \ -do { \ - (z)->d = d; \ - (z)->l = l; \ - (z)->a = a; \ - (z)->s = s; \ -} - -#define _mpz_neg(z) \ -do { \ - (z)->s ^= 1; \ -} while(0) - -/* ------------------------ debugging macros -------------------------------- */ - -#define debugprint(m,z) do { \ - char *_s = mpz_get_str(NULL, 10, z); \ - printf("[%d]%s\n", m, _s); \ - free(_s); \ -} while(0) - -#define debugprint2(m,z) do { \ - char *_s = mpz_get_str(NULL, 2, z); \ - printf("[%d]%s\n", m, _s); \ - free(_s); \ -} while(0) - -/* ---------------------- initialization/allocation ------------------------- */ - -/* Initialize a relative bignum. - * return values: none, can't fail */ -void mpz_init(mpz_ptr z) -{ - z->d = NULL; - z->a = z->l = z->s = 0; -} - -/* This function is used every time we need to set the z->d[l] word in the - * z->d array of the mpz_t type. It performs the allocation when - * needed. So if you call it with l = 0, there is anyway at least - * one word allocated. Warning: the normalization inside some function - * relies on this behaviour. - * - * return values: - * SBN_OK on success - * SBN_MEM on out of memory - * - * On error the previous memory configuration and memory of 'z' - * is untouched. - * - * The new words are initialized to zero. - * Note that this function relies on an ANSI-C realloc() that - * acts like free if the 'size' = 0, and return NULL in such a case, - * and also acts like malloc if the ptr = NULL. */ -int mpz_realloc(mpz_ptr z, u_int32_t i) -{ - void *new; - u_int32_t j; - - if (i < z->a) - return SBN_OK; - new = realloc(z->d, (i+1)*MPZ_ATOMSZ); - if (new == NULL) - return SBN_MEM; - z->d = new; - /* set the new words to zero */ - for (j = z->a; j <= i; j++) - z->d[j] = 0; - z->a = j; /* j = i+1 here */ - return SBN_OK; -} - -/* Normalize the length of z, that's to set z->l accordly to the - * most non-zero significant digit. Assume that all the storage - * is initialized to zero (that's a global assuption). */ -void mpz_normalize(mpz_ptr z) -{ - int32_t j; - - if (!z->a) - return; - j = z->a-1; - while(j >= 0) { - if (z->d[j]) - break; - j--; - } - z->l = j+1; - if (z->l == 0) - z->s = 0; -} - -/* If z == 0, make it positive */ -void mpz_normalize_sign(mpz_ptr z) -{ - if (z->l == 0) - z->s = 0; -} - -/* inline version of mpz_normalize() that assumes z->a > 0 */ -#define _mpz_normalize(z) \ -do { \ - int32_t j = (z)->a-1; \ - while(j >=0 && !(z)->d[j]) \ - j--; \ - (z)->l = j+1; \ -} while(0) - -/* Free a bignum, can't fail */ -void mpz_clear(mpz_ptr z) -{ - free(z->d); -} - -/* Free a bignum and prepare it to accept up to i+1 digits (base 256) - * Note: not GMP compatible. Don't alter the sign */ -int mpz_zero_realloc(mpz_ptr z, u_int32_t i) -{ - int err; - - if ((err = mpz_realloc(z, i)) != SBN_OK) - return err; - mpz_zero(z); - return SBN_OK; -} - -/* raw z = 0 - * Note: not GMP compatible. Don't alter the sign */ -void mpz_zero(mpz_ptr z) -{ - if (!z->l) - return; - memset(z->d, 0, z->l*MPZ_ATOMSZ); - z->l = 0; -} - -/* Create a stack-allocated clone of the bignum pointed by 'z' and make - * 'z' pointing to the clone. This is used when the different operators - * of some operations point to the same object. */ -#define _mpz_clone_stack(z) \ -do { \ - mpz_ptr t = alloca(sizeof(mpz_t)); \ - t->d = alloca((z)->a*MPZ_ATOMSZ); \ - t->s = (z)->s; \ - t->l = (z)->l; \ - t->a = (z)->a; \ - memcpy(t->d, (z)->d, (z)->a*MPZ_ATOMSZ); \ - (z) = t; \ -} while(0) - -/* Clone 'z' using the 'L' atoms pointed by 'D' using stack-allocated memory */ -#define _mpz_rawclone_stack(z, D, L) \ -do { \ - (z)->d = alloca((L)*MPZ_ATOMSZ); \ - (z)->l = z->a = (L); \ - (z)->s = 0; \ - memcpy((z)->d, (D), (L)*MPZ_ATOMSZ); \ -} while(0) - -/* Create a stack-allocated copy of 'z' in 'r'. 'r' is an mpz_ptr type */ -#define _mpz_copy_stack(r, z) \ -do { \ - r = alloca(sizeof(mpz_t)); \ - (r)->d = alloca((z)->a*MPZ_ATOMSZ); \ - (r)->s = (z)->s; \ - (r)->l = (z)->l; \ - (r)->a = (z)->a; \ - memcpy((r)->d, (z)->d, (z)->a*MPZ_ATOMSZ); \ -} while(0) - -/* ----------------------- basic raw operations ----------------------------- */ - -/* clear the sign flag, so 'z' will be ABS(z) */ -#define _mpz_abs(z) \ -do { \ - (z)->s = 0; \ -} while(0) - -/* ---------------------------- bits operations ----------------------------- */ -/* compute the number of bits needed to rappresent the number 'z' */ -u_int32_t mpz_bits(mpz_ptr z) -{ - u_int32_t bits = (z->l-1) * ATOMBITS; - mpz_atom_t x = z->d[z->l-1]; - while(x) { - bits++; - x >>= 1; - } - return bits; -} - -/* Set the bit 'i' in 'z' */ -int mpz_setbit(mpz_ptr z, u_int32_t i) -{ - u_int32_t atom = i >> DIVATOMBITS_SHIFT; - u_int32_t bit = i & MODATOMBITS_MASK; - int err; - - if ((err = mpz_realloc(z, atom)) != SBN_OK) - return err; - z->d[atom] |= (mpz_atom_t) 1 << bit; - if (z->l < atom+1) - z->l = atom+1; - return SBN_OK; -} - -/* Inline bit pusher that expects the user know what is doing. - * Used in the division algorithm. */ -#define _mpz_setbit(z, i) \ -do { \ - u_int32_t _atom = (i)>>DIVATOMBITS_SHIFT; \ - (z)->d[_atom] |= (mpz_atom_t) 1<<((i)&MODATOMBITS_MASK);\ - if ((z)->l < _atom+1) (z)->l = _atom+1; \ -} while(0) - -/* Faster version without normalization */ -#define __mpz_setbit(z, i) \ -do { \ - u_int32_t _atom = (i)>>DIVATOMBITS_SHIFT; \ - (z)->d[_atom] |= (mpz_atom_t) 1<<((i)&MODATOMBITS_MASK);\ -} while(0) - -/* Clear the bit 'i' in 'z' */ -int mpz_clrbit(mpz_ptr z, u_int32_t i) -{ - u_int32_t atom = i >> DIVATOMBITS_SHIFT; - u_int32_t bit = i & MODATOMBITS_MASK; - - if (atom >= z->l) - return SBN_OK; /* nothing to clear */ - z->d[atom] &= ~((mpz_atom_t) 1 << bit); - if (atom == z->l-1) - mpz_normalize(z); - return SBN_OK; -} - -/* Fast clear-bit with normalization */ -#define _mpz_clrbit(z, i) \ -do { \ - u_int32_t _atom = (i)>>DIVATOMBITS_SHIFT; \ - (z)->d[_atom] &= ~((mpz_atom_t) 1<<((i)&MODATOMBITS_MASK)); \ - if (_atom == z->l-1) \ - _mpz_normalize(z); \ -} while(0) - -/* Fast clear-bit without normalization */ -#define __mpz_clrbit(z, i) \ -do { \ - u_int32_t _atom = (i)>>DIVATOMBITS_SHIFT; \ - (z)->d[_atom] &= ~((mpz_atom_t) 1<<((i)&MODATOMBITS_MASK));\ -} while(0) - -/* test the bit 'i' of 'z' and return: - * 0 if the bit 'i' is not set or out of range - * > 0 if the bit 'i' is set */ -int mpz_testbit(mpz_ptr z, u_int32_t i) -{ - u_int32_t atom = i >> DIVATOMBITS_SHIFT; - u_int32_t bit = i & MODATOMBITS_MASK; - - if (atom >= z->l) - return 0; - return (z->d[atom] & ((mpz_atom_t) 1 << bit)); -} - -/* inline bit tester that expects the user know what is doing. - * It's used in the division algorithm. Return 0 if the bit is set, - * non zero if the bit isn't zet */ -#define _mpz_testbit(z, i) \ - ((z)->d[(i)>>DIVATOMBITS_SHIFT] & ((mpz_atom_t)1<<((i)&MODATOMBITS_MASK))) - -/* Return 1 if 'z' is odd, 0 if it's even. */ -#define mpz_is_odd(z) (((z)->l) ? ((z)->d[0] & 1) : 0) - -/* The same of mpz_odd() but assume there is at least an word allocated */ -#define _mpz_is_odd(z) ((z)->d[0] & 1) -#define _mpz_is_even(z) (!_mpz_is_odd(z)) - -/* -------------------------------- shifting -------------------------------- */ -/* Left shift of 'i' words */ -int mpz_lshiftword(mpz_ptr r, u_int32_t i) -{ - int err; - - if (!i) - return SBN_OK; - if ((err = mpz_realloc(r, (r->l+i)-1)) != SBN_OK) - return err; - memmove(r->d+i, r->d, r->l*MPZ_ATOMSZ); - memset(r->d, 0, i*MPZ_ATOMSZ); - r->l += i; - return SBN_OK; -} - -/* Right shift of 'i' words */ -int mpz_rshiftword(mpz_ptr r, u_int32_t i) -{ - if (!i) - return SBN_OK; - if (i >= r->l) { - mpz_zero(r); - return SBN_OK; - } - memmove(r->d, r->d+i, (r->l-i)*MPZ_ATOMSZ); - r->l -= i; - memset(r->d+r->l, 0, i); - return SBN_OK; -} - -/* Left shift of 'i' bits */ -int mpz_lshift(mpz_ptr r, mpz_ptr z, u_int32_t i) -{ - u_int32_t rawshift = i >> DIVATOMBITS_SHIFT; - u_int32_t bitshift = i & MODATOMBITS_MASK; - int32_t j; - mpz_carry_t x; - int err; - - /* clone 'z' in 'r' */ - if (r != z && ((err = mpz_set(r, z)) != SBN_OK)) - return err; - if (rawshift && ((err = mpz_lshiftword(r, rawshift)) != SBN_OK)) - return err; - if (!bitshift) - return SBN_OK; - /* We need an additional word */ - if ((err = mpz_realloc(r, r->l+1)) != SBN_OK) - return err; - /* note that here we are sure that 'bitshift' <= ATOMBITS */ - if (r->l) { - for (j = r->l-1; j >= 0; j--) { - x = (mpz_carry_t) r->d[j] << bitshift; - r->d[j] = x & MPZ_MASK; - r->d[j+1] |= x >> ATOMBITS; - } - if (r->d[r->l]) - r->l++; - } - return SBN_OK; -} - -/* Fast 'z' 1 bit left shift. Assume there is allocated space for - * an additional atom. Handle normalization */ -#define _mpz_self_lshift1(z) \ -do { \ - int32_t j; \ - for (j = (z)->l-1; j >= 0; j--) { \ - (z)->d[j+1] |= ((z)->d[j] & (1<<(ATOMBITS-1))) >> (ATOMBITS-1);\ - (z)->d[j] <<= 1; \ - } \ - if ((z)->d[(z)->l]) \ - (z)->l++; \ -} while(0); - -/* Fast 'z' 1 bit left shift + set bit 0 to 'b'. Assume there is allocated - * space for an additional atom. Handle normalization */ -#define _mpz_self_lshift1_setbit0(z, b) \ -do { \ - int32_t j; \ - for (j = (z)->l-1; j >= 0; j--) { \ - (z)->d[j+1] |= ((z)->d[j] & (1<<(ATOMBITS-1))) >> (ATOMBITS-1);\ - (z)->d[j] <<= 1; \ - } \ - (z)->d[0] |= b; \ - if ((z)->d[(z)->l]) \ - (z)->l++; \ -} while(0); - -/* Right shift of 'i' bits */ -int mpz_rshift(mpz_ptr r, mpz_ptr z, u_int32_t i) -{ - u_int32_t rawshift = i >> DIVATOMBITS_SHIFT; - u_int32_t bitshift = i & MODATOMBITS_MASK; - u_int32_t j; - mpz_carry_t x; - int err; - - /* clone 'z' in 'r' */ - if (r != z && ((err = mpz_set(r, z)) != SBN_OK)) - return err; - if (rawshift && ((err = mpz_rshiftword(r, rawshift)) != SBN_OK)) - return err; - if (!bitshift) - return SBN_OK; - /* note that here we are sure that 'bitshift' <= ATOMBITS */ - if (r->l) { - r->d[0] >>= bitshift; - for (j = 1; j < r->l; j++) { - x = (mpz_carry_t) r->d[j] << (ATOMBITS-bitshift); - r->d[j] = x >> ATOMBITS; - r->d[j-1] |= x & MPZ_MASK; - } - if (!r->d[r->l-1]) - r->l--; - } - return SBN_OK; -} - -/* Fast 'z' 1 bit right shift. Handle normalization. Assume z->a != 0 - * (so z->d != NULL), that's: don't call it without a reallocation. */ -#define _mpz_self_rshift1(z) \ -do { \ - u_int32_t j; \ - (z)->d[0] >>= 1; \ - for (j = 1; j < (z)->l; j++) { \ - (z)->d[j-1] |= ((z)->d[j] & 1) << (ATOMBITS-1); \ - (z)->d[j] >>= 1; \ - } \ - if (!(z)->d[(z)->l-1]) \ - (z)->l--; \ -} while(0); - -/* -------------------------- bitwise AND OR XOR NOT ------------------------ */ -/* 'r' = 'z' bit-AND 'm' */ -int mpz_and(mpz_ptr r, mpz_ptr z, mpz_ptr m) -{ - int err; - u_int32_t j; - u_int32_t len; - - if (z == m) { /* A AND A = A */ - mpz_set(r, z); - return SBN_OK; - } - len = MIN(z->l, m->l); - if ((err = mpz_realloc(r, len)) != SBN_OK) - return err; - for (j = 0; j < len; j++) - r->d[j] = z->d[j] & m->d[j]; - memset(r->d+j, 0, r->a - j); /* clear not-used words before normalize */ - mpz_normalize(r); - return SBN_OK; -} - -/* -------------------------------- compare --------------------------------- */ - -/* The same as mpz_cmpabs() for immediate. - * Relies on the fact that mpz_cmpabs() don't perform any allocation-related - * operation on the second operand. */ -int32_t mpz_cmpabsi_raw(mpz_ptr a, mpz_atom_t *d, u_int32_t l) -{ - mpz_t b; - - b->d = d; - b->l = b->a = l; - b->s = 0; - return mpz_cmpabs(a, b); -} - -/* compare ABS('a') and ABS('b'), return values: - * >0 if a > b - * 0 if a == b - * <0 if a < b - * - * 'a->d' and 'b->d' can point to statically allocated memory. - * - * Note that we can't use subtraction to return >0 or <0 if a-b != 0 - * since the type for length and atom is unsigned so it may overflow. - */ -int32_t mpz_cmpabs(mpz_ptr a, mpz_ptr b) -{ - int32_t i; - - if (a->l > b->l) return 1; - if (a->l < b->l) return -1; - i = a->l; - while(i--) { - if (a->d[i] > b->d[i]) return 1; - if (a->d[i] < b->d[i]) return -1; - } - return 0; -} - -/* the same as mpz_cmpabs() but 'b' is a 32bit unsigned immediate */ -int32_t mpz_cmpabs_ui(mpz_ptr a, u_int32_t u) -{ - mpz_t mpz; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - return mpz_cmpabs(a, mpz); -} - -/* compare 'a' and 'b'. Return values are the same as mpz_cmpabs() */ -int32_t mpz_cmp(mpz_ptr a, mpz_ptr b) -{ - if (!a->l && !b->l) /* 0 == 0 */ - return 0; - if (a->s == b->s) { /* same sign */ - if (a->s) return mpz_cmpabs(b,a); /* both negative */ - return mpz_cmpabs(a,b); /* both positive */ - } - /* one negative, one positive */ - if (a->s) - return -1; - return 1; -} - -/* The same as mpz_cmp() with unsigned 32bit immediate */ -int32_t mpz_cmp_ui(mpz_ptr a, u_int32_t u) -{ - mpz_t mpz; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - return mpz_cmp(a, mpz); -} - -/* signed integer version */ -int32_t mpz_cmp_si(mpz_ptr a, int32_t s) -{ - mpz_t mpz; - u_int32_t u = (s > 0) ? s : -s; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - mpz->s = s < 0; - return mpz_cmp(a, mpz); -} - -/* ---------------------------- addition ------------------------------------ */ - -/* Raw add of immediate, don't care about the sign since - * it's up to the caller */ -int mpz_addi_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) -{ - int err; - u_int32_t maxi = MAX(z->l, l); - mpz_atom_t car = 0; - mpz_carry_t sum; - u_int32_t j; - mpz_atom_t *t = NULL; - - if (r->d == d) { - if ((t = malloc(l*MPZ_ATOMSZ)) == NULL) - return SBN_MEM; - memcpy(t, d, l*MPZ_ATOMSZ); - d = t; - } - /* two sum of a,b requires at max MAX(len(a),len(b))+1 bytes */ - if (r != z && ((err = mpz_zero_realloc(r, maxi)) != SBN_OK)) - return err; - if ((err = mpz_realloc(z, (r == z) ? maxi : l)) != SBN_OK) - return err; - for(j = 0; j < l; j++) { - sum = (mpz_carry_t) d[j] + z->d[j] + car; - car = sum >> MPZ_SHIFT; - sum &= MPZ_MASK; - r->d[j] = sum; - } - for (j = l; j < z->l; j++) { - sum = (mpz_carry_t) z->d[j] + car; - car = sum >> MPZ_SHIFT; - sum &= MPZ_MASK; - r->d[j] = sum; - } - if (car) { - r->d[j] = car; - j++; - } - r->l = j; /* mpz_normalize() not needed */ - if (t) - free(t); - return SBN_OK; -} - -/* Add 'z' and a 32bit unsigned integer 'u' and put the result in 'r' - * Relies on the ability of mpz_add() to accept the last operator - * statically allocated */ -int mpz_add_ui(mpz_ptr r, mpz_ptr z, u_int32_t u) -{ - mpz_t mpz; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - return mpz_add(r, z, mpz); -} - -/* The same as mpz_add_ui but with signed integer */ -int mpz_add_si(mpz_ptr r, mpz_ptr z, int32_t s) -{ - mpz_t mpz; - u_int32_t u = (s > 0) ? s : -s; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - mpz->s = s < 0; - return mpz_add(r, z, mpz); -} - -/* 'r' = 'a' + 'b' - * b->d can point to statically allocated data */ -int mpz_add(mpz_ptr r, mpz_ptr a, mpz_ptr b) -{ - int cmp = mpz_cmpabs(a, b); - int err; - - /* both positive or negative */ - if (a->s == b->s) { - err = mpz_addi_raw(r, a, b->d, b->l); - r->s = a->s; - return err; - } - /* different signs if we are here */ - if (a->s) { /* a negative, b positive */ - if (cmp >= 0) { /* a >= b */ - err = mpz_subi_raw(r, a, b->d, b->l); - r->s = (r->l == 0) ? 0 : 1; /* negative */ - return err; - } else { /* a < b */ - err = mpz_subi_raw(r, b, a->d, a->l); - r->s = 0; /* positive */ - return err; - } - } else { /* a positive, b negative */ - if (cmp >= 0) { /* a >= b */ - err = mpz_subi_raw(r, a, b->d, b->l); - r->s = 0; /* positive */ - return err; - } else { /* a < b */ - err = mpz_subi_raw(r, b, a->d, a->l); - r->s = (r->l == 0) ? 0 : 1; /* negative */ - return err; - } - } - return SBN_OK; /* not reached */ -} - -/* ---------------------------- subtraction --------------------------------- */ - -/* WARNING: assume z > d */ -int mpz_subi_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) -{ - int err; - mpz_scarry_t sub; - mpz_atom_t car = 0; - u_int32_t j; - mpz_atom_t *t = NULL; - - if (r->d == d) { - if ((t = malloc(l*MPZ_ATOMSZ)) == NULL) - return SBN_MEM; - memcpy(t, d, l*MPZ_ATOMSZ); - d = t; - } - if (r != z && ((err = mpz_set(r, z)) != SBN_OK)) - return err; - for (j = 0; j < l; j++) { - sub = (mpz_scarry_t) z->d[j] - car - d[j]; - car = 0; - if (sub < 0) { - sub += MPZ_BASE; - car = 1; - } - r->d[j] = sub; - } - for (j = l; j < z->l; j++) { - sub = (mpz_scarry_t) z->d[j] - car; - car = 0; - if (sub < 0) { - sub += MPZ_BASE; - car = 1; - } - r->d[j] = sub; - } - r->l = j; - mpz_normalize(r); - if (t) - free(t); - return SBN_OK; -} - -/* 'r' = 'a' - 'b' - * b->d can be statically allocated data */ -int mpz_sub(mpz_ptr r, mpz_ptr a, mpz_ptr b) -{ - int cmp = mpz_cmpabs(a, b); - int err; - - /* different signs? */ - if (a->s != b->s) { - err = mpz_addi_raw(r, a, b->d, b->l); - r->s = a->s; - return err; - } - /* both positive or negative if we are here */ - if (a->s) { /* both negative */ - if (cmp >= 0) { /* a >= b */ - err = mpz_subi_raw(r, a, b->d, b->l); - r->s = (r->l == 0) ? 0 : 1; /* negative */ - return err; - } else { /* a < b */ - err = mpz_subi_raw(r, b, a->d, a->l); - r->s = 0; /* positive */ - return err; - } - } else { /* both positive */ - if (cmp >= 0) { /* a >= b */ - err = mpz_subi_raw(r, a, b->d, b->l); - r->s = 0; /* positive */ - return err; - } else { /* a < b */ - err = mpz_subi_raw(r, b, a->d, a->l); - r->s = (r->l == 0) ? 0 : 1; /* negative */ - return err; - } - } - return SBN_OK; /* not reached */ -} - -/* mpz_sub() with immediate. - * Relies on the fact that mpz_sub() works if the last argument - * is statically allocated */ -int mpz_sub_ui(mpz_ptr r, mpz_ptr z, u_int32_t u) -{ - mpz_t mpz; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - return mpz_sub(r, z, mpz); -} - -/* like mpz_sub_ui but with signed integer */ -int mpz_sub_si(mpz_ptr r, mpz_ptr z, int32_t s) -{ - mpz_t mpz; - u_int32_t u = (s > 0) ? s : -s; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - mpz->s = s < 0; - return mpz_sub(r, z, mpz); -} - -/* ------------------------------- product ---------------------------------- */ - -/* Raw multiplication of immediate, don't care about the sign - * since it's up to the caller */ -int mpz_muli_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) -{ - int err; - u_int32_t maxi = z->l+l; - mpz_atom_t car; - mpz_carry_t mul; - u_int32_t j, i; - mpz_t t, rt; - mpz_ptr rbak = NULL; - int tmptarget = (r == z); - mpz_atom_t *x = NULL; - - /* Make a copy of 'd' if it's == r */ - if (r->d == d) { - if ((x = malloc(l*MPZ_ATOMSZ)) == NULL) - return SBN_MEM; - memcpy(x, d, l*MPZ_ATOMSZ); - d = x; - } - /* if r and z are the same we need a temp bignum target */ - if (tmptarget) { - rbak = r; - r = rt; - mpz_init(r); - r->s = rbak->s; /* preserve the original sign */ - } - /* two product of a,b requires at max len(a)+len(b) bytes */ - if ((err = mpz_zero_realloc(r, maxi)) != SBN_OK) - goto error; - /* initialize the temp var */ - mpz_init(t); - if ((err = mpz_realloc(t, maxi)) != SBN_OK) - goto error; - for(j = 0; j < l; j++) { - car = 0; - mpz_zero(t); - for (i = 0; i < z->l; i++) { - /* note that A = B * C + D + E - * with A of N*2 bits and C,D,E of N bits - * can't overflow since: - * (2^N-1)*(2^N-1)+(2^N-1)+(2^N-1) == 2^(2*N)-1 */ - mul = (mpz_carry_t) d[j] * z->d[i] + car + r->d[i+j]; - car = mul >> MPZ_SHIFT; - mul &= MPZ_MASK; - r->d[i+j] = mul; - } - if (car) - r->d[i+j] = car; - } - r->l = maxi; - mpz_normalize(r); - if (tmptarget && ((err = mpz_set(rbak, rt)) != SBN_OK)) - goto error; - err = SBN_OK; - /* fall through */ -error: - mpz_clear(t); - if (tmptarget) - mpz_clear(rt); - if (x) - free(x); - return err; -} - -/* 'r' = 'z' * 'f' */ -int mpz_mul(mpz_ptr r, mpz_ptr z, mpz_ptr f) -{ - r->s = z->s^f->s; /* the sign is the xor of the two sings */ - return mpz_muli_raw(r, z, f->d, f->l); -} - -/* Mul 'z' and a 32bit unsigned integer 'u' and put the result in 'r' - * We don't need to touch the sign since the factor is >= 0 */ -int mpz_mul_ui(mpz_ptr r, mpz_ptr z, u_int32_t u) -{ - u32tompz(t,u,l); - r->s = z->s; - return mpz_muli_raw(r, z, t, l); -} - -/* Like mpz_mul_ui but with signed integer */ -int mpz_mul_si(mpz_ptr r, mpz_ptr z, int32_t s) -{ - u_int32_t u = (s > 0) ? s : -s; - u32tompz(t,u,l); - r->s = z->s^(s<0); - return mpz_muli_raw(r, z, t, l); -} - -/* 'r' = i! */ -int mpz_fac_ui(mpz_ptr r, u_int32_t i) -{ - u_int32_t j; - int err; - - if (!i) { - mpz_setzero(r); - return SBN_OK; - } - if ((err = mpz_set_ui(r, 1)) != SBN_OK) - return err; - for (j = 2; j <= i; j++) - if ((err = mpz_mul_ui(r, r, j)) != SBN_OK) - return err; - return SBN_OK; -} - -/* --------------------------- exponentialization --------------------------- */ - -/* compute b^e mod m. - * Note that there are much faster ways to do it. - * see www.nc.com for more information */ -int mpz_powm(mpz_ptr r, mpz_ptr b, mpz_ptr e, mpz_ptr m) -{ - int rs = 0, err; - mpz_t B, E; - - if (e->s) /* can't handle negative exponents */ - return SBN_INVAL; - - /* handle overlapping of modulo and result */ - if (r == m) - _mpz_clone_stack(m); - /* we need to work on copies of base and exponent */ - mpz_init(B); - mpz_init(E); - if ((err = mpz_set(B, b)) != SBN_OK) - return err; - if ((err = mpz_set(E, e)) != SBN_OK) { - mpz_clear(B); - return err; - } - /* make the base positive, but first compute the power sign, - * that's negative only if the base is negative and exponent odd */ - if (B->s && _mpz_is_odd(E)) - rs = 1; - _mpz_abs(B); - /* compute r = b^e mod m */ - mpz_set_ui(r, 1); - while(mpz_cmpabs_ui(E, 1) > 0) { - if (_mpz_is_odd(E)) { - if ((err = mpz_mul(r, r, B)) != SBN_OK) goto error; - if ((err = mpz_mod(r, r, m)) != SBN_OK) goto error; - } - _mpz_self_rshift1(E); /* e = e / 2 */ - if ((err = mpz_mul(B, B, B)) != SBN_OK) goto error; - if ((err = mpz_mod(B, B, m)) != SBN_OK) goto error; - } - if ((err = mpz_mul(r, r, B)) != SBN_OK) goto error; - r->s = rs; /* set the pre-computed sign */ - if ((err = mpz_mod(r, r, m)) != SBN_OK) goto error; - err = SBN_OK; - /* fall through */ -error: - mpz_clear(B); - mpz_clear(E); - return err; -} - -/* Just b^e. The algorithm is just the one of mpz_powm() without - * the modulo step. */ -int mpz_pow(mpz_ptr r, mpz_ptr b, mpz_ptr e) -{ - int rs = 0, err; - mpz_t B, E; - - if (e->s) /* can't handle negative exponents */ - return SBN_INVAL; - - /* we need to work on copies of base and exponent */ - mpz_init(B); - mpz_init(E); - if ((err = mpz_set(B, b)) != SBN_OK) - return err; - if ((err = mpz_set(E, e)) != SBN_OK) { - mpz_clear(B); - return err; - } - /* make the base positive, but first compute the power sign, - * that's negative only if the base is negative and exponent odd */ - if (B->s && _mpz_is_odd(E)) - rs = 1; - _mpz_abs(B); - /* compute r = b^e */ - mpz_set_ui(r, 1); - while(mpz_cmpabs_ui(E, 1) > 0) { - if (_mpz_is_odd(E)) { - if ((err = mpz_mul(r, r, B)) != SBN_OK) goto error; - } - _mpz_self_rshift1(E); /* e = e / 2 */ - if ((err = mpz_mul(B, B, B)) != SBN_OK) goto error; - } - if ((err = mpz_mul(r, r, B)) != SBN_OK) goto error; - r->s = rs; /* set the pre-computed sign */ - err = SBN_OK; - /* fall through */ -error: - mpz_clear(B); - mpz_clear(E); - return err; -} - -/* -------------------------- root extraction ------------------------------- */ - -/* r = floor(sqrt(z)). That's r*r <= z AND (r+1)*(r+1) > z. - * The algorithm used is very simple but very slow. It exploits - * the binary rappresentation. This should be replaced since - * performances are very poor */ -int mpz_sqrt(mpz_ptr r, mpz_ptr z) -{ - int j = mpz_bits(z); /* MSB bit of 'z' */ - int i = ((j-1)/2); /* MSB bit (sometimes one more) of 'r' */ - int b = i*2; /* bit to set to obtain 2^i * 2^i */ - int err; - u_int32_t atoms = j >> DIVATOMBITS_SHIFT; - mpz_t s, R, X; - - mpz_init(s); - mpz_init(R); - mpz_init(X); - if (r == z) { - _mpz_clone_stack(z); - } - if ((err = mpz_realloc(s, atoms)) != SBN_OK) return err; - if ((err = mpz_realloc(R, atoms)) != SBN_OK) return err; - if ((err = mpz_realloc(X, atoms)) != SBN_OK) return err; - if ((err = mpz_zero_realloc(r, atoms)) != SBN_OK) return err; - for(; i >= 0; i--, b -= 2) { - _mpz_setbit(R, b); - mpz_addi_raw(X, s, R->d, R->l); - _mpz_clrbit(R, b); - if (mpz_cmpabs(X, z) <= 0) { - mpz_set(s, X); - _mpz_setbit(r, i); - _mpz_setbit(R, b+1); - } - _mpz_self_rshift1(R); - } - mpz_clear(s); - mpz_clear(R); - mpz_clear(X); - return SBN_OK; -} - -/* ----------------------------- division ----------------------------------- */ - -/* Raw division of immediate don't care about the sign - * since it's up to the caller. - * - * compute: - * 'q' = 'z' / 'd' - * 'r' = 'z' % 'd' - * - * Assume: z >= 0, d > 0, all the arguments must not overlap. - * Arguments overlapping, sign, etc, are handled in mpz_tdiv_qr(). - * 'z' can be statically allocated. - * - * =========================================================================== - * - * I got this algorithm from PGP 2.6.3i (see the mp_udiv function). - * Here is how it works: - * - * Input: N=(Nn,...,N2,N1,N0)radix2 - * D=(Dn,...,D2,D1,D0)radix2 - * Output: Q=(Qn,...,Q2,Q1,Q0)radix2 = N/D - * R=(Rn,...,R2,R1,R0)radix2 = N%D - * - * Assume: N >= 0, D > 0 - * - * For j from 0 to n - * Qj <- 0 - * Rj <- 0 - * For j from n down to 0 - * R <- R*2 - * if Nj = 1 then R0 <- 1 - * if R => D then R <- (R - D), Qn <- 1 - * - * Note that the doubling of R is usually done leftshifting one position. - * The only operations needed are bit testing, bit setting and subtraction. - * - * Unfortunately it is quite slow. The algoritm is not very fast - * and the implementation may be smarter. The good point is that - * it's very simple to implement. - */ -int mpz_divi_qr_raw(mpz_ptr q, mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) -{ - int bit = mpz_bits(z) - 1; - - mpz_zero_realloc(q, z->l-l+1); - mpz_zero_realloc(r, l); - - while(bit >= 0) { - _mpz_self_lshift1_setbit0(r, (_mpz_testbit(z, bit) != 0)); - if (mpz_cmpabsi_raw(r, d, l) >= 0) { - _mpz_normalize(r); - mpz_subi_raw(r, r, d, l); - __mpz_setbit(q, bit); - } - bit--; - } - _mpz_normalize(q); - _mpz_normalize(r); - return SBN_OK; -} - -/* The same as mpz_divi_qr_raw() but only the remainder is computed */ -int mpz_divi_r_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) -{ - int bit = mpz_bits(z) - 1; - - mpz_zero_realloc(r, l); - - while(bit >= 0) { - _mpz_self_lshift1_setbit0(r, (_mpz_testbit(z, bit) != 0)); - if (mpz_cmpabsi_raw(r, d, l) >= 0) { - _mpz_normalize(r); - mpz_subi_raw(r, r, d, l); - } - bit--; - } - _mpz_normalize(r); - return SBN_OK; -} - -/* Wrapper for the real division function - * 'q' = 'z' / 'd' - * 'r' = 'z' % 'd' - * - * Assume that q and r are different pointers. - * d can be statically allocated. - * Relies on the fact that: - * mpz_set() can accept as second argument a statically allocated operator - * mpz_cmpabs() can accept as second argument a statically allocated op. - * mpz_divi_qr() can accept a statically allocated divident. - */ -int mpz_tdiv_qr(mpz_ptr q, mpz_ptr r, mpz_ptr z, mpz_ptr d) -{ - int cmp; - int err; - - if (d->l == 0) /* division by zero */ - return SBN_INVAL; - if (z == d) { - err = mpz_set_ui(q, 1); /* a/a = 1 */ - if (err != SBN_OK) - return err; - mpz_setzero(r); /* a%a = 0 */ - return SBN_OK; - } - cmp = mpz_cmpabs(z, d); - if (cmp < 0) { /* z < d */ - err = mpz_set(r, z); /* a%b = a with as = z->s^d->s; /* the sign is the xor of the two sings */ - r->s = z->s; /* the sign of the remainder is the sign of the divident */ - return mpz_divi_qr_raw(q, r, z, d->d, d->l); -} - -/* The same as mpz_tdiv_qr() but the divisor is a 32bit unsigned immediate */ -int mpz_tdiv_qr_ui(mpz_ptr q, mpz_ptr r, mpz_ptr z, u_int32_t u) -{ - mpz_t mpz; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - return mpz_tdiv_qr(q, r, z, mpz); -} - -/* Like mpz_tdiv_qr_si but with signed integer */ -int mpz_tdiv_qr_si(mpz_ptr q, mpz_ptr r, mpz_ptr z, int32_t s) -{ - mpz_t mpz; - u_int32_t u = (s > 0) ? s : -s; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - mpz->s = s < 0; - return mpz_tdiv_qr(q, r, z, mpz); -} - -/* Like mpz_tdiv_qr but only the remainder is computed */ -int mpz_tdiv_r(mpz_ptr r, mpz_ptr z, mpz_ptr d) -{ - int cmp; - - if (d->l == 0) /* division by zero */ - return SBN_INVAL; - if (z == d) { - mpz_setzero(r); /* a%a = 0 */ - return SBN_OK; - } - cmp = mpz_cmpabs(z, d); - if (cmp < 0) { /* z < d */ - if (r == z) - return SBN_OK; - return mpz_set(r, z); /* a%b = a with as = z->s; /* the sign of the remainder is the sign of the divident */ - return mpz_divi_r_raw(r, z, d->d, d->l); -} - -/* The same as mpz_tdiv_r() but the divisor is a 32bit unsigned immediate */ -int mpz_tdiv_r_ui(mpz_ptr r, mpz_ptr z, u_int32_t u) -{ - mpz_t mpz; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - return mpz_tdiv_r(r, z, mpz); -} - -/* Like the above but with signed integer */ -int mpz_tdiv_r_si(mpz_ptr r, mpz_ptr z, int32_t s) -{ - mpz_t mpz; - u_int32_t u = (s > 0) ? s : -s; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - mpz->s = s < 0; - return mpz_tdiv_r(r, z, mpz); -} - -/* Like mpz_tdiv_qr but only the quotient is computed. - * This is just a wrapper for mpz_tdiv_qr() */ -int mpz_tdiv_q(mpz_ptr q, mpz_ptr z, mpz_ptr d) -{ - int err; - mpz_t r; - - mpz_init(r); - err = mpz_tdiv_qr(q, r, z, d); - mpz_clear(r); - return err; -} - -/* The same as mpz_tdiv_q() but the divisor is a 32bit unsigned immediate */ -int mpz_tdiv_q_ui(mpz_ptr q, mpz_ptr z, u_int32_t u) -{ - mpz_t mpz; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - return mpz_tdiv_r(q, z, mpz); -} - -/* Like the above but with signed integer */ -int mpz_tdiv_q_si(mpz_ptr q, mpz_ptr z, int32_t s) -{ - mpz_t mpz; - u_int32_t u = (s > 0) ? s : -s; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - mpz->s = s < 0; - return mpz_tdiv_r(q, z, mpz); -} - -/* Division by one-atom divident. - * compute z = z / d; - * The remainder is returned. - * - * Assume: z > 0, d > 0 - * Operands overlapping is not allowed */ -mpz_atom_t _mpz_selfdiv1_qr_raw(mpz_ptr z, mpz_atom_t d) -{ - int32_t j; - mpz_carry_t t; - - /* divide */ - for (t = 0, j = z->l-1; j >= 0; j--) { - t = (t << MPZ_SHIFT) + z->d[j]; - z->d[j] = t / d; - t %= d; - } - /* normalize */ - if (!z->d[z->l-1]) - z->l--; - return t; -} - -/* Compute z mod m (modular reduction) */ -int mpz_mod(mpz_ptr r, mpz_ptr z, mpz_ptr m) -{ - int err; - - if (r == m) - _mpz_clone_stack(m); - if ((err = mpz_tdiv_r(r, z, m)) != SBN_OK) - return err; - if (r->l && z->s) { - if (m->s) { - if ((err = mpz_sub(r, r, m)) != SBN_OK) - return err; - } else { - if ((err = mpz_add(r, r, m)) != SBN_OK) - return err; - } - } - return SBN_OK; -} - -/* ---------------------------- assignment ---------------------------------- */ - -/* Set z = 0 - * Note: not GMP compatible */ -int mpz_setzero(mpz_ptr z) -{ - z->s = 0; - return mpz_zero_realloc(z, 0); -} - -/* assign 's' to 'd'. - * 's' can be statically allocated */ -int mpz_set(mpz_ptr d, mpz_ptr s) -{ - int err; - - if ((err = mpz_zero_realloc(d, s->l)) != SBN_OK) - return err; - memcpy(d->d, s->d, s->l*MPZ_ATOMSZ); - d->l = s->l; - d->s = s->s; - return SBN_OK; -} - -/* Like mpz_set() without reallocation. Assume there is enough - * space in d to get the value of s */ -#define _mpz_set(D, S) \ -do { \ - memcpy(D->d, S->d, S->l*MPZ_ATOMSZ); \ - D->l = S->l; \ - D->s = S->s; \ -} while(0) - -/* Set in 'z' the 32bit unsigned integer given as argument */ -int mpz_set_ui(mpz_ptr z, u_int32_t u) -{ - mpz_t mpz; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - return mpz_set(z, mpz); -} - -/* Set in 'z' the double d */ -int mpz_set_d(mpz_ptr z, double d) -{ - int i = 0; - u_int64_t u; - - z->s = (d < 0); - d = (d < 0) ? -d : d; - u = d; - - if (mpz_realloc(z, 8)) - return 1; - while(u) { - z->d[i] = u & MPZ_MASK; - u >>= MPZ_SHIFT; - i++; - } - z->l = i; - return 0; -} - -/* Set in 'z' the 64bit unsigned integer 'u' */ -int mpz_set_ui64(mpz_ptr z, u_int64_t u) -{ - int i = 0; - - z->s = 0; - if (mpz_realloc(z, 8)) - return 1; - while(u) { - z->d[i] = u & MPZ_MASK; - u >>= MPZ_SHIFT; - i++; - } - z->l = i; - return 0; -} - -/* Set in 'z' the 64bit signed integer 's' */ -int mpz_set_si64(mpz_ptr z, int64_t s) -{ - u_int64_t u; - int sign = s < 0, err; - - u = (s > 0) ? s : -s; - if ((err = mpz_set_ui64(z, u)) != SBN_OK) - return err; - z->s = sign; - return err; -} - -/* Set in 'z' the 32bit unsigned integer given as argument */ -int mpz_set_si(mpz_ptr z, int32_t s) -{ - int neg = s < 0; - int err; - u_int32_t u = neg ? -s : s; - mpz_t mpz; - - u32tompz(t,u,l); - u32pack(mpz,t,l); - if ((err = mpz_set(z, mpz))) - return err; - if (neg) - _mpz_neg(z); - return err; -} - -/* set 'd' to ABS('s'). */ -int mpz_abs(mpz_ptr d, mpz_ptr s) -{ - int err; - - if ((d != s) && ((err = mpz_set(d, s)) != SBN_OK)) - return err; - _mpz_abs(d); - return SBN_OK; -} - -/* set 'd' to -'s' */ -int mpz_neg(mpz_ptr d, mpz_ptr s) -{ - int err; - - if ((d != s) && ((err = mpz_set(d, s)) != SBN_OK)) - return err; - _mpz_neg(d); - return SBN_OK; -} - -/* ----------------------- number theoretic functions ----------------------- */ -/* Compute the GCD (greatest common divisor) for 'a' and 'b' using - * the binary GCD algorithm. - * - * 'g' = GCD('|a|', '|b|') - * - * g, a, b can overlap (we anyway need to work on copies of a and b) - * assume a > 0, b > 0. */ -int mpz_gcd_raw(mpz_ptr g, mpz_ptr a, mpz_atom_t *b, u_int32_t l) -{ - u_int32_t maxi = MAX(a->l, l); - mpz_t B, t; - int err; - - /* we need to work on copies. */ - _mpz_clone_stack(a); - _mpz_rawclone_stack(B, b, l); - _mpz_abs(a); - _mpz_abs(B); - /* Reset 'g', prepare to accept up to maxi+1 atoms, set it to 1 */ - if ((err = mpz_zero_realloc(g, maxi)) != SBN_OK) - return err; - g->d[0] = 1; /* after the realloc call there is at least 1 atom */ - g->l = 1; - - /* The binary GCD algorithm */ - mpz_init(t); - - /* While even(a) and even(b) -> a=a/2 b=b/2 g=g*2; */ - while(_mpz_is_even(a) && _mpz_is_even(B)) { - _mpz_self_rshift1(a); - _mpz_self_rshift1(B); - _mpz_self_lshift1(g); - } - /* While a > 0 */ - while(_mpz_nonzero(a)) { - /* While even(a) a=a/2 */ - while(_mpz_is_even(a)) - _mpz_self_rshift1(a); - /* While even(b) b=b/2 */ - while(_mpz_is_even(B)) - _mpz_self_rshift1(B); - /* t = abs(a-b)/2 - * if (a >= b) a = t else b = t */ - if (mpz_cmpabs(a, B) >= 0) { - if ((err = mpz_subi_raw(t, a, B->d, B->l)) != SBN_OK) - goto err; - _mpz_self_rshift1(t); - _mpz_set(a, t); - } else { - if ((err = mpz_subi_raw(t, B, a->d, a->l)) != SBN_OK) - goto err; - _mpz_self_rshift1(t); - _mpz_set(B, t); - } - } - /* GCD = g * b */ - mpz_muli_raw(g, g, B->d, B->l); - err = SBN_OK; - /* fall through */ -err: - mpz_clear(t); - return err; -} - -/* wrapper for mpz_gcd_raw(). set GCD(a, 0) = a */ -int mpz_gcd(mpz_ptr g, mpz_ptr a, mpz_ptr b) -{ - int err; - - if (_mpz_iszero(a)) { - if ((err = mpz_set(g, b)) != SBN_OK) - return err; - _mpz_abs(g); - return SBN_OK; - } - if (_mpz_iszero(b)) { - if ((err = mpz_set(g, a)) != SBN_OK) - return err; - _mpz_abs(g); - return SBN_OK; - } - return mpz_gcd_raw(g, a, b->d, b->l); -} - -/* GCD(a, b) with b unsigned 32bit integer immediate. - * if 'g' is not NULL the result is stored in g. - * if 'g' is NULL and the result fits inside the u_int32_t type - * it is returned. If the result doesn't fit (can happen only if b = 0) - * 0 is returned. */ -u_int32_t mpz_gcd_ui(mpz_ptr g, mpz_ptr a, u_int32_t b) -{ - /* TODO: implement me. */ - ((void) g); - ((void) a); - ((void) b); - return SBN_OK; -} - -/* ----------------------- to/from string conversion ------------------------ */ - -#define sbn_chartoval(c) (r_cset[tolower(c)]) -#define sbn_valtochar(v) (cset[v]) - -/* Extimate the number of bytes needed to store a string rappresentation - * in base 'b' of the number 'z'. The length is overstimated, assuming - * the precision of the C-lib log() is of 6 digits over the dot. - * the length of the minus sign and the nul term are not included */ -size_t mpz_sizeinbase(mpz_ptr z, u_int32_t b) -{ - double len; - - if (b < SBN_MINBASE || b > SBN_MAXBASE) - return SBN_INVAL; - len = ((basetable[b]+0.000001) * z->l) + 1; - return (size_t) len; -} - -/* Convert an mpz_t to a string rappresentation in base 'b' - * Always nul-terminate the string if l > 0. - * - * We use a common trick to speed-up the conversion. - * Instead to perform divisions with remainder between - * the bignum and the specified base, we use a base that's - * the biggest power of the real base. Then we use the CPU - * division to divide by the real base. This limits a lot - * the number of multi-precision divisions, that are slow. - * - * For example converting in base 10, every 10 divisions - * 9 are divisions between two mpz_atom_t vars, and only - * one between a bignum and an mpz_atom_t. - * - * TODO: Note that this is still not very good since we should - * at least handle the case of a base that's power of 2 - * in a special way (i.e. performing shiftings and bitwise - * andings). */ -int mpz_tostr(mpz_ptr z, u_int32_t b, void *s, size_t l) -{ - mpz_t t; - char *d = s, *p; - mpz_atom_t hb, hbn; - - if (b < SBN_MINBASE || b > SBN_MAXBASE) - return SBN_INVAL; - if (!l) - return SBN_OK; - /* Handle z = 0 */ - if (_mpz_iszero(z)) { - *d++ = '0'; - goto done; - } - /* get the biggest power of 'b' that fits in an mpz_atom_t - * and it's exponent from the table. */ - hbn = basepowtable[b].maxexp; - hb = basepowtable[b].maxpow; - l--; - mpz_init(t); - mpz_set(t, z); - while(_mpz_nonzero(t) && l) { - unsigned int i; - mpz_atom_t x; - x = _mpz_selfdiv1_qr_raw(t, (mpz_atom_t) hb); - for (i = 0; (i < hbn) && (l != 0); i++) { - *d++ = sbn_valtochar(x % b); - x /= b; - if (x == 0 && _mpz_iszero(t)) - break; - } - } - mpz_clear(t); -done: - /* add the sign if needed */ - if (l && z->s) - *d++ = '-'; - *d-- = '\0'; - /* reverse the result */ - p = s; - while(p < d) { - char t; - - t = *p; - *p = *d; - *d = t; - d--; - p++; - } - return SBN_OK; -} - -char *mpz_get_str(char *str, int b, mpz_ptr z) -{ - size_t len; - - if (b < SBN_MINBASE || b > SBN_MAXBASE) - return NULL; - - len = mpz_sizeinbase(z, b) + 2; - if (!str && ((str = malloc(len)) == NULL)) - return NULL; - mpz_tostr(z, b, str, len); - return str; -} - -/* set in 'z' the ascii rappresentation in 's' of the number in base 'b' - * - * On error the original value of 'z' is not guaranteed to be the same - * as before this function is called. - * - * Again possible optimizations are not implemented. Most notably - * the base power of 2 case. - */ -int mpz_set_str(mpz_ptr z, char *s, int b) -{ - size_t len = strlen(s); - char *t = s + len - 1; - int neg = 0, err; - mpz_t pow, toadd; - - /* seek the first non-blank char from the head */ - while(*s && isspace(*s)) { - s++; - len--; - } - /* check if the number is negative */ - if (len && *s == '-') { - neg = 1; - s++; - len--; - } - /* guess the base */ - if (b == 0) { - b = 10; - if (len && *s == '0') { - b = 8; - s++; - len--; - if (len && tolower(*s) == 'x') { - b = 16; - s++; - len--; - } else if (len && tolower(*s) == 'b') { - b = 2; - s++; - len--; - } - } - } - if (b < SBN_MINBASE || b > SBN_MAXBASE) - return SBN_INVAL; - /* seek the first non-blank char from the tail */ - while(t > s && isspace(*t)) - t--; - /* convert it */ - mpz_init(pow); - mpz_init(toadd); - mpz_zero(z); - if ((err = mpz_set_ui(pow, 1)) != SBN_OK) - return err; - while(t >= s) { - int digit; - - digit = sbn_chartoval(*t); - if (digit < 0 || digit >= b) { - err = SBN_INVAL; - goto error; - } - mpz_set_ui(toadd, digit); - if ((err = mpz_mul(toadd, toadd, pow)) != SBN_OK) - goto error; - if ((err = mpz_add(z, z, toadd)) != SBN_OK) - goto error; - if ((err = mpz_mul_ui(pow, pow, b)) != SBN_OK) - goto error; - t--; - } - z->s = neg; - err = SBN_OK; - /* fall through */ -error: - mpz_clear(pow); - mpz_clear(toadd); - return err; -} - -/* ------------------------------- random numbers --------------------------- */ - -/* The rc4_sbox array is static, but this doesn't mean you can't use this - * library with threads. To create a real context for every random - * generation session is an overkill here */ -static unsigned char rc4_sbox[256]; -/* We want to start every time with the same seed. This is very - * important when some random number trigger multi-precision operations - * bugs. This flags is used to initialize the sbox the first time */ -static int rc4_seedflag = 0; - -/* Initialize the sbox with the numbers from 0 to 255 */ -void sbn_rand_init(void) -{ - int i; - - rc4_seedflag = 1; - for (i = 0; i < 256; i++) - rc4_sbox[i] = i; -} - -/* Re-seed the generator with user-provided bytes */ -void sbn_seed(void *seed, size_t len) -{ - int i; - unsigned char *s = (unsigned char*)seed; - - for (i = 0; i < len; i++) - rc4_sbox[i&0xFF] ^= s[i]; - /* discard the first 256 bytes of output after the reseed */ - for (i = 0; i < 32; i++) - (void) sbn_rand(); -} - -/* Generates a 32bit random number using an RC4-like algorithm */ -u_int32_t sbn_rand(void) -{ - u_int32_t r = 0; - unsigned char *rc = (unsigned char*) &r; - static unsigned int i = 0, j = 0; - unsigned int si, sj, x; - - /* initialization, only needed the first time */ - if (!rc4_seedflag) - sbn_rand_init(); - /* generates 4 bytes of pseudo-random numbers using RC4 */ - for (x = 0; x < 4; x++) { - i = (i+1) & 0xff; - si = rc4_sbox[i]; - j = (j + si) & 0xff; - sj = rc4_sbox[j]; - rc4_sbox[i] = sj; - rc4_sbox[j] = si; - *rc++ = rc4_sbox[(si+sj)&0xff]; - } - return r; -} - -/* Generate a random number of at most 'len' atoms length. - * If 'len' is negative the number will be negative of length abs(len) */ -int mpz_random(mpz_ptr z, int32_t len) -{ - int i, err, sign = 0; - - if (len < 0) { - sign = 1; - len = -len; - } - if (!len) - return mpz_setzero(z); - if ((err = mpz_realloc(z, len-1)) != SBN_OK) - return err; - for (i = 0; i < len; i++) - z->d[i] = sbn_rand() & MPZ_MASK; - _mpz_normalize(z); - z->s = sign; - return SBN_OK; -} - -/* Convert the bignum to approsimated double */ -double mpz_get_d(mpz_ptr z) -{ - double d = 0; - u_int32_t l = z->l; - - while(l--) - d = z->d[l] + d*MPZ_BASE; - if (z->s) - d = -d; - return d; -} diff --git a/scan.c b/scan.c deleted file mode 100644 index ffba002..0000000 --- a/scan.c +++ /dev/null @@ -1,552 +0,0 @@ -/* Scanner mode for hping2 - * Copyright(C) 2003 Salvatore Sanfilippo - * All rights reserved */ - -/* TODO: - * an application-level aware UDP scanner. - * add ICMP handling in replies. - * The algorithm is far from be optimal, also there isn't a clear - * way to delay smaller amounts of time then usleep(1) without - * to use a dummy loop. - * */ - -/* $Id: scan.c,v 1.3 2003/10/22 10:41:00 antirez Exp $ */ - -#include -#include -#include -#include -#if 0 -#include -#endif -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#if 0 -#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) -/* union semun is defined by including */ -#else -/* according to X/OPEN we have to define it ourselves */ -union semun { - int val; /* value for SETVAL */ - struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ - unsigned short int *array; /* array for GETALL, SETALL */ - struct seminfo *__buf; /* buffer for IPC_INFO */ -}; -#endif -#endif - -#include "hping2.h" -#include "globals.h" -#include "hstring.h" - -#define SEM_MODE 0777 -#define MAXPORT 65535 - -int opt_scan_probes = 8; -float avrgms = 0; -int avrgcount = 0; - -/* ---------------------------- data structures ----------------------------- */ - -/* Note that while we don't use any kind of locking, to access - * this fields is safe. the 'retry' field is only accessed by the - * sendinf half, while the 'active' field is set by the receiver - * and tested by the sender so atomicity isn't an issue. */ -struct portinfo { - int active; - int retry; - time_t sentms; /* Upss... added this that requires locking, FIXME */ -}; - -/* ------------------------- shared memory related -------------------------- */ - -static int id; /* shared memory id */ - -static int shm_creat(int size) -{ - id = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777); - if (id == -1) - { - perror("[shm_creat] shmget"); - return -1; /* on error -1 */ - } - return id; /* on success > 0 */ -} - -static void *shm_attach(void) -{ - void *shared; - - shared = shmat(id, 0, 0); - if (shared == (void*) -1) - { - perror("[shm_attach] shmat"); - return NULL; /* on error NULL */ - } - return shared; /* on success the address */ -} - -static int shm_rm(void) -{ - struct shmid_ds shmemds; - - return shmctl(id, IPC_RMID, &shmemds); -} - -static int shm_detach(void *addr) -{ - return shmdt(addr); -} - -static void *shm_init(int size) -{ - if (shm_creat(size) == -1) - return NULL; - return shm_attach(); -} - -static void shm_close(void *addr) -{ - shm_detach(addr); - shm_rm(); -} - -/* ------------------------------ locking ---------------------------------- */ - -/* Note that a mutex can't be used with shared memory (on Linux), the only left - * option is a semaphore, but I tried to protect the critical code - * using the functions above: the scanner becomes too slow. For now - * it's better to have nothing at all, for the future we need something - * like a spinlock. (btw, note that the code should be safe on x86) */ - -/* I left this code here, just in the case it will be useful for testing */ -#if 0 -static int sem_init(void) -{ - int semid, sem_key; - - if ((sem_key = ftok("/tmp/hpingscansem", 1)) == -1) { - perror("ftok"); - exit(1); - } - - /* Semi-safe semaphore initialization from R.Stevens */ - - /* Try to create the semaphore with EXCL */ - if ((semid = semget(sem_key, 1, IPC_CREAT|IPC_EXCL|SEM_MODE)) != -1) { - /* success, we need to initialize it */ - union semun arg; - - arg.val = 1; - if (semctl(semid, 0, SETVAL, arg) == -1) { - perror("semctl"); - exit(1); - } - } else if (errno == EEXIST) { - if ((semid = semget(sem_key, 1, SEM_MODE)) == -1) { - perror("semget"); - exit(1); - } - } else { - perror("semget"); - exit(1); - } - return semid; -} - -static int ports_lock(int semid) -{ - struct sembuf op[1]; - - op[0].sem_num = 0; - op[0].sem_op = -1; - op[0].sem_flg = SEM_UNDO; - return semop(semid, op, 1); -} - -static int ports_unlock(int semid) -{ - struct sembuf op[1]; - - op[0].sem_num = 0; - op[0].sem_op = +1; - op[0].sem_flg = SEM_UNDO; - return semop(semid, op, 1); -} -#endif - -/* -------------------------------- misc ----------------------------------- */ -static char *tcp_strflags(char *s, unsigned int flags) -{ - char *ftab = "FSRPAYXY", *p = s; - int bit = 0; - - memset(s, '.', 8); - s[8] = '\0'; - while(bit < 8) { - if (flags & (1 << bit)) - p[bit] = ftab[bit]; - bit++; - } - return s; -} - -static char *port_to_name(int port) -{ - struct servent *se; - - se = getservbyport(htons(port), NULL); - if (!se) - return ""; - else - return se->s_name; -} - -/* ----------------------------- ports parsing ------------------------------ */ -static int parse_ports(struct portinfo *pi, char *ports) -{ - char *args[32], *p = strdup(ports); - int argc, j, i; - - if (!p) { - fprintf(stderr, "Out of memory"); - return 1; - } - argc = strftok(",", ports, args, 32); - for (j = 0; j < argc; j++) { - int neg = 0; - char *a = args[j]; - - /* ports negation */ - if (a[0] == '!') { - neg = 1; - a++; - } - /* range */ - if (strchr(a, '-')) { - char *range[2]; - int low, high; - - strftok("-", a, range, 2); - if (!strisnum(range[0]) || !strisnum(range[1])) - goto err; /* syntax error */ - low = strtol(range[0], NULL, 0); - high = strtol(range[1], NULL, 0); - if (low > high) { - int t; - t = high; - high = low; - low = t; - } - for (i = low; i <= high; i++) - pi[i].active = !neg; - /* all the ports */ - } else if (!strcmp(a, "all")) { - for (i = 0; i <= MAXPORT; i++) - pi[i].active = !neg; - /* /etc/services ports */ - } else if (!strcmp(a, "known")) { - struct servent *se; - setservent(0); - while((se = getservent()) != NULL) { - int port = ntohs(se->s_port); - if (port < 0 || port > MAXPORT) - continue; - pi[port].active = !neg; - } - /* a single port */ - } else { - int port; - if (!strisnum(a)) - goto err; /* syntax error */ - port = strtol(a, NULL, 0); - if (port < 0 || port > MAXPORT) - goto err; /* syntax error */ - pi[port].active = !neg; - } - } - free(p); - return 0; -err: - free(p); - return 1; -} - -/* -------------------------------- output ---------------------------------- */ -static void sender(struct portinfo *pi) -{ - int i, retry = 0; - time_t start_time; - - start_time = get_midnight_ut_ms(); - - while(1) { - int active = 0; - int recvd = 0; - retry ++; - for (i = 0; i < MAXPORT; i++) { - if (pi[i].active && pi[i].retry) { - active++; - pi[i].retry--; - sequence = -1; - dst_port = i; - pi[i].sentms = get_midnight_ut_ms(); - send_tcp(); - if (opt_waitinusec) { - if (usec_delay.it_interval.tv_usec) - usleep(usec_delay.it_interval.tv_usec); - } else { - sleep(sending_wait); - } - } - } - avrgms = (float) pi[MAXPORT+1].active; - if (retry >= 3) { - if (opt_debug) - printf("AVRGMS %f\n", avrgms); - if (avrgms) - usleep((int) (avrgms*1000)); - else - sleep(1); - } - for (i = 0; i < MAXPORT; i++) { - if (!pi[i].active && pi[i].retry) - recvd++; - } - /* More to scan? */ - if (!active) { - if (!recvd) - sleep(1); - fprintf(stderr, "All replies received. Done.\n"); - printf("Not responding ports: "); - for (i = 0; i < MAXPORT; i++) { - if (pi[i].active && !pi[i].retry) - printf("(%d %.11s) ", i, port_to_name(i)); - } - printf("\n"); - exit(0); - } - /* Are we sending too fast? */ - if ((!recvd && opt_waitinusec && - usec_delay.it_interval.tv_usec == 0 && - (get_midnight_ut_ms() - start_time) > 500) || - (opt_scan_probes-retry) <= 2) - { - if (opt_debug) - printf("SLOWING DONW\n"); - usec_delay.it_interval.tv_usec *= 10; - usec_delay.it_interval.tv_usec ++; - } - } -} - -/* -------------------------------- input ---------------------------------- */ -static void receiver(struct portinfo *pi, int childpid) -{ - struct myiphdr ip; - char packet[IP_MAX_SIZE+linkhdr_size]; - - while(1) - { - int len, iplen; - - len = read_packet(packet, IP_MAX_SIZE+linkhdr_size); - if (len == -1) { - perror("read_packet"); - continue; - } - /* minimal sanity checks */ - if (len < linkhdr_size) - continue; - iplen = len - linkhdr_size; - if (iplen < sizeof(struct myiphdr)) - continue; - /* copy the ip header in an access-safe place */ - memcpy(&ip, packet+linkhdr_size, sizeof(ip)); - /* check if the dest IP matches */ - if (memcmp(&ip.daddr, &local.sin_addr, sizeof(ip.daddr))) - continue; - /* check if the source IP matches */ - if (ip.protocol != IPPROTO_ICMP && - memcmp(&ip.saddr, &remote.sin_addr, sizeof(ip.saddr))) - continue; - if (ip.protocol == IPPROTO_TCP) { - struct mytcphdr tcp; - int iphdrlen = ip.ihl << 2; - char flags[16]; - time_t rttms; - int sport; - - /* more sanity checks */ - if ((iplen - iphdrlen) < sizeof(tcp)) - continue; - /* time to copy the TCP header in a safe place */ - memcpy(&tcp, packet+linkhdr_size+iphdrlen, sizeof(tcp)); - - /* check if the TCP dest port matches */ -#if 0 - printf("SRC: %d DST: %d\n", - ntohs(tcp.th_sport), - ntohs(tcp.th_dport)); -#endif - if (ntohs(tcp.th_dport) != initsport) - continue; - sport = htons(tcp.th_sport); - if (pi[sport].active == 0) - continue; - - - /* Note that we don't care about a wrote RTT - * result due to resend on the same port. */ - rttms = get_midnight_ut_ms() - pi[sport].sentms; - - avrgcount++; - avrgms = (avrgms*(avrgcount-1)/avrgcount)+(rttms/avrgcount); - /* The avrg RTT is shared using shared memory, - * no locking... */ - pi[MAXPORT+1].active = (int) avrgms; - - tcp_strflags(flags, tcp.th_flags); -#if 0 - printf("%5d: %s %3d %5d %5d %10ld (%2d)\n", - sport, - flags, - ip.ttl, - ip.id, - ntohs(tcp.th_win), - (long) rttms, - opt_scan_probes-(pi[sport].retry)); -#endif - if ((tcp.th_flags & TH_SYN) || opt_verbose) { - printf("%5d %-11.11s: %s %3d %5d %5d %5d\n", - sport, - port_to_name(sport), - flags, - ip.ttl, - ip.id, - ntohs(tcp.th_win), - iplen); - fflush(stdout); - } - pi[sport].active = 0; - } else if (ip.protocol == IPPROTO_ICMP) { - struct myicmphdr icmp; - struct myiphdr subip; - struct mytcphdr subtcp; - int iphdrlen = ip.ihl << 2; - unsigned char *p; - int port; - struct in_addr gwaddr; - - /* more sanity checks, we are only interested - * in ICMP quoting the original packet. */ - if ((iplen - iphdrlen) < sizeof(icmp)+sizeof(subip)+sizeof(subtcp)) - continue; - /* time to copy headers in a safe place */ - p = (unsigned char*) packet+linkhdr_size+iphdrlen; - memcpy(&icmp, p, sizeof(subtcp)); - p += sizeof(icmp); - memcpy(&subip, p, sizeof(ip)); - p += sizeof(ip); - memcpy(&subtcp, p, sizeof(subtcp)); - - /* Check if the ICMP quoted packet matches */ - /* check if the source IP matches */ - if (memcmp(&subip.saddr, &local.sin_addr, sizeof(subip.saddr))) - continue; - /* check if the destination IP matches */ - if (memcmp(&subip.daddr, &remote.sin_addr, sizeof(subip.daddr))) - continue; - /* check if the quoted TCP packet port matches */ - if (ntohs(subtcp.th_sport) != initsport) - continue; - port = htons(subtcp.th_dport); - if (pi[port].active == 0) - continue; - pi[port].active = 0; - memcpy(&gwaddr.s_addr, &ip.saddr, 4); - printf("%5d: %3d %5d %5d (ICMP %3d %3d from %s)\n", - port, - ip.ttl, - iplen, - ntohs(ip.id), - icmp.type, - icmp.code, - inet_ntoa(gwaddr)); - } - } -} - -/* ---------------------------------- main ---------------------------------- */ -static void do_exit(int sid) -{ - exit(0); -} - -void scanmain(void) -{ - struct portinfo *pi; - int ports = 0, i; - int childpid; - - pi = shm_init(sizeof(*pi)*(MAXPORT+2)); - pi[MAXPORT+1].active = 0; /* hold the average RTT */ - if (pi == NULL) { - fprintf(stderr, "Unable to create the shared memory"); - shm_close(pi); - exit(1); - } - for (i = 0; i <= MAXPORT; i++) { - pi[i].active = 0; - pi[i].retry = opt_scan_probes; - } - if (parse_ports(pi, opt_scanports)) { - fprintf(stderr, "Ports syntax error for scan mode\n"); - shm_close(pi); - exit(1); - } - for (i = 0; i <= MAXPORT; i++) { - if (!pi[i].active) - pi[i].retry = 0; - } - for (i = 0; i <= MAXPORT; i++) - ports += pi[i].active; - fprintf(stderr, "%d ports to scan, use -V to see all the replies\n", ports); - fprintf(stderr, "+----+-----------+---------+---+-----+-----+-----+\n"); - fprintf(stderr, "|port| serv name | flags |ttl| id | win | len |\n"); - fprintf(stderr, "+----+-----------+---------+---+-----+-----+-----+\n"); - - /* We are ready to fork, the input and output parts - * are separated processes */ - if ((childpid = fork()) == -1) { - perror("fork"); - shm_close(pi); - exit(1); - } - /* The parent is the receiver, the child the sender. - * it's almost the same but this way is simpler - * to make it working in pipe with other commands like grep. */ - if (childpid) { /* parent */ - Signal(SIGCHLD, do_exit); - Signal(SIGINT, do_exit); - Signal(SIGTERM, do_exit); - receiver(pi, childpid); - } else { /* child */ - Signal(SIGINT, do_exit); - Signal(SIGTERM, do_exit); - sender(pi); - } - /* UNREACHED */ -} diff --git a/script.c b/script.c deleted file mode 100644 index 124370c..0000000 --- a/script.c +++ /dev/null @@ -1,1360 +0,0 @@ -/* Hping's TCL scripting support - * Copyright (C) 2003 Salvatore Sanfilippo - * All Rights Reserved */ - -/* URGENT TODO: - * - * link header size in recv_handlers, -1 means autodetection. */ - -/* $Id: script.c,v 1.20 2004/05/29 06:48:13 antirez Exp $ */ - -#ifdef USE_TCL - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "release.h" -#include "hping2.h" -#include "ars.h" -#include "interface.h" -#include "apdutils.h" -#include "sbignum.h" - -#define HPING_IF_MAX 8 - -/* ----------------------- hping recv handlers code ------------------------- */ -struct recv_handler { - Tcl_Interp *rh_interp; /* If not null has [hpingevent] handler. */ - Tcl_Obj *rh_handlerscript; /* the [hpingevent] handler script. */ - char rh_ifname[HPING_IFNAME_LEN]; - int rh_linkhdrsize; /* -1 means autodetection */ - pcap_t *rh_pcapfp; - char rh_pcap_errbuf[PCAP_ERRBUF_SIZE]; -}; - -struct recv_handler recv_handlers[HPING_IFACE_MAX]; - -/* Recv handlers intialization */ -static void HpingRecvInit(struct recv_handler *ra, int len) -{ - memset(ra, 0, sizeof(*ra)*len); -} - -static void HpingRecvCloseHandler(struct recv_handler *ra) -{ - ra->rh_ifname[0] = '\0'; - if (ra->rh_interp != NULL) { - Tcl_DeleteFileHandler(pcap_fileno(ra->rh_pcapfp)); - Tcl_DecrRefCount(ra->rh_handlerscript); - } - pcap_close(ra->rh_pcapfp); - ra->rh_interp = NULL; -} - -static struct recv_handler *HpingRecvGetHandler(struct recv_handler *ra, int len, char *ifname, Tcl_Interp *interp) -{ - int i; - #if (!defined OSTYPE_LINUX) && (!defined __sun__) - int on = 1; - #endif - - for (i = 0; i < len; i++) { - if (!ra[i].rh_ifname[0]) - break; - if (!strcmp(ra[i].rh_ifname, ifname)) - return ra+i; - } - /* Not found, need to open it */ - if (i == len) { - /* XXX: with hping setfilter this is broken */ - /* All the slots are full, make space at the end */ - HpingRecvCloseHandler(ra+(len-1)); - i--; - } - /* Open a new handler */ - ra[i].rh_pcapfp = pcap_open_live(ifname, 99999, 0, 1, ra[i].rh_pcap_errbuf); - if (ra[i].rh_pcapfp == NULL) - return NULL; - #if (!defined OSTYPE_LINUX) && (!defined __sun__) - /* Return the packets to userspace as fast as possible */ - if (ioctl(pcap_fileno(ra[i].rh_pcapfp), BIOCIMMEDIATE, &on) == -1) { - /* XXX non-critical error */ - } - #endif - strlcpy(ra[i].rh_ifname, ifname, HPING_IFNAME_LEN); - ra[i].rh_interp = NULL; - ra[i].rh_linkhdrsize = dltype_to_lhs(pcap_datalink(ra[i].rh_pcapfp)); - return ra+i; -} - -/* ----------------------------- Sub commands ------------------------------- */ -/* hping resolve hostname */ -static int HpingResolveCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - struct sockaddr_in saddr; - char *hostname; - Tcl_Obj *result; - - result = Tcl_GetObjResult(interp); - if (objc != 3 && objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "?-ptr? hostname"); - return TCL_ERROR; - } - if (objc == 4) { - char *ptropt, *ipaddr; - struct in_addr ina; - struct hostent *he; - - ptropt = Tcl_GetStringFromObj(objv[2], NULL); - if (strcmp(ptropt, "-ptr")) { - Tcl_SetStringObj(result, "The only valid option for resolve is -ptr", -1); - return TCL_ERROR; - } - ipaddr = Tcl_GetStringFromObj(objv[3], NULL); - if (inet_aton(ipaddr, &ina) == 0) { - Tcl_SetStringObj(result, "Invalid IP address: ", -1); - Tcl_AppendStringsToObj(result, ipaddr, NULL); - return TCL_ERROR; - } - he = gethostbyaddr((const char*)&ina.s_addr, sizeof(ina.s_addr), AF_INET); - if (he == NULL) - Tcl_SetStringObj(result, ipaddr, -1); - else - Tcl_SetStringObj(result, he->h_name, -1); - return TCL_OK; - } - hostname = Tcl_GetStringFromObj(objv[2], NULL); - if (resolve_addr((struct sockaddr*)&saddr, hostname) != -1) { - Tcl_SetStringObj(result, inet_ntoa(saddr.sin_addr), -1); - return TCL_OK; - } else { - Tcl_SetStringObj(result, "Unable to resolve: ", -1); - Tcl_AppendStringsToObj(result, hostname, NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* raw socket is shared between different functions, but note - * that it gets open only once needed. This makes possible - * to run hping scripts doing unprivileged work without root - * access. */ -static int rawsocket = -1; - -/* hping send ?-nocompile? pktdescr */ -static int HpingSendCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - struct ars_packet p; - int nocompile = 0; - Tcl_Obj *result; - char *packetdescr, *noc; - - if (objc != 3 && objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "?-nocompile? packet"); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - if (objc == 4) { - noc = Tcl_GetStringFromObj(objv[2], NULL); - if (strcmp(noc, "-nocompile")) { - Tcl_SetStringObj(result, "Invalid option", -1); - return TCL_ERROR; - } - nocompile = 1; - objv++; - } - ars_init(&p); - packetdescr = Tcl_GetStringFromObj(objv[2], NULL); - if (rawsocket == -1) { - rawsocket = ars_open_rawsocket(&p); - if (rawsocket == -ARS_ERROR) { - Tcl_SetStringObj(result, "Error opening raw socket: ", -1); - Tcl_AppendStringsToObj(result, strerror(errno), NULL); - ars_destroy(&p); - return TCL_ERROR; - } - } - if (ars_d_build(&p, packetdescr) != -ARS_OK) { - Tcl_SetStringObj(result, "Packet building error: '", -1); - Tcl_AppendStringsToObj(result, p.p_error,"' in packet ", packetdescr, NULL); - ars_destroy(&p); - return TCL_ERROR; - } - if (!nocompile) { - if (ars_compile(&p) != -ARS_OK) { - Tcl_SetStringObj(result, "Packet compilation error: ", -1); - Tcl_AppendStringsToObj(result, p.p_error, NULL); - ars_destroy(&p); - return TCL_ERROR; - } - } - if (ars_send(rawsocket, &p, NULL, 0) != -ARS_OK) { - Tcl_SetStringObj(result, "Sending packet: ", -1); - Tcl_AppendStringsToObj(result, strerror(errno), NULL); - ars_destroy(&p); - return TCL_ERROR; - } - ars_destroy(&p); - return TCL_OK; -} - -/* hping sendraw pktdata */ -static int HpingSendRawCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - int error; - Tcl_Obj *result; - struct sockaddr_in sa; - char *pkt; - int pktlen; - struct ars_iphdr *ip; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "data"); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - /* Get packet data */ - pkt = Tcl_GetStringFromObj(objv[2], &pktlen); - /* Check if the packet is too short */ - if (pktlen < sizeof(struct ars_iphdr)) { - Tcl_SetStringObj(result, "Packet shorter than IPv4 header", -1); - return TCL_ERROR; - } - ip = (struct ars_iphdr*) pkt; - /* Get the destination IP from the packet itself */ - sa.sin_family = AF_INET; - memcpy(&sa.sin_addr.s_addr, &ip->daddr, 4); - /* Open the rawsocket if needed */ - if (rawsocket == -1) { - rawsocket = ars_open_rawsocket(NULL); - if (rawsocket == -ARS_ERROR) { - Tcl_SetStringObj(result, "Error opening raw socket: ", -1); - Tcl_AppendStringsToObj(result, strerror(errno), NULL); - return TCL_ERROR; - } - } - /* ready to send */ - error = sendto(rawsocket, pkt, pktlen, 0, (struct sockaddr*)&sa, sizeof(sa)); - if (error == -1) { - Tcl_SetStringObj(result, "sendto(2): ", -1); - Tcl_AppendStringsToObj(result, strerror(errno), NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -#define APD_MAX_LEN (65536*2+4096) -char *GetPacketDescription(char *data, int len, int hexdata) -{ - unsigned char *p = (char*)data; - struct ars_packet pkt; - char *d = malloc(APD_MAX_LEN); - char *ret; - - ars_init(&pkt); - if (hexdata) { - ars_set_option(&pkt, ARS_OPT_RAPD_HEXDATA); - } - if (ars_split_packet(p, len, 0, &pkt) != -ARS_OK) { - /* FIXME: handle this error properly */ - } - if (ars_d_from_ars(d, APD_MAX_LEN, &pkt) != -ARS_OK) { - /* FIXME: handle this error properly */ - } - ars_destroy(&pkt); - ret = strdup(d); - free(d); - return ret; -} - -/* Read a packet with a given timeout. - * The function returns -1 on error, non zero on a successful - * read, and 0 when no error occurred but the read must be - * reiterated (possibly before timeout expired). - * - * A zero timeout is valid, and means returns a packet if - * it is already in the buffer. A negative timeout of -1 - * means to wait forever. */ -int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *); /* pcap-int.h */ - -static int HpingReadPacket(struct recv_handler *ra, char *pkt, int pktlen, int timeout) -{ - struct timeval tv; - int retval, fd = pcap_fileno(ra->rh_pcapfp); - struct pcap_pkthdr hdr; - const unsigned char *d; - fd_set fs; - - if (timeout >= 0) { - tv.tv_sec = timeout/1000; - tv.tv_usec = (timeout%1000)*1000; - } - FD_ZERO(&fs); - FD_SET(fd, &fs); - if (timeout >= 0) - retval = select(fd+1, &fs, NULL, NULL, &tv); - else - retval = select(fd+1, &fs, NULL, NULL, NULL); - if (retval == -1) { - if (errno == EINTR) - return 0; - return -1; - } else if (retval == 0) { - return 0; - } - d = pcap_next(ra->rh_pcapfp, &hdr); - if (d == NULL) - return 0; - if (hdr.caplen > pktlen) - hdr.caplen = pktlen; - memcpy(pkt, d, hdr.caplen); - return hdr.caplen; -} - -static int HpingRecvPackets(struct recv_handler *ra, Tcl_Interp *interp, Tcl_Obj *o, int timeout, int maxpackets, int rapd, int hexdata) -{ - time_t startms = milliseconds(); - char _pkt[65535+255]; - char *pkt = _pkt; - int lhs = ra->rh_linkhdrsize; - - while(1) { - time_t elapsed; - int len; - - len = HpingReadPacket(ra, pkt, 65535+255, timeout); - if (len > 0) { - Tcl_Obj *element; - - /* Skip the link header */ - pkt += lhs; - len -= lhs; - /* Create the entry */ - if (rapd) { - char *apd; - - apd = GetPacketDescription(pkt, len, hexdata); - if (!apd) - return 1; - element = Tcl_NewStringObj(apd, -1); - free(apd); - } else { - element = Tcl_NewStringObj(pkt, len); - } - Tcl_ListObjAppendElement(interp, o, element); - /* Check if we reached the packets limit */ - if (maxpackets) { - maxpackets--; - if (maxpackets == 0) - return 0; - } - } - if (timeout == 0 && len != 0) - continue; - if (timeout >= 0) { - elapsed = milliseconds() - startms; - if (elapsed > timeout) - break; - } - } - return 0; -} - -/* hping (recv|recvraw) ifname ?timeout? ?maxpackets? - * A zero timeout means to return only packets already in queue - * A negative timeout means to wait forever - * A zero maxpackets means infinite packets limit. - * - * For default timeout is -1, maxpackets is 0 */ -static int __HpingRecvCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[], int rapd, int hexdata) -{ - Tcl_Obj *result; - struct recv_handler *ra; - char *ifname; - int timeout = -1; /* specified in ms */ - int maxpackets = 1; - - if (objc != 3 && objc != 4 && objc != 5) { - Tcl_WrongNumArgs(interp, 2, objv, "ifname ?timeout? ?maxpackets?"); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - ifname = Tcl_GetStringFromObj(objv[2], NULL); - if (objc >= 4) - Tcl_GetIntFromObj(interp, objv[3], &timeout); - if (objc == 5) - Tcl_GetIntFromObj(interp, objv[4], &maxpackets); - /* FIXME: check if maxpacket == 0 AND timeout == -1. In such - * a case the function will never return. */ - ra = HpingRecvGetHandler(recv_handlers, HPING_IFACE_MAX, ifname, interp); - if (ra == NULL) { - Tcl_SetStringObj(result, "Unable to open the interface", -1); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - if (HpingRecvPackets(ra, interp, result, timeout, maxpackets, rapd, hexdata)) - return TCL_ERROR; - return TCL_OK; -} - -/* The two wrappers for the __HpingRecvRawCmd() */ -static int HpingRecvRawCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - return __HpingRecvCmd(clientData, interp, objc, objv, 0, 0); -} - -static int HpingRecvCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - char *firstarg; - int hexdata = 0; - - if (objc >= 3) { - firstarg = Tcl_GetStringFromObj(objv[2], NULL); - if (!strcmp(firstarg, "-hexdata")) { - hexdata = 1; - objc--; - objv++; - } - } - return __HpingRecvCmd(clientData, interp, objc, objv, 1, hexdata); -} - -/* hping getinterfaces */ -static int HpingGetInterfacesCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - struct hpingif ifaces[HPING_IFACE_MAX]; - int found, i; - Tcl_Obj *result; - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 2, objv, ""); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - found = hping_get_interfaces(ifaces, HPING_IFACE_MAX); - if (found == -1) { - Tcl_SetStringObj(result, "Listing interfaces: ", -1); - Tcl_AppendStringsToObj(result, strerror(errno), NULL); - return TCL_ERROR; - } - for (i = 0; i < found; i++) { - struct in_addr ia; - char mtu[32]; - int j, flags = 0; - - snprintf(mtu, 32, "%d", ifaces[i].hif_mtu); - Tcl_AppendStringsToObj(result, "{", - ifaces[i].hif_name, " ", - mtu, " ", NULL); - Tcl_AppendStringsToObj(result, "{", NULL); - for (j = 0; j < ifaces[i].hif_naddr; j++) { - ia.s_addr = ifaces[i].hif_addr[j]; - Tcl_AppendStringsToObj(result, inet_ntoa(ia), NULL); - if ((j+1) < ifaces[i].hif_naddr) - Tcl_AppendStringsToObj(result, " ", NULL); - } - Tcl_AppendStringsToObj(result, "}", NULL); - if (ifaces[i].hif_broadcast) { - Tcl_AppendStringsToObj(result, " {", NULL); - for (j = 0; j < ifaces[i].hif_naddr; j++) { - ia.s_addr = ifaces[i].hif_baddr[j]; - Tcl_AppendStringsToObj(result, inet_ntoa(ia), NULL); - if ((j+1) < ifaces[i].hif_naddr) - Tcl_AppendStringsToObj(result, " ", NULL); - } - Tcl_AppendStringsToObj(result, "} {", NULL); - } else { - Tcl_AppendStringsToObj(result, " {} {", NULL); - } - if (ifaces[i].hif_loopback) { - Tcl_AppendStringsToObj(result, flags ? " " : "", "LOOPBACK", NULL); - flags++; - } - if (ifaces[i].hif_ptp) { - Tcl_AppendStringsToObj(result, flags ? " " : "", "POINTOPOINT", NULL); - flags++; - } - if (ifaces[i].hif_promisc) { - Tcl_AppendStringsToObj(result, flags ? " " : "", "PROMISC", NULL); - flags++; - } - if (ifaces[i].hif_broadcast) { - Tcl_AppendStringsToObj(result, flags ? " " : "", "BROADCAST", NULL); - flags++; - } - if (ifaces[i].hif_nolink) { - Tcl_AppendStringsToObj(result, flags ? " " : "", "NOLINK", NULL); - flags++; - } - Tcl_AppendStringsToObj(result, "}} ", NULL); - } - return TCL_OK; -} - -/* hping outifaddr destaddr */ -static int HpingGetOutIfAddrCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - struct sockaddr_in dest, ifaddr; - Tcl_Obj *result; - char *deststr; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "destaddr"); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - deststr = Tcl_GetStringFromObj(objv[2], NULL); - if (resolve_addr((struct sockaddr*)&dest, deststr) == -1) { - Tcl_SetStringObj(result, "Unable to resolve: ", -1); - Tcl_AppendStringsToObj(result, deststr, NULL); - return TCL_ERROR; - } - if (get_output_if(&dest, &ifaddr) == -1) { - Tcl_SetStringObj(result, "Can't get output interface: ", -1); - Tcl_AppendStringsToObj(result, strerror(errno), NULL); - return TCL_ERROR; - } - Tcl_SetStringObj(result, inet_ntoa(ifaddr.sin_addr), -1); - return TCL_OK; -} - -/* hping getfield layer field ?skip? packet */ -static int HpingGetFieldCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - char *layer, *field, *value, *packet; - int skip = 0; - Tcl_Obj *result; - - if (objc != 5 && objc != 6) { - Tcl_WrongNumArgs(interp, 2, objv, "layer field ?skip? packet"); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - layer = Tcl_GetStringFromObj(objv[2], NULL); - field = Tcl_GetStringFromObj(objv[3], NULL); - if (objc == 6) { - Tcl_GetIntFromObj(interp, objv[4], &skip); - packet = Tcl_GetStringFromObj(objv[5], NULL); - } else { - packet = Tcl_GetStringFromObj(objv[4], NULL); - } - value = ars_d_field_get(packet, layer, field, skip); - if (value) { - Tcl_SetStringObj(result, value, -1); - free(value); - } - return TCL_OK; -} - -/* hping hasfield layer field ?skip? packet */ -static int HpingHasFieldCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - char *layer, *field, *packet; - int skip = 0; - Tcl_Obj *result; - - if (objc != 5 && objc != 6) { - Tcl_WrongNumArgs(interp, 2, objv, "layer field ?skip? packet"); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - layer = Tcl_GetStringFromObj(objv[2], NULL); - field = Tcl_GetStringFromObj(objv[3], NULL); - if (objc == 6) { - Tcl_GetIntFromObj(interp, objv[4], &skip); - packet = Tcl_GetStringFromObj(objv[5], NULL); - } else { - packet = Tcl_GetStringFromObj(objv[4], NULL); - } - if (ars_d_field_off(packet, layer, field, skip, NULL, NULL, NULL)) - Tcl_SetIntObj(result, 1); - else - Tcl_SetIntObj(result, 0); - return TCL_OK; -} - -/* hping setfield layer field value ?skip? packet */ -static int HpingSetFieldCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - char *layer, *field, *value, *packet; - int skip = 0, vstart, vend; - Tcl_Obj *result; - - if (objc != 6 && objc != 7) { - Tcl_WrongNumArgs(interp, 2, objv, "layer field value ?skip? packet"); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - layer = Tcl_GetStringFromObj(objv[2], NULL); - field = Tcl_GetStringFromObj(objv[3], NULL); - value = Tcl_GetStringFromObj(objv[4], NULL); - if (objc == 7) { - Tcl_GetIntFromObj(interp, objv[5], &skip); - packet = Tcl_GetStringFromObj(objv[6], NULL); - } else { - packet = Tcl_GetStringFromObj(objv[5], NULL); - } - if (!ars_d_field_off(packet, layer, field, skip, NULL, &vstart, &vend)){ - Tcl_AppendStringsToObj(result, "no such field ", layer, " ", field, NULL); - return TCL_ERROR; - } - Tcl_AppendToObj(result, packet, vstart); - Tcl_AppendObjToObj(result, objv[4]); - Tcl_AppendStringsToObj(result, packet+vend+1, NULL); - return TCL_OK; -} - -/* hping delfield layer field ?skip? packet */ -static int HpingDelFieldCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - char *layer, *field, *packet; - int skip = 0, fstart, vend; - Tcl_Obj *result; - - if (objc != 5 && objc != 6) { - Tcl_WrongNumArgs(interp, 2, objv, "layer field ?skip? packet"); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - layer = Tcl_GetStringFromObj(objv[2], NULL); - field = Tcl_GetStringFromObj(objv[3], NULL); - if (objc == 6) { - Tcl_GetIntFromObj(interp, objv[4], &skip); - packet = Tcl_GetStringFromObj(objv[5], NULL); - } else { - packet = Tcl_GetStringFromObj(objv[4], NULL); - } - if (!ars_d_field_off(packet, layer, field, skip, &fstart, NULL, &vend)){ - if (objc == 6) - Tcl_AppendObjToObj(result, objv[5]); - else - Tcl_AppendObjToObj(result, objv[4]); - return TCL_OK; - } - if (packet[fstart-1] == ',' && - (packet[vend+1] == ')' || packet[vend+1] == ',')) { - fstart--; - } - Tcl_AppendToObj(result, packet, fstart); - if (packet[fstart-1] == '(' && packet[vend+1] == ',') - packet++; - Tcl_AppendStringsToObj(result, packet+vend+1, NULL); - return TCL_OK; -} - -/* hping checksum string */ -static int HpingChecksumCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - Tcl_Obj *result; - u_int16_t cksum; - char *data; - int len; - - result = Tcl_GetObjResult(interp); - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "string"); - return TCL_ERROR; - } - data = Tcl_GetStringFromObj(objv[2], &len); - cksum = ars_cksum(data, len); - Tcl_SetIntObj(result, cksum); - return TCL_OK; -} - -/* hping setfilter ifname filter */ -static int HpingSetFilterCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - struct recv_handler *ra; - struct bpf_program bpfp; - char *ifname, *filter; - Tcl_Obj *result; - - result = Tcl_GetObjResult(interp); - if (objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "ifname filter"); - return TCL_ERROR; - } - ifname = Tcl_GetStringFromObj(objv[2], NULL); - filter = Tcl_GetStringFromObj(objv[3], NULL); - /* Get the interface pcap handler */ - ra = HpingRecvGetHandler(recv_handlers, HPING_IFACE_MAX, ifname, interp); - if (ra == NULL) { - Tcl_SetStringObj(result, "Unable to open the interface setting the pcap filter", -1); - return TCL_ERROR; - } - /* Compile and set the filter */ - if (pcap_compile(ra->rh_pcapfp, &bpfp, filter, 0, 0) == -1) { - Tcl_AppendStringsToObj(result, "Error compiling the pcap filter: '", pcap_geterr(ra->rh_pcapfp), "'", NULL); - return TCL_ERROR; - } - if (pcap_setfilter(ra->rh_pcapfp, &bpfp) == -1) { - Tcl_AppendStringsToObj(result, "Error setting the pcap filter: '", pcap_geterr(ra->rh_pcapfp), "'", NULL); - pcap_freecode(&bpfp); - return TCL_ERROR; - } - pcap_freecode(&bpfp); - return TCL_OK; -} - -/* event handler for the [hping event] command. */ -void HpingEventHandler(void *clientData, int mask) -{ - struct recv_handler *ra = clientData; - - if (Tcl_EvalObjEx(ra->rh_interp, ra->rh_handlerscript, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT) != TCL_OK) { - Tcl_BackgroundError(ra->rh_interp); - } -} - -/* hping event ifname ?script? */ -static int HpingEventCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - struct recv_handler *ra; - char *ifname; - Tcl_Obj *result; - int scriptlen; - - result = Tcl_GetObjResult(interp); - if (objc != 3 && objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "ifname ?script?"); - return TCL_ERROR; - } - ifname = Tcl_GetStringFromObj(objv[2], NULL); - /* Get the interface pcap handler */ - ra = HpingRecvGetHandler(recv_handlers, HPING_IFACE_MAX, ifname, interp); - if (ra == NULL) { - Tcl_SetStringObj(result, "Unable to open the interface setting the pcap filter", -1); - return TCL_ERROR; - } - /* If the script argument is missing, return the script - * currently set if any */ - if(objc == 3) { - if(ra->rh_interp != NULL) - Tcl_SetObjResult(interp, ra->rh_handlerscript); - return TCL_OK; - } - /* Set the script in the target interface */ - if (ra->rh_interp != NULL) - Tcl_DecrRefCount(ra->rh_handlerscript); - /* CHeck if the script is empty, if so clear the handler */ - Tcl_GetStringFromObj(objv[3], &scriptlen); - if (scriptlen != 0) { - ra->rh_handlerscript = objv[3]; - Tcl_IncrRefCount(objv[3]); - ra->rh_interp = interp; - /* Register the handler for this file descriptor */ - Tcl_CreateFileHandler(pcap_fileno(ra->rh_pcapfp), TCL_READABLE, - HpingEventHandler, (void*)ra); - } else { - ra->rh_interp = NULL; - } - return TCL_OK; -} - -/* --------------------------------- Misc ----------------------------------- */ -#if 0 -/* hping setfilter ifname filter */ -static int HpingSoftrealtimeCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - struct sched_param sp; - int min, max, virtual_priority; - struct Tcl_Obj *result; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "priority (in the range 0-99)"); - return TCL_ERROR; - } - result = Tcl_GetObjResult(interp); - Tcl_GetIntFromObj(interp, objv[2], &virtual_priority); - if (virtual_priority < 0 || virtual_priority > 99) { - Tcl_SetStringObj(result, "priority must be in the range 0-99", -1); - return TCL_ERROR; - } - min = sched_get_priority_min(SCHED_RR); - max = sched_get_priority_max(SCHED_RR); - /* Map the virutal priority to the range supported in this OS */ - { - float vmul = (max-min)+1; - vmul /= 100; - sp.sched_priority = min + (int)(virtual_priority*vmul); - } - /* sched_setscheduler() may fail, but we just ignore the error */ - sched_setscheduler(0, SCHED_RR, &sp); - return TCL_OK; -} -#endif - -/* ---------------------- hping command implementation ---------------------- */ -struct subcmd { - char *name; - int (*proc)(ClientData cd, Tcl_Interp *i, int, Tcl_Obj *CONST objv[]); -} subcmds[] = { - { "resolve", HpingResolveCmd }, - { "send", HpingSendCmd }, - { "sendraw", HpingSendRawCmd }, - { "recv", HpingRecvCmd }, - { "recvraw", HpingRecvRawCmd }, - { "setfilter", HpingSetFilterCmd }, - { "iflist", HpingGetInterfacesCmd }, - { "outifa", HpingGetOutIfAddrCmd }, - { "getfield", HpingGetFieldCmd }, - { "hasfield", HpingHasFieldCmd }, - { "setfield", HpingSetFieldCmd }, - { "delfield", HpingDelFieldCmd }, - { "checksum", HpingChecksumCmd }, - { "event", HpingEventCmd }, -#if 0 - { "softrealtime", HpingSoftrealtimeCmd }, -#endif - { NULL, NULL }, -}; - -static int HpingObjCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - int i = 0; - char *scmd; - Tcl_Obj *result; - - if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); - return TCL_ERROR; - } - - scmd = Tcl_GetStringFromObj(objv[1], NULL); - while(subcmds[i].name) { - if (!strcmp(scmd, subcmds[i].name)) - return subcmds[i].proc(clientData, interp, objc, objv); - i++; - } - result = Tcl_GetObjResult(interp); - Tcl_SetStringObj(result, "Bad option ", -1); - Tcl_AppendStringsToObj(result, "\"", scmd, "\"", " must be: ", NULL); - i = 0; - while(subcmds[i].name) { - Tcl_AppendStringsToObj(result, subcmds[i].name, NULL); - if (subcmds[i+1].name) - Tcl_AppendStringsToObj(result, ", ", NULL); - i++; - } - return TCL_ERROR; -} - -/* -------------------- multiprecision math commands ------------------------ */ - -#if 0 -/* XXX: actually this binding is pretty naive, we are not using - * a Tcl dual-port rappresentation for bignums, instead we convert from/to - * string rappresentation, wasting the almost decent performences - * of the sbignum library (and even worse, because to/from string conversion - * is not optimized). Btw, for now this seems enough, there will be - * time to improve on this in the future if needed, without to break the API. */ - -static int BigBasicObjCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - Tcl_Obj *result; - mpz_t res, t; - char *s = NULL, *cmd; - - cmd = Tcl_GetStringFromObj(objv[0], NULL); - objc--; - objv++; - - result = Tcl_GetObjResult(interp); - mpz_init(res); - mpz_init(t); - mpz_setzero(res); - if (cmd[0] == '*' || cmd[0] == '/') { - if (mpz_set_ui(res, 1) != SBN_OK) - goto err; - } - if ((cmd[0] == '/' || cmd[0] == '%') && objc) { - s = Tcl_GetStringFromObj(objv[0], NULL); - if (mpz_set_str(res, s, 0) != SBN_OK) - goto err; - objc--; - objv++; - } - while(objc--) { - s = Tcl_GetStringFromObj(objv[0], NULL); - if (mpz_set_str(t, s, 0) != SBN_OK) - goto err; - switch(cmd[0]) { - case '+': - if (mpz_add(res, res, t) != SBN_OK) - goto err; - break; - case '-': - if (mpz_sub(res, res, t) != SBN_OK) - goto err; - break; - case '*': - if (mpz_mul(res, res, t) != SBN_OK) - goto err; - break; - case '/': - if (mpz_tdiv_q(res, res, t) != SBN_OK) - goto err; - break; - case '%': - if (mpz_mod(res, res, t) != SBN_OK) - goto err; - break; - } - objv++; - } - if ((s = mpz_get_str(NULL, 10, res)) == NULL) - goto err; - Tcl_SetStringObj(result, s, -1); - free(s); - mpz_clear(res); - mpz_clear(t); - return TCL_OK; -err: - mpz_clear(res); - mpz_clear(t); - Tcl_AppendStringsToObj(result, "Not a valid big number: ", s, NULL); - return TCL_ERROR; -} -#endif - -/* -------------------------- Mpz object implementation --------------------- */ - -static void Tcl_SetMpzObj(Tcl_Obj *objPtr, mpz_ptr val); -//static Tcl_Obj *Tcl_NewMpzObj(void); -static void FreeMpzInternalRep(Tcl_Obj *objPtr); -static void DupMpzInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); -static void UpdateStringOfMpz(Tcl_Obj *objPtr); -static int SetMpzFromAny(struct Tcl_Interp* interp, Tcl_Obj *objPtr); - -struct Tcl_ObjType tclMpzType = { - "mpz", - FreeMpzInternalRep, - DupMpzInternalRep, - UpdateStringOfMpz, - SetMpzFromAny -}; - -/* This function set objPtr as an mpz object with value - * 'val'. If 'val' == NULL, the mpz object is set to zero. */ -void Tcl_SetMpzObj(Tcl_Obj *objPtr, mpz_ptr val) -{ - Tcl_ObjType *typePtr; - mpz_ptr mpzPtr; - - /* It's not a good idea to set a shared object... */ - if (Tcl_IsShared(objPtr)) { - panic("Tcl_SetMpzObj called with shared object"); - } - /* Free the old object private data and invalidate the string - * representation. */ - typePtr = objPtr->typePtr; - if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { - (*typePtr->freeIntRepProc)(objPtr); - } - Tcl_InvalidateStringRep(objPtr); - /* Allocate and initialize a new bignum */ - mpzPtr = (mpz_ptr) ckalloc(sizeof(struct struct_sbnz)); - mpz_init(mpzPtr); - if (val && mpz_set(mpzPtr, val) != SBN_OK) { - panic("Out of memory in Tcl_SetMpzObj"); - } - /* Set it as object private data, and type */ - objPtr->typePtr = &tclMpzType; - objPtr->internalRep.otherValuePtr = (void*) mpzPtr; -} - -/* Return an mpz from the object. If the object is not of type mpz - * an attempt to convert it to mpz is done. On failure (the string - * representation of the object can't be converted on a bignum) - * an error is returned. */ -int Tcl_GetMpzFromObj(struct Tcl_Interp *interp, Tcl_Obj *objPtr, mpz_ptr *mpzPtrPtr) -{ - int result; - - if (objPtr->typePtr != &tclMpzType) { - result = SetMpzFromAny(interp, objPtr); - if (result != TCL_OK) - return result; - } - *mpzPtrPtr = (mpz_ptr) objPtr->internalRep.longValue; - return TCL_OK; -} - -/* Create a new mpz object */ -Tcl_Obj *Tcl_NewMpzObj(void) -{ - struct Tcl_Obj *objPtr; - - /* Create a new Tcl Object */ - objPtr = Tcl_NewObj(); - Tcl_SetMpzObj(objPtr, 0); - return objPtr; -} - -/* The 'free' method of the object. */ -void FreeMpzInternalRep(Tcl_Obj *objPtr) -{ - mpz_ptr mpzPtr = (mpz_ptr) objPtr->internalRep.otherValuePtr; - - mpz_clear(mpzPtr); - ckfree((void*)mpzPtr); -} - -/* The 'dup' method of the object */ -void DupMpzInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr) -{ - mpz_ptr mpzCopyPtr = (mpz_ptr) ckalloc(sizeof(struct struct_sbnz)); - mpz_ptr mpzSrcPtr; - - mpz_init(mpzCopyPtr); - mpzSrcPtr = (mpz_ptr) srcPtr->internalRep.otherValuePtr; - if (mpz_set(mpzCopyPtr, mpzSrcPtr) != SBN_OK) - panic("Out of memory inside DupMpzInternalRep()"); - copyPtr->internalRep.otherValuePtr = (void*) mpzCopyPtr; - copyPtr->typePtr = &tclMpzType; -} - -/* The 'update string' method of the object */ -void UpdateStringOfMpz(Tcl_Obj *objPtr) -{ - size_t len; - mpz_ptr mpzPtr = (mpz_ptr) objPtr->internalRep.otherValuePtr; - - len = mpz_sizeinbase(mpzPtr, 10)+2; - objPtr->bytes = ckalloc(len); - mpz_get_str(objPtr->bytes, 10, mpzPtr); - /* XXX: fixme, modifing the sbignum library it is - * possible to get the length of the written string. */ - objPtr->length = strlen(objPtr->bytes); -} - -/* The 'set from any' method of the object */ -int SetMpzFromAny(struct Tcl_Interp* interp, Tcl_Obj *objPtr) -{ - char *s; - mpz_t t; - mpz_ptr mpzPtr; - Tcl_ObjType *typePtr; - - if (objPtr->typePtr == &tclMpzType) - return TCL_OK; - - /* Try to convert */ - s = Tcl_GetStringFromObj(objPtr, NULL); - mpz_init(t); - if (mpz_set_str(t, s, 0) != SBN_OK) { - mpz_clear(t); - Tcl_ResetResult(interp); - Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "Invalid big number: \"", - s, "\" must be a relative integer number", - NULL); - return TCL_ERROR; - } - /* Allocate */ - mpzPtr = (mpz_ptr) ckalloc(sizeof(struct struct_sbnz)); - mpz_init(mpzPtr); - /* Free the old object private rep */ - typePtr = objPtr->typePtr; - if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { - (*typePtr->freeIntRepProc)(objPtr); - } - /* Set it */ - objPtr->typePtr = &tclMpzType; - objPtr->internalRep.otherValuePtr = (void*) mpzPtr; - memcpy(mpzPtr, t, sizeof(*mpzPtr)); - return TCL_OK; -} - -/* --------------- the actual commands for multipreicision math ------------- */ - -static int BigBasicObjCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - Tcl_Obj *result; - mpz_t res; - mpz_ptr t; - char *cmd; - - cmd = Tcl_GetStringFromObj(objv[0], NULL); - objc--; - objv++; - - result = Tcl_GetObjResult(interp); - mpz_init(res); - mpz_setzero(res); - if (cmd[0] == '*' || cmd[0] == '/') { - if (mpz_set_ui(res, 1) != SBN_OK) - goto err; - } - if ((cmd[0] == '/' || cmd[0] == '%' || cmd[0] == '-') && objc) { - if (Tcl_GetMpzFromObj(interp, objv[0], &t) != TCL_OK) - goto err; - if (mpz_set(res, t) != SBN_OK) - goto oom; - if (cmd[0] == '-' && objc == 1) - res->s = !res->s; - objc--; - objv++; - } - while(objc--) { - if (Tcl_GetMpzFromObj(interp, objv[0], &t) != TCL_OK) - goto err; - switch(cmd[0]) { - case '+': - if (mpz_add(res, res, t) != SBN_OK) - goto oom; - break; - case '-': - if (mpz_sub(res, res, t) != SBN_OK) - goto oom; - break; - case '*': - if (mpz_mul(res, res, t) != SBN_OK) - goto oom; - break; - case '/': - if (mpz_tdiv_q(res, res, t) != SBN_OK) - goto oom; - break; - case '%': - if (mpz_mod(res, res, t) != SBN_OK) - goto oom; - break; - } - objv++; - } - Tcl_SetMpzObj(result, res); - mpz_clear(res); - return TCL_OK; -err: - mpz_clear(res); - return TCL_ERROR; -oom: - Tcl_SetStringObj(result, "Out of memory doing multiprecision math", -1); - mpz_clear(res); - return TCL_ERROR; -} - -static int BigCmpObjCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - Tcl_Obj *result; - mpz_ptr a, b; - int cmp, res; - char *cmd; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "bignum bignum"); - return TCL_ERROR; - } - - cmd = Tcl_GetStringFromObj(objv[0], NULL); - if (Tcl_GetMpzFromObj(interp, objv[1], &a) != TCL_OK || - Tcl_GetMpzFromObj(interp, objv[2], &b) != TCL_OK) - return TCL_ERROR; - cmp = mpz_cmp(a, b); - - result = Tcl_GetObjResult(interp); - res = 0; - switch(cmd[0]) { - case '>': - switch(cmd[1]) { - case '=': - if (cmp >= 0) res = 1; - break; - default: - if (cmp > 0) res = 1; - break; - } - break; - case '<': - switch(cmd[1]) { - case '=': - if (cmp <= 0) res = 1; - break; - default: - if (cmp < 0) res = 1; - break; - } - break; - case '=': - if (cmp == 0) res = 1; - break; - case '!': - if (cmp != 0) res = 1; - break; - } - Tcl_SetIntObj(result, res); - return TCL_OK; -} - -static int BigRandObjCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - Tcl_Obj *result; - int len = 1; - mpz_t r; - - if (objc != 1 && objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "?atoms?"); - return TCL_ERROR; - } - if (objc == 2 && Tcl_GetIntFromObj(interp, objv[1], &len) != TCL_OK) - return TCL_ERROR; - result = Tcl_GetObjResult(interp); - mpz_init(r); - if (mpz_random(r, len) != SBN_OK) { - mpz_clear(r); - Tcl_SetStringObj(result, "Out of memory", -1); - return TCL_ERROR; - } - Tcl_SetMpzObj(result, r); - mpz_clear(r); - return TCL_OK; -} - -static int BigSrandObjCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - char *seed; - int len; - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "seed-string"); - return TCL_ERROR; - } - seed = Tcl_GetStringFromObj(objv[1], &len); - sbn_seed(seed, len); - return TCL_OK; -} - -static int BigPowObjCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - Tcl_Obj *result; - int mpzerr; - mpz_t r; /* result */ - mpz_ptr b, e, m; /* base, exponent, modulo */ - - if (objc != 3 && objc != 4) { - Tcl_WrongNumArgs(interp, 1, objv, "base exponent ?modulo?"); - return TCL_ERROR; - } - if (Tcl_GetMpzFromObj(interp, objv[1], &b) != TCL_OK || - Tcl_GetMpzFromObj(interp, objv[2], &e) != TCL_OK || - (objc == 4 && Tcl_GetMpzFromObj(interp, objv[3], &m) != TCL_OK)) - return TCL_ERROR; - result = Tcl_GetObjResult(interp); - mpz_init(r); - if (objc == 4) - mpzerr = mpz_powm(r, b, e, m); - else - mpzerr = mpz_pow(r, b, e); - if (mpzerr != SBN_OK) { - mpz_clear(r); - if (mpzerr == SBN_INVAL) - Tcl_SetStringObj(result, "Negative exponent", -1); - else - Tcl_SetStringObj(result, "Out of memory", -1); - return TCL_ERROR; - } - Tcl_SetMpzObj(result, r); - mpz_clear(r); - return TCL_OK; -} - -/* ------------------- interpreter creation/invocation ---------------------- */ - -static int HpingTcl_AppInit(Tcl_Interp *interp) -{ - /* Initialization */ - if (Tcl_Init(interp) == TCL_ERROR) - return TCL_ERROR; - HpingRecvInit(recv_handlers, HPING_IFACE_MAX); - /* Register hping API */ - Tcl_SetVar(interp, "hping_version", RELEASE_VERSION, TCL_GLOBAL_ONLY); - Tcl_SetVar(interp, "tcl_prompt1", "puts -nonewline {hping3> }", TCL_GLOBAL_ONLY); - Tcl_CreateObjCommand(interp, "hping", HpingObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "+", BigBasicObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "-", BigBasicObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "*", BigBasicObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "/", BigBasicObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "%", BigBasicObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, ">", BigCmpObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, ">=", BigCmpObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "<", BigCmpObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "<=", BigCmpObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "==", BigCmpObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "!=", BigCmpObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "rand", BigRandObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "srand", BigSrandObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - Tcl_CreateObjCommand(interp, "**", BigPowObjCmd, (ClientData)NULL, - (Tcl_CmdDeleteProc*)NULL); - /* Eval the hpingrc, fi any */ - { - char *home = getenv("HOME"); - if (home) { - char rcfile[PATH_MAX]; - snprintf(rcfile, PATH_MAX, "%s/.hpingrc", home); - rcfile[PATH_MAX-1] = '\0'; - Tcl_EvalFile(interp, rcfile); - Tcl_ResetResult(interp); - } - } - return TCL_OK; -} - -void hping_script(int argc, char **argv) -{ - Tcl_Main(argc, argv, HpingTcl_AppInit); - exit(0); -} - -#endif /* USE_TCL */ diff --git a/send.c b/send.c deleted file mode 100644 index b12e184..0000000 --- a/send.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * $smu-mark$ - * $name: sendudp.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:49 MET 1999$ - * $rev: 8$ - */ - -/* $Id: send.c,v 1.1.1.1 2003/08/31 17:23:53 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include - -#include "hping2.h" -#include "globals.h" - -static void select_next_random_source(void) -{ - unsigned char ra[4]; - - ra[0] = hp_rand() & 0xFF; - ra[1] = hp_rand() & 0xFF; - ra[2] = hp_rand() & 0xFF; - ra[3] = hp_rand() & 0xFF; - memcpy(&local.sin_addr.s_addr, ra, 4); - - if (opt_debug) - printf("DEBUG: the source address is %u.%u.%u.%u\n", - ra[0], ra[1], ra[2], ra[3]); -} - -static void select_next_random_dest(void) -{ - unsigned char ra[4]; - char a[4], b[4], c[4], d[4]; - - if (sscanf(targetname, "%4[^.].%4[^.].%4[^.].%4[^.]", a, b, c, d) != 4) - { - fprintf(stderr, - "wrong --rand-dest target host, correct examples:\n" - " x.x.x.x, 192,168.x.x, 128.x.x.255\n" - "you typed: %s\n", targetname); - exit(1); - } - a[3] = b[3] = c[3] = d[3] = '\0'; - - ra[0] = a[0] == 'x' ? (hp_rand() & 0xFF) : strtoul(a, NULL, 0); - ra[1] = b[0] == 'x' ? (hp_rand() & 0xFF) : strtoul(b, NULL, 0); - ra[2] = c[0] == 'x' ? (hp_rand() & 0xFF) : strtoul(c, NULL, 0); - ra[3] = d[0] == 'x' ? (hp_rand() & 0xFF) : strtoul(d, NULL, 0); - memcpy(&remote.sin_addr.s_addr, ra, 4); - - if (opt_debug) { - printf("DEBUG: the dest address is %u.%u.%u.%u\n", - ra[0], ra[1], ra[2], ra[3]); - } -} - -/* The signal handler for SIGALRM will send the packets */ -void send_packet (int signal_id) -{ - int errno_save = errno; - - if (opt_rand_dest) - select_next_random_dest(); - if (opt_rand_source) - select_next_random_source(); - - if (opt_rawipmode) send_rawip(); - else if (opt_icmpmode) send_icmp(); - else if (opt_udpmode) send_udp(); - else send_tcp(); - - sent_pkt++; - Signal(SIGALRM, send_packet); - - if (count != -1 && count == sent_pkt) { /* count reached? */ - Signal(SIGALRM, print_statistics); - alarm(COUNTREACHED_TIMEOUT); - } else if (!opt_listenmode) { - if (opt_waitinusec == FALSE) - alarm(sending_wait); - else - setitimer(ITIMER_REAL, &usec_delay, NULL); - } - errno = errno_save; -} diff --git a/sendhcmp.c b/sendhcmp.c deleted file mode 100644 index ee7057f..0000000 --- a/sendhcmp.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * $smu-mark$ - * $name: sendhcmp.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:49 MET 1999$ - * $rev: 4$ - */ - -/* $Id: sendhcmp.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include -#include -#include /* SIGALARM macro */ - -#include "hping2.h" -#include "globals.h" - -#define MUST_BE_UNREACHED 0 - -void send_hcmp(__u8 type, __u32 arg) -{ - static struct hcmphdr hcmph; /* static because we export this */ - /* to data_handler() */ - - data_size = signlen + sizeof(struct hcmphdr); - - /* build hcmp header */ - memset(&hcmph, 0, sizeof(hcmph)); - hcmph.type = type; - switch (type) - { - case HCMP_RESTART: - hcmph.typedep.seqnum = htons((__u16) arg); - break; - case HCMP_SOURCE_QUENCH: - case HCMP_SOURCE_STIRUP: - hcmph.typedep.usec = htonl(arg); - break; - default: - assert(MUST_BE_UNREACHED); - } - - /* use hcmphdr_p to transmit hcmph to data_handler() */ - hcmphdr_p = &hcmph; - kill(getpid(), SIGALRM); /* send hcmp */ - - return; -} diff --git a/sendicmp.c b/sendicmp.c deleted file mode 100644 index 7efb274..0000000 --- a/sendicmp.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * $smu-mark$ - * $name: sendicmp.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:49 MET 1999$ - * $rev: 8$ - */ - -/* $Id: sendicmp.c,v 1.1.1.1 2003/08/31 17:23:53 antirez Exp $ */ - -#include /* this should be not needed, but ip_icmp.h lacks it */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hping2.h" -#include "globals.h" - -static int _icmp_seq = 0; - -void send_icmp_echo(void); -void send_icmp_other(void); -void send_icmp_timestamp(void); -void send_icmp_address(void); - -void send_icmp(void) -{ - switch(opt_icmptype) - { - case ICMP_ECHO: /* type 8 */ - case ICMP_ECHOREPLY: /* type 0 */ - send_icmp_echo(); - break; - case ICMP_DEST_UNREACH: /* type 3 */ - case ICMP_SOURCE_QUENCH: /* type 4 */ - case ICMP_REDIRECT: /* type 5 */ - case ICMP_TIME_EXCEEDED: /* type 11 */ - send_icmp_other(); - break; - case ICMP_TIMESTAMP: - case ICMP_TIMESTAMPREPLY: - send_icmp_timestamp(); - break; - case ICMP_ADDRESS: - case ICMP_ADDRESSREPLY: - send_icmp_address(); - break; - default: - if (opt_force_icmp) { - send_icmp_other(); - break; - } else { - printf("[send_icmp] Unsupported icmp type!\n"); - exit(1); - } - } -} - -void send_icmp_echo(void) -{ - char *packet, *data; - struct myicmphdr *icmp; - - packet = malloc(ICMPHDR_SIZE + data_size); - if (packet == NULL) { - perror("[send_icmp] malloc"); - return; - } - - memset(packet, 0, ICMPHDR_SIZE + data_size); - - icmp = (struct myicmphdr*) packet; - data = packet + ICMPHDR_SIZE; - - /* fill icmp hdr */ - icmp->type = opt_icmptype; /* echo replay or echo request */ - icmp->code = opt_icmpcode; /* should be indifferent */ - icmp->checksum = 0; - icmp->un.echo.id = getpid() & 0xffff; - icmp->un.echo.sequence = _icmp_seq; - - /* data */ - data_handler(data, data_size); - - /* icmp checksum */ - if (icmp_cksum == -1) - icmp->checksum = cksum((u_short*)packet, ICMPHDR_SIZE + data_size); - else - icmp->checksum = icmp_cksum; - - /* adds this pkt in delaytable */ - if (opt_icmptype == ICMP_ECHO) - delaytable_add(_icmp_seq, 0, time(NULL), get_usec(), S_SENT); - - /* send packet */ - send_ip_handler(packet, ICMPHDR_SIZE + data_size); - free (packet); - - _icmp_seq++; -} - -void send_icmp_timestamp(void) -{ - char *packet; - struct myicmphdr *icmp; - struct icmp_tstamp_data *tstamp_data; - - packet = malloc(ICMPHDR_SIZE + sizeof(struct icmp_tstamp_data)); - if (packet == NULL) { - perror("[send_icmp] malloc"); - return; - } - - memset(packet, 0, ICMPHDR_SIZE + sizeof(struct icmp_tstamp_data)); - - icmp = (struct myicmphdr*) packet; - tstamp_data = (struct icmp_tstamp_data*) (packet + ICMPHDR_SIZE); - - /* fill icmp hdr */ - icmp->type = opt_icmptype; /* echo replay or echo request */ - icmp->code = 0; - icmp->checksum = 0; - icmp->un.echo.id = getpid() & 0xffff; - icmp->un.echo.sequence = _icmp_seq; - tstamp_data->orig = htonl(get_midnight_ut_ms()); - tstamp_data->recv = tstamp_data->tran = 0; - - /* icmp checksum */ - if (icmp_cksum == -1) - icmp->checksum = cksum((u_short*)packet, ICMPHDR_SIZE + - sizeof(struct icmp_tstamp_data)); - else - icmp->checksum = icmp_cksum; - - /* adds this pkt in delaytable */ - if (opt_icmptype == ICMP_TIMESTAMP) - delaytable_add(_icmp_seq, 0, time(NULL), get_usec(), S_SENT); - - /* send packet */ - send_ip_handler(packet, ICMPHDR_SIZE + sizeof(struct icmp_tstamp_data)); - free (packet); - - _icmp_seq++; -} - -void send_icmp_address(void) -{ - char *packet; - struct myicmphdr *icmp; - - packet = malloc(ICMPHDR_SIZE + 4); - if (packet == NULL) { - perror("[send_icmp] malloc"); - return; - } - - memset(packet, 0, ICMPHDR_SIZE + 4); - - icmp = (struct myicmphdr*) packet; - - /* fill icmp hdr */ - icmp->type = opt_icmptype; /* echo replay or echo request */ - icmp->code = 0; - icmp->checksum = 0; - icmp->un.echo.id = getpid() & 0xffff; - icmp->un.echo.sequence = _icmp_seq; - memset(packet+ICMPHDR_SIZE, 0, 4); - - /* icmp checksum */ - if (icmp_cksum == -1) - icmp->checksum = cksum((u_short*)packet, ICMPHDR_SIZE + 4); - else - icmp->checksum = icmp_cksum; - - /* adds this pkt in delaytable */ - if (opt_icmptype == ICMP_TIMESTAMP) - delaytable_add(_icmp_seq, 0, time(NULL), get_usec(), S_SENT); - - /* send packet */ - send_ip_handler(packet, ICMPHDR_SIZE + 4); - free (packet); - - _icmp_seq++; -} - -void send_icmp_other(void) -{ - char *packet, *data, *ph_buf; - struct myicmphdr *icmp; - struct myiphdr icmp_ip; - struct myudphdr *icmp_udp; - int udp_data_len = 0; - struct pseudohdr *pseudoheader; - int left_space = IPHDR_SIZE + UDPHDR_SIZE + data_size; - - packet = malloc(ICMPHDR_SIZE + IPHDR_SIZE + UDPHDR_SIZE + data_size); - ph_buf = malloc(PSEUDOHDR_SIZE + UDPHDR_SIZE + udp_data_len); - if (packet == NULL || ph_buf == NULL) { - perror("[send_icmp] malloc"); - return; - } - - memset(packet, 0, ICMPHDR_SIZE + IPHDR_SIZE + UDPHDR_SIZE + data_size); - memset(ph_buf, 0, PSEUDOHDR_SIZE + UDPHDR_SIZE + udp_data_len); - - icmp = (struct myicmphdr*) packet; - data = packet + ICMPHDR_SIZE; - pseudoheader = (struct pseudohdr *) ph_buf; - icmp_udp = (struct myudphdr *) (ph_buf + PSEUDOHDR_SIZE); - - /* fill icmp hdr */ - icmp->type = opt_icmptype; /* ICMP_TIME_EXCEEDED */ - icmp->code = opt_icmpcode; /* should be 0 (TTL) or 1 (FRAGTIME) */ - icmp->checksum = 0; - if (opt_icmptype == ICMP_REDIRECT) - memcpy(&icmp->un.gateway, &icmp_gw.sin_addr.s_addr, 4); - else - icmp->un.gateway = 0; /* not used, MUST be 0 */ - - /* concerned packet headers */ - /* IP header */ - icmp_ip.version = icmp_ip_version; /* 4 */ - icmp_ip.ihl = icmp_ip_ihl; /* IPHDR_SIZE >> 2 */ - icmp_ip.tos = icmp_ip_tos; /* 0 */ - icmp_ip.tot_len = htons((icmp_ip_tot_len ? icmp_ip_tot_len : (icmp_ip_ihl<<2) + UDPHDR_SIZE + udp_data_len)); - icmp_ip.id = htons(getpid() & 0xffff); - icmp_ip.frag_off = 0; /* 0 */ - icmp_ip.ttl = 64; /* 64 */ - icmp_ip.protocol = icmp_ip_protocol; /* 6 (TCP) */ - icmp_ip.check = 0; - memcpy(&icmp_ip.saddr, &icmp_ip_src.sin_addr.s_addr, 4); - memcpy(&icmp_ip.daddr, &icmp_ip_dst.sin_addr.s_addr, 4); - icmp_ip.check = cksum((__u16 *) &icmp_ip, IPHDR_SIZE); - - /* UDP header */ - memcpy(&pseudoheader->saddr, &icmp_ip_src.sin_addr.s_addr, 4); - memcpy(&pseudoheader->daddr, &icmp_ip_dst.sin_addr.s_addr, 4); - pseudoheader->protocol = icmp_ip.protocol; - pseudoheader->lenght = icmp_ip.tot_len; - icmp_udp->uh_sport = htons(icmp_ip_srcport); - icmp_udp->uh_dport = htons(icmp_ip_dstport); - icmp_udp->uh_ulen = htons(UDPHDR_SIZE + udp_data_len); - icmp_udp->uh_sum = cksum((__u16 *) ph_buf, PSEUDOHDR_SIZE + UDPHDR_SIZE + udp_data_len); - - /* filling icmp body with concerned packet header */ - - /* fill IP */ - if (left_space == 0) goto no_space_left; - memcpy(packet+ICMPHDR_SIZE, &icmp_ip, left_space); - left_space -= IPHDR_SIZE; - data += IPHDR_SIZE; - if (left_space <= 0) goto no_space_left; - - /* fill UDP */ - memcpy(packet+ICMPHDR_SIZE+IPHDR_SIZE, icmp_udp, left_space); - left_space -= UDPHDR_SIZE; - data += UDPHDR_SIZE; - if (left_space <= 0) goto no_space_left; - - /* fill DATA */ - data_handler(data, left_space); -no_space_left: - - /* icmp checksum */ - if (icmp_cksum == -1) - icmp->checksum = cksum((u_short*)packet, ICMPHDR_SIZE + IPHDR_SIZE + UDPHDR_SIZE + data_size); - else - icmp->checksum = icmp_cksum; - - /* send packet */ - send_ip_handler(packet, ICMPHDR_SIZE + IPHDR_SIZE + UDPHDR_SIZE + data_size); - free (packet); - free (ph_buf); -} diff --git a/sendip.c b/sendip.c deleted file mode 100644 index fd2a0c2..0000000 --- a/sendip.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * $smu-mark$ - * $name: sendip.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:49 MET 1999$ - * $rev: 8$ - */ - -/* $Id: sendip.c,v 1.2 2004/04/09 23:38:56 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include - -#include "hping2.h" -#include "globals.h" - -void send_ip (char* src, char *dst, char *data, unsigned int datalen, - int more_fragments, unsigned short fragoff, char *options, - char optlen) -{ - char *packet; - int result, - packetsize; - struct myiphdr *ip; - - packetsize = IPHDR_SIZE + optlen + datalen; - if ( (packet = malloc(packetsize)) == NULL) { - perror("[send_ip] malloc()"); - return; - } - - memset(packet, 0, packetsize); - ip = (struct myiphdr*) packet; - - /* copy src and dst address */ - memcpy(&ip->saddr, src, sizeof(ip->saddr)); - memcpy(&ip->daddr, dst, sizeof(ip->daddr)); - - /* build ip header */ - ip->version = 4; - ip->ihl = (IPHDR_SIZE + optlen + 3) >> 2; - ip->tos = ip_tos; - -#if defined OSTYPE_DARWIN || defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD || defined OSTYPE_BSDI -/* FreeBSD */ -/* NetBSD */ - ip->tot_len = packetsize; -#else -/* Linux */ -/* OpenBSD */ - ip->tot_len = htons(packetsize); -#endif - - if (!opt_fragment) - { - ip->id = (src_id == -1) ? - htons((unsigned short) rand()) : - htons((unsigned short) src_id); - } - else /* if you need fragmentation id must not be randomic */ - { - /* FIXME: when frag. enabled sendip_handler shold inc. ip->id */ - /* for every frame sent */ - ip->id = (src_id == -1) ? - htons(getpid() & 255) : - htons((unsigned short) src_id); - } - -#if defined OSTYPE_DARWIN || defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD | defined OSTYPE_BSDI -/* FreeBSD */ -/* NetBSD */ - ip->frag_off |= more_fragments; - ip->frag_off |= fragoff >> 3; -#else -/* Linux */ -/* OpenBSD */ - ip->frag_off |= htons(more_fragments); - ip->frag_off |= htons(fragoff >> 3); /* shift three flags bit */ -#endif - - ip->ttl = src_ttl; - if (opt_rawipmode) ip->protocol = raw_ip_protocol; - else if (opt_icmpmode) ip->protocol = 1; /* icmp */ - else if (opt_udpmode) ip->protocol = 17; /* udp */ - else ip->protocol = 6; /* tcp */ - ip->check = 0; /* always computed by the kernel */ - - /* copies options */ - if (options != NULL) - memcpy(packet+IPHDR_SIZE, options, optlen); - - /* copies data */ - memcpy(packet + IPHDR_SIZE + optlen, data, datalen); - - if (opt_debug == TRUE) - { - unsigned int i; - - for (i=0; i$ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:49 MET 1999$ - * $rev: 3$ - */ - -/* $Id: sendip_handler.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include - -#include "hping2.h" -#include "globals.h" - -void send_ip_handler(char *packet, unsigned int size) -{ - ip_optlen = ip_opt_build(ip_opt); - - if (!opt_fragment && (size+ip_optlen+20 >= h_if_mtu)) - { - /* auto-activate fragmentation */ - virtual_mtu = h_if_mtu-20; - virtual_mtu = virtual_mtu - (virtual_mtu % 8); - opt_fragment = TRUE; - opt_mf = opt_df = FALSE; /* deactivate incompatible options */ - if (opt_verbose || opt_debug) - printf("auto-activate fragmentation, fragments size: %d\n", virtual_mtu); - } - - if (!opt_fragment) - { - unsigned short fragment_flag = 0; - - if (opt_mf) fragment_flag |= MF; /* more fragments */ - if (opt_df) fragment_flag |= DF; /* dont fragment */ - send_ip((char*)&local.sin_addr, - (char*)&remote.sin_addr, - packet, size, fragment_flag, ip_frag_offset, - ip_opt, ip_optlen); - } - else - { - unsigned int remainder = size; - int frag_offset = 0; - - while(1) { - if (remainder <= virtual_mtu) - break; - - send_ip((char*)&local.sin_addr, - (char*)&remote.sin_addr, - packet+frag_offset, - virtual_mtu, MF, frag_offset, - ip_opt, ip_optlen); - - remainder-=virtual_mtu; - frag_offset+=virtual_mtu; - } - - send_ip((char*)&local.sin_addr, - (char*)&remote.sin_addr, - packet+frag_offset, - remainder, NF, frag_offset, - ip_opt, ip_optlen); - } -} diff --git a/sendtcp.c b/sendtcp.c deleted file mode 100644 index 6765ad4..0000000 --- a/sendtcp.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * $smu-mark$ - * $name: sendtcp.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:49 MET 1999$ - * $rev: 8$ - */ - -/* $Id: sendtcp.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include - -#include "hping2.h" -#include "globals.h" - -void send_tcp(void) -{ - int packet_size; - int tcp_opt_size = 0; - char *packet, *data; - struct mytcphdr *tcp; - struct pseudohdr *pseudoheader; - unsigned char *tstamp; - - if (opt_tcp_timestamp) - tcp_opt_size = 12; - - packet_size = TCPHDR_SIZE + tcp_opt_size + data_size; - packet = malloc(PSEUDOHDR_SIZE + packet_size); - if (packet == NULL) { - perror("[send_tcphdr] malloc()"); - return; - } - pseudoheader = (struct pseudohdr*) packet; - tcp = (struct mytcphdr*) (packet+PSEUDOHDR_SIZE); - tstamp = (unsigned char*) (packet+PSEUDOHDR_SIZE+TCPHDR_SIZE); - data = (char*) (packet+PSEUDOHDR_SIZE+TCPHDR_SIZE+tcp_opt_size); - - memset(packet, 0, PSEUDOHDR_SIZE+packet_size); - - /* tcp pseudo header */ - memcpy(&pseudoheader->saddr, &local.sin_addr.s_addr, 4); - memcpy(&pseudoheader->daddr, &remote.sin_addr.s_addr, 4); - pseudoheader->protocol = 6; /* tcp */ - pseudoheader->lenght = htons(TCPHDR_SIZE+tcp_opt_size+data_size); - - /* tcp header */ - tcp->th_dport = htons(dst_port); - tcp->th_sport = htons(src_port); - - /* sequence number and ack are random if not set */ - tcp->th_seq = (set_seqnum) ? htonl(tcp_seqnum) : htonl(rand()); - tcp->th_ack = (set_ack) ? htonl(tcp_ack) : htonl(rand()); - - tcp->th_off = src_thoff + (tcp_opt_size >> 2); - tcp->th_win = htons(src_winsize); - tcp->th_flags = tcp_th_flags; - - /* tcp timestamp option */ - if (opt_tcp_timestamp) { - __u32 randts = rand() ^ (rand() << 16); - tstamp[0] = tstamp[1] = 1; /* NOOP */ - tstamp[2] = 8; - tstamp[3] = 10; /* 10 bytes, kind+len+T1+T2 */ - memcpy(tstamp+4, &randts, 4); /* random */ - memset(tstamp+8, 0, 4); /* zero */ - } - - /* data */ - data_handler(data, data_size); - - /* compute checksum */ -#ifdef STUPID_SOLARIS_CHECKSUM_BUG - tcp->th_sum = packet_size; -#else - tcp->th_sum = cksum((u_short*) packet, PSEUDOHDR_SIZE + - packet_size); -#endif - - /* adds this pkt in delaytable */ - delaytable_add(sequence, src_port, time(NULL), get_usec(), S_SENT); - - /* send packet */ - send_ip_handler(packet+PSEUDOHDR_SIZE, packet_size); - free(packet); - - sequence++; /* next sequence number */ - if (!opt_keepstill) - src_port = (sequence + initsport) % 65536; - - if (opt_force_incdport) - dst_port++; -} diff --git a/sendudp.c b/sendudp.c deleted file mode 100644 index 6da7cd2..0000000 --- a/sendudp.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * $smu-mark$ - * $name: sendudp.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:49 MET 1999$ - * $rev: 8$ - */ - -/* $Id: sendudp.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include - -#include "hping2.h" -#include "globals.h" - -/* void hexdumper(unsigned char *packet, int size); */ - -void send_udp(void) -{ - int packet_size; - char *packet, *data; - struct myudphdr *udp; - struct pseudohdr *pseudoheader; - - packet_size = UDPHDR_SIZE + data_size; - packet = malloc(PSEUDOHDR_SIZE + packet_size); - if (packet == NULL) { - perror("[send_udphdr] malloc()"); - return; - } - pseudoheader = (struct pseudohdr*) packet; - udp = (struct myudphdr*) (packet+PSEUDOHDR_SIZE); - data = (char*) (packet+PSEUDOHDR_SIZE+UDPHDR_SIZE); - - memset(packet, 0, PSEUDOHDR_SIZE+packet_size); - - /* udp pseudo header */ - memcpy(&pseudoheader->saddr, &local.sin_addr.s_addr, 4); - memcpy(&pseudoheader->daddr, &remote.sin_addr.s_addr, 4); - pseudoheader->protocol = 17; /* udp */ - pseudoheader->lenght = htons(packet_size); - - /* udp header */ - udp->uh_dport = htons(dst_port); - udp->uh_sport = htons(src_port); - udp->uh_ulen = htons(packet_size); - - /* data */ - data_handler(data, data_size); - - /* compute checksum */ -#ifdef STUPID_SOLARIS_CHECKSUM_BUG - udp->uh_sum = packet_size; -#else - udp->uh_sum = cksum((__u16*) packet, PSEUDOHDR_SIZE + - packet_size); -#endif - - /* adds this pkt in delaytable */ - delaytable_add(sequence, src_port, time(NULL), get_usec(), S_SENT); - - /* send packet */ - send_ip_handler(packet+PSEUDOHDR_SIZE, packet_size); - free(packet); - - sequence++; /* next sequence number */ - - if (!opt_keepstill) - src_port = (sequence + initsport) % 65536; - - if (opt_force_incdport) - dst_port++; -} diff --git a/signal.c b/signal.c deleted file mode 100644 index 66e054c..0000000 --- a/signal.c +++ /dev/null @@ -1,31 +0,0 @@ -/* protable signal() like */ - -/* $Id: signal.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ - -#include - -/* Portable signal() from R.Stevens, - * modified to reset the handler */ -void (*Signal(int signo, void (*func)(int)))(int) -{ - struct sigaction act, oact; - - act.sa_handler = func; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; /* So if set SA_RESETHAND is cleared */ - if (signo == SIGALRM) - { -#ifdef SA_INTERRUPT - act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ -#endif - } - else - { -#ifdef SA_RESTART - act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD, Linux */ -#endif - } - if (sigaction(signo, &act, &oact) == -1) - return SIG_ERR; - return (oact.sa_handler); -} diff --git a/split.c b/split.c deleted file mode 100644 index fe6a6e2..0000000 --- a/split.c +++ /dev/null @@ -1,513 +0,0 @@ -/* Copyright (C) 2003 Salvatore Sanfilippo - * All rights reserved - * $Id: split.c,v 1.4 2003/09/07 11:21:18 antirez Exp $ */ - -#include -#include -#include -#include -#include - -#include "ars.h" - -int ars_seems_ip(struct ars_iphdr *ip, size_t size) -{ - if (ip->version == 4 && - ip->ihl >= 5 && - (ip->ihl << 2) <= size && - ars_check_ip_cksum(ip) == 1) - return 1; - return 0; -} - -int ars_guess_ipoff(void *packet, size_t size, int *lhs) -{ - size_t orig_size = size; - - while(1) { - struct ars_iphdr *ip = packet; - if (size < sizeof (struct ars_iphdr)) - break; - if (ars_seems_ip(ip, size) == 0) { - /* We may probably assume the link header size - * to be multiple of two */ - packet++; - size--; - continue; - } - *lhs = orig_size - size; - return -ARS_OK; - } - return -ARS_ERROR; -} - -int ars_check_ip_cksum(struct ars_iphdr *ip) -{ - int ip_hdrsize = ip->ihl << 2; - struct ars_iphdr *ip2; - - ip2 = alloca(ip_hdrsize); - memcpy(ip2, ip, ip_hdrsize); - ip2->check = 0; - ip2->check = ars_cksum(ip2, ip_hdrsize); - return (ip->check == ip2->check); -} - -int ars_check_icmp_cksum(struct ars_icmphdr *icmp, size_t size) -{ - struct ars_icmphdr *icmp2; - - icmp2 = alloca(size); - memcpy(icmp2, icmp, size); - icmp2->checksum = 0; - icmp2->checksum = ars_cksum(icmp2, size); - return (icmp->checksum == icmp2->checksum); -} - -#define ARS_SPLIT_DONE 0 -#define ARS_SPLIT_GET_IP 1 -#define ARS_SPLIT_GET_IPOPT 2 -#define ARS_SPLIT_GET_ICMP 3 -#define ARS_SPLIT_GET_UDP 4 -#define ARS_SPLIT_GET_TCP 5 -#define ARS_SPLIT_GET_TCPOPT 6 -#define ARS_SPLIT_GET_IGRP 7 -#define ARS_SPLIT_GET_IGRPENTRY 8 -#define ARS_SPLIT_GET_DATA 9 - -int ars_split_ip(struct ars_packet *pkt, void *packet, size_t size, - int *state, int *len); -int ars_split_ipopt(struct ars_packet *pkt, void *packet, size_t size, - int *state, int *len); -int ars_split_icmp(struct ars_packet *pkt, void *packet, size_t size, - int *state, int *len); -int ars_split_udp(struct ars_packet *pkt, void *packet, size_t size, - int *state, int *len); -int ars_split_tcp(struct ars_packet *pkt, void *packet, size_t size, - int *state, int *len); -int ars_split_tcpopt(struct ars_packet *pkt, void *packet, size_t size, - int *state, int *len); -int ars_split_igrp(struct ars_packet *pkt, void *packet, size_t size, - int *state, int *len); -int ars_split_igrpentry(struct ars_packet *pkt, void *packet, size_t size, - int *state, int *len); -int ars_split_data(struct ars_packet *pkt, void *packet, size_t size, - int *state, int *len); - -/* Take it in sync with ARS_SPLIT_* defines */ -int (*ars_split_state_handler[])(struct ars_packet *pkt, void *packet, - size_t size, int *state, int *len) = -{ - NULL, - ars_split_ip, - ars_split_ipopt, - ars_split_icmp, - ars_split_udp, - ars_split_tcp, - ars_split_tcpopt, - ars_split_igrp, - ars_split_igrpentry, - ars_split_data -}; - -int ars_split_packet(void *packet, size_t size, int ipoff, struct ars_packet *pkt) -{ - int offset = 0; - int state = ARS_SPLIT_GET_IP; - - /* User asks for IP offset auto detection */ - if (ipoff == -1 && ars_guess_ipoff(packet, size, &ipoff) != -ARS_OK) { - ars_set_error(pkt, "IP offset autodetection failed"); - return -ARS_INVALID; - } - offset += ipoff; - size -= ipoff; - - /* Implemented as a finite state machine: - * every state is handled with a protocol specific function */ - while (state != ARS_SPLIT_DONE) { - int error; - int len = 0; - - error = ars_split_state_handler[state](pkt, packet + offset, - size, &state, &len); - if (error != -ARS_OK) - return error; - /* put off the link layer padding */ - if (pkt->p_layer_nr == 1 && - pkt->p_layer[0].l_type == ARS_TYPE_IP) { - struct ars_iphdr *ip = pkt->p_layer[0].l_data; - size = MIN(size, ntohs(ip->tot_len)); - } - offset += len; - size -= len; - /* Force the DONE state if we reached the end */ - if (size == 0) - state = ARS_SPLIT_DONE; - } - return -ARS_OK; -} - -/* Select the right state based on the IP protocol field */ -void ars_ip_next_state(int ipproto, int *state) -{ - switch(ipproto) { - case ARS_IPPROTO_IPIP: - *state = ARS_SPLIT_GET_IP; - break; - case ARS_IPPROTO_ICMP: - *state = ARS_SPLIT_GET_ICMP; - break; - case ARS_IPPROTO_TCP: - *state = ARS_SPLIT_GET_TCP; - break; - case ARS_IPPROTO_UDP: - *state = ARS_SPLIT_GET_UDP; - break; - case ARS_IPPROTO_IGRP: - *state = ARS_SPLIT_GET_IGRP; - break; - default: - *state = ARS_SPLIT_GET_DATA; - break; - } -} - -int ars_split_ip(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) -{ - struct ars_iphdr *ip = packet, *newip; - int flags = 0; - int ipsize; - - - /* Check for bad header size and checksum */ - if (size < sizeof(struct ars_iphdr)) { - flags |= ARS_SPLIT_FTRUNC; - ipsize = size; - } else { - ipsize = ip->ihl << 2; - if (size < ipsize) { - flags |= ARS_SPLIT_FTRUNC; - ipsize = size; - } - else if (ip->ihl < 4 || ars_check_ip_cksum(ip) == 0) - flags |= ARS_SPLIT_FBADCKSUM; - ipsize = MIN(ipsize, 20); - } - if ((newip = ars_add_iphdr(pkt, 0)) == NULL) - return -ARS_NOMEM; - - memcpy(newip, ip, ipsize); - ars_set_flags(pkt, ARS_LAST_LAYER, flags); - *len = ipsize; - - if (flags & ARS_SPLIT_FTRUNC) { - *state = ARS_SPLIT_GET_DATA; - return -ARS_OK; - } - - if (ip->ihl > 5) { /* IP options */ - /* IP protocol saved so after the IP option - * processing we can start with the right status */ - pkt->aux_ipproto = ip->protocol; - *state = ARS_SPLIT_GET_IPOPT; - pkt->aux = (ip->ihl - 5) << 2; - return -ARS_OK; - } - ars_ip_next_state(ip->protocol, state); - return -ARS_OK; -} - -int ars_split_ipopt(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) -{ - struct ars_ipopt *ipopt = packet; - int flags = 0; - int optsize; - int error; - - if (ipopt->kind == ARS_IPOPT_END || ipopt->kind == ARS_IPOPT_NOOP) - optsize = 1; - else - optsize = ipopt->len; - - /* Avoid infinite loop with broken packets */ - if (optsize == 0) - optsize = 1; - - /* pkt->aux was set by ars_split_ip, or by ars_split_ipopt itself */ - size = MIN(size, pkt->aux); - if (size == 0) { - *len = 0; - *state = ARS_SPLIT_GET_DATA; - return -ARS_OK; - } - - if (size < optsize) { - flags |= ARS_SPLIT_FTRUNC; - optsize = size; - } - - pkt->aux -= optsize; - error = ars_add_generic(pkt, optsize, ARS_TYPE_IPOPT); - if (error != -ARS_OK) - return error; - memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, ipopt, optsize); - pkt->p_layer_nr++; - ars_set_flags(pkt, ARS_LAST_LAYER, flags); - - *len = optsize; - - if (pkt->aux > 0) { - *state = ARS_SPLIT_GET_IPOPT; - } else { - ars_ip_next_state(pkt->aux_ipproto, state); - } - return -ARS_OK; -} - -int ars_split_icmp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) -{ - struct ars_icmphdr *icmp = packet, *newicmp; - int flags = 0; - int icmpsize = ARS_ICMPHDR_SIZE; - - /* Check for bad header size and checksum */ - if (size < icmpsize) { - flags |= ARS_SPLIT_FTRUNC; - icmpsize = size; - } - else if (ars_check_icmp_cksum(icmp, size) == 0) - flags |= ARS_SPLIT_FBADCKSUM; - - if ((newicmp = ars_add_icmphdr(pkt, 0)) == NULL) - return -ARS_NOMEM; - memcpy(newicmp, icmp, icmpsize); - ars_set_flags(pkt, ARS_LAST_LAYER, flags); - - *len = icmpsize; - - if (flags & ARS_SPLIT_FTRUNC) { - *state = ARS_SPLIT_GET_DATA; - return -ARS_OK; - } - - switch(icmp->type) { - case ARS_ICMP_ECHO: - case ARS_ICMP_ECHOREPLY: - case ARS_ICMP_TIMESTAMP: - case ARS_ICMP_TIMESTAMPREPLY: - case ARS_ICMP_INFO_REQUEST: - case ARS_ICMP_INFO_REPLY: - *state = ARS_SPLIT_GET_DATA; - break; - default: - *state = ARS_SPLIT_GET_IP; - break; - } - return -ARS_OK; -} - -int ars_split_data(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) -{ - void *newdata; - - if ((newdata = ars_add_data(pkt, size)) == NULL) - return -ARS_NOMEM; - memcpy(newdata, packet, size); - - *len = size; - - *state = ARS_SPLIT_DONE; - return -ARS_OK; -} - -int ars_split_udp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) -{ - struct ars_udphdr *udp = packet, *newudp; - int flags = 0; - int udpsize = ARS_UDPHDR_SIZE; - int error; - u_int16_t udpcksum; - - /* XXX hack, we need to add a temp unusual layer (UDP+UDP_DATA) to - * use the ars_udptcp_cksum() function. */ - - /* --- HACK START --- */ - error = ars_add_generic(pkt, size, ARS_TYPE_UDP); - if (error != -ARS_OK) - return error; - newudp = pkt->p_layer[pkt->p_layer_nr].l_data; - memcpy(newudp, udp, size); - newudp->uh_sum = 0; - error = ars_udptcp_cksum(pkt, pkt->p_layer_nr, &udpcksum); - if (error != ARS_OK) { - printf("---ERROR DOING CHECKSUM\n"); - pkt->p_layer_nr++; /* just to be sane */ - return error; - } - error = ars_remove_layer(pkt, pkt->p_layer_nr); - if (error != ARS_OK) - return error; - /* --- HACK END --- */ - - /* Check for bad header size and checksum */ - if (size < udpsize) { - flags |= ARS_SPLIT_FTRUNC; - udpsize = size; - } - else if (udp->uh_sum != udpcksum) - flags |= ARS_SPLIT_FBADCKSUM; - - if ((newudp = ars_add_udphdr(pkt, 0)) == NULL) - return -ARS_NOMEM; - memcpy(newudp, udp, udpsize); - ars_set_flags(pkt, ARS_LAST_LAYER, flags); - - *len = udpsize; - *state = ARS_SPLIT_GET_DATA; - return -ARS_OK; -} - -int ars_split_tcp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) -{ - struct ars_tcphdr *tcp = packet, *newtcp; - int flags = 0; - int tcpsize = tcp->th_off << 2; /* FIXME: may access random memory */ - int error; - u_int16_t tcpcksum; - - /* XXX hack, we need to add a temp unusual layer (TCP+TCP_DATA) to - * use the ars_udptcp_cksum() function. */ - - /* --- HACK START --- */ - error = ars_add_generic(pkt, size, ARS_TYPE_TCP); - if (error != -ARS_OK) - return error; - newtcp = pkt->p_layer[pkt->p_layer_nr].l_data; - memcpy(newtcp, tcp, size); - newtcp->th_sum = 0; - error = ars_udptcp_cksum(pkt, pkt->p_layer_nr, &tcpcksum); - if (error != ARS_OK) { - pkt->p_layer_nr++; /* just to be sane */ - return error; - } - error = ars_remove_layer(pkt, pkt->p_layer_nr); - if (error != ARS_OK) - return error; - /* --- HACK END --- */ - - /* Check for bad header size and checksum */ - if (size < tcpsize) { - flags |= ARS_SPLIT_FTRUNC; - tcpsize = size; - } - else if (tcp->th_sum != tcpcksum) - flags |= ARS_SPLIT_FBADCKSUM; - - tcpsize = MIN(tcpsize, 20); - - if ((newtcp = ars_add_tcphdr(pkt, 0)) == NULL) - return -ARS_NOMEM; - memcpy(newtcp, tcp, tcpsize); - ars_set_flags(pkt, ARS_LAST_LAYER, flags); - - *len = tcpsize; - if (tcp->th_off > 5) { - *state = ARS_SPLIT_GET_TCPOPT; - pkt->aux = (tcp->th_off - 5) << 2; - } else { - *state = ARS_SPLIT_GET_DATA; - } - return -ARS_OK; -} - -int ars_split_tcpopt(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) -{ - struct ars_tcpopt *tcpopt = packet; - int flags = 0; - int optsize; - int error; - - if (tcpopt->kind == ARS_TCPOPT_EOL || tcpopt->kind == ARS_TCPOPT_NOP || - tcpopt->kind == ARS_TCPOPT_SACK_PERM) - optsize = 1; - else - optsize = tcpopt->len; - - /* Avoid infinite loop with broken packets */ - if (optsize == 0) - optsize = 1; - - /* pkt->aux was set by ars_split_tcp, or by ars_split_tcpopt itself */ - size = MIN(size, pkt->aux); - if (size == 0) { - *len = 0; - *state = ARS_SPLIT_GET_DATA; - return -ARS_OK; - } - - if (size < optsize) { - flags |= ARS_SPLIT_FTRUNC; - optsize = size; - } - - pkt->aux -= optsize; - error = ars_add_generic(pkt, optsize, ARS_TYPE_TCPOPT); - if (error != -ARS_OK) - return error; - memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, tcpopt, optsize); - pkt->p_layer_nr++; - ars_set_flags(pkt, ARS_LAST_LAYER, flags); - - *len = optsize; - - if (pkt->aux > 0) - *state = ARS_SPLIT_GET_TCPOPT; - else - *state = ARS_SPLIT_GET_DATA; - - return -ARS_OK; -} - -/* XXX: check for valid IGRP checksum */ -int ars_split_igrp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) -{ - struct ars_igrphdr *igrp = packet; - int flags = 0, igrpsize = sizeof(*igrp); - int error; - - if (size < sizeof(*igrp)) { - flags |= ARS_SPLIT_FTRUNC; - igrpsize = size; - } - error = ars_add_generic(pkt, sizeof(*igrp), ARS_TYPE_IGRP); - if (error != -ARS_OK) - return error; - memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, igrp, igrpsize); - pkt->p_layer_nr++; - ars_set_flags(pkt, ARS_LAST_LAYER, flags); - *len = igrpsize; - *state = ARS_SPLIT_GET_IGRPENTRY; - return -ARS_OK; -} - -int ars_split_igrpentry(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) -{ - struct ars_igrpentry *entry = packet; - int flags = 0, entrysize = sizeof(*entry); - int error; - - if (size < sizeof(*entry)) { - flags |= ARS_SPLIT_FTRUNC; - entrysize = size; - } - error = ars_add_generic(pkt, sizeof(*entry), ARS_TYPE_IGRPENTRY); - if (error != -ARS_OK) - return error; - memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, entry, entrysize); - pkt->p_layer_nr++; - ars_set_flags(pkt, ARS_LAST_LAYER, flags); - *len = entrysize; - *state = ARS_SPLIT_GET_IGRPENTRY; - return -ARS_OK; -} diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..699000f --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,39 @@ +# Executable +bin_PROGRAMS = hping3 + +noinst_LIBRARIES = libars.a + +libars_a_SOURCES = ars.c apd.c split.c rapd.c + +# Source files +hping3_SOURCES = adbuf.c antigetopt.c apdutils.c arsglue.c \ + binding.c cksum.c datafiller.c datahandler.c display_ipopt.c gethostname.c \ + getifname.c getlhs.c getusec.c hex.c hstring.c if_promisc.c interface.c \ + ip_opt_build.c libpcap_stuff.c listen.c logicmp.c main.c memlock.c \ + memlockall.c memstr.c memunlock.c memunlockall.c opensockraw.c \ + parseoptions.c random.c relid.c resolve.c rtt.c sbignum-tables.c \ + sbignum.c scan.c script.c send.c sendhcmp.c sendicmp.c sendip_handler.c \ + sendip.c sendrawip.c sendtcp.c sendudp.c signal.c sockopt.c \ + statistics.c strlcpy.c usage.c version.c waitpacket.c + +# Flags +AM_CFLAGS = @PCAP_CFLAGS@ @TCL_CFLAGS@ +hping3_LDADD = libars.a @PCAP_LIBS@ @TCL_LIBS@ + +.PHONY: depend clean-local install-bin-local + +depend: + @echo "Making dependences..." + @$(CC) $(AM_CFLAGS) -MM $(hping3_SOURCES) > .depend || true + +-include .depend + +clean-local: + rm -rf hping3 + +BIN_DISTDIR = $(PACKAGE_NAME)-$(PACKAGE_VERSION) + +install-bin-local: + @ABS_DISTDIR=$$(pwd)/../$(BIN_DISTDIR); \ + echo "Installing binary files in $$ABS_DISTDIR..."; \ + $(MAKE) install DESTDIR=$$ABS_DISTDIR; diff --git a/src/adbuf.c b/src/adbuf.c new file mode 100644 index 0000000..a34d0f9 --- /dev/null +++ b/src/adbuf.c @@ -0,0 +1,375 @@ +/* adbuf.c - dynamic buffers support + * + * Copyright(C) 2001-2003 Salvatore Sanfilippo + * All rights reserved. + * + * ----------------------------------------------------------------------------- + * Design principles: + * + * - This library is little and probably not so flexible nor + * full-featured. The goal is to have something of useful + * enough to build stuff like mysql queries without to care + * about allocation, but with very simple code so that security + * auditing is quite simple. + * - security is more important than speed in this context, so there + * is some redundant and useless check to prevent that some unsane use + * become a security problem. + * - while the library is binary-safe the buffers are implicitly + * nul termined. Even an empty buffer just initialized points + * to an empty nul termined string. This prevents problems passing + * strings that the user never nul-termined to functions that + * expects nul-termined strings. + * - memory is more important than speed in this context, so we do often + * realloc to change the buffer size even if not required. + * This should protect about strange usage patterns that may result + * in a lot of memory allocated. + * + * ----------------------------------------------------------------------------- + * Security auditing history: + * format is SECAUDIT(date)(time spent in seconds)(audited part) + * + * SECAUDIT(Dec 18 2001)(3600)(all) + * SECAUDIT(Aug 19 2003)(600)(adbuf_printf) + * + * After the last security auditing the code changed, so a new + * auditing is needed as fast as possible. + * Remember to audit adbuf.h too. + * + * ----------------------------------------------------------------------------- + * CHANGES + * + * 18 Aug 2003 - Changes section just created. + * 19 Aug 2003 - Added adbuf_printf(). + * + * ----------------------------------------------------------------------------- + * HISTORY OF SECURITY VULNERABILITIES + * + * - Nothing discovered for now. + * + * ----------------------------------------------------------------------------- + * TODO + * + * - adbuf_slice(), with Python-like semantics + * - adbuf_split(), similar to the TCL split command + * - minimal documentation + */ + +/* $Id: adbuf.c,v 1.1.1.1 2003/08/31 17:24:00 antirez Exp $ */ + +#include +#include +#include +#include +#include + +#include "adbuf.h" + +/* initialize a new buffer. The new empty buffer will + * appear as an empty nul terminated string to functions + * that expects a string */ +int adbuf_init(struct adbuf *b) +{ + b->buf = malloc(1); + /* note that if the allocation fails b->buf is set to NULL + * so it's safe to call adbuf_free() after a failed initialization */ + if (b->buf == NULL) + return 1; + b->buf[0] = '\0'; + b->size = 1; + b->left = 1; + return 0; +} + +/* free a buffer */ +void adbuf_free(struct adbuf *b) +{ + if (b->buf) { /* not really needed with sane libC */ + free(b->buf); + b->buf = NULL; + } +} + +/* reset the buffer */ +int adbuf_reset(struct adbuf *b) +{ + adbuf_free(b); + return adbuf_init(b); +} + +/* add data to the buffer 'b'. return 0 on success, 1 on out of memory. + * len = 0 and data = NULL is valid */ +int adbuf_add(struct adbuf *b, void *data, size_t len) +{ + if (adbuf_ptr(b) == NULL) + return 1; /* bad buffer in input */ + if (len == 0) + return 0; /* nothing to add */ + if ((len+1) > b->left) { /* need one more byte to add a nul term */ + size_t newsz = b->size + len + ADBUF_INCR; + void *t = realloc(b->buf, newsz); + + if (t == NULL) + return 1; /* out of memory */ + b->buf = t; + b->left += len + ADBUF_INCR; + b->size = newsz; + } + memcpy(b->buf + adbuf_used(b), data, len); + b->buf[adbuf_used(b)+len] = '\0'; /* always nul term */ + b->left -= len; + return 0; +} + +/* adbuf_addchar() is like adbuf_add() when {len} = 1, but sligthly + * optmized to add just one byte */ +int adbuf_addchar(struct adbuf *b, int c) +{ + if (adbuf_ptr(b) == NULL) + return 1; /* bad buffer in input */ + if (b->left >= 2) { + unsigned char *p = (unsigned char*) b->buf + adbuf_used(b); + + *p = c; + *(p+1) = '\0'; + b->left -= 1; + return 0; + } else { + unsigned char t[1]; + + t[0] = c; + return adbuf_add(b, &t, 1); + } + return 0; /* unreached */ +} + +/* add the given nul terminated string */ +int adbuf_strcat(struct adbuf *b, char *string) +{ + return adbuf_add(b, string, strlen(string)); +} + +/* concatenate the buffer b to the buffer a */ +int adbuf_cat(struct adbuf *a, struct adbuf *b) +{ + return adbuf_add(a, b->buf, adbuf_used(b)); +} + +/* cut the buffer to 'count' bytes on the right. If the used buffer is + * already smaller than 'count' no operation is performed. + * The function preserves the nul term. + * On success zero is returned. The function returns 1 on out of memory */ +int adbuf_cut(struct adbuf *b, size_t count) +{ + char *t; + + if (adbuf_ptr(b) == NULL) + return 1; /* bad buffer in input */ + if (count >= adbuf_used(b)) + return 0; + count++; /* preserve space for the nul term */ + t = realloc(b->buf, count); + if (t == NULL) + return 1; /* out of memory */ + t[count-1] = '\0'; + b->buf = t; + b->size = count; + b->left = 1; /* the nul term is conceptually free space */ + return 0; +} + +/* discard count characters on the left */ +int adbuf_ltrim(struct adbuf *b, size_t count) +{ + char *t; + size_t newlen; + + if (adbuf_ptr(b) == NULL) + return 1; /* bad buffer in input */ + if (count == 0) /* nothing to trim */ + return 0; + /* to discard all the buffer on the left is just + * the same as to reset the buffer */ + if (count >= adbuf_used(b)) + return adbuf_reset(b); + newlen = adbuf_used(b)-count; + t = malloc(newlen+1); /* add one byte for the nul term */ + if (t == NULL) + return 1; /* out of memory */ + memcpy(t, adbuf_ptr(b)+count, newlen); + t[newlen] = '\0'; + free(b->buf); + b->buf = t; + b->size = newlen+1; + b->left = 1; + return 0; +} + +/* discard count caracters on the right */ +int adbuf_rtrim(struct adbuf *b, size_t count) +{ + return adbuf_cut(b, adbuf_used(b)-count); +} + +#define ADBUF_ITOABUFSZ 32 /* ok for 64bit integers and more */ + +/* add the string rappresentation of the long integer l */ +int adbuf_add_long(struct adbuf *b, long l) +{ + int n = 0; + char s[ADBUF_ITOABUFSZ]; + char *p = s+ADBUF_ITOABUFSZ-1; + + *p-- = '\0'; + if (l < 0) { + n = 1; + l = -l; + } + while(p > s) { + *p-- = '0' + (l % 10); + l /= 10; + if (l == 0) + break; + } + if (n) + *p-- = '-'; + p++; + return adbuf_strcat(b, p); +} + +/* the same as adbuf_add_long() but with unsigned integers */ +int adbuf_add_ulong(struct adbuf *b, unsigned long l) +{ + char s[ADBUF_ITOABUFSZ]; + char *p = s+ADBUF_ITOABUFSZ-1; + *p-- = '\0'; + while(p >= s) { + *p-- = '0' + (l % 10); + l /= 10; + if (l == 0) + break; + } + p++; + return adbuf_strcat(b, p); +} + +/* clone the buffer src in the buffer dst. + * The buffers will be indipendent */ +int adbuf_clone(struct adbuf *src, struct adbuf *dst) +{ + if (adbuf_ptr(src) == NULL) + return 1; /* bad buffer in input */ + if (adbuf_init(dst)) + return 1; /* out of memory */ + return adbuf_add(dst, adbuf_ptr(src), adbuf_used(src)); +} + +/* Concat to the buffer using printf-like format. + * Note that while this function try to detect + * non-C99 vsnprintf() behaviour, it can be + * unsafe with some vsnprintf() implementation. + * + * On Linux with glibc >= 2.1, and recent *BSDs, and + * in any other system with a C99-wise vsprintf(), it is sane. + * On Linux with glibc < 2.1 it should be still secure, + * but the behaviour is different (unable to handle strings + * with more than ADBUF_PRINTF_BUFSZ chars). + * On other non-C99 systems be prepared to random results. */ +#define ADBUF_PRINTF_BUFSZ 1024 +int adbuf_printf(struct adbuf *dst, const char *fmt, ...) +{ + char buf[ADBUF_PRINTF_BUFSZ]; + int retval; + va_list ap; + + va_start(ap, fmt); + retval = vsnprintf(buf, ADBUF_PRINTF_BUFSZ, fmt, ap); + buf[ADBUF_PRINTF_BUFSZ-1] = '\0'; + va_end(ap); + + if (retval <= -1) { /* pre-C99 vsnprintf() behaviour */ + /* We just append the output without to care + * about a too slow buffer. This isn't a security + * issue, but the semantics of adbuf_printf() changes + * on this systems. */ + return adbuf_add(dst, buf, strlen(buf)); + } + if (retval >= ADBUF_PRINTF_BUFSZ) { /* PRINTF_BUFSZ wasn't enough */ + /* Use dynamic allocation */ + char *dynbuf; + int newretval; + + if ((dynbuf = malloc(retval+1)) == NULL) + return 1; /* Out of memory */ + va_start(ap, fmt); + newretval = vsnprintf(dynbuf, retval+1, fmt, ap); + dynbuf[retval] = '\0'; + va_end(ap); + + /* If we can trust the return value, we can avoid + * strlen() */ + if (newretval == retval) { + int rv; + rv = adbuf_add(dst, dynbuf, retval); + free(dynbuf); + return rv; + } else { /* On strange results we are more prudent */ + int rv; + rv = adbuf_add(dst, dynbuf, strlen(dynbuf)); + free(dynbuf); + return rv; + } + } else { /* The simple case */ + return adbuf_add(dst, buf, retval); + } +} + +#ifdef TEST_MAIN + +#include + +int main(void) +{ + struct adbuf b, bb; + int add = 0, i; + + adbuf_init(&b); + for(i = 0; i < 6; i++) + adbuf_strcat(&b, ".,;-+*#*+-;,."); + while(adbuf_used(&b) > 0) { + for (i = 0; i < add; i++) printf(" "); + printf("%s\n", adbuf_ptr(&b)); + adbuf_rtrim(&b, 1); + adbuf_ltrim(&b, 1); + add++; + } + adbuf_free(&b); + adbuf_init(&b); + for (i = 0; i < 6000; i++) { + char c; + for (c = 'A'; c <= 'Z'; c++) + adbuf_addchar(&b, c); + } + adbuf_rtrim(&b, adbuf_used(&b)-500); + printf("%s\n", adbuf_ptr(&b)); + adbuf_free(&b); + adbuf_init(&b); + adbuf_strcat(&b, "adbuf_printf with small output: "); + adbuf_printf(&b, "%d %04x", 123456789, 123456789); + printf("%s\n", adbuf_ptr(&b)); + adbuf_reset(&b); + for (i = 0; i < 1024; i++) { + adbuf_addchar(&b, 'X'); + } + adbuf_init(&bb); + adbuf_printf(&bb, "%s---%s", + adbuf_ptr(&b), adbuf_ptr(&b)); + adbuf_free(&b); + printf("bif printf test... "); + if (strlen(adbuf_ptr(&bb)) == (1024*2)+3) + printf("PASSED\n"); + else + printf("FALIED!!!\n"); + adbuf_free(&bb); + return 0; +} +#endif /* TEST_MAIN */ diff --git a/adbuf.h b/src/adbuf.h similarity index 76% rename from adbuf.h rename to src/adbuf.h index 8b8daee..ef8ad08 100644 --- a/adbuf.h +++ b/src/adbuf.h @@ -12,20 +12,20 @@ #include struct adbuf { - char *buf; - size_t size; /* total buffer size */ - size_t left; /* unused buffer size */ - /* the size of data stored is just size-left */ + char *buf; + size_t size; /* total buffer size */ + size_t left; /* unused buffer size */ + /* the size of data stored is just size-left */ }; -#define ADBUF_INCR 256 /* note that this MUST BE >= 1 */ -#define adbuf_used(b) ((b)->size - (b)->left) -#define adbuf_ptr(b) ((b)->buf) +#define ADBUF_INCR 256 /* note that this MUST BE >= 1 */ +#define adbuf_used(b) ((b)->size - (b)->left) +#define adbuf_ptr(b) ((b)->buf) /* Rawly create an adbuf object. 's' is supposed to be some heap * memory already allocated, with some nul-term string inside */ #define adbuf_from_heapstring(b,s) \ - do { b->buf = s; b->left = 0; b->size = strlen(s); } while(0) + do { b->buf = s; b->left = 0; b->size = strlen(s); } while(0) int adbuf_init(struct adbuf *b); void adbuf_free(struct adbuf *b); diff --git a/src/antigetopt.c b/src/antigetopt.c new file mode 100644 index 0000000..af89a4d --- /dev/null +++ b/src/antigetopt.c @@ -0,0 +1,297 @@ +/* antigetopt -- a getopt replacement + * Copyright(C) 2001 Salvatore Sanfilippo + * This software is released under the GPL license + * see the COPYING file for more information */ + +/* $Id: antigetopt.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +/* TODO: + * argument list sanity check */ + +#include +#include +#include + +#include "antigetopt.h" + +/* global vars */ +char *ago_optarg = NULL; +char *ago_optname = NULL; +char ago_optchar = '\0'; + +/* static vars */ +static struct ago_exception { + int (*tester)(void); + char *msg; +} ago_exceptions[3] = { + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL } +}; + +static int ago_exception_bits[] = { AGO_EXCEPT0, AGO_EXCEPT1, AGO_EXCEPT2 }; + +/* static functions */ +static struct ago_optlist +*ago_lookup(struct ago_optlist *list, char *arg, int *islong, int *amb); +static int strinitcmp(char *a, char *b); + +/*----------------------------- implementation ------------------------------ */ + +int antigetopt(int argc, char **argv, struct ago_optlist *list) +{ + static char **save_argv = NULL; + static char *chain = NULL; + static int endoptions = 0; + struct ago_optlist *opt; + int islong; + + /* Reset */ + if (argv == NULL) { + save_argv = NULL; + chain = NULL; + endoptions = 0; + return AGO_RESET; + } else { + if (save_argv == NULL) { + save_argv = argv+1; /* skips the argv[0] */ + /* XXX: argument list sanity check */ + } + } + +chain_start: + if (chain) { + if (*chain == '\0') + chain = NULL; + else { + if ((opt = ago_lookup(list, chain, &islong, NULL)) + == NULL) + return AGO_UNKNOWN; + if (!(opt->ao_flags & AGO_NOARG)) { + /* the if expression maybe false if the + * argument is optional */ + if (chain[1] == '\0' && *save_argv) + ago_optarg = *save_argv++; + /* while it is mandatory for the NEEDARG type */ + else if (opt->ao_flags & AGO_NEEDARG) + return AGO_REQARG; + } + chain++; + return opt->ao_id; + } + } + + argv = save_argv; + + /* handle the "--" special option */ + if (*argv && strcmp(*argv, "--") == 0) { + endoptions = 1; + argv++; + save_argv++; + } + + while(*argv) { + /* The option must start with '-' */ + if (!endoptions && argv[0][0] == '-' && argv[0][1] != '\0') { + int amb; + + /* note: ago_lookup also sets ago_optname */ + if ((opt = ago_lookup(list, argv[0], &islong, &amb)) + == NULL) + return amb ? AGO_AMBIG : AGO_UNKNOWN; + + /* handle the collapsed short options */ + if (!islong && argv[0][2] != '\0') { + chain = argv[0]+1; + save_argv++; + goto chain_start; + } + + /* if the option require or may have an argument */ + ago_optarg = NULL; + /* If the argument is needed we get the next argv[] + * element without care about what it contains */ + if (opt->ao_flags & AGO_NEEDARG) { + if (argv[1] == NULL) + return AGO_REQARG; + ago_optarg = argv[1]; + argv++; + } + /* If the argument is optional we only recognize it + * as argument if it does not starts with '-' */ + else if (opt->ao_flags & AGO_OPTARG) { + if (argv[1] && argv[1][0] != '-') { + ago_optarg = argv[1]; + argv++; + } + } + save_argv = argv+1; + return opt->ao_id; + } else { + save_argv = argv+1; + ago_optarg = argv[0]; + ago_optchar = '\0'; + ago_optname = NULL; + return AGO_ALONE; + } + } + return AGO_EOF; +} + +#define UNK_SHORT_ERRSTRING "invalid option -- %c\n" +#define UNK_LONG_ERRSTRING "unrecognized option `--%s'\n" +#define ARG_SHORT_ERRSTRING "option requires an argument -- %c\n" +#define ARG_LONG_ERRSTRING "option `--%s' requires an argument\n" +#define AMB_ERRSTRING "option `--%s' is ambiguos\n" +#define IERR_ERRSTRING "internal error. ago_gnu_error() called with " \ + "a bad error code (%d)\n" +void ago_gnu_error(char *pname, int error) +{ + if (pname) + fprintf(stderr, "%s: ", pname); + switch(error) { + case AGO_UNKNOWN: + if (ago_optname) + fprintf(stderr, UNK_LONG_ERRSTRING, + ago_optname); + else + fprintf(stderr, UNK_SHORT_ERRSTRING, + ago_optchar); + break; + case AGO_REQARG: + if (ago_optname) + fprintf(stderr, ARG_LONG_ERRSTRING, + ago_optname); + else + fprintf(stderr, ARG_SHORT_ERRSTRING, + ago_optchar); + break; + case AGO_AMBIG: + fprintf(stderr, AMB_ERRSTRING, ago_optname); + break; + default: + fprintf(stderr, IERR_ERRSTRING, error); + break; + } +} + +int ago_set_exception(int except_nr, int (*tester)(void), char *msg) +{ + if (tester == NULL || msg == NULL || except_nr < 0 || except_nr >= 3) + return -1; + ago_exceptions[except_nr].tester = tester; + ago_exceptions[except_nr].msg = msg; + return 0; +} + +/*-------------------------- static functions ------------------------------- */ + +struct ago_optlist +*ago_lookup(struct ago_optlist *list, char *arg, int *islong, int *amb) +{ + int i; + + /* ago_lookup can be receive as `arg' a pointer to a + * long argument, like --option, a pointer to a short + * argument like -O, or just a pointer to a char sequence + * in the case of collapsed short arguments like -abcde. */ + + /* Clear the 'ambiguos' flag, used to report the caller + * an ambiguos option abbreviation error */ + if (amb) *amb = 0; + + if (*arg == '-') /* skips the first - if any */ + arg++; + + switch(*arg) { + case '\0': + return NULL; + case '-': + *islong = 1; + arg++; /* skip the last - */ + break; + default: + *islong = 0; + break; + } + + /* search the argument in the list */ + if (*islong) { + int retval; + struct ago_optlist *last = NULL; + + while(!(list->ao_flags & AGO_ENDOFLIST)) { + ago_optname = arg; + ago_optchar = '\0'; + if ((retval = strinitcmp(arg, list->ao_long)) != 0) { + switch(retval) { + case 1: + if (last) { + if (amb) *amb = 1; + return NULL; + } + last = list; + break; + case 2: + goto ok; + } + } + list++; + } + if (last) { + ago_optname = last->ao_long; + list = last; + goto ok; + } + } else { + ago_optchar = *arg; + ago_optname = NULL; + while(!(list->ao_flags & AGO_ENDOFLIST)) { + if (*arg == list->ao_short) + goto ok; + list++; + } + } + return NULL; +ok: + /* handle the exceptions if any */ + for (i = 0; i < 3; i++) { + if ((list->ao_flags & ago_exception_bits[i]) && + ago_exceptions[i].tester) + { + if (ago_exceptions[i].tester()) { + if (ago_optname) { + fprintf(stderr, "%s `--%s'\n", + ago_exceptions[i].msg, + ago_optname); + } else { + fprintf(stderr, "%s `-%c'\n", + ago_exceptions[i].msg, + ago_optchar); + } + exit(1); + } + } + } + return list; +} + +/* Given two strings this function returns: + * 1, if the strings are the same for the len of the first string (abc, abcde) + * 2, if the strings are exactly the same: (abcd, abcd) + * otherwise zero is returned (abcde, abcd) ... (djf, 293492) */ +int strinitcmp(char *a, char *b) +{ + if (!a || !b) + return 0; + while (*a && *b) { + if (*a != *b) + return 0; + a++; b++; + } + if (*a) + return 0; + if (*a == *b) + return 2; + return 1; +} diff --git a/src/antigetopt.h b/src/antigetopt.h new file mode 100644 index 0000000..8b658f6 --- /dev/null +++ b/src/antigetopt.h @@ -0,0 +1,35 @@ +#ifndef __ANTIGETOPT_H +#define __ANTIGETOPT_H + +/* special return codes */ +enum { AGO_EOF=4000, AGO_ALONE, AGO_UNKNOWN, AGO_REQARG, AGO_RESET, AGO_AMBIG }; + +/* option flags */ +#define AGO_NOARG (1<<0) /* no argument */ +#define AGO_NEEDARG (1<<1) /* required argument */ +#define AGO_OPTARG (1<<2) /* optional argument */ +#define AGO_EXCEPT0 (1<<3) /* exception #0 */ +#define AGO_EXCEPT1 (1<<4) /* exception #1 */ +#define AGO_EXCEPT2 (1<<5) /* exception #3 */ +#define AGO_ENDOFLIST (1<<15) /* end of argument list marker */ + +/* option list null term */ +#define AGO_LIST_TERM {'\0',NULL,0,AGO_ENDOFLIST} + +/* The structure that defines an argument */ +struct ago_optlist { + char ao_short; + char *ao_long; + int ao_id; + int ao_flags; +}; + +extern char *ago_optarg; +extern char *ago_optname; +extern char ago_optchar; + +int antigetopt(int argc, char **argv, struct ago_optlist *list); +void ago_gnu_error(char *pname, int error); +int ago_set_exception(int except_nr, int (*tester)(void), char *msg); + +#endif /* __ANTIGETOPT_H */ diff --git a/src/apd.c b/src/apd.c new file mode 100644 index 0000000..3ad10b0 --- /dev/null +++ b/src/apd.c @@ -0,0 +1,1038 @@ +/* Copyright (C) 2000,2001 Salvatore Sanfilippo + * See the LICENSE file for more information. + * + * ARS Packet Description System. + * + * Please, prefix all the function with ars_d_ */ + +/* $Id: apd.c,v 1.3 2003/09/07 11:21:18 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ars.h" +#include "hstring.h" +#include "hex.h" + +/* FIXME: parsing should use dynamic buffers to use less memory. + * For now we support MTU up to 3000 */ +#define ARS_MAX_TSIZE (3000*4) +char *ars_d_parser(char *t, char *next, size_t size) +{ + int i = 0; + + if (size == 0 || next == NULL || *t == '\0') + return NULL; + size--; /* space for nul term */ + while (1) { + /* no space for the next char */ + if (i == size) { + next[i] = '\0'; + return t; + } + switch(*t) { + case '\0': + case '(': + case ')': + case ',': + case '=': + case '+': + if (i == 0) { + next[i] = *t; + next[i+1] = '\0'; + return t+1; + } else { + next[i] = '\0'; + return t; + } + default: + next[i++] = *t++; + break; + } + } + return NULL; /* unreached */ +} + +/* states */ +#define ARS_G_LAYER 0 +#define ARS_G_FIELD_OR_CBRACE 1 +#define ARS_G_VALUE 2 +#define ARS_G_OBRACE_OR_PLUS 3 +#define ARS_G_CBRACE 4 +#define ARS_G_COMMA_OR_CBRACE 5 +#define ARS_G_LEN_OR_PLUS 6 +#define ARS_G_PLUS 7 +#define ARS_G_EQUAL 8 + +struct ars_d_keyword_info { + char *ki_keyword; + int ki_opt; + void *(*ki_add) (struct ars_packet *pkt, int opt); + int (*ki_set) (struct ars_packet *pkt, int layer, char *f, char *v); +}; + +#define ARS_DKINFO_SIZE 64 + +/* If the user specify a layer number of -1 with *set functions, the + * last layer is selected */ +#define ARS_DEF_LAYER \ +do { \ + if (layer == ARS_LAST_LAYER) \ + layer = pkt->p_layer_nr - 1; \ + if (ars_valid_layer(layer) != -ARS_OK) \ + return -ARS_INVALID; \ +} while(0) + +#define BOGUS_SET_F(x) \ + int (x)(struct ars_packet *pkt, int layer, char *f, char *v) { return 0; } + +int ars_d_set_ip(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_udp(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_tcp(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_icmp(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_data(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_ipopt_rr(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_ipopt_ts(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_ipopt_sid(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_ipopt_sec(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_ipopt_dumb(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_tcpopt_mss(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_tcpopt_wscale(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_tcpopt_sack(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_tcpopt_echo(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_tcpopt_dumb(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_igrp(struct ars_packet *pkt, int layer, char *f, char *v); +int ars_d_set_igrpentry(struct ars_packet *pkt, int layer, char *f, char *v); +BOGUS_SET_F(ars_d_set_tcpopt_ts) + +struct ars_d_keyword_info ars_dkinfo[ARS_DKINFO_SIZE] = { + /* KEYWORD OPT ADD function SET function * + * --------------------------------------------------------- */ + {"ip", 0, ars_add_iphdr, ars_d_set_ip}, + {"ip.eol", ARS_IPOPT_EOL, ars_add_ipopt, ars_d_set_ipopt_dumb}, + {"ip.nop", ARS_IPOPT_NOP, ars_add_ipopt, ars_d_set_ipopt_dumb}, + {"ip.sec", ARS_IPOPT_SEC, ars_add_ipopt, ars_d_set_ipopt_sec}, + {"ip.sid", ARS_IPOPT_SID, ars_add_ipopt, ars_d_set_ipopt_sid}, + {"ip.lsrr", ARS_IPOPT_LSRR, ars_add_ipopt, ars_d_set_ipopt_rr}, + {"ip.ssrr", ARS_IPOPT_SSRR, ars_add_ipopt, ars_d_set_ipopt_rr}, + {"ip.rr", ARS_IPOPT_RR, ars_add_ipopt, ars_d_set_ipopt_rr}, + {"ip.ts", ARS_IPOPT_TIMESTAMP, ars_add_ipopt, ars_d_set_ipopt_ts}, + {"udp", 0, ars_add_udphdr, ars_d_set_udp}, + {"tcp", 0, ars_add_tcphdr, ars_d_set_tcp}, + {"tcp.eol", ARS_TCPOPT_EOL, ars_add_tcpopt, ars_d_set_tcpopt_dumb}, + {"tcp.nop", ARS_TCPOPT_NOP, ars_add_tcpopt, ars_d_set_tcpopt_dumb}, + {"tcp.mss", ARS_TCPOPT_MAXSEG, ars_add_tcpopt, ars_d_set_tcpopt_mss}, + {"tcp.wscale", ARS_TCPOPT_WINDOW, ars_add_tcpopt, ars_d_set_tcpopt_wscale}, + {"tcp.sackperm", ARS_TCPOPT_SACK_PERM, ars_add_tcpopt, ars_d_set_tcpopt_dumb}, + {"tcp.sack", ARS_TCPOPT_SACK, ars_add_tcpopt, ars_d_set_tcpopt_sack}, + {"tcp.echo", ARS_TCPOPT_ECHOREQUEST, ars_add_tcpopt, ars_d_set_tcpopt_echo}, + {"tcp.echoreply", ARS_TCPOPT_ECHOREPLY, ars_add_tcpopt, ars_d_set_tcpopt_echo}, + {"tcp.ts", ARS_TCPOPT_TIMESTAMP, ars_add_tcpopt, ars_d_set_tcpopt_ts}, + {"icmp", 0, ars_add_icmphdr, ars_d_set_icmp}, + {"igrp", 0, ars_add_igrphdr, ars_d_set_igrp}, + {"igrp.entry", 0, ars_add_igrpentry, ars_d_set_igrpentry}, + {"data", 0, ars_add_data, ars_d_set_data}, + {NULL, 0, NULL, NULL} /* nul term */ +}; + +struct ars_d_keyword_info *ars_get_keyword_by_name(char *name) +{ + struct ars_d_keyword_info *k = ars_dkinfo; + + while (k->ki_keyword) { + if (strcasecmp(k->ki_keyword, name) == 0) + return k; + k++; + } + return NULL; +} + +int ars_d_setlayer_size(struct ars_packet *pkt, int layer, char *size) +{ + size_t newsize; + + ARS_DEF_LAYER; + newsize = ars_atou(size); + if (newsize < 1 || newsize > pkt->p_layer[layer].l_size) { + ars_set_error(pkt, "Invalid layer size in description"); + return -ARS_INVALID; + } + pkt->p_layer[layer].l_size = newsize; + + __D(printf("Setting the layer to size %s\n", size);) + return -ARS_OK; +} + +int ars_d_set_ip(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_iphdr *ip; + + ARS_DEF_LAYER; + ip = pkt->p_layer[layer].l_data; + + if (strcasecmp(f, "saddr") == 0) { + return ars_resolve(pkt, &ip->saddr, v); + } else if (strcasecmp(f, "daddr") == 0) { + return ars_resolve(pkt, &ip->daddr, v); + } else if (strcasecmp(f, "ihl") == 0) { + ip->ihl = ars_atou(v); + pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_HDRLEN; + } else if (strcasecmp(f, "ver") == 0) { + ip->version = ars_atou(v); + pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_VERSION; + } else if (strcasecmp(f, "tos") == 0) { + ip->tos = ars_atou(v); + } else if (strcasecmp(f, "totlen") == 0) { + ip->tot_len = htons(ars_atou(v)); + pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_TOTLEN; + } else if (strcasecmp(f, "id") == 0) { + ip->id = htons(ars_atou(v)); + } else if (strcasecmp(f, "fragoff") == 0) { + ip->frag_off = ip->frag_off & 0xE000; + ip->frag_off |= htons(ars_atou(v) >> 3); + } else if (strcasecmp(f, "mf") == 0) { + if (ars_atou(v) == 0) + ip->frag_off &= htons(~ARS_IP_MF); + else + ip->frag_off |= htons(ARS_IP_MF); + } else if (strcasecmp(f, "df") == 0) { + if (ars_atou(v) == 0) + ip->frag_off &= htons(~ARS_IP_DF); + else + ip->frag_off |= htons(ARS_IP_DF); + } else if (strcasecmp(f, "rf") == 0) { + if (ars_atou(v) == 0) + ip->frag_off &= htons((u_int16_t)~ARS_IP_RF); + else + ip->frag_off |= htons(ARS_IP_RF); + } else if (strcasecmp(f, "ttl") == 0) { + ip->ttl = ars_atou(v); + } else if (strcasecmp(f, "proto") == 0) { + if (!strcasecmp(v, "icmp")) { + ip->protocol = ARS_IPPROTO_ICMP; + } else if (!strcasecmp(v, "udp")) { + ip->protocol = ARS_IPPROTO_UDP; + } else if (!strcasecmp(v, "tcp")) { + ip->protocol = ARS_IPPROTO_TCP; + } else { + ip->protocol = ars_atou(v); + } + pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_PROTOCOL; + } else if (strcasecmp(f, "cksum") == 0) { + ip->check = htons(ars_atou(v)); + pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_CKSUM; + } else { + ars_set_error(pkt, "Invalid field for IP layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +/* Note: for all the variable-length ip options the allocated layer data + * length is always as big as possible (40 bytes), so set_ipopt_rr() and + * other similar functions don't need to check if there is enough room. + * Of course functions shoult still check to not overflow over the 40 + * bytes, but this makes very little sense. */ +#define IPOPTRR_MAX_ENTRIES 9 +int ars_d_set_ipopt_rr(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_ipopt *ipopt; + + ARS_DEF_LAYER; + ipopt = pkt->p_layer[layer].l_data; + + if (strcasecmp(f, "optlen") == 0) { + ipopt->len = ars_atou(v); + } else if (strcasecmp(f, "ptr") == 0) { + ipopt->un.rr.ptr = ars_atou(v); + pkt->p_layer[layer].l_flags |= ARS_TAKE_IPOPT_PTR; + } else if (strcasecmp(f, "data") == 0) { + char *addrv[IPOPTRR_MAX_ENTRIES]; + int vlen = strlen(v), num, i; + char *vcopy = alloca(vlen+1); + unsigned char *data = pkt->p_layer[layer].l_data; + + memcpy(vcopy, v, vlen+1); + num = strftok("/", vcopy, addrv, IPOPTRR_MAX_ENTRIES); + for (i = 0; i < num; i++) { + __u32 addr; + int err; + + err = ars_resolve(pkt, &addr, addrv[i]); + if (err != -ARS_OK) + return err; + memcpy(data+3+(i*4), &addr, 4); + } + if (ARS_DONTTAKE(pkt->p_layer[layer].l_flags, + ARS_TAKE_IPOPT_PTR)) + { + /* For the record route option the default ptr + * is at the end of the specified entries */ + if (ipopt->kind == ARS_IPOPT_RR) { + ipopt->un.rr.ptr = 4+(num*4); + } else { + /* For SSRR and LSRR is set at the start + * if not otherwise specified. */ + ipopt->un.rr.ptr = 4; + } + } + } else { + ars_set_error(pkt, "Invalid field for IP.RR layer: '%s'", f); + return -ARS_INVALID; + } + + return -ARS_OK; +} + +#define IPOPTTS_MAX_ENTRIES 9 +int ars_d_set_ipopt_ts(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_ipopt *ipopt; + int flags, overflow; + + ARS_DEF_LAYER; + ipopt = pkt->p_layer[layer].l_data; + overflow = (ipopt->un.ts.flags & 0xF0) >> 4; + flags = ipopt->un.ts.flags & 0xF; + + if (strcasecmp(f, "optlen") == 0) { + ipopt->len = ars_atou(v); + } else if (strcasecmp(f, "ptr") == 0) { + ipopt->un.rr.ptr = ars_atou(v); + pkt->p_layer[layer].l_flags |= ARS_TAKE_IPOPT_PTR; + } else if (strcasecmp(f, "flags") == 0) { + if (strisnum(v)) { + flags = ars_atou(v) & 0xF; + } else { + if (!strcasecmp(v, "tsonly")) + flags = ARS_IPOPT_TS_TSONLY; + else if (!strcasecmp(v, "tsandaddr")) + flags = ARS_IPOPT_TS_TSANDADDR; + else if (!strcasecmp(v, "prespec")) + flags = ARS_IPOPT_TS_PRESPEC; + else { + ars_set_error(pkt, "Invalid symbol for ip.ts flags: '%s' (use: tsonly, tsandaddr, prespec or a numerical value)", v); + return -ARS_INVALID; + } + } + ipopt->un.ts.flags = ((overflow&0xF)<<4)|(flags&0xF); + } else if (strcasecmp(f, "overflow") == 0) { + overflow = ars_atou(v) & 0xF; + ipopt->un.ts.flags = ((overflow&0xF)<<4)|(flags&0xF); + } else if (strcasecmp(f, "data") == 0) { + char *addrv[IPOPTTS_MAX_ENTRIES]; + int vlen = strlen(v), num, i; + char *vcopy = alloca(vlen+1); + unsigned char *data = pkt->p_layer[layer].l_data; + + memcpy(vcopy, v, vlen+1); + num = strftok("/", vcopy, addrv, IPOPTTS_MAX_ENTRIES); + for (i = 0; i < num; i++) { + __u32 addr, ts; + int err; + char *p; + + p = strchr(addrv[i], '@'); + if (p) { + if (flags == ARS_IPOPT_TS_TSONLY) { + ars_set_error(pkt, "Gateway specified but ip.ts flags set to 'tsonly'. (Try flags=tsandaddr,data=...)"); + return -ARS_INVALID; + } + *p = '\0'; + p++; + err = ars_resolve(pkt, &addr, p); + if (err != -ARS_OK) + return err; + ts = ars_atou(addrv[i]); + ts = htonl(ts); + if (i < 4) { + memcpy(data+4+(i*8), &addr, 4); + memcpy(data+8+(i*8), &ts, 4); + }; + } else { + if (flags == ARS_IPOPT_TS_TSANDADDR || + flags == ARS_IPOPT_TS_PRESPEC) { + ars_set_error(pkt, "Gateway not specified in data for ip.ts, but flags set to 'tsandaddr' or 'prespec'. (Try flags=tsonly)"); + return -ARS_INVALID; + } + ts = ars_atou(addrv[i]); + ts = htonl(ts); + memcpy(data+4+(i*4), &ts, 4); + } + } + if (ARS_DONTTAKE(pkt->p_layer[layer].l_flags, + ARS_TAKE_IPOPT_PTR)) + { + if (flags == ARS_IPOPT_TS_TSANDADDR || + flags == ARS_IPOPT_TS_PRESPEC) { + ipopt->un.rr.ptr = 5+(num*8); + } else { + ipopt->un.rr.ptr = 5+(num*4); + } + } + } else { + ars_set_error(pkt, "Invalid field for IP.TS layer: '%s'", f); + return -ARS_INVALID; + } + + return -ARS_OK; +} + +int ars_d_set_ipopt_sid(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_ipopt *ipopt; + + ARS_DEF_LAYER; + ipopt = pkt->p_layer[layer].l_data; + if (strcasecmp(f, "optlen") == 0) { + ipopt->len = ars_atou(v); + } else if (strcasecmp(f, "sid") == 0) { + ipopt->un.sid.id = ars_atou(v); + } else { + ars_set_error(pkt, "Invalid field for IP.SID layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_d_set_ipopt_sec(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_ipopt *ipopt; + + ARS_DEF_LAYER; + ipopt = pkt->p_layer[layer].l_data; + if (strcasecmp(f, "optlen") == 0) { + ipopt->len = ars_atou(v); + } else if (strcasecmp(f, "seclev") == 0) { + ipopt->un.sec.s = ars_atou(v); + } else if (strcasecmp(f, "comp") == 0) { + ipopt->un.sec.c = ars_atou(v); + } else if (strcasecmp(f, "hrest") == 0) { + if (strlen(v) != 4) { + ars_set_error(pkt, "Invalid ip.sec hrest field value of '%s'(should be four hex digits, like this: ...,hrest=252A,...)", v); + return -ARS_INVALID; + } + if (hextobin(&ipopt->un.sec.h, v, 4)) { + ars_set_error(pkt, "Invalid hex value for ip.sec hex: '%s'", v); + return -ARS_INVALID; + } + } else if (strcasecmp(f, "tcc") == 0) { + if (strlen(v) != 6) { + ars_set_error(pkt, "Invalid ip.sec tcc field value of '%s'(should be six hex digits, like this: ...,tcc=252A27,...)", v); + return -ARS_INVALID; + } + if (hextobin(&ipopt->un.sec.h, v, 6)) { + ars_set_error(pkt, "Invalid hex value for ip.sec hex: '%s'", v); + return -ARS_INVALID; + } + } else { + ars_set_error(pkt, "Invalid field for IP.SEC layer: '%s'", f); + return -ARS_INVALID; + } + + return -ARS_OK; +} + +int ars_d_set_ipopt_dumb(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_ipopt *ipopt; + + ARS_DEF_LAYER; + ipopt = pkt->p_layer[layer].l_data; + if (strcasecmp(f, "optlen") == 0) { + ipopt->len = ars_atou(v); + } else { + ars_set_error(pkt, "Invalid field for IP.? layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_d_set_udp(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_udphdr *udp; + + ARS_DEF_LAYER; + udp = pkt->p_layer[layer].l_data; + + if (strcasecmp(f, "sport") == 0) { + udp->uh_sport = htons(ars_atou(v)); + } else if (strcasecmp(f, "dport") == 0) { + udp->uh_dport = htons(ars_atou(v)); + } else if (strcasecmp(f, "len") == 0) { + udp->uh_ulen = htons(ars_atou(v)); + pkt->p_layer[layer].l_flags |= ARS_TAKE_UDP_LEN; + } else if (strcasecmp(f, "cksum") == 0) { + udp->uh_sum = htons(ars_atou(v)); + pkt->p_layer[layer].l_flags |= ARS_TAKE_UDP_CKSUM; + } else { + ars_set_error(pkt, "Invalid field for UDP layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_d_set_tcp(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_tcphdr *tcp; + + ARS_DEF_LAYER; + tcp = pkt->p_layer[layer].l_data; + + if (strcasecmp(f, "sport") == 0) { + tcp->th_sport = htons(ars_atou(v)); + } else if (strcasecmp(f, "dport") == 0) { + tcp->th_dport = htons(ars_atou(v)); + } else if (strcasecmp(f, "seq") == 0) { + tcp->th_seq = htonl(ars_atou(v)); + } else if (strcasecmp(f, "ack") == 0) { + tcp->th_ack = htonl(ars_atou(v)); + } else if (strcasecmp(f, "x2") == 0) { + tcp->th_x2 = ars_atou(v); + } else if (strcasecmp(f, "off") == 0) { + tcp->th_off = ars_atou(v); + pkt->p_layer[layer].l_flags |= ARS_TAKE_TCP_HDRLEN; + } else if (strcasecmp(f, "flags") == 0) { + tcp->th_flags = 0; + if (strchr(v, 'f') || strchr(v, 'F')) + tcp->th_flags |= ARS_TCP_TH_FIN; + if (strchr(v, 's') || strchr(v, 'S')) + tcp->th_flags |= ARS_TCP_TH_SYN; + if (strchr(v, 'r') || strchr(v, 'R')) + tcp->th_flags |= ARS_TCP_TH_RST; + if (strchr(v, 'p') || strchr(v, 'P')) + tcp->th_flags |= ARS_TCP_TH_PUSH; + if (strchr(v, 'a') || strchr(v, 'A')) + tcp->th_flags |= ARS_TCP_TH_ACK; + if (strchr(v, 'u') || strchr(v, 'U')) + tcp->th_flags |= ARS_TCP_TH_URG; + if (strchr(v, 'x') || strchr(v, 'X')) + tcp->th_flags |= ARS_TCP_TH_X; + if (strchr(v, 'y') || strchr(v, 'Y')) + tcp->th_flags |= ARS_TCP_TH_Y; + } else if (strcasecmp(f, "win") == 0) { + tcp->th_win = htons(ars_atou(v)); + } else if (strcasecmp(f, "cksum") == 0) { + tcp->th_sum = htons(ars_atou(v)); + pkt->p_layer[layer].l_flags |= ARS_TAKE_TCP_CKSUM; + } else if (strcasecmp(f, "urp") == 0) { + tcp->th_urp = htons(ars_atou(v)); + } else { + ars_set_error(pkt, "Invalid field for TCP layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_d_set_tcpopt_mss(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_tcpopt *tcpopt; + + ARS_DEF_LAYER; + tcpopt = pkt->p_layer[layer].l_data; + if (strcasecmp(f, "optlen") == 0) { + tcpopt->len = ars_atou(v); + } else if (strcasecmp(f, "size") == 0) { + tcpopt->un.mss.size = htons(ars_atou(v)); + } else { + ars_set_error(pkt, "Invalid field for TCP.MSS layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_d_set_tcpopt_wscale(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_tcpopt *tcpopt; + + ARS_DEF_LAYER; + tcpopt = pkt->p_layer[layer].l_data; + if (strcasecmp(f, "optlen") == 0) { + tcpopt->len = ars_atou(v); + } else if (strcasecmp(f, "shift") == 0) { + tcpopt->un.win.shift = htons(ars_atou(v)); + } else { + ars_set_error(pkt, "Invalid field for TCP.WSCALE layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +#define TCPOPTSACK_MAX_ENTRIES 4 +int ars_d_set_tcpopt_sack(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_tcpopt *tcpopt; + + ARS_DEF_LAYER; + tcpopt = pkt->p_layer[layer].l_data; + if (strcasecmp(f, "optlen") == 0) { + tcpopt->len = ars_atou(v); + } else if (strcasecmp(f, "blocks") == 0) { + char *bv[TCPOPTSACK_MAX_ENTRIES]; + int vlen = strlen(v), num, i; + char *vcopy = alloca(vlen+1); + unsigned char *data = pkt->p_layer[layer].l_data; + + memcpy(vcopy, v, vlen+1); + num = strftok("/", vcopy, bv, TCPOPTSACK_MAX_ENTRIES); + for (i = 0; i < num; i++) { + char *p; + __u32 s_origin, s_len; + + p = strchr(bv[i], '-'); + if (!p) { + ars_set_error(pkt, "Invalid syntax for tcp.sack blocks: '%s' (try ...tcp.sack(blocks=123342-10/12653-50/0-0/0-0)... )"); + return -ARS_INVALID; + } + *p = '\0'; + p++; + s_origin = htonl(ars_atou(bv[i])); + s_len = htonl(ars_atou(p)); + memcpy(data+2+(i*8), &s_origin, 4); + memcpy(data+6+(i*8), &s_len, 4); + } + } else { + ars_set_error(pkt, "Invalid field for TCP.SACK layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_d_set_tcpopt_dumb(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_tcpopt *tcpopt; + + ARS_DEF_LAYER; + tcpopt = pkt->p_layer[layer].l_data; + if (strcasecmp(f, "optlen") == 0) { + tcpopt->len = ars_atou(v); + } else { + ars_set_error(pkt, "Invalid field for TCP.? layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_d_set_tcpopt_echo(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_tcpopt *tcpopt; + + ARS_DEF_LAYER; + tcpopt = pkt->p_layer[layer].l_data; + if (strcasecmp(f, "optlen") == 0) { + tcpopt->len = ars_atou(v); + } else if (strcasecmp(f, "info") == 0) { + u_int32_t info = htonl(ars_atou(v)); + memcpy(tcpopt->un.echo.info, &info, 4); + } else { + ars_set_error(pkt, "Invalid field for TCP.ECHO layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_d_set_icmp(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_icmphdr *icmp; + + ARS_DEF_LAYER; + icmp = pkt->p_layer[layer].l_data; + + if (strcasecmp(f, "type") == 0) { + icmp->type = ars_atou(v); + } else if (strcasecmp(f, "code") == 0) { + icmp->code = ars_atou(v); + } else if (strcasecmp(f, "cksum") == 0) { + icmp->checksum = htons(ars_atou(v)); + pkt->p_layer[layer].l_flags |= ARS_TAKE_ICMP_CKSUM; + } else if (strcasecmp(f, "id") == 0) { + icmp->un.echo.id = htons(ars_atou(v)); + } else if (strcasecmp(f, "seq") == 0) { + icmp->un.echo.sequence = htons(ars_atou(v)); + } else if (strcasecmp(f, "gw") == 0) { + return ars_resolve(pkt, &icmp->un.gateway, v); + } else if (strcasecmp(f, "unused") == 0) { + icmp->un.gateway = htonl(ars_atou(v)); + } else { + ars_set_error(pkt, "Invalid field for ICMP layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_d_set_igrp(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_igrphdr *igrp; + + ARS_DEF_LAYER; + igrp = pkt->p_layer[layer].l_data; + + if (strcasecmp(f, "version") == 0) { + igrp->version = ars_atou(v); + } else if (strcasecmp(f, "opcode") == 0) { + if (strcasecmp(v, "update") == 0) + igrp->opcode = ARS_IGRP_OPCODE_UPDATE; + else if (strcasecmp(v, "request") == 0) + igrp->opcode = ARS_IGRP_OPCODE_REQUEST; + else + igrp->opcode = ars_atou(v); + } else if (strcasecmp(f, "cksum") == 0) { + igrp->checksum = htons(ars_atou(v)); + pkt->p_layer[layer].l_flags |= ARS_TAKE_IGRP_CKSUM; + } else if (strcasecmp(f, "edition") == 0) { + igrp->edition = ars_atou(v); + } else if (strcasecmp(f, "autosys") == 0) { + igrp->autosys = htons(ars_atou(v)); + } else if (strcasecmp(f, "interior") == 0) { + igrp->interior = htons(ars_atou(v)); + } else if (strcasecmp(f, "system") == 0) { + igrp->system= htons(ars_atou(v)); + } else if (strcasecmp(f, "exterior") == 0) { + igrp->exterior = htons(ars_atou(v)); + } else { + ars_set_error(pkt, "Invalid field for IGRP layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +static int igrp_set_dest(unsigned char *d, char *v) +{ + int l = strlen(v); + char *vcopy = alloca(l+1); + char *f0, *f1, *f2; + + memcpy(vcopy, v, l+1); + f0 = vcopy; + if ((f1 = strchr(f0, '.')) == NULL) + return 1; + *f1++ = '\0'; + if ((f2 = strchr(f1, '.')) == NULL) + return 1; + *f2++ = '\0'; + if (!strisnum(f0) || !strisnum(f1) || !strisnum(f2)) + return 1; + d[0] = ars_atou(f0); + d[1] = ars_atou(f1); + d[2] = ars_atou(f2); + return 0; +} + +static void igrp_set_uint24(void *d, char *v) +{ + __u32 t; + unsigned char *x; + + t = htonl(ars_atou(v)); + x = (unsigned char*) &t; + memcpy(d, x+1, 3); +} + +int ars_d_set_igrpentry(struct ars_packet *pkt, int layer, char *f, char *v) +{ + struct ars_igrpentry *entry; + + ARS_DEF_LAYER; + entry = pkt->p_layer[layer].l_data; + + if (strcasecmp(f, "dest") == 0) { + if (igrp_set_dest(entry->destination, v)) { + ars_set_error(pkt, "Invalid IGRP entry 'dest' field value: '%s'\n", v); + return -ARS_INVALID; + } + } else if (strcasecmp(f, "delay") == 0) { + igrp_set_uint24(entry->delay, v); + } else if (strcasecmp(f, "bandwidth") == 0) { + igrp_set_uint24(entry->bandwidth, v); + } else if (strcasecmp(f, "mtu") == 0) { + __u16 mtu = htons(ars_atou(v)); + memcpy(entry->mtu, &mtu, 2); + } else if (strcasecmp(f, "reliability") == 0) { + entry->reliability = ars_atou(v); + } else if (strcasecmp(f, "load") == 0) { + entry->load = ars_atou(v); + } else if (strcasecmp(f, "hopcount") == 0) { + entry->hopcount = ars_atou(v); + } else { + ars_set_error(pkt, "Invalid field for IGRP.ENTRY layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +int ars_push_data(struct ars_packet *pkt, int layer, void *data, size_t size) +{ + char *p; + int old_size; + + ARS_DEF_LAYER; + old_size = pkt->p_layer[layer].l_size; + p = realloc(pkt->p_layer[layer].l_data, old_size + size); + if (p == NULL) + return -ARS_NOMEM; + memcpy(p+old_size, data, size); + pkt->p_layer[layer].l_data = p; + pkt->p_layer[layer].l_size += size; + return ARS_OK; +} + +static int hextab[256]; +static int hextab_initialized = 0; +static char *hexdig = "0123456789abcdef"; + +static char *ars_decode_hex(struct ars_packet *pkt, char *s, int *blen) +{ + int len = strlen(s), i; + unsigned char *d, *saved; + + if (len%2) { + ars_set_error(pkt, "Odd length of 'hex' data"); + return NULL; + } + *blen = len/2; + if (!hextab_initialized) { + memset(hextab, 255, 255); + for (i = 0; i < 16; i++) + hextab[(int)hexdig[i]] = i; + } + if ((d = malloc(*blen)) == NULL) { + ars_set_error(pkt, "Out of memory decoding 'hex' data"); + return NULL; + } + saved = d; + while(*s) { + int x0, x1; + + x0 = hextab[tolower(*s)]; + x1 = hextab[tolower(*(s+1))]; + if (x0 == 255 || x1 == 255) { + ars_set_error(pkt, "Wrong byte for 'hex' data: '%c%c'", + *s, *(s+1)); + free(saved); + return NULL; + } + *d++ = (x0 << 4) | x1; + s += 2; + } + return (char*)saved; +} + +static char *ars_decode_string(struct ars_packet *pkt, char *s, int *blen) +{ + int l = strlen(s), i; + int bl = 0; + unsigned char *d, *saved; + + if (!hextab_initialized) { + memset(hextab, -1, 255); + for (i = 0; i < 16; i++) + hextab[(int)hexdig[i]] = i; + } + if ((d = malloc(l)) == NULL) { + ars_set_error(pkt, "Out of memory decoding 'str' data"); + return NULL; + } + saved = d; + while(*s) { + if (*s == '\\' && *(s+1) && *(s+2)) { + *d++ = (hextab[(int)*(s+1)] << 4) + hextab[(int)*(s+2)]; + s += 3; + } else { + *d++ = *s++; + } + bl++; + } + *blen = bl; + return (char*)saved; +} + +#define ARS_DATA_BUF_SIZE 4096 +int ars_d_set_data(struct ars_packet *pkt, int layer, char *f, char *v) +{ + ARS_DEF_LAYER; + if (strcasecmp(f, "file") == 0) { + int fd, n_read; + unsigned char buffer[ARS_DATA_BUF_SIZE]; + + if ((fd = open(v, O_RDONLY)) == -1) { + ars_set_error(pkt, "Can't open the DATA file '%s': %s", + v, strerror(errno)); + return -ARS_ERROR; + } + if ((n_read = read(fd, buffer, ARS_DATA_BUF_SIZE)) == -1) { + close(fd); + ars_set_error(pkt, "Can't read DATA from file: %s", strerror(errno)); + return -ARS_ERROR; + } + close(fd); + if (n_read == 0) + return -ARS_OK; + return ars_push_data(pkt, layer, buffer, n_read); + } else if (strcasecmp(f, "str") == 0) { + char *binary; + int err, blen; + + binary = ars_decode_string(pkt, v, &blen); + if (binary == NULL) + return -ARS_ERROR; + err = ars_push_data(pkt, layer, binary, blen); + free(binary); + return err; + } else if (strcasecmp(f, "hex") == 0) { + char *binary; + int err, blen; + + binary = ars_decode_hex(pkt, v, &blen); + if (binary == NULL) + return -ARS_ERROR; + err = ars_push_data(pkt, layer, binary, blen); + free(binary); + return err; + } else if (strcasecmp(f, "uint32") == 0) { + int err; + __u32 t, nt; + t = ars_atou(v); + nt = htonl(t); + err = ars_push_data(pkt, layer, (char*)&nt, 4); + return err; + } else if (strcasecmp(f, "uint24") == 0) { + int err; + __u32 t, nt; + unsigned char *x = (unsigned char*) &nt; + t = ars_atou(v); + nt = htonl(t); + err = ars_push_data(pkt, layer, x+1, 3); + return err; + } else if (strcasecmp(f, "uint16") == 0) { + int err; + __u16 t, nt; + t = ars_atou(v); + nt = htons(t); + err = ars_push_data(pkt, layer, (char*)&nt, 2); + return err; + } else if (strcasecmp(f, "uint8") == 0) { + int err; + __u8 t; + t = ars_atou(v); + err = ars_push_data(pkt, layer, (char*)&t, 1); + return err; + } else { + ars_set_error(pkt, "Invalid field for DATA layer: '%s'", f); + return -ARS_INVALID; + } + return -ARS_OK; +} + +/* A Finite state machine to build the packet using the description */ +int ars_d_build(struct ars_packet *pkt, char *t) +{ + struct ars_d_keyword_info *k = NULL; + char next[ARS_MAX_TSIZE]; + char field[ARS_MAX_TSIZE]; + int state = ARS_G_LAYER; + int error; + void *p; + + while ((t = ars_d_parser(t, next, ARS_MAX_TSIZE)) != NULL) { + switch(state) { + case ARS_G_LAYER: + k = ars_get_keyword_by_name(next); + if (k == NULL) { + ars_set_error(pkt, "Unknown keyword: '%s'", next); + return -ARS_INVALID; + } + __D(printf("Adding a new layer (%s)\n", next);) + p = k->ki_add(pkt, k->ki_opt); + if (p == NULL) + return -ARS_INVALID; + state = ARS_G_OBRACE_OR_PLUS; + break; + case ARS_G_FIELD_OR_CBRACE: + if (next[0] == ')' && next[1] == '\0') { + state = ARS_G_LEN_OR_PLUS; + } else { + strncpy(field, next, ARS_MAX_TSIZE); + state = ARS_G_EQUAL; + } + break; + case ARS_G_VALUE: + if (k->ki_set == NULL) { + ars_set_error(pkt, "Field specified for" + "a layer that doesn't support fields"); + return -ARS_INVALID; + } + error = k->ki_set(pkt, ARS_LAST_LAYER, field, next); + if (error != -ARS_OK) + return error; + state = ARS_G_COMMA_OR_CBRACE; + break; + case ARS_G_OBRACE_OR_PLUS: + if (next[0] == '(' && next[1] == '\0') { + state = ARS_G_FIELD_OR_CBRACE; + break; + } else if (next[0] == '+' && next[1] == '\0') { + state = ARS_G_LAYER; + break; + } else { + ars_set_error(pkt, "Missing brace or plus"); + return -ARS_INVALID; + } + break; + case ARS_G_CBRACE: + if (next[0] != ')' || next[1] != '\0') { + ars_set_error(pkt, "Missing closed brace"); + return -ARS_INVALID; + } + state = ARS_G_LEN_OR_PLUS; + break; + case ARS_G_COMMA_OR_CBRACE: + if (next[0] == ')' && next[1] == '\0') { + state = ARS_G_LEN_OR_PLUS; + break; + } else if (next[0] == ',' && next[1] == '\0') { + state = ARS_G_FIELD_OR_CBRACE; + break; + } else { + ars_set_error(pkt, "Missing brace or comma"); + return -ARS_INVALID; + } + break; + case ARS_G_LEN_OR_PLUS: + if (next[0] == '+' && next[1] == '\0') { + state = ARS_G_LAYER; + break; + } + error = ars_d_setlayer_size(pkt, ARS_LAST_LAYER, next); + if (error != -ARS_OK) + return error; + state = ARS_G_PLUS; + break; + case ARS_G_PLUS: + if (next[0] != '+' || next[1] != '\0') { + ars_set_error(pkt, "Missing plus"); + return -ARS_INVALID; + } + state = ARS_G_LAYER; + break; + case ARS_G_EQUAL: + if (next[0] != '=' || next[1] != '\0') { + ars_set_error(pkt, "Missing equal"); + return -ARS_INVALID; + } + state = ARS_G_VALUE; + break; + } + } + if (state != ARS_G_LEN_OR_PLUS && state != ARS_G_PLUS && + state != ARS_G_OBRACE_OR_PLUS) { + ars_set_error(pkt, "Packet description truncated"); + return -ARS_INVALID; + } + return -ARS_OK; +} diff --git a/apdutils.c b/src/apdutils.c similarity index 65% rename from apdutils.c rename to src/apdutils.c index 7860d5d..4dd1efe 100644 --- a/apdutils.c +++ b/src/apdutils.c @@ -25,52 +25,52 @@ * the packet, otherwise 1 is returned. If a given index pointer * is NULL, it is just not used. */ int ars_d_firstfield_off(char *packet, char *layer, char *field, - int *field_start, int *value_start, int *value_end) + int *field_start, int *value_start, int *value_end) { - int layerlen = strlen(layer); - int fieldlen = strlen(field); - int pktlen = strlen(packet); - char *x = alloca(layerlen+3); - char *y = alloca(fieldlen+3); - char *p, *j, *w; - x[0] = '+'; - memcpy(x+1, layer, layerlen); - x[layerlen+1] = '('; - x[layerlen+2] = '\0'; - if (pktlen <= layerlen+1) - return 0; - if (memcmp(packet, x+1, layerlen+1) == 0) { - p = packet; - } else { - p = strstr(packet, x); - if (p == NULL) - return 0; - p++; - } - y[0] = ','; - memcpy(y+1, field, fieldlen); - y[fieldlen+1] = '='; - y[fieldlen+2] = '\0'; - p += layerlen + 1; - pktlen -= p-packet; - if (pktlen <= fieldlen+1) - return 0; - if ((j = strchr(p, ')')) == NULL) - return 0; - if (memcmp(p, y+1, fieldlen+1)) { - p = strstr(p, y); - if (p == NULL || p >= j) - return 0; - p++; - } - if (field_start) *field_start = p-packet; - p += fieldlen + 1; - if (value_start) *value_start = p-packet; - w = strchr(p, ','); - if (w && w < j) - j = w; - if (value_end) *value_end = (j-packet)-1; - return 1; + int layerlen = strlen(layer); + int fieldlen = strlen(field); + int pktlen = strlen(packet); + char *x = alloca(layerlen+3); + char *y = alloca(fieldlen+3); + char *p, *j, *w; + x[0] = '+'; + memcpy(x+1, layer, layerlen); + x[layerlen+1] = '('; + x[layerlen+2] = '\0'; + if (pktlen <= layerlen+1) + return 0; + if (memcmp(packet, x+1, layerlen+1) == 0) { + p = packet; + } else { + p = strstr(packet, x); + if (p == NULL) + return 0; + p++; + } + y[0] = ','; + memcpy(y+1, field, fieldlen); + y[fieldlen+1] = '='; + y[fieldlen+2] = '\0'; + p += layerlen + 1; + pktlen -= p-packet; + if (pktlen <= fieldlen+1) + return 0; + if ((j = strchr(p, ')')) == NULL) + return 0; + if (memcmp(p, y+1, fieldlen+1)) { + p = strstr(p, y); + if (p == NULL || p >= j) + return 0; + p++; + } + if (field_start) *field_start = p-packet; + p += fieldlen + 1; + if (value_start) *value_start = p-packet; + w = strchr(p, ','); + if (w && w < j) + j = w; + if (value_end) *value_end = (j-packet)-1; + return 1; } /* This function extends ars_d_firstfield_off(), allowing to specify @@ -80,26 +80,26 @@ int ars_d_firstfield_off(char *packet, char *layer, char *field, * a quoted IP packet that can be accessed using a skip value of 1 * (to skip the first IP layer). */ int ars_d_field_off(char *packet, char *layer, char *field, int skip, - int *field_start, int *value_start, int *value_end) + int *field_start, int *value_start, int *value_end) { - char *p = packet; - int end, toadd; + char *p = packet; + int end, toadd; - /* Minimal overhead with a zero skip */ - if (skip <= 0) - return ars_d_firstfield_off(packet, layer, field, - field_start, value_start, value_end); - do { - if (!ars_d_firstfield_off(p, layer, field, - field_start, value_start, &end)) - return 0; - toadd = p-packet; - p += end; - } while(skip--); - if (value_end) *value_end = end + toadd; - if (field_start) *field_start += toadd; - if (value_start) *value_start += toadd; - return 1; + /* Minimal overhead with a zero skip */ + if (skip <= 0) + return ars_d_firstfield_off(packet, layer, field, + field_start, value_start, value_end); + do { + if (!ars_d_firstfield_off(p, layer, field, + field_start, value_start, &end)) + return 0; + toadd = p-packet; + p += end; + } while(skip--); + if (value_end) *value_end = end + toadd; + if (field_start) *field_start += toadd; + if (value_start) *value_start += toadd; + return 1; } /* The function calls ars_d_field_off() in order to @@ -108,17 +108,17 @@ int ars_d_field_off(char *packet, char *layer, char *field, int skip, * NULL is returned. */ char *ars_d_field_get(char *packet, char *layer, char *field, int skip) { - int start, end, len; - char *x; + int start, end, len; + char *x; - if (!ars_d_field_off(packet, layer, field, skip, NULL, &start, &end)) - return NULL; - len = end-start+1; - if ((x = malloc(len+1)) == NULL) - return NULL; - memcpy(x, packet+start, len); - x[len] = '\0'; - return x; + if (!ars_d_field_off(packet, layer, field, skip, NULL, &start, &end)) + return NULL; + len = end-start+1; + if ((x = malloc(len+1)) == NULL) + return NULL; + memcpy(x, packet+start, len); + x[len] = '\0'; + return x; } #ifdef TESTMAIN @@ -126,27 +126,27 @@ char packet[] = "ip(ihl=5,ver=4,tos=00,totlen=1340,id=43581,fragoff=0,mf=0,df=1, int main(int argc, char **argv) { - int i = 10000; - int field_start, value_start, value_end; - int skip; + int i = 10000; + int field_start, value_start, value_end; + int skip; - if (argc != 4) - exit(1); - skip = atoi(argv[3]); - if (ars_d_field_off(packet, argv[1], argv[2], skip, - &field_start, &value_start, &value_end)) - { - int j; - printf("|"); - for (j = field_start; j <= value_end; j++) { - printf("%c", packet[j]); - } - printf("|\n"); - } - while(i--) { - ars_d_field_off(packet, argv[1], argv[2], skip, - NULL, NULL, NULL); - } - return 0; + if (argc != 4) + exit(1); + skip = atoi(argv[3]); + if (ars_d_field_off(packet, argv[1], argv[2], skip, + &field_start, &value_start, &value_end)) + { + int j; + printf("|"); + for (j = field_start; j <= value_end; j++) { + printf("%c", packet[j]); + } + printf("|\n"); + } + while(i--) { + ars_d_field_off(packet, argv[1], argv[2], skip, + NULL, NULL, NULL); + } + return 0; } #endif diff --git a/apdutils.h b/src/apdutils.h similarity index 68% rename from apdutils.h rename to src/apdutils.h index 2f8fc46..8a0503d 100644 --- a/apdutils.h +++ b/src/apdutils.h @@ -2,9 +2,9 @@ #define __APD_UTILS_H int ars_d_firstfield_off(char *packet, char *layer, char *field, - int *field_start, int *value_start, int *value_end); + int *field_start, int *value_start, int *value_end); int ars_d_field_off(char *packet, char *layer, char *field, int skip, - int *field_start, int *value_start, int *value_end); + int *field_start, int *value_start, int *value_end); char *ars_d_field_get(char *packet, char *layer, char *field, int skip); #endif diff --git a/src/ars.c b/src/ars.c new file mode 100644 index 0000000..d1ca8e4 --- /dev/null +++ b/src/ars.c @@ -0,0 +1,989 @@ +/* Copyright (C) 2000,2001 Salvatore Sanfilippo + * See the LICENSE file for more information. + * + * TODO: + * o Functions to add addresses and timestamps for some IP and TCP option + * o IGMP support + * o DNS support + * o ARS add_build_layer() facility and Co., read the PROPOSAL file. + */ + +/* $Id: ars.c,v 1.3 2004/04/14 12:30:18 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ars.h" + +/* prototypes */ +int ars_compiler_ip(struct ars_packet *pkt, int layer); +int ars_compiler_ipopt(struct ars_packet *pkt, int layer); +int ars_compiler_tcp(struct ars_packet *pkt, int layer); +int ars_compiler_tcpopt(struct ars_packet *pkt, int layer); +int ars_compiler_udp(struct ars_packet *pkt, int layer); +int ars_compiler_icmp(struct ars_packet *pkt, int layer); +int ars_compiler_igrp(struct ars_packet *pkt, int layer); +int ars_compiler_abort(struct ars_packet *pkt, int layer) { return 0; } + +/* Initialize a packets context: + * must be called before to work with the packet's layers */ +int ars_init(struct ars_packet *pkt) +{ + int j; + + pkt->p_error = NULL; + pkt->p_layer_nr = 0; + pkt->p_options = 0; + for (j = 0; j < ARS_MAX_LAYER; j++) { + pkt->p_layer[j].l_size = 0; + pkt->p_layer[j].l_flags = 0; + pkt->p_layer[j].l_type = ARS_TYPE_NULL; + pkt->p_layer[j].l_data = NULL; + pkt->p_layer[j].l_packet = pkt; + } + for (j = 0; j < ARS_TYPE_SIZE; j++) + pkt->p_default[j] = NULL; + return -ARS_OK; +} + +/* Destroy (free the allocated memory) a packet context */ +int ars_destroy(struct ars_packet *pkt) +{ + int j; + + free(pkt->p_error); + for (j = 0; j < ARS_MAX_LAYER; j++) { + if (pkt->p_layer[j].l_type != ARS_TYPE_NULL && + pkt->p_layer[j].l_data != NULL) + free(pkt->p_layer[j].l_data); + } + return ars_init(pkt); /* Re-initialize it */ +} + +/* THe out of memory message must be statically allocated */ +char *ars_error_nomem = "Out of memory"; + +/* Set the error description */ +int ars_set_error(struct ars_packet *pkt, const char *fmt, ...) +{ + va_list ap; + char buf[ARS_ERR_BUFSZ]; + + if (pkt == NULL) + return -ARS_OK; + + va_start(ap, fmt); + vsnprintf(buf, ARS_ERR_BUFSZ, fmt, ap); + buf[ARS_ERR_BUFSZ-1] = '\0'; + va_end(ap); + free(pkt->p_error); /* p_error is initialized to NULL */ + if ((pkt->p_error = strdup(buf)) == NULL) { + /* To put the error description for the -KO_NOMEM + * error we needs a statically allocated error message: + * Note that all other functions don't need to report + * a statically allocated error message for -KO_NOMEM + * it will be auto-selected if strdup() returns NULL */ + pkt->p_error = ars_error_nomem; + } + return -ARS_OK; /* report anyway success */ +} + +/* Set the default for a layer */ +int ars_set_default(struct ars_packet *pkt, int layer_type, void *def) +{ + pkt->p_default[layer_type] = def; + return -ARS_OK; +} + +/* return nonzero if the packet is full */ +int ars_nospace(struct ars_packet *pkt) +{ + return (pkt->p_layer_nr == ARS_MAX_LAYER); +} + +/* Check if the layer number is valid */ +int ars_valid_layer(int layer) +{ + if (layer < 0 || layer >= ARS_MAX_LAYER) + return -ARS_INVALID; + return -ARS_OK; +} + +/* Add an a generic layer */ +int ars_add_generic(struct ars_packet *pkt, size_t size, int type) +{ + int layer; + + if (ars_nospace(pkt)) { + ars_set_error(pkt, "No space for the next layer"); + return -ARS_NOSPACE; + } + layer = pkt->p_layer_nr; + /* You may want to create a 0 len layer and then realloc */ + if (size != 0) { + pkt->p_layer[layer].l_data = malloc(size); + if (pkt->p_layer[layer].l_data == NULL) { + ars_set_error(pkt, "Out of memory adding a new layer"); + return -ARS_NOMEM; + } + memset(pkt->p_layer[layer].l_data, 0, size); + /* Copy the default if any */ + if (pkt->p_default[type] != NULL) { + memcpy(pkt->p_layer[layer].l_data, + pkt->p_default[type], size); + } + } + pkt->p_layer[layer].l_type = type; + pkt->p_layer[layer].l_size = size; + return -ARS_OK; +} + +/* Add an IP layer */ +void *ars_add_iphdr(struct ars_packet *pkt, int unused) +{ + int retval; + + retval = ars_add_generic(pkt, sizeof(struct ars_iphdr), ARS_TYPE_IP); + if (retval != -ARS_OK) + return NULL; + pkt->p_layer_nr++; + return pkt->p_layer[pkt->p_layer_nr-1].l_data; +} + +/* Add on IP option */ +void *ars_add_ipopt(struct ars_packet *pkt, int option) +{ + int retval; + struct ars_ipopt *ipopt; + int opt_len; + + switch(option) { + case ARS_IPOPT_END: + case ARS_IPOPT_NOOP: + opt_len = 1; + break; + case ARS_IPOPT_SEC: + opt_len = 11; + break; + case ARS_IPOPT_SID: + opt_len = 4; + break; + case ARS_IPOPT_LSRR: + case ARS_IPOPT_SSRR: + case ARS_IPOPT_RR: + case ARS_IPOPT_TIMESTAMP: + /* We allocate the max (40 bytes) but the real layer size + * may be modified by ars_ipopt_set*() functions */ + opt_len = 40; + break; + default: + return NULL; /* Unsupported option */ + break; + } + + retval = ars_add_generic(pkt, opt_len, ARS_TYPE_IPOPT); + if (retval != -ARS_OK) + return NULL; + ipopt = pkt->p_layer[pkt->p_layer_nr].l_data; + pkt->p_layer_nr++; + + ipopt->kind = option; + /* END and NOOP hasn't the length byte */ + if (option == ARS_IPOPT_END || option == ARS_IPOPT_NOOP) + return ipopt; + ipopt->len = opt_len; /* the default, can be modified inside switch() */ + /* Perform some special operation for some option */ + switch(option) { + case ARS_IPOPT_LSRR: /* ars_ipopt_setls() will change some field */ + case ARS_IPOPT_SSRR: /* ars_ipopt_setss() will change some field */ + case ARS_IPOPT_RR: /* ars_ipopt_setrr() will change some field */ + /* RFC 791 needs the roomlen - 3 octects, so the gateways + * can compare len and ptr to check for room. + * Try to break this to stress lame TCP/IP implementation */ + ipopt->len = opt_len - 2 - 3; + ipopt->un.rr.ptr = 4; + break; + case ARS_IPOPT_TIMESTAMP: + ipopt->len = opt_len - 2 - 4; + ipopt->un.ts.ptr = 5; + ipopt->un.ts.flags = ARS_IPOPT_TS_TSONLY; /* default */ + break; + } + return ipopt; +} + +/* Add a UDP layer */ +void *ars_add_udphdr(struct ars_packet *pkt, int unused) +{ + int retval; + + retval = ars_add_generic(pkt, sizeof(struct ars_udphdr), ARS_TYPE_UDP); + if (retval != -ARS_OK) + return NULL; + pkt->p_layer_nr++; + return pkt->p_layer[pkt->p_layer_nr-1].l_data; +} + +/* Add a TCP layer */ +void *ars_add_tcphdr(struct ars_packet *pkt, int unused) +{ + int retval; + + retval = ars_add_generic(pkt, sizeof(struct ars_tcphdr), ARS_TYPE_TCP); + if (retval != -ARS_OK) + return NULL; + pkt->p_layer_nr++; + return pkt->p_layer[pkt->p_layer_nr-1].l_data; +} + +/* Add TCP options */ +void *ars_add_tcpopt(struct ars_packet *pkt, int option) +{ + int retval; + struct ars_tcpopt *tcpopt; + int opt_len; + + switch(option) { + case ARS_TCPOPT_NOP: + case ARS_TCPOPT_EOL: + opt_len = 1; + break; + case ARS_TCPOPT_MAXSEG: + opt_len = 4; + break; + case ARS_TCPOPT_WINDOW: + opt_len = 3; + break; + case ARS_TCPOPT_SACK_PERM: + opt_len = 2; + break; + case ARS_TCPOPT_SACK: + opt_len = 8*4+2; + break; + case ARS_TCPOPT_ECHOREQUEST: + case ARS_TCPOPT_ECHOREPLY: + opt_len = 6; + break; + case ARS_TCPOPT_TIMESTAMP: + opt_len = 10; + break; + default: + return NULL; /* Unsupported option */ + break; + } + + retval = ars_add_generic(pkt, opt_len, ARS_TYPE_TCPOPT); + if (retval != -ARS_OK) + return NULL; + tcpopt = pkt->p_layer[pkt->p_layer_nr].l_data; + pkt->p_layer_nr++; + + tcpopt->kind = option; + /* EOL and NOP lacks the len field */ + if (option != ARS_TCPOPT_EOL && option != ARS_TCPOPT_NOP) + tcpopt->len = opt_len; + + /* Perform some special operation for the option */ + switch(option) { + case ARS_TCPOPT_ECHOREQUEST: + case ARS_TCPOPT_ECHOREPLY: + memset(tcpopt->un.echo.info, 0, 4); + break; + case ARS_TCPOPT_TIMESTAMP: + memset(tcpopt->un.timestamp.tsval, 0, 4); + memset(tcpopt->un.timestamp.tsecr, 0, 4); + break; + } + return tcpopt; +} + +/* Add an ICMP layer */ +void *ars_add_icmphdr(struct ars_packet *pkt, int unused) +{ + int retval; + struct ars_icmphdr *icmp; + + retval = ars_add_generic(pkt, sizeof(struct ars_icmphdr),ARS_TYPE_ICMP); + if (retval != -ARS_OK) + return NULL; + icmp = pkt->p_layer[pkt->p_layer_nr].l_data; + icmp->type = ARS_ICMP_ECHO; + icmp->code = 0; + pkt->p_layer_nr++; + return (struct ars_icmphdr*) pkt->p_layer[pkt->p_layer_nr-1].l_data; +} + +/* Add an IGRP layer */ +void *ars_add_igrphdr(struct ars_packet *pkt, int unused) +{ + int retval; + struct ars_igrphdr *igrp; + + retval = ars_add_generic(pkt, sizeof(struct ars_igrphdr),ARS_TYPE_IGRP); + if (retval != -ARS_OK) + return NULL; + igrp = pkt->p_layer[pkt->p_layer_nr].l_data; + igrp->opcode = ARS_IGRP_OPCODE_REQUEST; + igrp->version = 1; + igrp->edition = 0; + igrp->autosys = 0; + igrp->interior = 0; + igrp->system = 0; + igrp->exterior = 0; + pkt->p_layer_nr++; + return pkt->p_layer[pkt->p_layer_nr-1].l_data; +} + +/* Add an IGRP entry */ +void *ars_add_igrpentry(struct ars_packet *pkt, int unused) +{ + int retval; + + retval = ars_add_generic(pkt, sizeof(struct ars_igrpentry),ARS_TYPE_IGRPENTRY); + if (retval != -ARS_OK) + return NULL; + pkt->p_layer_nr++; + return pkt->p_layer[pkt->p_layer_nr-1].l_data; +} + +/* Add data, for IP-RAW, TCP, UDP, and so on */ +void *ars_add_data(struct ars_packet *pkt, int size) +{ + int retval; + static void *ptr = "zzappt"; /* we can't return NULL for size == 0 */ + + if (size < 0) { + ars_set_error(pkt, "Tryed to add a DATA layer with size < 0"); + return NULL; + } + retval = ars_add_generic(pkt, size, ARS_TYPE_DATA); + if (retval != -ARS_OK) + return NULL; + pkt->p_layer_nr++; + if (size > 0) + return pkt->p_layer[pkt->p_layer_nr-1].l_data; + else + return ptr; +} + +/* Remove a layer */ +int ars_remove_layer(struct ars_packet *pkt, int layer) +{ + if (layer == ARS_LAST_LAYER) + layer = pkt->p_layer_nr -1; + if (ars_valid_layer(layer) != -ARS_OK) + return -ARS_INVALID; + + free(pkt->p_layer[layer].l_data); /* No problem if it's NULL */ + pkt->p_layer[layer].l_type = ARS_TYPE_NULL; + pkt->p_layer[layer].l_size = 0; + pkt->p_layer[layer].l_flags = 0; + pkt->p_layer[layer].l_data = NULL; + pkt->p_layer[layer].l_packet = pkt; + return -ARS_OK; +} + +/* Return the sum of the size of the specifed layer and of all the + * following layers */ +size_t ars_relative_size(struct ars_packet *pkt, int layer_nr) +{ + int j = layer_nr, rel_size = 0; + + while (j < ARS_MAX_LAYER && pkt->p_layer[j].l_type != ARS_TYPE_NULL) { + rel_size += pkt->p_layer[j].l_size; + j++; + } + return rel_size; +} + +/* Just a short cut for ars_relative_size(), to get the total size */ +size_t ars_packet_size(struct ars_packet *pkt) +{ + return ars_relative_size(pkt, 0); +} + +/* from R. Stevens's Network Programming */ +u_int16_t ars_cksum(void *vbuf, size_t nbytes) +{ + u_int16_t *buf = (u_int16_t*) vbuf; + u_int32_t sum; + u_int16_t oddbyte; + + sum = 0; + while (nbytes > 1) { + sum += *buf++; + nbytes -= 2; + } + if (nbytes == 1) { + oddbyte = 0; + *((u_int16_t *) &oddbyte) = *(u_int16_t *) buf; + sum += oddbyte; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return (u_int16_t) ~sum; +} + +/* Multiple buffers checksum facility */ +u_int16_t ars_multi_cksum(struct mc_context *c, int op, void *vbuf, + size_t nbytes) +{ + u_int16_t *buf = (u_int16_t*) vbuf; + u_int32_t sum; + u_int16_t oddbyte; + void *tmp; + + if (op == ARS_MC_INIT) { + c->oddbyte_flag = 0; + c->old = 0; + return -ARS_OK; + } else if (op == ARS_MC_UPDATE) { + if (c->oddbyte_flag) { + u_int8_t *x = (u_int8_t*)&oddbyte; + oddbyte = 0; + *((u_int16_t *) &oddbyte) = c->oddbyte << 8; + *((u_int16_t *) &oddbyte) |= *(u_int16_t *) buf; + oddbyte = (x[0] << 8) | x[1]; /* fix endianess */ + c->old += oddbyte; + nbytes--; + c->oddbyte_flag = 0; + /* We need to stay aligned -- bad slowdown, fix? */ + tmp = alloca(nbytes); + memcpy(tmp, vbuf+1, nbytes); + buf = tmp; + } + sum = c->old; + while (nbytes > 1) { + sum += *buf++; + nbytes -= 2; + } + c->old = sum; + if (nbytes == 1) { + c->oddbyte = *(u_int16_t*) buf; + c->oddbyte_flag++; + } + return -ARS_OK; + } else if (op == ARS_MC_FINAL) { + sum = c->old; + if (c->oddbyte_flag == 1) { + oddbyte = 0; + *((u_int16_t *) &oddbyte) = c->oddbyte; + sum += oddbyte; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return (u_int16_t) ~sum; + } else { + assert(0 && "else reached in ars_multi_cksum()"); + } + return 0; /* unreached, here to prevent warnings */ +} + +/* The ARS compiler table is just a function pointers array: + * For example to select the right function to compile an IP + * layer use: ars_compiler[ARS_TYPE_IP](pkt, layer); + * You can, of course, add your protocols and compilers: + * + * WARNING: take it syncronized with ars.h ARS_TYPE_* defines + */ +struct ars_layer_info ars_linfo[ARS_TYPE_SIZE] = { +/* NAME COMPILER ID * + * ---- -------- -- */ +{ "NULL", ars_compiler_abort, NULL, 0 }, +{ "IP", ars_compiler_ip, ars_rapd_ip, 1 }, +{ "IPOPT", ars_compiler_ipopt, ars_rapd_ipopt, 2 }, +{ "ICMP", ars_compiler_icmp, ars_rapd_icmp, 3 }, +{ "UDP", ars_compiler_udp, ars_rapd_udp, 4 }, +{ "TCP", ars_compiler_tcp, ars_rapd_tcp, 5 }, +{ "TCPOPT", ars_compiler_tcpopt, ars_rapd_tcpopt, 6 }, +{ "IGRP", ars_compiler_igrp, ars_rapd_igrp, 7 }, +{ "IGRPENTRY", NULL, ars_rapd_igrpentry, 8 }, +{ NULL, NULL, NULL, 9 }, +{ NULL, NULL, NULL, 10 }, +{ NULL, NULL, NULL, 11 }, +{ NULL, NULL, NULL, 12 }, +{ NULL, NULL, NULL, 13 }, +{ NULL, NULL, NULL, 14 }, +{ NULL, NULL, NULL, 15 }, +{ NULL, NULL, NULL, 16 }, +{ NULL, NULL, NULL, 17 }, +{ NULL, NULL, NULL, 18 }, +{ NULL, NULL, NULL, 19 }, +{ NULL, NULL, NULL, 20 }, +{ NULL, NULL, NULL, 21 }, +{ NULL, NULL, NULL, 22 }, +{ NULL, NULL, NULL, 23 }, +{ NULL, NULL, NULL, 24 }, +{ NULL, NULL, NULL, 25 }, +{ NULL, NULL, NULL, 26 }, +{ NULL, NULL, NULL, 27 }, +{ NULL, NULL, NULL, 28 }, +{ NULL, NULL, NULL, 29 }, +{ NULL, NULL, NULL, 30 }, +{ "DATA", NULL, ars_rapd_data, 31 } +}; + +/* This function call the right compiler for all the layers of the packet: + * A compiler just set the protocol fields like the checksum, len, and so on + * accordly to the following layers. + * Note that the layers are compiled from the last to the first, to ensure + * that the checksum and other dependences are sane. */ +int ars_compile(struct ars_packet *pkt) +{ + int j, err; + + for (j = pkt->p_layer_nr - 1; j >= 0; j--) { + __D(printf("Compiling layer %d\n", j);) + /* Skip NULL compilers */ + if (ars_linfo[pkt->p_layer[j].l_type].li_compiler != NULL) { + /* Call the compiler */ + err = ars_linfo[pkt->p_layer[j].l_type].li_compiler(pkt, j); + if (err != -ARS_OK) + return err; + } + } + return -ARS_OK; +} + +/* The IP compiler: probably the more complex, but still simple */ +int ars_compiler_ip(struct ars_packet *pkt, int layer) +{ + struct ars_iphdr *ip = pkt->p_layer[layer].l_data; + int j = layer, err; + int flags = pkt->p_layer[layer].l_flags; + int ipoptlen = 0; + struct mc_context mc; /* multi-buffer checksum context */ + + /* IP version */ + if (ARS_DONTTAKE(flags, ARS_TAKE_IP_VERSION)) + ip->version = 4; + /* IP header len */ + if (ARS_DONTTAKE(flags, ARS_TAKE_IP_HDRLEN)) { + ip->ihl = (ARS_IPHDR_SIZE >> 2); + /* Add IP options len */ + for (j = layer+1; j < ARS_MAX_LAYER; j++) { + if (pkt->p_layer[j].l_type != ARS_TYPE_IPOPT) + break; + ipoptlen += pkt->p_layer[j].l_size; + } + ip->ihl += ipoptlen >> 2; + } + /* IP tot len */ + if (ARS_DONTTAKE(flags, ARS_TAKE_IP_TOTLEN)) + ip->tot_len = htons(ars_relative_size(pkt, layer)); + /* IP protocol field */ + if (ARS_DONTTAKE(flags, ARS_TAKE_IP_PROTOCOL)) { + ip->protocol = ARS_IPPROTO_RAW; /* This is the default */ + while (j < ARS_MAX_LAYER) { + if (pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) { + j++; + continue; + } + switch(pkt->p_layer[j].l_type) { + case ARS_TYPE_IP: + ip->protocol = ARS_IPPROTO_IPIP; + break; + case ARS_TYPE_ICMP: + ip->protocol = ARS_IPPROTO_ICMP; + break; + case ARS_TYPE_UDP: + ip->protocol = ARS_IPPROTO_UDP; + break; + case ARS_TYPE_TCP: + ip->protocol = ARS_IPPROTO_TCP; + break; + case ARS_TYPE_IGRP: + ip->protocol = ARS_IPPROTO_IGRP; + break; + } + break; + } + } + /* We always calculate the IP checksum, since the kernel + * do it only for the first IP header in the datagram */ + if (ARS_DONTTAKE(flags, ARS_TAKE_IP_CKSUM)) { + ip->check = 0; + ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); + err = ars_multi_cksum(&mc, ARS_MC_UPDATE, ip, ARS_IPHDR_SIZE); + if (err != -ARS_OK) + return err; + for (j = layer+1; j < ARS_MAX_LAYER; j++) { + if (pkt->p_layer[j].l_type != ARS_TYPE_IPOPT) + break; + err = ars_multi_cksum(&mc, ARS_MC_UPDATE, + pkt->p_layer[j].l_data, + pkt->p_layer[j].l_size); + if (err != -ARS_OK) + return err; + } + ip->check = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); + } + return -ARS_OK; +} + +/* The ip options compiler: do just option padding with NOP options */ +int ars_compiler_ipopt(struct ars_packet *pkt, int layer) +{ + int j, opt_size; + + /* Padding is needed only in the last IP option */ + if (layer != ARS_MAX_LAYER-1 && + pkt->p_layer[layer+1].l_type == ARS_TYPE_IPOPT) + return ARS_OK; + + /* Search the layer of the relative first IP option */ + j = layer - 1; /* We know that 'layer' is an IP option */ + while (j < ARS_MAX_LAYER && j >= 0 && + pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) + j--; + j++; + __D(printf("First IP OPTION layer is %d\n", j);) + opt_size = ars_relative_size(pkt, j) - ars_relative_size(pkt, layer+1); + __D(printf("IP OPTION size %d\n", opt_size);) + if (opt_size % 4) { + int padding = 4 - (opt_size % 4); + unsigned char *t; + int cur_size = pkt->p_layer[layer].l_size; + + __D(printf("IP OPTION at layer %d needs %d bytes " + "of padding\n", layer, padding);) + t = realloc(pkt->p_layer[layer].l_data, cur_size + padding); + if (t == NULL) { + ars_set_error(pkt, "Out of memory padding IP options"); + return -ARS_NOMEM; + } + memset(t+cur_size, ARS_IPOPT_NOP, padding); + __D(printf("The last IP OPTION length was: %d\n", cur_size);) + pkt->p_layer[layer].l_data = t; + pkt->p_layer[layer].l_size += padding; + __D(printf("After padding it is: %d\n", pkt->p_layer[layer].l_size);) + } + return -ARS_OK; +} + +/* Compute the UDP and TCP checksum using the pseudoheader. + * Note that this functions automatically care about TCP/UDP data. + * FIXME: this doesn't work when the IP source address is 0.0.0.0 */ +int ars_udptcp_cksum(struct ars_packet *pkt, int layer, u_int16_t *sum) +{ + struct ars_iphdr *ip; + struct ars_pseudohdr pseudo; + struct mc_context mc; /* multi-buffer checksum context */ + int j = layer - 1, err; + + /* search the first IP layer on the left: + * it returns an error if between the IP and + * the TCP layer there aren't just IPOPT layers: + * even with malformed packets this does not + * makes sense. */ + while (j > 0 && pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) + j--; + if (pkt->p_layer[j].l_type != ARS_TYPE_IP) { + ars_set_error(pkt, "TCP/UDP checksum requested, but IP header " + "not found"); + return -ARS_INVALID; + } + ip = pkt->p_layer[j].l_data; + memset(&pseudo, 0, sizeof(pseudo)); /* actually not needed */ + /* Copy the src and dst IP address */ + memcpy(&pseudo.saddr, &ip->saddr, 4); + memcpy(&pseudo.daddr, &ip->daddr, 4); + pseudo.protocol = (pkt->p_layer[layer].l_type == ARS_TYPE_TCP) + ? ARS_IPPROTO_TCP : ARS_IPPROTO_UDP; + pseudo.lenght = htons(ars_relative_size(pkt, layer)); + + /* Finally do the checksum */ + ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); + err = ars_multi_cksum(&mc, ARS_MC_UPDATE, &pseudo, sizeof(pseudo)); + if (err != -ARS_OK) + return err; + for (j = layer; j < ARS_MAX_LAYER; j++) { + if (pkt->p_layer[j].l_type == ARS_TYPE_NULL) + break; + err = ars_multi_cksum(&mc, ARS_MC_UPDATE, + pkt->p_layer[j].l_data, + pkt->p_layer[j].l_size); + if (err != -ARS_OK) + return err; + } + *sum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); + return -ARS_OK; +} + +/* The tcp compiler */ +int ars_compiler_tcp(struct ars_packet *pkt, int layer) +{ + struct ars_tcphdr *tcp = pkt->p_layer[layer].l_data; + int j, err, tcpoptlen = 0; + int flags = pkt->p_layer[layer].l_flags; + + if (ARS_DONTTAKE(flags, ARS_TAKE_TCP_HDRLEN)) { + tcp->th_off = ARS_TCPHDR_SIZE >> 2; + /* Add the len of the options */ + for (j = layer+1; j < ARS_MAX_LAYER; j++) { + if (pkt->p_layer[j].l_type != ARS_TYPE_TCPOPT) + break; + tcpoptlen += pkt->p_layer[j].l_size; + } + tcp->th_off += tcpoptlen >> 2; + } + if (ARS_DONTTAKE(flags, ARS_TAKE_TCP_CKSUM)) { + tcp->th_sum = 0; + err = ars_udptcp_cksum(pkt, layer, &tcp->th_sum); + if (err != -ARS_OK) + return err; + } + return -ARS_OK; +} + +/* The tcp options compiler: do just option padding with NOP options */ +int ars_compiler_tcpopt(struct ars_packet *pkt, int layer) +{ + int j, opt_size; + + /* Padding is needed only in the last TCP option */ + if (layer != ARS_MAX_LAYER-1 && + pkt->p_layer[layer+1].l_type == ARS_TYPE_TCPOPT) + return ARS_OK; + + /* Search the layer of the relative first TCP option */ + j = layer - 1; /* We know that 'layer' is a tcp option */ + while (j < ARS_MAX_LAYER && j >= 0 && + pkt->p_layer[j].l_type == ARS_TYPE_TCPOPT) + j--; + j++; + __D(printf("First TCP OPTION layer is %d\n", j);) + opt_size = ars_relative_size(pkt, j) - ars_relative_size(pkt, layer+1); + __D(printf("TCP OPTION size %d\n", opt_size);) + if (opt_size % 4) { + int padding = 4 - (opt_size % 4); + unsigned char *t; + int cur_size = pkt->p_layer[layer].l_size; + + __D(printf("TCP OPTION at layer %d needs %d bytes " + "of padding\n", layer, padding);) + t = realloc(pkt->p_layer[layer].l_data, cur_size + padding); + if (t == NULL) { + ars_set_error(pkt, "Out of memory padding TCP options"); + return -ARS_NOMEM; + } + memset(t+cur_size, ARS_TCPOPT_NOP, padding); + pkt->p_layer[layer].l_size += padding; + } + return -ARS_OK; +} + +/* The udp compiler, very simple */ +int ars_compiler_udp(struct ars_packet *pkt, int layer) +{ + struct ars_udphdr *udp = pkt->p_layer[layer].l_data; + int err; + int flags = pkt->p_layer[layer].l_flags; + + if (ARS_DONTTAKE(flags, ARS_TAKE_UDP_LEN)) + udp->uh_ulen = htons(ars_relative_size(pkt, layer)); + + if (ARS_DONTTAKE(flags, ARS_TAKE_UDP_CKSUM)) { + udp->uh_sum = 0; + err = ars_udptcp_cksum(pkt, layer, &udp->uh_sum); + if (err != -ARS_OK) + return err; + } + return -ARS_OK; +} + +/* The icmp compiler, just compute the checksum */ +int ars_compiler_icmp(struct ars_packet *pkt, int layer) +{ + struct ars_icmphdr *icmp = pkt->p_layer[layer].l_data; + struct mc_context mc; /* multi-buffer checksum context */ + int err, j; + int flags = pkt->p_layer[layer].l_flags; + + if (ARS_DONTTAKE(flags, ARS_TAKE_ICMP_CKSUM)) { + icmp->checksum = 0; + ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); + for (j = layer; j < ARS_MAX_LAYER; j++) { + if (pkt->p_layer[j].l_type == ARS_TYPE_NULL) + break; + err = ars_multi_cksum(&mc, ARS_MC_UPDATE, + pkt->p_layer[j].l_data, + pkt->p_layer[j].l_size); + if (err != -ARS_OK) + return err; + } + icmp->checksum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); + } + return -ARS_OK; +} + +/* The igrp compiler, just compute the checksum */ +int ars_compiler_igrp(struct ars_packet *pkt, int layer) +{ + struct ars_igrphdr *igrp = pkt->p_layer[layer].l_data; + struct mc_context mc; /* multi-buffer checksum context */ + int err, j; + int flags = pkt->p_layer[layer].l_flags; + + if (ARS_DONTTAKE(flags, ARS_TAKE_IGRP_CKSUM)) { + igrp->checksum = 0; + ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0); + for (j = layer; j < ARS_MAX_LAYER; j++) { + if (pkt->p_layer[j].l_type == ARS_TYPE_NULL) + break; + err = ars_multi_cksum(&mc, ARS_MC_UPDATE, + pkt->p_layer[j].l_data, + pkt->p_layer[j].l_size); + if (err != -ARS_OK) + return err; + } + igrp->checksum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0); + } + return -ARS_OK; +} + +/* Open a raw socket, ready for IP header creation and broadcast addresses */ +int ars_open_rawsocket(struct ars_packet *pkt) +{ + int s; + const int one = 1; + + if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) { + ars_set_error(pkt, "Can't open the raw socket"); + return -ARS_ERROR; + } + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&one, + sizeof(one)) == -1 || + setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*)&one, + sizeof(one)) == -1) + { + close(s); + ars_set_error(pkt, "Can't set socket options"); + return -ARS_ERROR; + } + return s; +} + +/* Create the packets using the layers. This function is often called + * after the layers compilation. Note that since the packet created + * is sane the strange-rawsocket-behaviour of some *BSD will not + * be able to send this packet. Use the function ars_bsd_fix() to fix it. + * WARNING: The packets returned is malloc()ated, free it */ +int ars_build_packet(struct ars_packet *pkt, unsigned char **packet, size_t *size) +{ + size_t tot_size, offset = 0; + int j = 0; + + if ((tot_size = ars_packet_size(pkt)) == 0) { + ars_set_error(pkt, "Total size 0 building the packet"); + return -ARS_INVALID; + } + if ((*packet = malloc(tot_size)) == NULL) { + ars_set_error(pkt, "Out of memory building the packet"); + return -ARS_NOMEM; + } + while (j < ARS_MAX_LAYER && pkt->p_layer[j].l_type != ARS_TYPE_NULL) { + memcpy((*packet)+offset, pkt->p_layer[j].l_data, + pkt->p_layer[j].l_size); + offset += pkt->p_layer[j].l_size; + j++; + } + *size = tot_size; + return -ARS_OK; +} + +/* FreeBSD and NetBSD have a strange raw socket layer :( + * Call this function anyway to increase portability + * since it does not perform any operation if the + * system isn't FreeBSD or NetBSD. */ +int ars_bsd_fix(struct ars_packet *pkt, unsigned char *packet, size_t size) +{ + struct ars_iphdr *ip; + + if (pkt->p_layer[0].l_type != ARS_TYPE_IP || + size < sizeof(struct ars_iphdr)) { + ars_set_error(pkt, "BSD fix requested, but layer 0 not IP"); + return -ARS_INVALID; + } + ip = (struct ars_iphdr*) packet; +#if defined OSTYPE_DARWIN || defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD || defined OSTYPE_BSDI + ip->tot_len = ntohs(ip->tot_len); + ip->frag_off = ntohs(ip->frag_off); +#endif + return -ARS_OK; +} + +/* Set the flags for some layer: if layer == -1 the last layer will be used */ +int ars_set_flags(struct ars_packet *pkt, int layer, int flags) +{ + if (layer == ARS_LAST_LAYER) + layer = pkt->p_layer_nr - 1; + if (layer < 0 || layer >= ARS_MAX_LAYER) { + ars_set_error(pkt, "Invalid layer setting layer flags"); + return -ARS_INVALID; + } + pkt->p_layer[layer].l_flags = flags; + return -ARS_OK; +} + +/* Build, fix, and send the packet */ +int ars_send(int s, struct ars_packet *pkt, struct sockaddr *sa, socklen_t slen) +{ + struct sockaddr_in sain; + struct sockaddr *_sa = sa; + unsigned char *packet; + size_t size; + int error; + + /* Perform the socket address completion if sa == NULL */ + if (sa == NULL) { + struct ars_iphdr *ip; + + memset(&sain, 0, sizeof(sain)); + sain.sin_family = AF_INET; + /* The first layer MUST be IP if the user requested + * the socket address completion */ + if (pkt->p_layer[0].l_type != ARS_TYPE_IP) { + ars_set_error(pkt, "socket address completion" + "requested, but layer 0 isn't IP"); + return -ARS_ERROR; + } + ip = (struct ars_iphdr*) pkt->p_layer[0].l_data; + memcpy(&sain.sin_addr.s_addr, &ip->daddr, 4); + _sa = (struct sockaddr*) &sain; + slen = sizeof(sain); + } + if ((error = ars_build_packet(pkt, &packet, &size)) != ARS_OK) + return error; + if ((error = ars_bsd_fix(pkt, packet, size)) != ARS_OK) + return error; + error = sendto(s, packet, size, 0, _sa, slen); + free(packet); + return (error != -1) ? -ARS_OK : -ARS_ERROR; +} + +/* Resolve an hostname and write to 'dest' the IP */ +int ars_resolve(struct ars_packet *pkt, u_int32_t *dest, char *hostname) +{ + struct sockaddr_in sa; + + if (inet_pton(AF_INET, hostname, &sa.sin_addr) == 0) { + struct hostent *he; + he = gethostbyname(hostname); + if (he == NULL) { + ars_set_error(pkt, "Can't resolve the hostname"); + return -ARS_ERROR; + } + sa.sin_addr.s_addr = ((struct in_addr*) he->h_addr)->s_addr; + } + memcpy(dest, &sa.sin_addr.s_addr, sizeof(u_int32_t)); + return -ARS_OK; +} diff --git a/src/ars.h b/src/ars.h new file mode 100644 index 0000000..88567ae --- /dev/null +++ b/src/ars.h @@ -0,0 +1,524 @@ +/* Copyright (C) 2000,2001 Salvatore Sanfilippo + * See the LICENSE file for more information. */ + +/* $Id: ars.h,v 1.4 2004/06/04 07:22:38 antirez Exp $ */ + +#ifndef _ARS_H +#define _ARS_H + +/* define before including sys/socket.h */ +#if defined(__APPLE__) && !defined(_BSD_SOCKLEN_T_) +#define _BSD_SOCKLEN_T_ int +#endif + +#include +#include +#include +#include +#include "config.h" +#include "in.h" +#include "adbuf.h" +#include "fixtypes.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + + +#ifndef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +#ifndef MAX +#define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +#ifdef DEBUG +#define __D(x) x +#else +#define __D(x) do { } while (0); +#endif + +#ifndef __u8 +#define __u8 u_int8_t +#define __u16 u_int16_t +#define __u32 u_int32_t +#endif + +/* error codes */ +#define ARS_OK 0 +#define ARS_ERROR 1 +#define ARS_NOSPACE 2 +#define ARS_NOMEM 3 +#define ARS_INVALID 4 + +/* Headers size */ +#define ARS_ICMPHDR_SIZE sizeof(struct ars_icmphdr) +#define ARS_UDPHDR_SIZE sizeof(struct ars_udphdr) +#define ARS_TCPHDR_SIZE sizeof(struct ars_tcphdr) +#define ARS_IPHDR_SIZE sizeof(struct ars_iphdr) +#define ARS_PSEUDOHDR_SIZE sizeof(struct pseudohdr) +#define ARS_IGRPHDR_SIZE sizeof(struct ars_igrphdr) +#define ARS_IGRPENTRY_SIZE sizeof(struct ars_igrpentry) + +/* IP defines */ +#define ARS_MAX_IP_SIZE 65535 + +#define ARS_IP_MF ((unsigned short)0x2000) /* more fragments */ +#define ARS_IP_DF ((unsigned short)0x4000) /* dont fragment */ +#define ARS_IP_RF ((unsigned short)0x8000) /* reserved fragment flag */ + +#define ARS_IPOPT_COPY 0x80 +#define ARS_IPOPT_CLASS_MASK 0x60 +#define ARS_IPOPT_NUMBER_MASK 0x1f + +#define ARS_IPOPT_COPIED(o) ((o)&ARS_IPOPT_COPY) +#define ARS_IPOPT_CLASS(o) ((o)&ARS_IPOPT_CLASS_MASK) +#define ARS_IPOPT_NUMBER(o) ((o)&ARS_IPOPT_NUMBER_MASK) + +#define ARS_IPOPT_CONTROL 0x00 +#define ARS_IPOPT_RESERVED1 0x20 +#define ARS_IPOPT_MEASUREMENT 0x40 +#define ARS_IPOPT_RESERVED2 0x60 + +#define ARS_IPOPT_END (0 |ARS_IPOPT_CONTROL) +#define ARS_IPOPT_NOOP (1 |ARS_IPOPT_CONTROL) +#define ARS_IPOPT_SEC (2 |ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) +#define ARS_IPOPT_LSRR (3 |ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) +#define ARS_IPOPT_TIMESTAMP (4 |ARS_IPOPT_MEASUREMENT) +#define ARS_IPOPT_RR (7 |ARS_IPOPT_CONTROL) +#define ARS_IPOPT_SID (8 |ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) +#define ARS_IPOPT_SSRR (9 |ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) +#define ARS_IPOPT_RA (20|ARS_IPOPT_CONTROL|ARS_IPOPT_COPY) + +#define ARS_IPOPT_OPTVAL 0 +#define ARS_IPOPT_OLEN 1 +#define ARS_IPOPT_OFFSET 2 +#define ARS_IPOPT_MINOFF 4 +#define ARS_MAX_IPOPTLEN 40 +#define ARS_IPOPT_NOP ARS_IPOPT_NOOP +#define ARS_IPOPT_EOL ARS_IPOPT_END +#define ARS_IPOPT_TS ARS_IPOPT_TIMESTAMP + +#define ARS_IPOPT_TS_TSONLY 0 /* timestamps only */ +#define ARS_IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define ARS_IPOPT_TS_PRESPEC 3 /* specified modules only */ + +/* IPV4 and IPV6 string rappresentation len */ +#define ARS_INET_ADDRSTRLEN 16 +#define ARS_INET6_ADDRSTRLEN 46 + +/* TCP */ +#define ARS_TCPOPT_EOL 0 +#define ARS_TCPOPT_NOP 1 +#define ARS_TCPOPT_MAXSEG 2 +#define ARS_TCPOPT_WINDOW 3 +#define ARS_TCPOPT_SACK_PERM 4 +#define ARS_TCPOPT_SACK 5 +#define ARS_TCPOPT_ECHOREQUEST 6 +#define ARS_TCPOPT_ECHOREPLY 7 +#define ARS_TCPOPT_TIMESTAMP 8 + +#define ARS_TCP_TH_FIN 0x01 +#define ARS_TCP_TH_SYN 0x02 +#define ARS_TCP_TH_RST 0x04 +#define ARS_TCP_TH_PUSH 0x08 +#define ARS_TCP_TH_ACK 0x10 +#define ARS_TCP_TH_URG 0x20 +#define ARS_TCP_TH_X 0x40 /* X tcp flag */ +#define ARS_TCP_TH_Y 0x80 /* Y tcp flag */ + +/* ICMP TYPE */ +#define ARS_ICMP_ECHOREPLY 0 /* Echo Reply */ +#define ARS_ICMP_DEST_UNREACH 3 /* Destination Unreachable */ +#define ARS_ICMP_SOURCE_QUENCH 4 /* Source Quench */ +#define ARS_ICMP_REDIRECT 5 /* Redirect (change route) */ +#define ARS_ICMP_ECHO 8 /* Echo Request */ +#define ARS_ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ +#define ARS_ICMP_PARAMETERPROB 12 /* Parameter Problem */ +#define ARS_ICMP_TIMESTAMP 13 /* Timestamp Request */ +#define ARS_ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ +#define ARS_ICMP_INFO_REQUEST 15 /* Information Request */ +#define ARS_ICMP_INFO_REPLY 16 /* Information Reply */ +#define ARS_ICMP_ADDRESS 17 /* Address Mask Request */ +#define ARS_ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ + +/* Codes for UNREACHABLE */ +#define ARS_ICMP_UNR_NET 0 /* Network Unreachable */ +#define ARS_ICMP_UNR_HOST 1 /* Host Unreachable */ +#define ARS_ICMP_UNR_PROT 2 /* Protocol Unreachable */ +#define ARS_ICMP_UNR_PORT 3 /* Port Unreachable */ +#define ARS_ICMP_UNR_FRAG_NEEDED 4 /* Fragmentation Needed,DF set*/ +#define ARS_ICMP_UNR_SR_FAILED 5 /* Source Route failed */ +#define ARS_ICMP_UNR_UNK_NET 6 +#define ARS_ICMP_UNR_UNK_HOST 7 +#define ARS_ICMP_UNR_ISOLATED_HOST 8 +#define ARS_ICMP_UNR_NET_ANO 9 +#define ARS_ICMP_UNR_HOST_ANO 10 +#define ARS_ICMP_UNR_NET_UNR_TOS 11 +#define ARS_ICMP_UNR_HOST_UNR_TOS 12 +#define ARS_ICMP_UNR_PKT_FILTERED 13 /* Packet filtered */ +#define ARS_ICMP_UNR_PREC_VIOLATION 14 /* Precedence violation */ +#define ARS_ICMP_UNR_PREC_CUTOFF 15 /* Precedence cut off */ +#define ARS_NR_ICMP_UNREACH 15 /* Instead of hardcoded immediate value */ + +/* Codes for REDIRECT */ +#define ARS_ICMP_REDIR_NET 0 /* Redirect Net */ +#define ARS_ICMP_REDIR_HOST 1 /* Redirect Host */ +#define ARS_ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ +#define ARS_ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ + +/* Codes for TIME_EXCEEDED */ +#define ARS_ICMP_EXC_TTL 0 /* TTL count exceeded */ +#define ARS_ICMP_EXC_FRAGTIME 1 /* TTL exceeded reassembling */ + +/* IGRP defines */ +#define ARS_IGRP_OPCODE_UPDATE 1 +#define ARS_IGRP_OPCODE_REQUEST 2 + +/* The IP header structure */ +struct ars_iphdr { +#if defined (WORDS_BIGENDIAN) + __u8 version:4, + ihl:4; +#else + __u8 ihl:4, + version:4; +#endif + __u8 tos; + __u16 tot_len; + __u16 id; + __u16 frag_off; + __u8 ttl; + __u8 protocol; + __u16 check; + __u32 saddr; + __u32 daddr; +}; + +/* The IP options structure */ +struct ars_ipopt { + u_int8_t kind; + u_int8_t len; + union { + struct { + u_int16_t s; + u_int16_t c; + u_int16_t h; + u_int8_t tcc[3]; + } sec; /* security */ + struct { + u_int8_t ptr; + u_int8_t data[37]; + } src; /* loose and strict source routing */ + struct { + u_int8_t ptr; + u_int8_t data[37]; + } rr; /* record route */ + struct { + u_int16_t id; + } sid; /* stream id */ + struct { + u_int8_t ptr; + u_int8_t flags; + u_int8_t data[36]; + } ts; /* timestamp */ + } un; +}; + +/* The UDP header structure */ +struct ars_udphdr { + __u16 uh_sport; /* source port */ + __u16 uh_dport; /* destination port */ + __u16 uh_ulen; /* udp length */ + __u16 uh_sum; /* udp checksum */ +}; + +/* The TCP header structure */ +struct ars_tcphdr { + __u16 th_sport; /* source port */ + __u16 th_dport; /* destination port */ + __u32 th_seq; /* sequence number */ + __u32 th_ack; /* acknowledgement number */ +#if defined (WORDS_BIGENDIAN) + __u8 th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#else + __u8 th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#endif + __u8 th_flags; + __u16 th_win; /* window */ + __u16 th_sum; /* checksum */ + __u16 th_urp; /* urgent pointer */ +}; + +/* The TCP options structure */ +struct ars_tcpopt { + u_int8_t kind; + u_int8_t len; + union { + struct { + u_int16_t size; + } mss; + struct { + u_int8_t shift; + } win; + struct { + u_int8_t origin[4]; + u_int8_t size[4]; + } sack[4]; /* max 4 SACK blocks in 40 bytes of space */ + struct { + u_int8_t info[4]; + } echo; + struct { + u_int8_t tsval[4]; + u_int8_t tsecr[4]; + } timestamp; + } un; +}; + +/* The ICMP header structure */ +struct ars_icmphdr +{ + __u8 type; + __u8 code; + __u16 checksum; + union + { + struct + { + __u16 id; + __u16 sequence; + } echo; /* called echo since it's the most used */ + __u32 gateway; + } un; +}; + +/* TCP/UDP pseudo header used to compute the checksum */ +struct ars_pseudohdr +{ + __u32 saddr; + __u32 daddr; + __u8 zero; + __u8 protocol; + __u16 lenght; +}; + +/* The IGRP header structure */ +struct ars_igrphdr { +#if defined (WORDS_BIGENDIAN) + __u8 version:4, + opcode:4; +#else + __u8 opcode:4, + version:4; +#endif + __u8 edition; + __u16 autosys; + __u16 interior; + __u16 system; + __u16 exterior; + __u16 checksum; +}; + +/* The IGRP entry */ +struct ars_igrpentry { + __u8 destination[3]; + __u8 delay[3]; + __u8 bandwidth[3]; + __u8 mtu[2]; + __u8 reliability; + __u8 load; + __u8 hopcount; +}; + +struct ars_packet; /* forward declaration */ + +/* ARS layer */ +struct ars_layer { + int l_type; + int l_size; + int l_flags; + void *l_data; + struct ars_packet *l_packet; +}; + +#define ARS_MAX_LAYER 256 +#define ARS_ERR_BUFSZ 1024 + +/* Types */ +#define ARS_TYPE_SIZE 32 +#define ARS_TYPE_NULL 0 +#define ARS_TYPE_IP 1 +#define ARS_TYPE_IPOPT 2 +#define ARS_TYPE_ICMP 3 +#define ARS_TYPE_UDP 4 +#define ARS_TYPE_TCP 5 +#define ARS_TYPE_TCPOPT 6 +#define ARS_TYPE_IGRP 7 +#define ARS_TYPE_IGRPENTRY 8 +#define ARS_TYPE_DATA 31 + +/* ARS packet context */ +struct ars_packet { + char *p_error; + int p_layer_nr; + struct ars_layer p_layer[ARS_MAX_LAYER]; + void *p_default[ARS_TYPE_SIZE]; + int p_options; + int aux; /* Auxiliar variable for data exchange between functions */ + int aux_ipproto; /* This hold the ip->proto field seen in the last + IP datagram so that when the IP options processing + is done, the split-machine can continue with + the right state. */ +}; + +/* Facility to check for flags */ +#define ARS_TAKE(f,x) (f & x) +#define ARS_DONTTAKE(f, x) (!(f & x)) +#define ARS_TAKE_NONE 0 + +/* IP layer flags */ +#define ARS_TAKE_IP_VERSION (1 << 0) +#define ARS_TAKE_IP_HDRLEN (1 << 1) +#define ARS_TAKE_IP_TOTLEN (1 << 2) +#define ARS_TAKE_IP_PROTOCOL (1 << 3) +#define ARS_TAKE_IP_CKSUM (1 << 4) + +/* IP options layers flags */ +#define ARS_TAKE_IPOPT_PTR (1 << 0) /* for RR, LSRR, SSRR */ + +/* ICMP layer flags */ +#define ARS_TAKE_ICMP_CKSUM (1 << 0) + +/* UDP layer flags */ +#define ARS_TAKE_UDP_CKSUM (1 << 0) +#define ARS_TAKE_UDP_LEN (1 << 1) + +/* TCP layer flags */ +#define ARS_TAKE_TCP_HDRLEN (1 << 0) +#define ARS_TAKE_TCP_CKSUM (1 << 1) + +/* IGRP layer flags */ +#define ARS_TAKE_IGRP_CKSUM (1 << 0) + +/* Some function that acts on layer switch to the last layer with this */ +#define ARS_LAST_LAYER -1 + +/* Structure and defines needed to calculate the internet-like checksum + * when the data is splitted in more not adjacent buffers */ +#define ARS_MC_INIT 0 +#define ARS_MC_UPDATE 1 +#define ARS_MC_FINAL 2 + +struct mc_context { + u_int32_t oddbyte_flag; + u_int32_t old; + u_int8_t oddbyte; + u_int8_t pad; +}; + +/* ARS layer info structure */ +struct ars_layer_info { + char *li_name; /* NULL = unused slot */ + int (*li_compiler) (struct ars_packet *pkt, int layer); /* NULL = NOP */ + int (*li_rapd) (struct adbuf *dest, struct ars_packet *pkt, int layer); + int layer_id; +}; + +/* ARS layer info table */ +extern struct ars_layer_info ars_linfo[ARS_TYPE_SIZE]; + +/* ARS interface managment structure and defines */ +#define ARS_IF_UP (1 << 0) +#define ARS_IF_LOOP (1 << 1) +#define ARS_IF_IPV4 (1 << 2) +#define ARS_IF_IPV6 (1 << 3) +#define ARS_IF_MISCONF (1 << 4) + +#define ARS_IF_MAX_IFACE 16 +#define ARS_IF_NAME_SIZE 32 + +/* iface type are obtained using libpcap to avoid efforts duplication */ +struct ars_iface { + char if_name[ARS_IF_NAME_SIZE]; + int if_mtu; + int if_flags; + char if_ipv4addr[ARS_INET_ADDRSTRLEN]; + char if_ipv6addr[ARS_INET6_ADDRSTRLEN]; +}; + +/* Flags for packet splitting */ +#define ARS_SPLIT_FTRUNC (1 << 0) +#define ARS_SPLIT_FBADCKSUM (1 << 1) + +/* Ars packet options */ +#define ARS_OPT_RAPD_HEXDATA (1 << 0) /* Use hex format for RAPD data */ + +/* More macros */ +#define ars_atou(x) strtoul(x, (char **) NULL, 0) +#define ars_set_option(pkt,opt) do { (pkt)->p_options |= (opt); } while(0) +#define ars_clear_option(pkt,opt) do { (pkt)->p_options &= ~(opt); } while(0) +#define ars_test_option(pkt,opt) ((pkt)->p_options & (opt)) + +/* Prototypes */ +int ars_init(struct ars_packet *pkt); +int ars_destroy(struct ars_packet *pkt); +int ars_nospace(struct ars_packet *pkt); +int ars_add_generic(struct ars_packet *pkt, size_t size, int type); +void *ars_add_iphdr(struct ars_packet *pkt, int unused); +void *ars_add_ipopt(struct ars_packet *pkt, int option); +void *ars_add_udphdr(struct ars_packet *pkt, int unused); +void *ars_add_tcphdr(struct ars_packet *pkt, int unused); +void *ars_add_tcpopt(struct ars_packet *pkt, int option); +void *ars_add_icmphdr(struct ars_packet *pkt, int unused); +void *ars_add_igrphdr(struct ars_packet *pkt, int unused); +void *ars_add_igrpentry(struct ars_packet *pkt, int unused); +void *ars_add_data(struct ars_packet *pkt, int size); +size_t ars_relative_size(struct ars_packet *pkt, int layer_nr); +size_t ars_packet_size(struct ars_packet *pkt); +u_int16_t ars_cksum(void *vbuf, size_t nbytes); +u_int16_t ars_multi_cksum(struct mc_context *c, int op, void *vbuf, size_t nbytes); +int ars_compile(struct ars_packet *pkt); +int ars_udptcp_cksum(struct ars_packet *pkt, int layer, u_int16_t *sum); +int ars_open_rawsocket(struct ars_packet *pkt); +int ars_build_packet(struct ars_packet *pkt, unsigned char **packet, size_t *size); +int ars_bsd_fix(struct ars_packet *pkt, unsigned char *packet, size_t size); +int ars_set_flags(struct ars_packet *pkt, int layer, int flags); +int ars_send(int s, struct ars_packet *pkt, struct sockaddr *sa, socklen_t slen); +int ars_resolve(struct ars_packet *pkt, u_int32_t *dest, char *hostname); +int ars_set_error(struct ars_packet *pkt, const char *fmt, ...); +int ars_d_build(struct ars_packet *pkt, char *t); +int ars_valid_layer(int layer); +int ars_get_iface_list(struct ars_iface *iface, size_t *isize); +int ars_get_iface(char *name, struct ars_iface *i); +int ars_valid_layer(int layer); +int ars_remove_layer(struct ars_packet *pkt, int layer); + +/* split.c prototypes */ +int ars_seems_ip(struct ars_iphdr *ip, size_t size); +int ars_guess_ipoff(void *packet, size_t size, int *lhs); +int ars_check_ip_cksum(struct ars_iphdr *ip); +int ars_check_icmp_cksum(struct ars_icmphdr *icmp, size_t size); +int ars_split_packet(void *packet, size_t size, int ipoff, struct ars_packet *pkt); + +/* reverse apd */ +int ars_d_from_ars(char *dest, size_t len, struct ars_packet *pkt); +int ars_rapd_ip(struct adbuf *dest, struct ars_packet *pkt, int layer); +int ars_rapd_ipopt(struct adbuf *dest, struct ars_packet *pkt, int layer); +int ars_rapd_icmp(struct adbuf *dest, struct ars_packet *pkt, int layer); +int ars_rapd_udp(struct adbuf *dest, struct ars_packet *pkt, int layer); +int ars_rapd_tcp(struct adbuf *dest, struct ars_packet *pkt, int layer); +int ars_rapd_tcpopt(struct adbuf *dest, struct ars_packet *pkt, int layer); +int ars_rapd_igrp(struct adbuf *dest, struct ars_packet *pkt, int layer); +int ars_rapd_igrpentry(struct adbuf *dest, struct ars_packet *pkt, int layer); +int ars_rapd_data(struct adbuf *dest, struct ars_packet *pkt, int layer); + +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ + !defined(__bsdi__) && !defined(__APPLE__) +size_t strlcpy(char *dst, const char *src, size_t siz); +#endif + +#endif /* _ARS_H */ diff --git a/src/arsglue.c b/src/arsglue.c new file mode 100644 index 0000000..35bb8d1 --- /dev/null +++ b/src/arsglue.c @@ -0,0 +1,34 @@ +/* Glue between hping and the ars engine */ + +/* $Id: arsglue.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include +#include "ars.h" + +/* Send the APD described packet {s} */ +void hping_ars_send(char *apd) +{ + struct ars_packet p; + int s; + + ars_init(&p); + s = ars_open_rawsocket(&p); + if (s == -ARS_ERROR) { + perror("Opening raw socket"); + exit(1); + } + if (ars_d_build(&p, apd) != -ARS_OK) { + fprintf(stderr, "APD error: %s\n", p.p_error); + exit(1); + } + if (ars_compile(&p) != -ARS_OK) { + fprintf(stderr, "APD error compiling: %s\n", p.p_error); + exit(1); + } + if (ars_send(s, &p, NULL, 0) != -ARS_OK) { + perror("Sending the packet"); + exit(1); + } + exit(0); +} diff --git a/src/binding.c b/src/binding.c new file mode 100644 index 0000000..60c1e4d --- /dev/null +++ b/src/binding.c @@ -0,0 +1,57 @@ +/* + * $smu-mark$ + * $name: binding.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:46 MET 1999$ + * $rev: 11$ + */ + +/* $Id: binding.c,v 1.2 2003/09/01 00:15:22 antirez Exp $ */ + +#include +#include +#include +#include + +#include "hping2.h" +#include "globals.h" + +void inc_destparm(int sid) +{ + static long sec = 0; + static long usec = 0; + int *p; + int errno_save = errno; + + switch (ctrlzbind) { + case BIND_DPORT: + p = &dst_port; + break; + case BIND_TTL: + p = &src_ttl; + break; + default: + printf("error binding ctrl+z\n"); + /* errno = errno_save; */ + return; + } + + if ( (time(NULL) == sec) && ((get_usec() - usec) < 200000) ) { + if (*p > 0) + (*p)-=2; + if (*p < 0) + *p=0; + } else + (*p)++; + + printf("\b\b\b\b\b\b\b\b\b"); + printf("%d: ", *p); + fflush(stdout); + + sec = time(NULL); + usec = get_usec(); + signal(SIGTSTP, inc_destparm); + errno = errno_save; +} diff --git a/src/cksum.c b/src/cksum.c new file mode 100644 index 0000000..cadca4d --- /dev/null +++ b/src/cksum.c @@ -0,0 +1,30 @@ +/* $Id: cksum.c,v 1.3 2004/04/14 12:30:18 antirez Exp $ */ + +#include "hping2.h" /* only for arch semi-indipendent data types */ +#include "globals.h" + +/* + * from R. Stevens's Network Programming + */ +__u16 cksum(__u16 *buf, int nbytes) +{ + __u32 sum; + + sum = 0; + while (nbytes > 1) { + sum += *buf++; + nbytes -= 2; + } + + if (nbytes == 1) { + sum += *((__u8*)buf); + } + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + + /* return a bad checksum with --badcksum option */ + if (opt_badcksum) sum ^= 0x5555; + + return (__u16) ~sum; +} diff --git a/src/datafiller.c b/src/datafiller.c new file mode 100644 index 0000000..966cda7 --- /dev/null +++ b/src/datafiller.c @@ -0,0 +1,76 @@ +/* + * $smu-mark$ + * $name: datafiller.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:47 MET 1999$ + * $rev: 8$ + */ + +/* $Id: datafiller.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include /* memset */ + +#include "hping2.h" +#include "globals.h" + +void datafiller(char *p, int size) +{ + static int fd = 0; + int readed, diff; + + if (!fd) { + fd = open(datafilename, O_RDONLY); + if (fd == -1) { + perror("[datafiller] open()"); + fd = 0; /* will retry to open the file for + * the next packet */ + memset(p, 'X', size); + return; + } + } + + if (p == NULL && fd != -1) { /* seek operation */ + /* size-1 because packet with id 1 start from 0 */ + lseek(fd, (data_size-signlen)*(size-1), SEEK_SET); + return; + } + +restart: /* if EOF occurs, after rewind, restart */ + + readed = read(fd, p, size); + if (readed == size) + return; + else if (readed == -1) { + perror("[datafiller] read()"); + close(fd); + fd = 0; /* will retry to open the file for the next packet */ + memset(p, 'X', size); + return; + } + else if (readed < size && opt_end == FALSE) { + lseek(fd, 0, SEEK_SET); + if (readed == 0) + goto restart; + } + else if (readed < size && opt_end == TRUE) { + fprintf(stderr, "EOF reached, wait some second than press " + "ctrl+c\n"); + eof_reached = TRUE; + } else { + printf("[datafiller.c INTERNAL ERROR] readed = %d - " + "opt_end == %d\n", readed, opt_end); + exit(1); + } + diff = size - readed; + memset(p+readed, '\0', diff); /* padding */ + lseek(fd, 0, SEEK_SET); + return; +} diff --git a/src/datahandler.c b/src/datahandler.c new file mode 100644 index 0000000..99132ef --- /dev/null +++ b/src/datahandler.c @@ -0,0 +1,41 @@ +/* + * $smu-mark$ + * $name: datahandler.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:47 MET 1999$ + * $rev: 8$ + */ + +/* $Id: datahandler.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include + +#include "hping2.h" +#include "globals.h" + +void data_handler(char *data, int data_size) +{ + if (opt_listenmode) { /* send an HCMP */ + memcpy(data, rsign, signlen); /* ok, write own reverse sign */ + data+=signlen; + data_size-=signlen; + memcpy(data, hcmphdr_p, data_size); + return; /* done */ + } + + if (opt_sign) { + memcpy(data, sign, signlen); /* lenght pre-checked */ + data+=signlen; + data_size-=signlen; + } + + if (data_size == 0) + return; /* there is not space left */ + + if (opt_datafromfile) + datafiller(data, data_size); + else + memset(data, 'X', data_size); +} diff --git a/display_ipopt.c b/src/display_ipopt.c similarity index 52% rename from display_ipopt.c rename to src/display_ipopt.c index 7b05a50..0d471c4 100644 --- a/display_ipopt.c +++ b/src/display_ipopt.c @@ -60,79 +60,79 @@ struct myiphdr *ip; struct in_addr in; - ip = (struct myiphdr *)buf; - hlen = ip->ihl * 4; - - cp = (u_char *)buf + sizeof(struct myiphdr); + ip = (struct myiphdr *)buf; + hlen = ip->ihl * 4; + + cp = (u_char *)buf + sizeof(struct myiphdr); - for (; hlen > (int)sizeof(struct myiphdr); --hlen, ++cp) - switch (*cp) { - case IPOPT_EOL: - hlen = 0; - break; - case IPOPT_LSRR: - (void)printf("LSRR: "); - hlen -= 2; - j = *++cp; - ++cp; - if (j > IPOPT_MINOFF) - for (;;) { - l = *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - in.s_addr=htonl(l); - printf("\t%s",inet_ntoa(in)); - hlen -= 4; - j -= 4; - if (j <= IPOPT_MINOFF) - break; - (void)putchar('\n'); - } - break; - case IPOPT_RR: - j = *++cp; /* get length */ - i = *++cp; /* and pointer */ - hlen -= 2; - if (i > j) - i = j; - i -= IPOPT_MINOFF; - if (i <= 0) - continue; - if (i == old_rrlen - && cp == (u_char *)buf + sizeof(struct myiphdr) + 2 - && !memcmp((char *)cp, old_rr, i)) { - (void)printf("\t(same route)\n"); - i = ((i + 3) / 4) * 4; - hlen -= i; - cp += i; - break; - } - old_rrlen = i; - memcpy(old_rr, cp, i); - (void)printf("RR: "); - for (;;) { - l = *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - in.s_addr=htonl(l); - printf("\t%s",inet_ntoa(in)); - hlen -= 4; - i -= 4; - if (i <= 0) - break; - (void)putchar('\n'); - } - putchar('\n'); - - break; - case IPOPT_NOP: - (void)printf("NOP\n"); - break; - default: - (void)printf("unknown option %x\n", *cp); - break; - } + for (; hlen > (int)sizeof(struct myiphdr); --hlen, ++cp) + switch (*cp) { + case IPOPT_EOL: + hlen = 0; + break; + case IPOPT_LSRR: + (void)printf("LSRR: "); + hlen -= 2; + j = *++cp; + ++cp; + if (j > IPOPT_MINOFF) + for (;;) { + l = *++cp; + l = (l<<8) + *++cp; + l = (l<<8) + *++cp; + l = (l<<8) + *++cp; + in.s_addr=htonl(l); + printf("\t%s",inet_ntoa(in)); + hlen -= 4; + j -= 4; + if (j <= IPOPT_MINOFF) + break; + (void)putchar('\n'); + } + break; + case IPOPT_RR: + j = *++cp; /* get length */ + i = *++cp; /* and pointer */ + hlen -= 2; + if (i > j) + i = j; + i -= IPOPT_MINOFF; + if (i <= 0) + continue; + if (i == old_rrlen + && cp == (u_char *)buf + sizeof(struct myiphdr) + 2 + && !memcmp((char *)cp, old_rr, i)) { + (void)printf("\t(same route)\n"); + i = ((i + 3) / 4) * 4; + hlen -= i; + cp += i; + break; + } + old_rrlen = i; + memcpy(old_rr, cp, i); + (void)printf("RR: "); + for (;;) { + l = *++cp; + l = (l<<8) + *++cp; + l = (l<<8) + *++cp; + l = (l<<8) + *++cp; + in.s_addr=htonl(l); + printf("\t%s",inet_ntoa(in)); + hlen -= 4; + i -= 4; + if (i <= 0) + break; + (void)putchar('\n'); + } + putchar('\n'); + + break; + case IPOPT_NOP: + (void)printf("NOP\n"); + break; + default: + (void)printf("unknown option %x\n", *cp); + break; + } } diff --git a/fixtypes.h b/src/fixtypes.h similarity index 100% rename from fixtypes.h rename to src/fixtypes.h diff --git a/src/gethostname.c b/src/gethostname.c new file mode 100644 index 0000000..09b4778 --- /dev/null +++ b/src/gethostname.c @@ -0,0 +1,50 @@ +/* + * $smu-mark$ + * $name: gethostname.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:47 MET 1999$ + * $rev: 8$ + */ + +/* $Id: gethostname.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include + +char *get_hostname(char* addr) +{ + static char answer[1024]; + static char lastreq[1024] = {'\0'}; /* last request */ + struct hostent *he; + struct in_addr naddr; + static char *last_answerp = NULL; + + printf(" get hostname..."); fflush(stdout); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" + " " + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + + if (!strcmp(addr, lastreq)) + return last_answerp; + + strncpy(lastreq, addr, 1024); + inet_pton(AF_INET, addr, &naddr); + he = gethostbyaddr((char*)&naddr, 4, AF_INET); + + if (he == NULL) { + last_answerp = NULL; + return NULL; + } + + strncpy(answer, he->h_name, 1024); + last_answerp = answer; + + return answer; +} diff --git a/src/getifname.c b/src/getifname.c new file mode 100644 index 0000000..62c2d47 --- /dev/null +++ b/src/getifname.c @@ -0,0 +1,355 @@ +/* getifname.c -- network interface handling + * Copyright(C) 1999,2000,2001 Salvatore Sanfilippo + * Copyright(C) 2001 by Nicolas Jombart + * This code is under the GPL license */ + +/* BSD support thanks to Nicolas Jombart */ + +/* $Id: getifname.c,v 1.3 2003/10/22 10:41:00 antirez Exp $ */ + +#include /* perror */ +#include +#include +#include +#include +#include /* struct sockaddr_in */ +#include /* inet_ntoa */ +#include +#include /* close */ +#include + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ + defined(__bsdi__) || defined(__APPLE__) +#include +#include +#endif /* defined(__*BSD__) */ + +#include "hping2.h" +#include "globals.h" + +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ + !defined(__linux__) && !defined(__sun__) && !defined(__bsdi__) && \ + !defined(__APPLE__) +#error Sorry, interface code not implemented. +#endif + +#ifdef __sun__ +#include +#include +#include +#endif + +#if (defined OSTYPE_LINUX) || (defined __sun__) +int get_if_name(void) +{ + int fd; + struct ifconf ifc; + struct ifreq ibuf[16], + ifr, + *ifrp, + *ifend; + struct sockaddr_in sa; + struct sockaddr_in output_if_addr; + int known_output_if = 0; + + /* Try to get the output interface address according to + * the OS routing table */ + if (ifname[0] == '\0') { + if (get_output_if(&remote, &output_if_addr) == 0) { + known_output_if = 1; + if (opt_debug) + printf("DEBUG: Output interface address: %s\n", + inet_ntoa(sa.sin_addr)); + } else { + fprintf(stderr, "Warning: Unable to guess the output " + "interface\n"); + } + } + + if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("[get_if_name] socket(AF_INET, SOCK_DGRAM, 0)"); + return -1; + } + + memset(ibuf, 0, sizeof(struct ifreq)*16); + ifc.ifc_len = sizeof ibuf; + ifc.ifc_buf = (caddr_t) ibuf; + + /* gets interfaces list */ + if ( ioctl(fd, SIOCGIFCONF, (char*)&ifc) == -1 || + ifc.ifc_len < sizeof(struct ifreq) ) { + perror("[get_if_name] ioctl(SIOCGIFCONF)"); + close(fd); + return -1; + } + + /* ifrp points to buffer and ifend points to buffer's end */ + ifrp = ibuf; + ifend = (struct ifreq*) ((char*)ibuf + ifc.ifc_len); + + for (; ifrp < ifend; ifrp++) { + strlcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name)); + + if ( ioctl(fd, SIOCGIFFLAGS, (char*)&ifr) == -1) { + if (opt_debug) + perror("DEBUG: [get_if_name] ioctl(SIOCGIFFLAGS)"); + continue; + } + + if (opt_debug) + printf("DEBUG: if %s: ", ifr.ifr_name); + + /* Down interface? */ + if ( !(ifr.ifr_flags & IFF_UP) ) + { + if (opt_debug) + printf("DOWN\n"); + continue; + } + + if (known_output_if) { + /* Get the interface address */ + if (ioctl(fd, SIOCGIFADDR, (char*)&ifr) == -1) { + perror("[get_if_name] ioctl(SIOCGIFADDR)"); + continue; + } + /* Copy it */ + memcpy(&sa, &ifr.ifr_addr, + sizeof(struct sockaddr_in)); + /* Check if it is what we are locking for */ + if (sa.sin_addr.s_addr != + output_if_addr.sin_addr.s_addr) { + if (opt_debug) + printf("The address doesn't match\n"); + continue; + } + } else if (ifname[0] != '\0' && !strstr(ifr.ifr_name, ifname)) { + if (opt_debug) + printf("Don't Match (but seems to be UP)\n"); + continue; + } + + if (opt_debug) + printf("OK\n"); + + /* interface found, save if name */ + strlcpy(ifname, ifr.ifr_name, 1024); + + /* get if address */ + if ( ioctl(fd, SIOCGIFADDR, (char*)&ifr) == -1) { + perror("DEBUG: [get_if_name] ioctl(SIOCGIFADDR)"); + exit(1); + } + + /* save if address */ + memcpy(&sa, &ifr.ifr_addr, + sizeof(struct sockaddr_in)); + strlcpy(ifstraddr, inet_ntoa(sa.sin_addr), 1024); + + /* get if mtu */ + if ( ioctl(fd, SIOCGIFMTU, (char*)&ifr) == -1) { + perror("Warning: [get_if_name] ioctl(SIOCGIFMTU)"); + fprintf(stderr, "Using a fixed MTU of 1500\n"); + h_if_mtu = 1500; + } + else + { +#ifdef __sun__ + /* somehow solaris is braidamaged in wrt ifr_mtu */ + h_if_mtu = ifr.ifr_metric; +#else + h_if_mtu = ifr.ifr_mtu; +#endif + } + close(fd); + return 0; + } + /* interface not found, use 'lo' */ + strlcpy(ifname, "lo", 1024); + strlcpy(ifstraddr, "127.0.0.1", 1024); + h_if_mtu = 1500; + + close(fd); + return 0; +} + +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__bsdi__) || defined(__APPLE__) + +/* return interface informations : + - from the specified (-I) interface + - from the routing table + - or at least from the first UP interface found +*/ +int get_if_name(void) +{ + /* variable declarations */ + struct ifaddrs *ifap, *ifa; + char current_if_name[24]; + char saved_ifname[24]; + struct sockaddr_in output_if_addr; +#ifdef __NetBSD__ + int s; + struct ifreq ifr; +#endif /* __NetBSD__ */ + + if (getifaddrs(&ifap) < 0) + perror("getifaddrs"); + + saved_ifname[0] = 0; + + /* lookup desired interface */ + if(ifname[0] == 0) { + /* find gateway interface from kernel */ + if (get_output_if(&remote, &output_if_addr) == 0) { + if (opt_debug) + printf("DEBUG: Output interface address: %s\n", + inet_ntoa(output_if_addr.sin_addr)); + /* Put something in saved_ifname in order to tell + that the output adress is known */ + saved_ifname[0] = 'X'; saved_ifname[1] = 0; + } else { + fprintf(stderr, "Warning: Unable to guess the output " + "interface\n"); + } + } + else { + /* use the forced interface name */ + strlcpy(saved_ifname,ifname,24); + } + + /* get interface information */ + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + + if (opt_debug) printf("\n DEBUG: if %s: ", ifa->ifa_name); + + /* print if the data structure is null or not */ + if (ifa->ifa_data) { + if(opt_debug) printf("DEBUG: (struct DATA) "); } + else + if(opt_debug) printf("DEBUG: (struct DATA is NULL) "); + + if (!(ifa->ifa_flags & IFF_UP)) { /* if down */ + if (opt_debug) + printf("DEBUG: DOWN"); + continue; + } + + if ((ifa->ifa_flags & IFF_LOOPBACK)&& + (strncmp(saved_ifname,"lo0",3))) { /* if loopback */ + if (opt_debug) + printf("DEBUG: LOOPBACK, SKIPPED"); + continue; + } + + if (ifa->ifa_addr->sa_family == AF_LINK) { + if (opt_debug) + printf("DEBUG: AF_LINK "); + strlcpy(ifname,ifa->ifa_name,1024); + strlcpy(current_if_name,ifa->ifa_name,24); + +/* I don't know why NetBSD behavior is not the same */ +#ifdef __NetBSD__ + memset( &ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name)); + if( sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len ) + memcpy(&ifr.ifr_addr, ifa->ifa_addr, + ifa->ifa_addr->sa_len); + if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + perror("[get_if_name] socket"); + return -1; + } + if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) h_if_mtu = 0; + else h_if_mtu = ifr.ifr_mtu; + close(s); +#else + if( ifa->ifa_data ) + h_if_mtu = ((struct if_data *)ifa->ifa_data)->ifi_mtu; + else { + h_if_mtu = 1500; + fprintf(stderr, "Warning: fixing MTU to 1500 !\n"); + } +#endif /* __NetBSD__ */ + continue; + } + + if (ifa->ifa_addr->sa_family == AF_INET6) { + if (opt_debug) + printf("AF_INET6 "); + continue; + } + + if (ifa->ifa_addr->sa_family == AF_INET) { + if (opt_debug) + printf("AF_INET "); + + if(strncmp(ifa->ifa_name,current_if_name,24)) + continue; /* error */ + + if(opt_debug) printf("OK\n"); + + strlcpy(ifstraddr, + inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr), + 1024); + + if( (saved_ifname[0] == 0) || + (!strncmp(ifa->ifa_name, saved_ifname, 24)) || + (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == + output_if_addr.sin_addr.s_addr) ) + break; /* asked if found or first UP interface */ + } + + /* interface not found, use hardcoded 'lo' */ + strlcpy(ifname, "lo0", 1024); + strlcpy(ifstraddr, "127.0.0.1", 1024); + h_if_mtu = 1500; + } + + freeifaddrs(ifap); + return 0; +} + +#endif /* __*BSD__ */ + +/* Try to obtain the IP address of the output interface according + * to the OS routing table. Derived from R.Stevens */ +int get_output_if(struct sockaddr_in *dest, struct sockaddr_in *ifip) +{ + socklen_t len; + int sock_rt, on=1; + struct sockaddr_in iface_out; + + memset(&iface_out, 0, sizeof(iface_out)); + sock_rt = socket(AF_INET, SOCK_DGRAM, 0 ); + + dest->sin_port = htons(11111); + if (setsockopt(sock_rt, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) + == -1) { + if (opt_debug) + perror("DEBUG: [get_output_if] setsockopt(SOL_SOCKET, " + "SO_BROADCAST"); + close(sock_rt); + return -1; + } + + if (connect(sock_rt, (struct sockaddr*)dest, sizeof(struct sockaddr_in)) + == -1 ) { + if (opt_debug) + perror("DEBUG: [get_output_if] connect"); + close(sock_rt); + return -1; + } + + len = sizeof(iface_out); + if (getsockname(sock_rt, (struct sockaddr *)&iface_out, &len) == -1 ) { + if (opt_debug) + perror("DEBUG: [get_output_if] getsockname"); + close(sock_rt); + return -1; + } + close(sock_rt); + if (iface_out.sin_addr.s_addr == 0) + return 1; + memcpy(ifip, &iface_out, sizeof(struct sockaddr_in)); + return 0; +} diff --git a/src/getlhs.c b/src/getlhs.c new file mode 100644 index 0000000..b84cad6 --- /dev/null +++ b/src/getlhs.c @@ -0,0 +1,96 @@ +/* + * $smu-mark$ + * $name: getlhs.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:47 MET 1999$ + * $rev: 8$ + */ + +/* $Id: getlhs.c,v 1.5 2004/04/09 23:38:56 antirez Exp $ */ + +#include + +#include "hping2.h" +#include "globals.h" + + +int dltype_to_lhs(int dltype) +{ + int lhs; + + switch(dltype) { + case DLT_EN10MB: +#ifdef DLT_IEEE802 + case DLT_IEEE802: +#endif + lhs = 14; + break; + case DLT_SLIP: + case DLT_SLIP_BSDOS: + lhs = 16; + break; + case DLT_PPP: + case DLT_NULL: +#ifdef DLT_PPP_SERIAL + case DLT_PPP_SERIAL: +#endif +#ifdef DLT_LOOP + case DLT_LOOP: +#endif + lhs = 4; + break; + case DLT_PPP_BSDOS: + lhs = 24; + break; + case DLT_FDDI: + lhs = 13; + break; + case DLT_RAW: + lhs = 0; + break; +#ifdef DLT_IEE802_11 + case DLT_IEEE802_11: + lhs = 14; + break; +#endif + case DLT_ATM_RFC1483: +#ifdef DLT_CIP + case DLT_CIP: +#endif +#ifdef DLT_ATM_CLIP + case DLT_ATM_CLIP: +#endif + lhs = 8; + break; +#ifdef DLT_C_HDLC + case DLT_C_HDLC: + lhs = 4; + break; +#endif +#ifdef DLT_LINUX_SLL + case DLT_LINUX_SLL: +#endif +#ifdef DLT_LANE8023 + case DLT_LANE8023: +#endif + lhs = 16; + break; + default: + return -1; + break; + } + return lhs; +} + +int get_linkhdr_size(char *ifname) +{ + int dltype = pcap_datalink(pcapfp); + + if (opt_debug) + printf("DEBUG: dltype is %d\n", dltype); + + linkhdr_size = dltype_to_lhs(dltype); + return linkhdr_size; +} diff --git a/getusec.c b/src/getusec.c similarity index 80% rename from getusec.c rename to src/getusec.c index fd344ee..26022af 100644 --- a/getusec.c +++ b/src/getusec.c @@ -15,17 +15,17 @@ time_t get_usec(void) { - struct timeval tmptv; + struct timeval tmptv; - gettimeofday(&tmptv, NULL); - return tmptv.tv_usec; + gettimeofday(&tmptv, NULL); + return tmptv.tv_usec; } time_t milliseconds(void) { - struct timeval tv; - gettimeofday(&tv, NULL); - return ((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); + struct timeval tv; + gettimeofday(&tv, NULL); + return ((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); } /* This function returns milliseconds since 1 Jan 1970, diff --git a/src/globals.h b/src/globals.h new file mode 100644 index 0000000..9ef0ccb --- /dev/null +++ b/src/globals.h @@ -0,0 +1,147 @@ +/* + * $smu-mark$ + * $name: globals.h$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:47 MET 1999$ + * $rev: 9$ + */ + +/* $Id: globals.h,v 1.3 2004/06/18 09:53:11 antirez Exp $ */ + +#ifndef _GLOBALS_H +#define _GLOBALS_H + +extern float + rtt_min, + rtt_max, + rtt_avg; + +extern unsigned int + tcp_th_flags, + linkhdr_size, + h_if_mtu, + virtual_mtu, + ip_frag_offset, + signlen, + lsr_length, + ssr_length, + ip_tos, + set_seqnum, + tcp_seqnum, + set_ack, + ip_header_length, + tcp_ack; + +extern unsigned short int + data_size; + +extern int opt_debug, + sockpacket, + sockraw, + sent_pkt, + recv_pkt, + out_of_sequence_pkt, + sending_wait, + opt_rawipmode, + opt_icmpmode, + opt_udpmode, + opt_scanmode, + opt_listenmode, + opt_waitinusec, + opt_numeric, + opt_gethost, + opt_quiet, + opt_relid, + opt_fragment, + opt_df, + opt_mf, + opt_debug, + opt_verbose, + opt_winid_order, + opt_keepstill, + opt_datafromfile, + opt_hexdump, + opt_contdump, + opt_sign, + opt_safe, + opt_end, + opt_traceroute, + opt_seqnum, + opt_incdport, + opt_force_incdport, + opt_icmptype, + opt_icmpcode, + opt_rroute, + opt_tcpexitcode, + opt_badcksum, + opt_tr_keep_ttl, + opt_tcp_timestamp, + opt_clock_skew, + cs_window, + cs_window_shift, + cs_vector_len, + opt_tr_stop, + opt_tr_no_rtt, + opt_rand_dest, + opt_rand_source, + opt_lsrr, + opt_ssrr, + opt_beep, + opt_flood, + tcp_exitcode, + src_ttl, + src_id, + base_dst_port, + dst_port, + src_port, + initsport, + sequence, + src_winsize, + src_thoff, + count, + ctrlzbind, + delaytable_index, + eof_reached, + icmp_ip_version, + icmp_ip_ihl, + icmp_ip_tos, + icmp_ip_tot_len, + icmp_ip_id, + icmp_ip_srcport, + icmp_ip_dstport, + opt_force_icmp, + icmp_ip_protocol, + icmp_cksum, + raw_ip_protocol; + +extern unsigned char lsr[255], + ssr[255]; + +extern char ifname[1024], + ifstraddr[1024], + datafilename[1024], + targetname[1024], + targetstraddr[1024], + spoofaddr[1024], + icmp_ip_srcip[1024], + icmp_ip_dstip[1024], + icmp_gwip[1024], + sign[1024], + rsign[1024], + ip_opt[40], + ip_optlen, + *opt_scanports; + +extern struct sockaddr_in icmp_ip_src, icmp_ip_dst, icmp_gw, local, remote; +extern struct itimerval usec_delay; +extern volatile struct delaytable_element delaytable[TABLESIZE]; +extern struct hcmphdr *hcmphdr_p; + +#include +extern pcap_t *pcapfp; +extern char errbuf[PCAP_ERRBUF_SIZE]; +extern struct pcap_pkthdr hdr; + +#endif /* _GLOBALS_H */ diff --git a/hcmp.h b/src/hcmp.h similarity index 59% rename from hcmp.h rename to src/hcmp.h index eb290e5..848851b 100644 --- a/hcmp.h +++ b/src/hcmp.h @@ -10,17 +10,17 @@ /* Hping Control Message Protocol */ -#define HCMP_RESTART 1 -#define HCMP_SOURCE_QUENCH 2 -#define HCMP_SOURCE_STIRUP 3 -#define HCMP_CHPROTO 4 /* still unused */ +#define HCMP_RESTART 1 +#define HCMP_SOURCE_QUENCH 2 +#define HCMP_SOURCE_STIRUP 3 +#define HCMP_CHPROTO 4 /* still unused */ struct hcmphdr { - __u8 type; - union - { - __u16 seqnum; - __u32 usec; - } typedep; + __u8 type; + union + { + __u16 seqnum; + __u32 usec; + } typedep; }; diff --git a/hex.c b/src/hex.c similarity index 65% rename from hex.c rename to src/hex.c index dfa3606..e145859 100644 --- a/hex.c +++ b/src/hex.c @@ -35,28 +35,28 @@ static char hcharset[16] = "0123456789abcdef"; * get the length. */ int hextobin(void *dest, char *hexstr, int len) { - int i, binlen; - char *s = hexstr; - unsigned char *d = dest; + int i, binlen; + char *s = hexstr; + unsigned char *d = dest; - if (len == -1) - len = strlen(hexstr); - if (len % 2) - return 1; /* error, odd count */ - binlen = len / 2; - for (i = 0; i < binlen; i++) { - int high, low; + if (len == -1) + len = strlen(hexstr); + if (len % 2) + return 1; /* error, odd count */ + binlen = len / 2; + for (i = 0; i < binlen; i++) { + int high, low; - high = hval[((unsigned)*s)&0xFF]; - low = hval[((unsigned)*(s+1))&0xFF]; - if (high == 255 || low == 255) - return 1; /* invalid char in hex string */ - high <<= 4; - *d = high|low; - d++; - s+=2; - } - return 0; + high = hval[((unsigned)*s)&0xFF]; + low = hval[((unsigned)*(s+1))&0xFF]; + if (high == 255 || low == 255) + return 1; /* invalid char in hex string */ + high <<= 4; + *d = high|low; + d++; + s+=2; + } + return 0; } /* Convert binary data pointed by 'bin' of length 'len' into an hex string @@ -67,16 +67,16 @@ int hextobin(void *dest, char *hexstr, int len) * This function can't fail. */ void bintohex(char *dest, void *bin, int len) { - unsigned char *b = bin; - int i, high, low; + unsigned char *b = bin; + int i, high, low; - for (i = 0; i < len; i++) { - low = *b & 0xF; - high = (*b & 0xF0) >> 4; - *dest++ = hcharset[high]; - *dest++ = hcharset[low]; - b++; - } + for (i = 0; i < len; i++) { + low = *b & 0xF; + high = (*b & 0xF0) >> 4; + *dest++ = hcharset[high]; + *dest++ = hcharset[low]; + b++; + } } /* This example main show the usage. */ @@ -84,31 +84,31 @@ void bintohex(char *dest, void *bin, int len) #include int main(int argc, char **argv) { - unsigned char *buf; - char *xbuf; - int hlen, blen, i; + unsigned char *buf; + char *xbuf; + int hlen, blen, i; - if (argc == 1) - exit(1); + if (argc == 1) + exit(1); - /* Convert from hex to binary */ - hlen = strlen(argv[1]); - blen = (hlen+1)/2; - buf = malloc(blen); - if (!buf) - exit(1); - hextobin(buf, argv[1], -1); - for (i = 0; i < blen; i++) { - printf("%02x", buf[i]); - } - printf("\n"); + /* Convert from hex to binary */ + hlen = strlen(argv[1]); + blen = (hlen+1)/2; + buf = malloc(blen); + if (!buf) + exit(1); + hextobin(buf, argv[1], -1); + for (i = 0; i < blen; i++) { + printf("%02x", buf[i]); + } + printf("\n"); - /* and from binary to hex */ - xbuf = malloc((blen*2)+1); - if (!xbuf) - exit(1); - bintohex(xbuf, buf, blen); - printf("%s\n", xbuf); - return 0; + /* and from binary to hex */ + xbuf = malloc((blen*2)+1); + if (!xbuf) + exit(1); + bintohex(xbuf, buf, blen); + printf("%s\n", xbuf); + return 0; } #endif diff --git a/hex.h b/src/hex.h similarity index 100% rename from hex.h rename to src/hex.h diff --git a/src/hping2.h b/src/hping2.h new file mode 100644 index 0000000..cb23ee7 --- /dev/null +++ b/src/hping2.h @@ -0,0 +1,429 @@ +/* + * $smu-mark$ + * $name: hping2.h$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:48 MET 1999$ + * $rev: 9$ + */ + +/* $Id: hping2.h,v 1.4 2004/06/04 07:22:38 antirez Exp $ */ + +#ifndef _HPING2_H +#define _HPING2_H + +#include +#include +#include +#include +#include "config.h" +#include "fixtypes.h" + +/* types */ +#ifndef __u8 +#define __u8 u_int8_t +#endif /* __u8 */ +#ifndef __u16 +#define __u16 u_int16_t +#endif /* __u16 */ +#ifndef __u32 +#define __u32 u_int32_t +#endif /* __u32 */ + +#ifndef __uint8_t +#define __uint8_t u_int8_t +#endif /* __uint8_t */ +#ifndef __uint16_t +#define __uint16_t u_int16_t +#endif /* __uint16_t */ +#ifndef __uint32_t +#define __uint32_t u_int32_t +#endif /* __uint32_t */ + +#include "hcmp.h" /* Hping Control Message Protocol */ + +/* protocols header size */ +#ifndef ICMPHDR_SIZE +#define ICMPHDR_SIZE sizeof(struct myicmphdr) +#endif +#ifndef UDPHDR_SIZE +#define UDPHDR_SIZE sizeof(struct myudphdr) +#endif +#ifndef TCPHDR_SIZE +#define TCPHDR_SIZE sizeof(struct mytcphdr) +#endif +#ifndef IPHDR_SIZE +#define IPHDR_SIZE sizeof(struct myiphdr) +#endif + +/* wait X seconds after reached to sent packets in oreder to display replies */ +#define COUNTREACHED_TIMEOUT 1 + +/* requests status table stuffs */ +/* Warning, TABLESIZE 0 == floating point exception */ +#define TABLESIZE 400 +#define S_SENT 0 +#define S_RECV 1 + +/* usefull defines */ +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif +#ifndef PF_PACKET +#define PF_PACKET 17 /* kernel 2.[12].* with 2.0.* kernel headers? */ +#endif +#ifndef ETH_P_IP +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#endif +#ifndef ABS +#define ABS(x) (((x)>0) ? (x) : -(x)) +#endif + +/* header size of some physical layer type */ +#define PPPHDR_SIZE_LINUX 0 +#define PPPHDR_SIZE_FREEBSD 4 +#define PPPHDR_SIZE_OPENBSD 4 +#define PPPHDR_SIZE_NETBSD 4 +#define PPPHDR_SIZE_BSDI 4 +#define ETHHDR_SIZE 14 +#define LOHDR_SIZE 14 +#define WLANHDR_SIZE 14 +#define TRHDR_SIZE 20 + +/* packet size (physical header size + ip header + tcp header + 0 data bytes) */ +#ifndef IP_MAX_SIZE +#define IP_MAX_SIZE 65535 +#endif + +/* absolute offsets */ +#define ABS_OFFSETIP linkhdr_size +#define ABS_OFFSETTCP ( linkhdr_size + IPHDR_SIZE ) +#define ABS_OFFSETICMP ( linkhdr_size + IPHDR_SIZE ) +#define ABS_OFFSETUDP ( linkhdr_size + IPHDR_SIZE ) + +/* defaults and misc */ +#define DEFAULT_SENDINGWAIT 1 /* wait 1 sec. between sending each packets */ +#define DEFAULT_DPORT 0 /* default dest. port */ +#define DEFAULT_INITSPORT -1 /* default initial source port: -1 means random */ +#define DEFAULT_COUNT -1 /* default packets count: -1 means forever */ +#define DEFAULT_TTL 64 /* default ip->ttl value */ +#define DEFAULT_SRCWINSIZE 512 /* default tcp windows size */ +#define DEFAULT_VIRTUAL_MTU 16 /* tiny fragments */ +#define DEFAULT_ICMP_TYPE 8 /* echo request */ +#define DEFAULT_ICMP_CODE 0 /* icmp-type relative */ +#define DEFAULT_ICMP_IP_VERSION 4 +#define DEFAULT_ICMP_IP_IHL (IPHDR_SIZE >> 2) +#define DEFAULT_ICMP_IP_TOS 0 +#define DEFAULT_ICMP_IP_TOT_LEN 0 /* computed by send_icmp_*() */ +#define DEFAULT_ICMP_IP_ID 0 /* rand */ +#define DEFAULT_ICMP_CKSUM -1 /* -1 means compute the cksum */ +#define DEFAULT_ICMP_IP_PROTOCOL 6 /* TCP */ +#define DEFAULT_RAW_IP_PROTOCOL 6 /* TCP */ +#define DEFAULT_TRACEROUTE_TTL 1 + +#define BIND_NONE 0 /* no bind */ +#define BIND_DPORT 1 /* bind destination port */ +#define BIND_TTL 2 /* bind ip->ttl */ +#define DEFAULT_BIND BIND_DPORT + +#define DEFAULT_CS_WINDOW 300 +#define DEFAULT_CS_WINDOW_SHIFT 5 +#define DEFAULT_CS_VECTOR_LEN 10 + +/* fragmentation defines */ +#define MF ((unsigned short)0x2000) /* more fragments */ +#define DF ((unsigned short)0x4000) /* dont fragment */ +#define NF ((unsigned short)0x0000) /* no more fragments */ + +/* ip options defines */ +#define IPOPT_COPY 0x80 +#define IPOPT_CLASS_MASK 0x60 +#define IPOPT_NUMBER_MASK 0x1f + +#define IPOPT_COPIED(o) ((o)&IPOPT_COPY) +#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK) +#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_MEASUREMENT 0x40 +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_END (0 |IPOPT_CONTROL) +#define IPOPT_NOOP (1 |IPOPT_CONTROL) +#define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY) +#define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY) +#define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT) +#define IPOPT_RR (7 |IPOPT_CONTROL) +#define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY) +#define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY) +#define IPOPT_RA (20|IPOPT_CONTROL|IPOPT_COPY) + +#define IPOPT_OPTVAL 0 +#define IPOPT_OLEN 1 +#define IPOPT_OFFSET 2 +#define IPOPT_MINOFF 4 +#define MAX_IPOPTLEN 40 +#define IPOPT_NOP IPOPT_NOOP +#define IPOPT_EOL IPOPT_END +#define IPOPT_TS IPOPT_TIMESTAMP + +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ + +/* tcp flags */ +#ifndef TH_FIN +#define TH_FIN 0x01 +#endif +#ifndef TH_SYN +#define TH_SYN 0x02 +#endif +#ifndef TH_RST +#define TH_RST 0x04 +#endif +#ifndef TH_PUSH +#define TH_PUSH 0x08 +#endif +#ifndef TH_ACK +#define TH_ACK 0x10 +#endif +#ifndef TH_URG +#define TH_URG 0x20 +#endif +#ifndef TH_X +#define TH_X 0x40 /* X tcp flag */ +#endif +#ifndef TH_Y +#define TH_Y 0x80 /* Y tcp flag */ +#endif + +/* ICMP TYPE */ +#define ICMP_ECHOREPLY 0 /* Echo Reply */ +#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ +#define ICMP_SOURCE_QUENCH 4 /* Source Quench */ +#define ICMP_REDIRECT 5 /* Redirect (change route) */ +#define ICMP_ECHO 8 /* Echo Request */ +#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ +#define ICMP_PARAMETERPROB 12 /* Parameter Problem */ +#define ICMP_TIMESTAMP 13 /* Timestamp Request */ +#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ +#define ICMP_INFO_REQUEST 15 /* Information Request */ +#define ICMP_INFO_REPLY 16 /* Information Reply */ +#define ICMP_ADDRESS 17 /* Address Mask Request */ +#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ + +/* Codes for UNREACHABLE */ +#define ICMP_NET_UNREACH 0 /* Network Unreachable */ +#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ +#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ +#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ +#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ +#define ICMP_SR_FAILED 5 /* Source Route failed */ +#define ICMP_NET_UNKNOWN 6 +#define ICMP_HOST_UNKNOWN 7 +#define ICMP_HOST_ISOLATED 8 +#define ICMP_NET_ANO 9 +#define ICMP_HOST_ANO 10 +#define ICMP_NET_UNR_TOS 11 +#define ICMP_HOST_UNR_TOS 12 +#define ICMP_PKT_FILTERED 13 /* Packet filtered */ +#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ +#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ +#define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */ + +/* Codes for REDIRECT */ +#define ICMP_REDIR_NET 0 /* Redirect Net */ +#define ICMP_REDIR_HOST 1 /* Redirect Host */ +#define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ +#define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ + +/* Codes for TIME_EXCEEDED */ +#define ICMP_EXC_TTL 0 /* TTL count exceeded */ +#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ + +/* + * IP header + */ +struct myiphdr { +#if defined (WORDS_BIGENDIAN) + __u8 version:4, + ihl:4; +#else + __u8 ihl:4, + version:4; +#endif + __u8 tos; + __u16 tot_len; + __u16 id; + __u16 frag_off; + __u8 ttl; + __u8 protocol; + __u16 check; + __u32 saddr; + __u32 daddr; +}; + +/* + * UDP header + */ +struct myudphdr { + __u16 uh_sport; /* source port */ + __u16 uh_dport; /* destination port */ + __u16 uh_ulen; /* udp length */ + __u16 uh_sum; /* udp checksum */ +}; + +/* + * TCP header. + * Per RFC 793, September, 1981. + */ +struct mytcphdr { + __u16 th_sport; /* source port */ + __u16 th_dport; /* destination port */ + __u32 th_seq; /* sequence number */ + __u32 th_ack; /* acknowledgement number */ +#if defined (WORDS_BIGENDIAN) + __u8 th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#else + __u8 th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#endif + __u8 th_flags; + __u16 th_win; /* window */ + __u16 th_sum; /* checksum */ + __u16 th_urp; /* urgent pointer */ +}; + +/* + * ICMP header + */ +struct myicmphdr +{ + __u8 type; + __u8 code; + __u16 checksum; + union + { + struct + { + __u16 id; + __u16 sequence; + } echo; + __u32 gateway; + } un; +}; + +struct icmp_tstamp_data { + __u32 orig; + __u32 recv; + __u32 tran; +}; + +/* + * UDP/TCP pseudo header + * for cksum computing + */ +struct pseudohdr +{ + __u32 saddr; + __u32 daddr; + __u8 zero; + __u8 protocol; + __u16 lenght; +}; + +#define PSEUDOHDR_SIZE sizeof(struct pseudohdr) + +/* + * hping replies delay table + */ +struct delaytable_element { + int seq; + int src; + time_t sec; + time_t usec; + int status; +}; + +extern volatile struct delaytable_element delaytable[TABLESIZE]; + +/* protos */ +void nop(void); /* nop */ +int parse_options(int, char**); /* option parser */ +int get_if_name(void); /* get interface (see source) */ +int get_output_if(struct sockaddr_in *dest, struct sockaddr_in *ifip); +int dltype_to_lhs(int dltype); +int get_linkhdr_size(char*); /* get link layer hdr size */ +int open_sockpacket(void); /* open SOCK_PACKET socket */ +int open_sockpacket_ifindex(int ifindex); +int close_sockpacket(int); /* close SOCK_PACKET socket */ +int open_sockraw(void); /* open raw socket */ +void send_packet (int signal_id); +void send_rawip (void); +void send_tcp(void); +void send_udp(void); +void send_icmp(void); +void send_hcmp(__u8 type, __u32 arg); /* send hcmp packets */ +void send_ip (char*, char*, char*, unsigned int, int, unsigned short, + char*, char); +void send_ip_handler(char *packet, unsigned int size); /* fragmentation + handler */ +void wait_packet(void); /* handle incoming packets */ +void print_statistics(int); +void show_usage(void); +void show_version(void); +int resolve_addr(struct sockaddr * addr, char *hostname); /* resolver */ +void resolve(struct sockaddr*, char*); /* resolver, exit on err. */ +void log_icmp_unreach(char*, unsigned short);/* ICMP unreachable logger */ +void log_icmp_timeexc(char*, unsigned short);/* ICMP time exceeded logger */ +time_t get_usec(void); /* return current usec */ +time_t milliseconds(void); /* ms from UT midnight */ +long long mstime(void); /* ms from 1 Jan 1970 */ +#define get_midnight_ut_ms milliseconds /* backward compatibilty */ +__u16 cksum(__u16 *buf, int nwords); /* compute 16bit checksum */ +void inc_destparm(int sid); /* inc dst port or ttl */ +char *get_hostname(char*); /* get host from addr */ +void datafiller(char *p, int size); /* fill data from file */ +void data_handler(char *data, int data_size);/* handle data filling */ +void socket_broadcast(int sd); /* set SO_BROADCAST option */ +void socket_iphdrincl(int sd); /* set SO_IPHDRINCL option */ +void listenmain(void); /* main for listen mode */ +char *memstr(char *haystack, char *needle, int size); /* memstr */ +void tos_help(void); /* show the TOS help */ +int rtt(int *seqp, int recvport, float *ms_delay); /* compute round trip time */ +int relativize_id(int seqnum, int *ip_id); /* compute relative id */ +int if_promisc_on(int s); /* promisc. mode ON */ +int if_promisc_off(int s); /* promisc. mode OFF */ +int open_pcap(void); /* open libpcap socket */ +int close_pcap(void); /* close libpcap socket */ +int pcap_recv(char *, unsigned int); /* libpcap api wrapper */ +int memlock(char *addr, size_t size); /* disable paging */ +int memunlock(char *addr, size_t size); /* enable paging */ +int memlockall(void); /* disable paging (all pages) */ +int memunlockall(void); /* enable paging (all pages) */ +unsigned char ip_opt_build(char *ip_opt); /* build ip options */ +void display_ipopt(char* buf); /* display ip options */ +void icmp_help(void); /* show the ICMP help */ +void route_help(void); /* show the route help */ +void (*Signal(int signo, void (*func)(int)))(int); +void delaytable_add(int seq, int src, time_t sec, time_t usec, int status); +int read_packet(void *packet, int size); +void scanmain(void); +void hping_script(int argc, char **argv); +u_int32_t hp_rand(void); +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ + !defined(__bsdi__) && !defined(__APPLE__) +size_t strlcpy(char *dst, const char *src, size_t siz); +#endif + +/* ARS glue */ +void hping_ars_send(char *s); + +#endif /* _HPING2_H */ diff --git a/src/hstring.c b/src/hstring.c new file mode 100644 index 0000000..164c854 --- /dev/null +++ b/src/hstring.c @@ -0,0 +1,82 @@ +/* hstring.c - Random string-related functions for hping. + * Copyright(C) 2003 Salvatore Sanfilippo + * All rights reserved */ + +/* $Id: hstring.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include +#include + +/* return 1 if the string looks like an integer number + * otherwise 0 is returned. + * + * this function is equivalent to this regexp: + * [:space:]*-{0,1}[0-9]+[:space:]* + * in english: + * (0-inf spaces)(zero or one -)(1-inf digits)(0-inf spaces) + */ +int strisnum(char *s) +{ + int digits = 0; /* used to return false if there aren't digits */ + + while(isspace(*s)) + s++; /* skip initial spaces */ + if (*s == '-') /* negative number? */ + s++; + while(*s) { + if (isspace(*s)) { /* skip spaces in the tail */ + while(isspace(*s)) + s++; + if (*s) return 0; /* but don't allow other tail chars */ + return digits ? 1 : 0; + } + if (!isdigit(*s)) + return 0; + s++; + digits++; + } + return digits ? 1 : 0; +} + +/* function similar to strtok() more convenient when we know the + * max number of tokens, to tokenize with a single call. + * Unlike strtok(), strftok() is thread safe. + * + * ARGS: + * 'sep' is a string that contains all the delimiter characters + * 'str' is the string to tokenize, that will be modified + * 'tptrs' is an array of char* poiters that will contain the token pointers + * 'nptrs' is the length of the 'tptrs' array. + * + * RETURN VALUE: + * The number of extracted tokens is returned. + */ +size_t strftok(char *sep, char *str, char **tptrs, size_t nptrs) +{ + size_t seplen = strlen(sep); + size_t i, j = 0; + int inside = 0; + + while(*str) { + for(i = 0; i < seplen; i++) { + if (sep[i] == *str) + break; + } + if (i == seplen) { /* no match */ + if (!inside) { + tptrs[j++] = str; + inside = 1; + } + } else { /* match */ + if (inside) { + *str = '\0'; + if (j == nptrs) + return j; + inside = 0; + } + } + str++; + } + return j; +} diff --git a/hstring.h b/src/hstring.h similarity index 100% rename from hstring.h rename to src/hstring.h diff --git a/src/if_promisc.c b/src/if_promisc.c new file mode 100644 index 0000000..c3cb533 --- /dev/null +++ b/src/if_promisc.c @@ -0,0 +1,62 @@ +/* + * $smu-mark$ + * $name: if_promisc.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:48 MET 1999$ + * $rev: 2$ + */ + +/* $Id: if_promisc.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hping2.h" +#include "globals.h" + +int if_promisc_on(int s) +{ + struct ifreq ifr; + + strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + if ( ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { + perror("[if_prommisc_on] ioctl(SIOCGIFFLAGS)"); + return -1; + } + + if (!(ifr.ifr_flags & IFF_PROMISC)) { + ifr.ifr_flags |= IFF_PROMISC; + if ( ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { + perror("[if_promisc_on] ioctl(SIOCSIFFLAGS)"); + return -1; + } + } + return 0; +} + +int if_promisc_off(int s) +{ + struct ifreq ifr; + + strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + if ( ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { + perror("[if_promisc_off] ioctl(SIOCGIFFLAGS)"); + return -1; + } + + if (ifr.ifr_flags & IFF_PROMISC) { + ifr.ifr_flags ^= IFF_PROMISC; + if ( ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { + perror("[if_promisc_off] ioctl(SIOCSIFFLAGS)"); + return -1; + } + } + return 0; +} diff --git a/src/in.h b/src/in.h new file mode 100644 index 0000000..f025f14 --- /dev/null +++ b/src/in.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2000,2001 Salvatore Sanfilippo */ + +#ifndef ARS_IPPROTO_IP + +#define ARS_IPPROTO_IP 0 /* Dummy protocol for TCP. */ +#define ARS_IPPROTO_HOPOPTS 0 /* IPv6 Hop-by-Hop options. */ +#define ARS_IPPROTO_ICMP 1 /* Internet Control Message Protocol. */ +#define ARS_IPPROTO_IGMP 2 /* Internet Group Management Protocol. */ +#define ARS_IPPROTO_IPIP 4 /* IPIP tunnels (older KA9Q tunnels use 94).*/ +#define ARS_IPPROTO_TCP 6 /* Transmission Control Protocol. */ +#define ARS_IPPROTO_EGP 8 /* Exterior Gateway Protocol. */ +#define ARS_IPPROTO_IGRP 9 /* Cisco(R)'s IGRP Routing Portocol. */ +#define ARS_IPPROTO_PUP 12 /* PUP protocol. */ +#define ARS_IPPROTO_UDP 17 /* User Datagram Protocol. */ +#define ARS_IPPROTO_IDP 22 /* XNS IDP protocol. */ +#define ARS_IPPROTO_TP 29 /* SO Transport Protocol Class 4. */ +#define ARS_IPPROTO_IPV6 41 /* IPv6 header. */ +#define ARS_IPPROTO_ROUTING 43 /* IPv6 routing header. */ +#define ARS_IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header. */ +#define ARS_IPPROTO_RSVP 46 /* Reservation Protocol. */ +#define ARS_IPPROTO_GRE 47 /* General Routing Encapsulation. */ +#define ARS_IPPROTO_ESP 50 /* encapsulating security payload. */ +#define ARS_IPPROTO_AH 51 /* authentication header. */ +#define ARS_IPPROTO_ICMPV6 58 /* ICMPv6. */ +#define ARS_IPPROTO_NONE 59 /* IPv6 no next header. */ +#define ARS_IPPROTO_DSTOPTS 60 /* IPv6 destination options. */ +#define ARS_IPPROTO_MTP 92 /* Multicast Transport Protocol. */ +#define ARS_IPPROTO_ENCAP 98 /* Encapsulation Header. */ +#define ARS_IPPROTO_PIM 103 /* Protocol Independent Multicast. */ +#define ARS_IPPROTO_COMP 108 /* Compression Header Protocol. */ +#define ARS_IPPROTO_RAW 255 /* Raw IP packets. */ + +#endif diff --git a/src/interface.c b/src/interface.c new file mode 100644 index 0000000..365de77 --- /dev/null +++ b/src/interface.c @@ -0,0 +1,323 @@ +/* interfaces.c -- that's getifname.c redone with a decent API. + * This fils is for now used for the TCL bindings but it + * should replace getifname.c at some time. + * + * Note that most of the code comes from getifname.c, so the + * old copyright still apply: + * + * Copyright(C) 1999,2000,2001 Salvatore Sanfilippo + * Copyright(C) 2001 by Nicolas Jombart + * This code is under the GPL license + * + * What changes is the API design that's now sane, the changes + * are Copyright(C) 2003 Salvatore Sanfilippo. + */ + +/* $Id: interface.c,v 1.7 2003/09/08 15:32:40 antirez Exp $ */ + +#ifdef USE_TCL + +#include /* perror */ +#include +#include +#include +#include +#include /* struct sockaddr_in */ +#include /* inet_ntoa */ +#include +#include /* close */ + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ + defined(__bsdi__) || defined(__APPLE__) +#include +#include +#include +#include +#endif /* defined(__*BSD__) */ + +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ + !defined(__linux__) && !defined(__sun__) && !defined(__bsdi__) && \ + !defined(__APPLE__) +#error Sorry, interface code not implemented. +#endif + +#ifdef __sun__ +#include +#include +#include +#endif + +#include "hping2.h" +#include "globals.h" +#include "interface.h" + +/* This function fill the hpingif structures array poited by 'i', + * able to hold up to 'ilen' elements, with details about + * all the interfaces present in the system, with the UP flag set. + * + * The function returns the number of active interfaces found, + * regardless to 'ilen'. So if the returned value is > ilen + * the provided structures array was not enough to hold all + * the interfaces. + * + * On error -1 is returned, and errno set. */ +#if (defined OSTYPE_LINUX) || (defined __sun__) +int hping_get_interfaces(struct hpingif *hif, int ilen) +{ + int fd, found = 0, i; + struct ifconf ifc; + struct ifreq ibuf[HPING_IFACE_MAX], ifr; + + /* We need a socket to perform the ioctl()s */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) + return -1; + /* Setup the request structure */ + memset(ibuf, 0, sizeof(struct ifreq)*HPING_IFACE_MAX); + ifc.ifc_len = sizeof ibuf; + ifc.ifc_buf = (caddr_t) ibuf; + /* Get a list of interfaces */ + if (ioctl(fd, SIOCGIFCONF, (char*)&ifc) == -1 || + ifc.ifc_len < sizeof(struct ifreq)) + { + close(fd); + return -1; + } + /* Walk the interfaces list, searching for UP interfaces */ + for (i = 0; i < (ifc.ifc_len/sizeof(struct ifreq)); i++) { + struct ifreq *this = ibuf+i; + in_addr_t ifaddr, ifbaddr = 0; + struct sockaddr_in *sain; + int ifloopback, ifmtu, ifptp, ifpromisc, ifbroadcast, ifindex, ifnolink = 0; + + memset(&ifr, 0, sizeof(ifr)); + /* It seems we can avoid to call the ioctl against + * a bogus device with little efforts */ + if (!this->ifr_name[0]) + continue; + strlcpy(ifr.ifr_name, this->ifr_name, HPING_IFNAME_LEN); + /* Get the interface's flags */ + if (ioctl(fd, SIOCGIFFLAGS, (char*)&ifr) == -1) { + /* oops.. failed, continue with the next */ + continue; + } + /* If it's DOWN we are not intersted */ + if (!(ifr.ifr_flags & IFF_UP)) + continue; + ifloopback = (ifr.ifr_flags & IFF_LOOPBACK) != 0; + ifptp = (ifr.ifr_flags & IFF_POINTOPOINT) != 0; + ifpromisc = (ifr.ifr_flags & IFF_PROMISC) != 0; + ifbroadcast = (ifr.ifr_flags & IFF_BROADCAST) != 0; +#ifdef __sun__ + ifindex = -1; +#else + /* Get the interface index */ + if (ioctl(fd, SIOCGIFINDEX, (char*)&ifr) == -1) { + /* oops.. failed, continue with the next */ + continue; + } + ifindex = ifr.ifr_ifindex; +#endif + /* Get the interface address */ + if (ioctl(fd, SIOCGIFADDR, (char*)&ifr) == -1) { + /* oops.. failed, continue with the next */ + continue; + } + sain = (struct sockaddr_in*) &ifr.ifr_addr; + ifaddr = sain->sin_addr.s_addr; + /* Get the interface broadcast address */ + if (ifbroadcast) { + if (ioctl(fd, SIOCGIFBRDADDR, (char*)&ifr) == -1) { + /* oops.. failed, continue with the next */ + continue; + } + sain = (struct sockaddr_in*) &ifr.ifr_broadaddr; + ifbaddr = sain->sin_addr.s_addr; + } + /* Get the interface MTU */ + if (ioctl(fd, SIOCGIFMTU, (char*)&ifr) == -1) { + /* Failed... we wan't consider it fatal */ + ifmtu = 1500; + } + else + { +#ifdef __sun__ + /* somehow solaris is braidamaged in wrt ifr_mtu */ + ifmtu = ifr.ifr_metric; +#else + ifmtu = ifr.ifr_mtu; +#endif + } +#ifdef __linux__ + /* Get the interface link status using MII */ + { + struct mii_data *mii = (struct mii_data*)&ifr.ifr_data; + if (ioctl(fd, SIOCGMIIPHY, (char*)&ifr) != -1) { + int bmsr; + + mii->reg_num = MII_BMSR; + if (ioctl(fd, SIOCGMIIREG, (char*)&ifr) != -1) { + bmsr = mii->val_out; + ifnolink = !(bmsr & MII_BMSR_LINK_VALID); + } + } + } +#endif + /* Finally populate an hpingif entry if there is room */ + if (!ilen) + continue; + strlcpy(hif[found].hif_name, this->ifr_name, HPING_IFNAME_LEN); + hif[found].hif_mtu = ifmtu; + hif[found].hif_loopback = ifloopback; + hif[found].hif_ptp = ifptp; + hif[found].hif_broadcast = ifbroadcast; + hif[found].hif_promisc = ifpromisc; + hif[found].hif_addr[0] = ifaddr; + hif[found].hif_baddr[0] = ifbaddr; + hif[found].hif_naddr = 1; + hif[found].hif_nolink = ifnolink; + /* if_index should be set to -1 if the OS isn't Linux */ + hif[found].hif_index = ifindex; + found++; + ilen--; + } + close(fd); + return found; +} +#endif + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__bsdi__) || defined(__APPLE__) +/* I wish getifaddrs() API on linux... -- SS */ +int hping_get_interfaces(struct hpingif *hif, int ilen) +{ + int found = 0; + struct ifaddrs *ifap, *ifa; + struct if_data *ifdata; + int ifloopback, ifptp, ifpromisc, ifbroadcast, ifnolink; + + /* Get the interfaces list */ + if (getifaddrs(&ifap) == -1) + return -1; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + struct ifaddrs *ift; + struct sockaddr_in *sa, *ba; + int naddr = 0; + /* Not interested in DOWN interfaces */ + if (!(ifa->ifa_flags & IFF_UP)) + continue; + ifloopback = (ifa->ifa_flags & IFF_LOOPBACK) != 0; + ifptp = (ifa->ifa_flags & IFF_POINTOPOINT) != 0; + ifpromisc = (ifa->ifa_flags & IFF_PROMISC) != 0; + ifbroadcast = (ifa->ifa_flags & IFF_BROADCAST) != 0; + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + /* Now search for the AF_INET entry with the same name */ + ift = ifa->ifa_next; + for (; ift; ift = ift->ifa_next) { + if (ift->ifa_addr->sa_family == AF_INET && + ift->ifa_addr && + !strcmp(ifa->ifa_name, ift->ifa_name)) + { + sa = (struct sockaddr_in*) ift->ifa_addr; + ba = (struct sockaddr_in*) ift->ifa_broadaddr; + if (naddr < HPING_IFADDR_MAX) { + hif[found].hif_addr[naddr] = + sa->sin_addr.s_addr; + hif[found].hif_baddr[naddr] = + ba->sin_addr.s_addr; + naddr++; + } + } + } + if (!naddr) + continue; + /* Read the media status */ + { + struct ifmediareq ifmr; + int s = -1; + memset(&ifmr, 0, sizeof(ifmr)); + strncpy(ifmr.ifm_name, ifa->ifa_name, sizeof(ifmr.ifm_name)); + ifnolink = 0; + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s != -1 && + ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) != -1) + { + if (ifmr.ifm_status & IFM_AVALID) { + if (!(ifmr.ifm_status & IFM_ACTIVE)) + ifnolink = 1; + } + } + if (s != -1) + close(s); + } + /* Add the new entry and cotinue */ + ifdata = (struct if_data*) ifa->ifa_data; + strlcpy(hif[found].hif_name, ifa->ifa_name, HPING_IFNAME_LEN); + hif[found].hif_broadcast = ifbroadcast; + hif[found].hif_mtu = ifdata->ifi_mtu; + hif[found].hif_loopback = ifloopback; + hif[found].hif_ptp = ifptp; + hif[found].hif_promisc = ifpromisc; + hif[found].hif_naddr = naddr; + hif[found].hif_nolink = ifnolink; + /* if_index should be set to -1 if the OS isn't Linux */ + hif[found].hif_index = -1; + found++; + ilen--; + if (!ilen) + break; + } + freeifaddrs(ifap); + return found; +} +#endif /* __*BSD__ */ + +/* ------------------------------- test main -------------------------------- */ +#ifdef TESTMAIN +int main(void) +{ + struct hpingif ifaces[16]; + int found, i, j; + + found = hping_get_interfaces(ifaces, 16); + printf("Found %d active interfaces:\n", found); + printf("%-10.10s %-16.16s %-10.10s %-10.10s\n", + "NAME", "ADDR", "MTU", "INDEX"); + for (i = 0; i < found; i++) { + struct in_addr ia; + printf("%-10.10s %-10d %-10d", + ifaces[i].hif_name, + ifaces[i].hif_mtu, + ifaces[i].hif_index); + printf("("); + for (j = 0; j < ifaces[i].hif_naddr; j++) { + ia.s_addr = ifaces[i].hif_addr[j]; + printf("%-16.16s ", inet_ntoa(ia)); + } + printf(")"); + if (ifaces[i].hif_broadcast) { + printf("("); + for (j = 0; j < ifaces[i].hif_naddr; j++) { + ia.s_addr = ifaces[i].hif_baddr[j]; + printf("%-16.16s ", inet_ntoa(ia)); + } + printf(")"); + } + if (ifaces[i].hif_loopback) + printf(" LOOPBACK"); + if (ifaces[i].hif_ptp) + printf(" POINTOPOINT"); + if (ifaces[i].hif_promisc) + printf(" PROMISC"); + if (ifaces[i].hif_broadcast) + printf(" BROADCAST"); + if (ifaces[i].hif_nolink) + printf(" NOLINK"); + printf("\n"); + } + return 0; +} +#endif + +#endif /* USE_TCL */ diff --git a/src/interface.h b/src/interface.h new file mode 100644 index 0000000..605a06b --- /dev/null +++ b/src/interface.h @@ -0,0 +1,102 @@ +#ifndef __HPING_INTERFACE_H +#define __HPING_INTERFACE_H + +#ifndef _LINUX_MII_H +#define _LINUX_MII_H + +/* network interface ioctl's for MII commands */ +#ifndef SIOCGMIIPHY +#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Read from current PHY */ +#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read any PHY register */ +#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write any PHY register */ +#define SIOCGPARAMS (SIOCDEVPRIVATE+3) /* Read operational parameters */ +#define SIOCSPARAMS (SIOCDEVPRIVATE+4) /* Set operational parameters */ +#endif + +/* This data structure is used for all the MII ioctl's */ +struct mii_data { + __u16 phy_id; + __u16 reg_num; + __u16 val_in; + __u16 val_out; +}; + +/* Basic Mode Control Register */ +#define MII_BMCR 0x00 +#define MII_BMCR_RESET 0x8000 +#define MII_BMCR_LOOPBACK 0x4000 +#define MII_BMCR_100MBIT 0x2000 +#define MII_BMCR_AN_ENA 0x1000 +#define MII_BMCR_ISOLATE 0x0400 +#define MII_BMCR_RESTART 0x0200 +#define MII_BMCR_DUPLEX 0x0100 +#define MII_BMCR_COLTEST 0x0080 + +/* Basic Mode Status Register */ +#define MII_BMSR 0x01 +#define MII_BMSR_CAP_MASK 0xf800 +#define MII_BMSR_100BASET4 0x8000 +#define MII_BMSR_100BASETX_FD 0x4000 +#define MII_BMSR_100BASETX_HD 0x2000 +#define MII_BMSR_10BASET_FD 0x1000 +#define MII_BMSR_10BASET_HD 0x0800 +#define MII_BMSR_NO_PREAMBLE 0x0040 +#define MII_BMSR_AN_COMPLETE 0x0020 +#define MII_BMSR_REMOTE_FAULT 0x0010 +#define MII_BMSR_AN_ABLE 0x0008 +#define MII_BMSR_LINK_VALID 0x0004 +#define MII_BMSR_JABBER 0x0002 +#define MII_BMSR_EXT_CAP 0x0001 + +#define MII_PHY_ID1 0x02 +#define MII_PHY_ID2 0x03 + +/* Auto-Negotiation Advertisement Register */ +#define MII_ANAR 0x04 +/* Auto-Negotiation Link Partner Ability Register */ +#define MII_ANLPAR 0x05 +#define MII_AN_NEXT_PAGE 0x8000 +#define MII_AN_ACK 0x4000 +#define MII_AN_REMOTE_FAULT 0x2000 +#define MII_AN_ABILITY_MASK 0x07e0 +#define MII_AN_FLOW_CONTROL 0x0400 +#define MII_AN_100BASET4 0x0200 +#define MII_AN_100BASETX_FD 0x0100 +#define MII_AN_100BASETX_HD 0x0080 +#define MII_AN_10BASET_FD 0x0040 +#define MII_AN_10BASET_HD 0x0020 +#define MII_AN_PROT_MASK 0x001f +#define MII_AN_PROT_802_3 0x0001 + +/* Auto-Negotiation Expansion Register */ +#define MII_ANER 0x06 +#define MII_ANER_MULT_FAULT 0x0010 +#define MII_ANER_LP_NP_ABLE 0x0008 +#define MII_ANER_NP_ABLE 0x0004 +#define MII_ANER_PAGE_RX 0x0002 +#define MII_ANER_LP_AN_ABLE 0x0001 + +#endif /* _LINUX_MII_H */ + +#define HPING_IFNAME_LEN 24 +#define HPING_IFACE_MAX 64 +#define HPING_IFADDR_MAX 16 + +/* hping interface rappresentation */ +struct hpingif { + char hif_name[HPING_IFNAME_LEN]; + in_addr_t hif_addr[HPING_IFADDR_MAX]; /* ipv4 addresses */ + in_addr_t hif_baddr[HPING_IFADDR_MAX]; /* ipv4 broadcast addresses */ + int hif_naddr; + int hif_loopback; + int hif_ptp; + int hif_promisc; + int hif_broadcast; + int hif_nolink; /* only set with MII-capable devices */ + int hif_mtu; + int hif_index; /* only useful for linux sockpacket version */ +}; + +int hping_get_interfaces(struct hpingif *hif, int ilen); + +#endif diff --git a/ip_opt_build.c b/src/ip_opt_build.c similarity index 98% rename from ip_opt_build.c rename to src/ip_opt_build.c index ebaba58..e3d5c81 100644 --- a/ip_opt_build.c +++ b/src/ip_opt_build.c @@ -55,8 +55,8 @@ unsigned char ip_opt_build(char* ip_opt) } } - if (opt_rroute) - { + if (opt_rroute) + { if (optlen<=33) { ip_opt[optlen]=IPOPT_RR; @@ -71,7 +71,7 @@ unsigned char ip_opt_build(char* ip_opt) printf("Warning: no room for record route, discarding option\n"); opt_rroute=0; } - } + } if (optlen) { diff --git a/libpcap_stuff.c b/src/libpcap_stuff.c similarity index 52% rename from libpcap_stuff.c rename to src/libpcap_stuff.c index 26f9993..21cf55b 100644 --- a/libpcap_stuff.c +++ b/src/libpcap_stuff.c @@ -16,37 +16,39 @@ #include #include #include -#include +#if (!defined OSTYPE_LINUX) && (!defined __sun__) + #include +#endif #include #include "globals.h" int open_pcap() { - int on; + int on; - on = 1; /* no warning if BIOCIMMEDIATE will not be compiled */ - if (opt_debug) - printf("DEBUG: pcap_open_live(%s, 99999, 0, 1, %p)\n", - ifname, errbuf); + on = 1; /* no warning if BIOCIMMEDIATE will not be compiled */ + if (opt_debug) + printf("DEBUG: pcap_open_live(%s, 99999, 0, 1, %p)\n", + ifname, errbuf); - pcapfp = pcap_open_live(ifname, 99999, 0, 1, errbuf); - if (pcapfp == NULL) { - printf("[open_pcap] pcap_open_live: %s\n", errbuf); - return -1; - } + pcapfp = pcap_open_live(ifname, 99999, 0, 1, errbuf); + if (pcapfp == NULL) { + printf("[open_pcap] pcap_open_live: %s\n", errbuf); + return -1; + } #if (!defined OSTYPE_LINUX) && (!defined __sun__) - /* Return the packets to userspace as fast as possible */ - if (ioctl(pcap_fileno(pcapfp), BIOCIMMEDIATE, &on) == -1) - perror("[open_pcap] ioctl(... BIOCIMMEDIATE ...)"); + /* Return the packets to userspace as fast as possible */ + if (ioctl(pcap_fileno(pcapfp), BIOCIMMEDIATE, &on) == -1) + perror("[open_pcap] ioctl(... BIOCIMMEDIATE ...)"); #endif - return 0; + return 0; } int close_pcap() { - pcap_close(pcapfp); - return 0; + pcap_close(pcapfp); + return 0; } int pcap_recv(char *packet, unsigned int size) @@ -54,14 +56,14 @@ int pcap_recv(char *packet, unsigned int size) char *p = NULL; int pcapsize; - if (opt_debug) - printf("DEBUG: under pcap_recv()\n"); + if (opt_debug) + printf("DEBUG: under pcap_recv()\n"); while(p == NULL) { p = (char*) pcap_next(pcapfp, &hdr); - if (p == NULL && opt_debug) - printf("DEBUG: [pcap_recv] p = NULL\n"); - } + if (p == NULL && opt_debug) + printf("DEBUG: [pcap_recv] p = NULL\n"); + } pcapsize = hdr.caplen; diff --git a/src/listen.c b/src/listen.c new file mode 100644 index 0000000..f86ada8 --- /dev/null +++ b/src/listen.c @@ -0,0 +1,89 @@ +/* + * $smu-mark$ + * $name: listen.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:48 MET 1999$ + * $rev: 8$ + */ + +/* $Id: listen.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hping2.h" /* hping2.h includes hcmp.h */ +#include "globals.h" + +void listenmain(void) +{ + int size, ip_size; + int stdoutFD = fileno(stdout); + char packet[IP_MAX_SIZE+linkhdr_size]; + char *p, *ip_packet; + struct myiphdr ip; + __u16 id; + static __u16 exp_id; /* expected id */ + + exp_id = 1; + + while(1) { + size = read_packet(packet, IP_MAX_SIZE+linkhdr_size); + switch(size) { + case 0: + continue; + case -1: + exit(1); + } + + /* Skip truncated packets */ + if (size < linkhdr_size+IPHDR_SIZE) + continue; + ip_packet = packet + linkhdr_size; + + /* copy the ip header so it will be aligned */ + memcpy(&ip, ip_packet, sizeof(ip)); + id = ntohs(ip.id); + ip_size = ntohs(ip.tot_len); + if (size-linkhdr_size > ip_size) + size = ip_size; + else + size -= linkhdr_size; + + if ((p = memstr(ip_packet, sign, size))) { + if (opt_verbose) + fprintf(stderr, "packet %d received\n", id); + + if (opt_safe) { + if (id == exp_id) + exp_id++; + else { + if (opt_verbose) + fprintf(stderr, "packet not in sequence (id %d) received\n", id); + send_hcmp(HCMP_RESTART, exp_id); + if (opt_verbose) + fprintf(stderr, "HCMP restart from %d sent\n", exp_id); + continue; /* discard this packet */ + } + } + + p+=strlen(sign); + const size_t len = size-(p-ip_packet); + const ssize_t n = write(stdoutFD, p, len); + if (n != len) { + fprintf( + stderr, + "write() did not write %zu bytes as expected.", + len + ); + exit(1); + } + } + } +} diff --git a/src/logicmp.c b/src/logicmp.c new file mode 100644 index 0000000..ff40089 --- /dev/null +++ b/src/logicmp.c @@ -0,0 +1,74 @@ +/* + * $smu-mark$ + * $name: logicmp.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:48 MET 1999$ + * $rev: 8$ + */ + +/* $Id: logicmp.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include /* this should be not needed, but ip_icmp.h lacks it */ + +#include "hping2.h" +#include "globals.h" + +void log_icmp_timeexc(char *src_addr, unsigned short icmp_code) +{ + switch(icmp_code) { + case ICMP_EXC_TTL: + printf("TTL 0 during transit from ip=%s", src_addr); + break; + case ICMP_EXC_FRAGTIME: + printf("TTL 0 during reassembly from ip=%s", src_addr); + break; + } + if (opt_gethost) { + char *hostn; + + fflush(stdout); + hostn = get_hostname(src_addr); + printf("name=%s", (hostn) ? hostn : "UNKNOWN"); + } + putchar('\n'); +} + +void log_icmp_unreach(char *src_addr, unsigned short icmp_code) +{ + static char* icmp_unreach_msg[]={ + "Network Unreachable from", /* code 0 */ + "Host Unreachable from", /* code 1 */ + "Protocol Unreachable from", /* code 2 */ + "Port Unreachable from", /* code 3 */ + "Fragmentation Needed/DF set from", /* code 4 */ + "Source Route failed from", /* code 5 */ + NULL, /* code 6 */ + NULL, /* code 7 */ + NULL, /* code 8 */ + NULL, /* code 9 */ + NULL, /* code 10 */ + NULL, /* code 11 */ + NULL, /* code 12 */ + "Packet filtered from", /* code 13 */ + "Precedence violation from", /* code 14 */ + "precedence cut off from" /* code 15 */ + }; + + if (icmp_unreach_msg[icmp_code] != NULL) + printf("ICMP %s ip=%s", icmp_unreach_msg[icmp_code], src_addr); + else + printf("ICMP Unreachable type=%d from ip=%s", + icmp_code, src_addr); + + if (opt_gethost) { + char *hostn; + + fflush(stdout); + hostn = get_hostname(src_addr); + printf("name=%s", (hostn) ? hostn : "UNKNOWN"); + } + putchar('\n'); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..7645719 --- /dev/null +++ b/src/main.c @@ -0,0 +1,384 @@ +/* + * $smu-mark$ + * $name: main.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:48 MET 1999$ + * $rev: 8$ + */ + +/* + * hping official page at http://www.kyuzz.org/antirez + * Covered by GPL version 2, Read the COPYING file for more information + */ + +/* $Id: main.c,v 1.4 2004/06/18 09:53:11 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hping2.h" + +/* globals */ +unsigned int + tcp_th_flags = 0, + linkhdr_size, /* physical layer header size */ + ip_tos = 0, + set_seqnum = FALSE, + tcp_seqnum = FALSE, + set_ack, + h_if_mtu, + virtual_mtu = DEFAULT_VIRTUAL_MTU, + ip_frag_offset = 0, + signlen, + lsr_length = 0, + ssr_length = 0, + tcp_ack; + + +unsigned short int + data_size = 0; + +float + rtt_min = 0, + rtt_max = 0, + rtt_avg = 0; + +int + sockpacket, + sockraw, + sent_pkt = 0, + recv_pkt = 0, + out_of_sequence_pkt = 0, + sending_wait = DEFAULT_SENDINGWAIT, /* see DEFAULT_SENDINGWAIT */ + opt_rawipmode = FALSE, + opt_icmpmode = FALSE, + opt_udpmode = FALSE, + opt_scanmode = FALSE, + opt_listenmode = FALSE, + opt_waitinusec = FALSE, + opt_numeric = FALSE, + opt_gethost = TRUE, + opt_quiet = FALSE, + opt_relid = FALSE, + opt_fragment = FALSE, + opt_df = FALSE, + opt_mf = FALSE, + opt_debug = FALSE, + opt_verbose = FALSE, + opt_winid_order = FALSE, + opt_keepstill = FALSE, + opt_datafromfile= FALSE, + opt_hexdump = FALSE, + opt_contdump = FALSE, + opt_sign = FALSE, + opt_safe = FALSE, + opt_end = FALSE, + opt_traceroute = FALSE, + opt_seqnum = FALSE, + opt_incdport = FALSE, + opt_force_incdport = FALSE, + opt_icmptype = DEFAULT_ICMP_TYPE, + opt_icmpcode = DEFAULT_ICMP_CODE, + opt_rroute = FALSE, + opt_tcpexitcode = FALSE, + opt_badcksum = FALSE, + opt_tr_keep_ttl = FALSE, + opt_tcp_timestamp = FALSE, + opt_clock_skew = FALSE, + cs_window = DEFAULT_CS_WINDOW, + cs_window_shift = DEFAULT_CS_WINDOW_SHIFT, + cs_vector_len = DEFAULT_CS_VECTOR_LEN, + opt_tr_stop = FALSE, + opt_tr_no_rtt = FALSE, + opt_rand_dest = FALSE, + opt_rand_source = FALSE, + opt_lsrr = FALSE, + opt_ssrr = FALSE, + opt_cplt_rte = FALSE, + opt_beep = FALSE, + opt_flood = FALSE, + tcp_exitcode = 0, + src_ttl = DEFAULT_TTL, + src_id = -1, /* random */ + base_dst_port = DEFAULT_DPORT, + dst_port = DEFAULT_DPORT, + src_port, + sequence = 0, + initsport = DEFAULT_INITSPORT, + src_winsize = DEFAULT_SRCWINSIZE, + src_thoff = (TCPHDR_SIZE >> 2), + count = DEFAULT_COUNT, + ctrlzbind = DEFAULT_BIND, + delaytable_index= 0, + eof_reached = FALSE, + icmp_ip_version = DEFAULT_ICMP_IP_VERSION, + icmp_ip_ihl = DEFAULT_ICMP_IP_IHL, + icmp_ip_tos = DEFAULT_ICMP_IP_TOS, + icmp_ip_tot_len = DEFAULT_ICMP_IP_TOT_LEN, + icmp_ip_id = DEFAULT_ICMP_IP_ID, + icmp_ip_protocol= DEFAULT_ICMP_IP_PROTOCOL, + icmp_ip_srcport = DEFAULT_DPORT, + icmp_ip_dstport = DEFAULT_DPORT, + opt_force_icmp = FALSE, + icmp_cksum = DEFAULT_ICMP_CKSUM, + raw_ip_protocol = DEFAULT_RAW_IP_PROTOCOL; + +char + datafilename [1024], + targetname [1024], + targetstraddr [1024], + ifname [1024] = {'\0'}, + ifstraddr [1024], + spoofaddr [1024], + icmp_ip_srcip [1024], + icmp_ip_dstip [1024], + icmp_gwip [1024], + sign [1024], + rsign [1024], /* reverse sign (hping -> gniph) */ + ip_opt [40], + *opt_scanports = ""; + +unsigned char + lsr [255] = {0}, + ssr [255] = {0}; + +unsigned + ip_optlen = 0; + +struct sockaddr_in + icmp_ip_src, + icmp_ip_dst, + icmp_gw, + local, + remote; + +struct itimerval usec_delay; +volatile struct delaytable_element delaytable[TABLESIZE]; + +struct hcmphdr *hcmphdr_p; /* global pointer used by send_hcmp to transfer + hcmp headers to data_handler */ + +pcap_t *pcapfp; +char errbuf[PCAP_ERRBUF_SIZE]; +struct pcap_pkthdr hdr; + +/* main */ +int main(int argc, char **argv) +{ + char setflags[1024] = {'\0'}; + int c, hdr_size; + + /* Check for the scripting mode */ + if (argc == 1 || (argc > 1 && !strcmp(argv[1], "exec"))) { +#ifdef USE_TCL + if (argc != 1) { + argv++; + argc--; + } + hping_script(argc, argv); + exit(0); /* unreached */ +#else + fprintf(stderr, "Sorry, this hping binary was compiled " + "without TCL scripting support\n"); + exit(1); +#endif + } + + if (parse_options(argc, argv) == -1) { + printf("hping2: missing host argument\n" + "Try `hping2 --help' for more information.\n"); + exit(1); + } + + /* reverse sign */ + if (opt_sign || opt_listenmode) { + char *src = sign+strlen(sign)-1; /* last char before '\0' */ + char *dst = rsign; + + while(src>=sign) + *dst++ = *src--; + *dst = '\0'; + if (opt_debug) + printf("DEBUG: reverse sign: %s\n", rsign); + } + + /* get target address before interface processing */ + if ((!opt_listenmode && !opt_safe) && !opt_rand_dest) + resolve((struct sockaddr*)&remote, targetname); + + if (opt_rand_dest) { + strlcpy(targetstraddr, targetname, sizeof(targetstraddr)); + } else { + strlcpy(targetstraddr, inet_ntoa(remote.sin_addr), + sizeof(targetstraddr)); + } + + /* get interface's name and address */ + if ( get_if_name() == -1 ) { + printf("[main] no such device\n"); + exit(1); + } + + if (opt_verbose || opt_debug) { + printf("using %s, addr: %s, MTU: %d\n", + ifname, ifstraddr, h_if_mtu); + } + + /* open raw socket */ + sockraw = open_sockraw(); + if (sockraw == -1) { + printf("[main] can't open raw socket\n"); + exit(1); + } + + /* set SO_BROADCAST option */ + socket_broadcast(sockraw); + /* set SO_IPHDRINCL option */ + socket_iphdrincl(sockraw); + + /* open sock packet or libpcap socket */ + if (open_pcap() == -1) { + printf("[main] open_pcap failed\n"); + exit(1); + } + + /* get physical layer header size */ + if ( get_linkhdr_size(ifname) == -1 ) { + printf("[main] physical layer header size unknown\n"); + exit(1); + } + + if (spoofaddr[0] == '\0') + resolve((struct sockaddr*)&local, ifstraddr); + else + resolve((struct sockaddr*)&local, spoofaddr); + + if (icmp_ip_srcip[0] == '\0') + resolve((struct sockaddr*)&icmp_ip_src, "1.2.3.4"); + else + resolve((struct sockaddr*)&icmp_ip_src, icmp_ip_srcip); + + if (icmp_ip_dstip[0] == '\0') + resolve((struct sockaddr*)&icmp_ip_dst, "5.6.7.8"); + else + resolve((struct sockaddr*)&icmp_ip_dst, icmp_ip_dstip); + + if (icmp_gwip[0] == '\0') + resolve((struct sockaddr*)&icmp_gw, "0.0.0.0"); + else + resolve((struct sockaddr*)&icmp_gw, icmp_gwip); + + srand(time(NULL)); + + /* set initial source port */ + if (initsport == -1) + initsport = src_port = 1024 + (rand() % 2000); + else + src_port = initsport; + + for (c = 0; c < TABLESIZE; c++) + delaytable[c].seq = -1; + + /* use SIGALRM to send packets like ping do */ + Signal(SIGALRM, send_packet); + + /* binding */ + if (ctrlzbind != BIND_NONE) Signal(SIGTSTP, inc_destparm); + Signal(SIGINT, print_statistics); + Signal(SIGTERM, print_statistics); + + /* if we are in listemode enter in listenmain() else */ + /* print HPING... bla bla bla and enter in wait_packet() */ + if (opt_listenmode) { + fprintf(stderr, "hping2 listen mode\n"); + + /* memory protection */ + if (memlockall() == -1) { + perror("[main] memlockall()"); + fprintf(stderr, "Warning: can't disable memory paging!\n"); + } else if (opt_verbose || opt_debug) { + printf("Memory paging disabled\n"); + } + listenmain(); + /* UNREACHED */ + } + + /* Scan mode */ + if (opt_scanmode) { + fprintf(stderr, "Scanning %s (%s), port %s\n", + targetname, targetstraddr, opt_scanports); + scanmain(); + /* UNREACHED */ + } + + if (opt_rawipmode) { + strcat(setflags, "raw IP mode"); + hdr_size = IPHDR_SIZE; + } else if (opt_icmpmode) { + strcat(setflags, "icmp mode"); + hdr_size = IPHDR_SIZE + ICMPHDR_SIZE; + } else if (opt_udpmode) { + strcat(setflags, "udp mode"); + hdr_size = IPHDR_SIZE + UDPHDR_SIZE; + } else { + if (tcp_th_flags & TH_RST) strcat(setflags, "R"); + if (tcp_th_flags & TH_SYN) strcat(setflags, "S"); + if (tcp_th_flags & TH_ACK) strcat(setflags, "A"); + if (tcp_th_flags & TH_FIN) strcat(setflags, "F"); + if (tcp_th_flags & TH_PUSH) strcat(setflags, "P"); + if (tcp_th_flags & TH_URG) strcat(setflags, "U"); + if (tcp_th_flags & TH_X) strcat(setflags, "X"); + if (tcp_th_flags & TH_Y) strcat(setflags, "Y"); + if (setflags[0] == '\0') strcat(setflags, "NO FLAGS are"); + hdr_size = IPHDR_SIZE + TCPHDR_SIZE; + } + + printf("HPING %s (%s %s): %s set, %d headers + %d data bytes\n", + targetname, + ifname, + targetstraddr, + setflags, + hdr_size, + data_size); + + /* memory protection */ + if (opt_datafromfile || opt_sign) { + if (memlockall() == -1) { + perror("[main] memlockall()"); + fprintf(stderr, + "Warning: can't disable memory paging!\n"); + } else if (opt_verbose || opt_debug) { + printf("Memory paging disabled\n"); + } + } + + /* start packet sending */ + kill(getpid(), SIGALRM); + + /* flood mode? */ + if (opt_flood) { + fprintf(stderr, + "hping in flood mode, no replies will be shown\n"); + while (1) { + send_packet(0); + } + } + + /* main loop */ + while(1) + wait_packet(); + + return 0; +} diff --git a/memlock.c b/src/memlock.c similarity index 63% rename from memlock.c rename to src/memlock.c index a28fc33..566c761 100644 --- a/memlock.c +++ b/src/memlock.c @@ -16,16 +16,16 @@ int memlock(char *addr, size_t size) { #ifdef _POSIX_MEMLOCK_RANGE - unsigned long page_offset, page_size; + unsigned long page_offset, page_size; - page_size = sysconf(_SC_PAGESIZE); /* also .. */ - page_offset = (unsigned long) addr % page_size; + page_size = sysconf(_SC_PAGESIZE); /* also .. */ + page_offset = (unsigned long) addr % page_size; - addr -= page_offset; - size += page_offset; + addr -= page_offset; + size += page_offset; - return ( mlock(addr, size) ); + return ( mlock(addr, size) ); #endif - return (-1); + return (-1); } diff --git a/memlockall.c b/src/memlockall.c similarity index 88% rename from memlockall.c rename to src/memlockall.c index 658b1da..38a9e1f 100644 --- a/memlockall.c +++ b/src/memlockall.c @@ -18,8 +18,8 @@ int memlockall(void) /* #ifdef _POSIX_MEMLOCK */ /* NJ: better to test _POSIX_MEMLOCK value */ #if _POSIX_MEMLOCK == 1 - return ( mlockall(MCL_CURRENT|MCL_FUTURE) ); + return ( mlockall(MCL_CURRENT|MCL_FUTURE) ); #endif - return (-1); + return (-1); } diff --git a/memstr.c b/src/memstr.c similarity index 67% rename from memstr.c rename to src/memstr.c index 7048d33..c8961b7 100644 --- a/memstr.c +++ b/src/memstr.c @@ -15,13 +15,13 @@ char *memstr(char *haystack, char *needle, int size) { - char *p; - char needlesize = strlen(needle); + char *p; + char needlesize = strlen(needle); - for (p = haystack; p <= (haystack-needlesize+size); p++) - { - if (memcmp(p, needle, needlesize) == 0) - return p; /* found */ - } - return NULL; + for (p = haystack; p <= (haystack-needlesize+size); p++) + { + if (memcmp(p, needle, needlesize) == 0) + return p; /* found */ + } + return NULL; } diff --git a/memunlock.c b/src/memunlock.c similarity index 65% rename from memunlock.c rename to src/memunlock.c index 6bcd166..62c6f7a 100644 --- a/memunlock.c +++ b/src/memunlock.c @@ -16,15 +16,15 @@ int memunlock(char *addr, size_t size) { #ifdef _POSIX_MEMLOCK_RANGE - unsigned long page_offset, page_size; + unsigned long page_offset, page_size; - page_size = sysconf(_SC_PAGESIZE); - page_offset = (unsigned long) addr % page_size; + page_size = sysconf(_SC_PAGESIZE); + page_offset = (unsigned long) addr % page_size; - addr -= page_offset; - size += page_offset; + addr -= page_offset; + size += page_offset; - return ( munlock(addr, size) ); + return ( munlock(addr, size) ); #endif - return (-1); + return (-1); } diff --git a/memunlockall.c b/src/memunlockall.c similarity index 92% rename from memunlockall.c rename to src/memunlockall.c index 0191b43..6c0d100 100644 --- a/memunlockall.c +++ b/src/memunlockall.c @@ -18,8 +18,8 @@ int memunlockall(void) /* #ifdef _POSIX_MEMLOCK */ /* NJ: better to test _POSIX_MEMLOCK value */ #if _POSIX_MEMLOCK == 1 - return ( munlockall() ); + return ( munlockall() ); #endif - return(-1); + return(-1); } diff --git a/opensockraw.c b/src/opensockraw.c similarity index 75% rename from opensockraw.c rename to src/opensockraw.c index 5bf3b6f..b015d14 100644 --- a/opensockraw.c +++ b/src/opensockraw.c @@ -17,13 +17,13 @@ int open_sockraw() { - int s; + int s; - s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (s == -1) { - perror("[open_sockraw] socket()"); - return -1; - } + s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + if (s == -1) { + perror("[open_sockraw] socket()"); + return -1; + } - return s; + return s; } diff --git a/src/parseoptions.c b/src/parseoptions.c new file mode 100644 index 0000000..3172034 --- /dev/null +++ b/src/parseoptions.c @@ -0,0 +1,692 @@ +/* parseoptions.c -- options handling + * Copyright(C) 1999-2001 Salvatore Sanfilippo + * Under GPL, see the COPYING file for more information about + * the license. */ + +/* $Id: parseoptions.c,v 1.2 2004/06/18 09:53:11 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "antigetopt.h" + +#include "hping2.h" +#include "globals.h" + +enum { OPT_COUNT, OPT_INTERVAL, OPT_NUMERIC, OPT_QUIET, OPT_INTERFACE, + OPT_HELP, OPT_VERSION, OPT_DESTPORT, OPT_BASEPORT, OPT_TTL, OPT_ID, + OPT_WIN, OPT_SPOOF, OPT_FIN, OPT_SYN, OPT_RST, OPT_PUSH, OPT_ACK, + OPT_URG, OPT_XMAS, OPT_YMAS, OPT_FRAG, OPT_MOREFRAG, OPT_DONTFRAG, + OPT_FRAGOFF, OPT_TCPOFF, OPT_REL, OPT_DATA, OPT_RAWIP, OPT_ICMP, + OPT_UDP, OPT_BIND, OPT_UNBIND, OPT_DEBUG, OPT_VERBOSE, OPT_WINID, + OPT_KEEP, OPT_FILE, OPT_DUMP, OPT_PRINT, OPT_SIGN, OPT_LISTEN, + OPT_SAFE, OPT_TRACEROUTE, OPT_TOS, OPT_MTU, OPT_SEQNUM, OPT_BADCKSUM, + OPT_SETSEQ, OPT_SETACK, OPT_ICMPTYPE, OPT_ICMPCODE, OPT_END, + OPT_RROUTE, OPT_IPPROTO, OPT_ICMP_IPVER, OPT_ICMP_IPHLEN, + OPT_ICMP_IPLEN, OPT_ICMP_IPID, OPT_ICMP_IPPROTO, OPT_ICMP_CKSUM, + OPT_ICMP_TS, OPT_ICMP_ADDR, OPT_TCPEXITCODE, OPT_FAST, OPT_TR_KEEP_TTL, + OPT_TCP_TIMESTAMP, OPT_TR_STOP, OPT_TR_NO_RTT, OPT_ICMP_HELP, + OPT_RAND_DEST, OPT_RAND_SOURCE, OPT_LSRR, OPT_SSRR, OPT_ROUTE_HELP, + OPT_ICMP_IPSRC, OPT_ICMP_IPDST, OPT_ICMP_SRCPORT, OPT_ICMP_DSTPORT, + OPT_ICMP_GW, OPT_FORCE_ICMP, OPT_APD_SEND, OPT_SCAN, OPT_FASTER, + OPT_BEEP, OPT_FLOOD, OPT_CLOCK_SKEW, OPT_CS_WINDOW, OPT_CS_WINDOW_SHIFT, + OPT_CS_VECTOR_LEN }; + +static struct ago_optlist hping_optlist[] = { + { 'c', "count", OPT_COUNT, AGO_NEEDARG }, + { 'i', "interval", OPT_INTERVAL, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'n', "numeric", OPT_NUMERIC, AGO_NOARG }, + { 'q', "quiet", OPT_QUIET, AGO_NOARG }, + { 'I', "interface", OPT_INTERFACE, AGO_NEEDARG }, + { 'h', "help", OPT_HELP, AGO_NOARG }, + { 'v', "version", OPT_VERSION, AGO_NOARG }, + { 'p', "destport", OPT_DESTPORT, AGO_NEEDARG|AGO_EXCEPT0 }, + { 's', "baseport", OPT_BASEPORT, AGO_NEEDARG|AGO_EXCEPT0 }, + { 't', "ttl", OPT_TTL, AGO_NEEDARG }, + { 'N', "id", OPT_ID, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'w', "win", OPT_WIN, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'a', "spoof", OPT_SPOOF, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'F', "fin", OPT_FIN, AGO_NOARG|AGO_EXCEPT0 }, + { 'S', "syn", OPT_SYN, AGO_NOARG|AGO_EXCEPT0 }, + { 'R', "rst", OPT_RST, AGO_NOARG|AGO_EXCEPT0 }, + { 'P', "push", OPT_PUSH, AGO_NOARG|AGO_EXCEPT0 }, + { 'A', "ack", OPT_ACK, AGO_NOARG|AGO_EXCEPT0 }, + { 'U', "urg", OPT_URG, AGO_NOARG|AGO_EXCEPT0 }, + { 'X', "xmas", OPT_XMAS, AGO_NOARG|AGO_EXCEPT0 }, + { 'Y', "ymas", OPT_YMAS, AGO_NOARG|AGO_EXCEPT0 }, + { 'f', "frag", OPT_FRAG, AGO_NOARG|AGO_EXCEPT0 }, + { 'x', "morefrag", OPT_MOREFRAG, AGO_NOARG|AGO_EXCEPT0 }, + { 'y', "dontfrag", OPT_DONTFRAG, AGO_NOARG }, + { 'g', "fragoff", OPT_FRAGOFF, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'O', "tcpoff", OPT_TCPOFF, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'r', "rel", OPT_REL, AGO_NOARG }, + { 'd', "data", OPT_DATA, AGO_NEEDARG|AGO_EXCEPT0 }, + { '0', "rawip", OPT_RAWIP, AGO_NOARG|AGO_EXCEPT0 }, + { '1', "icmp", OPT_ICMP, AGO_NOARG }, + { '2', "udp", OPT_UDP, AGO_NOARG }, + { '8', "scan", OPT_SCAN, AGO_NEEDARG }, + { 'z', "bind", OPT_BIND, AGO_NOARG }, + { 'Z', "unbind", OPT_UNBIND, AGO_NOARG }, + { 'D', "debug", OPT_DEBUG, AGO_NOARG }, + { 'V', "verbose", OPT_VERBOSE, AGO_NOARG }, + { 'W', "winid", OPT_WINID, AGO_NOARG }, + { 'k', "keep", OPT_KEEP, AGO_NOARG }, + { 'E', "file", OPT_FILE, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'j', "dump", OPT_DUMP, AGO_NOARG|AGO_EXCEPT0 }, + { 'J', "print", OPT_PRINT, AGO_NOARG|AGO_EXCEPT0 }, + { 'e', "sign", OPT_SIGN, AGO_NEEDARG|AGO_EXCEPT0 }, + { '9', "listen", OPT_LISTEN, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'B', "safe", OPT_SAFE, AGO_NOARG|AGO_EXCEPT0 }, + { 'T', "traceroute", OPT_TRACEROUTE, AGO_NOARG }, + { 'o', "tos", OPT_TOS, AGO_NEEDARG }, + { 'm', "mtu", OPT_MTU, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'Q', "seqnum", OPT_SEQNUM, AGO_NOARG|AGO_EXCEPT0 }, + { 'b', "badcksum", OPT_BADCKSUM, AGO_NOARG|AGO_EXCEPT0 }, + { 'M', "setseq", OPT_SETSEQ, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'L', "setack", OPT_SETACK, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'C', "icmptype", OPT_ICMPTYPE, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'K', "icmpcode", OPT_ICMPCODE, AGO_NEEDARG|AGO_EXCEPT0 }, + { 'u', "end", OPT_END, AGO_NOARG|AGO_EXCEPT0 }, + { 'G', "rroute", OPT_RROUTE, AGO_NOARG }, + { 'H', "ipproto", OPT_IPPROTO, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-help", OPT_ICMP_HELP, AGO_NOARG }, + { '\0', "icmp-ipver", OPT_ICMP_IPVER, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-iphlen", OPT_ICMP_IPHLEN, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-iplen", OPT_ICMP_IPLEN, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-ipid", OPT_ICMP_IPID, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-ipproto", OPT_ICMP_IPPROTO, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-cksum", OPT_ICMP_CKSUM, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-ts", OPT_ICMP_TS, AGO_NOARG }, + { '\0', "icmp-addr", OPT_ICMP_ADDR, AGO_NOARG }, + { '\0', "tcpexitcode", OPT_TCPEXITCODE, AGO_NOARG }, + { '\0', "fast", OPT_FAST, AGO_NOARG|AGO_EXCEPT0 }, + { '\0', "faster", OPT_FASTER, AGO_NOARG|AGO_EXCEPT0 }, + { '\0', "tr-keep-ttl", OPT_TR_KEEP_TTL, AGO_NOARG }, + { '\0', "tcp-timestamp",OPT_TCP_TIMESTAMP, AGO_NOARG }, + { '\0', "tr-stop", OPT_TR_STOP, AGO_NOARG }, + { '\0', "tr-no-rtt", OPT_TR_NO_RTT, AGO_NOARG }, + { '\0', "rand-dest", OPT_RAND_DEST, AGO_NOARG }, + { '\0', "rand-source", OPT_RAND_SOURCE, AGO_NOARG }, + { '\0', "lsrr", OPT_LSRR, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "ssrr", OPT_SSRR, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "route-help", OPT_ROUTE_HELP, AGO_NOARG }, + { '\0', "apd-send", OPT_APD_SEND, AGO_NEEDARG }, + { '\0', "icmp-ipsrc", OPT_ICMP_IPSRC, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-ipdst", OPT_ICMP_IPDST, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-gw", OPT_ICMP_GW, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-srcport", OPT_ICMP_SRCPORT, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "icmp-dstport", OPT_ICMP_DSTPORT, AGO_NEEDARG|AGO_EXCEPT0 }, + { '\0', "force-icmp", OPT_FORCE_ICMP, AGO_NOARG }, + { '\0', "beep", OPT_BEEP, AGO_NOARG }, + { '\0', "flood", OPT_FLOOD, AGO_NOARG }, + { '\0', "clock-skew", OPT_CLOCK_SKEW, AGO_NOARG }, + { '\0', "clock-skew-win", OPT_CS_WINDOW, AGO_NEEDARG}, + { '\0', "clock-skew-win-shift", OPT_CS_WINDOW_SHIFT, AGO_NEEDARG}, + { '\0', "clock-skew-packets-per-sample", OPT_CS_VECTOR_LEN,AGO_NEEDARG}, + AGO_LIST_TERM +}; + +/* The following var is turned to 1 if the -i option is used. + * This allows to assign a different delay default value if + * the scanning mode is selected. */ +static int delay_changed = 0; + +static int suidtester(void) +{ + return (getuid() != geteuid()); +} + +void fail_parse_route(void) +{ + fprintf(stderr, "RECTUM\n"); + exit(1); +} + +void parse_route(unsigned char *route, unsigned int *route_len, char *str) +{ + struct in_addr ip; + unsigned int i = 0; + unsigned int j; + unsigned int n = 0; + unsigned int route_ptr = 256; + char c; + + route += 3; + while (str[i] != '\0') + { + for (j = i; isalnum(str[j]) || str[j] == '.'; j++); + switch(c = str[j]) + { + case '\0': + case '/': + if (n >= 62) + { + fprintf(stderr, "too long route\n"); + fail_parse_route(); + } + str[j] = '\0'; + if (inet_pton(AF_INET, str+i, &ip)) + { + memcpy(route+4*n, &ip.s_addr, 4); + n++; + if (c == '/') + str[j++] = '/'; + break; + } + fprintf(stderr, "invalid IP adress in route\n"); + fail_parse_route(); + case ':': + if ((!i) && j && j < 4) + { + sscanf(str, "%u:%n", &route_ptr, &i); + if (i == ++j) + { + if (route_ptr < 256) + break; + } + } + default: + fail_parse_route(); + } + i = j; + } + if (route_ptr == 256) + route[-1] = (unsigned char) ( n ? 8 : 4 ); + else + route[-1] = (unsigned char) route_ptr; + *route_len = 4*n + 3; + route[-2] = (unsigned char) *route_len; +} + +int parse_options(int argc, char **argv) +{ + int src_ttl_set = 0; + int targethost_set = 0; + int o; + + if (argc < 2) + return -1; + + ago_set_exception(0, suidtester, "Option disabled when setuid"); + + while ((o = antigetopt(argc, argv, hping_optlist)) != AGO_EOF) { + switch(o) { + case AGO_UNKNOWN: + case AGO_REQARG: + case AGO_AMBIG: + ago_gnu_error("hping", o); + fprintf(stderr, "Try hping --help\n"); + exit(1); + case AGO_ALONE: + if (targethost_set == 1) { + fprintf(stderr, "hping: you must specify only " + "one target host at a time\n"); + exit(1); + } else { + strlcpy(targetname, ago_optarg, 1024); + targethost_set = 1; + } + break; + case OPT_COUNT: + count = strtol(ago_optarg, NULL, 0); + break; + case OPT_INTERVAL: + delay_changed = 1; + if (*ago_optarg == 'u') { + opt_waitinusec = TRUE; + usec_delay.it_value.tv_sec = + usec_delay.it_interval.tv_sec = 0; + usec_delay.it_value.tv_usec = + usec_delay.it_interval.tv_usec = + atol(ago_optarg+1); + } + else + sending_wait = strtol(ago_optarg, NULL, 0); + break; + case OPT_NUMERIC: + opt_numeric = TRUE; + break; + case OPT_QUIET: + opt_quiet = TRUE; + break; + case OPT_INTERFACE: + strlcpy (ifname, ago_optarg, 1024); + break; + case OPT_HELP: + show_usage(); + break; + case OPT_VERSION: + show_version(); + break; + case OPT_DESTPORT: + if (*ago_optarg == '+') + { + opt_incdport = TRUE; + ago_optarg++; + } + if (*ago_optarg == '+') + { + opt_force_incdport = TRUE; + ago_optarg++; + } + base_dst_port = dst_port = strtol(ago_optarg, NULL, 0); + break; + case OPT_BASEPORT: + initsport = strtol(ago_optarg, NULL, 0); + break; + case OPT_TTL: + src_ttl = strtol(ago_optarg, NULL, 0); + src_ttl_set = 1; + break; + case OPT_ID: + src_id = strtol(ago_optarg, NULL, 0); + break; + case OPT_WIN: + src_winsize = strtol(ago_optarg, NULL, 0); + break; + case OPT_SPOOF: + strlcpy (spoofaddr, ago_optarg, 1024); + break; + case OPT_FIN: + tcp_th_flags |= TH_FIN; + break; + case OPT_SYN: + tcp_th_flags |= TH_SYN; + break; + case OPT_RST: + tcp_th_flags |= TH_RST; + break; + case OPT_PUSH: + tcp_th_flags |= TH_PUSH; + break; + case OPT_ACK: + tcp_th_flags |= TH_ACK; + break; + case OPT_URG: + tcp_th_flags |= TH_URG; + break; + case OPT_XMAS: + tcp_th_flags |= TH_X; + break; + case OPT_YMAS: + tcp_th_flags |= TH_Y; + break; + case OPT_FRAG: + opt_fragment = TRUE; + break; + case OPT_MOREFRAG: + opt_mf = TRUE; + break; + case OPT_DONTFRAG: + opt_df = TRUE; + break; + case OPT_FRAGOFF: + ip_frag_offset = strtol(ago_optarg, NULL, 0); + break; + case OPT_TCPOFF: + src_thoff = strtol(ago_optarg, NULL, 0); + break; + case OPT_REL: + opt_relid = TRUE; + break; + case OPT_DATA: + data_size = strtol(ago_optarg, NULL, 0); + break; + case OPT_RAWIP: + opt_rawipmode = TRUE; + break; + case OPT_ICMP: + opt_icmpmode = TRUE; + break; + case OPT_ICMP_TS: + opt_icmpmode = TRUE; + opt_icmptype = 13; + break; + case OPT_ICMP_ADDR: + opt_icmpmode = TRUE; + opt_icmptype = 17; + break; + case OPT_UDP: + opt_udpmode = TRUE; + break; + case OPT_SCAN: + opt_scanmode = TRUE; + opt_scanports = strdup(ago_optarg); + break; + case OPT_LISTEN: + opt_listenmode = TRUE; + strlcpy(sign, ago_optarg, 1024); + signlen = strlen(ago_optarg); + break; + case OPT_IPPROTO: + raw_ip_protocol = strtol(ago_optarg, NULL, 0); + break; + case OPT_ICMPTYPE: + opt_icmpmode= TRUE; + opt_icmptype = strtol(ago_optarg, NULL, 0); + break; + case OPT_ICMPCODE: + opt_icmpmode= TRUE; + opt_icmpcode = strtol(ago_optarg, NULL, 0); + break; + case OPT_BIND: + ctrlzbind = BIND_TTL; + break; + case OPT_UNBIND: + ctrlzbind = BIND_NONE; + break; + case OPT_DEBUG: + opt_debug = TRUE; + break; + case OPT_VERBOSE: + opt_verbose = TRUE; + break; + case OPT_WINID: + opt_winid_order = TRUE; + break; + case OPT_KEEP: + opt_keepstill = TRUE; + break; + case OPT_FILE: + opt_datafromfile = TRUE; + strlcpy(datafilename, ago_optarg, 1024); + break; + case OPT_DUMP: + opt_hexdump = TRUE; + break; + case OPT_PRINT: + opt_contdump = TRUE; + break; + case OPT_SIGN: + opt_sign = TRUE; + strlcpy(sign, ago_optarg, 1024); + signlen = strlen(ago_optarg); + break; + case OPT_SAFE: + opt_safe = TRUE; + break; + case OPT_END: + opt_end = TRUE; + break; + case OPT_TRACEROUTE: + opt_traceroute = TRUE; + break; + case OPT_TOS: + if (!strcmp(ago_optarg, "help")) + tos_help(); + else + { + static unsigned int tos_tmp = 0; + + sscanf(ago_optarg, "%2x", &tos_tmp); + ip_tos |= tos_tmp; /* OR tos */ + } + break; + case OPT_MTU: + virtual_mtu = strtol(ago_optarg, NULL, 0); + opt_fragment = TRUE; + if(virtual_mtu > 65535) { + virtual_mtu = 65535; + printf("Specified MTU too high, " + "fixed to 65535.\n"); + } + break; + case OPT_SEQNUM: + opt_seqnum = TRUE; + break; + case OPT_BADCKSUM: + opt_badcksum = TRUE; + break; + case OPT_SETSEQ: + set_seqnum = TRUE; + tcp_seqnum = strtoul(ago_optarg, NULL, 0); + break; + case OPT_SETACK: + set_ack = TRUE; + tcp_ack = strtoul(ago_optarg, NULL, 0); + break; + case OPT_RROUTE: + opt_rroute = TRUE; + break; + case OPT_ICMP_HELP: + icmp_help(); /* ICMP options help */ + break; + case OPT_ICMP_IPVER: + icmp_ip_version = strtol(ago_optarg, NULL, 0); + break; + case OPT_ICMP_IPHLEN: + icmp_ip_ihl = strtol(ago_optarg, NULL, 0); + break; + case OPT_ICMP_IPLEN: + icmp_ip_tot_len = strtol(ago_optarg, NULL, 0); + break; + case OPT_ICMP_IPID: + icmp_ip_id = strtol(ago_optarg, NULL, 0); + break; + case OPT_ICMP_IPPROTO: + icmp_ip_protocol = strtol(ago_optarg, NULL, 0); + break; + case OPT_ICMP_IPSRC: + strlcpy (icmp_ip_srcip, ago_optarg, 1024); + break; + case OPT_ICMP_IPDST: + strlcpy (icmp_ip_dstip, ago_optarg, 1024); + break; + case OPT_ICMP_GW: + strlcpy (icmp_gwip, ago_optarg, 1024); + break; + case OPT_ICMP_SRCPORT: + icmp_ip_srcport = strtol(ago_optarg, NULL, 0); + break; + case OPT_ICMP_DSTPORT: + icmp_ip_dstport = strtol(ago_optarg, NULL, 0); + break; + case OPT_FORCE_ICMP: + opt_force_icmp = TRUE; + break; + case OPT_ICMP_CKSUM: + icmp_cksum = strtol(ago_optarg, NULL, 0); + break; + case OPT_TCPEXITCODE: + opt_tcpexitcode = TRUE; + break; + case OPT_FAST: + delay_changed = 1; + opt_waitinusec = TRUE; + usec_delay.it_value.tv_sec = + usec_delay.it_interval.tv_sec = 0; + usec_delay.it_value.tv_usec = + usec_delay.it_interval.tv_usec = 100000; + break; + case OPT_FASTER: + delay_changed = 1; + opt_waitinusec = TRUE; + usec_delay.it_value.tv_sec = + usec_delay.it_interval.tv_sec = 0; + usec_delay.it_value.tv_usec = + usec_delay.it_interval.tv_usec = 1; + case OPT_TR_KEEP_TTL: + opt_tr_keep_ttl = TRUE; + break; + case OPT_TCP_TIMESTAMP: + opt_tcp_timestamp = TRUE; + break; + case OPT_TR_STOP: + opt_tr_stop = TRUE; + break; + case OPT_TR_NO_RTT: + opt_tr_no_rtt = TRUE; + break; + case OPT_RAND_DEST: + opt_rand_dest = TRUE; + break; + case OPT_RAND_SOURCE: + opt_rand_source = TRUE; + break; + case OPT_LSRR: + opt_lsrr = TRUE; + parse_route(lsr, &lsr_length, ago_optarg); + if (lsr[0]) + printf("Warning: erasing previously given " + "loose source route"); + lsr[0] = 131; + break; + case OPT_SSRR: + opt_ssrr = TRUE; + parse_route(ssr, &ssr_length, ago_optarg); + if (ssr[0]) + printf("Warning: erasing previously given " + "strong source route"); + ssr[0] = 137; + break; + case OPT_ROUTE_HELP: + route_help(); + break; + case OPT_APD_SEND: + hping_ars_send(ago_optarg); + break; + case OPT_BEEP: + opt_beep = TRUE; + break; + case OPT_FLOOD: + opt_flood = TRUE; + break; + case OPT_CLOCK_SKEW: + opt_tcp_timestamp = TRUE; + opt_clock_skew = TRUE; + break; + case OPT_CS_WINDOW: + cs_window = strtol(ago_optarg, NULL, 0); + if (cs_window < 30) { + fprintf(stderr, + "clock skew window can't be < 30 sec.\n"); + exit(1); + } + break; + case OPT_CS_WINDOW_SHIFT: + cs_window_shift = strtol(ago_optarg, NULL, 0); + if (cs_window_shift < 1) { + fprintf(stderr, + "clock skew window shift can't be < 1\n"); + exit(1); + } + break; + case OPT_CS_VECTOR_LEN: + cs_vector_len = strtol(ago_optarg, NULL, 0); + if (cs_vector_len < 1) { + fprintf(stderr, + "clock skew packets per sample can't be < 1\n"); + exit(1); + } + break; + } + } + + /* missing target host? */ + if (targethost_set == 0 && opt_listenmode && opt_safe) + { + printf( + "you must specify a target host if you require safe protocol\n" + "because hping needs a target for HCMP packets\n"); + exit(1); + } + + if (targethost_set == 0 && !opt_listenmode) return -1; + + if (opt_numeric == TRUE) opt_gethost = FALSE; + + /* some error condition */ + if (data_size+IPHDR_SIZE+TCPHDR_SIZE > 65535) { + printf("Option error: sorry, data size must be <= %lu\n", + (unsigned long)(65535-IPHDR_SIZE+TCPHDR_SIZE)); + exit(1); + } + else if (count <= 0 && count != -1) { + printf("Option error: count must > 0\n"); + exit(1); + } + else if (sending_wait < 0) { + printf("Option error: bad timing interval\n"); + exit(1); + } + else if (opt_waitinusec == TRUE && usec_delay.it_value.tv_usec < 0) + { + printf("Option error: bad timing interval\n"); + exit(1); + } + else if (opt_datafromfile == TRUE && data_size == 0) + { + printf("Option error: -E option useless without -d\n"); + exit(1); + } + else if (opt_sign && data_size && signlen > data_size) + { + printf( + "Option error: signature (%d bytes) is larger than data size\n" + "check -d option, don't specify -d to let hping compute it\n", signlen); + exit(1); + } + else if ((opt_sign || opt_listenmode) && signlen > 1024) + { + printf("Option error: signature too big\n"); + exit(1); + } + else if (opt_safe == TRUE && src_id != -1) + { + printf("Option error: sorry, you can't set id and " + "use safe protocol at some time\n"); + exit(1); + } + else if (opt_safe == TRUE && opt_datafromfile == FALSE && + opt_listenmode == FALSE) + { + printf("Option error: sorry, safe protocol is useless " + "without 'data from file' option\n"); + exit(1); + } + else if (opt_safe == TRUE && opt_sign == FALSE && + opt_listenmode == FALSE) + { + printf("Option error: sorry, safe protocol require you " + "sign your packets, see --sign | -e option\n"); + exit(1); + } else if (opt_rand_dest == TRUE && ifname[0] == '\0') { + printf("Option error: you need to specify an interface " + "when the --rand-dest option is enabled\n"); + exit(1); + } + + /* dependences */ + if (opt_safe == TRUE) + src_id = 1; + + if (opt_traceroute == TRUE && ctrlzbind == BIND_DPORT) + ctrlzbind = BIND_TTL; + + if (opt_traceroute == TRUE && src_ttl_set == 0) + src_ttl = DEFAULT_TRACEROUTE_TTL; + + /* set the data size to the signature len if the no data size + * was specified */ + if (opt_sign && !data_size) + data_size = signlen; + + /* If scan mode is on, and the -i option was not used, + * set the default delay to zero, that's send packets + * as fast as possible. */ + if (opt_scanmode && !delay_changed) { + opt_waitinusec = TRUE; + usec_delay.it_value.tv_sec = + usec_delay.it_interval.tv_sec = 0; + usec_delay.it_value.tv_usec = + usec_delay.it_interval.tv_usec = 0; + } + + return 1; +} diff --git a/src/random.c b/src/random.c new file mode 100644 index 0000000..965f7df --- /dev/null +++ b/src/random.c @@ -0,0 +1,89 @@ +/* rc4-based pseudo-random number generator for hping. + * Copyright (C) 2003 Salvatore Sanfilippo + * This software is released under the GPL license + * All rights reserved */ + +/* $Id: random.c,v 1.3 2004/06/04 07:22:38 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "fixtypes.h" + +u_int32_t hp_rand(void); + +/* The rc4 sbox */ +static unsigned char rc4_sbox[256]; +/* This flags is used to initialize the sbox the first time, + * without an explicit intialization step outside this file. */ +static int rc4_seedflag = 0; + +/* Initialize the sbox with pseudo random data */ +static void hp_rand_init(void) +{ + int i, fd; + + /* Strong sbox initialization */ + fd = open("/dev/urandom", O_RDONLY); + if (fd != -1) { + const ssize_t n = read(fd, rc4_sbox, 256); + if (n != 256) { + fprintf(stderr, "read() did not read 256 bytes as expected."); + exit(1); + } + close(fd); + } + /* Weaker sbox initialization */ + for (i = 0; i < 256; i++) { + struct timeval tv; + gettimeofday(&tv, NULL); + if (i&1) + rc4_sbox[i] ^= (tv.tv_usec >> (i&0xF)) & 0xFF; + else + rc4_sbox[i] ^= (tv.tv_sec >> (i&0xF)) & 0xFF; + } + rc4_seedflag = 1; +} + +#if 0 +/* Re-seed the generator with user-provided bytes. Not used for now. */ +static void hp_rand_seed(void *seed, size_t len) +{ + int i; + + if (len > 256) len = 256; + memcpy(rc4_sbox, seed, len); + /* discard the first 256 bytes of output after the reseed */ + for (i = 0; i < 32; i++) + (void) hp_rand(); +} +#endif + +/* Generates a 32bit random number using an RC4-like algorithm */ +u_int32_t hp_rand(void) +{ + u_int32_t r = 0; + unsigned char *rc = (unsigned char*) &r; + static unsigned int i = 0, j = 0; + unsigned int si, sj, x; + + /* initialization, only needed the first time */ + if (!rc4_seedflag) + hp_rand_init(); + /* generates 4 bytes of pseudo-random data using RC4 */ + for (x = 0; x < 4; x++) { + i = (i+1) & 0xff; + si = rc4_sbox[i]; + j = (j + si) & 0xff; + sj = rc4_sbox[j]; + rc4_sbox[i] = sj; + rc4_sbox[j] = si; + *rc++ = rc4_sbox[(si+sj)&0xff]; + } + return r; +} diff --git a/src/rapd.c b/src/rapd.c new file mode 100644 index 0000000..9418d6d --- /dev/null +++ b/src/rapd.c @@ -0,0 +1,440 @@ +/* rapd.c -- Reverse APD, from ARS packet to APD string description. + * Copyright (C) 2003 Salvatore Sanfilippo + * All rights reserved. */ + +/* $Id: rapd.c,v 1.7 2004/04/10 00:45:11 antirez Exp $ */ + +#include +#include +#include + +#include "ars.h" + +void trimlastchar(char *s) +{ + int len = strlen(s); + s[len-1] = '\0'; +} + +int ars_d_from_ars(char *dest, size_t len, struct ars_packet *pkt) +{ + int j, err; + struct adbuf buf; + + if (len <= 0) + return -ARS_OK; + if (adbuf_init(&buf)) + return -ARS_NOMEM; + for (j = 0; j < pkt->p_layer_nr; j++) { + __D(printf("ReverseAPD-ing layer %d\n", j);) + /* Skip NULL compilers */ + if (ars_linfo[pkt->p_layer[j].l_type].li_rapd != NULL) { + /* Call the layer to string converter */ + err = ars_linfo[pkt->p_layer[j].l_type].li_rapd(&buf, pkt, j); + if (err != -ARS_OK) { + adbuf_free(&buf); + return err; + } + } + } + adbuf_rtrim(&buf, 1); + strlcpy(dest, adbuf_ptr(&buf), len); + adbuf_free(&buf); + return -ARS_OK; +} + +/* layer rapd methods */ +int ars_rapd_ip(struct adbuf *dest, struct ars_packet *pkt, int layer) +{ + struct ars_iphdr *ip = pkt->p_layer[layer].l_data; + struct ars_iphdr *defip = pkt->p_default[pkt->p_layer[layer].l_type]; + adbuf_printf(dest, "ip("); + if (!defip || ip->ihl != defip->ihl) + adbuf_printf(dest, "ihl=0x%1x,", ip->ihl); + if (!defip || ip->version != defip->version) + adbuf_printf(dest, "ver=0x%1x,", ip->version); + if (!defip || ip->tos != defip->tos) + adbuf_printf(dest, "tos=0x%02x,", ip->tos); + adbuf_printf(dest, "totlen=%u,", ntohs(ip->tot_len)); + if (!defip || ip->id != defip->id) + adbuf_printf(dest, "id=%u,", ntohs(ip->id)); + adbuf_printf(dest, "fragoff=%u,", + (ntohs(ip->frag_off) & 0x1FFF) << 3); + if (!defip || + (ip->frag_off & ARS_IP_MF) != (defip->frag_off & ARS_IP_MF)) + adbuf_printf(dest, "mf=%d,", + (htons(ip->frag_off) & ARS_IP_MF) != 0); + if (!defip || + (ip->frag_off & ARS_IP_DF) != (defip->frag_off & ARS_IP_DF)) + adbuf_printf(dest, "df=%d,", + (htons(ip->frag_off) & ARS_IP_DF) != 0); + if (!defip || + (ip->frag_off & ARS_IP_RF) != (defip->frag_off & ARS_IP_RF)) + adbuf_printf(dest, "rf=%d,", + (htons(ip->frag_off) & ARS_IP_RF) != 0); + if (!defip || ip->ttl != defip->ttl) + adbuf_printf(dest, "ttl=%u,", ip->ttl); + /* TODO: the 'proto' field may not be added if the protocl + * that follows this layer looks as specified. */ + adbuf_printf(dest, "proto=%u,", ip->protocol); + adbuf_printf(dest, "cksum=0x%04x,", ip->check); + { + unsigned char *x = (unsigned char*) &ip->saddr; + adbuf_printf(dest, "saddr=%u.%u.%u.%u,", + x[0], x[1], x[2], x[3]); + x = (unsigned char*) &ip->daddr; + adbuf_printf(dest, "daddr=%u.%u.%u.%u", + x[0], x[1], x[2], x[3]); + } + adbuf_printf(dest, ")+"); + return -ARS_OK; +} + +int ars_rapd_ipopt(struct adbuf *dest, struct ars_packet *pkt, int layer) +{ + struct ars_ipopt ipopt; + int len = pkt->p_layer[layer].l_size; + unsigned char *optp = pkt->p_layer[layer].l_data; + int optlen, i; + + /* ip options may not be naturally aligned */ + memcpy(&ipopt, pkt->p_layer[layer].l_data, len); + optlen = ipopt.len; + + switch(ipopt.kind) { + case ARS_IPOPT_EOL: + adbuf_printf(dest, "ip.eol()+"); + break; + case ARS_IPOPT_NOP: + adbuf_printf(dest, "ip.nop()+"); + break; + case ARS_IPOPT_RR: + case ARS_IPOPT_LSRR: + case ARS_IPOPT_SSRR: + { + int ptr = 4; + char *optname = ""; + + switch(ipopt.kind) { + case ARS_IPOPT_RR: optname="rr"; break; + case ARS_IPOPT_LSRR: optname="lsrr"; break; + case ARS_IPOPT_SSRR: optname="ssrr"; break; + } + adbuf_printf(dest, "ip.%s(ptr=%u,data=", + optname, ipopt.un.rr.ptr); + while(1) { + unsigned char *x; + + if (ptr > 37 || + ptr > (optlen-3)) + break; + x = optp + ptr - 1; + adbuf_printf(dest, "%u.%u.%u.%u/", + x[0],x[1],x[2],x[3]); + ptr += 4; + } + if (ptr > 4) + adbuf_rtrim(dest, 1); + adbuf_printf(dest, ")+"); + } + break; + case ARS_IPOPT_TIMESTAMP: + { + int ptr = 5; + int overflow = (ipopt.un.ts.flags & 0xF0)>>4; + int flags = ipopt.un.ts.flags & 0xF; + char *strflags; + adbuf_printf(dest, "ip.ts(ptr=%u,", ipopt.un.ts.ptr); + switch(flags) { + case ARS_IPOPT_TS_TSONLY: strflags="tsonly"; break; + case ARS_IPOPT_TS_TSANDADDR: strflags="tsandaddr"; break; + case ARS_IPOPT_TS_PRESPEC: strflags="prespec"; break; + default: strflags=NULL; break; + } + if (strflags) { + adbuf_printf(dest, "flags=%s,", strflags); + } else { + adbuf_printf(dest, "flags=%u,", flags); + } + adbuf_printf(dest, "overflow=%u,data=", overflow); + while(1) { + unsigned char *x; + __u32 ts; + + if (ptr > 37 || + ptr > (optlen-4)) + break; + if (flags != ARS_IPOPT_TS_TSANDADDR && + flags != ARS_IPOPT_TS_PRESPEC) { + memcpy(&ts, optp+ptr-1, 4); + ts = ntohl(ts); + adbuf_printf(dest, "%u/", ts); + ptr += 4; + } else { + x = optp + ptr - 1; + memcpy(&ts, x+4, 4); + adbuf_printf(dest, "%u@%u.%u.%u.%u/", + ts,x[0],x[1],x[2],x[3]); + ptr += 8; + } + } + if (ptr > 5) + adbuf_rtrim(dest, 1); + adbuf_printf(dest, ")+"); + } + break; + default: + adbuf_printf(dest, "ip.unknown(hex="); + for (i = 0; i < optlen; i++) { + adbuf_printf(dest, "0x%02x", optp[i]); + } + adbuf_printf(dest, ")+"); + break; + } + return -ARS_OK; +} + +int ars_rapd_icmp(struct adbuf *dest, struct ars_packet *pkt, int layer) +{ + struct ars_icmphdr *icmp = pkt->p_layer[layer].l_data; + + adbuf_printf(dest, "icmp("); + adbuf_printf(dest, "type=%u,", icmp->type); + adbuf_printf(dest, "code=%u,", icmp->code); + if (icmp->type == ARS_ICMP_DEST_UNREACH || + icmp->type == ARS_ICMP_TIME_EXCEEDED || + icmp->type == ARS_ICMP_PARAMETERPROB || + icmp->type == ARS_ICMP_SOURCE_QUENCH) + { + adbuf_printf(dest, "unused=%lu,", (unsigned long) + ntohl(icmp->un.gateway)); + } + if (icmp->type == ARS_ICMP_ECHOREPLY || + icmp->type == ARS_ICMP_ECHO || + icmp->type == ARS_ICMP_TIMESTAMP || + icmp->type == ARS_ICMP_TIMESTAMPREPLY || + icmp->type == ARS_ICMP_INFO_REQUEST || + icmp->type == ARS_ICMP_INFO_REPLY) + { + adbuf_printf(dest, "id=%u,", ntohs(icmp->un.echo.id)); + adbuf_printf(dest, "seq=%u,", ntohs(icmp->un.echo.sequence)); + } + if (icmp->type == ARS_ICMP_REDIRECT) { + unsigned char x[4]; + memcpy(x, &icmp->un.gateway, 4); + adbuf_printf(dest, "gw=%u.%u.%u.%u,", + x[0], x[1], x[2], x[3]); + } + adbuf_rtrim(dest, 1); + adbuf_printf(dest, ")+"); + return -ARS_OK; +} + +int ars_rapd_udp(struct adbuf *dest, struct ars_packet *pkt, int layer) +{ + struct ars_udphdr *udp = pkt->p_layer[layer].l_data; + //struct ars_udphdr *defudp = pkt->p_default[pkt->p_layer[layer].l_type]; + adbuf_printf(dest, "udp("); + adbuf_printf(dest, "sport=%u,", ntohs(udp->uh_sport)); + adbuf_printf(dest, "dport=%u,", ntohs(udp->uh_dport)); + adbuf_printf(dest, "len=%u,", ntohs(udp->uh_ulen)); + adbuf_printf(dest, "cksum=0x%04x", ntohs(udp->uh_sum)); + adbuf_printf(dest, ")+"); + return -ARS_OK; +} + +int ars_rapd_tcp(struct adbuf *dest, struct ars_packet *pkt, int layer) +{ + struct ars_tcphdr *tcp = pkt->p_layer[layer].l_data; + struct ars_tcphdr *deftcp = pkt->p_default[pkt->p_layer[layer].l_type]; + adbuf_printf(dest, "tcp("); + adbuf_printf(dest, "sport=%u,", ntohs(tcp->th_sport)); + adbuf_printf(dest, "dport=%u,", ntohs(tcp->th_dport)); + adbuf_printf(dest, "seq=%lu,", ntohl(tcp->th_seq)); + adbuf_printf(dest, "ack=%lu,", ntohl(tcp->th_ack)); + if (!deftcp || tcp->th_x2 != deftcp->th_x2) + adbuf_printf(dest, "x2=0x%1x,", tcp->th_x2); + if (!deftcp || tcp->th_off != deftcp->th_off) + adbuf_printf(dest, "off=%u,", tcp->th_off); + adbuf_printf(dest, "flags="); + if (tcp->th_flags & ARS_TCP_TH_FIN) adbuf_printf(dest, "f"); + if (tcp->th_flags & ARS_TCP_TH_SYN) adbuf_printf(dest, "s"); + if (tcp->th_flags & ARS_TCP_TH_RST) adbuf_printf(dest, "r"); + if (tcp->th_flags & ARS_TCP_TH_PUSH) adbuf_printf(dest, "p"); + if (tcp->th_flags & ARS_TCP_TH_ACK) adbuf_printf(dest, "a"); + if (tcp->th_flags & ARS_TCP_TH_URG) adbuf_printf(dest, "u"); + if (tcp->th_flags & ARS_TCP_TH_X) adbuf_printf(dest, "x"); + if (tcp->th_flags & ARS_TCP_TH_Y) adbuf_printf(dest, "y"); + adbuf_printf(dest, ","); + adbuf_printf(dest, "win=%u,", ntohs(tcp->th_win)); + adbuf_printf(dest, "cksum=0x%04x,", ntohs(tcp->th_sum)); + if (!deftcp || tcp->th_urp != deftcp->th_urp) + adbuf_printf(dest, "urp=%u,", ntohs(tcp->th_urp)); + adbuf_rtrim(dest, 1); + adbuf_printf(dest, ")+"); + return -ARS_OK; +} + +int ars_rapd_tcpopt(struct adbuf *dest, struct ars_packet *pkt, int layer) +{ + struct ars_tcpopt tcpopt; + int len = pkt->p_layer[layer].l_size; + unsigned char *optp = pkt->p_layer[layer].l_data; + int optlen, i; + + /* tcp options may not be naturally aligned */ + memcpy(&tcpopt, pkt->p_layer[layer].l_data, len); + optlen = tcpopt.len; + + switch(tcpopt.kind) { + case ARS_TCPOPT_EOL: + adbuf_printf(dest, "tcp.eol()+"); + break; + case ARS_TCPOPT_NOP: + adbuf_printf(dest, "tcp.nop()+"); + break; + case ARS_TCPOPT_MAXSEG: + adbuf_printf(dest, "tcp.mss(size=%u)+", + ntohs(tcpopt.un.mss.size)); + break; + case ARS_TCPOPT_WINDOW: + adbuf_printf(dest, "tcp.wscale(shift=%u)+", + tcpopt.un.win.shift); + break; + case ARS_TCPOPT_SACK_PERM: + adbuf_printf(dest, "tcp.sackperm()+"); + break; + case ARS_TCPOPT_SACK: + adbuf_printf(dest, "tcp.sack(blocks="); + { + int blocks = (optlen-2)/8; + for (i = 0; i < blocks; i++) { + u_int32_t s_orig, s_size; + + memcpy(&s_orig, tcpopt.un.sack[i].origin, 4); + memcpy(&s_size, tcpopt.un.sack[i].size, 4); + adbuf_printf(dest, "%lu-%lu", + ntohl(s_orig), + ntohl(s_size)); + if ((i+1) != blocks) + adbuf_addchar(dest, '/'); + } + } + adbuf_printf(dest, ")+"); + break; + case ARS_TCPOPT_ECHOREQUEST: + { + __u32 info; + memcpy(&info, tcpopt.un.echo.info, 4); + adbuf_printf(dest, "tcp.echoreq(info=%lu)+", + (unsigned long) ntohl(info)); + } + break; + case ARS_TCPOPT_ECHOREPLY: + { + __u32 info; + memcpy(&info, tcpopt.un.echo.info, 4); + adbuf_printf(dest, "tcp.echoreply(info=%lu)+", + (unsigned long) ntohl(info)); + } + break; + case ARS_TCPOPT_TIMESTAMP: + { + __u32 tsval, tsecr; + memcpy(&tsval, tcpopt.un.timestamp.tsval, 4); + memcpy(&tsecr, tcpopt.un.timestamp.tsecr, 4); + adbuf_printf(dest, "tcp.timestamp(val=%lu,ecr=%lu)+", + (unsigned long) ntohl(tsval), + (unsigned long) ntohl(tsecr)); + } + break; + default: + adbuf_printf(dest, "tcp.unknown(hex="); + for (i = 0; i < optlen; i++) { + adbuf_printf(dest, "%02x", optp[i]); + } + adbuf_printf(dest, ")+"); + break; + } + return -ARS_OK; +} + +int ars_rapd_igrp(struct adbuf *dest, struct ars_packet *pkt, int layer) +{ + struct ars_igrphdr *igrp = pkt->p_layer[layer].l_data; + + adbuf_printf(dest, "igrp("); + adbuf_printf(dest, "version=%u,", igrp->version); + if (igrp->opcode == ARS_IGRP_OPCODE_UPDATE) { + adbuf_printf(dest, "opcode=update,", igrp->opcode); + } else if (igrp->opcode == ARS_IGRP_OPCODE_REQUEST) { + adbuf_printf(dest, "opcode=request,", igrp->opcode); + } else { + adbuf_printf(dest, "opcode=%u,", igrp->opcode); + } + adbuf_printf(dest, "edition=%u,", igrp->edition); + adbuf_printf(dest, "autosys=%u,", htons(igrp->autosys)); + adbuf_printf(dest, "interior=%u,", htons(igrp->interior)); + adbuf_printf(dest, "system=%u,", htons(igrp->system)); + adbuf_printf(dest, "exterior=%u,", htons(igrp->exterior)); + adbuf_printf(dest, "cksum=0x%04x", ntohs(igrp->checksum)); + adbuf_printf(dest, ")+"); + return -ARS_OK; +} + +static u_int32_t get_net_int24(void *ptr) +{ + unsigned char *x = (unsigned char*)ptr; + u_int32_t u; + + u = x[0] <<16 | x[1] << 8 | x[2]; + return u; +} + +int ars_rapd_igrpentry(struct adbuf *dest, struct ars_packet *pkt, int layer) +{ + struct ars_igrpentry *entry = pkt->p_layer[layer].l_data; + unsigned char *x = (unsigned char*) entry->destination; + + adbuf_printf(dest, "igrp.entry("); + adbuf_printf(dest, "dest=%u.%u.%u,", x[0], x[1], x[2]); + adbuf_printf(dest, "delay=%u,", get_net_int24(entry->delay)); + adbuf_printf(dest, "bandwidth=%u,", get_net_int24(entry->bandwidth)); + adbuf_printf(dest, "mtu=%u,", entry->mtu[0] << 8 | entry->mtu[1]); + adbuf_printf(dest, "reliability=%u,", entry->reliability); + adbuf_printf(dest, "load=%u,", entry->load); + adbuf_printf(dest, "hopcount=%u", entry->hopcount); + adbuf_printf(dest, ")+"); + return -ARS_OK; +} + +int ars_rapd_data(struct adbuf *dest, struct ars_packet *pkt, int layer) +{ + unsigned char *data = pkt->p_layer[layer].l_data; + int dlen = pkt->p_layer[layer].l_size, i; + + if (ars_test_option(pkt, ARS_OPT_RAPD_HEXDATA)) { + adbuf_printf(dest, "data(hex="); + for (i = 0; i < dlen; i++) { + adbuf_printf(dest, "%02x", data[i]); + } + adbuf_printf(dest, ")+"); + } else { + adbuf_printf(dest, "data(str="); + for (i = 0; i < dlen; i++) { + /* escape non-printable chars and chars + * having special meanings in APD packets. */ + if (isgraph(data[i]) && + data[i] != '(' && + data[i] != ')' && + data[i] != '+' && + data[i] != ',' && + data[i] != '=') + adbuf_printf(dest, "%c", data[i]); + else + adbuf_printf(dest, "\\%02x", data[i]); + } + adbuf_printf(dest, ")+"); + } + return 0; +} diff --git a/release.h b/src/release.h similarity index 62% rename from release.h rename to src/release.h index 3f76109..70ba9f2 100644 --- a/release.h +++ b/src/release.h @@ -1,18 +1,18 @@ -/* - * $smu-mark$ +/* + * $smu-mark$ * $name: release.h$ * $author: Salvatore Sanfilippo $ * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ * $license: This software is under GPL version 2 of license$ * $date: Fri Nov 16 11:55:49 MET 1999$ * $rev: 17$ - */ + */ #ifndef _RELEASE_H #define _RELEASE_H -#define RELEASE_VERSION "3.0.0-alpha-1" -#define RELEASE_DATE "$Id: release.h,v 1.4 2004/04/09 23:38:56 antirez Exp $" -#define CONTACTS "" +#define RELEASE_VERSION "3.0.0" +#define RELEASE_DATE "$Ide002f1e 2025-08-28 23:39:36 -0300 fabriciofx $" +#define CONTACTS ", " #endif /* _RELEASE_H */ diff --git a/src/relid.c b/src/relid.c new file mode 100644 index 0000000..a356da7 --- /dev/null +++ b/src/relid.c @@ -0,0 +1,48 @@ +/* + * $smu-mark$ + * $name: relid.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:49 MET 1999$ + * $rev: 3$ + */ + +/* FIXME: maybe it's better to avoid division per seq_diff and + at least add an option to switch on/off this feature */ + +/* $Id: relid.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include "hping2.h" +#include "globals.h" + +int relativize_id(int seqnum, int *ip_id) +{ + int seq_diff, backup_id; + static int last_seq = 0, last_id = -1; + + backup_id = *ip_id; + + if (last_id == -1) { + last_id = *ip_id; + last_seq = seqnum; + } + else + { + if ( (seq_diff=(seqnum-last_seq)) > 0) + { + if (last_id > *ip_id) /* rew */ + *ip_id = ((65535-last_id) + + *ip_id)/seq_diff; + else + *ip_id = (*ip_id-last_id) + /seq_diff; + last_id = backup_id; + last_seq = seqnum; + return TRUE; + } else { + out_of_sequence_pkt++; + } + } + return FALSE; +} diff --git a/resolve.c b/src/resolve.c similarity index 52% rename from resolve.c rename to src/resolve.c index b442162..966b760 100644 --- a/resolve.c +++ b/src/resolve.c @@ -22,33 +22,33 @@ /* On error -1 is returned, on success 0 */ int resolve_addr(struct sockaddr * addr, char *hostname) { - struct sockaddr_in *address; - struct hostent *host; + struct sockaddr_in *address; + struct hostent *host; - address = (struct sockaddr_in *)addr; + address = (struct sockaddr_in *)addr; - memset(address, 0, sizeof(struct sockaddr_in)); - address->sin_family = AF_INET; - address->sin_addr.s_addr = inet_addr(hostname); + memset(address, 0, sizeof(struct sockaddr_in)); + address->sin_family = AF_INET; + address->sin_addr.s_addr = inet_addr(hostname); - if ( (int)address->sin_addr.s_addr == -1) { - host = gethostbyname(hostname); - if (host) { - memcpy(&address->sin_addr, host->h_addr, - host->h_length); - return 0; - } else { - return -1; - } - } - return 0; + if ( (int)address->sin_addr.s_addr == -1) { + host = gethostbyname(hostname); + if (host) { + memcpy(&address->sin_addr, host->h_addr, + host->h_length); + return 0; + } else { + return -1; + } + } + return 0; } /* Like resolve_addr but exit on error */ void resolve(struct sockaddr *addr, char *hostname) { - if (resolve_addr(addr, hostname) == -1) { - fprintf(stderr, "Unable to resolve '%s'\n", hostname); - exit(1); - } + if (resolve_addr(addr, hostname) == -1) { + fprintf(stderr, "Unable to resolve '%s'\n", hostname); + exit(1); + } } diff --git a/src/rtt.c b/src/rtt.c new file mode 100644 index 0000000..18dcc5e --- /dev/null +++ b/src/rtt.c @@ -0,0 +1,101 @@ +/* + * $smu-mark$ + * $name: rtt.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:49 MET 1999$ + * $rev: 3$ + */ + +/* $Id: rtt.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include + +#include "hping2.h" +#include "globals.h" + +void minavgmax(float ms_delay) +{ + static int avg_counter = 0; + + if (rtt_min == 0 || ms_delay < rtt_min) + rtt_min = ms_delay; + if (rtt_max == 0 || ms_delay > rtt_max) + rtt_max = ms_delay; + avg_counter++; + rtt_avg = (rtt_avg*(avg_counter-1)/avg_counter)+(ms_delay/avg_counter); +} + +int rtt(int *seqp, int recvport, float *ms_delay) +{ + long sec_delay = 0, usec_delay = 0; + int i, tablepos = -1, status; + + if (*seqp != 0) { + for (i = 0; i < TABLESIZE; i++) + if (delaytable[i].seq == *seqp) { + tablepos = i; + break; + } + } else { + for (i=0; i + * All rights reserved. + * + * This code and the documentation is released under the GPL license + * version 2 of the license. You can get a copy of the license at + * http://www.gnu.org/licenses/gpl.html + * A copy of the license is distributed with this code, + * see the file COPYING. */ + +/* History of important bugs: + * + * 28 Feb 2002: Bad casting in low-level subtraction generated bad results + * for particular pairs of numbers. It was a bit hard to + * discover the real origin of the bug since all started + * with a strange behaviour of the Fermat little theorem. + * This was since the modular reduction uses the low-level + * subtraction to perform its work. Of course now it's fixed. + * + * 12 Sep 2003: Fixed a memory leak in mpz_tostr(). + */ + +#include +#include +#include +#include +#include + +#include "sbignum.h" +#include "sbignum-tables.h" + +/* All the function with the _raw suffix don't care about the sign + * and works if the last operand, that's specified as a mpz_atom_t pointer + * and a u_int32_t length is stored in statically allocated memory, while + * higher level functions expect operands declared as mpz_t and initialized + * with mpz_init(). */ + +/* Macros and functions starting with the '_' character are usually not + * exported faster versions of normal functions, that do some unsane assumption + * like there is enough memory to store the result and so on. + * They are used to build more complex functions */ + +/* --------------------------- Low level functions -------------------------- */ + +/* For the actual list of supported functions see sbignum.h */ + +/* inititialization/allocation */ +static int mpz_zero_realloc(mpz_ptr z, u_int32_t i); +static void mpz_zero(mpz_ptr z); +/* shifting */ +static int mpz_lshiftword(mpz_ptr r, u_int32_t i); +static int mpz_rshiftword(mpz_ptr r, u_int32_t i); +/* comparision */ +static int32_t mpz_cmpabsi_raw(mpz_ptr a, mpz_atom_t *d, u_int32_t l); +static int32_t mpz_cmpabs(mpz_ptr a, mpz_ptr b); +/* addition */ +static int mpz_addi_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l); +/* subtraction */ +static int mpz_subi_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l); +/* multiplication */ +static int mpz_muli_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l); +/* division */ +static int mpz_divi_qr_raw(mpz_ptr q, mpz_ptr r, mpz_ptr z, mpz_atom_t *d, + u_int32_t l); +static int mpz_divi_r_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l); +/* number theoretic functions */ +static int mpz_gcd_raw(mpz_ptr g, mpz_ptr a, mpz_atom_t *b, u_int32_t l); +/* to/from mpz conversions */ +static int mpz_tostr(mpz_ptr z, u_int32_t b, void *s, size_t l); +/* random numbers */ +static void sbn_rand_init(void); + +/* ================================== MPZ =================================== */ + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) + +/* 32bit integer to mpz conversion */ +#if ATOMBYTES == 4 +#define u32tompz(t,u,l) \ + mpz_atom_t t[1]; \ + u_int32_t l = 0; \ + t[0] = u; \ + if (t[0]) l = 1 +#elif ATOMBYTES == 2 +#define u32tompz(t,u,l) \ + mpz_atom_t t[2]; \ + u_int32_t l = 0; \ + t[0] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ + t[1] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ + if (t[1]) l = 1; \ + else if (t[0]) l = 2 +#elif ATOMBYTES == 1 +#define u32tompz(t,u,l) \ + mpz_atom_t t[4]; \ + u_int32_t l = 0; \ + t[0] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ + t[1] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ + t[2] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ + t[3] = u & MPZ_MASK; u >>= MPZ_SHIFT; \ + if (t[3]) l = 4; \ + else if (t[2]) l = 3; \ + else if (t[1]) l = 2; \ + else if (t[0]) l = 1 +#endif + +/* shift/andmask needed to division and modulo operation for ATOMBITS: + * a / ATOMBITS == A >> DIVATOMBITS_SHIFT + * a % ATOMBITS == A & MODATOMBITS_MASK */ +#if ATOMBYTES == 4 +#define DIVATOMBITS_SHIFT 5 +#elif ATOMBYTES == 2 +#define DIVATOMBITS_SHIFT 4 +#elif ATOMBYTES == 1 +#define DIVATOMBITS_SHIFT 3 +#endif +#define MODATOMBITS_MASK ((1<l = l; \ + (mpz)->a = l; \ + (mpz)->s = 0; \ + (mpz)->d = t; \ +} while(0) + +/* Raw inizialization of mpz_t elements */ +#define _mpz_raw_init(z, d, l, a, s) \ +do { \ + (z)->d = d; \ + (z)->l = l; \ + (z)->a = a; \ + (z)->s = s; \ +} + +#define _mpz_neg(z) \ +do { \ + (z)->s ^= 1; \ +} while(0) + +/* ------------------------ debugging macros -------------------------------- */ + +#define debugprint(m,z) do { \ + char *_s = mpz_get_str(NULL, 10, z); \ + printf("[%d]%s\n", m, _s); \ + free(_s); \ +} while(0) + +#define debugprint2(m,z) do { \ + char *_s = mpz_get_str(NULL, 2, z); \ + printf("[%d]%s\n", m, _s); \ + free(_s); \ +} while(0) + +/* ---------------------- initialization/allocation ------------------------- */ + +/* Initialize a relative bignum. + * return values: none, can't fail */ +void mpz_init(mpz_ptr z) +{ + z->d = NULL; + z->a = z->l = z->s = 0; +} + +/* This function is used every time we need to set the z->d[l] word in the + * z->d array of the mpz_t type. It performs the allocation when + * needed. So if you call it with l = 0, there is anyway at least + * one word allocated. Warning: the normalization inside some function + * relies on this behaviour. + * + * return values: + * SBN_OK on success + * SBN_MEM on out of memory + * + * On error the previous memory configuration and memory of 'z' + * is untouched. + * + * The new words are initialized to zero. + * Note that this function relies on an ANSI-C realloc() that + * acts like free if the 'size' = 0, and return NULL in such a case, + * and also acts like malloc if the ptr = NULL. */ +int mpz_realloc(mpz_ptr z, u_int32_t i) +{ + void *new; + u_int32_t j; + + if (i < z->a) + return SBN_OK; + new = realloc(z->d, (i+1)*MPZ_ATOMSZ); + if (new == NULL) + return SBN_MEM; + z->d = new; + /* set the new words to zero */ + for (j = z->a; j <= i; j++) + z->d[j] = 0; + z->a = j; /* j = i+1 here */ + return SBN_OK; +} + +/* Normalize the length of z, that's to set z->l accordly to the + * most non-zero significant digit. Assume that all the storage + * is initialized to zero (that's a global assuption). */ +void mpz_normalize(mpz_ptr z) +{ + int32_t j; + + if (!z->a) + return; + j = z->a-1; + while(j >= 0) { + if (z->d[j]) + break; + j--; + } + z->l = j+1; + if (z->l == 0) + z->s = 0; +} + +/* If z == 0, make it positive */ +void mpz_normalize_sign(mpz_ptr z) +{ + if (z->l == 0) + z->s = 0; +} + +/* inline version of mpz_normalize() that assumes z->a > 0 */ +#define _mpz_normalize(z) \ +do { \ + int32_t j = (z)->a-1; \ + while(j >=0 && !(z)->d[j]) \ + j--; \ + (z)->l = j+1; \ +} while(0) + +/* Free a bignum, can't fail */ +void mpz_clear(mpz_ptr z) +{ + free(z->d); +} + +/* Free a bignum and prepare it to accept up to i+1 digits (base 256) + * Note: not GMP compatible. Don't alter the sign */ +int mpz_zero_realloc(mpz_ptr z, u_int32_t i) +{ + int err; + + if ((err = mpz_realloc(z, i)) != SBN_OK) + return err; + mpz_zero(z); + return SBN_OK; +} + +/* raw z = 0 + * Note: not GMP compatible. Don't alter the sign */ +void mpz_zero(mpz_ptr z) +{ + if (!z->l) + return; + memset(z->d, 0, z->l*MPZ_ATOMSZ); + z->l = 0; +} + +/* Create a stack-allocated clone of the bignum pointed by 'z' and make + * 'z' pointing to the clone. This is used when the different operators + * of some operations point to the same object. */ +#define _mpz_clone_stack(z) \ +do { \ + mpz_ptr t = alloca(sizeof(mpz_t)); \ + t->d = alloca((z)->a*MPZ_ATOMSZ); \ + t->s = (z)->s; \ + t->l = (z)->l; \ + t->a = (z)->a; \ + memcpy(t->d, (z)->d, (z)->a*MPZ_ATOMSZ); \ + (z) = t; \ +} while(0) + +/* Clone 'z' using the 'L' atoms pointed by 'D' using stack-allocated memory */ +#define _mpz_rawclone_stack(z, D, L) \ +do { \ + (z)->d = alloca((L)*MPZ_ATOMSZ); \ + (z)->l = z->a = (L); \ + (z)->s = 0; \ + memcpy((z)->d, (D), (L)*MPZ_ATOMSZ); \ +} while(0) + +/* Create a stack-allocated copy of 'z' in 'r'. 'r' is an mpz_ptr type */ +#define _mpz_copy_stack(r, z) \ +do { \ + r = alloca(sizeof(mpz_t)); \ + (r)->d = alloca((z)->a*MPZ_ATOMSZ); \ + (r)->s = (z)->s; \ + (r)->l = (z)->l; \ + (r)->a = (z)->a; \ + memcpy((r)->d, (z)->d, (z)->a*MPZ_ATOMSZ); \ +} while(0) + +/* ----------------------- basic raw operations ----------------------------- */ + +/* clear the sign flag, so 'z' will be ABS(z) */ +#define _mpz_abs(z) \ +do { \ + (z)->s = 0; \ +} while(0) + +/* ---------------------------- bits operations ----------------------------- */ +/* compute the number of bits needed to rappresent the number 'z' */ +u_int32_t mpz_bits(mpz_ptr z) +{ + u_int32_t bits = (z->l-1) * ATOMBITS; + mpz_atom_t x = z->d[z->l-1]; + while(x) { + bits++; + x >>= 1; + } + return bits; +} + +/* Set the bit 'i' in 'z' */ +int mpz_setbit(mpz_ptr z, u_int32_t i) +{ + u_int32_t atom = i >> DIVATOMBITS_SHIFT; + u_int32_t bit = i & MODATOMBITS_MASK; + int err; + + if ((err = mpz_realloc(z, atom)) != SBN_OK) + return err; + z->d[atom] |= (mpz_atom_t) 1 << bit; + if (z->l < atom+1) + z->l = atom+1; + return SBN_OK; +} + +/* Inline bit pusher that expects the user know what is doing. + * Used in the division algorithm. */ +#define _mpz_setbit(z, i) \ +do { \ + u_int32_t _atom = (i)>>DIVATOMBITS_SHIFT; \ + (z)->d[_atom] |= (mpz_atom_t) 1<<((i)&MODATOMBITS_MASK);\ + if ((z)->l < _atom+1) (z)->l = _atom+1; \ +} while(0) + +/* Faster version without normalization */ +#define __mpz_setbit(z, i) \ +do { \ + u_int32_t _atom = (i)>>DIVATOMBITS_SHIFT; \ + (z)->d[_atom] |= (mpz_atom_t) 1<<((i)&MODATOMBITS_MASK);\ +} while(0) + +/* Clear the bit 'i' in 'z' */ +int mpz_clrbit(mpz_ptr z, u_int32_t i) +{ + u_int32_t atom = i >> DIVATOMBITS_SHIFT; + u_int32_t bit = i & MODATOMBITS_MASK; + + if (atom >= z->l) + return SBN_OK; /* nothing to clear */ + z->d[atom] &= ~((mpz_atom_t) 1 << bit); + if (atom == z->l-1) + mpz_normalize(z); + return SBN_OK; +} + +/* Fast clear-bit with normalization */ +#define _mpz_clrbit(z, i) \ +do { \ + u_int32_t _atom = (i)>>DIVATOMBITS_SHIFT; \ + (z)->d[_atom] &= ~((mpz_atom_t) 1<<((i)&MODATOMBITS_MASK)); \ + if (_atom == z->l-1) \ + _mpz_normalize(z); \ +} while(0) + +/* Fast clear-bit without normalization */ +#define __mpz_clrbit(z, i) \ +do { \ + u_int32_t _atom = (i)>>DIVATOMBITS_SHIFT; \ + (z)->d[_atom] &= ~((mpz_atom_t) 1<<((i)&MODATOMBITS_MASK));\ +} while(0) + +/* test the bit 'i' of 'z' and return: + * 0 if the bit 'i' is not set or out of range + * > 0 if the bit 'i' is set */ +int mpz_testbit(mpz_ptr z, u_int32_t i) +{ + u_int32_t atom = i >> DIVATOMBITS_SHIFT; + u_int32_t bit = i & MODATOMBITS_MASK; + + if (atom >= z->l) + return 0; + return (z->d[atom] & ((mpz_atom_t) 1 << bit)); +} + +/* inline bit tester that expects the user know what is doing. + * It's used in the division algorithm. Return 0 if the bit is set, + * non zero if the bit isn't zet */ +#define _mpz_testbit(z, i) \ + ((z)->d[(i)>>DIVATOMBITS_SHIFT] & ((mpz_atom_t)1<<((i)&MODATOMBITS_MASK))) + +/* Return 1 if 'z' is odd, 0 if it's even. */ +#define mpz_is_odd(z) (((z)->l) ? ((z)->d[0] & 1) : 0) + +/* The same of mpz_odd() but assume there is at least an word allocated */ +#define _mpz_is_odd(z) ((z)->d[0] & 1) +#define _mpz_is_even(z) (!_mpz_is_odd(z)) + +/* -------------------------------- shifting -------------------------------- */ +/* Left shift of 'i' words */ +int mpz_lshiftword(mpz_ptr r, u_int32_t i) +{ + int err; + + if (!i) + return SBN_OK; + if ((err = mpz_realloc(r, (r->l+i)-1)) != SBN_OK) + return err; + memmove(r->d+i, r->d, r->l*MPZ_ATOMSZ); + memset(r->d, 0, i*MPZ_ATOMSZ); + r->l += i; + return SBN_OK; +} + +/* Right shift of 'i' words */ +int mpz_rshiftword(mpz_ptr r, u_int32_t i) +{ + if (!i) + return SBN_OK; + if (i >= r->l) { + mpz_zero(r); + return SBN_OK; + } + memmove(r->d, r->d+i, (r->l-i)*MPZ_ATOMSZ); + r->l -= i; + memset(r->d+r->l, 0, i); + return SBN_OK; +} + +/* Left shift of 'i' bits */ +int mpz_lshift(mpz_ptr r, mpz_ptr z, u_int32_t i) +{ + u_int32_t rawshift = i >> DIVATOMBITS_SHIFT; + u_int32_t bitshift = i & MODATOMBITS_MASK; + int32_t j; + mpz_carry_t x; + int err; + + /* clone 'z' in 'r' */ + if (r != z && ((err = mpz_set(r, z)) != SBN_OK)) + return err; + if (rawshift && ((err = mpz_lshiftword(r, rawshift)) != SBN_OK)) + return err; + if (!bitshift) + return SBN_OK; + /* We need an additional word */ + if ((err = mpz_realloc(r, r->l+1)) != SBN_OK) + return err; + /* note that here we are sure that 'bitshift' <= ATOMBITS */ + if (r->l) { + for (j = r->l-1; j >= 0; j--) { + x = (mpz_carry_t) r->d[j] << bitshift; + r->d[j] = x & MPZ_MASK; + r->d[j+1] |= x >> ATOMBITS; + } + if (r->d[r->l]) + r->l++; + } + return SBN_OK; +} + +/* Fast 'z' 1 bit left shift. Assume there is allocated space for + * an additional atom. Handle normalization */ +#define _mpz_self_lshift1(z) \ +do { \ + int32_t j; \ + for (j = (z)->l-1; j >= 0; j--) { \ + (z)->d[j+1] |= ((z)->d[j] & (1<<(ATOMBITS-1))) >> (ATOMBITS-1);\ + (z)->d[j] <<= 1; \ + } \ + if ((z)->d[(z)->l]) \ + (z)->l++; \ +} while(0); + +/* Fast 'z' 1 bit left shift + set bit 0 to 'b'. Assume there is allocated + * space for an additional atom. Handle normalization */ +#define _mpz_self_lshift1_setbit0(z, b) \ +do { \ + int32_t j; \ + for (j = (z)->l-1; j >= 0; j--) { \ + (z)->d[j+1] |= ((z)->d[j] & (1<<(ATOMBITS-1))) >> (ATOMBITS-1);\ + (z)->d[j] <<= 1; \ + } \ + (z)->d[0] |= b; \ + if ((z)->d[(z)->l]) \ + (z)->l++; \ +} while(0); + +/* Right shift of 'i' bits */ +int mpz_rshift(mpz_ptr r, mpz_ptr z, u_int32_t i) +{ + u_int32_t rawshift = i >> DIVATOMBITS_SHIFT; + u_int32_t bitshift = i & MODATOMBITS_MASK; + u_int32_t j; + mpz_carry_t x; + int err; + + /* clone 'z' in 'r' */ + if (r != z && ((err = mpz_set(r, z)) != SBN_OK)) + return err; + if (rawshift && ((err = mpz_rshiftword(r, rawshift)) != SBN_OK)) + return err; + if (!bitshift) + return SBN_OK; + /* note that here we are sure that 'bitshift' <= ATOMBITS */ + if (r->l) { + r->d[0] >>= bitshift; + for (j = 1; j < r->l; j++) { + x = (mpz_carry_t) r->d[j] << (ATOMBITS-bitshift); + r->d[j] = x >> ATOMBITS; + r->d[j-1] |= x & MPZ_MASK; + } + if (!r->d[r->l-1]) + r->l--; + } + return SBN_OK; +} + +/* Fast 'z' 1 bit right shift. Handle normalization. Assume z->a != 0 + * (so z->d != NULL), that's: don't call it without a reallocation. */ +#define _mpz_self_rshift1(z) \ +do { \ + u_int32_t j; \ + (z)->d[0] >>= 1; \ + for (j = 1; j < (z)->l; j++) { \ + (z)->d[j-1] |= ((z)->d[j] & 1) << (ATOMBITS-1); \ + (z)->d[j] >>= 1; \ + } \ + if (!(z)->d[(z)->l-1]) \ + (z)->l--; \ +} while(0); + +/* -------------------------- bitwise AND OR XOR NOT ------------------------ */ +/* 'r' = 'z' bit-AND 'm' */ +int mpz_and(mpz_ptr r, mpz_ptr z, mpz_ptr m) +{ + int err; + u_int32_t j; + u_int32_t len; + + if (z == m) { /* A AND A = A */ + mpz_set(r, z); + return SBN_OK; + } + len = MIN(z->l, m->l); + if ((err = mpz_realloc(r, len)) != SBN_OK) + return err; + for (j = 0; j < len; j++) + r->d[j] = z->d[j] & m->d[j]; + memset(r->d+j, 0, r->a - j); /* clear not-used words before normalize */ + mpz_normalize(r); + return SBN_OK; +} + +/* -------------------------------- compare --------------------------------- */ + +/* The same as mpz_cmpabs() for immediate. + * Relies on the fact that mpz_cmpabs() don't perform any allocation-related + * operation on the second operand. */ +int32_t mpz_cmpabsi_raw(mpz_ptr a, mpz_atom_t *d, u_int32_t l) +{ + mpz_t b; + + b->d = d; + b->l = b->a = l; + b->s = 0; + return mpz_cmpabs(a, b); +} + +/* compare ABS('a') and ABS('b'), return values: + * >0 if a > b + * 0 if a == b + * <0 if a < b + * + * 'a->d' and 'b->d' can point to statically allocated memory. + * + * Note that we can't use subtraction to return >0 or <0 if a-b != 0 + * since the type for length and atom is unsigned so it may overflow. + */ +int32_t mpz_cmpabs(mpz_ptr a, mpz_ptr b) +{ + int32_t i; + + if (a->l > b->l) return 1; + if (a->l < b->l) return -1; + i = a->l; + while(i--) { + if (a->d[i] > b->d[i]) return 1; + if (a->d[i] < b->d[i]) return -1; + } + return 0; +} + +/* the same as mpz_cmpabs() but 'b' is a 32bit unsigned immediate */ +int32_t mpz_cmpabs_ui(mpz_ptr a, u_int32_t u) +{ + mpz_t mpz; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + return mpz_cmpabs(a, mpz); +} + +/* compare 'a' and 'b'. Return values are the same as mpz_cmpabs() */ +int32_t mpz_cmp(mpz_ptr a, mpz_ptr b) +{ + if (!a->l && !b->l) /* 0 == 0 */ + return 0; + if (a->s == b->s) { /* same sign */ + if (a->s) return mpz_cmpabs(b,a); /* both negative */ + return mpz_cmpabs(a,b); /* both positive */ + } + /* one negative, one positive */ + if (a->s) + return -1; + return 1; +} + +/* The same as mpz_cmp() with unsigned 32bit immediate */ +int32_t mpz_cmp_ui(mpz_ptr a, u_int32_t u) +{ + mpz_t mpz; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + return mpz_cmp(a, mpz); +} + +/* signed integer version */ +int32_t mpz_cmp_si(mpz_ptr a, int32_t s) +{ + mpz_t mpz; + u_int32_t u = (s > 0) ? s : -s; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + mpz->s = s < 0; + return mpz_cmp(a, mpz); +} + +/* ---------------------------- addition ------------------------------------ */ + +/* Raw add of immediate, don't care about the sign since + * it's up to the caller */ +int mpz_addi_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) +{ + int err; + u_int32_t maxi = MAX(z->l, l); + mpz_atom_t car = 0; + mpz_carry_t sum; + u_int32_t j; + mpz_atom_t *t = NULL; + + if (r->d == d) { + if ((t = malloc(l*MPZ_ATOMSZ)) == NULL) + return SBN_MEM; + memcpy(t, d, l*MPZ_ATOMSZ); + d = t; + } + /* two sum of a,b requires at max MAX(len(a),len(b))+1 bytes */ + if (r != z && ((err = mpz_zero_realloc(r, maxi)) != SBN_OK)) + return err; + if ((err = mpz_realloc(z, (r == z) ? maxi : l)) != SBN_OK) + return err; + for(j = 0; j < l; j++) { + sum = (mpz_carry_t) d[j] + z->d[j] + car; + car = sum >> MPZ_SHIFT; + sum &= MPZ_MASK; + r->d[j] = sum; + } + for (j = l; j < z->l; j++) { + sum = (mpz_carry_t) z->d[j] + car; + car = sum >> MPZ_SHIFT; + sum &= MPZ_MASK; + r->d[j] = sum; + } + if (car) { + r->d[j] = car; + j++; + } + r->l = j; /* mpz_normalize() not needed */ + if (t) + free(t); + return SBN_OK; +} + +/* Add 'z' and a 32bit unsigned integer 'u' and put the result in 'r' + * Relies on the ability of mpz_add() to accept the last operator + * statically allocated */ +int mpz_add_ui(mpz_ptr r, mpz_ptr z, u_int32_t u) +{ + mpz_t mpz; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + return mpz_add(r, z, mpz); +} + +/* The same as mpz_add_ui but with signed integer */ +int mpz_add_si(mpz_ptr r, mpz_ptr z, int32_t s) +{ + mpz_t mpz; + u_int32_t u = (s > 0) ? s : -s; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + mpz->s = s < 0; + return mpz_add(r, z, mpz); +} + +/* 'r' = 'a' + 'b' + * b->d can point to statically allocated data */ +int mpz_add(mpz_ptr r, mpz_ptr a, mpz_ptr b) +{ + int cmp = mpz_cmpabs(a, b); + int err; + + /* both positive or negative */ + if (a->s == b->s) { + err = mpz_addi_raw(r, a, b->d, b->l); + r->s = a->s; + return err; + } + /* different signs if we are here */ + if (a->s) { /* a negative, b positive */ + if (cmp >= 0) { /* a >= b */ + err = mpz_subi_raw(r, a, b->d, b->l); + r->s = (r->l == 0) ? 0 : 1; /* negative */ + return err; + } else { /* a < b */ + err = mpz_subi_raw(r, b, a->d, a->l); + r->s = 0; /* positive */ + return err; + } + } else { /* a positive, b negative */ + if (cmp >= 0) { /* a >= b */ + err = mpz_subi_raw(r, a, b->d, b->l); + r->s = 0; /* positive */ + return err; + } else { /* a < b */ + err = mpz_subi_raw(r, b, a->d, a->l); + r->s = (r->l == 0) ? 0 : 1; /* negative */ + return err; + } + } + return SBN_OK; /* not reached */ +} + +/* ---------------------------- subtraction --------------------------------- */ + +/* WARNING: assume z > d */ +int mpz_subi_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) +{ + int err; + mpz_scarry_t sub; + mpz_atom_t car = 0; + u_int32_t j; + mpz_atom_t *t = NULL; + + if (r->d == d) { + if ((t = malloc(l*MPZ_ATOMSZ)) == NULL) + return SBN_MEM; + memcpy(t, d, l*MPZ_ATOMSZ); + d = t; + } + if (r != z && ((err = mpz_set(r, z)) != SBN_OK)) + return err; + for (j = 0; j < l; j++) { + sub = (mpz_scarry_t) z->d[j] - car - d[j]; + car = 0; + if (sub < 0) { + sub += MPZ_BASE; + car = 1; + } + r->d[j] = sub; + } + for (j = l; j < z->l; j++) { + sub = (mpz_scarry_t) z->d[j] - car; + car = 0; + if (sub < 0) { + sub += MPZ_BASE; + car = 1; + } + r->d[j] = sub; + } + r->l = j; + mpz_normalize(r); + if (t) + free(t); + return SBN_OK; +} + +/* 'r' = 'a' - 'b' + * b->d can be statically allocated data */ +int mpz_sub(mpz_ptr r, mpz_ptr a, mpz_ptr b) +{ + int cmp = mpz_cmpabs(a, b); + int err; + + /* different signs? */ + if (a->s != b->s) { + err = mpz_addi_raw(r, a, b->d, b->l); + r->s = a->s; + return err; + } + /* both positive or negative if we are here */ + if (a->s) { /* both negative */ + if (cmp >= 0) { /* a >= b */ + err = mpz_subi_raw(r, a, b->d, b->l); + r->s = (r->l == 0) ? 0 : 1; /* negative */ + return err; + } else { /* a < b */ + err = mpz_subi_raw(r, b, a->d, a->l); + r->s = 0; /* positive */ + return err; + } + } else { /* both positive */ + if (cmp >= 0) { /* a >= b */ + err = mpz_subi_raw(r, a, b->d, b->l); + r->s = 0; /* positive */ + return err; + } else { /* a < b */ + err = mpz_subi_raw(r, b, a->d, a->l); + r->s = (r->l == 0) ? 0 : 1; /* negative */ + return err; + } + } + return SBN_OK; /* not reached */ +} + +/* mpz_sub() with immediate. + * Relies on the fact that mpz_sub() works if the last argument + * is statically allocated */ +int mpz_sub_ui(mpz_ptr r, mpz_ptr z, u_int32_t u) +{ + mpz_t mpz; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + return mpz_sub(r, z, mpz); +} + +/* like mpz_sub_ui but with signed integer */ +int mpz_sub_si(mpz_ptr r, mpz_ptr z, int32_t s) +{ + mpz_t mpz; + u_int32_t u = (s > 0) ? s : -s; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + mpz->s = s < 0; + return mpz_sub(r, z, mpz); +} + +/* ------------------------------- product ---------------------------------- */ + +/* Raw multiplication of immediate, don't care about the sign + * since it's up to the caller */ +int mpz_muli_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) +{ + int err; + u_int32_t maxi = z->l+l; + mpz_atom_t car; + mpz_carry_t mul; + u_int32_t j, i; + mpz_t t, rt; + mpz_ptr rbak = NULL; + int tmptarget = (r == z); + mpz_atom_t *x = NULL; + + /* Make a copy of 'd' if it's == r */ + if (r->d == d) { + if ((x = malloc(l*MPZ_ATOMSZ)) == NULL) + return SBN_MEM; + memcpy(x, d, l*MPZ_ATOMSZ); + d = x; + } + /* if r and z are the same we need a temp bignum target */ + if (tmptarget) { + rbak = r; + r = rt; + mpz_init(r); + r->s = rbak->s; /* preserve the original sign */ + } + /* two product of a,b requires at max len(a)+len(b) bytes */ + if ((err = mpz_zero_realloc(r, maxi)) != SBN_OK) + goto error; + /* initialize the temp var */ + mpz_init(t); + if ((err = mpz_realloc(t, maxi)) != SBN_OK) + goto error; + for(j = 0; j < l; j++) { + car = 0; + mpz_zero(t); + for (i = 0; i < z->l; i++) { + /* note that A = B * C + D + E + * with A of N*2 bits and C,D,E of N bits + * can't overflow since: + * (2^N-1)*(2^N-1)+(2^N-1)+(2^N-1) == 2^(2*N)-1 */ + mul = (mpz_carry_t) d[j] * z->d[i] + car + r->d[i+j]; + car = mul >> MPZ_SHIFT; + mul &= MPZ_MASK; + r->d[i+j] = mul; + } + if (car) + r->d[i+j] = car; + } + r->l = maxi; + mpz_normalize(r); + if (tmptarget && ((err = mpz_set(rbak, rt)) != SBN_OK)) + goto error; + err = SBN_OK; + /* fall through */ +error: + mpz_clear(t); + if (tmptarget) + mpz_clear(rt); + if (x) + free(x); + return err; +} + +/* 'r' = 'z' * 'f' */ +int mpz_mul(mpz_ptr r, mpz_ptr z, mpz_ptr f) +{ + r->s = z->s^f->s; /* the sign is the xor of the two sings */ + return mpz_muli_raw(r, z, f->d, f->l); +} + +/* Mul 'z' and a 32bit unsigned integer 'u' and put the result in 'r' + * We don't need to touch the sign since the factor is >= 0 */ +int mpz_mul_ui(mpz_ptr r, mpz_ptr z, u_int32_t u) +{ + u32tompz(t,u,l); + r->s = z->s; + return mpz_muli_raw(r, z, t, l); +} + +/* Like mpz_mul_ui but with signed integer */ +int mpz_mul_si(mpz_ptr r, mpz_ptr z, int32_t s) +{ + u_int32_t u = (s > 0) ? s : -s; + u32tompz(t,u,l); + r->s = z->s^(s<0); + return mpz_muli_raw(r, z, t, l); +} + +/* 'r' = i! */ +int mpz_fac_ui(mpz_ptr r, u_int32_t i) +{ + u_int32_t j; + int err; + + if (!i) { + mpz_setzero(r); + return SBN_OK; + } + if ((err = mpz_set_ui(r, 1)) != SBN_OK) + return err; + for (j = 2; j <= i; j++) + if ((err = mpz_mul_ui(r, r, j)) != SBN_OK) + return err; + return SBN_OK; +} + +/* --------------------------- exponentialization --------------------------- */ + +/* compute b^e mod m. + * Note that there are much faster ways to do it. + * see www.nc.com for more information */ +int mpz_powm(mpz_ptr r, mpz_ptr b, mpz_ptr e, mpz_ptr m) +{ + int rs = 0, err; + mpz_t B, E; + + if (e->s) /* can't handle negative exponents */ + return SBN_INVAL; + + /* handle overlapping of modulo and result */ + if (r == m) + _mpz_clone_stack(m); + /* we need to work on copies of base and exponent */ + mpz_init(B); + mpz_init(E); + if ((err = mpz_set(B, b)) != SBN_OK) + return err; + if ((err = mpz_set(E, e)) != SBN_OK) { + mpz_clear(B); + return err; + } + /* make the base positive, but first compute the power sign, + * that's negative only if the base is negative and exponent odd */ + if (B->s && _mpz_is_odd(E)) + rs = 1; + _mpz_abs(B); + /* compute r = b^e mod m */ + mpz_set_ui(r, 1); + while(mpz_cmpabs_ui(E, 1) > 0) { + if (_mpz_is_odd(E)) { + if ((err = mpz_mul(r, r, B)) != SBN_OK) goto error; + if ((err = mpz_mod(r, r, m)) != SBN_OK) goto error; + } + _mpz_self_rshift1(E); /* e = e / 2 */ + if ((err = mpz_mul(B, B, B)) != SBN_OK) goto error; + if ((err = mpz_mod(B, B, m)) != SBN_OK) goto error; + } + if ((err = mpz_mul(r, r, B)) != SBN_OK) goto error; + r->s = rs; /* set the pre-computed sign */ + if ((err = mpz_mod(r, r, m)) != SBN_OK) goto error; + err = SBN_OK; + /* fall through */ +error: + mpz_clear(B); + mpz_clear(E); + return err; +} + +/* Just b^e. The algorithm is just the one of mpz_powm() without + * the modulo step. */ +int mpz_pow(mpz_ptr r, mpz_ptr b, mpz_ptr e) +{ + int rs = 0, err; + mpz_t B, E; + + if (e->s) /* can't handle negative exponents */ + return SBN_INVAL; + + /* we need to work on copies of base and exponent */ + mpz_init(B); + mpz_init(E); + if ((err = mpz_set(B, b)) != SBN_OK) + return err; + if ((err = mpz_set(E, e)) != SBN_OK) { + mpz_clear(B); + return err; + } + /* make the base positive, but first compute the power sign, + * that's negative only if the base is negative and exponent odd */ + if (B->s && _mpz_is_odd(E)) + rs = 1; + _mpz_abs(B); + /* compute r = b^e */ + mpz_set_ui(r, 1); + while(mpz_cmpabs_ui(E, 1) > 0) { + if (_mpz_is_odd(E)) { + if ((err = mpz_mul(r, r, B)) != SBN_OK) goto error; + } + _mpz_self_rshift1(E); /* e = e / 2 */ + if ((err = mpz_mul(B, B, B)) != SBN_OK) goto error; + } + if ((err = mpz_mul(r, r, B)) != SBN_OK) goto error; + r->s = rs; /* set the pre-computed sign */ + err = SBN_OK; + /* fall through */ +error: + mpz_clear(B); + mpz_clear(E); + return err; +} + +/* -------------------------- root extraction ------------------------------- */ + +/* r = floor(sqrt(z)). That's r*r <= z AND (r+1)*(r+1) > z. + * The algorithm used is very simple but very slow. It exploits + * the binary rappresentation. This should be replaced since + * performances are very poor */ +int mpz_sqrt(mpz_ptr r, mpz_ptr z) +{ + int j = mpz_bits(z); /* MSB bit of 'z' */ + int i = ((j-1)/2); /* MSB bit (sometimes one more) of 'r' */ + int b = i*2; /* bit to set to obtain 2^i * 2^i */ + int err; + u_int32_t atoms = j >> DIVATOMBITS_SHIFT; + mpz_t s, R, X; + + mpz_init(s); + mpz_init(R); + mpz_init(X); + if (r == z) { + _mpz_clone_stack(z); + } + if ((err = mpz_realloc(s, atoms)) != SBN_OK) return err; + if ((err = mpz_realloc(R, atoms)) != SBN_OK) return err; + if ((err = mpz_realloc(X, atoms)) != SBN_OK) return err; + if ((err = mpz_zero_realloc(r, atoms)) != SBN_OK) return err; + for(; i >= 0; i--, b -= 2) { + _mpz_setbit(R, b); + mpz_addi_raw(X, s, R->d, R->l); + _mpz_clrbit(R, b); + if (mpz_cmpabs(X, z) <= 0) { + mpz_set(s, X); + _mpz_setbit(r, i); + _mpz_setbit(R, b+1); + } + _mpz_self_rshift1(R); + } + mpz_clear(s); + mpz_clear(R); + mpz_clear(X); + return SBN_OK; +} + +/* ----------------------------- division ----------------------------------- */ + +/* Raw division of immediate don't care about the sign + * since it's up to the caller. + * + * compute: + * 'q' = 'z' / 'd' + * 'r' = 'z' % 'd' + * + * Assume: z >= 0, d > 0, all the arguments must not overlap. + * Arguments overlapping, sign, etc, are handled in mpz_tdiv_qr(). + * 'z' can be statically allocated. + * + * =========================================================================== + * + * I got this algorithm from PGP 2.6.3i (see the mp_udiv function). + * Here is how it works: + * + * Input: N=(Nn,...,N2,N1,N0)radix2 + * D=(Dn,...,D2,D1,D0)radix2 + * Output: Q=(Qn,...,Q2,Q1,Q0)radix2 = N/D + * R=(Rn,...,R2,R1,R0)radix2 = N%D + * + * Assume: N >= 0, D > 0 + * + * For j from 0 to n + * Qj <- 0 + * Rj <- 0 + * For j from n down to 0 + * R <- R*2 + * if Nj = 1 then R0 <- 1 + * if R => D then R <- (R - D), Qn <- 1 + * + * Note that the doubling of R is usually done leftshifting one position. + * The only operations needed are bit testing, bit setting and subtraction. + * + * Unfortunately it is quite slow. The algoritm is not very fast + * and the implementation may be smarter. The good point is that + * it's very simple to implement. + */ +int mpz_divi_qr_raw(mpz_ptr q, mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) +{ + int bit = mpz_bits(z) - 1; + + mpz_zero_realloc(q, z->l-l+1); + mpz_zero_realloc(r, l); + + while(bit >= 0) { + _mpz_self_lshift1_setbit0(r, (_mpz_testbit(z, bit) != 0)); + if (mpz_cmpabsi_raw(r, d, l) >= 0) { + _mpz_normalize(r); + mpz_subi_raw(r, r, d, l); + __mpz_setbit(q, bit); + } + bit--; + } + _mpz_normalize(q); + _mpz_normalize(r); + return SBN_OK; +} + +/* The same as mpz_divi_qr_raw() but only the remainder is computed */ +int mpz_divi_r_raw(mpz_ptr r, mpz_ptr z, mpz_atom_t *d, u_int32_t l) +{ + int bit = mpz_bits(z) - 1; + + mpz_zero_realloc(r, l); + + while(bit >= 0) { + _mpz_self_lshift1_setbit0(r, (_mpz_testbit(z, bit) != 0)); + if (mpz_cmpabsi_raw(r, d, l) >= 0) { + _mpz_normalize(r); + mpz_subi_raw(r, r, d, l); + } + bit--; + } + _mpz_normalize(r); + return SBN_OK; +} + +/* Wrapper for the real division function + * 'q' = 'z' / 'd' + * 'r' = 'z' % 'd' + * + * Assume that q and r are different pointers. + * d can be statically allocated. + * Relies on the fact that: + * mpz_set() can accept as second argument a statically allocated operator + * mpz_cmpabs() can accept as second argument a statically allocated op. + * mpz_divi_qr() can accept a statically allocated divident. + */ +int mpz_tdiv_qr(mpz_ptr q, mpz_ptr r, mpz_ptr z, mpz_ptr d) +{ + int cmp; + int err; + + if (d->l == 0) /* division by zero */ + return SBN_INVAL; + if (z == d) { + err = mpz_set_ui(q, 1); /* a/a = 1 */ + if (err != SBN_OK) + return err; + mpz_setzero(r); /* a%a = 0 */ + return SBN_OK; + } + cmp = mpz_cmpabs(z, d); + if (cmp < 0) { /* z < d */ + err = mpz_set(r, z); /* a%b = a with as = z->s^d->s; /* the sign is the xor of the two sings */ + r->s = z->s; /* the sign of the remainder is the sign of the divident */ + return mpz_divi_qr_raw(q, r, z, d->d, d->l); +} + +/* The same as mpz_tdiv_qr() but the divisor is a 32bit unsigned immediate */ +int mpz_tdiv_qr_ui(mpz_ptr q, mpz_ptr r, mpz_ptr z, u_int32_t u) +{ + mpz_t mpz; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + return mpz_tdiv_qr(q, r, z, mpz); +} + +/* Like mpz_tdiv_qr_si but with signed integer */ +int mpz_tdiv_qr_si(mpz_ptr q, mpz_ptr r, mpz_ptr z, int32_t s) +{ + mpz_t mpz; + u_int32_t u = (s > 0) ? s : -s; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + mpz->s = s < 0; + return mpz_tdiv_qr(q, r, z, mpz); +} + +/* Like mpz_tdiv_qr but only the remainder is computed */ +int mpz_tdiv_r(mpz_ptr r, mpz_ptr z, mpz_ptr d) +{ + int cmp; + + if (d->l == 0) /* division by zero */ + return SBN_INVAL; + if (z == d) { + mpz_setzero(r); /* a%a = 0 */ + return SBN_OK; + } + cmp = mpz_cmpabs(z, d); + if (cmp < 0) { /* z < d */ + if (r == z) + return SBN_OK; + return mpz_set(r, z); /* a%b = a with as = z->s; /* the sign of the remainder is the sign of the divident */ + return mpz_divi_r_raw(r, z, d->d, d->l); +} + +/* The same as mpz_tdiv_r() but the divisor is a 32bit unsigned immediate */ +int mpz_tdiv_r_ui(mpz_ptr r, mpz_ptr z, u_int32_t u) +{ + mpz_t mpz; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + return mpz_tdiv_r(r, z, mpz); +} + +/* Like the above but with signed integer */ +int mpz_tdiv_r_si(mpz_ptr r, mpz_ptr z, int32_t s) +{ + mpz_t mpz; + u_int32_t u = (s > 0) ? s : -s; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + mpz->s = s < 0; + return mpz_tdiv_r(r, z, mpz); +} + +/* Like mpz_tdiv_qr but only the quotient is computed. + * This is just a wrapper for mpz_tdiv_qr() */ +int mpz_tdiv_q(mpz_ptr q, mpz_ptr z, mpz_ptr d) +{ + int err; + mpz_t r; + + mpz_init(r); + err = mpz_tdiv_qr(q, r, z, d); + mpz_clear(r); + return err; +} + +/* The same as mpz_tdiv_q() but the divisor is a 32bit unsigned immediate */ +int mpz_tdiv_q_ui(mpz_ptr q, mpz_ptr z, u_int32_t u) +{ + mpz_t mpz; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + return mpz_tdiv_r(q, z, mpz); +} + +/* Like the above but with signed integer */ +int mpz_tdiv_q_si(mpz_ptr q, mpz_ptr z, int32_t s) +{ + mpz_t mpz; + u_int32_t u = (s > 0) ? s : -s; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + mpz->s = s < 0; + return mpz_tdiv_r(q, z, mpz); +} + +/* Division by one-atom divident. + * compute z = z / d; + * The remainder is returned. + * + * Assume: z > 0, d > 0 + * Operands overlapping is not allowed */ +mpz_atom_t _mpz_selfdiv1_qr_raw(mpz_ptr z, mpz_atom_t d) +{ + int32_t j; + mpz_carry_t t; + + /* divide */ + for (t = 0, j = z->l-1; j >= 0; j--) { + t = (t << MPZ_SHIFT) + z->d[j]; + z->d[j] = t / d; + t %= d; + } + /* normalize */ + if (!z->d[z->l-1]) + z->l--; + return t; +} + +/* Compute z mod m (modular reduction) */ +int mpz_mod(mpz_ptr r, mpz_ptr z, mpz_ptr m) +{ + int err; + + if (r == m) + _mpz_clone_stack(m); + if ((err = mpz_tdiv_r(r, z, m)) != SBN_OK) + return err; + if (r->l && z->s) { + if (m->s) { + if ((err = mpz_sub(r, r, m)) != SBN_OK) + return err; + } else { + if ((err = mpz_add(r, r, m)) != SBN_OK) + return err; + } + } + return SBN_OK; +} + +/* ---------------------------- assignment ---------------------------------- */ + +/* Set z = 0 + * Note: not GMP compatible */ +int mpz_setzero(mpz_ptr z) +{ + z->s = 0; + return mpz_zero_realloc(z, 0); +} + +/* assign 's' to 'd'. + * 's' can be statically allocated */ +int mpz_set(mpz_ptr d, mpz_ptr s) +{ + int err; + + if ((err = mpz_zero_realloc(d, s->l)) != SBN_OK) + return err; + memcpy(d->d, s->d, s->l*MPZ_ATOMSZ); + d->l = s->l; + d->s = s->s; + return SBN_OK; +} + +/* Like mpz_set() without reallocation. Assume there is enough + * space in d to get the value of s */ +#define _mpz_set(D, S) \ +do { \ + memcpy(D->d, S->d, S->l*MPZ_ATOMSZ); \ + D->l = S->l; \ + D->s = S->s; \ +} while(0) + +/* Set in 'z' the 32bit unsigned integer given as argument */ +int mpz_set_ui(mpz_ptr z, u_int32_t u) +{ + mpz_t mpz; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + return mpz_set(z, mpz); +} + +/* Set in 'z' the double d */ +int mpz_set_d(mpz_ptr z, double d) +{ + int i = 0; + u_int64_t u; + + z->s = (d < 0); + d = (d < 0) ? -d : d; + u = d; + + if (mpz_realloc(z, 8)) + return 1; + while(u) { + z->d[i] = u & MPZ_MASK; + u >>= MPZ_SHIFT; + i++; + } + z->l = i; + return 0; +} + +/* Set in 'z' the 64bit unsigned integer 'u' */ +int mpz_set_ui64(mpz_ptr z, u_int64_t u) +{ + int i = 0; + + z->s = 0; + if (mpz_realloc(z, 8)) + return 1; + while(u) { + z->d[i] = u & MPZ_MASK; + u >>= MPZ_SHIFT; + i++; + } + z->l = i; + return 0; +} + +/* Set in 'z' the 64bit signed integer 's' */ +int mpz_set_si64(mpz_ptr z, int64_t s) +{ + u_int64_t u; + int sign = s < 0, err; + + u = (s > 0) ? s : -s; + if ((err = mpz_set_ui64(z, u)) != SBN_OK) + return err; + z->s = sign; + return err; +} + +/* Set in 'z' the 32bit unsigned integer given as argument */ +int mpz_set_si(mpz_ptr z, int32_t s) +{ + int neg = s < 0; + int err; + u_int32_t u = neg ? -s : s; + mpz_t mpz; + + u32tompz(t,u,l); + u32pack(mpz,t,l); + if ((err = mpz_set(z, mpz))) + return err; + if (neg) + _mpz_neg(z); + return err; +} + +/* set 'd' to ABS('s'). */ +int mpz_abs(mpz_ptr d, mpz_ptr s) +{ + int err; + + if ((d != s) && ((err = mpz_set(d, s)) != SBN_OK)) + return err; + _mpz_abs(d); + return SBN_OK; +} + +/* set 'd' to -'s' */ +int mpz_neg(mpz_ptr d, mpz_ptr s) +{ + int err; + + if ((d != s) && ((err = mpz_set(d, s)) != SBN_OK)) + return err; + _mpz_neg(d); + return SBN_OK; +} + +/* ----------------------- number theoretic functions ----------------------- */ +/* Compute the GCD (greatest common divisor) for 'a' and 'b' using + * the binary GCD algorithm. + * + * 'g' = GCD('|a|', '|b|') + * + * g, a, b can overlap (we anyway need to work on copies of a and b) + * assume a > 0, b > 0. */ +int mpz_gcd_raw(mpz_ptr g, mpz_ptr a, mpz_atom_t *b, u_int32_t l) +{ + u_int32_t maxi = MAX(a->l, l); + mpz_t B, t; + int err; + + /* we need to work on copies. */ + _mpz_clone_stack(a); + _mpz_rawclone_stack(B, b, l); + _mpz_abs(a); + _mpz_abs(B); + /* Reset 'g', prepare to accept up to maxi+1 atoms, set it to 1 */ + if ((err = mpz_zero_realloc(g, maxi)) != SBN_OK) + return err; + g->d[0] = 1; /* after the realloc call there is at least 1 atom */ + g->l = 1; + + /* The binary GCD algorithm */ + mpz_init(t); + + /* While even(a) and even(b) -> a=a/2 b=b/2 g=g*2; */ + while(_mpz_is_even(a) && _mpz_is_even(B)) { + _mpz_self_rshift1(a); + _mpz_self_rshift1(B); + _mpz_self_lshift1(g); + } + /* While a > 0 */ + while(_mpz_nonzero(a)) { + /* While even(a) a=a/2 */ + while(_mpz_is_even(a)) + _mpz_self_rshift1(a); + /* While even(b) b=b/2 */ + while(_mpz_is_even(B)) + _mpz_self_rshift1(B); + /* t = abs(a-b)/2 + * if (a >= b) a = t else b = t */ + if (mpz_cmpabs(a, B) >= 0) { + if ((err = mpz_subi_raw(t, a, B->d, B->l)) != SBN_OK) + goto err; + _mpz_self_rshift1(t); + _mpz_set(a, t); + } else { + if ((err = mpz_subi_raw(t, B, a->d, a->l)) != SBN_OK) + goto err; + _mpz_self_rshift1(t); + _mpz_set(B, t); + } + } + /* GCD = g * b */ + mpz_muli_raw(g, g, B->d, B->l); + err = SBN_OK; + /* fall through */ +err: + mpz_clear(t); + return err; +} + +/* wrapper for mpz_gcd_raw(). set GCD(a, 0) = a */ +int mpz_gcd(mpz_ptr g, mpz_ptr a, mpz_ptr b) +{ + int err; + + if (_mpz_iszero(a)) { + if ((err = mpz_set(g, b)) != SBN_OK) + return err; + _mpz_abs(g); + return SBN_OK; + } + if (_mpz_iszero(b)) { + if ((err = mpz_set(g, a)) != SBN_OK) + return err; + _mpz_abs(g); + return SBN_OK; + } + return mpz_gcd_raw(g, a, b->d, b->l); +} + +/* GCD(a, b) with b unsigned 32bit integer immediate. + * if 'g' is not NULL the result is stored in g. + * if 'g' is NULL and the result fits inside the u_int32_t type + * it is returned. If the result doesn't fit (can happen only if b = 0) + * 0 is returned. */ +u_int32_t mpz_gcd_ui(mpz_ptr g, mpz_ptr a, u_int32_t b) +{ + /* TODO: implement me. */ + ((void) g); + ((void) a); + ((void) b); + return SBN_OK; +} + +/* ----------------------- to/from string conversion ------------------------ */ + +#define sbn_chartoval(c) (r_cset[tolower(c)]) +#define sbn_valtochar(v) (cset[v]) + +/* Extimate the number of bytes needed to store a string rappresentation + * in base 'b' of the number 'z'. The length is overstimated, assuming + * the precision of the C-lib log() is of 6 digits over the dot. + * the length of the minus sign and the nul term are not included */ +size_t mpz_sizeinbase(mpz_ptr z, u_int32_t b) +{ + double len; + + if (b < SBN_MINBASE || b > SBN_MAXBASE) + return SBN_INVAL; + len = ((basetable[b]+0.000001) * z->l) + 1; + return (size_t) len; +} + +/* Convert an mpz_t to a string rappresentation in base 'b' + * Always nul-terminate the string if l > 0. + * + * We use a common trick to speed-up the conversion. + * Instead to perform divisions with remainder between + * the bignum and the specified base, we use a base that's + * the biggest power of the real base. Then we use the CPU + * division to divide by the real base. This limits a lot + * the number of multi-precision divisions, that are slow. + * + * For example converting in base 10, every 10 divisions + * 9 are divisions between two mpz_atom_t vars, and only + * one between a bignum and an mpz_atom_t. + * + * TODO: Note that this is still not very good since we should + * at least handle the case of a base that's power of 2 + * in a special way (i.e. performing shiftings and bitwise + * andings). */ +int mpz_tostr(mpz_ptr z, u_int32_t b, void *s, size_t l) +{ + mpz_t t; + char *d = s, *p; + mpz_atom_t hb, hbn; + + if (b < SBN_MINBASE || b > SBN_MAXBASE) + return SBN_INVAL; + if (!l) + return SBN_OK; + /* Handle z = 0 */ + if (_mpz_iszero(z)) { + *d++ = '0'; + goto done; + } + /* get the biggest power of 'b' that fits in an mpz_atom_t + * and it's exponent from the table. */ + hbn = basepowtable[b].maxexp; + hb = basepowtable[b].maxpow; + l--; + mpz_init(t); + mpz_set(t, z); + while(_mpz_nonzero(t) && l) { + unsigned int i; + mpz_atom_t x; + x = _mpz_selfdiv1_qr_raw(t, (mpz_atom_t) hb); + for (i = 0; (i < hbn) && (l != 0); i++) { + *d++ = sbn_valtochar(x % b); + x /= b; + if (x == 0 && _mpz_iszero(t)) + break; + } + } + mpz_clear(t); +done: + /* add the sign if needed */ + if (l && z->s) + *d++ = '-'; + *d-- = '\0'; + /* reverse the result */ + p = s; + while(p < d) { + char t; + + t = *p; + *p = *d; + *d = t; + d--; + p++; + } + return SBN_OK; +} + +char *mpz_get_str(char *str, int b, mpz_ptr z) +{ + size_t len; + + if (b < SBN_MINBASE || b > SBN_MAXBASE) + return NULL; + + len = mpz_sizeinbase(z, b) + 2; + if (!str && ((str = malloc(len)) == NULL)) + return NULL; + mpz_tostr(z, b, str, len); + return str; +} + +/* set in 'z' the ascii rappresentation in 's' of the number in base 'b' + * + * On error the original value of 'z' is not guaranteed to be the same + * as before this function is called. + * + * Again possible optimizations are not implemented. Most notably + * the base power of 2 case. + */ +int mpz_set_str(mpz_ptr z, char *s, int b) +{ + size_t len = strlen(s); + char *t = s + len - 1; + int neg = 0, err; + mpz_t pow, toadd; + + /* seek the first non-blank char from the head */ + while(*s && isspace(*s)) { + s++; + len--; + } + /* check if the number is negative */ + if (len && *s == '-') { + neg = 1; + s++; + len--; + } + /* guess the base */ + if (b == 0) { + b = 10; + if (len && *s == '0') { + b = 8; + s++; + len--; + if (len && tolower(*s) == 'x') { + b = 16; + s++; + len--; + } else if (len && tolower(*s) == 'b') { + b = 2; + s++; + len--; + } + } + } + if (b < SBN_MINBASE || b > SBN_MAXBASE) + return SBN_INVAL; + /* seek the first non-blank char from the tail */ + while(t > s && isspace(*t)) + t--; + /* convert it */ + mpz_init(pow); + mpz_init(toadd); + mpz_zero(z); + if ((err = mpz_set_ui(pow, 1)) != SBN_OK) + return err; + while(t >= s) { + int digit; + + digit = sbn_chartoval(*t); + if (digit < 0 || digit >= b) { + err = SBN_INVAL; + goto error; + } + mpz_set_ui(toadd, digit); + if ((err = mpz_mul(toadd, toadd, pow)) != SBN_OK) + goto error; + if ((err = mpz_add(z, z, toadd)) != SBN_OK) + goto error; + if ((err = mpz_mul_ui(pow, pow, b)) != SBN_OK) + goto error; + t--; + } + z->s = neg; + err = SBN_OK; + /* fall through */ +error: + mpz_clear(pow); + mpz_clear(toadd); + return err; +} + +/* ------------------------------- random numbers --------------------------- */ + +/* The rc4_sbox array is static, but this doesn't mean you can't use this + * library with threads. To create a real context for every random + * generation session is an overkill here */ +static unsigned char rc4_sbox[256]; +/* We want to start every time with the same seed. This is very + * important when some random number trigger multi-precision operations + * bugs. This flags is used to initialize the sbox the first time */ +static int rc4_seedflag = 0; + +/* Initialize the sbox with the numbers from 0 to 255 */ +void sbn_rand_init(void) +{ + int i; + + rc4_seedflag = 1; + for (i = 0; i < 256; i++) + rc4_sbox[i] = i; +} + +/* Re-seed the generator with user-provided bytes */ +void sbn_seed(void *seed, size_t len) +{ + int i; + unsigned char *s = (unsigned char*)seed; + + for (i = 0; i < len; i++) + rc4_sbox[i&0xFF] ^= s[i]; + /* discard the first 256 bytes of output after the reseed */ + for (i = 0; i < 32; i++) + (void) sbn_rand(); +} + +/* Generates a 32bit random number using an RC4-like algorithm */ +u_int32_t sbn_rand(void) +{ + u_int32_t r = 0; + unsigned char *rc = (unsigned char*) &r; + static unsigned int i = 0, j = 0; + unsigned int si, sj, x; + + /* initialization, only needed the first time */ + if (!rc4_seedflag) + sbn_rand_init(); + /* generates 4 bytes of pseudo-random numbers using RC4 */ + for (x = 0; x < 4; x++) { + i = (i+1) & 0xff; + si = rc4_sbox[i]; + j = (j + si) & 0xff; + sj = rc4_sbox[j]; + rc4_sbox[i] = sj; + rc4_sbox[j] = si; + *rc++ = rc4_sbox[(si+sj)&0xff]; + } + return r; +} + +/* Generate a random number of at most 'len' atoms length. + * If 'len' is negative the number will be negative of length abs(len) */ +int mpz_random(mpz_ptr z, int32_t len) +{ + int i, err, sign = 0; + + if (len < 0) { + sign = 1; + len = -len; + } + if (!len) + return mpz_setzero(z); + if ((err = mpz_realloc(z, len-1)) != SBN_OK) + return err; + for (i = 0; i < len; i++) + z->d[i] = sbn_rand() & MPZ_MASK; + _mpz_normalize(z); + z->s = sign; + return SBN_OK; +} + +/* Convert the bignum to approsimated double */ +double mpz_get_d(mpz_ptr z) +{ + double d = 0; + u_int32_t l = z->l; + + while(l--) + d = z->d[l] + d*MPZ_BASE; + if (z->s) + d = -d; + return d; +} diff --git a/sbignum.h b/src/sbignum.h similarity index 52% rename from sbignum.h rename to src/sbignum.h index 3c44b00..17e0347 100644 --- a/sbignum.h +++ b/src/sbignum.h @@ -40,10 +40,10 @@ typedef int32_t mpz_scarry_t; #define MPZ_BASE ((mpz_carry_t)MPZ_MASK+1) struct struct_sbnz { - mpz_atom_t *d; /* data the least significant word is d[0] */ - u_int32_t a; /* allocated bytes */ - u_int32_t l; /* number of used bytes */ - u_int32_t s; /* sign. non-zero if negative */ + mpz_atom_t *d; /* data the least significant word is d[0] */ + u_int32_t a; /* allocated bytes */ + u_int32_t l; /* number of used bytes */ + u_int32_t s; /* sign. non-zero if negative */ }; /* define the sbnz type */ typedef struct struct_sbnz *mpz_ptr; @@ -51,13 +51,13 @@ typedef struct struct_sbnz mpz_t[1]; /* Error codes */ enum sbn_err { - SBN_OK = 0, - SBN_MEM, - SBN_INVAL + SBN_OK = 0, + SBN_MEM, + SBN_INVAL }; -#define SBN_MINBASE 2 -#define SBN_MAXBASE 36 +#define SBN_MINBASE 2 +#define SBN_MAXBASE 36 /* Exported macros */ @@ -67,20 +67,20 @@ enum sbn_err { /* this is just the reverse. Equivalent to !_mpz_iszero */ #define _mpz_nonzero(z) ((z)->l != 0) -#define mpz_inc(z) mpz_add_ui(z, z, 1) -#define mpz_dec(z) mpz_sub_ui(z, z, 1) +#define mpz_inc(z) mpz_add_ui(z, z, 1) +#define mpz_dec(z) mpz_sub_ui(z, z, 1) /* ----------------------- Functions prototypes ----------------------------- */ /* inititialization/allocation */ -void mpz_init(mpz_ptr z); -void mpz_clear(mpz_ptr z); -int mpz_realloc(mpz_ptr z, u_int32_t i); +void mpz_init(mpz_ptr z); +void mpz_clear(mpz_ptr z); +int mpz_realloc(mpz_ptr z, u_int32_t i); /* shifting */ -int mpz_lshift(mpz_ptr r, mpz_ptr z, u_int32_t i); -int mpz_rshift(mpz_ptr r, mpz_ptr z, u_int32_t i); +int mpz_lshift(mpz_ptr r, mpz_ptr z, u_int32_t i); +int mpz_rshift(mpz_ptr r, mpz_ptr z, u_int32_t i); /* comparision */ -int32_t mpz_abscmp(mpz_ptr a, mpz_ptr b); +int32_t mpz_abscmp(mpz_ptr a, mpz_ptr b); int32_t mpz_abscmp_ui(mpz_ptr a, u_int32_t u); int32_t mpz_cmp(mpz_ptr a, mpz_ptr b); #define mpz_eq(a,b) (mpz_cmp(a,b) == 0) @@ -98,60 +98,60 @@ int32_t mpz_cmp_si(mpz_ptr a, int32_t s); #define mpz_gt_si(a,s) (mpz_cmp_si(a,s) > 0) #define mpz_ge_si(a,s) (mpz_cmp_si(a,s) >= 0) /* addition */ -int mpz_add_ui(mpz_ptr r, mpz_ptr z, u_int32_t u); -int mpz_add_si(mpz_ptr r, mpz_ptr z, int32_t s); -int mpz_add(mpz_ptr r, mpz_ptr a, mpz_ptr b); +int mpz_add_ui(mpz_ptr r, mpz_ptr z, u_int32_t u); +int mpz_add_si(mpz_ptr r, mpz_ptr z, int32_t s); +int mpz_add(mpz_ptr r, mpz_ptr a, mpz_ptr b); /* subtraction */ -int mpz_sub_ui(mpz_ptr r, mpz_ptr z, u_int32_t u); -int mpz_sub_si(mpz_ptr r, mpz_ptr z, int32_t s); -int mpz_sub(mpz_ptr r, mpz_ptr a, mpz_ptr b); +int mpz_sub_ui(mpz_ptr r, mpz_ptr z, u_int32_t u); +int mpz_sub_si(mpz_ptr r, mpz_ptr z, int32_t s); +int mpz_sub(mpz_ptr r, mpz_ptr a, mpz_ptr b); /* multiplication */ -int mpz_mul(mpz_ptr r, mpz_ptr z, mpz_ptr f); -int mpz_mul_ui(mpz_ptr r, mpz_ptr z, u_int32_t u); -int mpz_mul_si(mpz_ptr r, mpz_ptr z, int32_t s); -int mpz_fac_ui(mpz_ptr r, u_int32_t i); +int mpz_mul(mpz_ptr r, mpz_ptr z, mpz_ptr f); +int mpz_mul_ui(mpz_ptr r, mpz_ptr z, u_int32_t u); +int mpz_mul_si(mpz_ptr r, mpz_ptr z, int32_t s); +int mpz_fac_ui(mpz_ptr r, u_int32_t i); /* exponentialization */ -int mpz_powm(mpz_ptr r, mpz_ptr b, mpz_ptr e, mpz_ptr m); -int mpz_pow(mpz_ptr r, mpz_ptr b, mpz_ptr e); +int mpz_powm(mpz_ptr r, mpz_ptr b, mpz_ptr e, mpz_ptr m); +int mpz_pow(mpz_ptr r, mpz_ptr b, mpz_ptr e); /* division */ -int mpz_tdiv_qr(mpz_ptr q, mpz_ptr r, mpz_ptr z, mpz_ptr d); -int mpz_tdiv_qr_ui(mpz_ptr q, mpz_ptr r, mpz_ptr z, u_int32_t u); -int mpz_tdiv_qr_si(mpz_ptr q, mpz_ptr r, mpz_ptr z, int32_t s); -int mpz_tdiv_q(mpz_ptr q, mpz_ptr z, mpz_ptr d); -int mpz_tdiv_q_ui(mpz_ptr q, mpz_ptr z, u_int32_t u); -int mpz_tdiv_q_si(mpz_ptr q, mpz_ptr z, int32_t s); -int mpz_tdiv_r(mpz_ptr r, mpz_ptr z, mpz_ptr d); -int mpz_tdiv_r_ui(mpz_ptr r, mpz_ptr z, u_int32_t u); -int mpz_tdiv_r_si(mpz_ptr r, mpz_ptr z, int32_t s); -int mpz_mod(mpz_ptr r, mpz_ptr z, mpz_ptr m); +int mpz_tdiv_qr(mpz_ptr q, mpz_ptr r, mpz_ptr z, mpz_ptr d); +int mpz_tdiv_qr_ui(mpz_ptr q, mpz_ptr r, mpz_ptr z, u_int32_t u); +int mpz_tdiv_qr_si(mpz_ptr q, mpz_ptr r, mpz_ptr z, int32_t s); +int mpz_tdiv_q(mpz_ptr q, mpz_ptr z, mpz_ptr d); +int mpz_tdiv_q_ui(mpz_ptr q, mpz_ptr z, u_int32_t u); +int mpz_tdiv_q_si(mpz_ptr q, mpz_ptr z, int32_t s); +int mpz_tdiv_r(mpz_ptr r, mpz_ptr z, mpz_ptr d); +int mpz_tdiv_r_ui(mpz_ptr r, mpz_ptr z, u_int32_t u); +int mpz_tdiv_r_si(mpz_ptr r, mpz_ptr z, int32_t s); +int mpz_mod(mpz_ptr r, mpz_ptr z, mpz_ptr m); /* root extraction */ -int mpz_sqrt(mpz_ptr r, mpz_ptr z); +int mpz_sqrt(mpz_ptr r, mpz_ptr z); /* assignment */ -int mpz_setzero(mpz_ptr z); -int mpz_set(mpz_ptr d, mpz_ptr s); -int mpz_set_ui(mpz_ptr z, u_int32_t u); -int mpz_set_si(mpz_ptr z, int32_t s); -int mpz_abs(mpz_ptr d, mpz_ptr s); -int mpz_neg(mpz_ptr d, mpz_ptr s); +int mpz_setzero(mpz_ptr z); +int mpz_set(mpz_ptr d, mpz_ptr s); +int mpz_set_ui(mpz_ptr z, u_int32_t u); +int mpz_set_si(mpz_ptr z, int32_t s); +int mpz_abs(mpz_ptr d, mpz_ptr s); +int mpz_neg(mpz_ptr d, mpz_ptr s); /* bit operations */ u_int32_t mpz_bits(mpz_ptr z); -int mpz_setbit(mpz_ptr z, u_int32_t i); -int mpz_clrbit(mpz_ptr z, u_int32_t i); -int mpz_testbit(mpz_ptr z, u_int32_t i); +int mpz_setbit(mpz_ptr z, u_int32_t i); +int mpz_clrbit(mpz_ptr z, u_int32_t i); +int mpz_testbit(mpz_ptr z, u_int32_t i); /* number theoretic functions */ -int mpz_gcd(mpz_ptr g, mpz_ptr a, mpz_ptr b); +int mpz_gcd(mpz_ptr g, mpz_ptr a, mpz_ptr b); u_int32_t mpz_gcd_ui(mpz_ptr g, mpz_ptr a, u_int32_t b); /* to/from mpz conversions */ size_t mpz_sizeinbase(mpz_ptr z, u_int32_t b); -char *mpz_get_str(char *str, int b, mpz_ptr z); -int mpz_set_str(mpz_ptr z, char *s, int b); -double mpz_get_d(mpz_ptr z); -int mpz_set_d(mpz_ptr z, double d); -int mpz_set_si64(mpz_ptr z, int64_t s); -int mpz_set_ui64(mpz_ptr z, u_int64_t u); +char *mpz_get_str(char *str, int b, mpz_ptr z); +int mpz_set_str(mpz_ptr z, char *s, int b); +double mpz_get_d(mpz_ptr z); +int mpz_set_d(mpz_ptr z, double d); +int mpz_set_si64(mpz_ptr z, int64_t s); +int mpz_set_ui64(mpz_ptr z, u_int64_t u); /* random numbers */ u_int32_t sbn_rand(void); -void sbn_seed(void *seed, size_t len); -int mpz_random(mpz_ptr z, int32_t len); +void sbn_seed(void *seed, size_t len); +int mpz_random(mpz_ptr z, int32_t len); #endif /* _SBIGNUM_H */ diff --git a/src/scan.c b/src/scan.c new file mode 100644 index 0000000..d3674d5 --- /dev/null +++ b/src/scan.c @@ -0,0 +1,552 @@ +/* Scanner mode for hping2 + * Copyright(C) 2003 Salvatore Sanfilippo + * All rights reserved */ + +/* TODO: + * an application-level aware UDP scanner. + * add ICMP handling in replies. + * The algorithm is far from be optimal, also there isn't a clear + * way to delay smaller amounts of time then usleep(1) without + * to use a dummy loop. + * */ + +/* $Id: scan.c,v 1.3 2003/10/22 10:41:00 antirez Exp $ */ + +#include +#include +#include +#include +#if 0 +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#if 0 +#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) +/* union semun is defined by including */ +#else +/* according to X/OPEN we have to define it ourselves */ +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ + unsigned short int *array; /* array for GETALL, SETALL */ + struct seminfo *__buf; /* buffer for IPC_INFO */ +}; +#endif +#endif + +#include "hping2.h" +#include "globals.h" +#include "hstring.h" + +#define SEM_MODE 0777 +#define MAXPORT 65535 + +int opt_scan_probes = 8; +float avrgms = 0; +int avrgcount = 0; + +/* ---------------------------- data structures ----------------------------- */ + +/* Note that while we don't use any kind of locking, to access + * this fields is safe. the 'retry' field is only accessed by the + * sendinf half, while the 'active' field is set by the receiver + * and tested by the sender so atomicity isn't an issue. */ +struct portinfo { + int active; + int retry; + time_t sentms; /* Upss... added this that requires locking, FIXME */ +}; + +/* ------------------------- shared memory related -------------------------- */ + +static int id; /* shared memory id */ + +static int shm_creat(int size) +{ + id = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777); + if (id == -1) + { + perror("[shm_creat] shmget"); + return -1; /* on error -1 */ + } + return id; /* on success > 0 */ +} + +static void *shm_attach(void) +{ + void *shared; + + shared = shmat(id, 0, 0); + if (shared == (void*) -1) + { + perror("[shm_attach] shmat"); + return NULL; /* on error NULL */ + } + return shared; /* on success the address */ +} + +static int shm_rm(void) +{ + struct shmid_ds shmemds; + + return shmctl(id, IPC_RMID, &shmemds); +} + +static int shm_detach(void *addr) +{ + return shmdt(addr); +} + +static void *shm_init(int size) +{ + if (shm_creat(size) == -1) + return NULL; + return shm_attach(); +} + +static void shm_close(void *addr) +{ + shm_detach(addr); + shm_rm(); +} + +/* ------------------------------ locking ---------------------------------- */ + +/* Note that a mutex can't be used with shared memory (on Linux), the only left + * option is a semaphore, but I tried to protect the critical code + * using the functions above: the scanner becomes too slow. For now + * it's better to have nothing at all, for the future we need something + * like a spinlock. (btw, note that the code should be safe on x86) */ + +/* I left this code here, just in the case it will be useful for testing */ +#if 0 +static int sem_init(void) +{ + int semid, sem_key; + + if ((sem_key = ftok("/tmp/hpingscansem", 1)) == -1) { + perror("ftok"); + exit(1); + } + + /* Semi-safe semaphore initialization from R.Stevens */ + + /* Try to create the semaphore with EXCL */ + if ((semid = semget(sem_key, 1, IPC_CREAT|IPC_EXCL|SEM_MODE)) != -1) { + /* success, we need to initialize it */ + union semun arg; + + arg.val = 1; + if (semctl(semid, 0, SETVAL, arg) == -1) { + perror("semctl"); + exit(1); + } + } else if (errno == EEXIST) { + if ((semid = semget(sem_key, 1, SEM_MODE)) == -1) { + perror("semget"); + exit(1); + } + } else { + perror("semget"); + exit(1); + } + return semid; +} + +static int ports_lock(int semid) +{ + struct sembuf op[1]; + + op[0].sem_num = 0; + op[0].sem_op = -1; + op[0].sem_flg = SEM_UNDO; + return semop(semid, op, 1); +} + +static int ports_unlock(int semid) +{ + struct sembuf op[1]; + + op[0].sem_num = 0; + op[0].sem_op = +1; + op[0].sem_flg = SEM_UNDO; + return semop(semid, op, 1); +} +#endif + +/* -------------------------------- misc ----------------------------------- */ +static char *tcp_strflags(char *s, unsigned int flags) +{ + char *ftab = "FSRPAYXY", *p = s; + int bit = 0; + + memset(s, '.', 8); + s[8] = '\0'; + while(bit < 8) { + if (flags & (1 << bit)) + p[bit] = ftab[bit]; + bit++; + } + return s; +} + +static char *port_to_name(int port) +{ + struct servent *se; + + se = getservbyport(htons(port), NULL); + if (!se) + return ""; + else + return se->s_name; +} + +/* ----------------------------- ports parsing ------------------------------ */ +static int parse_ports(struct portinfo *pi, char *ports) +{ + char *args[32], *p = strdup(ports); + int argc, j, i; + + if (!p) { + fprintf(stderr, "Out of memory"); + return 1; + } + argc = strftok(",", ports, args, 32); + for (j = 0; j < argc; j++) { + int neg = 0; + char *a = args[j]; + + /* ports negation */ + if (a[0] == '!') { + neg = 1; + a++; + } + /* range */ + if (strchr(a, '-')) { + char *range[2]; + int low, high; + + strftok("-", a, range, 2); + if (!strisnum(range[0]) || !strisnum(range[1])) + goto err; /* syntax error */ + low = strtol(range[0], NULL, 0); + high = strtol(range[1], NULL, 0); + if (low > high) { + int t; + t = high; + high = low; + low = t; + } + for (i = low; i <= high; i++) + pi[i].active = !neg; + /* all the ports */ + } else if (!strcmp(a, "all")) { + for (i = 0; i <= MAXPORT; i++) + pi[i].active = !neg; + /* /etc/services ports */ + } else if (!strcmp(a, "known")) { + struct servent *se; + setservent(0); + while((se = getservent()) != NULL) { + int port = ntohs(se->s_port); + if (port < 0 || port > MAXPORT) + continue; + pi[port].active = !neg; + } + /* a single port */ + } else { + int port; + if (!strisnum(a)) + goto err; /* syntax error */ + port = strtol(a, NULL, 0); + if (port < 0 || port > MAXPORT) + goto err; /* syntax error */ + pi[port].active = !neg; + } + } + free(p); + return 0; +err: + free(p); + return 1; +} + +/* -------------------------------- output ---------------------------------- */ +static void sender(struct portinfo *pi) +{ + int i, retry = 0; + time_t start_time; + + start_time = get_midnight_ut_ms(); + + while(1) { + int active = 0; + int recvd = 0; + retry ++; + for (i = 0; i < MAXPORT; i++) { + if (pi[i].active && pi[i].retry) { + active++; + pi[i].retry--; + sequence = -1; + dst_port = i; + pi[i].sentms = get_midnight_ut_ms(); + send_tcp(); + if (opt_waitinusec) { + if (usec_delay.it_interval.tv_usec) + usleep(usec_delay.it_interval.tv_usec); + } else { + sleep(sending_wait); + } + } + } + avrgms = (float) pi[MAXPORT+1].active; + if (retry >= 3) { + if (opt_debug) + printf("AVRGMS %f\n", avrgms); + if (avrgms) + usleep((int) (avrgms*1000)); + else + sleep(1); + } + for (i = 0; i < MAXPORT; i++) { + if (!pi[i].active && pi[i].retry) + recvd++; + } + /* More to scan? */ + if (!active) { + if (!recvd) + sleep(1); + fprintf(stderr, "All replies received. Done.\n"); + printf("Not responding ports: "); + for (i = 0; i < MAXPORT; i++) { + if (pi[i].active && !pi[i].retry) + printf("(%d %.11s) ", i, port_to_name(i)); + } + printf("\n"); + exit(0); + } + /* Are we sending too fast? */ + if ((!recvd && opt_waitinusec && + usec_delay.it_interval.tv_usec == 0 && + (get_midnight_ut_ms() - start_time) > 500) || + (opt_scan_probes-retry) <= 2) + { + if (opt_debug) + printf("SLOWING DONW\n"); + usec_delay.it_interval.tv_usec *= 10; + usec_delay.it_interval.tv_usec ++; + } + } +} + +/* -------------------------------- input ---------------------------------- */ +static void receiver(struct portinfo *pi, int childpid) +{ + struct myiphdr ip; + char packet[IP_MAX_SIZE+linkhdr_size]; + + while(1) + { + int len, iplen; + + len = read_packet(packet, IP_MAX_SIZE+linkhdr_size); + if (len == -1) { + perror("read_packet"); + continue; + } + /* minimal sanity checks */ + if (len < linkhdr_size) + continue; + iplen = len - linkhdr_size; + if (iplen < sizeof(struct myiphdr)) + continue; + /* copy the ip header in an access-safe place */ + memcpy(&ip, packet+linkhdr_size, sizeof(ip)); + /* check if the dest IP matches */ + if (memcmp(&ip.daddr, &local.sin_addr, sizeof(ip.daddr))) + continue; + /* check if the source IP matches */ + if (ip.protocol != IPPROTO_ICMP && + memcmp(&ip.saddr, &remote.sin_addr, sizeof(ip.saddr))) + continue; + if (ip.protocol == IPPROTO_TCP) { + struct mytcphdr tcp; + int iphdrlen = ip.ihl << 2; + char flags[16]; + time_t rttms; + int sport; + + /* more sanity checks */ + if ((iplen - iphdrlen) < sizeof(tcp)) + continue; + /* time to copy the TCP header in a safe place */ + memcpy(&tcp, packet+linkhdr_size+iphdrlen, sizeof(tcp)); + + /* check if the TCP dest port matches */ +#if 0 + printf("SRC: %d DST: %d\n", + ntohs(tcp.th_sport), + ntohs(tcp.th_dport)); +#endif + if (ntohs(tcp.th_dport) != initsport) + continue; + sport = htons(tcp.th_sport); + if (pi[sport].active == 0) + continue; + + + /* Note that we don't care about a wrote RTT + * result due to resend on the same port. */ + rttms = get_midnight_ut_ms() - pi[sport].sentms; + + avrgcount++; + avrgms = (avrgms*(avrgcount-1)/avrgcount)+(rttms/avrgcount); + /* The avrg RTT is shared using shared memory, + * no locking... */ + pi[MAXPORT+1].active = (int) avrgms; + + tcp_strflags(flags, tcp.th_flags); +#if 0 + printf("%5d: %s %3d %5d %5d %10ld (%2d)\n", + sport, + flags, + ip.ttl, + ip.id, + ntohs(tcp.th_win), + (long) rttms, + opt_scan_probes-(pi[sport].retry)); +#endif + if ((tcp.th_flags & TH_SYN) || opt_verbose) { + printf("%5d %-11.11s: %s %3d %5d %5d %5d\n", + sport, + port_to_name(sport), + flags, + ip.ttl, + ip.id, + ntohs(tcp.th_win), + iplen); + fflush(stdout); + } + pi[sport].active = 0; + } else if (ip.protocol == IPPROTO_ICMP) { + struct myicmphdr icmp; + struct myiphdr subip; + struct mytcphdr subtcp; + int iphdrlen = ip.ihl << 2; + unsigned char *p; + int port; + struct in_addr gwaddr; + + /* more sanity checks, we are only interested + * in ICMP quoting the original packet. */ + if ((iplen - iphdrlen) < sizeof(icmp)+sizeof(subip)+sizeof(subtcp)) + continue; + /* time to copy headers in a safe place */ + p = (unsigned char*) packet+linkhdr_size+iphdrlen; + memcpy(&icmp, p, sizeof(icmp)); + p += sizeof(icmp); + memcpy(&subip, p, sizeof(ip)); + p += sizeof(ip); + memcpy(&subtcp, p, sizeof(subtcp)); + + /* Check if the ICMP quoted packet matches */ + /* check if the source IP matches */ + if (memcmp(&subip.saddr, &local.sin_addr, sizeof(subip.saddr))) + continue; + /* check if the destination IP matches */ + if (memcmp(&subip.daddr, &remote.sin_addr, sizeof(subip.daddr))) + continue; + /* check if the quoted TCP packet port matches */ + if (ntohs(subtcp.th_sport) != initsport) + continue; + port = htons(subtcp.th_dport); + if (pi[port].active == 0) + continue; + pi[port].active = 0; + memcpy(&gwaddr.s_addr, &ip.saddr, 4); + printf("%5d: %3d %5d %5d (ICMP %3d %3d from %s)\n", + port, + ip.ttl, + iplen, + ntohs(ip.id), + icmp.type, + icmp.code, + inet_ntoa(gwaddr)); + } + } +} + +/* ---------------------------------- main ---------------------------------- */ +static void do_exit(int sid) +{ + exit(0); +} + +void scanmain(void) +{ + struct portinfo *pi; + int ports = 0, i; + int childpid; + + pi = shm_init(sizeof(*pi)*(MAXPORT+2)); + pi[MAXPORT+1].active = 0; /* hold the average RTT */ + if (pi == NULL) { + fprintf(stderr, "Unable to create the shared memory"); + shm_close(pi); + exit(1); + } + for (i = 0; i <= MAXPORT; i++) { + pi[i].active = 0; + pi[i].retry = opt_scan_probes; + } + if (parse_ports(pi, opt_scanports)) { + fprintf(stderr, "Ports syntax error for scan mode\n"); + shm_close(pi); + exit(1); + } + for (i = 0; i <= MAXPORT; i++) { + if (!pi[i].active) + pi[i].retry = 0; + } + for (i = 0; i <= MAXPORT; i++) + ports += pi[i].active; + fprintf(stderr, "%d ports to scan, use -V to see all the replies\n", ports); + fprintf(stderr, "+----+-----------+---------+---+-----+-----+-----+\n"); + fprintf(stderr, "|port| serv name | flags |ttl| id | win | len |\n"); + fprintf(stderr, "+----+-----------+---------+---+-----+-----+-----+\n"); + + /* We are ready to fork, the input and output parts + * are separated processes */ + if ((childpid = fork()) == -1) { + perror("fork"); + shm_close(pi); + exit(1); + } + /* The parent is the receiver, the child the sender. + * it's almost the same but this way is simpler + * to make it working in pipe with other commands like grep. */ + if (childpid) { /* parent */ + Signal(SIGCHLD, do_exit); + Signal(SIGINT, do_exit); + Signal(SIGTERM, do_exit); + receiver(pi, childpid); + } else { /* child */ + Signal(SIGINT, do_exit); + Signal(SIGTERM, do_exit); + sender(pi); + } + /* UNREACHED */ +} diff --git a/src/script.c b/src/script.c new file mode 100644 index 0000000..27b9646 --- /dev/null +++ b/src/script.c @@ -0,0 +1,1382 @@ +/* Hping's TCL scripting support + * Copyright (C) 2003 Salvatore Sanfilippo + * All Rights Reserved */ + +/* URGENT TODO: + * + * link header size in recv_handlers, -1 means autodetection. */ + +/* $Id: script.c,v 1.20 2004/05/29 06:48:13 antirez Exp $ */ + +#ifdef USE_TCL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#if (!defined OSTYPE_LINUX) && (!defined __sun__) + #include +#endif +#include + +#include "release.h" +#include "hping2.h" +#include "ars.h" +#include "interface.h" +#include "apdutils.h" +#include "sbignum.h" + +#define HPING_IF_MAX 8 + +/* ----------------------- hping recv handlers code ------------------------- */ +struct recv_handler { + Tcl_Interp *rh_interp; /* If not null has [hpingevent] handler. */ + Tcl_Obj *rh_handlerscript; /* the [hpingevent] handler script. */ + char rh_ifname[HPING_IFNAME_LEN]; + int rh_linkhdrsize; /* -1 means autodetection */ + pcap_t *rh_pcapfp; + char rh_pcap_errbuf[PCAP_ERRBUF_SIZE]; +}; + +struct recv_handler recv_handlers[HPING_IFACE_MAX]; + +static void hping_panic(const char *msg) { + fprintf(stderr, "PANIC: %s\n", msg); + exit(1); +} + +/* Recv handlers intialization */ +static void HpingRecvInit(struct recv_handler *ra, int len) +{ + memset(ra, 0, sizeof(*ra)*len); +} + +static void HpingRecvCloseHandler(struct recv_handler *ra) +{ + ra->rh_ifname[0] = '\0'; + if (ra->rh_interp != NULL) { + Tcl_DeleteFileHandler(pcap_fileno(ra->rh_pcapfp)); + Tcl_DecrRefCount(ra->rh_handlerscript); + } + pcap_close(ra->rh_pcapfp); + ra->rh_interp = NULL; +} + +static struct recv_handler *HpingRecvGetHandler(struct recv_handler *ra, int len, char *ifname, Tcl_Interp *interp) +{ + int i; + #if (!defined OSTYPE_LINUX) && (!defined __sun__) + int on = 1; + #endif + + for (i = 0; i < len; i++) { + if (!ra[i].rh_ifname[0]) + break; + if (!strcmp(ra[i].rh_ifname, ifname)) + return ra+i; + } + /* Not found, need to open it */ + if (i == len) { + /* XXX: with hping setfilter this is broken */ + /* All the slots are full, make space at the end */ + HpingRecvCloseHandler(ra+(len-1)); + i--; + } + /* Open a new handler */ + ra[i].rh_pcapfp = pcap_open_live(ifname, 99999, 0, 1, ra[i].rh_pcap_errbuf); + if (ra[i].rh_pcapfp == NULL) + return NULL; + #if (!defined OSTYPE_LINUX) && (!defined __sun__) + /* Return the packets to userspace as fast as possible */ + if (ioctl(pcap_fileno(ra[i].rh_pcapfp), BIOCIMMEDIATE, &on) == -1) { + /* XXX non-critical error */ + } + #endif + strlcpy(ra[i].rh_ifname, ifname, HPING_IFNAME_LEN); + ra[i].rh_interp = NULL; + ra[i].rh_linkhdrsize = dltype_to_lhs(pcap_datalink(ra[i].rh_pcapfp)); + return ra+i; +} + +/* ----------------------------- Sub commands ------------------------------- */ +/* hping resolve hostname */ +static int HpingResolveCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct sockaddr_in saddr; + char *hostname; + Tcl_Obj *result; + + result = Tcl_GetObjResult(interp); + if (objc != 3 && objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "?-ptr? hostname"); + return TCL_ERROR; + } + if (objc == 4) { + char *ptropt, *ipaddr; + struct in_addr ina; + struct hostent *he; + + ptropt = Tcl_GetStringFromObj(objv[2], NULL); + if (strcmp(ptropt, "-ptr")) { + Tcl_SetStringObj(result, "The only valid option for resolve is -ptr", -1); + return TCL_ERROR; + } + ipaddr = Tcl_GetStringFromObj(objv[3], NULL); + if (inet_pton(AF_INET, ipaddr, &ina) == 0) { + Tcl_SetStringObj(result, "Invalid IP address: ", -1); + Tcl_AppendStringsToObj(result, ipaddr, NULL); + return TCL_ERROR; + } + he = gethostbyaddr((const char*)&ina.s_addr, sizeof(ina.s_addr), AF_INET); + if (he == NULL) + Tcl_SetStringObj(result, ipaddr, -1); + else + Tcl_SetStringObj(result, he->h_name, -1); + return TCL_OK; + } + hostname = Tcl_GetStringFromObj(objv[2], NULL); + if (resolve_addr((struct sockaddr*)&saddr, hostname) != -1) { + Tcl_SetStringObj(result, inet_ntoa(saddr.sin_addr), -1); + return TCL_OK; + } else { + Tcl_SetStringObj(result, "Unable to resolve: ", -1); + Tcl_AppendStringsToObj(result, hostname, NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +/* raw socket is shared between different functions, but note + * that it gets open only once needed. This makes possible + * to run hping scripts doing unprivileged work without root + * access. */ +static int rawsocket = -1; + +/* hping send ?-nocompile? pktdescr */ +static int HpingSendCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct ars_packet p; + int nocompile = 0; + Tcl_Obj *result; + char *packetdescr, *noc; + + if (objc != 3 && objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "?-nocompile? packet"); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + if (objc == 4) { + noc = Tcl_GetStringFromObj(objv[2], NULL); + if (strcmp(noc, "-nocompile")) { + Tcl_SetStringObj(result, "Invalid option", -1); + return TCL_ERROR; + } + nocompile = 1; + objv++; + } + ars_init(&p); + packetdescr = Tcl_GetStringFromObj(objv[2], NULL); + if (rawsocket == -1) { + rawsocket = ars_open_rawsocket(&p); + if (rawsocket == -ARS_ERROR) { + Tcl_SetStringObj(result, "Error opening raw socket: ", -1); + Tcl_AppendStringsToObj(result, strerror(errno), NULL); + ars_destroy(&p); + return TCL_ERROR; + } + } + if (ars_d_build(&p, packetdescr) != -ARS_OK) { + Tcl_SetStringObj(result, "Packet building error: '", -1); + Tcl_AppendStringsToObj(result, p.p_error,"' in packet ", packetdescr, NULL); + ars_destroy(&p); + return TCL_ERROR; + } + if (!nocompile) { + if (ars_compile(&p) != -ARS_OK) { + Tcl_SetStringObj(result, "Packet compilation error: ", -1); + Tcl_AppendStringsToObj(result, p.p_error, NULL); + ars_destroy(&p); + return TCL_ERROR; + } + } + if (ars_send(rawsocket, &p, NULL, 0) != -ARS_OK) { + Tcl_SetStringObj(result, "Sending packet: ", -1); + Tcl_AppendStringsToObj(result, strerror(errno), NULL); + ars_destroy(&p); + return TCL_ERROR; + } + ars_destroy(&p); + return TCL_OK; +} + +/* hping sendraw pktdata */ +static int HpingSendRawCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + int error; + Tcl_Obj *result; + struct sockaddr_in sa; + char *pkt; +#if TCL_MAJOR_VERSION == 8 + int pktlen; +#else + long pktlen; +#endif + struct ars_iphdr *ip; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "data"); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + /* Get packet data */ + pkt = Tcl_GetStringFromObj(objv[2], &pktlen); + /* Check if the packet is too short */ + if (pktlen < sizeof(struct ars_iphdr)) { + Tcl_SetStringObj(result, "Packet shorter than IPv4 header", -1); + return TCL_ERROR; + } + ip = (struct ars_iphdr*) pkt; + /* Get the destination IP from the packet itself */ + sa.sin_family = AF_INET; + memcpy(&sa.sin_addr.s_addr, &ip->daddr, 4); + /* Open the rawsocket if needed */ + if (rawsocket == -1) { + rawsocket = ars_open_rawsocket(NULL); + if (rawsocket == -ARS_ERROR) { + Tcl_SetStringObj(result, "Error opening raw socket: ", -1); + Tcl_AppendStringsToObj(result, strerror(errno), NULL); + return TCL_ERROR; + } + } + /* ready to send */ + error = sendto(rawsocket, pkt, pktlen, 0, (struct sockaddr*)&sa, sizeof(sa)); + if (error == -1) { + Tcl_SetStringObj(result, "sendto(2): ", -1); + Tcl_AppendStringsToObj(result, strerror(errno), NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +#define APD_MAX_LEN (65536*2+4096) +char *GetPacketDescription(char *data, int len, int hexdata) +{ + unsigned char *p = (unsigned char*)data; + struct ars_packet pkt; + char *d = malloc(APD_MAX_LEN); + char *ret; + + ars_init(&pkt); + if (hexdata) { + ars_set_option(&pkt, ARS_OPT_RAPD_HEXDATA); + } + if (ars_split_packet(p, len, 0, &pkt) != -ARS_OK) { + /* FIXME: handle this error properly */ + } + if (ars_d_from_ars(d, APD_MAX_LEN, &pkt) != -ARS_OK) { + /* FIXME: handle this error properly */ + } + ars_destroy(&pkt); + ret = strdup(d); + free(d); + return ret; +} + +/* Read a packet with a given timeout. + * The function returns -1 on error, non zero on a successful + * read, and 0 when no error occurred but the read must be + * reiterated (possibly before timeout expired). + * + * A zero timeout is valid, and means returns a packet if + * it is already in the buffer. A negative timeout of -1 + * means to wait forever. */ +int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *); /* pcap-int.h */ + +static int HpingReadPacket(struct recv_handler *ra, char *pkt, int pktlen, int timeout) +{ + struct timeval tv; + int retval, fd = pcap_fileno(ra->rh_pcapfp); + struct pcap_pkthdr hdr; + const unsigned char *d; + fd_set fs; + + if (timeout >= 0) { + tv.tv_sec = timeout/1000; + tv.tv_usec = (timeout%1000)*1000; + } + FD_ZERO(&fs); + FD_SET(fd, &fs); + if (timeout >= 0) + retval = select(fd+1, &fs, NULL, NULL, &tv); + else + retval = select(fd+1, &fs, NULL, NULL, NULL); + if (retval == -1) { + if (errno == EINTR) + return 0; + return -1; + } else if (retval == 0) { + return 0; + } + d = pcap_next(ra->rh_pcapfp, &hdr); + if (d == NULL) + return 0; + if (hdr.caplen > pktlen) + hdr.caplen = pktlen; + memcpy(pkt, d, hdr.caplen); + return hdr.caplen; +} + +static int HpingRecvPackets(struct recv_handler *ra, Tcl_Interp *interp, Tcl_Obj *o, int timeout, int maxpackets, int rapd, int hexdata) +{ + time_t startms = milliseconds(); + char _pkt[65535+255]; + char *pkt = _pkt; + int lhs = ra->rh_linkhdrsize; + + while(1) { + time_t elapsed; + int len; + + len = HpingReadPacket(ra, pkt, 65535+255, timeout); + if (len > 0) { + Tcl_Obj *element; + + /* Skip the link header */ + pkt += lhs; + len -= lhs; + /* Create the entry */ + if (rapd) { + char *apd; + + apd = GetPacketDescription(pkt, len, hexdata); + if (!apd) + return 1; + element = Tcl_NewStringObj(apd, -1); + free(apd); + } else { + element = Tcl_NewStringObj(pkt, len); + } + Tcl_ListObjAppendElement(interp, o, element); + /* Check if we reached the packets limit */ + if (maxpackets) { + maxpackets--; + if (maxpackets == 0) + return 0; + } + } + if (timeout == 0 && len != 0) + continue; + if (timeout >= 0) { + elapsed = milliseconds() - startms; + if (elapsed > timeout) + break; + } + } + return 0; +} + +/* hping (recv|recvraw) ifname ?timeout? ?maxpackets? + * A zero timeout means to return only packets already in queue + * A negative timeout means to wait forever + * A zero maxpackets means infinite packets limit. + * + * For default timeout is -1, maxpackets is 0 */ +static int __HpingRecvCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[], int rapd, int hexdata) +{ + Tcl_Obj *result; + struct recv_handler *ra; + char *ifname; + int timeout = -1; /* specified in ms */ + int maxpackets = 1; + + if (objc != 3 && objc != 4 && objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "ifname ?timeout? ?maxpackets?"); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + ifname = Tcl_GetStringFromObj(objv[2], NULL); + if (objc >= 4) + Tcl_GetIntFromObj(interp, objv[3], &timeout); + if (objc == 5) + Tcl_GetIntFromObj(interp, objv[4], &maxpackets); + /* FIXME: check if maxpacket == 0 AND timeout == -1. In such + * a case the function will never return. */ + ra = HpingRecvGetHandler(recv_handlers, HPING_IFACE_MAX, ifname, interp); + if (ra == NULL) { + Tcl_SetStringObj(result, "Unable to open the interface", -1); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + if (HpingRecvPackets(ra, interp, result, timeout, maxpackets, rapd, hexdata)) + return TCL_ERROR; + return TCL_OK; +} + +/* The two wrappers for the __HpingRecvRawCmd() */ +static int HpingRecvRawCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + return __HpingRecvCmd(clientData, interp, objc, objv, 0, 0); +} + +static int HpingRecvCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + char *firstarg; + int hexdata = 0; + + if (objc >= 3) { + firstarg = Tcl_GetStringFromObj(objv[2], NULL); + if (!strcmp(firstarg, "-hexdata")) { + hexdata = 1; + objc--; + objv++; + } + } + return __HpingRecvCmd(clientData, interp, objc, objv, 1, hexdata); +} + +/* hping getinterfaces */ +static int HpingGetInterfacesCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct hpingif ifaces[HPING_IFACE_MAX]; + int found, i; + Tcl_Obj *result; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + found = hping_get_interfaces(ifaces, HPING_IFACE_MAX); + if (found == -1) { + Tcl_SetStringObj(result, "Listing interfaces: ", -1); + Tcl_AppendStringsToObj(result, strerror(errno), NULL); + return TCL_ERROR; + } + for (i = 0; i < found; i++) { + struct in_addr ia; + char mtu[32]; + int j, flags = 0; + + snprintf(mtu, 32, "%d", ifaces[i].hif_mtu); + Tcl_AppendStringsToObj(result, "{", + ifaces[i].hif_name, " ", + mtu, " ", NULL); + Tcl_AppendStringsToObj(result, "{", NULL); + for (j = 0; j < ifaces[i].hif_naddr; j++) { + ia.s_addr = ifaces[i].hif_addr[j]; + Tcl_AppendStringsToObj(result, inet_ntoa(ia), NULL); + if ((j+1) < ifaces[i].hif_naddr) + Tcl_AppendStringsToObj(result, " ", NULL); + } + Tcl_AppendStringsToObj(result, "}", NULL); + if (ifaces[i].hif_broadcast) { + Tcl_AppendStringsToObj(result, " {", NULL); + for (j = 0; j < ifaces[i].hif_naddr; j++) { + ia.s_addr = ifaces[i].hif_baddr[j]; + Tcl_AppendStringsToObj(result, inet_ntoa(ia), NULL); + if ((j+1) < ifaces[i].hif_naddr) + Tcl_AppendStringsToObj(result, " ", NULL); + } + Tcl_AppendStringsToObj(result, "} {", NULL); + } else { + Tcl_AppendStringsToObj(result, " {} {", NULL); + } + if (ifaces[i].hif_loopback) { + Tcl_AppendStringsToObj(result, flags ? " " : "", "LOOPBACK", NULL); + flags++; + } + if (ifaces[i].hif_ptp) { + Tcl_AppendStringsToObj(result, flags ? " " : "", "POINTOPOINT", NULL); + flags++; + } + if (ifaces[i].hif_promisc) { + Tcl_AppendStringsToObj(result, flags ? " " : "", "PROMISC", NULL); + flags++; + } + if (ifaces[i].hif_broadcast) { + Tcl_AppendStringsToObj(result, flags ? " " : "", "BROADCAST", NULL); + flags++; + } + if (ifaces[i].hif_nolink) { + Tcl_AppendStringsToObj(result, flags ? " " : "", "NOLINK", NULL); + flags++; + } + Tcl_AppendStringsToObj(result, "}} ", NULL); + } + return TCL_OK; +} + +/* hping outifaddr destaddr */ +static int HpingGetOutIfAddrCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct sockaddr_in dest, ifaddr; + Tcl_Obj *result; + char *deststr; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "destaddr"); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + deststr = Tcl_GetStringFromObj(objv[2], NULL); + if (resolve_addr((struct sockaddr*)&dest, deststr) == -1) { + Tcl_SetStringObj(result, "Unable to resolve: ", -1); + Tcl_AppendStringsToObj(result, deststr, NULL); + return TCL_ERROR; + } + if (get_output_if(&dest, &ifaddr) == -1) { + Tcl_SetStringObj(result, "Can't get output interface: ", -1); + Tcl_AppendStringsToObj(result, strerror(errno), NULL); + return TCL_ERROR; + } + Tcl_SetStringObj(result, inet_ntoa(ifaddr.sin_addr), -1); + return TCL_OK; +} + +/* hping getfield layer field ?skip? packet */ +static int HpingGetFieldCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + char *layer, *field, *value, *packet; + int skip = 0; + Tcl_Obj *result; + + if (objc != 5 && objc != 6) { + Tcl_WrongNumArgs(interp, 2, objv, "layer field ?skip? packet"); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + layer = Tcl_GetStringFromObj(objv[2], NULL); + field = Tcl_GetStringFromObj(objv[3], NULL); + if (objc == 6) { + Tcl_GetIntFromObj(interp, objv[4], &skip); + packet = Tcl_GetStringFromObj(objv[5], NULL); + } else { + packet = Tcl_GetStringFromObj(objv[4], NULL); + } + value = ars_d_field_get(packet, layer, field, skip); + if (value) { + Tcl_SetStringObj(result, value, -1); + free(value); + } + return TCL_OK; +} + +/* hping hasfield layer field ?skip? packet */ +static int HpingHasFieldCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + char *layer, *field, *packet; + int skip = 0; + Tcl_Obj *result; + + if (objc != 5 && objc != 6) { + Tcl_WrongNumArgs(interp, 2, objv, "layer field ?skip? packet"); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + layer = Tcl_GetStringFromObj(objv[2], NULL); + field = Tcl_GetStringFromObj(objv[3], NULL); + if (objc == 6) { + Tcl_GetIntFromObj(interp, objv[4], &skip); + packet = Tcl_GetStringFromObj(objv[5], NULL); + } else { + packet = Tcl_GetStringFromObj(objv[4], NULL); + } + if (ars_d_field_off(packet, layer, field, skip, NULL, NULL, NULL)) + Tcl_SetIntObj(result, 1); + else + Tcl_SetIntObj(result, 0); + return TCL_OK; +} + +/* hping setfield layer field value ?skip? packet */ +static int HpingSetFieldCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + char *layer, *field, *packet; + int skip = 0, vstart, vend; + Tcl_Obj *result; + + if (objc != 6 && objc != 7) { + Tcl_WrongNumArgs(interp, 2, objv, "layer field value ?skip? packet"); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + layer = Tcl_GetStringFromObj(objv[2], NULL); + field = Tcl_GetStringFromObj(objv[3], NULL); + if (objc == 7) { + Tcl_GetIntFromObj(interp, objv[5], &skip); + packet = Tcl_GetStringFromObj(objv[6], NULL); + } else { + packet = Tcl_GetStringFromObj(objv[5], NULL); + } + if (!ars_d_field_off(packet, layer, field, skip, NULL, &vstart, &vend)){ + Tcl_AppendStringsToObj(result, "no such field ", layer, " ", field, NULL); + return TCL_ERROR; + } + Tcl_AppendToObj(result, packet, vstart); + Tcl_AppendObjToObj(result, objv[4]); + Tcl_AppendStringsToObj(result, packet+vend+1, NULL); + return TCL_OK; +} + +/* hping delfield layer field ?skip? packet */ +static int HpingDelFieldCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + char *layer, *field, *packet; + int skip = 0, fstart, vend; + Tcl_Obj *result; + + if (objc != 5 && objc != 6) { + Tcl_WrongNumArgs(interp, 2, objv, "layer field ?skip? packet"); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + layer = Tcl_GetStringFromObj(objv[2], NULL); + field = Tcl_GetStringFromObj(objv[3], NULL); + if (objc == 6) { + Tcl_GetIntFromObj(interp, objv[4], &skip); + packet = Tcl_GetStringFromObj(objv[5], NULL); + } else { + packet = Tcl_GetStringFromObj(objv[4], NULL); + } + if (!ars_d_field_off(packet, layer, field, skip, &fstart, NULL, &vend)){ + if (objc == 6) + Tcl_AppendObjToObj(result, objv[5]); + else + Tcl_AppendObjToObj(result, objv[4]); + return TCL_OK; + } + if (packet[fstart-1] == ',' && + (packet[vend+1] == ')' || packet[vend+1] == ',')) { + fstart--; + } + Tcl_AppendToObj(result, packet, fstart); + if (packet[fstart-1] == '(' && packet[vend+1] == ',') + packet++; + Tcl_AppendStringsToObj(result, packet+vend+1, NULL); + return TCL_OK; +} + +/* hping checksum string */ +static int HpingChecksumCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + Tcl_Obj *result; + u_int16_t cksum; + char *data; +#if TCL_MAJOR_VERSION == 8 + int len; +#else + long len; +#endif + + result = Tcl_GetObjResult(interp); + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "string"); + return TCL_ERROR; + } + data = Tcl_GetStringFromObj(objv[2], &len); + cksum = ars_cksum(data, len); + Tcl_SetIntObj(result, cksum); + return TCL_OK; +} + +/* hping setfilter ifname filter */ +static int HpingSetFilterCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct recv_handler *ra; + struct bpf_program bpfp; + char *ifname, *filter; + Tcl_Obj *result; + + result = Tcl_GetObjResult(interp); + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "ifname filter"); + return TCL_ERROR; + } + ifname = Tcl_GetStringFromObj(objv[2], NULL); + filter = Tcl_GetStringFromObj(objv[3], NULL); + /* Get the interface pcap handler */ + ra = HpingRecvGetHandler(recv_handlers, HPING_IFACE_MAX, ifname, interp); + if (ra == NULL) { + Tcl_SetStringObj(result, "Unable to open the interface setting the pcap filter", -1); + return TCL_ERROR; + } + /* Compile and set the filter */ + if (pcap_compile(ra->rh_pcapfp, &bpfp, filter, 0, 0) == -1) { + Tcl_AppendStringsToObj(result, "Error compiling the pcap filter: '", pcap_geterr(ra->rh_pcapfp), "'", NULL); + return TCL_ERROR; + } + if (pcap_setfilter(ra->rh_pcapfp, &bpfp) == -1) { + Tcl_AppendStringsToObj(result, "Error setting the pcap filter: '", pcap_geterr(ra->rh_pcapfp), "'", NULL); + pcap_freecode(&bpfp); + return TCL_ERROR; + } + pcap_freecode(&bpfp); + return TCL_OK; +} + +/* event handler for the [hping event] command. */ +void HpingEventHandler(void *clientData, int mask) +{ + struct recv_handler *ra = clientData; + + if (Tcl_EvalObjEx(ra->rh_interp, ra->rh_handlerscript, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT) != TCL_OK) { + Tcl_BackgroundError(ra->rh_interp); + } +} + +/* hping event ifname ?script? */ +static int HpingEventCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct recv_handler *ra; + char *ifname; + Tcl_Obj *result; +#if TCL_MAJOR_VERSION == 8 + int scriptlen; +#else + long scriptlen; +#endif + + result = Tcl_GetObjResult(interp); + if (objc != 3 && objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "ifname ?script?"); + return TCL_ERROR; + } + ifname = Tcl_GetStringFromObj(objv[2], NULL); + /* Get the interface pcap handler */ + ra = HpingRecvGetHandler(recv_handlers, HPING_IFACE_MAX, ifname, interp); + if (ra == NULL) { + Tcl_SetStringObj(result, "Unable to open the interface setting the pcap filter", -1); + return TCL_ERROR; + } + /* If the script argument is missing, return the script + * currently set if any */ + if(objc == 3) { + if(ra->rh_interp != NULL) + Tcl_SetObjResult(interp, ra->rh_handlerscript); + return TCL_OK; + } + /* Set the script in the target interface */ + if (ra->rh_interp != NULL) + Tcl_DecrRefCount(ra->rh_handlerscript); + /* CHeck if the script is empty, if so clear the handler */ + Tcl_GetStringFromObj(objv[3], &scriptlen); + if (scriptlen != 0) { + ra->rh_handlerscript = objv[3]; + Tcl_IncrRefCount(objv[3]); + ra->rh_interp = interp; + /* Register the handler for this file descriptor */ + Tcl_CreateFileHandler(pcap_fileno(ra->rh_pcapfp), TCL_READABLE, + HpingEventHandler, (void*)ra); + } else { + ra->rh_interp = NULL; + } + return TCL_OK; +} + +/* --------------------------------- Misc ----------------------------------- */ +#if 0 +/* hping setfilter ifname filter */ +static int HpingSoftrealtimeCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + struct sched_param sp; + int min, max, virtual_priority; + struct Tcl_Obj *result; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "priority (in the range 0-99)"); + return TCL_ERROR; + } + result = Tcl_GetObjResult(interp); + Tcl_GetIntFromObj(interp, objv[2], &virtual_priority); + if (virtual_priority < 0 || virtual_priority > 99) { + Tcl_SetStringObj(result, "priority must be in the range 0-99", -1); + return TCL_ERROR; + } + min = sched_get_priority_min(SCHED_RR); + max = sched_get_priority_max(SCHED_RR); + /* Map the virutal priority to the range supported in this OS */ + { + float vmul = (max-min)+1; + vmul /= 100; + sp.sched_priority = min + (int)(virtual_priority*vmul); + } + /* sched_setscheduler() may fail, but we just ignore the error */ + sched_setscheduler(0, SCHED_RR, &sp); + return TCL_OK; +} +#endif + +/* ---------------------- hping command implementation ---------------------- */ +struct subcmd { + char *name; + int (*proc)(ClientData cd, Tcl_Interp *i, int, Tcl_Obj *const objv[]); +} subcmds[] = { + { "resolve", HpingResolveCmd }, + { "send", HpingSendCmd }, + { "sendraw", HpingSendRawCmd }, + { "recv", HpingRecvCmd }, + { "recvraw", HpingRecvRawCmd }, + { "setfilter", HpingSetFilterCmd }, + { "iflist", HpingGetInterfacesCmd }, + { "outifa", HpingGetOutIfAddrCmd }, + { "getfield", HpingGetFieldCmd }, + { "hasfield", HpingHasFieldCmd }, + { "setfield", HpingSetFieldCmd }, + { "delfield", HpingDelFieldCmd }, + { "checksum", HpingChecksumCmd }, + { "event", HpingEventCmd }, +#if 0 + { "softrealtime", HpingSoftrealtimeCmd }, +#endif + { NULL, NULL }, +}; + +static int HpingObjCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + int i = 0; + char *scmd; + Tcl_Obj *result; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); + return TCL_ERROR; + } + + scmd = Tcl_GetStringFromObj(objv[1], NULL); + while(subcmds[i].name) { + if (!strcmp(scmd, subcmds[i].name)) + return subcmds[i].proc(clientData, interp, objc, objv); + i++; + } + result = Tcl_GetObjResult(interp); + Tcl_SetStringObj(result, "Bad option ", -1); + Tcl_AppendStringsToObj(result, "\"", scmd, "\"", " must be: ", NULL); + i = 0; + while(subcmds[i].name) { + Tcl_AppendStringsToObj(result, subcmds[i].name, NULL); + if (subcmds[i+1].name) + Tcl_AppendStringsToObj(result, ", ", NULL); + i++; + } + return TCL_ERROR; +} + +/* -------------------- multiprecision math commands ------------------------ */ + +#if 0 +/* XXX: actually this binding is pretty naive, we are not using + * a Tcl dual-port rappresentation for bignums, instead we convert from/to + * string rappresentation, wasting the almost decent performences + * of the sbignum library (and even worse, because to/from string conversion + * is not optimized). Btw, for now this seems enough, there will be + * time to improve on this in the future if needed, without to break the API. */ + +static int BigBasicObjCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + Tcl_Obj *result; + mpz_t res, t; + char *s = NULL, *cmd; + + cmd = Tcl_GetStringFromObj(objv[0], NULL); + objc--; + objv++; + + result = Tcl_GetObjResult(interp); + mpz_init(res); + mpz_init(t); + mpz_setzero(res); + if (cmd[0] == '*' || cmd[0] == '/') { + if (mpz_set_ui(res, 1) != SBN_OK) + goto err; + } + if ((cmd[0] == '/' || cmd[0] == '%') && objc) { + s = Tcl_GetStringFromObj(objv[0], NULL); + if (mpz_set_str(res, s, 0) != SBN_OK) + goto err; + objc--; + objv++; + } + while(objc--) { + s = Tcl_GetStringFromObj(objv[0], NULL); + if (mpz_set_str(t, s, 0) != SBN_OK) + goto err; + switch(cmd[0]) { + case '+': + if (mpz_add(res, res, t) != SBN_OK) + goto err; + break; + case '-': + if (mpz_sub(res, res, t) != SBN_OK) + goto err; + break; + case '*': + if (mpz_mul(res, res, t) != SBN_OK) + goto err; + break; + case '/': + if (mpz_tdiv_q(res, res, t) != SBN_OK) + goto err; + break; + case '%': + if (mpz_mod(res, res, t) != SBN_OK) + goto err; + break; + } + objv++; + } + if ((s = mpz_get_str(NULL, 10, res)) == NULL) + goto err; + Tcl_SetStringObj(result, s, -1); + free(s); + mpz_clear(res); + mpz_clear(t); + return TCL_OK; +err: + mpz_clear(res); + mpz_clear(t); + Tcl_AppendStringsToObj(result, "Not a valid big number: ", s, NULL); + return TCL_ERROR; +} +#endif + +/* -------------------------- Mpz object implementation --------------------- */ + +static void Tcl_SetMpzObj(Tcl_Obj *objPtr, mpz_ptr val); +//static Tcl_Obj *Tcl_NewMpzObj(void); +static void FreeMpzInternalRep(Tcl_Obj *objPtr); +static void DupMpzInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); +static void UpdateStringOfMpz(Tcl_Obj *objPtr); +static int SetMpzFromAny(struct Tcl_Interp* interp, Tcl_Obj *objPtr); + +struct Tcl_ObjType tclMpzType = { + "mpz", + FreeMpzInternalRep, + DupMpzInternalRep, + UpdateStringOfMpz, + SetMpzFromAny +}; + +/* This function set objPtr as an mpz object with value + * 'val'. If 'val' == NULL, the mpz object is set to zero. */ +void Tcl_SetMpzObj(Tcl_Obj *objPtr, mpz_ptr val) +{ + const Tcl_ObjType *typePtr; + mpz_ptr mpzPtr; + + /* It's not a good idea to set a shared object... */ + if (Tcl_IsShared(objPtr)) { + hping_panic("Tcl_SetMpzObj called with shared object"); + } + /* Free the old object private data and invalidate the string + * representation. */ + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); + } + Tcl_InvalidateStringRep(objPtr); + /* Allocate and initialize a new bignum */ + mpzPtr = (mpz_ptr) ckalloc(sizeof(struct struct_sbnz)); + mpz_init(mpzPtr); + if (val && mpz_set(mpzPtr, val) != SBN_OK) { + hping_panic("Out of memory in Tcl_SetMpzObj"); + } + /* Set it as object private data, and type */ + objPtr->typePtr = &tclMpzType; + objPtr->internalRep.otherValuePtr = (void*) mpzPtr; +} + +/* Return an mpz from the object. If the object is not of type mpz + * an attempt to convert it to mpz is done. On failure (the string + * representation of the object can't be converted on a bignum) + * an error is returned. */ +int Tcl_GetMpzFromObj(struct Tcl_Interp *interp, Tcl_Obj *objPtr, mpz_ptr *mpzPtrPtr) +{ + int result; + + if (objPtr->typePtr != &tclMpzType) { + result = SetMpzFromAny(interp, objPtr); + if (result != TCL_OK) + return result; + } + *mpzPtrPtr = (mpz_ptr) objPtr->internalRep.longValue; + return TCL_OK; +} + +/* Create a new mpz object */ +Tcl_Obj *Tcl_NewMpzObj(void) +{ + struct Tcl_Obj *objPtr; + + /* Create a new Tcl Object */ + objPtr = Tcl_NewObj(); + Tcl_SetMpzObj(objPtr, 0); + return objPtr; +} + +/* The 'free' method of the object. */ +void FreeMpzInternalRep(Tcl_Obj *objPtr) +{ + mpz_ptr mpzPtr = (mpz_ptr) objPtr->internalRep.otherValuePtr; + + mpz_clear(mpzPtr); + ckfree((void*)mpzPtr); +} + +/* The 'dup' method of the object */ +void DupMpzInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr) +{ + mpz_ptr mpzCopyPtr = (mpz_ptr) ckalloc(sizeof(struct struct_sbnz)); + mpz_ptr mpzSrcPtr; + + mpz_init(mpzCopyPtr); + mpzSrcPtr = (mpz_ptr) srcPtr->internalRep.otherValuePtr; + if (mpz_set(mpzCopyPtr, mpzSrcPtr) != SBN_OK) + hping_panic("Out of memory inside DupMpzInternalRep()"); + copyPtr->internalRep.otherValuePtr = (void*) mpzCopyPtr; + copyPtr->typePtr = &tclMpzType; +} + +/* The 'update string' method of the object */ +void UpdateStringOfMpz(Tcl_Obj *objPtr) +{ + size_t len; + mpz_ptr mpzPtr = (mpz_ptr) objPtr->internalRep.otherValuePtr; + + len = mpz_sizeinbase(mpzPtr, 10)+2; + objPtr->bytes = ckalloc(len); + mpz_get_str(objPtr->bytes, 10, mpzPtr); + /* XXX: fixme, modifing the sbignum library it is + * possible to get the length of the written string. */ + objPtr->length = strlen(objPtr->bytes); +} + +/* The 'set from any' method of the object */ +int SetMpzFromAny(struct Tcl_Interp* interp, Tcl_Obj *objPtr) +{ + char *s; + mpz_t t; + mpz_ptr mpzPtr; + const Tcl_ObjType *typePtr; + + if (objPtr->typePtr == &tclMpzType) + return TCL_OK; + + /* Try to convert */ + s = Tcl_GetStringFromObj(objPtr, NULL); + mpz_init(t); + if (mpz_set_str(t, s, 0) != SBN_OK) { + mpz_clear(t); + Tcl_ResetResult(interp); + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "Invalid big number: \"", + s, "\" must be a relative integer number", + NULL); + return TCL_ERROR; + } + /* Allocate */ + mpzPtr = (mpz_ptr) ckalloc(sizeof(struct struct_sbnz)); + mpz_init(mpzPtr); + /* Free the old object private rep */ + typePtr = objPtr->typePtr; + if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { + (*typePtr->freeIntRepProc)(objPtr); + } + /* Set it */ + objPtr->typePtr = &tclMpzType; + objPtr->internalRep.otherValuePtr = (void*) mpzPtr; + memcpy(mpzPtr, t, sizeof(*mpzPtr)); + return TCL_OK; +} + +/* --------------- the actual commands for multipreicision math ------------- */ + +static int BigBasicObjCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + Tcl_Obj *result; + mpz_t res; + mpz_ptr t; + char *cmd; + + cmd = Tcl_GetStringFromObj(objv[0], NULL); + objc--; + objv++; + + result = Tcl_GetObjResult(interp); + mpz_init(res); + mpz_setzero(res); + if (cmd[0] == '*' || cmd[0] == '/') { + if (mpz_set_ui(res, 1) != SBN_OK) + goto err; + } + if ((cmd[0] == '/' || cmd[0] == '%' || cmd[0] == '-') && objc) { + if (Tcl_GetMpzFromObj(interp, objv[0], &t) != TCL_OK) + goto err; + if (mpz_set(res, t) != SBN_OK) + goto oom; + if (cmd[0] == '-' && objc == 1) + res->s = !res->s; + objc--; + objv++; + } + while(objc--) { + if (Tcl_GetMpzFromObj(interp, objv[0], &t) != TCL_OK) + goto err; + switch(cmd[0]) { + case '+': + if (mpz_add(res, res, t) != SBN_OK) + goto oom; + break; + case '-': + if (mpz_sub(res, res, t) != SBN_OK) + goto oom; + break; + case '*': + if (mpz_mul(res, res, t) != SBN_OK) + goto oom; + break; + case '/': + if (mpz_tdiv_q(res, res, t) != SBN_OK) + goto oom; + break; + case '%': + if (mpz_mod(res, res, t) != SBN_OK) + goto oom; + break; + } + objv++; + } + Tcl_SetMpzObj(result, res); + mpz_clear(res); + return TCL_OK; +err: + mpz_clear(res); + return TCL_ERROR; +oom: + Tcl_SetStringObj(result, "Out of memory doing multiprecision math", -1); + mpz_clear(res); + return TCL_ERROR; +} + +static int BigCmpObjCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + Tcl_Obj *result; + mpz_ptr a, b; + int cmp, res; + char *cmd; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "bignum bignum"); + return TCL_ERROR; + } + + cmd = Tcl_GetStringFromObj(objv[0], NULL); + if (Tcl_GetMpzFromObj(interp, objv[1], &a) != TCL_OK || + Tcl_GetMpzFromObj(interp, objv[2], &b) != TCL_OK) + return TCL_ERROR; + cmp = mpz_cmp(a, b); + + result = Tcl_GetObjResult(interp); + res = 0; + switch(cmd[0]) { + case '>': + switch(cmd[1]) { + case '=': + if (cmp >= 0) res = 1; + break; + default: + if (cmp > 0) res = 1; + break; + } + break; + case '<': + switch(cmd[1]) { + case '=': + if (cmp <= 0) res = 1; + break; + default: + if (cmp < 0) res = 1; + break; + } + break; + case '=': + if (cmp == 0) res = 1; + break; + case '!': + if (cmp != 0) res = 1; + break; + } + Tcl_SetIntObj(result, res); + return TCL_OK; +} + +static int BigRandObjCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + Tcl_Obj *result; + int len = 1; + mpz_t r; + + if (objc != 1 && objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?atoms?"); + return TCL_ERROR; + } + if (objc == 2 && Tcl_GetIntFromObj(interp, objv[1], &len) != TCL_OK) + return TCL_ERROR; + result = Tcl_GetObjResult(interp); + mpz_init(r); + if (mpz_random(r, len) != SBN_OK) { + mpz_clear(r); + Tcl_SetStringObj(result, "Out of memory", -1); + return TCL_ERROR; + } + Tcl_SetMpzObj(result, r); + mpz_clear(r); + return TCL_OK; +} + +static int BigSrandObjCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + char *seed; +#if TCL_MAJOR_VERSION == 8 + int len; +#else + long len; +#endif + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "seed-string"); + return TCL_ERROR; + } + seed = Tcl_GetStringFromObj(objv[1], &len); + sbn_seed(seed, len); + return TCL_OK; +} + +static int BigPowObjCmd(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]) +{ + Tcl_Obj *result; + int mpzerr; + mpz_t r; /* result */ + mpz_ptr b, e, m; /* base, exponent, modulo */ + + if (objc != 3 && objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "base exponent ?modulo?"); + return TCL_ERROR; + } + if (Tcl_GetMpzFromObj(interp, objv[1], &b) != TCL_OK || + Tcl_GetMpzFromObj(interp, objv[2], &e) != TCL_OK || + (objc == 4 && Tcl_GetMpzFromObj(interp, objv[3], &m) != TCL_OK)) + return TCL_ERROR; + result = Tcl_GetObjResult(interp); + mpz_init(r); + if (objc == 4) + mpzerr = mpz_powm(r, b, e, m); + else + mpzerr = mpz_pow(r, b, e); + if (mpzerr != SBN_OK) { + mpz_clear(r); + if (mpzerr == SBN_INVAL) + Tcl_SetStringObj(result, "Negative exponent", -1); + else + Tcl_SetStringObj(result, "Out of memory", -1); + return TCL_ERROR; + } + Tcl_SetMpzObj(result, r); + mpz_clear(r); + return TCL_OK; +} + +/* ------------------- interpreter creation/invocation ---------------------- */ + +static int HpingTcl_AppInit(Tcl_Interp *interp) +{ + /* Initialization */ + if (Tcl_Init(interp) == TCL_ERROR) + return TCL_ERROR; + HpingRecvInit(recv_handlers, HPING_IFACE_MAX); + /* Register hping API */ + Tcl_SetVar(interp, "hping_version", RELEASE_VERSION, TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "tcl_prompt1", "puts -nonewline {hping3> }", TCL_GLOBAL_ONLY); + Tcl_CreateObjCommand(interp, "hping", HpingObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "+", BigBasicObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "-", BigBasicObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "*", BigBasicObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "/", BigBasicObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "%", BigBasicObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, ">", BigCmpObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, ">=", BigCmpObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "<", BigCmpObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "<=", BigCmpObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "==", BigCmpObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "!=", BigCmpObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "rand", BigRandObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "srand", BigSrandObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + Tcl_CreateObjCommand(interp, "**", BigPowObjCmd, (ClientData)NULL, + (Tcl_CmdDeleteProc*)NULL); + /* Eval the hpingrc, fi any */ + { + char *home = getenv("HOME"); + if (home) { + char rcfile[PATH_MAX]; + snprintf(rcfile, PATH_MAX, "%s/.hpingrc", home); + rcfile[PATH_MAX-1] = '\0'; + Tcl_EvalFile(interp, rcfile); + Tcl_ResetResult(interp); + } + } + return TCL_OK; +} + +void hping_script(int argc, char **argv) +{ + Tcl_Main(argc, argv, HpingTcl_AppInit); + exit(0); +} + +#endif /* USE_TCL */ diff --git a/src/send.c b/src/send.c new file mode 100644 index 0000000..4814cc8 --- /dev/null +++ b/src/send.c @@ -0,0 +1,94 @@ +/* + * $smu-mark$ + * $name: sendudp.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:49 MET 1999$ + * $rev: 8$ + */ + +/* $Id: send.c,v 1.1.1.1 2003/08/31 17:23:53 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hping2.h" +#include "globals.h" + +static void select_next_random_source(void) +{ + unsigned char ra[4]; + + ra[0] = hp_rand() & 0xFF; + ra[1] = hp_rand() & 0xFF; + ra[2] = hp_rand() & 0xFF; + ra[3] = hp_rand() & 0xFF; + memcpy(&local.sin_addr.s_addr, ra, 4); + + if (opt_debug) + printf("DEBUG: the source address is %u.%u.%u.%u\n", + ra[0], ra[1], ra[2], ra[3]); +} + +static void select_next_random_dest(void) +{ + unsigned char ra[4]; + char a[4], b[4], c[4], d[4]; + + if (sscanf(targetname, "%3[^.].%3[^.].%3[^.].%3[^.]", a, b, c, d) != 4) + { + fprintf(stderr, + "wrong --rand-dest target host, correct examples:\n" + " x.x.x.x, 192,168.x.x, 128.x.x.255\n" + "you typed: %s\n", targetname); + exit(1); + } + a[3] = b[3] = c[3] = d[3] = '\0'; + + ra[0] = a[0] == 'x' ? (hp_rand() & 0xFF) : strtoul(a, NULL, 0); + ra[1] = b[0] == 'x' ? (hp_rand() & 0xFF) : strtoul(b, NULL, 0); + ra[2] = c[0] == 'x' ? (hp_rand() & 0xFF) : strtoul(c, NULL, 0); + ra[3] = d[0] == 'x' ? (hp_rand() & 0xFF) : strtoul(d, NULL, 0); + memcpy(&remote.sin_addr.s_addr, ra, 4); + + if (opt_debug) { + printf("DEBUG: the dest address is %u.%u.%u.%u\n", + ra[0], ra[1], ra[2], ra[3]); + } +} + +/* The signal handler for SIGALRM will send the packets */ +void send_packet (int signal_id) +{ + int errno_save = errno; + + if (opt_rand_dest) + select_next_random_dest(); + if (opt_rand_source) + select_next_random_source(); + + if (opt_rawipmode) send_rawip(); + else if (opt_icmpmode) send_icmp(); + else if (opt_udpmode) send_udp(); + else send_tcp(); + + sent_pkt++; + Signal(SIGALRM, send_packet); + + if (count != -1 && count == sent_pkt) { /* count reached? */ + Signal(SIGALRM, print_statistics); + alarm(COUNTREACHED_TIMEOUT); + } else if (!opt_listenmode) { + if (opt_waitinusec == FALSE) + alarm(sending_wait); + else + setitimer(ITIMER_REAL, &usec_delay, NULL); + } + errno = errno_save; +} diff --git a/src/sendhcmp.c b/src/sendhcmp.c new file mode 100644 index 0000000..c327cdf --- /dev/null +++ b/src/sendhcmp.c @@ -0,0 +1,51 @@ +/* + * $smu-mark$ + * $name: sendhcmp.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:49 MET 1999$ + * $rev: 4$ + */ + +/* $Id: sendhcmp.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include +#include +#include /* SIGALARM macro */ + +#include "hping2.h" +#include "globals.h" + +#define MUST_BE_UNREACHED 0 + +void send_hcmp(__u8 type, __u32 arg) +{ + static struct hcmphdr hcmph; /* static because we export this */ + /* to data_handler() */ + + data_size = signlen + sizeof(struct hcmphdr); + + /* build hcmp header */ + memset(&hcmph, 0, sizeof(hcmph)); + hcmph.type = type; + switch (type) + { + case HCMP_RESTART: + hcmph.typedep.seqnum = htons((__u16) arg); + break; + case HCMP_SOURCE_QUENCH: + case HCMP_SOURCE_STIRUP: + hcmph.typedep.usec = htonl(arg); + break; + default: + assert(MUST_BE_UNREACHED); + } + + /* use hcmphdr_p to transmit hcmph to data_handler() */ + hcmphdr_p = &hcmph; + kill(getpid(), SIGALRM); /* send hcmp */ + + return; +} diff --git a/src/sendicmp.c b/src/sendicmp.c new file mode 100644 index 0000000..f8021fd --- /dev/null +++ b/src/sendicmp.c @@ -0,0 +1,281 @@ +/* + * $smu-mark$ + * $name: sendicmp.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:49 MET 1999$ + * $rev: 8$ + */ + +/* $Id: sendicmp.c,v 1.1.1.1 2003/08/31 17:23:53 antirez Exp $ */ + +#include /* this should be not needed, but ip_icmp.h lacks it */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hping2.h" +#include "globals.h" + +static int _icmp_seq = 0; + +void send_icmp_echo(void); +void send_icmp_other(void); +void send_icmp_timestamp(void); +void send_icmp_address(void); + +void send_icmp(void) +{ + switch(opt_icmptype) + { + case ICMP_ECHO: /* type 8 */ + case ICMP_ECHOREPLY: /* type 0 */ + send_icmp_echo(); + break; + case ICMP_DEST_UNREACH: /* type 3 */ + case ICMP_SOURCE_QUENCH: /* type 4 */ + case ICMP_REDIRECT: /* type 5 */ + case ICMP_TIME_EXCEEDED: /* type 11 */ + send_icmp_other(); + break; + case ICMP_TIMESTAMP: + case ICMP_TIMESTAMPREPLY: + send_icmp_timestamp(); + break; + case ICMP_ADDRESS: + case ICMP_ADDRESSREPLY: + send_icmp_address(); + break; + default: + if (opt_force_icmp) { + send_icmp_other(); + break; + } else { + printf("[send_icmp] Unsupported icmp type!\n"); + exit(1); + } + } +} + +void send_icmp_echo(void) +{ + char *packet, *data; + struct myicmphdr *icmp; + + packet = malloc(ICMPHDR_SIZE + data_size); + if (packet == NULL) { + perror("[send_icmp] malloc"); + return; + } + + memset(packet, 0, ICMPHDR_SIZE + data_size); + + icmp = (struct myicmphdr*) packet; + data = packet + ICMPHDR_SIZE; + + /* fill icmp hdr */ + icmp->type = opt_icmptype; /* echo replay or echo request */ + icmp->code = opt_icmpcode; /* should be indifferent */ + icmp->checksum = 0; + icmp->un.echo.id = getpid() & 0xffff; + icmp->un.echo.sequence = _icmp_seq; + + /* data */ + data_handler(data, data_size); + + /* icmp checksum */ + if (icmp_cksum == -1) + icmp->checksum = cksum((u_short*)packet, ICMPHDR_SIZE + data_size); + else + icmp->checksum = icmp_cksum; + + /* adds this pkt in delaytable */ + if (opt_icmptype == ICMP_ECHO) + delaytable_add(_icmp_seq, 0, time(NULL), get_usec(), S_SENT); + + /* send packet */ + send_ip_handler(packet, ICMPHDR_SIZE + data_size); + free (packet); + + _icmp_seq++; +} + +void send_icmp_timestamp(void) +{ + char *packet; + struct myicmphdr *icmp; + struct icmp_tstamp_data *tstamp_data; + + packet = malloc(ICMPHDR_SIZE + sizeof(struct icmp_tstamp_data)); + if (packet == NULL) { + perror("[send_icmp] malloc"); + return; + } + + memset(packet, 0, ICMPHDR_SIZE + sizeof(struct icmp_tstamp_data)); + + icmp = (struct myicmphdr*) packet; + tstamp_data = (struct icmp_tstamp_data*) (packet + ICMPHDR_SIZE); + + /* fill icmp hdr */ + icmp->type = opt_icmptype; /* echo replay or echo request */ + icmp->code = 0; + icmp->checksum = 0; + icmp->un.echo.id = getpid() & 0xffff; + icmp->un.echo.sequence = _icmp_seq; + tstamp_data->orig = htonl(get_midnight_ut_ms()); + tstamp_data->recv = tstamp_data->tran = 0; + + /* icmp checksum */ + if (icmp_cksum == -1) + icmp->checksum = cksum((u_short*)packet, ICMPHDR_SIZE + + sizeof(struct icmp_tstamp_data)); + else + icmp->checksum = icmp_cksum; + + /* adds this pkt in delaytable */ + if (opt_icmptype == ICMP_TIMESTAMP) + delaytable_add(_icmp_seq, 0, time(NULL), get_usec(), S_SENT); + + /* send packet */ + send_ip_handler(packet, ICMPHDR_SIZE + sizeof(struct icmp_tstamp_data)); + free (packet); + + _icmp_seq++; +} + +void send_icmp_address(void) +{ + char *packet; + struct myicmphdr *icmp; + + packet = malloc(ICMPHDR_SIZE + 4); + if (packet == NULL) { + perror("[send_icmp] malloc"); + return; + } + + memset(packet, 0, ICMPHDR_SIZE + 4); + + icmp = (struct myicmphdr*) packet; + + /* fill icmp hdr */ + icmp->type = opt_icmptype; /* echo replay or echo request */ + icmp->code = 0; + icmp->checksum = 0; + icmp->un.echo.id = getpid() & 0xffff; + icmp->un.echo.sequence = _icmp_seq; + memset(packet+ICMPHDR_SIZE, 0, 4); + + /* icmp checksum */ + if (icmp_cksum == -1) + icmp->checksum = cksum((u_short*)packet, ICMPHDR_SIZE + 4); + else + icmp->checksum = icmp_cksum; + + /* adds this pkt in delaytable */ + if (opt_icmptype == ICMP_TIMESTAMP) + delaytable_add(_icmp_seq, 0, time(NULL), get_usec(), S_SENT); + + /* send packet */ + send_ip_handler(packet, ICMPHDR_SIZE + 4); + free (packet); + + _icmp_seq++; +} + +void send_icmp_other(void) +{ + char *packet, *data, *ph_buf; + struct myicmphdr *icmp; + struct myiphdr icmp_ip; + struct myudphdr *icmp_udp; + int udp_data_len = 0; + struct pseudohdr *pseudoheader; + int left_space = IPHDR_SIZE + UDPHDR_SIZE + data_size; + + packet = malloc(ICMPHDR_SIZE + IPHDR_SIZE + UDPHDR_SIZE + data_size); + ph_buf = malloc(PSEUDOHDR_SIZE + UDPHDR_SIZE + udp_data_len); + if (packet == NULL || ph_buf == NULL) { + perror("[send_icmp] malloc"); + return; + } + + memset(packet, 0, ICMPHDR_SIZE + IPHDR_SIZE + UDPHDR_SIZE + data_size); + memset(ph_buf, 0, PSEUDOHDR_SIZE + UDPHDR_SIZE + udp_data_len); + + icmp = (struct myicmphdr*) packet; + data = packet + ICMPHDR_SIZE; + pseudoheader = (struct pseudohdr *) ph_buf; + icmp_udp = (struct myudphdr *) (ph_buf + PSEUDOHDR_SIZE); + + /* fill icmp hdr */ + icmp->type = opt_icmptype; /* ICMP_TIME_EXCEEDED */ + icmp->code = opt_icmpcode; /* should be 0 (TTL) or 1 (FRAGTIME) */ + icmp->checksum = 0; + if (opt_icmptype == ICMP_REDIRECT) + memcpy(&icmp->un.gateway, &icmp_gw.sin_addr.s_addr, 4); + else + icmp->un.gateway = 0; /* not used, MUST be 0 */ + + /* concerned packet headers */ + /* IP header */ + icmp_ip.version = icmp_ip_version; /* 4 */ + icmp_ip.ihl = icmp_ip_ihl; /* IPHDR_SIZE >> 2 */ + icmp_ip.tos = icmp_ip_tos; /* 0 */ + icmp_ip.tot_len = htons((icmp_ip_tot_len ? icmp_ip_tot_len : (icmp_ip_ihl<<2) + UDPHDR_SIZE + udp_data_len)); + icmp_ip.id = htons(getpid() & 0xffff); + icmp_ip.frag_off = 0; /* 0 */ + icmp_ip.ttl = 64; /* 64 */ + icmp_ip.protocol = icmp_ip_protocol; /* 6 (TCP) */ + icmp_ip.check = 0; + memcpy(&icmp_ip.saddr, &icmp_ip_src.sin_addr.s_addr, 4); + memcpy(&icmp_ip.daddr, &icmp_ip_dst.sin_addr.s_addr, 4); + icmp_ip.check = cksum((__u16 *) &icmp_ip, IPHDR_SIZE); + + /* UDP header */ + memcpy(&pseudoheader->saddr, &icmp_ip_src.sin_addr.s_addr, 4); + memcpy(&pseudoheader->daddr, &icmp_ip_dst.sin_addr.s_addr, 4); + pseudoheader->protocol = icmp_ip.protocol; + pseudoheader->lenght = icmp_ip.tot_len; + icmp_udp->uh_sport = htons(icmp_ip_srcport); + icmp_udp->uh_dport = htons(icmp_ip_dstport); + icmp_udp->uh_ulen = htons(UDPHDR_SIZE + udp_data_len); + icmp_udp->uh_sum = cksum((__u16 *) ph_buf, PSEUDOHDR_SIZE + UDPHDR_SIZE + udp_data_len); + + /* filling icmp body with concerned packet header */ + + /* fill IP */ + if (left_space == 0) goto no_space_left; + memcpy(packet+ICMPHDR_SIZE, &icmp_ip, left_space); + left_space -= IPHDR_SIZE; + data += IPHDR_SIZE; + if (left_space <= 0) goto no_space_left; + + /* fill UDP */ + memcpy(packet+ICMPHDR_SIZE+IPHDR_SIZE, icmp_udp, left_space); + left_space -= UDPHDR_SIZE; + data += UDPHDR_SIZE; + if (left_space <= 0) goto no_space_left; + + /* fill DATA */ + data_handler(data, left_space); +no_space_left: + + /* icmp checksum */ + if (icmp_cksum == -1) + icmp->checksum = cksum((u_short*)packet, ICMPHDR_SIZE + IPHDR_SIZE + UDPHDR_SIZE + data_size); + else + icmp->checksum = icmp_cksum; + + /* send packet */ + send_ip_handler(packet, ICMPHDR_SIZE + IPHDR_SIZE + UDPHDR_SIZE + data_size); + free (packet); + free (ph_buf); +} diff --git a/src/sendip.c b/src/sendip.c new file mode 100644 index 0000000..baab1eb --- /dev/null +++ b/src/sendip.c @@ -0,0 +1,127 @@ +/* + * $smu-mark$ + * $name: sendip.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:49 MET 1999$ + * $rev: 8$ + */ + +/* $Id: sendip.c,v 1.2 2004/04/09 23:38:56 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hping2.h" +#include "globals.h" + +void send_ip (char* src, char *dst, char *data, unsigned int datalen, + int more_fragments, unsigned short fragoff, char *options, + char optlen) +{ + char *packet; + int result, + packetsize; + struct myiphdr *ip; + + packetsize = IPHDR_SIZE + optlen + datalen; + if ( (packet = malloc(packetsize)) == NULL) { + perror("[send_ip] malloc()"); + return; + } + + memset(packet, 0, packetsize); + ip = (struct myiphdr*) packet; + + /* copy src and dst address */ + memcpy(&ip->saddr, src, sizeof(ip->saddr)); + memcpy(&ip->daddr, dst, sizeof(ip->daddr)); + + /* build ip header */ + ip->version = 4; + ip->ihl = (IPHDR_SIZE + optlen + 3) >> 2; + ip->tos = ip_tos; + +#if defined OSTYPE_DARWIN || defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD || defined OSTYPE_BSDI +/* FreeBSD */ +/* NetBSD */ + ip->tot_len = packetsize; +#else +/* Linux */ +/* OpenBSD */ + ip->tot_len = htons(packetsize); +#endif + + if (!opt_fragment) + { + ip->id = (src_id == -1) ? + htons((unsigned short) rand()) : + htons((unsigned short) src_id); + } + else /* if you need fragmentation id must not be randomic */ + { + /* FIXME: when frag. enabled sendip_handler shold inc. ip->id */ + /* for every frame sent */ + ip->id = (src_id == -1) ? + htons(getpid() & 255) : + htons((unsigned short) src_id); + } + +#if defined OSTYPE_DARWIN || defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD | defined OSTYPE_BSDI +/* FreeBSD */ +/* NetBSD */ + ip->frag_off |= more_fragments; + ip->frag_off |= fragoff >> 3; +#else +/* Linux */ +/* OpenBSD */ + ip->frag_off |= htons(more_fragments); + ip->frag_off |= htons(fragoff >> 3); /* shift three flags bit */ +#endif + + ip->ttl = src_ttl; + if (opt_rawipmode) ip->protocol = raw_ip_protocol; + else if (opt_icmpmode) ip->protocol = 1; /* icmp */ + else if (opt_udpmode) ip->protocol = 17; /* udp */ + else ip->protocol = 6; /* tcp */ + ip->check = 0; /* always computed by the kernel */ + + /* copies options */ + if (options != NULL) + memcpy(packet+IPHDR_SIZE, options, optlen); + + /* copies data */ + memcpy(packet + IPHDR_SIZE + optlen, data, datalen); + + if (opt_debug == TRUE) + { + unsigned int i; + + for (i=0; i$ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:49 MET 1999$ + * $rev: 3$ + */ + +/* $Id: sendip_handler.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include + +#include "hping2.h" +#include "globals.h" + +void send_ip_handler(char *packet, unsigned int size) +{ + ip_optlen = ip_opt_build(ip_opt); + + if (!opt_fragment && (size+ip_optlen+20 >= h_if_mtu)) + { + /* auto-activate fragmentation */ + virtual_mtu = h_if_mtu-20; + virtual_mtu = virtual_mtu - (virtual_mtu % 8); + opt_fragment = TRUE; + opt_mf = opt_df = FALSE; /* deactivate incompatible options */ + if (opt_verbose || opt_debug) + printf("auto-activate fragmentation, fragments size: %d\n", virtual_mtu); + } + + if (!opt_fragment) + { + unsigned short fragment_flag = 0; + + if (opt_mf) fragment_flag |= MF; /* more fragments */ + if (opt_df) fragment_flag |= DF; /* dont fragment */ + send_ip((char*)&local.sin_addr, + (char*)&remote.sin_addr, + packet, size, fragment_flag, ip_frag_offset, + ip_opt, ip_optlen); + } + else + { + unsigned int remainder = size; + int frag_offset = 0; + + while(1) { + if (remainder <= virtual_mtu) + break; + + send_ip((char*)&local.sin_addr, + (char*)&remote.sin_addr, + packet+frag_offset, + virtual_mtu, MF, frag_offset, + ip_opt, ip_optlen); + + remainder-=virtual_mtu; + frag_offset+=virtual_mtu; + } + + send_ip((char*)&local.sin_addr, + (char*)&remote.sin_addr, + packet+frag_offset, + remainder, NF, frag_offset, + ip_opt, ip_optlen); + } +} diff --git a/sendrawip.c b/src/sendrawip.c similarity index 50% rename from sendrawip.c rename to src/sendrawip.c index 3d60954..eff4448 100644 --- a/sendrawip.c +++ b/src/sendrawip.c @@ -13,15 +13,15 @@ void send_rawip(void) { - char *packet; + char *packet; - packet = malloc(data_size); - if (packet == NULL) { - perror("[send_rawip] malloc()"); - return; - } - memset(packet, 0, data_size); - data_handler(packet, data_size); - send_ip_handler(packet, data_size); - free(packet); + packet = malloc(data_size); + if (packet == NULL) { + perror("[send_rawip] malloc()"); + return; + } + memset(packet, 0, data_size); + data_handler(packet, data_size); + send_ip_handler(packet, data_size); + free(packet); } diff --git a/src/sendtcp.c b/src/sendtcp.c new file mode 100644 index 0000000..708a21e --- /dev/null +++ b/src/sendtcp.c @@ -0,0 +1,101 @@ +/* + * $smu-mark$ + * $name: sendtcp.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:49 MET 1999$ + * $rev: 8$ + */ + +/* $Id: sendtcp.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hping2.h" +#include "globals.h" + +void send_tcp(void) +{ + int packet_size; + int tcp_opt_size = 0; + char *packet, *data; + struct mytcphdr *tcp; + struct pseudohdr *pseudoheader; + unsigned char *tstamp; + + if (opt_tcp_timestamp) + tcp_opt_size = 12; + + packet_size = TCPHDR_SIZE + tcp_opt_size + data_size; + packet = malloc(PSEUDOHDR_SIZE + packet_size); + if (packet == NULL) { + perror("[send_tcphdr] malloc()"); + return; + } + pseudoheader = (struct pseudohdr*) packet; + tcp = (struct mytcphdr*) (packet+PSEUDOHDR_SIZE); + tstamp = (unsigned char*) (packet+PSEUDOHDR_SIZE+TCPHDR_SIZE); + data = (char*) (packet+PSEUDOHDR_SIZE+TCPHDR_SIZE+tcp_opt_size); + + memset(packet, 0, PSEUDOHDR_SIZE+packet_size); + + /* tcp pseudo header */ + memcpy(&pseudoheader->saddr, &local.sin_addr.s_addr, 4); + memcpy(&pseudoheader->daddr, &remote.sin_addr.s_addr, 4); + pseudoheader->protocol = 6; /* tcp */ + pseudoheader->lenght = htons(TCPHDR_SIZE+tcp_opt_size+data_size); + + /* tcp header */ + tcp->th_dport = htons(dst_port); + tcp->th_sport = htons(src_port); + + /* sequence number and ack are random if not set */ + tcp->th_seq = (set_seqnum) ? htonl(tcp_seqnum) : htonl(rand()); + tcp->th_ack = (set_ack) ? htonl(tcp_ack) : htonl(rand()); + + tcp->th_off = src_thoff + (tcp_opt_size >> 2); + tcp->th_win = htons(src_winsize); + tcp->th_flags = tcp_th_flags; + + /* tcp timestamp option */ + if (opt_tcp_timestamp) { + __u32 randts = rand() ^ (rand() << 16); + tstamp[0] = tstamp[1] = 1; /* NOOP */ + tstamp[2] = 8; + tstamp[3] = 10; /* 10 bytes, kind+len+T1+T2 */ + memcpy(tstamp+4, &randts, 4); /* random */ + memset(tstamp+8, 0, 4); /* zero */ + } + + /* data */ + data_handler(data, data_size); + + /* compute checksum */ +#ifdef STUPID_SOLARIS_CHECKSUM_BUG + tcp->th_sum = packet_size; +#else + tcp->th_sum = cksum((u_short*) packet, PSEUDOHDR_SIZE + + packet_size); +#endif + + /* adds this pkt in delaytable */ + delaytable_add(sequence, src_port, time(NULL), get_usec(), S_SENT); + + /* send packet */ + send_ip_handler(packet+PSEUDOHDR_SIZE, packet_size); + free(packet); + + sequence++; /* next sequence number */ + if (!opt_keepstill) + src_port = (sequence + initsport) % 65536; + + if (opt_force_incdport) + dst_port++; +} diff --git a/src/sendudp.c b/src/sendudp.c new file mode 100644 index 0000000..cab41ea --- /dev/null +++ b/src/sendudp.c @@ -0,0 +1,81 @@ +/* + * $smu-mark$ + * $name: sendudp.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:49 MET 1999$ + * $rev: 8$ + */ + +/* $Id: sendudp.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hping2.h" +#include "globals.h" + +/* void hexdumper(unsigned char *packet, int size); */ + +void send_udp(void) +{ + int packet_size; + char *packet, *data; + struct myudphdr *udp; + struct pseudohdr *pseudoheader; + + packet_size = UDPHDR_SIZE + data_size; + packet = malloc(PSEUDOHDR_SIZE + packet_size); + if (packet == NULL) { + perror("[send_udphdr] malloc()"); + return; + } + pseudoheader = (struct pseudohdr*) packet; + udp = (struct myudphdr*) (packet+PSEUDOHDR_SIZE); + data = (char*) (packet+PSEUDOHDR_SIZE+UDPHDR_SIZE); + + memset(packet, 0, PSEUDOHDR_SIZE+packet_size); + + /* udp pseudo header */ + memcpy(&pseudoheader->saddr, &local.sin_addr.s_addr, 4); + memcpy(&pseudoheader->daddr, &remote.sin_addr.s_addr, 4); + pseudoheader->protocol = 17; /* udp */ + pseudoheader->lenght = htons(packet_size); + + /* udp header */ + udp->uh_dport = htons(dst_port); + udp->uh_sport = htons(src_port); + udp->uh_ulen = htons(packet_size); + + /* data */ + data_handler(data, data_size); + + /* compute checksum */ +#ifdef STUPID_SOLARIS_CHECKSUM_BUG + udp->uh_sum = packet_size; +#else + udp->uh_sum = cksum((__u16*) packet, PSEUDOHDR_SIZE + + packet_size); +#endif + + /* adds this pkt in delaytable */ + delaytable_add(sequence, src_port, time(NULL), get_usec(), S_SENT); + + /* send packet */ + send_ip_handler(packet+PSEUDOHDR_SIZE, packet_size); + free(packet); + + sequence++; /* next sequence number */ + + if (!opt_keepstill) + src_port = (sequence + initsport) % 65536; + + if (opt_force_incdport) + dst_port++; +} diff --git a/src/signal.c b/src/signal.c new file mode 100644 index 0000000..2b4c8d7 --- /dev/null +++ b/src/signal.c @@ -0,0 +1,31 @@ +/* protable signal() like */ + +/* $Id: signal.c,v 1.2 2003/09/01 00:22:06 antirez Exp $ */ + +#include + +/* Portable signal() from R.Stevens, + * modified to reset the handler */ +void (*Signal(int signo, void (*func)(int)))(int) +{ + struct sigaction act, oact; + + act.sa_handler = func; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; /* So if set SA_RESETHAND is cleared */ + if (signo == SIGALRM) + { +#ifdef SA_INTERRUPT + act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ +#endif + } + else + { +#ifdef SA_RESTART + act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD, Linux */ +#endif + } + if (sigaction(signo, &act, &oact) == -1) + return SIG_ERR; + return (oact.sa_handler); +} diff --git a/sockopt.c b/src/sockopt.c similarity index 53% rename from sockopt.c rename to src/sockopt.c index b201a93..ed87ae1 100644 --- a/sockopt.c +++ b/src/sockopt.c @@ -17,24 +17,24 @@ void socket_broadcast(int sd) { - const int one = 1; + const int one = 1; - if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, - (char *)&one, sizeof(one)) == -1) - { - printf("[socket_broadcast] can't set SO_BROADCAST option\n"); - /* non fatal error */ - } + if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, + (char *)&one, sizeof(one)) == -1) + { + printf("[socket_broadcast] can't set SO_BROADCAST option\n"); + /* non fatal error */ + } } void socket_iphdrincl(int sd) { - const int one = 1; + const int one = 1; - if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, - (char *)&one, sizeof(one)) == -1) - { - printf("[socket_iphdrincl] can't set IP_HDRINCL option\n"); - /* non fatal error */ - } + if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, + (char *)&one, sizeof(one)) == -1) + { + printf("[socket_iphdrincl] can't set IP_HDRINCL option\n"); + /* non fatal error */ + } } diff --git a/src/split.c b/src/split.c new file mode 100644 index 0000000..47736d5 --- /dev/null +++ b/src/split.c @@ -0,0 +1,513 @@ +/* Copyright (C) 2003 Salvatore Sanfilippo + * All rights reserved + * $Id: split.c,v 1.4 2003/09/07 11:21:18 antirez Exp $ */ + +#include +#include +#include +#include +#include + +#include "ars.h" + +int ars_seems_ip(struct ars_iphdr *ip, size_t size) +{ + if (ip->version == 4 && + ip->ihl >= 5 && + (ip->ihl << 2) <= size && + ars_check_ip_cksum(ip) == 1) + return 1; + return 0; +} + +int ars_guess_ipoff(void *packet, size_t size, int *lhs) +{ + size_t orig_size = size; + + while(1) { + struct ars_iphdr *ip = packet; + if (size < sizeof (struct ars_iphdr)) + break; + if (ars_seems_ip(ip, size) == 0) { + /* We may probably assume the link header size + * to be multiple of two */ + packet++; + size--; + continue; + } + *lhs = orig_size - size; + return -ARS_OK; + } + return -ARS_ERROR; +} + +int ars_check_ip_cksum(struct ars_iphdr *ip) +{ + int ip_hdrsize = ip->ihl << 2; + struct ars_iphdr *ip2; + + ip2 = alloca(ip_hdrsize); + memcpy(ip2, ip, ip_hdrsize); + ip2->check = 0; + ip2->check = ars_cksum(ip2, ip_hdrsize); + return (ip->check == ip2->check); +} + +int ars_check_icmp_cksum(struct ars_icmphdr *icmp, size_t size) +{ + struct ars_icmphdr *icmp2; + + icmp2 = alloca(size); + memcpy(icmp2, icmp, size); + icmp2->checksum = 0; + icmp2->checksum = ars_cksum(icmp2, size); + return (icmp->checksum == icmp2->checksum); +} + +#define ARS_SPLIT_DONE 0 +#define ARS_SPLIT_GET_IP 1 +#define ARS_SPLIT_GET_IPOPT 2 +#define ARS_SPLIT_GET_ICMP 3 +#define ARS_SPLIT_GET_UDP 4 +#define ARS_SPLIT_GET_TCP 5 +#define ARS_SPLIT_GET_TCPOPT 6 +#define ARS_SPLIT_GET_IGRP 7 +#define ARS_SPLIT_GET_IGRPENTRY 8 +#define ARS_SPLIT_GET_DATA 9 + +int ars_split_ip(struct ars_packet *pkt, void *packet, size_t size, + int *state, int *len); +int ars_split_ipopt(struct ars_packet *pkt, void *packet, size_t size, + int *state, int *len); +int ars_split_icmp(struct ars_packet *pkt, void *packet, size_t size, + int *state, int *len); +int ars_split_udp(struct ars_packet *pkt, void *packet, size_t size, + int *state, int *len); +int ars_split_tcp(struct ars_packet *pkt, void *packet, size_t size, + int *state, int *len); +int ars_split_tcpopt(struct ars_packet *pkt, void *packet, size_t size, + int *state, int *len); +int ars_split_igrp(struct ars_packet *pkt, void *packet, size_t size, + int *state, int *len); +int ars_split_igrpentry(struct ars_packet *pkt, void *packet, size_t size, + int *state, int *len); +int ars_split_data(struct ars_packet *pkt, void *packet, size_t size, + int *state, int *len); + +/* Take it in sync with ARS_SPLIT_* defines */ +int (*ars_split_state_handler[])(struct ars_packet *pkt, void *packet, + size_t size, int *state, int *len) = +{ + NULL, + ars_split_ip, + ars_split_ipopt, + ars_split_icmp, + ars_split_udp, + ars_split_tcp, + ars_split_tcpopt, + ars_split_igrp, + ars_split_igrpentry, + ars_split_data +}; + +int ars_split_packet(void *packet, size_t size, int ipoff, struct ars_packet *pkt) +{ + int offset = 0; + int state = ARS_SPLIT_GET_IP; + + /* User asks for IP offset auto detection */ + if (ipoff == -1 && ars_guess_ipoff(packet, size, &ipoff) != -ARS_OK) { + ars_set_error(pkt, "IP offset autodetection failed"); + return -ARS_INVALID; + } + offset += ipoff; + size -= ipoff; + + /* Implemented as a finite state machine: + * every state is handled with a protocol specific function */ + while (state != ARS_SPLIT_DONE) { + int error; + int len = 0; + + error = ars_split_state_handler[state](pkt, packet + offset, + size, &state, &len); + if (error != -ARS_OK) + return error; + /* put off the link layer padding */ + if (pkt->p_layer_nr == 1 && + pkt->p_layer[0].l_type == ARS_TYPE_IP) { + struct ars_iphdr *ip = pkt->p_layer[0].l_data; + size = MIN(size, ntohs(ip->tot_len)); + } + offset += len; + size -= len; + /* Force the DONE state if we reached the end */ + if (size == 0) + state = ARS_SPLIT_DONE; + } + return -ARS_OK; +} + +/* Select the right state based on the IP protocol field */ +void ars_ip_next_state(int ipproto, int *state) +{ + switch(ipproto) { + case ARS_IPPROTO_IPIP: + *state = ARS_SPLIT_GET_IP; + break; + case ARS_IPPROTO_ICMP: + *state = ARS_SPLIT_GET_ICMP; + break; + case ARS_IPPROTO_TCP: + *state = ARS_SPLIT_GET_TCP; + break; + case ARS_IPPROTO_UDP: + *state = ARS_SPLIT_GET_UDP; + break; + case ARS_IPPROTO_IGRP: + *state = ARS_SPLIT_GET_IGRP; + break; + default: + *state = ARS_SPLIT_GET_DATA; + break; + } +} + +int ars_split_ip(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) +{ + struct ars_iphdr *ip = packet, *newip; + int flags = 0; + int ipsize; + + + /* Check for bad header size and checksum */ + if (size < sizeof(struct ars_iphdr)) { + flags |= ARS_SPLIT_FTRUNC; + ipsize = size; + } else { + ipsize = ip->ihl << 2; + if (size < ipsize) { + flags |= ARS_SPLIT_FTRUNC; + ipsize = size; + } + else if (ip->ihl < 4 || ars_check_ip_cksum(ip) == 0) + flags |= ARS_SPLIT_FBADCKSUM; + ipsize = MIN(ipsize, 20); + } + if ((newip = ars_add_iphdr(pkt, 0)) == NULL) + return -ARS_NOMEM; + + memcpy(newip, ip, ipsize); + ars_set_flags(pkt, ARS_LAST_LAYER, flags); + *len = ipsize; + + if (flags & ARS_SPLIT_FTRUNC) { + *state = ARS_SPLIT_GET_DATA; + return -ARS_OK; + } + + if (ip->ihl > 5) { /* IP options */ + /* IP protocol saved so after the IP option + * processing we can start with the right status */ + pkt->aux_ipproto = ip->protocol; + *state = ARS_SPLIT_GET_IPOPT; + pkt->aux = (ip->ihl - 5) << 2; + return -ARS_OK; + } + ars_ip_next_state(ip->protocol, state); + return -ARS_OK; +} + +int ars_split_ipopt(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) +{ + struct ars_ipopt *ipopt = packet; + int flags = 0; + int optsize; + int error; + + if (ipopt->kind == ARS_IPOPT_END || ipopt->kind == ARS_IPOPT_NOOP) + optsize = 1; + else + optsize = ipopt->len; + + /* Avoid infinite loop with broken packets */ + if (optsize == 0) + optsize = 1; + + /* pkt->aux was set by ars_split_ip, or by ars_split_ipopt itself */ + size = MIN(size, pkt->aux); + if (size == 0) { + *len = 0; + *state = ARS_SPLIT_GET_DATA; + return -ARS_OK; + } + + if (size < optsize) { + flags |= ARS_SPLIT_FTRUNC; + optsize = size; + } + + pkt->aux -= optsize; + error = ars_add_generic(pkt, optsize, ARS_TYPE_IPOPT); + if (error != -ARS_OK) + return error; + memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, ipopt, optsize); + pkt->p_layer_nr++; + ars_set_flags(pkt, ARS_LAST_LAYER, flags); + + *len = optsize; + + if (pkt->aux > 0) { + *state = ARS_SPLIT_GET_IPOPT; + } else { + ars_ip_next_state(pkt->aux_ipproto, state); + } + return -ARS_OK; +} + +int ars_split_icmp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) +{ + struct ars_icmphdr *icmp = packet, *newicmp; + int flags = 0; + int icmpsize = ARS_ICMPHDR_SIZE; + + /* Check for bad header size and checksum */ + if (size < icmpsize) { + flags |= ARS_SPLIT_FTRUNC; + icmpsize = size; + } + else if (ars_check_icmp_cksum(icmp, size) == 0) + flags |= ARS_SPLIT_FBADCKSUM; + + if ((newicmp = ars_add_icmphdr(pkt, 0)) == NULL) + return -ARS_NOMEM; + memcpy(newicmp, icmp, icmpsize); + ars_set_flags(pkt, ARS_LAST_LAYER, flags); + + *len = icmpsize; + + if (flags & ARS_SPLIT_FTRUNC) { + *state = ARS_SPLIT_GET_DATA; + return -ARS_OK; + } + + switch(icmp->type) { + case ARS_ICMP_ECHO: + case ARS_ICMP_ECHOREPLY: + case ARS_ICMP_TIMESTAMP: + case ARS_ICMP_TIMESTAMPREPLY: + case ARS_ICMP_INFO_REQUEST: + case ARS_ICMP_INFO_REPLY: + *state = ARS_SPLIT_GET_DATA; + break; + default: + *state = ARS_SPLIT_GET_IP; + break; + } + return -ARS_OK; +} + +int ars_split_data(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) +{ + void *newdata; + + if ((newdata = ars_add_data(pkt, size)) == NULL) + return -ARS_NOMEM; + memcpy(newdata, packet, size); + + *len = size; + + *state = ARS_SPLIT_DONE; + return -ARS_OK; +} + +int ars_split_udp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) +{ + struct ars_udphdr *udp = packet, *newudp; + int flags = 0; + int udpsize = ARS_UDPHDR_SIZE; + int error; + u_int16_t udpcksum; + + /* XXX hack, we need to add a temp unusual layer (UDP+UDP_DATA) to + * use the ars_udptcp_cksum() function. */ + + /* --- HACK START --- */ + error = ars_add_generic(pkt, size, ARS_TYPE_UDP); + if (error != -ARS_OK) + return error; + newudp = pkt->p_layer[pkt->p_layer_nr].l_data; + memcpy(newudp, udp, size); + newudp->uh_sum = 0; + error = ars_udptcp_cksum(pkt, pkt->p_layer_nr, &udpcksum); + if (error != ARS_OK) { + printf("---ERROR DOING CHECKSUM\n"); + pkt->p_layer_nr++; /* just to be sane */ + return error; + } + error = ars_remove_layer(pkt, pkt->p_layer_nr); + if (error != ARS_OK) + return error; + /* --- HACK END --- */ + + /* Check for bad header size and checksum */ + if (size < udpsize) { + flags |= ARS_SPLIT_FTRUNC; + udpsize = size; + } + else if (udp->uh_sum != udpcksum) + flags |= ARS_SPLIT_FBADCKSUM; + + if ((newudp = ars_add_udphdr(pkt, 0)) == NULL) + return -ARS_NOMEM; + memcpy(newudp, udp, udpsize); + ars_set_flags(pkt, ARS_LAST_LAYER, flags); + + *len = udpsize; + *state = ARS_SPLIT_GET_DATA; + return -ARS_OK; +} + +int ars_split_tcp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) +{ + struct ars_tcphdr *tcp = packet, *newtcp; + int flags = 0; + int tcpsize = tcp->th_off << 2; /* FIXME: may access random memory */ + int error; + u_int16_t tcpcksum; + + /* XXX hack, we need to add a temp unusual layer (TCP+TCP_DATA) to + * use the ars_udptcp_cksum() function. */ + + /* --- HACK START --- */ + error = ars_add_generic(pkt, size, ARS_TYPE_TCP); + if (error != -ARS_OK) + return error; + newtcp = pkt->p_layer[pkt->p_layer_nr].l_data; + memcpy(newtcp, tcp, size); + newtcp->th_sum = 0; + error = ars_udptcp_cksum(pkt, pkt->p_layer_nr, &tcpcksum); + if (error != ARS_OK) { + pkt->p_layer_nr++; /* just to be sane */ + return error; + } + error = ars_remove_layer(pkt, pkt->p_layer_nr); + if (error != ARS_OK) + return error; + /* --- HACK END --- */ + + /* Check for bad header size and checksum */ + if (size < tcpsize) { + flags |= ARS_SPLIT_FTRUNC; + tcpsize = size; + } + else if (tcp->th_sum != tcpcksum) + flags |= ARS_SPLIT_FBADCKSUM; + + tcpsize = MIN(tcpsize, 20); + + if ((newtcp = ars_add_tcphdr(pkt, 0)) == NULL) + return -ARS_NOMEM; + memcpy(newtcp, tcp, tcpsize); + ars_set_flags(pkt, ARS_LAST_LAYER, flags); + + *len = tcpsize; + if (tcp->th_off > 5) { + *state = ARS_SPLIT_GET_TCPOPT; + pkt->aux = (tcp->th_off - 5) << 2; + } else { + *state = ARS_SPLIT_GET_DATA; + } + return -ARS_OK; +} + +int ars_split_tcpopt(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) +{ + struct ars_tcpopt *tcpopt = packet; + int flags = 0; + int optsize; + int error; + + if (tcpopt->kind == ARS_TCPOPT_EOL || tcpopt->kind == ARS_TCPOPT_NOP || + tcpopt->kind == ARS_TCPOPT_SACK_PERM) + optsize = 1; + else + optsize = tcpopt->len; + + /* Avoid infinite loop with broken packets */ + if (optsize == 0) + optsize = 1; + + /* pkt->aux was set by ars_split_tcp, or by ars_split_tcpopt itself */ + size = MIN(size, pkt->aux); + if (size == 0) { + *len = 0; + *state = ARS_SPLIT_GET_DATA; + return -ARS_OK; + } + + if (size < optsize) { + flags |= ARS_SPLIT_FTRUNC; + optsize = size; + } + + pkt->aux -= optsize; + error = ars_add_generic(pkt, optsize, ARS_TYPE_TCPOPT); + if (error != -ARS_OK) + return error; + memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, tcpopt, optsize); + pkt->p_layer_nr++; + ars_set_flags(pkt, ARS_LAST_LAYER, flags); + + *len = optsize; + + if (pkt->aux > 0) + *state = ARS_SPLIT_GET_TCPOPT; + else + *state = ARS_SPLIT_GET_DATA; + + return -ARS_OK; +} + +/* XXX: check for valid IGRP checksum */ +int ars_split_igrp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) +{ + struct ars_igrphdr *igrp = packet; + int flags = 0, igrpsize = sizeof(*igrp); + int error; + + if (size < sizeof(*igrp)) { + flags |= ARS_SPLIT_FTRUNC; + igrpsize = size; + } + error = ars_add_generic(pkt, sizeof(*igrp), ARS_TYPE_IGRP); + if (error != -ARS_OK) + return error; + memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, igrp, igrpsize); + pkt->p_layer_nr++; + ars_set_flags(pkt, ARS_LAST_LAYER, flags); + *len = igrpsize; + *state = ARS_SPLIT_GET_IGRPENTRY; + return -ARS_OK; +} + +int ars_split_igrpentry(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) +{ + struct ars_igrpentry *entry = packet; + int flags = 0, entrysize = sizeof(*entry); + int error; + + if (size < sizeof(*entry)) { + flags |= ARS_SPLIT_FTRUNC; + entrysize = size; + } + error = ars_add_generic(pkt, sizeof(*entry), ARS_TYPE_IGRPENTRY); + if (error != -ARS_OK) + return error; + memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, entry, entrysize); + pkt->p_layer_nr++; + ars_set_flags(pkt, ARS_LAST_LAYER, flags); + *len = entrysize; + *state = ARS_SPLIT_GET_IGRPENTRY; + return -ARS_OK; +} diff --git a/src/statistics.c b/src/statistics.c new file mode 100644 index 0000000..a01a537 --- /dev/null +++ b/src/statistics.c @@ -0,0 +1,53 @@ +/* + * $smu-mark$ + * $name: statistics.c$ + * $author: Salvatore Sanfilippo $ + * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ + * $license: This software is under GPL version 2 of license$ + * $date: Fri Nov 5 11:55:50 MET 1999$ + * $rev: 8$ + */ + +/* $Id: statistics.c,v 1.3 2004/04/09 23:38:56 antirez Exp $ */ + +#include +#include + +#include "hping2.h" +#include "globals.h" + +void print_statistics(int signal_id) +{ + unsigned int lossrate; + + close_pcap(); + if (recv_pkt > 0) + lossrate = 100 - ((recv_pkt*100)/sent_pkt); + else + if (!sent_pkt) + lossrate = 0; + else + lossrate = 100; + + fprintf(stderr, "\n--- %s hping statistic ---\n", targetname); + fprintf(stderr, "%d packets tramitted, %d packets received, " + "%d%% packet loss\n", sent_pkt, recv_pkt, lossrate); + if (out_of_sequence_pkt) + fprintf(stderr, "%d out of sequence packets received\n", + out_of_sequence_pkt); + fprintf(stderr, "round-trip min/avg/max = %.1f/%.1f/%.1f ms\n", + rtt_min, rtt_avg, rtt_max); + + /* manage exit code */ + if (opt_tcpexitcode) + { + exit(tcp_exitcode); + } + else + { + if (recv_pkt) + exit(0); + else + exit(1); + } +}; diff --git a/strlcpy.c b/src/strlcpy.c similarity index 100% rename from strlcpy.c rename to src/strlcpy.c diff --git a/usage.c b/src/usage.c similarity index 90% rename from usage.c rename to src/usage.c index ea54d9d..c4edeee 100644 --- a/usage.c +++ b/src/usage.c @@ -13,9 +13,9 @@ #include #include -void show_usage(void) +void show_usage(void) { - printf( + printf( "usage: hping host [options]\n" " -h --help show this help\n" " -v --version show version\n" @@ -23,7 +23,7 @@ void show_usage(void) " -i --interval wait (uX for X microseconds, for example -i u1000)\n" " --fast alias for -i u10000 (10 packets for second)\n" " --faster alias for -i u1000 (100 packets for second)\n" -" --flood sent packets as fast as possible. Don't show replies.\n" +" --flood sent packets as fast as possible. Don't show replies.\n" " -n --numeric numeric output\n" " -q --quiet quiet\n" " -I --interface interface name (otherwise default routing interface)\n" @@ -104,16 +104,16 @@ void show_usage(void) " -T --traceroute traceroute mode (implies --bind and --ttl 1)\n" " --tr-stop Exit when receive the first not ICMP in traceroute mode\n" " --tr-keep-ttl Keep the source TTL fixed, useful to monitor just one hop\n" -" --tr-no-rtt Don't calculate/show RTT information in traceroute mode\n" +" --tr-no-rtt Don't calculate/show RTT information in traceroute mode\n" "ARS packet description (new, unstable)\n" " --apd-send Send the packet described with APD (see docs/APD.txt)\n" - ); - exit(0); + ); + exit(0); }; void tos_help(void) { - printf( + printf( "tos help:\n" " TOS Name Hex Value Typical Uses\n" "\n" @@ -121,13 +121,13 @@ void tos_help(void) " Maximum Throughput 08 ftp-data\n" " Maximum Reliability 04 snmp\n" " Minimum Cost 02 nntp\n" - ); - exit(0); + ); + exit(0); } void icmp_help(void) { - printf( + printf( "ICMP help:\n" " ICMP concerned packet options:\n" " --icmp-ipver set ip version ( default 4 )\n" @@ -140,17 +140,17 @@ void icmp_help(void) " --icmp-srcport set tcp/udp source port ( default random )\n" " --icmp-dstport set tcp/udp destination port ( default random )\n" " --icmp-cksum set icmp checksum ( default the right cksum)\n" - ); - exit(0); + ); + exit(0); } void route_help(void) { printf( "route help:\n" -" A route has the following format: [ptr:]IP1[/IP2[/IP3...]]\n" -" where ptr is the exact value of the pointer that will be used for the IP\n" -" option (be careful, no check is performed on this pointer), and defaults\n" -" to 8, or 4 if provided route is too short for 8;\n" -" and each IPx field is an IP address to include in the source route.\n"); +" A route has the following format: [ptr:]IP1[/IP2[/IP3...]]\n" +" where ptr is the exact value of the pointer that will be used for the IP\n" +" option (be careful, no check is performed on this pointer), and defaults\n" +" to 8, or 4 if provided route is too short for 8;\n" +" and each IPx field is an IP address to include in the source route.\n"); } diff --git a/version.c b/src/version.c similarity index 71% rename from version.c rename to src/version.c index 043920d..e5658e8 100644 --- a/version.c +++ b/src/version.c @@ -18,12 +18,12 @@ void show_version(void) { - printf("hping version %s (%s)\n", RELEASE_VERSION, RELEASE_DATE); + printf("hping version %s (%s)\n", RELEASE_VERSION, RELEASE_DATE); #ifdef USE_TCL - printf("This binary is TCL scripting capable\n"); + printf("This binary is TCL scripting capable\n"); #else - printf("NO TCL scripting support compiled in\n"); + printf("NO TCL scripting support compiled in\n"); #endif - exit(0); + exit(0); } diff --git a/src/waitpacket.c b/src/waitpacket.c new file mode 100644 index 0000000..ccfab74 --- /dev/null +++ b/src/waitpacket.c @@ -0,0 +1,780 @@ +/* waitpacket.c -- handle and print the incoming packet + * Copyright(C) 1999-2001 Salvatore Sanfilippo + * Under GPL, see the COPYING file for more information about + * the license. */ + +/* $Id: waitpacket.c,v 1.4 2004/06/18 09:53:11 antirez Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hping2.h" +#include "globals.h" + +static int icmp_unreach_rtt(void *quoted_ip, int size, + int *seqp, float *ms_delay); +static void print_tcp_timestamp(void *tcp, int tcpsize, int rttms); +static int recv_icmp(void *packet, size_t size); +static int recv_udp(void *packet, size_t size); +static int recv_tcp(void *packet, size_t size); +static void hex_dump(void *packet, int size); +static void human_dump(void *packet, int size); +static void handle_hcmp(char *packet, int size); + +static struct myiphdr ip; +static int ip_size; +static struct in_addr src, dst; + +/* This function is called for every matching packet received. + * If --beep option was specified, the user will hear a beep + * for every received packet. */ +void recv_beep(void) +{ + if (opt_beep) + printf("\a"); +} + +void wait_packet(void) +{ + int match = 0; + int size, iphdr_size, enc_size; + char packet [IP_MAX_SIZE+linkhdr_size]; + char *ip_packet, *enc_packet; + + size = read_packet(packet, IP_MAX_SIZE+linkhdr_size); + switch(size) { + case 0: + return; + case -1: + exit(1); + } + + /* Check if the packet is shorter than the link header size */ + if (size < linkhdr_size) { + if (opt_debug) + printf("DEBUG: WARNING: packet size < linkhdr_size\n"); + return; + } + + /* IP packet pointer and len */ + ip_packet = packet + linkhdr_size; + ip_size = size - linkhdr_size; + + /* Truncated IP header? */ + if (ip_size < IPHDR_SIZE) { + if (opt_debug) + printf("[|ip fix]\n"); + return; + } + + memcpy(&ip, packet+linkhdr_size, sizeof(ip)); + iphdr_size = ip.ihl * 4; + + /* Bad IP header len? */ + if (iphdr_size > ip_size) { + if (opt_debug) + printf("[|iphdr size]\n"); + return; + } + + /* Handle the HCMP for almost safe file transfer with hping */ + if (opt_sign) + handle_hcmp(ip_packet, ip_size); + + /* Check if the dest IP address is the one of our interface */ + if (memcmp(&ip.daddr, &local.sin_addr, sizeof(ip.daddr))) + return; + /* If the packet isn't an ICMP error it should come from + * our target IP addresss. We accepts packets from all the + * source if the random destination option is active */ + if (ip.protocol != IPPROTO_ICMP && !opt_rand_dest) { + if (memcmp(&ip.saddr, &remote.sin_addr, sizeof(ip.saddr))) + return; + } + + /* Get the encapsulated protocol offset and size */ + enc_packet = ip_packet + iphdr_size; + enc_size = ip_size - iphdr_size; + + /* Put the IP source and dest addresses in a struct in_addr */ + memcpy(&src, &(ip.saddr), sizeof(struct in_addr)); + memcpy(&dst, &(ip.daddr), sizeof(struct in_addr)); + + switch(ip.protocol) { + case IPPROTO_ICMP: + match = recv_icmp(enc_packet, enc_size); + break; + case IPPROTO_UDP: + match = recv_udp(enc_packet, enc_size); + break; + case IPPROTO_TCP: + match = recv_tcp(enc_packet, enc_size); + break; + default: + return; + } + + if (match) + recv_pkt++; + + /* Dump the packet in hex */ + if (opt_hexdump && match && !opt_quiet) + hex_dump(ip_packet, ip_size); + + /* Dump printable characters inside the packet */ + if (opt_contdump && match && !opt_quiet) + human_dump(ip_packet, ip_size); + + /* Display IP options */ + if (match && opt_rroute && !opt_quiet) + display_ipopt(ip_packet); + + /* --stop-tr stops hping in traceroute mode when the + * first not ICMP time exceeded packet is received */ + if (opt_traceroute && opt_tr_stop && match) { + struct myicmphdr icmp; + + if (ip.protocol != IPPROTO_ICMP) + print_statistics(0); + if (enc_size >= ICMPHDR_SIZE) { + memcpy(&icmp, enc_packet, sizeof(icmp)); + if (icmp.type != 11) + print_statistics(0); + } + } + + /* if the count was reached exit now */ + if (count != -1 && count == recv_pkt) + print_statistics(0); +} + +void log_ip(int status, int sequence) +{ + int rel_id, ip_id; + + /* get ip->id */ + if (opt_winid_order) + ip_id = ip.id; + else + ip_id = htons(ip.id); + + if (status == S_RECV) + printf("DUP! "); + + if (opt_relid) + rel_id = relativize_id(sequence, &ip_id); + else + rel_id = 0; + printf("len=%d ip=%s ttl=%d %sid%s%d ", ip_size, inet_ntoa(src), + ip.ttl, + (ntohs(ip.frag_off) ? "DF " : ""), + (rel_id ? "=+" : "="), ip_id); + if (opt_verbose && !opt_quiet) + printf("tos=%x iplen=%u\n", ip.tos, htons(ip.tot_len)); +} + +void log_icmp_ts(void *ts) +{ + struct icmp_tstamp_data icmp_tstamp; + + memcpy(&icmp_tstamp, ts, sizeof(icmp_tstamp)); + printf("ICMP timestamp: Originate=%u Receive=%u Transmit=%u\n", + (unsigned int) ntohl(icmp_tstamp.orig), + (unsigned int) ntohl(icmp_tstamp.recv), + (unsigned int) ntohl(icmp_tstamp.tran)); + printf("ICMP timestamp RTT tsrtt=%lu\n\n", + (long unsigned int) (get_midnight_ut_ms() + - ntohl(icmp_tstamp.orig))); +} + +void log_icmp_addr(void *addrptr) +{ + unsigned char *addr = addrptr; + printf("ICMP address mask: icmpam=%u.%u.%u.%u\n\n", + addr[0], addr[1], addr[2], addr[3]); +} + +void log_traceroute(void *packet, int size, int icmp_code) +{ + static unsigned char old_src_addr[4] = { 0, 0, 0, 0 }; + int sequence = 0, retval; + float rtt; + + if (!opt_tr_keep_ttl && !memcmp(&ip.saddr, old_src_addr, 4)) + return; + + retval = icmp_unreach_rtt(packet+ICMPHDR_SIZE, size-ICMPHDR_SIZE, + &sequence, &rtt); + memcpy(old_src_addr, &ip.saddr, sizeof(ip.saddr)); + printf("hop=%d ", src_ttl); + fflush(stdout); + log_icmp_timeexc(inet_ntoa(src), icmp_code); + if (retval != -1) + printf("hop=%d hoprtt=%.1f ms\n", + src_ttl, rtt); + if (!opt_tr_keep_ttl) + src_ttl++; +} + +int recv_icmp(void *packet, size_t size) +{ + struct myicmphdr icmp; + struct myiphdr quoted_ip; + + /* Check if the packet can contain the ICMP header */ + if (size < ICMPHDR_SIZE) { + printf("[|icmp]\n"); + return 0; + } + memcpy(&icmp, packet, sizeof(icmp)); + + /* --------------------------- * + * ICMP ECHO/TIMESTAMP/ADDRESS * + * --------------------------- */ + if ((icmp.type == ICMP_ECHOREPLY || + icmp.type == ICMP_TIMESTAMPREPLY || + icmp.type == ICMP_ADDRESSREPLY) && + icmp.un.echo.id == (getpid() & 0xffff)) + { + int icmp_seq = icmp.un.echo.sequence; + int status; + float ms_delay; + + recv_beep(); + /* obtain round trip time */ + status = rtt(&icmp_seq, 0, &ms_delay); + log_ip(status, icmp_seq); + + printf("icmp_seq=%d rtt=%.1f ms\n", icmp_seq, ms_delay); + if (icmp.type == ICMP_TIMESTAMPREPLY) { + if ((size - ICMPHDR_SIZE) >= 12) + log_icmp_ts(packet+ICMPHDR_SIZE); + else + printf("[|icmp timestamp]\n"); + } else if (icmp.type == ICMP_ADDRESSREPLY) { + if ((size - ICMPHDR_SIZE) >= 4) + log_icmp_addr(packet+ICMPHDR_SIZE); + else + printf("[|icmp subnet address]\n"); + } + return 1; + } + /* ------------------------------------ * + * ICMP DEST UNREACHABLE, TIME EXCEEDED * + * ------------------------------------ */ + else if (icmp.type == 3 || icmp.type == 11) { + if ((size - ICMPHDR_SIZE) < sizeof(struct myiphdr)) { + printf("[|icmp quoted ip]\n"); + return 0; + } + memcpy("ed_ip, packet+ICMPHDR_SIZE, sizeof(quoted_ip)); + if (memcmp("ed_ip.daddr, &remote.sin_addr, + sizeof(quoted_ip.daddr)) || + memcmp(&ip.daddr, &local.sin_addr, sizeof(ip.daddr))) + return 0; /* addresses don't match */ + /* Now we can handle the specific type */ + switch(icmp.type) { + case 3: + if (!opt_quiet) + log_icmp_unreach(inet_ntoa(src), icmp.code); + return 1; + case 11: + if (opt_traceroute) + log_traceroute(packet, size, icmp.code); + else + log_icmp_timeexc(inet_ntoa(src), icmp.code); + return 1; + } + } + + return 0; /* don't match */ +} + +int recv_udp(void *packet, size_t size) +{ + struct myudphdr udp; + int sequence = 0, status; + float ms_delay; + + if (size < UDPHDR_SIZE) { + printf("[|udp]\n"); + return 0; + } + memcpy(&udp, packet, sizeof(udp)); + + /* check if the packet matches */ + if ((ntohs(udp.uh_sport) == dst_port) || + (opt_force_incdport && + (ntohs(udp.uh_sport) >= base_dst_port && + ntohs(udp.uh_sport) <= dst_port))) + { + recv_beep(); + status = rtt(&sequence, ntohs(udp.uh_dport), &ms_delay); + if (!opt_quiet) { + log_ip(status, sequence); + printf("seq=%d rtt=%.1f ms\n", sequence, ms_delay); + } + if (opt_incdport && !opt_force_incdport) + dst_port++; + return 1; + } + return 0; +} + +int recv_tcp(void *packet, size_t size) +{ + struct mytcphdr tcp; + int sequence = 0, status; + float ms_delay; + char flags[16]; + + if (size < TCPHDR_SIZE) { + printf("[|tcp]\n"); + return 0; + } + memcpy(&tcp, packet, sizeof(tcp)); + + /* check if the packet matches */ + if ((ntohs(tcp.th_sport) == dst_port) || + (opt_force_incdport && + (ntohs(tcp.th_sport) >= base_dst_port && + ntohs(tcp.th_sport) <= dst_port))) + { + recv_beep(); + tcp_exitcode = tcp.th_flags; + + status = rtt(&sequence, ntohs(tcp.th_dport), &ms_delay); + + if (opt_seqnum) { + static __u32 old_th_seq = 0; + __u32 seq_diff, tmp; + + tmp = ntohl(tcp.th_seq); + if (tmp >= old_th_seq) + seq_diff = tmp - old_th_seq; + else + seq_diff = (4294967295U - old_th_seq) + + tmp; + old_th_seq = tmp; + printf("%10lu +%lu\n", + (unsigned long) tmp, + (unsigned long) seq_diff); + goto out; + } + + if (opt_quiet) + goto out; + + flags[0] = '\0'; + if (tcp.th_flags & TH_RST) strcat(flags, "R"); + if (tcp.th_flags & TH_SYN) strcat(flags, "S"); + if (tcp.th_flags & TH_ACK) strcat(flags, "A"); + if (tcp.th_flags & TH_FIN) strcat(flags, "F"); + if (tcp.th_flags & TH_PUSH) strcat(flags, "P"); + if (tcp.th_flags & TH_URG) strcat(flags, "U"); + if (tcp.th_flags & TH_X) strcat(flags, "X"); + if (tcp.th_flags & TH_Y) strcat(flags, "Y"); + if (flags[0] == '\0') strcat(flags, "none"); + + log_ip(status, sequence); + printf("sport=%d flags=%s seq=%d win=%d rtt=%.1f ms\n", + ntohs(tcp.th_sport), flags, sequence, + ntohs(tcp.th_win), ms_delay); + + if (opt_verbose) { + printf("seq=%lu ack=%lu sum=%x urp=%u\n\n", + (unsigned long) ntohl(tcp.th_seq), + (unsigned long) ntohl(tcp.th_ack), + tcp.th_sum, ntohs(tcp.th_urp)); + } + + /* Get and log the TCP timestamp */ + if (opt_tcp_timestamp && status != S_RECV) + print_tcp_timestamp(packet, size, (int)ms_delay); +out: + if (opt_incdport && !opt_force_incdport) + dst_port++; + return 1; + } + return 0; +} + +/* Try to extract information about the original packet from the + * ICMP error to obtain the round time trip + * + * Note that size is the the packet size starting from the + * IP packet quoted in the ICMP error, it may be negative + * if the ICMP is broken */ +int icmp_unreach_rtt(void *quoted_ip, int size, int *seqp, float *ms_delay) +{ + int src_port; + int sequence = 0; + int quoted_iphdr_size; + struct myudphdr udp; + struct myicmphdr icmp; + struct myiphdr qip; + + /* The user specified --no-rtt */ + if (opt_tr_no_rtt) + return -1; + + if (size < sizeof(struct myiphdr)) + return -1; + memcpy(&qip, quoted_ip, sizeof(struct myiphdr)); + quoted_iphdr_size = qip.ihl << 2; + /* Ok, enough room, try to get the rtt, + * but check if the original packet was an UDP/TCP one */ + if (qip.protocol == IPPROTO_TCP || + qip.protocol == IPPROTO_UDP) { + /* We need at least 2 bytes of the quoted UDP/TCP header + * for the source port */ + if ((size - quoted_iphdr_size) < 2) + return -1; + + /* Use the UDP header for both UDP and TCP, they are + * the same in the 4 first bytes (source and dest port) */ + memcpy(&udp, quoted_ip+quoted_iphdr_size, sizeof(udp)); + src_port = htons(udp.uh_sport); + return rtt(&sequence, src_port, ms_delay); + } else if (qip.protocol == IPPROTO_ICMP) { + int s; + + /* We need the whole 8 byte ICMP header to get + * the sequence field, also the type must be + * ICMP_ECHO */ + memcpy(&icmp, quoted_ip+quoted_iphdr_size, sizeof(icmp)); + if ((size - quoted_iphdr_size) < 8 || + icmp.type != ICMP_ECHO) + return -1; + + s = icmp.un.echo.sequence; + return rtt(&s, 0, ms_delay); + } + return -1; /* no way */ +} + +void clock_skew(int hz, __u32 tstamp, int rttms) +{ + long long tstampms = tstamp*(1000/hz); + long long tstampms2; /* tstamp after rtt correction */ + long long currdelta; /* current delta */ + long long localms; /* local clock */ + static long long *deltavect = NULL; /* delta vector, for samples collection */ + static long long *deltartt = NULL; /* rtt of every tstamp packet */ + + /* Deltas in deltavect with deltartt information are used to + * get samples of the time difference between the local host and + * the remote host. Every cs_vector_len packets caputed in the + * deltvact array are used to estimate the time delta that's + * put in turrn into the sample vector. */ + + static int deltanum = 0; /* number of deltas in deltavect */ + static long long *sample = NULL; /* error corrected delta vector */ + static long long *samplelocal = NULL; /* local time of captured delta vector */ + static int samplelen = 0; + + if (deltavect == NULL) { + deltavect = malloc(sizeof(*deltavect)*cs_vector_len); + deltartt = malloc(sizeof(*deltartt)*cs_vector_len); + if (deltavect == NULL) { + fprintf(stderr, "Out of memory in clock_skew()\n"); + exit(1); + } + deltanum = 0; + } + + printf(" Clock skew detection...\n"); + printf(" hz: %d\n", hz); + printf(" received tstamp (converted in ms according to hz): %lld\n", tstampms); + printf(" rtt in milliseconds: %d\n", rttms); + + tstampms2 = tstampms-(rttms/2); /* Assuming symmetric path for packets... */ + localms = mstime(); + currdelta = localms-tstampms2; + printf(" tstamp-(rtt/2): %lld\n", tstampms2); + printf(" local/remote clock delta: %lld\n", currdelta); + deltavect[deltanum] = currdelta; + deltartt[deltanum] = rttms; + deltanum++; + + /* When cs_vector_len packets are captured we can estimate + * the current clock difference between our local PC and the remote + * host. We call every delta estimation a "sample" */ + if (deltanum == cs_vector_len) { + long long sum = 0; + unsigned long long minrtt; + int j, validpackets; + + /* First we check what's the minimum RTT. We'll later + * discard packets with an RTT too high compared to + * the minimum one as this are source of errors. */ + minrtt = deltartt[0]; + for (j = 1; j < cs_vector_len; j++) + if (deltartt[j] < minrtt) minrtt = deltartt[j]; + + /* Now we can average the deltavect elements to get a + * sample. In the process information from packets with + * an rtt greater than 10% of the the min rtt are discarded */ + + validpackets = 0; + for (j = 0; j < cs_vector_len; j++) { + if (minrtt > 10 && (deltartt[j]-minrtt > minrtt/10)) { + printf(" # Not used packet %d/%d with rtt %lld (max acceptable %lld)\n", j+1, cs_vector_len, deltartt[j], minrtt+(minrtt/10)); + continue; + } + sum += deltavect[j]; + validpackets++; + } + + deltanum = 0; /* reset the counter anyway */ + if (validpackets) { + sum /= validpackets; + printf(" >> error corrected delta: %lld** (based on %d of %d packets)\n", sum, validpackets, cs_vector_len); + sample = realloc(sample,sizeof(*sample)*(samplelen+1)); + samplelocal = realloc(samplelocal,sizeof(*samplelocal)*(samplelen+1)); + if (!sample || !samplelocal) { + fprintf(stderr, "Out of memory in clock_skew()\n"); + exit(1); + } + sample[samplelen] = sum; + samplelocal[samplelen] = mstime(); + samplelen++; + } + } + + /* If we have enough data to start to compute the + * skew, compute it and display the information. */ + if (samplelen > cs_window_shift && + samplelocal[samplelen-1]-samplelocal[cs_window_shift-1] > cs_window*1000) + { + int i = samplelen-2, j; + long long skew, skewsum = 0, delta, localdelta = 0; + + /* Search the first sample from right to left so that + * the local time difference is >= the selected window */ + while(samplelocal[samplelen-1]-samplelocal[i]= 0; j--) { + localdelta = samplelocal[samplelen-1-j]-samplelocal[i-j]; + delta = sample[samplelen-1-j]-sample[i-j]; + skew = (delta*1000000)/localdelta; /* nanoseconds */ + printf("%lld ", skew); + skewsum += skew; + } + printf(") next line is the average\n"); + skewsum /= cs_window_shift; + printf(" %d sec. window SKEW: %lld nanoseconds/second\n", cs_window, skewsum); + /* Compute the SKEW from the full range of samples we have */ + skewsum = 0; + for (j = 0; j < cs_window_shift; j++) { + localdelta = samplelocal[samplelen-1-j]-samplelocal[cs_window_shift-1-j]; + delta = sample[samplelen-1-j]-sample[cs_window_shift-1-j]; + skew = (delta*1000000)/localdelta; /* nanoseconds */ + skewsum += skew; + } + skewsum /= cs_window_shift; + printf("> %lld sec. window SKEW: %lld nanoseconds/second\n", localdelta/1000, skewsum); + } else { + printf(" !! Not enough data to show reliable skew, wait please...\n"); + if (samplelen > 1) { + long long skew = 0, delta, localdelta; + localdelta = samplelocal[samplelen-1]-samplelocal[0]; + delta = sample[samplelen-1]-sample[0]; + skew = (delta*1000000)/localdelta; + printf("\n Early info just to take you happy... ;)\n"); + printf(" early unreliable skew guess: %lld nanoseconds per second\n", skew); + printf(" early guess localdelta: %lld ms\n", localdelta); + printf(" early delta: %lld ms\n", delta); + } + } + printf(" collected %d/%d deltas for next sample\n", + deltanum, cs_vector_len); +} + +void print_tcp_timestamp(void *tcp, int tcpsize, int rttms) +{ + int optlen; + unsigned char *opt; + __u32 tstamp = 0, echo; + static __u32 first_tstamp = 0; + static unsigned long long first_mstime = 0; + struct mytcphdr tmptcphdr; + unsigned int tcphdrlen; + + if (tcpsize < TCPHDR_SIZE) + return; + memcpy(&tmptcphdr, tcp, sizeof(struct mytcphdr)); + tcphdrlen = tmptcphdr.th_off * 4; + + /* bad len or no options in the TCP header */ + if (tcphdrlen <= 20 || tcphdrlen < tcpsize) + return; + optlen = tcphdrlen - TCPHDR_SIZE; + opt = (unsigned char*)tcp + TCPHDR_SIZE; /* skips the TCP fix header */ + while(optlen) { + switch(*opt) { + case 0: /* end of option */ + return; + case 1: /* noop */ + opt++; + optlen--; + continue; + default: + if (optlen < 2) + return; + if (opt[1] > optlen) + return; + if (opt[0] != 8) { /* not timestamp */ + optlen -= opt[1]; + opt += opt[1]; + continue; + } + /* timestamp found */ + if (opt[1] != 10) /* bad len */ + return; + memcpy(&tstamp, opt+2, 4); + memcpy(&echo, opt+6, 4); + tstamp = ntohl(tstamp); + echo = ntohl(echo); + goto found; + } + } +found: + printf(" TCP timestamp: tcpts=%u\n", tstamp); + if (first_tstamp) { + int tsdiff; + int hz_set[] = { 2, 10, 100, 1000, 0 }; + int hzdiff = -1; + int hz = 0, sec; + int days, hours, minutes; + unsigned long long mswait; + + mswait = mstime()-first_mstime; + tsdiff = (int)(((long long)(tstamp - first_tstamp)*1000)/mswait); + if (tsdiff > 0) { + int i = 0; + while(hz_set[i]) { + if (hzdiff == -1) { + hzdiff = ABS(tsdiff-hz_set[i]); + hz = hz_set[i]; + } else if (hzdiff > ABS(tsdiff-hz_set[i])) { + hzdiff = ABS(tsdiff-hz_set[i]); + hz = hz_set[i]; + } + i++; + } + printf(" HZ seems hz=%d (%d measured)\n", hz, tsdiff); + sec = tstamp/hz; /* Get the uptime in seconds */ + days = sec / (3600*24); + sec %= 3600*24; + hours = sec / 3600; + sec %= 3600; + minutes = sec / 60; + sec %= 60; + printf(" System uptime seems: %d days, %d hours, " + "%d minutes, %d seconds\n", + days, hours, minutes, sec); + } + if (hz > 0 && opt_clock_skew) clock_skew(hz,tstamp,rttms); + } else { + first_tstamp = tstamp; + first_mstime = mstime(); + } + printf("\n"); +} + +/* This function is exported to listen.c also */ +int read_packet(void *packet, int size) +{ + size = pcap_recv(packet, size); + if (size == -1) + perror("[wait_packet] pcap_recv()"); + return size; +} + +void hex_dump(void *packet, int size) +{ + unsigned char *byte = packet; + int count = 0; + + printf("\t\t"); + for (; byte < (unsigned char*) (packet+size); byte++) { + count++; + printf("%02x", *byte); + if (count % 2 == 0) printf(" "); + if (count % 16 == 0) printf("\n\t\t"); + } + printf("\n\n"); +} + +void human_dump(void *packet, int size) +{ + unsigned char *byte = packet; + int count = 0; + + printf("\t\t"); + for (; byte < (unsigned char*) (packet+size); byte++) { + count ++; + if (isprint(*byte)) + printf("%c", *byte); + else + printf("."); + if (count % 32 == 0) printf("\n\t\t"); + } + printf("\n\n"); +} + +void handle_hcmp(char *packet, int size) +{ + char *p; + struct hcmphdr hcmph; + unsigned int seq; + + /* Search for the reverse signature inside the packet */ + if ((p = memstr(packet, rsign, size)) == NULL) + return; + + if (opt_debug) + fprintf(stderr, "DEBUG: HCMP received\n"); + + p+=strlen(rsign); + if ((size-(packet-p)) < sizeof(struct hcmphdr)) { + if (opt_verbose || opt_debug) + fprintf(stderr, "bad HCMP len received\n"); + return; + } + + memcpy(&hcmph, p, sizeof(hcmph)); + + switch(hcmph.type) { + case HCMP_RESTART: + seq = ntohs(hcmph.typedep.seqnum); + src_id = seq; /* set the id */ + datafiller(NULL, seq); /* data seek */ + if (opt_debug) + printf("DEBUG: HCMP restart from %d\n", + seq); + return; + case HCMP_SOURCE_QUENCH: + case HCMP_SOURCE_STIRUP: + printf("HCMP source quench/stirup received\n"); + return; + default: + if (opt_verbose || opt_debug) + fprintf(stderr, "bad HCMP type received\n"); + return; + } +} diff --git a/statistics.c b/statistics.c deleted file mode 100644 index 744047c..0000000 --- a/statistics.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * $smu-mark$ - * $name: statistics.c$ - * $author: Salvatore Sanfilippo $ - * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ - * $license: This software is under GPL version 2 of license$ - * $date: Fri Nov 5 11:55:50 MET 1999$ - * $rev: 8$ - */ - -/* $Id: statistics.c,v 1.3 2004/04/09 23:38:56 antirez Exp $ */ - -#include -#include - -#include "hping2.h" -#include "globals.h" - -void print_statistics(int signal_id) -{ - unsigned int lossrate; - - close_pcap(); - if (recv_pkt > 0) - lossrate = 100 - ((recv_pkt*100)/sent_pkt); - else - if (!sent_pkt) - lossrate = 0; - else - lossrate = 100; - - fprintf(stderr, "\n--- %s hping statistic ---\n", targetname); - fprintf(stderr, "%d packets tramitted, %d packets received, " - "%d%% packet loss\n", sent_pkt, recv_pkt, lossrate); - if (out_of_sequence_pkt) - fprintf(stderr, "%d out of sequence packets received\n", - out_of_sequence_pkt); - fprintf(stderr, "round-trip min/avg/max = %.1f/%.1f/%.1f ms\n", - rtt_min, rtt_avg, rtt_max); - - /* manage exit code */ - if (opt_tcpexitcode) - { - exit(tcp_exitcode); - } - else - { - if (recv_pkt) - exit(0); - else - exit(1); - } -}; diff --git a/waitpacket.c b/waitpacket.c deleted file mode 100644 index a6c20f0..0000000 --- a/waitpacket.c +++ /dev/null @@ -1,780 +0,0 @@ -/* waitpacket.c -- handle and print the incoming packet - * Copyright(C) 1999-2001 Salvatore Sanfilippo - * Under GPL, see the COPYING file for more information about - * the license. */ - -/* $Id: waitpacket.c,v 1.4 2004/06/18 09:53:11 antirez Exp $ */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hping2.h" -#include "globals.h" - -static int icmp_unreach_rtt(void *quoted_ip, int size, - int *seqp, float *ms_delay); -static void print_tcp_timestamp(void *tcp, int tcpsize, int rttms); -static int recv_icmp(void *packet, size_t size); -static int recv_udp(void *packet, size_t size); -static int recv_tcp(void *packet, size_t size); -static void hex_dump(void *packet, int size); -static void human_dump(void *packet, int size); -static void handle_hcmp(char *packet, int size); - -static struct myiphdr ip; -static int ip_size; -static struct in_addr src, dst; - -/* This function is called for every matching packet received. - * If --beep option was specified, the user will hear a beep - * for every received packet. */ -void recv_beep(void) -{ - if (opt_beep) - printf("\a"); -} - -void wait_packet(void) -{ - int match = 0; - int size, iphdr_size, enc_size; - char packet [IP_MAX_SIZE+linkhdr_size]; - char *ip_packet, *enc_packet; - - size = read_packet(packet, IP_MAX_SIZE+linkhdr_size); - switch(size) { - case 0: - return; - case -1: - exit(1); - } - - /* Check if the packet is shorter than the link header size */ - if (size < linkhdr_size) { - if (opt_debug) - printf("DEBUG: WARNING: packet size < linkhdr_size\n"); - return; - } - - /* IP packet pointer and len */ - ip_packet = packet + linkhdr_size; - ip_size = size - linkhdr_size; - - /* Truncated IP header? */ - if (ip_size < IPHDR_SIZE) { - if (opt_debug) - printf("[|ip fix]\n"); - return; - } - - memcpy(&ip, packet+linkhdr_size, sizeof(ip)); - iphdr_size = ip.ihl * 4; - - /* Bad IP header len? */ - if (iphdr_size > ip_size) { - if (opt_debug) - printf("[|iphdr size]\n"); - return; - } - - /* Handle the HCMP for almost safe file transfer with hping */ - if (opt_sign) - handle_hcmp(ip_packet, ip_size); - - /* Check if the dest IP address is the one of our interface */ - if (memcmp(&ip.daddr, &local.sin_addr, sizeof(ip.daddr))) - return; - /* If the packet isn't an ICMP error it should come from - * our target IP addresss. We accepts packets from all the - * source if the random destination option is active */ - if (ip.protocol != IPPROTO_ICMP && !opt_rand_dest) { - if (memcmp(&ip.saddr, &remote.sin_addr, sizeof(ip.saddr))) - return; - } - - /* Get the encapsulated protocol offset and size */ - enc_packet = ip_packet + iphdr_size; - enc_size = ip_size - iphdr_size; - - /* Put the IP source and dest addresses in a struct in_addr */ - memcpy(&src, &(ip.saddr), sizeof(struct in_addr)); - memcpy(&dst, &(ip.daddr), sizeof(struct in_addr)); - - switch(ip.protocol) { - case IPPROTO_ICMP: - match = recv_icmp(enc_packet, enc_size); - break; - case IPPROTO_UDP: - match = recv_udp(enc_packet, enc_size); - break; - case IPPROTO_TCP: - match = recv_tcp(enc_packet, enc_size); - break; - default: - return; - } - - if (match) - recv_pkt++; - - /* Dump the packet in hex */ - if (opt_hexdump && match && !opt_quiet) - hex_dump(ip_packet, ip_size); - - /* Dump printable characters inside the packet */ - if (opt_contdump && match && !opt_quiet) - human_dump(ip_packet, ip_size); - - /* Display IP options */ - if (match && opt_rroute && !opt_quiet) - display_ipopt(ip_packet); - - /* --stop-tr stops hping in traceroute mode when the - * first not ICMP time exceeded packet is received */ - if (opt_traceroute && opt_tr_stop && match) { - struct myicmphdr icmp; - - if (ip.protocol != IPPROTO_ICMP) - print_statistics(0); - if (enc_size >= ICMPHDR_SIZE) { - memcpy(&icmp, enc_packet, sizeof(icmp)); - if (icmp.type != 11) - print_statistics(0); - } - } - - /* if the count was reached exit now */ - if (count != -1 && count == recv_pkt) - print_statistics(0); -} - -void log_ip(int status, int sequence) -{ - int rel_id, ip_id; - - /* get ip->id */ - if (opt_winid_order) - ip_id = ip.id; - else - ip_id = htons(ip.id); - - if (status == S_RECV) - printf("DUP! "); - - if (opt_relid) - rel_id = relativize_id(sequence, &ip_id); - else - rel_id = 0; - printf("len=%d ip=%s ttl=%d %sid%s%d ", ip_size, inet_ntoa(src), - ip.ttl, - (ntohs(ip.frag_off) ? "DF " : ""), - (rel_id ? "=+" : "="), ip_id); - if (opt_verbose && !opt_quiet) - printf("tos=%x iplen=%u\n", ip.tos, htons(ip.tot_len)); -} - -void log_icmp_ts(void *ts) -{ - struct icmp_tstamp_data icmp_tstamp; - - memcpy(&icmp_tstamp, ts, sizeof(icmp_tstamp)); - printf("ICMP timestamp: Originate=%u Receive=%u Transmit=%u\n", - (unsigned int) ntohl(icmp_tstamp.orig), - (unsigned int) ntohl(icmp_tstamp.recv), - (unsigned int) ntohl(icmp_tstamp.tran)); - printf("ICMP timestamp RTT tsrtt=%lu\n\n", - (long unsigned int) (get_midnight_ut_ms() - - ntohl(icmp_tstamp.orig))); -} - -void log_icmp_addr(void *addrptr) -{ - unsigned char *addr = addrptr; - printf("ICMP address mask: icmpam=%u.%u.%u.%u\n\n", - addr[0], addr[1], addr[2], addr[3]); -} - -void log_traceroute(void *packet, int size, int icmp_code) -{ - static unsigned char old_src_addr[4] = { 0, 0, 0, 0 }; - int sequence = 0, retval; - float rtt; - - if (!opt_tr_keep_ttl && !memcmp(&ip.saddr, old_src_addr, 4)) - return; - - retval = icmp_unreach_rtt(packet+ICMPHDR_SIZE, size-ICMPHDR_SIZE, - &sequence, &rtt); - memcpy(old_src_addr, &ip.saddr, sizeof(ip.saddr)); - printf("hop=%d ", src_ttl); - fflush(stdout); - log_icmp_timeexc(inet_ntoa(src), icmp_code); - if (retval != -1) - printf("hop=%d hoprtt=%.1f ms\n", - src_ttl, rtt); - if (!opt_tr_keep_ttl) - src_ttl++; -} - -int recv_icmp(void *packet, size_t size) -{ - struct myicmphdr icmp; - struct myiphdr quoted_ip; - - /* Check if the packet can contain the ICMP header */ - if (size < ICMPHDR_SIZE) { - printf("[|icmp]\n"); - return 0; - } - memcpy(&icmp, packet, sizeof(icmp)); - - /* --------------------------- * - * ICMP ECHO/TIMESTAMP/ADDRESS * - * --------------------------- */ - if ((icmp.type == ICMP_ECHOREPLY || - icmp.type == ICMP_TIMESTAMPREPLY || - icmp.type == ICMP_ADDRESSREPLY) && - icmp.un.echo.id == (getpid() & 0xffff)) - { - int icmp_seq = icmp.un.echo.sequence; - int status; - float ms_delay; - - recv_beep(); - /* obtain round trip time */ - status = rtt(&icmp_seq, 0, &ms_delay); - log_ip(status, icmp_seq); - - printf("icmp_seq=%d rtt=%.1f ms\n", icmp_seq, ms_delay); - if (icmp.type == ICMP_TIMESTAMPREPLY) { - if ((size - ICMPHDR_SIZE) >= 12) - log_icmp_ts(packet+ICMPHDR_SIZE); - else - printf("[|icmp timestamp]\n"); - } else if (icmp.type == ICMP_ADDRESSREPLY) { - if ((size - ICMPHDR_SIZE) >= 4) - log_icmp_addr(packet+ICMPHDR_SIZE); - else - printf("[|icmp subnet address]\n"); - } - return 1; - } - /* ------------------------------------ * - * ICMP DEST UNREACHABLE, TIME EXCEEDED * - * ------------------------------------ */ - else if (icmp.type == 3 || icmp.type == 11) { - if ((size - ICMPHDR_SIZE) < sizeof(struct myiphdr)) { - printf("[|icmp quoted ip]\n"); - return 0; - } - memcpy("ed_ip, packet+ICMPHDR_SIZE, sizeof(quoted_ip)); - if (memcmp("ed_ip.daddr, &remote.sin_addr, - sizeof(quoted_ip.daddr)) || - memcmp(&ip.daddr, &local.sin_addr, sizeof(ip.daddr))) - return 0; /* addresses don't match */ - /* Now we can handle the specific type */ - switch(icmp.type) { - case 3: - if (!opt_quiet) - log_icmp_unreach(inet_ntoa(src), icmp.code); - return 1; - case 11: - if (opt_traceroute) - log_traceroute(packet, size, icmp.code); - else - log_icmp_timeexc(inet_ntoa(src), icmp.code); - return 1; - } - } - - return 0; /* don't match */ -} - -int recv_udp(void *packet, size_t size) -{ - struct myudphdr udp; - int sequence = 0, status; - float ms_delay; - - if (size < UDPHDR_SIZE) { - printf("[|udp]\n"); - return 0; - } - memcpy(&udp, packet, sizeof(udp)); - - /* check if the packet matches */ - if ((ntohs(udp.uh_sport) == dst_port) || - (opt_force_incdport && - (ntohs(udp.uh_sport) >= base_dst_port && - ntohs(udp.uh_sport) <= dst_port))) - { - recv_beep(); - status = rtt(&sequence, ntohs(udp.uh_dport), &ms_delay); - if (!opt_quiet) { - log_ip(status, sequence); - printf("seq=%d rtt=%.1f ms\n", sequence, ms_delay); - } - if (opt_incdport && !opt_force_incdport) - dst_port++; - return 1; - } - return 0; -} - -int recv_tcp(void *packet, size_t size) -{ - struct mytcphdr tcp; - int sequence = 0, status; - float ms_delay; - char flags[16]; - - if (size < TCPHDR_SIZE) { - printf("[|tcp]\n"); - return 0; - } - memcpy(&tcp, packet, sizeof(tcp)); - - /* check if the packet matches */ - if ((ntohs(tcp.th_sport) == dst_port) || - (opt_force_incdport && - (ntohs(tcp.th_sport) >= base_dst_port && - ntohs(tcp.th_sport) <= dst_port))) - { - recv_beep(); - tcp_exitcode = tcp.th_flags; - - status = rtt(&sequence, ntohs(tcp.th_dport), &ms_delay); - - if (opt_seqnum) { - static __u32 old_th_seq = 0; - __u32 seq_diff, tmp; - - tmp = ntohl(tcp.th_seq); - if (tmp >= old_th_seq) - seq_diff = tmp - old_th_seq; - else - seq_diff = (4294967295U - old_th_seq) - + tmp; - old_th_seq = tmp; - printf("%10lu +%lu\n", - (unsigned long) tmp, - (unsigned long) seq_diff); - goto out; - } - - if (opt_quiet) - goto out; - - flags[0] = '\0'; - if (tcp.th_flags & TH_RST) strcat(flags, "R"); - if (tcp.th_flags & TH_SYN) strcat(flags, "S"); - if (tcp.th_flags & TH_ACK) strcat(flags, "A"); - if (tcp.th_flags & TH_FIN) strcat(flags, "F"); - if (tcp.th_flags & TH_PUSH) strcat(flags, "P"); - if (tcp.th_flags & TH_URG) strcat(flags, "U"); - if (tcp.th_flags & TH_X) strcat(flags, "X"); - if (tcp.th_flags & TH_Y) strcat(flags, "Y"); - if (flags[0] == '\0') strcat(flags, "none"); - - log_ip(status, sequence); - printf("sport=%d flags=%s seq=%d win=%d rtt=%.1f ms\n", - ntohs(tcp.th_sport), flags, sequence, - ntohs(tcp.th_win), ms_delay); - - if (opt_verbose) { - printf("seq=%lu ack=%lu sum=%x urp=%u\n\n", - (unsigned long) ntohl(tcp.th_seq), - (unsigned long) ntohl(tcp.th_ack), - tcp.th_sum, ntohs(tcp.th_urp)); - } - - /* Get and log the TCP timestamp */ - if (opt_tcp_timestamp && status != S_RECV) - print_tcp_timestamp(packet, size, (int)ms_delay); -out: - if (opt_incdport && !opt_force_incdport) - dst_port++; - return 1; - } - return 0; -} - -/* Try to extract information about the original packet from the - * ICMP error to obtain the round time trip - * - * Note that size is the the packet size starting from the - * IP packet quoted in the ICMP error, it may be negative - * if the ICMP is broken */ -int icmp_unreach_rtt(void *quoted_ip, int size, int *seqp, float *ms_delay) -{ - int src_port; - int sequence = 0; - int quoted_iphdr_size; - struct myudphdr udp; - struct myicmphdr icmp; - struct myiphdr qip; - - /* The user specified --no-rtt */ - if (opt_tr_no_rtt) - return -1; - - if (size < sizeof(struct myiphdr)) - return -1; - memcpy(&qip, quoted_ip, sizeof(struct myiphdr)); - quoted_iphdr_size = qip.ihl << 2; - /* Ok, enough room, try to get the rtt, - * but check if the original packet was an UDP/TCP one */ - if (qip.protocol == IPPROTO_TCP || - qip.protocol == IPPROTO_UDP) { - /* We need at least 2 bytes of the quoted UDP/TCP header - * for the source port */ - if ((size - quoted_iphdr_size) < 2) - return -1; - - /* Use the UDP header for both UDP and TCP, they are - * the same in the 4 first bytes (source and dest port) */ - memcpy(&udp, quoted_ip+quoted_iphdr_size, sizeof(udp)); - src_port = htons(udp.uh_sport); - return rtt(&sequence, src_port, ms_delay); - } else if (qip.protocol == IPPROTO_ICMP) { - int s; - - /* We need the whole 8 byte ICMP header to get - * the sequence field, also the type must be - * ICMP_ECHO */ - memcpy(&icmp, quoted_ip+quoted_iphdr_size, sizeof(icmp)); - if ((size - quoted_iphdr_size) < 8 || - icmp.type != ICMP_ECHO) - return -1; - - s = icmp.un.echo.sequence; - return rtt(&s, 0, ms_delay); - } - return -1; /* no way */ -} - -void clock_skew(int hz, __u32 tstamp, int rttms) -{ - long long tstampms = tstamp*(1000/hz); - long long tstampms2; /* tstamp after rtt correction */ - long long currdelta; /* current delta */ - long long localms; /* local clock */ - static long long *deltavect = NULL; /* delta vector, for samples collection */ - static long long *deltartt = NULL; /* rtt of every tstamp packet */ - - /* Deltas in deltavect with deltartt information are used to - * get samples of the time difference between the local host and - * the remote host. Every cs_vector_len packets caputed in the - * deltvact array are used to estimate the time delta that's - * put in turrn into the sample vector. */ - - static int deltanum = 0; /* number of deltas in deltavect */ - static long long *sample = NULL; /* error corrected delta vector */ - static long long *samplelocal = NULL; /* local time of captured delta vector */ - static int samplelen = 0; - - if (deltavect == NULL) { - deltavect = malloc(sizeof(*deltavect)*cs_vector_len); - deltartt = malloc(sizeof(*deltartt)*cs_vector_len); - if (deltavect == NULL) { - fprintf(stderr, "Out of memory in clock_skew()\n"); - exit(1); - } - deltanum = 0; - } - - printf(" Clock skew detection...\n"); - printf(" hz: %d\n", hz); - printf(" received tstamp (converted in ms according to hz): %lld\n", tstampms); - printf(" rtt in milliseconds: %d\n", rttms); - - tstampms2 = tstampms-(rttms/2); /* Assuming symmetric path for packets... */ - localms = mstime(); - currdelta = localms-tstampms2; - printf(" tstamp-(rtt/2): %lld\n", tstampms2); - printf(" local/remote clock delta: %lld\n", currdelta); - deltavect[deltanum] = currdelta; - deltartt[deltanum] = rttms; - deltanum++; - - /* When cs_vector_len packets are captured we can estimate - * the current clock difference between our local PC and the remote - * host. We call every delta estimation a "sample" */ - if (deltanum == cs_vector_len) { - long long sum = 0; - unsigned long long minrtt; - int j, validpackets; - - /* First we check what's the minimum RTT. We'll later - * discard packets with an RTT too high compared to - * the minimum one as this are source of errors. */ - minrtt = deltartt[0]; - for (j = 1; j < cs_vector_len; j++) - if (deltartt[j] < minrtt) minrtt = deltartt[j]; - - /* Now we can average the deltavect elements to get a - * sample. In the process information from packets with - * an rtt greater than 10% of the the min rtt are discarded */ - - validpackets = 0; - for (j = 0; j < cs_vector_len; j++) { - if (minrtt > 10 && (deltartt[j]-minrtt > minrtt/10)) { - printf(" # Not used packet %d/%d with rtt %lld (max acceptable %lld)\n", j+1, cs_vector_len, deltartt[j], minrtt+(minrtt/10)); - continue; - } - sum += deltavect[j]; - validpackets++; - } - - deltanum = 0; /* reset the counter anyway */ - if (validpackets) { - sum /= validpackets; - printf(" >> error corrected delta: %lld** (based on %d of %d packets)\n", sum, validpackets, cs_vector_len); - sample = realloc(sample,sizeof(*sample)*(samplelen+1)); - samplelocal = realloc(samplelocal,sizeof(*samplelocal)*(samplelen+1)); - if (!sample || !samplelocal) { - fprintf(stderr, "Out of memory in clock_skew()\n"); - exit(1); - } - sample[samplelen] = sum; - samplelocal[samplelen] = mstime(); - samplelen++; - } - } - - /* If we have enough data to start to compute the - * skew, compute it and display the information. */ - if (samplelen > cs_window_shift && - samplelocal[samplelen-1]-samplelocal[cs_window_shift-1] > cs_window*1000) - { - int i = samplelen-2, j; - long long skew, skewsum = 0, delta, localdelta = 0; - - /* Search the first sample from right to left so that - * the local time difference is >= the selected window */ - while(samplelocal[samplelen-1]-samplelocal[i]= 0; j--) { - localdelta = samplelocal[samplelen-1-j]-samplelocal[i-j]; - delta = sample[samplelen-1-j]-sample[i-j]; - skew = (delta*1000000)/localdelta; /* nanoseconds */ - printf("%lld ", skew); - skewsum += skew; - } - printf(") next line is the average\n"); - skewsum /= cs_window_shift; - printf(" %d sec. window SKEW: %lld nanoseconds/second\n", cs_window, skewsum); - /* Compute the SKEW from the full range of samples we have */ - skewsum = 0; - for (j = 0; j < cs_window_shift; j++) { - localdelta = samplelocal[samplelen-1-j]-samplelocal[cs_window_shift-1-j]; - delta = sample[samplelen-1-j]-sample[cs_window_shift-1-j]; - skew = (delta*1000000)/localdelta; /* nanoseconds */ - skewsum += skew; - } - skewsum /= cs_window_shift; - printf("> %lld sec. window SKEW: %lld nanoseconds/second\n", localdelta/1000, skewsum); - } else { - printf(" !! Not enough data to show reliable skew, wait please...\n"); - if (samplelen > 1) { - long long skew = 0, delta, localdelta; - localdelta = samplelocal[samplelen-1]-samplelocal[0]; - delta = sample[samplelen-1]-sample[0]; - skew = (delta*1000000)/localdelta; - printf("\n Early info just to take you happy... ;)\n"); - printf(" early unreliable skew guess: %lld nanoseconds per second\n", skew); - printf(" early guess localdelta: %lld ms\n", localdelta); - printf(" early delta: %lld ms\n", delta); - } - } - printf(" collected %d/%d deltas for next sample\n", - deltanum, cs_vector_len); -} - -void print_tcp_timestamp(void *tcp, int tcpsize, int rttms) -{ - int optlen; - unsigned char *opt; - __u32 tstamp = 0, echo; - static __u32 first_tstamp = 0; - static unsigned long long first_mstime = 0; - struct mytcphdr tmptcphdr; - unsigned int tcphdrlen; - - if (tcpsize < TCPHDR_SIZE) - return; - memcpy(&tmptcphdr, tcp, sizeof(struct mytcphdr)); - tcphdrlen = tmptcphdr.th_off * 4; - - /* bad len or no options in the TCP header */ - if (tcphdrlen <= 20 || tcphdrlen < tcpsize) - return; - optlen = tcphdrlen - TCPHDR_SIZE; - opt = (unsigned char*)tcp + TCPHDR_SIZE; /* skips the TCP fix header */ - while(optlen) { - switch(*opt) { - case 0: /* end of option */ - return; - case 1: /* noop */ - opt++; - optlen--; - continue; - default: - if (optlen < 2) - return; - if (opt[1] > optlen) - return; - if (opt[0] != 8) { /* not timestamp */ - optlen -= opt[1]; - opt += opt[1]; - continue; - } - /* timestamp found */ - if (opt[1] != 10) /* bad len */ - return; - memcpy(&tstamp, opt+2, 4); - memcpy(&echo, opt+6, 4); - tstamp = ntohl(tstamp); - echo = ntohl(echo); - goto found; - } - } -found: - printf(" TCP timestamp: tcpts=%u\n", tstamp); - if (first_tstamp) { - int tsdiff; - int hz_set[] = { 2, 10, 100, 1000, 0 }; - int hzdiff = -1; - int hz = 0, sec; - int days, hours, minutes; - unsigned long long mswait; - - mswait = mstime()-first_mstime; - tsdiff = (int)(((long long)(tstamp - first_tstamp)*1000)/mswait); - if (tsdiff > 0) { - int i = 0; - while(hz_set[i]) { - if (hzdiff == -1) { - hzdiff = ABS(tsdiff-hz_set[i]); - hz = hz_set[i]; - } else if (hzdiff > ABS(tsdiff-hz_set[i])) { - hzdiff = ABS(tsdiff-hz_set[i]); - hz = hz_set[i]; - } - i++; - } - printf(" HZ seems hz=%d (%d measured)\n", hz, tsdiff); - sec = tstamp/hz; /* Get the uptime in seconds */ - days = sec / (3600*24); - sec %= 3600*24; - hours = sec / 3600; - sec %= 3600; - minutes = sec / 60; - sec %= 60; - printf(" System uptime seems: %d days, %d hours, " - "%d minutes, %d seconds\n", - days, hours, minutes, sec); - } - if (hz > 0 && opt_clock_skew) clock_skew(hz,tstamp,rttms); - } else { - first_tstamp = tstamp; - first_mstime = mstime(); - } - printf("\n"); -} - -/* This function is exported to listen.c also */ -int read_packet(void *packet, int size) -{ - size = pcap_recv(packet, size); - if (size == -1) - perror("[wait_packet] pcap_recv()"); - return size; -} - -void hex_dump(void *packet, int size) -{ - unsigned char *byte = packet; - int count = 0; - - printf("\t\t"); - for (; byte < (unsigned char*) (packet+size); byte++) { - count++; - printf("%02x", *byte); - if (count % 2 == 0) printf(" "); - if (count % 16 == 0) printf("\n\t\t"); - } - printf("\n\n"); -} - -void human_dump(void *packet, int size) -{ - unsigned char *byte = packet; - int count = 0; - - printf("\t\t"); - for (; byte < (unsigned char*) (packet+size); byte++) { - count ++; - if (isprint(*byte)) - printf("%c", *byte); - else - printf("."); - if (count % 32 == 0) printf("\n\t\t"); - } - printf("\n\n"); -} - -void handle_hcmp(char *packet, int size) -{ - char *p; - struct hcmphdr hcmph; - unsigned int seq; - - /* Search for the reverse signature inside the packet */ - if ((p = memstr(packet, rsign, size)) == NULL) - return; - - if (opt_debug) - fprintf(stderr, "DEBUG: HCMP received\n"); - - p+=strlen(rsign); - if ((size-(packet-p)) < sizeof(struct hcmphdr)) { - if (opt_verbose || opt_debug) - fprintf(stderr, "bad HCMP len received\n"); - return; - } - - memcpy(&hcmph, p, sizeof(hcmph)); - - switch(hcmph.type) { - case HCMP_RESTART: - seq = ntohs(hcmph.typedep.seqnum); - src_id = seq; /* set the id */ - datafiller(NULL, seq); /* data seek */ - if (opt_debug) - printf("DEBUG: HCMP restart from %d\n", - seq); - return; - case HCMP_SOURCE_QUENCH: - case HCMP_SOURCE_STIRUP: - printf("HCMP source quench/stirup received\n"); - return; - default: - if (opt_verbose || opt_debug) - fprintf(stderr, "bad HCMP type received\n"); - return; - } -}