Skip to content

Commit b979956

Browse files
committed
fix(mdns): Add test programs
1 parent bb4f37f commit b979956

File tree

6 files changed

+205
-0
lines changed

6 files changed

+205
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# The following five lines of boilerplate have to be in your project's
2+
# CMakeLists in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.22)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
project(simple)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
idf_component_register(SRCS "simple.c"
2+
INCLUDE_DIRS ".")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
dependencies:
2+
## Required IDF version
3+
idf: ">=5.0"
4+
espressif/mdns:
5+
version: "^1.0.0"
6+
override_path: "../../../"
7+
protocol_examples_common:
8+
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Unlicense OR CC0-1.0
5+
*/
6+
#include <string.h>
7+
#include "esp_event.h"
8+
#include "esp_log.h"
9+
#include "esp_mac.h"
10+
#include "esp_netif.h"
11+
#include "esp_netif_ip_addr.h"
12+
#include "mdns.h"
13+
#include "nvs_flash.h"
14+
#include "protocol_examples_common.h"
15+
16+
static const char *TAG = "mdns-simple";
17+
18+
static void initialise_mdns(void)
19+
{
20+
const char *mdns_hostname = "minifritz";
21+
const char *mdns_instance = "Hristo's Time Capsule";
22+
23+
mdns_txt_item_t arduTxtData[4] = {
24+
{"board", "esp32"},
25+
{"tcp_check", "no"},
26+
{"ssh_upload", "no"},
27+
{"auth_upload", "no"}
28+
};
29+
30+
uint8_t mac[6];
31+
ESP_ERROR_CHECK(esp_read_mac(mac, ESP_MAC_WIFI_STA));
32+
33+
char *winstance = NULL;
34+
if (asprintf(&winstance, "%s [%02x:%02x:%02x:%02x:%02x:%02x]",
35+
mdns_hostname, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) < 0) {
36+
abort();
37+
}
38+
39+
ESP_ERROR_CHECK(mdns_init());
40+
ESP_ERROR_CHECK(mdns_hostname_set(mdns_hostname));
41+
ESP_LOGI(TAG, "mdns hostname set to: [%s]", mdns_hostname);
42+
ESP_ERROR_CHECK(mdns_instance_name_set(mdns_instance));
43+
44+
// Delegate host: 17.17.17.17
45+
mdns_ip_addr_t addr4 = { 0 };
46+
addr4.addr.type = ESP_IPADDR_TYPE_V4;
47+
esp_netif_str_to_ip4("17.17.17.17", &addr4.addr.u_addr.ip4);
48+
addr4.next = NULL;
49+
ESP_ERROR_CHECK(mdns_delegate_hostname_add(mdns_hostname, &addr4));
50+
ESP_ERROR_CHECK(mdns_delegate_hostname_add("megafritz", &addr4));
51+
52+
// Services and subtypes mirroring the fuzz test setup
53+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_fritz", "_tcp", 22, NULL, 0));
54+
ESP_ERROR_CHECK(mdns_service_subtype_add_for_host(NULL, "_fritz", "_tcp", NULL, "_server"));
55+
56+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_telnet", "_tcp", 22, NULL, 0));
57+
58+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_workstation", "_tcp", 9, NULL, 0));
59+
ESP_ERROR_CHECK(mdns_service_instance_name_set("_workstation", "_tcp", winstance));
60+
61+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_arduino", "_tcp", 3232, NULL, 0));
62+
ESP_ERROR_CHECK(mdns_service_txt_set("_arduino", "_tcp", arduTxtData, 4));
63+
64+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0));
65+
ESP_ERROR_CHECK(mdns_service_instance_name_set("_http", "_tcp", "ESP WebServer"));
66+
67+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_afpovertcp", "_tcp", 548, NULL, 0));
68+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_rfb", "_tcp", 885, NULL, 0));
69+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_smb", "_tcp", 885, NULL, 0));
70+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_adisk", "_tcp", 885, NULL, 0));
71+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_airport", "_tcp", 885, NULL, 0));
72+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_printer", "_tcp", 885, NULL, 0));
73+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_airplay", "_tcp", 885, NULL, 0));
74+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_raop", "_tcp", 885, NULL, 0));
75+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_uscan", "_tcp", 885, NULL, 0));
76+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_uscans", "_tcp", 885, NULL, 0));
77+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_ippusb", "_tcp", 885, NULL, 0));
78+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_scanner", "_tcp", 885, NULL, 0));
79+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_ipp", "_tcp", 885, NULL, 0));
80+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_ipps", "_tcp", 885, NULL, 0));
81+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_pdl-datastream", "_tcp", 885, NULL, 0));
82+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_ptp", "_tcp", 885, NULL, 0));
83+
ESP_ERROR_CHECK(mdns_service_add(NULL, "_sleep-proxy", "_udp", 885, NULL, 0));
84+
85+
free(winstance);
86+
}
87+
88+
void app_main(void)
89+
{
90+
ESP_ERROR_CHECK(nvs_flash_init());
91+
ESP_ERROR_CHECK(esp_netif_init());
92+
ESP_ERROR_CHECK(esp_event_loop_create_default());
93+
94+
ESP_LOGI(TAG, "mDNS Ver: %s", ESP_MDNS_VERSION_NUMBER);
95+
96+
initialise_mdns();
97+
98+
// Use the common connection helper to bring up Wi‑Fi/Ethernet
99+
ESP_ERROR_CHECK(example_connect());
100+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# This file was generated using idf.py save-defconfig. It can be edited manually.
2+
# Espressif IoT Development Framework (ESP-IDF) 6.0.0 Project Minimal Configuration
3+
#
4+
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
5+
CONFIG_MDNS_MAX_SERVICES=40
6+
CONFIG_MDNS_ENABLE_DEBUG_PRINTS=y
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env python3
2+
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
# SPDX-License-Identifier: Unlicense OR CC0-1.0
4+
"""
5+
Send a raw mDNS UDP payload (from AFL crash.bin) to the mDNS multicast group.
6+
7+
Usage:
8+
python tests/test_afl_fuzz_host/send_mdns.py crash.bin \
9+
[--group 224.0.0.251] [--port 5353] \
10+
[--src 192.168.1.10] [--bind-iface eth0] \
11+
[--count 1] [--interval 0.2]
12+
13+
Notes:
14+
- The input file should contain the UDP payload (DNS message) only, as produced by the fuzzer.
15+
- On Linux, specifying --bind-iface helps ensure the packet uses a specific interface.
16+
"""
17+
18+
import argparse
19+
import os
20+
import socket
21+
import sys
22+
import time
23+
24+
25+
def parse_args() -> argparse.Namespace:
26+
p = argparse.ArgumentParser(description="Send raw mDNS UDP payload to 224.0.0.251:5353")
27+
p.add_argument("bin", help="Path to UDP payload (e.g., crash.bin)")
28+
p.add_argument("--group", default="224.0.0.251", help="Multicast group (IPv4)")
29+
p.add_argument("--port", type=int, default=5353, help="Destination UDP port")
30+
p.add_argument("--src", help="Source IPv4 address to bind and use for multicast (sets IP_MULTICAST_IF)")
31+
p.add_argument("--bind-iface", help="Interface name to bind (Linux SO_BINDTODEVICE)")
32+
p.add_argument("--count", type=int, default=1, help="Number of times to send the payload")
33+
p.add_argument("--interval", type=float, default=0.2, help="Seconds between sends")
34+
return p.parse_args()
35+
36+
37+
def main() -> int:
38+
args = parse_args()
39+
40+
if not os.path.isfile(args.bin):
41+
print(f"File not found: {args.bin}", file=sys.stderr)
42+
return 2
43+
44+
payload = open(args.bin, "rb").read()
45+
if not payload:
46+
print("Empty payload", file=sys.stderr)
47+
return 3
48+
49+
dst = (args.group, args.port)
50+
51+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
52+
try:
53+
# Reuse addr and set TTL/hop limit to 255 as commonly used by mDNS
54+
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
55+
s.setsockopt(socket.IPPROTO_IP, socket.IP_TTL, 255)
56+
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
57+
# Avoid receiving our own multicast
58+
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 0)
59+
60+
if args.src:
61+
# Bind to source and set multicast interface
62+
s.bind((args.src, 0))
63+
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(args.src))
64+
65+
if args.bind_iface and hasattr(socket, 'SO_BINDTODEVICE'):
66+
try:
67+
s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, args.bind_iface.encode())
68+
except OSError as e:
69+
print(f"Warning: SO_BINDTODEVICE failed: {e}", file=sys.stderr)
70+
71+
for i in range(args.count):
72+
s.sendto(payload, dst)
73+
if i + 1 < args.count:
74+
time.sleep(args.interval)
75+
76+
print(f"Sent {args.count} packet(s) to {dst[0]}:{dst[1]} ({len(payload)} bytes)")
77+
return 0
78+
finally:
79+
s.close()
80+
81+
82+
if __name__ == "__main__":
83+
raise SystemExit(main())

0 commit comments

Comments
 (0)