keepsimple1 / mdns-sd

Rust library for mDNS based Service Discovery
Apache License 2.0
89 stars 38 forks source link

A and AAAA mDNS records #163

Closed Type1J closed 6 months ago

Type1J commented 6 months ago

An SRV record is most appropriate for my usecase, however, there are a few cases where the client has only a web browser. Since I'll always have an http server at a known port, I'll just need an A record. I don't see a way to do that with this library, but I was able to make a working SRV record.

How do I create an A record with this library?

If that's not yet a feature, please consider this issue a feature request.

keepsimple1 commented 6 months ago

How do I create an A record with this library?

Are you asking in the context of a server publishing the service? Or are you asking about a particular API? Currently, you can specify A record (i.e. IP address) when creating a new ServiceInfo::new . Please let me know more details about what's missing and/or what you would like to see.

and thanks for opening an issue.

Type1J commented 6 months ago

I see the IP parameter. I'll try it tomorrow sometime. If it creates an mDNS A record with the host name passed in, then I'll close this issue.

Type1J commented 6 months ago

It seems that this is actually working. My mistake was that I was using ping the-hostname.local on the host. All other hosts on the network are able to see the A record, but the host itself was not. I'm assuming that this behavior is expected.

Type1J commented 6 months ago

Thanks for this library!

keepsimple1 commented 6 months ago

All other hosts on the network are able to see the A record, but the host itself was not. I'm assuming that this behavior is expected.

Did you try calling ServiceDaemon::browse() on the host itself too? Was it not working (i.e. not resolving on the host itself) ?

Type1J commented 6 months ago

ServiceDaemon::browse() does resolve on and off of the host, but that is for the SRV record. I haven't tried sending the name of the A record. I am making the assumption that the parameter name service_type implies that only the name of an SRV record should be passed. Is that correct?

keepsimple1 commented 6 months ago

When you see ServiceDaemon::browse() resolves the instances, the A record is already received as part of ServiceInfo. You can use ServiceInfo::get_hostname() to get it.

From the service publishing side, the name of the A record is the host_name parameter in ServiceInfo::new .

Type1J commented 6 months ago

I'm not sure why, but ping does not resolve the host that it's on. For example, with ping host_a can be seen as host_a.local from host_b on the same network, but host_a.local does not resolve on host_a. This library can get around that somehow with the records that it manages. Maybe it's the port 53 resolver combining results with the port 5353 resolver if ping uses only the port 53 (non-multicast) resolver, but that's just speculation. I'm not sure why ping doesn't see it's own host, but this library does. I would like to know incase that information becomes useful someday.

Type1J commented 6 months ago

I'll add for clarification that even the A record added by this library is not resolved by ping on the host that is providing them, but it is resolve by ping on other hosts on the network. However, the library itself, as you said above, can see mDNS records everywhere, even on the host that is providing them.

dalepsmith commented 6 months ago

For ping to be able to use a .local hostname, the the name resolver needs to know about mdns. And for that to work, you need to have some kind of "mdns responder" running that will cache mdns announce messages so they can be looked up.

On Linux, that's typically avahi-daemon along with adding mdns to /etc/nsswitch.conf.

I think there are ways to use systemd to resolve .local names (I see a few hints in some man pages), but I've never been able to get that to work on a Debian system.

-Dale

keepsimple1 commented 6 months ago

I tried locally but didn't see the same issue. I'm using the example code (register.rs) in this library:

On Raspberry Pi 4 running official RaspberryPi OS:

$ cargo run --example register _pi-hello._udp test2 
    Finished dev [unoptimized + debuginfo] target(s) in 0.06s
     Running `target/debug/examples/register _pi-hello._udp test2`
Registered service test2._pi-hello._udp.local.
Daemon event: Announce("test2._pi-hello._udp.local.", "[192.168.0.115, fe80::7b51:d73f:8b57:14a9]")
Daemon event: Announce("test2._pi-hello._udp.local.", "[192.168.0.115, fe80::7b51:d73f:8b57:14a9]")

In the example code, host_name is hard-coded as mdns-example.local. (this can be improved ;-) )

Then I tried to use ping from both the same machine and a remote machine on the same network:

from the same machine: (RPi Linux)

$ ping mdns-example.local
PING mdns-example.local (192.168.0.115) 56(84) bytes of data.
64 bytes from 192.168.0.115 (192.168.0.115): icmp_seq=1 ttl=64 time=0.079 ms
$ ping mdns-example.local.
PING mdns-example.local. (192.168.0.115) 56(84) bytes of data.
64 bytes from 192.168.0.115 (192.168.0.115): icmp_seq=1 ttl=64 time=0.091 ms

from another machine: (macOS)

$ ping mdns-example.local. 
PING mdns-example.local (192.168.0.115): 56 data bytes
64 bytes from 192.168.0.115: icmp_seq=0 ttl=64 time=22.049 ms

Note, I can ping the name with or without the ending .

EDIT: please make sure you have the service publisher (using this library or something else) running when doing the ping? I believe ping / DNS will forward the resolution to mDNS when the hostname ends with .local. (also see /etc/nsswitch.conf as Dale pointed out)

dalepsmith commented 6 months ago

Note that RaspberryPi OS (raspbian) has avahi enabled by default and has it wired into the nss (name server switch).

And of course MacOS has Bonjour/mDNSResponder running.

-Dale

Type1J commented 6 months ago

Just FYI: I am running Nobara Linux 36, which is based on Fedora 36. In /etc/nsswitch.conf on the hosts: line I have hosts: files myhostname mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns.