richardschneider / net-mdns

Simple multicast DNS
MIT License
232 stars 81 forks source link

Allow dot in service name #64

Closed gilzad closed 5 years ago

gilzad commented 5 years ago

In Bonjour, Avahi and a commit to Jmdns it is possible to not only have a typical service like: instance._serviceType._protocol._domain but also instance._subinstance._serviceType._protocol._domain

I've tried that concatenation in net-mdns but then avahi won't resolve the service and Bonjour won't even find the published service (i.e. doesn't react to PTR or SRV). Upon investigation the domain-part in the PTR-record seems stripped.

Answers
    _itxpt_http._tcp.local: type PTR, class IN, TST-PC._fmstoip-add
        Name: _itxpt_http._tcp.local
        Type: PTR (domain name PoinTeR) (12)
        .000 0000 0000 0001 = Class: IN (0x0001)
        0... .... .... .... = Cache flush: False
        Time to live: 4500
        Data length: 23
        Domain Name: TST-PC._fmstoip-add
Additional records
    TST-PC._fmstoip-add: type SRV, class IN, priority 0, weight 0, port 8085, target TST-PC._fmstoip-add
        Service: TST-PC
        Protocol: _fmstoip-add
        Type: SRV (Server Selection) (33)
        .000 0000 0000 0001 = Class: IN (0x0001)
        0... .... .... .... = Cache flush: False
        Time to live: 4500
        Data length: 40
        Priority: 0
        Weight: 0
        Port: 8085
        Target: TST-PC._fmstoip-add

In comparison that's how Bonjour advertises its service like this:

Answers
    _services._dns-sd._udp.local: type PTR, class IN, _itxpt_http._tcp.local
        Name: _services._dns-sd._udp.local
        Type: PTR (domain name PoinTeR) (12)
        .000 0000 0000 0001 = Class: IN (0x0001)
        0... .... .... .... = Cache flush: False
        Time to live: 4500
        Data length: 2
        Domain Name: _itxpt_http._tcp.local
    _itxpt_http._tcp.local: type PTR, class IN, TST-PC._fmstoip-add._itxpt_http._tcp.local
        Name: _itxpt_http._tcp.local
        Type: PTR (domain name PoinTeR) (12)
        .000 0000 0000 0001 = Class: IN (0x0001)
        0... .... .... .... = Cache flush: False
        Time to live: 4500
        Data length: 2
        Domain Name: TST-PC._fmstoip-add._itxpt_http._tcp.local
    TST-PC._fmstoip-add._itxpt_http._tcp.local: type SRV, class IN, cache flush, priority 0, weight 0, port 8085, target TST-PC.local
        Service: TST-PC
        Protocol: _fmstoip-add
        Name: _itxpt_http._tcp.local
        Type: SRV (Server Selection) (33)
        .000 0000 0000 0001 = Class: IN (0x0001)
        1... .... .... .... = Cache flush: True
        Time to live: 120
        Data length: 15
        Priority: 0
        Weight: 0
        Port: 8085
        Target: TST-PC.local

And Avahi advertises like this:

Answers
    _itxpt_http._tcp.local: type PTR, class IN, TST-PC._fmstoip-add._itxpt_http._tcp.local
        Name: _itxpt_http._tcp.local
        Type: PTR (domain name PoinTeR) (12)
        .000 0000 0000 0001 = Class: IN (0x0001)
        0... .... .... .... = Cache flush: False
        Time to live: 4500
        Data length: 2
        Domain Name: TST-PC._fmstoip-add._itxpt_http._tcp.local
    TST-PC._fmstoip-add._itxpt_http._tcp.local: type SRV, class IN, cache flush, priority 0, weight 0, port 8085, target beaglebone.local
        Service: TST-PC
        Protocol: _fmstoip-add
        Name: _itxpt_http._tcp.local
        Type: SRV (Server Selection) (33)
        .000 0000 0000 0001 = Class: IN (0x0001)
        1... .... .... .... = Cache flush: True
        Time to live: 120
        Data length: 19
        Priority: 0
        Weight: 0
        Port: 8085
        Target: beaglebone.local
    _services._dns-sd._udp.local: type PTR, class IN, _itxpt_http._tcp.local
        Name: _services._dns-sd._udp.local
        Type: PTR (domain name PoinTeR) (12)
        .000 0000 0000 0001 = Class: IN (0x0001)
        0... .... .... .... = Cache flush: False
        Time to live: 4500
        Data length: 2
        Domain Name: _itxpt_http._tcp.local

I'm gladly willing to make a PR as soon as I've figured out what causes any possibly malformed(?) packets. I've chased a lot of suspectations in ServiceProfile() but didn't really gain the understanding to successfully publish a serivce with a name like TST-PC._fmstoip-add. Can I kindly ask for any hint on this?

richardschneider commented 5 years ago

Have you tried new ServiceProfile("instance", "subinstance._serviceType._protocol", port)?

Just like stackoverflow please show the code and explain what is expected.

gilzad commented 5 years ago

Thanks for the support. I've stripped my tests down to the PTR-record for now.

Yes, I have tried concatenating to the service name instead.

new ServiceProfile("TST-PC", "_fmstoip-add._itxpt_http._tcp", 8085, new[] { IPAddress.Parse(cbIpAddresses.SelectedItem.ToString()) });

This results in such a PTR record:

_fmstoip-add._itxpt_http._tcp.local: type PTR, class IN, TST-PC._fmstoip-add._itxpt_http._tcp.local
    Name: _fmstoip-add._itxpt_http._tcp.local
    Type: PTR (domain name PoinTeR) (12)
    .000 0000 0000 0001 = Class: IN (0x0001)
    0... .... .... .... = Cache flush: False
    Time to live: 4500
    Data length: 9
    Domain Name: TST-PC._fmstoip-add._itxpt_http._tcp.local

