pax_global_header00006660000000000000000000000064150104621150014505gustar00rootroot0000000000000052 comment=1eeef3e70e101cdc9eb48b178bc27a9093aea2ce zmap-4.3.4/000077500000000000000000000000001501046211500124645ustar00rootroot00000000000000zmap-4.3.4/.clang-format000066400000000000000000000004271501046211500150420ustar00rootroot00000000000000BasedOnStyle: LLVM IndentWidth: 8 UseTab: Always BreakBeforeBraces: Linux AllowShortIfStatementsOnASingleLine: false IndentCaseLabels: false DerivePointerAlignment: false PointerAlignment: Right BreakStringLiterals: false SortIncludes: false ReflowComments: false ColumnLimit: 0 zmap-4.3.4/.editorconfig000066400000000000000000000003231501046211500151370ustar00rootroot00000000000000root = true [*] end_of_line = lf insert_final_newline = true [*.{c,h}] indent_style = tab indent_size = 8 [CMakeLists.txt] indent_style = spaces indent_size = 4 [*.py] indent_style = spaces indent_size = 4 zmap-4.3.4/.github/000077500000000000000000000000001501046211500140245ustar00rootroot00000000000000zmap-4.3.4/.github/CODEOWNERS000066400000000000000000000003151501046211500154160ustar00rootroot00000000000000# Lines starting with '#' are comments. # Each line is a file pattern followed by one or more owners. # These owners will be the default owners for everything in the repo. * @zmap/zmap-maintainers zmap-4.3.4/.github/ISSUE_TEMPLATE/000077500000000000000000000000001501046211500162075ustar00rootroot00000000000000zmap-4.3.4/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000020011501046211500206720ustar00rootroot00000000000000--- name: Bug report about: ZMap is sending or receiving packets incorrectly title: '' labels: bug assignees: '' --- > Notice: Please don't file a bug report for questions on how to use ZMap, etc. Check out our [Resources](https://github.com/zmap/zmap/tree/main#resources) section for FAQ and feel free to chime in on [Github Discussions](https://github.com/zmap/zmap/discussions) if you're still unclear and we'll be happy to assist! **Describe the bug** A clear and concise description of what the bug is. Inability to get ZMap to run on a specific platform or network is not considered a bug. **CLI Arguments** Please paste your ZMap invocation below ``` # Paste Here ``` **Example Target IP** Please list any IPs that can be used for testing behavior. **Expected behavior** A clear and concise description of what you expected to happen. **Environment:** - OS: [e.g. Ubuntu Server 18.04] - Version: [e.g. from package manager, Github HEAD] **Additional context** Add any other context about the problem here. zmap-4.3.4/.github/workflows/000077500000000000000000000000001501046211500160615ustar00rootroot00000000000000zmap-4.3.4/.github/workflows/arch.Dockerfile000066400000000000000000000006201501046211500207650ustar00rootroot00000000000000FROM archlinux:latest RUN pacman-key --init RUN pacman -Syu --noconfirm RUN pacman -S --noconfirm base-devel cmake gmp gengetopt libpcap flex byacc json-c pkg-config libunistring judy python RUN pacman -Scc --noconfirm WORKDIR /zmap COPY . . RUN ls RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE . RUN make RUN cd .. RUN python ./scripts/check_manfile.py zmap-4.3.4/.github/workflows/cmake.yml000066400000000000000000000110361501046211500176650ustar00rootroot00000000000000name: CMake on: push: branches: [ main ] pull_request: branches: [ main ] env: ENABLE_DEVELOPMENT: ON ENABLE_LOG_TRACE: ON jobs: build-ubuntu: runs-on: ubuntu-latest container: image: ghcr.io/zmap/builder:2023-09-10 volumes: - ${{github.workspace}}:/zmap steps: - uses: actions/checkout@v2 - name: Make build directory run: mkdir -p /zmap/build - name: Configure CMake working-directory: /zmap/build # Configure CMake in a 'build' subdirectory. run: cmake -DENABLE_DEVELOPMENT=${{env.ENABLE_DEVELOPMENT}} -DENABLE_LOG_TRACE=${{env.ENABLE_LOG_TRACE}} /zmap - name: Build working-directory: /zmap/build # Build your program with the given configuration run: make - name: Check Manpages working-directory: /zmap run: python3 ./scripts/check_manfile.py build-ubuntu-16-04: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Compilation run: | docker build -t ubuntu-16.04-container -f .github/workflows/ubuntu-16.04.Dockerfile . docker run ubuntu-16.04-container build-ubuntu-18-04: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Compilation run: | docker build -t ubuntu-18.04-container -f .github/workflows/ubuntu-18.04.Dockerfile . docker run ubuntu-18.04-container build-ubuntu-20-04: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Compilation run: | docker build -t ubuntu-20.04-container -f .github/workflows/ubuntu-20.04.Dockerfile . docker run ubuntu-20.04-container build-ubuntu-22-04: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Compilation run: | docker build -t ubuntu-22.04-container -f .github/workflows/ubuntu-22.04.Dockerfile . docker run ubuntu-22.04-container build-ubuntu-24-04: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Compilation run: | docker build -t ubuntu-24.04-container -f .github/workflows/ubuntu-24.04.Dockerfile . docker run ubuntu-24.04-container build-debian: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Check Debian Compilation run: | docker build -t debian-container -f .github/workflows/debian.Dockerfile . docker run debian-container build-arch: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Check Arch Compilation run: | docker build -t arch-container -f .github/workflows/arch.Dockerfile . docker run arch-container build-fedora: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Check Fedora Compilation run: | docker build -t fedora-container -f .github/workflows/fedora.Dockerfile . docker run fedora-container build-mac: runs-on: macos-15 steps: - uses: actions/checkout@v2 - name: Download dependencies judy run: brew install judy - name: Download other deps run: brew install pkg-config cmake gmp gengetopt json-c byacc libunistring - name: Configure CMake # Configure CMake in a 'build' subdirectory. run: cmake -DENABLE_DEVELOPMENT=${{env.ENABLE_DEVELOPMENT}} -DENABLE_LOG_TRACE=${{env.ENABLE_LOG_TRACE}} . - name: Build # Build your program with the given configuration run: make - name: Check Manpages run: python3 ./scripts/check_manfile.py build-freebsd: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Test in FreeBSD id: test uses: vmactions/freebsd-vm@v1 with: envs: 'ENABLE_DEVELOPMENT ENABLE_LOG_TRACE' usesh: true prepare: | freebsd-update cron freebsd-update install pkg install -y judy byacc cmake flex gengetopt gmp json-c libunistring influxpkg-config python3 run: cd ~/work/zmap/zmap && cmake -DENABLE_DEVELOPMENT=${{env.ENABLE_DEVELOPMENT}} -DENABLE_LOG_TRACE=${{env.ENABLE_LOG_TRACE}} . && make && python3 ./scripts/check_manfile.py zmap-4.3.4/.github/workflows/debian.Dockerfile000066400000000000000000000006721501046211500213010ustar00rootroot00000000000000FROM debian:latest RUN apt-get update \ && apt-get install -y build-essential cmake libgmp3-dev gengetopt libpcap-dev flex \ byacc libjson-c-dev pkg-config libunistring-dev libjudy-dev cmake make python3 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /zmap COPY . . RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE . \ && make RUN python3 ./scripts/check_manfile.pyzmap-4.3.4/.github/workflows/docker-publish.yml000066400000000000000000000030221501046211500215140ustar00rootroot00000000000000name: Docker on: push: branches: - main tags: - v* env: IMAGE_NAME: zmap jobs: push: runs-on: ubuntu-latest permissions: packages: write contents: read steps: - uses: actions/checkout@v3 - uses: docker/setup-qemu-action@v1 - uses: docker/setup-buildx-action@v1 - name: Generate Image Tag id: image-tag run: | IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME # Change all uppercase to lowercase IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') # Strip git ref prefix from version VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') # Strip "v" prefix from tag name [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') # Use Docker `latest` tag convention [ "$VERSION" == "main" ] && VERSION=latest echo IMAGE_ID=$IMAGE_ID echo VERSION=$VERSION echo "::set-output name=IMG_TAG::${IMAGE_ID}:${VERSION}" - name: Log into GitHub Container Registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - name: Build and push uses: docker/build-push-action@v2 with: context: . push: true pull: true cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64,linux/arm64 tags: ${{ steps.image-tag.outputs.IMG_TAG }}zmap-4.3.4/.github/workflows/fedora.Dockerfile000066400000000000000000000005471501046211500213200ustar00rootroot00000000000000FROM fedora:latest RUN dnf update -y \ && dnf install -y gcc cmake gmp-devel gengetopt libpcap-devel flex byacc json-c-devel libunistring-devel Judy-devel python3 \ && dnf clean all WORKDIR /zmap COPY . . RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE . \ && make RUN python3 ./scripts/check_manfile.pyzmap-4.3.4/.github/workflows/integration.yml000066400000000000000000000007211501046211500211270ustar00rootroot00000000000000name: Integration Validation on: push: branches: [ main ] pull_request: branches: [ main ] env: ENABLE_DEVELOPMENT: ON ENABLE_LOG_TRACE: ON jobs: integration-tests: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v2 - name: Run Pytest run: | docker build -t pytest-container -f .github/workflows/pytest.Dockerfile . docker run pytest-container zmap-4.3.4/.github/workflows/pytest.Dockerfile000066400000000000000000000010341501046211500214000ustar00rootroot00000000000000FROM ubuntu:latest RUN apt-get update RUN apt-get install -y build-essential cmake libgmp3-dev gengetopt libpcap-dev flex \ byacc libjson-c-dev pkg-config libunistring-dev libjudy-dev cmake make python3 python3-pytest python3-timeout-decorator python3-bitarray curl RUN apt-get clean WORKDIR /zmap COPY . . RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE . \ && make WORKDIR /zmap/test/integration-tests # need to get the gateway mac RUN curl zmap.io \ && pytest -vv --durations=0 zmap-4.3.4/.github/workflows/scan_coverage.yml000066400000000000000000000015551501046211500214110ustar00rootroot00000000000000name: Daily ZMap Coverage Test # This workflow is triggered daily against main # It tests that in --fast-dryrun mode that ZMap scans all expected IPs+ports and doesn't scan targets multiple times # This test takes a while to run on: # Allow manual triggering via the GitHub Actions UI workflow_dispatch: # Schedule the workflow to run once per day schedule: - cron: "0 0 * * *" # Adjust the time as needed (this example runs at midnight UTC) env: ENABLE_DEVELOPMENT: ON ENABLE_LOG_TRACE: ON WITH_AES_HW: ON jobs: daily_scan_coverage_test: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v3 - name: Run Scan Coverage Tests run: | docker build -t coverage-container -f .github/workflows/scan_coverage_pytest.Dockerfile . docker run coverage-container zmap-4.3.4/.github/workflows/scan_coverage_pytest.Dockerfile000066400000000000000000000013021501046211500242550ustar00rootroot00000000000000FROM ubuntu:latest RUN apt-get update RUN apt-get install -y build-essential cmake libgmp3-dev gengetopt libpcap-dev flex byacc libjson-c-dev pkg-config \ libunistring-dev libjudy-dev cmake make python3 python3-pytest python3-timeout-decorator python3-bitarray curl RUN apt-get clean WORKDIR /zmap COPY . . RUN rm -f CMakeCache.txt # if building locally, this file can be present and cause build failure RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE -DWITH_AES_HW=$WITH_AES_HW . \ && make -j4 WORKDIR /zmap/test/integration-tests # need to get the gateway mac RUN curl zmap.io \ # launch the test && python3 test_full_ipv4_multi_port_scan.py zmap-4.3.4/.github/workflows/ubuntu-16.04.Dockerfile000066400000000000000000000007621501046211500220470ustar00rootroot00000000000000FROM ubuntu:16.04 # Set non-interactive mode so that apt-get does not prompt for input ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update \ && apt-get install -y build-essential cmake libgmp3-dev gengetopt libpcap-dev flex \ byacc libjson-c-dev pkg-config libunistring-dev libjudy-dev cmake make \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /zmap COPY . . RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE . \ && makezmap-4.3.4/.github/workflows/ubuntu-18.04.Dockerfile000066400000000000000000000007621501046211500220510ustar00rootroot00000000000000FROM ubuntu:18.04 # Set non-interactive mode so that apt-get does not prompt for input ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update \ && apt-get install -y build-essential cmake libgmp3-dev gengetopt libpcap-dev flex \ byacc libjson-c-dev pkg-config libunistring-dev libjudy-dev cmake make \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /zmap COPY . . RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE . \ && makezmap-4.3.4/.github/workflows/ubuntu-20.04.Dockerfile000066400000000000000000000007621501046211500220420ustar00rootroot00000000000000FROM ubuntu:20.04 # Set non-interactive mode so that apt-get does not prompt for input ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update \ && apt-get install -y build-essential cmake libgmp3-dev gengetopt libpcap-dev flex \ byacc libjson-c-dev pkg-config libunistring-dev libjudy-dev cmake make \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /zmap COPY . . RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE . \ && makezmap-4.3.4/.github/workflows/ubuntu-22.04.Dockerfile000066400000000000000000000007621501046211500220440ustar00rootroot00000000000000FROM ubuntu:22.04 # Set non-interactive mode so that apt-get does not prompt for input ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update \ && apt-get install -y build-essential cmake libgmp3-dev gengetopt libpcap-dev flex \ byacc libjson-c-dev pkg-config libunistring-dev libjudy-dev cmake make \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /zmap COPY . . RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE . \ && makezmap-4.3.4/.github/workflows/ubuntu-24.04.Dockerfile000066400000000000000000000007621501046211500220460ustar00rootroot00000000000000FROM ubuntu:24.04 # Set non-interactive mode so that apt-get does not prompt for input ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update \ && apt-get install -y build-essential cmake libgmp3-dev gengetopt libpcap-dev flex \ byacc libjson-c-dev pkg-config libunistring-dev libjudy-dev cmake make \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /zmap COPY . . RUN cmake -DENABLE_DEVELOPMENT=$ENABLE_DEVELOPMENT -DENABLE_LOG_TRACE=$ENABLE_LOG_TRACE . \ && makezmap-4.3.4/.gitignore000066400000000000000000000006241501046211500144560ustar00rootroot00000000000000!.clang-format *.o *.a *.pyc *.pyo *~ \#* src/zmap src/zopt.h src/zopt.c src/zbopt.h src/zbopt.c src/zitopt.c src/zitopt.h src/topt.c src/topt.h src/ztopt.c src/ztopt.h src/*.ggo src/zblocklist src/ztee src/ziterate lexer.c lexer.h parser.c parser.h *.deb !.gitignore !.travis.yml cmake_installer.sh CMakeFiles *.cmake Makefile CMakeCache.txt install_manifest.txt _CPack_Packages/* src/ztests *.DS_Store zmap-4.3.4/10gigE.md000066400000000000000000000037321501046211500140270ustar00rootroot0000000000000010GigE (Zippier) ZMap =========== It is possible to build ZMap to run at 95% of 10 GigE linespeed, sending over 14 million packets per second. This requires a compatible Intel 10 Gbps Ethernet NIC and Linux. ### Prerequisites 0. A working ZMap development environment (see [INSTALL.md](install.md)) 1. A [PF_RING ZC](http://www.ntop.org/products/pf_ring/pf_ring-zc-zero-copy/) license from ntop. 2. PF_RING ZC headers and kernel module 3. A 10 Gbps NIC with compatible "PF_RING-aware" drivers 4. A Linux (not BSD or Mac) installation 5. For best results, a computer with at least 8 *physical* cores on the same NUMA node. 6. libnuma (`sudo apt-get install libnuma-dev`) ### Building Most build errors are due to incorrectly building or installing PF_RING. Make sure you have build the drivers, the kernel module, and the userland library, as well as install the headers and kernel module to the correct locations. The PF_RING `make install` command might not copy `pfring_zc.h` to `/usr/include`, in which case manually install the file and set permissions correctly. To build navigate to the root of the repository and run: ``` $ cmake -DWITH_PFRING=ON -DENABLE_DEVELOPMENT=OFF . $ make ``` ### Running You'll have to carefully select the number of threads to use, as well as specify as zero-copy interface, e.g. `zc:eth1`. Use the `--cores` option to pick which cores to pin to. Make sure to pin to different physical cores, and note that some machines interleave physical and "virtual" cores. ``` $ sudo ./src/zmap -p 80 -i zc:eth7 -o output.csv -T 5 ``` ### Considerations DO NOT TAKE THIS LIGHTLY! Running ZMap at 10Gbps hits every /16 on the Internet over 200 times a second. Even if you have a large source IP range to scan from, it's very obvious that you're scanning. As always, follow scanning best practices, honor blocklist requests, and signal benign/research intent via domain names and websites on your scan IPs. Remember, you're sending a lot of traffic. zmap-4.3.4/AUTHORS000066400000000000000000000005071501046211500135360ustar00rootroot00000000000000Zakir Durumeric David Adrian Phillip Stephens Daniel Roethlisberger Eric Wustrow J. Alex Halderman Paul Pearce Ariana Mirian HD Moore zmap-4.3.4/CHANGELOG.md000066400000000000000000000314231501046211500143000ustar00rootroot00000000000000# 1.0.0 2013-8-16 * Initial public release. # 1.0.1 2013-8-17 ## BUGFIX * Issue #4 "Missing module_ssldb? Redis module won't compile." - removed dependencies on ssldb. ## SUPPORT * Issue #3 "Error after running make" - added documentation that ZMap requires 64-bit system. * Issue #1 "Failure at calloc for 'ip_seen' on KVM VPSs?" - added documentation on memory requirements for ZMap. # 1.0.2 2013-8-18 ## BUGFIX * Issue #14 "gcc 4.7.2 -Wunprototyped-calls error with recv_run." - changed recv_run header to match def in recv.c. # 1.0.3 2013-8-19 ## BUGFIX * Issues #21, #28 "fixed get_gateway malloc/memset errors". * Issue #24 "Makefile does not respect LDFLAGS" - changed = to += for CFLAGS, LDFAGS, and LDLIBS. # 1.1.0 2013-11-18 ## BUGFIX * Source port in UDP module corrected to use network order instead of host order. ## FEATURE * Updated probe and output module interface that allows arbitrary data to be passed from the probe module (e.g. additional TCP fields) that can then be output as requested. * Replaced simple_file, and redis_file output modules with csv module that allows user controlled output of what fields should be output to a csv file. As well, implemented `--list-output-fields` that allows users to find what fields are available. * Added output-filters that allow users to control what types of packets that want output (e.g. classification = "SYNACK" && is_repeat = 0). * Drop root privileges after opening necessary sockets if run as privileged user. * Added paged bitmap for removing duplicate responses so that if small subnets are scanned, large amount of memory is no longer required. * Fast scanning of small subnets. Scanning small subnets no longer requires iterating over the entire IPv4 address space, which allows ZMap-like speed for all network sizes. * Scan CIDR blocks from the command-line instead of only through whitelist file (e.g. ZMap -p 443 192.168.0.0/16 10.0.0.0/8). * Redis output module now allows connecting to arbitrary redis servers and lists from the command-line via output module parameter. * JSON output module added. * 32-bit support. * UDP Packet Support. # 1.1.1 2013-12-16 ## BUGFIX * Fixed bit-map, which was incorrectly deduplicating responses. * CMake correctly installs files into /etc/zmap. # 1.1.2 2014-01-21 ## BUGFIX * Off-by-one error in paged bitmap. # 1.2.0 2014-03-10 ## BUGFIX * ICMP values added incorrectly, timestamp unavailable. * Setting fixed number of probes may inadverantly target specific networks. * Scans occasionally skip cooldown period due to lock issue. ## FEATURE * Added MongoDB as a supported output module. * Added context to allow easier packaging in Debian and Ubuntu and Fedora and Brew and Macports. * Remove dnet dependency for Linux. * Remove random extra printed saddr. * Build with optimizations by default. * Added JSON metadata output. * Added syslog support. * Added BSD/mac support. * Removed bizarre executible bits on random example code in git repo. * Added support for scanning by FQDN. * Adding sharding support. # 1.2.1 2014-06-09 ## BUGFIX * UDP scans sometimes double-counted IP header length. * Properly check UDP packet length. * Integer overflow in JSON metadata when printing generator. * All calls to malloc checked for failure. ## FEATURE * Autodetect number of sender threads. * Add ignore-invalid-hosts option for blocklist. # 2.1.0 2015-09-02 ## BUGFIX * ZMap now filters out packets that are from the local MAC instead of only capturing packets from the local gateway. The prior approach caused valid responses to be dropped for a fair number of users. * ZMap would sometimes segfault if the number of threads was greater than the number of destination hosts. * ZMap did not crash when it was unable to write to the output file. This would cause ZMap to continue running when it was piped into another application and that application died. We not log_fatal if the output is no longer accessible per ferror. * Pcap filter captures outgoing packets. * Install overwrites blocklist file. * Output is sometimes colored. * Use correct email for Zakir in AUTHORS. * Random-number generator is now thread safe. * Finding a generator would crash with low probability. ## CHANGED * JSON output uses underscores instead of hyphens. * Removes support for deprecated simple_file and extended_file options. * Rename redis module to redis-packed. * Probe module API takes user data argument. * Output to `stdout` by default. * Remove space in csv output header. * Build with JSON support by default. * Don't print blocklisted CIDR blocks to log. These are available in `--metadata-file` and end up flooding the log with a ton of metadata. * Remove type field from JSON output module and get rid of header. * Remove `--summary`. This has been replaced by `--metadata-file`. * JSON metadata now uses ISO-8601 compatible timestamps instead of proprietary log format. * Remove buggy and never officially-released DNS probe module. * Add icmp-echo-time probe module for measuring RTT MongoDB output module. ## FEATURE * zblocklist (a standalone utility that allows you to efficiently check IP addresses against a ZMap compatible whitelist and blocklist. This is helpful if you are doing something like ```cat list-of-ips | zgrab``` and to make sure that you're still following your blocklist. * ztee (a standalone utility that buffers between ZMap and ZGrab) and allows extracting just IP address from a larger ZMap output in order to complete follow up handshakes without losing any data. * NTP probe module. * Status-updates-file (monitor output as a csv). * Add redis-csv output module. * Colored log output. * Add pf_ring and 10GigE support. * Optional app-success field output in monitor. # 2.1.1 2015-09-11 ## BUGFIX * make install works on more systems ## CHANGED * CMakeLists.txt is now much more sane and packager-friendly * Switch CHANGELOG and INSTALL to Markdown * Generate `*.ggo` files from `*.ggo.in` files that define ZMap version as a macro # 3.0.0 2023-06-23 We're happy to provide ZMap 3.0.0, only slightly under six years late. We recommend using this release over any previous 2.x release. ZMap 3.0.0 represents several years of development and contains more than a hundred small bug fixes from ZMap 2.1.1., including many fixes for UDP modules, sharding, and progress calculation. Below, are some of the most important changes: ## BUGFIX * Fix send rate calculations * Accept RST packets for SEQ+0 (per RFC) * Packets per second is packets per second now instead of IPs per second * MaxResults is now the number of packets that pass the output filter (#502) * Try all routing tables in Linux * Fix crash on invalid UDP packets * Fix failed initialize on single-question DNS probes * Fix inaccurate blocklist warning * Use monotonic OS clocks for monitoring and rate estimation * Fix bugs in UDP template arguments * Increase UDP PCAP snaplen to prevent packet truncation * Exit on failed sends * Fix incorrect time remaining calculations on sharded scans ## FEATURE * Added --list-of-ips feature which allows scanning a large number (e.g., hundreds of millions or billons) of individual IPS * Improved user messages when network settings can't be automatically discovered * Consistent ICMP support and handling across all probe modules (#470) * Set TCP MSS flags to avoid filtering by destination hosts (#673) * Sane default behavior that can be explained with other CLI flags * Non-Flat Result output and JSON result encoding * IP Fragment Checking * DNS, TCP SYN-ACK, and Bacnet Probe Module * Change Whitelist/Blacklist terms to Allowlist/Blocklist * Add extended validation bytes for probe modules that can use greater entropy * Support non-continuous source IP's (#516) * Add NetBSD and DragonFly BSD compatibility code (#411) * Improved ICMP validation based on returned packet (#419) ## REMOVED * Drop Redis and MongoDB support (#661) # 4.0.0 2023-11-06 ZMap 4.0.0 introduces the notion of multi-port scanning, which has been a long requested feature. This is a breaking change since ZMap now operates on a metric of (ip,port) target instead of simply IP (e.g., for scan rate). It also introduces new dependencies (e.g., libjudy) to support multi-port scanning and changes ZMap's command-line interface. Below are some of the most important changes: ## BUGFIX * Fix segmentation fault when passing no port to the ICMP module (or any module without a port requirement) ## FEATURE * Multi-port scanning support * Store link-layer timestamp in icmp_echo_time module (#726) * Build support for ARM-based Macs * Use the network interface containing the default route for usability * Improve the dst port validation # 4.1.0 2024-03-21 ZMap 4.1.0 contains a number of bug fixes and performance enhancements, especially around the sending of probe packets. Additionally, the `IP_ID` is now randomized to prevent the fingerprinting of ZMap scan traffic. Below are some of the most important changes: ## BUGFIX * Fixes a bug where an assertion error would always occur when the `-I` flag was used * Fixes `--probe-args` parsing with the DNS module * Prevents crash when `--batch` size overflowed the uint8 holding the batch_size * Fixes size calculation with `--iplayer` option that caused an overflow in `fake_eth_hdr` * Fixes shard initialization with multi-port that could cause the scan to scan port 0 * Fixes inaccurate estimated time remaining and percentage complete calculations during a multi-port scan * Fixes building from source on MidnightBSD * Fixes hit-rate calculation with multiple `--probes` packets per target ## FEATURE * Randomizes the IP packet ID to prevent fingerprinting of scan traffic * Adds support for Netmap to increase performance on supported NIC's w/ the requisite drivers * Adds send packet batching (using `sendmmsg`) to improve performance on Linux/BSD * Adds hardware acceleration for AES to improve performance when the CPU begins to become the bottleneck * Adds integration tests and compilation checks for supported OS's as Github Actions * Adds --probe-args options to the TCP SYN scan module to send TCP header options identical to Ubuntu (default), MacOS, Windows, or No Options. * Sets default number of sending threads to min(4, number of host cores) * Handles IPv6 addresses in `blocklist.conf` * Supports `--iplayer` on MacOS # 4.1.1 2024-05-21 ## DOCUMENTATION * updated CHANGELOG.md and README.md to contain the changes from v4.1.0 and point to the latest version. ## ENHANCEMENT * Use same IP TTL as ubuntu (#850) * Add TCP options parsing in receive thread (#858) ## BUGFIX * Fixed a bug which caused inaccurate ETA every 44 secs. * Fixed a bug where a malformed TCP options returned to the scanner would cause the receive thread to hang. # 4.2.0 2024-07-09 ## BUGFIX * Fixed a bug where ZMap's behavior with a --max-targets of a percentage with multiple ports was inconsistent with our documentation/expectations. (#886) ## ENHANCEMENT * Bump the base Docker image from Ubuntu 20.04 to 24.04 (#888) # 4.3.0 2024-11-27 ## FEATURE * New UDP probe for DTLS servers by @dlenskiSB in https://github.com/zmap/zmap/pull/890 * New UDP probes by @annalittle in https://github.com/zmap/zmap/pull/899 * Add source port validation CLI option and associated code to UDP module by @phillip-stephens in https://github.com/zmap/zmap/pull/901 ## BUGFIX * Fix 904 - multi-port scans lead to int overflow by @phillip-stephens in https://github.com/zmap/zmap/pull/905 * Fix ZMap not obeying `--rate` edge case by @phillip-stephens in https://github.com/zmap/zmap/pull/907 * Match JSON function to variable type by @phillip-stephens in https://github.com/zmap/zmap/pull/908 * Fix source port range size warning by @Murgeye in https://github.com/zmap/zmap/pull/891 ## ENHANCEMENT * Handle upgrade path for blacklist to blocklist by @phillip-stephens in https://github.com/zmap/zmap/pull/895 * Fixes ubuntu docker base image versions in github tests by @phillip-stephens in https://github.com/zmap/zmap/pull/898 * Fix Mac build CI step by @phillip-stephens in https://github.com/zmap/zmap/pull/906 # 4.3.1 2024-12-10 ## BUGFIX * Missed an uint32 which caused multi-port scans to end early by @phillip-stephens in https://github.com/zmap/zmap/pull/914 * Fix for #913 (where a handful of targets were scanned twice) and added IPv4 scan coverage integration test and python wrapper with --fast-dryrun by @phillip-stephens in https://github.com/zmap/zmap/pull/916 # 4.3.2 2025-01-28 ## BUGFIX * use the x86 ubuntu dockerfile base image, should fix failing daily test by @phillip-stephens in #920 * Fix typos by @BitHostDev in #923 * Fix leaks by @rex4539 in #921 * Fix NETLINK issues in ZMap caused by changes in latest linux kernel by @phillip-stephens in #925 # 4.3.3 2025-04-29 Misc bug fixes and improvements ## ENHANCEMENT * Add QUIC init probe in #930 ## BUGFIX * Fix size of recv validation from uint32[16] to uint32[4] in #926 # 4.3.4 2025-05-12 ## ENHANCEMENT * Have tagged version printed with --version rather than development commit zmap-4.3.4/CITATION.cff000066400000000000000000000017141501046211500143610ustar00rootroot00000000000000cff-version: 1.2.0 message: "If you use this software, please cite it as below." authors: - family-names: "Durumeric" given-names: "Zakir" orcid: "https://orcid.org/0000-0002-9647-4192" - family-names: "Wustrow" given-names: "Eric" - family-names: "Halderman" given-names: "J. Alex" orcid: "https://orcid.org/0000-0002-9116-5390" title: "zmap" # TODO add version/doi once we tag and release ZMap 4.1 into package managers date-released: 2013-08 url: "https://github.com/zmap/zmap" preferred-citation: type: "conference-paper" authors: - family-names: "Durumeric" given-names: "Zakir" orcid: "https://orcid.org/0000-0002-9647-4192" - family-names: "Wustrow" given-names: "Eric" - family-names: "Halderman" given-names: "J. Alex" orcid: "https://orcid.org/0000-0002-9116-5390" collection-title: "22nd USENIX Security Symposium" title: "ZMap: Fast Internet-Wide Scanning and its Security Applications" year: 2013 zmap-4.3.4/CMakeLists.txt000066400000000000000000000240631501046211500152310ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR) project(ZMAP C) set(ZMAP_VERSION v4.3.4) # Change DEVELOPMENT to version number for release option(ENABLE_DEVELOPMENT "Enable development specific compiler and linker flags" OFF) option(ENABLE_LOG_TRACE "Enable log trace messages" OFF) option(RESPECT_INSTALL_PREFIX_CONFIG "Respect CMAKE_INSTALL_PREFIX for /etc" OFF) option(WITH_WERROR "Build with -Werror" OFF) option(WITH_PFRING "Build with PF_RING ZC for send (10 GigE)" OFF) option(WITH_NETMAP "Build with netmap(4) for send/recv (10+ GigE)" OFF) option(WITH_AES_HW "Build with AES hardware acceleration (x86_64 and arm64)" OFF) option(FORCE_CONF_INSTALL "Overwrites existing configuration files at install" OFF) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(USING_CLANG "YES") else() set(USING_GCC "YES") endif() if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD" OR "${CMAKE_SYSTEM_NAME}" MATCHES "NetBSD" OR "${CMAKE_SYSTEM_NAME}" MATCHES "DragonFly" OR "${CMAKE_SYSTEM_NAME}" MATCHES "MidnightBSD") set(BSD "YES") endif() if("${CMAKE_SYSTEM_NAME}" MATCHES "NetBSD") set(NetBSD "YES") endif() # Hardening and warnings for building with gcc # Maybe add -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations set(GCCWARNINGS "-Wall -Wformat=2 -Wno-format-nonliteral" "-pedantic -fno-strict-aliasing" "-Wextra" "-Wfloat-equal -Wundef -Wwrite-strings -Wredundant-decls" "-Wnested-externs -Wbad-function-cast -Winit-self" "-Wmissing-noreturn" "-Wstack-protector" ) # Fix line breaks string(REPLACE ";" " " GCCWARNINGS "${GCCWARNINGS}") if(WITH_WERROR) set(GCCWARNINGS "${GCCWARNINGS} -Werror") endif() # Check for dependencies find_library(FOUND_JUDY HINTS /usr/include/ NAMES Judy libjudy-dev judy dev-libs/judy judy-devel) if (NOT FOUND_JUDY) message(FATAL_ERROR "Missing dependency: did not find Judy library, please install Judy or equivalent. More details in INSTALL.md") endif() find_library(FOUND_GMP HINTS /usr/include/ NAMES libgmp3-dev gmp dev-libs/gmp gmp-devel) if (NOT FOUND_GMP) message(FATAL_ERROR "Missing dependency: did not find gmp library, please install gmp or equivalent. More details in INSTALL.md") endif() find_library(FOUND_PCAP HINTS /usr/include/ NAMES pcap libpcap-dev libpcap net-libs/libpcap libpcap-devel) if (NOT FOUND_PCAP) message(FATAL_ERROR "Missing dependency: did not find libpcap library, please install libpcap or equivalent. More details in INSTALL.md") endif() find_program(FOUND_FLEX HINTS /usr/include/ /usr/bin/ NAMES flex sys-devel/flex) if (NOT FOUND_FLEX) message(FATAL_ERROR "Missing dependency: did not find flex, please install flex or equivalent. More details in INSTALL.md") endif() find_program(FOUND_BYACC HINTS /usr/include/ NAMES byacc dev-util/byacc) if (NOT FOUND_BYACC) message(FATAL_ERROR "Missing dependency: did not find byacc, please install byacc or equivalent. More details in INSTALL.md") endif() find_library(FOUND_JSON HINTS /usr/include/ NAMES json libjson-c-dev json-c-devel json-c dev-libs/json-c) if (NOT FOUND_JSON) message(FATAL_ERROR "Missing dependency: did not find libjson-c, please install libjson-c or equivalent. More details in INSTALL.md") endif() find_program(FOUND_GENGETOPT HINTS /usr/include/ NAMES gengetopt dev-util/gengetopt) if (NOT FOUND_GENGETOPT) message(FATAL_ERROR "Missing dependency: did not find gengetopt, please install gengetopt or equivalent. More details in INSTALL.md") endif() find_path(FOUND_LIBUNISTRING # UniString is neither a library or a program, but install several header files in the include path NAMES unistr.h PATH_SUFFIXES include ) if (NOT FOUND_LIBUNISTRING) message(FATAL_ERROR "Missing dependency: did not find libunistring, please install libunistring or equivalent. More details in INSTALL.md") endif() find_program(FOUND_PKGCONFIG HINTS /usr/include/ NAMES pkg-config dev-util/pkgconf) if (NOT FOUND_PKGCONFIG) message(FATAL_ERROR "Missing dependency: did not find pkg-config, please install pkg-config or equivalent. More details in INSTALL.md") endif() if(ENABLE_DEVELOPMENT) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g") else() # Hardening and optimizations for building with gcc set(GCCHARDENING "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-all -fwrapv -fPIC --param ssp-buffer-size=1") if(NOT APPLE AND NOT BSD) set(LDHARDENING "-z relro -z now") else() set(LDHARDENING "") endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCCHARDENING} -O2") set(CMAKE_EXE_LINKER_FLAGS "${LDHARDENING} ${CMAKE_EXE_LINKER_FLAGS}") endif() if(ENABLE_LOG_TRACE) add_definitions("-DDEBUG") endif() set(CMAKE_C_FLAGS "${GCCWARNINGS} ${CMAKE_C_FLAGS}") include(FindPkgConfig) pkg_check_modules(JSON json-c) if(JSON_FOUND) include_directories(${JSON_INCLUDE_DIRS}) else() message(FATAL_ERROR "Did not find libjson") endif() string(REPLACE ";" " " JSON_CFLAGS "${JSON_CFLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${JSON_CFLAGS}") if(WITH_PFRING) add_definitions("-DPFRING") set(PFRING_LIBRARIES pfring rt numa) endif() if(WITH_NETMAP) add_definitions("-DNETMAP") endif() if(WITH_AES_HW) add_definitions("-DAES_HW") endif() set(JUDY_LIBRARIES "Judy") # Standard FLAGS set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11") if(NOT APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") endif() # Set up OS-specific include directories if(APPLE) if(EXISTS /opt/local/include) include_directories(/opt/local/include) endif() if(EXISTS /opt/local/lib) link_directories(/opt/local/lib) endif() if(EXISTS /usr/local/include) include_directories(/usr/local/include) endif() if(EXISTS /usr/local/lib) link_directories(/usr/local/lib) endif() if(EXISTS /opt/homebrew) include_directories(/opt/homebrew/include) link_directories(/opt/homebrew/lib) endif() endif() if(BSD) include_directories(/usr/local/include) link_directories(/usr/local/lib) endif() if(NetBSD) include_directories(/usr/pkg/include) link_directories(/usr/pkg/lib) endif() add_subdirectory(lib) add_subdirectory(src) # Install conf files if(RESPECT_INSTALL_PREFIX_CONFIG) set(CONFIG_DESTINATION "etc/zmap") else() set(CONFIG_DESTINATION "/etc/zmap") endif() FILE(GLOB CONF_FILES "${PROJECT_SOURCE_DIR}/conf/*") # Upgrade path for old conf files - this is necessary for users upgrading from a version where we called the blocklist file blacklist.conf # Must occur before the install command if(EXISTS "${CONFIG_DESTINATION}/blacklist.conf") message(STATUS "Old configuration file detected at ${CONFIG_DESTINATION}/blacklist.conf, creating a symlink to ${CONFIG_DESTINATION}/blocklist.conf to match the new flag conventions") execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink "${CONFIG_DESTINATION}/blacklist.conf" "${CONFIG_DESTINATION}/blocklist.conf" ) message(STATUS "blocklist.conf has been successfully symlinked to blacklist.conf.") endif() # If the zmap.conf file exists and contains the old blacklist-file option, replace it with the new blocklist-file option if(EXISTS "${CONFIG_DESTINATION}/zmap.conf") file(READ "${CONFIG_DESTINATION}/zmap.conf" FILE_CONTENTS) if(FILE_CONTENTS MATCHES "blacklist-file \"${CONFIG_DESTINATION}/blacklist.conf\"") string(REPLACE "blacklist-file \"${CONFIG_DESTINATION}/blacklist.conf\"" "blocklist-file \"${CONFIG_DESTINATION}/blocklist.conf\"" FILE_CONTENTS "${FILE_CONTENTS}") file(WRITE "${CONFIG_DESTINATION}/zmap.conf" "${FILE_CONTENTS}") message(STATUS "Blacklist to blocklist file path successfully updated in ${CONFIG_DESTINATION}/zmap.conf.") else() message(STATUS "blacklist-file option does not exist in ${CONFIG_DESTINATION}/zmap.conf. No changes necessary to upgrade ZMap configuration file.") endif() else() message(STATUS "No ZMap configuration file detected at ${CONFIG_DESTINATION}/zmap.conf. No changes necessary to upgrade ZMap configuration file.") endif() message(STATUS "Default ZMap configuration file location is /etc/zmap") foreach(EACH_CONF ${CONF_FILES}) get_filename_component(CONF_BASENAME ${EACH_CONF} NAME) message(STATUS "Checking if ${CONF_BASENAME} exists there...") if(NOT EXISTS "${CONFIG_DESTINATION}/${CONF_BASENAME}") install(FILES ${EACH_CONF} DESTINATION ${CONFIG_DESTINATION}) elseif(FORCE_CONF_INSTALL) message(WARNING "FORCE_CONF_INSTALL will overwrite any existing configuration files") install(FILES ${EACH_CONF} DESTINATION ${CONFIG_DESTINATION}) else() message(WARNING "Existing configuration file detected at /etc/zmap/${CONF_BASENAME}, ${CONF_BASENAME} from sources will NOT be installed. Please check and install manually!") endif() endforeach() # Allow Debian Packaging include(InstallRequiredSystemLibraries) set(CPACK_SET_DESTDIR "on") set(CPACK_PACKAGING_INSTALL_PREFIX "/tmp") set(CPACK_GENERATOR "DEB") set(CPACK_DEBIAN_PACKAGE_VERSION ${ZMAP_VERSION}) set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") set(CPACK_DEBIAN_PACKAGE_SECTION "network") set(CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.1.3), libgmp10, libpcap0.8, libjson-c-dev") set(CPACK_PACKAGE_DESCRIPTION "Internet-scale network scanner") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "ZMap is an open source network scanner that enables researchers to easily perform Internet-wide network studies. With a single machine and a well provisioned network uplink, ZMap is capable of performing a complete scan of the IPv4 address space in under five minutes, approaching the theoretical limit of gigabit Ethernet. ZMap can be used to study protocol adoption over time, monitor service availability, and help us better understand large systems distributed across the Internet.") set(CPACK_PACKAGE_CONTACT "Zakir Durumeric ") set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${VERSION}_${CPACK_DEBIAN_ARCHITECTURE}") set(CPACK_COMPONENTS_ALL Libraries ApplicationData) include(CPack) zmap-4.3.4/CONTRIBUTING.md000066400000000000000000000027151501046211500147220ustar00rootroot00000000000000Contributing to ZMap ==================== ZMap accepts contributions in the form of issues and pull requests. In either case, before posting please [search](https://github.com/zmap/zmap/issues) to see if your change or bug report has been addressed previously. [INSTALL](INSTALL.md#building-from-source) provides guidance on building ZMap from source. Developing ---------- - ZMap code follows the [Linux kernel style guide][kernelguide]. We maintain [a configuration file](/.clang-format) for `clang-format` that applies this style. You can use the [format.sh](/format.sh) script to apply this style. - Before submitting a PR, please rebase/squash your commits down to a single commit. Follow these [commit message guidelines][guidelines], especially with regard to formatting. Reviewing --------- - All commits must be reviewed in the form of a pull request by a ZMap maintainer. This usually means @zakird or @dadrian (or both). - All pull-requests should be squash-merged into master. - When squash-merging, put the PR number in the commit title. GitHub does this automatically in the web interface. Condense the commit messages down to a single message; often this can just be the commit message from the first commit in a PR. Follow the commit formatting guidelines [here][guidelines]. [kernelguide]: https://www.kernel.org/doc/Documentation/process/coding-style.rst [guidelines]: https://github.com/torvalds/subsurface-for-dirk/blob/master/README#L92 zmap-4.3.4/Dockerfile000066400000000000000000000027021501046211500144570ustar00rootroot00000000000000#### # A Docker container for running zmap # # To build, beware of caching and: # # * If you wish to build current main # # docker build -t zmap . # # * If you wish to build a specific commit, git checkout to that specific commit before building # # To run CI pre-built images, use: # # docker run -it --rm --net=host ghcr.io/zmap/zmap #### FROM ubuntu:24.04 as builder ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Etc/UTC RUN apt-get update \ && apt-get install -y \ build-essential \ cmake \ libgmp3-dev \ gengetopt \ libpcap-dev \ flex \ byacc \ libjson-c-dev \ libjudy-dev \ pkg-config \ libunistring-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /usr/local/src COPY . . RUN cd /usr/local/src \ && mkdir -p /opt/zmap \ && cmake . -DRESPECT_INSTALL_PREFIX_CONFIG=ON \ && cmake --build . --parallel "$(nproc)" \ && cmake --install . --prefix "/opt/zmap" FROM ubuntu:24.04 LABEL org.opencontainers.image.source="https://github.com/zmap/zmap" RUN apt-get update \ && apt-get install -y \ libpcap0.8 \ libjson-c5 \ libjudydebian1 \ libgmp10 \ dumb-init \ && rm -rf /var/lib/apt/lists/* COPY --from=builder /opt/zmap /opt/zmap ENV PATH="/opt/zmap/sbin:${PATH}" # dumb-init allows us to more easily send signals to zmap, # for example by allowing ctrl-c of a running container and zmap will stop. ENTRYPOINT ["dumb-init", "/opt/zmap/sbin/zmap"] zmap-4.3.4/INSTALL.md000066400000000000000000000106661501046211500141250ustar00rootroot00000000000000# Installing and Building ZMap ## Installing via Package Manager ZMap operates on GNU/Linux, macOS, and BSD. The latest stable version may be available in package managers. | OS | | | ----------------------------------------- | ----------------------- | | Fedora 19+ or EPEL 6+ | `yum install zmap` | | Debian 8+ or Ubuntu 14.04+ | `apt install zmap` | | Gentoo | `emerge zmap` | | macOS (using [Homebrew](https://brew.sh)) | `brew install zmap` | | macOS (using [MacPorts](https://macports.org)) | `port install zmap`| | Arch Linux | `pacman -S zmap` | ## Building from Source ### Installing ZMap Dependencies ZMap has the following dependencies: - [CMake](http://www.cmake.org/) - Cross-platform, open-source build system - [GMP](http://gmplib.org/) - Arbitrary precision arithmetic - [gengetopt](http://www.gnu.org/software/gengetopt/gengetopt.html) - Command line option parsing - [libpcap](http://www.tcpdump.org/) - User-level packet capture library - [flex](http://flex.sourceforge.net/) and [byacc](http://invisible-island.net/byacc/) - Lexer and parser generator - [json-c](https://github.com/json-c/json-c/) - JSON parsing and output - [libunistring](https://www.gnu.org/software/libunistring/) - Unicode string library - [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) - compiler and library helper tool - [libjudy](https://judy.sourceforge.net/) - Judy Array for packet de-duplication Install the required dependencies with the following commands. * On Debian-based systems (including Ubuntu): ```sh sudo apt-get install build-essential cmake libgmp3-dev gengetopt libpcap-dev flex byacc libjson-c-dev pkg-config libunistring-dev libjudy-dev ``` * On RHEL- and Fedora-based systems (including CentOS): ```sh sudo dnf install gcc cmake gmp-devel gengetopt libpcap-devel flex byacc json-c-devel libunistring-devel Judy-devel ``` * On Arch systems ```sh pacman -S base-devel cmake gmp gengetopt libpcap flex byacc json-c pkg-config libunistring judy python ``` * On Gentoo systems ```sh emerge sys-devel/binutils dev-libs/gmp dev-util/gengetopt net-libs/libpcap sys-devel/flex dev-util/byacc dev-libs/json-c dev-util/pkgconf dev-libs/libunistring dev-libs/judy ``` * On macOS systems (using [Homebrew](https://brew.sh/)): ```sh brew install pkg-config cmake gmp gengetopt json-c byacc libunistring judy ``` * On macOS systems (using [MacPorts](https://macports.org/)): ``` sudo port install cmake byacc flex gengetopt pkgconfig gmp libpcap json-c libunistring judy ``` * To launch a shell inside a Docker container with the build dependencies mounted at `/src`: ```sh docker run -it -v $(pwd):/src zmap/builder ``` ### Building and Installing ZMap Once these prerequisites are installed, clone the ZMap repository and navigate into the cloned directory. ```sh cd zmap ``` Then, ZMap can be compiled by running: ```sh cmake . make -j4 ``` and then installed via `sudo make install`. ### Development Notes - Enabling development turns on debug symbols, and turns off optimizations. Release builds should be built with `-DENABLE_DEVELOPMENT=OFF`. - Enabling `log_trace` can have a major performance impact and should not be used except during early development. Release builds should be built with `-DENABLE_LOG_TRACE=OFF`. - Building packages for some systems like Fedora and RHEL requires a user-definable directory (buildroot) to put files. The way to respect this prefix is to run cmake with `-DRESPECT_INSTALL_PREFIX_CONFIG=ON`. - Manpages (and their HTML representations) are generated from the `.ronn` source files in the repository, using the [ronn](https://github.com/rtomayko/ronn) tool. This does not happen automatically as part of the build process; to regenerate the man pages you'll need to run `make manpages`. This target assumes that `ronn` is in your PATH. - Building with some versions of CMake may fail with `unable to find parser.h`. If this happens, try updating CMake. If it still fails, don't clone ZMap into a path that contains the string `.com`, and try again. - ZMap may be installed to an alternative directory, with the `CMAKE_INSTALL_PREFIX` option. For example, to install it in `$HOME/opt` run ```sh cmake -DCMAKE_INSTALL_PREFIX=$HOME/opt . make -j4 make install ``` zmap-4.3.4/LICENSE000066400000000000000000000236761501046211500135070ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS zmap-4.3.4/README.md000066400000000000000000000071511501046211500137470ustar00rootroot00000000000000ZMap: The Internet Scanner ========================== ![Build Status](https://github.com/zmap/zmap/actions/workflows/cmake.yml/badge.svg) ZMap is a fast stateless single packet network scanner designed for Internet-wide network surveys. On a typical desktop computer with a gigabit Ethernet connection, ZMap is capable of scanning the entire public IPv4 address space on a single port in under 45 minutes. For example, sending a TCP SYN packet to every IPv4 address on port 25 to find potential SMTP servers. With a 10gigE connection and either [netmap](http://info.iet.unipi.it/~luigi/netmap/) or [PF_RING](http://www.ntop.org/products/packet-capture/pf_ring/), ZMap can scan the IPv4 address space in under 5 minutes. ZMap operates on GNU/Linux, Mac OS, and BSD. ZMap currently has fully implemented probe modules for TCP SYN scans, ICMP, DNS queries, UPnP, BACNET, and can send a large number of [UDP probes](https://github.com/zmap/zmap/blob/master/examples/udp-probes/README). If you are looking to do more involved scans (e.g., banner grab or TLS handshake), take a look at [ZGrab 2](https://github.com/zmap/zgrab2), ZMap's sister project that performs stateful application-layer handshakes. Using ZMap ---------- If you haven't used ZMap before, we have a step-by-step [Getting Started Guide](https://github.com/zmap/zmap/wiki/Getting-Started-Guide) that details how to perform basic scans. Documentation about all of ZMap's options and more advanced functionality can be found in our [Wiki](https://github.com/zmap/zmap/wiki). For best practices, see [Scanning Best Practices](https://github.com/zmap/zmap/wiki/Scanning-Best-Practices). If you have questions, please first check our [FAQ](https://github.com/zmap/zmap/wiki/FAQ). Still have questions? Ask the community in [Github Discussions](https://github.com/zmap/zmap/discussions/categories/q-a). Please do not create an Issue for usage or support questions. Installation ------------ The latest stable release of ZMap is [4.3.4](https://github.com/zmap/zmap/releases/tag/v4.3.4) and supports Linux, macOS, and BSD. See [INSTALL](INSTALL.md) for instructions on to install ZMap through a package manager or from source. Architecture ------------ More information about ZMap's architecture and a comparison with other tools can be found in these research papers: * [ZMap: Fast Internet-Wide Scanning and its Security Applications](https://zmap.io/paper.pdf) * [Zippier ZMap: Internet-Wide Scanning at 10 Gbps](https://jhalderm.com/pub/papers/zmap10gig-woot14.pdf) * [Ten Years of ZMap](https://arxiv.org/pdf/2406.15585) If you use ZMap for published research, please cite the original research paper: ``` @inproceedings{durumeric2013zmap, title={{ZMap}: Fast Internet-wide scanning and its security applications}, author={Durumeric, Zakir and Wustrow, Eric and Halderman, J Alex}, booktitle={22nd USENIX Security Symposium}, year={2013} } ``` Citing the ZMap paper helps us to track ZMap usage within the research community and to pursue funding for continued development. License and Copyright --------------------- ZMap Copyright 2024 Regents of the University of Michigan Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See LICENSE for the specific language governing permissions and limitations under the License. zmap-4.3.4/README.netmap.md000066400000000000000000000061621501046211500152330ustar00rootroot00000000000000Fast packet I/O using netmap ============================ ZMap can be built for sending and receiving packets using netmap(4), for very high packet rates, especially on 10 GbE and faster links. See [netmap/README.md](https://github.com/luigirizzo/netmap) for more information on netmap. Netmap is available by default on FreeBSD on many architectures, including amd64 and arm64, and is easy to add to the kernel config on architectures where it is not built by default. On Linux, netmap itself and netmap-aware drivers can be installed by following the instructions in [netmap/LINUX/README.md](https://github.com/luigirizzo/netmap/blob/master/LINUX/README.md). ### Prerequisites 0. A working ZMap development environment (see [INSTALL.md](INSTALL.md)). 1. A kernel with netmap support (check for existence of `/dev/netmap`). 2. For best results, a NIC with a driver that is netmap-aware, such as FreeBSD's `ixgbe` or `ixl`. ### Building To build navigate to the root of the repository and run: ``` $ cmake -DWITH_NETMAP=ON -DENABLE_DEVELOPMENT=OFF . $ make ``` For best results on hardware that supports AES acceleration, additionally use `-DWITH_AES_HW=ON` to enable support for AES-NI and ARMv8 CE, where applicable. ### Running Run zmap as you would normally. ``` $ sudo ./src/zmap -p 443 -i ix0 -o output.csv ``` Warning: Netmap will disconnect the NIC from the host network stack for the duration of the scan. If you use an interface that you depend on for e.g. SSH access, you will lose connectivity until ZMap exits. ### Performance tuning For best results, use the `--cores` option to pick which cores to pin to, pinning to different physical cores. By default, the number of send threads is set to the number of available cores after setting aside one core for the receive thread, capped to 4 send threads, but you may still want to override the number of send threads with `-T`. The number of send threads cannot exceed the number of TX rings of the NIC. Tuning batch size can also have an effect on send rate. `--batch 256` is not an unreasonable starting point on 10 GbE hardware. ### Switch ports and STP Going into and leaving Netmap mode causes the link to go down and up as part of a PHY reset. If the interface is connected to a switch with STP enabled, then depending on port configuration, the switch might be muting the port for as many as 30 seconds while the port goes through the listening and learning STP states. To work around this, use `--netmap-wait-ping` with an address that you know will respond to ICMP echo requests. ZMap will then only start scanning after having received an ICMP echo reply from the address. ``` $ sudo ./src/zmap -p 443 -i ix0 -o output.csv --netmap-wait-ping 8.8.8.8 ``` ### Considerations DO NOT TAKE THIS LIGHTLY! Running ZMap at 10Gbps hits every /16 on the Internet over 200 times a second. Even if you have a large source IP range to scan from, it's very obvious that you're scanning. As always, follow scanning best practices, honor blocklist requests, and signal benign/research intent via domain names and websites on your scan IPs. Remember, you're sending a lot of traffic. zmap-4.3.4/checkFormat.sh000077500000000000000000000006611501046211500152540ustar00rootroot00000000000000#!/bin/bash CLANG_FORMAT=clang-format-6.0 files_to_lint=$(find ./src ./lib -type f -name '*.c' -or -name '*.h') fail=0 for f in ${files_to_lint}; do d="$(diff -u "$f" <($CLANG_FORMAT -style=file "$f") || true)" if ! [ -z "$d" ]; then printf "The file %s is not compliant with the coding style:\n%s\n" "$f" "$d" fail=1 fi done if [ "$fail" -eq "1" ]; then if [ ! -z $ZMAP_ENFORCE_FORMAT ]; then exit 1 fi fi zmap-4.3.4/conf/000077500000000000000000000000001501046211500134115ustar00rootroot00000000000000zmap-4.3.4/conf/blocklist.conf000066400000000000000000000021141501046211500162440ustar00rootroot00000000000000# From IANA IPv4 Special-Purpose Address Registry # http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml # Updated 2013-05-22 0.0.0.0/8 # RFC1122: "This host on this network" 10.0.0.0/8 # RFC1918: Private-Use 100.64.0.0/10 # RFC6598: Shared Address Space 127.0.0.0/8 # RFC1122: Loopback 169.254.0.0/16 # RFC3927: Link Local 172.16.0.0/12 # RFC1918: Private-Use 192.0.0.0/24 # RFC6890: IETF Protocol Assignments 192.0.2.0/24 # RFC5737: Documentation (TEST-NET-1) 192.88.99.0/24 # RFC3068: 6to4 Relay Anycast 192.168.0.0/16 # RFC1918: Private-Use 198.18.0.0/15 # RFC2544: Benchmarking 198.51.100.0/24 # RFC5737: Documentation (TEST-NET-2) 203.0.113.0/24 # RFC5737: Documentation (TEST-NET-3) 240.0.0.0/4 # RFC1112: Reserved 255.255.255.255/32 # RFC0919: Limited Broadcast # From IANA Multicast Address Space Registry # http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml # Updated 2013-06-25 224.0.0.0/4 # RFC5771: Multicast/Reserved zmap-4.3.4/conf/zmap.conf000066400000000000000000000007551501046211500152360ustar00rootroot00000000000000### Probe Module to use #probe-module tcp_synscan ### Destination port to scan #target-port 443 ### Scan rate in packets/sec #rate 10000 ### Scan rate in bandwidth (bits/sec); overrides `rate` #bandwidth 1M # 1mbps ### Blocklist file to use. We encourage you to exclude ### RFC1918, IANA reserved, and multicast networks, ### in addition to those who have opted out of your ### network scans. blocklist-file "/etc/zmap/blocklist.conf" ### Optionally print a summary at the end #summary zmap-4.3.4/containers/000077500000000000000000000000001501046211500146315ustar00rootroot00000000000000zmap-4.3.4/containers/build-push-builder.sh000077500000000000000000000003441501046211500206710ustar00rootroot00000000000000#!/usr/bin/env bash ZMAP_CONTAINER_TAG=${ZMAP_CONTAINER_TAG:-'latest'} docker build --platform linux/amd64 -f builder.dockerfile -t ghcr.io/zmap/builder:$ZMAP_CONTAINER_TAG . docker push ghcr.io/zmap/builder:$ZMAP_CONTAINER_TAG zmap-4.3.4/containers/builder.dockerfile000066400000000000000000000004701501046211500203110ustar00rootroot00000000000000FROM ubuntu:20.04 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update -y --quiet RUN apt-get install -y -qq \ build-essential \ byacc \ cmake \ flex \ gengetopt \ libgmp3-dev \ libjson-c-dev \ libpcap-dev \ libunistring-dev \ libjudy-dev \ pkg-config \ python3 zmap-4.3.4/examples/000077500000000000000000000000001501046211500143025ustar00rootroot00000000000000zmap-4.3.4/examples/forge-socket/000077500000000000000000000000001501046211500166725ustar00rootroot00000000000000zmap-4.3.4/examples/forge-socket/README000066400000000000000000000001441501046211500175510ustar00rootroot00000000000000Forge Socket ============ Forge Socket is now maintained at https://github.com/ewust/forge_socket. zmap-4.3.4/examples/probe-modules/000077500000000000000000000000001501046211500170575ustar00rootroot00000000000000zmap-4.3.4/examples/probe-modules/module_tcp_cisco_backdoor.c000066400000000000000000000163131501046211500244060ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ // probe module for performing TCP SYN scans #include #include #include #include #include #include #include "../../lib/includes.h" #include "../fieldset.h" #include "probe_modules.h" #include "packet.h" probe_module_t module_tcp_synscan; static uint32_t num_ports; static int synscan_global_initialize(struct state_conf *state) { num_ports = state->source_port_last - state->source_port_first + 1; return EXIT_SUCCESS; } static int synscan_init_perthread(void *buf, macaddr_t *src, macaddr_t *gw, port_h_t dst_port, __attribute__((unused)) void **arg_ptr) { memset(buf, 0, MAX_PACKET_SIZE); struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t len = htons(sizeof(struct ip) + sizeof(struct tcphdr)); make_ip_header(ip_header, IPPROTO_TCP, len); struct tcphdr *tcp_header = (struct tcphdr *)(&ip_header[1]); make_tcp_header(tcp_header, dst_port, TH_SYN); return EXIT_SUCCESS; } // instead of settings sequence number to be random for validation // let's instead set to something static so that we can easily // set acknowledgement number. I don't know how integer overflow // is going to act in this. // uint32_t tcp_seq = validation[0]; // From Mandiant // 1. To initiate the process, a uniquely crafted TCP SYN packet is sent // to port 80 of the “implanted†router. It is important to note that // the difference between the sequence and acknowledgment numbers must // be set to 0xC123D. Also the ACK number doesn’t need to be zero. #define BACKDOOR_SEQ 0x3D120C00 //#define BACKDOOR_SEQ 0x000C123D // wrong byte order #define BACKDOOR_ACK 0x0 #define EXPECTED_RESPONSE_SEQ 0 //#define EXPECTED_RESPONSE_ACK 0x000C123E // wrong byte order #define EXPECTED_RESPONSE_ACK 0x3E120C00 static int synscan_make_packet(void *buf, UNUSED size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, UNUSED void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct tcphdr *tcp_header = (struct tcphdr *)(&ip_header[1]); ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_ttl = ttl; tcp_header->th_sport = htons(get_src_port(num_ports, probe_num, validation)); tcp_header->th_seq = BACKDOOR_SEQ; tcp_header->th_ack = BACKDOOR_ACK; tcp_header->th_sum = 0; tcp_header->th_sum = tcp_checksum(sizeof(struct tcphdr), ip_header->ip_src.s_addr, ip_header->ip_dst.s_addr, tcp_header); ip_header->ip_sum = 0; ip_header->ip_id = ip_id; ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); return EXIT_SUCCESS; } static void synscan_print_packet(FILE *fp, void *packet) { struct ether_header *ethh = (struct ether_header *)packet; struct ip *iph = (struct ip *)ðh[1]; struct tcphdr *tcph = (struct tcphdr *)&iph[1]; fprintf(fp, "tcp { source: %u | dest: %u | seq: %u | checksum: %#04X }\n", ntohs(tcph->th_sport), ntohs(tcph->th_dport), ntohl(tcph->th_seq), ntohs(tcph->th_sum)); fprintf_ip_header(fp, iph); fprintf_eth_header(fp, ethh); fprintf(fp, "------------------------------------------------------\n"); } static int synscan_validate_packet(const struct ip *ip_hdr, uint32_t len, __attribute__((unused)) uint32_t *src_ip, uint32_t *validation) { if (ip_hdr->ip_p != IPPROTO_TCP) { return 0; } if ((4 * ip_hdr->ip_hl + sizeof(struct tcphdr)) > len) { // buffer not large enough to contain expected tcp header return 0; } struct tcphdr *tcp = (struct tcphdr *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); uint16_t sport = tcp->th_sport; uint16_t dport = tcp->th_dport; // validate source port if (ntohs(sport) != zconf.target_port) { return 0; } // validate destination port if (!check_dst_port(ntohs(dport), num_ports, validation)) { return 0; } // DO NOT validate ack number as this is currently statically set // validate tcp acknowledgement number // if (htonl(tcp->th_ack) != htonl(validation[0])+1) { // return 0; //} return 1; } static void synscan_process_packet(const u_char *packet, uint32_t len, fieldset_t *fs, __attribute__((unused)) uint32_t *validation, __attribute__((unused)) struct timespec ts) { struct ip *ip_hdr = (struct ip *)&packet[sizeof(struct ether_header)]; struct tcphdr *tcp = (struct tcphdr *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); fs_add_uint64(fs, "sport", (uint64_t)ntohs(tcp->th_sport)); fs_add_uint64(fs, "dport", (uint64_t)ntohs(tcp->th_dport)); fs_add_uint64(fs, "seqnum", (uint64_t)ntohl(tcp->th_seq)); fs_add_uint64(fs, "acknum", (uint64_t)ntohl(tcp->th_ack)); fs_add_uint64(fs, "window", (uint64_t)ntohs(tcp->th_win)); fs_add_uint64(fs, "urgentptr", (uint64_t)ntohs(tcp->th_urp)); fs_add_uint64(fs, "flags", (uint64_t)ntohs(tcp->th_flags)); fs_add_binary(fs, "raw", len, (void *)packet, 0); if (tcp->th_flags & TH_RST) { // RST packet fs_add_string(fs, "classification", (char *)"rst", 0); fs_add_bool(fs, "success", 0); } else if (tcp->th_seq == EXPECTED_RESPONSE_SEQ && tcp->th_urp) { fs_add_string(fs, "classification", (char *)"backdoor", 0); fs_add_bool(fs, "success", 1); } else { // SYNACK packet fs_add_string(fs, "classification", (char *)"synack", 0); fs_add_bool(fs, "success", 1); } } static fielddef_t fields[] = { {.name = "sport", .type = "int", .desc = "TCP source port"}, {.name = "dport", .type = "int", .desc = "TCP destination port"}, {.name = "seqnum", .type = "int", .desc = "TCP sequence number"}, {.name = "acknum", .type = "int", .desc = "TCP acknowledgement number"}, {.name = "window", .type = "int", .desc = "TCP window"}, {.name = "urgentptr", .type = "int", .desc = "Urgent POinter"}, {.name = "flags", .type = "int", .desc = "tcp flags"}, {.name = "raw", .type = "binary", .desc = "raw packet"}, {.name = "classification", .type = "string", .desc = "packet classification"}, {.name = "success", .type = "bool", .desc = "is response considered success"}}; probe_module_t module_tcp_cisco_backdoor = { .name = "tcp_cisco_backdoor", .packet_length = 54, .pcap_filter = "tcp && tcp[13] & 4 != 0 || tcp[13] == 18", .pcap_snaplen = 256, .port_args = 1, .global_initialize = &synscan_global_initialize, .thread_initialize = &synscan_init_perthread, .make_packet = &synscan_make_packet, .print_packet = &synscan_print_packet, .process_packet = &synscan_process_packet, .validate_packet = &synscan_validate_packet, .close = NULL, .helptext = "Probe module that sends a TCP SYN packet to a specific " "port. Possible classifications are: synack and rst. A " "SYN-ACK packet is considered a success and a reset packet " "is considered a failed response.", .output_type = OUTPUT_TYPE_STATIC, .fields = fields, .numfields = 10}; zmap-4.3.4/examples/udp-probes/000077500000000000000000000000001501046211500163625ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/README000066400000000000000000000124441501046211500172470ustar00rootroot00000000000000 UDP Data Probes ====== This directory contains a set of data files that can be used with the UDP probe module. USING: ----- $ zmap -M udp -p 137 --probe-args=file:examples/udp-probes/netbios_137.pkt PROBES: ----- ard_3282.pkt This probe triggers a response from Apple Remote Desktop services on UDP port 3283 bacnet_47808.pkt This probe triggers a response from BACnet services on UDP port 47808 bacnet_rpm_47808.pkt blank_space.pkt This probe consists of a blank space character chargen_19.pkt This probe triggers a response from Character Generation protocol services on UDP port 19 citrix_1604.pkt This probe triggers a response from Citrix application discovery services on UDP port 1604 coap_5683.pkt This probe triggers a response from COAP services on UDP port 5683 db2_523.pkt db2disco_523.pkt This probe triggers a response from IBM DB2 discovery services on UDP port 523 digi1_2362.pkt This probe triggers a response from Digi ADDP discovery services on UDP port 2362 (default magic) digi2_2362.pkt This probe triggers a response from Digi ADDP discovery services on UDP port 2362 (devkit magic) digi3_2362.pkt This probe triggers a response from Digi ADDP discovery services on UDP port 2362 (oem magic) dns_53_queryAwww.google.it.pkt This probe queries for the domain www.google.it A record over UDP port 53 dns_53_queryAwww.google.com.pkt This probe queries for the domain www.google.com A record over UDP port 53 dns_53.pkt This probe queries for the DNS vendor and version using the BIND version TXT record over UDP port 53 dtls1.2_443_client_hello.pkt This probe sends a DTLS 1.2 (RFC 6347) client hello and solicits a server response (standard UDP port is 443) ipmi_623.pkt This probe triggers a Get Channel Authentication reply from IPMI endpoints on UDP port 623 ldap_389.pkt This probe triggers a response from Lightweight Directory Access Protocol services on UDP port 389 mdns_5353.pkt This probe triggers a response from mDNS/Avahi/Bonjour discovery services on UDP port 5353 memcache_11211.pkt This probe triggers a response from memcached on UDP port 11211 (stats items). mssql_1434.pkt This probe triggers a response from Microsoft SQL Server discovery services on UDP port 1434 nat_port_mapping_5351.pkt natpmp_5351.pkt This probe triggers a response from NATPMP-enabled devices on UDP port 5351 netbios_137.pkt This probe triggers a status reply from NetBIOS services on UDP port 137 netis_53413.pkt newline.pkt This probe consists of a newline character. ntp_123_monlist.pkt This probe triggers a response for command "monlist" from NTP services on UDP port 123 ntp_123.pkt This probe triggers a response from NTP services on UDP port 123 null_byte.pkt This probe consists of a null byte. pca_nq_5632.pkt This probe triggers a response from PC Anywhere services on UDP port 5632 (network query) pca_st_5632.pkt This probe triggers a response from PC Anywhere services on UDP port 5632 (status) pcanywhere_5632.pkt portmap_111.pkt This probe triggers a response from SunRPC portmapper services on UDP port 111 qotd_17.pkt This probe triggers a response from Quote of the Day services on UDP port 17 quic_ping_443.pkt This probe consists of a QUIC initial packet with version 0xbabababa to force Version Negotiation. Generated using https://github.com/kelmenhorst/quic-ping/ rdp_3389.pkt This probe triggers a response from Remote Desktop Protocol services on UDP port 3389 ripv1_520.pkt This probe triggers a response from the RIPv1 enabled routers/devices on UDP port 520 sentinel_5093.pkt This probe triggers a response from the Sentinel license manager service on UDP port 5093 sip_5060.pkt sip_options.tpl snmp1_161.pkt This probe queries for the system description field of SNMP v1 services using community string public over UDP port 161 snmp2_161.pkt This probe queries for the system description field of SNMP v2 services using community string public over UDP port 161 snmp3_161.pkt This probe triggers a response from SNMP v3 services on UDP port 161 ssdp_1900.pkt start_of_heading.pkt This probe consists of a start of heading byte. tftp_69.pkt This probe triggers a response from Trivial File Transfer protocol services on UDP port 69 ubiquiti_10001.pkt ubiquiti_discovery_v1_10001.pkt ubiquiti_discovery_v2_10001.pkt upnp_1900.pkt This probe triggers a response from UPnP SSDP services on UDP port 1900 valve_27015.pkt This probe triggers a response from Valve (Steam) services on UDP port 27015, the default for gameplay traffic wdbrpc_17185.pkt This probe triggers a response from VxWorks WDBRPC services on UDP port 17185 wsd_3702.pkt This probe triggers a response from WSD/DPWS services on UDP port 3702 wsd_malformed_3702.pkt xdcmp_177.pkt This probe triggers a response from X Display Manager Control Protocol services on UDP port 177 NOTES: ----- Most of these probes return useful data in the response. Parsing this data requires capturing the raw output and decoding this using a protocol-specific dissector. In most cases, Wireshark is capable of decoding these replies. zmap-4.3.4/examples/udp-probes/ard_3283.pkt000066400000000000000000000000051501046211500203220ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/bacnet_47808.pkt000066400000000000000000000000221501046211500211020ustar00rootroot00000000000000 Ö ?ÿÿKLzmap-4.3.4/examples/udp-probes/bacnet_rpm_47808.pkt000066400000000000000000000000451501046211500217650ustar00rootroot00000000000000 %   , 8 9 : F M x yzmap-4.3.4/examples/udp-probes/blank_space.pkt000066400000000000000000000000011501046211500213330ustar00rootroot00000000000000 zmap-4.3.4/examples/udp-probes/chargen_19.pkt000066400000000000000000000000011501046211500210110ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/citrix_1604.pkt000066400000000000000000000000361501046211500210550ustar00rootroot000000000000000ý¨ãzmap-4.3.4/examples/udp-probes/coap_5683.pkt000066400000000000000000000000251501046211500205060ustar00rootroot00000000000000@}p».well-knowncorezmap-4.3.4/examples/udp-probes/db2_523.pkt000066400000000000000000000000241501046211500201360ustar00rootroot00000000000000DB2GETADDRSQL09010zmap-4.3.4/examples/udp-probes/db2disco_523.pkt000066400000000000000000000000241501046211500211600ustar00rootroot00000000000000DB2GETADDRSQL05000zmap-4.3.4/examples/udp-probes/digi1_2362.pkt000066400000000000000000000000161501046211500205500ustar00rootroot00000000000000DIGIÿÿÿÿÿÿzmap-4.3.4/examples/udp-probes/digi2_2362.pkt000066400000000000000000000000161501046211500205510ustar00rootroot00000000000000DVKTÿÿÿÿÿÿzmap-4.3.4/examples/udp-probes/digi3_2362.pkt000066400000000000000000000000161501046211500205520ustar00rootroot00000000000000DGDPÿÿÿÿÿÿzmap-4.3.4/examples/udp-probes/dns_53.pkt000066400000000000000000000000361501046211500201740ustar00rootroot000000000000004ïVERSIONBINDzmap-4.3.4/examples/udp-probes/dns_53_queryAwww.google.com.pkt000066400000000000000000000000401501046211500243120ustar00rootroot00000000000000® wwwgooglecomzmap-4.3.4/examples/udp-probes/dns_53_queryAwww.google.it.pkt000066400000000000000000000000371501046211500241560ustar00rootroot00000000000000Kwwwgoogleitzmap-4.3.4/examples/udp-probes/dtls1.2_443_client_hello.pkt000066400000000000000000000001631501046211500234040ustar00rootroot00000000000000þÿfZZþý¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥2À,Ì©À­À À+À¬À À0̨ÀÀ/ÀÀ5œÀœ/ŸÌªÀŸ9žÀž3zmap-4.3.4/examples/udp-probes/ipmi_623.pkt000066400000000000000000000000271501046211500204310ustar00rootroot00000000000000ÿ È8޵zmap-4.3.4/examples/udp-probes/ldap_389.pkt000066400000000000000000000000651501046211500204260ustar00rootroot000000000000000„-c„$  ‡ objectclass0„ zmap-4.3.4/examples/udp-probes/mdns_5353.pkt000066400000000000000000000000561501046211500205230ustar00rootroot00000000000000 _services_dns-sd_udplocal zmap-4.3.4/examples/udp-probes/memcache_11211.pkt000066400000000000000000000000251501046211500213660ustar00rootroot00000000000000ZMstats items zmap-4.3.4/examples/udp-probes/mssql_1434.pkt000066400000000000000000000000011501046211500207030ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/nat_port_mapping_5351.pkt000066400000000000000000000000221501046211500231120ustar00rootroot00000000000000ã³äƒzmap-4.3.4/examples/udp-probes/natpmp_5351.pkt000066400000000000000000000000041501046211500210500ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/netbios_137.pkt000066400000000000000000000000621501046211500211350ustar00rootroot00000000000000åØ CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!zmap-4.3.4/examples/udp-probes/netis_53413.pkt000066400000000000000000000000221501046211500207550ustar00rootroot00000000000000 ž!½­zmap-4.3.4/examples/udp-probes/newline.pkt000066400000000000000000000000011501046211500205320ustar00rootroot00000000000000 zmap-4.3.4/examples/udp-probes/ntp_123.pkt000066400000000000000000000000601501046211500202640ustar00rootroot00000000000000ãúÅO#Kq±Rózmap-4.3.4/examples/udp-probes/ntp_123_monlist.pkt000066400000000000000000000003001501046211500220260ustar00rootroot00000000000000*zmap-4.3.4/examples/udp-probes/null_byte.pkt000066400000000000000000000000011501046211500210660ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/openvpn_1194.pkt000066400000000000000000000000221501046211500212370ustar00rootroot0000000000000088±&Þzmap-4.3.4/examples/udp-probes/pca_nq_5632.pkt000066400000000000000000000000021501046211500210120ustar00rootroot00000000000000NQzmap-4.3.4/examples/udp-probes/pca_st_5632.pkt000066400000000000000000000000021501046211500210220ustar00rootroot00000000000000STzmap-4.3.4/examples/udp-probes/pcanywhere_5632.pkt000066400000000000000000000000221501046211500217200ustar00rootroot00000000000000NQAô¿¦zmap-4.3.4/examples/udp-probes/portmap_111.pkt000066400000000000000000000000501501046211500211410ustar00rootroot00000000000000©ÿᆠzmap-4.3.4/examples/udp-probes/qotd_17.pkt000066400000000000000000000000021501046211500203500ustar00rootroot00000000000000 zmap-4.3.4/examples/udp-probes/quic_ping_443.pkt000066400000000000000000000022601501046211500214520ustar00rootroot00000000000000ÀDö5™ÞÑU—E 5úÞÓ4”Κ@ ¡ˆ¸>êû[ÐyTK ϵ*ÄØóçA´qà4ƒßôãzmap-4.3.4/examples/udp-probes/rdp_3389.pkt000066400000000000000000000000221501046211500203470ustar00rootroot00000000000000ÿTzmap-4.3.4/examples/udp-probes/ripv1_520.pkt000066400000000000000000000000301501046211500205220ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/sentinel_5093.pkt000066400000000000000000000000061501046211500213770ustar00rootroot00000000000000zzmap-4.3.4/examples/udp-probes/sip_5060.pkt000066400000000000000000000000071501046211500203440ustar00rootroot00000000000000OPTIONSzmap-4.3.4/examples/udp-probes/sip_options.tpl000066400000000000000000000006461501046211500214570ustar00rootroot00000000000000OPTIONS sip:${RAND_ALPHA=8}@${DADDR} SIP/2.0 Via: SIP/2.0/UDP ${SADDR}:${SPORT};branch=${RAND_ALPHA=6}.${RAND_DIGIT=10};rport;alias From: sip:${RAND_ALPHA=8}@${SADDR}:${SPORT};tag=${RAND_DIGIT=8} To: sip:${RAND_ALPHA=8}@${DADDR} Call-ID: ${RAND_DIGIT=10}@${SADDR} CSeq: 1 OPTIONS Contact: sip:${RAND_ALPHA=8}@${SADDR}:${SPORT} Content-Length: 0 Max-Forwards: 20 User-Agent: ${RAND_ALPHA=8} Accept: text/plain zmap-4.3.4/examples/udp-probes/snmp1_161.pkt000066400000000000000000000000531501046211500205250ustar00rootroot000000000000000)public VZÜ]00 +zmap-4.3.4/examples/udp-probes/snmp2_161.pkt000066400000000000000000000000501501046211500205230ustar00rootroot000000000000000&public¡Ücš0 0 +zmap-4.3.4/examples/udp-probes/snmp3_161.pkt000066400000000000000000000000741501046211500205320ustar00rootroot000000000000000:0Jiÿã00  7ð0zmap-4.3.4/examples/udp-probes/ssdp_1900.pkt000066400000000000000000000001241501046211500205210ustar00rootroot00000000000000M-SEARCH * HTTP/1.1 HOST:239.255.255.250:1900 ST:ssdp:all MAN:"ssdp:discover" zmap-4.3.4/examples/udp-probes/start_of_heading.pkt000066400000000000000000000000011501046211500223710ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/tftp_69.pkt000066400000000000000000000000161501046211500203720ustar00rootroot00000000000000/anetasciizmap-4.3.4/examples/udp-probes/ubiquiti_10001.pkt000066400000000000000000000000221501046211500214500ustar00rootroot00000000000000£fzmap-4.3.4/examples/udp-probes/ubiquiti_discovery_v1_10001.pkt000066400000000000000000000000041501046211500241450ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/ubiquiti_discovery_v2_10001.pkt000066400000000000000000000000041501046211500241460ustar00rootroot00000000000000zmap-4.3.4/examples/udp-probes/upnp_1900.pkt000066400000000000000000000001431501046211500205330ustar00rootroot00000000000000M-SEARCH * HTTP/1.1 Host:239.255.255.250:1900 ST:upnp:rootdevice Man:"ssdp:discover" MX:3 zmap-4.3.4/examples/udp-probes/valve_27015.pkt000066400000000000000000000000311501046211500207470ustar00rootroot00000000000000ÿÿÿÿTSource Engine Queryzmap-4.3.4/examples/udp-probes/wdbrpc_17185.pkt000066400000000000000000000001001501046211500211170ustar00rootroot00000000000000 úºUUUUÿÿU<zmap-4.3.4/examples/udp-probes/wsd_3702.pkt000066400000000000000000000011631501046211500203530ustar00rootroot00000000000000 urn:schemas-xmlsoap-org:ws:2005:04:discoveryhttp://schemas.xmlsoap.org/ws/2005/04/discovery/Probeurn:uuid:ce04dad0-5d2c-4026-9146-1aabfc1e4111wsdp:Device zmap-4.3.4/examples/udp-probes/wsd_malformed_3702.pkt000066400000000000000000000000051501046211500223730ustar00rootroot00000000000000<:/> zmap-4.3.4/examples/udp-probes/xdmcp_177.pkt000066400000000000000000000000071501046211500206100ustar00rootroot00000000000000zmap-4.3.4/format.sh000077500000000000000000000012251501046211500143130ustar00rootroot00000000000000#!/bin/bash set -e set -o pipefail MAJOR_REV=$((clang-format --version | awk '{print $3}' | cut -d '.' -f 1) || echo 0) if [ $MAJOR_REV -lt 5 ]; then echo "error: need at least clang-format version 5.x" exit 1 fi FORMAT_CMD="clang-format -i -style=file" # No files passed, format everything if [ $# -eq 0 ]; then echo "formatting all C code in src/ and lib/" find ./src -type f -name '*.c' -exec $FORMAT_CMD {} \; find ./src -type f -name '*.h' -exec $FORMAT_CMD {} \; find ./lib -type f -name '*.c' -exec $FORMAT_CMD {} \; find ./lib -type f -name '*.h' -exec $FORMAT_CMD {} \; exit 0 fi # File names passed, format only those files $FORMAT_CMD $@ zmap-4.3.4/lib/000077500000000000000000000000001501046211500132325ustar00rootroot00000000000000zmap-4.3.4/lib/CMakeLists.txt000066400000000000000000000005671501046211500160020ustar00rootroot00000000000000SET(LIB_SOURCES blocklist.c cachehash.c constraint.c logger.c pbm.c random.c rijndael-alg-fst.c xalloc.c lockfd.c util.c queue.c csv.c aes128.c ) add_library(zmaplib STATIC ${LIB_SOURCES}) target_link_libraries( zmaplib ${JUDY_LIBRARIES} ) target_include_directories (zmaplib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) zmap-4.3.4/lib/aes128.c000066400000000000000000000244151501046211500144070ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "aes128.h" #include "../lib/rijndael-alg-fst.h" #include "../lib/logger.h" #include #include #include #include #include #define AES128_ROUNDS 10 #define BITS_PER_BYTE 8 #ifdef AES_HW #if defined(__x86_64__) #define AES_HW_NAME "AES-NI" #include #include static bool aes128_hw_supported(void) { static const uint32_t flag_cpuid_ecx_aesni = 0x02000000; uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; __cpuid(1, eax, ebx, ecx, edx); return (ecx & flag_cpuid_ecx_aesni) != 0; } #if defined(__clang__) #pragma clang attribute push(__attribute__((target("sse2,aes"))), apply_to = function) #elif defined(__GNUC__) #pragma GCC push_options #pragma GCC target("sse2,aes") #endif struct aes128_hw_ctx { __m128i rk[AES128_ROUNDS + 1]; }; static __m128i aes128_hw_round_key(__m128i rk, __m128i rc) { rc = _mm_shuffle_epi32(rc, _MM_SHUFFLE(3, 3, 3, 3)); rk = _mm_xor_si128(rk, _mm_slli_si128(rk, 4)); rk = _mm_xor_si128(rk, _mm_slli_si128(rk, 4)); rk = _mm_xor_si128(rk, _mm_slli_si128(rk, 4)); return _mm_xor_si128(rk, rc); } static void aes128_hw_key_sched(uint8_t const *key, struct aes128_hw_ctx *ctx) { __m128i *rk = ctx->rk; rk[0] = _mm_loadu_si128((__m128i const *)key); rk[1] = aes128_hw_round_key(rk[0], _mm_aeskeygenassist_si128(rk[0], 0x01)); rk[2] = aes128_hw_round_key(rk[1], _mm_aeskeygenassist_si128(rk[1], 0x02)); rk[3] = aes128_hw_round_key(rk[2], _mm_aeskeygenassist_si128(rk[2], 0x04)); rk[4] = aes128_hw_round_key(rk[3], _mm_aeskeygenassist_si128(rk[3], 0x08)); rk[5] = aes128_hw_round_key(rk[4], _mm_aeskeygenassist_si128(rk[4], 0x10)); rk[6] = aes128_hw_round_key(rk[5], _mm_aeskeygenassist_si128(rk[5], 0x20)); rk[7] = aes128_hw_round_key(rk[6], _mm_aeskeygenassist_si128(rk[6], 0x40)); rk[8] = aes128_hw_round_key(rk[7], _mm_aeskeygenassist_si128(rk[7], 0x80)); rk[9] = aes128_hw_round_key(rk[8], _mm_aeskeygenassist_si128(rk[8], 0x1B)); rk[10] = aes128_hw_round_key(rk[9], _mm_aeskeygenassist_si128(rk[9], 0x36)); } static void aes128_hw_enc_block(struct aes128_hw_ctx const *ctx, uint8_t const *pt, uint8_t *ct) { __m128i const *rk = ctx->rk; __m128i block = _mm_loadu_si128((__m128i *)pt); block = _mm_xor_si128(block, rk[0]); block = _mm_aesenc_si128(block, rk[1]); block = _mm_aesenc_si128(block, rk[2]); block = _mm_aesenc_si128(block, rk[3]); block = _mm_aesenc_si128(block, rk[4]); block = _mm_aesenc_si128(block, rk[5]); block = _mm_aesenc_si128(block, rk[6]); block = _mm_aesenc_si128(block, rk[7]); block = _mm_aesenc_si128(block, rk[8]); block = _mm_aesenc_si128(block, rk[9]); block = _mm_aesenclast_si128(block, rk[10]); _mm_storeu_si128((__m128i *)ct, block); } #if defined(__clang__) #pragma clang attribute pop #elif defined(__GNUC__) #pragma GCC pop_options #endif #elif defined(__aarch64__) #define AES_HW_NAME "ARMv8 CE" #ifdef __ARM_ACLE #include #endif #ifdef __ARM_NEON #include #endif #if defined(__APPLE__) #include #include #elif defined(__FreeBSD__) #include #ifndef HWCAP_NEON #define HWCAP_NEON 0x00001000 #endif #ifndef HWCAP2_AES #define HWCAP2_AES 0x00000001 #endif #elif defined(__linux__) #include #ifndef HWCAP_NEON #define HWCAP_NEON 0x00000010 #endif #ifndef HWCAP_AES #define HWCAP_AES 0x00001000 #endif #else #warning "Runtime detection of AES hardware acceleration not implemented for platform" #endif static bool aes128_hw_supported(void) { #if defined(__APPLE__) int value = 0; size_t value_len = sizeof(value); if (sysctlbyname("hw.optional.arm.FEAT_AES", &value, &value_len, NULL, 0) == -1) { return false; } assert(value_len == sizeof(value)); return (value != 0); #elif defined(__FreeBSD__) unsigned long hwcap = 0, hwcap2 = 0; elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2)); return ((hwcap & HWCAP_NEON) && (hwcap2 & HWCAP2_AES)); #elif defined(__linux__) unsigned long hwcap = getauxval(AT_HWCAP); return ((hwcap & HWCAP_NEON) && (hwcap & HWCAP_AES)); #else return true; #endif } #if defined(__clang__) #pragma clang attribute push(__attribute__((target("aes"))), apply_to = function) #elif defined(__GNUC__) #pragma GCC push_options #pragma GCC target("+aes") #endif struct aes128_hw_ctx { uint8_t rk[AES128_ROUNDS + 1][AES128_KEY_BYTES]; }; // clang-format off static uint8_t const sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, }; // clang-format on static uint8_t const rcon[AES128_ROUNDS + 1] = {0, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; static void aes128_hw_key_sched(uint8_t const *key, struct aes128_hw_ctx *ctx) { memcpy(ctx->rk[0], key, AES128_KEY_BYTES); for (size_t i = 1; i < AES128_ROUNDS + 1; i++) { ctx->rk[i][0] = ctx->rk[i - 1][0] ^ sbox[ctx->rk[i - 1][13]] ^ rcon[i]; ctx->rk[i][1] = ctx->rk[i - 1][1] ^ sbox[ctx->rk[i - 1][14]]; ctx->rk[i][2] = ctx->rk[i - 1][2] ^ sbox[ctx->rk[i - 1][15]]; ctx->rk[i][3] = ctx->rk[i - 1][3] ^ sbox[ctx->rk[i - 1][12]]; *(uint32_t *)&ctx->rk[i][4] = *(uint32_t *)&ctx->rk[i - 1][4] ^ *(uint32_t *)&ctx->rk[i][0]; *(uint32_t *)&ctx->rk[i][8] = *(uint32_t *)&ctx->rk[i - 1][8] ^ *(uint32_t *)&ctx->rk[i][4]; *(uint32_t *)&ctx->rk[i][12] = *(uint32_t *)&ctx->rk[i - 1][12] ^ *(uint32_t *)&ctx->rk[i][8]; } } static void aes128_hw_enc_block(struct aes128_hw_ctx const *ctx, uint8_t const *pt, uint8_t *ct) { uint8x16_t block = vld1q_u8(pt); block = vaeseq_u8(block, vld1q_u8(ctx->rk[0])); block = vaesmcq_u8(block); block = vaeseq_u8(block, vld1q_u8(ctx->rk[1])); block = vaesmcq_u8(block); block = vaeseq_u8(block, vld1q_u8(ctx->rk[2])); block = vaesmcq_u8(block); block = vaeseq_u8(block, vld1q_u8(ctx->rk[3])); block = vaesmcq_u8(block); block = vaeseq_u8(block, vld1q_u8(ctx->rk[4])); block = vaesmcq_u8(block); block = vaeseq_u8(block, vld1q_u8(ctx->rk[5])); block = vaesmcq_u8(block); block = vaeseq_u8(block, vld1q_u8(ctx->rk[6])); block = vaesmcq_u8(block); block = vaeseq_u8(block, vld1q_u8(ctx->rk[7])); block = vaesmcq_u8(block); block = vaeseq_u8(block, vld1q_u8(ctx->rk[8])); block = vaesmcq_u8(block); block = vaeseq_u8(block, vld1q_u8(ctx->rk[9])); block = veorq_u8(block, vld1q_u8(ctx->rk[10])); vst1q_u8(ct, block); } #if defined(__clang__) #pragma clang attribute pop #elif defined(__GNUC__) #pragma GCC pop_options #endif #else #error "AES hardware acceleration not implemented for this architecture" #endif #endif // AES_HW struct aes128_ctx { union { struct { uint32_t rk[(AES128_ROUNDS + 1) * 4]; } sw; #ifdef AES_HW struct aes128_hw_ctx hw; #endif } u; }; #ifdef AES_HW static bool use_hw = false; #endif static pthread_once_t aes128_inited = PTHREAD_ONCE_INIT; static void aes128_init_once(void) { #ifdef AES_HW use_hw = aes128_hw_supported(); if (use_hw) { log_debug("aes128", "AES hardware acceleration available, using " AES_HW_NAME); } else { log_debug("aes128", "AES hardware acceleration unavailable, using software AES"); } #else log_debug("aes128", "Built without AES hardware acceleration, using software AES"); #endif } aes128_ctx_t * aes128_init(uint8_t const *key) { pthread_once(&aes128_inited, aes128_init_once); aes128_ctx_t *ctx = (aes128_ctx_t *)malloc(sizeof(aes128_ctx_t)); assert(ctx); memset(ctx, 0, sizeof(aes128_ctx_t)); #ifdef AES_HW if (use_hw) { aes128_hw_key_sched(key, &ctx->u.hw); return ctx; } #endif int rv = rijndaelKeySetupEnc(ctx->u.sw.rk, key, AES128_KEY_BYTES * BITS_PER_BYTE); assert(rv == AES128_ROUNDS); return ctx; } void aes128_encrypt_block(aes128_ctx_t *ctx, uint8_t const *pt, uint8_t *ct) { #ifdef AES_HW if (use_hw) { aes128_hw_enc_block(&ctx->u.hw, pt, ct); return; } #endif rijndaelEncrypt(ctx->u.sw.rk, AES128_ROUNDS, pt, ct); } void aes128_fini(aes128_ctx_t *ctx) { free(ctx); } void aes128_selftest(void) { // Test vector from appendix C of NIST FIPS-197. uint8_t const pt[AES128_BLOCK_BYTES] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; uint8_t const key[AES128_KEY_BYTES] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; uint8_t const expected_ct[AES128_BLOCK_BYTES] = {0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a}; uint8_t actual_ct[AES128_BLOCK_BYTES]; memset(actual_ct, 0, sizeof(actual_ct)); aes128_ctx_t *ctx = aes128_init(key); aes128_encrypt_block(ctx, pt, actual_ct); aes128_fini(ctx); if (memcmp(actual_ct, expected_ct, AES128_BLOCK_BYTES) != 0) { log_fatal("aes128", "AES self-test with NIST test vector failed"); } } zmap-4.3.4/lib/aes128.h000066400000000000000000000012141501046211500144040ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_AES_H #define ZMAP_AES_H #include #define AES128_KEY_BYTES 16 #define AES128_BLOCK_BYTES 16 typedef struct aes128_ctx aes128_ctx_t; aes128_ctx_t *aes128_init(uint8_t const *key); void aes128_encrypt_block(aes128_ctx_t *ctx, uint8_t const *pt, uint8_t *ct); void aes128_fini(aes128_ctx_t *ctx); void aes128_selftest(void); #endif zmap-4.3.4/lib/blocklist.c000066400000000000000000000201061501046211500153630ustar00rootroot00000000000000/* * Blocklist Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include #include #include #include #include #include "blocklist.h" #include "constraint.h" #include "logger.h" #include "xalloc.h" #define ADDR_DISALLOWED 0 #define ADDR_ALLOWED 1 typedef struct bl_linked_list { bl_cidr_node_t *first; bl_cidr_node_t *last; uint32_t len; } bl_ll_t; static constraint_t *constraint = NULL; // keep track of the prefixes we've tried to BL/WL // for logging purposes static bl_ll_t *blocklisted_cidrs = NULL; static bl_ll_t *allowlisted_cidrs = NULL; void bl_ll_add(bl_ll_t *l, struct in_addr addr, uint16_t p) { assert(l); bl_cidr_node_t *new = xmalloc(sizeof(bl_cidr_node_t)); new->next = NULL; new->ip_address = addr.s_addr; new->prefix_len = p; if (!l->first) { l->first = new; } else { l->last->next = new; } l->last = new; l->len++; } bl_cidr_node_t *get_blocklisted_cidrs(void) { return blocklisted_cidrs->first; } bl_cidr_node_t *get_allowlisted_cidrs(void) { return allowlisted_cidrs->first; } uint32_t blocklist_lookup_index(uint64_t index) { return ntohl(constraint_lookup_index(constraint, index, ADDR_ALLOWED)); } // check whether a single IP address is allowed to be scanned. // 1 => is allowed // 0 => is not allowed int blocklist_is_allowed(uint32_t s_addr) { return constraint_lookup_ip(constraint, ntohl(s_addr)) == ADDR_ALLOWED; } static void _add_constraint(struct in_addr addr, int prefix_len, int value) { constraint_set(constraint, ntohl(addr.s_addr), prefix_len, value); if (value == ADDR_ALLOWED) { bl_ll_add(allowlisted_cidrs, addr, prefix_len); } else if (value == ADDR_DISALLOWED) { bl_ll_add(blocklisted_cidrs, addr, prefix_len); } else { log_fatal("blocklist", "unknown type of blocklist operation specified"); } } // blocklist a CIDR network allocation // e.g. blocklist_add("128.255.134.0", 24) void blocklist_prefix(char *ip, int prefix_len) { struct in_addr addr; addr.s_addr = inet_addr(ip); _add_constraint(addr, prefix_len, ADDR_DISALLOWED); } // allowlist a CIDR network allocation void allowlist_prefix(char *ip, int prefix_len) { struct in_addr addr; addr.s_addr = inet_addr(ip); _add_constraint(addr, prefix_len, ADDR_ALLOWED); } static int is_ip_ipv6(char *ip) { // don't modify the input string char *new_str = strdup(ip); // check if there's a subnet mask_char char *mask_char = strchr(new_str, '/'); if (mask_char != NULL) { // set mask_char char to NULL char, so we can check if subnet is valid IPv6 *mask_char = '\0'; } // attempt conversion of IP into IPv6 struct to check if IP is an IPv6 address struct in6_addr ipv6_addr; if (inet_pton(AF_INET6, new_str, &ipv6_addr) == 1) { free(new_str); return true; } free(new_str); return false; } static int init_from_string(char *ip, int value) { if (is_ip_ipv6(ip)) { log_debug("constraint", "ignoring IPv6 IP/subnet: %s", ip); return 0; } int prefix_len = 32; char *slash = strchr(ip, '/'); if (slash) { // split apart network and prefix length *slash = '\0'; char *end; char *len = slash + 1; errno = 0; prefix_len = strtol(len, &end, 10); if (end == len || errno != 0 || prefix_len < 0 || prefix_len > 32) { log_fatal("constraint", "'%s' is not a valid IPv4 prefix length", len); return -1; } } struct in_addr addr; int ret = -1; if (inet_aton(ip, &addr) == 0) { // Not an IP and not a CIDR block, try dns resolution struct addrinfo hint, *res; memset(&hint, 0, sizeof(hint)); hint.ai_family = PF_INET; int r = getaddrinfo(ip, NULL, &hint, &res); if (r) { log_error("constraint", "'%s' is not a valid IP " "address or hostname", ip); return -1; } // Got some addrinfo, let's see what happens for (struct addrinfo *aip = res; aip; aip = aip->ai_next) { if (aip->ai_family != AF_INET) { continue; } struct sockaddr_in *sa = (struct sockaddr_in *)aip->ai_addr; memcpy(&addr, &sa->sin_addr, sizeof(addr)); log_debug("constraint", "%s retrieved by hostname", inet_ntoa(addr)); ret = 0; _add_constraint(addr, prefix_len, value); } } else { _add_constraint(addr, prefix_len, value); return 0; } return ret; } static int init_from_file(char *file, const char *name, int value, int ignore_invalid_hosts) { FILE *fp; char line[1000]; fp = fopen(file, "r"); if (fp == NULL) { log_fatal(name, "unable to open %s file: %s: %s", name, file, strerror(errno)); } while (fgets(line, sizeof(line), fp) != NULL) { char *comment = strchr(line, '#'); if (comment) { *comment = '\0'; } // hostnames can be up to 255 bytes char ip[256]; if ((sscanf(line, "%255s", ip)) == EOF) { continue; } if (init_from_string(ip, value)) { if (!ignore_invalid_hosts) { log_fatal(name, "unable to parse %s file: %s", name, file); } } } fclose(fp); return 0; } static void init_from_array(char **cidrs, size_t len, int value, int ignore_invalid_hosts) { for (int i = 0; i < (int)len; i++) { int ret = init_from_string(cidrs[i], value); if (ret && !ignore_invalid_hosts) { log_fatal("constraint", "Unable to init from CIDR list"); } } } uint64_t blocklist_count_allowed(void) { assert(constraint); return constraint_count_ips(constraint, ADDR_ALLOWED); } uint64_t blocklist_count_not_allowed(void) { assert(constraint); return constraint_count_ips(constraint, ADDR_DISALLOWED); } // network order uint32_t blocklist_ip_to_index(uint32_t ip) { assert(constraint); uint32_t ip_hostorder = ntohl(ip); return constraint_lookup_ip(constraint, ip_hostorder); } // Initialize address constraints from allowlist and blocklist files. // Either can be set to NULL to omit. int blocklist_init(char *allowlist_filename, char *blocklist_filename, char **allowlist_entries, size_t allowlist_entries_len, char **blocklist_entries, size_t blocklist_entries_len, int ignore_invalid_hosts) { assert(!constraint); blocklisted_cidrs = xcalloc(1, sizeof(bl_ll_t)); allowlisted_cidrs = xcalloc(1, sizeof(bl_ll_t)); if (allowlist_filename && allowlist_entries) { log_warn("allowlist", "both a allowlist file and destination addresses " "were specified. The union of these two sources " "will be utilized."); } if (allowlist_filename || allowlist_entries_len > 0) { // using a allowlist, so default to allowing nothing constraint = constraint_init(ADDR_DISALLOWED); log_debug("constraint", "blocklisting 0.0.0.0/0"); if (allowlist_filename) { init_from_file(allowlist_filename, "allowlist", ADDR_ALLOWED, ignore_invalid_hosts); } if (allowlist_entries) { init_from_array(allowlist_entries, allowlist_entries_len, ADDR_ALLOWED, ignore_invalid_hosts); } } else { // no allowlist, so default to allowing everything log_debug("blocklist", "no allowlist file or allowlist entries provided"); constraint = constraint_init(ADDR_ALLOWED); } if (blocklist_filename) { init_from_file(blocklist_filename, "blocklist", ADDR_DISALLOWED, ignore_invalid_hosts); } if (blocklist_entries) { init_from_array(blocklist_entries, blocklist_entries_len, ADDR_DISALLOWED, ignore_invalid_hosts); } init_from_string(strdup("0.0.0.0"), ADDR_DISALLOWED); constraint_paint_value(constraint, ADDR_ALLOWED); uint64_t allowed = blocklist_count_allowed(); log_debug("constraint", "%lu addresses (%0.0f%% of address " "space) can be scanned", allowed, allowed * 100. / ((long long int)1 << 32)); if (!allowed) { log_error("blocklist", "no addresses are eligible to be scanned in the " "current configuration. This may be because the " "blocklist being used by ZMap (%s) prevents " "any addresses from receiving probe packets.", blocklist_filename); return EXIT_FAILURE; } return EXIT_SUCCESS; } zmap-4.3.4/lib/blocklist.h000066400000000000000000000026501501046211500153740ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #ifndef BLACKLIST_H #define BLACKLIST_H typedef struct bl_cidr_node { uint32_t ip_address; int prefix_len; struct bl_cidr_node *next; } bl_cidr_node_t; uint32_t blocklist_lookup_index(uint64_t index); int blocklist_is_allowed(uint32_t s_addr); void blocklist_prefix(char *ip, int prefix_len); void allowlist_prefix(char *ip, int prefix_len); int blocklist_init(char *allowlist, char *blocklist, char **allowlist_entries, size_t allowlist_entries_len, char **blocklist_entries, size_t blocklist_entries_len, int ignore_invalid_hosts); uint64_t blocklist_count_allowed(void); uint64_t blocklist_count_not_allowed(void); uint32_t blocklist_ip_to_index(uint32_t ip); bl_cidr_node_t *get_blocklisted_cidrs(void); bl_cidr_node_t *get_allowlisted_cidrs(void); #endif zmap-4.3.4/lib/cachehash.c000066400000000000000000000125351501046211500153130ustar00rootroot00000000000000/* * CacheHash Copyright 2014 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "cachehash.h" #include #include #include #include #include #include #include #define EVICTION_NEEDED 1 #define EVICTION_UNNEC 0 // doubly-linked-list node typedef struct node { struct node *next; struct node *prev; void *key; size_t keylen; void *data; } node_t; // data structure that contains the enterity of a linked list // we typedef this as cachehash in cachehash.h s.t. external interface is clean struct cachehash_s { Pvoid_t judy; void *malloced; node_t *start; node_t *end; node_t *curr_end; size_t maxsize; size_t currsize; cachehash_process_cb *evict_cb; }; cachehash *cachehash_init(size_t maxitems, cachehash_process_cb *cb) { assert(maxitems > 0); cachehash *retv = malloc(sizeof(cachehash)); assert(retv); memset(retv, 0, sizeof(cachehash)); // allocate nodes all at once to avoid fragmented memory node_t *nodes = calloc(maxitems, sizeof(node_t)); retv->malloced = nodes; assert(nodes); retv->start = nodes; retv->curr_end = nodes; retv->end = &nodes[maxitems - 1]; retv->maxsize = maxitems; retv->currsize = 0; // initial node nodes[0].next = &nodes[1]; // middle nodes for (unsigned int i = 1; i < maxitems - 1; i++) { nodes[i].prev = &nodes[i - 1]; nodes[i].next = &nodes[i + 1]; } // last node nodes[maxitems - 1].prev = &nodes[maxitems - 2]; retv->evict_cb = cb; return retv; } void cachehash_set_evict_cb(cachehash *ch, cachehash_process_cb *cb) { ch->evict_cb = cb; } // is the hashcache full? static inline int eviction_needed(cachehash *ch) { assert(ch); return ch->currsize == ch->maxsize; } // completely evict the LRU object // does not cb to user w/ object static inline void *evict(cachehash *ch) { assert(ch); node_t *last = ch->end; // remove item from judy array int rc; JHSD(rc, ch->judy, last->key, last->keylen); // we should never end up with something in the linked list // that's not in the judy array. assert(rc); // reset linked list node void *retv = last->data; last->data = NULL; free(last->key); last->key = NULL; last->keylen = 0; ch->currsize--; ch->curr_end = ch->end; return retv; } static inline void use(cachehash *ch, node_t *n) { assert(ch); assert(n); //if first node, nothing to do and return if (n == ch->start) { return; } // remove from current spot in linked list node_t *prev = n->prev; n->prev->next = n->next; // if last node then no next, but must update LL if (n->next) { n->next->prev = prev; } else { ch->end = prev; } // front of list n->next = ch->start; ch->start->prev = n; ch->start = n; n->prev = NULL; } static inline node_t *judy_get(cachehash *ch, void *key, size_t keylen) { assert(ch); assert(key); assert(keylen); Word_t *v_; JHSG(v_, ch->judy, key, keylen); if (!v_) { return NULL; } return (node_t *)*v_; } void *cachehash_has(cachehash *ch, const void *key, size_t keylen) { assert(ch); assert(key); assert(keylen); node_t *n = judy_get(ch, (void *)key, keylen); if (n) { return n->data; } else { return NULL; } } void *cachehash_get(cachehash *ch, const void *key, size_t keylen) { assert(ch); assert(key); assert(keylen); node_t *n = judy_get(ch, (void *)key, keylen); if (n) { use(ch, n); return n->data; } else { return NULL; } } void *cachehash_evict_if_full(cachehash *ch) { assert(ch); if (eviction_needed(ch) == EVICTION_UNNEC) { return NULL; } return evict(ch); } void cachehash_put(cachehash *ch, const void *key, size_t keylen, void *value) { assert(ch); assert(key); assert(keylen); void *evicted = cachehash_evict_if_full(ch); if (evicted && ch->evict_cb) { ch->evict_cb(evicted); ch->curr_end = ch->end; } // create new node node_t *n; void *newkey = malloc(keylen); n = ch->curr_end; memcpy(newkey, key, keylen); n->key = newkey; n->keylen = keylen; n->data = value; //n->prev = ch->curr_end->prev; //n->next = ch->curr_end->next; if (ch->curr_end != ch->end) { ch->curr_end = ch->curr_end->next; ch->curr_end->prev = n; } use(ch, n); ch->currsize++; // add to judy array Word_t *v_; JHSI(v_, ch->judy, (void *)key, keylen); // key should not already be in hash table assert(!*v_); *v_ = (Word_t)n; } // print out entire state. void cachehash_debug_dump(cachehash *ch) { printf("Statistics:\n"); printf("\tcurrent size: %lu\n", ch->currsize); printf("\tmaximum size: %lu\n", ch->maxsize); printf("\n"); printf("Linked List:\n"); size_t i = 0; node_t *n = ch->start; do { if (n->key) { printf("\t%lu: %s -> %s\n", i++, (char *)n->key, (char *)n->data); } else { printf("\t%lu: EMPTY\n", i++); } n = n->next; } while (n); } void cachehash_free(cachehash *ch, cachehash_process_cb *cb) { assert(ch); int rc; JHSFA(rc, ch->judy); node_t *n = ch->start; do { if (n->key) { free(n->key); if (cb) { cb(n->data); } } n = n->next; } while (n); free(ch->malloced); free(ch); } void cachehash_iter(cachehash *ch, cachehash_process_cb *cb) { node_t *n = ch->start; do { if (n->key) { cb(n->data); } else { break; } n = n->next; } while (n); } zmap-4.3.4/lib/cachehash.h000066400000000000000000000032171501046211500153150ustar00rootroot00000000000000/* * CacheHash Copyright 2014 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef CACHEHASH_H #define CACHEHASH_H #include #include #ifdef __cplusplus extern "C" { #endif typedef struct cachehash_s cachehash; // function defintion for cachehash callbacks typedef void(cachehash_process_cb)(void *data); // initialize new cache hash cachehash *cachehash_init(size_t maxitems, cachehash_process_cb *cb); // return item from cachehash without changing its location in LL void *cachehash_has(cachehash *ch, const void *key, size_t keylen); // return item from cachehash and move to front void *cachehash_get(cachehash *ch, const void *key, size_t keylen); // add item to the cachehash void cachehash_put(cachehash *ch, const void *key, size_t keylen, void *value); // free memory used by a cachehash. unusable until new initialization void cachehash_free(cachehash *ch, cachehash_process_cb *cb); // evict the LRU if the cachehash is full void *cachehash_evict_if_full(cachehash *ch); // iterate over all values in the cache hash in MRU -> LRU order void cachehash_iter(cachehash *ch, cachehash_process_cb *cb); // print out hash cache to stdout assuming that all keys and values // are null-terminated ASCII strings void cachehash_debug_dump(cachehash *ch); // change the callback function for the cachehash void cachehash_set_evict_cb(cachehash *ch, cachehash_process_cb *cb); #ifdef __cplusplus } #endif #endif /* CACHEHASH_H */ zmap-4.3.4/lib/constraint.c000066400000000000000000000274361501046211500155760ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include "../lib/constraint.h" #include "../lib/logger.h" #include "../lib/xalloc.h" // // Efficient address-space constraints (AH 7/2013) // // This module uses a tree-based representation to efficiently // manipulate and query constraints on the address space to be // scanned. It provides a value for every IP address, and these // values are applied by setting them for network prefixes. Order // matters: setting a value replaces any existing value for that // prefix or subsets of it. We use this to implement network // allowlisting and blocklisting. // // Think of setting values in this structure like painting // subnets with different colors. We can paint subnets black to // exclude them and white to allow them. Only the top color shows. // This makes for potentially very powerful constraint specifications. // // Internally, this is implemented using a binary tree, where each // node corresponds to a network prefix. (E.g., the root is // 0.0.0.0/0, and its children, if present, are 0.0.0.0/1 and // 128.0.0.0/1.) Each leaf of the tree stores the value that applies // to every address within the leaf's portion of the prefix space. // // As an optimization, after all values are set, we look up the // value or subtree for every /16 prefix and cache them as an array. // This lets subsequent lookups bypass the bottom half of the tree. // /* * Constraint Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ typedef struct node { struct node *l; struct node *r; value_t value; uint64_t count; } node_t; // As an optimization, we precompute lookups for every prefix of this // length: #define RADIX_LENGTH 18 struct _constraint { node_t *root; // root node of the tree uint32_t *radix; // array of prefixes (/RADIX_LENGTH) that are painted // paint_value size_t radix_len; // number of prefixes in radix array int painted; // have we precomputed counts for each node? value_t paint_value; // value for which we precomputed counts }; // Tree operations respect the invariant that every node that isn't a // leaf has exactly two children. #define IS_LEAF(node) ((node)->l == NULL) // Allocate a new leaf with the given value static node_t *_create_leaf(value_t value) { node_t *node = xmalloc(sizeof(node_t)); node->l = NULL; node->r = NULL; node->value = value; return node; } // Free the subtree rooted at node. static void _destroy_subtree(node_t *node) { if (node == NULL) return; _destroy_subtree(node->l); _destroy_subtree(node->r); free(node); } // Convert from an internal node to a leaf. static void _convert_to_leaf(node_t *node) { assert(node); assert(!IS_LEAF(node)); _destroy_subtree(node->l); _destroy_subtree(node->r); node->l = NULL; node->r = NULL; } // Recursive function to set value for a given network prefix within // the tree. (Note: prefix must be in host byte order.) static void _set_recurse(node_t *node, uint32_t prefix, int len, value_t value) { assert(node); assert(0 <= len && len <= 256); if (len == 0) { // We're at the end of the prefix; make this a leaf and set the // value. if (!IS_LEAF(node)) { _convert_to_leaf(node); } node->value = value; return; } if (IS_LEAF(node)) { // We're not at the end of the prefix, but we hit a leaf. if (node->value == value) { // A larger prefix has the same value, so we're done. return; } // The larger prefix has a different value, so we need to // convert it into an internal node and continue processing on // one of the leaves. node->l = _create_leaf(node->value); node->r = _create_leaf(node->value); } // We're not at the end of the prefix, and we're at an internal // node. Recurse on the left or right subtree. if (prefix & 0x80000000) { _set_recurse(node->r, prefix << 1, len - 1, value); } else { _set_recurse(node->l, prefix << 1, len - 1, value); } // At this point, we're an internal node, and the value is set // by one of our children or its descendent. If both children are // leaves with the same value, we can discard them and become a left. if (IS_LEAF(node->r) && IS_LEAF(node->l) && node->r->value == node->l->value) { node->value = node->l->value; _convert_to_leaf(node); } } // Set the value for a given network prefix, overwriting any existing // values on that prefix or subsets of it. // (Note: prefix must be in host byte order.) void constraint_set(constraint_t *con, uint32_t prefix, int len, value_t value) { assert(con); _set_recurse(con->root, prefix, len, value); con->painted = 0; } // Return the value pertaining to an address, according to the tree // starting at given root. (Note: address must be in host byte order.) static int _lookup_ip(node_t *root, uint32_t address) { assert(root); node_t *node = root; uint32_t mask = 0x80000000; for (;;) { if (IS_LEAF(node)) { return node->value; } if (address & mask) { node = node->r; } else { node = node->l; } mask >>= 1; } } // Return the value pertaining to an address. // (Note: address must be in host byte order.) value_t constraint_lookup_ip(constraint_t *con, uint32_t address) { assert(con); return _lookup_ip(con->root, address); } // Return the nth painted IP address. static int _lookup_index(node_t *root, uint64_t n) { assert(root); node_t *node = root; uint32_t ip = 0; uint32_t mask = 0x80000000; for (;;) { if (IS_LEAF(node)) { return ip | n; } if (n < node->l->count) { node = node->l; } else { n -= node->l->count; node = node->r; ip |= mask; } mask >>= 1; } } // For a given value, return the IP address with zero-based index n. // (i.e., if there are three addresses with value 0xFF, looking up index 1 // will return the second one). // Note that the tree must have been previously painted with this value. uint32_t constraint_lookup_index(constraint_t *con, uint64_t index, value_t value) { assert(con); if (!con->painted || con->paint_value != value) { constraint_paint_value(con, value); } uint64_t radix_idx = index / (1 << (32 - RADIX_LENGTH)); if (radix_idx < con->radix_len) { // Radix lookup uint32_t radix_offset = index % (1 << (32 - RADIX_LENGTH)); // TODO: bitwise maths return con->radix[radix_idx] | radix_offset; } // Otherwise, do the "slow" lookup in tree. // Note that tree counts do NOT include things in the radix, // so we subtract these off here. index -= con->radix_len * (1 << (32 - RADIX_LENGTH)); assert(index < con->root->count); return _lookup_index(con->root, index); } // Implement count_ips by recursing on halves of the tree. Size represents // the number of addresses in a prefix at the current level of the tree. // If paint is specified, each node will have its count set to the number of // leaves under it set to value. // If exclude_radix is specified, the number of addresses will exclude prefixes // that are a /RADIX_LENGTH or larger static uint64_t _count_ips_recurse(node_t *node, value_t value, uint64_t size, int paint, int exclude_radix) { assert(node); uint64_t n; if (IS_LEAF(node)) { if (node->value == value) { n = size; // Exclude prefixes already included in the radix if (exclude_radix && size >= (1 << (32 - RADIX_LENGTH))) { n = 0; } } else { n = 0; } } else { n = _count_ips_recurse(node->l, value, size >> 1, paint, exclude_radix) + _count_ips_recurse(node->r, value, size >> 1, paint, exclude_radix); } if (paint) { node->count = n; } return n; } // Return a node that determines the values for the addresses with // the given prefix. This is either the internal node that // corresponds to the end of the prefix or a leaf node that // encompasses the prefix. (Note: prefix must be in host byte order.) static node_t *_lookup_node(node_t *root, uint32_t prefix, int len) { assert(root); assert(0 <= len && len <= 32); node_t *node = root; uint32_t mask = 0x80000000; int i; for (i = 0; i < len; i++) { if (IS_LEAF(node)) { return node; } if (prefix & mask) { node = node->r; } else { node = node->l; } mask >>= 1; } return node; } // For each node, precompute the count of leaves beneath it set to value. // Note that the tree can be painted for only one value at a time. void constraint_paint_value(constraint_t *con, value_t value) { assert(con); log_debug("constraint", "Painting value %lu", value); // Paint everything except what we will put in radix _count_ips_recurse(con->root, value, (uint64_t)1 << 32, 1, 1); // Fill in the radix array with a list of addresses uint32_t i; con->radix_len = 0; for (i = 0; i < (1 << RADIX_LENGTH); i++) { uint32_t prefix = i << (32 - RADIX_LENGTH); node_t *node = _lookup_node(con->root, prefix, RADIX_LENGTH); if (IS_LEAF(node) && node->value == value) { // Add this prefix to the radix con->radix[con->radix_len++] = prefix; } } log_debug("constraint", "%lu IPs in radix array, %lu IPs in tree", con->radix_len * (1 << (32 - RADIX_LENGTH)), con->root->count); con->painted = 1; con->paint_value = value; } // Return the number of addresses that have a given value. uint64_t constraint_count_ips(constraint_t *con, value_t value) { assert(con); if (con->painted && con->paint_value == value) { return con->root->count + con->radix_len * (1 << (32 - RADIX_LENGTH)); } else { return _count_ips_recurse(con->root, value, (uint64_t)1 << 32, 0, 0); } } // Initialize the tree. // All addresses will initially have the given value. constraint_t *constraint_init(value_t value) { constraint_t *con = xmalloc(sizeof(constraint_t)); con->root = _create_leaf(value); con->radix = xcalloc(sizeof(uint32_t), 1 << RADIX_LENGTH); con->painted = 0; return con; } // Deinitialize and free the tree. void constraint_free(constraint_t *con) { assert(con); log_debug("constraint", "Cleaning up"); _destroy_subtree(con->root); free(con->radix); free(con); } /* int main(void) { log_init(stderr, LOG_DEBUG); constraint_t *con = constraint_init(0); constraint_set(con, ntohl(inet_addr("128.128.0.0")), 1, 22); constraint_set(con, ntohl(inet_addr("128.128.0.0")), 1, 1); constraint_set(con, ntohl(inet_addr("128.0.0.0")), 1, 1); constraint_set(con, ntohl(inet_addr("10.0.0.0")), 24, 1); constraint_set(con, ntohl(inet_addr("10.0.0.0")), 24, 0); constraint_set(con, ntohl(inet_addr("10.11.12.0")), 24, 1); constraint_set(con, ntohl(inet_addr("141.212.0.0")), 16, 0); for (int x=1; x < 2; x++) { if (x == 1) { constraint_optimize(con); } printf("count(0)=%ld\n", constraint_count_ips(con, 0)); printf("count(1)=%ld\n", constraint_count_ips(con, 1)); printf("%d\n", constraint_lookup_ip(con,ntohl(inet_addr("10.11.12.0")))); assert(constraint_count_ips(con, 0) + constraint_count_ips(con, 1) == (uint64_t)1 << 32); uint32_t i=0, count=0; do { if (constraint_lookup_ip(con, i)) count++; } while (++i != 0); printf("derived count(1)=%u\n", count); } constraint_free(con); } */ zmap-4.3.4/lib/constraint.h000066400000000000000000000023171501046211500155720ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef CONSTRAINT_H #define CONSTRAINT_H #include typedef struct _constraint constraint_t; typedef uint32_t value_t; constraint_t *constraint_init(value_t value); void constraint_free(constraint_t *con); void constraint_set(constraint_t *con, uint32_t prefix, int len, value_t value); value_t constraint_lookup_ip(constraint_t *con, uint32_t address); uint64_t constraint_count_ips(constraint_t *con, value_t value); uint32_t constraint_lookup_index(constraint_t *con, uint64_t index, value_t value); void constraint_paint_value(constraint_t *con, value_t value); #endif //_CONSTRAINT_H zmap-4.3.4/lib/csv.c000066400000000000000000000025571501046211500142020ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "csv.h" int csv_find_index(char *header, const char **names, size_t names_len) { char *split = header; for (int idx = 0; split != NULL; ++idx) { char *front = (idx == 0) ? split : split + 1; for (size_t i = 0; i < names_len; ++i) { if (strncmp(front, names[i], strlen(names[i])) == 0) { return idx; } } split = strchr(front, ','); } return -1; } char *csv_get_index(char *row, size_t idx) { char *split = row; for (size_t i = 0; i < idx; ++i) { split = strchr(split + 1, ','); if (split == NULL) { return NULL; } } char *entry; char *start = (idx == 0) ? split : split + 1; char *end = strchr(start, ','); if (end != NULL) { entry = strndup(start, end - start); } else { entry = strdup(start); } return entry; } zmap-4.3.4/lib/csv.h000066400000000000000000000014471501046211500142040ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ZMAP_CSV_H #define ZMAP_CSV_H #include int csv_find_index(char *header, const char **names, size_t names_len); char *csv_get_index(char *row, size_t idx); #endif zmap-4.3.4/lib/includes.h000066400000000000000000000023551501046211500152160ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __FAVOR_BSD #define __FAVOR_BSD 2 #endif #ifndef __USE_BSD #define __USE_BSD #endif #include #include #include #include #include #include #include #if defined(__NetBSD__) #define ICMP_UNREACH_PRECEDENCE_CUTOFF ICMP_UNREACH_PREC_CUTOFF #include #else #include #endif #include #include #include // NOTE: net/if.h MUST be included BEFORE ifaddrs.h #include #define MAC_ADDR_LEN ETHER_ADDR_LEN #define UNUSED __attribute__((unused)) zmap-4.3.4/lib/lockfd.c000066400000000000000000000026171501046211500146460ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include "xalloc.h" static pthread_mutex_t **mutexes = NULL; static pthread_mutex_t *get_mutex(int fd) { assert(fd < 3 && "todo: implement generically"); if (!mutexes) { mutexes = xmalloc(3 * sizeof(char *)); assert(mutexes); } if (!mutexes[fd]) { mutexes[fd] = xmalloc(sizeof(pthread_mutex_t)); assert(mutexes[fd]); pthread_mutex_init(mutexes[fd], NULL); assert(mutexes[fd]); } return mutexes[fd]; } int lock_fd(int fd) { return pthread_mutex_lock(get_mutex(fd)); } int unlock_fd(int fd) { return pthread_mutex_unlock(get_mutex(fd)); } int lock_file(FILE *f) { assert(f); return lock_fd(fileno(f)); } int unlock_file(FILE *f) { assert(f); return unlock_fd(fileno(f)); } zmap-4.3.4/lib/lockfd.h000066400000000000000000000013411501046211500146440ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include int lock_fd(int fd); int unlock_fd(int fd); int lock_file(FILE *f); int unlock_file(FILE *f); zmap-4.3.4/lib/logger.c000066400000000000000000000136511501046211500146630ustar00rootroot00000000000000/* * Logger Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include #include #include #include #include #include "logger.h" #include "xalloc.h" #include "lockfd.h" static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static enum LogLevel log_output_level = ZLOG_INFO; static FILE *log_output_stream = NULL; static int color = 0; static int log_to_syslog = 0; static const char *log_level_name[] = {"FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"}; #define RED "\x1b[31m" #define GREEN "\x1b[32m" #define YELLOW "\x1b[33m" #define BLUE "\x1b[34m" #define MAGENTA "\x1b[35m" #define CYAN "\x1b[36m" #define RESET "\033[0m" #define COLOR(x) \ do { \ if (color) \ fprintf(log_output_stream, "%s", x); \ } while (0) static const char *color_for_level(enum LogLevel level) { switch (level) { case ZLOG_FATAL: return RED; case ZLOG_ERROR: return MAGENTA; case ZLOG_WARN: return YELLOW; case ZLOG_INFO: return GREEN; case ZLOG_DEBUG: return BLUE; case ZLOG_TRACE: return RESET; default: return RESET; } } static int LogLogVA(enum LogLevel level, const char *loggerName, const char *logMessage, va_list args) { if (level <= log_output_level) { if (!log_output_stream) { log_output_stream = stderr; } // if logging to a shared output channel, then use a global // lock across ZMap. Otherwise, if we're logging to a file, // only lockin with the module, in order to avoid having // corrupt log entries. if (log_output_stream == stdout || log_output_stream == stderr) { lock_file(log_output_stream); } else { pthread_mutex_lock(&mutex); } if (color) { COLOR(color_for_level(level)); } const char *levelName = log_level_name[level]; struct timeval now; char timestamp[256]; gettimeofday(&now, NULL); time_t sec = now.tv_sec; struct tm *ptm = localtime(&sec); strftime(timestamp, 20, "%b %d %H:%M:%S", ptm); fprintf(log_output_stream, "%s.%03ld [%s] ", timestamp, (long)now.tv_usec / 1000, levelName); if (loggerName) { fprintf(log_output_stream, "%s: ", loggerName); } if (logMessage) { vfprintf(log_output_stream, logMessage, args); } if (loggerName || logMessage) { fputs("\n", log_output_stream); } if (color) { COLOR(RESET); } fflush(log_output_stream); if (log_output_stream == stdout || log_output_stream == stderr) { unlock_file(log_output_stream); } else { pthread_mutex_unlock(&mutex); } } return EXIT_SUCCESS; } int log_fatal(const char *name, const char *message, ...) { va_list va; va_start(va, message); LogLogVA(ZLOG_FATAL, name, message, va); va_end(va); if (log_to_syslog) { va_start(va, message); vsyslog(LOG_MAKEPRI(LOG_USER, LOG_CRIT), message, va); va_end(va); } exit(EXIT_FAILURE); } int log_error(const char *name, const char *message, ...) { va_list va; va_start(va, message); int ret = LogLogVA(ZLOG_ERROR, name, message, va); va_end(va); if (log_to_syslog) { va_start(va, message); vsyslog(LOG_MAKEPRI(LOG_USER, LOG_ERR), message, va); va_end(va); } return ret; } int log_warn(const char *name, const char *message, ...) { va_list va; va_start(va, message); int ret = LogLogVA(ZLOG_WARN, name, message, va); va_end(va); if (log_to_syslog) { va_start(va, message); vsyslog(LOG_MAKEPRI(LOG_USER, LOG_WARNING), message, va); va_end(va); } return ret; } int log_info(const char *name, const char *message, ...) { va_list va; va_start(va, message); int ret = LogLogVA(ZLOG_INFO, name, message, va); va_end(va); char *prefixed = xmalloc(strlen(name) + strlen(message) + 3); strcpy(prefixed, name); strcat(prefixed, ": "); strcat(prefixed, message); if (log_to_syslog) { va_start(va, message); vsyslog(LOG_MAKEPRI(LOG_USER, LOG_INFO), prefixed, va); va_end(va); } free(prefixed); return ret; } int log_debug(const char *name, const char *message, ...) { va_list va; va_start(va, message); int ret = LogLogVA(ZLOG_DEBUG, name, message, va); va_end(va); char *prefixed = xmalloc(strlen(name) + strlen(message) + 3); strcpy(prefixed, name); strcat(prefixed, ": "); strcat(prefixed, message); if (log_to_syslog) { va_start(va, message); vsyslog(LOG_MAKEPRI(LOG_USER, LOG_DEBUG), prefixed, va); va_end(va); } free(prefixed); return ret; } #ifdef DEBUG extern int log_trace(const char *name, const char *message, ...) { va_list va; va_start(va, message); int ret = LogLogVA(ZLOG_TRACE, name, message, va); va_end(va); char *prefixed = xmalloc(strlen(name) + strlen(message) + 3); strcpy(prefixed, name); strcat(prefixed, ": "); strcat(prefixed, message); if (log_to_syslog) { va_start(va, message); vsyslog(LOG_MAKEPRI(LOG_USER, LOG_DEBUG), prefixed, va); va_end(va); } free(prefixed); return ret; } #endif int log_init(FILE *stream, enum LogLevel level, int syslog_enabled, const char *appname) { log_output_stream = stream; log_output_level = level; if (syslog_enabled) { log_to_syslog = 1; openlog(appname, 0, LOG_USER); // no options } if (isatty(fileno(log_output_stream))) { color = 1; } return 0; } void check_and_log_file_error(FILE *file, const char *name) { if (ferror(file)) { log_fatal(name, "unable to write to file"); } } size_t dstrftime(char *buf, size_t maxsize, const char *format, double tm) { struct timeval tv; double tm_floor; tm_floor = floor(tm); tv.tv_sec = (long)tm_floor; tv.tv_usec = (long)(tm - floor(tm)) * 1000000; return strftime(buf, maxsize, format, localtime((const time_t *)&tv)); } zmap-4.3.4/lib/logger.h000066400000000000000000000032241501046211500146630ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #ifndef LOGGER_H #define LOGGER_H #ifdef __cplusplus extern "C" { #endif // do not collide with constants defined in syslog.h enum LogLevel { ZLOG_FATAL, ZLOG_ERROR, ZLOG_WARN, ZLOG_INFO, ZLOG_DEBUG, ZLOG_TRACE, ZNUM_LOGLEVELS }; int log_fatal(const char *loggerName, const char *logMessage, ...) __attribute__((noreturn)); int log_error(const char *loggerName, const char *logMessage, ...); int log_warn(const char *loggerName, const char *logMessage, ...); int log_info(const char *loggerName, const char *logMessage, ...); int log_debug(const char *loggerName, const char *logMessage, ...); #ifdef DEBUG int log_trace(const char *loggerName, const char *logMessage, ...); #else #define log_trace(...) ; #endif int log_init(FILE *stream, enum LogLevel level, int syslog_enabled, const char *syslog_app); void check_and_log_file_error(FILE *file, const char *name); size_t dstrftime(char *, size_t, const char *, double); #ifdef __cplusplus } #endif #endif // _LOGGER_H zmap-4.3.4/lib/pbm.c000066400000000000000000000050221501046211500141530ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include "logger.h" #include "xalloc.h" #define NUM_VALUES 0xFFFFFFFF #define PAGE_SIZE_IN_BITS 0x10000 #define PAGE_SIZE_IN_BYTES (PAGE_SIZE_IN_BITS / 8) #define NUM_PAGES 0x10000 #define PAGE_MASK 0xFFFF uint8_t **pbm_init(void) { uint8_t **retv = xcalloc(NUM_PAGES, sizeof(void *)); return retv; } uint8_t *bm_init(void) { uint8_t *bm = xmalloc(PAGE_SIZE_IN_BYTES); memset(bm, 0, PAGE_SIZE_IN_BYTES); return bm; } int bm_check(uint8_t *bm, uint16_t v) { uint16_t page_idx = (v >> 3); uint8_t bit_idx = (uint8_t)(v & 0x07); return bm[page_idx] & (1 << bit_idx); } void bm_set(uint8_t *bm, uint16_t v) { uint16_t page_idx = (v >> 3); uint8_t bit_idx = (uint8_t)(v & 0x07); bm[page_idx] |= (1 << bit_idx); } int pbm_check(uint8_t **b, uint32_t v) { uint32_t top = v >> 16; uint32_t bottom = v & PAGE_MASK; return b[top] && bm_check(b[top], bottom); } void pbm_set(uint8_t **b, uint32_t v) { uint16_t top = (uint16_t)(v >> 16); uint16_t bottom = (uint16_t)(v & PAGE_MASK); if (!b[top]) { b[top] = bm_init(); } bm_set(b[top], bottom); } uint32_t pbm_load_from_file(uint8_t **b, char *file) { if (!b) { log_fatal("pbm", "load_from_file called with NULL PBM"); } if (!file) { log_fatal("pbm", "load_from_file called with NULL filename"); } FILE *fp = fopen(file, "r"); if (fp == NULL) { log_fatal("pbm", "unable to open file: %s: %s", file, strerror(errno)); } char line[1000]; uint32_t count = 0; while (fgets(line, sizeof(line), fp)) { char *comment = strchr(line, '#'); if (comment) { *comment = '\0'; } struct in_addr addr; if (inet_aton(line, &addr) != 1) { log_fatal("pbm", "unable to parse IP address: %s", line); } pbm_set(b, addr.s_addr); ++count; } fclose(fp); return count; } zmap-4.3.4/lib/pbm.h000066400000000000000000000017111501046211500141610ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ZMAP_PBM_H #define ZMAP_PBM_H #include uint8_t *bm_init(void); int bm_check(uint8_t *bm, uint16_t v); void bm_set(uint8_t *bm, uint16_t v); uint8_t **pbm_init(void); int pbm_check(uint8_t **b, uint32_t v); void pbm_set(uint8_t **b, uint32_t v); uint32_t pbm_load_from_file(uint8_t **b, char *file); #endif /* ZMAP_PBM_H */ zmap-4.3.4/lib/queue.c000066400000000000000000000045541501046211500145320ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "queue.h" #include "xalloc.h" #include zqueue_t *queue_init(void) { zqueue_t *p = xmalloc(sizeof(zqueue_t)); p->front = NULL; p->back = NULL; p->size = 0; pthread_mutex_init(&p->lock, NULL); pthread_cond_init(&p->empty, NULL); return p; } int is_empty(zqueue_t *queue) { return queue->size == 0; } void push_back(void *data, zqueue_t *queue) { znode_t *new_node = xmalloc(sizeof(znode_t)); new_node->prev = NULL; new_node->next = NULL; new_node->data = data; pthread_mutex_lock(&queue->lock); if (is_empty(queue)) { queue->front = new_node; queue->back = new_node; } else { queue->back->next = new_node; new_node->prev = queue->back; queue->back = new_node; } queue->size++; pthread_cond_signal(&queue->empty); pthread_mutex_unlock(&queue->lock); } znode_t *pop_front(zqueue_t *queue) { pthread_mutex_lock(&queue->lock); while (is_empty(queue)) { pthread_cond_wait(&queue->empty, &queue->lock); } znode_t *temp = pop_front_unsafe(queue); pthread_mutex_unlock(&queue->lock); return temp; } znode_t *pop_front_unsafe(zqueue_t *queue) { znode_t *temp = queue->front; queue->front = temp->next; if (queue->front != NULL) { queue->front->prev = NULL; } queue->size--; return temp; } znode_t *get_front(zqueue_t *queue) { pthread_mutex_lock(&queue->lock); while (is_empty(queue)) { pthread_cond_wait(&queue->empty, &queue->lock); } znode_t *temp = queue->front; pthread_mutex_unlock(&queue->lock); return temp; } znode_t *get_back(zqueue_t *queue) { pthread_mutex_lock(&queue->lock); while (is_empty(queue)) { pthread_cond_wait(&queue->empty, &queue->lock); } znode_t *temp = queue->back; pthread_mutex_unlock(&queue->lock); return temp; } size_t get_size(zqueue_t *queue) { return queue->size; } zmap-4.3.4/lib/queue.h000066400000000000000000000025061501046211500145320ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ZMAP_QUEUE_H #define ZMAP_QUEUE_H #include #include #include #include typedef struct zqueue_node { void *data; struct zqueue_node *prev; struct zqueue_node *next; } znode_t; typedef struct zqueue { struct zqueue_node *front; struct zqueue_node *back; size_t size; // Threading utilities pthread_mutex_t lock; pthread_cond_t empty; } zqueue_t; zqueue_t *queue_init(void); int is_empty(zqueue_t *queue); void push_back(void *data, zqueue_t *queue); znode_t *pop_front(zqueue_t *queue); znode_t *pop_front_unsafe(zqueue_t *queue); znode_t *get_front(zqueue_t *queue); znode_t *get_back(zqueue_t *queue); size_t get_size(zqueue_t *queue); #endif /* ZMAP_QUEUE_H */ zmap-4.3.4/lib/random.c000066400000000000000000000013161501046211500146570ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "random.h" #include #include #include #include #include #include "logger.h" #define RANDSRC "/dev/urandom" int random_bytes(void *dst, size_t n) { FILE *f = fopen(RANDSRC, "rb"); if (!f) { log_fatal("random", "unable to read /dev/urandom: %s", strerror(errno)); } size_t r = fread(dst, n, 1, f); fclose(f); if (r < 1) { return 0; } return 1; } zmap-4.3.4/lib/random.h000066400000000000000000000013521501046211500146640ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #ifndef RANDOM_H #define RANDOM_H int random_bytes(void *dst, size_t n); #endif zmap-4.3.4/lib/rijndael-alg-fst.c000066400000000000000000001676711501046211500165430ustar00rootroot00000000000000/** * rijndael-alg-fst.c * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rijndael-alg-fst.h" /* Te0[x] = S [x].[02, 01, 01, 03]; Te1[x] = S [x].[03, 02, 01, 01]; Te2[x] = S [x].[01, 03, 02, 01]; Te3[x] = S [x].[01, 01, 03, 02]; Te4[x] = S [x].[01, 01, 01, 01]; Td0[x] = Si[x].[0e, 09, 0d, 0b]; Td1[x] = Si[x].[0b, 0e, 09, 0d]; Td2[x] = Si[x].[0d, 0b, 0e, 09]; Td3[x] = Si[x].[09, 0d, 0b, 0e]; Td4[x] = Si[x].[01, 01, 01, 01]; */ // clang-format off static const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; static const u32 Te1[256] = { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }; static const u32 Te2[256] = { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }; static const u32 Te3[256] = { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }; static const u32 Te4[256] = { 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, }; static const u32 Td0[256] = { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }; static const u32 Td1[256] = { 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, }; static const u32 Td2[256] = { 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, }; static const u32 Td3[256] = { 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }; static const u32 Td4[256] = { 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, }; // clang-format on static const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) #ifdef _MSC_VER #define GETU32(p) SWAP(*((u32 *)(p))) #define PUTU32(ct, st) \ { \ *((u32 *)(ct)) = SWAP((st)); \ } #else #define GETU32(pt) \ (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ \ ((u32)(pt)[3])) #define PUTU32(ct, st) \ { \ (ct)[0] = (u8)((st) >> 24); \ (ct)[1] = (u8)((st) >> 16); \ (ct)[2] = (u8)((st) >> 8); \ (ct)[3] = (u8)(st); \ } #endif /** * Expand the cipher key into the encryption key schedule. * * @return the number of rounds for the given cipher key size. */ int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int i = 0; u32 temp; rk[0] = GETU32(cipherKey); rk[1] = GETU32(cipherKey + 4); rk[2] = GETU32(cipherKey + 8); rk[3] = GETU32(cipherKey + 12); if (keyBits == 128) { for (;;) { temp = rk[3]; rk[4] = rk[0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24)] & 0x000000ff) ^ rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; if (++i == 10) { return 10; } rk += 4; } } rk[4] = GETU32(cipherKey + 16); rk[5] = GETU32(cipherKey + 20); if (keyBits == 192) { for (;;) { temp = rk[5]; rk[6] = rk[0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24)] & 0x000000ff) ^ rcon[i]; rk[7] = rk[1] ^ rk[6]; rk[8] = rk[2] ^ rk[7]; rk[9] = rk[3] ^ rk[8]; if (++i == 8) { return 12; } rk[10] = rk[4] ^ rk[9]; rk[11] = rk[5] ^ rk[10]; rk += 6; } } rk[6] = GETU32(cipherKey + 24); rk[7] = GETU32(cipherKey + 28); if (keyBits == 256) { for (;;) { temp = rk[7]; rk[8] = rk[0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24)] & 0x000000ff) ^ rcon[i]; rk[9] = rk[1] ^ rk[8]; rk[10] = rk[2] ^ rk[9]; rk[11] = rk[3] ^ rk[10]; if (++i == 7) { return 14; } temp = rk[11]; rk[12] = rk[4] ^ (Te4[(temp >> 24)] & 0xff000000) ^ (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(temp) & 0xff] & 0x000000ff); rk[13] = rk[5] ^ rk[12]; rk[14] = rk[6] ^ rk[13]; rk[15] = rk[7] ^ rk[14]; rk += 8; } } return 0; } /** * Expand the cipher key into the decryption key schedule. * * @return the number of rounds for the given cipher key size. */ int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int Nr, i, j; u32 temp; /* expand the cipher key: */ Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); /* invert the order of the round keys: */ for (i = 0, j = 4 * Nr; i < j; i += 4, j -= 4) { temp = rk[i]; rk[i] = rk[j]; rk[j] = temp; temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; } /* apply the inverse MixColumn transform to all round keys but the first * and the last: */ for (i = 1; i < Nr; i++) { rk += 4; rk[0] = Td0[Te4[(rk[0] >> 24)] & 0xff] ^ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[0]) & 0xff] & 0xff]; rk[1] = Td0[Te4[(rk[1] >> 24)] & 0xff] ^ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[1]) & 0xff] & 0xff]; rk[2] = Td0[Te4[(rk[2] >> 24)] & 0xff] ^ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[2]) & 0xff] & 0xff]; rk[3] = Td0[Te4[(rk[3] >> 24)] & 0xff] ^ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[3]) & 0xff] & 0xff]; } return Nr; } void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(pt) ^ rk[0]; s1 = GETU32(pt + 4) ^ rk[1]; s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[4]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[5]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[6]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[7]; /* round 2: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[8]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[9]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; /* round 3: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; /* round 4: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; /* round 5: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; /* round 6: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; /* round 7: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; /* round 8: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; /* round 9: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; /* round 11: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; /* round 13: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Te0[(s0 >> 24)] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3) & 0xff] ^ rk[4]; t1 = Te0[(s1 >> 24)] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0) & 0xff] ^ rk[5]; t2 = Te0[(s2 >> 24)] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1) & 0xff] ^ rk[6]; t3 = Te0[(s3 >> 24)] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te0[(t0 >> 24)] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[(t3) & 0xff] ^ rk[0]; s1 = Te0[(t1 >> 24)] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[(t0) & 0xff] ^ rk[1]; s2 = Te0[(t2 >> 24)] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[(t1) & 0xff] ^ rk[2]; s3 = Te0[(t3 >> 24)] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[(t2) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Te4[(t0 >> 24)] & 0xff000000) ^ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t3) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(ct, s0); s1 = (Te4[(t1 >> 24)] & 0xff000000) ^ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t0) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(ct + 4, s1); s2 = (Te4[(t2 >> 24)] & 0xff000000) ^ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t1) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(ct + 8, s2); s3 = (Te4[(t3 >> 24)] & 0xff000000) ^ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t2) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(ct + 12, s3); } void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(ct) ^ rk[0]; s1 = GETU32(ct + 4) ^ rk[1]; s2 = GETU32(ct + 8) ^ rk[2]; s3 = GETU32(ct + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[4]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[5]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[6]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[7]; /* round 2: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[8]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[9]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; /* round 3: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; /* round 4: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; /* round 5: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; /* round 6: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; /* round 7: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; /* round 8: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; /* round 9: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; /* round 11: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; /* round 13: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Td0[(s0 >> 24)] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[(s1) & 0xff] ^ rk[4]; t1 = Td0[(s1 >> 24)] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[(s2) & 0xff] ^ rk[5]; t2 = Td0[(s2 >> 24)] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[(s3) & 0xff] ^ rk[6]; t3 = Td0[(s3 >> 24)] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[(s0) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Td0[(t0 >> 24)] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[(t1) & 0xff] ^ rk[0]; s1 = Td0[(t1 >> 24)] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[(t2) & 0xff] ^ rk[1]; s2 = Td0[(t2 >> 24)] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[(t3) & 0xff] ^ rk[2]; s3 = Td0[(t3 >> 24)] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[(t0) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Td4[(t0 >> 24)] & 0xff000000) ^ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t1) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(pt, s0); s1 = (Td4[(t1 >> 24)] & 0xff000000) ^ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t2) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(pt + 4, s1); s2 = (Td4[(t2 >> 24)] & 0xff000000) ^ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t3) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(pt + 8, s2); s3 = (Td4[(t3 >> 24)] & 0xff000000) ^ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t0) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(pt + 12, s3); } #ifdef INTERMEDIATE_VALUE_KAT void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) { int r; u32 s0, s1, s2, s3, t0, t1, t2, t3; /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(block) ^ rk[0]; s1 = GETU32(block + 4) ^ rk[1]; s2 = GETU32(block + 8) ^ rk[2]; s3 = GETU32(block + 12) ^ rk[3]; rk += 4; /* * Nr - 1 full rounds: */ for (r = (rounds < Nr ? rounds : Nr - 1); r > 0; r--) { t0 = Te0[(s0 >> 24)] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3) & 0xff] ^ rk[0]; t1 = Te0[(s1 >> 24)] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0) & 0xff] ^ rk[1]; t2 = Te0[(s2 >> 24)] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1) & 0xff] ^ rk[2]; t3 = Te0[(s3 >> 24)] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2) & 0xff] ^ rk[3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; rk += 4; } /* * apply last round and * map cipher state to byte array block: */ if (rounds == Nr) { t0 = (Te4[(s0 >> 24)] & 0xff000000) ^ (Te4[(s1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(s2 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(s3) & 0xff] & 0x000000ff) ^ rk[0]; t1 = (Te4[(s1 >> 24)] & 0xff000000) ^ (Te4[(s2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(s3 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(s0) & 0xff] & 0x000000ff) ^ rk[1]; t2 = (Te4[(s2 >> 24)] & 0xff000000) ^ (Te4[(s3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(s0 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(s1) & 0xff] & 0x000000ff) ^ rk[2]; t3 = (Te4[(s3 >> 24)] & 0xff000000) ^ (Te4[(s0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(s1 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(s2) & 0xff] & 0x000000ff) ^ rk[3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; } PUTU32(block, s0); PUTU32(block + 4, s1); PUTU32(block + 8, s2); PUTU32(block + 12, s3); } void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) { int r; u32 s0, s1, s2, s3, t0, t1, t2, t3; /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(block) ^ rk[0]; s1 = GETU32(block + 4) ^ rk[1]; s2 = GETU32(block + 8) ^ rk[2]; s3 = GETU32(block + 12) ^ rk[3]; rk += 4; /* * Nr - 1 full rounds: */ for (r = (rounds < Nr ? rounds : Nr) - 1; r > 0; r--) { t0 = Td0[(s0 >> 24)] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[(s1) & 0xff] ^ rk[0]; t1 = Td0[(s1 >> 24)] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[(s2) & 0xff] ^ rk[1]; t2 = Td0[(s2 >> 24)] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[(s3) & 0xff] ^ rk[2]; t3 = Td0[(s3 >> 24)] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[(s0) & 0xff] ^ rk[3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; rk += 4; } /* * complete the last round and * map cipher state to byte array block: */ t0 = (Td4[(s0 >> 24)] & 0xff000000) ^ (Td4[(s3 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(s2 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(s1) & 0xff] & 0x000000ff); t1 = (Td4[(s1 >> 24)] & 0xff000000) ^ (Td4[(s0 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(s3 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(s2) & 0xff] & 0x000000ff); t2 = (Td4[(s2 >> 24)] & 0xff000000) ^ (Td4[(s1 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(s0 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(s3) & 0xff] & 0x000000ff); t3 = (Td4[(s3 >> 24)] & 0xff000000) ^ (Td4[(s2 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(s1 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(s0) & 0xff] & 0x000000ff); if (rounds == Nr) { t0 ^= rk[0]; t1 ^= rk[1]; t2 ^= rk[2]; t3 ^= rk[3]; } PUTU32(block, t0); PUTU32(block + 4, t1); PUTU32(block + 8, t2); PUTU32(block + 12, t3); } #endif /* INTERMEDIATE_VALUE_KAT */ zmap-4.3.4/lib/rijndael-alg-fst.h000066400000000000000000000037051501046211500165330ustar00rootroot00000000000000/** * rijndael-alg-fst.h * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef RIJNDAEL_ALG_FST_H #define RIJNDAEL_ALG_FST_H #define MAXKC (256 / 32) #define MAXKB (256 / 8) #define MAXNR 14 typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]); void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]); #ifdef INTERMEDIATE_VALUE_KAT void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds); void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds); #endif /* INTERMEDIATE_VALUE_KAT */ #endif /* RIJNDAEL_ALG_FST_H */ zmap-4.3.4/lib/types.h000066400000000000000000000017261501046211500145550ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ZMAP_TYPES_H #define ZMAP_TYPES_H #include #include typedef uint32_t ipaddr_n_t; // IPv4 address network order typedef uint32_t ipaddr_h_t; // IPv4 address host order typedef uint16_t port_n_t; // port network order typedef uint16_t port_h_t; // port host order typedef unsigned char macaddr_t; #endif /* ZMAP_TYPES_H */ zmap-4.3.4/lib/util.c000066400000000000000000000200111501046211500143450ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include "util.h" #include #include #include #include #include "includes.h" #include "xalloc.h" #include #include #include #include #include #include #include "../lib/logger.h" #define MAX_SPLITS 128 int max_int(int a, int b) { if (a >= b) { return a; } return b; } int min_int(int a, int b) { if (a >= b) { return b; } return a; } uint64_t min_uint64_t(uint64_t a, uint64_t b) { if (a >= b) { return b; } return a; } void enforce_range(const char *name, int v, int min, int max) { if (check_range(v, min, max) == EXIT_FAILURE) { log_fatal("zmap", "argument `%s' must be between %d and %d\n", name, min, max); } } void split_string(const char *in, int *len, const char ***results) { const char **fields = xcalloc(MAX_SPLITS, sizeof(const char *)); int retvlen = 0; const char *currloc = in; // parse csv into a set of strings while (1) { assert(retvlen < MAX_SPLITS); size_t len = strcspn(currloc, ", "); if (len == 0) { currloc++; } else { char *new = xmalloc(len + 1); strncpy(new, currloc, len); new[len] = '\0'; fields[retvlen++] = new; assert(fields[retvlen - 1]); } if (len == strlen(currloc)) { break; } currloc += len; } *results = fields; *len = retvlen; } void fprintw(FILE *f, const char *s, size_t w) { if (strlen(s) <= w) { fprintf(f, "%s", s); return; } // process each line individually in order to // respect existing line breaks in string. char *news = strdup(s); char *pch = strtok(news, "\n"); while (pch) { if (strlen(pch) <= w) { printf("%s\n", pch); pch = strtok(NULL, "\n"); continue; } char *t = pch; while (strlen(t)) { size_t numchars = 0; // number of chars to print char *tmp = t; while (1) { size_t new = strcspn(tmp, " ") + 1; if (new == strlen(tmp) || new > w) { // there are no spaces in the string, // so, just print the entire thing on // one line; numchars += new; break; } else if (numchars + new > w) { // if we added any more, we'd be over w // chars so time to print the line and // move on to the next. break; } else { tmp += (size_t) new; numchars += new; } } fprintf(f, "%.*s\n", (int)numchars, t); t += (size_t)numchars; if (t > pch + (size_t)strlen(pch)) { break; } } pch = strtok(NULL, "\n"); } free(news); } // parse a string representing a number/percentage of targets // A percentage is interpreted as percent of the search space, so 2^32 * port_count uint64_t parse_max_targets(char *max_targets, int port_count) { assert(port_count > 0); char *end; errno = 0; double v = strtod(max_targets, &end); if (end == max_targets || errno != 0) { log_fatal("argparse", "can't convert max-targets to a number"); } if (end[0] == '%' && end[1] == '\0') { // treat as percentage of the search space, so percent of 2^32 * num_ports uint64_t search_space = ((uint64_t)1 << 32) * port_count; v = v * search_space / 100.; } else if (end[0] != '\0') { log_fatal("eargparse", "extra characters after max-targets"); } if (v <= 0) { return 0; } else if (v >= (((uint64_t)1 << 32) * port_count)) { return (((uint64_t)1 << 32) * port_count); } else { return v; } } // pretty print elapsed (or estimated) number of seconds void time_string(uint32_t time, int est, char *buf, size_t len) { int y = time / 31556736; int d = (time % 31556736) / 86400; int h = (time % 86400) / 3600; int m = (time % 3600) / 60; int s = time % 60; if (est) { if (y > 0) { snprintf(buf, len, "%d years", y); } else if (d > 9) { snprintf(buf, len, "%dd", d); } else if (d > 0) { snprintf(buf, len, "%dd%02dh", d, h); } else if (h > 9) { snprintf(buf, len, "%dh", h); } else if (h > 0) { snprintf(buf, len, "%dh%02dm", h, m); } else if (m > 9) { snprintf(buf, len, "%dm", m); } else if (m > 0) { snprintf(buf, len, "%dm%02ds", m, s); } else { snprintf(buf, len, "%ds", s); } } else { if (d > 0) { snprintf(buf, len, "%dd%d:%02d:%02d", d, h, m, s); } else if (h > 0) { snprintf(buf, len, "%d:%02d:%02d", h, m, s); } else { snprintf(buf, len, "%d:%02d", m, s); } } } // pretty print quantities void number_string(uint32_t n, char *buf, size_t len) { int figs = 0; if (n < 1000) { snprintf(buf, len, "%u ", n); } else if (n < 1000000) { if (n < 10000) { figs = 2; } else if (n < 100000) { figs = 1; } snprintf(buf, len, "%0.*f K", figs, (float)n / 1000.); } else { if (figs < 10000000) { figs = 2; } else if (figs < 100000000) { figs = 1; } snprintf(buf, len, "%0.*f M", figs, (float)n / 1000000.); } } int parse_mac(macaddr_t *out, char *in) { if (strlen(in) < MAC_ADDR_LEN * 3 - 1) return 0; char octet[4]; octet[2] = '\0'; for (int i = 0; i < MAC_ADDR_LEN; i++) { if (i < MAC_ADDR_LEN - 1 && in[i * 3 + 2] != ':') { return 0; } strncpy(octet, &in[i * 3], 2); char *err = NULL; long b = strtol(octet, &err, 16); if (err && *err != '\0') { return 0; } out[i] = b & 0xFF; } return 1; } int check_range(int v, int min, int max) { if (v < min || v > max) { return EXIT_FAILURE; } return EXIT_SUCCESS; } int file_exists(char *name) { FILE *file = fopen(name, "r"); if (!file) return 0; fclose(file); return 1; } #if defined(__APPLE__) #include #endif int drop_privs(void) { struct passwd *pw; if (geteuid() != 0) { /* Not root */ return EXIT_SUCCESS; } if ((pw = getpwnam("nobody")) != NULL) { if (setuid(pw->pw_uid) == 0) { return EXIT_SUCCESS; // success } } return EXIT_FAILURE; } #if defined(__APPLE__) #include int set_cpu(uint32_t core) { mach_port_t tid = pthread_mach_thread_np(pthread_self()); struct thread_affinity_policy policy; policy.affinity_tag = core; kern_return_t ret = thread_policy_set(tid, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, THREAD_AFFINITY_POLICY_COUNT); if (ret != KERN_SUCCESS) { return EXIT_FAILURE; } return EXIT_SUCCESS; } #elif defined(__DragonFly__) #include int set_cpu(uint32_t core) { if (usched_set(getpid(), USCHED_SET_CPU, &core, sizeof(core)) != 0) { return EXIT_FAILURE; } return EXIT_SUCCESS; } #elif defined(__NetBSD__) int set_cpu(uint32_t core) { cpuset_t *cpuset = cpuset_create(); if (cpuset == NULL) { return EXIT_FAILURE; } cpuset_zero(cpuset); cpuset_set(core, cpuset); cpuset_destroy(cpuset); if (pthread_setaffinity_np(pthread_self(), cpuset_size(cpuset), cpuset) != 0) { return EXIT_FAILURE; } return EXIT_SUCCESS; } #else #if defined(__FreeBSD__) #include #include #include #define cpu_set_t cpuset_t #endif int set_cpu(uint32_t core) { cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(core, &cpuset); if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) != 0) { return EXIT_FAILURE; } return EXIT_SUCCESS; } #endif double now(void) { struct timeval now; gettimeofday(&now, NULL); return (double)now.tv_sec + (double)now.tv_usec / 1000000.; } double steady_now(void) { #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); return (double)tp.tv_sec + (double)tp.tv_nsec / 1000000000.; #else struct timeval now; gettimeofday(&now, NULL); return (double)now.tv_sec + (double)now.tv_usec / 1000000.; #endif } zmap-4.3.4/lib/util.h000066400000000000000000000046461501046211500143720ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ZMAP_UTIL_H #define ZMAP_UTIL_H #include #include #include #include "types.h" int max_int(int a, int b); int min_int(int a, int b); uint64_t min_uint64_t(uint64_t a, uint64_t b); uint64_t parse_max_targets(char *max_targets, int port_count); void enforce_range(const char *name, int v, int min, int max); // Splits comma delimited string into char*[]. Does not handle // escaping or complicated setups - designed to process a set // of fields that the user wants output void split_string(const char *in, int *len, const char ***results); // Print a string using w length long lines, attempting to break on // spaces void fprintw(FILE *f, const char *s, size_t w); // pretty print elapsed (or estimated) number of seconds void time_string(uint32_t time, int est, char *buf, size_t len); // pretty print quantities void number_string(uint32_t n, char *buf, size_t len); // Convert a string representation of a MAC address to a byte array int parse_mac(macaddr_t *out, char *in); int check_range(int v, int min, int max); int file_exists(char *name); // If running as root, drops privileges to that of user "nobody". // Otherwise, does nothing. int drop_privs(void); // Set CPU affinity to a single core int set_cpu(uint32_t core); // The number of seconds and microseconds since the Epoch. double now(void); // The number of seconds and nanoseconds since an unspecified point in time. // On supported hosts, this value is guaranteed to never decrease. // // According to the POSIX specification the `clock_gettime` function is part // of the Timers option and may not be available on all implementations. // // On hosts where a monotonic clock is not available, this falls back // to `gettimeofday` which was ZMap's original implementation. double steady_now(void); #endif /* ZMAP_UTIL_H */ zmap-4.3.4/lib/xalloc.c000066400000000000000000000023061501046211500146610ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "xalloc.h" #include "logger.h" #include #include static void die(void) __attribute__((noreturn)); void *xcalloc(size_t count, size_t size) { void *res = calloc(count, size); if (res == NULL) { die(); } return res; } void xfree(void *ptr) { free(ptr); } void *xmalloc(size_t size) { void *res = malloc(size); if (res == NULL) { die(); } memset(res, 0, size); return res; } void *xrealloc(void *ptr, size_t size) { void *res = realloc(ptr, size); if (res == NULL) { die(); } return res; } void die(void) { log_fatal("zmap", "Out of memory"); } zmap-4.3.4/lib/xalloc.h000066400000000000000000000015221501046211500146650ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ZMAP_ALLOC_H #define ZMAP_ALLOC_H #include void *xcalloc(size_t count, size_t size); void xfree(void *ptr); void *xmalloc(size_t size); void *xrealloc(void *ptr, size_t size); #endif /* ZMAP_ALLOC_H */ zmap-4.3.4/release-build.sh000066400000000000000000000001531501046211500155340ustar00rootroot00000000000000#!/bin/bash cmake \ -DENABLE_DEVELOPMENT=off \ -DZMAP_VERSION=$1 \ -DENABLE_LOG_TRACE=off \ . make zmap-4.3.4/scripts/000077500000000000000000000000001501046211500141535ustar00rootroot00000000000000zmap-4.3.4/scripts/check_manfile.py000077500000000000000000000017721501046211500173070ustar00rootroot00000000000000#!/usr/bin/env python3 # # CI runs this script to verify that options appearing in ZTools' ggo.in files # also appear in their .ronn files. It does not check that `make manpages` has # actually been run. # # This script assumes it's being run from the root of the zmap repository. # import sys checks = [ ("zopt.ggo.in", "zmap.1.ronn"), ("zbopt.ggo.in", "zblocklist.1.ronn"), ("zitopt.ggo.in", "ziterate.1.ronn"), ("ztopt.ggo.in", "ztee.1.ronn") ] failures = False for ggo, ronn in checks: options = [] with open("src/" + ggo) as fd: for l in fd: if l.startswith("option "): option = l.split()[1].lstrip('"').rstrip('"') options.append(option) man = open("src/" + ronn).read() for option in options: if option not in man: failures = True sys.stderr.write(f"option \"{option}\" is present in \"{ggo}\" but missing from man file \"{ronn}\"\n") sys.stderr.flush() if failures: sys.exit(1) zmap-4.3.4/src/000077500000000000000000000000001501046211500132535ustar00rootroot00000000000000zmap-4.3.4/src/.gitignore000066400000000000000000000000421501046211500152370ustar00rootroot00000000000000lexer.c lexer.h parser.c parser.h zmap-4.3.4/src/CMakeLists.txt000066400000000000000000000170641501046211500160230ustar00rootroot00000000000000include_directories( "${CMAKE_CURRENT_BINARY_DIR}" ${PROJECT_SOURCE_DIR}/lib ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/src/output_modules ${PROJECT_SOURCE_DIR}/src/tests ) # ADD YOUR PROBE MODULE HERE set(EXTRA_PROBE_MODULES ) # ADD YOUR OUTPUT MODULE HERE set(EXTRA_OUTPUT_MODULES ) set(OUTPUT_MODULE_SOURCES output_modules/module_csv.c output_modules/module_json.c output_modules/output_modules.c ) set(PROBE_MODULE_SOURCES probe_modules/module_icmp_echo.c probe_modules/module_icmp_echo_time.c probe_modules/module_tcp_synscan.c probe_modules/module_tcp_synackscan.c #probe_modules/module_tcp_cisco_backdoor.c probe_modules/module_udp.c probe_modules/module_ipip.c probe_modules/packet.c probe_modules/probe_modules.c probe_modules/module_ntp.c probe_modules/module_upnp.c probe_modules/module_dns.c probe_modules/module_bacnet.c ) set(SOURCES aesrand.c cyclic.c expression.c fieldset.c filter.c get_gateway.c iterator.c monitor.c ports.c recv.c send.c shard.c socket.c state.c summary.c utility.c validate.c zmap.c zopt_compat.c "${CMAKE_CURRENT_BINARY_DIR}/zopt.h" "${CMAKE_CURRENT_BINARY_DIR}/lexer.c" "${CMAKE_CURRENT_BINARY_DIR}/parser.c" ${EXTRA_PROBE_MODULES} ${EXTRA_OUTPUT_MODULES} ${PROBE_MODULE_SOURCES} ${OUTPUT_MODULE_SOURCES} ) set(ZTESTSOURCES aesrand.c cyclic.c expression.c fieldset.c filter.c get_gateway.c iterator.c monitor.c ports.c recv.c send.c shard.c socket.c state.c summary.c utility.c validate.c ztopt_compat.c ${PROBE_MODULE_SOURCES} ${OUTPUT_MODULE_SOURCES} tests/test_harness.c "${CMAKE_CURRENT_BINARY_DIR}/ztopt.h" "${CMAKE_CURRENT_BINARY_DIR}/lexer.c" "${CMAKE_CURRENT_BINARY_DIR}/parser.c" ${EXTRA_PROBE_MODULES} ${EXTRA_OUTPUT_MODULES} ) set(ZBLSOURCES zblocklist.c zbopt_compat.c "${CMAKE_CURRENT_BINARY_DIR}/zbopt.h" ) set(ZITSOURCES aesrand.c cyclic.c iterator.c ports.c shard.c state.c validate.c zitopt_compat.c ziterate.c "${CMAKE_CURRENT_BINARY_DIR}/zitopt.h" ) set(ZTEESOURCES ztee.c topt_compat.c "${CMAKE_CURRENT_BINARY_DIR}/topt.h" ) # Handle various versions of socket if(WITH_PFRING) set(SOURCES ${SOURCES} socket-pfring.c) set(ZTESTSOURCES ${ZTESTSOURCES} socket-pfring.c) elseif(WITH_NETMAP) set(SOURCES ${SOURCES} socket-netmap.c send-netmap.c) set(ZTESTSOURCES ${ZTESTSOURCES} socket-netmap.c send-netmap.c) if(APPLE OR BSD) set(SOURCES ${SOURCES} if-netmap-bsd.c) set(ZTESTSOURCES ${ZTESTSOURCES} if-netmap-bsd.c) else() set(SOURCES ${SOURCES} if-netmap-linux.c) set(ZTESTSOURCES ${ZTESTSOURCES} if-netmap-linux.c) endif() elseif (APPLE OR BSD) set(SOURCES ${SOURCES} socket-bsd.c send-bsd.c) set(ZTESTSOURCES ${ZTESTSOURCES} socket-bsd.c send-bsd.c) else() set(SOURCES ${SOURCES} socket-linux.c send-linux.c) set(ZTESTSOURCES ${ZTESTSOURCES} socket-linux.c send-linux.c) endif() # Handle various versions of recv if(WITH_PFRING) set(SOURCES ${SOURCES} recv-pfring.c) set(ZTESTSOURCES ${ZTESTSOURCES} recv-pfring.c) elseif(WITH_NETMAP) set(SOURCES ${SOURCES} recv-netmap.c) set(ZTESTSOURCES ${ZTESTSOURCES} recv-netmap.c) else() set(SOURCES ${SOURCES} recv-pcap.c) set(ZTESTSOURCES ${ZTESTSOURCES} recv-pcap.c) endif() # Set configure time zmap version configure_file(topt.ggo.in ${CMAKE_BINARY_DIR}/src/topt.ggo @ONLY) configure_file(zbopt.ggo.in ${CMAKE_BINARY_DIR}/src/zbopt.ggo @ONLY) configure_file(zitopt.ggo.in ${CMAKE_BINARY_DIR}/src/zitopt.ggo @ONLY) configure_file(zopt.ggo.in ${CMAKE_BINARY_DIR}/src/zopt.ggo @ONLY) configure_file(ztopt.ggo.in ${CMAKE_BINARY_DIR}/src/ztopt.ggo @ONLY) # Additional ggo.in's should be added here and CMakeVersion.txt # This sets a *build* time dependency that checks git if("${ZMAP_VERSION}" STREQUAL "DEVELOPMENT") add_custom_target(git_versioning ALL COMMAND ${CMAKE_COMMAND} -D ORIG_SRC_DIR:STRING="${CMAKE_SOURCE_DIR}" -P "${CMAKE_SOURCE_DIR}/src/CMakeVersion.txt" ) endif() add_custom_command(OUTPUT zopt.h COMMAND gengetopt -C --no-help --no-version --unamed-opts=SUBNETS -i "${CMAKE_CURRENT_BINARY_DIR}/zopt.ggo" -F "${CMAKE_CURRENT_BINARY_DIR}/zopt" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/zopt.ggo" ) add_custom_command(OUTPUT topt.h COMMAND gengetopt -S --no-help --no-version --unamed-opts=FILE -i "${CMAKE_CURRENT_BINARY_DIR}/topt.ggo" -F "${CMAKE_CURRENT_BINARY_DIR}/topt" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/topt.ggo" ) add_custom_command(OUTPUT zbopt.h COMMAND gengetopt -C --no-help --no-version -i "${CMAKE_CURRENT_BINARY_DIR}/zbopt.ggo" -F "${CMAKE_CURRENT_BINARY_DIR}/zbopt" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/zbopt.ggo" ) add_custom_command(OUTPUT zitopt.h COMMAND gengetopt -C --no-help --no-version --unamed-opts=SUBNETS -i "${CMAKE_CURRENT_BINARY_DIR}/zitopt.ggo" -F "${CMAKE_CURRENT_BINARY_DIR}/zitopt" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/zitopt.ggo" ) add_custom_command(OUTPUT ztopt.h COMMAND gengetopt -C --no-help --no-version -i "${CMAKE_CURRENT_BINARY_DIR}/ztopt.ggo" -F "${CMAKE_CURRENT_BINARY_DIR}/ztopt" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/ztopt.ggo" ) add_custom_command(OUTPUT lexer.c COMMAND flex -o "${CMAKE_CURRENT_BINARY_DIR}/lexer.c" --header-file="${CMAKE_CURRENT_BINARY_DIR}/lexer.h" "${CMAKE_CURRENT_SOURCE_DIR}/lexer.l" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/lexer.l" ) if(NetBSD) add_custom_command(OUTPUT parser.c COMMAND yacc -d -o "${CMAKE_CURRENT_BINARY_DIR}/parser.c" "${CMAKE_CURRENT_SOURCE_DIR}/parser.y" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/parser.y" ) else() add_custom_command(OUTPUT parser.c COMMAND byacc -d -o "${CMAKE_CURRENT_BINARY_DIR}/parser.c" "${CMAKE_CURRENT_SOURCE_DIR}/parser.y" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/parser.y" ) endif() add_custom_target(manpages ronn "${CMAKE_CURRENT_SOURCE_DIR}/zmap.1.ronn" --organization="ZMap" --manual="zmap" COMMAND ronn "${CMAKE_CURRENT_SOURCE_DIR}/zblocklist.1.ronn" --organization="ZMap" --manual="zblocklist" COMMAND ronn "${CMAKE_CURRENT_SOURCE_DIR}/ziterate.1.ronn" --organization="ZMap" --manual="ziterate" COMMAND ronn "${CMAKE_CURRENT_SOURCE_DIR}/ztee.1.ronn" --organization="ZMap" --manual="ztee" SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/zblocklist.1.ronn" "${CMAKE_CURRENT_SOURCE_DIR}/ziterate.1.ronn" "${CMAKE_CURRENT_SOURCE_DIR}/zmap.1.ronn" "${CMAKE_CURRENT_SOURCE_DIR}/ztee.1.ronn" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) add_executable(zmap ${SOURCES}) add_executable(zblocklist ${ZBLSOURCES}) add_executable(ziterate ${ZITSOURCES}) add_executable(ztee ${ZTEESOURCES}) add_executable(ztests ${ZTESTSOURCES}) if(APPLE OR BSD) else() set(ZTESTSOURCES ${ZTESTSOURCES} send-linux.c) set(SOURCES ${SOURCES} send-linux.c) endif() target_link_libraries( zmap zmaplib ${PFRING_LIBRARIES} pcap gmp m unistring ${JSON_LIBRARIES} ${JUDY_LIBRARIES} ) target_link_libraries( zblocklist zmaplib m ) target_link_libraries( ziterate zmaplib gmp m ) target_link_libraries( ztee zmaplib m ) target_link_libraries( ztests zmaplib ${PFRING_LIBRARIES} pcap gmp m unistring ${JSON_LIBRARIES} ${JUDY_LIBRARIES} ) # Install binary install( TARGETS zmap zblocklist ziterate ztee RUNTIME DESTINATION sbin ) # Install Manpages install( FILES zmap.1 zblocklist.1 ziterate.1 ztee.1 DESTINATION share/man/man1 ) zmap-4.3.4/src/CMakeVersion.txt000066400000000000000000000013641501046211500163460ustar00rootroot00000000000000set(GIT_CMD "git") set(GIT_ARGS "log" "-n" "1" "--pretty=format:%h - %ad") execute_process(COMMAND ${GIT_CMD} ${GIT_ARGS} RESULT_VARIABLE GIT_RESULT OUTPUT_VARIABLE GIT_COMMIT) if (GIT_RESULT) set (GIT_COMMIT "UNKNOWN") endif() set(ZMAP_VERSION "Development Build. Commit ${GIT_COMMIT}") configure_file("${ORIG_SRC_DIR}/src/topt.ggo.in" "${CMAKE_BINARY_DIR}/topt.ggo" @ONLY) configure_file("${ORIG_SRC_DIR}/src/zbopt.ggo.in" "${CMAKE_BINARY_DIR}/zbopt.ggo" @ONLY) configure_file("${ORIG_SRC_DIR}/src/zitopt.ggo.in" "${CMAKE_BINARY_DIR}/zitopt.ggo" @ONLY) configure_file("${ORIG_SRC_DIR}/src/zopt.ggo.in" "${CMAKE_BINARY_DIR}/zopt.ggo" @ONLY) configure_file("${ORIG_SRC_DIR}/src/ztopt.ggo.in" "${CMAKE_BINARY_DIR}/ztopt.ggo" @ONLY) zmap-4.3.4/src/aesrand.c000066400000000000000000000032531501046211500150370ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include "../lib/logger.h" #include "../lib/aes128.h" #include "../lib/random.h" #include "../lib/xalloc.h" #include "aesrand.h" struct aesrand { uint32_t input[AES128_BLOCK_BYTES / sizeof(uint32_t)]; uint8_t output[AES128_BLOCK_BYTES]; bool remaining; aes128_ctx_t *aes128; }; static aesrand_t *_aesrand_init(uint8_t *key) { aesrand_t *aes = xmalloc(sizeof(aesrand_t)); memset(aes, 0, sizeof(*aes)); aes->aes128 = aes128_init(key); return aes; } aesrand_t *aesrand_init_from_seed(uint64_t seed) { uint8_t key[AES128_KEY_BYTES]; memset(key, 0, sizeof(key)); for (size_t i = 0; i < sizeof(seed); ++i) { key[i] = (uint8_t)((seed >> 8 * i) & 0xFF); } return _aesrand_init(key); } aesrand_t *aesrand_init_from_random(void) { uint8_t key[AES128_KEY_BYTES]; if (!random_bytes(key, sizeof(key))) { log_fatal("aesrand", "Couldn't get random bytes"); } return _aesrand_init(key); } uint64_t aesrand_getword(aesrand_t *aes) { uint64_t retval; if (aes->remaining) { memcpy(&retval, &aes->output[sizeof(retval)], sizeof(retval)); aes->remaining = false; return retval; } memcpy(aes->input, aes->output, sizeof(aes->input)); aes128_encrypt_block(aes->aes128, (uint8_t *)aes->input, aes->output); memcpy(&retval, aes->output, sizeof(retval)); aes->remaining = true; return retval; } zmap-4.3.4/src/aesrand.h000066400000000000000000000010701501046211500150370ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #ifndef AESRAND_H #define AESRAND_H typedef struct aesrand aesrand_t; aesrand_t *aesrand_init_from_random(void); aesrand_t *aesrand_init_from_seed(uint64_t); uint64_t aesrand_getword(aesrand_t *aes); aesrand_t *aesrand_free(aesrand_t *aes); #endif zmap-4.3.4/src/constants.h000066400000000000000000000007271501046211500154460ustar00rootroot00000000000000/* * ZMap Copyright 2023 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_CONSTANTS_H #define ZMAP_CONSTANTS_H #ifndef ZMAP_DEFAULT_BLOCKLIST #define ZMAP_DEFAULT_BLOCKLIST "/etc/zmap/blocklist.conf" #endif #endif /* ZMAP_CONSTANTS_H */ zmap-4.3.4/src/cyclic.c000066400000000000000000000140161501046211500146670ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ /* * cyclic provides an inexpensive approach to iterating over the IPv4 address * space in a random(-ish) manner such that we connect to every host once in * a scan execution without having to keep track of the IPs that have been * scanned or need to be scanned and such that each scan has a different * ordering. We accomplish this by utilizing a cyclic multiplicative group * of integers modulo a prime and generating a new primitive root (generator) * for each scan. * * We know that 3 is a generator of (Z mod 2^32 + 15 - {0}, *) * and that we have coverage over the entire address space because 2**32 + 15 * is prime and ||(Z mod PRIME - {0}, *)|| == PRIME - 1. Therefore, we * just need to find a new generator (primitive root) of the cyclic group for * each scan that we perform. * * Because generators map to generators over an isomorphism, we can efficiently * find random primitive roots of our mult. group by finding random generators * of the group (Zp-1, +) which is isomorphic to (Zp*, *). Specifically the * generators of (Zp-1, +) are { s | (s, p-1) == 1 } which implies that * the generators of (Zp*, *) are { d^s | (s, p-1) == 1 }. where d is a known * generator of the multiplicative group. We efficiently find * generators of the additive group by precalculating the psub1_f of * p - 1 and randomly checking random numbers against the psub1_f until * we find one that is coprime and map it into Zp*. Because * totient(totient(p)) ~= 10^9, this should take relatively few * iterations to find a new generator. */ #include "cyclic.h" #include #include #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/logger.h" // We will pick the first cyclic group from this list that is // larger than the number of IPs in our allowlist. E.g. for an // entire Internet scan, this would be cyclic32 // Note: this list should remain ordered by size (primes) ascending. static cyclic_group_t groups[] = { {// 2^8 + 1 .prime = 257, .known_primroot = 3, .prime_factors = {2}, // prime factors of prime - 1 .num_prime_factors = 1}, {// 2^16 + 1 .prime = 65537, .known_primroot = 3, .prime_factors = {2}, .num_prime_factors = 1}, {// 2^24 + 43 .prime = 16777259, .known_primroot = 2, .prime_factors = {2, 23, 103, 3541}, .num_prime_factors = 4}, {// 2^28 + 3 .prime = 268435459, .known_primroot = 2, .prime_factors = {2, 3, 19, 87211}, .num_prime_factors = 4}, {// 2^32 + 15 .prime = 4294967311, .known_primroot = 3, .prime_factors = {2, 3, 5, 131, 364289}, .num_prime_factors = 5}, {// 2^33 + 17 .prime = 8589934609, .known_primroot = 19, .prime_factors = {2, 3, 59, 3033169}, .num_prime_factors = 4}, {// 2^34 + 25 .prime = 17179869209, .known_primroot = 3, .prime_factors = {2, 83, 1277, 20261}, .num_prime_factors = 4}, {// 2^36 + 31 .prime = 68719476767, .known_primroot = 5, .prime_factors = {2, 163, 883, 238727}, .num_prime_factors = 4}, {// 2^40 + 15 .prime = 1099511627791, .known_primroot = 3, .prime_factors = {2, 3, 5, 36650387593}, .num_prime_factors = 4}, {// 2^44 + 7 .prime = 17592186044423, .known_primroot = 5, .prime_factors = {2, 11, 53, 97, 155542661}, .num_prime_factors = 5}, {// 2^48 + 23 .prime = 281474976710677, .known_primroot = 6, .prime_factors = {2, 3, 7, 1361, 2462081249}, .num_prime_factors = 5}, }; // Return a (random) number coprime with (p - 1) of the group, // which is a generator of the additive group mod (p - 1) static uint32_t find_primroot(const cyclic_group_t *group, aesrand_t *aes) { uint32_t candidate = (uint32_t)((aesrand_getword(aes) & 0xFFFFFFFF) % group->prime); uint64_t retv = 0; // The maximum primitive root we can return needs to be small enough such // that there is no overflow when multiplied by any element in the largest // group in ZMap, which currently has p = 2^{32} + 15. const uint64_t max_root = (UINT64_C(1) << 22); // Repeatedly find a generator until we hit one that is small enough. For // the largest group, we have a very low probability of ever executing this // loop more than once, and for small groups it will only execute once. do { candidate += 1; // Only one of these mods will ever have an effect. candidate %= group->prime; candidate %= max_root; if (candidate == 0) { continue; } mpz_t prime; mpz_init_set_ui(prime, group->prime); int ok = 1; for (size_t i = 0; i < group->num_prime_factors && ok; ++i) { const uint64_t q = group->prime_factors[i]; const uint64_t k = (group->prime - 1) / q; mpz_t base, power, res; mpz_init_set_ui(base, candidate); mpz_init_set_ui(power, k); mpz_init(res); mpz_powm(res, base, power, prime); uint64_t res_ui = mpz_get_ui(res); if (res_ui == 1) { ok = 0; } mpz_clear(base); mpz_clear(power); mpz_clear(res); } if (ok) { retv = candidate; break; } } while (1); log_debug("zmap", "Isomorphism: %llu", retv); return retv; } const cyclic_group_t *get_group(uint64_t min_size) { for (unsigned i = 0; i < sizeof(groups); ++i) { if (groups[i].prime > min_size) { return &groups[i]; } } // Should not reach, final group should always be larger than 2^48 // which is max based on 2**32 IPs and 2**16 ports assert(0); } cycle_t make_cycle(const cyclic_group_t *group, aesrand_t *aes) { cycle_t cycle; cycle.group = group; cycle.generator = find_primroot(group, aes); cycle.offset = (uint32_t)(aesrand_getword(aes) & 0xFFFFFFFF); cycle.offset %= group->prime; cycle.order = group->prime - 1; return cycle; } zmap-4.3.4/src/cyclic.h000066400000000000000000000023601501046211500146730ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef CYCLIC_H #define CYCLIC_H #include #include #include "aesrand.h" // Represents a multiplicative cyclic group (Z/pZ)* typedef struct cyclic_group { uint64_t prime; // p uint64_t known_primroot; // Known primitive root of (Z/pZ)* size_t num_prime_factors; // Length of num_prime_factors uint64_t prime_factors[10]; // Unique prime factors of (p-1) } cyclic_group_t; // Represents a cycle in a group typedef struct cycle { const cyclic_group_t *group; uint64_t generator; uint64_t order; uint32_t offset; } cycle_t; // Get a cyclic_group_t of at least min_size. // Pointer into static data, do not free(). const cyclic_group_t *get_group(uint64_t min_size); // Generate cycle (find generator and inverse) cycle_t make_cycle(const cyclic_group_t *group, aesrand_t *aes); // Perform the isomorphism from (Z/pZ)+ to (Z/pZ)* // Given known primitive root of (Z/pZ)* n, with x in (Z/pZ)+, do: // f(x) = n^x mod p // #endif zmap-4.3.4/src/expression.c000066400000000000000000000075671501046211500156350ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "expression.h" #include "fieldset.h" #include "../lib/xalloc.h" /* Static helper functions */ static node_t *alloc_node(void); static int eval_gt_node(node_t *node, fieldset_t *fields); static int eval_lt_node(node_t *node, fieldset_t *fields); static int eval_eq_node(node_t *node, fieldset_t *fields); static int eval_lt_eq_node(node_t *node, fieldset_t *fields); static int eval_gt_eq_node(node_t *node, fieldset_t *fields); static node_t *alloc_node(void) { node_t *node = xmalloc(sizeof(node_t)); return node; } static int eval_gt_node(node_t *node, fieldset_t *fields) { int index = node->left_child->value.field.index; uint64_t expected = node->right_child->value.int_literal; uint64_t actual = fs_get_uint64_by_index(fields, index); return (actual > expected); } static int eval_lt_node(node_t *node, fieldset_t *fields) { int index = node->left_child->value.field.index; uint64_t expected = node->right_child->value.int_literal; uint64_t actual = fs_get_uint64_by_index(fields, index); return (actual < expected); } static int eval_eq_node(node_t *node, fieldset_t *fields) { node_t *literal = node->right_child; int index = node->left_child->value.field.index; char *expected, *actual; switch (literal->type) { case STRING: expected = literal->value.string_literal; actual = fs_get_string_by_index(fields, index); return (strcmp(expected, actual) == 0); break; case INT: return (fs_get_uint64_by_index(fields, index) == literal->value.int_literal); break; default: printf("wat\n"); break; } return 0; } static int eval_lt_eq_node(node_t *node, fieldset_t *fields) { return !(eval_gt_node(node, fields)); } static int eval_gt_eq_node(node_t *node, fieldset_t *fields) { return !(eval_lt_node(node, fields)); } /* Exposed functions */ node_t *make_op_node(enum operation op) { node_t *node = alloc_node(); node->type = OP; node->value.op = op; return node; } node_t *make_field_node(char *fieldname) { node_t *node = alloc_node(); node->type = FIELD; node->value.field.fieldname = fieldname; return node; } node_t *make_string_node(char *literal) { node_t *node = alloc_node(); node->type = STRING; node->value.string_literal = literal; return node; } node_t *make_int_node(int literal) { node_t *node = alloc_node(); node->type = INT; node->value.int_literal = literal; return node; } int evaluate_expression(node_t *root, fieldset_t *fields) { if (!root) return 1; switch (root->type) { /* XXX Not sure if runs */ case FIELD: case STRING: case INT: return 1; case OP: break; } switch (root->value.op) { case GT: return eval_gt_node(root, fields); case LT: return eval_lt_node(root, fields); case EQ: return eval_eq_node(root, fields); case NEQ: return (!eval_eq_node(root, fields)); case LT_EQ: return eval_lt_eq_node(root, fields); case GT_EQ: return eval_gt_eq_node(root, fields); case AND: return (evaluate_expression(root->left_child, fields) && evaluate_expression(root->right_child, fields)); case OR: return (evaluate_expression(root->left_child, fields) || evaluate_expression(root->right_child, fields)); } return 0; } void print_expression(node_t *root) { if (!root) return; printf("%s", "( "); print_expression(root->left_child); switch (root->type) { case OP: printf(" %i ", root->value.op); break; case FIELD: printf(" (%s", root->value.field.fieldname); break; case STRING: printf("%s) ", root->value.string_literal); break; case INT: printf(" %llu) ", (long long unsigned)root->value.int_literal); break; default: break; } print_expression(root->right_child); printf("%s", " )"); } zmap-4.3.4/src/expression.h000066400000000000000000000022151501046211500156230ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_TREE_H #define ZMAP_TREE_H #include "fieldset.h" #include #include #include #include enum operation { GT, LT, EQ, NEQ, AND, OR, LT_EQ, GT_EQ }; enum node_type { OP, FIELD, STRING, INT }; struct field_id { int index; char *fieldname; }; union node_value { struct field_id field; char *string_literal; uint64_t int_literal; enum operation op; }; typedef struct node_st { struct node_st *left_child; struct node_st *right_child; enum node_type type; union node_value value; } node_t; node_t *make_op_node(enum operation op); node_t *make_field_node(char *fieldname); node_t *make_string_node(char *literal); node_t *make_int_node(int literal); int evaluate_expression(node_t *root, fieldset_t *fields); void print_expression(node_t *root); #endif /* ZMAP_TREE_H */ zmap-4.3.4/src/fieldset.c000066400000000000000000000237231501046211500152250ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "fieldset.h" #include #include #include #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wundef" #include #pragma GCC diagnostic pop #include "../lib/logger.h" #include "../lib/xalloc.h" void gen_fielddef_set(fielddefset_t *fds, fielddef_t fs[], int len) { if (fds->len + len > MAX_FIELDS) { log_fatal("fieldset", "out of room in field def set"); } fielddef_t *open = &(fds->fielddefs[fds->len]); memcpy(open, fs, len * sizeof(fielddef_t)); fds->len += len; } fieldset_t *fs_new_fieldset(fielddefset_t *fds) { fieldset_t *f = xcalloc(1, sizeof(fieldset_t)); f->len = 0; f->type = FS_FIELDSET; f->fds = fds; return f; } fieldset_t *fs_new_repeated_field(int type, int free_) { fieldset_t *f = xcalloc(1, sizeof(fieldset_t)); f->len = 0; f->type = FS_REPEATED; f->inner_type = type; f->free_ = free_; return f; } fieldset_t *fs_new_repeated_uint64(void) { return fs_new_repeated_field(FS_UINT64, 0); } fieldset_t *fs_new_repeated_bool(void) { return fs_new_repeated_field(FS_BOOL, 0); } fieldset_t *fs_new_repeated_string(int free_) { return fs_new_repeated_field(FS_STRING, free_); } fieldset_t *fs_new_repeated_binary(int free_) { return fs_new_repeated_field(FS_BINARY, free_); } fieldset_t *fs_new_repeated_fieldset(void) { return fs_new_repeated_field(FS_FIELDSET, 0); } static inline void fs_add_word(fieldset_t *fs, const char *name, int type, int free_, size_t len, field_val_t value) { if (fs->len + 1 >= MAX_FIELDS) { log_fatal("fieldset", "out of room in fieldset"); } if (fs->type == FS_REPEATED && fs->inner_type != type) { log_fatal( "fieldset", "object added to repeated field does not match type of repeated field."); } field_t *f = &(fs->fields[fs->len]); // if we have a fieldset definition, then we can validate that the name // of the field is as expected if (fs->fds && strcmp(fs->fds->fielddefs[fs->len].name, name)) { log_fatal("fieldset", "added field (%s) is not next expected field (%s).", name, fs->fds->fielddefs[fs->len].name); } fs->len++; f->type = type; f->name = name; f->len = len; f->value = value; f->free_ = free_; } static void fs_modify_word(fieldset_t *fs, const char *name, int type, int free_, size_t len, field_val_t value) { for (int i = 0; i < fs->len; i++) { if (!strcmp(fs->fields[i].name, name)) { if (fs->fields[i].free_) { free(fs->fields[i].value.ptr); fs->fields[i].value.ptr = NULL; } fs->fields[i].type = type; fs->fields[i].free_ = free_; fs->fields[i].len = len; fs->fields[i].value = value; return; } } // TODO(ZD): We need to test, but this is really unsafe to just add because it // will all but guarantee that it's in the wrong place //fs_add_word(fs, name, type, free_, len, value); log_fatal("fs", "attempting to modify non-existent field"); } static char *sanitize_utf8(const char *buf) { const char *ptr = buf; // Count how many errors we encounter uint32_t i = 0; // Upper bounds to ensure termination even if u8_check is unsafe while (i < strlen(buf) && ptr < buf + strlen(buf)) { ptr = (char *)u8_check((uint8_t *)ptr, strlen(ptr)); if (ptr == NULL) { break; } assert(ptr >= buf); assert(ptr < buf + strlen(buf)); ptr++; i++; } // i is the total number of errors. We need 2 extra bytes for each rune char *safe_buf = xmalloc(strlen(buf) + i * 2 + 1); char *safe_ptr = NULL; memcpy(safe_buf, buf, strlen(buf)); // Fix exactly i errors for (uint32_t j = 0; j < i; j++) { // Always operate on the working buffer safe_ptr = (char *)u8_check((uint8_t *)safe_buf, strlen(safe_buf)); // This implies we had less errors than we should. // This is temporary debug code. if (safe_ptr == NULL) { log_warn( "fieldset", "UTF8 Sanitization issue. %u errors, fell through iter %u. Orig: %s new: %s", i, j, buf, safe_buf); i = j; break; } // XXX Uncomment when we remove above log_warn. // assert(safe_ptr != NULL); assert(safe_ptr >= safe_buf); assert(safe_ptr < safe_buf + strlen(safe_buf)); // Shift the rest of the string by 2 bytes if (strlen(safe_ptr) > 1) { memcpy(safe_ptr + 3, safe_ptr + 1, strlen(safe_ptr + 1)); } // UTF8 replacement rune safe_ptr[0] = (char)0xef; safe_ptr[1] = (char)0xbf; safe_ptr[2] = (char)0xbd; } // We now have a valid utf8 string assert(u8_check((uint8_t *)safe_buf, strlen(safe_buf)) == NULL); // We should be null terminated assert(safe_buf[strlen(buf) + i * 2] == '\0'); // We should be the right length assert(strlen(safe_buf) == (strlen(buf) + i * 2)); return safe_buf; } void fs_add_null(fieldset_t *fs, const char *name) { field_val_t val = {.ptr = NULL}; fs_add_word(fs, name, FS_NULL, 0, 0, val); } void fs_add_string(fieldset_t *fs, const char *name, char *value, int free_) { field_val_t val = {.ptr = value}; fs_add_word(fs, name, FS_STRING, free_, strlen(value), val); } void fs_add_unsafe_string(fieldset_t *fs, const char *name, char *value, int free_) { if (u8_check((uint8_t *)value, strlen(value)) == NULL) { field_val_t val = {.ptr = value}; fs_add_word(fs, name, FS_STRING, free_, strlen(value), val); } else { char *safe_value = sanitize_utf8(value); if (free_) { free(value); } field_val_t val = {.ptr = safe_value}; fs_add_word(fs, name, FS_STRING, 1, strlen(safe_value), val); } } void fs_chkadd_string(fieldset_t *fs, const char *name, char *value, int free_) { if (value) { fs_add_string(fs, name, value, free_); } else { fs_add_null(fs, name); } } void fs_chkadd_unsafe_string(fieldset_t *fs, const char *name, char *value, int free_) { if (value) { fs_add_unsafe_string(fs, name, value, free_); } else { fs_add_null(fs, name); } } void fs_add_constchar(fieldset_t *fs, const char *name, const char *value) { field_val_t val = {.ptr = (char *)value}; fs_add_word(fs, name, FS_STRING, 0, strlen(value), val); } void fs_add_uint64(fieldset_t *fs, const char *name, uint64_t value) { field_val_t val = {.num = value}; fs_add_word(fs, name, FS_UINT64, 0, sizeof(uint64_t), val); } void fs_add_bool(fieldset_t *fs, const char *name, int value) { field_val_t val = {.num = value}; fs_add_word(fs, name, FS_BOOL, 0, sizeof(int), val); } void fs_add_binary(fieldset_t *fs, const char *name, size_t len, void *value, int free_) { field_val_t val = {.ptr = value}; fs_add_word(fs, name, FS_BINARY, free_, len, val); } void fs_add_fieldset(fieldset_t *fs, const char *name, fieldset_t *child) { field_val_t val = {.ptr = child}; fs_add_word(fs, name, FS_FIELDSET, 1, sizeof(void *), val); } void fs_add_repeated(fieldset_t *fs, const char *name, fieldset_t *child) { field_val_t val = {.ptr = child}; fs_add_word(fs, name, FS_REPEATED, 1, sizeof(void *), val); } // Modify void fs_modify_null(fieldset_t *fs, const char *name) { field_val_t val = {.ptr = NULL}; fs_modify_word(fs, name, FS_NULL, 0, 0, val); } void fs_modify_string(fieldset_t *fs, const char *name, char *value, int free_) { field_val_t val = {.ptr = value}; fs_modify_word(fs, name, FS_STRING, free_, strlen(value), val); } void fs_modify_constchar(fieldset_t *fs, const char *name, const char *value) { field_val_t val = {.ptr = (char *)value}; fs_modify_word(fs, name, FS_STRING, 0, strlen(value), val); } void fs_modify_uint64(fieldset_t *fs, const char *name, uint64_t value) { field_val_t val = {.num = value}; fs_modify_word(fs, name, FS_UINT64, 0, sizeof(uint64_t), val); } void fs_modify_bool(fieldset_t *fs, const char *name, int value) { field_val_t val = {.num = value}; fs_modify_word(fs, name, FS_BOOL, 0, sizeof(int), val); } void fs_modify_binary(fieldset_t *fs, const char *name, size_t len, void *value, int free_) { field_val_t val = {.ptr = value}; fs_modify_word(fs, name, FS_BINARY, free_, len, val); } uint64_t fs_get_uint64_by_index(fieldset_t *fs, int index) { return (uint64_t)fs->fields[index].value.num; } char *fs_get_string_by_index(fieldset_t *fs, int index) { return (char *)fs->fields[index].value.ptr; } int fds_get_index_by_name(fielddefset_t *fds, const char *name) { for (int i = 0; i < fds->len; i++) { if (!strcmp(fds->fielddefs[i].name, name)) { return i; } } return -1; } void field_free(field_t *f) { if (f->type == FS_FIELDSET || f->type == FS_REPEATED) { fs_free((fieldset_t *)f->value.ptr); } else if (f->free_) { free(f->value.ptr); } } void fs_free(fieldset_t *fs) { if (!fs) { return; } for (int i = 0; i < fs->len; i++) { field_t *f = &(fs->fields[i]); field_free(f); } free(fs); } void fs_generate_fieldset_translation(translation_t *t, fielddefset_t *avail, const char **req, int reqlen) { memset(t, 0, sizeof(translation_t)); if (!t) { log_fatal("fieldset", "unable to allocate memory for translation"); } for (int i = 0; i < reqlen; i++) { int l = fds_get_index_by_name(avail, req[i]); if (l < 0) { log_fatal("fieldset", "specified field (%s) not " "available in selected " "probe module.", req[i]); } t->translation[t->len++] = l; } } void fs_generate_full_fieldset_translation(translation_t *t, fielddefset_t *avail) { memset(t, 0, sizeof(translation_t)); if (!t) { log_fatal("fieldset", "unable to allocate memory for translation"); } t->len = avail->len; for (int i = 0; i < avail->len; i++) { t->translation[i] = i; } } fieldset_t *translate_fieldset(fieldset_t *fs, translation_t *t) { fieldset_t *retv = fs_new_fieldset(NULL); if (!retv) { log_fatal("fieldset", "unable to allocate space for translated field set"); } for (int i = 0; i < t->len; i++) { int o = t->translation[i]; memcpy(&(retv->fields[i]), &(fs->fields[o]), sizeof(field_t)); } retv->len = t->len; return retv; } zmap-4.3.4/src/fieldset.h000066400000000000000000000104411501046211500152230ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include "types.h" #ifndef FIELDSET_H #define FIELDSET_H // maximum number of records that can be stored in a fieldset #define MAX_FIELDS 128 #define MAX_LIST_LENGTH 255 // types of data that can be stored in a field #define FS_RESERVED 0 #define FS_STRING 1 #define FS_UINT64 2 #define FS_BINARY 3 #define FS_NULL 4 #define FS_BOOL 7 // recursive support #define FS_FIELDSET 5 #define FS_REPEATED 6 // definition of a field that's provided by a probe module // these are used so that users can ask at the command-line // what fields are available for consumption typedef struct field_def { const char *name; const char *type; const char *desc; } fielddef_t; typedef struct fielddef_set { fielddef_t fielddefs[MAX_FIELDS]; int len; } fielddefset_t; typedef union field_val { void *ptr; uint64_t num; } field_val_t; // the internal field type used by fieldset typedef struct field { const char *name; int type; int free_; size_t len; field_val_t value; } field_t; // data structure that is populated by the probe module // and translated into the data structure that's passed // to the output module typedef struct fieldset { int len; field_t fields[MAX_FIELDS]; fielddefset_t *fds; // only used for repeated. int inner_type; // type of repeated element. e.g., FS_STRING int type; // REPEATED or FIELDSET int free_; // should elements be freed } fieldset_t; // we pass a different fieldset to an output module than // the probe module generates for us because a user may // only want certain fields and will expect them in a certain // order. We generate a translated fieldset that contains // only the fields we want to export to the output module. // a translation specifies how to efficiently convert the fs // povided by the probe module to the fs for the output module. typedef struct translation { int len; int translation[MAX_FIELDS]; } translation_t; fieldset_t *fs_new_fieldset(fielddefset_t *); fieldset_t *fs_new_repeated_field(int type, int free_); fieldset_t *fs_new_repeated_uint64(void); fieldset_t *fs_new_repeated_bool(void); fieldset_t *fs_new_repeated_string(int free_); fieldset_t *fs_new_repeated_binary(int free_); fieldset_t *fs_new_repeated_fieldset(void); char *fs_get_string_by_index(fieldset_t *fs, int index); int fds_get_index_by_name(fielddefset_t *fds, const char *name); void gen_fielddef_set(fielddefset_t *fds, fielddef_t fs[], int len); void fs_add_null(fieldset_t *fs, const char *name); void fs_add_uint64(fieldset_t *fs, const char *name, uint64_t value); void fs_add_bool(fieldset_t *fs, const char *name, int value); void fs_add_string(fieldset_t *fs, const char *name, char *value, int free_); void fs_add_unsafe_string(fieldset_t *fs, const char *name, char *value, int free_); void fs_chkadd_string(fieldset_t *fs, const char *name, char *value, int free_); void fs_chkadd_unsafe_string(fieldset_t *fs, const char *name, char *value, int free_); void fs_add_constchar(fieldset_t *fs, const char *name, const char *value); void fs_add_binary(fieldset_t *fs, const char *name, size_t len, void *value, int free_); void fs_add_fieldset(fieldset_t *fs, const char *name, fieldset_t *child); void fs_add_repeated(fieldset_t *fs, const char *name, fieldset_t *child); // Modify void fs_modify_null(fieldset_t *fs, const char *name); void fs_modify_uint64(fieldset_t *fs, const char *name, uint64_t value); void fs_modify_bool(fieldset_t *fs, const char *name, int value); void fs_modify_string(fieldset_t *fs, const char *name, char *value, int free_); void fs_modify_binary(fieldset_t *fs, const char *name, size_t len, void *value, int free_); uint64_t fs_get_uint64_by_index(fieldset_t *fs, int index); void fs_free(fieldset_t *fs); void fs_generate_fieldset_translation(translation_t *t, fielddefset_t *avail, const char **req, int reqlen); fieldset_t *translate_fieldset(fieldset_t *fs, translation_t *t); void fs_generate_full_fieldset_translation(translation_t *t, fielddefset_t *avail); #endif // FIELDSET_H zmap-4.3.4/src/filter.c000066400000000000000000000051011501046211500147010ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "filter.h" #include "state.h" #include "lexer.h" #include "parser.h" #include "expression.h" #include "../lib/logger.h" #include extern int yyparse(void); node_t *zfilter; static int validate_node(node_t *node, fielddefset_t *fields) { int index, found = 0; if (node->type == OP) { // These end up getting validated later if (node->value.op == AND || node->value.op == OR) { return 1; } // Comparison node (=, >, <, etc.) // Validate that the field (left child) exists in the fieldset for (index = 0; index < fields->len; index++) { if (fields->fielddefs[index].name) { if (strcmp(fields->fielddefs[index].name, node->left_child->value.field .fieldname) == 0) { node->left_child->value.field.index = index; found = 1; break; } } } if (!found) { fprintf(stderr, "Field '%s' does not exist\n", node->left_child->value.field.fieldname); return 0; } // Fieldname is fine, match the type. switch (node->right_child->type) { case STRING: if (strcmp(fields->fielddefs[index].type, "string") == 0) { return 1; } else { fprintf(stderr, "Field '%s' is not of type 'string'\n", fields->fielddefs[index].name); return 0; } case INT: if (strcmp(fields->fielddefs[index].type, "int") == 0 || strcmp(fields->fielddefs[index].type, "bool") == 0) { return 1; } else { fprintf(stderr, "Field '%s' is not of type 'int'\n", fields->fielddefs[index].name); return 0; } default: return 0; } } else { // All non-op nodes are valid return 1; } // Didn't validate return 0; } int parse_filter_string(char *filter) { YY_BUFFER_STATE buffer_state = yy_scan_string(filter); int status = yyparse(); yy_delete_buffer(buffer_state); if (status) { // Error log_error("zmap", "Unable to parse filter string: '%s'", filter); return 0; } zconf.filter.expression = zfilter; return 1; } /* * 0 Valid * -1 Invalid Field Name * -2 Type Mismatch */ int validate_filter(node_t *root, fielddefset_t *fields) { int valid; if (!root) { return 1; } valid = validate_node(root, fields); if (!valid) { return 0; } return (validate_filter(root->left_child, fields) && validate_filter(root->right_child, fields)); } zmap-4.3.4/src/filter.h000066400000000000000000000010571501046211500147140ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_FILTER_H #define ZMAP_FILTER_H #include "expression.h" #include "fieldset.h" struct output_filter { node_t *expression; }; int parse_filter_string(char *filter); int validate_filter(node_t *root, fielddefset_t *fields); #endif /* ZMAP_FILTER_H */ zmap-4.3.4/src/get_gateway-bsd.h000066400000000000000000000140701501046211500164740ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_GET_GATEWAY_BSD_H #define ZMAP_GET_GATEWAY_BSD_H #ifdef ZMAP_GET_GATEWAY_LINUX_H #error "Don't include both get_gateway-bsd.h and get_gateway-linux.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #define ROUNDUP(a) ((a) > 0 ? (1 + (((a)-1) | (sizeof(int) - 1))) : sizeof(int)) #define UNUSED __attribute__((unused)) int get_hw_addr(struct in_addr *gw_ip, UNUSED char *iface, unsigned char *hw_mac) { int mib[6]; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_FLAGS; mib[5] = RTF_LLINFO; size_t bufsz = 0; if (sysctl(mib, 6, NULL, &bufsz, NULL, 0) == -1) { log_debug("get_hw_addr", "sysctl getting buffer size: %d %s", errno, strerror(errno)); return EXIT_FAILURE; } uint8_t *buf = (uint8_t *)malloc(bufsz); assert(buf); if (sysctl(mib, 6, buf, &bufsz, NULL, 0) == -1) { log_debug("get_hw_addr", "sysctl getting buffer data: %d %s", errno, strerror(errno)); free(buf); return EXIT_FAILURE; } int result = EXIT_FAILURE; uint8_t *bufend = buf + bufsz; size_t min_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_inarp) + sizeof(struct sockaddr_dl); struct rt_msghdr *rtm = (struct rt_msghdr *)buf; for (uint8_t *p = buf; p < bufend; p += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)p; if ((p + sizeof(struct rt_msghdr) > bufend) || (p + rtm->rtm_msglen > bufend) || (rtm->rtm_msglen < min_msglen)) { break; } struct sockaddr_inarp *sin = (struct sockaddr_inarp *)(rtm + 1); struct sockaddr_dl *sdl = (struct sockaddr_dl *)(sin + 1); assert(sin->sin_family == AF_INET); if (sin->sin_addr.s_addr != gw_ip->s_addr) { continue; } assert(sdl->sdl_family == AF_LINK); memcpy(hw_mac, LLADDR(sdl), ETHER_ADDR_LEN); result = EXIT_SUCCESS; } free(buf); return result; } int get_iface_ip(char *iface, struct in_addr *ip) { assert(iface); struct ifaddrs *ifaddr, *ifa; if (getifaddrs(&ifaddr)) { log_fatal( "get-iface-ip", "ZMap is unable able to retrieve a list of available network " "interfaces: %s. You can manually specify the network interface " "to use with the \"-i\" flag.", strerror(errno)); } for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET) { continue; } if (!strcmp(iface, ifa->ifa_name)) { struct sockaddr_in *sin = (struct sockaddr_in *)ifa->ifa_addr; ip->s_addr = sin->sin_addr.s_addr; log_debug("get-iface-ip", "IP address found for %s: %s", iface, inet_ntoa(*ip)); freeifaddrs(ifaddr); return EXIT_SUCCESS; } } log_fatal("get-iface-ip", "The specified network interface (\"%s\") does not" " exist or does not have an assigned IPv4 address.", iface); return EXIT_FAILURE; } int get_iface_hw_addr(char *iface, unsigned char *hw_mac) { struct ifaddrs *ifa; if (getifaddrs(&ifa) == -1) { log_debug("get_iface_hw_addr", "getifaddrs(): %d %s", errno, strerror(errno)); return EXIT_FAILURE; } int result = EXIT_FAILURE; for (struct ifaddrs *p = ifa; p; p = p->ifa_next) { if (strcmp(p->ifa_name, iface) == 0 && p->ifa_addr != NULL && p->ifa_addr->sa_family == AF_LINK) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)p->ifa_addr; memcpy(hw_mac, LLADDR(sdl), ETHER_ADDR_LEN); result = EXIT_SUCCESS; break; } } freeifaddrs(ifa); return result; } int _get_default_gw(struct in_addr *gw, char **iface) { char buf[4096]; struct rt_msghdr *rtm = (struct rt_msghdr *)&buf; memset(rtm, 0, sizeof(buf)); int seq = 0x00FF; rtm->rtm_msglen = sizeof(buf); rtm->rtm_type = RTM_GET; rtm->rtm_flags = RTF_GATEWAY; rtm->rtm_version = RTM_VERSION; rtm->rtm_seq = seq; rtm->rtm_addrs = RTA_DST | RTA_IFP; rtm->rtm_pid = getpid(); int fd = socket(PF_ROUTE, SOCK_RAW, 0); assert(fd > 0); if (!write(fd, (char *)rtm, sizeof(buf))) { log_fatal( "get-gateway", "Unable to send request to retrieve default" "gateway MAC address. You will need to manually specify your " "gateway MAC with the \"-G\" or \"--gateway-mac\" flag."); } size_t len; while (rtm->rtm_type == RTM_GET && (len = read(fd, rtm, sizeof(buf))) > 0) { if (len < (int)sizeof(*rtm)) { close(fd); return (-1); } if (rtm->rtm_type == RTM_GET && rtm->rtm_pid == getpid() && rtm->rtm_seq == seq) { if (rtm->rtm_errno) { close(fd); errno = rtm->rtm_errno; return (-1); } break; } } struct sockaddr *sa = (struct sockaddr *)(rtm + 1); for (int i = 0; i < RTAX_MAX; i++) { if (rtm->rtm_addrs & (1 << i)) { if ((1 << i) == RTA_IFP) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; if (!sdl) { log_fatal( "get-gateway", "Unable to parse kernel response to request " "for gateway MAC address. You will need to manually specify " "your gateway MAC with the \"-G\" or \"--gateway-mac\" flag."); } char *_iface = xmalloc(sdl->sdl_nlen + 1); memcpy(_iface, sdl->sdl_data, sdl->sdl_nlen); _iface[sdl->sdl_nlen + 1] = 0; *iface = _iface; } if ((1 << i) == RTA_GATEWAY) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; gw->s_addr = sin->sin_addr.s_addr; } // next element sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); } } close(fd); return EXIT_SUCCESS; } char *get_default_iface(void) { struct in_addr t; char *retv = NULL; _get_default_gw(&t, &retv); return retv; } int get_default_gw(struct in_addr *gw, UNUSED char *iface) { char *_iface = NULL; _get_default_gw(gw, &_iface); return EXIT_SUCCESS; } #endif /* ZMAP_GET_GATEWAY_BSD_H */ zmap-4.3.4/src/get_gateway-linux.h000066400000000000000000000202321501046211500170600ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_GET_GATEWAY_LINUX_H #define ZMAP_GET_GATEWAY_LINUX_H #ifdef ZMAP_GET_GATEWAY_BSD_H #error "Don't include both get_gateway-bsd.h and get_gateway-linux.h" #endif #include #include #include #include #include #define GW_BUFFER_SIZE 64000 int read_nl_sock(int sock, char *buf, int buf_len) { int msg_len = 0; char *pbuf = buf; do { int len = recv(sock, pbuf, buf_len - msg_len, 0); if (len <= 0) { log_debug("get-gw", "recv failed: %s", strerror(errno)); return -1; } int bytes_read = 0; while (bytes_read < len) { struct nlmsghdr *nlhdr = (struct nlmsghdr *)pbuf; if (NLMSG_OK(nlhdr, ((unsigned int)len)) == 0 || nlhdr->nlmsg_type == NLMSG_ERROR) { log_debug("get-gw", "recv failed: %s", strerror(errno)); return -1; } if (nlhdr->nlmsg_type == NLMSG_DONE) { return msg_len; } else { msg_len += nlhdr->nlmsg_len; pbuf += nlhdr->nlmsg_len; bytes_read += nlhdr->nlmsg_len; } if ((nlhdr->nlmsg_flags & NLM_F_MULTI) == 0) { return msg_len; } } } while (1); return msg_len; } int send_nl_req(uint16_t msg_type, uint32_t seq, void *payload, uint32_t payload_len) { int sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if (sock < 0) { log_error("get-gw", "unable to get socket: %s", strerror(errno)); return -1; } if (NLMSG_SPACE(payload_len) < payload_len) { close(sock); // Integer overflow return -1; } struct nlmsghdr *nlmsg; nlmsg = xmalloc(NLMSG_SPACE(payload_len)); memset(nlmsg, 0, NLMSG_SPACE(payload_len)); memcpy(NLMSG_DATA(nlmsg), payload, payload_len); nlmsg->nlmsg_type = msg_type; nlmsg->nlmsg_len = NLMSG_LENGTH(payload_len); nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; nlmsg->nlmsg_seq = seq; nlmsg->nlmsg_pid = getpid(); if (send(sock, nlmsg, nlmsg->nlmsg_len, 0) < 0) { log_error("get-gw", "failure sending: %s", strerror(errno)); return -1; } free(nlmsg); return sock; } int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac) { struct ndmsg req; memset(&req, 0, sizeof(struct ndmsg)); if (!gw_ip || !hw_mac) { return -1; } // Send RTM_GETNEIGH request req.ndm_family = AF_INET; req.ndm_ifindex = if_nametoindex(iface); req.ndm_state = NUD_REACHABLE; req.ndm_type = NDA_LLADDR; int sock = send_nl_req(RTM_GETNEIGH, 1, &req, sizeof(req)); // Read responses char *buf = xmalloc(GW_BUFFER_SIZE); int nl_len = read_nl_sock(sock, buf, GW_BUFFER_SIZE); if (nl_len <= 0) { free(buf); return -1; } // Parse responses struct nlmsghdr *nlhdr = (struct nlmsghdr *)buf; while (NLMSG_OK(nlhdr, nl_len)) { struct rtattr *rt_attr; struct rtmsg *rt_msg; int rt_len; unsigned char mac[6]; struct in_addr dst_ip; int correct_ip = 0; rt_msg = (struct rtmsg *)NLMSG_DATA(nlhdr); if ((rt_msg->rtm_family != AF_INET)) { free(buf); return -1; } rt_attr = (struct rtattr *)RTM_RTA(rt_msg); rt_len = RTM_PAYLOAD(nlhdr); while (RTA_OK(rt_attr, rt_len)) { switch (rt_attr->rta_type) { case NDA_LLADDR: if (RTA_PAYLOAD(rt_attr) != IFHWADDRLEN) { // could be using a VPN log_fatal( "get_gateway", "Unexpected hardware address length (%d)." " If you are using a VPN, supply the --iplayer flag (and provide an" " interface via -i)", RTA_PAYLOAD(rt_attr)); } memcpy(mac, RTA_DATA(rt_attr), IFHWADDRLEN); break; case NDA_DST: if (RTA_PAYLOAD(rt_attr) != sizeof(dst_ip)) { // could be using a VPN log_fatal( "get_gateway", "Unexpected IP address length (%d)." " If you are using a VPN, supply the --iplayer flag" " (and provide an interface via -i)", RTA_PAYLOAD(rt_attr)); } memcpy(&dst_ip, RTA_DATA(rt_attr), sizeof(dst_ip)); if (memcmp(&dst_ip, gw_ip, sizeof(dst_ip)) == 0) { correct_ip = 1; } break; } rt_attr = RTA_NEXT(rt_attr, rt_len); } if (correct_ip) { memcpy(hw_mac, mac, IFHWADDRLEN); free(buf); return 0; } nlhdr = NLMSG_NEXT(nlhdr, nl_len); } free(buf); return -1; } // gw and iface[IF_NAMESIZE] MUST be allocated int _get_default_gw(struct in_addr *gw, char *iface) { struct rtmsg req; unsigned int nl_len; char buf[8192]; struct nlmsghdr *nlhdr; if (!gw || !iface) { return -1; } // Send RTM_GETROUTE request memset(&req, 0, sizeof(req)); int sock = send_nl_req(RTM_GETROUTE, 0, &req, sizeof(req)); // Read responses nl_len = read_nl_sock(sock, buf, sizeof(buf)); if (nl_len <= 0) { return -1; } // Parse responses nlhdr = (struct nlmsghdr *)buf; while (NLMSG_OK(nlhdr, nl_len)) { struct rtattr *rt_attr; struct rtmsg *rt_msg; int rt_len; int has_gw = 0; rt_msg = (struct rtmsg *)NLMSG_DATA(nlhdr); // There could be multiple routing tables. Loop until we find the // correct one. if ((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN)) { nlhdr = NLMSG_NEXT(nlhdr, nl_len); continue; } rt_attr = (struct rtattr *)RTM_RTA(rt_msg); rt_len = RTM_PAYLOAD(nlhdr); while (RTA_OK(rt_attr, rt_len)) { switch (rt_attr->rta_type) { case RTA_OIF: if_indextoname(*(int *)RTA_DATA(rt_attr), iface); break; case RTA_GATEWAY: gw->s_addr = *(unsigned int *)RTA_DATA(rt_attr); has_gw = 1; break; } rt_attr = RTA_NEXT(rt_attr, rt_len); } if (has_gw) { return 0; } nlhdr = NLMSG_NEXT(nlhdr, nl_len); } return -1; } char *get_default_iface(void) { struct in_addr gw; char *iface; iface = malloc(IF_NAMESIZE); memset(iface, 0, IF_NAMESIZE); if (_get_default_gw(&gw, iface)) { log_fatal( "send", "ZMap could not detect your default network interface. " "You likely do not have sufficient privileges to open a raw packet socket. " "Are you running as root or with the CAP_NET_RAW capability? If you are, you " "may need to manually set interface using the \"-i\" flag."); } else { return iface; } } int get_default_gw(struct in_addr *gw, char *iface) { char _iface[IF_NAMESIZE]; memset(_iface, 0, IF_NAMESIZE); _get_default_gw(gw, _iface); if (strcmp(iface, _iface)) { log_fatal( "get-gateway", "The specified network (\"%s\") does not match " "the interface associated with the default gateway (%s). You will " "need to manually specify the MAC address of your gateway using " "the \"--gateway-mac\" flag.", iface, _iface); } return EXIT_SUCCESS; } int get_iface_ip(char *iface, struct in_addr *ip) { int sock; struct ifreq ifr; memset(&ifr, 0, sizeof(struct ifreq)); sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { log_fatal("get-iface-ip", "failure opening socket: %s", strerror(errno)); } ifr.ifr_addr.sa_family = AF_INET; strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1); if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) { close(sock); log_fatal( "get-iface-ip", "Unable to automatically identify the correct " "source address for %s interface. ioctl failure: %s. " "If this is the unexpected interface, you can manually specify " "the correct interface with \"-i\" flag. If this is the correct " "interface, you likely need to manually specify the source IP " "address to use with the \"-S\" flag.", iface, strerror(errno)); } ip->s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; close(sock); return EXIT_SUCCESS; } int get_iface_hw_addr(char *iface, unsigned char *hw_mac) { int s; struct ifreq buffer; // Load the hwaddr from a dummy socket s = socket(PF_INET, SOCK_DGRAM, 0); if (s < 0) { log_error("get_iface_hw_addr", "Unable to open socket: %s", strerror(errno)); return EXIT_FAILURE; } memset(&buffer, 0, sizeof(buffer)); strncpy(buffer.ifr_name, iface, IFNAMSIZ); ioctl(s, SIOCGIFHWADDR, &buffer); close(s); memcpy(hw_mac, buffer.ifr_hwaddr.sa_data, 6); return EXIT_SUCCESS; } #endif /* ZMAP_GET_GATEWAY_LINUX_H */ zmap-4.3.4/src/get_gateway.c000066400000000000000000000013561501046211500157240ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/logger.h" #include "../lib/xalloc.h" #include #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ defined(__DragonFly__) #include "get_gateway-bsd.h" #else // (linux) #include "get_gateway-linux.h" #endif zmap-4.3.4/src/get_gateway.h000066400000000000000000000012011501046211500157160ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef GET_GATEWAY_H #define GET_GATEWAY_H #include int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac); int get_default_gw(struct in_addr *gw, char *iface); int get_iface_ip(char *iface, struct in_addr *ip); int get_iface_hw_addr(char *iface, unsigned char *hw_mac); char *get_default_iface(void); #endif zmap-4.3.4/src/if-netmap-bsd.c000066400000000000000000000062071501046211500160520ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef __FreeBSD__ #error "NETMAP requires FreeBSD or Linux" #endif #include "if-netmap.h" #include "../lib/includes.h" #include "../lib/logger.h" #include #include #include #include #include #include #include static void fetch_if_data(struct if_data *ifd, char const *ifname, int fd) { struct ifreq ifr; bzero(&ifr, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)ifd; if (ioctl(fd, SIOCGIFDATA, &ifr) == -1) { log_fatal("if-netmap-bsd", "unable to retrieve if_data: %d: %s", errno, strerror(errno)); } } void if_wait_for_phy_reset(char const *ifname, int fd) { struct if_data ifd; bzero(&ifd, sizeof(ifd)); for (size_t i = 0; i < 40 /* 10s */; i++) { fetch_if_data(&ifd, ifname, fd); if (ifd.ifi_link_state == LINK_STATE_UP) { return; } usleep(250000); } log_fatal("if-netmap-bsd", "timeout waiting for PHY reset to complete"); } size_t if_get_data_link_size(char const *ifname, int fd) { struct if_data ifd; bzero(&ifd, sizeof(ifd)); fetch_if_data(&ifd, ifname, fd); switch (ifd.ifi_type) { case IFT_ETHER: log_debug("if-netmap-bsd", "IFT_ETHER"); return sizeof(struct ether_header); default: log_fatal("if-netmap-bsd", "Unsupported if type %u", ifd.ifi_type); } } // Notes on if counters: // On interfaces without hardware counters (HWSTATS), ipackets misses // packets that we do not forward to the host ring pair. // oqdrops counts packets the host OS could not send due to netmap mode. struct if_stats_ctx { char *ifname; // owned int fd; // borrowed bool hwstats; uint64_t ifi_ipackets; uint64_t ifi_iqdrops; uint64_t ifi_ierrors; uint64_t ifi_oerrors; }; if_stats_ctx_t * if_stats_init(char const *ifname, int fd) { if_stats_ctx_t *ctx = malloc(sizeof(struct if_stats_ctx)); bzero(ctx, sizeof(struct if_stats_ctx)); ctx->ifname = strdup(ifname); ctx->fd = fd; struct if_data ifd; bzero(&ifd, sizeof(ifd)); fetch_if_data(&ifd, ctx->ifname, ctx->fd); ctx->hwstats = (ifd.ifi_hwassist & IFCAP_HWSTATS) != 0; if (ctx->hwstats) { ctx->ifi_ipackets = ifd.ifi_ipackets; } else { ctx->ifi_ipackets = 0; } ctx->ifi_iqdrops = ifd.ifi_iqdrops; ctx->ifi_ierrors = ifd.ifi_ierrors; ctx->ifi_oerrors = ifd.ifi_oerrors; return ctx; } void if_stats_fini(if_stats_ctx_t *ctx) { free(ctx->ifname); free(ctx); } bool if_stats_have_recv_ctr(if_stats_ctx_t *ctx) { return ctx->hwstats; } int if_stats_get(if_stats_ctx_t *ctx, uint64_t *ps_recv, uint64_t *ps_drop, uint64_t *ps_ifdrop) { struct if_data ifd; bzero(&ifd, sizeof(ifd)); fetch_if_data(&ifd, ctx->ifname, ctx->fd); if (ctx->hwstats) { *ps_recv = ifd.ifi_ipackets - ctx->ifi_ipackets; } *ps_drop = ifd.ifi_iqdrops - ctx->ifi_iqdrops; *ps_ifdrop = ifd.ifi_ierrors - ctx->ifi_ierrors + ifd.ifi_oerrors - ctx->ifi_oerrors; return 0; } zmap-4.3.4/src/if-netmap-linux.c000066400000000000000000000140151501046211500164350ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "if-netmap.h" #include "../lib/includes.h" #include "../lib/logger.h" #include "utility.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int nlrt_socket(void) { int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd == -1) { log_fatal("if-netmap-linux", "socket(NETLINK_ROUTE): %d: %s", errno, strerror(errno)); } int one = 1; (void)setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one)); struct sockaddr_nl sanl; memset(&sanl, 0, sizeof(sanl)); sanl.nl_family = AF_NETLINK; if (bind(fd, (struct sockaddr *)&sanl, sizeof(sanl)) == -1) { log_fatal("if-netmap-linux", "bind(AF_NETLINK): %d: %s", errno, strerror(errno)); } return fd; } static void fetch_stats64(struct rtnl_link_stats64 *rtlstats64, char const *ifname, int nlrtfd) { struct { struct nlmsghdr nlh; struct if_stats_msg ifsm; } nlreq; memset(&nlreq, 0, sizeof(nlreq)); nlreq.nlh.nlmsg_len = sizeof(nlreq); nlreq.nlh.nlmsg_type = RTM_GETSTATS; nlreq.nlh.nlmsg_flags = NLM_F_REQUEST; nlreq.ifsm.ifindex = if_nametoindex(ifname); nlreq.ifsm.filter_mask = IFLA_STATS_LINK_64; struct iovec iov[2]; memset(&iov[0], 0, sizeof(iov[0])); iov[0].iov_base = (void *)&nlreq; iov[0].iov_len = sizeof(nlreq); struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iov[0]; msg.msg_iovlen = 1; if (sendmsg(nlrtfd, &msg, 0) == -1) { log_fatal("if-netmap-linux", "sendmsg(RTM_GETSTATS): %d: %s", errno, strerror(errno)); } struct nlresp { struct nlmsghdr nlh; union { struct { struct rtmsg rth; struct rtnl_link_stats64 rtlstats64; } ans; struct { struct nlmsgerr nlerr; } err; } u; } nlresp; static_assert(sizeof(nlresp.u.ans) >= sizeof(nlresp.u.err), "ans is at least as large as err"); static const size_t ans_size = offsetof(struct nlresp, u.ans) + sizeof(nlresp.u.ans); static const size_t err_size = offsetof(struct nlresp, u.err) + sizeof(nlresp.u.err); memset(iov, 0, sizeof(iov)); iov[0].iov_base = (void *)&nlresp; iov[0].iov_len = offsetof(struct nlresp, u.ans.rtlstats64); iov[1].iov_base = (void *)rtlstats64; // caller-provided iov[1].iov_len = sizeof(struct rtnl_link_stats64); memset(&msg, 0, sizeof(msg)); msg.msg_iov = iov; msg.msg_iovlen = 2; ssize_t n = recvmsg(nlrtfd, &msg, 0); if (n == -1) { log_fatal("if-netmap-linux", "recvmsg(RTM_GETSTATS): %d: %s", errno, strerror(errno)); } if ((size_t)n < err_size) { log_fatal("if-netmap-linux", "received %zu expected %zu or larger", (size_t)n, err_size); } if (nlresp.nlh.nlmsg_type == NLMSG_ERROR) { // copy second iov into ans in first iov to get contiguous struct nlmsgerr nlresp.u.ans.rtlstats64 = *rtlstats64; assert(nlresp.u.err.nlerr.error < 0); errno = -nlresp.u.err.nlerr.error; log_fatal("if-netmap-linux", "received NLMSG_ERROR: %d: %s", errno, strerror(errno)); } if (nlresp.nlh.nlmsg_type != RTM_NEWSTATS) { log_fatal("if-netmap-linux", "received unexpected nlmsg_type %u", nlresp.nlh.nlmsg_type); } if ((size_t)n != ans_size) { log_fatal("if-netmap-linux", "received %zu expected %zu", (size_t)n, ans_size); } } void if_wait_for_phy_reset(char const *ifname, int fd) { // clobber deliberately fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (fd == -1) { log_fatal("if-netmap-linux", "socket(AF_INET): %d: %s", errno, strerror(errno)); } for (size_t i = 0; i < 40 /* 10s */; i++) { struct ifreq ifr; cross_platform_strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1); struct ethtool_value etv; etv.cmd = ETHTOOL_GLINK; ifr.ifr_data = (void *)&etv; if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) { log_fatal("if-netmap-linux", "ioctl(SIOCETHTOOL): %d: %s", errno, strerror(errno)); } if (etv.data != 0 /* carrier */) { close(fd); return; } usleep(250000); } log_fatal("if-netmap-linux", "timeout waiting for PHY reset to complete"); } size_t if_get_data_link_size(UNUSED char const *ifname, UNUSED int fd) { // Assuming Ethernet is not entirely unreasonable, as that's // the only thing we support on the send path anyway. // TODO figure out actual link type or link header size return sizeof(struct ether_header); } struct if_stats_ctx { char *ifname; // owned int nlrtfd; // owned // uint64_t rx_packets; uint64_t rx_dropped; uint64_t rx_errors; uint64_t tx_errors; }; if_stats_ctx_t * if_stats_init(char const *ifname, UNUSED int fd) { if_stats_ctx_t *ctx = malloc(sizeof(struct if_stats_ctx)); memset(ctx, 0, sizeof(struct if_stats_ctx)); ctx->ifname = strdup(ifname); ctx->nlrtfd = nlrt_socket(); struct rtnl_link_stats64 rtlstats64; memset(&rtlstats64, 0, sizeof(rtlstats64)); fetch_stats64(&rtlstats64, ctx->ifname, ctx->nlrtfd); //ctx->rx_packets = rtlstats64.rx_packets; ctx->rx_dropped = rtlstats64.rx_dropped; ctx->rx_errors = rtlstats64.rx_errors; ctx->tx_errors = rtlstats64.tx_errors; return ctx; } void if_stats_fini(if_stats_ctx_t *ctx) { free(ctx->ifname); close(ctx->nlrtfd); free(ctx); } bool if_stats_have_recv_ctr(UNUSED if_stats_ctx_t *ctx) { return false; } int if_stats_get(if_stats_ctx_t *ctx, UNUSED uint64_t *ps_recv, uint64_t *ps_drop, uint64_t *ps_ifdrop) { struct rtnl_link_stats64 rtlstats64; memset(&rtlstats64, 0, sizeof(rtlstats64)); fetch_stats64(&rtlstats64, ctx->ifname, ctx->nlrtfd); //*ps_recv = rtlstats64.rx_packets - ctx->rx_packets; *ps_drop = rtlstats64.rx_dropped - ctx->rx_dropped; *ps_ifdrop = rtlstats64.rx_errors - ctx->rx_errors + rtlstats64.tx_errors - ctx->tx_errors; return 0; } zmap-4.3.4/src/if-netmap.h000066400000000000000000000041041501046211500153030ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_IF_NETMAP_H #define ZMAP_IF_NETMAP_H // Platform-specific functionality required for NETMAP. #include #include #include // Wait until a NICs PHY has reset and the interface is ready for sending // packets again. Must be called after the reset has begun. Upon return, the // interface is ready for sending packets. Exits on timeout. // // *ifname* is the name of the interface. // *fd* is the file descriptor to the main netmap socket. void if_wait_for_phy_reset(char const *ifname, int fd); // Get the size of the link layer header for the interface. // // *ifname* is the name of the interface. // *fd* is the file descriptor to the main netmap socket. size_t if_get_data_link_size(char const *ifname, int fd); // Opaque context for the if_stats_* set of functions. struct if_stats_ctx; typedef struct if_stats_ctx if_stats_ctx_t; // Initialise interface statistics. // // *ifname* is the name of the interface. // *fd* is the file descriptor to the netmap socket used for recv. if_stats_ctx_t *if_stats_init(char const *ifname, int fd); // Returns true if the count of received packets is available // through if_stats_get(), false otherwise. If this returns // false, the caller will need to count received packets. bool if_stats_have_recv_ctr(if_stats_ctx_t *ctx); // Get recv, drop and ifdrop counters. // Some interfaces do not report any received packets while in // netmap mode. In that case, *ps_recv* will not be set. // Check if_stats_have_recv_ctr() for whether the interface // supports received packet count in netmap mode. int if_stats_get(if_stats_ctx_t *ctx, uint64_t *ps_recv, uint64_t *ps_drop, uint64_t *ps_ifdrop); // Clean up and invalidate the if_stats_* context. void if_stats_fini(if_stats_ctx_t *ctx); #endif /* ZMAP_IF_NETMAP_H */ zmap-4.3.4/src/iterator.c000066400000000000000000000102021501046211500152430ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include "../lib/includes.h" #include "../lib/blocklist.h" #include "../lib/logger.h" #include "../lib/xalloc.h" #include "../lib/util.h" #include "iterator.h" #include "aesrand.h" #include "shard.h" #include "state.h" struct iterator { cycle_t cycle; uint8_t num_threads; shard_t *thread_shards; uint8_t *complete; pthread_mutex_t mutex; uint32_t curr_threads; }; void shard_complete(uint8_t thread_id, void *arg) { iterator_t *it = (iterator_t *)arg; assert(thread_id < it->num_threads); pthread_mutex_lock(&it->mutex); it->complete[thread_id] = 1; it->curr_threads--; shard_t *s = &it->thread_shards[thread_id]; zsend.packets_sent += s->state.packets_sent; zsend.targets_scanned += s->state.targets_scanned; zsend.sendto_failures += s->state.packets_failed; uint8_t done = 1; for (uint8_t i = 0; done && (i < it->num_threads); ++i) { done = done && it->complete[i]; } if (done) { zsend.finish = now(); zsend.complete = 1; zsend.first_scanned = it->thread_shards[0].state.first_scanned; } pthread_mutex_unlock(&it->mutex); } static uint64_t bits_needed(uint64_t n) { n -= 1; int r = 0; while (n) { r++; n >>= 1; } return r; } iterator_t *iterator_init(uint8_t num_threads, uint16_t shard, uint16_t num_shards, uint64_t num_addrs, uint32_t num_ports) { uint8_t bits_for_ip = bits_needed(num_addrs); log_debug("iterator", "bits needed for %u addresses: %u", num_addrs, bits_for_ip); uint8_t bits_for_port = bits_needed(num_ports); log_debug("iterator", "bits needed for %u ports: %u", num_ports, bits_for_port); uint64_t group_min_size = ((uint64_t)1) << (bits_for_ip + bits_for_port); log_debug("iterator", "minimum elements to iterate over: %llu", group_min_size); iterator_t *it = xmalloc(sizeof(struct iterator)); const cyclic_group_t *group = get_group(group_min_size); if (num_addrs > (1LL << 32)) { zsend.max_ip_index = 0xFFFFFFFF; } else { zsend.max_ip_index = (uint32_t)num_addrs; } log_debug("iterator", "max ip index %ul", zsend.max_ip_index); // The candidate is upper-bounded by the modulus of the group, which is the prime number chosen in cyclic.c. // All primes are chosen to be greater than the number of allowed targets. // We must re-roll if the candidate target is out of bounds of (2 ** 32) * (2 ** number of ports). zsend.max_target_index = 1ULL << (32 + bits_for_port); log_debug("iterator", "max target index %ull", zsend.max_target_index); it->cycle = make_cycle(group, zconf.aes); it->num_threads = num_threads; it->curr_threads = num_threads; it->thread_shards = xcalloc(num_threads, sizeof(shard_t)); it->complete = xcalloc(it->num_threads, sizeof(uint8_t)); pthread_mutex_init(&it->mutex, NULL); log_debug("iterator", "max targets is %u", zsend.max_targets); for (uint8_t i = 0; i < num_threads; ++i) { shard_init(&it->thread_shards[i], shard, num_shards, i, num_threads, zsend.max_targets, bits_for_port, &it->cycle, shard_complete, it); } zconf.generator = it->cycle.generator; return it; } uint64_t iterator_get_sent(iterator_t *it) { uint64_t sent = 0; for (uint8_t i = 0; i < it->num_threads; ++i) { sent += it->thread_shards[i].state.packets_sent; } return sent; } uint64_t iterator_get_iterations(iterator_t *it) { uint64_t iterations = 0; for (uint8_t i = 0; i < it->num_threads; ++i) { iterations += it->thread_shards[i].iterations; } return iterations; } uint32_t iterator_get_fail(iterator_t *it) { uint32_t fails = 0; for (uint8_t i = 0; i < it->num_threads; ++i) { fails += it->thread_shards[i].state.packets_failed; } return fails; } shard_t *get_shard(iterator_t *it, uint8_t thread_id) { assert(thread_id < it->num_threads); return &it->thread_shards[thread_id]; } uint32_t iterator_get_curr_send_threads(iterator_t *it) { assert(it); return it->curr_threads; } zmap-4.3.4/src/iterator.h000066400000000000000000000016151501046211500152600ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_ITERATOR_H #define ZMAP_ITERATOR_H #include #include "../lib/includes.h" #include "aesrand.h" #include "cyclic.h" #include "shard.h" typedef struct iterator iterator_t; iterator_t *iterator_init(uint8_t num_threads, uint16_t shard, uint16_t num_shards, uint64_t num_addrs, uint32_t num_ports); uint64_t iterator_get_sent(iterator_t *it); uint64_t iterator_get_iterations(iterator_t *it); uint32_t iterator_get_fail(iterator_t *it); uint32_t iterator_get_curr_send_threads(iterator_t *it); shard_t *get_shard(iterator_t *it, uint8_t thread_id); #endif /* ZMAP_ITERATOR_H */ zmap-4.3.4/src/lexer.l000066400000000000000000000020751501046211500145530ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ %{ #pragma GCC diagnostic ignored "-Wredundant-decls" #pragma GCC diagnostic ignored "-Wmissing-noreturn" #include #include "parser.h" %} %option noinput %option nounput %% [0-9]+ yylval.int_literal = (uint64_t) atoll(yytext); return T_NUMBER; \n /* Ignore end of line */ [ \t]+ /* Ignore whitespace */ != return T_NOT_EQ; >= return T_GT_EQ; "<=" return T_LT_EQ; && return T_AND; "||" return T_OR; = return '='; ">" return '>'; "<" return '<'; "(" return '('; ")" return ')'; [a-zA-Z][-_a-zA-Z0-9]+ yylval.string_literal = strdup(yytext); return T_FIELD; %% zmap-4.3.4/src/monitor.c000066400000000000000000000372671501046211500151250ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ // module responsible for printing on-screen updates during the scan process #include "monitor.h" #define __STDC_FORMAT_MACROS #include #include #include #include #include #include #include #include #include #include #include #include "../lib/lockfd.h" #include "../lib/logger.h" #include "../lib/util.h" #include "../lib/xalloc.h" #include "blocklist.h" #include "iterator.h" #include "recv.h" #include "state.h" #define UPDATE_INTERVAL 1 // seconds #define NUMBER_STR_LEN 20 #define WARMUP_PERIOD 5 #define MIN_HITRATE_TIME_WINDOW 5 // seconds // internal monitor status that is used to track deltas typedef struct internal_scan_status { double last_now; uint64_t last_sent; uint64_t last_tried_sent; uint64_t last_send_failures; uint64_t last_recv_net_success; uint64_t last_recv_app_success; uint64_t last_recv_total; uint64_t last_pcap_drop; double min_hitrate_start; } int_status_t; // exportable status information that can be printed to screen typedef struct export_scan_status { uint64_t total_sent; uint64_t total_tried_sent; uint64_t recv_success_unique; uint64_t app_recv_success_unique; uint64_t total_recv; uint64_t complete; uint32_t send_threads; double percent_complete; double hitrate; // network, e.g. SYN-ACK vs RST double app_hitrate; // application level, e.g. DNS response versus correct // lookup. double send_rate; char send_rate_str[NUMBER_STR_LEN]; double send_rate_avg; char send_rate_avg_str[NUMBER_STR_LEN]; double recv_rate; char recv_rate_str[NUMBER_STR_LEN]; double recv_avg; char recv_avg_str[NUMBER_STR_LEN]; double recv_total_rate; double recv_total_avg; double app_success_rate; char app_success_rate_str[NUMBER_STR_LEN]; double app_success_avg; char app_success_avg_str[NUMBER_STR_LEN]; uint64_t pcap_drop; uint64_t pcap_ifdrop; uint64_t pcap_drop_total; char pcap_drop_total_str[NUMBER_STR_LEN]; double pcap_drop_last; char pcap_drop_last_str[NUMBER_STR_LEN]; double pcap_drop_avg; char pcap_drop_avg_str[NUMBER_STR_LEN]; uint32_t time_remaining; char time_remaining_str[NUMBER_STR_LEN]; uint32_t time_past; char time_past_str[NUMBER_STR_LEN]; uint64_t fail_total; double fail_avg; double fail_last; float seconds_under_min_hitrate; } export_status_t; static FILE *status_fd = NULL; // find minimum of an array of doubles static double min_d(double array[], int n) { double value = INFINITY; for (int i = 0; i < n; i++) { if (array[i] < value) { value = array[i]; } } return value; } // estimate time remaining time based on config and state double compute_remaining_time(double age, uint64_t packets_sent, uint64_t iterations) { if (!zsend.complete) { double remaining[] = {INFINITY, INFINITY, INFINITY, INFINITY, INFINITY}; if (zsend.list_of_ips_pbm) { // Estimate progress using group iterations double done = (double)iterations / ((uint64_t)0xFFFFFFFFU / zconf.total_shards); remaining[0] = (1. - done) * (age / done) + zconf.cooldown_secs; } if (zsend.max_targets) { double done = (double)packets_sent / ((uint64_t)zsend.max_targets * zconf.packet_streams / zconf.total_shards); remaining[1] = (1. - done) * (age / done) + zconf.cooldown_secs; } if (zconf.max_runtime) { remaining[2] = (zconf.max_runtime - age) + zconf.cooldown_secs; } if (zconf.max_results) { double done = (double)zrecv.filter_success / zconf.max_results; remaining[3] = (1. - done) * (age / done); } if (zsend.max_ip_index) { double done = (double)packets_sent / ((uint64_t)zsend.max_ip_index * zconf.ports->port_count * zconf.packet_streams / zconf.total_shards); remaining[4] = (1. - done) * (age / done) + zconf.cooldown_secs; } double remaining_time = min_d(remaining, sizeof(remaining) / sizeof(double)); if (remaining_time < 0) { // remaining time cannot be less than zero return 0; } return remaining_time; } else { double remaining_time = zconf.cooldown_secs - (now() - zsend.finish); if (remaining_time < 0) { // remaining time cannot be less than zero return 0; } return remaining_time; } } static void update_pcap_stats(pthread_mutex_t *recv_ready_mutex) { // ask pcap for fresh values pthread_mutex_lock(recv_ready_mutex); recv_update_stats(); pthread_mutex_unlock(recv_ready_mutex); } static void export_stats(int_status_t *intrnl, export_status_t *exp, iterator_t *it) { uint64_t total_sent = iterator_get_sent(it); uint64_t total_iterations = iterator_get_iterations(it); uint32_t total_fail = iterator_get_fail(it); uint64_t total_recv = zrecv.pcap_recv; uint64_t recv_success = zrecv.success_unique; uint32_t app_success = zrecv.app_success_unique; double cur_time = now(); double age = cur_time - zsend.start; // time of entire scan // time since the last time we updated double delta = cur_time - intrnl->last_now; double remaining_secs = compute_remaining_time(age, total_sent, total_iterations); // export amount of time the scan has been running if (age < WARMUP_PERIOD) { exp->time_remaining_str[0] = '\0'; } else { char buf[20]; time_string(ceil(remaining_secs), 1, buf, sizeof(buf)); snprintf(exp->time_remaining_str, NUMBER_STR_LEN, " (%s left)", buf); } exp->time_past = age; exp->time_remaining = remaining_secs; time_string((int)age, 0, exp->time_past_str, NUMBER_STR_LEN); // export recv statistics exp->recv_rate = ceil((recv_success - intrnl->last_recv_net_success) / delta); number_string(exp->recv_rate, exp->recv_rate_str, NUMBER_STR_LEN); exp->recv_avg = recv_success / age; number_string(exp->recv_avg, exp->recv_avg_str, NUMBER_STR_LEN); exp->recv_total_rate = (total_recv - intrnl->last_recv_total) / delta; exp->recv_total_avg = total_recv / age; // application level statistics if (zconf.fsconf.app_success_index >= 0) { exp->app_success_rate = (app_success - intrnl->last_recv_app_success) / delta; number_string(exp->app_success_rate, exp->app_success_rate_str, NUMBER_STR_LEN); exp->app_success_avg = (app_success / age); number_string(exp->app_success_avg, exp->app_success_avg_str, NUMBER_STR_LEN); } if (!total_sent) { exp->hitrate = 0; exp->app_hitrate = 0; } else if (zconf.dedup_method == DEDUP_METHOD_NONE) { // receive thread won't de-dupe packets, so don't need to care about number of probes exp->hitrate = recv_success * 100.0 / total_sent; exp->app_hitrate = app_success * 100.0 / total_sent; } else { // receive thread will de-dupe packets for a given target, so we'll divide by the number of probes to get accurate hit-rate exp->hitrate = recv_success * 100.0 / (total_sent / zconf.packet_streams); exp->app_hitrate = app_success * 100.0 / (total_sent / zconf.packet_streams); } if (age > WARMUP_PERIOD && exp->hitrate < zconf.min_hitrate) { if (fabs(intrnl->min_hitrate_start) < .00001) { intrnl->min_hitrate_start = cur_time; } } else { intrnl->min_hitrate_start = 0.0; } if (fabs(intrnl->min_hitrate_start) < .00001) { exp->seconds_under_min_hitrate = 0; } else { exp->seconds_under_min_hitrate = cur_time - intrnl->min_hitrate_start; } if (!zsend.complete) { exp->send_rate = ceil((total_sent - intrnl->last_sent) / delta); number_string(exp->send_rate, exp->send_rate_str, NUMBER_STR_LEN); exp->send_rate_avg = total_sent / age; number_string(exp->send_rate_avg, exp->send_rate_avg_str, NUMBER_STR_LEN); } else { exp->send_rate_avg = total_sent / (zsend.finish - zsend.start); number_string(exp->send_rate_avg, exp->send_rate_avg_str, NUMBER_STR_LEN); } // export other pre-calculated values exp->total_sent = total_sent; exp->total_tried_sent = total_iterations; exp->percent_complete = 100. * age / (age + remaining_secs); exp->recv_success_unique = recv_success; exp->app_recv_success_unique = app_success; exp->total_recv = total_recv; exp->complete = zsend.complete; // pcap dropped packets exp->pcap_drop = zrecv.pcap_drop; exp->pcap_ifdrop = zrecv.pcap_ifdrop; exp->pcap_drop_total = exp->pcap_drop + exp->pcap_ifdrop; exp->pcap_drop_last = (exp->pcap_drop_total - intrnl->last_pcap_drop) / delta; exp->pcap_drop_avg = exp->pcap_drop_total / age; number_string(exp->pcap_drop_total, exp->pcap_drop_total_str, NUMBER_STR_LEN); number_string(exp->pcap_drop_last, exp->pcap_drop_last_str, NUMBER_STR_LEN); number_string(exp->pcap_drop_avg, exp->pcap_drop_avg_str, NUMBER_STR_LEN); zsend.sendto_failures = total_fail; exp->fail_total = zsend.sendto_failures; exp->fail_last = (exp->fail_total - intrnl->last_send_failures) / delta; exp->fail_avg = exp->fail_total / age; // misc exp->send_threads = iterator_get_curr_send_threads(it); // Update internal stats intrnl->last_now = cur_time; intrnl->last_sent = exp->total_sent; intrnl->last_recv_net_success = exp->recv_success_unique; intrnl->last_recv_app_success = exp->app_recv_success_unique; intrnl->last_pcap_drop = exp->pcap_drop_total; intrnl->last_send_failures = exp->fail_total; intrnl->last_recv_total = exp->total_recv; } static void log_drop_warnings(export_status_t *exp) { if (exp->pcap_drop_last / exp->recv_rate > 0.05) { log_warn("monitor", "Dropped %.0f packets in the last second, (%u total " "dropped (pcap: %u + iface: %u))", exp->pcap_drop_last, exp->pcap_drop_total, exp->pcap_drop, exp->pcap_ifdrop); } if (exp->fail_last / exp->send_rate > 0.01) { log_warn("monitor", "Failed to send %.0f packets/sec (%u total failures)", exp->fail_last, exp->fail_total); } } static void onscreen_appsuccess(export_status_t *exp) { // this when probe module handles application-level success rates if (!exp->complete) { fprintf(stderr, "%5s %0.0f%%%s; sent: %" PRIu64 " %sp/s (%sp/s avg); " "recv: %" PRIu64 " %sp/s (%sp/s avg); " "app success: %" PRIu64 " %sp/s (%sp/s avg); " "drops: %sp/s (%sp/s avg); " "hitrate: %0.2f%% " "app hitrate: %0.2f%%\n", exp->time_past_str, exp->percent_complete, exp->time_remaining_str, exp->total_sent, exp->send_rate_str, exp->send_rate_avg_str, exp->recv_success_unique, exp->recv_rate_str, exp->recv_avg_str, exp->app_recv_success_unique, exp->app_success_rate_str, exp->app_success_avg_str, exp->pcap_drop_last_str, exp->pcap_drop_avg_str, exp->hitrate, exp->app_hitrate); } else { fprintf(stderr, "%5s %0.0f%%%s; sent: %" PRIu64 " done (%sp/s avg); " "recv: %" PRIu64 " %sp/s (%sp/s avg); " "app success: %" PRIu64 " %sp/s (%sp/s avg); " "drops: %sp/s (%sp/s avg); " "hitrate: %0.2f%% " "app hitrate: %0.2f%%\n", exp->time_past_str, exp->percent_complete, exp->time_remaining_str, exp->total_sent, exp->send_rate_avg_str, exp->recv_success_unique, exp->recv_rate_str, exp->recv_avg_str, exp->app_recv_success_unique, exp->app_success_rate_str, exp->app_success_avg_str, exp->pcap_drop_last_str, exp->pcap_drop_avg_str, exp->hitrate, exp->app_hitrate); } } static void onscreen_generic(export_status_t *exp) { if (!exp->complete) { fprintf(stderr, "%5s %0.0f%%%s; send: %" PRIu64 " %sp/s (%sp/s avg); " "recv: %" PRIu64 " %sp/s (%sp/s avg); " "drops: %sp/s (%sp/s avg); " "hitrate: %0.2f%%\n", exp->time_past_str, exp->percent_complete, exp->time_remaining_str, exp->total_sent, exp->send_rate_str, exp->send_rate_avg_str, exp->recv_success_unique, exp->recv_rate_str, exp->recv_avg_str, exp->pcap_drop_last_str, exp->pcap_drop_avg_str, exp->hitrate); } else { fprintf(stderr, "%5s %0.0f%%%s; send: %" PRIu64 " done (%sp/s avg); " "recv: %" PRIu64 " %sp/s (%sp/s avg); " "drops: %sp/s (%sp/s avg); " "hitrate: %0.2f%%\n", exp->time_past_str, exp->percent_complete, exp->time_remaining_str, exp->total_sent, exp->send_rate_avg_str, exp->recv_success_unique, exp->recv_rate_str, exp->recv_avg_str, exp->pcap_drop_last_str, exp->pcap_drop_avg_str, exp->hitrate); } fflush(stderr); } static FILE *init_status_update_file(char *path) { FILE *f = fopen(path, "w"); if (!f) { log_fatal("csv", "could not open status updates file (%s): %s", zconf.status_updates_file, strerror(errno)); } log_debug("monitor", "status updates CSV will be saved to %s", zconf.status_updates_file); fprintf( f, "real-time,time-elapsed,time-remaining," "percent-complete,hit-rate,active-send-threads," "sent-total,sent-last-one-sec,sent-avg-per-sec," "recv-success-total,recv-success-last-one-sec,recv-success-avg-per-sec," "recv-total,recv-total-last-one-sec,recv-total-avg-per-sec," "pcap-drop-total,drop-last-one-sec,drop-avg-per-sec," "sendto-fail-total,sendto-fail-last-one-sec,sendto-fail-avg-per-sec\n"); fflush(f); return f; } static void update_status_updates_file(export_status_t *exp, FILE *f) { struct timeval now; char timestamp[256]; gettimeofday(&now, NULL); time_t sec = now.tv_sec; struct tm *ptm = localtime(&sec); strftime(timestamp, 20, "%Y-%m-%d %H:%M:%S", ptm); fprintf(f, "%s,%u,%u," "%f,%f,%u," "%" PRIu64 ",%.0f,%.0f," "%" PRIu64 ",%.0f,%.0f," "%" PRIu64 ",%.0f,%.0f," "%" PRIu64 ",%.0f,%.0f," "%" PRIu64 ",,%.0f,%.0f\n", timestamp, exp->time_past, exp->time_remaining, exp->percent_complete, exp->hitrate, exp->send_threads, exp->total_sent, exp->send_rate, exp->send_rate_avg, exp->recv_success_unique, exp->recv_rate, exp->recv_avg, exp->total_recv, exp->recv_total_rate, exp->recv_total_avg, exp->pcap_drop_total, exp->pcap_drop_last, exp->pcap_drop_avg, exp->fail_total, exp->fail_last, exp->fail_avg); fflush(f); } static inline void check_min_hitrate(export_status_t *exp) { if (exp->seconds_under_min_hitrate >= MIN_HITRATE_TIME_WINDOW) { log_fatal("monitor", "hitrate below %.0f for %.0f seconds. aborting scan.", zconf.min_hitrate, exp->seconds_under_min_hitrate); } } static inline void check_max_sendto_failures(export_status_t *exp) { if (zconf.max_sendto_failures >= 0 && exp->fail_total > (uint32_t)zconf.max_sendto_failures) { log_fatal("monitor", "maximum number of sendto failures (%i) exceeded", zconf.max_sendto_failures); } } void monitor_init(void) { if (zconf.status_updates_file) { status_fd = init_status_update_file(zconf.status_updates_file); assert(status_fd); } } void export_then_update(int_status_t *internal_status, iterator_t *it, export_status_t *export_status, pthread_mutex_t *lock) { update_pcap_stats(lock); export_stats(internal_status, export_status, it); log_drop_warnings(export_status); check_min_hitrate(export_status); check_max_sendto_failures(export_status); if (!zconf.quiet) { lock_file(stderr); if (zconf.fsconf.app_success_index >= 0) { onscreen_appsuccess(export_status); } else { onscreen_generic(export_status); } unlock_file(stderr); } if (status_fd) { update_status_updates_file(export_status, status_fd); } } void monitor_run(iterator_t *it, pthread_mutex_t *lock) { int_status_t *internal_status = xmalloc(sizeof(int_status_t)); export_status_t *export_status = xmalloc(sizeof(export_status_t)); // wait for the scanning process to finish while (!(zsend.complete && zrecv.complete)) { export_then_update(internal_status, it, export_status, lock); sleep(UPDATE_INTERVAL); } // final update export_then_update(internal_status, it, export_status, lock); if (!zconf.quiet) { lock_file(stderr); fflush(stderr); unlock_file(stderr); } if (status_fd) { fflush(status_fd); fclose(status_fd); } } zmap-4.3.4/src/monitor.h000066400000000000000000000007201501046211500151120ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include "iterator.h" #ifndef MONITOR_H #define MONITOR_H void monitor_run(iterator_t *it, pthread_mutex_t *lock); void monitor_init(void); #endif zmap-4.3.4/src/output_modules/000077500000000000000000000000001501046211500163435ustar00rootroot00000000000000zmap-4.3.4/src/output_modules/module_csv.c000066400000000000000000000063441501046211500206560ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include #include #include #include #include "../../lib/logger.h" #include "../fieldset.h" #include "output_modules.h" static FILE *file = NULL; int csv_init(struct state_conf *conf, const char **fields, int fieldlens) { assert(conf); if (conf->output_filename) { if (!strcmp(conf->output_filename, "-")) { file = stdout; } else { if (!(file = fopen(conf->output_filename, "w"))) { log_fatal( "csv", "could not open CSV output file (%s): %s", conf->output_filename, strerror(errno)); } } } else { file = stdout; log_debug("csv", "no output file selected, will use stdout"); } if (!conf->no_header_row) { log_debug("csv", "more than one field, will add headers"); for (int i = 0; i < fieldlens; i++) { if (i) { fprintf(file, ","); } fprintf(file, "%s", fields[i]); } fprintf(file, "\n"); } check_and_log_file_error(file, "csv"); return EXIT_SUCCESS; } int csv_close(__attribute__((unused)) struct state_conf *c, __attribute__((unused)) struct state_send *s, __attribute__((unused)) struct state_recv *r) { if (file) { fflush(file); fclose(file); } return EXIT_SUCCESS; } static void hex_encode(FILE *f, unsigned char *readbuf, size_t len) { for (size_t i = 0; i < len; i++) { fprintf(f, "%02x", readbuf[i]); } check_and_log_file_error(f, "csv"); } int csv_process(fieldset_t *fs) { if (!file) { return EXIT_SUCCESS; } for (int i = 0; i < fs->len; i++) { field_t *f = &(fs->fields[i]); if (i) { fprintf(file, ","); } if (f->type == FS_STRING) { if (strchr((char *)f->value.ptr, ',')) { fprintf(file, "\"%s\"", (char *)f->value.ptr); } else { fprintf(file, "%s", (char *)f->value.ptr); } } else if (f->type == FS_UINT64) { fprintf(file, "%" PRIu64, (uint64_t)f->value.num); } else if (f->type == FS_BOOL) { fprintf(file, "%" PRIi32, (int)f->value.num); } else if (f->type == FS_BINARY) { hex_encode(file, (unsigned char *)f->value.ptr, f->len); } else if (f->type == FS_NULL) { // do nothing } else { log_fatal("csv", "received unknown output type"); } } fprintf(file, "\n"); fflush(file); check_and_log_file_error(file, "csv"); return EXIT_SUCCESS; } output_module_t module_csv_file = { .name = "csv", .init = &csv_init, .start = NULL, .update = NULL, .update_interval = 0, .close = &csv_close, .process_ip = &csv_process, .supports_dynamic_output = NO_DYNAMIC_SUPPORT, .helptext = "Outputs one or more output fields as a comma-delimited file. By default, the " "probe module does not filter out duplicates or limit to successful fields, " "but rather includes all received packets. Fields can be controlled by " "setting --output-fields. Filtering out failures and duplicate packets can " "be achieved by setting an --output-filter."}; zmap-4.3.4/src/output_modules/module_csv.h000066400000000000000000000010221501046211500206470ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "../fieldset.h" #include "output_modules.h" int csv_init(struct state_conf *conf, char **fields, int fieldlens); int csv_process(fieldset_t *fs); int csv_close(struct state_conf *c, struct state_send *s, struct state_recv *r); zmap-4.3.4/src/output_modules/module_json.c000066400000000000000000000103031501046211500210220ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include #include "../../lib/includes.h" #include "../../lib/xalloc.h" #include #include #include #include #include #include #include #include #include "../../lib/logger.h" #include "output_modules.h" #include "../probe_modules/probe_modules.h" static FILE *file = NULL; int json_output_file_init(struct state_conf *conf, UNUSED const char **fields, UNUSED int fieldlens) { assert(conf); if (!conf->output_filename) { file = stdout; } else if (!strcmp(conf->output_filename, "-")) { file = stdout; } else { if (!(file = fopen(conf->output_filename, "w"))) { log_fatal("output-json", "could not open JSON output file (%s): %s", conf->output_filename, strerror(errno)); } } check_and_log_file_error(file, "json"); return EXIT_SUCCESS; } char *hex_encode(unsigned char *packet, int buflen) { char *buf = xmalloc(2 * buflen + 1); for (int i = 0; i < buflen; i++) { snprintf(buf + (i * 2), 3, "%.2x", packet[i]); } buf[buflen * 2] = 0; return buf; } json_object *fs_to_jsonobj(fieldset_t *fs); json_object *repeated_to_jsonobj(fieldset_t *fs); json_object *field_to_jsonobj(field_t *f) { if (f->type == FS_STRING) { return json_object_new_string((char *)f->value.ptr); } else if (f->type == FS_UINT64) { return json_object_new_int64(f->value.num); } else if (f->type == FS_BOOL) { return json_object_new_boolean(f->value.num); } else if (f->type == FS_BINARY) { char *encoded = hex_encode(f->value.ptr, f->len); json_object *t = json_object_new_string(encoded); free(encoded); return t; } else if (f->type == FS_NULL) { return NULL; } else if (f->type == FS_FIELDSET) { return fs_to_jsonobj((fieldset_t *)f->value.ptr); } else if (f->type == FS_REPEATED) { return repeated_to_jsonobj((fieldset_t *)f->value.ptr); } else { log_fatal("json", "received unknown output type: %i", f->type); } } json_object *repeated_to_jsonobj(fieldset_t *fs) { json_object *obj = json_object_new_array(); for (int i = 0; i < fs->len; i++) { field_t *f = &(fs->fields[i]); json_object_array_add(obj, field_to_jsonobj(f)); } return obj; } json_object *fs_to_jsonobj(fieldset_t *fs) { json_object *obj = json_object_new_object(); for (int i = 0; i < fs->len; i++) { field_t *f = &(fs->fields[i]); if (f->type != FS_NULL) { json_object_object_add(obj, f->name, field_to_jsonobj(f)); } } return obj; } int json_output_to_file(fieldset_t *fs) { if (!file) { return EXIT_SUCCESS; } json_object *record = fs_to_jsonobj(fs); fprintf(file, "%s\n", json_object_to_json_string_ext(record, JSON_C_TO_STRING_PLAIN)); fflush(file); check_and_log_file_error(file, "json"); json_object_put(record); return EXIT_SUCCESS; } int json_output_file_close(UNUSED struct state_conf *c, UNUSED struct state_send *s, UNUSED struct state_recv *r) { if (file) { fflush(file); fclose(file); } return EXIT_SUCCESS; } int print_json_fieldset(fieldset_t *fs) { json_object *record = fs_to_jsonobj(fs); fprintf(stdout, "%s\n", json_object_to_json_string(record)); json_object_put(record); return EXIT_SUCCESS; } output_module_t module_json_file = { .name = "json", .init = &json_output_file_init, .start = NULL, .update = NULL, .update_interval = 0, .close = &json_output_file_close, .process_ip = &json_output_to_file, .supports_dynamic_output = DYNAMIC_SUPPORT, .helptext = "Outputs one or more output fields as a json valid file. By default, the \n" "probe module does not filter out duplicates or limit to successful fields, \n" "but rather includes all received packets. Fields can be controlled by \n" "setting --output-fields. Filtering out failures and duplicate packets can \n" "be achieved by setting an --output-filter."}; zmap-4.3.4/src/output_modules/module_json.h000066400000000000000000000012571501046211500210370ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "fieldset.h" int print_json_fieldset(fieldset_t *fs); zmap-4.3.4/src/output_modules/output_modules.c000066400000000000000000000020311501046211500215730ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include "output_modules.h" extern output_module_t module_csv_file; extern output_module_t module_json_file; output_module_t *output_modules[] = { &module_csv_file, &module_json_file, // ADD YOUR MODULE HERE }; output_module_t *get_output_module_by_name(const char *name) { int num_modules = (int)(sizeof(output_modules) / sizeof(output_modules[0])); for (int i = 0; i < num_modules; i++) { if (!strcmp(output_modules[i]->name, name)) { return output_modules[i]; } } return NULL; } void print_output_modules(void) { int num_modules = (int)(sizeof(output_modules) / sizeof(output_modules[0])); for (int i = 0; i < num_modules; i++) { printf("%s\n", output_modules[i]->name); } } zmap-4.3.4/src/output_modules/output_modules.h000066400000000000000000000022651501046211500216110ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef OUTPUT_MODULES_H #define OUTPUT_MODULES_H #include "../state.h" #include "../fieldset.h" #define NO_DYNAMIC_SUPPORT 0 #define DYNAMIC_SUPPORT 1 // called at scanner initialization typedef int (*output_init_cb)(struct state_conf *, const char **fields, int fieldslen); // called on packet receipt typedef int (*output_packet_cb)(fieldset_t *fs); // called periodically during the scan typedef int (*output_update_cb)(struct state_conf *, struct state_send *, struct state_recv *); typedef struct output_module { const char *name; int supports_dynamic_output; unsigned update_interval; output_init_cb init; output_update_cb start; output_update_cb update; output_update_cb close; output_packet_cb process_ip; const char *helptext; } output_module_t; output_module_t *get_output_module_by_name(const char *); void print_output_modules(void); #endif // HEADER_OUTPUT_MODULES_H zmap-4.3.4/src/parser.y000066400000000000000000000042611501046211500147440ustar00rootroot00000000000000%{ #include #include #include "expression.h" #include "lexer.h" #include "filter.h" void yyerror(const char *str) { fprintf(stderr,"Parse error: %s\n",str); } int yywrap(void) { return 1; } extern node_t *zfilter; %} %union { int int_literal; char *string_literal; struct node_st *expr; } %token '(' ')' T_AND T_OR %token T_NUMBER %token T_FIELD %token T_NOT_EQ T_GT_EQ '>' '<' '=' T_LT_EQ %left T_OR %left T_AND %type filter %type number_filter %type string_filter %type filter_expr %% expression: filter_expr { zfilter = $1; } filter_expr: filter_expr T_OR filter_expr { $$ = make_op_node(OR); $$->left_child = $1; $$->right_child = $3; } | filter_expr T_AND filter_expr { $$ = make_op_node(AND); $$->left_child = $1; $$->right_child = $3; } | '(' filter_expr ')' { $$ = $2; } | filter { $$ = $1; } ; filter: number_filter { $$ = $1; } | string_filter { $$ = $1; } ; number_filter: T_FIELD '=' T_NUMBER { $$ = make_op_node(EQ); $$->left_child = make_field_node($1); $$->right_child = make_int_node($3); } | T_FIELD '>' T_NUMBER { $$ = make_op_node(GT); $$->left_child = make_field_node($1); $$->right_child = make_int_node($3); } | T_FIELD '<' T_NUMBER { $$ = make_op_node(LT); $$->left_child = make_field_node($1); $$->right_child = make_int_node($3); } | T_FIELD T_NOT_EQ T_NUMBER { $$ = make_op_node(NEQ); $$->left_child = make_field_node($1); $$->right_child = make_int_node($3); } | T_FIELD T_GT_EQ T_NUMBER { $$ = make_op_node(GT_EQ); $$->left_child = make_field_node($1); $$->right_child = make_int_node($3); } | T_FIELD T_LT_EQ T_NUMBER { $$ = make_op_node(LT_EQ); $$->left_child = make_field_node($1); $$->right_child = make_int_node($3); } ; string_filter: T_FIELD '=' T_FIELD { $$ = make_op_node(EQ); $$->left_child = make_field_node($1); $$->right_child = make_string_node($3); } | T_FIELD T_NOT_EQ T_FIELD { $$ = make_op_node(NEQ); $$->left_child = make_field_node($1); $$->right_child = make_string_node($3); } ; %% zmap-4.3.4/src/ports.c000066400000000000000000000033561501046211500145750ustar00rootroot00000000000000/* * ZMap Copyright 2023 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ /* * ZIterate is a simple utility that will iteratate over the IPv4 * space in a pseudo-random fashion, utilizing the sharding capabilities * of * ZMap. */ #define _GNU_SOURCE #include #include "state.h" #include "../lib/pbm.h" #include "../lib/logger.h" static void add_port(struct port_conf *ports, int port) { if (port < 0 || port > 0xFFFF) { log_fatal("ports", "invalid target port specified: %i", port); } ports->ports[ports->port_count] = port; if (ports->port_bitmap) { bm_set(ports->port_bitmap, port); } ports->port_count++; } void parse_ports(char *portdef, struct port_conf *ports) { if (!strcmp(portdef, "*")) { for (int i = 0; i <= 0xFFFF; i++) { add_port(ports, i); } return; } char *next = strtok(portdef, ","); while (next != NULL) { char *dash = strchr(next, '-'); if (dash) { // range *dash = '\0'; int first = atoi(next); int last = atoi(dash + 1); if (last > 0xFFFF) { log_fatal("ports", "invalid target port specified: %i", last); } if (first > last) { log_fatal("ports", "invalid target port range: %i-%i", first, last); } for (int i = first; i <= last; i++) { add_port(ports, i); } } else { add_port(ports, atoi(next)); } next = strtok(NULL, ","); } } zmap-4.3.4/src/ports.h000066400000000000000000000001161501046211500145710ustar00rootroot00000000000000#include "state.h" void parse_ports(char *portdef, struct port_conf *ports); zmap-4.3.4/src/probe_modules/000077500000000000000000000000001501046211500161125ustar00rootroot00000000000000zmap-4.3.4/src/probe_modules/module_bacnet.c000066400000000000000000000150201501046211500210550ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include #include "../../lib/includes.h" #include "packet.h" #include "probe_modules.h" #include "module_bacnet.h" #include "module_udp.h" #include "logger.h" #define ICMP_UNREACH_HEADER_SIZE 8 #define SOURCE_PORT_VALIDATION_MODULE_DEFAULT true; // default to validating source port static bool should_validate_src_port = SOURCE_PORT_VALIDATION_MODULE_DEFAULT #define ZMAP_BACNET_PACKET_LEN \ (sizeof(struct ether_header) + sizeof(struct ip) + \ sizeof(struct udphdr) + 0x11) probe_module_t module_bacnet; static int num_ports; static uint8_t bacnet_body[] = {0x0c, 0x02, 0x3f, 0xff, 0xff, 0x19, 0x4b}; #define BACNET_BODY_LEN 7 static inline uint8_t get_invoke_id(uint32_t *validation) { return (uint8_t)((validation[1] >> 24) & 0xFF); } int bacnet_init_perthread(void **arg) { uint32_t seed = aesrand_getword(zconf.aes); aesrand_t *aes = aesrand_init_from_seed(seed); *arg = aes; return EXIT_SUCCESS; } int bacnet_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg) { memset(buf, 0, MAX_PACKET_SIZE); struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct udphdr *udp_header = (struct udphdr *)(&ip_header[1]); struct bacnet_probe *bnp = (struct bacnet_probe *)&udp_header[1]; uint8_t *body = (uint8_t *)&bnp[1]; make_eth_header(eth_header, src, gw); uint16_t ip_len = sizeof(struct ip) + sizeof(struct udphdr) + 0x11; assert(ip_len <= MAX_PACKET_SIZE); make_ip_header(ip_header, IPPROTO_UDP, htons(ip_len)); uint16_t udp_len = sizeof(struct udphdr) + 0x11; make_udp_header(udp_header, udp_len); bnp->vlc.type = ZMAP_BACNET_TYPE_IP; bnp->vlc.function = ZMAP_BACNET_FUNCTION_UNICAST_NPDU; bnp->vlc.length = htons(0x11); bnp->npdu.version = ZMAP_BACNET_NPDU_VERSION_ASHRAE_135_1995; bnp->npdu.control = 0x04; bnp->apdu.type_flags = 0x00; bnp->apdu.max_segments_apdu = 0x05; bnp->apdu.server_choice = 0x0c; memcpy(body, bacnet_body, BACNET_BODY_LEN); return EXIT_SUCCESS; } int bacnet_make_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dport, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, UNUSED void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct udphdr *udp_header = (struct udphdr *)&ip_header[1]; struct bacnet_probe *bnp = (struct bacnet_probe *)&udp_header[1]; ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_ttl = ttl; ip_header->ip_sum = 0; ip_header->ip_id = ip_id; udp_header->uh_sport = htons(get_src_port(num_ports, probe_num, validation)); udp_header->uh_dport = dport; bnp->apdu.invoke_id = get_invoke_id(validation); ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); *buf_len = ZMAP_BACNET_PACKET_LEN; return EXIT_SUCCESS; } int bacnet_validate_packet(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, const struct port_conf *ports) { // this will reject packets that aren't UDP or ICMP and fully process ICMP packets if (udp_do_validate_packet(ip_hdr, len, src_ip, validation, num_ports, should_validate_src_port, ports) == PACKET_INVALID) { return PACKET_INVALID; } if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp = get_udp_header(ip_hdr, len); if (!udp) { return PACKET_INVALID; } const size_t min_len = sizeof(struct udphdr) + sizeof(struct bacnet_vlc); if (udp->uh_ulen < min_len) { return PACKET_INVALID; } struct bacnet_vlc *vlc = (struct bacnet_vlc *)get_udp_payload(udp, len); if (vlc->type != ZMAP_BACNET_TYPE_IP) { return PACKET_INVALID; } } return PACKET_VALID; } void bacnet_process_packet(const u_char *packet, uint32_t len, fieldset_t *fs, UNUSED uint32_t *validation, UNUSED struct timespec ts) { struct ip *ip_hdr = get_ip_header(packet, len); assert(ip_hdr); if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp = get_udp_header(ip_hdr, len); assert(udp); fs_add_uint64(fs, "sport", ntohs(udp->uh_sport)); fs_add_uint64(fs, "dport", ntohs(udp->uh_dport)); fs_add_constchar(fs, "classification", "bacnet"); fs_add_bool(fs, "success", 1); fs_add_null_icmp(fs); uint32_t udp_offset = sizeof(struct ether_header) + ip_hdr->ip_hl * 4; uint32_t payload_offset = udp_offset + sizeof(struct udphdr); assert(payload_offset < len); uint8_t *payload = get_udp_payload(udp, len); uint32_t payload_len = len - payload_offset; fs_add_binary(fs, "udp_payload", payload_len, (void *)payload, 0); fs_add_null_icmp(fs); } else if (ip_hdr->ip_p == IPPROTO_ICMP) { fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_constchar(fs, "classification", "icmp"); fs_add_bool(fs, "success", 0); fs_add_null(fs, "udp_payload"); fs_populate_icmp_from_iphdr(ip_hdr, len, fs); } } int bacnet_global_initialize(struct state_conf *conf) { num_ports = conf->source_port_last - conf->source_port_first + 1; if (conf->validate_source_port_override == VALIDATE_SRC_PORT_DISABLE_OVERRIDE) { log_debug("bacnet", "disabling source port validation"); should_validate_src_port = false; } return EXIT_SUCCESS; } static fielddef_t fields[] = { {.name = "sport", .type = "int", .desc = "UDP source port"}, {.name = "dport", .type = "int", .desc = "UDP destination port"}, CLASSIFICATION_SUCCESS_FIELDSET_FIELDS, {.name = "udp_payload", .type = "binary", .desc = "UDP payload"}, ICMP_FIELDSET_FIELDS, }; probe_module_t module_bacnet = {.name = "bacnet", .max_packet_length = ZMAP_BACNET_PACKET_LEN, .pcap_filter = "udp || icmp", .pcap_snaplen = 1500, .port_args = 1, .global_initialize = &bacnet_global_initialize, .thread_initialize = &bacnet_init_perthread, .prepare_packet = &bacnet_prepare_packet, .make_packet = &bacnet_make_packet, .print_packet = &udp_print_packet, .validate_packet = &bacnet_validate_packet, .process_packet = &bacnet_process_packet, .close = &udp_global_cleanup, .output_type = OUTPUT_TYPE_STATIC, .fields = fields, .numfields = sizeof(fields) / sizeof(fields[0])}; zmap-4.3.4/src/probe_modules/module_bacnet.h000066400000000000000000000026121501046211500210650ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_MODULE_BACNET_H #define ZMAP_MODULE_BACNET_H #include #include #include #include #include #include "probe_modules.h" extern probe_module_t module_bacnet; struct __attribute__((__packed__)) bacnet_vlc { uint8_t type; uint8_t function; uint16_t length; }; typedef struct bacnet_vlc bacnet_vlc_t; struct __attribute__((__packed__)) bacnet_npdu { uint8_t version; uint8_t control; }; typedef struct bacnet_npdu bacnet_npdu_t; struct __attribute__((__packed__)) bacnet_apdu { uint8_t type_flags; uint8_t max_segments_apdu; uint8_t invoke_id; uint8_t server_choice; }; typedef struct bacnet_apdu bacnet_apdu_t; struct __attribute__((__packed__)) bacnet_probe { struct bacnet_vlc vlc; struct bacnet_npdu npdu; struct bacnet_apdu apdu; }; typedef struct bacnet_probe bacnet_probe_t; typedef struct bacnet_oid bacnet_oid_t; #define ZMAP_BACNET_TYPE_IP 0x81 #define ZMAP_BACNET_FUNCTION_UNICAST_NPDU 0x0a #define ZMAP_BACNET_NPDU_VERSION_ASHRAE_135_1995 0x01 #define ZMAP_BACNET_SERVER_CHOICE_READ_PROPERTY 0x0c #endif /* ZMAP_MODULE_BACNET_H */ zmap-4.3.4/src/probe_modules/module_dns.c000066400000000000000000001132671501046211500204210ustar00rootroot00000000000000/* * ZMap Copyright 2015 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ // Module for scanning for open UDP DNS resolvers. // // This module optionally takes in an argument of the form "TYPE,QUESTION" // (e.g. "A,google.com"). // // Given no arguments it will default to asking for an A record for // www.google.com. // // This module does minimal answer verification. It only verifies that the // response roughly looks like a DNS response. It will not, for example, // require the QR bit be set to 1. All such analysis should happen offline. // Specifically, to be included in the output it requires: // - That the response packet is >= the query packet. // - That the ports match and the packet is complete. // To be marked as success it also requires: // - That the response bytes that should be the ID field matches the send bytes. // - That the response bytes that should be question match send bytes. // To be marked as app_success it also requires: // - That the QR bit be 1 and rcode == 0. // // Usage: // zmap -p 53 --probe-module=dns --probe-args="ANY,www.example.com" // -O json --output-fields=* 8.8.8.8 // // We also support multiple questions, of the form: // "A,example.com;AAAA,www.example.com" This requires --probes=X, where X // is a multiple of the number of questions in --probe-args, and either // --output-filter="" or --output-module=csv to remove the implicit // "filter_duplicates" configuration flag. // #include "module_dns.h" #include #include #include #include #include #include #include "../../lib/includes.h" #include "../../lib/random.h" #include "../../lib/xalloc.h" #include "probe_modules.h" #include "packet.h" #include "logger.h" #include "module_udp.h" #include "../fieldset.h" #define DNS_PAYLOAD_LEN_LIMIT 512 // This is arbitrary #define PCAP_SNAPLEN 1500 // This is even more arbitrary #define MAX_QTYPE 255 #define ICMP_UNREACH_HEADER_SIZE 8 #define BAD_QTYPE_STR "BAD QTYPE" #define BAD_QTYPE_VAL -1 #define MAX_LABEL_RECURSION 10 #define DNS_QR_ANSWER 1 #define SOURCE_PORT_VALIDATION_MODULE_DEFAULT true; // default to validating source port static bool should_validate_src_port = SOURCE_PORT_VALIDATION_MODULE_DEFAULT // Note: each label has a max length of 63 bytes. So someone has to be doing // something really annoying. Will raise a warning. // THIS INCLUDES THE NULL BYTE #define MAX_NAME_LENGTH 512 // zmap boilerplate probe_module_t module_dns; static int num_ports; const char default_domain[] = "www.google.com"; const uint16_t default_qtype = DNS_QTYPE_A; const uint8_t default_rdbit = 0xFF; static char **dns_packets; static uint16_t *dns_packet_lens; // Not including udp header static uint16_t *qname_lens; static char **qnames; static uint16_t *qtypes; static int num_questions = 0; // How many DNS questions to query. Note: There's a requirement that probes is a multiple of DNS questions // necessary to null-terminate these since strtrk_r can take multiple delimitors as a char*, and since these are contiguous in memory, // they were being used jointly when the intention is to use only one at a time. static const char *probe_arg_delimitor = ";\0"; static const char *domain_qtype_delimitor = ",\0"; static const char *rn_delimitor = ":\0"; static uint8_t *rdbits; const char *qopts_rn = "nr"; // used in query to disable recursion bit in DNS header /* Array of qtypes we support. Jumping through some hoops (1 level of * indirection) so the per-packet processing time is fast. Keep this in sync * with: dns_qtype (.h) qtype_strid_to_qtype (below) qtype_qtype_to_strid * (below, and setup_qtype_str_map()) */ const char *qtype_strs[] = {"A", "NS", "CNAME", "SOA", "PTR", "MX", "TXT", "AAAA", "RRSIG", "ALL"}; const int qtype_strs_len = 10; const dns_qtype qtype_strid_to_qtype[] = { DNS_QTYPE_A, DNS_QTYPE_NS, DNS_QTYPE_CNAME, DNS_QTYPE_SOA, DNS_QTYPE_PTR, DNS_QTYPE_MX, DNS_QTYPE_TXT, DNS_QTYPE_AAAA, DNS_QTYPE_RRSIG, DNS_QTYPE_ALL}; int8_t qtype_qtype_to_strid[256] = {BAD_QTYPE_VAL}; void setup_qtype_str_map(void) { qtype_qtype_to_strid[DNS_QTYPE_A] = 0; qtype_qtype_to_strid[DNS_QTYPE_NS] = 1; qtype_qtype_to_strid[DNS_QTYPE_CNAME] = 2; qtype_qtype_to_strid[DNS_QTYPE_SOA] = 3; qtype_qtype_to_strid[DNS_QTYPE_PTR] = 4; qtype_qtype_to_strid[DNS_QTYPE_MX] = 5; qtype_qtype_to_strid[DNS_QTYPE_TXT] = 6; qtype_qtype_to_strid[DNS_QTYPE_AAAA] = 7; qtype_qtype_to_strid[DNS_QTYPE_RRSIG] = 8; qtype_qtype_to_strid[DNS_QTYPE_ALL] = 9; } static uint16_t qtype_str_to_code(const char *str) { for (int i = 0; i < qtype_strs_len; i++) { if (strcmp(qtype_strs[i], str) == 0) return qtype_strid_to_qtype[i]; } return 0; } static uint16_t domain_to_qname(char **qname_handle, const char *domain) { // String + 1byte header + null byte uint16_t len = strlen(domain) + 1 + 1; char *qname = xmalloc(len); // Add a . before the domain. This will make the following simpler. qname[0] = '.'; // Move the domain into the qname buffer. strcpy(qname + 1, domain); for (int i = 0; i < len; i++) { if (qname[i] == '.') { int j; for (j = i + 1; j < (len - 1); j++) { if (qname[j] == '.') { break; } } qname[i] = j - i - 1; } } *qname_handle = qname; assert((*qname_handle)[len - 1] == '\0'); return len; } static int build_global_dns_packets(char *domains[], int num_domains, size_t *max_len) { size_t _max_len = 0; for (int i = 0; i < num_domains; i++) { qname_lens[i] = domain_to_qname(&qnames[i], domains[i]); if (domains[i] != (char *)default_domain) { free(domains[i]); } uint16_t len = sizeof(dns_header) + qname_lens[i] + sizeof(dns_question_tail); dns_packet_lens[i] = len; if (len > _max_len) { _max_len = len; } if (dns_packet_lens[i] > DNS_PAYLOAD_LEN_LIMIT) { log_fatal("dns", "DNS packet bigger (%d) than our limit (%d)", dns_packet_lens[i], DNS_PAYLOAD_LEN_LIMIT); return EXIT_FAILURE; } dns_packets[i] = xmalloc(dns_packet_lens[i]); dns_header *dns_header_p = (dns_header *)dns_packets[i]; char *qname_p = dns_packets[i] + sizeof(dns_header); dns_question_tail *tail_p = (dns_question_tail *)(dns_packets[i] + sizeof(dns_header) + qname_lens[i]); // All other header fields should be 0. Except id, which we set // per thread. Please recurse as needed. dns_header_p->rd = rdbits[i]; // We have 1 question dns_header_p->qdcount = htons(1); memcpy(qname_p, qnames[i], qname_lens[i]); // Set the qtype to what we passed from args tail_p->qtype = htons(qtypes[i]); // Set the qclass to The Internet tail_p->qclass = htons(0x01); } *max_len = _max_len; return EXIT_SUCCESS; } static uint16_t get_name_helper(const char *data, uint16_t data_len, const char *payload, uint16_t payload_len, char *name, uint16_t name_len, uint16_t recursion_level) { log_trace("dns", "_get_name_helper IN, datalen: %d namelen: %d recursion: %d", data_len, name_len, recursion_level); if (data_len == 0 || name_len == 0 || payload_len == 0) { log_trace( "dns", "_get_name_helper OUT, err. 0 length field. datalen %d namelen %d payloadlen %d", data_len, name_len, payload_len); return 0; } if (recursion_level > MAX_LABEL_RECURSION) { log_trace("dns", "_get_name_helper OUT. ERR, MAX RECURSION"); return 0; } uint16_t bytes_consumed = 0; // The start of data is either a sequence of labels or a ptr. while (data_len > 0) { uint8_t byte = data[0]; // Is this a pointer? if (byte >= 0xc0) { log_trace("dns", "_get_name_helper, ptr encountered"); // Do we have enough bytes to check ahead? if (data_len < 2) { log_trace( "dns", "_get_name_helper OUT. ptr byte encountered. No offset. ERR."); return 0; } // No. ntohs isn't needed here. It's because of // the upper 2 bits indicating a pointer. uint16_t offset = ((byte & 0x03) << 8) | (uint8_t)data[1]; log_trace("dns", "_get_name_helper. ptr offset 0x%x", offset); if (offset >= payload_len) { log_trace( "dns", "_get_name_helper OUT. offset exceeded payload len %d ERR", payload_len); return 0; } // We need to add a dot if we are: // -- Not first level recursion. // -- have consumed bytes if (recursion_level > 0 || bytes_consumed > 0) { if (name_len < 1) { log_warn( "dns", "Exceeded static name field allocation."); return 0; } name[0] = '.'; name++; name_len--; } uint16_t rec_bytes_consumed = get_name_helper( payload + offset, payload_len - offset, payload, payload_len, name, name_len, recursion_level + 1); // We are done so don't bother to increment the // pointers. if (rec_bytes_consumed == 0) { log_trace( "dns", "_get_name_helper OUT. rec level %d failed", recursion_level); return 0; } else { bytes_consumed += 2; log_trace( "dns", "_get_name_helper OUT. rec level %d success. " "%d rec bytes consumed. %d bytes consumed.", recursion_level, rec_bytes_consumed, bytes_consumed); return bytes_consumed; } } else if (byte == '\0') { // don't bother with pointer incrementation. We're done. bytes_consumed += 1; log_trace( "dns", "_get_name_helper OUT. rec level %d success. %d bytes consumed.", recursion_level, bytes_consumed); return bytes_consumed; } else { log_trace("dns", "_get_name_helper, segment 0x%hx encountered", byte); // We've now consumed a byte. ++data; --data_len; // Mark byte consumed after we check for first // iteration. Do we have enough data left (must have // null byte too)? if ((byte + 1) > data_len) { log_trace( "dns", "_get_name_helper OUT. ERR. Not enough data for segment %hd"); return 0; } // If we've consumed any bytes and are in a label, we're // in a label chain. We need to add a dot. if (bytes_consumed > 0) { if (name_len < 1) { log_warn( "dns", "Exceeded static name field allocation."); return 0; } name[0] = '.'; name++; name_len--; } // Now we've consumed a byte. ++bytes_consumed; // Did we run out of our arbitrary buffer? if (byte > name_len) { log_warn( "dns", "Exceeded static name field allocation."); return 0; } assert(data_len > 0); memcpy(name, data, byte); name += byte; name_len -= byte; data_len -= byte; data += byte; bytes_consumed += byte; // Handled in the byte+1 check above. assert(data_len > 0); } } // We should never get here. // For each byte we either have: // -- a ptr, which terminates // -- a null byte, which terminates // -- a segment length which either terminates or ensures we keep // looping assert(0); return 0; } // data: Where we are in the dns payload // payload: the entire udp payload static char *get_name(const char *data, uint16_t data_len, const char *payload, uint16_t payload_len, uint16_t *bytes_consumed) { log_trace("dns", "call to get_name, data_len: %d", data_len); char *name = xmalloc(MAX_NAME_LENGTH); *bytes_consumed = get_name_helper(data, data_len, payload, payload_len, name, MAX_NAME_LENGTH - 1, 0); if (*bytes_consumed == 0) { free(name); return NULL; } // Our memset ensured null byte. assert(name[MAX_NAME_LENGTH - 1] == '\0'); log_trace( "dns", "return success from get_name, bytes_consumed: %d, string: %s", *bytes_consumed, name); return name; } static bool process_response_question(char **data, uint16_t *data_len, const char *payload, uint16_t payload_len, fieldset_t *list) { // Payload is the start of the DNS packet, including header // data is handle to the start of this RR // data_len is a pointer to the how much total data we have to work // with. This is awful. I'm bad and should feel bad. uint16_t bytes_consumed = 0; char *question_name = get_name(*data, *data_len, payload, payload_len, &bytes_consumed); // Error. if (question_name == NULL) { return true; } assert(bytes_consumed > 0); if ((bytes_consumed + sizeof(dns_question_tail)) > *data_len) { free(question_name); return true; } dns_question_tail *tail = (dns_question_tail *)(*data + bytes_consumed); uint16_t qtype = ntohs(tail->qtype); uint16_t qclass = ntohs(tail->qclass); // Build our new question fieldset fieldset_t *qfs = fs_new_fieldset(NULL); fs_add_unsafe_string(qfs, "name", question_name, 1); fs_add_uint64(qfs, "qtype", qtype); if (qtype > MAX_QTYPE || qtype_qtype_to_strid[qtype] == BAD_QTYPE_VAL) { fs_add_string(qfs, "qtype_str", (char *)BAD_QTYPE_STR, 0); } else { // I've written worse things than this 3rd arg. But I want to be // fast. fs_add_string(qfs, "qtype_str", (char *)qtype_strs[qtype_qtype_to_strid[qtype]], 0); } fs_add_uint64(qfs, "qclass", qclass); // Now we're adding the new fs to the list. fs_add_fieldset(list, NULL, qfs); // Now update the pointers. *data = *data + bytes_consumed + sizeof(dns_question_tail); *data_len = *data_len - bytes_consumed - sizeof(dns_question_tail); return false; } static bool process_response_answer(char **data, uint16_t *data_len, const char *payload, uint16_t payload_len, fieldset_t *list) { log_trace("dns", "call to process_response_answer, data_len: %d", *data_len); // Payload is the start of the DNS packet, including header // data is handle to the start of this RR // data_len is a pointer to the how much total data we have to work // with. This is awful. I'm bad and should feel bad. uint16_t bytes_consumed = 0; char *answer_name = get_name(*data, *data_len, payload, payload_len, &bytes_consumed); // Error. if (answer_name == NULL) { return true; } assert(bytes_consumed > 0); if ((bytes_consumed + sizeof(dns_answer_tail)) > *data_len) { free(answer_name); return true; } dns_answer_tail *tail = (dns_answer_tail *)(*data + bytes_consumed); uint16_t type = ntohs(tail->type); uint16_t class = ntohs(tail->class); uint32_t ttl = ntohl(tail->ttl); uint16_t rdlength = ntohs(tail->rdlength); char *rdata = tail->rdata; if ((rdlength + bytes_consumed + sizeof(dns_answer_tail)) > *data_len) { free(answer_name); return true; } // Build our new question fieldset fieldset_t *afs = fs_new_fieldset(NULL); fs_add_unsafe_string(afs, "name", answer_name, 1); fs_add_uint64(afs, "type", type); if (type > MAX_QTYPE || qtype_qtype_to_strid[type] == BAD_QTYPE_VAL) { fs_add_string(afs, "type_str", (char *)BAD_QTYPE_STR, 0); } else { // I've written worse things than this 3rd arg. But I want to be // fast. fs_add_string(afs, "type_str", (char *)qtype_strs[qtype_qtype_to_strid[type]], 0); } fs_add_uint64(afs, "class", class); fs_add_uint64(afs, "ttl", ttl); fs_add_uint64(afs, "rdlength", rdlength); // XXX Fill this out for the other types we care about. if (type == DNS_QTYPE_NS || type == DNS_QTYPE_CNAME) { uint16_t rdata_bytes_consumed = 0; char *rdata_name = get_name(rdata, rdlength, payload, payload_len, &rdata_bytes_consumed); if (rdata_name == NULL) { fs_add_uint64(afs, "rdata_is_parsed", 0); fs_add_binary(afs, "rdata", rdlength, rdata, 0); } else { fs_add_uint64(afs, "rdata_is_parsed", 1); fs_add_unsafe_string(afs, "rdata", rdata_name, 1); } } else if (type == DNS_QTYPE_MX) { uint16_t rdata_bytes_consumed = 0; if (rdlength <= 4) { fs_add_uint64(afs, "rdata_is_parsed", 0); fs_add_binary(afs, "rdata", rdlength, rdata, 0); } else { char *rdata_name = get_name(rdata + 2, rdlength - 2, payload, payload_len, &rdata_bytes_consumed); if (rdata_name == NULL) { fs_add_uint64(afs, "rdata_is_parsed", 0); fs_add_binary(afs, "rdata", rdlength, rdata, 0); } else { // (largest value 16bit) + " " + answer + null char *rdata_with_pref = xmalloc(5 + 1 + strlen(rdata_name) + 1); uint8_t num_printed = snprintf(rdata_with_pref, 6, "%hu ", ntohs(*(uint16_t *)rdata)); memcpy(rdata_with_pref + num_printed, rdata_name, strlen(rdata_name)); fs_add_uint64(afs, "rdata_is_parsed", 1); fs_add_unsafe_string(afs, "rdata", rdata_with_pref, 1); } } } else if (type == DNS_QTYPE_TXT) { if (rdlength >= 1 && (rdlength - 1) != *(uint8_t *)rdata) { log_warn( "dns", "TXT record with wrong TXT len. Not processing."); fs_add_uint64(afs, "rdata_is_parsed", 0); fs_add_binary(afs, "rdata", rdlength, rdata, 0); } else { fs_add_uint64(afs, "rdata_is_parsed", 1); char *txt = xmalloc(rdlength); memcpy(txt, rdata + 1, rdlength - 1); fs_add_unsafe_string(afs, "rdata", txt, 1); } } else if (type == DNS_QTYPE_A) { if (rdlength != 4) { log_warn( "dns", "A record with IP of length %d. Not processing.", rdlength); fs_add_uint64(afs, "rdata_is_parsed", 0); fs_add_binary(afs, "rdata", rdlength, rdata, 0); } else { fs_add_uint64(afs, "rdata_is_parsed", 1); char *addr = strdup(inet_ntoa(*(struct in_addr *)rdata)); fs_add_unsafe_string(afs, "rdata", addr, 1); } } else if (type == DNS_QTYPE_AAAA) { if (rdlength != 16) { log_warn( "dns", "AAAA record with IP of length %d. Not processing.", rdlength); fs_add_uint64(afs, "rdata_is_parsed", 0); fs_add_binary(afs, "rdata", rdlength, rdata, 0); } else { fs_add_uint64(afs, "rdata_is_parsed", 1); char *ipv6_str = xmalloc(INET6_ADDRSTRLEN); inet_ntop(AF_INET6, (struct sockaddr_in6 *)rdata, ipv6_str, INET6_ADDRSTRLEN); fs_add_unsafe_string(afs, "rdata", ipv6_str, 1); } } else { fs_add_uint64(afs, "rdata_is_parsed", 0); fs_add_binary(afs, "rdata", rdlength, rdata, 0); } // Now we're adding the new fs to the list. fs_add_fieldset(list, NULL, afs); // Now update the pointers. *data = *data + bytes_consumed + sizeof(dns_answer_tail) + rdlength; *data_len = *data_len - bytes_consumed - sizeof(dns_answer_tail) - rdlength; log_trace("dns", "return success from process_response_answer, data_len: %d", *data_len); return false; } /* * Start of required zmap exports. */ static int dns_global_initialize(struct state_conf *conf) { setup_qtype_str_map(); if (conf->validate_source_port_override == VALIDATE_SRC_PORT_DISABLE_OVERRIDE) { log_debug("dns", "disabling source port validation"); should_validate_src_port = false; } if (!conf->probe_args) { log_fatal("dns", "Need probe args, e.g. --probe-args=\"A,example.com\""); } // strip off any leading or trailing semicolons if (*conf->probe_args == probe_arg_delimitor[0]) { log_debug("dns", "Probe args (%s) contains leading semicolon. Stripping.", conf->probe_args); conf->probe_args++; } if (conf->probe_args[strlen(conf->probe_args) - 1] == probe_arg_delimitor[0]) { log_debug("dns", "Probe args (%s) contains trailing semicolon. Stripping.", conf->probe_args); conf->probe_args[strlen(conf->probe_args) - 1] = '\0'; } char **domains = NULL; num_questions = 0; if (conf->probe_args) { char *questions_ctx; char *domain_ctx; char *domain_and_qtype = strtok_r(conf->probe_args, probe_arg_delimitor, &questions_ctx); // Process each pair while (domain_and_qtype != NULL) { // resize the array to accommodate the new pair domains = xrealloc(domains, (num_questions + 1) * sizeof(char *)); qtypes = xrealloc(qtypes, (num_questions + 1) * sizeof(uint16_t)); rdbits = xrealloc(rdbits, (num_questions + 1) * sizeof(uint8_t)); rdbits[num_questions] = default_rdbit; // Tokenize pair based on comma char *qtype_token = strtok_r(domain_and_qtype, domain_qtype_delimitor, &domain_ctx); char *domain_token = strtok_r(NULL, domain_qtype_delimitor, &domain_ctx); if (strchr(qtype_token, rn_delimitor[0]) != NULL) { // need to check if user supplied the no-recursion bit char *rbit_ctx; char *recurse_token = strtok_r(qtype_token, rn_delimitor, &rbit_ctx); recurse_token = strtok_r(NULL, rn_delimitor, &rbit_ctx); // check if the no-recursion field matches the expected value ("nr") if (strcmp(recurse_token, qopts_rn) == 0) { rdbits[num_questions] = 0; } else { log_warn("dns", "invalid text after DNS query type (%s). no recursion set with \"nr\"", recurse_token); } } if (domain_token == NULL || qtype_token == NULL) { log_fatal("dns", "Invalid probe args (%s). Format: \"A,google.com\" " "or \"A,google.com;A,example.com\"", conf->probe_args); } if (strlen(domain_token) == 0) { log_fatal("dns", "Invalid domain, domain cannot be empty."); } uint domain_len = strlen(domain_token); // add space for the null terminator char *domain_ptr = xmalloc(domain_len + 1); strncpy(domain_ptr, domain_token, domain_len + 1); // add null terminator domain_ptr[domain_len] = '\0'; // print debug info if (rdbits[num_questions] == 0) { // recursion disabled log_debug("dns", "parsed user input to scan domain (%s), for qtype (%s) w/o recursion", domain_ptr, qtype_token); } else { log_debug("dns", "parsed user input to scan domain (%s), for qtype (%s) with recursion", domain_ptr, qtype_token); } // add the new pair to the array domains[num_questions] = domain_ptr; qtypes[num_questions] = qtype_str_to_code(qtype_token); if (!qtypes[num_questions]) { log_fatal("dns", "Incorrect qtype supplied. %s", qtype_token); } // move to the next pair of domain/qtype domain_and_qtype = strtok_r(NULL, probe_arg_delimitor, &questions_ctx); num_questions++; } } if (num_questions == 0) { // user didn't provide any questions, setting up a default log_warn("dns", "no dns questions provided, using default domain (%s) and qtype (%s)", default_domain, qtype_strs[qtype_qtype_to_strid[default_qtype]]); // Resize the array to accommodate the new pair domains = xrealloc(domains, (num_questions + 1) * sizeof(char *)); qtypes = xrealloc(qtypes, (num_questions + 1) * sizeof(uint16_t)); rdbits = xrealloc(rdbits, (num_questions + 1) * sizeof(uint8_t)); rdbits[num_questions] = default_rdbit; // Add the new pair to the array domains[num_questions] = strdup(default_domain); qtypes[num_questions] = default_qtype; num_questions = 1; } else { log_debug("dns", "number of dns questions: %d", num_questions); } if (conf->packet_streams % num_questions != 0) { // probe count must be a multiple of the number of DNS questions log_fatal("dns", "number of probes (%d) must be a multiple of the number of DNS questions (%d)." "Example: '-P 4 --probe-args \"A,google.com;AAAA,cloudflare.com\"'", conf->packet_streams, num_questions); } // Setup the global structures dns_packets = xmalloc(sizeof(char *) * num_questions); dns_packet_lens = xmalloc(sizeof(uint16_t) * num_questions); qname_lens = xmalloc(sizeof(uint16_t) * num_questions); qnames = xmalloc(sizeof(char *) * num_questions); num_ports = conf->source_port_last - conf->source_port_first + 1; size_t max_payload_len; int ret = build_global_dns_packets(domains, num_questions, &max_payload_len); module_dns.max_packet_length = max_payload_len + sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr); return ret; } static int dns_global_cleanup(UNUSED struct state_conf *zconf, UNUSED struct state_send *zsend, UNUSED struct state_recv *zrecv) { if (dns_packets) { for (int i = 0; i < num_questions; i++) { if (dns_packets[i]) { free(dns_packets[i]); } } free(dns_packets); } dns_packets = NULL; if (qnames) { for (int i = 0; i < num_questions; i++) { if (qnames[i]) { free(qnames[i]); } } free(qnames); } qnames = NULL; if (dns_packet_lens) { free(dns_packet_lens); } if (qname_lens) { free(qname_lens); } if (qtypes) { free(qtypes); } return EXIT_SUCCESS; } int dns_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg_ptr) { memset(buf, 0, MAX_PACKET_SIZE); // Setup assuming num_questions == 0 struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t len = htons(sizeof(struct ip) + sizeof(struct udphdr) + dns_packet_lens[0]); make_ip_header(ip_header, IPPROTO_UDP, len); struct udphdr *udp_header = (struct udphdr *)(&ip_header[1]); len = sizeof(struct udphdr) + dns_packet_lens[0]; make_udp_header(udp_header, len); char *payload = (char *)(&udp_header[1]); memcpy(payload, dns_packets[0], dns_packet_lens[0]); return EXIT_SUCCESS; } // get_dns_question_index_by_probe_num - Find the dns question associated with this probe number // We allow users to enter a probe count that is a multiple of the number of DNS questions. // send.c will iterate with this probe count, sending a packet for each probe number // Ex. -P 4 --probe-args="A,google.com;AAAA,cloudflare.com" - send 2 probes for each question // Probe_num | num_questions = dns_index // 0 | 2 = 0 // 1 | 2 = 1 // 2 | 2 = 0 // 3 | 2 = 1 int get_dns_question_index_by_probe_num(int probe_num) { assert(probe_num >= 0); return probe_num % num_questions; } int dns_make_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dport, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, UNUSED void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct udphdr *udp_header = (struct udphdr *)&ip_header[1]; // For num_questions == 0, we handle this in per-thread init. Do less // work if (num_questions > 0) { int dns_index = get_dns_question_index_by_probe_num(probe_num); uint16_t encoded_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + dns_packet_lens[dns_index]); make_ip_header(ip_header, IPPROTO_UDP, encoded_len); encoded_len = sizeof(struct udphdr) + dns_packet_lens[dns_index]; make_udp_header(udp_header, encoded_len); char *payload = (char *)(&udp_header[1]); *buf_len = sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr) + dns_packet_lens[dns_index]; assert(*buf_len <= MAX_PACKET_SIZE); memcpy(payload, dns_packets[dns_index], dns_packet_lens[dns_index]); } ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_ttl = ttl; ip_header->ip_id = ip_id; // Above we wanted to look up the dns question index (so we could send 2 probes for the same DNS query) // Here we want the port to be unique regardless of if this is the 2nd probe to the same DNS query so using // probe_num itself to set the unique UDP source port. udp_header->uh_sport = htons(get_src_port(num_ports, probe_num, validation)); udp_header->uh_dport = dport; dns_header *dns_header_p = (dns_header *)&udp_header[1]; dns_header_p->id = validation[2] & 0xFFFF; ip_header->ip_sum = 0; ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); return EXIT_SUCCESS; } void dns_print_packet(FILE *fp, void *packet) { struct ether_header *ethh = (struct ether_header *)packet; struct ip *iph = (struct ip *)ðh[1]; struct udphdr *udph = (struct udphdr *)(&iph[1]); fprintf(fp, PRINT_PACKET_SEP); fprintf(fp, "dns { source: %u | dest: %u | checksum: %#04X }\n", ntohs(udph->uh_sport), ntohs(udph->uh_dport), ntohs(udph->uh_sum)); fprintf_ip_header(fp, iph); fprintf_eth_header(fp, ethh); fprintf(fp, PRINT_PACKET_SEP); } int dns_validate_packet(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, const struct port_conf *ports) { // this does the heavy lifting including ICMP validation if (udp_do_validate_packet(ip_hdr, len, src_ip, validation, num_ports, should_validate_src_port, ports) == PACKET_INVALID) { return PACKET_INVALID; } if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp = get_udp_header(ip_hdr, len); if (!udp) { return PACKET_INVALID; } // verify our packet length uint16_t udp_len = ntohs(udp->uh_ulen); int match = 0; for (int i = 0; i < num_questions; i++) { if (udp_len >= dns_packet_lens[i]) { match += 1; } } if (match == 0) { return PACKET_INVALID; } if (len < udp_len) { return PACKET_INVALID; } } return PACKET_VALID; } void dns_add_null_fs(fieldset_t *fs) { fs_add_null(fs, "dns_id"); fs_add_null(fs, "dns_rd"); fs_add_null(fs, "dns_tc"); fs_add_null(fs, "dns_aa"); fs_add_null(fs, "dns_opcode"); fs_add_null(fs, "dns_qr"); fs_add_null(fs, "dns_rcode"); fs_add_null(fs, "dns_cd"); fs_add_null(fs, "dns_ad"); fs_add_null(fs, "dns_z"); fs_add_null(fs, "dns_ra"); fs_add_null(fs, "dns_qdcount"); fs_add_null(fs, "dns_ancount"); fs_add_null(fs, "dns_nscount"); fs_add_null(fs, "dns_arcount"); fs_add_repeated(fs, "dns_questions", fs_new_repeated_fieldset()); fs_add_repeated(fs, "dns_answers", fs_new_repeated_fieldset()); fs_add_repeated(fs, "dns_authorities", fs_new_repeated_fieldset()); fs_add_repeated(fs, "dns_additionals", fs_new_repeated_fieldset()); fs_add_uint64(fs, "dns_parse_err", 1); fs_add_uint64(fs, "dns_unconsumed_bytes", 0); } void dns_process_packet(const u_char *packet, uint32_t len, fieldset_t *fs, uint32_t *validation, UNUSED struct timespec ts) { struct ip *ip_hdr = (struct ip *)&packet[sizeof(struct ether_header)]; if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp_hdr = get_udp_header(ip_hdr, len); assert(udp_hdr); uint16_t udp_len = ntohs(udp_hdr->uh_ulen); int match = 0; bool is_valid = false; for (int i = 0; i < num_questions; i++) { if (udp_len < dns_packet_lens[i]) { continue; } match += 1; char *qname_p = NULL; dns_question_tail *tail_p = NULL; dns_header *dns_header_p = (dns_header *)&udp_hdr[1]; // verify our dns transaction id if (dns_header_p->id == (validation[2] & 0xFFFF)) { // Verify our question qname_p = (char *)dns_header_p + sizeof(dns_header); tail_p = (dns_question_tail *)(dns_packets[i] + sizeof(dns_header) + qname_lens[i]); // Verify our qname if (strcmp(qnames[i], qname_p) == 0) { // Verify the qtype and qclass. if (tail_p->qtype == htons(qtypes[i]) && tail_p->qclass == htons(0x01)) { is_valid = true; break; } } } } assert(match > 0); dns_header *dns_hdr = (dns_header *)&udp_hdr[1]; uint16_t qr = dns_hdr->qr; uint16_t rcode = dns_hdr->rcode; // Success: Has the right validation bits and the right Q // App success: has qr and rcode bits right // Any app level parsing issues: dns_parse_err // fs_add_uint64(fs, "sport", ntohs(udp_hdr->uh_sport)); fs_add_uint64(fs, "dport", ntohs(udp_hdr->uh_dport)); // High level info fs_add_string(fs, "classification", (char *)"dns", 0); fs_add_bool(fs, "success", is_valid); // additional UDP information fs_add_bool(fs, "app_success", is_valid && (qr == DNS_QR_ANSWER) && (rcode == DNS_RCODE_NOERR)); // ICMP info fs_add_null_icmp(fs); fs_add_uint64(fs, "udp_len", udp_len); // DNS data if (!is_valid) { dns_add_null_fs(fs); } else { // DNS header fs_add_uint64(fs, "dns_id", ntohs(dns_hdr->id)); fs_add_uint64(fs, "dns_rd", dns_hdr->rd); fs_add_uint64(fs, "dns_tc", dns_hdr->tc); fs_add_uint64(fs, "dns_aa", dns_hdr->aa); fs_add_uint64(fs, "dns_opcode", dns_hdr->opcode); fs_add_uint64(fs, "dns_qr", qr); fs_add_uint64(fs, "dns_rcode", rcode); fs_add_uint64(fs, "dns_cd", dns_hdr->cd); fs_add_uint64(fs, "dns_ad", dns_hdr->ad); fs_add_uint64(fs, "dns_z", dns_hdr->z); fs_add_uint64(fs, "dns_ra", dns_hdr->ra); fs_add_uint64(fs, "dns_qdcount", ntohs(dns_hdr->qdcount)); fs_add_uint64(fs, "dns_ancount", ntohs(dns_hdr->ancount)); fs_add_uint64(fs, "dns_nscount", ntohs(dns_hdr->nscount)); fs_add_uint64(fs, "dns_arcount", ntohs(dns_hdr->arcount)); // And now for the complicated part. Hierarchical data. char *data = ((char *)dns_hdr) + sizeof(dns_header); uint16_t data_len = udp_len - sizeof(udp_hdr) - sizeof(dns_header); bool err = false; // Questions fieldset_t *list = fs_new_repeated_fieldset(); for (int i = 0; i < ntohs(dns_hdr->qdcount) && !err; i++) { err = process_response_question( &data, &data_len, (char *)dns_hdr, udp_len, list); } fs_add_repeated(fs, "dns_questions", list); // Answers list = fs_new_repeated_fieldset(); for (int i = 0; i < ntohs(dns_hdr->ancount) && !err; i++) { err = process_response_answer(&data, &data_len, (char *)dns_hdr, udp_len, list); } fs_add_repeated(fs, "dns_answers", list); // Authorities list = fs_new_repeated_fieldset(); for (int i = 0; i < ntohs(dns_hdr->nscount) && !err; i++) { err = process_response_answer(&data, &data_len, (char *)dns_hdr, udp_len, list); } fs_add_repeated(fs, "dns_authorities", list); // Additionals list = fs_new_repeated_fieldset(); for (int i = 0; i < ntohs(dns_hdr->arcount) && !err; i++) { err = process_response_answer(&data, &data_len, (char *)dns_hdr, udp_len, list); } fs_add_repeated(fs, "dns_additionals", list); // Do we have unconsumed data? if (data_len != 0) { err = true; } // Did we parse OK? fs_add_uint64(fs, "dns_parse_err", err); fs_add_uint64(fs, "dns_unconsumed_bytes", data_len); } // Now the raw stuff. fs_add_binary(fs, "raw_data", (udp_len - sizeof(struct udphdr)), (void *)&udp_hdr[1], 0); } else if (ip_hdr->ip_p == IPPROTO_ICMP) { fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_constchar(fs, "classification", "icmp"); fs_add_bool(fs, "success", 0); fs_add_bool(fs, "app_success", 0); // Populate all ICMP Fields fs_populate_icmp_from_iphdr(ip_hdr, len, fs); fs_add_null(fs, "udp_len"); dns_add_null_fs(fs); fs_add_binary(fs, "raw_data", len, (char *)packet, 0); } else { // This should not happen. Both the pcap filter and validate // packet prevent this. log_fatal("dns", "Die. This can only happen if you " "change the pcap filter and don't update the " "process function."); } } static fielddef_t fields[] = { {.name = "sport", .type = "int", .desc = "UDP source port"}, {.name = "dport", .type = "int", .desc = "UDP destination port"}, CLASSIFICATION_SUCCESS_FIELDSET_FIELDS, {.name = "app_success", .type = "bool", .desc = "Is the RA bit set with no error code?"}, ICMP_FIELDSET_FIELDS, {.name = "udp_len", .type = "int", .desc = "UDP packet length"}, {.name = "dns_id", .type = "int", .desc = "DNS transaction ID"}, {.name = "dns_rd", .type = "int", .desc = "DNS recursion desired"}, {.name = "dns_tc", .type = "int", .desc = "DNS packet truncated"}, {.name = "dns_aa", .type = "int", .desc = "DNS authoritative answer"}, {.name = "dns_opcode", .type = "int", .desc = "DNS opcode (query type)"}, {.name = "dns_qr", .type = "int", .desc = "DNS query(0) or response (1)"}, {.name = "dns_rcode", .type = "int", .desc = "DNS response code"}, {.name = "dns_cd", .type = "int", .desc = "DNS checking disabled"}, {.name = "dns_ad", .type = "int", .desc = "DNS authenticated data"}, {.name = "dns_z", .type = "int", .desc = "DNS reserved"}, {.name = "dns_ra", .type = "int", .desc = "DNS recursion available"}, {.name = "dns_qdcount", .type = "int", .desc = "DNS number questions"}, {.name = "dns_ancount", .type = "int", .desc = "DNS number answer RR's"}, {.name = "dns_nscount", .type = "int", .desc = "DNS number NS RR's in authority section"}, {.name = "dns_arcount", .type = "int", .desc = "DNS number additional RR's"}, {.name = "dns_questions", .type = "repeated", .desc = "DNS question list"}, {.name = "dns_answers", .type = "repeated", .desc = "DNS answer list"}, {.name = "dns_authorities", .type = "repeated", .desc = "DNS authority list"}, {.name = "dns_additionals", .type = "repeated", .desc = "DNS additional list"}, {.name = "dns_parse_err", .type = "int", .desc = "Problem parsing the DNS response"}, {.name = "dns_unconsumed_bytes", .type = "int", .desc = "Bytes left over when parsing" " the DNS response"}, {.name = "raw_data", .type = "binary", .desc = "UDP payload"}, }; probe_module_t module_dns = { .name = "dns", .max_packet_length = 0, // set in init .pcap_filter = "udp || icmp", .pcap_snaplen = PCAP_SNAPLEN, .port_args = 1, .global_initialize = &dns_global_initialize, .prepare_packet = &dns_prepare_packet, .make_packet = &dns_make_packet, .print_packet = &dns_print_packet, .validate_packet = &dns_validate_packet, .process_packet = &dns_process_packet, .close = &dns_global_cleanup, .output_type = OUTPUT_TYPE_DYNAMIC, .fields = fields, .numfields = sizeof(fields) / sizeof(fields[0]), .helptext = "This module sends out DNS queries and parses basic responses. " "By default, the module will perform an A record lookup for " "google.com. You can specify other queries using the --probe-args " "argument in the form: 'type,query', e.g. 'A,google.com'. The --probes/-P " "flag must be set to a multiple of the number of DNS questions. The module " "supports sending the the following types of queries: A, NS, CNAME, SOA, " "PTR, MX, TXT, AAAA, RRSIG, and ALL. In order to send queries with the " "'recursion desired' bit set to 0, append the suffix ':nr' to the query " "type, e.g. 'A:nr,google.com'. The module will accept and attempt " "to parse all DNS responses. There is currently support for parsing out " "full data from A, NS, CNAME, MX, TXT, and AAAA. Any other types will be " "output in raw form." }; zmap-4.3.4/src/probe_modules/module_dns.h000066400000000000000000000035171501046211500204220ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include typedef struct __attribute__((packed)) { uint16_t id; /* transaction ID */ unsigned rd : 1; /* recursion desired */ unsigned tc : 1; /* truncation */ unsigned aa : 1; /* authoritative answer */ unsigned opcode : 4; /* opcode 0=std query 1=Inverse query 2=srv status request */ unsigned qr : 1; /* query/response */ unsigned rcode : 4; /* response code */ unsigned cd : 1; /* checking disabled */ unsigned ad : 1; /* authenticated data */ unsigned z : 1; /* reserved set to 0 */ unsigned ra : 1; /* recursion available */ uint16_t qdcount; /* # entries in question section */ uint16_t ancount; /* # RR in answer section */ uint16_t nscount; /* # name server RR in authority section */ uint16_t arcount; /* # RR in additional information section */ } dns_header; typedef struct __attribute__((packed)) { uint16_t qtype; uint16_t qclass; } dns_question_tail; typedef struct __attribute__((packed)) { uint16_t type; uint16_t class; uint32_t ttl; uint16_t rdlength; char rdata[]; } dns_answer_tail; typedef enum { DNS_QTYPE_A = 1, DNS_QTYPE_NS = 2, DNS_QTYPE_CNAME = 5, DNS_QTYPE_SOA = 6, DNS_QTYPE_PTR = 12, DNS_QTYPE_MX = 15, DNS_QTYPE_TXT = 16, DNS_QTYPE_AAAA = 28, DNS_QTYPE_RRSIG = 46, DNS_QTYPE_ALL = 255 } dns_qtype; typedef enum { DNS_RCODE_NOERR = 0, DNS_RCODE_FORMATERR = 1, DNS_RCODE_SRVFAILURE = 2, DNS_RCODE_NXDOMAIN = 3, DNS_RCODE_QTYPENOTIMPL = 4, DNS_RCODE_QRYREFUSED = 5 } dns_rcode; zmap-4.3.4/src/probe_modules/module_icmp_echo.c000066400000000000000000000245201501046211500215540ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ // probe module for performing ICMP echo request (ping) scans #include #include #include #include #include #include #include #include "../../lib/includes.h" #include "../../lib/xalloc.h" #include "probe_modules.h" #include "../fieldset.h" #include "packet.h" #include "logger.h" #include "validate.h" #define ICMP_SMALLEST_SIZE 5 #define ICMP_MAX_PAYLOAD_LEN 1458 #define ICMP_TIMXCEED_UNREACH_HEADER_SIZE 8 probe_module_t module_icmp_echo; const char *icmp_usage_error = "unknown ICMP probe specification (expected file:/path or text:STRING or hex:01020304)"; static size_t icmp_payload_len = 0; static const size_t icmp_payload_default_len = 20; static char *icmp_payload = NULL; int icmp_global_initialize(struct state_conf *conf) { if (!(conf->probe_args && strlen(conf->probe_args) > 0)) { icmp_payload = xmalloc(icmp_payload_default_len); icmp_payload_len = icmp_payload_default_len; return EXIT_SUCCESS; } char *c = strchr(conf->probe_args, ':'); if (!c) { log_error("icmp", icmp_usage_error); return EXIT_FAILURE; } ++c; if (strncmp(conf->probe_args, "text", 4) == 0) { icmp_payload = strdup(c); icmp_payload_len = strlen(icmp_payload); } else if (strncmp(conf->probe_args, "file", 4) == 0) { FILE *inp = fopen(c, "rb"); if (!inp) { log_error("icmp", "could not open ICMP data file '%s'", c); return EXIT_FAILURE; } if (fseek(inp, 0, SEEK_END)) { log_error("icmp", "unable to get size of ICMP data file '%s'", c); fclose(inp); return EXIT_FAILURE; } size_t input_size = ftell(inp); if (input_size > ICMP_MAX_PAYLOAD_LEN) { log_error( "icmp", "input file larger than %d bytes and will not fit on the wire (%llu bytes provided)", ICMP_MAX_PAYLOAD_LEN, input_size); fclose(inp); return EXIT_FAILURE; } if (fseek(inp, 0, SEEK_SET)) { log_error("icmp", "unable to read ICMP data file '%s'", c); fclose(inp); return EXIT_FAILURE; } icmp_payload = xmalloc(ICMP_MAX_PAYLOAD_LEN); icmp_payload_len = fread(icmp_payload, 1, ICMP_MAX_PAYLOAD_LEN, inp); fclose(inp); } else if (strncmp(conf->probe_args, "hex", 3) == 0) { if (strlen(c) % 2 != 0) { log_error( "icmp", "invalid hex input (length must be a multiple of 2)"); return EXIT_FAILURE; } icmp_payload_len = strlen(c) / 2; icmp_payload = xmalloc(icmp_payload_len); unsigned int n; for (size_t i = 0; i < icmp_payload_len; i++) { if (sscanf(c + (i * 2), "%2x", &n) != 1) { free(icmp_payload); log_error("icmp", "non-hex character: '%c'", c[i * 2]); return EXIT_FAILURE; } icmp_payload[i] = (char)(n & 0xff); } } else { log_error("icmp", icmp_usage_error); return EXIT_FAILURE; } if (icmp_payload_len > ICMP_MAX_PAYLOAD_LEN) { log_error( "icmp", "reducing ICMP payload must be at most %d bytes to fit on the wire (%d were provided)\n", ICMP_MAX_PAYLOAD_LEN, icmp_payload_len); return EXIT_FAILURE; } module_icmp_echo.max_packet_length = sizeof(struct ether_header) + sizeof(struct ip) + ICMP_MINLEN + icmp_payload_len; assert(module_icmp_echo.max_packet_length <= 1500); return EXIT_SUCCESS; } int icmp_global_cleanup(__attribute__((unused)) struct state_conf *zconf, __attribute__((unused)) struct state_send *zsend, __attribute__((unused)) struct state_recv *zrecv) { if (icmp_payload) { free(icmp_payload); icmp_payload = NULL; } return EXIT_SUCCESS; } static int icmp_echo_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg_ptr) { memset(buf, 0, MAX_PACKET_SIZE); struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t len = htons(sizeof(struct ip) + ICMP_MINLEN + icmp_payload_len); make_ip_header(ip_header, IPPROTO_ICMP, len); struct icmp *icmp_header = (struct icmp *)(&ip_header[1]); make_icmp_header(icmp_header); char *payload = (char *)icmp_header + ICMP_MINLEN; memcpy(payload, icmp_payload, icmp_payload_len); return EXIT_SUCCESS; } static int icmp_echo_make_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, UNUSED port_n_t dst_port, uint8_t ttl, uint32_t *validation, UNUSED int probe_num, uint16_t ip_id, UNUSED void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct icmp *icmp_header = (struct icmp *)(&ip_header[1]); uint16_t icmp_idnum = validation[1] & 0xFFFF; uint16_t icmp_seqnum = validation[2] & 0xFFFF; ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_ttl = ttl; icmp_header->icmp_id = icmp_idnum; icmp_header->icmp_seq = icmp_seqnum; icmp_header->icmp_cksum = 0; icmp_header->icmp_cksum = icmp_checksum((unsigned short *)icmp_header, ICMP_MINLEN + icmp_payload_len); // Update the IP and UDP headers to match the new payload length size_t ip_len = sizeof(struct ip) + ICMP_MINLEN + icmp_payload_len; ip_header->ip_len = htons(ip_len); ip_header->ip_id = ip_id; ip_header->ip_sum = 0; ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); *buf_len = ip_len + sizeof(struct ether_header); return EXIT_SUCCESS; } static void icmp_echo_print_packet(FILE *fp, void *packet) { struct ether_header *ethh = (struct ether_header *)packet; struct ip *iph = (struct ip *)ðh[1]; struct icmp *icmp_header = (struct icmp *)(&iph[1]); fprintf(fp, "icmp { type: %u | code: %u " "| checksum: %#04X | id: %u | seq: %u }\n", icmp_header->icmp_type, icmp_header->icmp_code, ntohs(icmp_header->icmp_cksum), ntohs(icmp_header->icmp_id), ntohs(icmp_header->icmp_seq)); fprintf_ip_header(fp, iph); fprintf_eth_header(fp, ethh); fprintf(fp, PRINT_PACKET_SEP); } static int imcp_validate_id_seq(struct icmp *icmp_h, uint32_t *validation) { if (icmp_h->icmp_id != (validation[1] & 0xFFFF)) { return PACKET_INVALID; } if (icmp_h->icmp_seq != (validation[2] & 0xFFFF)) { return PACKET_INVALID; } return PACKET_VALID; } static int icmp_validate_packet(const struct ip *ip_hdr, uint32_t len, UNUSED uint32_t *src_ip, uint32_t *validation, UNUSED const struct port_conf *ports) { if (ip_hdr->ip_p != IPPROTO_ICMP) { return PACKET_INVALID; } struct icmp *icmp_h = get_icmp_header(ip_hdr, len); if (!icmp_h) { return PACKET_INVALID; } if (icmp_h->icmp_type == ICMP_ECHOREPLY) { return imcp_validate_id_seq(icmp_h, validation); } else { // handle unresearch/quench/redirect/timeout struct ip *ip_inner; size_t ip_inner_len; int icmp_inner_valid = icmp_helper_validate( ip_hdr, len, sizeof(struct icmp), &ip_inner, &ip_inner_len); if (icmp_inner_valid == PACKET_INVALID) { return PACKET_INVALID; } struct icmp *icmp_inner = get_icmp_header(ip_inner, ip_inner_len); if (!icmp_inner) { return PACKET_INVALID; } validate_gen(ip_hdr->ip_dst.s_addr, ip_inner->ip_dst.s_addr, 0, (uint8_t *)validation); // validate icmp id and seqnum return imcp_validate_id_seq(icmp_inner, validation); } } static void icmp_echo_process_packet(const u_char *packet, uint32_t len, fieldset_t *fs, UNUSED uint32_t *validation, UNUSED struct timespec ts) { struct ip *ip_hdr = (struct ip *)&packet[sizeof(struct ether_header)]; struct icmp *icmp_hdr = (struct icmp *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); fs_add_uint64(fs, "type", icmp_hdr->icmp_type); fs_add_uint64(fs, "code", icmp_hdr->icmp_code); fs_add_uint64(fs, "icmp_id", ntohs(icmp_hdr->icmp_id)); fs_add_uint64(fs, "seq", ntohs(icmp_hdr->icmp_seq)); uint32_t hdrlen = sizeof(struct ether_header) + 4 * ip_hdr->ip_hl + 4; switch (icmp_hdr->icmp_type) { case ICMP_ECHOREPLY: fs_add_string(fs, "classification", (char *)"echoreply", 0); fs_add_uint64(fs, "success", 1); break; case ICMP_UNREACH: fs_add_string(fs, "classification", (char *)"unreach", 0); fs_add_bool(fs, "success", 0); break; case ICMP_SOURCEQUENCH: fs_add_string(fs, "classification", (char *)"sourcequench", 0); fs_add_bool(fs, "success", 0); break; case ICMP_REDIRECT: fs_add_string(fs, "classification", (char *)"redirect", 0); fs_add_bool(fs, "success", 0); break; case ICMP_TIMXCEED: fs_add_string(fs, "classification", (char *)"timxceed", 0); fs_add_bool(fs, "success", 0); break; default: fs_add_string(fs, "classification", (char *)"other", 0); fs_add_bool(fs, "success", 0); break; } int datalen = len - hdrlen; if (datalen > 0) { const uint8_t *data = (uint8_t *)&packet[hdrlen]; fs_add_binary(fs, "data", (size_t)datalen, (void *)data, 0); } else { fs_add_null(fs, "data"); } } static fielddef_t fields[] = { {.name = "type", .type = "int", .desc = "icmp message type"}, {.name = "code", .type = "int", .desc = "icmp message sub type code"}, {.name = "icmp_id", .type = "int", .desc = "icmp id number"}, {.name = "seq", .type = "int", .desc = "icmp sequence number"}, {.name = "classification", .type = "string", .desc = "probe module classification"}, {.name = "success", .type = "bool", .desc = "did probe module classify response as success"}, {.name = "data", .type = "binary", .desc = "ICMP payload"}}; probe_module_t module_icmp_echo = { .name = "icmp_echoscan", .max_packet_length = 48, .pcap_filter = "icmp and icmp[0]!=8", .pcap_snaplen = 96, .port_args = 0, .global_initialize = &icmp_global_initialize, .close = &icmp_global_cleanup, .prepare_packet = &icmp_echo_prepare_packet, .make_packet = &icmp_echo_make_packet, .print_packet = &icmp_echo_print_packet, .process_packet = &icmp_echo_process_packet, .validate_packet = &icmp_validate_packet, .helptext = "Probe module that sends ICMP echo requests to hosts.\n" "Payload of ICMP packets will consist of zeroes unless you customize it with\n" " --probe-args=file:/path_to_payload_file\n" " --probe-args=text:SomeText\n" " --probe-args=hex:5061796c6f6164", .output_type = OUTPUT_TYPE_STATIC, .fields = fields, .numfields = 7}; zmap-4.3.4/src/probe_modules/module_icmp_echo_time.c000066400000000000000000000213151501046211500225710ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ // probe module for performing ICMP echo request (ping) scans that allows // calculation of RTT #include #include #include #include #include #include #include #include "../../lib/includes.h" #include "probe_modules.h" #include "../fieldset.h" #include "packet.h" #include "validate.h" #define ICMP_SMALLEST_SIZE 5 #define ICMP_TIMXCEED_UNREACH_HEADER_SIZE 8 probe_module_t module_icmp_echo_time; struct icmp_payload_for_rtt { uint32_t sent_tv_sec; uint32_t sent_tv_usec; ipaddr_n_t dst; }; static int icmp_echo_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg_ptr) { memset(buf, 0, MAX_PACKET_SIZE); struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t len = htons(sizeof(struct ip) + sizeof(struct icmp) - 8); make_ip_header(ip_header, IPPROTO_ICMP, len); struct icmp *icmp_header = (struct icmp *)(&ip_header[1]); make_icmp_header(icmp_header); return EXIT_SUCCESS; } static int icmp_echo_make_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, UNUSED port_n_t dport, uint8_t ttl, uint32_t *validation, UNUSED int probe_num, uint16_t ip_id, UNUSED void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct icmp *icmp_header = (struct icmp *)(&ip_header[1]); struct icmp_payload_for_rtt *payload = (struct icmp_payload_for_rtt *)(((char *)icmp_header) + 8); uint16_t icmp_idnum = validation[1] & 0xFFFF; uint16_t icmp_seqnum = validation[2] & 0xFFFF; struct timeval tv; ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_ttl = ttl; icmp_header->icmp_id = icmp_idnum; icmp_header->icmp_seq = icmp_seqnum; gettimeofday(&tv, NULL); payload->sent_tv_sec = tv.tv_sec; payload->sent_tv_usec = tv.tv_usec; payload->dst = dst_ip; icmp_header->icmp_cksum = 0; icmp_header->icmp_cksum = icmp_checksum((unsigned short *)icmp_header, sizeof(struct icmp)); // Update the IP and UDP headers to match the new payload length size_t ip_len = sizeof(struct ip) + ICMP_MINLEN + sizeof(struct icmp_payload_for_rtt); ip_header->ip_len = htons(ip_len); ip_header->ip_id = ip_id; ip_header->ip_sum = 0; ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); *buf_len = ip_len + sizeof(struct ether_header); return EXIT_SUCCESS; } static void icmp_echo_print_packet(FILE *fp, void *packet) { struct ether_header *ethh = (struct ether_header *)packet; struct ip *iph = (struct ip *)ðh[1]; struct icmp *icmp_header = (struct icmp *)(&iph[1]); fprintf(fp, "icmp { type: %u | code: %u " "| checksum: %#04X | id: %u | seq: %u }\n", icmp_header->icmp_type, icmp_header->icmp_code, ntohs(icmp_header->icmp_cksum), ntohs(icmp_header->icmp_id), ntohs(icmp_header->icmp_seq)); fprintf_ip_header(fp, iph); fprintf_eth_header(fp, ethh); fprintf(fp, PRINT_PACKET_SEP); } static int icmp_validate_packet(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, UNUSED const struct port_conf *ports) { if (ip_hdr->ip_p != IPPROTO_ICMP) { return 0; } if (((uint32_t)4 * ip_hdr->ip_hl + ICMP_SMALLEST_SIZE) > len) { // buffer not large enough to contain expected icmp header return 0; } struct icmp *icmp_h = (struct icmp *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); uint16_t icmp_idnum = icmp_h->icmp_id; uint16_t icmp_seqnum = icmp_h->icmp_seq; // ICMP validation is tricky: for some packet types, we must look inside // the payload if (icmp_h->icmp_type == ICMP_TIMXCEED || icmp_h->icmp_type == ICMP_UNREACH) { // Should have 16B TimeExceeded/Dest_Unreachable header + // original IP header + 1st 8B of original ICMP frame if ((4 * ip_hdr->ip_hl + ICMP_TIMXCEED_UNREACH_HEADER_SIZE + sizeof(struct ip)) > len) { return 0; } struct ip *ip_inner = (struct ip *)((char *)icmp_h + 8); if (((uint32_t)4 * ip_hdr->ip_hl + ICMP_TIMXCEED_UNREACH_HEADER_SIZE + 4 * ip_inner->ip_hl + 8 /*1st 8 bytes of original*/) > len) { return 0; } struct icmp *icmp_inner = (struct icmp *)((char *)ip_inner + 4 * ip_hdr->ip_hl); // Regenerate validation and icmp id based off inner payload icmp_idnum = icmp_inner->icmp_id; icmp_seqnum = icmp_inner->icmp_seq; *src_ip = ip_inner->ip_dst.s_addr; validate_gen(ip_hdr->ip_dst.s_addr, ip_inner->ip_dst.s_addr, 0, (uint8_t *)validation); } // validate icmp id and seqnum if (icmp_idnum != (validation[1] & 0xFFFF)) { return 0; } if (icmp_seqnum != (validation[2] & 0xFFFF)) { return 0; } return 1; } static void icmp_echo_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *fs, UNUSED uint32_t *validation, UNUSED struct timespec ts) { struct ip *ip_hdr = (struct ip *)&packet[sizeof(struct ether_header)]; struct icmp *icmp_hdr = (struct icmp *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); fs_add_uint64(fs, "type", icmp_hdr->icmp_type); fs_add_uint64(fs, "code", icmp_hdr->icmp_code); fs_add_uint64(fs, "icmp_id", ntohs(icmp_hdr->icmp_id)); fs_add_uint64(fs, "seq", ntohs(icmp_hdr->icmp_seq)); struct icmp_payload_for_rtt *payload = (struct icmp_payload_for_rtt *)(((char *)icmp_hdr) + 8); uint64_t sent_timestamp_ts = (uint64_t)payload->sent_tv_sec; uint64_t sent_timestamp_us = (uint64_t)payload->sent_tv_usec; uint64_t recv_timestamp_ts = (uint64_t)ts.tv_sec; uint64_t recv_timestamp_us = (uint64_t)ts.tv_nsec / 1000; uint64_t rtt_us = (recv_timestamp_ts * 1000000 + recv_timestamp_us) - (sent_timestamp_ts * 1000000 + sent_timestamp_us); fs_add_uint64(fs, "sent_timestamp_ts", sent_timestamp_ts); fs_add_uint64(fs, "sent_timestamp_us", sent_timestamp_us); fs_add_uint64(fs, "recv_timestamp_ts", recv_timestamp_ts); fs_add_uint64(fs, "recv_timestamp_us", recv_timestamp_us); fs_add_uint64(fs, "rtt_us", rtt_us); fs_add_uint64(fs, "dst_raw", (uint64_t)payload->dst); switch (icmp_hdr->icmp_type) { case ICMP_ECHOREPLY: fs_add_string(fs, "classification", (char *)"echoreply", 0); fs_add_uint64(fs, "success", 1); break; case ICMP_UNREACH: fs_add_string(fs, "classification", (char *)"unreach", 0); fs_add_uint64(fs, "success", 0); break; case ICMP_SOURCEQUENCH: fs_add_string(fs, "classification", (char *)"sourcequench", 0); fs_add_uint64(fs, "success", 0); break; case ICMP_REDIRECT: fs_add_string(fs, "classification", (char *)"redirect", 0); fs_add_uint64(fs, "success", 0); break; case ICMP_TIMXCEED: fs_add_string(fs, "classification", (char *)"timxceed", 0); fs_add_uint64(fs, "success", 0); break; default: fs_add_string(fs, "classification", (char *)"other", 0); fs_add_uint64(fs, "success", 0); break; } } static fielddef_t fields[] = { {.name = "type", .type = "int", .desc = "icmp message type"}, {.name = "code", .type = "int", .desc = "icmp message sub type code"}, {.name = "icmp_id", .type = "int", .desc = "icmp id number"}, {.name = "seq", .type = "int", .desc = "icmp sequence number"}, {.name = "sent_timestamp_ts", .type = "int", .desc = "timestamp of sent probe in seconds since Epoch"}, {.name = "sent_timestamp_us", .type = "int", .desc = "microsecond part of sent timestamp"}, {.name = "recv_timestamp_ts", .type = "int", .desc = "timestamp of receive probe in seconds since Epoch"}, {.name = "recv_timestamp_us", .type = "int", .desc = "microsecond part of receive timestamp"}, {.name = "rtt_us", .type = "int", .desc = "round-trip time in microseconds"}, {.name = "dst_raw", .type = "int", .desc = "raw destination IP address of sent probe"}, {.name = "classification", .type = "string", .desc = "probe module classification"}, {.name = "success", .type = "int", .desc = "did probe module classify response as success"}}; probe_module_t module_icmp_echo_time = { .name = "icmp_echo_time", .max_packet_length = 62, .pcap_filter = "icmp and icmp[0]!=8", .pcap_snaplen = 96, .port_args = 0, .prepare_packet = &icmp_echo_prepare_packet, .make_packet = &icmp_echo_make_packet, .print_packet = &icmp_echo_print_packet, .process_packet = &icmp_echo_process_packet, .validate_packet = &icmp_validate_packet, .close = NULL, .output_type = OUTPUT_TYPE_STATIC, .fields = fields, .numfields = 12}; zmap-4.3.4/src/probe_modules/module_ipip.c000066400000000000000000000331371501046211500205730ustar00rootroot00000000000000/* heavily copied from module_udp.c */ #include #include #include #include #include #include #include #include "../../lib/blocklist.h" #include "../../lib/includes.h" #include "../../lib/xalloc.h" #include "../../lib/lockfd.h" #include "../../lib/logger.h" #include "../../lib/xalloc.h" #include "../state.h" #include "../validate.h" #include "probe_modules.h" #include "packet.h" #define MAX_UDP_PAYLOAD_LEN 200 #define ICMP_UNREACH_HEADER_SIZE 8 #define UNUSED __attribute__((unused)) #define SOURCE_PORT_VALIDATION_MODULE_DEFAULT true; // default to validating source port static bool should_validate_src_port = SOURCE_PORT_VALIDATION_MODULE_DEFAULT static char *udp_send_msg = NULL; static int udp_send_msg_len = 0; static const char *udp_send_msg_default = "GET / HTTP/1.1\r\nHost: www\r\n\r\n"; #define DEFUALT_PAYLOAD_LEN (30) const char *ipip_usage_error = "unknown UDP probe specification (expected file:/path or text:STRING or hex:01020304)"; static int num_ports; probe_module_t module_ipip; int ipip_global_initialize(struct state_conf *conf) { char *args, *c; int i; unsigned int n; FILE *inp; num_ports = conf->source_port_last - conf->source_port_first + 1; if (conf->validate_source_port_override == VALIDATE_SRC_PORT_DISABLE_OVERRIDE) { log_debug("ipip", "disabling source port validation"); should_validate_src_port = false; } udp_send_msg = strdup(udp_send_msg_default); udp_send_msg_len = strlen(udp_send_msg); if (!(conf->probe_args && strlen(conf->probe_args) > 0)) return (0); args = strdup(conf->probe_args); assert(args); c = strchr(args, ':'); if (!c) { free(args); free(udp_send_msg); log_fatal("ipip", "%s", ipip_usage_error); } *c++ = 0; if (strcmp(args, "text") == 0) { free(udp_send_msg); udp_send_msg = strdup(c); udp_send_msg_len = strlen(udp_send_msg); } else if (strcmp(args, "file") == 0) { inp = fopen(c, "rb"); if (!inp) { free(udp_send_msg); // c points to memory in args, let exit free args log_fatal("ipip", "could not open UDP data file '%s'", c); } free(udp_send_msg); udp_send_msg = xmalloc(MAX_UDP_PAYLOAD_LEN); udp_send_msg_len = fread(udp_send_msg, 1, MAX_UDP_PAYLOAD_LEN, inp); fclose(inp); } else if (strcmp(args, "hex") == 0) { udp_send_msg_len = strlen(c) / 2; free(udp_send_msg); udp_send_msg = xmalloc(udp_send_msg_len); for (i = 0; i < udp_send_msg_len; i++) { if (sscanf(c + (i * 2), "%2x", &n) != 1) { char nonhexchr = c[i * 2]; free(args); free(udp_send_msg); log_fatal("ipip", "non-hex character: '%c'", nonhexchr); } udp_send_msg[i] = (n & 0xff); } } else { free(udp_send_msg); free(args); log_fatal("ipip", "%s", ipip_usage_error); } if (udp_send_msg_len > MAX_UDP_PAYLOAD_LEN) { log_warn("ipip", "warning: reducing UDP payload to %d " "bytes (from %d) to fit on the wire", MAX_UDP_PAYLOAD_LEN, udp_send_msg_len); udp_send_msg_len = MAX_UDP_PAYLOAD_LEN; } module_ipip.max_packet_length = sizeof(struct ether_header) + sizeof(struct ip) * 2 + sizeof(struct udphdr) + udp_send_msg_len; assert(module_ipip.max_packet_length <= MAX_PACKET_SIZE); free(args); return EXIT_SUCCESS; } int ipip_global_cleanup(UNUSED struct state_conf *zconf, UNUSED struct state_send *zsend, UNUSED struct state_recv *zrecv) { if (udp_send_msg) { free(udp_send_msg); udp_send_msg = NULL; } return EXIT_SUCCESS; } int ipip_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg_ptr) { memset(buf, 0, MAX_PACKET_SIZE); struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t len = htons(sizeof(struct ip) * 2 + sizeof(struct udphdr) + udp_send_msg_len); make_ip_header(ip_header, IPPROTO_IPIP, len); struct ip *ip_header2 = &ip_header[1]; len = htons(sizeof(struct ip) + sizeof(struct udphdr) + udp_send_msg_len); make_ip_header(ip_header2, IPPROTO_UDP, len); struct udphdr *udp_header = (struct udphdr *)(&ip_header2[1]); len = sizeof(struct udphdr) + udp_send_msg_len; make_udp_header(udp_header, len); char *payload = (char *)(&udp_header[1]); memcpy(payload, udp_send_msg, udp_send_msg_len); return EXIT_SUCCESS; } int ipip_make_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dport, UNUSED uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, UNUSED void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct ip *ip_header2 = (struct ip *)(&ip_header[1]); struct udphdr *udp_header = (struct udphdr *)&ip_header2[1]; ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_id = ip_id; ip_header2->ip_src.s_addr = dst_ip; ip_header2->ip_dst.s_addr = src_ip; // TODO put "external_ip" ip_header2->ip_id = ip_id; udp_header->uh_sport = htons(get_src_port(num_ports, probe_num, validation)); udp_header->uh_dport = dport; ip_header2->ip_sum = 0; ip_header2->ip_sum = zmap_ip_checksum((unsigned short *)ip_header2); ip_header->ip_sum = 0; ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); // Output the total length of the packet const size_t header_len = sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct ip) + sizeof(struct udphdr); *buf_len = header_len + udp_send_msg_len; return EXIT_SUCCESS; } void ipip_print_packet(FILE *fp, void *packet) { struct ether_header *ethh = (struct ether_header *)packet; struct ip *iph = (struct ip *)ðh[1]; struct ip *iph2 = (struct ip *)&iph[1]; struct udphdr *udph = (struct udphdr *)(&iph2[1]); fprintf(fp, "udp { source: %u | dest: %u | checksum: %#04X }\n", ntohs(udph->uh_sport), ntohs(udph->uh_dport), ntohs(udph->uh_sum)); fprintf_ip_header(fp, iph2); fprintf_ip_header(fp, iph); fprintf_eth_header(fp, ethh); fprintf(fp, "------------------------------------------------------\n"); } void ipip_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *fs, UNUSED uint32_t *validation, UNUSED const struct timespec ts) { struct ip *ip_hdr = (struct ip *)&packet[sizeof(struct ether_header)]; if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp = (struct udphdr *)((char *)ip_hdr + ip_hdr->ip_hl * 4); fs_add_constchar(fs, "classification", "udp"); fs_add_bool(fs, "success", 1); fs_add_uint64(fs, "sport", ntohs(udp->uh_sport)); fs_add_uint64(fs, "dport", ntohs(udp->uh_dport)); fs_add_null(fs, "icmp_responder"); fs_add_null(fs, "icmp_type"); fs_add_null(fs, "icmp_code"); fs_add_null(fs, "icmp_unreach_str"); fs_add_uint64(fs, "udp_pkt_size", ntohs(udp->uh_ulen)); // Verify that the UDP length is big enough for the header and // at least one byte uint16_t data_len = ntohs(udp->uh_ulen); if (data_len > sizeof(struct udphdr)) { uint32_t overhead = (sizeof(struct udphdr) + (ip_hdr->ip_hl * 4)); uint32_t max_rlen = len - overhead; uint32_t max_ilen = ntohs(ip_hdr->ip_len) - overhead; // Verify that the UDP length is inside of our received // buffer if (data_len > max_rlen) { data_len = max_rlen; } // Verify that the UDP length is inside of our IP packet if (data_len > max_ilen) { data_len = max_ilen; } fs_add_binary(fs, "data", data_len, (void *)&udp[1], 0); // Some devices reply with a zero UDP length but still // return data, ignore the data } else { fs_add_null(fs, "data"); } } else if (ip_hdr->ip_p == IPPROTO_ICMP) { struct icmp *icmp = (struct icmp *)((char *)ip_hdr + ip_hdr->ip_hl * 4); struct ip *ip_inner = (struct ip *)((char *)icmp + ICMP_UNREACH_HEADER_SIZE); // ICMP unreach comes from another server (not the one we sent a // probe to); But we will fix up saddr to be who we sent the // probe to, in case you care. fs_modify_string(fs, "saddr", make_ip_str(ip_inner->ip_dst.s_addr), 1); fs_add_string(fs, "classification", (char *)"icmp-unreach", 0); fs_add_bool(fs, "success", 0); fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_string(fs, "icmp_responder", make_ip_str(ip_hdr->ip_src.s_addr), 1); fs_add_uint64(fs, "icmp_type", icmp->icmp_type); fs_add_uint64(fs, "icmp_code", icmp->icmp_code); if (icmp->icmp_code <= ICMP_UNREACH_PRECEDENCE_CUTOFF) { fs_add_string( fs, "icmp_unreach_str", (char *)icmp_unreach_strings[icmp->icmp_code], 0); } else { fs_add_string(fs, "icmp_unreach_str", (char *)"unknown", 0); } fs_add_null(fs, "udp_pkt_size"); fs_add_null(fs, "data"); } else { fs_add_string(fs, "classification", (char *)"other", 0); fs_add_bool(fs, "success", 0); fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_null(fs, "icmp_responder"); fs_add_null(fs, "icmp_type"); fs_add_null(fs, "icmp_code"); fs_add_null(fs, "icmp_unreach_str"); fs_add_null(fs, "udp_pkt_size"); fs_add_null(fs, "data"); } } int ipip_validate_packet(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, const struct port_conf *ports) { if (ip_hdr->ip_p == IPPROTO_UDP) { if ((4 * ip_hdr->ip_hl + sizeof(struct udphdr)) > len) { // buffer not large enough to contain expected udp // header return PACKET_INVALID; } struct udphdr *udp = (struct udphdr *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); uint16_t dport = ntohs(udp->uh_dport); if (should_validate_src_port && !check_src_port(dport, ports)) { return PACKET_INVALID; } if (!blocklist_is_allowed(*src_ip)) { return PACKET_INVALID; } uint16_t sport = ntohs(udp->uh_sport); if (check_dst_port(sport, num_ports, validation)) { return PACKET_VALID; } for (unsigned i = 0; i < zconf.number_source_ips; i++) { validate_gen( zconf.source_ip_addresses[i], ip_hdr->ip_src.s_addr, udp->uh_dport, (uint8_t *)validation); if (check_dst_port(sport, num_ports, validation)) { return PACKET_VALID; } } } else if (ip_hdr->ip_p == IPPROTO_ICMP) { // IPIP can return ICMP Destination unreach // IP( ICMP( IP ( IP( UDP ) ) ) ) for a destination unreach uint32_t min_len = 4 * ip_hdr->ip_hl + ICMP_UNREACH_HEADER_SIZE + sizeof(struct ip) + sizeof(struct ip) + sizeof(struct udphdr); if (len < min_len) { return PACKET_INVALID; } struct icmp *icmp = (struct icmp *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); if (icmp->icmp_type != ICMP_UNREACH) { return PACKET_INVALID; } struct ip *ip_inner1 = (struct ip *)((char *)icmp + ICMP_UNREACH_HEADER_SIZE); // update min_len according to first internal IP packet min_len = min_len - sizeof(struct ip) + 4 * ip_inner1->ip_hl; if (len < min_len) { return PACKET_INVALID; } uint32_t dest = ip_inner1->ip_dst.s_addr; if (!blocklist_is_allowed(dest)) { return PACKET_INVALID; } struct ip *ip_inner2 = (struct ip *)((char *)ip_inner1 + 4 * ip_inner1->ip_hl); // update min_len according to second internal IP packet min_len = min_len - sizeof(struct ip) + 4 * ip_inner2->ip_hl; if (len < min_len) { return PACKET_INVALID; } // ensure the internal dst addr is the outer src addr and vice versa if (ip_inner1->ip_dst.s_addr != ip_inner2->ip_src.s_addr || ip_inner1->ip_src.s_addr != ip_inner2->ip_dst.s_addr) { return PACKET_INVALID; } struct udphdr *udp = (struct udphdr *)((char *)ip_inner2 + 4 * ip_inner2->ip_hl); // we can always check the destination port because this is the // original packet and wouldn't have been altered by something // responding on a different port uint16_t dport = ntohs(udp->uh_dport); if (should_validate_src_port && !check_src_port(dport, ports)) { return PACKET_INVALID; } uint16_t sport = ntohs(udp->uh_sport); if (!check_dst_port(sport, num_ports, validation)) { return PACKET_INVALID; } return PACKET_VALID; } return PACKET_INVALID; } static fielddef_t fields[] = { {.name = "classification", .type = "string", .desc = "packet classification"}, {.name = "success", .type = "bool", .desc = "is response considered success"}, {.name = "sport", .type = "int", .desc = "UDP source port"}, {.name = "dport", .type = "int", .desc = "UDP destination port"}, {.name = "icmp_responder", .type = "string", .desc = "Source IP of ICMP_UNREACH message"}, {.name = "icmp_type", .type = "int", .desc = "icmp message type"}, {.name = "icmp_code", .type = "int", .desc = "icmp message sub type code"}, {.name = "icmp_unreach_str", .type = "string", .desc = "for icmp_unreach responses, the string version of icmp_code (e.g. network-unreach)"}, {.name = "udp_pkt_size", .type = "int", .desc = "UDP packet length"}, {.name = "data", .type = "binary", .desc = "UDP payload"}}; probe_module_t module_ipip = { .name = "ipip", .max_packet_length = sizeof(struct ether_header) + sizeof(struct ip) * 2 + sizeof(struct udphdr) + DEFUALT_PAYLOAD_LEN, .pcap_filter = "udp || icmp", .pcap_snaplen = 1500, .port_args = 1, .global_initialize = &ipip_global_initialize, .prepare_packet = &ipip_prepare_packet, .make_packet = &ipip_make_packet, .print_packet = &ipip_print_packet, .validate_packet = &ipip_validate_packet, .process_packet = &ipip_process_packet, .close = &ipip_global_cleanup, .helptext = "Probe module that sends UDP packets to hosts. Packets can " "optionally be templated based on destination host. Specify" " packet file with --probe-args=file:/path_to_packet_file " "and templates with template:/path_to_template_file.", .fields = fields, .numfields = sizeof(fields) / sizeof(fields[0])}; zmap-4.3.4/src/probe_modules/module_ntp.c000066400000000000000000000217241501046211500204320ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include #include "../../lib/includes.h" #include "probe_modules.h" #include "module_udp.h" #include "module_ntp.h" #include "packet.h" #include "logger.h" #define MAX_NTP_PAYLOAD_LEN 1472 #define ICMP_UNREACH_HEADER_SIZE 8 probe_module_t module_ntp; static int num_ports; #define SOURCE_PORT_VALIDATION_MODULE_DEFAULT true; // default to validating source port static bool should_validate_src_port = SOURCE_PORT_VALIDATION_MODULE_DEFAULT int ntp_global_initialize(struct state_conf *conf) { num_ports = conf->source_port_last - conf->source_port_first + 1; if (conf->validate_source_port_override == VALIDATE_SRC_PORT_DISABLE_OVERRIDE) { log_debug("ntp", "disabling source port validation"); should_validate_src_port = false; } return udp_global_initialize(conf); } int ntp_validate_packet(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, const struct port_conf *ports) { return udp_do_validate_packet(ip_hdr, len, src_ip, validation, num_ports, should_validate_src_port, ports); } void ntp_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *fs, UNUSED uint32_t *validation, UNUSED struct timespec ts) { struct ip *ip_hdr = (struct ip *)&packet[sizeof(struct ether_header)]; uint64_t temp64; uint8_t temp8; uint32_t temp32; if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp = (struct udphdr *)((char *)ip_hdr + ip_hdr->ip_hl * 4); uint8_t *ptr = (uint8_t *)&udp[1]; fs_add_string(fs, "classification", (char *)"ntp", 0); fs_add_bool(fs, "success", 1); fs_add_uint64(fs, "sport", ntohs(udp->uh_sport)); fs_add_uint64(fs, "dport", ntohs(udp->uh_dport)); fs_add_null(fs, "icmp_responder"); fs_add_null(fs, "icmp_type"); fs_add_null(fs, "icmp_code"); fs_add_null(fs, "icmp_unreach_str"); if (len > 90) { temp8 = *((uint8_t *)ptr); fs_add_uint64(fs, "LI_VN_MODE", temp8); temp8 = *((uint8_t *)ptr + 1); fs_add_uint64(fs, "stratum", temp8); temp8 = *((uint8_t *)ptr + 2); fs_add_uint64(fs, "poll", temp8); temp8 = *((uint8_t *)ptr + 3); fs_add_uint64(fs, "precision", temp8); temp32 = *((uint32_t *)ptr + 4); fs_add_uint64(fs, "root_delay", temp32); temp32 = *((uint32_t *)ptr + 8); fs_add_uint64(fs, "root_dispersion", temp32); temp32 = *((uint32_t *)ptr + 12); fs_add_uint64(fs, "reference_clock_identifier", temp32); temp64 = *((uint64_t *)ptr + 16); fs_add_uint64(fs, "reference_timestamp", temp64); temp64 = *((uint64_t *)ptr + 24); fs_add_uint64(fs, "originate_timestamp", temp64); temp64 = *((uint64_t *)ptr + 32); fs_add_uint64(fs, "receive_timestamp", temp64); temp64 = *((uint64_t *)ptr + 39); fs_add_uint64(fs, "transmit_timestamp", temp64); } else { fs_add_null(fs, "LI_VN_MODE"); fs_add_null(fs, "stratum"); fs_add_null(fs, "poll"); fs_add_null(fs, "precision"); fs_add_null(fs, "root_delay"); fs_add_null(fs, "root_dispersion"); fs_add_null(fs, "reference_clock_identifier"); fs_add_null(fs, "reference_timestamp"); fs_add_null(fs, "originate_timestamp"); fs_add_null(fs, "receive_timestamp"); fs_add_null(fs, "transmit_timestamp"); } } else if (ip_hdr->ip_p == IPPROTO_ICMP) { struct icmp *icmp = (struct icmp *)((char *)ip_hdr + ip_hdr->ip_hl * 4); struct ip *ip_inner = (struct ip *)((char *)icmp + ICMP_UNREACH_HEADER_SIZE); fs_modify_string(fs, "saddr", make_ip_str(ip_inner->ip_dst.s_addr), 1); fs_add_constchar(fs, "classification", "icmp"); fs_add_bool(fs, "success", 0); fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_string(fs, "icmp_responder", make_ip_str(ip_hdr->ip_src.s_addr), 1); fs_add_uint64(fs, "icmp_type", icmp->icmp_type); fs_add_uint64(fs, "icmp_code", icmp->icmp_code); fs_add_null(fs, "icmp_unreach_str"); fs_add_null(fs, "LI_VN_MODE"); fs_add_null(fs, "stratum"); fs_add_null(fs, "poll"); fs_add_null(fs, "precision"); fs_add_null(fs, "root_delay"); fs_add_null(fs, "root_dispersion"); fs_add_null(fs, "reference_clock_identifier"); fs_add_null(fs, "reference_timestamp"); fs_add_null(fs, "originate_timestamp"); fs_add_null(fs, "receive_timestamp"); fs_add_null(fs, "transmit_timestamp"); } else { fs_add_constchar(fs, "classification", "other"); fs_add_bool(fs, "success", 0); fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_null(fs, "icmp_responder"); fs_add_null(fs, "icmp_type"); fs_add_null(fs, "icmp_code"); fs_add_null(fs, "icmp_unreach_str"); fs_add_null(fs, "LI_VN_MODE"); fs_add_null(fs, "stratum"); fs_add_null(fs, "poll"); fs_add_null(fs, "precision"); fs_add_null(fs, "root_delay"); fs_add_null(fs, "root_dispersion"); fs_add_null(fs, "reference_clock_identifier"); fs_add_null(fs, "reference_timestamp"); fs_add_null(fs, "originate_timestamp"); fs_add_null(fs, "receive_timestamp"); fs_add_null(fs, "transmit_timestamp"); } } int ntp_init_perthread(void **arg) { uint32_t seed = aesrand_getword(zconf.aes); aesrand_t *aes = aesrand_init_from_seed(seed); *arg = aes; return EXIT_SUCCESS; } int ntp_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg) { memset(buf, 0, MAX_PACKET_SIZE); struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t len = htons(sizeof(struct ip) + sizeof(struct udphdr) + sizeof(struct ntphdr)); make_ip_header(ip_header, IPPROTO_UDP, len); struct udphdr *udp_header = (struct udphdr *)(&ip_header[1]); struct ntphdr *ntp_header = (struct ntphdr *)(&udp_header[1]); ntp_header->LI_VN_MODE = 227; len = sizeof(struct udphdr) + sizeof(struct ntphdr); make_udp_header(udp_header, len); // TODO(dadrian): Should this have a payload? It was being set incorrectly. size_t header_len = sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr) + sizeof(struct ntphdr); module_ntp.max_packet_length = header_len; return EXIT_SUCCESS; } void ntp_print_packet(FILE *fp, void *packet) { struct ether_header *ethh = (struct ether_header *)packet; struct ip *iph = (struct ip *)ðh[1]; struct udphdr *udph = (struct udphdr *)(iph + 4 * iph->ip_hl); struct ntphdr *ntph = (struct ntphdr *)&udph[1]; fprintf(fp, "ntp { LI_VN_MODE: %u | stratum: %u | poll: %u }\n", ntph->LI_VN_MODE, ntph->stratum, ntph->poll); fprintf(fp, "udp { source: %u | dest: %u | checksum: %#04X }\n", ntohs(udph->uh_sport), ntohs(udph->uh_dport), ntohs(udph->uh_sum)); fprintf_ip_header(fp, iph); fprintf_eth_header(fp, ethh); fprintf(fp, PRINT_PACKET_SEP); } static fielddef_t fields[] = { {.name = "classification", .type = "string", .desc = "packet classification"}, {.name = "success", .type = "bool", .desc = "is response considered success"}, {.name = "sport", .type = "int", .desc = "UDP source port"}, {.name = "dport", .type = "int", .desc = "UDP destination port"}, ICMP_FIELDSET_FIELDS, {.name = "LI_VN_MODE", .type = "int", .desc = "leap indication, version number, mode"}, {.name = "stratum", .type = "int", .desc = "stratum"}, {.name = "poll", .type = "int", .desc = "poll"}, {.name = "precision", .type = "int", .desc = "precision"}, {.name = "root_delay", .type = "int", .desc = "root delay"}, {.name = "root_dispersion", .type = "int", .desc = "root dispersion"}, {.name = "reference_clock_identifier", .type = "int", .desc = "code identifying clock reference"}, {.name = "reference_timestamp", .type = "int", .desc = "local time at which local clock was last set or corrected"}, {.name = "originate_timestamp", .type = "int", .desc = "local time at which request deparated client for service"}, {.name = "receive_timestamp", .type = "int", .desc = "local time at which request arrvied at service host"}, {.name = "transmit_timestamp", .type = "int", .desc = "local time which reply departed service host for client"}, }; probe_module_t module_ntp = {.name = "ntp", .max_packet_length = 0, // set in init .pcap_filter = "udp || icmp", .pcap_snaplen = 1500, .port_args = 1, .global_initialize = &ntp_global_initialize, .thread_initialize = &ntp_init_perthread, .prepare_packet = &ntp_prepare_packet, .make_packet = &udp_make_packet, .print_packet = &ntp_print_packet, .validate_packet = &ntp_validate_packet, .process_packet = &ntp_process_packet, .close = &udp_global_cleanup, .output_type = OUTPUT_TYPE_STATIC, .fields = fields, .numfields = sizeof(fields) / sizeof(fields[0])}; zmap-4.3.4/src/probe_modules/module_ntp.h000066400000000000000000000015501501046211500204320ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "../state.h" #include "../fieldset.h" #ifndef MODULE_NTP_H #define MODULE_NTP_H #include #include #include #include #include struct __attribute__((__packed__)) ntphdr { // typedef uint8_t LI_VN_MODE; uint8_t stratum; uint8_t poll; uint8_t precision; uint32_t root_delay; uint32_t root_dispersion; uint32_t ref_ID; uint64_t reference_timestamp; uint64_t origin_timestamp; uint64_t receive_timestamp; uint64_t transmit_timestamp; // uint32_t key_ID; // uint64_t dgst_1; // uint64_t dgst_2; }; #endif zmap-4.3.4/src/probe_modules/module_tcp_synackscan.c000066400000000000000000000175361501046211500226420ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ // probe module for performing TCP SYN scans #include #include #include #include #include #include #include #include "../../lib/includes.h" #include "../fieldset.h" #include "logger.h" #include "probe_modules.h" #include "packet.h" #include "validate.h" #include "module_tcp_synscan.h" #define ZMAP_TCP_SYNACKSCAN_TCP_HEADER_LEN 24 #define ZMAP_TCP_SYNACKSCAN_PACKET_LEN 58 #define SOURCE_PORT_VALIDATION_MODULE_DEFAULT true; // default to validating source port static bool should_validate_src_port = SOURCE_PORT_VALIDATION_MODULE_DEFAULT probe_module_t module_tcp_synackscan; static uint32_t num_ports; static int synackscan_global_initialize(struct state_conf *state) { num_ports = state->source_port_last - state->source_port_first + 1; if (state->validate_source_port_override == VALIDATE_SRC_PORT_DISABLE_OVERRIDE) { log_debug("tcp_synack", "disabling source port validation"); should_validate_src_port = false; } return EXIT_SUCCESS; } static int synackscan_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg_ptr) { memset(buf, 0, MAX_PACKET_SIZE); struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t len = htons(sizeof(struct ip) + ZMAP_TCP_SYNACKSCAN_TCP_HEADER_LEN); make_ip_header(ip_header, IPPROTO_TCP, len); struct tcphdr *tcp_header = (struct tcphdr *)(&ip_header[1]); make_tcp_header(tcp_header, TH_SYN | TH_ACK); set_mss_option(tcp_header); return EXIT_SUCCESS; } static int synackscan_make_packet(void *buf, UNUSED size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dport, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, UNUSED void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct tcphdr *tcp_header = (struct tcphdr *)(&ip_header[1]); uint32_t tcp_seq = validation[0]; uint32_t tcp_ack = validation[2]; // get_src_port() below uses validation 1 internally. ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_ttl = ttl; ip_header->ip_id = ip_id; tcp_header->th_sport = htons(get_src_port(num_ports, probe_num, validation)); tcp_header->th_dport = dport; tcp_header->th_seq = tcp_seq; tcp_header->th_ack = tcp_ack; tcp_header->th_sum = 0; tcp_header->th_sum = tcp_checksum(ZMAP_TCP_SYNACKSCAN_TCP_HEADER_LEN, ip_header->ip_src.s_addr, ip_header->ip_dst.s_addr, tcp_header); ip_header->ip_sum = 0; ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); *buf_len = ZMAP_TCP_SYNACKSCAN_PACKET_LEN; return EXIT_SUCCESS; } static int synackscan_validate_packet(const struct ip *ip_hdr, uint32_t len, UNUSED uint32_t *src_ip, uint32_t *validation, const struct port_conf *ports) { if (ip_hdr->ip_p == IPPROTO_TCP) { struct tcphdr *tcp = get_tcp_header(ip_hdr, len); if (!tcp) { return PACKET_INVALID; } uint16_t sport = ntohs(tcp->th_sport); uint16_t dport = ntohs(tcp->th_dport); // validate source port if (should_validate_src_port && !check_src_port(sport, ports)) { return PACKET_INVALID; } // validate destination port if (!check_dst_port(dport, num_ports, validation)) { return PACKET_INVALID; } // check whether we'll ever send to this IP during the scan if (!blocklist_is_allowed(*src_ip)) { return PACKET_INVALID; } // We handle RST packets different than all other packets if (tcp->th_flags & TH_RST) { // A RST packet must have either: // 1) resp(ack) == sent(seq) + 1, or // 2) resp(seq) == sent(ack), or // 3) resp(seq) == sent(ack) + 1 // All other cases are a failure. if (htonl(tcp->th_ack) != htonl(validation[0]) + 1 && htonl(tcp->th_seq) != htonl(validation[2]) && htonl(tcp->th_seq) != (htonl(validation[2]) + 1)) { return PACKET_INVALID; } } else { // For non RST packets, we must have resp(ack) == sent(seq) + 1 if (htonl(tcp->th_ack) != htonl(validation[0]) + 1) { return PACKET_INVALID; } } } else if (ip_hdr->ip_p == IPPROTO_ICMP) { struct ip *ip_inner; size_t ip_inner_len; if (icmp_helper_validate(ip_hdr, len, sizeof(struct udphdr), &ip_inner, &ip_inner_len) == PACKET_INVALID) { return PACKET_INVALID; } struct tcphdr *tcp = get_tcp_header(ip_inner, ip_inner_len); if (!tcp) { return PACKET_INVALID; } // we can always check the destination port because this is the // original packet and wouldn't have been altered by something // responding on a different port uint16_t sport = ntohs(tcp->th_sport); uint16_t dport = ntohs(tcp->th_dport); if (!check_src_port(dport, ports)) { return PACKET_INVALID; } validate_gen(ip_hdr->ip_dst.s_addr, ip_inner->ip_dst.s_addr, tcp->th_dport, (uint8_t *)validation); if (!check_dst_port(sport, num_ports, validation)) { return PACKET_INVALID; } } else { return PACKET_INVALID; } return PACKET_VALID; } static void synackscan_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *fs, UNUSED uint32_t *validation, UNUSED struct timespec ts) { struct ip *ip_hdr = get_ip_header(packet, len); if (ip_hdr->ip_p == IPPROTO_TCP) { struct tcphdr *tcp = get_tcp_header(ip_hdr, len); fs_add_uint64(fs, "sport", (uint64_t)ntohs(tcp->th_sport)); fs_add_uint64(fs, "dport", (uint64_t)ntohs(tcp->th_dport)); fs_add_uint64(fs, "seqnum", (uint64_t)ntohl(tcp->th_seq)); fs_add_uint64(fs, "acknum", (uint64_t)ntohl(tcp->th_ack)); fs_add_uint64(fs, "window", (uint64_t)ntohs(tcp->th_win)); if (tcp->th_flags & TH_RST) { // RST packet fs_add_constchar(fs, "classification", "rst"); } else { // SYNACK packet fs_add_constchar(fs, "classification", "synack"); } fs_add_bool(fs, "success", 1); fs_add_null_icmp(fs); } else if (ip_hdr->ip_p == IPPROTO_ICMP) { // tcp fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_null(fs, "seqnum"); fs_add_null(fs, "acknum"); fs_add_null(fs, "window"); // global fs_add_constchar(fs, "classification", "icmp"); fs_add_bool(fs, "success", 0); // icmp fs_populate_icmp_from_iphdr(ip_hdr, len, fs); } } static fielddef_t fields[] = { {.name = "sport", .type = "int", .desc = "TCP source port"}, {.name = "dport", .type = "int", .desc = "TCP destination port"}, {.name = "seqnum", .type = "int", .desc = "TCP sequence number"}, {.name = "acknum", .type = "int", .desc = "TCP acknowledgement number"}, {.name = "window", .type = "int", .desc = "TCP window"}, CLASSIFICATION_SUCCESS_FIELDSET_FIELDS, ICMP_FIELDSET_FIELDS, }; probe_module_t module_tcp_synackscan = { .name = "tcp_synackscan", .max_packet_length = ZMAP_TCP_SYNACKSCAN_PACKET_LEN, .pcap_filter = "(tcp && tcp[13] & 4 != 0 || tcp[13] == 18) || icmp", .pcap_snaplen = 96, .port_args = 1, .global_initialize = &synackscan_global_initialize, .prepare_packet = &synackscan_prepare_packet, .make_packet = &synackscan_make_packet, .print_packet = &synscan_print_packet, .process_packet = &synackscan_process_packet, .validate_packet = &synackscan_validate_packet, .close = NULL, .helptext = "Probe module that sends a TCP SYNACK packet to a specific " "port. Possible classifications are: synack and rst. A " "SYN-ACK packet is considered a failure and a reset packet " "is considered a success.", .output_type = OUTPUT_TYPE_STATIC, .fields = fields, .numfields = sizeof(fields) / sizeof(fields[0])}; zmap-4.3.4/src/probe_modules/module_tcp_synscan.c000066400000000000000000000327171501046211500221610ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ // probe module for performing TCP SYN scans #include #include #include #include #include #include #include #include #include "../../lib/includes.h" #include "../fieldset.h" #include "logger.h" #include "module_tcp_synscan.h" #include "probe_modules.h" #include "packet.h" #include "validate.h" // defaults static uint8_t zmap_tcp_synscan_tcp_header_len = 20; static uint8_t zmap_tcp_synscan_packet_len = 54; #define SOURCE_PORT_VALIDATION_MODULE_DEFAULT true; // default to validating source port static bool should_validate_src_port = SOURCE_PORT_VALIDATION_MODULE_DEFAULT probe_module_t module_tcp_synscan; static uint16_t num_source_ports; static uint8_t os_for_tcp_options; static int synscan_global_initialize(struct state_conf *state) { num_source_ports = state->source_port_last - state->source_port_first + 1; if (state->validate_source_port_override == VALIDATE_SRC_PORT_DISABLE_OVERRIDE) { log_debug("tcp_synscan", "disabling source port validation"); should_validate_src_port = false; } // Based on the OS, we'll set the TCP options differently if (!state->probe_args) { // user didn't provide any probe args, defaulting to windows log_debug("tcp_synscan", "no probe-args, " "defaulting to Windows-style TCP options. Windows-style TCP options offer the highest hit-rate with the least bytes per probe."); state->probe_args = (char *)"windows"; } if (strcmp(state->probe_args, "smallest-probes") == 0) { os_for_tcp_options = SMALLEST_PROBES_OS_OPTIONS; zmap_tcp_synscan_tcp_header_len = 24; zmap_tcp_synscan_packet_len = 58; } else if (strcmp(state->probe_args, "bsd") == 0) { os_for_tcp_options = BSD_OS_OPTIONS; zmap_tcp_synscan_tcp_header_len = 44; zmap_tcp_synscan_packet_len = 78; } else if (strcmp(state->probe_args, "windows") == 0) { os_for_tcp_options = WINDOWS_OS_OPTIONS; zmap_tcp_synscan_tcp_header_len = 32; zmap_tcp_synscan_packet_len = 66; } else if (strcmp(state->probe_args, "linux") == 0) { os_for_tcp_options = LINUX_OS_OPTIONS; zmap_tcp_synscan_tcp_header_len = 40; zmap_tcp_synscan_packet_len = 74; } else { log_fatal("tcp_synscan", "unknown " "probe-args value: %s, probe-args " "should have format: \"--probe-args=os\" " "where os can be \"smallest-probes\", \"bsd\", " "\"windows\", and \"linux\"", state->probe_args); } // set max packet length accordingly for accurate send rate calculation module_tcp_synscan.max_packet_length = zmap_tcp_synscan_packet_len; // double-check arithmetic assert(zmap_tcp_synscan_packet_len - zmap_tcp_synscan_tcp_header_len == 34); return EXIT_SUCCESS; } static int synscan_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg_ptr) { struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t len = htons(sizeof(struct ip) + zmap_tcp_synscan_tcp_header_len); make_ip_header(ip_header, IPPROTO_TCP, len); struct tcphdr *tcp_header = (struct tcphdr *)(&ip_header[1]); make_tcp_header(tcp_header, TH_SYN); set_tcp_options(tcp_header, os_for_tcp_options); return EXIT_SUCCESS; } static int synscan_make_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dport, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, UNUSED void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct tcphdr *tcp_header = (struct tcphdr *)(&ip_header[1]); uint32_t tcp_seq = validation[0]; ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_ttl = ttl; port_h_t sport = get_src_port(num_source_ports, probe_num, validation); tcp_header->th_sport = htons(sport); tcp_header->th_dport = dport; tcp_header->th_seq = tcp_seq; // checksum value must be zero when calculating packet's checksum tcp_header->th_sum = 0; tcp_header->th_sum = tcp_checksum(zmap_tcp_synscan_tcp_header_len, ip_header->ip_src.s_addr, ip_header->ip_dst.s_addr, tcp_header); ip_header->ip_id = ip_id; // checksum value must be zero when calculating packet's checksum ip_header->ip_sum = 0; ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); *buf_len = zmap_tcp_synscan_packet_len; return EXIT_SUCCESS; } // not static because used by synack scan void synscan_print_packet(FILE *fp, void *packet) { struct ether_header *ethh = (struct ether_header *)packet; struct ip *iph = (struct ip *)ðh[1]; struct tcphdr *tcph = (struct tcphdr *)&iph[1]; if (zconf.fast_dryrun) { // We'll just print a binary representation of the dst IP and the dst Port to reduce data output/save time struct in_addr *dest_IP = (struct in_addr *)&(iph->ip_dst); // Writing binary IP addresses const uint8_t IP_ADDR_LEN = 4; const uint8_t TCP_PORT_LEN = 2; fwrite(&(dest_IP->s_addr), IP_ADDR_LEN,1, fp); // Write destination IP (binary) fwrite(&(tcph->th_dport), TCP_PORT_LEN,1, fp); // Write destination port (binary) return; } fprintf(fp, "tcp { source: %u | dest: %u | seq: %u | checksum: %#04X }\n", ntohs(tcph->th_sport), ntohs(tcph->th_dport), ntohl(tcph->th_seq), ntohs(tcph->th_sum)); fprintf_ip_header(fp, iph); fprintf_eth_header(fp, ethh); fprintf(fp, PRINT_PACKET_SEP); } static int synscan_validate_packet(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, const struct port_conf *ports) { if (ip_hdr->ip_p == IPPROTO_TCP) { struct tcphdr *tcp = get_tcp_header(ip_hdr, len); if (!tcp) { return PACKET_INVALID; } port_h_t sport = ntohs(tcp->th_sport); port_h_t dport = ntohs(tcp->th_dport); // validate source port if (should_validate_src_port && !check_src_port(sport, ports)) { return PACKET_INVALID; } // validate destination port if (!check_dst_port(dport, num_source_ports, validation)) { return PACKET_INVALID; } // check whether we'll ever send to this IP during the scan if (!blocklist_is_allowed(*src_ip)) { return PACKET_INVALID; } // We treat RST packets different from non RST packets if (tcp->th_flags & TH_RST) { // For RST packets, recv(ack) == sent(seq) + 0 or + 1 if (htonl(tcp->th_ack) != htonl(validation[0]) && htonl(tcp->th_ack) != htonl(validation[0]) + 1) { return PACKET_INVALID; } } else { // For non RST packets, recv(ack) == sent(seq) + 1 if (htonl(tcp->th_ack) != htonl(validation[0]) + 1) { return PACKET_INVALID; } } } else if (ip_hdr->ip_p == IPPROTO_ICMP) { struct ip *ip_inner; size_t ip_inner_len; if (icmp_helper_validate(ip_hdr, len, sizeof(struct tcphdr), &ip_inner, &ip_inner_len) == PACKET_INVALID) { return PACKET_INVALID; } struct tcphdr *tcp = get_tcp_header(ip_inner, ip_inner_len); if (!tcp) { return PACKET_INVALID; } // we can always check the destination port because this is the // original packet and wouldn't have been altered by something // responding on a different port. Note this is *different* // than the logic above because we're validating the probe packet // rather than the response packet port_h_t sport = ntohs(tcp->th_sport); port_h_t dport = ntohs(tcp->th_dport); if (!check_src_port(dport, ports)) { return PACKET_INVALID; } validate_gen(ip_hdr->ip_dst.s_addr, ip_inner->ip_dst.s_addr, tcp->th_dport, (uint8_t *)validation); if (!check_dst_port(sport, num_source_ports, validation)) { return PACKET_INVALID; } } else { return PACKET_INVALID; } return PACKET_VALID; } static void add_tcpopt_to_fs(fieldset_t *fs, int64_t *val, const char *label) { if (*val != -1) { fs_add_uint64(fs, label, *((uint64_t *) val)); } else { fs_add_null(fs, label); } } static void parse_tcp_opts(struct tcphdr *tcp, fieldset_t *fs) { int64_t mss = -1, wscale = -1, sack_perm = -1, ts_val = -1, ts_ecr = -1; size_t header_size = tcp->th_off * 4; for (size_t curr_idx = 20; curr_idx < header_size; ) { uint8_t kind = *(((uint8_t *) tcp) + curr_idx); // single-octet options without length field switch (kind) { case TCPOPT_EOL: // End of option list case TCPOPT_NOP: // NOP curr_idx += 1; continue; default: break; } if (curr_idx + 1 >= header_size) { // length field extends beyond end of header break; } uint8_t len = *(((uint8_t *) tcp) + curr_idx + 1); if ((len <= 1) || (curr_idx + len > header_size)) { // option length is too small to include the length // field itself, or extends beyond end of header break; } uint8_t *val = ((uint8_t *) tcp) + curr_idx + 2; switch (kind) { case TCPOPT_MAXSEG: // MSS if (len != TCPOLEN_MAXSEG) { goto break_loop; } mss = ntohs(*(uint16_t *) val); break; case TCPOPT_WINDOW: // Window scale if (len != TCPOLEN_WINDOW) { goto break_loop; } wscale = pow(2, *((uint8_t *) val)); break; case TCPOPT_SACK_PERMITTED: // SACK permitted if (len != TCPOLEN_SACK_PERMITTED) { goto break_loop; } sack_perm = 1; break; case TCPOPT_TIMESTAMP: // TCP Timestamp if (len != TCPOLEN_TIMESTAMP) { goto break_loop; } // Retrieve TS value and TS echo reply ts_val = ntohl(*(uint32_t *) val); ts_ecr = ntohl(*((uint32_t *) (val + 4))); break; default: break; } curr_idx += len; } break_loop: add_tcpopt_to_fs(fs, &mss, "tcpopt_mss"); add_tcpopt_to_fs(fs, &wscale, "tcpopt_wscale"); add_tcpopt_to_fs(fs, &sack_perm, "tcpopt_sack_perm"); add_tcpopt_to_fs(fs, &ts_val, "tcpopt_ts_val"); add_tcpopt_to_fs(fs, &ts_ecr, "tcpopt_ts_ecr"); } static void synscan_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *fs, UNUSED uint32_t *validation, UNUSED struct timespec ts) { struct ip *ip_hdr = get_ip_header(packet, len); assert(ip_hdr); if (ip_hdr->ip_p == IPPROTO_TCP) { struct tcphdr *tcp = get_tcp_header(ip_hdr, len); assert(tcp); fs_add_uint64(fs, "sport", (uint64_t)ntohs(tcp->th_sport)); fs_add_uint64(fs, "dport", (uint64_t)ntohs(tcp->th_dport)); fs_add_uint64(fs, "seqnum", (uint64_t)ntohl(tcp->th_seq)); fs_add_uint64(fs, "acknum", (uint64_t)ntohl(tcp->th_ack)); fs_add_uint64(fs, "window", (uint64_t)ntohs(tcp->th_win)); parse_tcp_opts(tcp, fs); if (tcp->th_flags & TH_RST) { // RST packet fs_add_constchar(fs, "classification", "rst"); fs_add_bool(fs, "success", 0); } else { // SYNACK packet fs_add_constchar(fs, "classification", "synack"); fs_add_bool(fs, "success", 1); } fs_add_null_icmp(fs); } else if (ip_hdr->ip_p == IPPROTO_ICMP) { // tcp fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_null(fs, "seqnum"); fs_add_null(fs, "acknum"); fs_add_null(fs, "window"); fs_add_null(fs, "tcpopt_mss"); fs_add_null(fs, "tcpopt_wscale"); fs_add_null(fs, "tcpopt_sack_perm"); fs_add_null(fs, "tcpopt_ts_val"); fs_add_null(fs, "tcpopt_ts_ecr"); // global fs_add_constchar(fs, "classification", "icmp"); fs_add_bool(fs, "success", 0); // icmp fs_populate_icmp_from_iphdr(ip_hdr, len, fs); } } static fielddef_t fields[] = { {.name = "sport", .type = "int", .desc = "TCP source port"}, {.name = "dport", .type = "int", .desc = "TCP destination port"}, {.name = "seqnum", .type = "int", .desc = "TCP sequence number"}, {.name = "acknum", .type = "int", .desc = "TCP acknowledgement number"}, {.name = "window", .type = "int", .desc = "TCP window"}, {.name = "tcpopt_mss", .type = "int", .desc = "TCP MSS option"}, {.name = "tcpopt_wscale", .type = "int", .desc = "TCP Window scale option"}, {.name = "tcpopt_sack_perm", .type = "int", .desc = "TCP SACK permitted option"}, {.name = "tcpopt_ts_val", .type = "int", .desc = "TCP timestamp option value"}, {.name = "tcpopt_ts_ecr", .type = "int", .desc = "TCP timestamp option echo reply"}, CLASSIFICATION_SUCCESS_FIELDSET_FIELDS, ICMP_FIELDSET_FIELDS, }; probe_module_t module_tcp_synscan = { .name = "tcp_synscan", .pcap_filter = "(tcp && tcp[13] & 4 != 0 || tcp[13] == 18) || icmp", .pcap_snaplen = 96, .port_args = 1, .global_initialize = &synscan_global_initialize, .prepare_packet = &synscan_prepare_packet, .make_packet = &synscan_make_packet, .print_packet = &synscan_print_packet, .process_packet = &synscan_process_packet, .validate_packet = &synscan_validate_packet, .close = NULL, .helptext = "Probe module that sends a TCP SYN packet to a specific port. Possible " "classifications are: synack and rst. A SYN-ACK packet is considered a " "success and a reset packet is considered a failed response. " "By default, TCP header options are set identically to the values used by " "Windows (MSS, SACK permitted, and WindowScale = 8). Use \"--probe-args=n\" " "to set the options, valid options are " "\"smallest-probes\", \"bsd\", \"linux\", \"windows\" (default). " "The \"smallest-probes\" option only sends MSS to achieve a better hit-rate " "than no options while staying within the minimum Ethernet payload size. Windows-style " "TCP options offer the highest hit-rate with a modest increase in probe size.", .output_type = OUTPUT_TYPE_STATIC, .fields = fields, .numfields = sizeof(fields) / sizeof(fields[0])}; zmap-4.3.4/src/probe_modules/module_tcp_synscan.h000066400000000000000000000013521501046211500221550ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ // probe module for performing TCP SYN scans #include #include #include #include #include #include #include "../../lib/includes.h" #include "../fieldset.h" #include "probe_modules.h" #include "packet.h" #define SMALLEST_PROBES_OS_OPTIONS 0x00 #define LINUX_OS_OPTIONS 0x01 #define BSD_OS_OPTIONS 0x02 #define WINDOWS_OS_OPTIONS 0x03 void synscan_print_packet(FILE *fp, void *packet); zmap-4.3.4/src/probe_modules/module_udp.c000066400000000000000000000660711501046211500204250ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ /* send module for performing arbitrary UDP scans */ #include #include #include #include #include #include #include #include #include "../../lib/blocklist.h" #include "../../lib/includes.h" #include "../../lib/xalloc.h" #include "../../lib/lockfd.h" #include "logger.h" #include "probe_modules.h" #include "packet.h" #include "aesrand.h" #include "state.h" #include "module_udp.h" #define MAX_UDP_PAYLOAD_LEN 1472 #define ICMP_HEADER_SIZE 8 #define JAN_1970 2208988800UL /* 1970 - 1900 in seconds. See RFC5905. */ #define FRAC 4294967296. /* 2^32 as a double */ static uint8_t *udp_fixed_payload = NULL; static size_t udp_fixed_payload_len = 0; static udp_payload_template_t *udp_template = NULL; const char *udp_usage_error = "unknown UDP probe specification (expected file:/path or text:STRING or hex:01020304 or template:/path or template-fields)"; const unsigned char *charset_alphanum = (unsigned char *)"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; const unsigned char *charset_alpha = (unsigned char *)"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const unsigned char *charset_digit = (unsigned char *)"0123456789"; const unsigned char charset_all[257] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x00}; static int num_ports; #define SOURCE_PORT_VALIDATION_MODULE_DEFAULT false; // default to NOT validating source port static bool should_validate_src_port = SOURCE_PORT_VALIDATION_MODULE_DEFAULT probe_module_t module_udp; // Field definitions for template parsing and displaying usage static uint32_t udp_num_template_field_types = 16; static udp_payload_field_type_def_t udp_payload_template_fields[] = { {.name = "SADDR_N", .ftype = UDP_SADDR_N, .max_length = 4, .desc = "Source IP address in network byte order"}, {.name = "SADDR", .ftype = UDP_SADDR_A, .max_length = 15, .desc = "Source IP address in dotted-quad format"}, {.name = "DADDR_N", .ftype = UDP_DADDR_N, .max_length = 4, .desc = "Destination IP address in network byte order"}, {.name = "DADDR", .ftype = UDP_DADDR_A, .max_length = 15, .desc = "Destination IP address in dotted-quad format"}, {.name = "SPORT_N", .ftype = UDP_SPORT_N, .max_length = 2, .desc = "UDP source port in network byte order"}, {.name = "SPORT", .ftype = UDP_SPORT_A, .max_length = 5, .desc = "UDP source port in ascii format"}, {.name = "DPORT_N", .ftype = UDP_DPORT_N, .max_length = 2, .desc = "UDP destination port in network byte order"}, {.name = "DPORT", .ftype = UDP_DPORT_A, .max_length = 5, .desc = "UDP destination port in ascii format"}, {.name = "RAND_BYTE", .ftype = UDP_RAND_BYTE, .max_length = 0, .desc = "Random bytes from 0-255"}, {.name = "RAND_DIGIT", .ftype = UDP_RAND_DIGIT, .max_length = 0, .desc = "Random digits from 0-9"}, {.name = "RAND_ALPHA", .ftype = UDP_RAND_ALPHA, .max_length = 0, .desc = "Random mixed-case letters (a-z)"}, {.name = "RAND_ALPHANUM", .ftype = UDP_RAND_ALPHANUM, .max_length = 0, .desc = "Random mixed-case letters (a-z) and numbers"}, {.name = "HEX", .ftype = UDP_HEX, .max_length = 0, .desc = "String of hex-encoded byte values"}, {.name = "UNIXTIME_SEC", .ftype = UDP_UNIXTIME_SEC, .max_length = 4, .desc = "Time in seconds since the Unix epoch in network byte order"}, {.name = "UNIXTIME_USEC", .ftype = UDP_UNIXTIME_USEC, .max_length = 4, .desc = "Microsecond part of Unix time in network byte order"}, {.name = "NTP_TIMESTAMP", .ftype = UDP_NTP_TIMESTAMP, .max_length = 8, .desc = "64 bit NTP timestamp in network byte order (RFC5905)"}}; void udp_set_num_ports(int x) { num_ports = x; } int udp_global_initialize(struct state_conf *conf) { uint32_t udp_template_max_len = 0; num_ports = conf->source_port_last - conf->source_port_first + 1; should_validate_src_port = SOURCE_PORT_VALIDATION_MODULE_DEFAULT if (conf->validate_source_port_override == VALIDATE_SRC_PORT_ENABLE_OVERRIDE) { log_debug("udp", "enabling source port validation"); should_validate_src_port = true; } if (!conf->probe_args) { log_error( "udp", "%s", "--probe-args are required, run --probe-module=udp --help for a longer description of the arguments"); return EXIT_FAILURE; } const char *args = conf->probe_args; if (strcmp(args, "template-fields") == 0) { lock_file(stderr); fprintf( stderr, "%s", "List of allowed UDP template fields (name: description)\n\n"); for (uint32_t i = 0; i < udp_num_template_field_types; ++i) { fprintf(stderr, "%s: %s\n", udp_payload_template_fields[i].name, udp_payload_template_fields[i].desc); } fprintf(stderr, "%s\n", ""); fflush(stderr); unlock_file(stderr); exit(0); } const char *c = strchr(args, ':'); if (!c) { log_fatal("udp", udp_usage_error); } size_t arg_name_len = c - args; c++; if (strncmp(args, "text", arg_name_len) == 0) { udp_fixed_payload = (uint8_t *)strdup(c); udp_fixed_payload_len = strlen(c); } else if (strncmp(args, "file", arg_name_len) == 0) { udp_fixed_payload = xmalloc(MAX_UDP_PAYLOAD_LEN); FILE *f = fopen(c, "rb"); if (!f) { log_fatal("udp", "could not open UDP data file '%s'\n", c); } udp_fixed_payload_len = fread(udp_fixed_payload, 1, MAX_UDP_PAYLOAD_LEN, f); fclose(f); } else if (strncmp(args, "template", arg_name_len) == 0) { uint8_t in[MAX_UDP_PAYLOAD_LEN]; FILE *f = fopen(c, "rb"); if (!f) { log_fatal("udp", "could not open UDP data file '%s'\n", c); } size_t in_len = fread(in, 1, MAX_UDP_PAYLOAD_LEN, f); fclose(f); udp_template = udp_template_load(in, in_len, &udp_template_max_len); module_udp.make_packet = udp_make_templated_packet; } else if (strncmp(args, "hex", arg_name_len) == 0) { udp_fixed_payload_len = strlen(c) / 2; udp_fixed_payload = xmalloc(udp_fixed_payload_len); unsigned int n; for (size_t i = 0; i < udp_fixed_payload_len; i++) { if (sscanf(c + (i * 2), "%2x", &n) != 1) { log_fatal("udp", "non-hex character: '%c'", c[i * 2]); } udp_fixed_payload[i] = (n & 0xff); } } else { log_fatal("udp", udp_usage_error); } if (udp_fixed_payload_len > MAX_UDP_PAYLOAD_LEN) { log_warn("udp", "warning: reducing fixed UDP payload to %d " "bytes (from %d) to fit on the wire\n", MAX_UDP_PAYLOAD_LEN, udp_fixed_payload_len); udp_fixed_payload_len = MAX_UDP_PAYLOAD_LEN; } size_t header_len = sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr); if (udp_fixed_payload_len > 0) { module_udp.max_packet_length = header_len + udp_fixed_payload_len; } else if (udp_template_max_len > 0) { module_udp.max_packet_length = header_len + udp_template_max_len; } assert(module_udp.max_packet_length); assert(module_udp.max_packet_length <= MAX_PACKET_SIZE); return EXIT_SUCCESS; } int udp_global_cleanup(UNUSED struct state_conf *zconf, UNUSED struct state_send *zsend, UNUSED struct state_recv *zrecv) { if (udp_fixed_payload) { free(udp_fixed_payload); udp_fixed_payload = NULL; } if (udp_template) { udp_template_free(udp_template); udp_template = NULL; } return EXIT_SUCCESS; } int udp_init_perthread(void **arg_ptr) { // Seed our random number generator with the global generator uint32_t seed = aesrand_getword(zconf.aes); aesrand_t *aes = aesrand_init_from_seed(seed); *arg_ptr = aes; return EXIT_SUCCESS; } int udp_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg_ptr) { memset(buf, 0, MAX_PACKET_SIZE); struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + udp_fixed_payload_len); make_ip_header(ip_header, IPPROTO_UDP, ip_len); struct udphdr *udp_header = (struct udphdr *)(&ip_header[1]); uint16_t udp_len = sizeof(struct udphdr) + udp_fixed_payload_len; make_udp_header(udp_header, udp_len); if (udp_fixed_payload) { void *payload = &udp_header[1]; memcpy(payload, udp_fixed_payload, udp_fixed_payload_len); } return EXIT_SUCCESS; } int udp_make_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dport, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, UNUSED void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct udphdr *udp_header = (struct udphdr *)&ip_header[1]; size_t headers_len = sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr); ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_ttl = ttl; udp_header->uh_sport = htons(get_src_port(num_ports, probe_num, validation)); udp_header->uh_dport = dport; ip_header->ip_id = ip_id; ip_header->ip_sum = 0; ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); // Output the total length of the packet *buf_len = headers_len + udp_fixed_payload_len; return EXIT_SUCCESS; } int udp_make_templated_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dport, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, void *arg) { struct ether_header *eth_header = (struct ether_header *)buf; struct ip *ip_header = (struct ip *)(ð_header[1]); struct udphdr *udp_header = (struct udphdr *)&ip_header[1]; size_t headers_len = sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr); ip_header->ip_src.s_addr = src_ip; ip_header->ip_dst.s_addr = dst_ip; ip_header->ip_ttl = ttl; udp_header->uh_sport = htons(get_src_port(num_ports, probe_num, validation)); udp_header->uh_dport = dport; char *payload = (char *)&udp_header[1]; memset(payload, 0, MAX_UDP_PAYLOAD_LEN); // Grab our random number generator aesrand_t *aes = (aesrand_t *)arg; // The buf is a stack var of our caller of size MAX_PACKET_SIZE // Recalculate the payload using the loaded template int payload_len = udp_template_build(udp_template, payload, MAX_UDP_PAYLOAD_LEN, ip_header, udp_header, aes); // If success is zero, the template output was truncated if (payload_len <= 0) { log_fatal("udp", "UDP payload template generated an empty payload"); } // Update the IP and UDP headers to match the new payload length ip_header->ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + payload_len); udp_header->uh_ulen = ntohs(sizeof(struct udphdr) + payload_len); ip_header->ip_sum = 0; ip_header->ip_id = ip_id; ip_header->ip_sum = zmap_ip_checksum((unsigned short *)ip_header); // Recalculate the total length of the packet *buf_len = headers_len + payload_len; return EXIT_SUCCESS; } void udp_print_packet(FILE *fp, void *packet) { struct ether_header *ethh = (struct ether_header *)packet; struct ip *iph = (struct ip *)ðh[1]; struct udphdr *udph = (struct udphdr *)(&iph[1]); fprintf(fp, "udp { source: %u | dest: %u | checksum: %#04X }\n", ntohs(udph->uh_sport), ntohs(udph->uh_dport), ntohs(udph->uh_sum)); fprintf_ip_header(fp, iph); fprintf_eth_header(fp, ethh); fprintf(fp, PRINT_PACKET_SEP); } void udp_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *fs, UNUSED uint32_t *validation, UNUSED struct timespec ts) { struct ip *ip_hdr = (struct ip *)&packet[sizeof(struct ether_header)]; if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp = get_udp_header(ip_hdr, len); fs_add_constchar(fs, "classification", "udp"); fs_add_bool(fs, "success", 1); fs_add_uint64(fs, "sport", ntohs(udp->uh_sport)); fs_add_uint64(fs, "dport", ntohs(udp->uh_dport)); fs_add_uint64(fs, "udp_pkt_size", ntohs(udp->uh_ulen)); // Verify that the UDP length is big enough for the header and // at least one byte uint16_t data_len = ntohs(udp->uh_ulen); if (data_len > sizeof(struct udphdr)) { uint32_t overhead = (sizeof(struct udphdr) + (ip_hdr->ip_hl * 4)); uint32_t max_rlen = len - overhead; uint32_t max_ilen = ntohs(ip_hdr->ip_len) - overhead; // Verify that the UDP length is inside of our received // buffer if (data_len > max_rlen) { data_len = max_rlen; } // Verify that the UDP length is inside of our IP packet if (data_len > max_ilen) { data_len = max_ilen; } fs_add_binary(fs, "data", data_len, (void *)&udp[1], 0); // Some devices reply with a zero UDP length but still // return data, ignore the data } else { fs_add_null(fs, "data"); } fs_add_null_icmp(fs); } else if (ip_hdr->ip_p == IPPROTO_ICMP) { fs_add_constchar(fs, "classification", "icmp"); fs_add_bool(fs, "success", 0); fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_null(fs, "udp_pkt_size"); fs_add_null(fs, "data"); fs_populate_icmp_from_iphdr(ip_hdr, len, fs); } else { fs_add_constchar(fs, "classification", "other"); fs_add_bool(fs, "success", 0); fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_null(fs, "udp_pkt_size"); fs_add_null(fs, "data"); fs_add_null_icmp(fs); } } int udp_validate_packet(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, const struct port_conf *ports) { return udp_do_validate_packet(ip_hdr, len, src_ip, validation, num_ports, should_validate_src_port, ports); } // Do very basic validation that this is an ICMP response to a packet we sent // Find the application layer packet that was originally sent and give it back // to the caller to do additional validation (e.g., correct TCP destination // port) int udp_do_validate_packet(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, int num_ports, int validate_port, const struct port_conf *ports) { if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp = get_udp_header(ip_hdr, len); if (!udp) { return PACKET_INVALID; } uint16_t dport = ntohs(udp->uh_dport); if (!check_dst_port(dport, num_ports, validation)) { return PACKET_INVALID; } if (!blocklist_is_allowed(*src_ip)) { return PACKET_INVALID; } if (validate_port == SRC_PORT_VALIDATION) { uint16_t sport = ntohs(udp->uh_sport); if (!check_src_port(sport, ports)) { return PACKET_INVALID; } } } else if (ip_hdr->ip_p == IPPROTO_ICMP) { struct ip *ip_inner; size_t ip_inner_len; if (icmp_helper_validate(ip_hdr, len, sizeof(struct udphdr), &ip_inner, &ip_inner_len) == PACKET_INVALID) { return PACKET_INVALID; } struct udphdr *udp = get_udp_header(ip_inner, ip_inner_len); // we can always check the destination port because this is the // original packet and wouldn't have been altered by something // responding on a different port uint16_t dport = ntohs(udp->uh_dport); uint16_t sport = ntohs(udp->uh_sport); if (!check_src_port(dport, ports)) { return PACKET_INVALID; } if (!check_dst_port(sport, num_ports, validation)) { return PACKET_INVALID; } } else { return PACKET_INVALID; } return PACKET_VALID; } // Add a new field to the template void udp_template_add_field(udp_payload_template_t *t, udp_payload_field_type_t ftype, unsigned int length, char *data) { udp_payload_field_t *c; t->fcount++; t->fields = xrealloc(t->fields, sizeof(udp_payload_field_t) * t->fcount); t->fields[t->fcount - 1] = xmalloc(sizeof(udp_payload_field_t)); c = t->fields[t->fcount - 1]; assert(c); c->ftype = ftype; c->length = length; c->data = data; } // Free all buffers held by the payload template, including its own void udp_template_free(udp_payload_template_t *t) { for (unsigned int x = 0; x < t->fcount; x++) { if (t->fields[x]->data) { free(t->fields[x]->data); t->fields[x]->data = NULL; } free(t->fields[x]); t->fields[x] = NULL; } free(t->fields); t->fields = NULL; t->fcount = 0; free(t); } int udp_random_bytes(char *dst, int len, const unsigned char *charset, int charset_len, aesrand_t *aes) { int i; for (i = 0; i < len; i++) { *dst++ = charset[(aesrand_getword(aes) & 0xFFFFFFFF) % charset_len]; } return i; } int udp_template_build(udp_payload_template_t *t, char *out, unsigned int len, struct ip *ip_hdr, struct udphdr *udp_hdr, aesrand_t *aes) { udp_payload_field_t *c; char *p; char *max; char tmp[256]; int full = 0; unsigned int x, y; uint32_t *u32; uint16_t *u16; int32_t *i32; struct timeval tv = (struct timeval){0}; max = out + len; p = out; for (x = 0; x < t->fcount; x++) { c = t->fields[x]; // Exit the processing loop if our packet buffer would overflow if (p + c->length >= max) { full = 1; return 0; } switch (c->ftype) { // These fields have a specified output length value case UDP_DATA: case UDP_HEX: if (!(c->data && c->length)) break; memcpy(p, c->data, c->length); p += c->length; break; case UDP_RAND_DIGIT: p += udp_random_bytes(p, c->length, charset_digit, 10, aes); break; case UDP_RAND_ALPHA: p += udp_random_bytes(p, c->length, charset_alpha, 52, aes); break; case UDP_RAND_ALPHANUM: p += udp_random_bytes(p, c->length, charset_alphanum, 62, aes); break; case UDP_RAND_BYTE: p += udp_random_bytes(p, c->length, charset_all, 256, aes); break; // These fields need to calculate size on their own // TODO: Condense these case statements to remove redundant code case UDP_SADDR_A: if (p + 15 >= max) { full = 1; break; } // Write to stack and then memcpy in order to properly // track length inet_ntop(AF_INET, (char *)&ip_hdr->ip_src, tmp, sizeof(tmp) - 1); memcpy(p, tmp, strlen(tmp)); p += strlen(tmp); break; case UDP_DADDR_A: if (p + 15 >= max) { full = 1; break; } // Write to stack and then memcpy in order to properly // track length inet_ntop(AF_INET, (char *)&ip_hdr->ip_dst, tmp, sizeof(tmp) - 1); memcpy(p, tmp, strlen(tmp)); p += strlen(tmp); break; case UDP_SADDR_N: if (p + 4 >= max) { full = 1; break; } u32 = (uint32_t *)p; *u32 = ip_hdr->ip_src.s_addr; p += 4; break; case UDP_DADDR_N: if (p + 4 >= max) { full = 1; break; } u32 = (uint32_t *)p; *u32 = ip_hdr->ip_dst.s_addr; p += 4; break; case UDP_SPORT_N: if (p + 2 >= max) { full = 1; break; } u16 = (uint16_t *)p; *u16 = udp_hdr->uh_sport; p += 2; break; case UDP_DPORT_N: if (p + 2 >= max) { full = 1; break; } u16 = (uint16_t *)p; *u16 = udp_hdr->uh_dport; p += 2; break; case UDP_SPORT_A: if (p + 5 >= max) { full = 1; break; } y = snprintf(tmp, 6, "%d", ntohs(udp_hdr->uh_sport)); memcpy(p, tmp, y); p += y; break; case UDP_DPORT_A: if (p + 5 >= max) { full = 1; break; } y = snprintf(tmp, 6, "%d", ntohs(udp_hdr->uh_dport)); memcpy(p, tmp, y); p += y; break; case UDP_UNIXTIME_SEC: case UDP_UNIXTIME_USEC: if (p + 4 >= max) { full = 1; break; } if (tv.tv_sec == 0) { gettimeofday(&tv, NULL); } i32 = (int32_t *)p; if (c->ftype == UDP_UNIXTIME_SEC) { *i32 = htonl(tv.tv_sec); } else { *i32 = htonl(tv.tv_usec); } p += 4; break; case UDP_NTP_TIMESTAMP: if (p + 8 >= max) { full = 1; break; } if (tv.tv_sec == 0) { gettimeofday(&tv, NULL); } u32 = (uint32_t *)p; *u32 = htonl((uint32_t)(tv.tv_sec + JAN_1970)); p += 4; u32 = (uint32_t *)p; *u32 = htonl((uint32_t)(tv.tv_usec / 1e6 * FRAC)); p += 4; break; } // Bail out if our packet buffer would overflow if (full == 1) { return 0; } } return p - out; } // Convert a string field name to a field type, parsing any specified length // value int udp_template_field_lookup(const char *vname, udp_payload_field_t *c) { static const size_t fcount = sizeof(udp_payload_template_fields) / sizeof(udp_payload_template_fields[0]); size_t vname_len = strlen(vname); size_t type_name_len = vname_len; const char *param = strstr(vname, "="); if (param) { type_name_len = param - vname; param++; } // Check for HEX= field which uses the parameter to encode hex values instead of the field length if (strncmp(vname, "HEX", 3) == 0 && strlen("HEX") == type_name_len) { c->ftype = UDP_HEX; c->length = strlen(param) / 2; c->data = xmalloc(c->length); unsigned int n; for (size_t i = 0; i < c->length; i++) { if (sscanf(param + (i * 2), "%2x", &n) != 1) { log_fatal("udp", "non-hex character: '%c'", param[i * 2]); } c->data[i] = (n & 0xff); } return 1; } // Most field types treat their parameter as a generator output length // unless it is ignored (ADDR, PORT, etc). long olen = 0; if (param && !*param) { log_fatal( "udp", "invalid template: field spec %s is invalid (missing length)", vname); } if (param) { char *end = NULL; errno = 0; olen = strtol(param, &end, 10); if (errno) { log_fatal( "udp", "invalid template: unable to read length from %s: %s", vname, strerror(errno)); } if (!end || end != vname + vname_len) { log_fatal( "udp", "invalid template: unable to read length from %s", vname); } if (olen < 0 || olen > MAX_UDP_PAYLOAD_LEN) { log_fatal( "udp", "invalid template: field size %d is larger than the max (%d)", olen, MAX_UDP_PAYLOAD_LEN); } } // Find a field that matches the for (unsigned int f = 0; f < fcount; f++) { const udp_payload_field_type_def_t *ftype = &udp_payload_template_fields[f]; if (strncmp(vname, ftype->name, type_name_len) == 0 && strlen(ftype->name) == type_name_len) { c->ftype = ftype->ftype; c->length = ftype->max_length ? ftype->max_length : (size_t)olen; c->data = NULL; return 1; } } // No match, skip and treat it as a data field return 0; } // Allocate a payload template and populate it by parsing a template file as a // binary buffer udp_payload_template_t *udp_template_load(uint8_t *buf, uint32_t buf_len, uint32_t *max_pkt_len) { udp_payload_template_t *t = xmalloc(sizeof(udp_payload_template_t)); uint32_t _max_pkt_len = 0; // The last $ we encountered outside of a field specifier uint8_t *dollar = NULL; // The last { we encountered outside of a field specifier uint8_t *lbrack = NULL; // Track the start pointer of a data field (static) uint8_t *s = buf; // Track the index into the template uint8_t *p = buf; char *tmp; unsigned int tlen; udp_payload_field_t c; t->fcount = 0; t->fields = NULL; while (p < (buf + buf_len)) { switch (*p) { case '$': if ((dollar && !lbrack) || !dollar) { dollar = p; } p++; continue; case '{': if (dollar && !lbrack) { lbrack = p; } p++; continue; case '}': if (!(dollar && lbrack)) { p++; continue; } // Store the leading bytes before ${ as a data field tlen = dollar - s; if (tlen > 0) { tmp = xmalloc(tlen); memcpy(tmp, s, tlen); udp_template_add_field(t, UDP_DATA, tlen, tmp); _max_pkt_len += tlen; } tmp = xcalloc(1, p - lbrack); memcpy(tmp, lbrack + 1, p - lbrack - 1); if (udp_template_field_lookup(tmp, &c)) { udp_template_add_field(t, c.ftype, c.length, c.data); _max_pkt_len += c.length; // Push the pointer past the } if this was a // valid variable s = p + 1; } else { // Rewind back to the ${ sequence if this was an // invalid variable s = dollar; } free(tmp); break; default: if (dollar && lbrack) { p++; continue; } } dollar = NULL; lbrack = NULL; p++; } // Store the trailing bytes as a final data field if (s < p) { tlen = p - s; tmp = xmalloc(tlen); memcpy(tmp, s, tlen); udp_template_add_field(t, UDP_DATA, tlen, tmp); _max_pkt_len += tlen; } *max_pkt_len = _max_pkt_len; return t; } static fielddef_t fields[] = { CLASSIFICATION_SUCCESS_FIELDSET_FIELDS, {.name = "sport", .type = "int", .desc = "UDP source port"}, {.name = "dport", .type = "int", .desc = "UDP destination port"}, {.name = "udp_pkt_size", .type = "int", .desc = "UDP packet length"}, {.name = "data", .type = "binary", .desc = "UDP payload"}, ICMP_FIELDSET_FIELDS, }; probe_module_t module_udp = { .name = "udp", .max_packet_length = 0, // set in init .pcap_filter = "udp || icmp", .pcap_snaplen = MAX_UDP_PAYLOAD_LEN + 20 + 24, // Ether Header, IP Header with Options .port_args = 1, .global_initialize = &udp_global_initialize, .thread_initialize = &udp_init_perthread, .prepare_packet = &udp_prepare_packet, .make_packet = &udp_make_packet, // can be overridden to udp_make_templated_packet by udp_global_initalize .print_packet = &udp_print_packet, .validate_packet = &udp_validate_packet, .process_packet = &udp_process_packet, .close = &udp_global_cleanup, .helptext = "Probe module that sends UDP packets to hosts. Packets can " "optionally be templated based on destination host. Specify " "packet file with --probe-args=file:/path_to_packet_file " "and templates with template:/path_to_template_file.", .fields = fields, .numfields = sizeof(fields) / sizeof(fields[0])}; zmap-4.3.4/src/probe_modules/module_udp.h000066400000000000000000000053101501046211500204170ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include "aesrand.h" #include "types.h" #include "state.h" #define NO_SRC_PORT_VALIDATION 0 #define SRC_PORT_VALIDATION 1 typedef enum udp_payload_field_type { UDP_DATA, UDP_SADDR_N, UDP_SADDR_A, UDP_DADDR_N, UDP_DADDR_A, UDP_SPORT_N, UDP_SPORT_A, UDP_DPORT_N, UDP_DPORT_A, UDP_RAND_BYTE, UDP_RAND_DIGIT, UDP_RAND_ALPHA, UDP_RAND_ALPHANUM, UDP_HEX, UDP_UNIXTIME_SEC, UDP_UNIXTIME_USEC, UDP_NTP_TIMESTAMP } udp_payload_field_type_t; typedef struct udp_payload_field_type_def { const char *name; const char *desc; size_t max_length; udp_payload_field_type_t ftype; } udp_payload_field_type_def_t; typedef struct udp_payload_field { enum udp_payload_field_type ftype; size_t length; char *data; } udp_payload_field_t; typedef struct udp_payload_template { unsigned int fcount; struct udp_payload_field **fields; } udp_payload_template_t; typedef struct udp_payload_output { int length; char *data; } udp_payload_output_t; void udp_print_packet(FILE *fp, void *packet); int udp_make_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dport, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, void *arg); int udp_make_templated_packet(void *buf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dport, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, void *arg); int udp_do_validate_packet(const struct ip *ip_hdr, uint32_t len, UNUSED uint32_t *src_ip, uint32_t *validation, int num_ports, int expected_port, const struct port_conf *ports); void udp_set_num_ports(int); int udp_global_initialize(struct state_conf *conf); int udp_global_cleanup(UNUSED struct state_conf *zconf, UNUSED struct state_send *zsend, UNUSED struct state_recv *zrecv); void udp_template_add_field(udp_payload_template_t *t, udp_payload_field_type_t ftype, unsigned int length, char *data); void udp_template_free(udp_payload_template_t *t); int udp_template_build(udp_payload_template_t *t, char *out, unsigned int len, struct ip *ip_hdr, struct udphdr *udp_hdr, aesrand_t *aes); int udp_template_field_lookup(const char *vname, udp_payload_field_t *c); udp_payload_template_t *udp_template_load(uint8_t *buf, uint32_t buf_len, uint32_t *max_pkt_len); zmap-4.3.4/src/probe_modules/module_upnp.c000066400000000000000000000211761501046211500206140ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include #include "../../lib/includes.h" #include "../../lib/logger.h" #include "../../lib/xalloc.h" #include "../fieldset.h" #include "probe_modules.h" #include "packet.h" #include "module_udp.h" #define ICMP_UNREACH_HEADER_SIZE 8 #define SOURCE_PORT_VALIDATION_MODULE_DEFAULT true; // default to validating source port static bool should_validate_src_port = SOURCE_PORT_VALIDATION_MODULE_DEFAULT static const char *upnp_query = "M-SEARCH * HTTP/1.1\r\n" "Host:239.255.255.250:1900\r\n" "ST:upnp:rootdevice\r\n" "Man:\"ssdp:discover\"\r\nMX:3\r\n\r\n"; probe_module_t module_upnp; static int num_ports; int upnp_global_initialize(struct state_conf *state) { num_ports = state->source_port_last - state->source_port_first + 1; if (state->validate_source_port_override == VALIDATE_SRC_PORT_DISABLE_OVERRIDE) { log_debug("upnp", "disabling source port validation"); should_validate_src_port = false; } udp_set_num_ports(num_ports); return EXIT_SUCCESS; } int upnp_prepare_packet(void *buf, macaddr_t *src, macaddr_t *gw, UNUSED void *arg_ptr) { memset(buf, 0, MAX_PACKET_SIZE); struct ether_header *eth_header = (struct ether_header *)buf; make_eth_header(eth_header, src, gw); struct ip *ip_header = (struct ip *)(ð_header[1]); uint16_t len = htons(sizeof(struct ip) + sizeof(struct udphdr) + strlen(upnp_query)); make_ip_header(ip_header, IPPROTO_UDP, len); struct udphdr *udp_header = (struct udphdr *)(&ip_header[1]); len = sizeof(struct udphdr) + strlen(upnp_query); make_udp_header(udp_header, len); char *payload = (char *)(&udp_header[1]); assert(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr) + strlen(upnp_query) <= MAX_PACKET_SIZE); assert(MAX_PACKET_SIZE - ((char *)payload - (char *)buf) > strlen(upnp_query)); strcpy(payload, upnp_query); return EXIT_SUCCESS; } int upnp_validate_packet(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, const struct port_conf *ports) { return udp_do_validate_packet(ip_hdr, len, src_ip, validation, num_ports, should_validate_src_port, ports); } void upnp_process_packet(const u_char *packet, UNUSED uint32_t len, fieldset_t *fs, UNUSED uint32_t *validation, UNUSED struct timespec ts) { struct ip *ip_hdr = (struct ip *)&packet[sizeof(struct ether_header)]; if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp = (struct udphdr *)((char *)ip_hdr + ip_hdr->ip_hl * 4); char *payload = (char *)(&udp[1]); uint16_t plen = udp->uh_ulen - 8; char *s = xmalloc(plen + 1); strncpy(s, payload, plen); s[plen] = 0; int is_first = 1; const char *classification = "none"; uint64_t is_success = 0; char *server = NULL, *location = NULL, *usn = NULL, *st = NULL, *cachecontrol = NULL, *ext = NULL, *xusragent = NULL, *date = NULL, *agent = NULL; char *pch = strtok(s, "\n"); while (pch != NULL) { if (pch[strlen(pch) - 1] == '\r') { pch[strlen(pch) - 1] = '\0'; } if (strlen(pch) == 0) { pch = strtok(NULL, "\n"); continue; } // the first pch is always supposed to be an HTTP // response if (is_first) { if (strcmp(pch, "HTTP/1.1 200 OK")) { classification = "no-http-header"; is_success = 0; goto cleanup; } is_first = 0; is_success = 1; classification = "upnp"; pch = strtok(NULL, "\n"); continue; } char *value = pch; char *key = strsep(&value, ":"); if (!key) { pch = strtok(NULL, "\n"); continue; } if (!value) { pch = strtok(NULL, "\n"); continue; } if (value[0] == ' ') { value += (size_t)1; } if (!strcasecmp(key, "server")) { server = strdup(value); } else if (!strcasecmp(key, "location")) { location = strdup(value); } else if (!strcasecmp(key, "USN")) { usn = strdup(value); } else if (!strcasecmp(key, "EXT")) { ext = strdup(value); } else if (!strcasecmp(key, "ST")) { st = strdup(value); } else if (!strcasecmp(key, "Agent")) { agent = strdup(value); } else if (!strcasecmp(key, "X-User-Agent")) { xusragent = strdup(value); } else if (!strcasecmp(key, "date")) { date = strdup(value); } else if (!strcasecmp(key, "Cache-Control")) { cachecontrol = strdup(value); } else { // log_debug("upnp-module", "new key: %s", key); } pch = strtok(NULL, "\n"); } cleanup: fs_add_string(fs, "classification", (char *)classification, 0); fs_add_bool(fs, "success", is_success); fs_chkadd_unsafe_string(fs, "server", server, 1); fs_chkadd_unsafe_string(fs, "location", location, 1); fs_chkadd_unsafe_string(fs, "usn", usn, 1); fs_chkadd_unsafe_string(fs, "st", st, 1); fs_chkadd_unsafe_string(fs, "ext", ext, 1); fs_chkadd_unsafe_string(fs, "cache_control", cachecontrol, 1); fs_chkadd_unsafe_string(fs, "x_user_agent", xusragent, 1); fs_chkadd_unsafe_string(fs, "agent", agent, 1); fs_chkadd_unsafe_string(fs, "date", date, 1); fs_add_uint64(fs, "sport", ntohs(udp->uh_sport)); fs_add_uint64(fs, "dport", ntohs(udp->uh_dport)); fs_add_null(fs, "icmp_responder"); fs_add_null(fs, "icmp_type"); fs_add_null(fs, "icmp_code"); fs_add_null(fs, "icmp_unreach_str"); fs_add_binary(fs, "data", (ntohs(udp->uh_ulen) - sizeof(struct udphdr)), (void *)&udp[1], 0); free(s); } else if (ip_hdr->ip_p == IPPROTO_ICMP) { fs_add_constchar(fs, "classification", "icmp"); fs_add_uint64(fs, "success", 0); fs_add_null(fs, "server"); fs_add_null(fs, "location"); fs_add_null(fs, "usn"); fs_add_null(fs, "st"); fs_add_null(fs, "ext"); fs_add_null(fs, "cache_control"); fs_add_null(fs, "x_user_agent"); fs_add_null(fs, "agent"); fs_add_null(fs, "date"); fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_populate_icmp_from_iphdr(ip_hdr, len, fs); fs_add_null(fs, "data"); } else { fs_add_constchar(fs, "classification", "other"); fs_add_bool(fs, "success", 0); fs_add_null(fs, "server"); fs_add_null(fs, "location"); fs_add_null(fs, "usn"); fs_add_null(fs, "st"); fs_add_null(fs, "ext"); fs_add_null(fs, "cache_control"); fs_add_null(fs, "x_user_agent"); fs_add_null(fs, "agent"); fs_add_null(fs, "date"); fs_add_null(fs, "sport"); fs_add_null(fs, "dport"); fs_add_null(fs, "icmp_responder"); fs_add_null(fs, "icmp_type"); fs_add_null(fs, "icmp_code"); fs_add_null(fs, "icmp_unreach_str"); fs_add_null(fs, "data"); } } static fielddef_t fields[] = { {.name = "classification", .type = "string", .desc = "packet classification"}, {.name = "success", .type = "bool", .desc = "is response considered success"}, {.name = "server", .type = "string", .desc = "UPnP server"}, {.name = "location", .type = "string", .desc = "UPnP location"}, {.name = "usn", .type = "string", .desc = "UPnP usn"}, {.name = "st", .type = "string", .desc = "UPnP st"}, {.name = "ext", .type = "string", .desc = "UPnP ext"}, {.name = "cache_control", .type = "string", .desc = "UPnP cache-control"}, {.name = "x_user_agent", .type = "string", .desc = "UPnP x-user-agent"}, {.name = "agent", .type = "string", .desc = "UPnP agent"}, {.name = "date", .type = "string", .desc = "UPnP date"}, {.name = "sport", .type = "int", .desc = "UDP source port"}, {.name = "dport", .type = "int", .desc = "UDP destination port"}, ICMP_FIELDSET_FIELDS, {.name = "data", .type = "binary", .desc = "UDP payload"}}; probe_module_t module_upnp = { .name = "upnp", .max_packet_length = 139, .pcap_filter = "udp || icmp", .pcap_snaplen = 2048, .port_args = 1, .global_initialize = &upnp_global_initialize, .prepare_packet = &upnp_prepare_packet, .make_packet = &udp_make_packet, .print_packet = &udp_print_packet, .process_packet = &upnp_process_packet, .validate_packet = &upnp_validate_packet, // UPnP isn't actually dynamic, however, we don't handle escaping // properly in the CSV module and this will force users to use JSON. .output_type = OUTPUT_TYPE_DYNAMIC, .close = NULL, .helptext = "Probe module that sends a TCP SYN packet to a specific " "port. Possible classifications are: synack and rst. A " "SYN-ACK packet is considered a success and a reset packet " "is considered a failed response.", .fields = fields, .numfields = 18}; zmap-4.3.4/src/probe_modules/packet.c000066400000000000000000000325431501046211500175340ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include "../../lib/includes.h" #include "../../lib/xalloc.h" #include "packet.h" #include "module_tcp_synscan.h" #include "logger.h" #ifndef NDEBUG void print_macaddr(struct ifreq *i) { printf("Device %s -> Ethernet %02x:%02x:%02x:%02x:%02x:%02x\n", i->ifr_name, (int)((unsigned char *)&i->ifr_addr.sa_data)[0], (int)((unsigned char *)&i->ifr_addr.sa_data)[1], (int)((unsigned char *)&i->ifr_addr.sa_data)[2], (int)((unsigned char *)&i->ifr_addr.sa_data)[3], (int)((unsigned char *)&i->ifr_addr.sa_data)[4], (int)((unsigned char *)&i->ifr_addr.sa_data)[5]); } #endif /* NDEBUG */ #define IP_ADDR_LEN_STR 20 void fprintf_ip_header(FILE *fp, struct ip *iph) { struct in_addr *s = (struct in_addr *)&(iph->ip_src); struct in_addr *d = (struct in_addr *)&(iph->ip_dst); char srcip[IP_ADDR_LEN_STR + 1]; char dstip[IP_ADDR_LEN_STR + 1]; // inet_ntoa is a const char * so we if just call it in // fprintf, you'll get back wrong results since we're // calling it twice. strncpy(srcip, inet_ntoa(*s), IP_ADDR_LEN_STR - 1); strncpy(dstip, inet_ntoa(*d), IP_ADDR_LEN_STR - 1); srcip[IP_ADDR_LEN_STR] = '\0'; dstip[IP_ADDR_LEN_STR] = '\0'; fprintf(fp, "ip { saddr: %s | daddr: %s | checksum: %#04X }\n", srcip, dstip, ntohs(iph->ip_sum)); } void fprintf_eth_header(FILE *fp, struct ether_header *ethh) { if (!zconf.send_ip_pkts) { fprintf(fp, "eth { shost: %02x:%02x:%02x:%02x:%02x:%02x | " "dhost: %02x:%02x:%02x:%02x:%02x:%02x }\n", (int)((unsigned char *)ethh->ether_shost)[0], (int)((unsigned char *)ethh->ether_shost)[1], (int)((unsigned char *)ethh->ether_shost)[2], (int)((unsigned char *)ethh->ether_shost)[3], (int)((unsigned char *)ethh->ether_shost)[4], (int)((unsigned char *)ethh->ether_shost)[5], (int)((unsigned char *)ethh->ether_dhost)[0], (int)((unsigned char *)ethh->ether_dhost)[1], (int)((unsigned char *)ethh->ether_dhost)[2], (int)((unsigned char *)ethh->ether_dhost)[3], (int)((unsigned char *)ethh->ether_dhost)[4], (int)((unsigned char *)ethh->ether_dhost)[5]); } } void make_eth_header(struct ether_header *ethh, macaddr_t *src, macaddr_t *dst) { memcpy(ethh->ether_shost, src, ETHER_ADDR_LEN); memcpy(ethh->ether_dhost, dst, ETHER_ADDR_LEN); ethh->ether_type = htons(ETHERTYPE_IP); } void make_ip_header(struct ip *iph, uint8_t protocol, uint16_t len) { iph->ip_hl = 5; // Internet Header Length iph->ip_v = 4; // IPv4 iph->ip_tos = 0; // Type of Service iph->ip_len = len; iph->ip_id = htons(54321); // identification number iph->ip_off = 0; // fragmentation flag iph->ip_ttl = MAXTTL; // time to live (TTL) iph->ip_p = protocol; // upper layer protocol => TCP // we set the checksum = 0 for now because that's // what it needs to be when we run the IP checksum iph->ip_sum = 0; } void make_icmp_header(struct icmp *buf) { memset(buf, 0, sizeof(struct icmp)); buf->icmp_type = ICMP_ECHO; buf->icmp_code = 0; buf->icmp_seq = 0; } void make_tcp_header(struct tcphdr *tcp_header, uint16_t th_flags) { tcp_header->th_seq = random(); tcp_header->th_ack = 0; tcp_header->th_x2 = 0; tcp_header->th_off = 5; // data offset tcp_header->th_flags = 0; tcp_header->th_flags |= th_flags; tcp_header->th_win = htons(65535); // largest possible window tcp_header->th_sum = 0; tcp_header->th_urp = 0; } size_t set_mss_option(struct tcphdr *tcp_header) { // This only sets MSS, which is a single-word option. // seems like assumption here is that word-size = 32 bits // MSS field // 0 byte = TCP Option Kind = 0x2 // 1 byte = Length of entire MSS field = 4 // 2-3 byte = Value of MSS size_t header_size = tcp_header->th_off * 4; // 4 is word size uint8_t *base = (uint8_t *)tcp_header; uint8_t *last_opt = (uint8_t *)base + header_size; // TCP Option "header" last_opt[0] = 2; // the value in the TCP options spec denoting this as MSS last_opt[1] = 4; // MSS is 4 bytes long, length goes here // Default Linux MSS is 1460, which 0x05b4 last_opt[2] = 0x05; last_opt[3] = 0xb4; tcp_header->th_off += 1; return tcp_header->th_off * 4; } size_t set_nop_plus_windows_scale(struct tcphdr *tcp_header, uint8_t os) { size_t header_size = tcp_header->th_off * 4; uint8_t *last_opt = (uint8_t *)tcp_header + header_size; // NOP = 1 byte last_opt[0] = 0x01; // kind for NOP last_opt += 1; // WindowScale = 3 bytes last_opt[0] = 0x03; // kind for WindowScale field last_opt[1] = 0x03; // length for WindowScale field if (os == LINUX_OS_OPTIONS) { last_opt[2] = 0x07; // 7 is used as the linux default WindowScale. It represents 2^7 = x128 window size multiplier } else if (os == BSD_OS_OPTIONS) { last_opt[2] = 0x06; // 6 is used as the MacOS/BSD default WindowScale. It represents 2^6 = x64 window size multiplier } else if (os == WINDOWS_OS_OPTIONS) { last_opt[2] = 0x08; // 8 is used as the windows default WindowScale. It represents 2^8 = x256 window size multiplier } tcp_header->th_off += 1; return tcp_header->th_off * 4; } // sets 2x NOPs and a timestamp (10 bytes) option = 12 bytes size_t set_timestamp_option_with_nops(struct tcphdr *tcp_header) { size_t header_size = tcp_header->th_off * 4; uint8_t *last_opt = (uint8_t *)tcp_header + header_size; // NOP = 1 byte last_opt[0] = 0x01; // kind for NOP last_opt[1] = 0x01; // kind for NOP last_opt += 2; // exact method of getting this timestamp isn't important, only that it is a 4 byte value - RFC 7323 uint32_t now = time(NULL); last_opt[0] = 0x08; // kind for timestamp field last_opt[1] = 0x0a; // length for timestamp field *(uint32_t *)(last_opt + 2) = htonl(now); // set current time in correct byte order // final 4 bytes of timestamp field are left zeroed for the timestamp echo value last_opt += 10; // update our pointer 10 bytes ahead tcp_header->th_off += 3; return tcp_header->th_off * 4; } size_t set_sack_permitted_with_timestamp(struct tcphdr *tcp_header) { size_t header_size = tcp_header->th_off * 4; uint8_t *last_opt = (uint8_t *)tcp_header + header_size; // SACKPermitted = 2 bytes last_opt[0] = 0x04; // kind for SACKPermitted last_opt[1] = 0x02; // set the length last_opt += 2; // increment pointer // exact method of getting this timestamp isn't important, only that it is a 4 byte value - RFC 7323 uint32_t now = time(NULL); last_opt[0] = 0x08; // kind for timestamp field last_opt[1] = 0x0a; // length for timestamp field *(uint32_t *)(last_opt + 2) = htonl(now); // set current time in correct byte order // final 4 bytes of timestamp field are left zeroed for the timestamp echo value last_opt += 10; // update our pointer 10 bytes ahead tcp_header->th_off += 3; return tcp_header->th_off * 4; } // sets 2x NOPs and a SACKPermitted (2 bytes) option = 4 bytes size_t set_nop_plus_sack_permitted(struct tcphdr *tcp_header) { size_t header_size = tcp_header->th_off * 4; uint8_t *last_opt = (uint8_t *)tcp_header + header_size; // NOP = 1 byte last_opt[0] = 0x01; // kind for NOP last_opt[1] = 0x01; last_opt += 2; // SACKPermitted = 2 bytes last_opt[0] = 0x04; // kind for SACKPermitted last_opt[1] = 0x02; // set the length last_opt += 2; // increment pointer tcp_header->th_off += 1; return tcp_header->th_off * 4; } size_t set_sack_permitted_plus_eol(struct tcphdr *tcp_header) { size_t header_size = tcp_header->th_off * 4; uint8_t *last_opt = (uint8_t *)tcp_header + header_size; // SACKPermitted = 2 bytes last_opt[0] = 0x04; // kind for SACKPermitted last_opt[1] = 0x02; // set the length last_opt += 2; // increment pointer // EOL = 1 byte last_opt[0] = 0x00; // kind for EOL last_opt[1] = 0x00; // kind for EOL last_opt += 2; // increment pointer tcp_header->th_off += 1; return tcp_header->th_off * 4; } // set_tcp_options adds the relevant TCP options so ZMap-sent packets have the same TCP header as linux-sent ones size_t set_tcp_options(struct tcphdr *tcp_header, uint8_t os_options_type) { if (os_options_type == SMALLEST_PROBES_OS_OPTIONS) { // the minimum Ethernet payload is 46 bytes. A TCP header + IP header is 40 bytes, giving us 6 bytes to work with. // However, the word size is 4 bytes, so we can only use 44 or 48 bytes. Since we're trying to stay as close to the // minimum payload size, we'll use 4 bytes for the MSS option and the last 2 will be padded by the OS. set_mss_option(tcp_header); } else if (os_options_type == LINUX_OS_OPTIONS) { set_mss_option(tcp_header); set_sack_permitted_with_timestamp(tcp_header); set_nop_plus_windows_scale(tcp_header, os_options_type); } else if (os_options_type == BSD_OS_OPTIONS) { set_mss_option(tcp_header); set_nop_plus_windows_scale(tcp_header, os_options_type); set_timestamp_option_with_nops(tcp_header); set_sack_permitted_plus_eol(tcp_header); } else if (os_options_type == WINDOWS_OS_OPTIONS) { set_mss_option(tcp_header); set_nop_plus_windows_scale(tcp_header, os_options_type); set_nop_plus_sack_permitted(tcp_header); } else { // should not his this case log_fatal("packet", "unknown OS for TCP options: %d", os_options_type); } return tcp_header->th_off * 4; } void make_udp_header(struct udphdr *udp_header, uint16_t len) { udp_header->uh_ulen = htons(len); // checksum ignored in IPv4 if 0 udp_header->uh_sum = 0; } int icmp_helper_validate(const struct ip *ip_hdr, uint32_t len, size_t min_l4_len, struct ip **probe_pkt, size_t *probe_len) { // We're only equipped to handle ICMP packets at this point assert(ip_hdr->ip_p == IPPROTO_ICMP); // Several ICMP responses can be generated by hosts along the way in // response to a non-ICMP probe packet. These include: // * Source quench (ICMP_SOURCE_QUENCH) // * Destination Unreachable (ICMP_DEST_UNREACH) // * Redirect (ICMP_REDIRECT) // * Time exceeded (ICMP_TIME_EXCEEDED) // In all of these cases, the IP header and first 8 bytes of the // original packet are included in the responses and can be used // to understand where the probe packet was sent. // Check if the response was large enough to contain an IP header const uint32_t min_len = 4 * ip_hdr->ip_hl + ICMP_HEADER_SIZE + sizeof(struct ip) + min_l4_len; if (len < min_len) { return PACKET_INVALID; } // Check that ICMP response is one of these four struct icmp *icmp = (struct icmp *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); if (!(icmp->icmp_type == ICMP_UNREACH || icmp->icmp_type == ICMP_SOURCEQUENCH || icmp->icmp_type == ICMP_REDIRECT || icmp->icmp_type == ICMP_TIMXCEED)) { return PACKET_INVALID; } struct ip *ip_inner = (struct ip *)((char *)icmp + ICMP_HEADER_SIZE); size_t inner_packet_len = len - (4 * ip_hdr->ip_hl + ICMP_HEADER_SIZE); // Now we know the actual inner ip length, we should recheck the buffer // to make sure it has enough room for the application layer packet if (inner_packet_len < (4 * ip_inner->ip_hl + min_l4_len)) { return PACKET_INVALID; } // find original destination IP and check that we sent a packet // to that IP address uint32_t dest = ip_inner->ip_dst.s_addr; if (!blocklist_is_allowed(dest)) { return PACKET_INVALID; } *probe_pkt = ip_inner; *probe_len = inner_packet_len; return PACKET_VALID; } void fs_add_null_icmp(fieldset_t *fs) { fs_add_null(fs, "icmp_responder"); fs_add_null(fs, "icmp_type"); fs_add_null(fs, "icmp_code"); fs_add_null(fs, "icmp_unreach_str"); } void fs_add_failure_no_port(fieldset_t *fs) { fs_add_null(fs, "icmp_responder"); fs_add_null(fs, "icmp_type"); fs_add_null(fs, "icmp_code"); fs_add_null(fs, "icmp_unreach_str"); } void fs_populate_icmp_from_iphdr(struct ip *ip, size_t len, fieldset_t *fs) { assert(ip && "no ip header provide to fs_populate_icmp_from_iphdr"); assert(fs && "no fieldset provided to fs_populate_icmp_from_iphdr"); struct icmp *icmp = get_icmp_header(ip, len); assert(icmp); // ICMP unreach comes from another server (not the one we sent a // probe to); But we will fix up saddr to be who we sent the // probe to, in case you care. struct ip *ip_inner = get_inner_ip_header(icmp, len); fs_modify_string(fs, "saddr", make_ip_str(ip_inner->ip_dst.s_addr), 1); // Add other ICMP fields from within the header fs_add_string(fs, "icmp_responder", make_ip_str(ip->ip_src.s_addr), 1); fs_add_uint64(fs, "icmp_type", icmp->icmp_type); fs_add_uint64(fs, "icmp_code", icmp->icmp_code); if (icmp->icmp_code <= ICMP_UNREACH_PRECEDENCE_CUTOFF) { fs_add_constchar(fs, "icmp_unreach_str", icmp_unreach_strings[icmp->icmp_code]); } else { fs_add_constchar(fs, "icmp_unreach_str", "unknown"); } } // Note: caller must free return value char *make_ip_str(uint32_t ip) { struct in_addr t; t.s_addr = ip; const char *temp = inet_ntoa(t); char *retv = xmalloc(strlen(temp) + 1); strcpy(retv, temp); return retv; } const char *icmp_unreach_strings[] = { "network unreachable", "host unreachable", "protocol unreachable", "port unreachable", "fragments required", "source route failed", "network unknown", "host unknown", "source host isolated", "network admin. prohibited", "host admin. prohibited", "network unreachable TOS", "host unreachable TOS", "communication admin. prohibited", "host presdence violation", "precedence cutoff"}; zmap-4.3.4/src/probe_modules/packet.h000066400000000000000000000170741501046211500175430ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "../../lib/includes.h" #include "../../lib/blocklist.h" #include "../../lib/pbm.h" #include "../state.h" #include "../send.h" #ifndef PACKET_H #define PACKET_H #define ICMP_UNREACH_HEADER_SIZE 8 #define PACKET_VALID 1 #define PACKET_INVALID 0 #define ICMP_HEADER_SIZE 8 #define PRINT_PACKET_SEP \ "------------------------------------------------------\n" #define CLASSIFICATION_SUCCESS_FIELDSET_FIELDS \ {.name = "classification", \ .type = "string", \ .desc = "packet classification"}, \ { \ .name = "success", .type = "bool", \ .desc = "is response considered success" \ } #define CLASSIFICATION_SUCCESS_FIELDSET_LEN 2 #define ICMP_FIELDSET_FIELDS \ {.name = "icmp_responder", \ .type = "string", \ .desc = "Source IP of ICMP_UNREACH messages"}, \ {.name = "icmp_type", .type = "int", .desc = "icmp message type"}, \ {.name = "icmp_code", \ .type = "int", \ .desc = "icmp message sub type code"}, \ { \ .name = "icmp_unreach_str", .type = "string", \ .desc = \ "for icmp_unreach responses, the string version of icmp_code (e.g. network-unreach)" \ } #define ICMP_FIELDSET_LEN 4 typedef unsigned short __attribute__((__may_alias__)) alias_unsigned_short; void make_eth_header(struct ether_header *ethh, macaddr_t *src, macaddr_t *dst); void make_ip_header(struct ip *iph, uint8_t, uint16_t); void make_tcp_header(struct tcphdr *, uint16_t th_flags); size_t set_mss_option(struct tcphdr *tcp_header); size_t set_tcp_options(struct tcphdr *tcp_header, uint8_t os); void make_icmp_header(struct icmp *); void make_udp_header(struct udphdr *udp_header, uint16_t len); void fprintf_ip_header(FILE *fp, struct ip *iph); void fprintf_eth_header(FILE *fp, struct ether_header *ethh); static inline unsigned short in_checksum(unsigned short *ip_pkt, int len) { unsigned long sum = 0; for (int nwords = len / 2; nwords > 0; nwords--) { sum += *ip_pkt++; } if (len % 2 == 1) { sum += *((unsigned char *)ip_pkt); } sum = (sum >> 16) + (sum & 0xffff); return (unsigned short)(~sum); } static inline unsigned short in_icmp_checksum(unsigned short *ip_pkt, int len) { unsigned long sum = 0; for (int nwords = len / 2; nwords > 0; nwords--) { sum += *ip_pkt++; } if (len % 2 == 1) { sum += *((unsigned char *)ip_pkt); } sum = (sum >> 16) + (sum & 0xffff); return (unsigned short)(~sum); } static inline unsigned short zmap_ip_checksum(unsigned short *buf) { return in_checksum(buf, (int)sizeof(struct ip)); } static inline unsigned short icmp_checksum(unsigned short *buf, size_t buflen) { return in_icmp_checksum(buf, buflen); } static inline uint16_t tcp_checksum(unsigned short len_tcp, uint32_t saddr, uint32_t daddr, struct tcphdr *tcp_pkt) { alias_unsigned_short *src_addr = (alias_unsigned_short *)&saddr; alias_unsigned_short *dest_addr = (alias_unsigned_short *)&daddr; unsigned char prot_tcp = 6; unsigned long sum = 0; int nleft = len_tcp; unsigned short *w; w = (unsigned short *)tcp_pkt; // calculate the checksum for the tcp header and tcp data while (nleft > 1) { sum += *w++; nleft -= 2; } // if nleft is 1 there is still one byte left. // We add a padding byte (0xFF) to build a 16bit word if (nleft > 0) { sum += *w & ntohs(0xFF00); } // add the pseudo header sum += src_addr[0]; sum += src_addr[1]; sum += dest_addr[0]; sum += dest_addr[1]; sum += htons(len_tcp); sum += htons(prot_tcp); sum = (sum >> 16) + (sum & 0xFFFF); sum += (sum >> 16); // Take the one's complement of sum return (unsigned short)(~sum); } // Returns 0 if dst_port is outside the expected valid range, non-zero otherwise static inline int check_dst_port(uint16_t port, int num_ports, uint32_t *validation) { if (port > zconf.source_port_last || port < zconf.source_port_first) { return 0; } int32_t to_validate = port - zconf.source_port_first; int32_t min = validation[1] % num_ports; int32_t max = (validation[1] + zconf.packet_streams - 1) % num_ports; if (min <= max) { return (to_validate <= max && to_validate >= min); } else { return ((to_validate <= max) != (to_validate >= min)); } } static inline uint16_t get_src_port(int num_ports, int probe_num, uint32_t *validation) { return zconf.source_port_first + ((validation[1] + probe_num) % num_ports); } static inline int check_src_port(uint16_t port, const struct port_conf *ports) { return bm_check(ports->port_bitmap, port); } static inline struct ip *get_ip_header(const u_char *packet, uint32_t len) { if (len < sizeof(struct ether_header)) { return NULL; } return (struct ip *)&packet[sizeof(struct ether_header)]; } static inline struct tcphdr *get_tcp_header(const struct ip *ip_hdr, uint32_t len) { // buf not large enough to contain expected tcp header if ((4 * ip_hdr->ip_hl + sizeof(struct tcphdr)) > len) { return NULL; } return (struct tcphdr *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); } static inline struct udphdr *get_udp_header(const struct ip *ip_hdr, uint32_t len) { // buf not large enough to contain expected udp header if ((4 * ip_hdr->ip_hl + sizeof(struct udphdr)) > len) { return NULL; } return (struct udphdr *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); } static inline struct icmp *get_icmp_header(const struct ip *ip_hdr, uint32_t len) { // buf not large enough to contain expected icmp header if ((4 * ip_hdr->ip_hl + sizeof(struct icmp)) > len) { return NULL; } return (struct icmp *)((char *)ip_hdr + 4 * ip_hdr->ip_hl); } static inline uint8_t *get_udp_payload(const struct udphdr *udp, UNUSED uint32_t len) { return (uint8_t *)(&udp[1]); } static inline struct ip *get_inner_ip_header(const struct icmp *icmp, uint32_t len) { if (len < (ICMP_UNREACH_HEADER_SIZE + sizeof(struct ip))) { return NULL; } return (struct ip *)((char *)icmp + ICMP_UNREACH_HEADER_SIZE); } // Note: caller must free return value char *make_ip_str(uint32_t ip); extern const char *icmp_unreach_strings[]; int icmp_helper_validate(const struct ip *ip_hdr, uint32_t len, size_t min_l4_len, struct ip **probe_pkt, size_t *probe_len); void fs_add_null_icmp(fieldset_t *fs); void fs_populate_icmp_from_iphdr(struct ip *ip, size_t len, fieldset_t *fs); #endif zmap-4.3.4/src/probe_modules/probe_modules.c000066400000000000000000000101211501046211500211100ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include #include #include "../../lib/includes.h" #include "../../lib/logger.h" #include "../../lib/xalloc.h" #include "../fieldset.h" #include "probe_modules.h" #include "packet.h" extern probe_module_t module_tcp_synscan; extern probe_module_t module_tcp_synackscan; extern probe_module_t module_icmp_echo; extern probe_module_t module_icmp_echo_time; extern probe_module_t module_udp; extern probe_module_t module_ntp; extern probe_module_t module_upnp; extern probe_module_t module_dns; extern probe_module_t module_ipip; extern probe_module_t module_bacnet; // ADD YOUR MODULE HERE probe_module_t *probe_modules[] = { &module_tcp_synscan, &module_tcp_synackscan, &module_icmp_echo, &module_icmp_echo_time, &module_udp, &module_ntp, &module_upnp, &module_dns, &module_bacnet, &module_ipip, // ADD YOUR MODULE HERE }; probe_module_t *get_probe_module_by_name(const char *name) { int len = (int)(sizeof(probe_modules) / sizeof(probe_modules[0])); for (int i = 0; i < len; i++) { if (!strcmp(probe_modules[i]->name, name)) { return probe_modules[i]; } } return NULL; } void print_probe_modules(void) { int len = (int)(sizeof(probe_modules) / sizeof(probe_modules[0])); for (int i = 0; i < len; i++) { printf("%s\n", probe_modules[i]->name); } } void fs_add_ip_fields(fieldset_t *fs, struct ip *ip) { // WARNING: you must update fs_ip_fields_len as well // as the definitions set (ip_fiels) if you // change the fields added below: fs_add_string(fs, "saddr", make_ip_str(ip->ip_src.s_addr), 1); fs_add_uint64(fs, "saddr_raw", (uint64_t)ip->ip_src.s_addr); fs_add_string(fs, "daddr", make_ip_str(ip->ip_dst.s_addr), 1); fs_add_uint64(fs, "daddr_raw", (uint64_t)ip->ip_dst.s_addr); fs_add_uint64(fs, "ipid", ntohs(ip->ip_id)); fs_add_uint64(fs, "ttl", ip->ip_ttl); } #define TIMESTR_LEN 55 void fs_add_system_fields(fieldset_t *fs, int is_repeat, int in_cooldown, const struct timespec ts) { fs_add_bool(fs, "repeat", is_repeat); fs_add_bool(fs, "cooldown", in_cooldown); char *timestr = xmalloc(TIMESTR_LEN + 1); char *timestr_ms = xmalloc(TIMESTR_LEN + 1); struct tm *ptm = localtime(&ts.tv_sec); strftime(timestr, TIMESTR_LEN, "%Y-%m-%dT%H:%M:%S.%%03d%z", ptm); snprintf(timestr_ms, TIMESTR_LEN, timestr, ts.tv_nsec / 1000000); free(timestr); fs_add_string(fs, "timestamp_str", timestr_ms, 1); fs_add_uint64(fs, "timestamp_ts", (uint64_t)ts.tv_sec); fs_add_uint64(fs, "timestamp_us", (uint64_t)(ts.tv_nsec/1000)); } int ip_fields_len = 6; fielddef_t ip_fields[] = { {.name = "saddr", .type = "string", .desc = "source IP address of response"}, {.name = "saddr_raw", .type = "int", .desc = "network order integer form of source IP address"}, {.name = "daddr", .type = "string", .desc = "destination IP address of response"}, {.name = "daddr_raw", .type = "int", .desc = "network order integer form of destination IP address"}, {.name = "ipid", .type = "int", .desc = "IP identification number of response"}, {.name = "ttl", .type = "int", .desc = "time-to-live of response packet"}}; int sys_fields_len = 5; fielddef_t sys_fields[] = { {.name = "repeat", .type = "bool", .desc = "Is response a repeat response from host"}, {.name = "cooldown", .type = "bool", .desc = "Was response received during the cooldown period"}, {.name = "timestamp_str", .type = "string", .desc = "timestamp of when response arrived in ISO8601 format."}, {.name = "timestamp_ts", .type = "int", .desc = "timestamp of when response arrived in seconds since Epoch"}, {.name = "timestamp_us", .type = "int", .desc = "microsecond part of timestamp (e.g. microseconds since 'timestamp-ts')"}}; zmap-4.3.4/src/probe_modules/probe_modules.h000066400000000000000000000113261501046211500211250ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "../state.h" #include "../fieldset.h" #ifndef PROBE_MODULES_H #define PROBE_MODULES_H #define OUTPUT_TYPE_STATIC 1 #define OUTPUT_TYPE_DYNAMIC 2 // Source Port Validation Override by User, overrides module default behavior #define VALIDATE_SRC_PORT_UNSET_OVERRIDE -1 #define VALIDATE_SRC_PORT_DISABLE_OVERRIDE 0 #define VALIDATE_SRC_PORT_ENABLE_OVERRIDE 1 typedef struct probe_response_type { const uint8_t is_success; const char *name; } response_type_t; typedef int (*probe_global_init_cb)(struct state_conf *); // Called once per send thread to initialize state. typedef int (*probe_thread_init_cb)(void **arg_ptr); // The make_packet callback is passed a buffer pointing at an ethernet header. // The buffer is MAX_PACKET_SIZE bytes. There are 1..n packet buffers in use // per send thread. For each buffer, prepare_packet is called once before the // first call to make_packet. // // The probe module is expected to write all the constant packet contents // in prepare_packet, and only write the fields that need to be updated for // each packet being sent in make_packet. // typedef int (*probe_prepare_packet_cb)(void *packetbuf, macaddr_t *src_mac, macaddr_t *gw_mac, void *arg); // The make_packet callback is passed a buffer pointing at an ethernet header. // The buffer is MAX_PACKET_SIZE bytes. The callback must update the value // pointed at by buf_len with the actual length of the packet. The contents of // the buffer will match a previously sent packet by this send thread, so // content not overwritten by make_packet can be relied upon to be intact. // Beyond that, the probe module should not make any assumptions about buffers. // Every invocation of make_packet contains a unique (src_ip, probe_num) tuple. // // The probe module is responsible for populating the IP header. The src_ip, // dst_ip, and ttl are provided by the framework and must be set on the IP // header. // // The uin32_t validation parameter is a pointer to four 4-byte words of // validation data. The data is deterministic based on the the validation // state, and is constant across a src_ip. To get the src_port, use the // get_src_port function which takes probe_num and validation as parameters. // typedef int (*probe_make_packet_cb)(void *packetbuf, size_t *buf_len, ipaddr_n_t src_ip, ipaddr_n_t dst_ip, port_n_t dst_port, uint8_t ttl, uint32_t *validation, int probe_num, uint16_t ip_id, void *arg); typedef void (*probe_print_packet_cb)(FILE *, void *packetbuf); typedef int (*probe_close_cb)(struct state_conf *, struct state_send *, struct state_recv *); typedef int (*probe_validate_packet_cb)(const struct ip *ip_hdr, uint32_t len, uint32_t *src_ip, uint32_t *validation, const struct port_conf *ports); typedef void (*probe_classify_packet_cb)(const u_char *packetbuf, uint32_t len, fieldset_t *, uint32_t *validation, const struct timespec ts); typedef struct probe_module { const char *name; // TODO(dadrian): Completely get rid of this. We can do bandwidth rate // limiting by actually counting how much data is sent over the wire. We // know the lengths of packets from the make_packet API. size_t max_packet_length; const char *pcap_filter; size_t pcap_snaplen; // Should ZMap complain if the user hasn't specified valid // source and target port numbers? uint8_t port_args; probe_global_init_cb global_initialize; probe_thread_init_cb thread_initialize; probe_prepare_packet_cb prepare_packet; probe_make_packet_cb make_packet; probe_print_packet_cb print_packet; probe_validate_packet_cb validate_packet; probe_classify_packet_cb process_packet; probe_close_cb close; int output_type; fielddef_t *fields; int numfields; const char *helptext; } probe_module_t; probe_module_t *get_probe_module_by_name(const char *); void fs_add_ip_fields(fieldset_t *fs, struct ip *ip); void fs_add_system_fields(fieldset_t *fs, int is_repeat, int in_cooldown, const struct timespec ts); void print_probe_modules(void); extern int ip_fields_len; extern int sys_fields_len; extern fielddef_t ip_fields[]; extern fielddef_t sys_fields[]; #endif // HEADER_PROBE_MODULES_H zmap-4.3.4/src/recv-internal.h000066400000000000000000000010721501046211500161750ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_RECV_INTERNAL_H #define ZMAP_RECV_INTERNAL_H #include void handle_packet(uint32_t buflen, const uint8_t *bytes, const struct timespec ts); void recv_init(void); void recv_packets(void); void recv_cleanup(void); #endif /* ZMAP_RECV_INTERNAL_H */ zmap-4.3.4/src/recv-netmap.c000066400000000000000000000302601501046211500156410ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #if !(defined(__FreeBSD__) || defined(__linux__)) #error "NETMAP requires FreeBSD or Linux" #endif #include "recv.h" #include "recv-internal.h" #include "socket.h" #include "send.h" #include "send-internal.h" #include "probe_modules/packet.h" #include "if-netmap.h" #include "state.h" #include "../lib/includes.h" #include "../lib/logger.h" #include #include #include #include #include #include #include #include #include #include #include static void handle_packet_wait_ping(uint32_t buflen, const uint8_t *bytes, UNUSED const struct timespec ts); static void (*handle_packet_func)(uint32_t buflen, const uint8_t *bytes, const struct timespec ts); typedef size_t (*make_packet_func_t)(uint8_t *buf, void const *arg); // Send a packet on a netmap ring and fd directly. // Used to send packets before send threads are up. static void send_packet(make_packet_func_t mkpkt, void const *arg) { // Synthesize a sock_t for the main netmap fd. // We're syncing all TX rings this way, not just ring 0. sock_t sock; sock.nm.tx_ring_idx = 0; sock.nm.tx_ring_fd = zconf.nm.nm_fd; batch_t *batch = create_packet_batch(1); batch->packets[0].len = mkpkt(batch->packets[0].buf, arg); assert(batch->packets[0].len <= MAX_PACKET_SIZE); batch->len = 1; if (send_batch_internal(sock, batch) != 1) { log_fatal("recv-netmap", "Failed to send packet: %d: %s", errno, strerror(errno)); } free_packet_batch(batch); } // Submit a packet for sending by send thread 0. // Used to send packets after send threads are up. // Submitted packets are sent once per scan batch. static void submit_packet(make_packet_func_t mkpkt, void const *arg) { batch_t *batch = create_packet_batch(1); batch->packets[0].len = mkpkt(batch->packets[0].buf, arg); assert(batch->packets[0].len <= MAX_PACKET_SIZE); batch->len = 1; submit_batch_internal(batch); // consumes batch } // In netmap mode, the OS network stack never gets to see incoming packets // unless we explicitly forward them to the host rings; hence the kernel will // not be responding to ARP requests. To remove the need for static ARP // entries on the gateway, respond to ARP requests from the gateway for any of // the source IPs of the scan. #define ARP_ETHER_INET_PKT_LEN (sizeof(struct ether_header) + sizeof(struct arphdr) + 2 * ETHER_ADDR_LEN + 2 * sizeof(uint32_t)) #define x_ar_sha(ap) ((uint8_t *)((ap) + 1)) #define x_ar_spa(ap) (((uint8_t *)((ap) + 1)) + ETHER_ADDR_LEN) #define x_ar_tha(ap) (((uint8_t *)((ap) + 1)) + ETHER_ADDR_LEN + sizeof(uint32_t)) #define x_ar_tpa(ap) (((uint8_t *)((ap) + 1)) + 2 * ETHER_ADDR_LEN + sizeof(uint32_t)) static size_t make_arp_resp(uint8_t *buf, void const *arg) { struct arphdr const *req_ah = (struct arphdr const *)arg; struct ether_header *eh = (struct ether_header *)buf; memcpy(eh->ether_shost, zconf.hw_mac, ETHER_ADDR_LEN); memcpy(eh->ether_dhost, x_ar_sha(req_ah), ETHER_ADDR_LEN); eh->ether_type = htons(ETHERTYPE_ARP); struct arphdr *ah = (struct arphdr *)(eh + 1); ah->ar_hrd = htons(ARPHRD_ETHER); ah->ar_pro = htons(ETHERTYPE_IP); ah->ar_hln = ETHER_ADDR_LEN; ah->ar_pln = sizeof(uint32_t); ah->ar_op = htons(ARPOP_REPLY); memcpy(x_ar_sha(ah), zconf.hw_mac, ETHER_ADDR_LEN); *(uint32_t *)x_ar_spa(ah) = *(uint32_t *)x_ar_tpa(req_ah); memcpy(x_ar_tha(ah), x_ar_sha(req_ah), ETHER_ADDR_LEN); *(uint32_t *)x_ar_tpa(ah) = *(uint32_t *)x_ar_spa(req_ah); return ARP_ETHER_INET_PKT_LEN; } static void handle_packet_arp(uint32_t buflen, const uint8_t *bytes, UNUSED const struct timespec ts) { if (buflen < ARP_ETHER_INET_PKT_LEN) { return; } struct ether_header *eh = (struct ether_header *)bytes; if (eh->ether_type != htons(ETHERTYPE_ARP)) { return; } struct arphdr *ah = (struct arphdr *)(eh + 1); if (ah->ar_op != htons(ARPOP_REQUEST) || ah->ar_hrd != htons(ARPHRD_ETHER) || ah->ar_pro != htons(ETHERTYPE_IP) || ah->ar_hln != ETHER_ADDR_LEN || ah->ar_pln != sizeof(uint32_t)) { return; } macaddr_t *sender_hardware_address = (macaddr_t *)x_ar_sha(ah); if (memcmp(sender_hardware_address, eh->ether_shost, ETHER_ADDR_LEN) != 0 || memcmp(sender_hardware_address, zconf.gw_mac, ETHER_ADDR_LEN) != 0) { return; } in_addr_t target_protocol_address = *(in_addr_t *)x_ar_tpa(ah); for (size_t i = 0; i < zconf.number_source_ips; i++) { if (target_protocol_address == zconf.source_ip_addresses[i]) { log_debug("recv-netmap", "Received ARP request from gateway"); if (handle_packet_func == handle_packet_wait_ping) { send_packet(make_arp_resp, (void const *)ah); } else { submit_packet(make_arp_resp, (void const *)ah); } return; } } } static size_t make_wait_ping_req(uint8_t *buf, UNUSED void const *arg) { struct ether_header *eh = (struct ether_header *)buf; make_eth_header(eh, zconf.hw_mac, zconf.gw_mac); struct ip *iph = (struct ip *)(eh + 1); uint16_t iplen = sizeof(struct ip) + ICMP_MINLEN; make_ip_header(iph, IPPROTO_ICMP, htons(iplen)); iph->ip_src.s_addr = zconf.source_ip_addresses[0]; iph->ip_dst.s_addr = zconf.nm.wait_ping_dstip; struct icmp *icmph = (struct icmp *)(iph + 1); memset(icmph, 0, sizeof(struct icmp)); icmph->icmp_type = ICMP_ECHO; icmph->icmp_cksum = icmp_checksum((unsigned short *)icmph, ICMP_MINLEN); iph->ip_sum = 0; iph->ip_sum = zmap_ip_checksum((unsigned short *)iph); return sizeof(struct ether_header) + iplen; } static void handle_packet_wait_ping(uint32_t buflen, const uint8_t *bytes, UNUSED const struct timespec ts) { if (buflen < sizeof(struct ether_header) + sizeof(struct ip) + ICMP_MINLEN) { return; } struct ether_header *eh = (struct ether_header *)bytes; if (eh->ether_type != htons(ETHERTYPE_IP)) { return; } struct ip *iph = (struct ip *)(eh + 1); if (iph->ip_v != 4 || iph->ip_p != IPPROTO_ICMP || iph->ip_src.s_addr != zconf.nm.wait_ping_dstip) { return; } struct icmp *icmph = (struct icmp *)(iph + 1); if (icmph->icmp_type != ICMP_ECHOREPLY) { return; } log_debug("recv-netmap", "Received ICMP echo reply, ready to commence scan"); handle_packet_func = handle_packet; } #ifndef NSEC_PER_SEC #define NSEC_PER_SEC 1000000000 #endif static struct timespec timespec_diff(struct timespec const *t1, struct timespec const *t0) { struct timespec diff = { .tv_sec = t1->tv_sec - t0->tv_sec, .tv_nsec = t1->tv_nsec - t0->tv_nsec, }; if (diff.tv_nsec < 0) { diff.tv_sec--; diff.tv_nsec += NSEC_PER_SEC; } return diff; } static void timespec_get_monotonic(struct timespec *t) { if (clock_gettime(CLOCK_MONOTONIC, t) == -1) { log_fatal("recv-netmap", "Failed to obtain monotonic time: %d: %s", errno, strerror(errno)); } } // Drive RX and TX ringbuffers directly to wait for end-to-end connectivity. // Ping an IP address every second and do not return before receiving a reply. static void wait_for_e2e_connectivity(void) { static const time_t timeout_secs = 60; struct timespec t_start; timespec_get_monotonic(&t_start); struct timespec t_last_send; memset(&t_last_send, 0, sizeof(t_last_send)); // handle_packet_wait_ping called from recv_packets will // set handle_packet_func to handle_packet upon receipt // of the expected ICMP echo response packet. while (handle_packet_func == handle_packet_wait_ping) { struct timespec t_now; timespec_get_monotonic(&t_now); if (timespec_diff(&t_now, &t_start).tv_sec >= timeout_secs) { log_fatal("recv-netmap", "No ICMP echo reply received in %zus", (size_t)timeout_secs); } if (timespec_diff(&t_now, &t_last_send).tv_sec >= 1) { send_packet(make_wait_ping_req, NULL); timespec_get_monotonic(&t_last_send); log_debug("recv-netmap", "Sent ICMP echo request"); } recv_packets(); } } static struct pollfd fds; static struct netmap_if *nm_if; static bool *in_multi_seg_packet; static if_stats_ctx_t *stats_ctx; static bool need_recv_counter; static uint64_t recv_counter; void recv_init(void) { fds.fd = zconf.nm.nm_fd; fds.events = POLLIN; nm_if = zconf.nm.nm_if; in_multi_seg_packet = (bool *)malloc(nm_if->ni_rx_rings * sizeof(bool)); assert(in_multi_seg_packet); for (size_t ri = 0; ri < nm_if->ni_rx_rings; ri++) { in_multi_seg_packet[ri] = false; } zconf.data_link_size = if_get_data_link_size(zconf.iface, zconf.nm.nm_fd); log_debug("recv-netmap", "data_link_size %d", zconf.data_link_size); if (zconf.nm.wait_ping_dstip != 0) { handle_packet_func = handle_packet_wait_ping; wait_for_e2e_connectivity(); } else { handle_packet_func = handle_packet; } stats_ctx = if_stats_init(zconf.iface, zconf.nm.nm_fd); assert(stats_ctx); need_recv_counter = !if_stats_have_recv_ctr(stats_ctx); if (need_recv_counter) { recv_counter = 0; } } void recv_cleanup(void) { if_stats_fini(stats_ctx); stats_ctx = NULL; free(in_multi_seg_packet); in_multi_seg_packet = NULL; nm_if = NULL; } void recv_packets(void) { // On Linux, EINTR seems to happen here once at startup. // Haven't seen any EINTR on FreeBSD. Retry is not wrong // and making the total delay longer should not hurt. // We may want to look into the root cause some time tho. for (ssize_t retry = 5; retry >= 0; retry--) { int ret = poll(&fds, 1, 100 /* ms */); if (ret > 0) { break; } else if (ret == 0) { return; } else if (errno != EINTR || retry == 0) { log_error("recv-netmap", "poll(POLLIN) failed: %d: %s", errno, strerror(errno)); return; } else { log_debug("recv-netmap", "poll(POLLIN) failed: %d: %s (retrying)", errno, strerror(errno)); } } for (unsigned int ri = 0; ri < nm_if->ni_rx_rings; ri++) { struct netmap_ring *rxring = NETMAP_RXRING(nm_if, ri); unsigned head = rxring->head; unsigned tail = rxring->tail; for (; head != tail; head = nm_ring_next(rxring, head)) { struct netmap_slot *slot = rxring->slot + head; // Some NICs can produce multi-segment packets, // e.g. ixgbe and i40e on Linux. // A multi-segment packet is a single received // frame split into multiple netmap buffers; // "segment" here refers neither to TCP // segmentation, nor IP fragmentation. // // In the absence of ZMap support for handling // vectored packets, to avoid the overhead of // reassembly into contiguous memory, and based // on the premise that ZMap scans won't need to // see full packet data for packets larger than // txring->nr_buf_size, pass the first segment // to the handler and skip the rest. // // We cannot depend on multi-segment packets // all fitting into a ring in one sync, thus // have to keep track of state across calls to // recv_packets(). if ((slot->flags & NS_MOREFRAG) != 0) { if (in_multi_seg_packet[ri]) { // Middle segment. continue; } else { // Head segment. in_multi_seg_packet[ri] = true; } } else if (in_multi_seg_packet[ri]) { // Tail segment. in_multi_seg_packet[ri] = false; continue; } char *buf = NETMAP_BUF(rxring, slot->buf_idx); struct timespec ts; ts.tv_sec = rxring->ts.tv_sec; ts.tv_nsec = rxring->ts.tv_usec * 1000; if (need_recv_counter) { recv_counter++; } handle_packet_arp(slot->len, (uint8_t *)buf, ts); handle_packet_func(slot->len, (uint8_t *)buf, ts); } rxring->cur = rxring->head = head; } #if 0 // We can get by without this sync because we are getting // called again in a tight loop and poll() will sync then, // saving us a kernel round trip. // When we are done and the outer loop is broken, then we // do not care about dropped packets anymore anyway, as we // will be about to terminate. // Leaving this here for future debugging. if (ioctl(fds.fd, NIOCRXSYNC, NULL) == -1) { log_error("recv-netmap", "ioctl(NIOCRXSYNC) failed: %d: %s", errno, strerror(errno)); } #endif } int recv_update_stats(void) { if (!stats_ctx) { return EXIT_FAILURE; } if (if_stats_get(stats_ctx, &zrecv.pcap_recv, &zrecv.pcap_drop, &zrecv.pcap_ifdrop) == -1) { return EXIT_FAILURE; } if (need_recv_counter) { zrecv.pcap_recv = (uint32_t)recv_counter; } return EXIT_SUCCESS; } zmap-4.3.4/src/recv-pcap.c000066400000000000000000000075551501046211500153130ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "recv.h" #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/logger.h" #include #include #if defined __linux__ && __linux__ #include #endif #include "recv-internal.h" #include "state.h" #include "probe_modules/probe_modules.h" #define PCAP_PROMISC 1 #define PCAP_TIMEOUT 100 static pcap_t *pc = NULL; void packet_cb(u_char __attribute__((__unused__)) * user, const struct pcap_pkthdr *p, const u_char *bytes) { struct timespec ts; if (!p) { return; } if (zrecv.filter_success >= zconf.max_results) { // Libpcap can process multiple packets per pcap_dispatch; // we need to throw out results once we've // gotten our --max-results worth. return; } // length of entire packet captured by libpcap uint32_t buflen = (uint32_t)p->caplen; ts.tv_sec = p->ts.tv_sec; ts.tv_nsec = p->ts.tv_usec * 1000; handle_packet(buflen, bytes, ts); } #define BPFLEN 1024 void recv_init(void) { char bpftmp[BPFLEN]; char errbuf[PCAP_ERRBUF_SIZE]; pc = pcap_open_live(zconf.iface, zconf.probe_module->pcap_snaplen, PCAP_PROMISC, PCAP_TIMEOUT, errbuf); if (pc == NULL) { log_fatal("recv", "could not open device %s: %s", zconf.iface, errbuf); } switch (pcap_datalink(pc)) { case DLT_NULL: // utun on macOS log_debug("recv", "BSD loopback encapsulation"); zconf.data_link_size = 4; break; case DLT_EN10MB: log_debug("recv", "Data link layer Ethernet"); zconf.data_link_size = sizeof(struct ether_header); break; case DLT_RAW: log_info("recv", "Data link RAW"); zconf.data_link_size = 0; break; #if defined __linux__ && __linux__ case DLT_LINUX_SLL: log_info("recv", "Data link cooked socket"); zconf.data_link_size = SLL_HDR_LEN; break; #endif default: log_error("recv", "unknown data link layer: %u", pcap_datalink(pc)); } struct bpf_program bpf; if (!zconf.send_ip_pkts) { snprintf(bpftmp, sizeof(bpftmp) - 1, "not ether src %02x:%02x:%02x:%02x:%02x:%02x", zconf.hw_mac[0], zconf.hw_mac[1], zconf.hw_mac[2], zconf.hw_mac[3], zconf.hw_mac[4], zconf.hw_mac[5]); assert(strlen(zconf.probe_module->pcap_filter) + 10 < (BPFLEN - strlen(bpftmp))); } else { bpftmp[0] = 0; } if (zconf.probe_module->pcap_filter) { if (!zconf.send_ip_pkts) { strcat(bpftmp, " and ("); } else { strcat(bpftmp, "("); } strcat(bpftmp, zconf.probe_module->pcap_filter); strcat(bpftmp, ")"); } if (strcmp(bpftmp, "")) { if (pcap_compile(pc, &bpf, bpftmp, 1, 0) < 0) { log_fatal("recv", "couldn't compile filter"); } if (pcap_setfilter(pc, &bpf) < 0) { log_fatal("recv", "couldn't install filter"); } } // set pcap_dispatch to not hang if it never receives any packets // this could occur if you ever scan a small number of hosts as // documented in issue #74. if (pcap_setnonblock(pc, 1, errbuf) == -1) { log_fatal("recv", "pcap_setnonblock error:%s", errbuf); } } void recv_packets(void) { int ret = pcap_dispatch(pc, -1, packet_cb, NULL); if (ret == -1) { log_fatal("recv", "pcap_dispatch error"); } else if (ret == 0) { usleep(1000); } } void recv_cleanup(void) { pcap_close(pc); pc = NULL; } int recv_update_stats(void) { if (!pc) { return EXIT_FAILURE; } struct pcap_stat pcst; if (pcap_stats(pc, &pcst)) { log_error("recv", "unable to retrieve pcap statistics: %s", pcap_geterr(pc)); return EXIT_FAILURE; } else { zrecv.pcap_recv = pcst.ps_recv; zrecv.pcap_drop = pcst.ps_drop; zrecv.pcap_ifdrop = pcst.ps_ifdrop; } return EXIT_SUCCESS; } zmap-4.3.4/src/recv-pfring.c000066400000000000000000000034701501046211500156450ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "recv.h" #include "recv-internal.h" #include "../lib/includes.h" #include "../lib/logger.h" #include #include #include #include "state.h" static pfring_zc_pkt_buff *pf_buffer; static pfring_zc_queue *pf_recv; void recv_init() { // Get the socket and packet handle pf_recv = zconf.pf.recv; pf_buffer = pfring_zc_get_packet_handle(zconf.pf.cluster); if (pf_buffer == NULL) { log_fatal("recv", "Could not get packet handle: %s", strerror(errno)); } zconf.data_link_size = sizeof(struct ether_header); } void recv_cleanup() { if (!pf_recv) { return; } pfring_zc_sync_queue(pf_recv, rx_only); } void recv_packets() { int ret = pfring_zc_recv_pkt(pf_recv, &pf_buffer, 0); // Empty queue, return to let outer loop check for termination if (ret == 0) { usleep(1000); return; } // Handle other errors, by not doing anything and logging if (ret != 1) { log_error("recv", "Error: %d", ret); return; } // Successfully got a packet, now handle it struct timespec ts; ts.tv_sec = pf_buffer->ts.tv_sec; ts.tv_nsec = pf_buffer->ts.tv_nsec; //* 1000; uint8_t *pkt_buf = pfring_zc_pkt_buff_data(pf_buffer, pf_recv); handle_packet(pf_buffer->len, pkt_buf, ts); } int recv_update_stats(void) { if (!pf_recv) { return EXIT_FAILURE; } pfring_zc_stat pfst; if (pfring_zc_stats(pf_recv, &pfst)) { log_error("recv", "unable to retrieve pfring statistics"); return EXIT_FAILURE; } else { zrecv.pcap_recv = pfst.recv; zrecv.pcap_drop = pfst.drop; } return EXIT_SUCCESS; } zmap-4.3.4/src/recv.c000066400000000000000000000155741501046211500143720ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "recv.h" #include #include "../lib/includes.h" #include "cachehash.h" #include "../lib/util.h" #include "../lib/logger.h" #include "../lib/pbm.h" #include #include #include "recv-internal.h" #include "state.h" #include "validate.h" #include "fieldset.h" #include "shard.h" #include "expression.h" #include "probe_modules/packet.h" #include "probe_modules/probe_modules.h" #include "output_modules/output_modules.h" static u_char fake_eth_hdr[65535]; // bitmap of observed IP addresses static uint8_t **seen = NULL; static cachehash *ch = NULL; void handle_packet(uint32_t buflen, const u_char *bytes, const struct timespec ts) { if ((sizeof(struct ip) + zconf.data_link_size) > buflen) { // buffer not large enough to contain ethernet // and ip headers. further action would overrun buf return; } struct ip *ip_hdr = (struct ip *)&bytes[zconf.data_link_size]; uint32_t src_ip = ip_hdr->ip_src.s_addr; uint16_t src_port = 0; uint32_t len_ip_and_payload = buflen - (zconf.send_ip_pkts ? 0 : sizeof(struct ether_header)); // extract port if TCP or UDP packet to both generate validation data and to // check if the response is a duplicate if (ip_hdr->ip_p == IPPROTO_TCP) { struct tcphdr *tcp = get_tcp_header(ip_hdr, len_ip_and_payload); if (tcp) { src_port = tcp->th_sport; } } else if (ip_hdr->ip_p == IPPROTO_UDP) { struct udphdr *udp = get_udp_header(ip_hdr, len_ip_and_payload); if (udp) { src_port = udp->uh_sport; } } uint32_t validation[VALIDATE_BYTES / sizeof(uint32_t)]; // TODO: for TTL exceeded messages, ip_hdr->saddr is going to be // different and we must calculate off potential payload message instead validate_gen(ip_hdr->ip_dst.s_addr, ip_hdr->ip_src.s_addr, src_port, (uint8_t *)validation); if (!zconf.probe_module->validate_packet( ip_hdr, len_ip_and_payload, &src_ip, validation, zconf.ports)) { zrecv.validation_failed++; return; } else { zrecv.validation_passed++; } // woo! We've validated that the packet is a response to our scan int is_repeat = 0; if (zconf.dedup_method == DEDUP_METHOD_FULL) { is_repeat = pbm_check(seen, ntohl(src_ip)); } else if (zconf.dedup_method == DEDUP_METHOD_WINDOW) { target_t t = {.ip = src_ip, .port = src_port, .status = 0}; if (cachehash_get(ch, &t, sizeof(target_t))) { is_repeat = 1; } else { cachehash_put(ch, &t, sizeof(target_t), (void *)1); } } // track whether this is the first packet in an IP fragment. if (ip_hdr->ip_off & IP_MF) { zrecv.ip_fragments++; } fieldset_t *fs = fs_new_fieldset(&zconf.fsconf.defs); fs_add_ip_fields(fs, ip_hdr); // HACK: // probe modules expect the full ethernet frame // in process_packet. For VPN, we only get back an IP frame. // Here, we fake an ethernet frame (which is initialized to // have ETH_P_IP proto and 00s for dest/src). if (zconf.send_ip_pkts) { static const uint32_t available_space = sizeof(fake_eth_hdr) - sizeof(struct ether_header); assert(buflen > (uint32_t)zconf.data_link_size); buflen -= zconf.data_link_size; if (buflen > available_space) { buflen = available_space; } memcpy(&fake_eth_hdr[sizeof(struct ether_header)], bytes + zconf.data_link_size, buflen); bytes = fake_eth_hdr; buflen += sizeof(struct ether_header); } zconf.probe_module->process_packet(bytes, buflen, fs, validation, ts); fs_add_system_fields(fs, is_repeat, zsend.complete, ts); int success_index = zconf.fsconf.success_index; assert(success_index < fs->len); int is_success = fs_get_uint64_by_index(fs, success_index); if (is_success) { zrecv.success_total++; if (!is_repeat) { zrecv.success_unique++; if (zconf.dedup_method == DEDUP_METHOD_FULL) { pbm_set(seen, ntohl(src_ip)); } else if (zconf.dedup_method == DEDUP_METHOD_WINDOW) { } } if (zsend.complete) { zrecv.cooldown_total++; if (!is_repeat) { zrecv.cooldown_unique++; } } } else { zrecv.failure_total++; } // probe module includes app_success field if (zconf.fsconf.app_success_index >= 0) { int is_app_success = fs_get_uint64_by_index(fs, zconf.fsconf.app_success_index); if (is_app_success) { zrecv.app_success_total++; if (!is_repeat) { zrecv.app_success_unique++; } } } fieldset_t *o = NULL; // we need to translate the data provided by the probe module // into a fieldset that can be used by the output module if (!is_success && zconf.default_mode) { goto cleanup; } if (is_repeat && zconf.default_mode) { goto cleanup; } if (!evaluate_expression(zconf.filter.expression, fs)) { goto cleanup; } zrecv.filter_success++; o = translate_fieldset(fs, &zconf.fsconf.translation); if (zconf.output_module && zconf.output_module->process_ip) { zconf.output_module->process_ip(o); } cleanup: fs_free(fs); free(o); if (zconf.output_module && zconf.output_module->update && !(zrecv.success_unique % zconf.output_module->update_interval)) { zconf.output_module->update(&zconf, &zsend, &zrecv); } } int recv_run(pthread_mutex_t *recv_ready_mutex) { log_trace("recv", "recv thread started"); log_debug("recv", "capturing responses on %s", zconf.iface); if (!zconf.dryrun) { recv_init(); } if (zconf.send_ip_pkts) { struct ether_header *eth = (struct ether_header *)fake_eth_hdr; memset(fake_eth_hdr, 0, sizeof(fake_eth_hdr)); eth->ether_type = htons(ETHERTYPE_IP); } // initialize paged bitmap if (zconf.dedup_method == DEDUP_METHOD_FULL) { seen = pbm_init(); } else if (zconf.dedup_method == DEDUP_METHOD_WINDOW) { ch = cachehash_init(zconf.dedup_window_size, NULL); } if (zconf.default_mode) { log_info("recv", "duplicate responses will be excluded from output"); log_info("recv", "unsuccessful responses will be excluded from output"); } else { log_info( "recv", "duplicate responses will be passed to the output module"); log_info( "recv", "unsuccessful responses will be passed to the output module"); } pthread_mutex_lock(recv_ready_mutex); zconf.recv_ready = 1; pthread_mutex_unlock(recv_ready_mutex); zrecv.start = now(); if (zconf.max_results == 0) { zconf.max_results = -1; } do { if (zconf.dryrun) { sleep(1); } else { recv_packets(); if (zconf.max_results && zrecv.filter_success >= zconf.max_results) { break; } } } while ( !(zsend.complete && (now() - zsend.finish > zconf.cooldown_secs))); zrecv.finish = now(); // get final pcap statistics before closing recv_update_stats(); if (!zconf.dryrun) { pthread_mutex_lock(recv_ready_mutex); recv_cleanup(); pthread_mutex_unlock(recv_ready_mutex); } zrecv.complete = 1; log_debug("recv", "thread finished"); return 0; } zmap-4.3.4/src/recv.h000066400000000000000000000007131501046211500143640ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_RECV_H #define ZMAP_RECV_H #include int recv_update_stats(void); int recv_run(pthread_mutex_t *recv_ready_mutex); #endif /* ZMP_RECV_H */ zmap-4.3.4/src/send-bsd.c000066400000000000000000000073451501046211500151270ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "send.h" #include #include #include #include #include #include #include #include #include #include #include #include "state.h" #include "probe_modules/packet.h" #include "../lib/includes.h" #include "../lib/logger.h" int send_run_init(UNUSED sock_t sock) { // Don't need to do anything on BSD-like variants return EXIT_SUCCESS; } static int send_packet(sock_t sock, uint8_t *buf, int len, UNUSED uint32_t retry_ct) { if (zconf.send_ip_pkts) { buf += sizeof(struct ether_header); struct ip *iph = (struct ip *)buf; #if defined(__APPLE__) || (defined(__FreeBSD__) && __FreeBSD_version < 1100030) // Early BSD's raw IP sockets required IP headers to have len // and off fields in host byte order, as they were being byte // swapped on the way out. Getting byte order wrong would // result in EINVAL from sendto(2) below. // Most modern BSD systems have fixed this and removed the byte // swapping on raw IP sockets, while some, notably macOS, still // require header fields in host byte order. // See ip(4) for details on byte order requirements of raw IP // sockets. // Swap byte order on the first send attempt for a given packet // (retry_ct == 0), and rely on the caller to pass us the same // buffer again for retries (retry_ct > 0), with the buffer // still containing the header fields in corrected byte order. if (retry_ct == 0) { iph->ip_len = ntohs(iph->ip_len); iph->ip_off = ntohs(iph->ip_off); iph->ip_sum = 0; } #endif struct sockaddr_in sai; bzero(&sai, sizeof(sai)); sai.sin_family = AF_INET; sai.sin_addr.s_addr = iph->ip_dst.s_addr; return sendto(sock.sock, buf, len, 0, (struct sockaddr *)&sai, sizeof(sai)); } else { return write(sock.sock, buf, len); } } // macOS doesn't have sendmmsg as of Sonoma. Since we want a uniform interface, we'll emulate the send_batch used in Linux. // FreeBSD does have sendmmsg, but it is a libc wrapper around the sendmsg syscall, without the perf benefits of sendmmsg. // The behavior in sendmmsg is to send as many packets as possible until one fails, and then return the number of sent packets. // Following the same pattern for consistency // Returns - number of packets sent // Returns -1 and sets errno if no packets could be sent successfully int send_batch(sock_t sock, batch_t *batch, int retries) { if (batch->len == 0) { // nothing to send return EXIT_SUCCESS; } int packets_sent = 0; int rc = 0; for (int packet_num = 0; packet_num < batch->len; packet_num++) { for (int retry_ct = 0; retry_ct < retries; retry_ct++) { rc = send_packet(sock, batch->packets[packet_num].buf, batch->packets[packet_num].len, retry_ct); if (rc >= 0) { packets_sent++; break; } } if (rc < 0) { // packet couldn't be sent in retries number of attempts struct ip *iph = (struct ip *)(batch->packets[packet_num].buf + sizeof(struct ether_header)); char addr_str_buf[INET_ADDRSTRLEN]; const char *addr_str = inet_ntop( AF_INET, &iph->ip_dst, addr_str_buf, INET_ADDRSTRLEN); if (addr_str != NULL) { log_debug("send-bsd", "send_packet failed for %s. %s", addr_str, strerror(errno)); } } } if (packets_sent == 0) { // simulating the return behaviour of the Linux send_mmsg sys call on error. Returns -1 and leaves // errno as set by send_packet return -1; } return packets_sent; } zmap-4.3.4/src/send-internal.h000066400000000000000000000012731501046211500161720ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef SEND_INTERNAL_H #define SEND_INTERNAL_H #include "socket.h" int send_run_init(sock_t s); int send_batch(sock_t sock, batch_t *batch, int retries); #if defined(PFRING) #include "send-pfring.h" #elif defined(NETMAP) void submit_batch_internal(batch_t *batch); int send_batch_internal(sock_t sock, batch_t *batch); #elif defined(__linux__) #include "send-linux.h" #endif #endif // SEND_INTERNAL_H zmap-4.3.4/src/send-linux.c000066400000000000000000000105411501046211500155060ustar00rootroot00000000000000/* * Copyright 2023 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/logger.h" #include "./send.h" #include "./send-linux.h" #include "state.h" // Dummy sockaddr for sendto static struct sockaddr_ll sockaddr; int send_run_init(sock_t s) { // Get the actual socket int sock = s.sock; // get source interface index struct ifreq if_idx; memset(&if_idx, 0, sizeof(struct ifreq)); if (strlen(zconf.iface) >= IFNAMSIZ) { log_error("send", "device interface name (%s) too long\n", zconf.iface); return EXIT_FAILURE; } strncpy(if_idx.ifr_name, zconf.iface, IFNAMSIZ - 1); if (ioctl(sock, SIOCGIFINDEX, &if_idx) < 0) { log_error("send", "%s", "SIOCGIFINDEX"); return EXIT_FAILURE; } int ifindex = if_idx.ifr_ifindex; // destination address for the socket memset((void *)&sockaddr, 0, sizeof(struct sockaddr_ll)); sockaddr.sll_ifindex = ifindex; sockaddr.sll_halen = ETH_ALEN; if (zconf.send_ip_pkts) { sockaddr.sll_protocol = htons(ETHERTYPE_IP); } memcpy(sockaddr.sll_addr, zconf.gw_mac, ETH_ALEN); return EXIT_SUCCESS; } int send_batch(sock_t sock, batch_t *batch, int retries) { if (batch->len == 0) { // nothing to send return EXIT_SUCCESS; } struct mmsghdr msgvec[batch->capacity]; // Array of multiple msg header structures struct msghdr msgs[batch->capacity]; struct iovec iovs[batch->capacity]; size_t buf_offset = 0; if (zconf.send_ip_pkts) { buf_offset = sizeof(struct ether_header); } for (int i = 0; i < batch->len; ++i) { struct iovec *iov = &iovs[i]; iov->iov_base = batch->packets[i].buf + buf_offset; iov->iov_len = batch->packets[i].len - buf_offset; struct msghdr *msg = &msgs[i]; memset(msg, 0, sizeof(struct msghdr)); // based on https://github.com/torvalds/linux/blob/master/net/socket.c#L2180 msg->msg_name = (struct sockaddr *)&sockaddr; msg->msg_namelen = sizeof(struct sockaddr_ll); msg->msg_iov = iov; msg->msg_iovlen = 1; msgvec[i].msg_hdr = *msg; msgvec[i].msg_len = batch->packets[i].len - buf_offset; } // set up per-retry variables, so we can only re-submit what didn't send successfully struct mmsghdr *current_msg_vec = msgvec; int total_packets_sent = 0; int num_of_packets_in_batch = batch->len; for (int i = 0; i < retries; i++) { // according to manpages // On success, sendmmsg() returns the number of messages sent from msgvec; if this is less than vlen, the // caller can retry with a further sendmmsg() call to send the remaining messages. // On error, -1 is returned, and errno is set to indicate the error. int rv = sendmmsg(sock.sock, current_msg_vec, num_of_packets_in_batch, 0); if (rv < 0) { // retry if sending all packets failed log_error("batch send", "error in sendmmsg: %s", strerror(errno)); continue; } // if rv is positive, it gives the number of packets successfully sent total_packets_sent += rv; if (rv == num_of_packets_in_batch) { // all packets in batch were sent successfully break; } // batch send was only partially successful, we'll retry if we have retries available log_warn("batch send", "only successfully sent %d packets out of a batch of %d packets", total_packets_sent, batch->len); // per the manpages for sendmmsg, packets are sent sequentially and the call returns upon a // failure, returning the number of packets successfully sent // remove successfully sent packets from batch for retry current_msg_vec = &msgvec[total_packets_sent]; num_of_packets_in_batch = batch->len - total_packets_sent; } return total_packets_sent; } zmap-4.3.4/src/send-linux.h000066400000000000000000000011171501046211500155120ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_SEND_LINUX_H #define ZMAP_SEND_LINUX_H #include #include #include #include #include #include #include #include #include "../lib/includes.h" #endif /* ZMAP_SEND_LINUX_H */ zmap-4.3.4/src/send-netmap.c000066400000000000000000000106711501046211500156370ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #if !(defined(__FreeBSD__) || defined(__linux__)) #error "NETMAP requires FreeBSD or Linux" #endif #include "send.h" #include #include #include #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/logger.h" #include "../lib/queue.h" #include "socket.h" #include "state.h" static pthread_once_t submit_queue_inited = PTHREAD_ONCE_INIT; static zqueue_t *submit_queue; static void submit_queue_init_once(void) { submit_queue = queue_init(); assert(submit_queue); } int send_run_init(sock_t sock) { if (sock.nm.tx_ring_idx == 0) { pthread_once(&submit_queue_inited, submit_queue_init_once); } struct pollfd fds = { .fd = sock.nm.tx_ring_fd, .events = POLLOUT, }; log_debug("send-netmap", "tx ring %" PRIu32 ": polling for POLLOUT", sock.nm.tx_ring_idx); if (poll(&fds, 1, -1) == -1) { log_error("send-netmap", "poll(POLLOUT) failed: %d: %s", errno, strerror(errno)); return -1; } return 0; } // Called from the recv thread to submit a batch of packets // for sending on thread 0; typically batch size is just 1. // Used for responding to ARP requests. // The way this works is rather inefficient and only makes // sense for low volume packets. // Since we don't know if send_run_init() has been called // yet or not, we need to ensure the queue is initialized. void submit_batch_internal(batch_t *batch) { pthread_once(&submit_queue_inited, submit_queue_init_once); push_back((void *)batch, submit_queue); } int send_batch_internal(sock_t sock, batch_t *batch) { struct netmap_ring *ring = NETMAP_TXRING(zconf.nm.nm_if, sock.nm.tx_ring_idx); struct pollfd fds = { .fd = sock.nm.tx_ring_fd, .events = POLLOUT, }; for (int i = 0; i < batch->len; i++) { if (ring->head == ring->tail && poll(&fds, 1, -1) == -1) { int oerrno = errno; log_debug("send-netmap", "poll(POLLOUT) failed: %d: %s", errno, strerror(errno)); errno = oerrno; return -1; } uint32_t len = batch->packets[i].len; assert(len <= ring->nr_buf_size); memcpy(NETMAP_BUF(ring, ring->slot[ring->cur].buf_idx), batch->packets[i].buf, len); ring->slot[ring->cur].len = len; ring->head = ring->cur = nm_ring_next(ring, ring->cur); } if (ioctl(fds.fd, NIOCTXSYNC, NULL) == -1) { int oerrno = errno; log_debug("send-netmap", "ioctl(NIOCTXSYNC) failed: %d: %s", errno, strerror(errno)); errno = oerrno; return -1; } return batch->len; } // Netmap's send_batch does not use attempts, because retries do // not make sense based on the premise that syncing a TX ring will // never fail for transient reasons. // // Netmap's send_batch never reports batches as partially failed, // because the netmap API does not have partial failure semantics. // All we know is that a poll or ioctl syscall failed, not if or // how many of the packets we placed in the ringbuffer were sent. // // There is a bit of unused optimization potential here; ZMap's // current architecture requires us to copy packet data on the // send path, we cannot supply netmap buffers to ZMap to write // into directly. And even though netmap would allow us to reuse // data still in buffers (unless NS_BUF_CHANGED has been set by // the kernel), we cannot take advantage of that currently. int send_batch(sock_t sock, batch_t *batch, UNUSED int attempts) { // On send thread 0, send any batches that have been // submitted onto the submit_queue before sending the // actual batch. There should only be packets in the // submit_queue very infrequently. if (sock.nm.tx_ring_idx == 0) { while (!is_empty(submit_queue)) { znode_t *node = pop_front(submit_queue); batch_t *extra_batch = (batch_t *)node->data; assert(extra_batch->len > 0); free(node); if (send_batch_internal(sock, extra_batch) != extra_batch->len) { log_error("send-netmap", "Failed to send extra batch of %u submitted packet(s)", extra_batch->len); } else { log_debug("send-netmap", "Sent extra batch of %u submitted packet(s)", extra_batch->len); } free_packet_batch(extra_batch); } } if (batch->len == 0) { return 0; } return send_batch_internal(sock, batch); } zmap-4.3.4/src/send-pfring.h000066400000000000000000000020421501046211500156360ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_SEND_PFRING_H #define ZMAP_SEND_PFRING_H #include "../lib/includes.h" #include #if defined(ZMAP_SEND_BSD_H) || defined(ZMAP_SEND_LINUX_H) #error "Don't include send-bsd.h or send-linux.h with send-pfring.h" #endif int send_run_init(sock_t socket) { (void)socket; // All init for pfring happens in get_socket return 0; } int send_batch(sock_t sock, batch_t *batch, UNUSED int attempts) { for (int i = 0; i < batch->len; i++) { uint32_t len = batch->packets[i].len; sock.pf.buffers[i]->len = len; memcpy(pfring_zc_pkt_buff_data(sock.pf.buffers[i], sock.pf.queue), batch->packets[i].buf, len); } return pfring_zc_send_pkt_burst(sock.pf.queue, sock.pf.buffers, batch->len, 1 /* flush */); } #endif /* ZMAP_SEND_PFRING_H */ zmap-4.3.4/src/send.c000066400000000000000000000371221501046211500143550ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "send.h" #include #include #include #include #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/util.h" #include "../lib/logger.h" #include "../lib/random.h" #include "../lib/blocklist.h" #include "../lib/lockfd.h" #include "../lib/pbm.h" #include "../lib/xalloc.h" #include "send-internal.h" #include "aesrand.h" #include "get_gateway.h" #include "iterator.h" #include "probe_modules/packet.h" #include "probe_modules/probe_modules.h" #include "shard.h" #include "state.h" #include "validate.h" // The iterator over the cyclic group // Lock for send run static pthread_mutex_t send_mutex = PTHREAD_MUTEX_INITIALIZER; // Source ports for outgoing packets static uint16_t num_src_ports; void sig_handler_increase_speed(UNUSED int signal) { int old_rate = zconf.rate; zconf.rate += (zconf.rate * 0.05); log_info("send", "send rate increased from %i to %i pps.", old_rate, zconf.rate); } void sig_handler_decrease_speed(UNUSED int signal) { int old_rate = zconf.rate; zconf.rate -= (zconf.rate * 0.05); log_info("send", "send rate decreased from %i to %i pps.", old_rate, zconf.rate); } // global sender initialize (not thread specific) iterator_t *send_init(void) { // generate a new primitive root and starting position iterator_t *it; uint32_t num_subshards = (uint32_t)zconf.senders * (uint32_t)zconf.total_shards; if (num_subshards > (blocklist_count_allowed() * zconf.ports->port_count)) { log_fatal("send", "senders * shards > allowed probes"); } if (zsend.max_targets && (num_subshards > zsend.max_targets)) { log_fatal("send", "senders * shards > max targets"); } uint64_t num_addrs = blocklist_count_allowed(); it = iterator_init(zconf.senders, zconf.shard_num, zconf.total_shards, num_addrs, zconf.ports->port_count); // determine the source address offset from which we'll send packets struct in_addr temp; temp.s_addr = zconf.source_ip_addresses[0]; log_debug("send", "srcip_first: %s", inet_ntoa(temp)); temp.s_addr = zconf.source_ip_addresses[zconf.number_source_ips - 1]; log_debug("send", "srcip_last: %s", inet_ntoa(temp)); // process the source port range that ZMap is allowed to use num_src_ports = zconf.source_port_last - zconf.source_port_first + 1; log_debug("send", "will send from %u address%s on %hu source ports", zconf.number_source_ips, ((zconf.number_source_ips == 1) ? "" : "es"), num_src_ports); // global initialization for send module assert(zconf.probe_module); if (zconf.probe_module->global_initialize) { if (zconf.probe_module->global_initialize(&zconf)) { log_fatal( "send", "global initialization for probe module failed."); } } // only allow bandwidth or rate if (zconf.bandwidth > 0 && zconf.rate > 0) { log_fatal( "send", "must specify rate or bandwidth, or neither, not both."); } // Convert specified bandwidth to packet rate. This is an estimate using the // max packet size a probe module will generate. if (zconf.bandwidth > 0) { size_t pkt_len = zconf.probe_module->max_packet_length; pkt_len *= 8; // 7 byte MAC preamble, 1 byte Start frame, 4 byte CRC, 12 byte // inter-frame gap pkt_len += 8 * 24; // adjust calculated length if less than the minimum size of an // ethernet frame if (pkt_len < 84 * 8) { pkt_len = 84 * 8; } // rate is a uint32_t so, don't overflow if (zconf.bandwidth / pkt_len > 0xFFFFFFFFu) { zconf.rate = 0; } else { zconf.rate = zconf.bandwidth / pkt_len; if (zconf.rate == 0) { log_warn( "send", "bandwidth %lu bit/s is slower than 1 pkt/s, " "setting rate to 1 pkt/s", zconf.bandwidth); zconf.rate = 1; } } log_debug( "send", "using bandwidth %lu bits/s for %zu byte probe, rate set to %d pkt/s", zconf.bandwidth, pkt_len / 8, zconf.rate); } // convert default placeholder to default value if (zconf.rate == -1) { // default 10K pps zconf.rate = 10000; } // log rate, if explicitly specified if (zconf.rate < 0) { log_fatal("send", "rate impossibly slow"); } if (zconf.rate > 0 && zconf.bandwidth <= 0) { log_debug("send", "rate set to %d pkt/s", zconf.rate); } // Get the source hardware address, and give it to the probe // module if (!zconf.hw_mac_set) { if (get_iface_hw_addr(zconf.iface, zconf.hw_mac)) { log_fatal( "send", "ZMap could not retrieve the hardware (MAC) address for " "the interface \"%s\". You likely do not privileges to open a raw packet socket. " "Are you running as root or with the CAP_NET_RAW capability? If you are, you " "may need to manually set the source MAC address with the \"--source-mac\" flag.", zconf.iface); return NULL; } log_debug( "send", "no source MAC provided. " "automatically detected %02x:%02x:%02x:%02x:%02x:%02x as hw " "interface for %s", zconf.hw_mac[0], zconf.hw_mac[1], zconf.hw_mac[2], zconf.hw_mac[3], zconf.hw_mac[4], zconf.hw_mac[5], zconf.iface); } log_debug("send", "source MAC address %02x:%02x:%02x:%02x:%02x:%02x", zconf.hw_mac[0], zconf.hw_mac[1], zconf.hw_mac[2], zconf.hw_mac[3], zconf.hw_mac[4], zconf.hw_mac[5]); if (zconf.dryrun) { log_info("send", "dryrun mode -- won't actually send packets"); } // initialize random validation key validate_init(); // setup signal handlers for changing scan speed signal(SIGUSR1, sig_handler_increase_speed); signal(SIGUSR2, sig_handler_decrease_speed); zsend.start = now(); return it; } static inline ipaddr_n_t get_src_ip(ipaddr_n_t dst, int local_offset) { if (zconf.number_source_ips == 1) { return zconf.source_ip_addresses[0]; } return zconf.source_ip_addresses[(ntohl(dst) + local_offset) % zconf.number_source_ips]; } // one sender thread int send_run(sock_t st, shard_t *s) { log_debug("send", "send thread started"); pthread_mutex_lock(&send_mutex); // allocate batch batch_t *batch = create_packet_batch(zconf.batch); // OS specific per-thread init if (send_run_init(st)) { pthread_mutex_unlock(&send_mutex); return EXIT_FAILURE; } // MAC address length in characters char mac_buf[(ETHER_ADDR_LEN * 2) + (ETHER_ADDR_LEN - 1) + 1]; char *p = mac_buf; for (int i = 0; i < ETHER_ADDR_LEN; i++) { if (i == ETHER_ADDR_LEN - 1) { snprintf(p, 3, "%.2x", zconf.hw_mac[i]); p += 2; } else { snprintf(p, 4, "%.2x:", zconf.hw_mac[i]); p += 3; } } log_debug("send", "source MAC address %s", mac_buf); void *probe_data = NULL; if (zconf.probe_module->thread_initialize) { int rv = zconf.probe_module->thread_initialize(&probe_data); if (rv != EXIT_SUCCESS) { pthread_mutex_unlock(&send_mutex); log_fatal("send", "Send thread initialization for probe module failed: %u", rv); } } pthread_mutex_unlock(&send_mutex); if (zconf.probe_module->prepare_packet) { for (size_t i = 0; i < batch->capacity; i++) { int rv = zconf.probe_module->prepare_packet( batch->packets[i].buf, zconf.hw_mac, zconf.gw_mac, probe_data); if (rv != EXIT_SUCCESS) { log_fatal("send", "Probe module failed to prepare packet: %u", rv); } } } // adaptive timing to hit target rate uint64_t count = 0; uint64_t last_count = count; double last_time = steady_now(); uint32_t delay = 0; uint interval = 0; volatile uint vi; struct timespec ts, rem; double send_rate = (double)zconf.rate / ((double)zconf.senders * zconf.packet_streams); const double slow_rate = 1000; // packets per seconds per thread // at which it uses the slow methods long nsec_per_sec = 1000 * 1000 * 1000; long long sleep_time = nsec_per_sec; if (zconf.rate > 0) { delay = 10000; if (send_rate < slow_rate) { // set the initial time difference sleep_time = nsec_per_sec / send_rate; last_time = steady_now() - (1.0 / send_rate); } else { // estimate initial rate for (vi = delay; vi--;) ; delay *= 1 / (steady_now() - last_time) / ((double)zconf.rate / (double)zconf.senders); interval = ((double)zconf.rate / (double)zconf.senders) / 20; last_time = steady_now(); assert(interval > 0); if (delay == 0) { // at extremely high bandwidths, the delay could be set to zero. // this breaks the multiplier logic below, so we'll hard-set it to 1 in this case. delay = 1; } } } int attempts = zconf.retries + 1; // Get the initial IP to scan. target_t current = shard_get_cur_target(s); uint32_t current_ip = current.ip; uint16_t current_port = current.port; // If provided a list of IPs to scan, then the first generated address // might not be on that list. Iterate until the current IP is one the // list, then start the true scanning process. if (zconf.list_of_ips_filename) { while (!pbm_check(zsend.list_of_ips_pbm, current_ip)) { current = shard_get_next_target(s); current_ip = current.ip; current_port = current.port; if (current.status == ZMAP_SHARD_DONE) { log_debug( "send", "never made it to send loop in send thread %i", s->thread_id); goto cleanup; } } } while (1) { // Adaptive timing delay if (count && delay > 0) { if (send_rate < slow_rate) { double t = steady_now(); double last_rate = (1.0 / (t - last_time)); sleep_time *= ((last_rate / send_rate) + 1) / 2; ts.tv_sec = sleep_time / nsec_per_sec; ts.tv_nsec = sleep_time % nsec_per_sec; log_debug("sleep", "sleep for %d sec, %ld nanoseconds", ts.tv_sec, ts.tv_nsec); while (nanosleep(&ts, &rem) == -1) { } last_time = t; } else { for (vi = delay; vi--;) ; if (!interval || (count % interval == 0)) { double t = steady_now(); assert(count > last_count); assert(t > last_time); double multiplier = (double)(count - last_count) / (t - last_time) / (zconf.rate / zconf.senders); uint32_t old_delay = delay; delay *= multiplier; if (delay == old_delay) { if (multiplier > 1.0) { delay *= 2; } else if (multiplier < 1.0) { delay *= 0.5; } } if (delay == 0) { // delay could become zero if the actual send rate stays below the target rate for long enough // this could be due to things like VM cpu contention, or the NIC being saturated. // However, we never want delay to become 0, as this would remove any rate limiting for the rest // of the ZMap invocation (since 0 * multiplier = 0 for any multiplier). To prevent the removal // of rate-limiting we'll set delay to one here. delay = 1; } last_count = count; last_time = t; } } } // Check if the program has otherwise completed and break out of the send loop. if (zrecv.complete) { goto cleanup; } if (zconf.max_runtime && zconf.max_runtime <= now() - zsend.start) { goto cleanup; } // Check if we've finished this shard or thread before sending each // packet, regardless of batch size. if (s->state.max_targets && s->state.targets_scanned >= s->state.max_targets) { log_debug( "send", "send thread %hhu finished (max targets of %u reached)", s->thread_id, s->state.max_targets); goto cleanup; } if (s->state.max_packets && s->state.packets_sent >= s->state.max_packets) { log_debug( "send", "send thread %hhu finished (max packets of %u reached)", s->thread_id, s->state.max_packets); goto cleanup; } if (current.status == ZMAP_SHARD_DONE) { log_debug( "send", "send thread %hhu finished, shard depleted", s->thread_id); goto cleanup; } for (int i = 0; i < zconf.packet_streams; i++) { count++; uint32_t src_ip = get_src_ip(current_ip, i); uint8_t size_of_validation = VALIDATE_BYTES / sizeof(uint32_t); uint32_t validation[size_of_validation]; validate_gen(src_ip, current_ip, htons(current_port), (uint8_t *)validation); uint8_t ttl = zconf.probe_ttl; size_t length = 0; zconf.probe_module->make_packet( batch->packets[batch->len].buf, &length, src_ip, current_ip, htons(current_port), ttl, validation, i, // Grab last 2 bytes of validation for ip_id (uint16_t)(validation[size_of_validation - 1] & 0xFFFF), probe_data); if (length > MAX_PACKET_SIZE) { log_fatal( "send", "send thread %hhu set length (%zu) larger than MAX (%zu)", s->thread_id, length, MAX_PACKET_SIZE); } batch->packets[batch->len].len = (uint32_t)length; if (zconf.dryrun) { batch->len++; if (batch->len == batch->capacity) { lock_file(stdout); for (int i = 0; i < batch->len; i++) { zconf.probe_module->print_packet(stdout, batch->packets[i].buf); } unlock_file(stdout); // reset batch length for next batch batch->len = 0; } } else { batch->len++; if (batch->len == batch->capacity) { // batch is full, sending int rc = send_batch(st, batch, attempts); // whether batch succeeds or fails, this was the only attempt. Any re-tries are handled within batch if (rc < 0) { log_error("send_batch", "could not send any batch packets: %s", strerror(errno)); // rc is the last error code if all packets couldn't be sent s->state.packets_failed += batch->len; } else { // rc is number of packets sent successfully, if > 0 s->state.packets_failed += batch->len - rc; } // reset batch length for next batch batch->len = 0; } } s->state.packets_sent++; } // Track the number of targets (ip,port)s we actually scanned. s->state.targets_scanned++; // Get the next IP to scan current = shard_get_next_target(s); current_ip = current.ip; current_port = current.port; if (zconf.list_of_ips_filename && current.status != ZMAP_SHARD_DONE) { // If we have a list of IPs bitmap, ensure the next IP // to scan is on the list. while (!pbm_check(zsend.list_of_ips_pbm, current_ip)) { current = shard_get_next_target(s); current_ip = current.ip; if (current.status == ZMAP_SHARD_DONE) { log_debug( "send", "send thread %hhu shard finished in get_next_ip_loop depleted", s->thread_id); goto cleanup; } } } } cleanup: if (!zconf.dryrun && send_batch(st, batch, attempts) < 0) { log_error("send_batch cleanup", "could not send remaining batch packets: %s", strerror(errno)); } else if (zconf.dryrun) { lock_file(stdout); for (int i = 0; i < batch->len; i++) { zconf.probe_module->print_packet(stdout, batch->packets[i].buf); } unlock_file(stdout); // reset batch length for next batch batch->len = 0; } free_packet_batch(batch); s->cb(s->thread_id, s->arg); if (zconf.dryrun) { lock_file(stdout); fflush(stdout); unlock_file(stdout); } log_debug("send", "thread %hu cleanly finished", s->thread_id); return EXIT_SUCCESS; } batch_t *create_packet_batch(uint16_t capacity) { // allocating batch and associated data structures in single xmalloc for cache locality batch_t *batch = (batch_t *)xmalloc(sizeof(batch_t) + capacity * sizeof(struct batch_packet)); batch->packets = (struct batch_packet *)(batch + 1); batch->capacity = capacity; batch->len = 0; return batch; } void free_packet_batch(batch_t *batch) { // batch was created with a single xmalloc, so this will free the component array too xfree(batch); } zmap-4.3.4/src/send.h000066400000000000000000000027001501046211500143540ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef SEND_H #define SEND_H #include "iterator.h" #include "socket.h" #include iterator_t *send_init(void); int send_run(sock_t, shard_t *); // Fit two packets with metadata into one 4k page. // 2k seems like more than enough with typical MTU of // 1500, and we don't want to cause IP fragmentation. #define MAX_PACKET_SIZE (2048 - sizeof(uint32_t) - 2 * sizeof(uint8_t)) // Metadata and initial packet bytes are adjacent, // for cache locality esp. with short packets. // buf is aligned such that the end of the Ethernet // header and beginning of the IP header will align // to a 32 bit boundary, such that reading/writing // IP addresses and other 32 bit header fields is // properly aligned. struct batch_packet { uint32_t len; uint8_t unused[2]; uint8_t buf[MAX_PACKET_SIZE]; }; static_assert((offsetof(struct batch_packet, buf) + sizeof(struct ether_header)) % sizeof(uint32_t) == 0, "buf is aligned such that IP header is 32-bit aligned"); typedef struct { struct batch_packet *packets; uint16_t len; uint16_t capacity; } batch_t; batch_t *create_packet_batch(uint16_t capacity); void free_packet_batch(batch_t *batch); #endif // SEND_H zmap-4.3.4/src/shard.c000066400000000000000000000146021501046211500145230ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include #include "../lib/includes.h" #include "../lib/logger.h" #include "../lib/blocklist.h" #include "shard.h" #include "state.h" static inline uint16_t extract_port(uint64_t v, uint8_t bits) { uint64_t mask = (1 << bits) - 1; return (uint16_t)(v & mask); } static inline uint32_t extract_ip(uint64_t v, uint8_t bits) { return (uint32_t)(v >> bits); } static void shard_roll_to_valid(shard_t *s) { uint64_t current_ip_index = (s->current - 1) >> s->bits_for_port; uint16_t candidate_port = extract_port(s->current - 1, s->bits_for_port); if (current_ip_index < zsend.max_ip_index && candidate_port < zconf.ports->port_count) { return; } shard_get_next_target(s); } void shard_init(shard_t *shard, uint16_t shard_idx, uint16_t num_shards, uint8_t thread_idx, uint8_t num_threads, uint64_t max_total_targets, uint8_t bits_for_port, const cycle_t *cycle, shard_complete_cb cb, void *arg) { // Start out by figuring out how many shards we have. A single shard of // ZMap (set with --shards=N, --shard=n) may have several subshards, if // ZMap is being ran multithreaded (set with --sender-threads=T). // // Total number of subshards is S = N*T. Subshard ID's range from [0, // N*T). assert(num_shards > 0); assert(num_threads > 0); assert(shard_idx < num_shards); assert(thread_idx < num_threads); uint32_t num_subshards = (uint32_t)num_shards * (uint32_t)num_threads; uint64_t num_elts = cycle->order; assert(num_subshards < num_elts); assert(!max_total_targets || (num_subshards <= max_total_targets)); // This instance of ZMap will run T subshards, with one subshard per // thread. This composes a single shard, as specified by the command // line flag --shard=n. E.g. to run shard with index n, we must run // subshards with indices the range [n*T, (n+1)*T]. // // We can calculate our subshard index i = n*T + t. uint32_t sub_idx = shard_idx * num_threads + thread_idx; // Given i, we want to calculate the start of subshard i. Subshards // define ranges over exponents of g. They range from [0, Q-1), where Q // is the number of elements in (the order of) the group generated by // g. // // Let e_b = floor(Q / S) * i uint64_t exponent_begin = (num_elts / num_subshards) * sub_idx; // The stopping exponent is the first element of the next shard. // // e_e = floor(Q / S) * ((i + 1) % S) uint64_t exponent_end = (num_elts / num_subshards) * ((sub_idx + 1) % num_subshards); // We actually offset the begin and end of each cycle. Given an offset // k, shift each exponent by k modulo Q. exponent_begin = (exponent_begin + cycle->offset) % num_elts; exponent_end = (exponent_end + cycle->offset) % num_elts; // Multiprecision variants of everything above mpz_t generator_m, exponent_begin_m, exponent_end_m, prime_m; mpz_init_set_ui(generator_m, cycle->generator); mpz_init_set_ui(exponent_begin_m, exponent_begin); mpz_init_set_ui(exponent_end_m, exponent_end); mpz_init_set_ui(prime_m, cycle->group->prime); // Calculate the first and last points of the shard as powers of g // modulo p. mpz_t start_m, stop_m; mpz_init(start_m); mpz_init(stop_m); mpz_powm(start_m, generator_m, exponent_begin_m, prime_m); mpz_powm(stop_m, generator_m, exponent_end_m, prime_m); // Pull the result out as a uint64_t shard->params.first = (uint64_t)mpz_get_ui(start_m); shard->params.last = (uint64_t)mpz_get_ui(stop_m); shard->params.factor = cycle->generator; shard->params.modulus = cycle->group->prime; shard->bits_for_port = bits_for_port; // Set the shard at the beginning. shard->current = shard->params.first; // Set the (thread) id shard->thread_id = thread_idx; // Set max_targets if applicable if (max_total_targets > 0) { uint64_t max_targets_this_shard = max_total_targets / num_subshards; if (sub_idx < (max_total_targets % num_subshards)) { ++max_targets_this_shard; } shard->state.max_targets = max_targets_this_shard; } // Set the callbacks shard->cb = cb; shard->arg = arg; // If the beginning of a shard isn't pointing to a valid index in the // blocklist, find the first element that is. shard_roll_to_valid(shard); // Clear everything mpz_clear(generator_m); mpz_clear(exponent_begin_m); mpz_clear(exponent_end_m); mpz_clear(prime_m); mpz_clear(start_m); mpz_clear(stop_m); } target_t shard_get_cur_target(shard_t *shard) { if (shard->current == ZMAP_SHARD_DONE) { // shard_roll_to_valid() has rolled to the very end. return (target_t){ .ip = 0, .port = 0, .status = ZMAP_SHARD_DONE}; } uint32_t ip = extract_ip(shard->current - 1, shard->bits_for_port); uint16_t port = extract_port(shard->current - 1, shard->bits_for_port); return (target_t){.ip = (uint32_t)blocklist_lookup_index(ip), .port = (uint16_t)zconf.ports->ports[port], .status = ZMAP_SHARD_OK}; } static inline uint64_t shard_get_next_elem(shard_t *shard) { shard->current *= shard->params.factor; shard->current %= shard->params.modulus; return shard->current; } target_t shard_get_next_target(shard_t *shard) { if (shard->current == ZMAP_SHARD_DONE) { return (target_t){ .ip = 0, .port = 0, .status = ZMAP_SHARD_DONE}; } while (1) { uint64_t candidate = shard_get_next_elem(shard); if (candidate == shard->params.last) { shard->current = ZMAP_SHARD_DONE; shard->iterations++; return (target_t){ .ip = 0, .port = 0, .status = ZMAP_SHARD_DONE}; } if (candidate >= zsend.max_target_index) { // If the candidate is out of bounds, re-roll. This will happen since we choose primes/moduli that are // larger than the number of allowed targets. The IP is bounded below by checking against zsend.max_ip_index. continue; } // Good candidate, proceed with it. uint32_t candidate_ip = extract_ip(candidate - 1, shard->bits_for_port); uint16_t candidate_port = extract_port(candidate - 1, shard->bits_for_port); if (candidate_ip < zsend.max_ip_index && candidate_port < zconf.ports->port_count) { shard->iterations++; return (target_t){ .ip = blocklist_lookup_index(candidate_ip), .port = zconf.ports->ports[candidate_port], .status = ZMAP_SHARD_OK}; } } } zmap-4.3.4/src/shard.h000066400000000000000000000025331501046211500145300ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_SHARD_H #define ZMAP_SHARD_H #include #include "cyclic.h" #define ZMAP_SHARD_DONE 0 #define ZMAP_SHARD_OK 1 typedef void (*shard_complete_cb)(uint8_t id, void *arg); typedef struct shard { struct shard_state { uint64_t packets_sent; uint64_t targets_scanned; uint64_t max_targets; uint64_t max_packets; uint32_t packets_failed; uint64_t first_scanned; } state; struct shard_params { uint64_t first; uint64_t last; uint64_t factor; uint64_t modulus; } params; uint64_t current; uint64_t iterations; uint8_t thread_id; uint8_t bits_for_port; shard_complete_cb cb; void *arg; } shard_t; void shard_init(shard_t *shard, uint16_t shard_idx, uint16_t num_shards, uint8_t thread_idx, uint8_t num_threads, uint64_t max_total_targets, uint8_t bits_for_port, const cycle_t *cycle, shard_complete_cb cb, void *arg); typedef struct target { uint32_t ip; uint16_t port; uint8_t status; } target_t; target_t shard_get_cur_target(shard_t *shard); target_t shard_get_next_target(shard_t *shard); #endif /* ZMAP_SHARD_H */ zmap-4.3.4/src/socket-bsd.c000066400000000000000000000047251501046211500154650ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "socket.h" #include #include "../lib/includes.h" #include "../lib/logger.h" #include #include #include #include #include #include #include "state.h" sock_t get_socket(UNUSED uint32_t id) { sock_t sock; sock.sock = -1; #if !(defined(__APPLE__) || defined(__FreeBSD__)) if (zconf.send_ip_pkts && !zconf.dryrun) { log_fatal("socket", "iplayer not supported on this flavour of BSD"); } #endif if (zconf.send_ip_pkts) { int fd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW); if (fd == -1) { log_fatal("socket-bsd", "obtaining socket(PF_INET, SOCK_RAW, IPPROTO_IP) failed: %d %s. You likely do not have privileges to open a raw packet socket. " "Are you running as root?", errno, strerror(errno)); } int yes = 1; if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &yes, sizeof(yes)) == -1) { // could not inform the kernel that ZMap will be filling out the IP header and the kernel does not need to log_fatal("socket-bsd", "setsockopt(IP_HDRINCL) failed: %d %s", errno, strerror(errno)); } sock.sock = fd; } else { int bpf; char file[32]; // Try to find a valid bpf for (int i = 0; i < 128; i++) { snprintf(file, sizeof(file), "/dev/bpf%d", i); bpf = open(file, O_WRONLY); if (bpf != -1 || errno != EBUSY) break; } // Make sure it worked if (bpf < 0) { log_fatal("socket-bsd", "could not get an open packet filter"); } // Set up an ifreq to bind to struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, zconf.iface, sizeof(ifr.ifr_name)); // Bind the bpf to the interface if (ioctl(bpf, BIOCSETIF, (char *)&ifr) < 0) { close(bpf); log_fatal("socket-bsd", "could not bind the packet filter to the interface %s", ifr.ifr_name); } // Inform the interface that the source address will be filled out by ZMap and the kernel doens't need to write it int write_addr_enable = 1; if (ioctl(bpf, BIOCSHDRCMPLT, &write_addr_enable) < 0) { close(bpf); log_fatal("socket-bsd", "could not set the status of the header complete flag to the packet filter on interface %s", ifr.ifr_name); } sock.sock = bpf; } return sock; } zmap-4.3.4/src/socket-linux.c000066400000000000000000000014351501046211500160470ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "socket.h" #include #include #include "../lib/includes.h" #include "../lib/logger.h" #include "state.h" sock_t get_socket(UNUSED uint32_t id) { int sock; if (zconf.send_ip_pkts) { sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW); } else { sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); } if (sock <= 0) { log_fatal("send", "couldn't create socket. " "Are you root? Error: %s\n", strerror(errno)); } sock_t s; s.sock = sock; return s; } zmap-4.3.4/src/socket-netmap.c000066400000000000000000000034111501046211500161700ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #if !(defined(__FreeBSD__) || defined(__linux__)) #error "NETMAP requires FreeBSD or Linux" #endif #include "socket.h" #include "../lib/includes.h" #include "../lib/logger.h" #include "state.h" #include "utility.h" #include #include #include #include #include #include // Open another file descriptor on the NIC, scoped to just one pair of rings, // allowing the send threads to sync and poll just their tx ring w/o wreaking // havoc on tx rings in use by other send threads, changing head/cur/tail // underneath them unexpectedly. sock_t get_socket(uint32_t id) { sock_t sock; sock.nm.tx_ring_idx = id; sock.nm.tx_ring_fd = open(NETMAP_DEVICE_NAME, O_RDWR); if (sock.nm.tx_ring_fd == -1) { log_fatal("socket-netmap", "open(\"" NETMAP_DEVICE_NAME "\") failed: %d: %s", errno, strerror(errno)); } struct nmreq_register nmrreg; memset(&nmrreg, 0, sizeof(nmrreg)); nmrreg.nr_ringid = sock.nm.tx_ring_idx; nmrreg.nr_mode = NR_REG_ONE_NIC; nmrreg.nr_flags = NR_TX_RINGS_ONLY | NR_NO_TX_POLL; struct nmreq_header nmrhdr; memset(&nmrhdr, 0, sizeof(nmrhdr)); nmrhdr.nr_version = NETMAP_API; nmrhdr.nr_reqtype = NETMAP_REQ_REGISTER; cross_platform_strlcpy(nmrhdr.nr_name, zconf.iface, sizeof(nmrhdr.nr_name)); nmrhdr.nr_body = (uint64_t)&nmrreg; if (ioctl(sock.nm.tx_ring_fd, NIOCCTRL, &nmrhdr) == -1) { log_fatal("socket-netmap", "ioctl(NIOCCTRL) failed: %d: %s", errno, strerror(errno)); } return sock; } zmap-4.3.4/src/socket-pfring.c000066400000000000000000000010401501046211500161650ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "socket.h" #include "../lib/includes.h" #include "state.h" #include sock_t get_socket(uint32_t id) { sock_t sock; sock.pf.queue = zconf.pf.queues[id]; sock.pf.buffers = zconf.pf.buffers + zconf.batch * id; return sock; } zmap-4.3.4/src/socket.c000066400000000000000000000016311501046211500147100ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "socket.h" #include #include #include "../lib/includes.h" #include "../lib/logger.h" sock_t get_dryrun_socket(void) { sock_t s; memset(&s, 0, sizeof(s)); #if !(defined(PFRING) || defined(NETMAP)) // we need a socket in order to gather details about the system // such as source MAC address and IP address. However, because // we don't want to require root access in order to run dryrun, // we just create a TCP socket. s.sock = socket(AF_INET, SOCK_STREAM, 0); if (s.sock <= 0) { log_fatal("send", "couldn't create socket. Error: %s\n", strerror(errno)); } #endif return s; } zmap-4.3.4/src/socket.h000066400000000000000000000015601501046211500147160ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef ZMAP_SOCKET_H #define ZMAP_SOCKET_H #include #include "../lib/includes.h" #if defined(PFRING) && defined(NETMAP) #error "PFRING and NETMAP are mutually exclusive, only define one of them" #endif #ifdef PFRING #include #endif typedef union { #ifdef PFRING struct { pfring_zc_queue *queue; pfring_zc_pkt_buff **buffers; int idx; } pf; #elif defined(NETMAP) struct { uint32_t tx_ring_idx; int tx_ring_fd; } nm; #else int sock; #endif } sock_t; sock_t get_dryrun_socket(void); sock_t get_socket(uint32_t id); #endif /* ZMAP_SOCKET_H */ zmap-4.3.4/src/state.c000066400000000000000000000053241501046211500145430ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "state.h" #include "../lib/logger.h" const char *const DEDUP_METHOD_NAMES[] = {"default", "none", "full", "window"}; // global configuration and defaults struct state_conf zconf = { .allowlist_filename = NULL, .bandwidth = 0, .batch = 64, .blocklist_filename = NULL, .cooldown_secs = 0, .custom_metadata_str = NULL, .data_link_size = 0, .default_mode = 0, .dedup_method = 0, .dedup_window_size = 0, .dryrun = 0, .fast_dryrun = 0, .hw_mac = {0}, .hw_mac_set = 0, .gw_ip = 0, .gw_mac = {0}, .gw_mac_set = 0, .iface = NULL, .list_of_ips_count = 0, .list_of_ips_filename = NULL, .log_directory = NULL, .log_file = NULL, .log_level = LOG_INFO, .max_results = 0, .max_runtime = 0, .max_sendto_failures = -1, .max_targets = UINT64_MAX, .metadata_file = NULL, .metadata_filename = NULL, .min_hitrate = 0.0, .no_header_row = 0, .notes = NULL, .number_source_ips = 0, .output_args = NULL, .output_fields = NULL, .output_fields_len = 0, .output_filename = NULL, .output_filter_str = NULL, .output_module = NULL, .packet_streams = 1, .ports = NULL, .probe_args = NULL, .probe_module = NULL, .probe_ttl = IPDEFTTL, .quiet = 0, .rate = -1, .raw_output_fields = NULL, .recv_ready = 0, .retries = 10, .seed = 0, .seed_provided = 0, .senders = 1, .send_ip_pkts = 0, .source_port_first = 32768, // (these are the default .source_port_last = 61000, // ephemeral range on Linux), .status_updates_file = NULL, .syslog = 1}; void init_empty_global_configuration(struct state_conf *c) { memset(c->source_ip_addresses, 0, sizeof(c->source_ip_addresses)); } // global sender stats and defaults struct state_send zsend = { .start = 0.0, .finish = 0.0, .packets_sent = 0, .targets_scanned = 0, .warmup = 1, .complete = 0, .sendto_failures = 0, .max_targets = 0, .list_of_ips_pbm = NULL, }; // global receiver stats and defaults struct state_recv zrecv = { .success_unique = 0, .success_total = 0, .app_success_unique = 0, .app_success_total = 0, .validation_passed = 0, .validation_failed = 0, .cooldown_unique = 0, .cooldown_total = 0, .failure_total = 0, .filter_success = 0, .ip_fragments = 0, .complete = 0, .pcap_recv = 0, .pcap_drop = 0, .pcap_ifdrop = 0, }; zmap-4.3.4/src/state.h000066400000000000000000000134371501046211500145540ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef STATE_H #define STATE_H #include #include #include "../lib/includes.h" #ifdef PFRING #include #endif #include "aesrand.h" #include "fieldset.h" #include "filter.h" #include "types.h" #define MAC_ADDR_LEN_BYTES 6 #define DEDUP_METHOD_DEFAULT 0 #define DEDUP_METHOD_NONE 1 #define DEDUP_METHOD_FULL 2 #define DEDUP_METHOD_WINDOW 3 extern const char *const DEDUP_METHOD_NAMES[]; struct probe_module; struct output_module; struct fieldset_conf { fielddefset_t defs; fielddefset_t outdefs; translation_t translation; int success_index; int app_success_index; int classification_index; }; // global configuration struct state_conf { int log_level; struct port_conf *ports; port_h_t source_port_first; port_h_t source_port_last; // overrides a probe module's default behavior and forces it to perform source port validation, if supported // -1 = unset, 0 = validation disabled, 1 = validation enabled int8_t validate_source_port_override; // maximum number of packets that the scanner will send before // terminating uint64_t max_targets; // maximum number of seconds that scanner will run before terminating uint32_t max_runtime; // maximum number of results before terminating uint64_t max_results; // name of network interface that // will be utilized for sending/receiving char *iface; // rate in packets per second // that the sender will maintain int rate; // rate in bits per second uint64_t bandwidth; // how many seconds after the termination of the sender will the // receiver continue to process responses int cooldown_secs; // number of sending threads uint8_t senders; uint16_t batch; uint32_t pin_cores_len; uint32_t *pin_cores; // should use CLI provided randomization seed instead of generating // a random seed. int seed_provided; uint64_t seed; aesrand_t *aes; // generator of the cyclic multiplicative group that is utilized for // address generation uint32_t generator; // sharding options uint16_t shard_num; uint16_t total_shards; int packet_streams; struct probe_module *probe_module; char *output_module_name; struct output_module *output_module; char *probe_args; uint8_t probe_ttl; char *output_args; macaddr_t gw_mac[MAC_ADDR_LEN_BYTES]; macaddr_t hw_mac[MAC_ADDR_LEN_BYTES]; uint32_t gw_ip; int gw_mac_set; int hw_mac_set; in_addr_t source_ip_addresses[256]; uint32_t number_source_ips; int send_ip_pkts; char *output_filename; char *blocklist_filename; char *allowlist_filename; char *list_of_ips_filename; uint32_t list_of_ips_count; char *metadata_filename; FILE *metadata_file; char *notes; char *custom_metadata_str; char **destination_cidrs; int destination_cidrs_len; const char *raw_output_fields; const char **output_fields; struct output_filter filter; char *output_filter_str; struct fieldset_conf fsconf; int output_fields_len; char *log_file; char *log_directory; char *status_updates_file; int dryrun; int fast_dryrun; int quiet; int ignore_invalid_hosts; int syslog; int recv_ready; int retries; uint64_t total_allowed; uint64_t total_disallowed; int max_sendto_failures; float min_hitrate; int data_link_size; int default_mode; int no_header_row; int dedup_method; int dedup_window_size; #ifdef PFRING struct { pfring_zc_cluster *cluster; pfring_zc_queue *send; pfring_zc_queue *recv; pfring_zc_queue **queues; pfring_zc_pkt_buff **buffers; pfring_zc_buffer_pool *prefetches; } pf; #endif #ifdef NETMAP struct { int nm_fd; void *nm_mem; struct netmap_if *nm_if; uint32_t wait_ping_dstip; } nm; #endif }; extern struct state_conf zconf; void init_empty_global_configuration(struct state_conf *c); // global sender stats struct state_send { double start; double finish; uint64_t packets_sent; uint64_t targets_scanned; int warmup; int complete; uint32_t first_scanned; uint64_t max_targets; uint32_t sendto_failures; uint32_t max_ip_index; uint64_t max_target_index; uint8_t **list_of_ips_pbm; }; extern struct state_send zsend; // global receiver stats struct state_recv { // valid responses classified as "success" uint64_t success_total; // unique IPs that sent valid responses classified as "success" uint64_t success_unique; // valid responses classified as "success" uint64_t app_success_total; // unique IPs that sent valid responses classified as "success" uint64_t app_success_unique; // valid responses classified as "success" received during cooldown uint64_t cooldown_total; // unique IPs that first sent valid "success"es during cooldown uint64_t cooldown_unique; // valid responses NOT classified as "success" uint64_t failure_total; // valid responses that passed the filter uint64_t filter_success; // how many packets did we receive that were marked as being the first // fragment in a stream uint32_t ip_fragments; // metrics about _only_ validate_packet uint64_t validation_passed; uint64_t validation_failed; int complete; // has the scanner finished sending? double start; // timestamp of when recv started double finish; // timestamp of when recv terminated // number of packets captured by pcap filter uint64_t pcap_recv; // number of packets dropped because there was no room in // the operating system's buffer when they arrived, because // packets weren't being read fast enough uint64_t pcap_drop; // number of packets dropped by the network interface or its driver. uint64_t pcap_ifdrop; }; extern struct state_recv zrecv; struct port_conf { uint port_count; uint16_t ports[0xFFFF + 1]; uint8_t *port_bitmap; }; #endif // _STATE_H zmap-4.3.4/src/summary.c000066400000000000000000000302011501046211500151100ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include "summary.h" #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/logger.h" #include "../lib/blocklist.h" #include "state.h" #include "probe_modules/probe_modules.h" #include "output_modules/output_modules.h" #define STRTIME_LEN 1024 #include void json_metadata(FILE *file) { char send_start_time[STRTIME_LEN + 1]; assert(dstrftime(send_start_time, STRTIME_LEN, "%Y-%m-%dT%H:%M:%S%z", zsend.start)); char send_end_time[STRTIME_LEN + 1]; assert(dstrftime(send_end_time, STRTIME_LEN, "%Y-%m-%dT%H:%M:%S%z", zsend.finish)); char recv_start_time[STRTIME_LEN + 1]; assert(dstrftime(recv_start_time, STRTIME_LEN, "%Y-%m-%dT%H:%M:%S%z", zrecv.start)); char recv_end_time[STRTIME_LEN + 1]; assert(dstrftime(recv_end_time, STRTIME_LEN, "%Y-%m-%dT%H:%M:%S%z", zrecv.finish)); double hitrate = ((double)100 * zrecv.success_unique) / ((double)zsend.targets_scanned); json_object *obj = json_object_new_object(); // scanner host name char hostname[1024]; if (gethostname(hostname, 1023) < 0) { log_error("json_metadata", "unable to retrieve local hostname"); } else { hostname[1023] = '\0'; json_object_object_add(obj, "local_hostname", json_object_new_string(hostname)); struct hostent *h = gethostbyname(hostname); if (h) { json_object_object_add( obj, "full_hostname", json_object_new_string(h->h_name)); } else { log_error("json_metadata", "unable to retrieve complete hostname"); } } if (zconf.ports) { json_object_object_add( obj, "source_port_first", json_object_new_int(zconf.source_port_first)); json_object_object_add( obj, "source_port_last", json_object_new_int(zconf.source_port_last)); json_object *target_ports = json_object_new_array(); for (uint i = 0; i < zconf.ports->port_count; i++) { json_object_array_add( target_ports, json_object_new_int(zconf.ports->ports[i])); } json_object_object_add(obj, "target_ports", target_ports); } json_object_object_add(obj, "max_targets", json_object_new_int64(zconf.max_targets)); json_object_object_add(obj, "max_runtime", json_object_new_int64(zconf.max_runtime)); json_object_object_add(obj, "max_results", json_object_new_int64(zconf.max_results)); json_object_object_add(obj, "output_results", json_object_new_int64(zrecv.filter_success)); if (zconf.iface) { json_object_object_add(obj, "iface", json_object_new_string(zconf.iface)); } json_object_object_add(obj, "rate", json_object_new_int(zconf.rate)); json_object_object_add(obj, "bandwidth", json_object_new_int64(zconf.bandwidth)); json_object_object_add(obj, "cooldown_secs", json_object_new_int(zconf.cooldown_secs)); json_object_object_add(obj, "senders", json_object_new_int(zconf.senders)); json_object_object_add(obj, "seed", json_object_new_int64(zconf.seed)); json_object_object_add(obj, "seed_provided", json_object_new_int64(zconf.seed_provided)); json_object_object_add(obj, "generator", json_object_new_int64(zconf.generator)); json_object_object_add(obj, "hitrate", json_object_new_double(hitrate)); json_object_object_add(obj, "shard_num", json_object_new_int(zconf.shard_num)); json_object_object_add(obj, "total_shards", json_object_new_int(zconf.total_shards)); json_object_object_add(obj, "min_hitrate", json_object_new_double(zconf.min_hitrate)); json_object_object_add(obj, "max_sendto_failures", json_object_new_int(zconf.max_sendto_failures)); json_object_object_add(obj, "syslog", json_object_new_int(zconf.syslog)); json_object_object_add(obj, "default_mode", json_object_new_int(zconf.default_mode)); json_object_object_add(obj, "pcap_recv", json_object_new_int64(zrecv.pcap_recv)); json_object_object_add(obj, "pcap_drop", json_object_new_int64(zrecv.pcap_drop)); json_object_object_add(obj, "pcap_ifdrop", json_object_new_int64(zrecv.pcap_ifdrop)); json_object_object_add(obj, "ip_fragments", json_object_new_int64(zrecv.ip_fragments)); json_object_object_add(obj, "blocklist_total_allowed", json_object_new_int64(zconf.total_allowed)); json_object_object_add(obj, "blocklist_total_not_allowed", json_object_new_int64(zconf.total_disallowed)); json_object_object_add(obj, "validation_passed", json_object_new_int64(zrecv.validation_passed)); json_object_object_add(obj, "validation_failed", json_object_new_int64(zrecv.validation_failed)); // json_object_object_add(obj, "blocklisted", // json_object_new_int64(zsend.blocklisted)); // json_object_object_add(obj, "allowlisted", // json_object_new_int64(zsend.allowlisted)); json_object_object_add(obj, "first_scanned", json_object_new_int64(zsend.first_scanned)); json_object_object_add(obj, "send_to_failures", json_object_new_int64(zsend.sendto_failures)); json_object_object_add(obj, "packets_sent", json_object_new_int64(zsend.packets_sent)); json_object_object_add(obj, "targets_scanned", json_object_new_int64(zsend.targets_scanned)); json_object_object_add(obj, "success_total", json_object_new_int64(zrecv.success_total)); json_object_object_add(obj, "success_unique", json_object_new_int64(zrecv.success_unique)); if (zconf.fsconf.app_success_index >= 0) { json_object_object_add( obj, "app_success_total", json_object_new_int64(zrecv.app_success_total)); json_object_object_add( obj, "app_success_unique", json_object_new_int64(zrecv.app_success_unique)); } json_object_object_add(obj, "success_cooldown_total", json_object_new_int64(zrecv.cooldown_total)); json_object_object_add(obj, "success_cooldown_unique", json_object_new_int64(zrecv.cooldown_unique)); json_object_object_add(obj, "failure_total", json_object_new_int64(zrecv.failure_total)); json_object_object_add(obj, "packet_streams", json_object_new_int(zconf.packet_streams)); json_object_object_add( obj, "probe_module", json_object_new_string( ((probe_module_t *)zconf.probe_module)->name)); json_object_object_add( obj, "output_module", json_object_new_string( ((output_module_t *)zconf.output_module)->name)); json_object_object_add(obj, "send_start_time", json_object_new_string(send_start_time)); json_object_object_add(obj, "send_end_time", json_object_new_string(send_end_time)); json_object_object_add(obj, "recv_start_time", json_object_new_string(recv_start_time)); json_object_object_add(obj, "recv_end_time", json_object_new_string(recv_end_time)); if (zconf.output_filter_str) { json_object_object_add( obj, "output_filter", json_object_new_string(zconf.output_filter_str)); } if (zconf.log_file) { json_object_object_add(obj, "log_file", json_object_new_string(zconf.log_file)); } if (zconf.log_directory) { json_object_object_add( obj, "log_directory", json_object_new_string(zconf.log_directory)); } if (zconf.destination_cidrs_len) { json_object *cli_dest_cidrs = json_object_new_array(); for (int i = 0; i < zconf.destination_cidrs_len; i++) { json_object_array_add( cli_dest_cidrs, json_object_new_string(zconf.destination_cidrs[i])); } json_object_object_add(obj, "cli_cidr_destinations", cli_dest_cidrs); } if (zconf.probe_args) { json_object_object_add( obj, "probe_args", json_object_new_string(zconf.probe_args)); } if (zconf.probe_ttl) { json_object_object_add(obj, "probe_ttl", json_object_new_int(zconf.probe_ttl)); } if (zconf.output_args) { json_object_object_add( obj, "output_args", json_object_new_string(zconf.output_args)); } { char mac_buf[(MAC_ADDR_LEN * 2) + (MAC_ADDR_LEN - 1) + 1]; memset(mac_buf, 0, sizeof(mac_buf)); char *p = mac_buf; for (int i = 0; i < MAC_ADDR_LEN; i++) { if (i == MAC_ADDR_LEN - 1) { snprintf(p, 3, "%.2x", zconf.gw_mac[i]); p += 2; } else { snprintf(p, 4, "%.2x:", zconf.gw_mac[i]); p += 3; } } json_object_object_add(obj, "gateway_mac", json_object_new_string(mac_buf)); } if (zconf.gw_ip) { struct in_addr addr; addr.s_addr = zconf.gw_ip; json_object_object_add(obj, "gateway_ip", json_object_new_string(inet_ntoa(addr))); } { char mac_buf[(ETHER_ADDR_LEN * 2) + (ETHER_ADDR_LEN - 1) + 1]; char *p = mac_buf; for (int i = 0; i < ETHER_ADDR_LEN; i++) { if (i == ETHER_ADDR_LEN - 1) { snprintf(p, 3, "%.2x", zconf.hw_mac[i]); p += 2; } else { snprintf(p, 4, "%.2x:", zconf.hw_mac[i]); p += 3; } } json_object_object_add(obj, "source_mac", json_object_new_string(mac_buf)); } json_object *source_ips = json_object_new_array(); for (uint i = 0; i < zconf.number_source_ips; i++) { struct in_addr temp; temp.s_addr = zconf.source_ip_addresses[i]; json_object_array_add(source_ips, json_object_new_string( strdup(inet_ntoa(temp)))); } json_object_object_add(obj, "source_ips", source_ips); if (zconf.output_filename) { json_object_object_add( obj, "output_filename", json_object_new_string(zconf.output_filename)); } if (zconf.blocklist_filename) { json_object_object_add( obj, "blocklist_filename", json_object_new_string(zconf.blocklist_filename)); } if (zconf.allowlist_filename) { json_object_object_add( obj, "allowlist_filename", json_object_new_string(zconf.allowlist_filename)); } if (zconf.list_of_ips_filename) { json_object_object_add( obj, "list_of_ips_filename", json_object_new_string(zconf.list_of_ips_filename)); json_object_object_add( obj, "list_of_ips_count", json_object_new_int64(zconf.list_of_ips_count)); } json_object_object_add(obj, "dryrun", json_object_new_int(zconf.dryrun)); json_object_object_add(obj, "quiet", json_object_new_int(zconf.quiet)); json_object_object_add(obj, "log_level", json_object_new_int(zconf.log_level)); json_object_object_add( obj, "deduplication_method", json_object_new_string(DEDUP_METHOD_NAMES[zconf.dedup_method])); if (zconf.dedup_method == DEDUP_METHOD_WINDOW) { json_object_object_add( obj, "deduplication_window_size", json_object_new_int(zconf.dedup_window_size)); } // parse out JSON metadata that was supplied on the command-line if (zconf.custom_metadata_str) { json_object *user = json_tokener_parse(zconf.custom_metadata_str); if (!user) { log_error("json-metadata", "unable to parse user metadata"); } else { json_object_object_add(obj, "user-metadata", user); } } if (zconf.notes) { json_object_object_add(obj, "notes", json_object_new_string(zconf.notes)); } // add blocklisted and allowlisted CIDR blocks bl_cidr_node_t *b = get_blocklisted_cidrs(); if (b) { json_object *blocklisted_cidrs = json_object_new_array(); do { char cidr[50]; struct in_addr addr; addr.s_addr = b->ip_address; sprintf(cidr, "%s/%i", inet_ntoa(addr), b->prefix_len); json_object_array_add(blocklisted_cidrs, json_object_new_string(cidr)); } while (b && (b = b->next)); json_object_object_add(obj, "blocklisted_networks", blocklisted_cidrs); } b = get_allowlisted_cidrs(); if (b) { json_object *allowlisted_cidrs = json_object_new_array(); do { char cidr[50]; struct in_addr addr; addr.s_addr = b->ip_address; sprintf(cidr, "%s/%i", inet_ntoa(addr), b->prefix_len); json_object_array_add(allowlisted_cidrs, json_object_new_string(cidr)); } while (b && (b = b->next)); json_object_object_add(obj, "allowlisted_networks", allowlisted_cidrs); } fprintf(file, "%s\n", json_object_to_json_string(obj)); json_object_put(obj); } zmap-4.3.4/src/summary.h000066400000000000000000000013531501046211500151230ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ZMAP_SUMMARY_H #define ZMAP_SUMMARY_H #include void json_metadata(FILE *); #endif /* ZMAP_SUMMARY_H */ zmap-4.3.4/src/tests/000077500000000000000000000000001501046211500144155ustar00rootroot00000000000000zmap-4.3.4/src/tests/test_harness.c000066400000000000000000000044451501046211500172720ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/blocklist.h" #include "../lib/logger.h" #include "../lib/random.h" #include "../lib/util.h" #include "../lib/xalloc.h" #include "aesrand.h" #include "send.h" #include "recv.h" #include "state.h" #include "monitor.h" #include "get_gateway.h" #include "filter.h" #include "summary.h" #include "output_modules/output_modules.h" #include "probe_modules/probe_modules.h" #include "output_modules/module_json.h" #include "ztopt.h" int test_recursive_fieldsets(void) { fieldset_t *outer = fs_new_fieldset(NULL); fieldset_t *inner = fs_new_fieldset(NULL); fieldset_t *repeated = fs_new_repeated_string(0); assert(repeated->type == FS_REPEATED); assert(repeated->len == 0); assert(repeated->inner_type == FS_STRING); for (int i = 0; i < 10; i++) { fs_add_string(repeated, NULL, (char *)"hello world!", 0); } fs_add_repeated(outer, (char *)"repeatedstuff", repeated); fs_add_string(outer, "name", strdup("value"), 0); fs_add_string(inner, "name2", strdup("value2"), 0); fs_add_fieldset(outer, "inner", inner); print_json_fieldset(outer); fs_free(outer); return EXIT_SUCCESS; } int main(UNUSED int argc, UNUSED char **argv) { struct gengetopt_args_info args; struct cmdline_parser_params *params; params = cmdline_parser_params_create(); assert(params); params->initialize = 1; params->override = 0; params->check_required = 0; if (cmdline_parser_ext(argc, argv, &args, params) != 0) { exit(EXIT_SUCCESS); } // Handle help text and version if (args.help_given) { cmdline_parser_print_help(); exit(EXIT_SUCCESS); } if (args.version_given) { cmdline_parser_print_version(); exit(EXIT_SUCCESS); } for (int i = 0; i < 100000000; i++) test_recursive_fieldsets(); return EXIT_SUCCESS; } zmap-4.3.4/src/topt.ggo.in000066400000000000000000000031351501046211500153460ustar00rootroot00000000000000# ZTee Copyright 2014 Regents of the University of Michigan # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at http://www.apache.org/licenses/LICENSE-2.0 # ztee option description to be processed by gengetopt package "ztee" version "@ZMAP_VERSION@" purpose "A buffering output splitter" section "Basic arguments" option "success-only" - "Only write to stdout rows where success=1 or success=true" optional option "monitor" m "Print monitor data to stderr" optional option "status-updates-file" u "File to write status updates, in CSV format" typestr="monitor.csv" optional string option "log-file" l "File to log errors, etc. to" optional string option "raw" r "Ignore input formatting and pass through raw input" optional section "Additional options" option "help" h "Print help and exit" optional option "version" V "Print version and exit" optional text "\nExamples:\n\ zmap -p 80 -o - | ztee zmap.csv (save zmap output to zmap.csv and output all IP addresses to stdout)\n\ zmap -p 80 --output-fields=* -o - | ztee --success-only zmap.csv (save all zmap output to zmap.csv, print IPs from successful rows to stdout)\n\ zmap -p 80 -o - | ztee -u status.csv zmap.csv (save zmap output to zmap.csv, write status updates to status.csv, print all IPs to stdout)\n\ echo \"hello, ztee\" | ztee --raw out.txt (write text to out.txt and to stdout, like tee)" zmap-4.3.4/src/topt_compat.c000066400000000000000000000015731501046211500157560ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if __GNUC__ < 4 #error "gcc version >= 4 is required" #elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #elif __GNUC_MINOR__ >= 4 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif #include "topt.c" zmap-4.3.4/src/utility.c000066400000000000000000000042271501046211500151270ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include "state.h" #include "utility.h" #include "../lib/logger.h" in_addr_t string_to_ip_address(char *t) { in_addr_t r = inet_addr(t); if (r == INADDR_NONE) { log_fatal("send", "invalid ip address: `%s'", t); } return r; } void add_to_array(char *to_add) { if (zconf.number_source_ips >= 256) { // log fatal here log_fatal("parse", "over 256 source IP addresses provided"); } log_debug("SEND", "ipaddress: %s\n", to_add); zconf.source_ip_addresses[zconf.number_source_ips] = string_to_ip_address(to_add); zconf.number_source_ips++; } void parse_source_ip_addresses(char given_string[]) { char *dash = strchr(given_string, '-'); char *comma = strchr(given_string, ','); if (dash && comma) { *comma = '\0'; parse_source_ip_addresses(given_string); parse_source_ip_addresses(comma + 1); } else if (comma) { while (comma) { *comma = '\0'; add_to_array(given_string); given_string = comma + 1; comma = strchr(given_string, ','); if (!comma) { add_to_array(given_string); } } } else if (dash) { *dash = '\0'; log_debug("SEND", "address: %s\n", given_string); log_debug("SEND", "address: %s\n", dash + 1); in_addr_t start = ntohl(string_to_ip_address(given_string)); in_addr_t end = ntohl(string_to_ip_address(dash + 1)) + 1; while (start != end) { struct in_addr temp; temp.s_addr = htonl(start); add_to_array(strdup(inet_ntoa(temp))); start++; } } else { add_to_array(given_string); } } // Not all platforms have strlcpy, so we provide our own using strncpy size_t cross_platform_strlcpy(char *dst, const char *src, size_t siz) { if (siz == 0) // Handle zero size as strlcpy does return strlen(src); strncpy(dst, src, siz - 1); // Copy at most size - 1 characters dst[siz - 1] = '\0'; // Ensure null-termination return strlen(src); // Return the length of src } zmap-4.3.4/src/utility.h000066400000000000000000000015501501046211500151300ustar00rootroot00000000000000/* * Copyright 2021 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef UTILITY_H #define UTILITY_H #include void parse_source_ip_addresses(char given_string[]); in_addr_t string_to_ip_address(char *t); size_t cross_platform_strlcpy(char *dst, const char *src, size_t siz); #endif // UTILITY_H zmap-4.3.4/src/validate.c000066400000000000000000000031021501046211500152040ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #include #include #include "../lib/aes128.h" #include "../lib/random.h" #include "../lib/logger.h" #include "validate.h" static aes128_ctx_t *aes128 = NULL; /* * validate.c encrypts the src IP, dst IP and source port of a probe into a 16-bit value put in the IPID. * We use a random key to encrypt the values, static across this ZMap run, so we can * identify packets that came form this ZMap scan. * This is used to validate a probe response and ensure it is a response to a probe we sent in this ZMap run. */ void validate_init(void) { uint8_t key[AES128_KEY_BYTES]; if (!random_bytes(key, sizeof(key))) { log_fatal("validate", "couldn't get random bytes"); } aes128 = aes128_init(key); } void validate_gen(const uint32_t src, const uint32_t dst, const uint16_t dst_port, uint8_t output[VALIDATE_BYTES]) { validate_gen_ex(src, dst, (uint32_t)dst_port, 0, output); } void validate_gen_ex(const uint32_t input0, const uint32_t input1, const uint32_t input2, const uint32_t input3, uint8_t output[VALIDATE_BYTES]) { assert(aes128); uint32_t aes_input[AES128_BLOCK_BYTES / sizeof(uint32_t)]; aes_input[0] = input0; aes_input[1] = input1; aes_input[2] = input2; aes_input[3] = input3; aes128_encrypt_block(aes128, (uint8_t *)aes_input, output); } zmap-4.3.4/src/validate.h000066400000000000000000000012571501046211500152220ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef VALIDATE_H #define VALIDATE_H #define VALIDATE_BYTES 16 void validate_init(void); void validate_gen(const uint32_t src, const uint32_t dst, const uint16_t dst_port, uint8_t output[VALIDATE_BYTES]); void validate_gen_ex(const uint32_t input0, const uint32_t input1, const uint32_t input2, const uint32_t input3, uint8_t output[VALIDATE_BYTES]); #endif //_VALIDATE_H zmap-4.3.4/src/zblocklist.1000066400000000000000000000031001501046211500155070ustar00rootroot00000000000000.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "ZBLOCKLIST" "1" "February 2024" "ZMap" "zblocklist" . .SH "NAME" \fBzblocklist\fR \- zmap IP blocklist tool . .SH "SYNOPSIS" zblocklist [ \-b ] [ \-w ] [ OPTIONS\.\.\. ] . .SH "DESCRIPTION" \fIZBlacklist\fR is a network tool for limiting and deduplicating a list of IP addresses using a blocklist or allowlist\. . .SH "OPTIONS" . .SS "BASIC OPTIONS" . .TP \fB\-b\fR, \fB\-\-blocklist\-file=path\fR File of subnets to exclude, in CIDR notation, one\-per line\. It is recommended you use this to exclude RFC 1918 addresses, multicast, IANA reserved space, and other IANA special\-purpose addresses\. An example blocklist file \fBblocklist\.conf\fR for this purpose\. . .TP \fB\-w\fR, \fB\-\-allowlist\-file=name\fR File of subnets to include, in CIDR notation, one\-per line\. All other subnets will be excluded\. . .TP \fB\-l\fR, \fB\-\-log\-file=name\fR File to log to\. . .TP \fB\-\-disable\-syslog\fR Disable logging messages to syslog\. . .TP \fB\-v\fR, \fB\-\-verbosity\fR Level of log detail (0\-5, default=3) . .TP \fB\-\-no\-duplicate\-checking\fR Don\'t deduplicate input addresses\. Default is false\. . .TP \fB\-\-ignore\-blocklist\-errors\fR Ignore invalid, malformed, or unresolvable entries in the blocklist/allowlist\. Default is false\. . .TP \fB\-\-ignore\-input\-errors\fR Don\'t print invalid entries in the input\. Default is false\. . .SS "ADDITIONAL OPTIONS" . .TP \fB\-h\fR, \fB\-\-help\fR Print help and exit . .TP \fB\-V\fR, \fB\-\-version\fR Print version and exit zmap-4.3.4/src/zblocklist.1.html000066400000000000000000000113461501046211500164650ustar00rootroot00000000000000 zblocklist(1) - zmap IP blocklist tool
  1. zblocklist(1)
  2. zblocklist
  3. zblocklist(1)

NAME

zblocklist - zmap IP blocklist tool

SYNOPSIS

zblocklist [ -b <blocklist> ] [ -w <allowlist> ] [ OPTIONS... ]

DESCRIPTION

ZBlacklist is a network tool for limiting and deduplicating a list of IP addresses using a blocklist or allowlist.

OPTIONS

BASIC OPTIONS

-b, --blocklist-file=path

File of subnets to exclude, in CIDR notation, one-per line. It is recommended you use this to exclude RFC 1918 addresses, multicast, IANA reserved space, and other IANA special-purpose addresses. An example blocklist file blocklist.conf for this purpose.

-w, --allowlist-file=name

File of subnets to include, in CIDR notation, one-per line. All other subnets will be excluded.

-l, --log-file=name

File to log to.

--disable-syslog

Disable logging messages to syslog.

-v, --verbosity

Level of log detail (0-5, default=3)

--no-duplicate-checking

Don't deduplicate input addresses. Default is false.

--ignore-blocklist-errors

Ignore invalid, malformed, or unresolvable entries in the blocklist/allowlist. Default is false.

--ignore-input-errors

Don't print invalid entries in the input. Default is false.

ADDITIONAL OPTIONS

-h, --help

Print help and exit

-V, --version

Print version and exit

  1. ZMap
  2. February 2024
  3. zblocklist(1)
zmap-4.3.4/src/zblocklist.1.ronn000066400000000000000000000026161501046211500164750ustar00rootroot00000000000000zblocklist(1) - zmap IP blocklist tool ====================================== ## SYNOPSIS zblocklist [ -b <blocklist> ] [ -w <allowlist> ] [ OPTIONS... ] ## DESCRIPTION *ZBlacklist* is a network tool for limiting and deduplicating a list of IP addresses using a blocklist or allowlist. ## OPTIONS ### BASIC OPTIONS ### * `-b`, `--blocklist-file=path`: File of subnets to exclude, in CIDR notation, one-per line. It is recommended you use this to exclude RFC 1918 addresses, multicast, IANA reserved space, and other IANA special-purpose addresses. An example blocklist file **blocklist.conf** for this purpose. * `-w`, `--allowlist-file=name`: File of subnets to include, in CIDR notation, one-per line. All other subnets will be excluded. * `-l`, `--log-file=name`: File to log to. * `--disable-syslog`: Disable logging messages to syslog. * `-v`, `--verbosity`: Level of log detail (0-5, default=3) * `--no-duplicate-checking`: Don't deduplicate input addresses. Default is false. * `--ignore-blocklist-errors`: Ignore invalid, malformed, or unresolvable entries in the blocklist/allowlist. Default is false. * `--ignore-input-errors`: Don't print invalid entries in the input. Default is false. ### ADDITIONAL OPTIONS ### * `-h`, `--help`: Print help and exit * `-V`, `--version`: Print version and exit zmap-4.3.4/src/zblocklist.c000066400000000000000000000153521501046211500156050ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ /* * ZBlocklist is a simple utility that (1) excludes IP addresses on a specified * blocklist from being scanned, and (2) ensures the uniqueness of output * addresses such that no host is scanned twice. ZBlocklist takes in a list * of addresses on stdin and outputs addresses that are acceptable to scan * on stdout. The utility uses the blocklist data structures from ZMap for * checking scan eligibility and a paged bitmap for duplicate prevention. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/blocklist.h" #include "../lib/logger.h" #include "../lib/pbm.h" #include "zbopt.h" // struct zbl_stats { // uint32_t cidr_entries; // uint32_t allowed_addrs; // uint32_t input_addrs; // uint32_t uniq_input_addrs; // uint32_t blocked_addrs; // uint32_t output_addrs; // uint32_t duplicates; //}; #undef MIN #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) // allow 1mb lines + newline + \0 #define MAX_LINE_LENGTH 1024 * 1024 + 2 static inline char *zmin(char *a, char *b) { if (a && !b) return a; else if (b && !a) return b; else return MIN(a, b); } struct zbl_conf { char *blocklist_filename; char *allowlist_filename; char *log_filename; int check_duplicates; int ignore_blocklist_errors; int ignore_input_errors; int verbosity; int disable_syslog; // struct zbl_stats stats; }; #define SET_IF_GIVEN(DST, ARG) \ { \ if (args.ARG##_given) { \ (DST) = args.ARG##_arg; \ }; \ } #define SET_BOOL(DST, ARG) \ { \ if (args.ARG##_given) { \ (DST) = 1; \ }; \ } int main(int argc, char **argv) { struct zbl_conf conf; conf.verbosity = 3; memset(&conf, 0, sizeof(struct zbl_conf)); int no_dupchk_pres = 0; conf.ignore_blocklist_errors = 0; conf.ignore_input_errors = 0; struct gengetopt_args_info args; struct cmdline_parser_params *params; params = cmdline_parser_params_create(); assert(params); params->initialize = 1; params->override = 0; params->check_required = 0; if (cmdline_parser_ext(argc, argv, &args, params) != 0) { exit(EXIT_SUCCESS); } // Handle help text and version if (args.help_given) { cmdline_parser_print_help(); exit(EXIT_SUCCESS); } if (args.version_given) { cmdline_parser_print_version(); exit(EXIT_SUCCESS); } // Set the log file and metadata file if (args.log_file_given) { conf.log_filename = strdup(args.log_file_arg); } if (args.verbosity_given) { conf.verbosity = args.verbosity_arg; } // Blocklist and allowlist if (args.blocklist_file_given) { conf.blocklist_filename = strdup(args.blocklist_file_arg); } if (args.allowlist_file_given) { conf.allowlist_filename = strdup(args.allowlist_file_arg); } // Read the boolean flags SET_BOOL(no_dupchk_pres, no_duplicate_checking); conf.check_duplicates = !no_dupchk_pres; SET_BOOL(conf.ignore_blocklist_errors, ignore_blocklist_errors); SET_BOOL(conf.ignore_input_errors, ignore_input_errors); SET_BOOL(conf.disable_syslog, disable_syslog); // initialize logging FILE *logfile = stderr; if (conf.log_filename) { logfile = fopen(conf.log_filename, "w"); if (!logfile) { fprintf( stderr, "FATAL: unable to open specified logfile (%s)\n", conf.log_filename); exit(1); } } if (log_init(logfile, conf.verbosity, !conf.disable_syslog, "zblocklist")) { fprintf(stderr, "FATAL: unable able to initialize logging\n"); exit(1); } if (!conf.blocklist_filename && !conf.allowlist_filename) { log_fatal("zblocklist", "must specify either a allowlist or blocklist file"); } // parse blocklist if (conf.blocklist_filename) { log_debug("zblocklist", "blocklist file at %s to be used", conf.blocklist_filename); } else { log_debug("zblocklist", "no blocklist file specified"); } if (conf.blocklist_filename && access(conf.blocklist_filename, R_OK) == -1) { log_fatal("zblocklist", "unable to read specified blocklist file (%s)", conf.blocklist_filename); } if (conf.allowlist_filename) { log_debug("zblocklist", "allowlist file at %s to be used", conf.allowlist_filename); } else { log_debug("zblocklist", "no allowlist file specified"); } if (conf.allowlist_filename && access(conf.allowlist_filename, R_OK) == -1) { log_fatal("zblocklist", "unable to read specified allowlist file (%s)", conf.allowlist_filename); } if (blocklist_init(conf.allowlist_filename, conf.blocklist_filename, NULL, 0, NULL, 0, conf.ignore_blocklist_errors)) { log_fatal("zmap", "unable to initialize blocklist / allowlist"); } // initialize paged bitmap uint8_t **seen = NULL; if (conf.check_duplicates) { seen = pbm_init(); if (!seen) { log_fatal("zblocklist", "unable to initialize paged bitmap"); } } // process addresses char *line = malloc(MAX_LINE_LENGTH); assert(line); char *original = malloc(MAX_LINE_LENGTH); assert(original); while (fgets(line, MAX_LINE_LENGTH, stdin) != NULL) { size_t len = strlen(line); if (len >= (MAX_LINE_LENGTH - 1)) { log_fatal("zblocklist", "received line longer than max length: %i", MAX_LINE_LENGTH); } // remove new line memcpy(original, line, len + 1); char *n = zmin(zmin(zmin(zmin(strchr(line, '\n'), strchr(line, ',')), strchr(line, '\t')), strchr(line, ' ')), strchr(line, '#')); assert(n); n[0] = 0; log_debug("zblocklist", "input value %s", line); // parse into int struct in_addr addr; if (!inet_aton(line, &addr)) { log_warn("zblocklist", "invalid input address: %s", line); if (!conf.ignore_input_errors) { printf("%s", original); } continue; } if (conf.check_duplicates) { if (pbm_check(seen, ntohl(addr.s_addr))) { log_debug("zblocklist", "%s is a duplicate: skipped", line); continue; } else { log_debug("zblocklist", "%s not a duplicate: skipped", line); } } else { log_debug("zblocklist", "no duplicate checking for %s", line); } // check if in blocklist if (blocklist_is_allowed(addr.s_addr)) { if (conf.check_duplicates) { if (!pbm_check(seen, ntohl(addr.s_addr))) { pbm_set(seen, ntohl(addr.s_addr)); printf("%s", original); } } else { printf("%s", original); } } } return EXIT_SUCCESS; } zmap-4.3.4/src/zbopt.ggo.in000066400000000000000000000033011501046211500155110ustar00rootroot00000000000000# ZBlacklist Copyright 2014 Regents of the University of Michigan # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at http://www.apache.org/licenses/LICENSE-2.0 # zblocklist option description to be processed by gengetopt package "zblocklist" version "@ZMAP_VERSION@" purpose "A tool for limiting and deduplicating a list of IP addresses" section "Basic arguments" option "blocklist-file" b "File of subnets to exclude, in CIDR notation, one-per line." optional string option "allowlist-file" w "File of subnets to include, in CIDR notation, one-per line." optional string option "log-file" l "File to log to" optional string option "verbosity" v "Set log level verbosity (0-5, default 3)" default="3" optional int option "no-duplicate-checking" - "Don't deduplicate IP addresses (default false)" optional option "ignore-blocklist-errors" - "Ignore invalid entries in the blocklist/allowlist (default false)" optional option "ignore-input-errors" - "Don't print invalid entries in the input (default false)" optional option "disable-syslog" - "Disables logging messages to syslog" optional section "Additional options" option "help" h "Print help and exit" optional option "version" V "Print version and exit" optional section "Notes" text "At least one of --allowlist-file or --blocklist-file must be specified. Blacklist files take precedence over allowlist files when both are specified. This results in an output of {allowlist - blocklist}." zmap-4.3.4/src/zbopt_compat.c000066400000000000000000000010621501046211500161170ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #if __GNUC__ < 4 #error "gcc version >= 4 is required" #elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #elif __GNUC_MINOR__ >= 4 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif #include "zbopt.c" zmap-4.3.4/src/ziterate.1000066400000000000000000000036601501046211500151710ustar00rootroot00000000000000.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "ZITERATE" "1" "December 2024" "ZMap" "ziterate" . .SH "NAME" \fBziterate\fR \- ZMap IP permutation generation file . .SH "SYNOPSIS" ziterate [ \-b ] [ \-w ] [ OPTIONS\.\.\. ] . .SH "DESCRIPTION" \fIZIterate\fR is a network tool that will produce IPv4 addresses in a psuedorandom order similar to how ZMap generates random addresses to be scanned\. . .SH "OPTIONS" . .SS "BASIC OPTIONS" . .TP \fB\-p\fR, \fB\-\-target\-ports=port(s)\fR List of TCP/UDP ports and/or port ranges to scan\. (e\.g\., 80,443,100\-105)\. Use \'*\' to scan all ports, including port 0\. If no port is specified, ziterate will output only IPs\. . .TP \fB\-b\fR, \fB\-\-blocklist\-file=path\fR File of subnets to exclude, in CIDR notation, one\-per line\. It is recommended you use this to exclude RFC 1918 addresses, multicast, IANA reserved space, and other IANA special\-purpose addresses\. An example blocklist file \fBblocklist\.conf\fR for this purpose\. . .TP \fB\-w\fR, \fB\-\-allowlist\-file=name\fR File of subnets to include, in CIDR notation, one\-per line\. All other subnets will be excluded\. . .TP \fB\-l\fR, \fB\-\-log\-file=name\fR File to log to\. . .TP \fB\-\-disable\-syslog\fR Disable logging messages to syslog\. . .TP \fB\-v\fR, \fB\-\-verbosity\fR Level of log detail (0\-5, default=3) . .TP \fB\-\-ignore\-blocklist\-errors\fR Ignore invalid entries in the blocklist\. Default is false\. . .TP \fB\-\-seed=n\fR Seed used to select address permutation\. . .TP \fB\-n\fR, \fB\-\-max\-targets=n\fR Cap number of IPs to generate (as a number or a percentage of the address space) . .SS "SHARDING" . .TP \fB\-\-shards=n\fR Total number of shards\. . .TP \fB\-\-shard=n\fR Shard this scan is targeting\. Zero indexed\. . .SS "ADDITIONAL OPTIONS" . .TP \fB\-h\fR, \fB\-\-help\fR Print help text and exit\. . .TP \fB\-V\fR, \fB\-\-version\fR Print version and exit\. zmap-4.3.4/src/ziterate.1.html000066400000000000000000000123101501046211500161240ustar00rootroot00000000000000 ziterate(1) - ZMap IP permutation generation file
  1. ziterate(1)
  2. ziterate
  3. ziterate(1)

NAME

ziterate - ZMap IP permutation generation file

SYNOPSIS

ziterate [ -b <blocklist> ] [ -w <allowlist> ] [ OPTIONS... ]

DESCRIPTION

ZIterate is a network tool that will produce IPv4 addresses in a psuedorandom order similar to how ZMap generates random addresses to be scanned.

OPTIONS

BASIC OPTIONS

-p, --target-ports=port(s)

List of TCP/UDP ports and/or port ranges to scan. (e.g., 80,443,100-105). Use '*' to scan all ports, including port 0. If no port is specified, ziterate will output only IPs.

-b, --blocklist-file=path

File of subnets to exclude, in CIDR notation, one-per line. It is recommended you use this to exclude RFC 1918 addresses, multicast, IANA reserved space, and other IANA special-purpose addresses. An example blocklist file blocklist.conf for this purpose.

-w, --allowlist-file=name

File of subnets to include, in CIDR notation, one-per line. All other subnets will be excluded.

-l, --log-file=name

File to log to.

--disable-syslog

Disable logging messages to syslog.

-v, --verbosity

Level of log detail (0-5, default=3)

--ignore-blocklist-errors

Ignore invalid entries in the blocklist. Default is false.

--seed=n

Seed used to select address permutation.

-n, --max-targets=n

Cap number of IPs to generate (as a number or a percentage of the address space)

SHARDING

--shards=n

Total number of shards.

--shard=n

Shard this scan is targeting. Zero indexed.

ADDITIONAL OPTIONS

-h, --help

Print help text and exit.

-V, --version

Print version and exit.

  1. ZMap
  2. December 2024
  3. ziterate(1)
zmap-4.3.4/src/ziterate.1.ronn000066400000000000000000000034001501046211500161340ustar00rootroot00000000000000ziterate(1) - ZMap IP permutation generation file ================================================= ## SYNOPSIS ziterate [ -b <blocklist> ] [ -w <allowlist> ] [ OPTIONS... ] ## DESCRIPTION *ZIterate* is a network tool that will produce IPv4 addresses in a psuedorandom order similar to how ZMap generates random addresses to be scanned. ## OPTIONS ### BASIC OPTIONS ### * `-p`, `--target-ports=port(s)`: List of TCP/UDP ports and/or port ranges to scan. (e.g., 80,443,100-105). Use '*' to scan all ports, including port 0. If no port is specified, ziterate will output only IPs. * `-b`, `--blocklist-file=path`: File of subnets to exclude, in CIDR notation, one-per line. It is recommended you use this to exclude RFC 1918 addresses, multicast, IANA reserved space, and other IANA special-purpose addresses. An example blocklist file **blocklist.conf** for this purpose. * `-w`, `--allowlist-file=name`: File of subnets to include, in CIDR notation, one-per line. All other subnets will be excluded. * `-l`, `--log-file=name`: File to log to. * `--disable-syslog`: Disable logging messages to syslog. * `-v`, `--verbosity`: Level of log detail (0-5, default=3) * `--ignore-blocklist-errors`: Ignore invalid entries in the blocklist. Default is false. * `--seed=n`: Seed used to select address permutation. * `-n`, `--max-targets=n`: Cap number of IPs to generate (as a number or a percentage of the address space) ### SHARDING ### * `--shards=n`: Total number of shards. * `--shard=n`: Shard this scan is targeting. Zero indexed. ### ADDITIONAL OPTIONS ### * `-h`, `--help`: Print help text and exit. * `-V`, `--version`: Print version and exit. zmap-4.3.4/src/ziterate.c000066400000000000000000000146071501046211500152560ustar00rootroot00000000000000/* * ZMap Copyright 2023 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ /* * ZIterate is a simple utility that will iteratate over the IPv4 * space in a pseudo-random fashion, utilizing the sharding capabilities * of * ZMap. */ #define _GNU_SOURCE #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/blocklist.h" #include "../lib/logger.h" #include "../lib/random.h" #include "../lib/util.h" #include "../lib/xalloc.h" #include "iterator.h" #include "ports.h" #include "state.h" #include "validate.h" #include "zitopt.h" struct zit_conf { char *blocklist_filename; char *allowlist_filename; char **destination_cidrs; int destination_cidrs_len; char *log_filename; int check_duplicates; int ignore_errors; int verbosity; int disable_syslog; // sharding options uint16_t shard_num; uint16_t total_shards; uint64_t seed; aesrand_t *aes; uint32_t max_hosts; }; #define SET_BOOL(DST, ARG) \ { \ if (args.ARG##_given) { \ (DST) = 1; \ }; \ } int main(int argc, char **argv) { struct zit_conf conf; memset(&conf, 0, sizeof(struct zit_conf)); conf.verbosity = 3; conf.ignore_errors = 0; struct gengetopt_args_info args; struct cmdline_parser_params *params; params = cmdline_parser_params_create(); assert(params); params->initialize = 1; params->override = 0; params->check_required = 0; if (cmdline_parser_ext(argc, argv, &args, params) != 0) { exit(EXIT_SUCCESS); } // Handle help text and version if (args.help_given) { cmdline_parser_print_help(); exit(EXIT_SUCCESS); } if (args.version_given) { cmdline_parser_print_version(); exit(EXIT_SUCCESS); } // Set the log file and metadata file if (args.log_file_given) { conf.log_filename = strdup(args.log_file_arg); } if (args.verbosity_given) { conf.verbosity = args.verbosity_arg; } // Read the boolean flags SET_BOOL(conf.ignore_errors, ignore_blocklist_errors); SET_BOOL(conf.disable_syslog, disable_syslog); // initialize logging FILE *logfile = stderr; if (conf.log_filename) { logfile = fopen(conf.log_filename, "w"); if (!logfile) { fprintf( stderr, "FATAL: unable to open specified logfile (%s)\n", conf.log_filename); exit(1); } } if (log_init(logfile, conf.verbosity, !conf.disable_syslog, "ziterate")) { fprintf(stderr, "FATAL: unable able to initialize logging\n"); exit(1); } // Blocklist and allowlist if (args.blocklist_file_given) { conf.blocklist_filename = strdup(args.blocklist_file_arg); } if (args.allowlist_file_given) { conf.allowlist_filename = strdup(args.allowlist_file_arg); } conf.destination_cidrs = args.inputs; conf.destination_cidrs_len = args.inputs_num; // max targets if (args.max_targets_given) { conf.max_hosts = parse_max_targets(args.max_targets_arg, zconf.ports->port_count); } // sanity check blocklist file if (conf.blocklist_filename) { log_debug("ziterate", "blocklist file at %s to be used", conf.blocklist_filename); } else { log_debug("ziterate", "no blocklist file specified"); } if (conf.blocklist_filename && access(conf.blocklist_filename, R_OK) == -1) { log_fatal("ziterate", "unable to read specified blocklist file (%s)", conf.blocklist_filename); } // sanity check allowlist file if (conf.allowlist_filename) { log_debug("ziterate", "allowlist file at %s to be used", conf.allowlist_filename); } else { log_debug("ziterate", "no allowlist file specified"); } if (conf.allowlist_filename && access(conf.allowlist_filename, R_OK) == -1) { log_fatal("ziterate", "unable to read specified allowlist file (%s)", conf.allowlist_filename); } // parse blocklist and allowlist if (blocklist_init(conf.allowlist_filename, conf.blocklist_filename, conf.destination_cidrs, conf.destination_cidrs_len, NULL, 0, conf.ignore_errors)) { log_fatal("ziterate", "unable to initialize blocklist / allowlist"); } // Set up sharding conf.shard_num = 0; conf.total_shards = 1; if ((args.shard_given || args.shards_given) && !args.seed_given) { log_fatal("ziterate", "Need to specify seed if sharding a scan"); } if (args.shard_given ^ args.shards_given) { log_fatal( "ziterate", "Need to specify both shard number and total number of shards"); } if (args.shard_given) { enforce_range("shard", args.shard_arg, 0, 65534); conf.shard_num = args.shard_arg; } if (args.shards_given) { enforce_range("shards", args.shards_arg, 1, 65535); conf.total_shards = args.shards_arg; } if (conf.shard_num >= conf.total_shards) { log_fatal("ziterate", "With %hhu total shards, shard number (%hhu)" " must be in range [0, %hhu)", conf.total_shards, conf.shard_num, conf.total_shards); } log_debug( "ziterate", "Initializing sharding (%d shards, shard number %d, seed %llu)", conf.total_shards, conf.shard_num, conf.seed); // Check for a random seed if (args.seed_given) { conf.seed = args.seed_arg; } else { if (!random_bytes(&conf.seed, sizeof(uint64_t))) { log_fatal("ziterate", "unable to generate random bytes " "needed for seed"); } } zconf.aes = aesrand_init_from_seed(conf.seed); zconf.ports = xmalloc(sizeof(struct port_conf)); if (args.target_ports_given) { parse_ports(args.target_ports_arg, zconf.ports); } else { zconf.ports->port_count = 1; } uint64_t num_addrs = blocklist_count_allowed(); if (zconf.list_of_ips_filename) { log_debug("send", "forcing max group size for compatibility with -I"); num_addrs = 0xFFFFFFFF; } iterator_t *it = iterator_init(1, conf.shard_num, conf.total_shards, num_addrs, zconf.ports->port_count); shard_t *shard = get_shard(it, 0); target_t current = shard_get_cur_target(shard); for (uint32_t count = 0; current.ip; ++count) { if (conf.max_hosts && count >= conf.max_hosts) { break; } struct in_addr next_ip; next_ip.s_addr = current.ip; if (current.port) { printf("%s,%u\n", inet_ntoa(next_ip), current.port); } else { printf("%s\n", inet_ntoa(next_ip)); } current = shard_get_next_target(shard); } return EXIT_SUCCESS; } zmap-4.3.4/src/zitopt.ggo.in000066400000000000000000000041621501046211500157120ustar00rootroot00000000000000# ZIterate Copyright 2014 Regents of the University of Michigan # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at http://www.apache.org/licenses/LICENSE-2.0 # ziterate option description to be processed by gengetopt package "ziterate" version "@ZMAP_VERSION@" purpose "A tool for iterating over the IPv4 space" section "Basic arguments" option "target-ports" p "comma-delimited list of ports to scan (for TCP and UDP scans)" typestr="ports" optional string option "blocklist-file" b "File of subnets to exclude, in CIDR notation, one-per line." optional string option "allowlist-file" w "File of subnets to include, in CIDR notation, one-per line." optional string option "log-file" l "File to log to" optional string option "verbosity" v "Set log level verbosity (0-5, default 3)" default="3" optional int option "ignore-blocklist-errors" - "Ignore invalid entries in the blocklist/allowlist (default false)" optional option "seed" e "Seed used to select address permutation" typestr="n" optional longlong option "max-targets" n "Cap number of IPs to generate (as a number or a percentage of the address space)" typestr="n" optional string option "disable-syslog" - "Disables logging messages to syslog" optional section "Sharding" option "shards" - "total number of shards" typestr="N" optional int default="1" option "shard" - "shard this scan is targeting (0 indexed)" typestr="n" optional int default="0" section "Additional options" option "help" h "Print help and exit" optional option "version" V "Print version and exit" optional text "\nExamples:\n\ ziterate (iterate over all public IPv4 addresses)\n\ ziterate -b exclusions 10.0.0.0/8 (iterate all IPs in 10./8 except those in blocklist)\n\ ziterate -p 80,100-102 (scan full IPv4 on ports 80, 100, 101, 102)\n" zmap-4.3.4/src/zitopt_compat.c000066400000000000000000000010631501046211500163130ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #if __GNUC__ < 4 #error "gcc version >= 4 is required" #elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #elif __GNUC_MINOR__ >= 4 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif #include "zitopt.c" zmap-4.3.4/src/zmap.1000066400000000000000000000312461501046211500143120ustar00rootroot00000000000000.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "ZMAP" "1" "December 2024" "ZMap" "zmap" . .SH "NAME" \fBzmap\fR \- The Fast Internet Scanner . .SH "SYNOPSIS" zmap [ \-p ] [ \-o ] [ OPTIONS\.\.\. ] [ ip/hostname/range ] . .SH "DESCRIPTION" \fIZMap\fR is a network tool for scanning the entire IPv4 address space (or large samples)\. ZMap is capable of scanning the entire Internet in around 45 minutes on a gigabit network connection, reaching ~98% theoretical line speed\. . .SH "OPTIONS" . .SS "BASIC OPTIONS" . .TP \fBip\fR/\fBhostname\fR/\fBrange\fR IP addresses or DNS hostnames to scan\. Accepts IP ranges in CIDR block notation\. Defaults to 0\.0\.0/8 . .TP \fB\-p\fR, \fB\-\-target\-ports=port(s)\fR List of TCP/UDP ports and/or port ranges to scan (e\.g\., 80,443,100\-105)\. Use \'*\' to scan all ports, including port 0\. . .TP \fB\-o\fR, \fB\-\-output\-file=name\fR When using an output module that uses a file, write results to this file\. Use \- for stdout\. . .TP \fB\-b\fR, \fB\-\-blocklist\-file=path\fR File of subnets to exclude, in CIDR notation, one\-per line\. It is recommended you use this to exclude RFC 1918 addresses, multicast, IANA reserved space, and other IANA special\-purpose addresses\. An example blocklist file \fBblocklist\.conf\fR for this purpose\. . .TP \fB\-w\fR, \fB\-\-allowlist\-file=path\fR File of subnets to scan, in CIDR notation, one\-per line\. Specifying a allowlist file is equivalent to specifying to ranges directly on the command line interface, but allows specifying a large number of subnets\. Note: if you are specifying a large number of individual IP addresses (more than 10 million), you should instead use \fB\-\-list\-of\-ips\-file\fR\. . .TP \fB\-I\fR, \fB\-\-list\-of\-ips\-file=path\fR File of individual IP addresses to scan, one\-per line\. This feature allows you to scan a large number of unrelated addresses\. If you have a small number of IPs, it is faster to specify these on the command line or by using \fB\-\-allowlist\-file\fR\. This should only be used when scanning more than 10 million addresses\. When used in with \-\-allowlist\-path, only hosts in the intersection of both sets will be scanned\. Hosts specified here, but included in the blocklist will be excluded\. . .SS "SCAN OPTIONS" . .TP \fB\-r\fR, \fB\-\-rate=pps\fR Set the send rate in packets/sec\. Note: when combined with \-\-probes, this is total packets per second, not IPs per second\. Setting the rate to 0 will scan at full line rate\. Default: 10000 pps\. . .TP \fB\-B\fR, \fB\-\-bandwidth=bps\fR Set the send rate in bits/second (supports suffixes G, M, and K (e\.g\. \-B 10M for 10 mbps)\. This overrides the \-\-rate flag\. . .TP \fB\-n\fR, \fB\-\-max\-targets=n\fR Cap the number of targets to probe\. This can either be a number (e\.g\. \-n 1000) or a percentage (e\.g\. \-n 0\.1%) of the scannable address space (after excluding blocklist)\. A target is an IP/port pair, if scanning multiple ports, and an IP otherwise\. In the case of percents and multiple ports, the percent is of the total number of IP/port pair combinations\. . .TP \fB\-N\fR, \fB\-\-max\-results=n\fR Exit after receiving this many results . .TP \fB\-t\fR, \fB\-\-max\-runtime=secs\fR Cap the length of time for sending packets . .TP \fB\-c\fR, \fB\-\-cooldown\-time=secs\fR How long to continue receiving after sending has completed (default=8) . .TP \fB\-e\fR, \fB\-\-seed=n\fR Seed used to select address permutation\. Use this if you want to scan addresses in the same order for multiple ZMap runs\. . .TP \fB\-P\fR, \fB\-\-probes=n\fR Number of probes to send to each IP/Port pair (default=1)\. Since ZMap composes Ethernet frames directly, probes can be lost en\-route to destination\. Increasing the \-\-probes increases the chance that an online host will receive a probe in an unreliable network\. This is contrasted with \fB\-\-retries\fR which just gives the number of attempts to send a single probe on the source NIC\. . .TP \fB\-\-retries=n\fR Number of times to try resending a packet if the sendto call fails (default=10) . .TP \fB\-\-batch=n\fR Number of packets to batch before calling the appropriate syscall to send\. Used to take advantage of Linux\'s \fBsendmmsg\fR syscall to send the entire batch at once\. Only available on Linux, other OS\'s will send each packet individually\. (default=64) . .SS "SCAN SHARDING" . .TP \fB\-\-shards=N\fR Split the scan up into N shards/partitions among different instances of zmap (default=1)\. When sharding, \fB\-\-seed\fR is required\. . .TP \fB\-\-shard=n\fR Set which shard to scan (default=0)\. Shards are 0\-indexed in the range [0, N), where N is the total number of shards\. When sharding \fB\-\-seed\fR is required\. . .SS "NETWORK OPTIONS" . .TP \fB\-s\fR, \fB\-\-source\-port=port|range\fR Source port(s) to send packets from . .TP \fB\-\-validate\-source\-port=enable|disable\fR Used as an override to enable/disable source port validation\. Source port validation will check that a received probe response\'s src port matches the dst port of the probe sent to that IP/port pair\. This ensures that multiple ZMap scans to the same hosts but to different ports will not interfere with each other\. This overrides each modules default behavior on whether or not to validate source ports with probe responses\. . .TP \fB\-S\fR, \fB\-\-source\-ip=ip|range\fR Source address(es) to send packets from\. Either single IP or range (e\.g\. 10\.0\.0\.1\-10\.0\.0\.9) . .TP \fB\-G\fR, \fB\-\-gateway\-mac=addr\fR Gateway MAC address to send packets to (in case auto\-detection fails) . .TP \fB\-\-source\-mac=addr\fR Source MAC address to send packets from (in case auto\-detection fails) . .TP \fB\-i\fR, \fB\-\-interface=name\fR Network interface to use . .TP \fB\-X\fR, \fB\-\-iplayer\fR Send IP layer packets instead of ethernet packets (for non\-Ethernet interface) . .TP \fB\-\-netmap\-wait\-ping=ip\fR (Netmap only) Wait for ip to respond to ICMP Echo request before commencing scan\. Useful if connected to a switch with STP enabled, where the PHY reset that is needed for entering and leaving Netmap mode will cause the switch to mute the port until the spanning tree protocol has determined that the link should be set into forward state\. . .SS "PROBE OPTIONS" ZMap allows users to specify and write their own probe modules\. Probe modules are responsible for generating probe packets to send, and processing responses from hosts\. . .TP \fB\-\-list\-probe\-modules\fR List available probe modules (e\.g\. tcp_synscan) . .TP \fB\-M\fR, \fB\-\-probe\-module=name\fR Select probe module (default=tcp_synscan) . .TP \fB\-\-probe\-args=args\fR Arguments to pass to probe module . .TP \fB\-\-probe\-ttl=hops\fR Set TTL value for probe IP packets . .TP \fB\-\-list\-output\-fields\fR List the fields the selected probe module can send to the output module . .SS "OUTPUT OPTIONS" ZMap allows users to specify and write their own output modules for use with ZMap\. Output modules are responsible for processing the fieldsets returned by the probe module, and outputting them to the user\. Users can specify output fields, and write filters over the output fields\. . .TP \fB\-\-list\-output\-modules\fR List available output modules (e\.g\. csv) . .TP \fB\-O\fR, \fB\-\-output\-module=name\fR Select output module (default=csv) . .TP \fB\-\-output\-args=args\fR Arguments to pass to output module . .TP \fB\-f\fR, \fB\-\-output\-fields=fields\fR Comma\-separated list of fields to output . .TP \fB\-\-output\-filter\fR Specify an output filter over the fields defined by the probe module\. See the output filter section for more details\. . .TP \fB\-\-no\-header\-row\fR Excludes any header rows (e\.g\., CSV header fields) from ZMap output\. This is useful if you\'re piping results into another application that expects only data\. . .SS "RESPONSE DEDUPLICATION" Hosts will oftentimes send multiple responses to a probe (either because the scanner doesn\'t send back a RST packet or because the host has a misimplemented TCP stack\. To address this, ZMap will attempt to deduplicate responsive (ip,port) targets\. . .TP \fB\-\-dedup\-method\fR Specifies the method ZMap will use to deduplicate responses\. Options are: full, window, and none\. Full deduplication uses a 32\-bit bitmap and guarantees that no duplicates will be emitted\. However, full\-deduplication requires around 500MB of memory for a single port\. We do not support full deduplication for multiple ports\. Window uses a sliding window of the last (user\-defined) number of responses as set by \-\-dedup\-window\-size\. None will prevent any deduplication\. . .TP \fB\-\-dedup\-window\-size=targets\fR Specifies the size of the sliding window as the last n target responses to be used for deduplication\. Only applicable if using window deduplication\. . .SS "LOGGING AND METADATA OPTIONS" . .TP \fB\-q\fR, \fB\-\-quiet\fR Do not print status updates once per second . .TP \fB\-v\fR, \fB\-\-verbosity=n\fR Level of log detail (0\-5, default=3) . .TP \fB\-l\fR, \fB\-\-log\-file=filename\fR Output file for log messages\. By default, stderr\. . .TP \fB\-m\fR, \fB\-\-metadata\-file=filename\fR Output file for scan metadata (JSON) . .TP \fB\-L\fR, \fB\-\-log\-directory\fR Write log entries to a timestamped file in this directory . .TP \fB\-u\fR, \fB\-\-status\-updates\-file\fR Write scan progress updates to CSV file" . .TP \fB\-\-disable\-syslog\fR Disables logging messages to syslog . .TP \fB\-\-notes\fR Inject user\-specified notes into scan metadata . .TP \fB\-\-user\-metadata\fR Inject user\-specified JSON metadata into scan metadata . .SS "ADDITIONAL OPTIONS" . .TP \fB\-T\fR, \fB\-\-sender\-threads=n\fR Threads used to send packets\. ZMap will attempt to detect the optimal number of send threads based on the number of processor cores\. Defaults to min(4, number of processor cores on host \- 1)\. . .TP \fB\-C\fR, \fB\-\-config=filename\fR Read a configuration file, which can specify any other options\. . .TP \fB\-d\fR, \fB\-\-dryrun\fR Print out each packet to stdout instead of sending it (useful for debugging) . .TP \fB\-\-fast\-dryrun\fR Don\'t actually send packets, print out a binary representation probe dst IP and dst Port\. Used for faster integration tests, not for general use\. . .TP \fB\-\-max\-sendto\-failures\fR Maximum NIC sendto failures before scan is aborted . .TP \fB\-\-min\-hitrate\fR Minimum hitrate that scan can hit before scan is aborted . .TP \fB\-\-cores\fR Comma\-separated list of cores to pin to . .TP \fB\-\-ignore\-blocklist\-errors\fR Ignore invalid, malformed, or unresolvable entries in allowlist/blocklist file\. Replaces the pre\-v3\.x \fB\-\-ignore\-invalid\-hosts\fR option\. . .TP \fB\-h\fR, \fB\-\-help\fR Print help and exit . .TP \fB\-V\fR, \fB\-\-version\fR Print version and exit . .SS "OUTPUT FILTERS" Results generated by a probe module can be filtered before being passed to the output module\. Filters are defined over the output fields of a probe module\. Filters are written in a simple filtering language, similar to SQL, and are passed to ZMap using the \fB\-\-output\-filter\fR option\. Output filters are commonly used to filter out duplicate results, or to only pass only successful responses to the output module\. . .P Filter expressions are of the form \fB \fR\. The type of \fB\fR must be either a string or unsigned integer literal, and match the type of \fB\fR\. The valid operations for integer comparisons are = !=, \fI,\fR, \fI=,\fR=\. The operations for string comparisons are =, !=\. The \fB\-\-list\-output\-fields\fR flag will print what fields and types are available for the selected probe module, and then exit\. . .P Compound filter expressions may be constructed by combining filter expressions using parenthesis to specify order of operations, the && (logical AND) and || (logical OR) operators\. . .P For example, a filter for only successful, non\-duplicate responses would be written as: \fB\-\-output\-filter="success = 1 && repeat = 0"\fR . .SS "UDP PROBE MODULE OPTIONS" These arguments are all passed using the \fB\-\-probe\-args=args\fR option\. Only one argument may be passed at a time\. . .TP \fBfile:/path/to/file\fR Path to payload file to send to each host over UDP\. . .TP \fBtemplate:/path/to/template\fR Path to template file\. For each destination host, the template file is populated, set as the UDP payload, and sent\. . .TP \fBtext:\fR ASCII text to send to each destination host . .TP \fBhex:\fR Hex\-encoded binary to send to each destination host . .TP \fBtemplate\-fields\fR Print information about the allowed template fields and exit\. . .SS "MID\-SCAN CHANGES" You can change the rate at which ZMap is scanning mid\-scan by sending SIGUSR1 (increase) and SIGUSR2 (decrease) signals to ZMap\. These will result in the scan rate increasing or decreasing by 5%\. zmap-4.3.4/src/zmap.1.html000066400000000000000000000432701501046211500152550ustar00rootroot00000000000000 zmap(1) - The Fast Internet Scanner
  1. zmap(1)
  2. zmap
  3. zmap(1)

NAME

zmap - The Fast Internet Scanner

SYNOPSIS

zmap [ -p <port(s)> ] [ -o <outfile> ] [ OPTIONS... ] [ ip/hostname/range ]

DESCRIPTION

ZMap is a network tool for scanning the entire IPv4 address space (or large samples). ZMap is capable of scanning the entire Internet in around 45 minutes on a gigabit network connection, reaching ~98% theoretical line speed.

OPTIONS

BASIC OPTIONS

ip/hostname/range

IP addresses or DNS hostnames to scan. Accepts IP ranges in CIDR block notation. Defaults to 0.0.0/8

-p, --target-ports=port(s)

List of TCP/UDP ports and/or port ranges to scan (e.g., 80,443,100-105). Use '*' to scan all ports, including port 0.

-o, --output-file=name

When using an output module that uses a file, write results to this file. Use - for stdout.

-b, --blocklist-file=path

File of subnets to exclude, in CIDR notation, one-per line. It is recommended you use this to exclude RFC 1918 addresses, multicast, IANA reserved space, and other IANA special-purpose addresses. An example blocklist file blocklist.conf for this purpose.

-w, --allowlist-file=path

File of subnets to scan, in CIDR notation, one-per line. Specifying a allowlist file is equivalent to specifying to ranges directly on the command line interface, but allows specifying a large number of subnets. Note: if you are specifying a large number of individual IP addresses (more than 10 million), you should instead use --list-of-ips-file.

-I, --list-of-ips-file=path

File of individual IP addresses to scan, one-per line. This feature allows you to scan a large number of unrelated addresses. If you have a small number of IPs, it is faster to specify these on the command line or by using --allowlist-file. This should only be used when scanning more than 10 million addresses. When used in with --allowlist-path, only hosts in the intersection of both sets will be scanned. Hosts specified here, but included in the blocklist will be excluded.

SCAN OPTIONS

-r, --rate=pps

Set the send rate in packets/sec. Note: when combined with --probes, this is total packets per second, not IPs per second. Setting the rate to 0 will scan at full line rate. Default: 10000 pps.

-B, --bandwidth=bps

Set the send rate in bits/second (supports suffixes G, M, and K (e.g. -B 10M for 10 mbps). This overrides the --rate flag.

-n, --max-targets=n

Cap the number of targets to probe. This can either be a number (e.g. -n 1000) or a percentage (e.g. -n 0.1%) of the scannable address space (after excluding blocklist). A target is an IP/port pair, if scanning multiple ports, and an IP otherwise. In the case of percents and multiple ports, the percent is of the total number of IP/port pair combinations.

-N, --max-results=n

Exit after receiving this many results

-t, --max-runtime=secs

Cap the length of time for sending packets

-c, --cooldown-time=secs

How long to continue receiving after sending has completed (default=8)

-e, --seed=n

Seed used to select address permutation. Use this if you want to scan addresses in the same order for multiple ZMap runs.

-P, --probes=n

Number of probes to send to each IP/Port pair (default=1). Since ZMap composes Ethernet frames directly, probes can be lost en-route to destination. Increasing the --probes increases the chance that an online host will receive a probe in an unreliable network. This is contrasted with --retries which just gives the number of attempts to send a single probe on the source NIC.

--retries=n

Number of times to try resending a packet if the sendto call fails (default=10)

--batch=n

Number of packets to batch before calling the appropriate syscall to send. Used to take advantage of Linux's sendmmsg syscall to send the entire batch at once. Only available on Linux, other OS's will send each packet individually. (default=64)

SCAN SHARDING

--shards=N

Split the scan up into N shards/partitions among different instances of zmap (default=1). When sharding, --seed is required.

--shard=n

Set which shard to scan (default=0). Shards are 0-indexed in the range [0, N), where N is the total number of shards. When sharding --seed is required.

NETWORK OPTIONS

-s, --source-port=port|range

Source port(s) to send packets from

--validate-source-port=enable|disable

Used as an override to enable/disable source port validation. Source port validation will check that a received probe response's src port matches the dst port of the probe sent to that IP/port pair. This ensures that multiple ZMap scans to the same hosts but to different ports will not interfere with each other. This overrides each modules default behavior on whether or not to validate source ports with probe responses.

-S, --source-ip=ip|range

Source address(es) to send packets from. Either single IP or range (e.g. 10.0.0.1-10.0.0.9)

-G, --gateway-mac=addr

Gateway MAC address to send packets to (in case auto-detection fails)

--source-mac=addr

Source MAC address to send packets from (in case auto-detection fails)

-i, --interface=name

Network interface to use

-X, --iplayer

Send IP layer packets instead of ethernet packets (for non-Ethernet interface)

--netmap-wait-ping=ip

(Netmap only) Wait for ip to respond to ICMP Echo request before commencing scan. Useful if connected to a switch with STP enabled, where the PHY reset that is needed for entering and leaving Netmap mode will cause the switch to mute the port until the spanning tree protocol has determined that the link should be set into forward state.

PROBE OPTIONS

ZMap allows users to specify and write their own probe modules. Probe modules are responsible for generating probe packets to send, and processing responses from hosts.

--list-probe-modules

List available probe modules (e.g. tcp_synscan)

-M, --probe-module=name

Select probe module (default=tcp_synscan)

--probe-args=args

Arguments to pass to probe module

--probe-ttl=hops

Set TTL value for probe IP packets

--list-output-fields

List the fields the selected probe module can send to the output module

OUTPUT OPTIONS

ZMap allows users to specify and write their own output modules for use with ZMap. Output modules are responsible for processing the fieldsets returned by the probe module, and outputting them to the user. Users can specify output fields, and write filters over the output fields.

--list-output-modules

List available output modules (e.g. csv)

-O, --output-module=name

Select output module (default=csv)

--output-args=args

Arguments to pass to output module

-f, --output-fields=fields

Comma-separated list of fields to output

--output-filter

Specify an output filter over the fields defined by the probe module. See the output filter section for more details.

--no-header-row

Excludes any header rows (e.g., CSV header fields) from ZMap output. This is useful if you're piping results into another application that expects only data.

RESPONSE DEDUPLICATION

Hosts will oftentimes send multiple responses to a probe (either because the scanner doesn't send back a RST packet or because the host has a misimplemented TCP stack. To address this, ZMap will attempt to deduplicate responsive (ip,port) targets.

--dedup-method

Specifies the method ZMap will use to deduplicate responses. Options are: full, window, and none. Full deduplication uses a 32-bit bitmap and guarantees that no duplicates will be emitted. However, full-deduplication requires around 500MB of memory for a single port. We do not support full deduplication for multiple ports. Window uses a sliding window of the last (user-defined) number of responses as set by --dedup-window-size. None will prevent any deduplication.

--dedup-window-size=targets

Specifies the size of the sliding window as the last n target responses to be used for deduplication. Only applicable if using window deduplication.

LOGGING AND METADATA OPTIONS

-q, --quiet

Do not print status updates once per second

-v, --verbosity=n

Level of log detail (0-5, default=3)

-l, --log-file=filename

Output file for log messages. By default, stderr.

-m, --metadata-file=filename

Output file for scan metadata (JSON)

-L, --log-directory

Write log entries to a timestamped file in this directory

-u, --status-updates-file

Write scan progress updates to CSV file"

--disable-syslog

Disables logging messages to syslog

--notes

Inject user-specified notes into scan metadata

--user-metadata

Inject user-specified JSON metadata into scan metadata

ADDITIONAL OPTIONS

-T, --sender-threads=n

Threads used to send packets. ZMap will attempt to detect the optimal number of send threads based on the number of processor cores. Defaults to min(4, number of processor cores on host - 1).

-C, --config=filename

Read a configuration file, which can specify any other options.

-d, --dryrun

Print out each packet to stdout instead of sending it (useful for debugging)

--fast-dryrun

Don't actually send packets, print out a binary representation probe dst IP and dst Port. Used for faster integration tests, not for general use.

--max-sendto-failures

Maximum NIC sendto failures before scan is aborted

--min-hitrate

Minimum hitrate that scan can hit before scan is aborted

--cores

Comma-separated list of cores to pin to

--ignore-blocklist-errors

Ignore invalid, malformed, or unresolvable entries in allowlist/blocklist file. Replaces the pre-v3.x --ignore-invalid-hosts option.

-h, --help

Print help and exit

-V, --version

Print version and exit

OUTPUT FILTERS

Results generated by a probe module can be filtered before being passed to the output module. Filters are defined over the output fields of a probe module. Filters are written in a simple filtering language, similar to SQL, and are passed to ZMap using the --output-filter option. Output filters are commonly used to filter out duplicate results, or to only pass only successful responses to the output module.

Filter expressions are of the form <fieldname> <operation> <value>. The type of <value> must be either a string or unsigned integer literal, and match the type of <fieldname>. The valid operations for integer comparisons are = !=, , , =, =. The operations for string comparisons are =, !=. The --list-output-fields flag will print what fields and types are available for the selected probe module, and then exit.

Compound filter expressions may be constructed by combining filter expressions using parenthesis to specify order of operations, the && (logical AND) and || (logical OR) operators.

For example, a filter for only successful, non-duplicate responses would be written as: --output-filter="success = 1 && repeat = 0"

UDP PROBE MODULE OPTIONS

These arguments are all passed using the --probe-args=args option. Only one argument may be passed at a time.

file:/path/to/file

Path to payload file to send to each host over UDP.

template:/path/to/template

Path to template file. For each destination host, the template file is populated, set as the UDP payload, and sent.

text:<text>

ASCII text to send to each destination host

hex:<hex>

Hex-encoded binary to send to each destination host

template-fields

Print information about the allowed template fields and exit.

MID-SCAN CHANGES

You can change the rate at which ZMap is scanning mid-scan by sending SIGUSR1 (increase) and SIGUSR2 (decrease) signals to ZMap. These will result in the scan rate increasing or decreasing by 5%.

  1. ZMap
  2. December 2024
  3. zmap(1)
zmap-4.3.4/src/zmap.1.ronn000066400000000000000000000305371501046211500152670ustar00rootroot00000000000000zmap(1) - The Fast Internet Scanner =================================== ## SYNOPSIS zmap [ -p <port(s)> ] [ -o <outfile> ] [ OPTIONS... ] [ ip/hostname/range ] ## DESCRIPTION *ZMap* is a network tool for scanning the entire IPv4 address space (or large samples). ZMap is capable of scanning the entire Internet in around 45 minutes on a gigabit network connection, reaching ~98% theoretical line speed. ## OPTIONS ### BASIC OPTIONS ### * `ip`/`hostname`/`range`: IP addresses or DNS hostnames to scan. Accepts IP ranges in CIDR block notation. Defaults to 0.0.0/8 * `-p`, `--target-ports=port(s)`: List of TCP/UDP ports and/or port ranges to scan (e.g., 80,443,100-105). Use '*' to scan all ports, including port 0. * `-o`, `--output-file=name`: When using an output module that uses a file, write results to this file. Use - for stdout. * `-b`, `--blocklist-file=path`: File of subnets to exclude, in CIDR notation, one-per line. It is recommended you use this to exclude RFC 1918 addresses, multicast, IANA reserved space, and other IANA special-purpose addresses. An example blocklist file **blocklist.conf** for this purpose. * `-w`, `--allowlist-file=path`: File of subnets to scan, in CIDR notation, one-per line. Specifying a allowlist file is equivalent to specifying to ranges directly on the command line interface, but allows specifying a large number of subnets. Note: if you are specifying a large number of individual IP addresses (more than 10 million), you should instead use `--list-of-ips-file`. * `-I`, `--list-of-ips-file=path`: File of individual IP addresses to scan, one-per line. This feature allows you to scan a large number of unrelated addresses. If you have a small number of IPs, it is faster to specify these on the command line or by using `--allowlist-file`. This should only be used when scanning more than 10 million addresses. When used in with --allowlist-path, only hosts in the intersection of both sets will be scanned. Hosts specified here, but included in the blocklist will be excluded. ### SCAN OPTIONS ### * `-r`, `--rate=pps`: Set the send rate in packets/sec. Note: when combined with --probes, this is total packets per second, not IPs per second. Setting the rate to 0 will scan at full line rate. Default: 10000 pps. * `-B`, `--bandwidth=bps`: Set the send rate in bits/second (supports suffixes G, M, and K (e.g. -B 10M for 10 mbps). This overrides the --rate flag. * `-n`, `--max-targets=n`: Cap the number of targets to probe. This can either be a number (e.g. -n 1000) or a percentage (e.g. -n 0.1%) of the scannable address space (after excluding blocklist). A target is an IP/port pair, if scanning multiple ports, and an IP otherwise. In the case of percents and multiple ports, the percent is of the total number of IP/port pair combinations. * `-N`, `--max-results=n`: Exit after receiving this many results * `-t`, `--max-runtime=secs`: Cap the length of time for sending packets * `-c`, `--cooldown-time=secs`: How long to continue receiving after sending has completed (default=8) * `-e`, `--seed=n`: Seed used to select address permutation. Use this if you want to scan addresses in the same order for multiple ZMap runs. * `-P`, `--probes=n`: Number of probes to send to each IP/Port pair (default=1). Since ZMap composes Ethernet frames directly, probes can be lost en-route to destination. Increasing the --probes increases the chance that an online host will receive a probe in an unreliable network. This is contrasted with `--retries` which just gives the number of attempts to send a single probe on the source NIC. * `--retries=n`: Number of times to try resending a packet if the sendto call fails (default=10) * `--batch=n`: Number of packets to batch before calling the appropriate syscall to send. Used to take advantage of Linux's `sendmmsg` syscall to send the entire batch at once. Only available on Linux, other OS's will send each packet individually. (default=64) ### SCAN SHARDING ### * `--shards=N`: Split the scan up into N shards/partitions among different instances of zmap (default=1). When sharding, **--seed** is required. * `--shard=n`: Set which shard to scan (default=0). Shards are 0-indexed in the range [0, N), where N is the total number of shards. When sharding **--seed** is required. ### NETWORK OPTIONS ### * `-s`, `--source-port=port|range`: Source port(s) to send packets from * `--validate-source-port=enable|disable`: Used as an override to enable/disable source port validation. Source port validation will check that a received probe response's src port matches the dst port of the probe sent to that IP/port pair. This ensures that multiple ZMap scans to the same hosts but to different ports will not interfere with each other. This overrides each modules default behavior on whether or not to validate source ports with probe responses. * `-S`, `--source-ip=ip|range`: Source address(es) to send packets from. Either single IP or range (e.g. 10.0.0.1-10.0.0.9) * `-G`, `--gateway-mac=addr`: Gateway MAC address to send packets to (in case auto-detection fails) * `--source-mac=addr`: Source MAC address to send packets from (in case auto-detection fails) * `-i`, `--interface=name`: Network interface to use * `-X`, `--iplayer`: Send IP layer packets instead of ethernet packets (for non-Ethernet interface) * `--netmap-wait-ping=ip`: (Netmap only) Wait for ip to respond to ICMP Echo request before commencing scan. Useful if connected to a switch with STP enabled, where the PHY reset that is needed for entering and leaving Netmap mode will cause the switch to mute the port until the spanning tree protocol has determined that the link should be set into forward state. ### PROBE OPTIONS ### ZMap allows users to specify and write their own probe modules. Probe modules are responsible for generating probe packets to send, and processing responses from hosts. * `--list-probe-modules`: List available probe modules (e.g. tcp_synscan) * `-M`, `--probe-module=name`: Select probe module (default=tcp_synscan) * `--probe-args=args`: Arguments to pass to probe module * `--probe-ttl=hops`: Set TTL value for probe IP packets * `--list-output-fields`: List the fields the selected probe module can send to the output module ### OUTPUT OPTIONS ### ZMap allows users to specify and write their own output modules for use with ZMap. Output modules are responsible for processing the fieldsets returned by the probe module, and outputting them to the user. Users can specify output fields, and write filters over the output fields. * `--list-output-modules`: List available output modules (e.g. csv) * `-O`, `--output-module=name`: Select output module (default=csv) * `--output-args=args`: Arguments to pass to output module * `-f`, `--output-fields=fields`: Comma-separated list of fields to output * `--output-filter`: Specify an output filter over the fields defined by the probe module. See the output filter section for more details. * `--no-header-row`: Excludes any header rows (e.g., CSV header fields) from ZMap output. This is useful if you're piping results into another application that expects only data. ### RESPONSE DEDUPLICATION ### Hosts will oftentimes send multiple responses to a probe (either because the scanner doesn't send back a RST packet or because the host has a misimplemented TCP stack. To address this, ZMap will attempt to deduplicate responsive (ip,port) targets. * `--dedup-method`: Specifies the method ZMap will use to deduplicate responses. Options are: full, window, and none. Full deduplication uses a 32-bit bitmap and guarantees that no duplicates will be emitted. However, full-deduplication requires around 500MB of memory for a single port. We do not support full deduplication for multiple ports. Window uses a sliding window of the last (user-defined) number of responses as set by --dedup-window-size. None will prevent any deduplication. * `--dedup-window-size=targets`: Specifies the size of the sliding window as the last n target responses to be used for deduplication. Only applicable if using window deduplication. ### LOGGING AND METADATA OPTIONS ### * `-q`, `--quiet`: Do not print status updates once per second * `-v`, `--verbosity=n`: Level of log detail (0-5, default=3) * `-l`, `--log-file=filename`: Output file for log messages. By default, stderr. * `-m`, `--metadata-file=filename`: Output file for scan metadata (JSON) * `-L`, `--log-directory`: Write log entries to a timestamped file in this directory * `-u`, `--status-updates-file`: Write scan progress updates to CSV file" * `--disable-syslog`: Disables logging messages to syslog * `--notes`: Inject user-specified notes into scan metadata * `--user-metadata`: Inject user-specified JSON metadata into scan metadata ### ADDITIONAL OPTIONS ### * `-T`, `--sender-threads=n`: Threads used to send packets. ZMap will attempt to detect the optimal number of send threads based on the number of processor cores. Defaults to min(4, number of processor cores on host - 1). * `-C`, `--config=filename`: Read a configuration file, which can specify any other options. * `-d`, `--dryrun`: Print out each packet to stdout instead of sending it (useful for debugging) * `--fast-dryrun`: Don't actually send packets, print out a binary representation probe dst IP and dst Port. Used for faster integration tests, not for general use. * `--max-sendto-failures`: Maximum NIC sendto failures before scan is aborted * `--min-hitrate`: Minimum hitrate that scan can hit before scan is aborted * `--cores`: Comma-separated list of cores to pin to * `--ignore-blocklist-errors`: Ignore invalid, malformed, or unresolvable entries in allowlist/blocklist file. Replaces the pre-v3.x `--ignore-invalid-hosts` option. * `-h`, `--help`: Print help and exit * `-V`, `--version`: Print version and exit ### OUTPUT FILTERS ### Results generated by a probe module can be filtered before being passed to the output module. Filters are defined over the output fields of a probe module. Filters are written in a simple filtering language, similar to SQL, and are passed to ZMap using the `--output-filter` option. Output filters are commonly used to filter out duplicate results, or to only pass only successful responses to the output module. Filter expressions are of the form ` `. The type of `` must be either a string or unsigned integer literal, and match the type of ``. The valid operations for integer comparisons are = !=, <, >, <=, >=. The operations for string comparisons are =, !=. The `--list-output-fields` flag will print what fields and types are available for the selected probe module, and then exit. Compound filter expressions may be constructed by combining filter expressions using parenthesis to specify order of operations, the && (logical AND) and || (logical OR) operators. For example, a filter for only successful, non-duplicate responses would be written as: `--output-filter="success = 1 && repeat = 0"` ### UDP PROBE MODULE OPTIONS ### These arguments are all passed using the `--probe-args=args` option. Only one argument may be passed at a time. * `file:/path/to/file`: Path to payload file to send to each host over UDP. * `template:/path/to/template`: Path to template file. For each destination host, the template file is populated, set as the UDP payload, and sent. * `text:`: ASCII text to send to each destination host * `hex:`: Hex-encoded binary to send to each destination host * `template-fields`: Print information about the allowed template fields and exit. ### MID-SCAN CHANGES ### You can change the rate at which ZMap is scanning mid-scan by sending SIGUSR1 (increase) and SIGUSR2 (decrease) signals to ZMap. These will result in the scan rate increasing or decreasing by 5%. zmap-4.3.4/src/zmap.c000066400000000000000000001156761501046211500144060ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../lib/includes.h" #include "../lib/blocklist.h" #include "../lib/logger.h" #include "../lib/random.h" #include "../lib/util.h" #include "../lib/xalloc.h" #include "../lib/pbm.h" #include "../lib/aes128.h" #include "aesrand.h" #include "constants.h" #include "ports.h" #include "zopt.h" #include "send.h" #include "recv.h" #include "state.h" #include "monitor.h" #include "get_gateway.h" #include "filter.h" #include "summary.h" #include "utility.h" #include "output_modules/output_modules.h" #include "probe_modules/probe_modules.h" #ifdef PFRING #include static int64_t distrib_func(pfring_zc_pkt_buff *pkt, pfring_zc_queue *in_queue, void *arg) { (void)pkt; (void)in_queue; (void)arg; return 0; } #endif #ifdef NETMAP #if !(defined(__FreeBSD__) || defined(__linux__)) #error "NETMAP requires FreeBSD or Linux" #endif #include "if-netmap.h" #include #include #include #include #endif pthread_mutex_t recv_ready_mutex = PTHREAD_MUTEX_INITIALIZER; int get_num_cores(void) { return sysconf(_SC_NPROCESSORS_ONLN); } typedef struct send_arg { uint32_t cpu; sock_t sock; shard_t *shard; } send_arg_t; typedef struct recv_arg { uint32_t cpu; } recv_arg_t; typedef struct mon_start_arg { uint32_t cpu; iterator_t *it; pthread_mutex_t *recv_ready_mutex; } mon_start_arg_t; const char *default_help_text = "By default, ZMap prints out unique, successful " "IP addresses (e.g., SYN-ACK from a TCP SYN scan) " "in ASCII form (e.g., 192.168.1.5) to stdout or the specified output " "file. Internally this is handled by the \"csv\" output module and is " "equivalent to running zmap --output-module=csv --output-fields=saddr " "--output-filter=\"success = 1 && repeat = 0\" --no-header-row."; static void *start_send(void *arg) { send_arg_t *s = (send_arg_t *)arg; log_debug("zmap", "Pinning a send thread to core %u", s->cpu); set_cpu(s->cpu); int ret = send_run(s->sock, s->shard); free(s); if (ret != EXIT_SUCCESS) { log_fatal("send", "send_run failed, terminating"); } return NULL; } static void *start_recv(void *arg) { recv_arg_t *r = (recv_arg_t *)arg; log_debug("zmap", "Pinning receive thread to core %u", r->cpu); set_cpu(r->cpu); recv_run(&recv_ready_mutex); return NULL; } static void *start_mon(void *arg) { mon_start_arg_t *mon_arg = (mon_start_arg_t *)arg; log_debug("zmap", "Pinning monitor thread to core %u", mon_arg->cpu); set_cpu(mon_arg->cpu); monitor_run(mon_arg->it, mon_arg->recv_ready_mutex); free(mon_arg); return NULL; } static void network_config_init(void) { if (zconf.iface == NULL) { zconf.iface = get_default_iface(); assert(zconf.iface); log_debug("zmap", "no interface provided. will use default" " interface (%s).", zconf.iface); } if (zconf.number_source_ips == 0) { struct in_addr default_ip; if (get_iface_ip(zconf.iface, &default_ip) < 0) { log_fatal("zmap", "could not detect default IP address for %s." " Try specifying a source address (-S).", zconf.iface); } zconf.source_ip_addresses[0] = default_ip.s_addr; zconf.number_source_ips++; log_debug( "zmap", "no source IP address given. will use default address: %s.", inet_ntoa(default_ip)); } if (!zconf.gw_mac_set) { struct in_addr gw_ip; memset(&gw_ip, 0, sizeof(struct in_addr)); if (get_default_gw(&gw_ip, zconf.iface) < 0) { log_fatal( "zmap", "could not detect default gateway address for %s." " Try setting default gateway mac address (-G)." " If this is a newly launched machine, try completing an outgoing network connection (e.g. curl https://zmap.io), and trying again.", zconf.iface); } log_debug("zmap", "found gateway IP %s on %s", inet_ntoa(gw_ip), zconf.iface); zconf.gw_ip = gw_ip.s_addr; memset(&zconf.gw_mac, 0, MAC_ADDR_LEN); if (get_hw_addr(&gw_ip, zconf.iface, zconf.gw_mac)) { log_fatal( "zmap", "could not detect GW MAC address for %s on %s." " Try setting default gateway mac address (-G), or run" " \"arp \" in terminal." " If this is a newly launched machine, try completing an outgoing network connection (e.g. curl https://zmap.io), and trying again." " If you are using a VPN, supply the --iplayer flag (and provide an interface via -i)", inet_ntoa(gw_ip), zconf.iface); } zconf.gw_mac_set = 1; } log_debug("send", "gateway MAC address %02x:%02x:%02x:%02x:%02x:%02x", zconf.gw_mac[0], zconf.gw_mac[1], zconf.gw_mac[2], zconf.gw_mac[3], zconf.gw_mac[4], zconf.gw_mac[5]); } static void start_zmap(void) { // Initialization assert(zconf.output_module && "no output module set"); log_debug("zmap", "output module: %s", zconf.output_module->name); if (zconf.output_module && zconf.output_module->init) { if (zconf.output_module->init(&zconf, zconf.output_fields, zconf.output_fields_len)) { log_fatal( "zmap", "output module did not initialize successfully."); } } iterator_t *it = send_init(); if (!it) { log_fatal("zmap", "unable to initialize sending component"); } if (zconf.output_module && zconf.output_module->start) { zconf.output_module->start(&zconf, &zsend, &zrecv); } if (zconf.fast_dryrun) { // fast dryrun mode is a special case of dryrun mode zconf.dryrun = 1; } // start threads uint32_t cpu = 0; pthread_t *tsend, trecv, tmon; int r; bool monitor_thread_started = (!zconf.quiet || zconf.status_updates_file) && (!zconf.dryrun || zconf.fast_dryrun); bool recv_thread_started = !zconf.dryrun || monitor_thread_started; // monitor thread needs recv thread to exit if (recv_thread_started) { // only start recv thread if not in dryrun mode recv_arg_t *recv_arg = xmalloc(sizeof(recv_arg_t)); recv_arg->cpu = zconf.pin_cores[cpu % zconf.pin_cores_len]; cpu += 1; r = pthread_create(&trecv, NULL, start_recv, recv_arg); if (r != 0) { log_fatal("zmap", "unable to create recv thread"); } for (;;) { pthread_mutex_lock(&recv_ready_mutex); if (zconf.recv_ready) { pthread_mutex_unlock(&recv_ready_mutex); break; } pthread_mutex_unlock(&recv_ready_mutex); } } #ifdef PFRING pfring_zc_worker *zw = pfring_zc_run_balancer( zconf.pf.queues, &zconf.pf.send, zconf.senders, 1, zconf.pf.prefetches, round_robin_bursts_policy, NULL, distrib_func, NULL, 0, zconf.pin_cores[cpu & zconf.pin_cores_len]); cpu += 1; #endif tsend = xmalloc(zconf.senders * sizeof(pthread_t)); for (uint8_t i = 0; i < zconf.senders; i++) { sock_t sock; if (zconf.dryrun) { sock = get_dryrun_socket(); } else { sock = get_socket(i); } send_arg_t *arg = xmalloc(sizeof(send_arg_t)); arg->sock = sock; arg->shard = get_shard(it, i); arg->cpu = zconf.pin_cores[cpu % zconf.pin_cores_len]; cpu += 1; int r = pthread_create(&tsend[i], NULL, start_send, arg); if (r != 0) { log_fatal("zmap", "unable to create send thread"); exit(EXIT_FAILURE); } } log_debug("zmap", "%d sender threads spawned", zconf.senders); if (monitor_thread_started) { // we'll print monitor for fast-dryrun so we can watch the long-running long tests OR under normal usage monitor_init(); mon_start_arg_t *mon_arg = xmalloc(sizeof(mon_start_arg_t)); mon_arg->it = it; mon_arg->recv_ready_mutex = &recv_ready_mutex; mon_arg->cpu = zconf.pin_cores[cpu % zconf.pin_cores_len]; int m = pthread_create(&tmon, NULL, start_mon, mon_arg); if (m != 0) { log_fatal("zmap", "unable to create monitor thread"); exit(EXIT_FAILURE); } } #ifndef PFRING drop_privs(); #endif // wait for completion for (uint8_t i = 0; i < zconf.senders; i++) { int r = pthread_join(tsend[i], NULL); if (r != 0) { log_fatal("zmap", "unable to join send thread"); exit(EXIT_FAILURE); } } log_debug("zmap", "senders finished"); #ifdef PFRING pfring_zc_kill_worker(zw); pfring_zc_sync_queue(zconf.pf.send, tx_only); log_debug("zmap", "send queue flushed"); #endif if (recv_thread_started) { // only join recv thread if not in dryrun mode r = pthread_join(trecv, NULL); if (r != 0) { log_fatal("zmap", "unable to join recv thread"); exit(EXIT_FAILURE); } } if (monitor_thread_started) { r = pthread_join(tmon, NULL); if (r != 0) { log_fatal("zmap", "unable to join monitor thread"); exit(EXIT_FAILURE); } } // finished if (zconf.metadata_filename) { json_metadata(zconf.metadata_file); } if (zconf.output_module && zconf.output_module->close) { zconf.output_module->close(&zconf, &zsend, &zrecv); } if (zconf.probe_module && zconf.probe_module->close) { zconf.probe_module->close(&zconf, &zsend, &zrecv); } #ifdef PFRING pfring_zc_destroy_cluster(zconf.pf.cluster); #endif log_info("zmap", "completed"); } #define SET_IF_GIVEN(DST, ARG) \ { \ if (args.ARG##_given) { \ (DST) = args.ARG##_arg; \ }; \ } #define SET_BOOL(DST, ARG) \ { \ if (args.ARG##_given) { \ (DST) = 1; \ }; \ } int main(int argc, char *argv[]) { struct gengetopt_args_info args; struct cmdline_parser_params *params; params = cmdline_parser_params_create(); params->initialize = 1; params->override = 0; params->check_required = 0; int config_loaded = 0; if (cmdline_parser_ext(argc, argv, &args, params) != 0) { exit(EXIT_SUCCESS); } if (args.config_given || file_exists(args.config_arg)) { params->initialize = 0; params->override = 0; if (cmdline_parser_config_file(args.config_arg, &args, params) != 0) { exit(EXIT_FAILURE); } config_loaded = 1; } // set defaults before loading in command line arguments init_empty_global_configuration(&zconf); // initialize logging. if no log file or log directory are specified // default to using stderr. zconf.log_level = args.verbosity_arg; zconf.log_file = args.log_file_arg; zconf.log_directory = args.log_directory_arg; if (args.disable_syslog_given) { zconf.syslog = 0; } else { zconf.syslog = 1; } if (zconf.log_file && zconf.log_directory) { log_init(stderr, zconf.log_level, zconf.syslog, "zmap"); log_fatal("zmap", "log-file and log-directory cannot " "specified simultaneously."); } FILE *log_location = NULL; if (zconf.log_file) { log_location = fopen(zconf.log_file, "w"); } else if (zconf.log_directory) { time_t now; time(&now); struct tm *local = localtime(&now); char path[100]; strftime(path, 100, "zmap-%Y-%m-%dT%H%M%S%z.log", local); char *fullpath = xmalloc(strlen(zconf.log_directory) + strlen(path) + 2); sprintf(fullpath, "%s/%s", zconf.log_directory, path); log_location = fopen(fullpath, "w"); free(fullpath); } else { log_location = stderr; } if (!log_location) { log_init(stderr, zconf.log_level, zconf.syslog, "zmap"); log_fatal("zmap", "unable to open specified log file: %s", strerror(errno)); } log_init(log_location, zconf.log_level, zconf.syslog, "zmap"); log_debug("zmap", "zmap main thread started"); if (config_loaded) { log_debug("zmap", "Loaded configuration file %s", args.config_arg); } if (zconf.syslog) { log_debug("zmap", "syslog support enabled"); } else { log_info("zmap", "syslog support disabled"); } // parse the provided probe and output module s.t. that we can support // other command-line helpers (e.g. probe help) log_debug("zmap", "requested ouput-module: %s", args.output_module_arg); // ZMap's default behavior is to provide a simple file of the unique IP // addresses that responded successfully. We only use this simple "default" // mode if none of {output module, output filter, output fields} are set. zconf.default_mode = (!(args.output_module_given || args.output_filter_given || args.output_fields_given)); if (zconf.default_mode) { log_info( "zmap", "By default, ZMap will output the unique IP addresses " "of hosts that respond successfully (e.g., SYN-ACK packet). This " "is equivalent to running ZMap with the following flags: " "--output-module=csv --output-fields=saddr --output-filter='" "success=1 && repeat=0' --no-header-row. " "If you want all responses, explicitly set an output module or " "set --output-filter=\"\"."); zconf.output_module = get_output_module_by_name("csv"); zconf.output_module_name = strdup("csv"); zconf.no_header_row = 1; } else if (!args.output_module_given) { log_debug("zmap", "No output module provided. Will use csv."); zconf.output_module = get_output_module_by_name("csv"); zconf.output_module_name = strdup("csv"); } else { zconf.output_module = get_output_module_by_name(args.output_module_arg); if (!zconf.output_module) { log_fatal( "zmap", "specified output module (%s) does not exist\n", args.output_module_arg); } zconf.output_module_name = strdup(args.output_module_arg); } zconf.probe_module = get_probe_module_by_name(args.probe_module_arg); if (!zconf.probe_module) { log_fatal("zmap", "specified probe module (%s) does not exist\n", args.probe_module_arg); exit(EXIT_FAILURE); } // check whether the probe module is going to generate dynamic data // and that the output module can support exporting that data out of // zmap. If they can't, then quit. if (zconf.probe_module->output_type == OUTPUT_TYPE_DYNAMIC && !zconf.output_module->supports_dynamic_output) { log_fatal( "zmap", "specified probe module (%s) requires dynamic " "output support, which output module (%s) does not support. " "Most likely you want to use JSON output.", args.probe_module_arg, args.output_module_arg); } if (args.help_given) { cmdline_parser_print_help(); printf("\nProbe Module (%s) Help:\n", zconf.probe_module->name); if (zconf.probe_module->helptext) { fprintw(stdout, zconf.probe_module->helptext, 80); } else { printf("no help text available\n"); } assert(zconf.output_module && "no output module set"); const char *module_name = zconf.default_mode ? "Default" : zconf.output_module->name; printf("\nOutput Module (%s) Help:\n", module_name); if (zconf.default_mode) { fprintw(stdout, default_help_text, 80); } else if (zconf.output_module->helptext) { fprintw(stdout, zconf.output_module->helptext, 80); } else { printf("no help text available\n"); } exit(EXIT_SUCCESS); } if (args.version_given) { cmdline_parser_print_version(); exit(EXIT_SUCCESS); } if (args.list_output_modules_given) { print_output_modules(); exit(EXIT_SUCCESS); } if (args.list_probe_modules_given) { print_probe_modules(); exit(EXIT_SUCCESS); } if (args.iplayer_given) { zconf.send_ip_pkts = 1; zconf.gw_mac_set = 1; memset(zconf.gw_mac, 0, MAC_ADDR_LEN); } if (cmdline_parser_required(&args, CMDLINE_PARSER_PACKAGE) != 0) { exit(EXIT_FAILURE); } aes128_selftest(); // now that we know the probe module, let's find what it supports memset(&zconf.fsconf, 0, sizeof(struct fieldset_conf)); // the set of fields made available to a user is constructed // of IP header fields + probe module fields + system fields fielddefset_t *fds = &(zconf.fsconf.defs); gen_fielddef_set(fds, (fielddef_t *)&(ip_fields), ip_fields_len); gen_fielddef_set(fds, zconf.probe_module->fields, zconf.probe_module->numfields); gen_fielddef_set(fds, (fielddef_t *)&(sys_fields), sys_fields_len); if (args.list_output_fields_given) { for (int i = 0; i < fds->len; i++) { printf("%-15s %6s: %s\n", fds->fielddefs[i].name, fds->fielddefs[i].type, fds->fielddefs[i].desc); } exit(EXIT_SUCCESS); } // find the fields we need for the framework zconf.fsconf.success_index = fds_get_index_by_name(fds, "success"); if (zconf.fsconf.success_index < 0) { log_fatal("fieldset", "probe module does not supply " "required success field."); } zconf.fsconf.app_success_index = fds_get_index_by_name(fds, "app_success"); if (zconf.fsconf.app_success_index < 0) { log_debug("fieldset", "probe module does not supply " "application success field."); } else { log_debug( "fieldset", "probe module supplies app_success" " output field. It will be included in monitor output"); } zconf.fsconf.classification_index = fds_get_index_by_name(fds, "classification"); if (zconf.fsconf.classification_index < 0) { log_fatal("fieldset", "probe module does not supply " "required packet classification field."); } zconf.ignore_invalid_hosts = args.ignore_blocklist_errors_given; SET_BOOL(zconf.dryrun, dryrun); SET_BOOL(zconf.fast_dryrun, fast_dryrun); SET_BOOL(zconf.quiet, quiet); SET_BOOL(zconf.no_header_row, no_header_row); zconf.cooldown_secs = args.cooldown_time_arg; SET_IF_GIVEN(zconf.output_filename, output_file); SET_IF_GIVEN(zconf.blocklist_filename, blocklist_file); SET_IF_GIVEN(zconf.list_of_ips_filename, list_of_ips_file); SET_IF_GIVEN(zconf.probe_args, probe_args); SET_IF_GIVEN(zconf.probe_ttl, probe_ttl); SET_IF_GIVEN(zconf.output_args, output_args); SET_IF_GIVEN(zconf.iface, interface); SET_IF_GIVEN(zconf.max_runtime, max_runtime); SET_IF_GIVEN(zconf.max_results, max_results); SET_IF_GIVEN(zconf.rate, rate); SET_IF_GIVEN(zconf.packet_streams, probes); SET_IF_GIVEN(zconf.status_updates_file, status_updates_file); SET_IF_GIVEN(zconf.retries, retries); SET_IF_GIVEN(zconf.max_sendto_failures, max_sendto_failures); SET_IF_GIVEN(zconf.min_hitrate, min_hitrate); if (zconf.retries < 0) { log_fatal("zmap", "Invalid retry count"); } if (zconf.max_sendto_failures >= 0) { log_debug("zmap", "scan will abort if more than %i " "sendto failures occur", zconf.max_sendto_failures); } if (zconf.min_hitrate > 0.0) { log_debug("zmap", "scan will abort if hitrate falls below %f", zconf.min_hitrate); } if (args.metadata_file_arg) { zconf.metadata_filename = args.metadata_file_arg; if (!strcmp(zconf.metadata_filename, "-")) { zconf.metadata_file = stdout; } else { zconf.metadata_file = fopen(zconf.metadata_filename, "w"); } if (!zconf.metadata_file) { log_fatal("metadata", "unable to open metadata file (%s): %s", zconf.metadata_filename, strerror(errno)); } log_debug("metadata", "metadata will be saved to %s", zconf.metadata_filename); } if (args.user_metadata_given) { zconf.custom_metadata_str = args.user_metadata_arg; if (!json_tokener_parse(zconf.custom_metadata_str)) { log_fatal("metadata", "unable to parse custom user metadata"); } else { log_debug("metadata", "user metadata validated successfully"); } } if (args.notes_given) { zconf.notes = args.notes_arg; } // find if zmap wants any specific cidrs scanned instead // of the entire Internet zconf.destination_cidrs = args.inputs; zconf.destination_cidrs_len = args.inputs_num; if (zconf.destination_cidrs && zconf.blocklist_filename && !strcmp(zconf.blocklist_filename, ZMAP_DEFAULT_BLOCKLIST)) { log_warn( "blocklist", "ZMap is currently using the default blocklist located " "at " ZMAP_DEFAULT_BLOCKLIST ". By default, this blocklist excludes locally " "scoped networks (e.g. 10.0.0.0/8, 127.0.0.1/8, and 192.168.0.0/16). If you are" " trying to scan local networks, you can change the default blocklist by " "editing the default ZMap configuration at " ZMAP_DEFAULT_BLOCKLIST "." " If you have modified the default blocklist, you can ignore this message."); } SET_IF_GIVEN(zconf.allowlist_filename, allowlist_file); zconf.validate_source_port_override = VALIDATE_SRC_PORT_UNSET_OVERRIDE; if (args.validate_source_port_given) { if (strcmp(args.validate_source_port_arg, "enable") == 0) { // user wants to force source port validation zconf.validate_source_port_override = VALIDATE_SRC_PORT_ENABLE_OVERRIDE; } else if (strcmp(args.validate_source_port_arg, "disable") == 0) { // user wants to force disable source port validation zconf.validate_source_port_override = VALIDATE_SRC_PORT_DISABLE_OVERRIDE; } else { // unknown value log_fatal("zmap", "unknown value for --validate-source-port, use either \"enable\" or \"disable\""); } } if (zconf.probe_module->port_args) { if (args.source_port_given) { char *dash = strchr(args.source_port_arg, '-'); if (dash) { // range *dash = '\0'; zconf.source_port_first = atoi(args.source_port_arg); enforce_range("starting source-port", zconf.source_port_first, 0, 0xFFFF); zconf.source_port_last = atoi(dash + 1); enforce_range("ending source-port", zconf.source_port_last, 0, 0xFFFF); if (zconf.source_port_first > zconf.source_port_last) { fprintf( stderr, "%s: invalid source port range: " "last port is less than first port\n", CMDLINE_PARSER_PACKAGE); exit(EXIT_FAILURE); } } else { // single port int port = atoi(args.source_port_arg); enforce_range("source-port", port, 0, 0xFFFF); zconf.source_port_first = port; zconf.source_port_last = port; } int num_source_ports = (zconf.source_port_last - zconf.source_port_first) + 1; if (zconf.packet_streams > num_source_ports) { log_fatal("zmap", "The number of probes sent to each target ip/port (%i) " "must be smaller than the size of the source port range (%u-%u, size: %i). " "Otherwise, some generated probe packets will be identical.", zconf.packet_streams, zconf.source_port_first, zconf.source_port_last, (zconf.source_port_last - zconf.source_port_first) + 1); } else if (((float)zconf.packet_streams / (float)num_source_ports) > 0.1) { log_warn("zmap", "ZMap is configured to use a relatively small number" " of source ports (fewer than 10x the number of probe packets per target ip/port)," " which limits the entropy that ZMap has available for " " validating responses. We recommend that you use a larger port range."); } } if (!args.target_ports_given) { log_fatal("zmap", "target ports (-p) required for %s probe", zconf.probe_module->name); } } else { if (args.target_ports_given) { log_fatal("zmap", "Destination port cannot be set for %s probe", zconf.probe_module->name); } } zconf.ports = xmalloc(sizeof(struct port_conf)); zconf.ports->port_bitmap = bm_init(); if (args.target_ports_given) { parse_ports(args.target_ports_arg, zconf.ports); } else { char *line = strdup("0"); parse_ports(line, zconf.ports); } if (args.dedup_method_given) { if (!strcmp(args.dedup_method_arg, "default")) { if (zconf.ports->port_count > 1) { zconf.dedup_method = DEDUP_METHOD_WINDOW; } else { zconf.dedup_method = DEDUP_METHOD_FULL; } } else if (!strcmp(args.dedup_method_arg, "none")) { zconf.dedup_method = DEDUP_METHOD_NONE; } else if (!strcmp(args.dedup_method_arg, "full")) { zconf.dedup_method = DEDUP_METHOD_FULL; } else if (!strcmp(args.dedup_method_arg, "window")) { zconf.dedup_method = DEDUP_METHOD_WINDOW; } else { log_fatal( "dedup", "Invalid dedup option provided. Legal options are: default, none, full, window."); } } else { if (zconf.ports->port_count > 1) { zconf.dedup_method = DEDUP_METHOD_WINDOW; } else { zconf.dedup_method = DEDUP_METHOD_FULL; } } if (zconf.dedup_method == DEDUP_METHOD_FULL && zconf.ports->port_count > 1) { log_fatal( "dedup", "full response de-duplication is not supported for multiple ports"); } if (zconf.dedup_method == DEDUP_METHOD_WINDOW) { if (args.dedup_window_size_given) { zconf.dedup_window_size = args.dedup_window_size_arg; } else { zconf.dedup_window_size = 1000000; } log_info("dedup", "Response deduplication method is %s with size %u", DEDUP_METHOD_NAMES[zconf.dedup_method], zconf.dedup_window_size); } else { log_info("dedup", "Response deduplication method is %s", DEDUP_METHOD_NAMES[zconf.dedup_method]); } // process the list of requested output fields. if (args.output_fields_given) { zconf.raw_output_fields = args.output_fields_arg; } else { if (zconf.ports->port_count > 1) { zconf.raw_output_fields = "saddr,sport"; } else { zconf.raw_output_fields = "saddr"; } } // add all fields if wildcard received if (!strcmp(zconf.raw_output_fields, "*")) { zconf.output_fields_len = zconf.fsconf.defs.len; zconf.output_fields = xcalloc(zconf.fsconf.defs.len, sizeof(const char *)); for (int i = 0; i < zconf.fsconf.defs.len; i++) { zconf.output_fields[i] = zconf.fsconf.defs.fielddefs[i].name; } fs_generate_full_fieldset_translation(&zconf.fsconf.translation, &zconf.fsconf.defs); } else { split_string(zconf.raw_output_fields, &(zconf.output_fields_len), &(zconf.output_fields)); for (int i = 0; i < zconf.output_fields_len; i++) { log_debug("zmap", "requested output field (%i): %s", i, zconf.output_fields[i]); } // generate a translation that can be used to convert output // from a probe module to the input for an output module fs_generate_fieldset_translation( &zconf.fsconf.translation, &zconf.fsconf.defs, zconf.output_fields, zconf.output_fields_len); } // default filtering behavior is to drop unsuccessful and duplicates if (zconf.default_mode) { log_debug( "filter", "No output filter specified. Will use default: exclude duplicates and unsuccessful"); } else if (args.output_filter_given && strcmp(args.output_filter_arg, "")) { // Run it through yyparse to build the expression tree if (!parse_filter_string(args.output_filter_arg)) { log_fatal("zmap", "Unable to parse filter expression"); } // Check the fields used against the fieldset in use if (!validate_filter(zconf.filter.expression, &zconf.fsconf.defs)) { log_fatal("zmap", "Invalid filter"); } zconf.output_filter_str = args.output_filter_arg; log_debug("filter", "will use output filter %s", args.output_filter_arg); } else if (args.output_filter_given) { // (empty filter argument) log_debug( "filter", "Empty output filter provided. ZMap will output all " "results, including duplicate and non-successful responses."); } else { log_info( "filter", "No output filter provided. ZMap will output all " "results, including duplicate and non-successful responses (e.g., " "RST and ICMP packets). If you want a filter similar to ZMap's " "default behavior, you can set an output filter similar to the " "following: --output-filter=\"success=1 && repeat=0\"."); } if (args.source_ip_given) { parse_source_ip_addresses(args.source_ip_arg); } if (args.gateway_mac_given) { if (!parse_mac(zconf.gw_mac, args.gateway_mac_arg)) { fprintf(stderr, "%s: invalid MAC address `%s'\n", CMDLINE_PARSER_PACKAGE, args.gateway_mac_arg); exit(EXIT_FAILURE); } zconf.gw_mac_set = 1; } if (args.source_mac_given) { if (!parse_mac(zconf.hw_mac, args.source_mac_arg)) { fprintf(stderr, "%s: invalid MAC address `%s'\n", CMDLINE_PARSER_PACKAGE, args.gateway_mac_arg); exit(EXIT_FAILURE); } log_debug("send", "source MAC address specified on CLI: " "%02x:%02x:%02x:%02x:%02x:%02x", zconf.hw_mac[0], zconf.hw_mac[1], zconf.hw_mac[2], zconf.hw_mac[3], zconf.hw_mac[4], zconf.hw_mac[5]); zconf.hw_mac_set = 1; } // Check for a random seed if (args.seed_given) { zconf.seed = args.seed_arg; zconf.seed_provided = 1; } else { // generate a seed randomly if (!random_bytes(&zconf.seed, sizeof(uint64_t))) { log_fatal("zmap", "unable to generate random bytes " "needed for seed"); } zconf.seed_provided = 0; } zconf.aes = aesrand_init_from_seed(zconf.seed); // Set up sharding zconf.shard_num = 0; zconf.total_shards = 1; if ((args.shard_given || args.shards_given) && !args.seed_given) { log_fatal("zmap", "Need to specify seed if sharding a scan"); } if (args.shard_given ^ args.shards_given) { log_fatal( "zmap", "Need to specify both shard number and total number of shards"); } if (args.shard_given) { enforce_range("shard", args.shard_arg, 0, 65534); } if (args.shards_given) { enforce_range("shards", args.shards_arg, 1, 65535); } SET_IF_GIVEN(zconf.shard_num, shard); SET_IF_GIVEN(zconf.total_shards, shards); if (zconf.shard_num >= zconf.total_shards) { log_fatal("zmap", "With %hhu total shards, shard number (%hhu)" " must be in range [0, %hhu)", zconf.total_shards, zconf.shard_num, zconf.total_shards); } if (args.bandwidth_given) { // Supported: G,g=*1000000000; M,m=*1000000 K,k=*1000 bits per // second zconf.bandwidth = atoi(args.bandwidth_arg); char *suffix = args.bandwidth_arg; while (*suffix >= '0' && *suffix <= '9') { suffix++; } if (*suffix) { switch (*suffix) { case 'G': case 'g': zconf.bandwidth *= 1000000000; break; case 'M': case 'm': zconf.bandwidth *= 1000000; break; case 'K': case 'k': zconf.bandwidth *= 1000; break; default: fprintf(stderr, "%s: unknown bandwidth suffix '%s' " "(supported suffixes are G, M and K)\n", CMDLINE_PARSER_PACKAGE, suffix); exit(EXIT_FAILURE); } } } if (args.batch_given && args.batch_arg >= 1 && args.batch_arg <= UINT16_MAX) { zconf.batch = args.batch_arg; } else if (args.batch_given) { log_fatal("zmap", "batch size must be > 0 and <= 65535"); } if (args.max_targets_given) { zconf.max_targets = parse_max_targets(args.max_targets_arg, zconf.ports->port_count); } // blocklist if (blocklist_init(zconf.allowlist_filename, zconf.blocklist_filename, zconf.destination_cidrs, zconf.destination_cidrs_len, NULL, 0, zconf.ignore_invalid_hosts)) { log_fatal("zmap", "unable to initialize blocklist / allowlist"); } // if there's a list of ips to scan, then initialize PBM and populate // it based on the provided file if (zconf.list_of_ips_filename) { zsend.list_of_ips_pbm = pbm_init(); zconf.list_of_ips_count = pbm_load_from_file( zsend.list_of_ips_pbm, zconf.list_of_ips_filename); } // compute number of targets uint64_t allowed = blocklist_count_allowed(); zconf.total_allowed = allowed; zconf.total_disallowed = blocklist_count_not_allowed(); assert(allowed <= (1LL << 32)); if (!zconf.total_allowed) { log_fatal("zmap", "zero eligible addresses to scan"); } if (zconf.list_of_ips_count > 0 && 0xFFFFFFFFU / zconf.list_of_ips_count > 100000) { log_warn( "zmap", "list of IPs is small compared to address space. Performance will suffer, consider using an allowlist instead"); } if (zconf.max_targets) { zsend.max_targets = zconf.max_targets; } // Perform network initialization before initializing // PFRING and NETMAP, as they depend on the interface name // being available. // NETMAP will additionally break network connectivity of // the host through the chosen NIC. If one wanted to do // active ARP or IPv6 ND as part of network initialization // instead of just querying the kernel, that would also // have to happen before NETMAP binding to the interface. network_config_init(); #ifdef NETMAP // Initialize netmap(4) before computing number of threads, // because we want to know the number of tx queues for that. if (zconf.send_ip_pkts) { log_fatal("zmap", "netmap does not support IP layer mode (--iplayer/-X)"); } assert(zconf.iface); log_warn("zmap", "netmap will disconnect the NIC from the host while zmap is executing"); usleep(100000); zconf.nm.nm_fd = open(NETMAP_DEVICE_NAME, O_RDWR); if (zconf.nm.nm_fd == -1) { log_fatal("zmap", "netmap open(\"" NETMAP_DEVICE_NAME "\") failed: %d: %s", errno, strerror(errno)); } struct nmreq_register nmrreg; memset(&nmrreg, 0, sizeof(nmrreg)); nmrreg.nr_mode = NR_REG_ALL_NIC; nmrreg.nr_flags = NR_NO_TX_POLL; struct nmreq_header nmrhdr; memset(&nmrhdr, 0, sizeof(nmrhdr)); nmrhdr.nr_version = NETMAP_API; nmrhdr.nr_reqtype = NETMAP_REQ_REGISTER; cross_platform_strlcpy(nmrhdr.nr_name, zconf.iface, sizeof(nmrhdr.nr_name)); nmrhdr.nr_body = (uint64_t)&nmrreg; if (ioctl(zconf.nm.nm_fd, NIOCCTRL, &nmrhdr) == -1) { log_fatal("zmap", "netmap ioctl(NIOCCTRL) failed: %d: %s", errno, strerror(errno)); } // From this point on, the host and NIC are separated until // we close the file descriptor or exit. We _could_ pass // packets unrelated to the scan up to the host and back via // the host rings, but that is not currently done in order // to avoid adding complexity to perf-sensitive code paths. zconf.nm.nm_mem = mmap(NULL, nmrreg.nr_memsize, PROT_WRITE | PROT_READ, MAP_SHARED, zconf.nm.nm_fd, 0); if (zconf.nm.nm_mem == MAP_FAILED) { log_fatal("zmap", "netmap mmap() failed: %d: %s", errno, strerror(errno)); } zconf.nm.nm_if = NETMAP_IF(zconf.nm.nm_mem, nmrreg.nr_offset); log_info("zmap", "netmap bound to %s with %" PRIu32 " tx rings, %" PRIu32 " rx rings", zconf.nm.nm_if->ni_name, zconf.nm.nm_if->ni_tx_rings, zconf.nm.nm_if->ni_rx_rings); for (uint32_t i = 0; i < zconf.nm.nm_if->ni_tx_rings; i++) { struct netmap_ring *ring = NETMAP_TXRING(zconf.nm.nm_if, i); log_debug("zmap", "tx ring %d has %" PRIu32 " slots of %" PRIu32 " bytes each", i, ring->num_slots, ring->nr_buf_size); } for (uint32_t i = 0; i < zconf.nm.nm_if->ni_rx_rings; i++) { struct netmap_ring *ring = NETMAP_RXRING(zconf.nm.nm_if, i); log_debug("zmap", "rx ring %d has %" PRIu32 " slots of %" PRIu32 " bytes each", i, ring->num_slots, ring->nr_buf_size); } // Enabling netmap mode on an interface resets PHY, which // on physical NICs can take multiple seconds to complete. // To avoid dropping packets while the reset is ongoing, // wait for the interface to come back up here. log_debug("zmap", "waiting for PHY reset to complete"); if_wait_for_phy_reset(zconf.iface, zconf.nm.nm_fd); log_debug("zmap", "PHY reset is complete, link state is up"); if (args.netmap_wait_ping_arg != NULL) { zconf.nm.wait_ping_dstip = string_to_ip_address(args.netmap_wait_ping_arg); } #endif #ifndef PFRING // Set the correct number of threads, default to min(4, number of cores on host - 1, as available) if (args.sender_threads_given) { if (args.sender_threads_arg > 255) { log_fatal("zmap", "cannot use > 255 sending threads. We advise using a sending thread per CPU " "core while reserving one core for packet receiving and monitoring. Using a large number of sender threads " "will likely decrease performance, not increase it."); } zconf.senders = args.sender_threads_arg; } else { // use one fewer than the number of cores on the machine such that the // receiver thread can use a core for processing responses int available_cores = get_num_cores(); if (available_cores > 1) { available_cores--; } int senders = (int) min_uint64_t(min_uint64_t(available_cores, 4), (zconf.total_allowed * zconf.ports->port_count)); zconf.senders = senders; log_debug("zmap", "will use %i sender threads based on core availability and number of targets", senders); } #ifdef NETMAP if (zconf.senders > (int)zconf.nm.nm_if->ni_tx_rings) { zconf.senders = (int)zconf.nm.nm_if->ni_tx_rings; log_debug("zmap", "capping to %i sender threads based on number of TX rings", zconf.senders); } #endif if (2 * zconf.senders >= zsend.max_targets) { log_warn( "zmap", "too few targets relative to senders, dropping to one sender"); zconf.senders = 1; } // reserving 1 core for the receiver/monitor thread int sender_cap = get_num_cores() - 1; if (sender_cap < 1) { // we need at least 1 core to send sender_cap = 1; } if (zconf.senders > sender_cap) { log_warn( "zmap", "ZMap has been configured to use a larger number of sending threads (%d) than the number of " "dedicated cores (%d) that can be assigned to sending packets. We advise using a sending thread per CPU " "core while reserving one core for packet receiving and monitoring. Using a large number of sender threads " "will likely decrease performance, not increase it.", zconf.senders, get_num_cores()); } #else zconf.senders = args.sender_threads_arg; #endif // Figure out what cores to bind to if (args.cores_given) { const char **core_list = NULL; int len = 0; split_string(args.cores_arg, &len, &core_list); zconf.pin_cores_len = (uint32_t)len; zconf.pin_cores = xcalloc(zconf.pin_cores_len, sizeof(uint32_t)); for (uint32_t i = 0; i < zconf.pin_cores_len; ++i) { zconf.pin_cores[i] = atoi(core_list[i]); } } else { int num_cores = get_num_cores(); zconf.pin_cores_len = (uint32_t)num_cores; zconf.pin_cores = xcalloc(zconf.pin_cores_len, sizeof(uint32_t)); for (uint32_t i = 0; i < zconf.pin_cores_len; ++i) { zconf.pin_cores[i] = i; } } // PFRING #ifdef PFRING #define MAX_CARD_SLOTS 32768 #define QUEUE_LEN 8192 #define ZMAP_PF_BUFFER_SIZE 1536 #define ZMAP_PF_ZC_CLUSTER_ID 9627 uint32_t user_buffers = zconf.senders * zconf.batch; uint32_t queue_buffers = zconf.senders * QUEUE_LEN; uint32_t card_buffers = 2 * MAX_CARD_SLOTS; uint32_t total_buffers = user_buffers + queue_buffers + card_buffers + 2; uint32_t metadata_len = 0; uint32_t numa_node = 0; // TODO zconf.pf.cluster = pfring_zc_create_cluster( ZMAP_PF_ZC_CLUSTER_ID, ZMAP_PF_BUFFER_SIZE, metadata_len, total_buffers, numa_node, NULL, 0); if (zconf.pf.cluster == NULL) { log_fatal("zmap", "Could not create zc cluster: %s", strerror(errno)); } zconf.pf.buffers = xcalloc(user_buffers, sizeof(pfring_zc_pkt_buff *)); for (uint32_t i = 0; i < user_buffers; ++i) { zconf.pf.buffers[i] = pfring_zc_get_packet_handle(zconf.pf.cluster); if (zconf.pf.buffers[i] == NULL) { log_fatal("zmap", "Could not get ZC packet handle"); } } zconf.pf.send = pfring_zc_open_device(zconf.pf.cluster, zconf.iface, tx_only, 0); if (zconf.pf.send == NULL) { log_fatal("zmap", "Could not open device %s for TX. [%s]", zconf.iface, strerror(errno)); } zconf.pf.recv = pfring_zc_open_device(zconf.pf.cluster, zconf.iface, rx_only, 0); if (zconf.pf.recv == NULL) { log_fatal("zmap", "Could not open device %s for RX. [%s]", zconf.iface, strerror(errno)); } zconf.pf.queues = xcalloc(zconf.senders, sizeof(pfring_zc_queue *)); for (uint32_t i = 0; i < zconf.senders; ++i) { zconf.pf.queues[i] = pfring_zc_create_queue(zconf.pf.cluster, QUEUE_LEN); if (zconf.pf.queues[i] == NULL) { log_fatal("zmap", "Could not create queue: %s", strerror(errno)); } } zconf.pf.prefetches = pfring_zc_create_buffer_pool(zconf.pf.cluster, 8); if (zconf.pf.prefetches == NULL) { log_fatal("zmap", "Could not open prefetch pool: %s", strerror(errno)); } #endif // resume scan if requested start_zmap(); fclose(log_location); cmdline_parser_free(&args); free(params); return EXIT_SUCCESS; } zmap-4.3.4/src/zmap_schema.py000066400000000000000000000052631501046211500161220ustar00rootroot00000000000000from zschema.leaves import * from zschema.compounds import * import zschema.registry zmap_base = Record({ "saddr":IPv4Address(), "saddr_raw":Unsigned32BitInteger(), "daddr":IPv4Address(), "daddr_raw":Unsigned32BitInteger(), "ipid":Unsigned32BitInteger(), "ttl":Unsigned32BitInteger(), "classification":String(), "success":Unsigned32BitInteger(), "app_success":Unsigned32BitInteger(), "repeat":Unsigned32BitInteger(), "cooldown":Unsigned32BitInteger(), "timestamp_str":String(), "timestamp_ts":Unsigned32BitInteger(), "timestamp_us":Unsigned32BitInteger(), "icmp_responder":String(), "icmp_type":Unsigned32BitInteger(), "icmp_code":Unsigned32BitInteger(), "icmp_unreach_str":String(), "sport":Unsigned32BitInteger(), "dport":Unsigned32BitInteger(), "data":String(), "length":Unsigned32BitInteger(), }) zmap_upnp = Record({ "type":String(), "server":AnalyzedString(), "location":AnalyzedString(), "usn":String(), "st":String(), "ext":String(), "cache_control":String(), "x_user_agent":String(), "agent":String(), "date":String(), }, extends=zmap_base) zschema.registry.register_schema("zmap-upnp", zmap_upnp) dns_question = SubRecord({ "name":String(), "qtype":Unsigned32BitInteger(), "qtype_str":String(), "qclass":Unsigned32BitInteger(), }) dns_answer = SubRecord({ "name":String(), "type":Unsigned32BitInteger(), "type_str":String(), "class":Unsigned32BitInteger(), "ttl":Unsigned32BitInteger(), "rdlength":Unsigned32BitInteger(), "rdata_is_parsed":Unsigned32BitInteger(), "rdata":String(), # hex }) zmap_dns = Record({ "qr":Unsigned16BitInteger(), "rcode":Unsigned16BitInteger(), "dns_id":Unsigned32BitInteger(), "dns_rd":Unsigned32BitInteger(), "dns_tc":Unsigned32BitInteger(), "dns_aa":Unsigned32BitInteger(), "dns_opcode":Unsigned32BitInteger(), "dns_qr":Unsigned32BitInteger(), "dns_rcode":Unsigned32BitInteger(), "dns_cd":Unsigned32BitInteger(), "dns_ad":Unsigned32BitInteger(), "dns_z":Unsigned32BitInteger(), "dns_ra":Unsigned32BitInteger(), "dns_qdcount":Unsigned32BitInteger(), "dns_ancount":Unsigned32BitInteger(), "dns_nscount":Unsigned32BitInteger(), "dns_arcount":Unsigned32BitInteger(), "dns_questions":ListOf(dns_question), "dns_answers":ListOf(dns_answer), "dns_authorities":ListOf(dns_answer), "dns_additionals":ListOf(dns_answer), "dns_unconsumed_bytes":Unsigned32BitInteger(), "dns_parse_err":Unsigned32BitInteger(), "raw_data":String(), "udp_len":Unsigned32BitInteger(), }, extends=zmap_base) zschema.registry.register_schema("zmap-dns", zmap_dns) zmap-4.3.4/src/zopt.ggo.in000066400000000000000000000177601501046211500153650ustar00rootroot00000000000000# ZMap Copyright 2013 Regents of the University of Michigan # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at http://www.apache.org/licenses/LICENSE-2.0 # zmap option description to be processed by gengetopt package "zmap" version "@ZMAP_VERSION@" purpose "A fast Internet-wide scanner." section "Basic Arguments" option "target-ports" p "comma-delimited list of ports and port ranges to scan (for TCP and UDP scans)" typestr="ports" optional string option "output-file" o "Output file" typestr="name" optional string option "blocklist-file" b "File of subnets to exclude, in CIDR notation, e.g. 192.168.0.0/16" typestr="path" optional string option "allowlist-file" w "File of subnets to constrain scan to, in CIDR notation, e.g. 192.168.0.0/16" typestr="path" optional string option "list-of-ips-file" I "List of individual addresses to scan in random order. Use --allowlist-file unless >1 million IPs" typestr="path" optional string section "Scan Options" option "rate" r "Set send rate in packets/sec" typestr="pps" optional int option "bandwidth" B "Set send rate in bits/second (supports suffixes G, M and K)" typestr="bps" optional string option "batch" - "Set batch size for how many packets to send in a single syscall. Advantageous on Linux or with netmap (default=64)" typestr="pps" optional int option "max-targets" n "Cap number of targets to probe (as a number '-n 1000' or a percentage '-n 1%' of the target search space). A target is an IP/port pair, if scanning multiple ports, and an IP otherwise." typestr="n" optional string option "max-runtime" t "Cap length of time for sending packets" typestr="secs" optional int option "max-results" N "Cap number of results to return" typestr="n" optional int option "probes" P "Number of probes to send to each IP/Port pair" typestr="n" default="1" optional int option "cooldown-time" c "How long to continue receiving after sending last probe" typestr="secs" default="8" optional int option "seed" e "Seed used to select address permutation" typestr="n" optional longlong option "retries" - "Max number of times to try to send packet if send fails" typestr="n" default="10" optional int option "dryrun" d "Don't actually send packets" optional option "fast-dryrun" - "Don't actually send packets, print out a binary representation probe dst IP and dst Port. Used for faster integration tests, not for general use." optional section "Scan Sharding" option "shards" - "Set the total number of shards" typestr="N" optional int default="1" option "shard" - "Set which shard this scan is (0 indexed)" typestr="n" optional int default="0" section "Network Options" option "source-port" s "Source port(s) for scan packets" typestr="port|range" optional string option "validate-source-port" - "Override to validate if probe responses have a valid src port corresponding to sent probe's dst port. \"enable\" or \"disable\"" typestr="enable|disable" optional string option "source-ip" S "Source address(es) for scan packets" typestr="ip|range" optional string option "gateway-mac" G "Specify gateway MAC address" typestr="addr" optional string option "source-mac" - "Source MAC address" typestr="addr" optional string option "interface" i "Specify network interface to use" typestr="name" optional string option "iplayer" X "Sends IP packets instead of Ethernet (for VPNs)" optional option "netmap-wait-ping" - "Wait for IP to respond to ping before commencing scan (netmap only)" typestr="ip" optional string section "Probe Modules" option "probe-module" M "Select probe module" typestr="name" default="tcp_synscan" optional string option "probe-args" - "Arguments to pass to probe module" typestr="args" optional string option "probe-ttl" - "Set TTL value for probe IP packets" typestr="n" default="64" optional int option "list-probe-modules" - "List available probe modules" optional section "Results Output" option "output-fields" f "Fields that should be output in result set" typestr="fields" optional string option "output-module" O "Select output module" typestr="name" optional string option "output-args" - "Arguments to pass to output module" typestr="args" optional string option "output-filter" - "Specify a filter over the response fields to limit what responses get sent to the output module" typestr="filter" optional string option "list-output-modules" - "List available output modules" optional option "list-output-fields" - "List all fields that can be output by selected probe module" optional option "no-header-row" - "Precludes outputting any header rows in data (e.g., CSV headers)" optional section "Response Deduplication" option "dedup-method" - "Specifies how response deduplication should be performed. Options: default, none, full, window" typestr="method" optional string option "dedup-window-size" - "Specifies window size for how many recent responses to keep in memory for deduplication" typestr="targets" default="1000000" optional int section "Logging and Metadata" option "verbosity" v "Level of log detail (0-5)" typestr="n" default="3" optional int option "log-file" l "Write log entries to file" typestr="name" optional string option "log-directory" L "Write log entries to a timestamped file in this directory" typestr="directory" optional string option "metadata-file" m "Output file for scan metadata (JSON)" typestr="name" optional string option "status-updates-file" u "Write scan progress updates to CSV file" typestr="name" optional string option "quiet" q "Do not print status updates" optional option "disable-syslog" - "Disables logging messages to syslog" optional option "notes" - "Inject user-specified notes into scan metadata" typestr="notes" optional string option "user-metadata" - "Inject user-specified JSON metadata into scan metadata" typestr="json" optional string section "Additional Options" option "config" C "Read a configuration file, which can specify any of these options" typestr="filename" default="/etc/zmap/zmap.conf" optional string option "max-sendto-failures" - "Maximum NIC sendto failures before scan is aborted" typestr="n" default="-1" optional int option "min-hitrate" - "Minimum hitrate that scan can hit before scan is aborted" typestr="n" default="0.0" optional float option "sender-threads" T "Threads used to send packets" typestr="n" default="4" optional int option "cores" - "Comma-separated list of cores to pin to" optional string option "ignore-blocklist-errors" - "Ignore invalid entries in allowlist/blocklist file." optional option "help" h "Print help and exit" optional option "version" V "Print version and exit" optional text "\nExamples:\n\ zmap -p 80 (scan full IPv4 address space for hosts on TCP/80)\n\ zmap -N 5 -B 10M -p 80 (find 5 HTTP servers, scanning at 10 Mb/s)\n\ zmap -p 80 10.0.0.0/8 192.168.0.0/16 (scan both subnets on TCP/80)\n\ zmap -p 80 1.2.3.4 10.0.0.3 (scan 1.2.3.4, 10.0.0.3 on TCP/80)\n\ zmap -p 80,100-102 (scan full IPv4 on ports 80, 100, 101, 102)" zmap-4.3.4/src/zopt_compat.c000066400000000000000000000010611501046211500157540ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #if __GNUC__ < 4 #error "gcc version >= 4 is required" #elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #elif __GNUC_MINOR__ >= 4 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif #include "zopt.c" zmap-4.3.4/src/ztee.1000066400000000000000000000034261501046211500143110ustar00rootroot00000000000000.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "ZTEE" "1" "November 2023" "ZMap" "ztee" . .SH "NAME" \fBztee\fR \- output buffer and splitter . .SH "SYNOPSIS" ztee [ OPTIONS\.\.\. ] [ FILE\.\.\. ] . .SH "DESCRIPTION" \fIZTee\fR is an output buffer and splitter for use with ZMap output data\. ZTee should be used whenever ZMap is piped into an application scanner, placed between ZMap and the application scanner\. ZTee writes the transformed output to stdout, and writes the original output to FILE\. . .P See \fB\-\-help\fR for examples\. . .SH "CSV PROCESSING AND RAW MODE" \fIZTee\fR operates by default on CSV\-format output from ZMap\. It only outputs IP addresses (from the input\'s \fBip\fR or \fBsaddr\fR field) to stdout, while writing all input to the output file\. ZTee does not print the first line of input to stdout, since that row is the CSV header\. . .P To operate on data in any other format, pass the \fB\-\-raw\fR flag\. In raw mode, ztee behaves like tee: it will not transform or attempt to parse the input data\. . .SH "OPTIONS" . .SS "BASIC OPTIONS" . .TP \fB\-r\fR, \fB\-\-raw\fR Ignore input formatting and pass through raw input\. This causes ztee to behave exactly like tee, with the addition of buffering\. . .TP \fB\-\-success\-only\fR Only write to stdout rows where success=1 or success=true\. Invalid in combination with \fB\-\-raw\fR\. . .TP \fB\-m\fR, \fB\-\-monitor\fR Print monitor data to stderr . .TP \fB\-u\fR, \fB\-\-status\-updates\-file\fR Write status updates (monitor data) to the given file, in CSV format . .TP \fB\-l\fR, \fB\-\-log\-file=name\fR Write errors etc\. to the given file\. If none, ZTee logs to stderr\. . .SS "ADDITIONAL OPTIONS" . .TP \fB\-h, \-\-help\fR Display help . .TP \fB\-V, \-\-version\fR Display version zmap-4.3.4/src/ztee.1.html000066400000000000000000000117431501046211500152550ustar00rootroot00000000000000 ztee(1) - output buffer and splitter
  1. ztee(1)
  2. ztee
  3. ztee(1)

NAME

ztee - output buffer and splitter

SYNOPSIS

ztee [ OPTIONS... ] [ FILE... ]

DESCRIPTION

ZTee is an output buffer and splitter for use with ZMap output data. ZTee should be used whenever ZMap is piped into an application scanner, placed between ZMap and the application scanner. ZTee writes the transformed output to stdout, and writes the original output to FILE.

See --help for examples.

CSV PROCESSING AND RAW MODE

ZTee operates by default on CSV-format output from ZMap. It only outputs IP addresses (from the input's ip or saddr field) to stdout, while writing all input to the output file. ZTee does not print the first line of input to stdout, since that row is the CSV header.

To operate on data in any other format, pass the --raw flag. In raw mode, ztee behaves like tee: it will not transform or attempt to parse the input data.

OPTIONS

BASIC OPTIONS

-r, --raw

Ignore input formatting and pass through raw input. This causes ztee to behave exactly like tee, with the addition of buffering.

--success-only

Only write to stdout rows where success=1 or success=true. Invalid in combination with --raw.

-m, --monitor

Print monitor data to stderr

-u, --status-updates-file

Write status updates (monitor data) to the given file, in CSV format

-l, --log-file=name

Write errors etc. to the given file. If none, ZTee logs to stderr.

ADDITIONAL OPTIONS

-h, --help

Display help

-V, --version

Display version

  1. ZMap
  2. November 2023
  3. ztee(1)
zmap-4.3.4/src/ztee.1.ronn000066400000000000000000000030771501046211500152660ustar00rootroot00000000000000ztee(1) - output buffer and splitter ==================================== ## SYNOPSIS ztee [ OPTIONS... ] [ FILE... ] ## DESCRIPTION *ZTee* is an output buffer and splitter for use with ZMap output data. ZTee should be used whenever ZMap is piped into an application scanner, placed between ZMap and the application scanner. ZTee writes the transformed output to stdout, and writes the original output to FILE. See `--help` for examples. ## CSV PROCESSING AND RAW MODE *ZTee* operates by default on CSV-format output from ZMap. It only outputs IP addresses (from the input's `ip` or `saddr` field) to stdout, while writing all input to the output file. ZTee does not print the first line of input to stdout, since that row is the CSV header. To operate on data in any other format, pass the `--raw` flag. In raw mode, ztee behaves like tee: it will not transform or attempt to parse the input data. ## OPTIONS ### BASIC OPTIONS ### * `-r`, `--raw`: Ignore input formatting and pass through raw input. This causes ztee to behave exactly like tee, with the addition of buffering. * `--success-only`: Only write to stdout rows where success=1 or success=true. Invalid in combination with `--raw`. * `-m`, `--monitor`: Print monitor data to stderr * `-u`, `--status-updates-file`: Write status updates (monitor data) to the given file, in CSV format * `-l`, `--log-file=name`: Write errors etc. to the given file. If none, ZTee logs to stderr. ### ADDITIONAL OPTIONS ### * `-h, --help`: Display help * `-V, --version`: Display version zmap-4.3.4/src/ztee.c000066400000000000000000000323131501046211500143700ustar00rootroot00000000000000/* * ZTee Copyright 2014 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ // without defining this, FreeBSD throws a warning. #define _WITH_GETLINE #include #include #include #include #include #include #include #include #include #include "../lib/lockfd.h" #include "../lib/logger.h" #include "../lib/queue.h" #include "../lib/util.h" #include "../lib/xalloc.h" #include "../lib/csv.h" #include "topt.h" typedef enum file_format { FORMAT_CSV, FORMAT_JSON, FORMAT_RAW } format_t; static const char *format_names[] = {"csv", "json", "raw"}; typedef struct ztee_conf { // Files char *output_filename; char *status_updates_filename; char *log_file_name; FILE *output_file; FILE *status_updates_file; FILE *log_file; // Log level int log_level; // Input formats format_t in_format; format_t out_format; // Output config int success_only; // Monitor config int monitor; // Field indices size_t ip_field; size_t success_field; } ztee_conf_t; static ztee_conf_t tconf; static int print_from_csv(char *line); static format_t test_input_format(char *line, size_t len) { // Check for empty input, remember line contains '\n' if (len < 2) { return FORMAT_RAW; } if (len >= 3) { // If the input is JSON, the line should look like // {.......}\n if (line[0] == '{' && line[len - 2] == '}') { return FORMAT_JSON; } } if (strchr(line, ',') != NULL) { return FORMAT_CSV; } return FORMAT_RAW; } int done = 0; int process_done = 0; int total_read_in = 0; int read_in_last_sec = 0; int total_written = 0; double start_time; pthread_t threads[3]; // one thread reads in // one thread writes out and parses // pops next element and determines what to do // if zqueue_t is empty and read_in is finished, then // it exits void *process_queue(void *my_q); // uses fgets to read from stdin and add it to the zqueue_t void *read_in(void *my_q); // does the same as find UP but finds only successful IPs, determined by the // is_successful field and flag void find_successful_IP(char *my_string); // finds IP in the string of csv and sends it to stdout for zgrab // you need to know what position is the csv string the ip field is in // zero indexed void find_IP(char *my_string); // writes a csv string out to csv file // fprintf(stderr, "Is empty inside if %i\n", is_empty(queue)); void write_out_to_file(char *data); // figure out how many fields are present if it is a csv void figure_out_fields(char *data); // check that the output file is either in a csv form or json form // throws error is it is not either // NOTE: JSON OUTPUT NOT IMPLEMENTED void output_file_is_csv(void); void print_thread_error(char *string); // monitor code for ztee // executes every second void *monitor_ztee(void *my_q); #define SET_IF_GIVEN(DST, ARG) \ { \ if (args.ARG##_given) { \ (DST) = args.ARG##_arg; \ }; \ } #define SET_BOOL(DST, ARG) \ { \ if (args.ARG##_given) { \ (DST) = 1; \ }; \ } int main(int argc, char *argv[]) { struct gengetopt_args_info args; struct cmdline_parser_params *params; params = cmdline_parser_params_create(); assert(params); params->initialize = 1; params->override = 0; params->check_required = 0; if (cmdline_parser_ext(argc, argv, &args, params) != 0) { exit(EXIT_SUCCESS); } signal(SIGPIPE, SIG_IGN); // Handle help text and version if (args.help_given) { cmdline_parser_print_help(); exit(EXIT_SUCCESS); } if (args.version_given) { cmdline_parser_print_version(); exit(EXIT_SUCCESS); } // Try opening the log file tconf.log_level = ZLOG_WARN; if (args.log_file_given) { tconf.log_file = fopen(args.log_file_arg, "w"); } else { tconf.log_file = stderr; } // Check for an error opening the log file if (tconf.log_file == NULL) { log_init(stderr, tconf.log_level, 0, "ztee"); log_fatal("ztee", "Could not open log file"); } // Actually init the logging infrastructure log_init(tconf.log_file, tconf.log_level, 0, "ztee"); // Check for an output file if (args.inputs_num < 1) { log_fatal("ztee", "No output file specified"); } if (args.inputs_num > 1) { log_fatal("ztee", "Extra positional arguments starting with %s", args.inputs[1]); } tconf.output_filename = args.inputs[0]; tconf.output_file = fopen(tconf.output_filename, "w"); if (!tconf.output_file) { log_fatal("ztee", "Could not open output file %s, %s", tconf.output_filename, strerror(errno)); } // Read actual options int raw = 0; SET_BOOL(tconf.success_only, success_only); SET_BOOL(tconf.monitor, monitor); SET_BOOL(raw, raw); // Open the status update file if necessary if (args.status_updates_file_given) { // Try to open the status output file char *filename = args.status_updates_file_arg; FILE *file = fopen(filename, "w"); if (!file) { char *err = strerror(errno); log_fatal("ztee", "unable to open status updates file %s (%s)", filename, err); } // Set the variables in state tconf.status_updates_filename = filename; tconf.status_updates_file = file; } // Read the first line of the input file size_t first_line_len = 1024; char *first_line = xmalloc(first_line_len); if (getline(&first_line, &first_line_len, stdin) < 0) { log_fatal("ztee", "reading input to test format failed"); } // Detect the input format if (!raw) { format_t format = test_input_format(first_line, first_line_len); log_info("ztee", "detected input format %s", format_names[format]); tconf.in_format = format; } else { tconf.in_format = FORMAT_RAW; log_info("ztee", "raw input"); } if (tconf.in_format == FORMAT_JSON) { log_fatal("ztee", "json input not implemented"); } // Find fields if needed char *header = strdup(first_line); int found_success = 0; int found_ip = 0; if (tconf.in_format == FORMAT_CSV) { static const char *success_names[] = {"success"}; static const char *ip_names[] = {"saddr", "ip"}; int success_idx = csv_find_index(header, success_names, 1); if (success_idx >= 0) { found_success = 1; tconf.success_field = (size_t)success_idx; } int ip_idx = csv_find_index(header, ip_names, 2); if (found_ip >= 0) { found_ip = 1; tconf.ip_field = (size_t)ip_idx; } if (!found_ip) { log_fatal("ztee", "Unable to find IP/SADDR field"); } } if (tconf.success_only) { if (tconf.in_format != FORMAT_CSV) { log_fatal("ztee", "success filter requires csv input"); } if (!found_success) { log_fatal("ztee", "Could not find success field"); } } // Make the queue zqueue_t *queue = queue_init(); assert(queue); // Add the first line to the queue if needed push_back(first_line, queue); // Start the regular read thread pthread_t read_thread; if (pthread_create(&read_thread, NULL, read_in, queue)) { log_fatal("ztee", "unable to start read thread"); } // Record the start time start_time = now(); // Start the process thread pthread_t process_thread; if (pthread_create(&process_thread, NULL, process_queue, queue)) { log_fatal("ztee", "unable to start process thread"); } // Start the monitor thread if necessary, and join to it if (tconf.monitor || tconf.status_updates_file) { pthread_t monitor_thread; if (pthread_create(&monitor_thread, NULL, monitor_ztee, queue)) { log_fatal("ztee", "unable to create monitor thread"); } pthread_join(monitor_thread, NULL); } // Join to the remaining threads, pthread_join(read_thread, NULL); pthread_join(process_thread, NULL); return 0; } void *process_queue(void *arg) { zqueue_t *queue = arg; FILE *output_file = tconf.output_file; while (!process_done) { pthread_mutex_lock(&queue->lock); while (!done && is_empty(queue)) { pthread_cond_wait(&queue->empty, &queue->lock); } if (done && is_empty(queue)) { process_done = 1; pthread_mutex_unlock(&queue->lock); continue; } znode_t *node = pop_front_unsafe(queue); pthread_mutex_unlock(&queue->lock); // Write raw data to output file fprintf(output_file, "%s", (char *)node->data); fflush(output_file); if (ferror(output_file)) { log_fatal("ztee", "Error writing to output file"); } // Dump to stdout switch (tconf.in_format) { case FORMAT_JSON: log_fatal("ztee", "JSON input format unimplemented"); break; case FORMAT_CSV: print_from_csv((char *)node->data); break; default: // Handle raw fprintf(stdout, "%s", (char *)node->data); break; } // Check to see if write failed fflush(stdout); if (ferror(stdout)) { log_fatal("ztee", "%s", "Error writing to stdout"); } // Record output lines total_written++; // Free the memory free(node->data); free(node); } process_done = 1; fflush(output_file); fclose(output_file); return NULL; } void *read_in(void *arg) { // Allocate buffers zqueue_t *queue = (zqueue_t *)arg; size_t length = 1000; char *input = xcalloc(sizeof(char), length); ; // Read in from stdin and add to back of linked list while (getline(&input, &length, stdin) > 0) { push_back((void *)strdup(input), queue); total_read_in++; read_in_last_sec++; } pthread_mutex_lock(&queue->lock); done = 1; pthread_cond_signal(&queue->empty); pthread_mutex_unlock(&queue->lock); return NULL; } int print_from_csv(char *line) { if (total_written == 0) { return 1; } if (tconf.success_only) { char *success_entry = csv_get_index(line, tconf.success_field); if (success_entry == NULL) { return 1; } int success = 0; if (atoi(success_entry)) { success = 1; } else if (strcasecmp(success_entry, "true") == 0) { success = 1; } if (!success) { return 1; } } // Find the ip char *ip = csv_get_index(line, tconf.ip_field); int ret = fprintf(stdout, "%s\n", ip); if (ferror(stdout)) { log_fatal("ztee", "unable to write to stdout"); } return ret; } void output_file_is_csv(void) { return; /* char *dot = strrchr(output_filename); if dot == NULL { return; } */ /* int length = strlen(output_filename); char *end_of_file = malloc(sizeof(char*) *4); strncpy(end_of_file, output_filename+(length - 3), 3); end_of_file[4] = '\0'; const char *csv = "csv\n"; const char *json = "jso\n"; if(!strncmp(end_of_file, csv, 3) && !strncmp(end_of_file, json, 3)){ log_fatal("ztee", "Invalid output format"); } if(!strncmp(end_of_file, csv, 3)) output_csv = 1; if(!strncmp(end_of_file, json, 3)) output_csv = 0; */ } void print_thread_error(char *string) { fprintf(stderr, "Could not create thread %s\n", string); return; } #define TIME_STR_LEN 20 typedef struct ztee_stats { // Read stats uint32_t total_read; uint32_t read_per_sec_avg; uint32_t read_last_sec; // Buffer stats uint32_t buffer_cur_size; uint32_t buffer_avg_size; uint64_t _buffer_size_sum; // Duration double _last_age; uint32_t time_past; char time_past_str[TIME_STR_LEN]; } stats_t; void update_stats(stats_t *stats, zqueue_t *queue) { double age = now() - start_time; double delta = age - stats->_last_age; stats->_last_age = age; stats->time_past = age; time_string((int)age, 0, stats->time_past_str, TIME_STR_LEN); uint32_t total_read = total_read_in; stats->read_last_sec = (total_read - stats->total_read) / delta; stats->total_read = total_read; stats->read_per_sec_avg = stats->total_read / age; stats->buffer_cur_size = get_size(queue); stats->_buffer_size_sum += stats->buffer_cur_size; stats->buffer_avg_size = stats->_buffer_size_sum / age; } void *monitor_ztee(void *arg) { zqueue_t *queue = (zqueue_t *)arg; stats_t *stats = xmalloc(sizeof(stats_t)); if (tconf.status_updates_file) { fprintf( tconf.status_updates_file, "time_past,total_read_in,read_in_last_sec,read_per_sec_avg," "buffer_current_size,buffer_avg_size\n"); fflush(tconf.status_updates_file); if (ferror(tconf.status_updates_file)) { log_fatal("ztee", "unable to write to status updates file"); } } while (!process_done) { sleep(1); update_stats(stats, queue); if (tconf.monitor) { lock_file(stderr); fprintf( stderr, "%5s read_rate: %u rows/s (avg %u rows/s), buffer_size: %u (avg %u)\n", stats->time_past_str, stats->read_last_sec, stats->read_per_sec_avg, stats->buffer_cur_size, stats->buffer_avg_size); fflush(stderr); unlock_file(stderr); if (ferror(stderr)) { log_fatal( "ztee", "unable to write status updates to stderr"); } } if (tconf.status_updates_file) { fprintf(tconf.status_updates_file, "%u,%u,%u,%u,%u,%u\n", stats->time_past, stats->total_read, stats->read_last_sec, stats->read_per_sec_avg, stats->buffer_cur_size, stats->buffer_avg_size); fflush(tconf.status_updates_file); if (ferror(tconf.status_updates_file)) { log_fatal( "ztee", "unable to write to status updates file"); } } } if (tconf.monitor) { lock_file(stderr); fflush(stderr); unlock_file(stderr); } if (tconf.status_updates_file) { fflush(tconf.status_updates_file); fclose(tconf.status_updates_file); } return NULL; } zmap-4.3.4/src/ztopt.ggo.in000066400000000000000000000011221501046211500155320ustar00rootroot00000000000000# ZTests Copyright 2014 Regents of the University of Michigan # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at http://www.apache.org/licenses/LICENSE-2.0 # ztests option description to be processed by gengetopt package "ztests" version "@ZMAP_VERSION@" purpose "A tests harness tool for zmap" section "Additional options" option "help" h "Print help and exit" optional option "version" V "Print version and exit" optional zmap-4.3.4/src/ztopt_compat.c000066400000000000000000000010621501046211500161410ustar00rootroot00000000000000/* * ZMap Copyright 2013 Regents of the University of Michigan * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #if __GNUC__ < 4 #error "gcc version >= 4 is required" #elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #elif __GNUC_MINOR__ >= 4 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif #include "ztopt.c" zmap-4.3.4/test/000077500000000000000000000000001501046211500134435ustar00rootroot00000000000000zmap-4.3.4/test/.gitignore000066400000000000000000000001071501046211500154310ustar00rootroot00000000000000*.*-t* *-t* tempfile outfile !.gitignore !integration-tests/ shardfile zmap-4.3.4/test/configs/000077500000000000000000000000001501046211500150735ustar00rootroot00000000000000zmap-4.3.4/test/configs/blocklist_shard.conf000066400000000000000000000021151501046211500211100ustar00rootroot00000000000000# From IANA IPv4 Special-Purpose Address Registry # http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml # Updated 2013-05-22 0.0.0.0/8 # RFC1122: "This host on this network" 10.0.0.0/8 # RFC1918: Private-Use 100.64.0.0/10 # RFC6598: Shared Address Space 127.0.0.0/8 # RFC1122: Loopback 169.254.0.0/16 # RFC3927: Link Local 172.16.0.0/12 # RFC1918: Private-Use 192.0.0.0/24 # RFC6890: IETF Protocol Assignments 192.0.2.0/24 # RFC5737: Documentation (TEST-NET-1) 192.88.99.0/24 # RFC3068: 6to4 Relay Anycast #192.168.0.0/16 # RFC1918: Private-Use 198.18.0.0/15 # RFC2544: Benchmarking 198.51.100.0/24 # RFC5737: Documentation (TEST-NET-2) 203.0.113.0/24 # RFC5737: Documentation (TEST-NET-3) 240.0.0.0/4 # RFC1112: Reserved 255.255.255.255/32 # RFC0919: Limited Broadcast # From IANA Multicast Address Space Registry # http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml # Updated 2013-06-25 224.0.0.0/4 # RFC5771: Multicast/Reserved zmap-4.3.4/test/integration-tests/000077500000000000000000000000001501046211500171265ustar00rootroot00000000000000zmap-4.3.4/test/integration-tests/test_dryrun_tcp.py000066400000000000000000000566121501046211500227420ustar00rootroot00000000000000import ipaddress import math import os import random import re import time import zmap_wrapper import utils def test_num_returned_ips_equals_requested(): """ scan a number of IPs and ensure the scanned result includes the correct number of unique IPs """ ip_reqs = [5, 65, 249] for num_of_ips in ip_reqs: t = zmap_wrapper.Wrapper(port=80, num_of_ips=num_of_ips) packet_list = t.run() assert len(packet_list) == num_of_ips dest_ip_set = set() for packet in packet_list: assert packet["tcp"]["dest"] == "80", "packets not sent to correct port" dest_ip_set.add(packet["ip"]["daddr"]) assert len(dest_ip_set) == num_of_ips, "incorrectly scanned IP multiple times" def test_num_returned_ips_equals_requested_with_threads(): """ scan a number of IPs with varying thread cts and ensure the scanned result includes the correct number of unique IPs """ # we'll try with different num_of_ips threads = [1, 2, 4, 5, 8, 34] num_of_ip_tests = [36, 1001] for thread in threads: for num_ips in num_of_ip_tests: t = zmap_wrapper.Wrapper(port=22, num_of_ips=num_ips, threads=thread) packet_list = t.run() assert len(packet_list) == num_ips for packet in packet_list: assert packet["tcp"]["dest"] == "22", "packets not sent to correct port" def test_multi_port_single_ip(): """ scan a single IP with multiple ports and ensure the scanned result includes the correct number of unique IPs and all expected ports are scanned """ port_tests = ["22", "22,80,443,8080", "22-32", "22-32,80,443-445,8080,10"] expected_output = [utils.parse_ports_string(port_test) for port_test in port_tests] for test_iter in range(10): # using iterations to check for bugs in shard code for port_test_index in range(len(port_tests)): packet_list = zmap_wrapper.Wrapper(port=port_tests[port_test_index], subnet="1.1.1.1", threads=1).run() # check that packet_list and expected_output are the same port_list = sorted([packet["tcp"]["dest"] for packet in packet_list]) assert sorted(port_list) == sorted(expected_output[port_test_index]), "didn't scan all the expected ports" def assert_expected_ips_and_ports_were_scanned(expected_ips, expected_port_set, packet_list): ip_to_port_set = {} for packet in packet_list: dst_ip = packet["ip"]["daddr"] dst_port = packet["tcp"]["dest"] if dst_ip not in ip_to_port_set: ip_to_port_set[dst_ip] = set() assert dst_port not in ip_to_port_set[dst_ip], "scanned port multiple times for the same IP" ip_to_port_set[dst_ip].add(dst_port) assert dst_ip in expected_ips, "scanned IP not in subnet" assert dst_port in expected_port_set, "scanned port not in expected ports" def test_multi_port_with_subnet(): """ scan a subnet with multiple ports and ensure the scanned result includes the correct number of unique IPs and all expected ports are scanned """ port_tests = ["22", "22,80,443,8080", "22-32", "22-32,80,443-445,8080,10"] subnet = "1.1.1.0/29" expected_ports = [utils.parse_ports_string(port_test) for port_test in port_tests] expected_ips = set(str(ip) for ip in ipaddress.ip_network(subnet)) for test_iter in range(10): # using iterations to check for bugs in shard code for port_test_index in range(len(port_tests)): expected_port_set = set(expected_ports[port_test_index]) # the ports expected to be scanned in this iter. packet_list = zmap_wrapper.Wrapper(port=port_tests[port_test_index], subnet=subnet, threads=1).run() assert len(packet_list) == len(expected_ips) * len(expected_ports[port_test_index]), ("incorrect number of " "packets sent") assert_expected_ips_and_ports_were_scanned(expected_ips, expected_port_set, packet_list) def test_multi_port_with_subnet_and_threads(): """ scan a subnet with multiple ports running on multiple threads and ensure the scanned result includes the correct number of unique IPs and all expected ports are scanned """ port_tests = ["22-32,80,443-445,8080,10"] subnet = "1.1.1.0/29" expected_ports = [utils.parse_ports_string(port_test) for port_test in port_tests] expected_ips = set(str(ip) for ip in ipaddress.ip_network(subnet)) for thread_ct in range(1, 8): for test_iter in range(5): # using iterations to check for bugs in shard code for port_test_index in range(len(port_tests)): expected_port_set = set(expected_ports[port_test_index]) packet_list = zmap_wrapper.Wrapper(port=port_tests[port_test_index], subnet=subnet, threads=thread_ct).run() assert len(packet_list) == len(expected_ips) * len(expected_ports[port_test_index]), ("incorrect " "number of " "packets sent") assert_expected_ips_and_ports_were_scanned(expected_ips, expected_port_set, packet_list) ## Shards def test_full_coverage_of_subnet_with_shards(): """ scan a subnet with varying shard counts and ensure the union of all scanned results includes the correct number of unique IPs """ shards_cts = [1, 4, 5, 8] subnet = "174.189.0.0/20" subnet_size = int(subnet.split("/")[1]) seed = 123 for shard_ct in shards_cts: ip_list = [] for shard in range(shard_ct): packets = zmap_wrapper.Wrapper(subnet=subnet, shard=shard, shards=shard_ct, seed=seed).run() even_split_search_space = math.pow(2, 32 - subnet_size) / shard_ct assert abs( # check that shards are splitting up the search space *relatively* evenly len(packets) - even_split_search_space) <= 100 for packet in packets: ip_list.append(packet["ip"]["daddr"]) assert_subnet_scanned_correctly(ip_list, subnet, subnet_size) def assert_subnet_scanned_correctly(ip_list, subnet, subnet_size): """ Asserts that the scanned IPs are unique, cover the subnet, and are not outside the subnet """ assert utils.check_uniqueness_ip_list(ip_list), "scanned target IP multiple times" assert not len(ip_list) > math.pow(2, 32 - subnet_size), "scanned IPs other than those in the subnet" assert not len(ip_list) < math.pow(2, 32 - subnet_size), "did not scan enough IPs to cover the subnet" assert utils.check_coverage_of_ip_list(ip_list, subnet), "the entirety of the subnet was not scanned" ## Subnet def test_full_coverage_of_subnets(): """ scan a number of subnets and ensure the scanned result fully scans the search space """ subnets = ["174.189.0.0/20", "65.189.78.0/24", "112.16.17.32/32"] for subnet in subnets: subnet_size = int(subnet.split("/")[1]) packets = zmap_wrapper.Wrapper(subnet=subnet, threads=1).run() even_split_search_space = math.pow(2, 32 - subnet_size) ip_list = [packet["ip"]["daddr"] for packet in packets] assert_subnet_scanned_correctly(ip_list, subnet, subnet_size) def test_full_coverage_of_large_subnets(): """ scan a large subnet and ensure the scanned result fully scans the search space """ subnets = ["1.0.0.0/15"] for subnet in subnets: subnet_size = int(subnet.split("/")[1]) packets = zmap_wrapper.Wrapper(subnet=subnet, threads=1).run() ip_list = [packet["ip"]["daddr"] for packet in packets] assert_subnet_scanned_correctly(ip_list, subnet, subnet_size) def test_multiple_subnets(): """ scan multiple subnets in one scan and ensure the scanned result fully scans the search space """ subnets = ["174.189.0.0/24", "23.45.67.76/30"] expected_num_ips = math.pow(2, 32 - 24) + math.pow(2, 32 - 30) packets = zmap_wrapper.Wrapper(subnet=" ".join(subnets)).run() assert len(packets) == expected_num_ips ip_list = [packet["ip"]["daddr"] for packet in packets] for subnet in subnets: assert utils.check_coverage_of_ip_list(ip_list, subnet), "the entirety of the subnet was not scanned" def test_multiple_ips(): """ scan multiple IPs in one scan and ensure the scanned result fully scans the search space """ ips = ["174.189.78.3", "1.1.1.1", "8.8.8.8"] expected_num_ips = len(ips) packets = zmap_wrapper.Wrapper(subnet=" ".join(ips), threads=1).run() assert len(packets) == expected_num_ips ip_list = [packet["ip"]["daddr"] for packet in packets] for ip in ips: assert ip in ip_list, "an IP was not scanned" def test_multiple_ips_and_subnets(): """ scan multiple IPs and subnets in one scan and ensure the scanned result fully scans the search space """ ips = ["174.189.78.3", "1.1.1.1", "8.8.8.8"] subnets = ["174.189.0.0/28", "23.45.67.76/30"] ips_and_subnets = ips + subnets # 3 IPs and 2 subnets, 16 and 4 IPs, respectively expected_num_ips = 3 + math.pow(2, 32 - 28) + math.pow(2, 32 - 30) packets = zmap_wrapper.Wrapper(subnet=" ".join(ips_and_subnets), threads=1).run() assert len(packets) == expected_num_ips for packet in packets: # ensure proper fields are present assert packet.get("tcp") assert packet.get("ip") assert packet.get("eth") ip_list = [packet["ip"]["daddr"] for packet in packets] for ip in ips: assert ip in ip_list, "an IP was not scanned" for subnet in subnets: assert utils.check_coverage_of_ip_list(ip_list, subnet), "the entirety of the subnet was not scanned" ## Seed def test_same_seed(): """ scan the same subnet twice with the same seed and check that the same IPs are scanned in the same order """ subnet = "174.189.0.0/28" seed = 123 # must use a single thread to have deterministic results packets1 = zmap_wrapper.Wrapper(subnet=subnet, seed=seed, threads=1).run() packets2 = zmap_wrapper.Wrapper(subnet=subnet, seed=seed, threads=1).run() assert len(packets1) == len(packets2) for i in range(len(packets1)): assert packets1[i]["ip"]["daddr"] == packets2[i]["ip"]["daddr"], "scanned IPs in different order with same seed" def test_different_seeds(): """ scan the same subnet twice with different seeds and check that the IPs are scanned in a different order """ subnet = "174.189.0.0/28" seed1 = 123 seed2 = 987 # must use a single thread to have deterministic results packets1 = zmap_wrapper.Wrapper(subnet=subnet, seed=seed1, threads=1).run() packets2 = zmap_wrapper.Wrapper(subnet=subnet, seed=seed2, threads=1).run() assert len(packets1) == len(packets2) are_packets_in_same_order = True for i in range(len(packets1)): if packets1[i]["ip"]["daddr"] != packets2[i]["ip"]["daddr"]: are_packets_in_same_order = False break assert not are_packets_in_same_order, "scanned IPs in same order with different seeds" """ --rate and --max-runtime """ def test_rate_limit(): """ scan with a rate limit and ensure the rate is respected """ start_time = time.time() # scan 1k packets with a rate of 1k. The scan should stop after ~1 seconds # uses bounded_runtime_test to ensure the test doesn't run indefinitely should anything go wrong expected_runtime = 1 utils.bounded_runtime_test(zmap_wrapper.Wrapper(threads=1, rate=1000, num_of_ips=1000)) assert time.time() - start_time < expected_runtime + 0.5, "max_runtime was not respected" # add small amt. buffer def test_max_runtime(): """ scan with a max runtime and ensure the scan stops after the correct amount of time """ start_time = time.time() # scan full IPv4 space with a max runtime of 2 seconds. The scan should stop after 2 seconds # uses bounded_runtime_test to ensure the test doesn't run indefinitely should anything go wrong max_runtime = 1 utils.bounded_runtime_test(zmap_wrapper.Wrapper(threads=1, max_runtime=max_runtime)) assert time.time() - start_time < max_runtime + 0.5, "max_runtime was not respected" # add small amt. buffer def test_max_runtime_and_rate(): """ scan with a max runtime and a rate limit and ensure the scan stops after the correct amount of time AND the rate is respected """ start_time = time.time() # scan full IPv4 space with a max runtime of 1 seconds and a rate of 1000. The scan should stop after 1 seconds # uses bounded_runtime_test to ensure the test doesn't run indefinitely should anything go wrong expected_runtime = 1 + 0.5 packets = utils.bounded_runtime_test(zmap_wrapper.Wrapper(threads=1, max_runtime=1, rate=1000)) assert time.time() - start_time < expected_runtime, "scan did not stop after ~1 seconds" assert len(packets) > 0, "no packets were sent" assert len(packets) < 1100, "rate was not respected" # add small buffer """ --source-port and --source-ip """ def test_source_port_option(): """ scan using various single and multiple source ports and ensure the correct source ports are used """ source_port_tests = [ "80", # single port "22-24", # multiple ports ] for source_port in source_port_tests: packets = zmap_wrapper.Wrapper(threads=1, source_port=source_port, num_of_ips=500).run() expected_ports_to_packets_sent = {} if "-" not in source_port: # using a single source port expected_ports_to_packets_sent[source_port] = 0 else: # using a source port range expected_ports = utils.enumerate_port_range(source_port) for port in expected_ports: expected_ports_to_packets_sent[port] = 0 for packet in packets: assert packet.get("tcp") assert packet["tcp"]["source"] in expected_ports_to_packets_sent, "incorrect source port used" expected_ports_to_packets_sent[packet["tcp"]["source"]] += 1 # check that all source ports used at least once for port, uses in expected_ports_to_packets_sent.items(): assert uses > 0, "source port {} not used".format(port) def test_source_ip_option(): """ scan using various source IP(s) and ensure the correct source IP(s) are used """ source_ip_tests = [ "134.23.98.23", # single IP "189.23.45.32-189.23.45.34", # range ] for source_ip in source_ip_tests: packets = zmap_wrapper.Wrapper(threads=1, source_ip=source_ip, num_of_ips=1000).run() expected_ips_to_packets_sent = {} if "-" not in source_ip: # using a single source IP expected_ips_to_packets_sent[source_ip] = 0 else: # using a source IP range expected_ips = utils.enumerate_IP_range(source_ip) for ip in expected_ips: expected_ips_to_packets_sent[ip] = 0 for packet in packets: assert packet.get("ip") # check if source_ip is a single IP or a subnet assert packet["ip"]["saddr"] in expected_ips_to_packets_sent, "incorrect source IP used" expected_ips_to_packets_sent[packet["ip"]["saddr"]] += 1 # check that all source ips used at least once for ip, uses in expected_ips_to_packets_sent.items(): assert uses > 0, "source IP {} not used".format(ip) def test_source_mac_option(): """ scan using various source MACs and ensure the correct source MACs are used """ subnet = "45.23.128.0/30" source_mac_tests = ["00:00:00:00:00:00", "ff:ff:ff:ff:ff:ff", "01:23:45:67:89:ab"] for source_mac in source_mac_tests: packets = zmap_wrapper.Wrapper(threads=1, source_mac=source_mac, subnet=subnet).run() for packet in packets: assert packet.get("eth") assert packet["eth"]["shost"] == source_mac, "incorrect source MAC used" """ --probes """ def probes_helper(probes: int, subnet: str): """ helper that takes in a number of probes and a subnet and ensures the correct number of packets are sent to that subnet """ packets = zmap_wrapper.Wrapper(subnet=subnet, threads=1, probes=str(probes)).run() if probes == 0: assert len(packets) == 0, "packets were sent when no probes were specified" return # no need to check anything else # count how many packets were sent to each IP ip_to_num_packets = {} for packet in packets: ip = packet["ip"]["daddr"] if ip in ip_to_num_packets: ip_to_num_packets[ip] += 1 else: ip_to_num_packets[ip] = 1 for expected_ip in ipaddress.ip_network(subnet): assert ip_to_num_packets[str(expected_ip)], "IP not scanned" assert ip_to_num_packets[str(expected_ip)] == probes, "incorrect number of packets sent" def test_probes_option(): """ scan using various numbers of probes and ensure the correct number of packets are sent """ probe_tests = [0, 1, 2, 3, 4, 8, 13, 21] subnets = [ "178.1.128.0/28", "45.23.128.0/30", "69.2.1.0/27" ] for subnet_test in subnets: for probe_test in probe_tests: probes_helper(probe_test, subnet_test) """ --list-of-ips """ def test_list_of_ips_option(): """ scan using a list of IPs and ensure the correct IPs are scanned """ ips = utils.write_ips_to_file(1000, "ips.txt") packets = zmap_wrapper.Wrapper(threads=2, list_of_ips_file="ips.txt").run() actual_packet_ips = list(packet["ip"]["daddr"] for packet in packets) assert sorted(actual_packet_ips) == sorted(ips), "scanned IPs not in the list of IPs" # cleanup os.remove("ips.txt") """ ---allowlist-file """ allowed_subnets = [ "178.1.1.0/30", "173.31.16.0/31", "103.0.113.0/32" ] def test_allowlist(): """ scan using an allowlist and ensure only IPs in the allowlist are scanned """ with open("allowlist.txt", "w") as file: for subnet in allowed_subnets: file.write(subnet + "\n") expected_ips = set(str(ip) for subnet in allowed_subnets for ip in ipaddress.ip_network(subnet)) packets = zmap_wrapper.Wrapper(threads=1, allowlist_file="allowlist.txt").run() actual_packet_ips = set(packet["ip"]["daddr"] for packet in packets) assert actual_packet_ips == expected_ips, "scanned IPs not in the allowlist" # cleanup os.remove("allowlist.txt") def test_allowlist_with_subnet(): """ Per the code: "allowlist: both a allowlist file and destination addresses were specified. The union of these two sources will be utilized." Test will ensure that both the allowlist file and the subnet are used to scan the correct IPs """ scanning_subnet = "34.1.128.0/21" with open("allowlist.txt", "w") as file: for subnet in allowed_subnets: file.write(subnet + "\n") expected_ips = set(str(ip) for subnet in allowed_subnets for ip in ipaddress.ip_network(subnet)) # append the IPs in the scanning subnet to the expected IPs expected_ips = expected_ips.union(set(str(ip) for ip in ipaddress.ip_network(scanning_subnet))) packets = zmap_wrapper.Wrapper(threads=1, allowlist_file="allowlist.txt", subnet=scanning_subnet).run() actual_packet_ips = set(packet["ip"]["daddr"] for packet in packets) assert actual_packet_ips == expected_ips, "scanned IPs not in the allowlist" # cleanup os.remove("allowlist.txt") """ --blocklist-file """ def blocklist_helper(blocklist_subnet_str: str, scanned_subnet_str: str): """ helper that takes in a blocklist subnet and a scanned subnet and ensures only IPs not in the blocklist are scanned """ blocklist_subnet = ipaddress.ip_network(blocklist_subnet_str) scanned_subnet = ipaddress.ip_network(scanned_subnet_str) blocklist_ips = set(str(ip) for ip in blocklist_subnet) all_ips = set(str(ip) for ip in scanned_subnet) unblocked_ips = all_ips - blocklist_ips with open("blocklist.txt", "w") as file: file.write(blocklist_subnet_str) packets = zmap_wrapper.Wrapper(subnet=scanned_subnet_str, threads=1, blocklist_file="blocklist.txt").run() actual_packet_ips = {packet["ip"]["daddr"] for packet in packets} for ip in blocklist_ips: assert ip not in actual_packet_ips, "blocked IP was scanned" for ip in unblocked_ips: assert ip in actual_packet_ips, "unblocked IP was not scanned" os.remove("blocklist.txt") def test_blocklist_partially_covers_subnet(): """ scan a subnet partially covered by a blocklist and ensure only IPs not in the blocklist are scanned """ tests = [ ("1.1.1.128/26", "1.1.1.0/24"), ("100.64.0.0/26", "100.64.0.0/24"), ("172.31.16.0/28", "172.31.16.0/26"), ("203.0.113.128/27", "203.0.113.0/24"), ("198.51.100.16/29", "198.51.100.0/25") ] for blocklist_subnet_str, scanned_subnet_str in tests: blocklist_helper(blocklist_subnet_str, scanned_subnet_str) def test_blocklist_does_not_cover_subnet(): """ scan a subnet not covered by a blocklist and ensure all IPs are scanned """ tests = [ ("10.0.0.0/24", "10.0.1.0/24"), ("192.0.2.0/24", "192.0.3.0/24"), ("172.16.0.0/24", "172.16.1.0/24"), ("203.0.113.0/24", "203.0.114.0/24"), ("198.51.100.0/24", "198.51.101.0/24") ] for blocklist_subnet_str, scanned_subnet_str in tests: blocklist_helper(blocklist_subnet_str, scanned_subnet_str) def test_blocklist_fully_covers_subnet(): """ scan a subnet fully covered by a blocklist and ensure no IPs are scanned """ blocklist_helper("10.0.0.0/24", "10.0.0.0/24") ## --iplayer def test_ip_layer_option(): ips = ["174.189.78.3", "1.1.1.1", "8.8.8.8", "175.189.78.0/28", "176.145.2.0/30"] # 3 IPs and 2 subnets, 16 and 4 IPs, respectively expected_num_ips = 3 + math.pow(2, 32 - 28) + math.pow(2, 32 - 30) expected_scanned_ips = set(ips[:3] + [str(ip) for subnet in ips[3:] for ip in ipaddress.ip_network(subnet)]) packets = zmap_wrapper.Wrapper(subnet=" ".join(ips), threads=1, iplayer=True).run() assert len(packets) == expected_num_ips for packet in packets: # ensure proper fields are present assert packet["ip"] assert packet["tcp"] assert not packet.get("eth") ip_list = [packet["ip"]["daddr"] for packet in packets] for actual_ip in ip_list: assert actual_ip in expected_scanned_ips, "an IP was not scanned" ## --max-targets def test_max_targets_option(): """ scan using various numbers of max targets and ensure the correct number of packets are sent """ tests = [ # Format: (max_targets, ports, expected_num_ips) ("5", "80", 5), ("109", "80", 109), ("10", "80-81", 10), # target is IP + port, so specifying multiple ports should not affect the number of IPs ("0.0001%", "80", 4294), # 0.0001% of the IPv4 space, rounded down ("0.0001%", "80-81", 8589) # 0.0001% of the IPv4 space over 2 ports, rounded down ] for max_targets, ports, expected_num_ips in tests: packets = zmap_wrapper.Wrapper(threads=1, max_targets=max_targets, port=ports).run() assert len( packets) == expected_num_ips, "incorrect number of packets sent for test with max_targets = " + max_targets + " and ports = " + ports zmap-4.3.4/test/integration-tests/test_full_ipv4_multi_port_scan.py000066400000000000000000000311441501046211500257300ustar00rootroot00000000000000from bitarray import bitarray from ipaddress import IPv4Address, IPv4Network import os import struct import subprocess import sys import unittest IPV4_SPACE = 2**32 # Total number of IPv4 addresses MAX_ERRORS = 10 # Number of errors before early exit, -1 to disable TOP_LEVEL_DIR = "../../" # TOP_LEVEL_DIR = "/Users/phillip/zmap-dev/zmap/" # Uncomment and set if running locally BLOCKLIST_FILE = "conf/blocklist.conf" ZMAP_ABS_PATH = "src/zmap" WARNING_COLOR = '\033[93m' BLOCKLISTED = -1 DUPLICATE = -2 SUCCESS = 1 def load_blocklist(file_path): """ Load blocklist CIDR ranges from a file. Args: file_path (str): Path to the blocklist file. Returns: blocklist: List of IPv4Network objects representing the blocklist ranges. """ blocklist = [] try: with open(file_path, "r") as file: for line in file: # Ignore comments and empty lines line = line.split("#")[0].strip() if line: blocklist.append(IPv4Network(line)) except Exception as e: print(f"Error loading blocklist: {e}") return blocklist def is_blocklisted(ip:int, blocklist_bitmap): """ Check if an IP address is in the blocklist Args: ip (int): IP address to check blocklist_bitmap (bitarray): Bitmap of blocklisted IPs 1 = blocklisted, 0 = not blocklisted Returns: bool: True if the IP is blocklisted, False otherwise """ return blocklist_bitmap[ip] def create_bitmap(ports): """Create a bitmap for all IPs and each port Args: ports (list[int]): List of ports to create bitmaps for Returns: dict: Dictionary of bitmaps, keyed by port """ bitmap_by_port = {} for port in ports: bitmap_by_port[port] = bitarray(IPV4_SPACE) return bitmap_by_port def create_blocklist_bitmap(blocklist): """Create a bitmap for all blocklisted IPs Args: blocklist (list[IPv4Network]): List of blocklisted networks Returns: bitarray: Bitmap of blocklisted IPs 1 = blocklisted, 0 = not blocklisted """ bitmap = bitarray(IPV4_SPACE) for net in blocklist: number_ips = net.num_addresses start_ip = int(net.network_address) bitmap[start_ip:start_ip + number_ips] = True # efficient bulk set # print(f"DEBUG: blocklist net: {net} with size {net.num_addresses}") return bitmap def validate_bitmap(bitmap, ports, blocked_bitmap:bitarray, subnet:str=None): """Validate that all non-blocklisted IPs are scanned Args: bitmap (dict[int]bitarray): Dictionary of bitarrays, keyed by port ports (list[int]): List of ports to validate blocked_bitmap (bitarray): Bitmap of blocklisted IPs 1 = blocklisted, 0 = not blocklisted subnet (str): Optional subnet to validate against. Used if we only scan a subset of the IPv4 space Returns: list[str]: List of errors encountered during validation, capped at MAX_ERRORS """ expected_ips = ~blocked_bitmap if subnet: # a subset of the IPv4 space was scanned, so we need to adjust the expected IPs subnet = IPv4Network(subnet) start_ip = int(subnet.network_address) number_ips = subnet.num_addresses expected_ips[0:start_ip] = False expected_ips[start_ip + number_ips:len(expected_ips)] = False errors = [] for port in ports: difference_bitmap = bitmap[port] & ~expected_ips for diff_i in difference_bitmap.search(bitarray('1')): # Find the first unexpected + scanned IP ip_str = str(IPv4Address(diff_i)) err_str = f"{ip_str}:{port} was blocked and scanned" print(err_str) errors.append(err_str) if MAX_ERRORS != -1 and len(errors) >= MAX_ERRORS: # early exit optimization return errors difference_bitmap = ~(bitmap[port] | ~expected_ips) # equiv. to expected and not scanned for diff_i in difference_bitmap.search(bitarray('1')): # Find the first unscanned IP ip_str = str(IPv4Address(diff_i)) err_str = f"{ip_str}:{port} was not blocked and not scanned" print(err_str) errors.append(err_str) if MAX_ERRORS != -1 and len(errors) >= MAX_ERRORS: # early exit optimization return errors return errors class TestBitmapValidation(unittest.TestCase): """ Unit tests for validate_bitmap function """ def setUp(self, ports=None): if ports is None: self.ports = [80, 81] else: self.ports = ports self.bitmap = create_bitmap(self.ports) self.blocklist_bitmap = bitarray(IPV4_SPACE) self.blocklist_bitmap.setall(False) def test_validate_bitmap(self): with self.subTest("Negative Test Case - Scanned IP/Port out of subnet"): self.setUp([80]) ip = int(IPv4Address("2.2.2.2")) self.bitmap[80].setall(False) self.bitmap[80][ip] = True self.bitmap[80][ip + 1] = True # out of subnet self.bitmap[80][ip - 1] = True # out of subnet errors = validate_bitmap(self.bitmap, self.ports, self.blocklist_bitmap, "2.2.2.2/32") self.assertEqual(len(errors), 2) with self.subTest("Negative Test Case - Didn't scan subnet"): self.setUp([80]) ip = int(IPv4Address("2.2.2.2")) self.bitmap[80].setall(False) self.bitmap[80][ip - 1] = True # out of subnet errors = validate_bitmap(self.bitmap, self.ports, self.blocklist_bitmap, "2.2.2.2/32") self.assertEqual(len(errors), 2) with self.subTest("Negative Test Case - Scanned IP/Port that is blocked"): self.setUp() ip = int(IPv4Address("2.2.2.2")) self.bitmap[80].setall(True) self.bitmap[81].setall(True) self.blocklist_bitmap[ip] = True errors = validate_bitmap(self.bitmap, self.ports, self.blocklist_bitmap) self.assertGreater(len(errors), 0) self.assertIn("2.2.2.2:80 was blocked and scanned", errors) self.assertIn("2.2.2.2:81 was blocked and scanned", errors) with self.subTest("Negative Test Case - Not-scanned IP/Port that isn't blocked"): self.setUp() self.bitmap[80].setall(True) self.bitmap[81].setall(True) self.blocklist_bitmap.setall(False) ip = int(IPv4Address("3.3.3.3")) self.bitmap[80][ip] = False self.bitmap[81][ip] = False errors = validate_bitmap(self.bitmap, self.ports, self.blocklist_bitmap) self.assertGreater(len(errors), 0) self.assertIn("3.3.3.3:80 was not blocked and not scanned", errors) self.assertIn("3.3.3.3:81 was not blocked and not scanned", errors) with self.subTest("Postive Test Case"): self.setUp() self.bitmap[80].setall(True) self.bitmap[81].setall(True) self.blocklist_bitmap.setall(False) errors = validate_bitmap(self.bitmap, self.ports, self.blocklist_bitmap) self.assertEqual(len(errors), 0) with self.subTest("Postive Test Case - Subnet"): ip = int(IPv4Address("4.4.4.4")) self.setUp([80]) self.blocklist_bitmap.setall(False) self.bitmap[80][ip] = True errors = validate_bitmap(self.bitmap, self.ports, self.blocklist_bitmap, "4.4.4.4/32") self.assertEqual(len(errors), 0) def run_test(scanner_command, ports, subnet=None): """ Runs an integration test for ZMap, using the provided scanner command and ports to scan. Starts a sub-process to run ZMap, pipes it's stderr to the test's stdout so we can see progress in logs. Reads stdout of ZMap to get the scanned IPs and ports and uses a per-port bitmap of the IPv4 address space to validate that each IP is scanned and scanned exactly once. Args: scanner_command (list[str]): ZMap scanner command to run ports (list[int]): List of ports to scan subnet (str): Optional subnet to scan ex. 1.1.1.0/24 """ blocklist = load_blocklist(TOP_LEVEL_DIR + BLOCKLIST_FILE) blocklist_bitmap = create_blocklist_bitmap(blocklist) print("DEBUG: blocklist loaded and bitmap created") bitmap = create_bitmap(ports) errors = [] try: process = subprocess.Popen( scanner_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1024 * 1024 * 6, # 6MB buffer ) except Exception as e: print(f"Error during starting ZMap. You may need to set your top-level directory to the correct path: {e}") return try: # Process stderr in real time and print it to sys.stdout so we can see ZMap progress in logs def stream_stderr(proc_stderr): for line in proc_stderr: sys.stdout.write(str(line) + "\n") # Directly forward stderr to stdout in real time import threading stderr_thread = threading.Thread(target=stream_stderr, args=(process.stderr,)) stderr_thread.start() size_of_struct = 6 # 4 bytes for IP, 2 bytes for port format_str = "!IH" # network byte order, unsigned int, unsigned short chunk = bytearray(size_of_struct * 256) while True: chunk = process.stdout.read(size_of_struct * 256) if not chunk: break # End of output for ip, port in struct.iter_unpack(format_str, chunk): if port not in ports: print(f"{WARNING_COLOR}Unexpected port ({port}) with IP ({IPv4Address(ip)})") errors.append(f"Unexpected port ({port}) with IP ({IPv4Address(ip)})") continue if bitmap[port][ip]: print(f"{WARNING_COLOR}Error: {IPv4Address(ip)},{port} scanned more than once") errors.append(f"Error: {IPv4Address(ip)},{port} scanned more than once") os._exit(1) bitmap[port][ip] = True if MAX_ERRORS != -1 and len(errors) >= MAX_ERRORS: break process.stdout.close() process.wait() stderr_thread.join() # Ensure stderr thread finishes except Exception as e: print(f"Error during execution: {e} + {e.with_traceback()}") return if len(errors) != 0: print(f"ERROR: execution completed with {len(errors)} errors") os._exit(1) print(f"DEBUG: execution completed with no errors, proceeding to bitmap validation") for error in validate_bitmap(bitmap, ports, blocklist_bitmap, subnet): print(f"Bitmap Validation Error: {error}") errors.append(error) # Final validation/summary if len(errors) == 0: print(f"Integration test passed successfully: {scanner_command}") return print(f"{len(errors)} Errors encountered during scan:\n") for error in errors: print(f"During-Scan Error: {error}") os._exit(1) if __name__ == "__main__": base_scanner_cmd = [ TOP_LEVEL_DIR + ZMAP_ABS_PATH, "--seed", "2", "-B", "200G", "--fast-dryrun", "-c", "0", "--batch", "256", "--verbosity", "1", "-X", "--blocklist-file", TOP_LEVEL_DIR + BLOCKLIST_FILE ] # 3 Port, Subnets of range /32 -> /2 for i in range(32, 1, -1): subnet = f"128.0.0.0/{i}" scanner_cmd = base_scanner_cmd + ["-p", "80-81,443", "-T", "1", subnet] print(f"Running ZMap Command: {" ".join(scanner_cmd)}") ports_to_scan = [80,81,443] run_test(scanner_cmd, ports_to_scan, subnet) # Single Port, Subnets of range /32 -> /1 for i in range(32, 0, -1): subnet = f"128.0.0.0/{i}" scanner_cmd = base_scanner_cmd + ["-p", "80", "-T", "1", subnet] print(f"Running ZMap Command: {" ".join(scanner_cmd)}") ports_to_scan = [80] run_test(scanner_cmd, ports_to_scan, subnet) # Single Port, Single Thread, Full IPv4 scanner_cmd = base_scanner_cmd + ["-p", "80", "-T", "1"] print(f"Running ZMap Command: {" ".join(scanner_cmd)}") ports_to_scan = [80] run_test(scanner_cmd, ports_to_scan) # Single Port, 2 Thread, Full IPv4 scanner_cmd = base_scanner_cmd + ["-p", "80", "-T", "2"] print(f"Running ZMap Command: {" ".join(scanner_cmd)}") ports_to_scan = [80] run_test(scanner_cmd, ports_to_scan) # Two Ports, Two Thread, Full IPv4 scanner_cmd = base_scanner_cmd + ["-p", "80,443", "-T", "2"] print(f"Running ZMap Command: {" ".join(scanner_cmd)}") ports_to_scan = [80,443] run_test(scanner_cmd, ports_to_scan) zmap-4.3.4/test/integration-tests/test_scan.py000066400000000000000000000035061501046211500214670ustar00rootroot00000000000000import os import zmap_wrapper output_file_path = "output.txt" def test_scan_known_good_ips(): """ This test will scan (not dry run) known active IPs and check that they are all scanned """ known_active_ips = ["1.1.1.1", "8.8.8.8"] # create file called "output.txt" in current directory with open(output_file_path, 'w') as file: file.write("") # using known dns resolvers to make this test deterministic t = zmap_wrapper.Wrapper(dryrun=False, port=53, subnet=" ".join(known_active_ips), threads=1, output_file=output_file_path, max_cooldown=3) t.run() # read the file into a list of IPs ips = [] with open(output_file_path, 'r') as file: for line in file: ips.append(line.strip()) for ip in known_active_ips: assert ip in ips, "an expected IP was not scanned" # clean up os.remove(output_file_path) def test_scan_known_good_ips_with_iplayer(): """ This test will scan (not dry run) known active IPs and check that they are all scanned Uses the --iplayer flag to test only sending IP packets (lets the OS compose the Ethernet frame) """ known_active_ips = ["1.1.1.1", "8.8.8.8"] # create file called "output.txt" in current directory with open(output_file_path, 'w') as file: file.write("") # using known dns resolvers to make this test deterministic t = zmap_wrapper.Wrapper(dryrun=False, port=53, subnet=" ".join(known_active_ips), threads=1, output_file=output_file_path, max_cooldown=3, iplayer=True) t.run() # read the file into a list of IPs ips = [] with open(output_file_path, 'r') as file: for line in file: ips.append(line.strip()) for ip in known_active_ips: assert ip in ips, "an expected IP was not scanned" # clean up os.remove(output_file_path) zmap-4.3.4/test/integration-tests/utils.py000066400000000000000000000136721501046211500206510ustar00rootroot00000000000000import ipaddress import re from random import random from timeout_decorator import timeout import typing import zmap_wrapper def enumerate_IP_range(ip_range: str): """ Args: ip_range (str): IP range in notation "start_ip-end_ip" Returns: List[str]: List of IP addresses in the range """ start_ip, end_ip = ip_range.split("-") start_ip = ipaddress.ip_address(ip_range.split("-")[0]) end_ip = ipaddress.ip_address(ip_range.split("-")[1]) return [str(ipaddress.ip_address(ip)) for ip in range(int(start_ip), int(end_ip) + 1)] def test_enumerate_IP_range(): ip_range = "189.23.45.32-189.23.45.34" # range expected_ips = [ "189.23.45.32", "189.23.45.33", "189.23.45.34", ] assert enumerate_IP_range(ip_range) == expected_ips def enumerate_port_range(port_range: str): """ Args: port_range (str): Port range in notation "start_port-end_port" Returns: List[int]: List of ports in the range """ start_port, end_port = port_range.split("-") return list(str(i) for i in range(int(start_port), int(end_port) + 1)) def test_enumerate_port_range(): port_range = "22-25" # range expected_ports = ["22", "23", "24", "25"] assert enumerate_port_range(port_range) == expected_ports ## utils def check_uniqueness_ip_list(ip_list): """ Args: ip_list (List(str)): List of IP addresses Returns: bool: True if all IPs are unique, False otherwise """ return len(ip_list) == len(set(ip_list)) def test_check_uniqueness_ip_list(): ip_list = [ "1.1.1.1", "1.1.1.1" ] assert not check_uniqueness_ip_list(ip_list) ip_list = ["1.1.1.1"] assert check_uniqueness_ip_list(ip_list) def check_coverage_of_ip_list(ip_list: typing.List[str], subnet: str): """ Checks if a list of IPs fully covers a subnet Args: ip_list (List(str)): List of IP addresses subnet (str): subnet in CIDR notation Returns: bool: True if all IPs in subnet are present in ip_list, False otherwise """ # Convert the subnet string to an ipaddress object subnet = ipaddress.ip_network(subnet) # Convert the list of IPs to ipaddress objects ip_objects = {ipaddress.ip_address(ip) for ip in ip_list} # Check if all IPs in the subnet are covered by the IP list for ip in subnet.hosts(): if ip not in ip_objects: return False return True def test_check_coverage_of_ip_list(): ip_list = [ "192.168.1.0", "192.168.1.1", "192.168.1.2", "192.168.1.3", ] subnet = "192.168.1.0/30" assert check_coverage_of_ip_list(ip_list, subnet) ip_list = [ "192.168.1.0", "192.168.1.2", "192.168.1.3", ] assert not check_coverage_of_ip_list(ip_list, subnet) def parse_ports_string(port_string) -> typing.List[str]: """ Parses a string of ports in the format "22-25,80,443" into a list of individual ports Args: port_string (str): String of ports in the format "22-25,80,443" Returns: List[str]: List of individual ports """ ports = [] # Regular expression to match individual ports or port ranges pattern = re.compile(r'(\d+)-(\d+)|(\d+)') matches = pattern.findall(port_string) for match in matches: if match[0]: # If it's a port range start = int(match[0]) end = int(match[1]) ports.extend(range(start, end + 1)) else: # If it's a single port ports.append(int(match[2])) return [str(port) for port in ports] def test_parse_ports_string(): tests = { "22": ["22"], "22-25": ["22", "23", "24", "25"], "22,80": ["22", "80"], "24-28,443,34,8080-8085": ["24", "25", "26", "27", "28", "443", "34", "8080", "8081", "8082", "8083", "8084", "8085"] } for t in tests: output = parse_ports_string(t) expected_output = tests[t] assert len(output) == len(expected_output), "lists don't match in length" output.sort() expected_output.sort() for i in range(len(output)): assert output[i] == expected_output[i], "lists do not match" @timeout(5) # bounding the runtime of the test so we don't get a stalled Github action should a failure occur in ZMap def bounded_runtime_test(t: zmap_wrapper.Wrapper): return t.run() def write_ips_to_file(num_of_ips, filename): """ Writes a list of public, non-blocked IPs to a file Args: num_of_ips (int): Number of IPs to write to the file filename (str): File to write the IPs to Returns: List of IPs written to the file, as strings """ subnet_pattern = r'\b(?:\d{1,3}\.){3}\d{1,3}/\d{1,2}\b' # read in blocked subnets in file "blocklist.conf" into a list blocked_subnets = [] with open("../../conf/blocklist.conf", "r") as file: for line in file: if not line.startswith("#") and "/" in line: # need to use a regex to pull out the subnet subnet = re.findall(subnet_pattern, line.strip()) if subnet: blocked_subnets.append(subnet[0]) # generate a list of num_of_ips random, non-blocked public IPs ips = set() for _ in range(num_of_ips): while True: ip = str(ipaddress.IPv4Address(int(2 ** 32 * random()))) # ensure the IP is not in the blocklist if any(ipaddress.ip_address(ip) in ipaddress.ip_network(subnet) for subnet in blocked_subnets): # IP is blocked continue if ipaddress.ip_address(ip).is_global and not ipaddress.ip_address(ip).is_reserved and ip not in ips: # found a good IP ips.add(ip) break # write the IPs to a file with open(filename, "w") as file: for ip in ips: file.write(ip + "\n") return ips zmap-4.3.4/test/integration-tests/zmap_wrapper.py000066400000000000000000000114751501046211500222170ustar00rootroot00000000000000import re import subprocess import sys PACKET_SEP = "-" * 54 class Wrapper: def __init__(self, port="80", subnet="", num_of_ips=-1, threads=-1, shards=-1, shard=-1, seed=-1, iplayer=False, dryrun=True, output_file="", max_runtime=-1, max_cooldown=-1, blocklist_file="", allowlist_file="", list_of_ips_file="", probes="", source_ip="", source_port="", source_mac="", rate=-1, max_targets=""): self.port = port self.subnet = subnet self.num_of_ips = num_of_ips self.threads = threads self.shards = shards self.shard = shard self.seed = seed self.iplayer = iplayer self.dryrun = dryrun self.output_file = output_file self.max_runtime = max_runtime self.max_cooldown = max_cooldown self.blocklist_file = blocklist_file self.allowlist_file = allowlist_file self.list_of_ips_file = list_of_ips_file self.probes = probes self.source_ip = source_ip self.source_port = source_port self.source_mac = source_mac self.rate = rate self.max_targets = max_targets def run(self): args = ["../../src/zmap"] args.extend(["-p", str(self.port)]) if self.subnet: args.extend(self.subnet.split()) if self.num_of_ips != -1: args.extend(["-n", str(self.num_of_ips)]) if self.threads != -1: args.extend(["-T", str(self.threads)]) if self.shards != -1: args.extend(["--shards=" + str(self.shards)]) if self.shard != -1: args.extend(["--shard=" + str(self.shard)]) if self.seed != -1: args.extend(["--seed=" + str(self.seed)]) if self.iplayer: args.extend(["--iplayer"]) if self.dryrun: args.extend(["--dryrun"]) if self.output_file: args.extend(["-o", self.output_file]) if self.max_runtime != -1: args.extend(["--max-runtime="+ str(self.max_runtime)]) if self.max_cooldown != -1: args.extend(["-c", str(self.max_cooldown)]) if self.blocklist_file: args.extend(["--blocklist-file=" + self.blocklist_file]) if self.allowlist_file: args.extend(["--allowlist-file=" + self.allowlist_file]) if self.list_of_ips_file: args.extend(["--list-of-ips-file=" + self.list_of_ips_file]) if self.probes: args.extend(["--probes=" + self.probes]) if self.source_ip: args.extend(["--source-ip=" + self.source_ip]) if self.source_port: args.extend(["--source-port=" + self.source_port]) if self.source_mac: args.extend(["--source-mac=" + self.source_mac]) if self.rate != -1: args.extend(["--rate=" + str(self.rate)]) if self.max_targets != "": args.extend(["--max-targets=" + str(self.max_targets)]) test_output = subprocess.run(args, stdout=subprocess.PIPE).stdout.decode('utf-8') packets = parse_output_into_obj_list(test_output) return packets def parse_output_into_obj_list(zmap_output: str): """ Chunks the entire ZMap output stream into individual packet outputs, and passes this to parse_packet_string """ packets = [] blocks = zmap_output.split(PACKET_SEP) for block in blocks: block = block.strip() if not block: continue packets.append(parse_packet_string(block)) return packets def parse_packet_string(block): """ Parses a string of packet output from zmap into a dictionary object storing the packet's fields """ # reg ex strings to find the fields we're interested in tcp_pattern = re.compile(r"tcp { source: (\d+) \| dest: (\d+) \| seq: (\d+) \| checksum: (.+?) }") ip_pattern = re.compile(r"ip { saddr: ([\d.]+) \| daddr: ([\d.]+) \| checksum: (.+?) }") eth_pattern = re.compile(r"eth { shost: ([\w:]+) \| dhost: ([\w:]+) }") tcp_match = tcp_pattern.search(block) ip_match = ip_pattern.search(block) eth_match = eth_pattern.search(block) packet = {} if tcp_match: packet["tcp"] = { "source": tcp_match.group(1), "dest": tcp_match.group(2), "seq": int(tcp_match.group(3)), "checksum": tcp_match.group(4) } if ip_match: packet["ip"] = { "saddr": ip_match.group(1), "daddr": ip_match.group(2), "checksum": ip_match.group(3) } if eth_match: packet["eth"] = { "shost": eth_match.group(1), "dhost": eth_match.group(2) } if len(packet) == 0: # packet object is empty, cannot proceed sys.exit("packet output \"{}\" has no expected fields: \"tcp\", \"ip\", or \"eth\"".format(block)) return packet zmap-4.3.4/test/test-shard.sh000077500000000000000000000034121501046211500160600ustar00rootroot00000000000000#!/bin/bash set -e SHARDS=19 for i in {0..18}; do ../src/zmap -v 5 -p 80 --dryrun -G 00:00:00:00:00:00 --seed 1234 --shards=$SHARDS --shard=$i 1.2.3.0/24 | grep daddr | awk '{print $7}' > s$i.scanned ../src/zmap -v 5 -p 80 --dryrun -G 00:00:00:00:00:00 --seed 8675309 --shards=$SHARDS --shard=$i 1.2.3.0/24 -T 3 | grep daddr | awk '{print $7}' > t$i.scanned done SHARDS=258 for i in {0..257}; do ../src/zmap -v 5 -p 80 --dryrun -G 00:00:00:00:00:00 --seed 11043 --shards=$SHARDS --shard=$i 1.2.0.0/16 | grep daddr | awk '{print $7}' > bs$i.scanned ../src/zmap -v 5 -p 80 --dryrun -G 00:00:00:00:00:00 --seed 829 --shards=$SHARDS --shard=$i 1.2.0.0/16 -T 3 | grep daddr | awk '{print $7}' > bt$i.scanned done ../src/zmap -v 5 -p 80 --dryrun -G 00:00:00:00:00:00 --seed 18172017 1.2.3.0/24 -T 3 | grep daddr | awk '{print $7}' > one_t3$i.scanned ../src/zmap -v 5 -p 80 --dryrun -G 00:00:00:00:00:00 --seed 13332727813 1.2.3.0/24 -T 1 | grep daddr | awk '{print $7}' > one_one$i.scanned echo "19 Shards - Expect: 256" cat s*.scanned | wc -l echo "Duplicates:" cat s*.scanned | sort | uniq -d | wc -l echo "" echo "258 Shards - Expect: 65536" cat bs*.scanned | wc -l echo "Duplicates:" cat bs*.scanned | sort | uniq -d | wc -l echo "" echo "258 Shards, 3 Threads - Expect: 65536" cat bt*.scanned | wc -l echo "Duplicates:" cat bt*.scanned | sort | uniq -d | wc -l echo "" echo "19 Shards, 3 Threads - Expect: 256" cat t*.scanned | wc -l echo "Duplicates:" cat t*.scanned | sort | uniq -d | wc -l echo "" echo "1 Shard, 3 Threads - Expect: 256" cat one_t*.scanned | wc -l echo "Duplicates:" cat one_t*.scanned | sort | uniq -d | wc -l echo "" echo "1 Shard, 1 Thread - Expect: 256" cat one_one*.scanned | wc -l echo "Duplicates:" cat one_one*.scanned | sort | uniq -d | wc -l echo "" zmap-4.3.4/test/test_big_group.sh000077500000000000000000000047331501046211500170250ustar00rootroot00000000000000#!/bin/sh ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 -T 5 --shards=5 --shard=0 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort > shardfile ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 -T 5 --shards=5 --shard=1 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort >> shardfile ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 -T 5 --shards=5 --shard=2 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort >> shardfile ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 -T 5 --shards=5 --shard=3 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort >> shardfile ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 -T 5 --shards=5 --shard=4 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort >> shardfile cat shardfile | sort > temp mv temp shardfile echo "Line Count: (Should be 65536)" cat shardfile | wc -l echo "Duplicate Count" cat shardfile | uniq -d | wc -l rm outfile rm shardfile ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 141.212.0.0/16 5.6.0.0/16 -T 4 --shards=5 --shard=0 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort > shardfile ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 141.212.0.0/16 5.6.0.0/16 -T 4 --shards=5 --shard=1 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort >> shardfile ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 141.212.0.0/16 5.6.0.0/16 -T 4 --shards=5 --shard=2 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort >> shardfile ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 141.212.0.0/16 5.6.0.0/16 -T 4 --shards=5 --shard=3 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort >> shardfile ../src/zmap -p 80 -c 1 -b configs/blocklist_shard.conf --seed=1234 --dryrun 1.1.0.0/16 141.212.0.0/16 5.6.0.0/16 -T 4 --shards=5 --shard=4 > outfile cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | sort >> shardfile cat shardfile | sort > temp mv temp shardfile echo "Line Count: (Should be 196608)" cat shardfile | wc -l echo "Duplicate Count" cat shardfile | uniq -d | wc -l rm outfile rm shardfile zmap-4.3.4/test/test_sharding.py000066400000000000000000000045641501046211500166640ustar00rootroot00000000000000import sh import unittest from sh import cut, grep, cat, wc, uniq, mv zmap_std_args = [ "-b", "configs/blocklist_shard.conf", "--seed=1234", "192.168.1.0/24", "--dryrun", "-c", "1" ] zmap = sh.Command("../src/zmap").bake(*zmap_std_args) def shard_file_name(shards, threads): # Use naming conversion -t return ''.join([str(shards), '-t', str(threads)]) def output_file_name(shards, shard, threads): # Use naming convention: .-t return ''.join([str(shards), '.', str(shard), '-t', str(threads)]) def parse(filename, **kwargs): # cat outfile | grep ip | cut -d '|' -f 2 | cut -d ' ' -f 3 | cut -d '.' -f 4 | sort -n | wc -l return sh.sort(cut(cut(cut(grep(cat(filename), "ip"), d="|", f=2), d=" ", f=3), d=".", f=4), "-n", _out=kwargs.get("_out")) class TestSharding(unittest.TestCase): NUM_IPS = 256 def setUp(self): pass def takeDown(self): pass def _runTest(self, shards, max_threads): for threads in range(1, max_threads + 1): for shard in range(0, shards): with sh.sudo: outfile = output_file_name(shards, shard, threads) zmap(p=80, T=threads, shards=shards, shard=shard, _out="tempfile") parse("tempfile", _out=outfile) dup_lines = int(wc(uniq(cat(outfile), "-d"), "-l")) self.assertEqual(dup_lines, 0) shard_file = shard_file_name(shards, threads) if shard == 0: cat(outfile, _out=shard_file) else: cat(shard_file, outfile, _out="tempfile") mv("tempfile", shard_file) for threads in range(1, max_threads + 1): shard_file = shard_file_name(shards, threads) num_lines = int(wc(cat(shard_file), "-l")) self.assertEqual(num_lines, TestSharding.NUM_IPS) dup_lines = int(wc(uniq(sh.sort(cat(shard_file), "-n"), "-d"), "-l")) self.assertEqual(dup_lines, 0) def testOneShard(self): # Test with one shard self._runTest(1, 4) def testTwoShards(self): self._runTest(2, 4) if __name__ == '__main__': unittest.main() zmap-4.3.4/test/test_zblocklist.py000066400000000000000000000075671501046211500172530ustar00rootroot00000000000000import unittest import subprocess import os import sys executable_path = None class ZBlocklistTest(unittest.TestCase): BLOCKLIST = [ "10.0.0.0/8 # private subnet", "192.168.0.0/16 # private subnet", "128.255.0.0/16 # university of iowa", "141.212.120.0/24 # halderman lab" ] ALLOWLIST = [ "141.212.0.0/16 # university of michigan", ] IPS = [ "61.193.80.24", "195.19.1.6", "114.34.253.25", "180.69.174.9", "38.134.130.203", "192.168.1.50", "98.125.221.180", "197.160.60.150", "47.139.63.128", "95.224.78.221", "170.114.52.252", "10.0.0.5", "128.255.134.1", "141.212.120.10", "141.212.12.6" ] IPS_MINUS_BL = [ "61.193.80.24", "195.19.1.6", "114.34.253.25", "180.69.174.9", "38.134.130.203", "98.125.221.180", "197.160.60.150", "47.139.63.128", "95.224.78.221", "170.114.52.252", "141.212.12.6" ] WL_IPS = [ "141.212.120.10", "141.212.12.6" ] WL_IPS_MINUS_BL = [ "141.212.12.6" ] COMMENT_STRS = [ "# some comment here", " # some comment here", ",google.com,data", "\t#some comment here" ] def setUp(self): global executable_path self.path = executable_path with open("/tmp/blocklist", "w") as fd: for line in self.BLOCKLIST: fd.write("%s\n" % line) with open("/tmp/allowlist", "w") as fd: for line in self.ALLOWLIST: fd.write("%s\n" % line) with open("/tmp/ips", "w") as fd: for line in self.IPS: fd.write("%s\n" % line) with open("/tmp/ips-commented", "w") as fd: for line in self.IPS: for comment in self.COMMENT_STRS: fd.write("%s%s\n" % (line, comment)) def tearDown(self): if os.path.exists("/tmp/blocklist"): os.remove("/tmp/blocklist") if os.path.exists("/tmp/allowlist"): os.remove("/tmp/allowlist") if os.path.exists("/tmp/ips"): os.remove("/tmp/ips") if os.path.exists("/tmp/ips-commented"): os.remove("/tmp/ips-commented") def execute(self, allowlist, blocklist, ipsfile="/tmp/ips", numtimestocat=1): cmd = "cat" for _ in range(0, numtimestocat): cmd += " %s" % ipsfile cmd += " | %s" % self.path if allowlist: cmd = cmd + " -w %s" % allowlist if blocklist: cmd = cmd + " -b %s" % blocklist results = subprocess.check_output(cmd, shell=True) ips = results.rstrip().split("\n") return ips def testValidBlocklist(self): res = self.execute(None, "/tmp/blocklist") self.assertEqual(set(res), set(self.IPS_MINUS_BL)) def testValidAllowlist(self): res = self.execute("/tmp/allowlist", None) self.assertEqual(set(res), set(self.WL_IPS)) def testValidAllowAndBlockList(self): res = self.execute("/tmp/allowlist", "/tmp/blocklist") self.assertEqual(set(res), set(self.WL_IPS_MINUS_BL)) def testDuplicateChecking(self): res = self.execute(None, "/tmp/blocklist", numtimestocat=5) self.assertEqual(len(res), len(self.IPS_MINUS_BL)) self.assertEqual(set(res), set(self.IPS_MINUS_BL)) def testCommentCharacters(self): res = self.execute(None, "/tmp/blocklist", ipsfile="/tmp/ips-commented") self.assertEqual(set(res), set(self.IPS_MINUS_BL)) if __name__ == "__main__": if len(sys.argv) != 2: print("USAGE: %s zblocklist" % sys.argv[0]) sys.exit(1) executable_path = sys.argv[1] assert(os.path.exists(executable_path)) unittest.main(argv=sys.argv[:1])