fix(mdns): Add unit tests for fa84ee6e4

This commit is contained in:
David Cermak
2026-05-28 11:44:47 +02:00
parent 1b4fcb0cd4
commit 8d7b943252
3 changed files with 109 additions and 2 deletions
@@ -0,0 +1,80 @@
# mDNS host unit tests and fuzzing
This directory builds the mDNS component as a Linux host binary with stubs for ESP-IDF networking. It supports two modes:
- **Unit tests** — Unity/CMock regression tests (ASan/UBSan enabled)
- **Fuzzing** — AFL++ harness that feeds random packets into the receive path
## Prerequisites
- ESP-IDF installed and `IDF_PATH` set (`. $IDF_PATH/export.sh`)
- `libbsd-dev`
- For unit tests: `ruby` (CMock code generation)
- For fuzzing: AFL++ (`afl-cc`, `afl-fuzz`) and `dnslib` (`pip install dnslib`)
From the repository root:
```bash
cd components/mdns/tests/host_unit_test
```
Run `idf.py reconfigure` once before building. This generates `build/config/` headers used by the host build.
## Unit tests
Available test suites (pass one to `-DUNIT_TESTS=`):
| Suite | Description |
|-------|-------------|
| `test_receiver` | Packet receive / parse path |
| `test_sender` | Packet send path |
| `test_browse` | Browse / TXT comparison regressions |
Example — build and run the receiver tests:
```bash
. $IDF_PATH/export.sh
idf.py reconfigure
mkdir -p build2 && cd build2
cmake -DUNIT_TESTS=test_receiver ..
cmake --build .
ctest --extra-verbose
```
Or run the binary directly:
```bash
./mdns_host_unit_test --test
```
Repeat with `-DUNIT_TESTS=test_sender` or `-DUNIT_TESTS=test_browse` in a separate build directory.
## Fuzzer tests
Build the AFL-instrumented harness (no `-DUNIT_TESTS`; uses `main.c`):
```bash
export IDF_PATH=/path/to/esp-idf # required in the fuzz container
cd input && python generate_cases.py && cd ..
cmake -B build2 -S . -G Ninja -DCMAKE_C_COMPILER=afl-cc
cmake --build build2
afl-fuzz -i input -o out -- build2/mdns_host_unit_test
```
The harness reads packets from stdin and exercises IPv4/IPv6 and port 5353/53 combinations. Crashes are written to `out/default/crashes/`.
### Reproducing a crash
Build the non-unit-test binary with a normal compiler, then pass a crash file:
```bash
cmake -B build2 -S .
cmake --build build2
./build2/mdns_host_unit_test out/default/crashes/id_000000,...
```
With sanitizers enabled, ASan/UBSan report buffer overruns and undefined behaviour directly during unit tests and fuzzing.
@@ -3,4 +3,8 @@
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#if __has_include("esp_assert.h")
#include_next "esp_assert.h"
#else
#define ESP_STATIC_ASSERT _Static_assert
#endif
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -9,7 +9,7 @@
#include "unity_main.h"
#include "mock_mdns_pcb.h"
#include "mock_mdns_send.h"
#include "create_test_packet.h"
#include "mdns_private.h"
static void test_mdns_hostname_queries(void)
{
@@ -61,6 +61,27 @@ static void test_mdns_with_answers(void)
}
/*
* Regression test for fa84ee6: packets shorter than MDNS_HEAD_LEN (12) must
* be rejected before reading the additional RR count at offset 10.
* An 11-byte AFL input (id_000005) previously passed the old check and read
* one byte past the RX buffer.
*/
static void test_mdns_reject_short_packet(void)
{
static const uint8_t eleven_byte_packet[] = {
0x00, 0xc0, 0x32, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x54, 0x01
};
for (size_t len = 0; len < MDNS_HEAD_LEN; len++) {
const uint8_t *data = eleven_byte_packet;
send_packet(true, true, (uint8_t *)data, len);
send_packet(true, false, (uint8_t *)data, len);
send_packet(false, true, (uint8_t *)data, len);
send_packet(false, false, (uint8_t *)data, len);
}
}
static void mdns_priv_create_answer_from_parsed_packet_Callback(mdns_parsed_packet_t* parsed_packet, int cmock_num_calls)
{
printf("callback\n");
@@ -89,5 +110,7 @@ void run_unity_tests(void)
// Run test with answers
RUN_TEST(test_mdns_with_answers);
RUN_TEST(test_mdns_reject_short_packet);
UNITY_END();
}