mdns-sd

August 12, 2026 · View on GitHub

Build Cargo docs.rs Rust version: 1.70+

This is a small implementation of mDNS (Multicast DNS) based service discovery in safe Rust, with a small set of dependencies. Some highlights:

  • supports both the client (querier) and the server (responder) uses.
  • supports macOS, Linux and Windows.
  • supports IPv4 and IPv6.
  • works with both sync and async code.
  • no dependency on any async runtimes.

Approach

We are not using async/.await internally, instead we create a new thread to run a mDNS daemon.

The API interacts with the daemon via flume channels that work easily with both sync and async code. For more details, please see the documentation.

Compatibility and Limitations

This implementation is based on the following RFCs:

This is still beta software. We focus on the common use cases at hand. And we tested with some existing common tools (e.g. Avahi on Linux, dns-sd on MacOS, and Bonjour library on iOS) to verify the basic compatibility.

The following table shows how much this implementation is compliant with RFCs regarding major features:

FeatureRFC sectionComplianceNotes
One-Shot Multicast DNS Queries (i.e. Legacy Unicast Responses)RFC 6762 section 5.1 section 6.7Reply unicast to the querier when the source port is not 5353, regardless of whether the query was multicast or unicast
Randomized Initial Query DelayRFC 6762 section 5.2jitter the first query of a continuous-monitoring series by a random delay to avoid synchronization across queriers. ℹ️ we use a shorter 10-50 ms window instead of the RFC's 20-120 ms
Unicast ResponsesRFC 6762 section 5.4
Multicast Rate LimitingRFC 6762 section 6a given record is not re-multicast on an interface until at least one second has elapsed. ℹ️ probe queries and legacy unicast responses (§6.7) are exempt per the RFC; the separate 250 ms probe-query interval is not yet implemented
Response Delay for Shared RecordsRFC 6762 section 6delay responses to shared (e.g. PTR) queries by a random amount to allow aggregation and reduce collisions. ℹ️ we use a shorter window than the RFC's 20-120 ms
Known-Answer SuppressionRFC 6762 section 7.1
Multipacket Known Answer Suppression querierRFC 6762 section 7.2
Multipacket Known Answer Suppression responderRFC 6762 section 7.2because we don't support Unicast yet.
ProbingRFC 6762 section 8.1
Simultaneous Probe TiebreakingRFC 6762 section 8.2
Conflict ResolutionRFC 6762 section 9see DnsNameChange type
Goodbye PacketsRFC 6762 section 10.1
Announcements to Flush Outdated Cache EntriesRFC 6762 section 10.2i.e. cache-flush bit
Cache Flush on Failure IndicationRFC 6762 section 10.4API: ServiceDaemon::verify()
Outgoing packet sizeRFC 6762 section 17By default, outgoing packet max size is 1452 bytes, i.e. the Ethernet MTU. API: ServiceDaemon::set_max_packet_size()

License

Licensed under either of

at your option.

Contribution

Contributions are welcome! Please open an issue in GitHub if any questions.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the above license(s), shall be dual licensed as above, without any additional terms or conditions.