Code Monkey home page Code Monkey logo

dnssd's People

Contributors

brutella avatar ericvh avatar erwanmas avatar jamessanford avatar jmalloc avatar lencerf avatar leoon-ding avatar lhecker avatar lukasmalkmus avatar rblenkinsopp avatar ripienaar avatar stapelberg avatar stefanopulze avatar testwill avatar xpol avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dnssd's Issues

panic (sigsegv) in dnssd.probeAtInterface()

github.com/brutella/dnssd v1.1.1
MacOS 10.14.6 (Mojave)
go version go1.14.1 darwin/amd64

I've been successfully using the library for some time, but in the last few days, my program has been crashing at unpredictable times with the following panic stack trace.

Here's how I start the responder:

	cfg := dnssd.Config{
		Name: serviceName,
		Type: "_osc._udp",
		Port: int(oscListenPort),
	}
	var service dnssd.Service
	if service, err = dnssd.NewService(cfg); err != nil {
		return
	}
	var responder dnssd.Responder
	if responder, err = dnssd.NewResponder(); err != nil {
		return
	}
	if _, err = responder.Add(service); err != nil {
		return
	}

	go func() {
		ctx, cancel := context.WithCancel(context.Background())
		responderCancel = cancel
		defer cancel()

		if err = responder.Respond(ctx); err != nil {
			return
		}
	}()

How can I help get more useful debugging info so you can help diagnose?

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x13a6946]

goroutine 3864 [running]:
github.com/brutella/dnssd.probeAtInterface(0x164fd40, 0xc001bb5880, 0x1650e40, 0xc0009cd440, 0xc00ad31670, 0xe, 0x158de5c, 0x9, 0x158c55e, 0x5, ...)
	/Users/tynor/go/pkg/mod/github.com/brutella/[email protected]/probe.go:178 +0x8f6
github.com/brutella/dnssd.probe(0x164fd40, 0xc001bb5880, 0x1650e40, 0xc0009cd440, 0xc00ad31670, 0xe, 0x158de5c, 0x9, 0x158c55e, 0x5, ...)
	/Users/tynor/go/pkg/mod/github.com/brutella/[email protected]/probe.go:114 +0x337
github.com/brutella/dnssd.probeService(0x164fd40, 0xc001bb5880, 0x1650e40, 0xc0009cd440, 0xc00ad31670, 0xe, 0x158de5c, 0x9, 0x158c55e, 0x5, ...)
	/Users/tynor/go/pkg/mod/github.com/brutella/[email protected]/probe.go:61 +0x35b
github.com/brutella/dnssd.ReprobeService(0x164fd40, 0xc001bb5880, 0xc00ad31670, 0xe, 0x158de5c, 0x9, 0x158c55e, 0x5, 0xc001cf7c40, 0x37, ...)
	/Users/tynor/go/pkg/mod/github.com/brutella/[email protected]/probe.go:49 +0x14c
github.com/brutella/dnssd.(*responder).reprobe(0xc00b050e80, 0xc000010b28)
	/Users/tynor/go/pkg/mod/github.com/brutella/[email protected]/responder.go:348 +0x13b
created by github.com/brutella/dnssd.(*responder).respond
	/Users/tynor/go/pkg/mod/github.com/brutella/[email protected]/responder.go:248 +0x474

G601: Implicit memory aliasing in for loop. (gosec)

I realized that the browsing query wasn't send on all my network interfaces, but multiple times on the same interface:

DEBUG 2021/01/29 11:05:39.304802 Send browsing query at docker0
DEBUG 2021/01/29 11:05:39.304884 Send browsing query at docker0
DEBUG 2021/01/29 11:05:39.304929 Send browsing query at veth8e256c1
DEBUG 2021/01/29 11:05:39.304990 Send browsing query at veth8e256c1
DEBUG 2021/01/29 11:05:39.305033 Send browsing query at vethb987ea9

The reason of this behaviour is because of Implicit memory aliasing in for loop see here
Such issues can easily be found by a linter like golangci-lint.
Running the linter locally found more critical entries:

