[GH-ISSUE #24] Support for mDNS, Multicast DNS #21

Closed
opened 2026-03-07 22:18:00 +03:00 by kerem · 4 comments
Owner

Originally created by @bluejekyll on GitHub (Jun 26, 2016).
Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/24

Should be very simple extension over the UDP version.

https://tools.ietf.org/html/rfc6762

also, see IPv6 neighbor discovery and SLAAC:
https://tools.ietf.org/html/rfc4861
https://tools.ietf.org/html/rfc4862

Originally created by @bluejekyll on GitHub (Jun 26, 2016). Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/24 Should be very simple extension over the UDP version. https://tools.ietf.org/html/rfc6762 also, see IPv6 neighbor discovery and SLAAC: https://tools.ietf.org/html/rfc4861 https://tools.ietf.org/html/rfc4862
kerem 2026-03-07 22:18:00 +03:00
Author
Owner

@briansmith commented on GitHub (Jan 1, 2018):

I suggest adding "mDNS" to the issue title.

There are two parts to this: Querying and responding (serving). It isn't possible to implement serving without querying because the first step of serving is "[...] for all those resource records that a Multicast DNS responder desires to be unique on the local link, it MUST send a Multicast DNS query asking for those resource records, to see if any of them are already in use." This implies that querying should be implemented first.

Regarding responding, ideally a multicast DNS responder implementation will be very compact; i.e. .the size considerations that prompted the minimization work for the resolver would also apply to the multicast DNS responder. In particular, it would be great to be able to embed the responder into a tiny IoT-like device.

<!-- gh-comment-id:354683098 --> @briansmith commented on GitHub (Jan 1, 2018): I suggest adding "mDNS" to the issue title. There are two parts to this: Querying and responding (serving). It isn't possible to implement serving without querying because the first step of serving is "[...] for all those resource records that a Multicast DNS responder desires to be unique on the local link, it MUST send a Multicast DNS query asking for those resource records, to see if any of them are already in use." This implies that querying should be implemented first. Regarding responding, ideally a multicast DNS responder implementation will be very compact; i.e. .the size considerations that prompted the minimization work for the resolver would also apply to the multicast DNS responder. In particular, it would be great to be able to embed the responder into a tiny IoT-like device.
Author
Owner

@briansmith commented on GitHub (Jan 2, 2018):

Note also that Multicast DNS reserves special semantics to ".local" addresses:

This document specifies that the DNS top-level domain ".local." is a
special domain with special semantics, namely that any fully
qualified name ending in ".local." is link-local, and names within
this domain are meaningful only on the link where they originate.
This is analogous to IPv4 addresses in the 169.254/16 prefix or IPv6
addresses in the FE80::/10 prefix, which are link-local and
meaningful only on the link where they originate.

Any DNS query for a name ending with ".local." MUST be sent to the
mDNS IPv4 link-local multicast address 224.0.0.251 (or its IPv6
equivalent FF02::FB). The design rationale for using a fixed
multicast address instead of selecting from a range of multicast
addresses using a hash function is discussed in Appendix B.
Implementers MAY choose to look up such names concurrently via other
mechanisms (e.g., Unicast DNS) and coalesce the results in some
fashion.

<!-- gh-comment-id:354700795 --> @briansmith commented on GitHub (Jan 2, 2018): Note also that Multicast DNS reserves special semantics to ".local" addresses: > This document specifies that the DNS top-level domain ".local." is a special domain with special semantics, namely that any fully qualified name ending in ".local." is link-local, and names within this domain are meaningful only on the link where they originate. This is analogous to IPv4 addresses in the 169.254/16 prefix or IPv6 addresses in the FE80::/10 prefix, which are link-local and meaningful only on the link where they originate. > > Any DNS query for a name ending with ".local." MUST be sent to the mDNS IPv4 link-local multicast address 224.0.0.251 (or its IPv6 equivalent FF02::FB). The design rationale for using a fixed multicast address instead of selecting from a range of multicast addresses using a hash function is discussed in Appendix B. Implementers MAY choose to look up such names concurrently via other mechanisms (e.g., Unicast DNS) and coalesce the results in some fashion.
Author
Owner

@bluejekyll commented on GitHub (Jan 29, 2018):

My current plan is to build two implementations (not sure if they will be new crates yet). There will be a new trust_dns_proto::MuticastStream, which is nearly identical to trust_dns_proto::UdpStream. I want to try and just use UdpStream under the covers. The Client will be able to send one-shot, https://tools.ietf.org/html/rfc6762#section-5, queries using this stream.

For the resolution, the Resolver will gain a new multicast resolution component through the NameServerPool. multicast_conns will be a new field, with IPv4 and IPv6 associated (thought I'm not yet sure about registering IPv6 and IPv4 at the same time here, that might create unnecessary duplication of multicast messages on the network). https://tools.ietf.org/html/rfc6762#section-20 only discusses IPv4 and IPv6 from the stand-point of registration, and doesn't give good guidance on query implementations. The RFC mentions allowing other non-.local. queries to be sent via multicast. My plan would be this:

{
  if name in zone `.local.` query only via multicast; 
  else query default registered nameservers;
          on failure attempt to resolve via multicast with a one-shot query;
}

This will make multicast only a last resort for non-.local. names, of course this logic could always be triggered by not adding any default nameservers. One negative issue with the continuous mDNS record maintenance is that queries are intended to be actively requested for names that are queried. This would require a background processing thread to maintain a consistent schedule (I don't think we should spin up additional threads in the Resolver, so this seems like a non-starter). The other option would be to only perform this maintenance on the primary thread on a turn of the Resolvers event loop (this will be the initial implementation) by utilizing the fact that multiple queries can be safely associated to a single DNS packet, this option seems reasonable. This does mean that records could go stale over longer periods, but why put traffic on the network when nothing is actually requesting names. It might be worthwhile to give an API into the maintenance method such that in cases where the Resolver is embedded in other software, that software could spin up an additional thread and call the query maintenance method on a fixed schedule.

For a multicast dns responder my current plan is to modify the Server to add a special authority for registering .local. names and service all multicast requests that are received. The Server can be managed either through dynamic dns, or if it's embedded, a direct API should be added for managing the .local. Authority. Query forwarding will not be implemented as part of the initial mDNS support in the server. This can be added at the same point that general purpose forwarding is built in.

<!-- gh-comment-id:361158367 --> @bluejekyll commented on GitHub (Jan 29, 2018): My current plan is to build two implementations (not sure if they will be new crates yet). There will be a new `trust_dns_proto::MuticastStream`, which is nearly identical to `trust_dns_proto::UdpStream`. I want to try and just use `UdpStream` under the covers. The `Client` will be able to send `one-shot`, https://tools.ietf.org/html/rfc6762#section-5, queries using this stream. For the resolution, the `Resolver` will gain a new multicast resolution component through the `NameServerPool`. `multicast_conns` will be a new field, with IPv4 and IPv6 associated (thought I'm not yet sure about registering IPv6 and IPv4 at the same time here, that might create unnecessary duplication of multicast messages on the network). https://tools.ietf.org/html/rfc6762#section-20 only discusses IPv4 and IPv6 from the stand-point of registration, and doesn't give good guidance on query implementations. The RFC mentions allowing other non-`.local.` queries to be sent via multicast. My plan would be this: ``` { if name in zone `.local.` query only via multicast; else query default registered nameservers; on failure attempt to resolve via multicast with a one-shot query; } ``` This will make multicast only a last resort for non-`.local.` names, of course this logic could always be triggered by not adding any default nameservers. One negative issue with the continuous mDNS record maintenance is that queries are intended to be actively requested for names that are queried. This would require a background processing thread to maintain a consistent schedule (I don't think we should spin up additional threads in the `Resolver`, so this seems like a non-starter). The other option would be to only perform this maintenance on the primary thread on a turn of the `Resolver`s event loop (this will be the initial implementation) by utilizing the fact that multiple queries can be safely associated to a single DNS packet, this option seems reasonable. This does mean that records could go stale over longer periods, but why put traffic on the network when nothing is actually requesting names. It might be worthwhile to give an API into the maintenance method such that in cases where the `Resolver` is embedded in other software, that software could spin up an additional thread and call the query maintenance method on a fixed schedule. For a multicast dns responder my current plan is to modify the `Server` to add a special authority for registering `.local.` names and service all multicast requests that are received. The `Server` can be managed either through dynamic dns, or if it's embedded, a direct API should be added for managing the `.local.` Authority. Query forwarding will not be implemented as part of the initial mDNS support in the server. This can be added at the same point that general purpose forwarding is built in.
Author
Owner

@bluejekyll commented on GitHub (Feb 13, 2018):

I've run into a complexity on implementing mDNS support. I can easily create one-shot DNS queries. It's also possible to create a server that receives multicast packets. But on existing operating systems that already support mDNS, we can not create another "continuous", fully compliant, mDNS responder. This is due to the fact that we can no reuse the address that is owned by the host OS, specifically 0.0.0.0:5353 and/or [::0]:5353. If the operating system has some means of creating network namespaces, like LXC or Docker, or somehow getting a separate IP, then this wouldn't necessarily be a blocker, but would require running in a container.

This is a bit of a bummer, as there is not good reason why the spec doesn't allow this. What is possibly is to bind a listening address directly to the mDNS well-known multicast address and port 5353, as is required by the multicast spec for UDP, but this is only one half of the equation.

One option for the server is to create dual sockets, one for receiving bound to the UDP multicast addresses, and then one for replies bound to a random port and address. It's not clear at this point whether standard mDNS clients out there would accept responses that don't come from some address specifically from port 5353 (they might accept any response). For the client/respolver, it's more egregious in that mDNS responders will assume that the client is not fully mDNS compliant if it does not send packets from port 5353, not doing so is outside the RFC:

A compliant Multicast DNS querier, which implements the rules
   specified in this document, MUST send its Multicast DNS queries from
   UDP source port 5353 (the well-known port assigned to mDNS), and MUST
   listen for Multicast DNS replies sent to UDP destination port 5353 at
   the mDNS link-local multicast address (224.0.0.251 and/or its IPv6
   equivalent FF02::FB).

For now I will move forward with supporting one-shot mDNS requests and routing. We should probably feature flag off continuous mDNS queries. This is disappointing.

<!-- gh-comment-id:365181079 --> @bluejekyll commented on GitHub (Feb 13, 2018): I've run into a complexity on implementing mDNS support. I can easily create [one-shot](https://tools.ietf.org/html/rfc6762#section-5) DNS queries. It's also possible to create a server that receives multicast packets. But on existing operating systems that already support mDNS, we can not create another "continuous", fully compliant, mDNS responder. This is due to the fact that we can no reuse the address that is owned by the host OS, specifically `0.0.0.0:5353` and/or `[::0]:5353`. If the operating system has some means of creating network namespaces, like LXC or Docker, or somehow getting a separate IP, then this wouldn't necessarily be a blocker, but would require running in a container. This is a bit of a bummer, as there is not good reason *why* the spec doesn't allow this. What is possibly is to bind a listening address directly to the mDNS well-known multicast address and port `5353`, as is required by the multicast spec for UDP, but this is only one half of the equation. One option for the server is to create dual sockets, one for receiving bound to the UDP multicast addresses, and then one for replies bound to a random port and address. It's not clear at this point whether standard mDNS clients out there would accept responses that don't come from some address specifically from port 5353 (they might accept any response). For the client/respolver, it's more egregious in that mDNS responders will assume that the client is not fully mDNS compliant if it does not send packets from port 5353, not doing so is outside the RFC: ```text A compliant Multicast DNS querier, which implements the rules specified in this document, MUST send its Multicast DNS queries from UDP source port 5353 (the well-known port assigned to mDNS), and MUST listen for Multicast DNS replies sent to UDP destination port 5353 at the mDNS link-local multicast address (224.0.0.251 and/or its IPv6 equivalent FF02::FB). ``` For now I will move forward with supporting one-shot mDNS requests and routing. We should probably feature flag off continuous mDNS queries. This is disappointing.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hickory-dns#21
No description provided.