Vendored libslirp (#2045)
Add vendored libslirp into the repo with a shim to remove its dependency on glib.
This commit is contained in:
parent
747f50de98
commit
a2406e3c0e
|
@ -21,7 +21,7 @@ jobs:
|
||||||
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list
|
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install --allow-downgrades cmake ninja-build extra-cmake-modules libpcap0.8-dev libsdl2-dev \
|
sudo apt install --allow-downgrades cmake ninja-build extra-cmake-modules libpcap0.8-dev libsdl2-dev \
|
||||||
qt6-{base,base-private,multimedia}-dev libslirp0 libslirp-dev libarchive-dev libzstd-dev libfuse2
|
qt6-{base,base-private,multimedia}-dev libarchive-dev libzstd-dev libfuse2
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: cmake -B build -G Ninja -DUSE_QT6=ON -DCMAKE_INSTALL_PREFIX=/usr
|
run: cmake -B build -G Ninja -DUSE_QT6=ON -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
- name: Build
|
- name: Build
|
||||||
|
@ -63,7 +63,7 @@ jobs:
|
||||||
apt update
|
apt update
|
||||||
apt -y full-upgrade
|
apt -y full-upgrade
|
||||||
apt -y install git {gcc-12,g++-12}-aarch64-linux-gnu cmake ninja-build extra-cmake-modules \
|
apt -y install git {gcc-12,g++-12}-aarch64-linux-gnu cmake ninja-build extra-cmake-modules \
|
||||||
{libsdl2,qt6-{base,base-private,multimedia},libslirp,libarchive,libzstd}-dev:arm64 \
|
{libsdl2,qt6-{base,base-private,multimedia},libarchive,libzstd}-dev:arm64 \
|
||||||
pkg-config dpkg-dev
|
pkg-config dpkg-dev
|
||||||
- name: Check out source
|
- name: Check out source
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
update: true
|
update: true
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pacman -Sq --noconfirm git pkgconf mingw-w64-x86_64-{cmake,SDL2,qt5-static,libslirp,libarchive,toolchain}
|
run: pacman -Sq --noconfirm git pkgconf mingw-w64-x86_64-{cmake,SDL2,qt5-static,libarchive,toolchain}
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
working-directory: ${{runner.workspace}}
|
working-directory: ${{runner.workspace}}
|
||||||
|
|
12
README.md
12
README.md
|
@ -34,9 +34,9 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
1. Install dependencies:
|
1. Install dependencies:
|
||||||
* Ubuntu 22.04: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev qtbase5-private-dev qtmultimedia5-dev libslirp-dev libarchive-dev libzstd-dev`
|
* Ubuntu 22.04: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev qtbase5-private-dev qtmultimedia5-dev libarchive-dev libzstd-dev`
|
||||||
* Older Ubuntu: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default qtbase5-private-dev qtmultimedia5-dev libslirp-dev libarchive-dev libzstd-dev`
|
* Older Ubuntu: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default qtbase5-private-dev qtmultimedia5-dev libarchive-dev libzstd-dev`
|
||||||
* Arch Linux: `sudo pacman -S base-devel cmake extra-cmake-modules git libpcap sdl2 qt5-base qt5-multimedia libslirp libarchive zstd`
|
* Arch Linux: `sudo pacman -S base-devel cmake extra-cmake-modules git libpcap sdl2 qt5-base qt5-multimedia libarchive zstd`
|
||||||
3. Download the melonDS repository and prepare:
|
3. Download the melonDS repository and prepare:
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/melonDS-emu/melonDS
|
git clone https://github.com/melonDS-emu/melonDS
|
||||||
|
@ -63,7 +63,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
||||||
cd melonDS
|
cd melonDS
|
||||||
```
|
```
|
||||||
#### Dynamic builds (with DLLs)
|
#### Dynamic builds (with DLLs)
|
||||||
5. Install dependencies: `pacman -S mingw-w64-x86_64-{cmake,SDL2,toolchain,qt5-base,qt5-svg,qt5-multimedia,qt5-tools,libslirp,libarchive,zstd}`
|
5. Install dependencies: `pacman -S mingw-w64-x86_64-{cmake,SDL2,toolchain,qt5-base,qt5-svg,qt5-multimedia,qt5-tools,libarchive,zstd}`
|
||||||
6. Compile:
|
6. Compile:
|
||||||
```bash
|
```bash
|
||||||
cmake -B build
|
cmake -B build
|
||||||
|
@ -74,7 +74,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
||||||
If everything went well, melonDS and the libraries it needs should now be in the `dist` folder.
|
If everything went well, melonDS and the libraries it needs should now be in the `dist` folder.
|
||||||
|
|
||||||
#### Static builds (without DLLs, standalone executable)
|
#### Static builds (without DLLs, standalone executable)
|
||||||
5. Install dependencies: `pacman -S mingw-w64-x86_64-{cmake,SDL2,toolchain,qt5-static,libslirp,libarchive,zstd}`
|
5. Install dependencies: `pacman -S mingw-w64-x86_64-{cmake,SDL2,toolchain,qt5-static,libarchive,zstd}`
|
||||||
6. Compile:
|
6. Compile:
|
||||||
```bash
|
```bash
|
||||||
cmake -B build -DBUILD_STATIC=ON -DCMAKE_PREFIX_PATH=/mingw64/qt5-static
|
cmake -B build -DBUILD_STATIC=ON -DCMAKE_PREFIX_PATH=/mingw64/qt5-static
|
||||||
|
@ -84,7 +84,7 @@ If everything went well, melonDS should now be in the `build` folder.
|
||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
1. Install the [Homebrew Package Manager](https://brew.sh)
|
1. Install the [Homebrew Package Manager](https://brew.sh)
|
||||||
2. Install dependencies: `brew install git pkg-config cmake sdl2 qt@6 libslirp libarchive zstd`
|
2. Install dependencies: `brew install git pkg-config cmake sdl2 qt@6 libarchive zstd`
|
||||||
3. Download the melonDS repository and prepare:
|
3. Download the melonDS repository and prepare:
|
||||||
```zsh
|
```zsh
|
||||||
git clone https://github.com/melonDS-emu/melonDS
|
git clone https://github.com/melonDS-emu/melonDS
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
# https://clang.llvm.org/docs/ClangFormat.html
|
||||||
|
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false # although we like it, it creates churn
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlinesLeft: true
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: false # churn
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterReturnType: None # AlwaysBreakAfterDefinitionReturnType is taken into account
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: true
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 80
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: '.*_BEGIN$' # only PREC_BEGIN ?
|
||||||
|
MacroBlockEnd: '.*_END$'
|
||||||
|
MaxEmptyLinesToKeep: 2
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Auto
|
||||||
|
UseTab: Never
|
||||||
|
...
|
|
@ -0,0 +1,11 @@
|
||||||
|
*.[aod]
|
||||||
|
*.gcda
|
||||||
|
*.gcno
|
||||||
|
*.gcov
|
||||||
|
*.lib
|
||||||
|
*.obj
|
||||||
|
/build/
|
||||||
|
/TAGS
|
||||||
|
/cscope*
|
||||||
|
/src/libslirp-version.h
|
||||||
|
/tags
|
|
@ -0,0 +1,110 @@
|
||||||
|
image: fedora:latest
|
||||||
|
|
||||||
|
variables:
|
||||||
|
DEPS: meson ninja-build
|
||||||
|
gcc libasan liblsan libubsan pkg-config glib2-devel
|
||||||
|
mingw64-gcc mingw64-pkg-config mingw64-glib2
|
||||||
|
clang-analyzer git-core
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- dnf install -y $DEPS
|
||||||
|
- git fetch --tags https://gitlab.freedesktop.org/slirp/libslirp.git
|
||||||
|
- git describe
|
||||||
|
|
||||||
|
build:
|
||||||
|
script:
|
||||||
|
- meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||||
|
- ninja -C build
|
||||||
|
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
||||||
|
- ninja -C build scan-build
|
||||||
|
|
||||||
|
build-asan:
|
||||||
|
script:
|
||||||
|
- CFLAGS=-fsanitize=address meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||||
|
- ninja -C build
|
||||||
|
- (cd build && ASAN_OPTIONS=detect_leaks=0 meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
||||||
|
|
||||||
|
build-lsan:
|
||||||
|
script:
|
||||||
|
- CFLAGS=-fsanitize=leak meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||||
|
- ninja -C build
|
||||||
|
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
||||||
|
|
||||||
|
build-usan:
|
||||||
|
script:
|
||||||
|
- CFLAGS=-fsanitize=undefined meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||||
|
- ninja -C build
|
||||||
|
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
|
||||||
|
|
||||||
|
fuzz:
|
||||||
|
parallel:
|
||||||
|
matrix:
|
||||||
|
- TARGET: [arp, ip-header, udp, udp-h, tftp, dhcp, icmp, tcp, tcp-h, ndp, ip6-header, udp6, udp6-h, tftp6, icmp6, tcp6, tcp6-h]
|
||||||
|
script:
|
||||||
|
- CC=clang CXX=clang++ meson build -Dllvm-fuzz=true || (cat build/meson-logs/meson-log.txt && exit 1)
|
||||||
|
- ninja -C build
|
||||||
|
- build/fuzzing/fuzz-$TARGET -seed=1234 -runs=1000000 fuzzing/IN_$TARGET
|
||||||
|
artifacts:
|
||||||
|
when: on_failure
|
||||||
|
paths:
|
||||||
|
- crash-*
|
||||||
|
- leak-*
|
||||||
|
- oom-*
|
||||||
|
- timeout-*
|
||||||
|
|
||||||
|
build-mingw64:
|
||||||
|
script:
|
||||||
|
- (mkdir buildw && cd buildw && mingw64-meson --werror) || (cat buildw/meson-logs/meson-log.txt && exit 1)
|
||||||
|
- ninja -C buildw
|
||||||
|
|
||||||
|
Coverity:
|
||||||
|
only:
|
||||||
|
refs:
|
||||||
|
- master
|
||||||
|
- coverity
|
||||||
|
script:
|
||||||
|
- dnf update -y
|
||||||
|
- dnf install -y curl clang
|
||||||
|
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
|
||||||
|
--form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
|
||||||
|
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||||
|
- CC=clang meson build
|
||||||
|
- cov-analysis-linux64-*/bin/cov-build --dir cov-int ninja -C build
|
||||||
|
- tar cfz cov-int.tar.gz cov-int
|
||||||
|
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||||
|
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
||||||
|
--form file=@cov-int.tar.gz --form version="`git describe --tags`"
|
||||||
|
--form description="`git describe --tags` / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID "
|
||||||
|
|
||||||
|
integration-slirp4netns:
|
||||||
|
variables:
|
||||||
|
SLIRP4NETNS_VERSION: "v1.1.12"
|
||||||
|
# Consumed by `make benchmark`
|
||||||
|
BENCHMARK_IPERF3_DURATION: "10"
|
||||||
|
script:
|
||||||
|
# Install libslirp
|
||||||
|
- meson build
|
||||||
|
- ninja -C build install
|
||||||
|
# Register the path of libslirp.so.0
|
||||||
|
- echo /usr/local/lib64 >/etc/ld.so.conf.d/libslirp.conf
|
||||||
|
- ldconfig
|
||||||
|
# Install the dependencies of slirp4netns and its test suite
|
||||||
|
# TODO: install udhcpc for `slirp4netns/tests/test-slirp4netns-dhcp.sh` (currently skipped, due to lack of udhcpc)
|
||||||
|
- dnf install -y autoconf automake findutils iperf3 iproute iputils jq libcap-devel libseccomp-devel nmap-ncat util-linux
|
||||||
|
# Check whether the runner environment is configured correctly
|
||||||
|
- unshare -rn true || (echo Make sure you have relaxed seccomp and appamor && exit 1)
|
||||||
|
- unshare -rn ip tap add tap0 mode tap || (echo Make sure you have /dev/net/tun && exit 1)
|
||||||
|
# Install slirp4netns
|
||||||
|
- git clone https://github.com/rootless-containers/slirp4netns -b "${SLIRP4NETNS_VERSION}"
|
||||||
|
- cd slirp4netns
|
||||||
|
- ./autogen.sh
|
||||||
|
- ./configure
|
||||||
|
- make
|
||||||
|
- make install
|
||||||
|
- slirp4netns --version
|
||||||
|
# Run slirp4netns integration test
|
||||||
|
- make distcheck || (cat $(find . -name 'test-suite.log' ) && exit 1)
|
||||||
|
# Run benchmark test to ensure that libslirp can actually handle packets, with several MTU configurations
|
||||||
|
- make benchmark MTU=1500
|
||||||
|
- make benchmark MTU=512
|
||||||
|
- make benchmark MTU=65520
|
|
@ -0,0 +1,3 @@
|
||||||
|
[gitpublishprofile "default"]
|
||||||
|
base = master
|
||||||
|
to = slirp@lists.freedesktop.org
|
|
@ -0,0 +1,238 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [4.8.0] - TODO
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
- tcp: Fix testing for last fragment
|
||||||
|
- tftp: Fix use-after-free
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add support for Haiku !123
|
||||||
|
- ncsi: Add manufacturer's ID !122
|
||||||
|
- ncsi: Add Get Version ID command !122
|
||||||
|
- ncsi: Add out-of-band ethernet address !125
|
||||||
|
- ncsi: Add Mellanox Get Mac Address handler !125
|
||||||
|
- icmp6: Add echo request forwarding support
|
||||||
|
- Add fuzzing infrastructure
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix missing cleanups
|
||||||
|
- windows: Build fixes
|
||||||
|
- ipv6: Use target address from Neighbor Advertisement !129
|
||||||
|
- dns: Reject domain-search when any entry ends with ".."
|
||||||
|
- dns: Use localhost as dns when /etc/resolv.conf empty !130
|
||||||
|
- icmp: Handle ICMP packets as IPPROTO_IP on BSD !133
|
||||||
|
- eth: pad ethernet frames to 60 bytes #34
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- windows: Bump the minimum Windows version to Windows 7
|
||||||
|
|
||||||
|
## [4.7.0] - 2022-04-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Allow disabling the internal DHCP server !22
|
||||||
|
- icmp: Support falling back on trying a SOCK_RAW socket !92
|
||||||
|
- Support Unix sockets in hostfwd !103
|
||||||
|
- IPv6 DNS proxying support !110
|
||||||
|
- bootp: add support for UEFI HTTP boot !111
|
||||||
|
- New callback that supports CFI better !117
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- dhcp: Always send DHCP_OPT_LEN bytes in options !97
|
||||||
|
- Fix Haiku build !98 !99
|
||||||
|
- Fix memory leak when using libresolv !100
|
||||||
|
- Ensure sin6_scope_id is zero for global addresses !102
|
||||||
|
- resolv: fix IPv6 resolution on Darwin !104
|
||||||
|
- socket: Initialize so_type in socreate !109
|
||||||
|
- Handle ECONNABORTED from recv !116
|
||||||
|
|
||||||
|
## [4.6.1] - 2021-06-18
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix DHCP regression introduced in 4.6.0. !95
|
||||||
|
|
||||||
|
## [4.6.0] - 2021-06-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- mbuf: Add debugging helpers for allocation. !90
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Revert "Set macOS deployment target to macOS 10.4". !93
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- mtod()-related buffer overflows (CVE-2021-3592 #44, CVE-2021-3593 #45,
|
||||||
|
CVE-2021-3594 #47, CVE-2021-3595 #46).
|
||||||
|
- poll_fd: add missing fd registration for UDP and ICMP
|
||||||
|
- ncsi: make ncsi_calculate_checksum work with unaligned data. !89
|
||||||
|
- Various typos and doc fixes. !88
|
||||||
|
|
||||||
|
## [4.5.0] - 2021-05-18
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- IPv6 forwarding. !62 !75 !77
|
||||||
|
- slirp_neighbor_info() to dump the ARP/NDP tables. !71
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Lazy guest address resolution for IPv6. !81
|
||||||
|
- Improve signal handling when spawning a child. !61
|
||||||
|
- Set macOS deployment target to macOS 10.4. !72
|
||||||
|
- slirp_add_hostfwd: Ensure all error paths set errno. !80
|
||||||
|
- More API documentation.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Assertion failure on unspecified IPv6 address. !86
|
||||||
|
- Disable polling for PRI on MacOS, fixing some closing streams issues. !73
|
||||||
|
- Various memory leak fixes on fastq/batchq. !68
|
||||||
|
- Memory leak on IPv6 fast-send. !67
|
||||||
|
- Slow socket response on Windows. !64
|
||||||
|
- Misc build and code cleanups. !60 !63 !76 !79 !84
|
||||||
|
|
||||||
|
## [4.4.0] - 2020-12-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- udp, udp6, icmp: handle TTL value. !48
|
||||||
|
- Enable forwarding ICMP errors. !49
|
||||||
|
- Add DNS resolving for iOS. !54
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Improve meson subproject() support. !53
|
||||||
|
- Removed Makefile-based build system. !56
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- socket: consume empty packets. !55
|
||||||
|
- check pkt_len before reading protocol header (CVE-2020-29129). !57
|
||||||
|
- ip_stripoptions use memmove (fixes undefined behaviour). !47
|
||||||
|
- various Coverity-related changes/fixes.
|
||||||
|
|
||||||
|
## [4.3.1] - 2020-07-08
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- A silent truncation could occur in `slirp_fmt()`, which will now print a
|
||||||
|
critical message. See also #22.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- CVE-2020-10756 - Drop bogus IPv6 messages that could lead to data leakage.
|
||||||
|
See !44 and !42.
|
||||||
|
- Fix win32 builds by using the SLIRP_PACKED definition.
|
||||||
|
- Various coverity scan errors fixed. !41
|
||||||
|
- Fix new GCC warnings. !43
|
||||||
|
|
||||||
|
## [4.3.0] - 2020-04-22
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `SLIRP_VERSION_STRING` macro, with the git sha suffix when building from git
|
||||||
|
- `SlirpConfig.disable_dns`, to disable DNS redirection #16
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- `slirp_version_string()` now has the git sha suffix when building form git
|
||||||
|
- Limit DNS redirection to port 53 #16
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix build regression with mingw & NetBSD
|
||||||
|
- Fix use-afte-free in `ip_reass()` (CVE-2020-1983)
|
||||||
|
|
||||||
|
## [4.2.0] - 2020-03-17
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- New API function `slirp_add_unix`: add a forward rule to a Unix socket.
|
||||||
|
- New API function `slirp_remove_guestfwd`: remove a forward rule previously
|
||||||
|
added by `slirp_add_exec`, `slirp_add_unix` or `slirp_add_guestfwd`
|
||||||
|
- New `SlirpConfig.outbound_addr{,6}` fields to bind output socket to a
|
||||||
|
specific address
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- socket: do not fallback on host loopback if `get_dns_addr()` failed
|
||||||
|
or the address is in slirp network
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- ncsi: fix checksum OOB memory access
|
||||||
|
- `tcp_emu()`: fix OOB accesses
|
||||||
|
- tftp: restrict relative path access
|
||||||
|
- state: fix loading of guestfwd state
|
||||||
|
|
||||||
|
## [4.1.0] - 2019-12-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- The `slirp_new()` API, simpler and more extensible than `slirp_init()`.
|
||||||
|
- Allow custom MTU configuration.
|
||||||
|
- Option to disable host loopback connections.
|
||||||
|
- CI now runs scan-build too.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Disable `tcp_emu()` by default. `tcp_emu()` is known to have caused
|
||||||
|
several CVEs, and not useful today in most cases. The feature can
|
||||||
|
be still enabled by setting `SlirpConfig.enable_emu` to true.
|
||||||
|
- meson build system is now `subproject()` friendly.
|
||||||
|
- Replace remaining `malloc()`/`free()` with glib (which aborts on OOM)
|
||||||
|
- Various code cleanups.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- The `slirp_init()` API.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `getpeername()` error after `shutdown(SHUT_WR)`.
|
||||||
|
- Exec forward: correctly parse command lines that contain spaces.
|
||||||
|
- Allow 0.0.0.0 destination address.
|
||||||
|
- Make host receive broadcast packets.
|
||||||
|
- Various memory related fixes (heap overflow, leaks, NULL
|
||||||
|
dereference).
|
||||||
|
- Compilation warnings, dead code.
|
||||||
|
|
||||||
|
## [4.0.0] - 2019-05-24
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Installable as a shared library.
|
||||||
|
- meson build system
|
||||||
|
(& make build system for in-tree QEMU integration)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Standalone project, removing any QEMU dependency.
|
||||||
|
- License clarifications.
|
||||||
|
|
||||||
|
[Unreleased]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.8.0...master
|
||||||
|
[4.8.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.7.0...v4.8.0
|
||||||
|
[4.7.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.6.1...v4.7.0
|
||||||
|
[4.6.1]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.6.0...v4.6.1
|
||||||
|
[4.6.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.5.0...v4.6.0
|
||||||
|
[4.5.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.4.0...v4.5.0
|
||||||
|
[4.4.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.1...v4.4.0
|
||||||
|
[4.3.1]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.0...v4.3.1
|
||||||
|
[4.3.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.2.0...v4.3.0
|
||||||
|
[4.2.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.1.0...v4.2.0
|
||||||
|
[4.1.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.0.0...v4.1.0
|
||||||
|
[4.0.0]: https://gitlab.freedesktop.org/slirp/libslirp/commits/v4.0.0
|
|
@ -0,0 +1,63 @@
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(libslirp VERSION 4.8.0 LANGUAGES C)
|
||||||
|
|
||||||
|
set(SLIRP_MAJOR_VERSION "${libslirp_VERSION_MAJOR}")
|
||||||
|
set(SLIRP_MINOR_VERSION "${libslirp_VERSION_MINOR}")
|
||||||
|
set(SLIRP_MICRO_VERSION "${libslirp_VERSION_PATCH}")
|
||||||
|
set(SLIRP_VERSION_STRING "\"${libslirp_VERSION}\"")
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
src/arp_table.c
|
||||||
|
src/bootp.c
|
||||||
|
src/cksum.c
|
||||||
|
src/dhcpv6.c
|
||||||
|
src/dnssearch.c
|
||||||
|
src/if.c
|
||||||
|
src/ip6_icmp.c
|
||||||
|
src/ip6_input.c
|
||||||
|
src/ip6_output.c
|
||||||
|
src/ip_icmp.c
|
||||||
|
src/ip_input.c
|
||||||
|
src/ip_output.c
|
||||||
|
src/mbuf.c
|
||||||
|
src/misc.c
|
||||||
|
src/ncsi.c
|
||||||
|
src/ndp_table.c
|
||||||
|
src/sbuf.c
|
||||||
|
src/slirp.c
|
||||||
|
src/socket.c
|
||||||
|
src/state.c
|
||||||
|
src/stream.c
|
||||||
|
src/tcp_input.c
|
||||||
|
src/tcp_output.c
|
||||||
|
src/tcp_subr.c
|
||||||
|
src/tcp_timer.c
|
||||||
|
src/tftp.c
|
||||||
|
src/udp6.c
|
||||||
|
src/udp.c
|
||||||
|
src/util.c
|
||||||
|
src/version.c
|
||||||
|
src/vmstate.c
|
||||||
|
|
||||||
|
# glib shim
|
||||||
|
glib/glib.c
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/libslirp-version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/libslirp-version.h")
|
||||||
|
|
||||||
|
add_library(slirp STATIC ${SOURCES})
|
||||||
|
target_include_directories(slirp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/glib")
|
||||||
|
target_include_directories(slirp PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
target_include_directories(slirp PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
|
||||||
|
target_compile_definitions(slirp PRIVATE BUILDING_LIBSLIRP)
|
||||||
|
target_compile_definitions(slirp PRIVATE "G_LOG_DOMAIN=\"Slirp\"")
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
target_link_libraries(slirp PRIVATE ws2_32 iphlpapi)
|
||||||
|
elseif(HAIKU)
|
||||||
|
target_Link_libraries(slirp PRIVATE network)
|
||||||
|
elseif(APPLE)
|
||||||
|
target_link_libraries(slirp PRIVATE resolv)
|
||||||
|
endif()
|
|
@ -0,0 +1,62 @@
|
||||||
|
Slirp was written by Danny Gasparovski.
|
||||||
|
Copyright (c), 1995,1996 All Rights Reserved.
|
||||||
|
|
||||||
|
Slirp is free software; "free" as in you don't have to pay for it, and you
|
||||||
|
are free to do whatever you want with it. I do not accept any donations,
|
||||||
|
monetary or otherwise, for Slirp. Instead, I would ask you to pass this
|
||||||
|
potential donation to your favorite charity. In fact, I encourage
|
||||||
|
*everyone* who finds Slirp useful to make a small donation to their
|
||||||
|
favorite charity (for example, GreenPeace). This is not a requirement, but
|
||||||
|
a suggestion from someone who highly values the service they provide.
|
||||||
|
|
||||||
|
The copyright terms and conditions:
|
||||||
|
|
||||||
|
---BEGIN---
|
||||||
|
|
||||||
|
Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED ``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
|
||||||
|
DANNY GASPAROVSKI 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.
|
||||||
|
|
||||||
|
---END---
|
||||||
|
|
||||||
|
This basically means you can do anything you want with the software, except
|
||||||
|
1) call it your own, and 2) claim warranty on it. There is no warranty for
|
||||||
|
this software. None. Nada. If you lose a million dollars while using
|
||||||
|
Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***.
|
||||||
|
|
||||||
|
If these conditions cannot be met due to legal restrictions (E.g. where it
|
||||||
|
is against the law to give out Software without warranty), you must cease
|
||||||
|
using the software and delete all copies you have.
|
||||||
|
|
||||||
|
Slirp uses code that is copyrighted by the following people/organizations:
|
||||||
|
|
||||||
|
Juha Pirkola.
|
||||||
|
Gregory M. Christy.
|
||||||
|
The Regents of the University of California.
|
||||||
|
Carnegie Mellon University.
|
||||||
|
The Australian National University.
|
||||||
|
RSA Data Security, Inc.
|
||||||
|
|
||||||
|
Please read the top of each source file for the details on the various
|
||||||
|
copyrights.
|
|
@ -0,0 +1,60 @@
|
||||||
|
# libslirp
|
||||||
|
|
||||||
|
libslirp is a user-mode networking library used by virtual machines,
|
||||||
|
containers or various tools.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
A C compiler, meson and glib2 development libraries.
|
||||||
|
|
||||||
|
(see also [.gitlab-ci.yml](.gitlab-ci.yml) DEPS variable for the list
|
||||||
|
of dependencies on Fedora)
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
You may build and install the shared library with meson:
|
||||||
|
|
||||||
|
``` sh
|
||||||
|
meson build
|
||||||
|
ninja -C build install
|
||||||
|
```
|
||||||
|
And configure QEMU with --enable-slirp=system to link against it.
|
||||||
|
|
||||||
|
(QEMU may build with the submodule static library using --enable-slirp=git)
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
Unfortunately, there are no automated tests available.
|
||||||
|
|
||||||
|
You may run QEMU ``-net user`` linked with your development version.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Feel free to open issues on the [project
|
||||||
|
issues](https://gitlab.freedesktop.org/slirp/libslirp/issues) page.
|
||||||
|
|
||||||
|
You may clone the [gitlab
|
||||||
|
project](https://gitlab.freedesktop.org/slirp/libslirp) and create a
|
||||||
|
merge request.
|
||||||
|
|
||||||
|
Contributing with gitlab allows gitlab workflow, tracking issues,
|
||||||
|
running CI etc.
|
||||||
|
|
||||||
|
Alternatively, you may send patches to slirp@lists.freedesktop.org
|
||||||
|
mailing list.
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
We intend to use [libtool's
|
||||||
|
versioning](https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html)
|
||||||
|
for the shared libraries and use [SemVer](http://semver.org/) for
|
||||||
|
project versions.
|
||||||
|
|
||||||
|
For the versions available, see the [tags on this
|
||||||
|
repository](https://gitlab.freedesktop.org/slirp/libslirp/releases).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
See the [COPYRIGHT](COPYRIGHT) file for details.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
../IN_ndp/ndp.pcap
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
../IN_udp/DNS_freedesktop_1-1-1-1.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_dhcp/dhcp.pkt
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_dhcp/dhcp_capture.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_icmp/icmp_capture.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tcp/nc-10.0.2.2-8080.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tcp/nc-ident.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_icmp/ping_10-0-2-2.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tcp/tcp_qemucapt.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tftp/tftp-get-blah.pkt
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tftp/tftp_capture.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tftp/tftp_get_libslirp-txt.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_udp6/DNS_freedesktop_1-1-1-1.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_icmp6/icmp_capture.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_icmp6/ping_10-0-2-2.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tcp6/tcp_qemucapt.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_udp6/tftp_capture.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_udp6/tftp_get_libslirp-txt.pcap
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
IN_tcp
|
|
@ -0,0 +1 @@
|
||||||
|
IN_tcp
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
IN_tcp6
|
|
@ -0,0 +1 @@
|
||||||
|
IN_tcp6
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
IN_udp
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
../IN_dhcp/dhcp.pkt
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_dhcp/dhcp_capture.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tftp/tftp-get-blah.pkt
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tftp/tftp_capture.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tftp/tftp_get_libslirp-txt.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
IN_udp6
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
../IN_tftp6/tftp_capture.pcap
|
|
@ -0,0 +1 @@
|
||||||
|
../IN_tftp6/tftp_get_libslirp-txt.pcap
|
|
@ -0,0 +1,59 @@
|
||||||
|
# Fuzzing libslirp state and instructions
|
||||||
|
|
||||||
|
## Current state
|
||||||
|
We chose to use libFuzzer because of its custom mutator feature, which allows to keep coherent informations inside the packets being sent to libslirp. This ease the process of fuzzing as packets are less likely to be rejected early during processing them.
|
||||||
|
|
||||||
|
In the current state, the `meson.build` file is not compatible with the original one used by libSlirp main repository but it should be easy to merge them in a clean way. Also **in the current state, it seems that there is a memory leak inside the fuzzing code**, which make it run out of memory. The current goal is to find and get rid of this leak to allow fuzzing for longer without the process being interrupted because of it.
|
||||||
|
|
||||||
|
Six harness are currently available, more are to be added later to focus on other parts of the code :
|
||||||
|
|
||||||
|
- **fuzz-ip-header** : the mutator focuses on the ip header field informations,
|
||||||
|
- **fuzz-udp** : the mutator only work on udp packets, mutating the udp header and content, or only one or the other (-h,-d),
|
||||||
|
- **fuzz-tcp** : the mutator targets tcp packets, header+data or only one or the other, or only one or the other (-h,-d),
|
||||||
|
- **fuzz-icmp** : the mutator focuses on icmp packets,
|
||||||
|
|
||||||
|
These harness should be good starting examples on how to fuzz libslirp using libFuzzer.
|
||||||
|
|
||||||
|
## Running the fuzzer
|
||||||
|
|
||||||
|
Building the fuzzers/harness requires the use of clang as libFuzzer is part of LLVM.
|
||||||
|
You can build it running :
|
||||||
|
|
||||||
|
`CC=clang meson build && ninja -C build`
|
||||||
|
|
||||||
|
It will build the fuzzer in the ./build/fuzzing/ directory.
|
||||||
|
|
||||||
|
A script named `fuzzing/coverage.py` is available to generate coverage informations. **It makes a lot of assumptions on the directory structure** and should be read before use.
|
||||||
|
|
||||||
|
To run the fuzzer, simply run some of:
|
||||||
|
|
||||||
|
- `build/fuzzing/fuzz-ip-header fuzzing/IN_ip-header`
|
||||||
|
- `build/fuzzing/fuzz-udp fuzzing/IN_udp`
|
||||||
|
- `build/fuzzing/fuzz-udp-h fuzzing/IN_udp-h`
|
||||||
|
- `build/fuzzing/fuzz-tftp fuzzing/IN_tftp`
|
||||||
|
- `build/fuzzing/fuzz-dhcp fuzzing/IN_dhcp`
|
||||||
|
- `build/fuzzing/fuzz-icmp fuzzing/IN_icmp`
|
||||||
|
- `build/fuzzing/fuzz-tcp fuzzing/IN_tcp`
|
||||||
|
|
||||||
|
Your current directory should be a separate directory as crashes to it. New inputs found by the fuzzer will go directly in the `IN` folder.
|
||||||
|
|
||||||
|
# Adding new files to the corpus
|
||||||
|
|
||||||
|
In its current state, the fuzzing code is taking pcap files as input, we produced some using `tcpdump` on linux inside qemu with default settings.
|
||||||
|
Those files should be captured using the `EN10MB (Ethernet)` data link type, this can be set with the flag `-y` but it seems this can't be done while listening on all interfaces (`-i any`).
|
||||||
|
New files should give new coverage, to ensure a new file is usefull the `coverage.py` script (see next section) can be used to compare the coverage with and without that new file.
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
|
||||||
|
The `coverage.py` script allows to see coverage informations about the corpus. It makes a lot of assumptions on the directory structure so it should be read and probably modified before running it.
|
||||||
|
It must be called with the protocol to cover: `python coverage.py udp report`.
|
||||||
|
To generate coverage informations, the following flags are passed to the fuzzer and libslirp :
|
||||||
|
|
||||||
|
- g
|
||||||
|
- fsanitize-coverage=edge,indirect-calls,trace-cmp
|
||||||
|
- fprofile-instr-generate
|
||||||
|
- fcoverage-mapping
|
||||||
|
|
||||||
|
The last 2 arguments should also be passed to the linker.
|
||||||
|
|
||||||
|
Then the `llvm-profdata` and `llvm-cov` tools can be used to generate a report and a fancy set of HTML files with line-coverage informations.
|
|
@ -0,0 +1,37 @@
|
||||||
|
from os import chdir,listdir,environ
|
||||||
|
from os.path import isfile,join,isdir
|
||||||
|
from subprocess import DEVNULL, run
|
||||||
|
import sys
|
||||||
|
|
||||||
|
ignored_files = "-ignore-filename-regex=glib -ignore-filename-regex=fuzz -ignore-filename-regex=helper -ignore-filename-regex=h$"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
chdir("build/fuzzing/out")
|
||||||
|
available_targets = [exe for exe in listdir("../") if isfile(join("..", exe))]
|
||||||
|
available_corpus_path = [exe for exe in listdir("../../../fuzzing/") if isdir(join("../../../fuzzing/", exe))]
|
||||||
|
available_result_types = ["export", "show", "report"]
|
||||||
|
if len(sys.argv) != 4 or sys.argv[1] not in available_targets or sys.argv[2] not in available_corpus_path or sys.argv[3] not in available_result_types:
|
||||||
|
print("usage : python coverage.py fuzz_target IN_protol result_type")
|
||||||
|
print(" - available targets : ")
|
||||||
|
print(available_targets)
|
||||||
|
print(" - available_corpus_path : ")
|
||||||
|
print(available_corpus_path)
|
||||||
|
print(" - available result types : ")
|
||||||
|
print(available_result_types)
|
||||||
|
exit(0)
|
||||||
|
fuzzing_target = sys.argv[1]
|
||||||
|
corpus_path = "../../../fuzzing/"+sys.argv[2]+"/"
|
||||||
|
result_type = sys.argv[3]
|
||||||
|
if fuzzing_target in available_targets:
|
||||||
|
environ["LLVM_PROFILE_FILE"] = fuzzing_target + "_%p.profraw"
|
||||||
|
corpus = listdir(corpus_path)
|
||||||
|
for f in corpus:
|
||||||
|
#print(corpus_path+f)
|
||||||
|
run(["../" + fuzzing_target, corpus_path+f,"-detect_leaks=0"], stdin=DEVNULL, stdout=DEVNULL, stderr=DEVNULL)
|
||||||
|
run(["llvm-profdata merge -sparse " + fuzzing_target + "_*.profraw -o " + fuzzing_target + ".profdata"], shell=True)
|
||||||
|
if result_type == "export" :
|
||||||
|
run(["llvm-cov show ../" + fuzzing_target + " -format=html -output-dir=../report -instr-profile=" + fuzzing_target + ".profdata " + ignored_files], shell=True)
|
||||||
|
elif result_type == "show" :
|
||||||
|
run(["llvm-cov show ../" + fuzzing_target + " -instr-profile=" + fuzzing_target + ".profdata " + ignored_files], shell=True)
|
||||||
|
else:
|
||||||
|
run(["llvm-cov report ../" + fuzzing_target + " -instr-profile=" + fuzzing_target + ".profdata " + ignored_files], shell=True)
|
|
@ -0,0 +1,2 @@
|
||||||
|
[libfuzzer]
|
||||||
|
max_len = 1024
|
|
@ -0,0 +1,35 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MIN_NUMBER_OF_RUNS 1
|
||||||
|
#define EXIT_TEST_SKIP 77
|
||||||
|
|
||||||
|
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
GError *err = NULL;
|
||||||
|
char *name = argv[i];
|
||||||
|
char *buf;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (!g_file_get_contents(name, &buf, &size, &err)) {
|
||||||
|
g_warning("Failed to read '%s': %s", name, err->message);
|
||||||
|
g_clear_error(&err);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print("%s...\n", name);
|
||||||
|
for (j = 0; j < MIN_NUMBER_OF_RUNS; j++) {
|
||||||
|
if (LLVMFuzzerTestOneInput((void *)buf, size) == EXIT_TEST_SKIP) {
|
||||||
|
return EXIT_TEST_SKIP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,271 @@
|
||||||
|
#include "helper.h"
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#define MIN_NUMBER_OF_RUNS 1
|
||||||
|
#define EXIT_TEST_SKIP 77
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||||
|
struct in6_addr ip6_host;
|
||||||
|
struct in6_addr ip6_dns;
|
||||||
|
|
||||||
|
/// Function to compute the checksum of the ip header, should be compatible with
|
||||||
|
/// TCP and UDP checksum calculation too.
|
||||||
|
uint16_t compute_checksum(uint8_t *Data, size_t Size)
|
||||||
|
{
|
||||||
|
uint32_t sum = 0;
|
||||||
|
uint16_t *Data_as_u16 = (uint16_t *)Data;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < Size / 2; i++) {
|
||||||
|
uint16_t val = ntohs(*(Data_as_u16 + i));
|
||||||
|
sum += val;
|
||||||
|
}
|
||||||
|
if (Size % 2 == 1)
|
||||||
|
sum += Data[Size - 1] << 8;
|
||||||
|
|
||||||
|
uint16_t carry = sum >> 16;
|
||||||
|
uint32_t sum_val = carry + (sum & 0xFFFF);
|
||||||
|
uint16_t result = (sum_val >> 16) + (sum_val & 0xFFFF);
|
||||||
|
return ~result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||||
|
{
|
||||||
|
/* FIXME: fail on some addr? */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int listen(int sockfd, int backlog)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||||
|
{
|
||||||
|
/* FIXME: fail on some addr? */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
|
||||||
|
{
|
||||||
|
/* FIXME: partial send? */
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||||
|
const struct sockaddr *dest_addr, socklen_t addrlen)
|
||||||
|
{
|
||||||
|
/* FIXME: partial send? */
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t recv(int sockfd, void *buf, size_t len, int flags)
|
||||||
|
{
|
||||||
|
memset(buf, 0, len);
|
||||||
|
return len / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
|
||||||
|
struct sockaddr *src_addr, socklen_t *addrlen)
|
||||||
|
{
|
||||||
|
memset(buf, 0, len);
|
||||||
|
memset(src_addr, 0, *addrlen);
|
||||||
|
return len / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setsockopt(int sockfd, int level, int optname, const void *optval,
|
||||||
|
socklen_t optlen)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||||
|
static void empty_logging_func(const gchar *log_domain,
|
||||||
|
GLogLevelFlags log_level, const gchar *message,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Disables logging for oss-fuzz. Must be used with each target. */
|
||||||
|
static void fuzz_set_logging_func(void)
|
||||||
|
{
|
||||||
|
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||||
|
g_log_set_default_handler(empty_logging_func, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t send_packet(const void *pkt, size_t pkt_len, void *opaque)
|
||||||
|
{
|
||||||
|
return pkt_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t clock_get_ns(void *opaque)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *timer_new(SlirpTimerCb cb, void *cb_opaque, void *opaque)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_mod(void *timer, int64_t expire_timer, void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_free(void *timer, void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void guest_error(const char *msg, void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_poll_fd(int fd, void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unregister_poll_fd(int fd, void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void notify(void *opaque)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static const SlirpCb slirp_cb = {
|
||||||
|
.send_packet = send_packet,
|
||||||
|
.guest_error = guest_error,
|
||||||
|
.clock_get_ns = clock_get_ns,
|
||||||
|
.timer_new = timer_new,
|
||||||
|
.timer_mod = timer_mod,
|
||||||
|
.timer_free = timer_free,
|
||||||
|
.register_poll_fd = register_poll_fd,
|
||||||
|
.unregister_poll_fd = unregister_poll_fd,
|
||||||
|
.notify = notify,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_EVID 1024
|
||||||
|
static int fake_events[MAX_EVID];
|
||||||
|
|
||||||
|
static int add_poll_cb(int fd, int events, void *opaque)
|
||||||
|
{
|
||||||
|
g_assert(fd < G_N_ELEMENTS(fake_events));
|
||||||
|
fake_events[fd] = events;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_revents_cb(int idx, void *opaque)
|
||||||
|
{
|
||||||
|
return fake_events[idx] & ~(SLIRP_POLL_ERR | SLIRP_POLL_HUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fuzzing strategy is the following :
|
||||||
|
// LLVMFuzzerTestOneInput :
|
||||||
|
// - build a slirp instance,
|
||||||
|
// - extract the packets from the pcap one by one,
|
||||||
|
// - send the data to `slirp_input`
|
||||||
|
// - call `slirp_pollfds_fill` and `slirp_pollfds_poll` to advance slirp
|
||||||
|
// - cleanup slirp when the whole pcap has been unwrapped.
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
Slirp *slirp = NULL;
|
||||||
|
struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
|
||||||
|
struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
|
||||||
|
struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
|
||||||
|
struct in_addr fwd = { .s_addr = htonl(0x0a000205) }; /* 10.0.2.5 */
|
||||||
|
struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
|
||||||
|
struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
|
||||||
|
struct in6_addr ip6_prefix;
|
||||||
|
int ret, vprefix6_len = 64;
|
||||||
|
const char *vhostname = NULL;
|
||||||
|
const char *tftp_server_name = NULL;
|
||||||
|
const char *tftp_export = "fuzzing/tftp";
|
||||||
|
const char *bootfile = NULL;
|
||||||
|
const char **dnssearch = NULL;
|
||||||
|
const char *vdomainname = NULL;
|
||||||
|
const pcap_hdr_t *hdr = (const void *)data;
|
||||||
|
const pcaprec_hdr_t *rec = NULL;
|
||||||
|
uint32_t timeout = 0;
|
||||||
|
|
||||||
|
if (size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
data += sizeof(*hdr);
|
||||||
|
size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
setenv("SLIRP_FUZZING", "1", 0);
|
||||||
|
|
||||||
|
fuzz_set_logging_func();
|
||||||
|
|
||||||
|
ret = inet_pton(AF_INET6, "fec0::", &ip6_prefix);
|
||||||
|
g_assert_cmpint(ret, ==, 1);
|
||||||
|
|
||||||
|
ip6_host = ip6_prefix;
|
||||||
|
ip6_host.s6_addr[15] |= 2;
|
||||||
|
ip6_dns = ip6_prefix;
|
||||||
|
ip6_dns.s6_addr[15] |= 3;
|
||||||
|
|
||||||
|
slirp =
|
||||||
|
slirp_init(false, true, net, mask, host, true, ip6_prefix, vprefix6_len,
|
||||||
|
ip6_host, vhostname, tftp_server_name, tftp_export, bootfile,
|
||||||
|
dhcp, dns, ip6_dns, dnssearch, vdomainname, &slirp_cb, NULL);
|
||||||
|
|
||||||
|
slirp_add_exec(slirp, "cat", &fwd, 1234);
|
||||||
|
|
||||||
|
|
||||||
|
for ( ; size > sizeof(*rec); data += rec->incl_len, size -= rec->incl_len) {
|
||||||
|
rec = (const void *)data;
|
||||||
|
data += sizeof(*rec);
|
||||||
|
size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
g_debug("unsupported rec->incl_len != rec->orig_len");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14) {
|
||||||
|
if (data[12] == 0x08 && data[13] == 0x00) {
|
||||||
|
/* IPv4 */
|
||||||
|
if (rec->incl_len >= 14 + 16) {
|
||||||
|
uint32_t ipsource = * (uint32_t*) (data + 14 + 12);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (data[12] == 0x86 && data[13] == 0xdd) {
|
||||||
|
if (rec->incl_len >= 14 + 24) {
|
||||||
|
struct in6_addr *ipsource = (struct in6_addr *) (data + 14 + 8);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slirp_input(slirp, data, rec->incl_len);
|
||||||
|
slirp_pollfds_fill(slirp, &timeout, add_poll_cb, NULL);
|
||||||
|
slirp_pollfds_poll(slirp, 0, get_revents_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
slirp_cleanup(slirp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef _HELPER_H
|
||||||
|
#define _HELPER_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* as defined in sdkddkver.h */
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0600 /* Vista */
|
||||||
|
#endif
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#define PSEUDO_IP_SIZE (4*2 + 4)
|
||||||
|
#define PSEUDO_IPV6_SIZE (16*2 + 4)
|
||||||
|
|
||||||
|
uint16_t compute_checksum(uint8_t *Data, size_t Size);
|
||||||
|
|
||||||
|
extern struct in6_addr ip6_host;
|
||||||
|
extern struct in6_addr ip6_dns;
|
||||||
|
|
||||||
|
#endif /* _HELPER_H */
|
|
@ -0,0 +1,64 @@
|
||||||
|
extra_sources = []
|
||||||
|
extra_cargs = []
|
||||||
|
extra_ldargs = []
|
||||||
|
fuzzing_engine = []
|
||||||
|
|
||||||
|
|
||||||
|
extra_cargs += '-g'
|
||||||
|
if fuzzer_build
|
||||||
|
extra_cargs += '-fsanitize=fuzzer,address'
|
||||||
|
extra_cargs += '-fsanitize-coverage=edge,indirect-calls,trace-cmp'
|
||||||
|
extra_cargs += '-DCUSTOM_MUTATOR'
|
||||||
|
extra_cargs += '-fprofile-instr-generate'
|
||||||
|
extra_cargs += '-fcoverage-mapping'
|
||||||
|
|
||||||
|
extra_ldargs += '-fsanitize=fuzzer,address'
|
||||||
|
extra_ldargs += '-fprofile-instr-generate'
|
||||||
|
extra_ldargs += '-fcoverage-mapping'
|
||||||
|
endif
|
||||||
|
|
||||||
|
deps = [glib_dep, libslirp_dep, platform_deps]
|
||||||
|
|
||||||
|
exes = [
|
||||||
|
['fuzz-arp', ['slirp_fuzz_arp.c', 'helper.c']],
|
||||||
|
['fuzz-ip-header', ['slirp_fuzz_ip_header.c', 'helper.c']],
|
||||||
|
['fuzz-udp', ['slirp_fuzz_udp.c', 'helper.c']],
|
||||||
|
['fuzz-udp-h', ['slirp_fuzz_udp_header.c', 'helper.c']],
|
||||||
|
['fuzz-udp-d', ['slirp_fuzz_udp_data.c', 'helper.c']],
|
||||||
|
['fuzz-tftp', ['slirp_fuzz_udp_data.c', 'helper.c']],
|
||||||
|
['fuzz-dhcp', ['slirp_fuzz_udp_data.c', 'helper.c']],
|
||||||
|
['fuzz-tcp', ['slirp_fuzz_tcp.c', 'helper.c']],
|
||||||
|
['fuzz-tcp-h', ['slirp_fuzz_tcp_header.c', 'helper.c']],
|
||||||
|
['fuzz-tcp-d', ['slirp_fuzz_tcp_data.c', 'helper.c']],
|
||||||
|
['fuzz-icmp', ['slirp_fuzz_icmp.c', 'helper.c']],
|
||||||
|
|
||||||
|
['fuzz-ndp', ['slirp_fuzz_icmp6.c', 'helper.c']],
|
||||||
|
['fuzz-ip6-header', ['slirp_fuzz_ip6_header.c', 'helper.c']],
|
||||||
|
['fuzz-udp6', ['slirp_fuzz_udp6.c', 'helper.c']],
|
||||||
|
['fuzz-udp6-h', ['slirp_fuzz_udp6_header.c', 'helper.c']],
|
||||||
|
['fuzz-udp6-d', ['slirp_fuzz_udp6_data.c', 'helper.c']],
|
||||||
|
['fuzz-tftp6', ['slirp_fuzz_udp6_data.c', 'helper.c']],
|
||||||
|
['fuzz-tcp6', ['slirp_fuzz_tcp6.c', 'helper.c']],
|
||||||
|
['fuzz-tcp6-h', ['slirp_fuzz_tcp6_header.c', 'helper.c']],
|
||||||
|
['fuzz-tcp6-d', ['slirp_fuzz_tcp6_data.c', 'helper.c']],
|
||||||
|
['fuzz-icmp6', ['slirp_fuzz_icmp6.c', 'helper.c']],
|
||||||
|
]
|
||||||
|
|
||||||
|
if fuzzer_build
|
||||||
|
foreach exe : exes
|
||||||
|
executable(
|
||||||
|
exe[0], exe[1],
|
||||||
|
dependencies : deps,
|
||||||
|
c_args: extra_cargs,
|
||||||
|
link_args: extra_ldargs,
|
||||||
|
)
|
||||||
|
endforeach
|
||||||
|
endif
|
||||||
|
|
||||||
|
if fuzz_reproduce
|
||||||
|
executable(['reproducer', ['reproducer.c', 'helper.c']],
|
||||||
|
dependencies: deps,
|
||||||
|
c_args: extra_cargs,
|
||||||
|
link_args: extra_ldargs,
|
||||||
|
)
|
||||||
|
endif
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
export CC=${CC:-clang}
|
||||||
|
export CXX=${CXX:-clang++}
|
||||||
|
export WORK=${WORK:-$(pwd)}
|
||||||
|
export OUT=${OUT:-$(pwd)/out}
|
||||||
|
|
||||||
|
build=$WORK/build
|
||||||
|
rm -rf $build
|
||||||
|
mkdir -p $build
|
||||||
|
mkdir -p $OUT
|
||||||
|
|
||||||
|
fuzzflag="oss-fuzz=true"
|
||||||
|
if [ -z "$FUZZING_ENGINE" ]; then
|
||||||
|
fuzzflag="llvm-fuzz=true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
meson $build \
|
||||||
|
-D$fuzzflag \
|
||||||
|
-Db_lundef=false \
|
||||||
|
-Ddefault_library=static \
|
||||||
|
-Dstatic=true \
|
||||||
|
-Dbuildtype=debugoptimized
|
||||||
|
|
||||||
|
ninja -C $build
|
||||||
|
|
||||||
|
zip -jqr $OUT/fuzz-arp_seed_corpus.zip "$(dirname "$0")/IN_arp"
|
||||||
|
zip -jqr $OUT/fuzz-ip-header_seed_corpus.zip "$(dirname "$0")/IN_ip-header"
|
||||||
|
zip -jqr $OUT/fuzz-udp_seed_corpus.zip "$(dirname "$0")/IN_udp"
|
||||||
|
zip -jqr $OUT/fuzz-udp-h_seed_corpus.zip "$(dirname "$0")/IN_udp-h"
|
||||||
|
zip -jqr $OUT/fuzz-tftp_seed_corpus.zip "$(dirname "$0")/IN_tftp"
|
||||||
|
zip -jqr $OUT/fuzz-dhcp_seed_corpus.zip "$(dirname "$0")/IN_dhcp"
|
||||||
|
zip -jqr $OUT/fuzz-icmp_seed_corpus.zip "$(dirname "$0")/IN_icmp"
|
||||||
|
zip -jqr $OUT/fuzz-tcp_seed_corpus.zip "$(dirname "$0")/IN_tcp"
|
||||||
|
zip -jqr $OUT/fuzz-tcp-h_seed_corpus.zip "$(dirname "$0")/IN_tcp-h"
|
||||||
|
|
||||||
|
zip -jqr $OUT/fuzz-ndp_seed_corpus.zip "$(dirname "$0")/IN_ndp"
|
||||||
|
zip -jqr $OUT/fuzz-ip6-header_seed_corpus.zip "$(dirname "$0")/IN_ip6-header"
|
||||||
|
zip -jqr $OUT/fuzz-udp6_seed_corpus.zip "$(dirname "$0")/IN_udp6"
|
||||||
|
zip -jqr $OUT/fuzz-udp6-h_seed_corpus.zip "$(dirname "$0")/IN_udp6-h"
|
||||||
|
zip -jqr $OUT/fuzz-tftp6_seed_corpus.zip "$(dirname "$0")/IN_tftp6"
|
||||||
|
zip -jqr $OUT/fuzz-icmp6_seed_corpus.zip "$(dirname "$0")/IN_icmp6"
|
||||||
|
zip -jqr $OUT/fuzz-tcp6_seed_corpus.zip "$(dirname "$0")/IN_tcp6"
|
||||||
|
|
||||||
|
find $build -type f -executable -name "fuzz-*" -exec mv {} $OUT \;
|
||||||
|
find $build -type f -name "*.options" -exec mv {} $OUT \;
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* as defined in sdkddkver.h */
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0600 /* Vista */
|
||||||
|
#endif
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
|
||||||
|
#define MIN_NUMBER_OF_RUNS 1
|
||||||
|
#define EXIT_TEST_SKIP 77
|
||||||
|
|
||||||
|
extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
GError *err = NULL;
|
||||||
|
char *name = argv[i];
|
||||||
|
char *buf;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (!g_file_get_contents(name, &buf, &size, &err)) {
|
||||||
|
g_warning("Failed to read '%s': %s", name, err->message);
|
||||||
|
g_clear_error(&err);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print("%s...\n", name);
|
||||||
|
for (j = 0; j < MIN_NUMBER_OF_RUNS; j++) {
|
||||||
|
if (LLVMFuzzerTestOneInput((void *)buf, size) == EXIT_TEST_SKIP) {
|
||||||
|
return EXIT_TEST_SKIP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
|
||||||
|
/* Structure for the fuzzers */
|
||||||
|
typedef struct pcap_hdr_s {
|
||||||
|
guint32 magic_number; /* magic number */
|
||||||
|
guint16 version_major; /* major version number */
|
||||||
|
guint16 version_minor; /* minor version number */
|
||||||
|
gint32 thiszone; /* GMT to local correction */
|
||||||
|
guint32 sigfigs; /* accuracy of timestamps */
|
||||||
|
guint32 snaplen; /* max length of captured packets, in octets */
|
||||||
|
guint32 network; /* data link type */
|
||||||
|
} pcap_hdr_t;
|
||||||
|
|
||||||
|
typedef struct pcaprec_hdr_s {
|
||||||
|
guint32 ts_sec; /* timestamp seconds */
|
||||||
|
guint32 ts_usec; /* timestamp microseconds */
|
||||||
|
guint32 incl_len; /* number of octets of packet saved in file */
|
||||||
|
guint32 orig_len; /* actual length of packet */
|
||||||
|
} pcaprec_hdr_t;
|
|
@ -0,0 +1,90 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *arp_data;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arp_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint16_t arp_size = rec->incl_len - 14;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the ip header, maybe the IPs or
|
||||||
|
// total length should be excluded ?
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, arp_data, arp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// For now we dont want to change the header size as it would require to
|
||||||
|
// resize the `Data` array to include the new bytes inside the whole
|
||||||
|
// packet.
|
||||||
|
// This should be easy as LibFuzzer probably does it by itself or
|
||||||
|
// reserved enough space in Data beforehand, needs some research to
|
||||||
|
// confirm.
|
||||||
|
// FIXME: allow up to grow header size to 60 bytes,
|
||||||
|
// requires to update the `header length` before calculating
|
||||||
|
// checksum
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, arp_size, arp_size);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(arp_data, Data_to_mutate, arp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,129 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
uint32_t ipsource;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 16) {
|
||||||
|
ipsource = * (uint32_t*) (ip_data + 12);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't mutate
|
||||||
|
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not ICMP from the mutation strategy
|
||||||
|
if (ip_data[9] != IPPROTO_ICMP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||||
|
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_icmp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint16_t total_length =
|
||||||
|
ntohs(*((uint16_t *)ip_data + 1)); // network order to host order
|
||||||
|
uint16_t icmp_size =
|
||||||
|
(total_length - ip_hl_in_bytes); /* total length -> is stored at the
|
||||||
|
offset 2 in the header */
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (icmp_size > MaxSize || icmp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in icmp
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, start_of_icmp, icmp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// For now we dont want to change the header size as it would require to
|
||||||
|
// resize the `Data` array to include the new bytes inside the whole
|
||||||
|
// packet.
|
||||||
|
// This should be easy as LibFuzzer probably does it by itself or
|
||||||
|
// reserved enough space in Data beforehand, needs some research to
|
||||||
|
// confirm.
|
||||||
|
// FIXME: allow up to grow header size to 60 bytes,
|
||||||
|
// requires to update the `header length` before calculating
|
||||||
|
// checksum
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, icmp_size, icmp_size);
|
||||||
|
|
||||||
|
// Set the `checksum` field to 0 and calculate the new checksum
|
||||||
|
*(uint16_t *)(Data_to_mutate + 2) = 0;
|
||||||
|
uint16_t new_checksum =
|
||||||
|
compute_checksum(Data_to_mutate, icmp_size);
|
||||||
|
*(uint16_t *)(Data_to_mutate + 2) = htons(new_checksum);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_icmp, Data_to_mutate, icmp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,134 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 24) {
|
||||||
|
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not ICMP from the mutation strategy
|
||||||
|
if (ip_data[6] != IPPROTO_ICMPV6)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allocate a bit more than needed, this is useful for
|
||||||
|
// checksum calculation.
|
||||||
|
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
|
||||||
|
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||||
|
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_icmp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint16_t icmp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (icmp_size > MaxSize || icmp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in icmp
|
||||||
|
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
|
||||||
|
memcpy(Data_to_mutate, start_of_icmp, icmp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// For now we dont want to change the header size as it would require to
|
||||||
|
// resize the `Data` array to include the new bytes inside the whole
|
||||||
|
// packet.
|
||||||
|
// This should be easy as LibFuzzer probably does it by itself or
|
||||||
|
// reserved enough space in Data beforehand, needs some research to
|
||||||
|
// confirm.
|
||||||
|
// FIXME: allow up to grow header size to 60 bytes,
|
||||||
|
// requires to update the `header length` before calculating
|
||||||
|
// checksum
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, icmp_size, icmp_size);
|
||||||
|
|
||||||
|
// Set the `checksum` field to 0 and calculate the new checksum
|
||||||
|
*(uint16_t *)(Data_to_mutate + 2) = 0;
|
||||||
|
// Copy the source and destination IP addresses, the tcp length and
|
||||||
|
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||||
|
// the new checksum.
|
||||||
|
memcpy(Data_to_mutate + icmp_size, ip_data + 8, 16*2);
|
||||||
|
|
||||||
|
*(Data_to_mutate + icmp_size + 16*2 + 1) = IPPROTO_ICMPV6;
|
||||||
|
|
||||||
|
*(Data_to_mutate + icmp_size + 16*2 + 2) = (uint8_t)(icmp_size / 256);
|
||||||
|
*(Data_to_mutate + icmp_size + 16*2 + 3) = (uint8_t)(icmp_size % 256);
|
||||||
|
|
||||||
|
uint16_t new_checksum =
|
||||||
|
compute_checksum(Data_to_mutate, icmp_size + PSEUDO_IPV6_SIZE);
|
||||||
|
*(uint16_t *)(Data_to_mutate + 2) = htons(new_checksum);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_icmp, Data_to_mutate, icmp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,103 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 24) {
|
||||||
|
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||||
|
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the ip header, maybe the IPs or
|
||||||
|
// total length should be excluded ?
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, ip_data, ip_hl_in_bytes);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// For now we dont want to change the header size as it would require to
|
||||||
|
// resize the `Data` array to include the new bytes inside the whole
|
||||||
|
// packet.
|
||||||
|
// This should be easy as LibFuzzer probably does it by itself or
|
||||||
|
// reserved enough space in Data beforehand, needs some research to
|
||||||
|
// confirm.
|
||||||
|
// FIXME: allow up to grow header size to 60 bytes,
|
||||||
|
// requires to update the `header length` before calculating
|
||||||
|
// checksum
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, ip_hl_in_bytes, ip_hl_in_bytes);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(ip_data, Data_to_mutate, ip_hl_in_bytes);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,112 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
uint32_t ipsource;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 16) {
|
||||||
|
ipsource = * (uint32_t*) (ip_data + 12);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't mutate
|
||||||
|
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||||
|
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > MaxSize || ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the ip header, maybe the IPs or
|
||||||
|
// total length should be excluded ?
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, ip_data, ip_hl_in_bytes);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// For now we dont want to change the header size as it would require to
|
||||||
|
// resize the `Data` array to include the new bytes inside the whole
|
||||||
|
// packet.
|
||||||
|
// This should be easy as LibFuzzer probably does it by itself or
|
||||||
|
// reserved enough space in Data beforehand, needs some research to
|
||||||
|
// confirm.
|
||||||
|
// FIXME: allow up to grow header size to 60 bytes,
|
||||||
|
// requires to update the `header length` before calculating
|
||||||
|
// checksum
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, ip_hl_in_bytes, ip_hl_in_bytes);
|
||||||
|
|
||||||
|
// Set the `checksum` field to 0 and calculate the new checksum
|
||||||
|
*(uint16_t *)(Data_to_mutate + 10) = 0;
|
||||||
|
uint16_t new_checksum =
|
||||||
|
compute_checksum(Data_to_mutate, ip_hl_in_bytes);
|
||||||
|
*(uint16_t *)(Data_to_mutate + 10) = htons(new_checksum);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(ip_data, Data_to_mutate, ip_hl_in_bytes);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,138 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
uint32_t ipsource;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 16) {
|
||||||
|
ipsource = * (uint32_t*) (ip_data + 12);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't mutate
|
||||||
|
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not TCP from the mutation strategy
|
||||||
|
if (ip_data[9] != IPPROTO_TCP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allocate a bit more than needed, this is useful for
|
||||||
|
// checksum calculation.
|
||||||
|
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
|
||||||
|
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||||
|
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
|
||||||
|
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the tcp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
|
||||||
|
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the TCP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, tcp_size, tcp_size);
|
||||||
|
|
||||||
|
// Set the `checksum` field to 0 to calculate the new checksum
|
||||||
|
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||||
|
// Copy the source and destination IP addresses, the tcp length and
|
||||||
|
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||||
|
// the new checksum.
|
||||||
|
memcpy(Data_to_mutate + tcp_size, ip_data + 12, 4*2);
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
|
||||||
|
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
|
||||||
|
|
||||||
|
uint16_t new_checksum =
|
||||||
|
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,134 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 24) {
|
||||||
|
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not TCP from the mutation strategy
|
||||||
|
if (ip_data[6] != IPPROTO_TCP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allocate a bit more than needed, this is useful for
|
||||||
|
// checksum calculation.
|
||||||
|
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
|
||||||
|
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||||
|
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint16_t tcp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the tcp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
|
||||||
|
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the TCP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, tcp_size, tcp_size);
|
||||||
|
|
||||||
|
// Set the `checksum` field to 0 to calculate the new checksum
|
||||||
|
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||||
|
// Copy the source and destination IP addresses, the tcp length and
|
||||||
|
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||||
|
// the new checksum.
|
||||||
|
memcpy(Data_to_mutate + tcp_size, ip_data + 8, 16*2);
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 16*2 + 1) = IPPROTO_TCP;
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 16*2 + 2) = (uint8_t)(tcp_size / 256);
|
||||||
|
*(Data_to_mutate + tcp_size + 16*2 + 3) = (uint8_t)(tcp_size % 256);
|
||||||
|
|
||||||
|
uint16_t new_checksum =
|
||||||
|
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IPV6_SIZE);
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,137 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 24) {
|
||||||
|
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not TCP from the mutation strategy
|
||||||
|
if (ip_data[6] != IPPROTO_TCP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allocate a bit more than needed, this is useful for
|
||||||
|
// checksum calculation.
|
||||||
|
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
|
||||||
|
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||||
|
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint8_t tcp_header_size = 4 * (*(start_of_tcp + 12) >> 4);
|
||||||
|
uint8_t *start_of_data = ip_data + ip_hl_in_bytes + tcp_header_size;
|
||||||
|
uint16_t tcp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||||
|
uint16_t tcp_data_size = (tcp_size - (uint16_t)tcp_header_size);
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (tcp_data_size > MaxSize || tcp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - tcp_header_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the tcp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
|
||||||
|
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the TCP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate + tcp_header_size, tcp_data_size, tcp_data_size);
|
||||||
|
|
||||||
|
// Set the `checksum` field to 0 to calculate the new checksum
|
||||||
|
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||||
|
// Copy the source and destination IP addresses, the tcp length and
|
||||||
|
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||||
|
// the new checksum.
|
||||||
|
memcpy(Data_to_mutate + tcp_size, ip_data + 8, 16*2);
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 16*2 + 1) = IPPROTO_TCP;
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 16*2 + 2) = (uint8_t)(tcp_size / 256);
|
||||||
|
*(Data_to_mutate + tcp_size + 16*2 + 3) = (uint8_t)(tcp_size % 256);
|
||||||
|
|
||||||
|
uint16_t new_checksum =
|
||||||
|
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IPV6_SIZE);
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,136 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 24) {
|
||||||
|
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not TCP from the mutation strategy
|
||||||
|
if (ip_data[6] != IPPROTO_TCP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allocate a bit more than needed, this is useful for
|
||||||
|
// checksum calculation.
|
||||||
|
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
|
||||||
|
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||||
|
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint8_t tcp_header_size = (*(start_of_tcp + 12) >> 4) * 4;
|
||||||
|
uint16_t tcp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes ||
|
||||||
|
tcp_header_size > MaxSize || tcp_header_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the tcp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
|
||||||
|
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the TCP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, tcp_header_size, tcp_header_size);
|
||||||
|
|
||||||
|
// Set the `checksum` field to 0 to calculate the new checksum
|
||||||
|
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||||
|
// Copy the source and destination IP addresses, the tcp length and
|
||||||
|
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||||
|
// the new checksum.
|
||||||
|
memcpy(Data_to_mutate + tcp_size, ip_data + 8, 16*2);
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 16*2 + 1) = IPPROTO_TCP;
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 16*2 + 2) = (uint8_t)(tcp_size / 256);
|
||||||
|
*(Data_to_mutate + tcp_size + 16*2 + 3) = (uint8_t)(tcp_size % 256);
|
||||||
|
|
||||||
|
uint16_t new_checksum =
|
||||||
|
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IPV6_SIZE);
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,141 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
uint32_t ipsource;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 16) {
|
||||||
|
ipsource = * (uint32_t*) (ip_data + 12);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't mutate
|
||||||
|
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not TCP from the mutation strategy
|
||||||
|
if (ip_data[9] != IPPROTO_TCP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allocate a bit more than needed, this is useful for
|
||||||
|
// checksum calculation.
|
||||||
|
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
|
||||||
|
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||||
|
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint8_t tcp_header_size = 4 * (*(start_of_tcp + 12) >> 4);
|
||||||
|
uint8_t *start_of_data = ip_data + ip_hl_in_bytes + tcp_header_size;
|
||||||
|
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
|
||||||
|
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
|
||||||
|
uint16_t tcp_data_size = (tcp_size - (uint16_t)tcp_header_size);
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (tcp_data_size > MaxSize || tcp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - tcp_header_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the tcp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
|
||||||
|
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the TCP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate + tcp_header_size, tcp_data_size, tcp_data_size);
|
||||||
|
|
||||||
|
// Set the `checksum` field to 0 to calculate the new checksum
|
||||||
|
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||||
|
// Copy the source and destination IP addresses, the tcp length and
|
||||||
|
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||||
|
// the new checksum.
|
||||||
|
memcpy(Data_to_mutate + tcp_size, ip_data + 12, 4*2);
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
|
||||||
|
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
|
||||||
|
|
||||||
|
uint16_t new_checksum =
|
||||||
|
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
uint32_t ipsource;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 16) {
|
||||||
|
ipsource = * (uint32_t*) (ip_data + 12);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't mutate
|
||||||
|
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not TCP from the mutation strategy
|
||||||
|
if (ip_data[9] != IPPROTO_TCP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allocate a bit more than needed, this is useful for
|
||||||
|
// checksum calculation.
|
||||||
|
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
|
||||||
|
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||||
|
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint8_t tcp_header_size = (*(start_of_tcp + 12) >> 4) * 4;
|
||||||
|
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
|
||||||
|
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes ||
|
||||||
|
tcp_header_size > MaxSize || tcp_header_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the tcp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
|
||||||
|
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole TCP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the TCP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, tcp_header_size, tcp_header_size);
|
||||||
|
|
||||||
|
// Set the `checksum` field to 0 to calculate the new checksum
|
||||||
|
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
|
||||||
|
// Copy the source and destination IP addresses, the tcp length and
|
||||||
|
// protocol number at the end of the `Data_to_mutate` array to calculate
|
||||||
|
// the new checksum.
|
||||||
|
memcpy(Data_to_mutate + tcp_size, ip_data + 12, 4*2);
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
|
||||||
|
|
||||||
|
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
|
||||||
|
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
|
||||||
|
|
||||||
|
uint16_t new_checksum =
|
||||||
|
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
|
||||||
|
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,121 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
uint32_t ipsource;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 16) {
|
||||||
|
ipsource = * (uint32_t*) (ip_data + 12);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't mutate
|
||||||
|
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not UDP from the mutation strategy
|
||||||
|
if (ip_data[9] != IPPROTO_UDP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||||
|
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint16_t udp_size = ntohs(*(uint16_t *)(start_of_udp + 4));
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the udp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the UDP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, udp_size, udp_size);
|
||||||
|
|
||||||
|
// Drop checksum
|
||||||
|
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,120 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 24) {
|
||||||
|
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not UDP from the mutation strategy
|
||||||
|
if (ip_data[6] != IPPROTO_UDP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||||
|
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint16_t udp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the udp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the UDP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, udp_size, udp_size);
|
||||||
|
|
||||||
|
// Drop checksum
|
||||||
|
// Stricto sensu, UDPv6 makes checksums mandatory, but libslirp doesn't
|
||||||
|
// check that actually
|
||||||
|
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,122 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 24) {
|
||||||
|
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not UDP from the mutation strategy
|
||||||
|
if (ip_data[6] != IPPROTO_UDP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||||
|
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint8_t udp_header_size = 8;
|
||||||
|
uint16_t udp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||||
|
uint16_t udp_data_size = (udp_size - (uint16_t)udp_header_size);
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (udp_data_size > MaxSize || udp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - udp_header_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the udp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the UDP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate + udp_header_size, udp_data_size, udp_data_size);
|
||||||
|
|
||||||
|
// Drop checksum
|
||||||
|
// Stricto sensu, UDPv6 makes checksums mandatory, but libslirp doesn't
|
||||||
|
// check that actually
|
||||||
|
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,121 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "../src/ip6.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 24) {
|
||||||
|
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't receive
|
||||||
|
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not UDP from the mutation strategy
|
||||||
|
if (ip_data[6] != IPPROTO_UDP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
|
||||||
|
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint8_t udp_header_size = 8;
|
||||||
|
uint16_t udp_size = ntohs(*(uint16_t *)(ip_data + 4));
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the udp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the UDP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, udp_header_size, udp_header_size);
|
||||||
|
|
||||||
|
// Drop checksum
|
||||||
|
// Stricto sensu, UDPv6 makes checksums mandatory, but libslirp doesn't
|
||||||
|
// check that actually
|
||||||
|
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,123 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
uint32_t ipsource;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 16) {
|
||||||
|
ipsource = * (uint32_t*) (ip_data + 12);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't mutate
|
||||||
|
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not UDP from the mutation strategy
|
||||||
|
if (ip_data[9] != IPPROTO_UDP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||||
|
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint8_t udp_header_size = 8;
|
||||||
|
uint16_t udp_size = ntohs(*(uint16_t *)(start_of_udp + 4));
|
||||||
|
uint16_t udp_data_size = (udp_size - (uint16_t)udp_header_size);
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (udp_data_size > MaxSize || udp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - udp_header_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the udp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the UDP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate + udp_header_size, udp_data_size, udp_data_size);
|
||||||
|
|
||||||
|
// Drop checksum
|
||||||
|
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
|
@ -0,0 +1,122 @@
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/libslirp.h"
|
||||||
|
#include "helper.h"
|
||||||
|
#include "slirp_base_fuzz.h"
|
||||||
|
|
||||||
|
#ifdef CUSTOM_MUTATOR
|
||||||
|
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||||
|
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
|
||||||
|
|
||||||
|
/// This is a custom mutator, this allows us to mutate only specific parts of
|
||||||
|
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
|
||||||
|
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
|
||||||
|
size_t MaxSize, unsigned int Seed)
|
||||||
|
{
|
||||||
|
size_t current_size = Size;
|
||||||
|
uint8_t *Data_ptr = Data;
|
||||||
|
uint8_t *ip_data;
|
||||||
|
uint32_t ipsource;
|
||||||
|
bool mutated = false;
|
||||||
|
|
||||||
|
pcap_hdr_t *hdr = (void *)Data_ptr;
|
||||||
|
pcaprec_hdr_t *rec = NULL;
|
||||||
|
|
||||||
|
if (current_size < sizeof(pcap_hdr_t)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Data_ptr += sizeof(*hdr);
|
||||||
|
current_size -= sizeof(*hdr);
|
||||||
|
|
||||||
|
if (hdr->magic_number == 0xd4c3b2a1) {
|
||||||
|
g_debug("FIXME: byteswap fields");
|
||||||
|
return 0;
|
||||||
|
} /* else assume native pcap file */
|
||||||
|
if (hdr->network != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
|
||||||
|
rec = (void *)Data_ptr;
|
||||||
|
Data_ptr += sizeof(*rec);
|
||||||
|
current_size -= sizeof(*rec);
|
||||||
|
|
||||||
|
if (rec->incl_len != rec->orig_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len > current_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rec->incl_len < 14 + 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_data = Data_ptr + 14;
|
||||||
|
|
||||||
|
if (rec->incl_len >= 14 + 16) {
|
||||||
|
ipsource = * (uint32_t*) (ip_data + 12);
|
||||||
|
|
||||||
|
// This an answer, which we will produce, so don't mutate
|
||||||
|
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude packets that are not UDP from the mutation strategy
|
||||||
|
if (ip_data[9] != IPPROTO_UDP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t Data_to_mutate[MaxSize];
|
||||||
|
uint8_t ip_hl = (ip_data[0] & 0xF);
|
||||||
|
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (ip_hl_in_bytes > rec->incl_len - 14)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
|
||||||
|
uint8_t udp_header_size = 8;
|
||||||
|
uint16_t udp_size = ntohs(*(uint16_t *)(start_of_udp + 4));
|
||||||
|
|
||||||
|
// The size inside the packet can't be trusted, if it is too big it can
|
||||||
|
// lead to heap overflows in the fuzzing code.
|
||||||
|
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
|
||||||
|
// rec->incl_len and manually calculate the size.
|
||||||
|
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Copy interesting data to the `Data_to_mutate` array
|
||||||
|
// here we want to fuzz everything in the udp packet
|
||||||
|
memset(Data_to_mutate, 0, MaxSize);
|
||||||
|
memcpy(Data_to_mutate, start_of_udp, udp_size);
|
||||||
|
|
||||||
|
// Call to libfuzzer's mutation function.
|
||||||
|
// Pass the whole UDP packet, mutate it and then fix checksum value
|
||||||
|
// so the packet isn't rejected.
|
||||||
|
// The new size of the data is returned by LLVMFuzzerMutate.
|
||||||
|
// Fixme: allow to change the size of the UDP packet, this will require
|
||||||
|
// to fix the size before calculating the new checksum and change
|
||||||
|
// how the Data_ptr is advanced.
|
||||||
|
// Most offsets bellow should be good for when the switch will be
|
||||||
|
// done to avoid overwriting new/mutated data.
|
||||||
|
LLVMFuzzerMutate(Data_to_mutate, udp_header_size, udp_header_size);
|
||||||
|
|
||||||
|
// Drop checksum
|
||||||
|
*(uint16_t *)(Data_to_mutate + 6) = 0;
|
||||||
|
|
||||||
|
// Copy the mutated data back to the `Data` array
|
||||||
|
memcpy(start_of_udp, Data_to_mutate, udp_size);
|
||||||
|
|
||||||
|
mutated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mutated)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
#endif // CUSTOM_MUTATOR
|
Binary file not shown.
|
@ -0,0 +1,132 @@
|
||||||
|
//
|
||||||
|
// Created by nhp on 14-05-24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "glib.h"
|
||||||
|
|
||||||
|
GString* g_string_new(gchar* initial) {
|
||||||
|
GString* str = g_new0(GString, 1);
|
||||||
|
|
||||||
|
if (initial != NULL) {
|
||||||
|
int len = strlen(initial);
|
||||||
|
gchar* p = malloc(len);
|
||||||
|
memcpy(p, initial, len);
|
||||||
|
str->str = p;
|
||||||
|
str->len = len;
|
||||||
|
str->allocated_len = len;
|
||||||
|
} else {
|
||||||
|
gchar* p = malloc(64);
|
||||||
|
str->str = p;
|
||||||
|
str->len = 0;
|
||||||
|
str->allocated_len = 64;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar* g_string_free(GString* str, gboolean free_segment) {
|
||||||
|
char* seg = str->str;
|
||||||
|
free(str);
|
||||||
|
if (free_segment) {
|
||||||
|
free(str->str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return seg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void g_string_append_printf(GString* str, const gchar* format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int need_len = vsnprintf(NULL, 0, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (str->len + need_len + 1 < str->allocated_len) {
|
||||||
|
gsize new_len = str->len + need_len + 1;
|
||||||
|
gchar* newp = realloc(str->str, new_len);
|
||||||
|
str->str = newp;
|
||||||
|
str->allocated_len = new_len;
|
||||||
|
str->len = new_len - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar* temp = malloc(need_len + 1);
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(temp, need_len, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
strcat(str->str, temp);
|
||||||
|
free(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar* g_strstr_len(const gchar* haystack, int len, const gchar* needle) {
|
||||||
|
if (len == -1) return strstr(haystack, needle);
|
||||||
|
size_t needle_len = strlen(needle);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
size_t found = 0;
|
||||||
|
for (int j = i; j < len; j++) {
|
||||||
|
if (haystack[j] == needle[j - i]) found++;
|
||||||
|
else break;
|
||||||
|
if (found == needle_len) return (gchar*) haystack + j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar* g_strdup(const gchar* str) {
|
||||||
|
if (str == NULL) return NULL;
|
||||||
|
else return strdup(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int g_strv_length(GStrv strings) {
|
||||||
|
gint count = 0;
|
||||||
|
while (strings[count])
|
||||||
|
count++;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void g_strfreev(GStrv strings) {
|
||||||
|
for (int i = 0; strings[i] != NULL; i++) {
|
||||||
|
free(strings[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not good but all we're using slirp for is beaming pokemans over the internet so it's probably okay
|
||||||
|
gint g_rand_int_range(GRand* grand, gint min, gint max) {
|
||||||
|
double r = (double) rand();
|
||||||
|
double range = (double) (max - min);
|
||||||
|
double r2 = (r / (double) RAND_MAX) * range;
|
||||||
|
return MIN(max, ((int) r2) + min);
|
||||||
|
}
|
||||||
|
|
||||||
|
GRand* g_rand_new() {
|
||||||
|
return malloc(sizeof(GRand));
|
||||||
|
}
|
||||||
|
|
||||||
|
void g_rand_free(GRand* rand) {
|
||||||
|
free(rand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void g_error_free(GError* error) {
|
||||||
|
free(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean g_shell_parse_argv(const gchar* command_line, gint* argcp, gchar*** argvp, GError** error) {
|
||||||
|
const gchar* message = "Unimplemented.";
|
||||||
|
GError* err = malloc(sizeof(GError));
|
||||||
|
err->message = message;
|
||||||
|
*error = err;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean g_spawn_async_with_fds(const gchar *working_directory, gchar **argv,
|
||||||
|
gchar **envp, GSpawnFlags flags,
|
||||||
|
GSpawnChildSetupFunc child_setup,
|
||||||
|
gpointer user_data, GPid *child_pid, gint stdin_fd,
|
||||||
|
gint stdout_fd, gint stderr_fd, GError **error)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
#ifndef GLIB_SHIM_H
|
||||||
|
#define GLIB_SHIM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(_MSC_VER)
|
||||||
|
#define G_OS_WIN32 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define G_LITTLE_ENDIAN 0
|
||||||
|
#define G_BIG_ENDIAN 1
|
||||||
|
#define G_BYTE_ORDER G_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
#define GUINT16_FROM_BE(n) ntohs(n)
|
||||||
|
#define GUINT16_TO_BE(n) htons(n)
|
||||||
|
#define GUINT32_FROM_BE(n) ntohl(n)
|
||||||
|
#define GUINT32_TO_BE(n) htonl(n)
|
||||||
|
|
||||||
|
#define GINT16_TO_BE(n) (int16_t) htons(n)
|
||||||
|
#define GINT16_FROM_BE(n) (int16_t) ntohs(n)
|
||||||
|
#define GINT32_TO_BE(n) (int32_t) htonl(n)
|
||||||
|
#define GINT32_FROM_BE(n) (int32_t) ntohl(n)
|
||||||
|
|
||||||
|
#define G_N_ELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||||
|
|
||||||
|
#define G_GNUC_PRINTF(x, y)
|
||||||
|
|
||||||
|
#define GLIB_CHECK_VERSION(x, y, z) 1
|
||||||
|
#define G_STATIC_ASSERT(...)
|
||||||
|
#define g_assert assert
|
||||||
|
#define G_UNLIKELY(x) __builtin_expect(x, 0)
|
||||||
|
|
||||||
|
#define g_return_if_fail(expr) \
|
||||||
|
do { \
|
||||||
|
if (!(expr)) \
|
||||||
|
return; \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define g_return_val_if_fail(expr, val) \
|
||||||
|
do { \
|
||||||
|
if (!(expr)) \
|
||||||
|
return (val); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define g_warn_if_reached() \
|
||||||
|
do { \
|
||||||
|
g_warning("g_warn_if_reached: Reached " __FILE__ ":%d", __LINE__); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
|
||||||
|
#define g_warn_if_fail(expr) \
|
||||||
|
do { \
|
||||||
|
if (!(expr)) \
|
||||||
|
g_warning("g_warn_if_fail: Expression '" #expr "' failed at " __FILE__ ":%d", __LINE__); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define g_assert_not_reached() \
|
||||||
|
do { \
|
||||||
|
assert(false && "g_assert_not_reached"); \
|
||||||
|
__builtin_unreachable(); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define GLIB_SIZEOF_VOID_P 8
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) (a > b ? a : b)
|
||||||
|
#endif
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) (a < b ? a : b)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE true
|
||||||
|
#endif
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef bool gboolean;
|
||||||
|
typedef char gchar;
|
||||||
|
typedef int gint;
|
||||||
|
typedef size_t gsize;
|
||||||
|
typedef void* gpointer;
|
||||||
|
|
||||||
|
#define g_debug(format, ...) printf("[" G_LOG_DOMAIN ": debug] " format, ##__VA_ARGS__)
|
||||||
|
#define g_warning(format, ...) printf("[" G_LOG_DOMAIN ": warning] " format, ##__VA_ARGS__)
|
||||||
|
#define g_error(format, ...) printf("[" G_LOG_DOMAIN ": error] " format, ##__VA_ARGS__)
|
||||||
|
#define g_critical(format, ...) printf("[" G_LOG_DOMAIN ": critical] " format, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define g_new(type, count) (type*) (count > 0 ? malloc(sizeof(type) * count) : NULL)
|
||||||
|
#define g_new0(type, count) (type*) (count > 0 ? calloc(count, sizeof(type)) : NULL)
|
||||||
|
|
||||||
|
#define g_malloc malloc
|
||||||
|
#define g_malloc0(size) calloc(1, size)
|
||||||
|
#define g_realloc realloc
|
||||||
|
#define g_free free
|
||||||
|
|
||||||
|
#define g_getenv(var) getenv(var)
|
||||||
|
|
||||||
|
typedef struct GString {
|
||||||
|
gchar* str;
|
||||||
|
gsize len;
|
||||||
|
gsize allocated_len;
|
||||||
|
} GString;
|
||||||
|
|
||||||
|
typedef gchar** GStrv;
|
||||||
|
|
||||||
|
GString* g_string_new(gchar* initial);
|
||||||
|
gchar* g_string_free(GString* string, gboolean free_segment);
|
||||||
|
void g_string_append_printf(GString* gstr, const gchar* format, ...);
|
||||||
|
gchar* g_strstr_len(const gchar* haystack, int len, const gchar* needle);
|
||||||
|
gchar* g_strdup(const gchar* str);
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define g_ascii_strcasecmp(a, b) stricmp(a, b)
|
||||||
|
#else
|
||||||
|
#define g_ascii_strcasecmp(a, b) strcasecmp(a, b)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define g_str_has_prefix(str, pfx) (strncmp(str, pfx, strlen(pfx)) == 0)
|
||||||
|
#define g_snprintf snprintf
|
||||||
|
#define g_vsnprintf vsnprintf
|
||||||
|
|
||||||
|
gint g_strv_length(GStrv strings);
|
||||||
|
void g_strfreev(GStrv strings);
|
||||||
|
|
||||||
|
typedef uint32_t GRand;
|
||||||
|
gint g_rand_int_range(GRand* grand, gint min, gint max);
|
||||||
|
GRand* g_rand_new();
|
||||||
|
void g_rand_free(GRand* rand);
|
||||||
|
|
||||||
|
typedef struct GError {
|
||||||
|
const gchar* message;
|
||||||
|
} GError;
|
||||||
|
|
||||||
|
void g_error_free(GError* error);
|
||||||
|
#define g_strerror(err) strerror(err)
|
||||||
|
|
||||||
|
typedef void (*GSpawnChildSetupFunc)(gpointer ptr);
|
||||||
|
typedef enum GSpawnFlags {
|
||||||
|
G_SPAWN_SEARCH_PATH
|
||||||
|
} GSpawnFlags;
|
||||||
|
|
||||||
|
typedef gint GPid;
|
||||||
|
|
||||||
|
gboolean g_shell_parse_argv(const gchar* command_line, gint* argcp, gchar*** argvp, GError** error);
|
||||||
|
|
||||||
|
gboolean g_spawn_async_with_fds(const gchar *working_directory, gchar **argv,
|
||||||
|
gchar **envp, GSpawnFlags flags,
|
||||||
|
GSpawnChildSetupFunc child_setup,
|
||||||
|
gpointer user_data, GPid *child_pid, gint stdin_fd,
|
||||||
|
gint stdout_fd, gint stderr_fd, GError **error);
|
||||||
|
|
||||||
|
typedef struct { gchar* key; int value; } GDebugKey;
|
||||||
|
#define g_parse_debug_string(str, keys, nkeys) 0
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,248 @@
|
||||||
|
project('libslirp', 'c',
|
||||||
|
version : '4.8.0',
|
||||||
|
license : 'BSD-3-Clause',
|
||||||
|
default_options : ['warning_level=1', 'c_std=gnu99'],
|
||||||
|
meson_version : '>= 0.50',
|
||||||
|
)
|
||||||
|
|
||||||
|
version = meson.project_version()
|
||||||
|
varr = version.split('.')
|
||||||
|
major_version = varr[0]
|
||||||
|
minor_version = varr[1]
|
||||||
|
micro_version = varr[2]
|
||||||
|
|
||||||
|
conf = configuration_data()
|
||||||
|
conf.set('SLIRP_MAJOR_VERSION', major_version)
|
||||||
|
conf.set('SLIRP_MINOR_VERSION', minor_version)
|
||||||
|
conf.set('SLIRP_MICRO_VERSION', micro_version)
|
||||||
|
|
||||||
|
want_ossfuzz = get_option('oss-fuzz')
|
||||||
|
want_libfuzzer = get_option('llvm-fuzz')
|
||||||
|
fuzz_reproduce = get_option('fuzz-reproduce')
|
||||||
|
if want_ossfuzz and want_libfuzzer
|
||||||
|
error('only one of oss-fuzz and llvm-fuzz can be specified')
|
||||||
|
endif
|
||||||
|
fuzzer_build = want_ossfuzz or want_libfuzzer
|
||||||
|
if fuzzer_build and fuzz_reproduce
|
||||||
|
error('fuzzer build and reproducer build are mutually exclusive')
|
||||||
|
endif
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
add_languages('cpp', required : fuzzer_build)
|
||||||
|
|
||||||
|
if get_option('static') == true
|
||||||
|
add_global_arguments('-static', language : 'c')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if cc.get_argument_syntax() != 'msvc'
|
||||||
|
r = run_command('build-aux/git-version-gen',
|
||||||
|
'@0@/.tarball-version'.format(meson.current_source_dir()),
|
||||||
|
check : false)
|
||||||
|
|
||||||
|
full_version = r.stdout().strip()
|
||||||
|
if r.returncode() != 0 or full_version.startswith('UNKNOWN')
|
||||||
|
full_version = meson.project_version()
|
||||||
|
elif not full_version.startswith(meson.project_version())
|
||||||
|
error('meson.build project version @0@ does not match git-describe output @1@'
|
||||||
|
.format(meson.project_version(), full_version))
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
full_version = meson.project_version()
|
||||||
|
endif
|
||||||
|
conf.set_quoted('SLIRP_VERSION_STRING', full_version + get_option('version_suffix'))
|
||||||
|
|
||||||
|
# libtool versioning - this applies to libslirp
|
||||||
|
#
|
||||||
|
# See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details
|
||||||
|
#
|
||||||
|
# - If interfaces have been changed or added, but binary compatibility
|
||||||
|
# has been preserved, change:
|
||||||
|
# CURRENT += 1
|
||||||
|
# REVISION = 0
|
||||||
|
# AGE += 1
|
||||||
|
# - If binary compatibility has been broken (eg removed or changed
|
||||||
|
# interfaces), change:
|
||||||
|
# CURRENT += 1
|
||||||
|
# REVISION = 0
|
||||||
|
# AGE = 0
|
||||||
|
# - If the interface is the same as the previous version, but bugs are
|
||||||
|
# fixed, change:
|
||||||
|
# REVISION += 1
|
||||||
|
lt_current = 4
|
||||||
|
lt_revision = 0
|
||||||
|
lt_age = 4
|
||||||
|
lt_version = '@0@.@1@.@2@'.format(lt_current - lt_age, lt_age, lt_revision)
|
||||||
|
|
||||||
|
host_system = host_machine.system()
|
||||||
|
|
||||||
|
#glib_dep = dependency('glib-2.0', static : get_option('static'))
|
||||||
|
|
||||||
|
glib_dep = declare_dependency(
|
||||||
|
include_directories: [include_directories('glib', is_system: true)],
|
||||||
|
sources: ['glib/glib.c']
|
||||||
|
)
|
||||||
|
|
||||||
|
add_project_arguments(cc.get_supported_arguments('-Wmissing-prototypes', '-Wstrict-prototypes',
|
||||||
|
'-Wredundant-decls', '-Wundef', '-Wwrite-strings'),
|
||||||
|
language: 'c', native: false)
|
||||||
|
|
||||||
|
platform_deps = []
|
||||||
|
|
||||||
|
if host_system == 'windows'
|
||||||
|
platform_deps += [
|
||||||
|
cc.find_library('ws2_32'),
|
||||||
|
cc.find_library('iphlpapi')
|
||||||
|
]
|
||||||
|
elif host_system == 'darwin'
|
||||||
|
platform_deps += [
|
||||||
|
cc.find_library('resolv')
|
||||||
|
]
|
||||||
|
elif host_system == 'haiku'
|
||||||
|
platform_deps += [
|
||||||
|
cc.find_library('network')
|
||||||
|
]
|
||||||
|
endif
|
||||||
|
|
||||||
|
cargs = [
|
||||||
|
'-DG_LOG_DOMAIN="Slirp"',
|
||||||
|
'-DBUILDING_LIBSLIRP',
|
||||||
|
]
|
||||||
|
|
||||||
|
if cc.check_header('valgrind/valgrind.h')
|
||||||
|
cargs += [ '-DHAVE_VALGRIND=1' ]
|
||||||
|
endif
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
'src/arp_table.c',
|
||||||
|
'src/bootp.c',
|
||||||
|
'src/cksum.c',
|
||||||
|
'src/dhcpv6.c',
|
||||||
|
'src/dnssearch.c',
|
||||||
|
'src/if.c',
|
||||||
|
'src/ip6_icmp.c',
|
||||||
|
'src/ip6_input.c',
|
||||||
|
'src/ip6_output.c',
|
||||||
|
'src/ip_icmp.c',
|
||||||
|
'src/ip_input.c',
|
||||||
|
'src/ip_output.c',
|
||||||
|
'src/mbuf.c',
|
||||||
|
'src/misc.c',
|
||||||
|
'src/ncsi.c',
|
||||||
|
'src/ndp_table.c',
|
||||||
|
'src/sbuf.c',
|
||||||
|
'src/slirp.c',
|
||||||
|
'src/socket.c',
|
||||||
|
'src/state.c',
|
||||||
|
'src/stream.c',
|
||||||
|
'src/tcp_input.c',
|
||||||
|
'src/tcp_output.c',
|
||||||
|
'src/tcp_subr.c',
|
||||||
|
'src/tcp_timer.c',
|
||||||
|
'src/tftp.c',
|
||||||
|
'src/udp.c',
|
||||||
|
'src/udp6.c',
|
||||||
|
'src/util.c',
|
||||||
|
'src/version.c',
|
||||||
|
'src/vmstate.c',
|
||||||
|
]
|
||||||
|
|
||||||
|
mapfile = 'src/libslirp.map'
|
||||||
|
vflag = []
|
||||||
|
vflag_test = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
|
||||||
|
if cc.has_link_argument('-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), 'src/libslirp.test.map'))
|
||||||
|
vflag += vflag_test
|
||||||
|
endif
|
||||||
|
|
||||||
|
if fuzzer_build
|
||||||
|
cargs += '-fsanitize-coverage=edge,indirect-calls,trace-cmp'
|
||||||
|
cargs += '-fsanitize=fuzzer-no-link,address'
|
||||||
|
cargs += '-fprofile-instr-generate'
|
||||||
|
cargs += '-fcoverage-mapping'
|
||||||
|
cargs += '-g'
|
||||||
|
cargs += '-DSLIRP_DEBUG'
|
||||||
|
vflag += '-fsanitize=fuzzer-no-link,address'
|
||||||
|
vflag += '-fsanitize-coverage=edge,indirect-calls,trace-cmp'
|
||||||
|
vflag += '-fprofile-instr-generate'
|
||||||
|
vflag += '-fcoverage-mapping'
|
||||||
|
endif
|
||||||
|
if fuzz_reproduce
|
||||||
|
cargs += '-DSLIRP_DEBUG'
|
||||||
|
cargs += '-g'
|
||||||
|
endif
|
||||||
|
|
||||||
|
install_devel = not meson.is_subproject()
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
input : 'src/libslirp-version.h.in',
|
||||||
|
output : 'libslirp-version.h',
|
||||||
|
install : install_devel,
|
||||||
|
install_dir : join_paths(get_option('includedir'), 'slirp'),
|
||||||
|
configuration : conf
|
||||||
|
)
|
||||||
|
|
||||||
|
if fuzzer_build or fuzz_reproduce
|
||||||
|
lib = static_library('slirp', sources,
|
||||||
|
c_args : cargs,
|
||||||
|
link_args : vflag,
|
||||||
|
link_depends : mapfile,
|
||||||
|
dependencies : [glib_dep, platform_deps],
|
||||||
|
)
|
||||||
|
else
|
||||||
|
lib = library('slirp', sources,
|
||||||
|
version : lt_version,
|
||||||
|
c_args : cargs,
|
||||||
|
link_args : vflag,
|
||||||
|
link_depends : mapfile,
|
||||||
|
dependencies : [glib_dep, platform_deps],
|
||||||
|
install : install_devel or get_option('default_library') == 'shared',
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
pingtest = executable('pingtest', 'test/pingtest.c',
|
||||||
|
link_with: [ lib ],
|
||||||
|
c_args : cargs,
|
||||||
|
link_args : vflag,
|
||||||
|
include_directories: [ 'src' ],
|
||||||
|
dependencies : [ platform_deps ]
|
||||||
|
)
|
||||||
|
|
||||||
|
test('ping', pingtest)
|
||||||
|
|
||||||
|
ncsitest = executable('ncsitest', 'test/ncsitest.c',
|
||||||
|
link_with: [lib],
|
||||||
|
c_args : cargs,
|
||||||
|
link_args : vflag,
|
||||||
|
include_directories: ['src'],
|
||||||
|
dependencies: [glib_dep, platform_deps]
|
||||||
|
)
|
||||||
|
|
||||||
|
test('ncsi', ncsitest)
|
||||||
|
|
||||||
|
if install_devel
|
||||||
|
install_headers(['src/libslirp.h'], subdir : 'slirp')
|
||||||
|
|
||||||
|
pkg = import('pkgconfig')
|
||||||
|
|
||||||
|
pkg.generate(
|
||||||
|
version : version,
|
||||||
|
libraries : lib,
|
||||||
|
requires : [
|
||||||
|
'glib-2.0',
|
||||||
|
],
|
||||||
|
name : 'slirp',
|
||||||
|
description : 'User-space network stack',
|
||||||
|
filebase : 'slirp',
|
||||||
|
subdirs : 'slirp',
|
||||||
|
)
|
||||||
|
else
|
||||||
|
if get_option('default_library') == 'both'
|
||||||
|
lib = lib.get_static_lib()
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
libslirp_dep = declare_dependency(
|
||||||
|
link_with : lib,
|
||||||
|
include_directories : [include_directories('src'), include_directories('.')],
|
||||||
|
)
|
||||||
|
|
||||||
|
subdir('fuzzing')
|
|
@ -0,0 +1,14 @@
|
||||||
|
option('version_suffix', type: 'string', value: '',
|
||||||
|
description: 'Suffix to append to SLIRP_VERSION_STRING')
|
||||||
|
|
||||||
|
option('oss-fuzz', type : 'boolean', value : 'false',
|
||||||
|
description : 'build against oss-fuzz')
|
||||||
|
|
||||||
|
option('llvm-fuzz', type : 'boolean', value : 'false',
|
||||||
|
description : 'build against LLVM libFuzzer')
|
||||||
|
|
||||||
|
option('fuzz-reproduce', type : 'boolean', value : 'false',
|
||||||
|
description : 'build a standalone executable to reproduce fuzz cases')
|
||||||
|
|
||||||
|
option('static', type : 'boolean', value : 'false',
|
||||||
|
description : 'build static binary, only for debugging, otherwise rather use --default-library static')
|
|
@ -0,0 +1,98 @@
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/*
|
||||||
|
* ARP table
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 AdaCore
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "slirp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void arp_table_add(Slirp *slirp, uint32_t ip_addr,
|
||||||
|
const uint8_t ethaddr[ETH_ALEN])
|
||||||
|
{
|
||||||
|
const uint32_t broadcast_addr =
|
||||||
|
~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
|
||||||
|
ArpTable *arptbl = &slirp->arp_table;
|
||||||
|
int i;
|
||||||
|
char ethaddr_str[ETH_ADDRSTRLEN];
|
||||||
|
char addr[INET_ADDRSTRLEN];
|
||||||
|
|
||||||
|
DEBUG_CALL("arp_table_add");
|
||||||
|
DEBUG_ARG("ip = %s", inet_ntop(AF_INET, &(struct in_addr){ .s_addr = ip_addr },
|
||||||
|
addr, sizeof(addr)));
|
||||||
|
DEBUG_ARG("hw addr = %s", slirp_ether_ntoa(ethaddr, ethaddr_str,
|
||||||
|
sizeof(ethaddr_str)));
|
||||||
|
|
||||||
|
if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
|
||||||
|
/* Do not register broadcast addresses */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for an entry */
|
||||||
|
for (i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||||
|
if (arptbl->table[i].ar_sip == ip_addr) {
|
||||||
|
/* Update the entry */
|
||||||
|
memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No entry found, create a new one */
|
||||||
|
arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
|
||||||
|
memcpy(arptbl->table[arptbl->next_victim].ar_sha, ethaddr, ETH_ALEN);
|
||||||
|
arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
|
||||||
|
uint8_t out_ethaddr[ETH_ALEN])
|
||||||
|
{
|
||||||
|
const uint32_t broadcast_addr =
|
||||||
|
~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
|
||||||
|
ArpTable *arptbl = &slirp->arp_table;
|
||||||
|
int i;
|
||||||
|
char ethaddr_str[ETH_ADDRSTRLEN];
|
||||||
|
char addr[INET_ADDRSTRLEN];
|
||||||
|
|
||||||
|
DEBUG_CALL("arp_table_search");
|
||||||
|
DEBUG_ARG("ip = %s", inet_ntop(AF_INET, &(struct in_addr){ .s_addr = ip_addr },
|
||||||
|
addr, sizeof(addr)));
|
||||||
|
|
||||||
|
/* If broadcast address */
|
||||||
|
if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
|
||||||
|
/* return Ethernet broadcast address */
|
||||||
|
memset(out_ethaddr, 0xff, ETH_ALEN);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||||
|
if (arptbl->table[i].ar_sip == ip_addr) {
|
||||||
|
memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN);
|
||||||
|
DEBUG_ARG("found hw addr = %s",
|
||||||
|
slirp_ether_ntoa(out_ethaddr, ethaddr_str,
|
||||||
|
sizeof(ethaddr_str)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,398 @@
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/*
|
||||||
|
* QEMU BOOTP/DHCP server
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "slirp.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
/* Windows ntohl() returns an u_long value.
|
||||||
|
* Add a type cast to match the format strings. */
|
||||||
|
#define ntohl(n) ((uint32_t)ntohl(n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* XXX: only DHCP is supported */
|
||||||
|
|
||||||
|
#define LEASE_TIME (24 * 3600)
|
||||||
|
|
||||||
|
#define UEFI_HTTP_VENDOR_CLASS_ID "HTTPClient"
|
||||||
|
|
||||||
|
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
|
||||||
|
|
||||||
|
#define DPRINTF(...) DEBUG_RAW_CALL(__VA_ARGS__)
|
||||||
|
|
||||||
|
static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
|
||||||
|
const uint8_t *macaddr)
|
||||||
|
{
|
||||||
|
BOOTPClient *bc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
|
||||||
|
bc = &slirp->bootp_clients[i];
|
||||||
|
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
found:
|
||||||
|
bc = &slirp->bootp_clients[i];
|
||||||
|
bc->allocated = 1;
|
||||||
|
paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
|
||||||
|
return bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
|
||||||
|
const uint8_t *macaddr)
|
||||||
|
{
|
||||||
|
uint32_t req_addr = ntohl(paddr->s_addr);
|
||||||
|
uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
|
||||||
|
BOOTPClient *bc;
|
||||||
|
|
||||||
|
if (req_addr >= dhcp_addr && req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
|
||||||
|
bc = &slirp->bootp_clients[req_addr - dhcp_addr];
|
||||||
|
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
|
||||||
|
bc->allocated = 1;
|
||||||
|
return bc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
|
||||||
|
const uint8_t *macaddr)
|
||||||
|
{
|
||||||
|
BOOTPClient *bc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
|
||||||
|
if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
found:
|
||||||
|
bc = &slirp->bootp_clients[i];
|
||||||
|
bc->allocated = 1;
|
||||||
|
paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
|
||||||
|
return bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dhcp_decode(const struct bootp_t *bp,
|
||||||
|
const uint8_t *bp_end,
|
||||||
|
int *pmsg_type,
|
||||||
|
struct in_addr *preq_addr)
|
||||||
|
{
|
||||||
|
const uint8_t *p;
|
||||||
|
int len, tag;
|
||||||
|
|
||||||
|
*pmsg_type = 0;
|
||||||
|
preq_addr->s_addr = htonl(0L);
|
||||||
|
|
||||||
|
p = bp->bp_vend;
|
||||||
|
if (memcmp(p, rfc1533_cookie, 4) != 0)
|
||||||
|
return;
|
||||||
|
p += 4;
|
||||||
|
while (p < bp_end) {
|
||||||
|
tag = p[0];
|
||||||
|
if (tag == RFC1533_PAD) {
|
||||||
|
p++;
|
||||||
|
} else if (tag == RFC1533_END) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
p++;
|
||||||
|
if (p >= bp_end)
|
||||||
|
break;
|
||||||
|
len = *p++;
|
||||||
|
if (p + len > bp_end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case RFC2132_MSG_TYPE:
|
||||||
|
if (len >= 1)
|
||||||
|
*pmsg_type = p[0];
|
||||||
|
break;
|
||||||
|
case RFC2132_REQ_ADDR:
|
||||||
|
if (len >= 4) {
|
||||||
|
memcpy(&(preq_addr->s_addr), p, 4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
|
||||||
|
bp->bp_ciaddr.s_addr) {
|
||||||
|
memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bootp_reply(Slirp *slirp,
|
||||||
|
const struct bootp_t *bp,
|
||||||
|
const uint8_t *bp_end)
|
||||||
|
{
|
||||||
|
BOOTPClient *bc = NULL;
|
||||||
|
struct mbuf *m;
|
||||||
|
struct bootp_t *rbp;
|
||||||
|
struct sockaddr_in saddr, daddr;
|
||||||
|
struct in_addr preq_addr;
|
||||||
|
int dhcp_msg_type, val;
|
||||||
|
uint8_t *q;
|
||||||
|
uint8_t *end;
|
||||||
|
uint8_t client_ethaddr[ETH_ALEN];
|
||||||
|
|
||||||
|
/* extract exact DHCP msg type */
|
||||||
|
dhcp_decode(bp, bp_end, &dhcp_msg_type, &preq_addr);
|
||||||
|
DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
|
||||||
|
if (preq_addr.s_addr != htonl(0L))
|
||||||
|
DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
|
||||||
|
else {
|
||||||
|
DPRINTF("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dhcp_msg_type == 0)
|
||||||
|
dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
|
||||||
|
|
||||||
|
if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Get client's hardware address from bootp request */
|
||||||
|
memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
|
||||||
|
|
||||||
|
m = m_get(slirp);
|
||||||
|
if (!m) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m->m_data += IF_MAXLINKHDR;
|
||||||
|
m_inc(m, sizeof(struct bootp_t) + DHCP_OPT_LEN);
|
||||||
|
rbp = (struct bootp_t *)m->m_data;
|
||||||
|
m->m_data += sizeof(struct udpiphdr);
|
||||||
|
memset(rbp, 0, sizeof(struct bootp_t) + DHCP_OPT_LEN);
|
||||||
|
|
||||||
|
if (dhcp_msg_type == DHCPDISCOVER) {
|
||||||
|
if (preq_addr.s_addr != htonl(0L)) {
|
||||||
|
bc = request_addr(slirp, &preq_addr, client_ethaddr);
|
||||||
|
if (bc) {
|
||||||
|
daddr.sin_addr = preq_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bc) {
|
||||||
|
new_addr:
|
||||||
|
bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
|
||||||
|
if (!bc) {
|
||||||
|
DPRINTF("no address left\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
|
||||||
|
} else if (preq_addr.s_addr != htonl(0L)) {
|
||||||
|
bc = request_addr(slirp, &preq_addr, client_ethaddr);
|
||||||
|
if (bc) {
|
||||||
|
daddr.sin_addr = preq_addr;
|
||||||
|
memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
|
||||||
|
} else {
|
||||||
|
/* DHCPNAKs should be sent to broadcast */
|
||||||
|
daddr.sin_addr.s_addr = 0xffffffff;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr);
|
||||||
|
if (!bc) {
|
||||||
|
/* if never assigned, behaves as if it was already
|
||||||
|
assigned (windows fix because it remembers its address) */
|
||||||
|
goto new_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update ARP table for this IP address */
|
||||||
|
arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
|
||||||
|
|
||||||
|
saddr.sin_addr = slirp->vhost_addr;
|
||||||
|
saddr.sin_port = htons(BOOTP_SERVER);
|
||||||
|
|
||||||
|
daddr.sin_port = htons(BOOTP_CLIENT);
|
||||||
|
|
||||||
|
rbp->bp_op = BOOTP_REPLY;
|
||||||
|
rbp->bp_xid = bp->bp_xid;
|
||||||
|
rbp->bp_htype = 1;
|
||||||
|
rbp->bp_hlen = 6;
|
||||||
|
memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
|
||||||
|
|
||||||
|
rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
|
||||||
|
rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
|
||||||
|
|
||||||
|
q = rbp->bp_vend;
|
||||||
|
end = rbp->bp_vend + DHCP_OPT_LEN;
|
||||||
|
memcpy(q, rfc1533_cookie, 4);
|
||||||
|
q += 4;
|
||||||
|
|
||||||
|
if (bc) {
|
||||||
|
DPRINTF("%s addr=%08" PRIx32 "\n",
|
||||||
|
(dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
|
||||||
|
ntohl(daddr.sin_addr.s_addr));
|
||||||
|
|
||||||
|
if (dhcp_msg_type == DHCPDISCOVER) {
|
||||||
|
*q++ = RFC2132_MSG_TYPE;
|
||||||
|
*q++ = 1;
|
||||||
|
*q++ = DHCPOFFER;
|
||||||
|
} else /* DHCPREQUEST */ {
|
||||||
|
*q++ = RFC2132_MSG_TYPE;
|
||||||
|
*q++ = 1;
|
||||||
|
*q++ = DHCPACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slirp->bootp_filename) {
|
||||||
|
g_assert(strlen(slirp->bootp_filename) < sizeof(rbp->bp_file));
|
||||||
|
strcpy(rbp->bp_file, slirp->bootp_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
*q++ = RFC2132_SRV_ID;
|
||||||
|
*q++ = 4;
|
||||||
|
memcpy(q, &saddr.sin_addr, 4);
|
||||||
|
q += 4;
|
||||||
|
|
||||||
|
*q++ = RFC1533_NETMASK;
|
||||||
|
*q++ = 4;
|
||||||
|
memcpy(q, &slirp->vnetwork_mask, 4);
|
||||||
|
q += 4;
|
||||||
|
|
||||||
|
if (!slirp->restricted) {
|
||||||
|
*q++ = RFC1533_GATEWAY;
|
||||||
|
*q++ = 4;
|
||||||
|
memcpy(q, &saddr.sin_addr, 4);
|
||||||
|
q += 4;
|
||||||
|
|
||||||
|
*q++ = RFC1533_DNS;
|
||||||
|
*q++ = 4;
|
||||||
|
memcpy(q, &slirp->vnameserver_addr, 4);
|
||||||
|
q += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
*q++ = RFC2132_LEASE_TIME;
|
||||||
|
*q++ = 4;
|
||||||
|
val = htonl(LEASE_TIME);
|
||||||
|
memcpy(q, &val, 4);
|
||||||
|
q += 4;
|
||||||
|
|
||||||
|
if (*slirp->client_hostname) {
|
||||||
|
val = strlen(slirp->client_hostname);
|
||||||
|
if (q + val + 2 >= end) {
|
||||||
|
g_warning("DHCP packet size exceeded, "
|
||||||
|
"omitting host name option.");
|
||||||
|
} else {
|
||||||
|
*q++ = RFC1533_HOSTNAME;
|
||||||
|
*q++ = val;
|
||||||
|
memcpy(q, slirp->client_hostname, val);
|
||||||
|
q += val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slirp->vdomainname) {
|
||||||
|
val = strlen(slirp->vdomainname);
|
||||||
|
if (q + val + 2 >= end) {
|
||||||
|
g_warning("DHCP packet size exceeded, "
|
||||||
|
"omitting domain name option.");
|
||||||
|
} else {
|
||||||
|
*q++ = RFC1533_DOMAINNAME;
|
||||||
|
*q++ = val;
|
||||||
|
memcpy(q, slirp->vdomainname, val);
|
||||||
|
q += val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slirp->tftp_server_name) {
|
||||||
|
val = strlen(slirp->tftp_server_name);
|
||||||
|
if (q + val + 2 >= end) {
|
||||||
|
g_warning("DHCP packet size exceeded, "
|
||||||
|
"omitting tftp-server-name option.");
|
||||||
|
} else {
|
||||||
|
*q++ = RFC2132_TFTP_SERVER_NAME;
|
||||||
|
*q++ = val;
|
||||||
|
memcpy(q, slirp->tftp_server_name, val);
|
||||||
|
q += val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slirp->vdnssearch) {
|
||||||
|
val = slirp->vdnssearch_len;
|
||||||
|
if (q + val >= end) {
|
||||||
|
g_warning("DHCP packet size exceeded, "
|
||||||
|
"omitting domain-search option.");
|
||||||
|
} else {
|
||||||
|
memcpy(q, slirp->vdnssearch, val);
|
||||||
|
q += val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this allows to support UEFI HTTP boot: according to the UEFI
|
||||||
|
specification, DHCP server must send vendor class identifier option
|
||||||
|
set to "HTTPClient" string, when responding to DHCP requests as part
|
||||||
|
of the UEFI HTTP boot
|
||||||
|
|
||||||
|
we assume that, if the bootfile parameter was configured as an http
|
||||||
|
URL, the user intends to perform UEFI HTTP boot, so send this option
|
||||||
|
automatically */
|
||||||
|
if (slirp->bootp_filename && g_str_has_prefix(slirp->bootp_filename, "http://")) {
|
||||||
|
val = strlen(UEFI_HTTP_VENDOR_CLASS_ID);
|
||||||
|
if (q + val + 2 >= end) {
|
||||||
|
g_warning("DHCP packet size exceeded, "
|
||||||
|
"omitting vendor class id option.");
|
||||||
|
} else {
|
||||||
|
*q++ = RFC2132_VENDOR_CLASS_ID;
|
||||||
|
*q++ = val;
|
||||||
|
memcpy(q, UEFI_HTTP_VENDOR_CLASS_ID, val);
|
||||||
|
q += val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
static const char nak_msg[] = "requested address not available";
|
||||||
|
|
||||||
|
DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
|
||||||
|
|
||||||
|
*q++ = RFC2132_MSG_TYPE;
|
||||||
|
*q++ = 1;
|
||||||
|
*q++ = DHCPNAK;
|
||||||
|
|
||||||
|
*q++ = RFC2132_MESSAGE;
|
||||||
|
*q++ = sizeof(nak_msg) - 1;
|
||||||
|
memcpy(q, nak_msg, sizeof(nak_msg) - 1);
|
||||||
|
q += sizeof(nak_msg) - 1;
|
||||||
|
}
|
||||||
|
assert(q < end);
|
||||||
|
*q++ = RFC1533_END;
|
||||||
|
|
||||||
|
daddr.sin_addr.s_addr = 0xffffffffu;
|
||||||
|
|
||||||
|
assert(q <= end);
|
||||||
|
|
||||||
|
m->m_len = sizeof(struct bootp_t) + (end - rbp->bp_vend) - sizeof(struct ip) - sizeof(struct udphdr);
|
||||||
|
udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootp_input(struct mbuf *m)
|
||||||
|
{
|
||||||
|
struct bootp_t *bp = mtod_check(m, sizeof(struct bootp_t));
|
||||||
|
|
||||||
|
if (!m->slirp->disable_dhcp && bp && bp->bp_op == BOOTP_REQUEST) {
|
||||||
|
bootp_reply(m->slirp, bp, m_end(m));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||||
|
/* bootp/dhcp defines */
|
||||||
|
|
||||||
|
#ifndef SLIRP_BOOTP_H
|
||||||
|
#define SLIRP_BOOTP_H
|
||||||
|
|
||||||
|
#define BOOTP_SERVER 67
|
||||||
|
#define BOOTP_CLIENT 68
|
||||||
|
|
||||||
|
#define BOOTP_REQUEST 1
|
||||||
|
#define BOOTP_REPLY 2
|
||||||
|
|
||||||
|
#define RFC1533_COOKIE 99, 130, 83, 99
|
||||||
|
#define RFC1533_PAD 0
|
||||||
|
#define RFC1533_NETMASK 1
|
||||||
|
#define RFC1533_TIMEOFFSET 2
|
||||||
|
#define RFC1533_GATEWAY 3
|
||||||
|
#define RFC1533_TIMESERVER 4
|
||||||
|
#define RFC1533_IEN116NS 5
|
||||||
|
#define RFC1533_DNS 6
|
||||||
|
#define RFC1533_LOGSERVER 7
|
||||||
|
#define RFC1533_COOKIESERVER 8
|
||||||
|
#define RFC1533_LPRSERVER 9
|
||||||
|
#define RFC1533_IMPRESSSERVER 10
|
||||||
|
#define RFC1533_RESOURCESERVER 11
|
||||||
|
#define RFC1533_HOSTNAME 12
|
||||||
|
#define RFC1533_BOOTFILESIZE 13
|
||||||
|
#define RFC1533_MERITDUMPFILE 14
|
||||||
|
#define RFC1533_DOMAINNAME 15
|
||||||
|
#define RFC1533_SWAPSERVER 16
|
||||||
|
#define RFC1533_ROOTPATH 17
|
||||||
|
#define RFC1533_EXTENSIONPATH 18
|
||||||
|
#define RFC1533_IPFORWARDING 19
|
||||||
|
#define RFC1533_IPSOURCEROUTING 20
|
||||||
|
#define RFC1533_IPPOLICYFILTER 21
|
||||||
|
#define RFC1533_IPMAXREASSEMBLY 22
|
||||||
|
#define RFC1533_IPTTL 23
|
||||||
|
#define RFC1533_IPMTU 24
|
||||||
|
#define RFC1533_IPMTUPLATEAU 25
|
||||||
|
#define RFC1533_INTMTU 26
|
||||||
|
#define RFC1533_INTLOCALSUBNETS 27
|
||||||
|
#define RFC1533_INTBROADCAST 28
|
||||||
|
#define RFC1533_INTICMPDISCOVER 29
|
||||||
|
#define RFC1533_INTICMPRESPOND 30
|
||||||
|
#define RFC1533_INTROUTEDISCOVER 31
|
||||||
|
#define RFC1533_INTROUTESOLICIT 32
|
||||||
|
#define RFC1533_INTSTATICROUTES 33
|
||||||
|
#define RFC1533_LLTRAILERENCAP 34
|
||||||
|
#define RFC1533_LLARPCACHETMO 35
|
||||||
|
#define RFC1533_LLETHERNETENCAP 36
|
||||||
|
#define RFC1533_TCPTTL 37
|
||||||
|
#define RFC1533_TCPKEEPALIVETMO 38
|
||||||
|
#define RFC1533_TCPKEEPALIVEGB 39
|
||||||
|
#define RFC1533_NISDOMAIN 40
|
||||||
|
#define RFC1533_NISSERVER 41
|
||||||
|
#define RFC1533_NTPSERVER 42
|
||||||
|
#define RFC1533_VENDOR 43
|
||||||
|
#define RFC1533_NBNS 44
|
||||||
|
#define RFC1533_NBDD 45
|
||||||
|
#define RFC1533_NBNT 46
|
||||||
|
#define RFC1533_NBSCOPE 47
|
||||||
|
#define RFC1533_XFS 48
|
||||||
|
#define RFC1533_XDM 49
|
||||||
|
|
||||||
|
#define RFC2132_REQ_ADDR 50
|
||||||
|
#define RFC2132_LEASE_TIME 51
|
||||||
|
#define RFC2132_MSG_TYPE 53
|
||||||
|
#define RFC2132_SRV_ID 54
|
||||||
|
#define RFC2132_PARAM_LIST 55
|
||||||
|
#define RFC2132_MESSAGE 56
|
||||||
|
#define RFC2132_MAX_SIZE 57
|
||||||
|
#define RFC2132_RENEWAL_TIME 58
|
||||||
|
#define RFC2132_REBIND_TIME 59
|
||||||
|
#define RFC2132_VENDOR_CLASS_ID 60
|
||||||
|
#define RFC2132_TFTP_SERVER_NAME 66
|
||||||
|
|
||||||
|
#define DHCPDISCOVER 1
|
||||||
|
#define DHCPOFFER 2
|
||||||
|
#define DHCPREQUEST 3
|
||||||
|
#define DHCPACK 5
|
||||||
|
#define DHCPNAK 6
|
||||||
|
|
||||||
|
#define RFC1533_VENDOR_MAJOR 0
|
||||||
|
#define RFC1533_VENDOR_MINOR 0
|
||||||
|
|
||||||
|
#define RFC1533_VENDOR_MAGIC 128
|
||||||
|
#define RFC1533_VENDOR_ADDPARM 129
|
||||||
|
#define RFC1533_VENDOR_ETHDEV 130
|
||||||
|
#define RFC1533_VENDOR_HOWTO 132
|
||||||
|
#define RFC1533_VENDOR_MNUOPTS 160
|
||||||
|
#define RFC1533_VENDOR_SELECTION 176
|
||||||
|
#define RFC1533_VENDOR_MOTD 184
|
||||||
|
#define RFC1533_VENDOR_NUMOFMOTD 8
|
||||||
|
#define RFC1533_VENDOR_IMG 192
|
||||||
|
#define RFC1533_VENDOR_NUMOFIMG 16
|
||||||
|
|
||||||
|
#define RFC1533_END 255
|
||||||
|
#define BOOTP_VENDOR_LEN 64
|
||||||
|
#define DHCP_OPT_LEN 312
|
||||||
|
|
||||||
|
struct bootp_t {
|
||||||
|
struct ip ip;
|
||||||
|
struct udphdr udp;
|
||||||
|
uint8_t bp_op;
|
||||||
|
uint8_t bp_htype;
|
||||||
|
uint8_t bp_hlen;
|
||||||
|
uint8_t bp_hops;
|
||||||
|
uint32_t bp_xid;
|
||||||
|
uint16_t bp_secs;
|
||||||
|
uint16_t unused;
|
||||||
|
struct in_addr bp_ciaddr;
|
||||||
|
struct in_addr bp_yiaddr;
|
||||||
|
struct in_addr bp_siaddr;
|
||||||
|
struct in_addr bp_giaddr;
|
||||||
|
uint8_t bp_hwaddr[16];
|
||||||
|
uint8_t bp_sname[64];
|
||||||
|
char bp_file[128];
|
||||||
|
uint8_t bp_vend[];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t allocated;
|
||||||
|
uint8_t macaddr[6];
|
||||||
|
} BOOTPClient;
|
||||||
|
|
||||||
|
#define NB_BOOTP_CLIENTS 16
|
||||||
|
|
||||||
|
/* Process a bootp packet from the guest */
|
||||||
|
void bootp_input(struct mbuf *m);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,179 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1988, 1992, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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.
|
||||||
|
*
|
||||||
|
* @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
|
||||||
|
* in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "slirp.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checksum routine for Internet Protocol family headers (Portable Version).
|
||||||
|
*
|
||||||
|
* This routine is very heavily used in the network
|
||||||
|
* code and should be modified for each CPU to be as fast as possible.
|
||||||
|
*
|
||||||
|
* XXX Since we will never span more than 1 mbuf, we can optimise this
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
|
||||||
|
#define REDUCE \
|
||||||
|
{ \
|
||||||
|
l_util.l = sum; \
|
||||||
|
sum = l_util.s[0] + l_util.s[1]; \
|
||||||
|
ADDCARRY(sum); \
|
||||||
|
}
|
||||||
|
|
||||||
|
int cksum(struct mbuf *m, int len)
|
||||||
|
{
|
||||||
|
register uint16_t *w;
|
||||||
|
register int sum = 0;
|
||||||
|
register int mlen = 0;
|
||||||
|
int byte_swapped = 0;
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t c[2];
|
||||||
|
uint16_t s;
|
||||||
|
} s_util;
|
||||||
|
union {
|
||||||
|
uint16_t s[2];
|
||||||
|
uint32_t l;
|
||||||
|
} l_util;
|
||||||
|
|
||||||
|
if (m->m_len == 0)
|
||||||
|
goto cont;
|
||||||
|
w = mtod(m, uint16_t *);
|
||||||
|
|
||||||
|
mlen = m->m_len;
|
||||||
|
|
||||||
|
if (len < mlen)
|
||||||
|
mlen = len;
|
||||||
|
len -= mlen;
|
||||||
|
/*
|
||||||
|
* Force to even boundary.
|
||||||
|
*/
|
||||||
|
if ((1 & (uintptr_t)w) && (mlen > 0)) {
|
||||||
|
REDUCE;
|
||||||
|
sum <<= 8;
|
||||||
|
s_util.c[0] = *(uint8_t *)w;
|
||||||
|
w = (uint16_t *)((int8_t *)w + 1);
|
||||||
|
mlen--;
|
||||||
|
byte_swapped = 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Unroll the loop to make overhead from
|
||||||
|
* branches &c small.
|
||||||
|
*/
|
||||||
|
while ((mlen -= 32) >= 0) {
|
||||||
|
sum += w[0];
|
||||||
|
sum += w[1];
|
||||||
|
sum += w[2];
|
||||||
|
sum += w[3];
|
||||||
|
sum += w[4];
|
||||||
|
sum += w[5];
|
||||||
|
sum += w[6];
|
||||||
|
sum += w[7];
|
||||||
|
sum += w[8];
|
||||||
|
sum += w[9];
|
||||||
|
sum += w[10];
|
||||||
|
sum += w[11];
|
||||||
|
sum += w[12];
|
||||||
|
sum += w[13];
|
||||||
|
sum += w[14];
|
||||||
|
sum += w[15];
|
||||||
|
w += 16;
|
||||||
|
}
|
||||||
|
mlen += 32;
|
||||||
|
while ((mlen -= 8) >= 0) {
|
||||||
|
sum += w[0];
|
||||||
|
sum += w[1];
|
||||||
|
sum += w[2];
|
||||||
|
sum += w[3];
|
||||||
|
w += 4;
|
||||||
|
}
|
||||||
|
mlen += 8;
|
||||||
|
if (mlen == 0 && byte_swapped == 0)
|
||||||
|
goto cont;
|
||||||
|
REDUCE;
|
||||||
|
while ((mlen -= 2) >= 0) {
|
||||||
|
sum += *w++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte_swapped) {
|
||||||
|
REDUCE;
|
||||||
|
sum <<= 8;
|
||||||
|
if (mlen == -1) {
|
||||||
|
s_util.c[1] = *(uint8_t *)w;
|
||||||
|
sum += s_util.s;
|
||||||
|
mlen = 0;
|
||||||
|
} else
|
||||||
|
|
||||||
|
mlen = -1;
|
||||||
|
} else if (mlen == -1)
|
||||||
|
s_util.c[0] = *(uint8_t *)w;
|
||||||
|
|
||||||
|
cont:
|
||||||
|
if (len) {
|
||||||
|
DEBUG_ERROR("cksum: out of data");
|
||||||
|
DEBUG_ERROR(" len = %d", len);
|
||||||
|
}
|
||||||
|
if (mlen == -1) {
|
||||||
|
/* The last mbuf has odd # of bytes. Follow the
|
||||||
|
standard (the odd byte may be shifted left by 8 bits
|
||||||
|
or not as determined by endian-ness of the machine) */
|
||||||
|
s_util.c[1] = 0;
|
||||||
|
sum += s_util.s;
|
||||||
|
}
|
||||||
|
REDUCE;
|
||||||
|
return (~sum & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ip6_cksum(struct mbuf *m)
|
||||||
|
{
|
||||||
|
/* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum
|
||||||
|
* separately from the mbuf */
|
||||||
|
struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
|
||||||
|
struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
|
||||||
|
int sum;
|
||||||
|
|
||||||
|
save_ip = *ip;
|
||||||
|
|
||||||
|
ih->ih_src = save_ip.ip_src;
|
||||||
|
ih->ih_dst = save_ip.ip_dst;
|
||||||
|
ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
|
||||||
|
ih->ih_zero_hi = 0;
|
||||||
|
ih->ih_zero_lo = 0;
|
||||||
|
ih->ih_nh = save_ip.ip_nh;
|
||||||
|
|
||||||
|
sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr)) + ntohl(ih->ih_pl));
|
||||||
|
|
||||||
|
*ip = save_ip;
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1995 Danny Gasparovski.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEBUG_H_
|
||||||
|
#define DEBUG_H_
|
||||||
|
|
||||||
|
#define DBG_CALL (1 << 0)
|
||||||
|
#define DBG_MISC (1 << 1)
|
||||||
|
#define DBG_ERROR (1 << 2)
|
||||||
|
#define DBG_TFTP (1 << 3)
|
||||||
|
#define DBG_VERBOSE_CALL (1 << 4)
|
||||||
|
|
||||||
|
extern int slirp_debug;
|
||||||
|
|
||||||
|
#define DEBUG_CALL(name) \
|
||||||
|
do { \
|
||||||
|
if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
|
||||||
|
g_debug(name "..."); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG_VERBOSE_CALL(name) \
|
||||||
|
do { \
|
||||||
|
if (G_UNLIKELY(slirp_debug & DBG_VERBOSE_CALL)) { \
|
||||||
|
g_debug(name "..."); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG_RAW_CALL(...) \
|
||||||
|
do { \
|
||||||
|
if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
|
||||||
|
g_debug(__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG_ARG(...) \
|
||||||
|
do { \
|
||||||
|
if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
|
||||||
|
g_debug(" " __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG_MISC(...) \
|
||||||
|
do { \
|
||||||
|
if (G_UNLIKELY(slirp_debug & DBG_MISC)) { \
|
||||||
|
g_debug(__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG_ERROR(...) \
|
||||||
|
do { \
|
||||||
|
if (G_UNLIKELY(slirp_debug & DBG_ERROR)) { \
|
||||||
|
g_debug(__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG_TFTP(...) \
|
||||||
|
do { \
|
||||||
|
if (G_UNLIKELY(slirp_debug & DBG_TFTP)) { \
|
||||||
|
g_debug(__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* DEBUG_H_ */
|
|
@ -0,0 +1,224 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* SLIRP stateless DHCPv6
|
||||||
|
*
|
||||||
|
* We only support stateless DHCPv6, e.g. for network booting.
|
||||||
|
* See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details.
|
||||||
|
*
|
||||||
|
* Copyright 2016 Thomas Huth, Red Hat Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "slirp.h"
|
||||||
|
#include "dhcpv6.h"
|
||||||
|
|
||||||
|
/* DHCPv6 message types */
|
||||||
|
#define MSGTYPE_REPLY 7
|
||||||
|
#define MSGTYPE_INFO_REQUEST 11
|
||||||
|
|
||||||
|
/* DHCPv6 option types */
|
||||||
|
#define OPTION_CLIENTID 1
|
||||||
|
#define OPTION_IAADDR 5
|
||||||
|
#define OPTION_ORO 6
|
||||||
|
#define OPTION_DNS_SERVERS 23
|
||||||
|
#define OPTION_BOOTFILE_URL 59
|
||||||
|
|
||||||
|
struct requested_infos {
|
||||||
|
uint8_t *client_id;
|
||||||
|
int client_id_len;
|
||||||
|
bool want_dns;
|
||||||
|
bool want_boot_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyze the info request message sent by the client to see what data it
|
||||||
|
* provided and what it wants to have. The information is gathered in the
|
||||||
|
* "requested_infos" struct. Note that client_id (if provided) points into
|
||||||
|
* the odata region, thus the caller must keep odata valid as long as it
|
||||||
|
* needs to access the requested_infos struct.
|
||||||
|
*/
|
||||||
|
static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
|
||||||
|
struct requested_infos *ri)
|
||||||
|
{
|
||||||
|
int i, req_opt;
|
||||||
|
|
||||||
|
while (olen > 4) {
|
||||||
|
/* Parse one option */
|
||||||
|
int option = odata[0] << 8 | odata[1];
|
||||||
|
int len = odata[2] << 8 | odata[3];
|
||||||
|
|
||||||
|
if (len + 4 > olen) {
|
||||||
|
slirp->cb->guest_error("Guest sent bad DHCPv6 packet!",
|
||||||
|
slirp->opaque);
|
||||||
|
return -E2BIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (option) {
|
||||||
|
case OPTION_IAADDR:
|
||||||
|
/* According to RFC3315, we must discard requests with IA option */
|
||||||
|
return -EINVAL;
|
||||||
|
case OPTION_CLIENTID:
|
||||||
|
if (len > 256) {
|
||||||
|
/* Avoid very long IDs which could cause problems later */
|
||||||
|
return -E2BIG;
|
||||||
|
}
|
||||||
|
ri->client_id = odata + 4;
|
||||||
|
ri->client_id_len = len;
|
||||||
|
break;
|
||||||
|
case OPTION_ORO: /* Option request option */
|
||||||
|
if (len & 1) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
/* Check which options the client wants to have */
|
||||||
|
for (i = 0; i < len; i += 2) {
|
||||||
|
req_opt = odata[4 + i] << 8 | odata[4 + i + 1];
|
||||||
|
switch (req_opt) {
|
||||||
|
case OPTION_DNS_SERVERS:
|
||||||
|
ri->want_dns = true;
|
||||||
|
break;
|
||||||
|
case OPTION_BOOTFILE_URL:
|
||||||
|
ri->want_boot_url = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DEBUG_MISC("dhcpv6: Unsupported option request %d",
|
||||||
|
req_opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d", option,
|
||||||
|
len);
|
||||||
|
}
|
||||||
|
|
||||||
|
odata += len + 4;
|
||||||
|
olen -= len + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle information request messages
|
||||||
|
*/
|
||||||
|
static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
|
||||||
|
uint32_t xid, uint8_t *odata, int olen)
|
||||||
|
{
|
||||||
|
struct requested_infos ri = { NULL };
|
||||||
|
struct sockaddr_in6 sa6, da6;
|
||||||
|
struct mbuf *m;
|
||||||
|
uint8_t *resp;
|
||||||
|
|
||||||
|
if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = m_get(slirp);
|
||||||
|
if (!m) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(m->m_data, 0, m->m_size);
|
||||||
|
m->m_data += IF_MAXLINKHDR;
|
||||||
|
resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr);
|
||||||
|
|
||||||
|
/* Fill in response */
|
||||||
|
*resp++ = MSGTYPE_REPLY;
|
||||||
|
*resp++ = (uint8_t)(xid >> 16);
|
||||||
|
*resp++ = (uint8_t)(xid >> 8);
|
||||||
|
*resp++ = (uint8_t)xid;
|
||||||
|
|
||||||
|
if (ri.client_id) {
|
||||||
|
*resp++ = OPTION_CLIENTID >> 8; /* option-code high byte */
|
||||||
|
*resp++ = OPTION_CLIENTID; /* option-code low byte */
|
||||||
|
*resp++ = ri.client_id_len >> 8; /* option-len high byte */
|
||||||
|
*resp++ = ri.client_id_len; /* option-len low byte */
|
||||||
|
memcpy(resp, ri.client_id, ri.client_id_len);
|
||||||
|
resp += ri.client_id_len;
|
||||||
|
}
|
||||||
|
if (ri.want_dns) {
|
||||||
|
*resp++ = OPTION_DNS_SERVERS >> 8; /* option-code high byte */
|
||||||
|
*resp++ = OPTION_DNS_SERVERS; /* option-code low byte */
|
||||||
|
*resp++ = 0; /* option-len high byte */
|
||||||
|
*resp++ = 16; /* option-len low byte */
|
||||||
|
memcpy(resp, &slirp->vnameserver_addr6, 16);
|
||||||
|
resp += 16;
|
||||||
|
}
|
||||||
|
if (ri.want_boot_url) {
|
||||||
|
uint8_t *sa = slirp->vhost_addr6.s6_addr;
|
||||||
|
int slen, smaxlen;
|
||||||
|
|
||||||
|
*resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */
|
||||||
|
*resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */
|
||||||
|
smaxlen = (uint8_t *)m->m_data + slirp->if_mtu - (resp + 2);
|
||||||
|
slen = slirp_fmt((char *)resp + 2, smaxlen,
|
||||||
|
"tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
|
||||||
|
"%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
|
||||||
|
sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],
|
||||||
|
sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],
|
||||||
|
sa[15], slirp->bootp_filename);
|
||||||
|
*resp++ = slen >> 8; /* option-len high byte */
|
||||||
|
*resp++ = slen; /* option-len low byte */
|
||||||
|
resp += slen;
|
||||||
|
}
|
||||||
|
|
||||||
|
sa6.sin6_addr = slirp->vhost_addr6;
|
||||||
|
sa6.sin6_port = DHCPV6_SERVER_PORT;
|
||||||
|
da6.sin6_addr = srcsas->sin6_addr;
|
||||||
|
da6.sin6_port = srcsas->sin6_port;
|
||||||
|
m->m_data += sizeof(struct ip6) + sizeof(struct udphdr);
|
||||||
|
m->m_len = resp - (uint8_t *)m->m_data;
|
||||||
|
udp6_output(NULL, m, &sa6, &da6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle DHCPv6 messages sent by the client
|
||||||
|
*/
|
||||||
|
void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m)
|
||||||
|
{
|
||||||
|
uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr);
|
||||||
|
int data_len = m->m_len - sizeof(struct udphdr);
|
||||||
|
uint32_t xid;
|
||||||
|
|
||||||
|
if (data_len < 4) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xid = ntohl(*(uint32_t *)data) & 0xffffff;
|
||||||
|
|
||||||
|
switch (data[0]) {
|
||||||
|
case MSGTYPE_INFO_REQUEST:
|
||||||
|
dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||||
|
/*
|
||||||
|
* Definitions and prototypes for SLIRP stateless DHCPv6
|
||||||
|
*
|
||||||
|
* Copyright 2016 Thomas Huth, Red Hat Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef SLIRP_DHCPV6_H
|
||||||
|
#define SLIRP_DHCPV6_H
|
||||||
|
|
||||||
|
#define DHCPV6_SERVER_PORT 547
|
||||||
|
|
||||||
|
#define ALLDHCP_MULTICAST \
|
||||||
|
{ \
|
||||||
|
.s6_addr = { \
|
||||||
|
0xff, \
|
||||||
|
0x02, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x00, \
|
||||||
|
0x01, \
|
||||||
|
0x00, \
|
||||||
|
0x02 \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define in6_dhcp_multicast(a) in6_equal(a, &(struct in6_addr)ALLDHCP_MULTICAST)
|
||||||
|
|
||||||
|
/* Process a DHCPv6 packet from the guest */
|
||||||
|
void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m);
|
||||||
|
|
||||||
|
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue