Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Service discovery example #6

Open
fhunleth opened this issue Dec 18, 2018 · 10 comments
Open

Service discovery example #6

fhunleth opened this issue Dec 18, 2018 · 10 comments

Comments

@fhunleth
Copy link
Contributor

I'd like to advertise an ssh service so that a laptop running on the same LAN can discover the device. I've tried avahi-browse _ssh._tcp on my Linux laptop and made several attempts with registering a service. Is there an example somewhere on how to do this? or something similar that I could modify? I saw that you could register PTR and TXT records in the readme, but my attempts to use those have failed.

@entone
Copy link
Contributor

entone commented Dec 18, 2018

I haven't specifically tested SSH advertising, but in general the TXT advertising has worked. Can you post your registration code for the SSH service?

@fhunleth
Copy link
Contributor Author

I tried a few things, but I definitely have the feeling of not knowing enough about mDNS to make good guesses. Here's one iteration:

    domain = "nerves.local"
    Mdns.Server.add_service(%Mdns.Server.Service{
      domain: domain,
      data: :ip,
      ttl: 120,
      type: :a
    })  
    Mdns.Server.add_service(%Mdns.Server.Service{
      domain: domain,
      data: "_ssh._tcp.local",
      ttl: 120,                                                                                                                                                                              
      type: :txt
    })       

@entone
Copy link
Contributor

entone commented Dec 18, 2018

can you try making :txt -> :ptr

@fhunleth
Copy link
Contributor Author

That was my first try.

@entone
Copy link
Contributor

entone commented Dec 18, 2018

hmm, did you try using the built-in client?

Mdns.Client.query("_ssh._tcp.local")

anything with that?

@entone
Copy link
Contributor

entone commented Dec 18, 2018

also, you are starting the server as well?

ping nerves.local works fine?

@entone
Copy link
Contributor

entone commented Dec 18, 2018

after looking at the code, it may be necessary to pass the domain.

avahi-browse -d nerves.local _ssh._tcp

@entone
Copy link
Contributor

entone commented Dec 18, 2018

Specifically, this line https://github.com/rosetta-home/mdns/blob/master/lib/mdns/server.ex#L106

I'm not sure that is at all necessary.

@fazibear
Copy link
Contributor

fazibear commented May 13, 2019

This is what I've figured out today. Just an ssh service discovery.

[
  # create domain for an ip
  %Mdns.Server.Service{domain: "somedomain.local", data: :ip, ttl: 450, type: :a},

  # make service discoverable
  %Mdns.Server.Service{domain: "_services._dns-sd._udp.local",data: "_ssh._tcp.local",ttl: 4500, type: :ptr},

  # register ssh service
  %Mdns.Server.Service{domain: "_ssh._tcp.local",data: "SOME NAME._ssh._tcp.local",ttl: 4500, type: :ptr},


  # point service to our domain and port (22)
  %Mdns.Server.Service{domain: "SOME NAME._ssh._tcp.local",data: {0,0,22, 'somedomain.local'},ttl: 4500,type: :srv},

  # empty txt service (some tools expext that)
  %Mdns.Server.Service{domain: "SOME NAME._ssh._tcp.local",data: [],ttl: 4500,type: :txt})
] |> Enum.each(&Mdns.Server.add_service/1)

Also, there is pending PR with a working example: nerves-project-attic/nerves_init_gadget#62

Move the domain problem here: #7

@jackyz
Copy link

jackyz commented Nov 27, 2019

I had dig this problem for a while, and here is a example of service record.

service = "_nerves._tcp"
host = "hello"
domain = "local"

Mdns.Server.start(interface: ip_tuple)
Mdns.Server.set_ip(ip_tuple)
[
  # public the host :a
  %Mdns.Server.Service{domain: "#{host}.#{domain}", type: :a, ttl: 120, data: :ip},
  # public the service :ptr
  %Mdns.Server.Service{domain: "_services._dns-sd._udp.#{domain}", type: :ptr, ttl: 120, data: "#{service}.#{domain}"},
  # public the instance of the service :ptr
  %Mdns.Server.Service{domain: "#{service}.#{domain}", type: :ptr, ttl: 120, data: "#{host}.#{service}.#{domain}"},
  # public the info to connect the instance :srv
  # !!! you must use list instead of string when add srv recode due to the inet:dns just use list
  %Mdns.Server.Service{domain: String.to_charlist("#{host}.#{service}.#{domain}"), type: :srv, ttl: 120, data: {0, 0, 8080, String.to_charlist("#{host}.#{domain}")}},
  # public the extra info to connect the instance :txt
  %Mdns.Server.Service{domain: "#{host}.#{service}.#{domain}", type: :txt, ttl: 120, data: ["info=12341234"]}
] |> Enum.each(&Mdns.Server.add_service/1)

Logger.debug("Restarted Mdns server for service...")

Note the String.to_charlist usage when adding a :srv record, it's an ugly work around. there is a bug in somewhere, the inner inet:dns module only use list (instead of string). You can reproduce this bug easily.

the list will work well

DNS.Record.encode(%DNS.Record{header: %DNS.Header{aa: true, qr: true, opcode: 0, rcode: 0}, anlist: [%DNS.Resource{bm: [], class: :in, cnt: 0, type: :srv, ttl: 120, data: {0, 0, 8080, 'abc.local'}, domain: 'abc._nerves._tcp.local'}]})

but the string will throw an exception

DNS.Record.encode(%DNS.Record{header: %DNS.Header{aa: true, qr: true, opcode: 0, rcode: 0}, anlist: [%DNS.Resource{bm: [], class: :in, cnt: 0, type: :srv, ttl: 120, data: {0, 0, 8080, "abc.local"}, domain: "abc._nerves._tcp.local"}]})

There is still a problem in the L106. When the domain was set to a list, it's doesn't match the right side to_string(q.domain), I use to_sting(service.domain) as well, a careful improve was needed. maybe I will commit a pull request.

Then you can use dns-sd -L hello _nerves._tcp to test the result.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants