For a lot longer than I thought it would take, as all things in software turn out to be , I’ve been working on adding multicast DNS to the TRust-DNS libraries. I wrote a post about performing multicast requests in Rust related to this work: Multicasting in Rust. Hopefully others will find that information useful for similar tools.

As to DNS, this work is all need to support multicast DNS. Beyond the additional protocol, I’ve added the beginnings of a DNS-SD, DNS Service Discovery, implementation. This currently requires the experimental mdns feature to be enabled for both mDNS and DNS-SD to be compiled into the library. DNS-SD does not technically require mDNS and can work against traditional DNS nodes, but mDNS does require DNS-SD for some of it’s more interesting features (at some future point we can untether DNS-SD from the mdns feature). Here’s the trait for the DNS-SD extension:

/// An extension for the Resolver to perform DNS Service Discovery pub trait DnsSdFuture { /// List all services available /// /// https://tools.ietf.org/html/rfc6763#section-4.1 /// /// For registered service types, see: https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml fn list_services<N: IntoName>(&self, name: N) -> ListServicesFuture; /// Retrieve service information /// /// https://tools.ietf.org/html/rfc6763#section-6 fn service_info<N: IntoName>(&self, name: N) -> ServiceInfoFuture; }

I’ve put a single “test” in the library, it can be run with this and if you have any mDNS devices on your network you may get results:

$> cd resolver $> cargo test --features mdns test_list_services -- --nocapture --ignored ... running 1 test service: not\040real\040name._http._tcp.local. service: SRV { priority: 0, weight: 0, port: 80, target: Name { is_fqdn: true, labels: [ DVR-89B6, local ] } } info: { "platform": Some( "tcd/Series4" ), "path": Some( "/index.html" ), "swversion": Some( "1.2.3.4" ), "TSN": Some( "DEADBEEF" ) } ip: 198.51.100.1 test dns_sd::tests::test_list_services ... ok ...

The result above is from the TiVo on my network (yes, I still have a TiVo, don’t ask). I’ve changed some of the private information to bogus details for this post, so some of those things are fake. Breaking this down here’s the test:

fn test_list_services() { let mut io_loop = Core::new().unwrap();

We create a Resolver like normal:

let resolver = ResolverFuture::new( ResolverConfig::default(), ResolverOpts { ip_strategy: LookupIpStrategy::Ipv6thenIpv4, ..ResolverOpts::default() }, &io_loop.handle(), );

Then we run the new list_services function to find all services, this actually performs a PTR lookup. It uses the default timeout to wait for responses, and then returns any that were found:

let response = io_loop .run(resolver.list_services("_http._tcp.local.")) .expect("failed to run lookup"); for name in response.iter() { println!("service: {}", name);

Now lookup the service’s connection info with the new lookup_srv function (described below):

let srvs = io_loop .run(resolver.lookup_srv(name)) .expect("failed to lookup name"); for srv in srvs.iter() { println!("service: {:#?}", srv);

Now lookup the service’s information with the new service_info function:

let info = io_loop .run(resolver.service_info(name)) .expect("info failed");

The result of the service lookup returns an type that can return the output as a HashMap :

let info = info.to_map(); println!("info: {:#?}", info); } for ip in srvs.ip_iter() { println!("ip: {}", ip); } } }

And that’s it, mDNS with DNS-SD. Now this isn’t a full implementation of the spec. To get here required a lot of work, PR#363. There were many underlying refactorings required in the library. For example, the protocols all used to immediately return on the first response. With the new DnsRequestOptions object passed into the trust-dns-proto requests, we optionally specify to allow more than one DnsResponse . DnsRequest and DnsResponse were added to the trust-dns-proto library, which helps clarify some areas of code where just Message was being used for inbound and outbound Message s. Those changes are in addition to the multicast protocol addition. In theory this will also allow for single multi-query DnsRequest s to be sent and received, but that’s not implemented yet (this will allow the SRV and TXT lookups to be combined into a single request).

In addition to that, to make the the SRV response processing better for the lookup_srv , the DnsResponse will be searched for IPs matching the target of SRV record. As of now this will not perform a recursive query, as CNAME does, some additional thought needs to be put into when to perform an A or AAAA lookup. The response Message should have this associated, so in most cases this does not matter, but libraries using the Resolver should be aware of this case. This is a general improvement on all SRV lookups in the library, the new ip_iter function on SrvLookup will provide access to these IPs. Also, I’ve deprecated the lookup_service and srv_lookup functions on ResolverFuture as I realized those were naively and overly simplistic in favor of the new lookup_srv implementation.

Why am I writing this post? I’d love some feedback on these implementations. I plan to land this as is in the master branch (after I review the code), and subsequently release in 0.9 (still feature flagged off) when that’s ready. Also, I think I’ve temporarily reached my limit with with mDNS and DNS-SD, so if others are interested in picking up the torch from here, I’d happily try to help mentor any additional changes.

For now, I think I’m going to switch gears and finalize TLS support in the Resolver since the creation of 1.1.1.1 .

Thanks!