browse.go:60:31: G601: Implicit memory aliasing in for loop. (gosec)
                        q := &Query{msg: m, iface: &iface}
                                                   ^
mdns.go:130:33: G601: Implicit memory aliasing in for loop. (gosec)
                        if err := connIPv4.JoinGroup(&iface, &net.UDPAddr{IP: IPv4LinkLocalMulticast}); err != nil {
                                                     ^
mdns.go:146:33: G601: Implicit memory aliasing in for loop. (gosec)
                        if err := connIPv6.JoinGroup(&iface, &net.UDPAddr{IP: IPv6LinkLocalMulticast}); err != nil {
                                                     ^
probe.go:33:7: G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec)
        r := rand.New(rand.NewSource(time.Now().UnixNano()))
             ^
resolve.go:41:31: G601: Implicit memory aliasing in for loop. (gosec)
                        q := &Query{msg: m, iface: &iface}
                                                   ^
responder.go:64:14: G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec)
                random:    rand.New(rand.NewSource(time.Now().UnixNano())),
                           ^

I would like to fix the points and add the golangci-lint linter in the refactoring branch. Are you fine with that?

Browse example only works with full service strings

I tried the browse example to test out lookup of all services.

Using just _tcp yields no results. Compare that to avahi-browse _tcp wich yields a lot of results

./browse -Type _tcp
Browsing for _tcp.local.
DATE: –––Wed Mar 1 2023–––
16:08:35.855  ...STARTING...
Timestamp	A/R	if Domain	Service Type	Service Name
^C

However I get results with a broader query

./browse -Type _googlecast._tcp
Browsing for _googlecast._tcp.local.
DATE: –––Wed Mar 1 2023–––
16:09:43.070  ...STARTING...
Timestamp	A/R	if Domain	Service Type	Service Name
16:09:43.164	Add	wlp0s20f3	local	_googlecast._tcp	Google-Nest-Mini-6147e2ff355612c5da0029f5a82002a2 ([192.168.1.26])
16:09:43.165	Add	wlp0s20f3	local	_googlecast._tcp	M65Q7-H1-a4cbf4829ec90c72e9f4e42c2b2ca294 ([192.168.1.103])
^C

Panic when request interfaces are nil

Attempting to create a simple service following the sample in HAP,

Steps to Reproduce

  1. Run the HAP sample application shown in the README.md.
  2. Notice that it panics in DNSSD with the following stack-trace:
goroutine 7 [running]:
github.com/brutella/dnssd.(*Service).IPsAtInterface(0xc0000916b8, 0x0)
        C:/Users/rober/go/pkg/mod/github.com/brutella/[email protected]/service.go:154 +0x3d
github.com/brutella/dnssd.A({{0xc0000299b0, 0xa}, {0x99a57d, 0x9}, {0x998f38, 0x5}, {0xc0000299c0, 0xc}, 0xc0001c2f00, 0x0, ...}, ...)
[signal C:/Users/rober/go/pkg/mod/github.com/brutella/[email protected]/dns.go:116 +0x39
github.com/brutella/dnssd.containsConflictingAnswers(0xc0002581f8, 0xc000006820)
        C:/Users/rober/go/pkg/mod/github.com/brutella/[email protected]/responder.go:465 +0xbb
github.com/brutella/dnssd.findConflicts(0xc0002581f8, {0xc000208050, 0x1, 0x1?})
        C:/Users/rober/go/pkg/mod/github.com/brutella/[email protected]/responder.go:446 +0x9b
github.com/brutella/dnssd.(*responder).handleRequest(0xc0001c4700, 0xc0002581f8)
        C:/Users/rober/go/pkg/mod/github.com/brutella/[email protected]/responder.go:238 +0x195
github.com/brutella/dnssd.(*responder).respond(0xc0001c4700, {0xa3df30, 0xc0001d8300})
        C:/Users/rober/go/pkg/mod/github.com/brutella/[email protected]/responder.go:203 +0x1d4
github.com/brutella/dnssd.(*responder).Respond(0xc0001c4700, {0xa3df30, 0xc0001d8300})
        C:/Users/rober/go/pkg/mod/github.com/brutella/[email protected]/responder.go:113 +0x3ef
github.com/brutella/hap.(*Server).listenAndServe.func1()
        C:/Users/rober/go/pkg/mod/github.com/brutella/[email protected]/server.go:205 +0x37
created by github.com/brutella/hap.(*Server).listenAndServe
        C:/Users/rober/go/pkg/mod/github.com/brutella/[email protected]/server.go:204 +0x465

Process finished with the exit code 2

Expected Behaviour

The HAP server announces correctly on DNSSD and no panic occurs.

Investigation

Looking into this further, it's failing because the iface parameter being passed to the A() and AAAA() is nil which causes those functions to fail.

It's nil because the implementation of payloadHandler.ReadFrom which is used internally by mdnsConn.readInto, doesn't set the cm parameter (leaving it nil), which the rest of the dnssd stack fails to deal with correctly.

Possible Fixes

  • Have the A() and AAAA() methods deal with a possibly nil interface (iface) argument.
  • Prevent the iface parameter of the dnssd.request struct from being nil in the first place.

I've tested the first of these two options and DNSSD then exhibits the correct behaviour (and I will submit an MR for this) however the second possible fix might be the better solution (though both can be implemented together to be suitable defensive).

Reproduction Machine Network Configuration

For additional reference, my network configuration which exposes this issue is (Public IPs and MACs redacted):

`ipconfig /all` output
Ethernet adapter Ethernet:

   Connection-specific DNS Suffix  . : xxxx.local
   Description . . . . . . . . . . . : Intel(R) Ethernet Connection I217-V
   Physical Address. . . . . . . . . : XX-XX-XX-XX-XX-XX
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
   IPv6 Address. . . . . . . . . . . : xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx(Preferred)
   Temporary IPv6 Address. . . . . . : xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx(Deprecated)
   Temporary IPv6 Address. . . . . . : xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx(Preferred)
   Link-local IPv6 Address . . . . . : xxxx::xxxx:xxxx:xxxx:xxxx%X(Preferred)
   IPv4 Address. . . . . . . . . . . : 10.4.1.2(Preferred)
   Subnet Mask . . . . . . . . . . . : 255.255.0.0
   Lease Obtained. . . . . . . . . . : 14 May 2022 08:20:32
   Lease Expires . . . . . . . . . . : 16 May 2022 11:01:35
   Default Gateway . . . . . . . . . : xxxx::xxxx:xxxx:xxxx:xxxx%X
                                       10.4.0.1
   DHCP Server . . . . . . . . . . . : 10.4.0.1
   DHCPv6 IAID . . . . . . . . . . . : 213671924
   DHCPv6 Client DUID. . . . . . . . : XX-XX-XX-XX-XX-XX-XX-XX-XX-XX-XX-XX-XX-XX
   DNS Servers . . . . . . . . . . . : 10.4.0.1
   Primary WINS Server . . . . . . . : 10.4.1.1
   NetBIOS over Tcpip. . . . . . . . : Enabled

Unknown adapter Private Internet Access:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Private Internet Access Network Adapter
   Physical Address. . . . . . . . . : XX-XX-XX-XX-XX-XX
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes

Wireless LAN adapter WiFi:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . : xxxx.local
   Description . . . . . . . . . . . : Broadcom 802.11ac Network Adapter
   Physical Address. . . . . . . . . : XX-XX-XX-XX-XX-XX
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes

Wireless LAN adapter Local Area Connection* 1:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Microsoft Wi-Fi Direct Virtual Adapter
   Physical Address. . . . . . . . . : XX-XX-XX-XX-XX-XX
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes

Wireless LAN adapter Local Area Connection* 2:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Microsoft Wi-Fi Direct Virtual Adapter #2
   Physical Address. . . . . . . . . : XX-XX-XX-XX-XX-XX
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes

Ethernet adapter Bluetooth Network Connection:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Bluetooth Device (Personal Area Network)
   Physical Address. . . . . . . . . : XX-XX-XX-XX-XX-XX
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes

Ethernet adapter vEthernet (WSL):

   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Hyper-V Virtual Ethernet Adapter
   Physical Address. . . . . . . . . : XX-XX-XX-XX-XX-XX
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : xxxx::xxxx:xxxx:xxxx:xxxx%X(Preferred)
   IPv4 Address. . . . . . . . . . . : 172.29.112.1(Preferred)
   Subnet Mask . . . . . . . . . . . : 255.255.240.0
   Default Gateway . . . . . . . . . :
   DHCPv6 IAID . . . . . . . . . . . : 721425757
   DHCPv6 Client DUID. . . . . . . . : XX-XX-XX-XX-XX-XX-XX-XX-XX-XX-XX-XX-XX-XX
   NetBIOS over Tcpip. . . . . . . . : Enabled

Rediscovery services and mdns

I use this package to manage some hardware , my source is her https://github.com/ErwanMAS/godfrey4home/blob/master/src/homekit-switch.go .

After registration , and a long time .
When i restart , the bridge , my iphone can not reconnect to the hk bridge .

I ran some tcpdump on 5353 , and i saw that the phone always made a query on _hap._tcp.local. PTR .

The mdns hc bridge provide by /brutella/hc/ , does not reply , with a answer .

If i comment this line , i have what i think the good behavior, the bridge reply with a response to himself .

resp.Answer = remove(req.msg.Answer, resp.Answer)

I think the object req.msg.Answer , must not store answers from his own local services .

How to get hostname and port from a browse?

I am trying to update my code to use the new 1.2.0 version of the library (was using 1.1.1). browse.go has changed to use BrowseEntry's instead of Service objects. I can't find a way to get the Hostname and Port of the browsed service in my addFunc. None of the relevant example cmd programs (e.g., cmd/browse, cmd/resolve) appear to print hostname or port for the discovered services.

Help?

Race condition uncovered during tests

I'm using dnssd in a project of mine and I run my tests with the race detector. This surfaced a race in dnssd:

==================
WARNING: DATA RACE
Write at 0x00c00029e0b7 by goroutine 31:
  github.com/brutella/dnssd.(*mdnsConn).readInto.func3()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/mdns.go:260 +0x63

Previous read at 0x00c00029e0b7 by goroutine 29:
  github.com/brutella/dnssd.(*mdnsConn).readInto.func1()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/mdns.go:188 +0x7f

Goroutine 31 (running) created at:
  github.com/brutella/dnssd.(*mdnsConn).readInto()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/mdns.go:258 +0xc7
  github.com/brutella/dnssd.(*mdnsConn).Drain()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/mdns.go:178 +0x1e3
  github.com/brutella/dnssd.probeAtInterface()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/probe.go:163 +0x9fa
  github.com/brutella/dnssd.probe()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/probe.go:114 +0x441
  github.com/brutella/dnssd.probeService()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/probe.go:61 +0x3ae
  github.com/brutella/dnssd.ProbeService()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/probe.go:38 +0x43d
  github.com/brutella/dnssd.(*responder).register()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/responder.go:185 +0x481
  github.com/brutella/dnssd.(*responder).Respond()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/responder.go:104 +0x20b
  github.com/hemtjanst/fargton/bridge.(*Server).Start.func4()
      /home/daenney/Development/github.com/hemtjanst/fargton/bridge/server.go:226 +0x6e

Goroutine 29 (running) created at:
  github.com/brutella/dnssd.(*mdnsConn).readInto()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/mdns.go:185 +0x13a
  github.com/brutella/dnssd.(*mdnsConn).Drain()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/mdns.go:178 +0x1e3
  github.com/brutella/dnssd.probeAtInterface()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/probe.go:163 +0x9fa
  github.com/brutella/dnssd.probe()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/probe.go:114 +0x441
  github.com/brutella/dnssd.probeService()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/probe.go:61 +0x3ae
  github.com/brutella/dnssd.ProbeService()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/probe.go:38 +0x43d
  github.com/brutella/dnssd.(*responder).register()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/responder.go:185 +0x481
  github.com/brutella/dnssd.(*responder).Respond()
      /home/daenney/Development/go/pkg/mod/github.com/brutella/[email protected]/responder.go:104 +0x20b
  github.com/hemtjanst/fargton/bridge.(*Server).Start.func4()
      /home/daenney/Development/github.com/hemtjanst/fargton/bridge/server.go:226 +0x6e
==================

This happens b/c the isReading var in readInto needs a lock around it to ensure it can safely be modified.

dnssd on Linux not responding to multicast DNS lookups

linux% go get github.com/brutella/hklight
linux% $GOPATH/bin/hklight

The service appears, but after two minutes, is removed:

osx% dns-sd -B _hap._tcp
Browsing for _hap._tcp
DATE: ---Wed 22 Nov 2017---
21:57:49.094  ...STARTING...
Timestamp     A/R    Flags  if Domain               Service Type         Instance Name
21:57:49.095  Add        2   5 local.               _hap._tcp.           Personal_Light_Bulb
21:59:47.216  Rmv        0   5 local.               _hap._tcp.           Personal_Light_Bulb

If you run tcpdump and run browse.go,
you can see lookup packets but no answer.

osx% tcpdump -n -p -v -i en4 port 5353

osx% go get -d github.com/brutella/dnssd
osx% cd $GOPATH/src/github.com/brutella/dnssd/_cmd
osx% go run browse.go
tcpdump: listening on en4, link-type EN10MB (Ethernet), capture size 262144 bytes
22:00:27.957981 IP (tos 0x0, ttl 1, id 7291, offset 0, flags [none], proto UDP (17), length 61)
    192.168.1.40.5353 > 224.0.0.251.5353: 0 PTR (QM)? _hap._tcp.local. (33)

by default listens on port 5353

I am using your hc project in my choria.io project to do some IoT work and really loving it.

Unfortunately though due to this line:

var DefaultResponder, _ = NewResponder()

Even when hc is not enabled a mdns listener is started and active and talking to the network, this is not desired as I tend to run my software on very large server estates - 10s of thousands of nodes - all of them joining mDNS is a bit of a surprise :) I'd like to enable it only when configured to be enabled.

Investigating further I cannot see anywhere where this DefaultResponder is used in hc or dnssd, would it be possible to either remove this line if its unused or turn it into something thats lazy started only when needed?

I can send a PR with your guidance @brutella

thanks

Browse in refactoring branch is broken for windows

Unfortunately setting a control message is not supported for windows, see here: https://github.com/golang/net/blob/master/ipv6/control_windows.go

So a Request struct will never have a iface. It will always be nil:

dnssd/mdns.go

Line 222 in 0d9d12f

if cm != nil {

This leads to a nil pointer exception at:

log.Debug.Printf("Receive message at %s\n%s\n", req.iface.Name, req.msg)

And it will never notify about any service because the ifaceIPs dictionary is always empty for windows:

for ifaceName, ips := range srv.ifaceIPs {

Publish service on provided interfaces only

Hello,

First of all thank you for the library.

I had couple of issues:
How can I publish service on selected interface only? Providing config.Ifaces seems not working.

Here is the testing code:

package main

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"time"

	slog "log"

	"github.com/brutella/dnssd"
)

func main() {
	// log.Debug.Enable()
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go startDNSSDServer(ctx)

	time.Sleep(time.Second)
	go queryDNSSD(ctx)

	go func() {
		stop := make(chan os.Signal, 1)
		signal.Notify(stop, os.Interrupt)

		select {
		case <-stop:
			cancel()
		}
	}()

	<-ctx.Done()
}

func queryDNSSD(ctx context.Context) {
	service := "_service_type._tcp.local."

	slog.Printf("Lookup %s\n", service)

	addFn := func(e dnssd.BrowseEntry) {
		slog.Printf(
			"%s can be reached at %s %v\n",
			e.ServiceInstanceName(),
			e.IPs,
			e.Text)
	}

	if err := dnssd.LookupType(ctx, service, addFn, func(dnssd.BrowseEntry) {}); err != nil {
		fmt.Println(err)
		return
	}
}

func startDNSSDServer(ctx context.Context) {
	txtRecord := map[string]string{
		"txtvers": "1",
		"data":    "some-data",
	}
	config := dnssd.Config{
		Name:   "my_service",
		Type:   "_service_type._tcp",
		Domain: "local",
		Port:   1337,
		Text:   txtRecord,
		Ifaces: []string{"en0"},
		// IPs: []net.IP{net.ParseIP("192.168.228.92")},
	}

	service, err := dnssd.NewService(config)
	if err != nil {
		slog.Fatal(err)
	}

	responder, err := dnssd.NewResponder()
	if err != nil {
		slog.Fatal(err)
	}

	_, err = responder.Add(service)
	if err != nil {
		slog.Fatal(err)
	}

	slog.Println("Starting dnssd server")
	err = responder.Respond(ctx)
	if err != nil {
		slog.Fatal(err)
	}
}

This outputs:

$ go run main.go
2022/04/01 12:21:33 Starting dnssd server
2022/04/01 12:21:34 Lookup _service_type._tcp.local.
2022/04/01 12:21:34 my_service._service_type._tcp.local. can be reached at [127.0.0.1 ::1 fe80::1] map[data:some-data txtvers:1]
2022/04/01 12:21:34 my_service._service_type._tcp.local. can be reached at [192.168.228.92 fe80::107e:be39:9b23:64e5] map[data:some-data txtvers:1]
2022/04/01 12:21:34 my_service._service_type._tcp.local. can be reached at [fe80::f483:f4ff:fe0f:6312] map[data:some-data txtvers:1]
2022/04/01 12:21:34 my_service._service_type._tcp.local. can be reached at [fe80::278d:3c6:4662:f2b2] map[data:some-data txtvers:1]
2022/04/01 12:21:34 my_service._service_type._tcp.local. can be reached at [fe80::503:1e69:3b2e:b7a4] map[data:some-data txtvers:1]

As you can see from output, it includes multiple interfaces.

Second issue I had is related to TXT records. In the same file if you remove time.Sleep() before querying data, the results do not include TXT record. Might be related to #16.

Output:

$ go run main.go
2022/04/01 12:29:14 Lookup _service_type._tcp.local.
2022/04/01 12:29:14 Starting dnssd server
2022/04/01 12:29:14 my_service._service_type._tcp.local. can be reached at [192.168.228.92 fe80::107e:be39:9b23:64e5] map[]
2022/04/01 12:29:14 my_service._service_type._tcp.local. can be reached at [127.0.0.1 ::1 fe80::1] map[data:some-data txtvers:1]
2022/04/01 12:29:15 my_service._service_type._tcp.local. can be reached at [fe80::f483:f4ff:fe0f:6312] map[data:some-data txtvers:1]
2022/04/01 12:29:15 my_service._service_type._tcp.local. can be reached at [fe80::278d:3c6:4662:f2b2] map[data:some-data txtvers:1]
2022/04/01 12:29:15 my_service._service_type._tcp.local. can be reached at [fe80::503:1e69:3b2e:b7a4] map[data:some-data txtvers:1]

Fix IP address of a service is published on all network interfaces

Registering a service with a fixed IP address might not work as expected because the IP address is announced on all multicast network interfaces. But the IP address might not be accessible from all network interfaces.

Instead a fixed IP address should be specified for a specific network interface.

Dealing with IP changes

Sometimes DHCP or manual changes can cause a computer's IP address to change. It looks like dnssd currently caches the IPs in the Service's IfaceIPs. This means the incorrect IP will be included in mdns responses.

Support hot plugging

Services should be renounced after a new network interface is active.

Currently there is no way to tell if a network interface is operational.
net.FlagUp only tells that a network interface is configured and up.
Also a network interface can have a valid IP address even though for example no ethernet cable is attached.

Wait until net.FlagRunning is added to Go.
golang/go#29991

Question: Refactoring branch

Thanks for your great work with this project.

We are currently facing the issue that for IPv6 link local the interface name is needed to establish a connection.
You implemented this feature in your refactoring branch along with other fixes like e45ff4e.

Now i wonder if there is a reason why the branch was not merged into master. On a first glance it works stable. Are there some open issues? Do you think the refactoring branch can be used in production?

Custom hostnames never get registered?

I'm using this patch to be able to set a hostname for the register example:

diff --git a/_cmd/register.go b/_cmd/register.go
index d866c64..9d49ad3 100644
--- a/_cmd/register.go
+++ b/_cmd/register.go
@@ -15,6 +15,7 @@ import (
 var instanceFlag = flag.String("Name", "Service", "Service name")
 var serviceFlag = flag.String("Type", "_asdf._tcp.", "Service type")
 var domainFlag = flag.String("Domain", "local.", "domain")
+var hostFlag = flag.String("Host", "", "hostname")
 var portFlag = flag.Int("Port", 12345, "Port")

 var timeFormat = "15:04:05.000"
@@ -39,7 +40,7 @@ func main() {
        if resp, err := dnssd.NewResponder(); err != nil {
                fmt.Println(err)
        } else {
-               srv := dnssd.NewService(*instanceFlag, *serviceFlag, *domainFlag, "", nil, *portFlag)
+               srv := dnssd.NewService(*instanceFlag, *serviceFlag, *domainFlag, *hostFlag, nil, *portFlag)

                go func() {
                        stop := make(chan os.Signal, 1)

If I don't specify a hostname, everything works as expected:

./register  2>&1 | grep -v DEBUG                             130 ↵
Registering Service Service._asdf._tcp.local. port 12345
DATE: –––Thu Mar 22 2018–––
18:20:53.110	...STARTING...
;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;tmm1-imac.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 tmm1-imac.local.
tmm1-imac.local.	120	IN	A	10.0.1.240

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;tmm1-imac.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 tmm1-imac.local.
tmm1-imac.local.	120	IN	A	10.0.1.240

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;tmm1-imac.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 tmm1-imac.local.
tmm1-imac.local.	120	IN	A	10.0.1.240

18:20:53.987	Got a reply for service Service._asdf._tcp.local.: Name now registered and active

But if I pass in a hostname, it appends a number to the end and keep incrementing it forever:

Registering Service Service._asdf._tcp.local. port 12345
DATE: –––Thu Mar 22 2018–––
18:21:09.860	...STARTING...
;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown.local.
unknown.local.	120	IN	A	10.0.1.240
unknown.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown.local.
unknown.local.	120	IN	A	10.0.1.240
unknown.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown-2.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown-2.local.
unknown-2.local.	120	IN	A	10.0.1.240
unknown-2.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown-2.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown-2.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown-2.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown-2.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown-2.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown-2.local.
unknown-2.local.	120	IN	A	10.0.1.240
unknown-2.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown-2.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown-2.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown-2.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown-2.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown-3.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown-3.local.
unknown-3.local.	120	IN	A	10.0.1.240
unknown-3.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown-3.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown-3.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown-3.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown-3.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown-3.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown-3.local.
unknown-3.local.	120	IN	A	10.0.1.240
unknown-3.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown-3.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown-3.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown-3.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown-3.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown-4.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown-4.local.
unknown-4.local.	120	IN	A	10.0.1.240
unknown-4.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown-4.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown-4.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown-4.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown-4.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown-4.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown-4.local.
unknown-4.local.	120	IN	A	10.0.1.240
unknown-4.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown-4.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown-4.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown-4.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown-4.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown-5.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown-5.local.
unknown-5.local.	120	IN	A	10.0.1.240
unknown-5.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown-5.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown-5.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown-5.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown-5.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

;; flags:; QUERY: 2, ANSWER: 0, AUTHORITY: 7, ADDITIONAL: 0

;; QUESTION SECTION:
;Service._asdf._tcp.local.	CLASS32769	 ANY
;unknown-5.local.	CLASS32769	 ANY

;; AUTHORITY SECTION:
Service._asdf._tcp.local.	120	IN	SRV	0 0 12345 unknown-5.local.
unknown-5.local.	120	IN	A	10.0.1.240
unknown-5.local.	120	IN	AAAA	fe80::2b8:2527:4334:98b4
unknown-5.local.	120	IN	AAAA	fe80::4aa:883:df8b:110c
unknown-5.local.	120	IN	AAAA	fe80::d8d2:50ff:fea2:33f8
unknown-5.local.	120	IN	AAAA	fe80::cfa4:720:c5b6:d2f4
unknown-5.local.	120	IN	AAAA	fe80::121a:1fda:9977:8b89

^C

Trying to publish A record

I'm using the example code here and trying to register a Record:
https://github.com/brutella/dnssd/tree/v1.2.4/cmd/register

I've adjusted:
cfg := dnssd.Config{
Name: *instanceFlag,
Type: *serviceFlag,
Domain: *domainFlag,
Port: *portFlag,
Ifaces: ifaces,
IPs: []net.IP{net.ParseIP("127.0.0.1")}, //hardcoded just for a test (although docs say this is deprecated)
}

Trying to get a test.local to resolve to 127.0.0.1 (or whatever IP I like).

$ dns-sd -B. --> this does detect the Service
Timestamp A/R Flags if Domain Service Type Instance Name
13:30:38.961 Add 3 6 local. _http._tcp. test

$ dns-sd -G v4 test.local --> this does not show any entries. Where as other mDNS devices on my network pop up such as Octopi.local and my printer.

$ ping test.local
ping: cannot resolve test.local: Unknown host

When I try this with the dns-sd -P "test" _http._tcp local 8888 test.local 127.0.0.1. --> this works and I see the A record when I packet sniff and also name resolution works.

Just curious what I am doing wrong, or need example code to make it happen :)
Thanks!

Howto: query meta service _services._dns-sd._udp.local

I'm trying to send out a unicast QU for service discovery at startup of my application. I can't find a way to use the library to do that. LookupType() does not expose a way to set the unicast bit and unconditionally sends out a QM query.

I tried to copy and paste the browse.go functions into my app and adapt them, but got stuck since I can't create a Query struct (all fields are unexported) and I can't find a public constructor function.

Ideas?

(if you agree that this is a reasonable use case and adding a call to setQuestionUnicast() in lookupType is the fix, I could create a pull request. Perhaps create a new func LookupTypeUnicast() that passes in a boolean to tell lookupType() to set the bit?)

LookupInstance how to use

i'm try to resolve onetime some record via dnssd.LookupInstance, but it stuck.
Can you provide example? Or does it work?

Lookup services will fail to list ips if the service name contains more than one dot

Browsing services with multiple dots in their domain name fails to read A records.

Consider the following answer:

****** ;; opcode: QUERY, status: NOERROR, id: 0
;; flags: qr aa; QUERY: 0, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 4

;; ANSWER SECTION:
_raop._tcp.local.       4500    IN      PTR     CEDD39ACA62E\@Corpisone._raop._tcp.local.

;; ADDITIONAL SECTION:
CEDD39ACA62E\@Corpisone._raop._tcp.local.       4500    CLASS32769      TXT     "sf=0x4" "fv=76400.10" "am=ShairportSync" "vs=105.1" "tp=TCP,UDP" "vn=65537" "ss=16" "sr=44100" "da=true" "sv=false" "et=0,1" "ek=1" "cn=0,1" "ch=2" "txtvers=1" "pw=false"
CEDD39ACA62E\@Corpisone._raop._tcp.local.       4500    CLASS32769      SRV     0 0 5000 airport.corpisone.container.local.
airport.corpisone.container.local.      120     CLASS32769      A       10.0.4.18
airport.corpisone.container.local.      120     CLASS32769      NSEC    airport.corpisone.container.local. A

While parsing the srv record:

dnssd/cache.go

Line 63 in 7335cb4

entry.SetHostname(rr.Target)

ParseHostName will apparently fail to set the hostname

func (s *Service) SetHostname(hostname string) {

In turn, when parsing the A record, it will fail to recognize the entry as valid:

dnssd/cache.go

Line 70 in 7335cb4

if entry.Hostname() == rr.Hdr.Name {

... ultimately not listing the service IP.

The above works well if the service name contains just one level (eg: "foobar.local.")

Maybe I'm missing something here - plus I'm not familiar with the spec...

What are your thoughts?

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.