Summary
The mDNS_daemon thread panics via a hard assert! in DnsOutPacket::write_utf8 when it has to write a DNS label of 64 bytes or more:
// src/dns_parser.rs (v0.20.2, also present on `main`)
fn write_utf8(&mut self, s: &str) {
assert!(s.len() < 64); // <-- panics here
self.write_byte(s.len() as u8);
self.write_bytes(s.as_bytes());
}
Because this runs on the daemon's own background thread (mDNS_daemon), the panic is uncatchable by the library user: the thread unwinds, its flume senders are dropped, every browse/monitor Receiver disconnects, and mDNS discovery is silently and permanently dead for the rest of the process lifetime.
Observed in production on 2026-07-19 on a normal home LAN, apparently triggered by a single device emitting a malformed/oversized name.
thread 'mDNS_daemon' panicked at .../mdns-sd-0.20.2/src/dns_parser.rs:1623:
assertion failed: s.len() < 64
Why it is reachable from the network
write_utf8 is called by write_name for every label of every name written into an outgoing packet:
DnsOutPacket::write_question → write_name(&question.entry.name)
DnsOutPacket::write_record → write_name(record.get_name())
DnsPointer::write → write_name(&self.alias) (PTR target)
DnsSrv::write → write_name(&self.host) (SRV host)
Some of those names originate from records the daemon learned from the network and later re-emits (responses, known-answer suppression, re-announcements). So a remote peer on the LAN can get a name with a ≥ 64-byte label into the daemon's write path and take the whole daemon down. A single misbehaving device is enough.
Per RFC 1035 §2.3.4 / §3.1 a label is limited to 63 octets, so a ≥ 64-byte label is malformed input — but malformed input from the network should never be able to panic the daemon thread.
Expected behavior
The write path should treat an over-length label as a recoverable error rather than asserting:
- make
write_name / write_utf8 fallible (return an error) and have write_record / write_question drop or skip the offending record, or
- defensively truncate/skip labels ≥ 64 bytes,
so that one malformed name cannot kill the mDNS_daemon thread and disable discovery process-wide.
Notes / transparency
- Reproduced by reading the source; I do not have a captured packet of the exact offending name (it was seen once on a live network), so I can't yet point at the precise upstream that produced the ≥ 64-byte label. Happy to add a
tcpdump/pcap capture if you can suggest which record type to watch for.
- Downstream we are mitigating by supervising the
ServiceDaemon: we detect the disconnected browse receiver as "daemon died" and recreate the daemon with exponential backoff. That keeps discovery alive, but the panic still costs a full daemon restart and a discovery gap, so a graceful fix in the writer would be much better.
Version: mdns-sd 0.20.2 (assertion also present on main).
Thanks for the library!
Summary
The
mDNS_daemonthread panics via a hardassert!inDnsOutPacket::write_utf8when it has to write a DNS label of 64 bytes or more:Because this runs on the daemon's own background thread (
mDNS_daemon), the panic is uncatchable by the library user: the thread unwinds, itsflumesenders are dropped, everybrowse/monitorReceiverdisconnects, and mDNS discovery is silently and permanently dead for the rest of the process lifetime.Observed in production on 2026-07-19 on a normal home LAN, apparently triggered by a single device emitting a malformed/oversized name.
Why it is reachable from the network
write_utf8is called bywrite_namefor every label of every name written into an outgoing packet:DnsOutPacket::write_question→write_name(&question.entry.name)DnsOutPacket::write_record→write_name(record.get_name())DnsPointer::write→write_name(&self.alias)(PTR target)DnsSrv::write→write_name(&self.host)(SRV host)Some of those names originate from records the daemon learned from the network and later re-emits (responses, known-answer suppression, re-announcements). So a remote peer on the LAN can get a name with a ≥ 64-byte label into the daemon's write path and take the whole daemon down. A single misbehaving device is enough.
Per RFC 1035 §2.3.4 / §3.1 a label is limited to 63 octets, so a ≥ 64-byte label is malformed input — but malformed input from the network should never be able to panic the daemon thread.
Expected behavior
The write path should treat an over-length label as a recoverable error rather than asserting:
write_name/write_utf8fallible (return an error) and havewrite_record/write_questiondrop or skip the offending record, orso that one malformed name cannot kill the
mDNS_daemonthread and disable discovery process-wide.Notes / transparency
tcpdump/pcapcapture if you can suggest which record type to watch for.ServiceDaemon: we detect the disconnectedbrowsereceiver as "daemon died" and recreate the daemon with exponential backoff. That keeps discovery alive, but the panic still costs a full daemon restart and a discovery gap, so a graceful fix in the writer would be much better.Version:
mdns-sd0.20.2 (assertion also present onmain).Thanks for the library!