In that case neither Avahi nor Bonjour sees the service while browsing.

Whilst concatenating to the instance name...

new ServiceProfile("TST-PC._fmstoip-add", "_itxpt_http._tcp", 8085, new[] { IPAddress.Parse(cbIpAddresses.SelectedItem.ToString()) });

...results in such a PTR record:

_itxpt_http._tcp.local: type PTR, class IN, TST-PC._fmstoip-add._itxpt_http._tcp.local
    Name: _itxpt_http._tcp.local
    Type: PTR (domain name PoinTeR) (12)
    .000 0000 0000 0001 = Class: IN (0x0001)
    0... .... .... .... = Cache flush: False
    Time to live: 4500
    Data length: 22
    Domain Name: TST-PC._fmstoip-add._itxpt_http._tcp.local

In that case Avahi can show the service. But seemingly with the wrong name: + eth0 IPv4 TST-PC _fmstoip-add._itxpt_http._tcp local

Here is a 'good' PTR record from Avahi or Bonjour (they create the same PTR):

_itxpt_http._tcp.local: type PTR, class IN, TST-PC._fmstoip-add._itxpt_http._tcp.local
    Name: _itxpt_http._tcp.local
    Type: PTR (domain name PoinTeR) (12)
    .000 0000 0000 0001 = Class: IN (0x0001)
    0... .... .... .... = Cache flush: False
    Time to live: 4500
    Data length: 2
    Domain Name: TST-PC._fmstoip-add._itxpt_http._tcp.local

A 'working' publishing from Bonjour or Avahi would appear in avahi-browse as such: + eth0 IPv4 TST-PC._fmstoip-add _itxpt_http._tcp local

The only obvious difference I see in net-mdns vs. Avahi|Bonjour is the Data length (net-mdns: 22, Avahi|Bonjour: 2).

Why I can't say what I'm expecting yet: If I suppress the PTR-record in net-mdns and publish a usual service like

new ServiceProfile("TST-PC", "_itxpt_http._tcp", 8085, new[] { IPAddress.Parse(cbIpAddresses.SelectedItem.ToString()) });

..then both Avahi and Bonjour do find the service. But as soon as I add a dot the instance name, Bonjour won't find the service at all. Avahi will, but with the wrong name as shown above.

Could there be anything to the Data-length from net-mdns that confuses those clients?

Sorry I'm not much of a help yet.

richardschneider commented 5 years ago

The data length mismatch is most likely due to the name compression feature. net-mdns supports this. So it's unclear why the difference exists.

Is it possible for you to attach the binary (or base-64 encoded) message sent by Bonjour?

richardschneider commented 5 years ago

It's more than just "adding a dot". You are using DNS-SD subtypes, which was never implemented. I've now added subtype support in release v0.22.0.

Try this

var profile = new ServiceProfile(
  "TST-PC", "_itxpt_http._tcp", 8085, 
  new[] { IPAddress.Parse(cbIpAddresses.SelectedItem.ToString()) });
profile.Subtypes.Add("_fmstoip-add");

Looking forward to see if this works!

gilzad commented 5 years ago

If it's subtypes, then I'm embarrassed to not have looked into the right rfc beforehand.

But I'm not quite sure about the added _sub from the refered rfc for two reasons:

I can force Avahi to publish a subtype with that _sub delimiter with an explicit parameter:

avahi-publish-service TST-PC _itxpt_http._tcp 8085 --sub _fmstoip-add._itxpt_http._tcp

And I'm glad you added support for that. But I fear that covers a different use case.

Avahi publishes an extended instance name just like this: avahi-publish-service TST-PC._fmstoip-add _itxpt_http._tcp 8085

..where the first parameter TST-PC._fmstoip-add is the instance name.

Binary pcap of Avahi publishing an extended instance name

If you need the pcap dump from Bonjour, I'd like to send it to you through a private channel (Bonjour sends a bit too much of private info).

gilzad commented 5 years ago

I have to add: Of course I did check the subtypes you implemented. But unfortunately without the expected result.

The subtype records would only be sent as a response to a QM specifically for that subtype. Rightfully so, but that doesn't make the service appear as TST-PC._fmstoip-add in the clients.

richardschneider commented 5 years ago

I think the issue that net-mdns does not allow an instance-name to contain any character (as per section 4.1.1).

This will also require changes to net-dns.

gilzad commented 5 years ago

Sorry I was out of reach last week. I finally found the cause of this issue after I had stripped down everything to just using net-dns and and .NET's UdpClient. I should have pulled more often. Just before opening an issue on net-dns, I saw your comment on escaping domain names.

Since this issue is remotely related to the solution from net-dns: I checked it with an escaped dot \. and the instance name is being published correctly now. Thanks for the quick support!

richardschneider commented 5 years ago

I've just released v0.23.0 It contains the net-dns updates. Would you mind trying it and reporting back to me.

Thanks - Richard

gilzad commented 5 years ago

Of course! I manipulated the Spike-app..

ServiceProfile z1 = new ServiceProfile("z1\\._test", "_soap._tcp", 5012);

And the service does show up in both my clients (Avahi and Bonjour). Here is how Avahi discovers and resolves the published service:

avahi-browse -r _soap._tcp
+   eth0 IPv4 z1._test                                      _soap._tcp           local
=   eth0 IPv4 z1._test                                      _soap._tcp           local
   hostname = [z1\._test.soap.local]
   address = [192.168.200.1]
   port = [5012]
   txt = ["foo=bar" "txtvers=1"]

I assume there is an issue with the host name in the SRV record. [edit] I moved my related discussion about it to https://github.com/richardschneider/net-mdns/issues/68 . In my opinion this specific issue (dot in instance name) is fixed and it can be closed now.