Giter Club home page Giter Club logo

mdns's Introduction

mdns

Build Status

Simple mDNS client/server library in Golang. mDNS or Multicast DNS can be used to discover services on the local network without the use of an authoritative DNS server. This enables peer-to-peer discovery. It is important to note that many networks restrict the use of multicasting, which prevents mDNS from functioning. Notably, multicast cannot be used in any sort of cloud, or shared infrastructure environment. However it works well in most office, home, or private infrastructure environments.

Using the library is very simple, here is an example of publishing a service entry:

// Setup our service export
host, _ := os.Hostname()
info := []string{"My awesome service"}
service, _ := mdns.NewMDNSService(host, "_foobar._tcp", "", "", 8000, nil, info)

// Create the mDNS server, defer shutdown
server, _ := mdns.NewServer(&mdns.Config{Zone: service})
defer server.Shutdown()

Doing a lookup for service providers is also very simple:

// Make a channel for results and start listening
entriesCh := make(chan *mdns.ServiceEntry, 4)
go func() {
    for entry := range entriesCh {
        fmt.Printf("Got new entry: %v\n", entry)
    }
}()

// Start the lookup
mdns.Lookup("_foobar._tcp", entriesCh)
close(entriesCh)

mdns's People

Contributors

armon avatar azlyth avatar boydjeff avatar brutella avatar calebalbers avatar dependabot[bot] avatar hashicorp-copywrite[bot] avatar jcodybaker avatar jefferai avatar loshz avatar mkeeler avatar muesli avatar reddaly avatar richtr avatar ryanuber avatar sean- avatar stapelberg avatar yinghau76 avatar zimbatm 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  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

mdns's Issues

mans doesn't work on Solaris

trying a simple client test on Solaris:

/var/tmp/mdns_client
2015/05/27 23:49:54 [ERR] mdns: Failed to bind to udp4 port: listen udp4 0.0.0.0:5353->224.0.0.251: option not supported by protocol
2015/05/27 23:49:54 [ERR] mdns: Failed to bind to udp6 port: listen udp6 [::]:5353->ff02::fb: option not supported by protocol

Code:

package main

import (
    "fmt"
    "github.com/hashicorp/mdns"
)

func main() {
    // Make a channel for results and start listening
    entriesCh := make(chan *mdns.ServiceEntry, 4)
    go func() {
        for entry := range entriesCh {
            fmt.Printf("Got new entry: %v\n", entry)
        }
    }()

    // Start the lookup
    mdns.Lookup("_http._tcp", entriesCh)
    close(entriesCh)
}

Running go test in mans produces:

$ go test -v
=== RUN   TestServer_StartStop
--- FAIL: TestServer_StartStop (0.00s)
        server_test.go:12: err: No multicast listeners could be started
=== RUN   TestServer_Lookup
--- FAIL: TestServer_Lookup (0.00s)
        server_test.go:20: err: No multicast listeners could be started
=== RUN   TestNewMDNSService_BadParams
--- PASS: TestNewMDNSService_BadParams (0.00s)
=== RUN   TestMDNSService_BadAddr
--- PASS: TestMDNSService_BadAddr (0.00s)
=== RUN   TestMDNSService_ServiceAddr
--- PASS: TestMDNSService_ServiceAddr (0.00s)
=== RUN   TestMDNSService_InstanceAddr_ANY
--- PASS: TestMDNSService_InstanceAddr_ANY (0.00s)
=== RUN   TestMDNSService_InstanceAddr_SRV
--- PASS: TestMDNSService_InstanceAddr_SRV (0.00s)
=== RUN   TestMDNSService_InstanceAddr_A
--- PASS: TestMDNSService_InstanceAddr_A (0.00s)
=== RUN   TestMDNSService_InstanceAddr_AAAA
--- PASS: TestMDNSService_InstanceAddr_AAAA (0.00s)
=== RUN   TestMDNSService_InstanceAddr_TXT
--- PASS: TestMDNSService_InstanceAddr_TXT (0.00s)
=== RUN   TestMDNSService_HostNameQuery
--- PASS: TestMDNSService_HostNameQuery (0.00s)
=== RUN   TestMDNSService_serviceEnum_PTR
--- PASS: TestMDNSService_serviceEnum_PTR (0.00s)
FAIL
exit status 1
FAIL    github.com/hashicorp/mdns       0.013s

add interface to mdns discover

Patch looks very trivial:

	// validate and set interface
	if args["interface"] != "" {
		if params.Interface, err = net.InterfaceByName(args["interface"]); err != nil {
			return nil, fmt.Errorf("discover-mdns: Failed to discover host interface(%s): %s", args["interface"], err)
		}
	}

Is this package still maintained?

It does not seem so, 12 open pull requests and no recent activity.
I would like to use this package but not if its unmaintained.
Can somebody suggest an alternative package?
Somebody wants to fork an maintain?

nil pointer dereference

There are network situations where multicast is disabled for IPv6, but not IPv4. And there are situations where the network may change (if you need to connect and disconnect from a VPN, for example). If the user has not set DisableIPv6 in the QueryParam struct to true, then a segfault may occur. I've created a PR for a fix (#118), and given details of how the pieces fall in place for a segfault in the description.

As I've looked at the other Issues and PRs for this library, I see that my PR really should be combined with #87. PR#87 sets both mconn6 and uconn6 to nil if either is nil. As I thought about it, my PR#118 can be ignored completely if PR#87 is changed to add v6 = false in the if block. This has the same effect of the user setting DisableIPv6 to true, but it's like mdns has tested the environment and seen that IPv6 is not viable for both unicast and multicast and sets DisableIPv6 to true for the user. Perhaps adding a log message and setting v6 to false is the right way to go.

So, I'm proposing mdns use one of two solutions:

  1. Merge both #87 and #118
  2. Add a log message and v6 = false inside the if block in #87

This issue might be a duplicate of #43, but that issue is old, therefore doesn't reflect the latest code, and lacks detail to know for sure.

Allow the requestor to specify the DNS record type

I ran into a problem with the client package, where I needed to be able to specify the type of record being requested. If this is a feature that might be useful to others, I have the pull request below.

doesn't interoperate with mdns-scan or Avahi

Entries published with this package can be browsed with this package. However, they don't show up in either mdns-scan or avahi-browser -a

Using ngrep and tcpdump, it seems like the mdns.Server responds to queries, but somehow those other standard tools don't seem to recognize the responses.

Server code crashes with a segfault

Hey, I am trying to use this library, but it crashes under Linux. It works fine on OS X Yosemite, but when I tried to run it under Ubuntu 14.04 in vbox, I get a crash. I will try to look at the code and see if I can resolve it, but I just wanted to document the crash here.

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x4c90a3]

goroutine 12 [running]:
github.com/hashicorp/mdns.(_MDNSService).Records(0x0, 0xc20801eb60, 0x15, 0x1000c, 0x0, 0x0, 0x0)
/home/loc/projects/go/src/github.com/hashicorp/mdns/zone.go:139 +0x343
github.com/hashicorp/mdns.(_Server).handleQuestion(0xc20803b680, 0xc20801eb60, 0x15, 0x1000c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)

Example code in README does not compile

Hello,

I was trying the code in the example and I am getting:
./main.go:14: unknown mdns.MDNSService field 'Info' in struct literal
When I commented it out, I then got:
./main.go:16: service.Init undefined (type *mdns.MDNSService has no field or method Init)

Any chance on an update to the README example code?

Thanks,
Glen

No results (Windows)

Seems to work fine on a Pi. Here's the same code running under Windows:

c:\repo\src>go run mdns.go
2020/03/31 16:21:23 [ERR] mdns: Failed to bind to udp6 port: listen udp6 [ff02::fb]:5353: setsockopt: not supported by windows
2020/03/31 16:21:24 [ERR] mdns: Failed to read packet: read udp4 0.0.0.0:52447: use of closed network connection

Doesn't work in Windows 10 browser

Looks like the project has been abandoned?

On Windows10 I tried this for use in the browser, but it didn't work. What am I doing wrong?

// Setup our service export
host, _ := os.Hostname()
fmt.Printf("Hostname at %s\n", host)
info := []string{"My awesome service"}
ip := net.ParseIP("127.0.0.1")
service, err2 := mdns.NewMDNSService(host, "_http._tcp.", "", "server.", 8089, []net.IP{ip}, info)
// fmt.Fprintf(w, "NewMDNSService err: %v", err2)
fmt.Println(err2)
// Create the mDNS server, defer shutdown
server, err2 := mdns.NewServer(&mdns.Config{Zone: service})
// fmt.Fprintf(w, "NewMDNSService err: %v", err2)
fmt.Println(err2)

// defer server.Shutdown()
_ = server

No results ?

Hi,

I'm trying to complete my tool by discovering xbmc jsonrpc service that is published via zeroconf.

Avahi-tools give me the correct output:

$ avahi-browse -a -d local
...
+ wlp2s0 IPv4 XBMC (raspbmc)                                _xbmc-events._udp    local
+ wlp2s0 IPv4 XBMC (raspbmc)                                _xbmc-jsonrpc-h._tcp local
+ wlp2s0 IPv4 XBMC (raspbmc)                                _xbmc-jsonrpc._tcp   local

But, taking your example in README, I've got no response...

package main

import (
    "fmt"
    "github.com/armon/mdns"
)

func main() {

    entriesCh := make(chan *mdns.ServiceEntry, 4)
    go func() {
        for entry := range entriesCh {
            fmt.Printf("Got new entry: %v\n", entry)
        }
    }()

    // Start the lookup
    mdns.Lookup("_xbmc-jsonrpc._tcp", entriesCh)
    close(entriesCh)
}

What am I doing wrong ?

Thanks :)

EDIT:

It seems that I can only lookup services on localhost. I tried with "_workstation._tcp" and the program only return my current computer...

Crash when no IF_MULTICAST support

Hi there! I'm using this to test mDNS inside Docker overlay networking (yeah, I know, weird, but I have a use case for it), and the library causes a panic (instead of returning an error) when you try to use it without IF_MULTICAST set on the network interface (which, incidentally, is the default inside Docker - there's no multicast flag yet).

Decreased reliance on explicit IP addressing and updates to DNS record presentation

I made a number of changes to this library based on a need for decreasing the reliance on explicit IP addressing. The full diff of changes can be viewed at richtr/mdns@armon:master...master.

The summary of the changes is as follows:

  1. Don't require an upfront IP address to be passed in when creating a new mDNS service. Instead, determine the local machine's FQDN and then resolve this to both its IPv4 and IPv6 addresses implicitly.

  2. When an mDNS query is received then return both a service's A record and its AAAA record (in line with other mDNS library behavior) rather than filtering out one or the other.

  3. Ensure the mDNS SRV record response provides a resolvable FQDN address as per the spec.

    From this:

    myservice._ws._tcp.local. 10  IN  SRV  10 1 8080 myservice._ws._tcp.local.
    

    to this:

    myservice._ws._tcp.local. 10  IN  SRV  10 1 8080 MyMacBook.local.
    
  4. Ensure mDNS A and AAAA record responses relate to the resolvable SRV name as per the spec:

    From this:

    myservice._ws._tcp.local. 10  IN  A     127.0.0.1
    myservice._ws._tcp.local. 10  IN  AAAA  ::1
    

    to this:

    MyMacBook.local. 10  IN  A     10.112.0.152
    MyMacBook.local. 10  IN  AAAA  fe80::7aca:39ff:feb4:42c1
    
  5. Update the tests and README example according to the changes above.

Are these changes that we could incorporate in to this library somehow? If you would like this in the form of a pull request just let me know.

Multiple Answer RRs are not sent as separate entries

Hello,

Thank you for the library!

I am using library to discover specific services on local network by querying service type. There can be multiple services of the same type from same machine/device. There is an issue I have encountered, query responses that have multiple answers are not reported as separate entries.

Checkout wireshark screenshot:

Screenshot 2022-04-06 at 16 16 50

Here 192.168.80.92 is the address of device running the client code. 192.168.80.182 is the server which responds to mdns queries (it is windows machine, uses bonjour service).
As you can see from screenshot, the are 2 services of type _itxpt_http._tcp. The Answer section contains 2 records, + additional records for each of these 2 answers.

The client code:

package main

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

	"github.com/hashicorp/mdns"
)

func main() {
	timeout := 2 * time.Second
	ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
	ctx, cancel := context.WithTimeout(ctx, timeout)
	defer cancel()

	entriesCh := make(chan *mdns.ServiceEntry, 4)
	go mdns.Query(&mdns.QueryParam{
		Service:     "_itxpt_http._tcp",
		Entries:     entriesCh,
		DisableIPv6: true,
		Domain:      "local",
		Timeout:     timeout,
	})

	for {
		select {
		case entry := <-entriesCh:
			fmt.Println("Got new entry:", entry.Name)
		case <-ctx.Done():
			fmt.Println("done")
			return
		}
	}
}

Client only registers 1 entry, with values of second answer:

$ go run client.go
Got new entry: vehicle-1000_inventory._itxpt_http._tcp.local.
done

Is there a way to get these values as two separate entries?
Like:

Got new entry: vehicle-1000_avms._itxpt_http._tcp.local.
Got new entry: vehicle-1000_inventory._itxpt_http._tcp.local.

It seems like the entry gets overwritten with the data from last answer in this loop: https://github.com/hashicorp/mdns/blob/v1.0.5/client.go#L272

Why is the TTL always set to 0?

I was having issues getting the services I was advertising through this library to show up in other mDNS clients that are not using this library.

Having registered a service via this library I could dig it as follows:

$> dig -p 5353 @224.0.0.251 _ws._tcp.local. any

; <<>> DiG 9.8.3-P1 <<>> -p 5353 @224.0.0.251 _ws._tcp.local. any
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44747
;; flags: qr rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;_ws._tcp.local.            IN  ANY

;; ANSWER SECTION:
_ws._tcp.local.     0   IN  PTR myservice._ws._tcp.local.
0234234242_authservice_bws._ws._tcp.local. 0 IN SRV 10 1 2010 myservice._ws._tcp.local.
0234234242_authservice_bws._ws._tcp.local. 0 IN A 10.112.0.236
0234234242_authservice_bws._ws._tcp.local. 0 IN TXT "Local web service"

;; Query time: 7 msec
;; SERVER: 10.112.0.236#5353(224.0.0.251)
;; WHEN: Fri May 23 14:15:47 2014
;; MSG SIZE  rcvd: 330

So the service existed and was being advertised but was not showing up via e.g. dns-sd:

$> dns-sd -B _ws._tcp

<No records>

Changing the Ttl values set throughout zone.go from 0 to 10 seems to resolve this problem. It seems some clients ignore services received with a TTL of 0 which seems like reasonable behaviour.

So I'm wondering why DNS record TTL is always set to 0 in this library. Could this library instead set DNS record TTLs to a different reasonable default value such as 10 so it plays nicely with other clients (or let developers configure TTLs somehow)?

Service based query fails over and returns random mDNS responses

The mdns.Lookup returns random results, when target service type is not found.

This is an undocumented and random response, which makes this library useless for service lookup.

github.com/hashicorp/mdns v1.0.5


import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"time"

	"github.com/hashicorp/mdns"
)

func main() {

	// Make a channel for results and start listening
	entriesCh := make(chan *mdns.ServiceEntry, 4)
	go func() {
		for entry := range entriesCh {
			fmt.Printf("Got new entry: %v\n", entry)
		}
	}()
	// Start the lookup
	mdns.Lookup("_pcm._tcp", entriesCh)
	close(entriesCh)
}
Got new entry: &{PCM-Sink._pcm._tcp.local. mdns-C78.local. 192.168.1.66 <nil> 3333 path=/foobar|board=esp32 [path=/foobar board=esp32] 192.168.1.66 true true}
2023/03/01 11:52:10 [INFO] mdns: Closing client {true true 0xc000128038 0xc000128040 0xc000128048 0xc000128050 1 0xc00010e120}
alex@ubuntu:~/eclipse-workspace/mdns$ ./mdns 
Got new entry: &{PCM-Sink._pcm._tcp.local. mdns-C78.local. 192.168.1.66 <nil> 3333 path=/foobar|board=esp32 [path=/foobar board=esp32] 192.168.1.66 true true}
2023/03/01 11:52:13 [INFO] mdns: Closing client {true true 0xc000014048 0xc000014050 0xc000014058 0xc000014060 1 0xc00001c1e0}
alex@ubuntu:~/eclipse-workspace/mdns$ ./mdns 
2023/03/01 11:52:25 [INFO] mdns: Closing client {true true 0xc000014048 0xc000014050 0xc000014058 0xc000014060 1 0xc00001c1e0}
alex@ubuntu:~/eclipse-workspace/mdns$ ./mdns 
Got new entry: &{mac-address-id._googlezone._tcp.local. mac-address-id.local. 192.168.1.42 ***}
Got new entry: &{mac-address-id._agentdvr._tcp.local. mac-address-id.agentdvr.local. 192.168.1.221 ***}
Got new entry: &{Chromecast-Ultra._googlecast._tcp.local. mac-address-id.local. 192.168.1.42 ***}
Got new entry: &{spotify._spotify-connect._tcp.local. 521797894248-0.local. 192.168.1.15 ***}
Got new entry: &{mac-address-id._googlezone._tcp.local. mac-address-id.local. 192.168.1.27 ***}
Got new entry: &{mac-address-id._googlezone._tcp.local. mac-address-id.local. 192.168.1.25 ***}
Got new entry: &{OctoPrint\ instance\ on\ octoprint._octoprint._tcp.local. octoprint.local. 192.168.1.53 ***}
Got new entry: &{mac._googlezone._tcp.local. mac.local. 192.168.1.26 ***}
Got new entry: &{mac._googlezone._tcp.local. mac.local. 192.168.1.28 ***}
Got new entry: &{iPhone._rdlink._tcp.local. iPhone.local. 192.168.1.55 ***}
Got new entry: &{Family\ Room\ TV._viziocast._tcp.local. CastTV.local. 192.168.1.103 ***}
Got new entry: &{xxx::windows11._oculusal_sp._tcp.local. windows11.local. 192.168.1.221 ***}
2023/03/01 11:52:27 [INFO] mdns: Closing client {true true 0xc000014048 0xc000014050 0xc000014058 0xc000014060 1 0xc00001c1e0}

osx - Failed to bind to udp6 port: listen udp6 ff02::fb: setsockopt: can't assign requested address

Getting this error when trying to use Lookup/Query - OSX 10.9.4 Go 1.4.2

Specifically this test - TestServer_Lookup

➜  mdns git:(master) go test -run Lookup
2015/04/23 17:03:29 [ERR] mdns: Failed to bind to udp6 port: listen udp6 ff02::fb: setsockopt: can't assign requested address
2015/04/23 17:03:29 [INFO] mdns: Closing client {0xc20802c068 0xc20802c070 0xc20802c078 <nil> true 0xc208030360 {1 0}}
2015/04/23 17:03:29 [ERR] mdns: Failed to read packet: read udp4: use of closed network connection
2015/04/23 17:03:29 [ERR] mdns: Failed to read packet: read udp6: use of closed network connection
2015/04/23 17:03:29 [ERR] mdns: Failed to read packet: read udp4: use of closed network connection
PASS
ok      github.com/hashicorp/mdns   0.121s

Also this simple program failed to run.

package main

import (
    "fmt"
    "time"

    "github.com/hashicorp/mdns"
)

func main() {

    // Make a channel for results and start listening
    entriesCh := make(chan *mdns.ServiceEntry, 4)
    go func() {
        for entry := range entriesCh {
            fmt.Printf("Got new entry: %v\n", entry)
        }
    }()

    // Start the lookup
    //mdns.Lookup("_googlecast._tcp.local.", entriesCh)

    params := mdns.DefaultParams("_googlecast._tcp.local.")

    params.Entries = make(chan *mdns.ServiceEntry, 4)

    mdns.Query(params)

    time.Sleep(10 * time.Second)

    close(entriesCh)

}
➜  mDNSLocal  go run client.go
2015/04/23 16:37:55 [ERR] mdns: Failed to bind to udp6 port: listen udp6 ff02::fb: setsockopt: can't assign requested address
2015/04/23 16:37:56 [INFO] mdns: Closing client {0xc208038020 0xc208038028 0xc208038030 <nil> true 0xc2080520c0 {1 0}}
2015/04/23 16:37:56 [ERR] mdns: Failed to read packet: read udp4: use of closed network connection
2015/04/23 16:37:56 [ERR] mdns: Failed to read packet: read udp6: use of closed network connection
2015/04/23 16:37:56 [ERR] mdns: Failed to read packet: read udp4: use of closed network connection

Having read some other issues, I've checked that the OSX firewall is not on. Also it looks like I have an IPv6 address.

➜  mdns git:(master) ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
    options=3<RXCSUM,TXCSUM>
    inet6 ::1 prefixlen 128
    inet 127.0.0.1 netmask 0xff000000
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
    nd6 options=1<PERFORMNUD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    options=10b<RXCSUM,TXCSUM,VLAN_HWTAGGING,AV>
    ether 40:6c:8f:1c:3f:72
    inet6 fe80::426c:8fff:fe1c:3f72%en0 prefixlen 64 scopeid 0x4
    inet 192.168.1.110 netmask 0xffffff00 broadcast 192.168.1.255
    nd6 options=1<PERFORMNUD>
    media: autoselect (100baseTX <full-duplex,flow-control>)
    status: active
fw0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 4078
    lladdr 40:6c:8f:ff:fe:5d:de:be
    nd6 options=1<PERFORMNUD>
    media: autoselect <full-duplex>
    status: inactive
en1: flags=8823<UP,BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
    ether 70:73:cb:c2:cd:ab
    nd6 options=1<PERFORMNUD>
    media: autoselect (<unknown type>)
    status: inactive
en4: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
    options=60<TSO4,TSO6>
    ether b2:00:15:dd:eb:e1
    media: autoselect <full-duplex>
    status: inactive
p2p0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 2304
    ether 02:73:cb:c2:cd:ab
    media: autoselect
    status: inactive
bridge0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    options=63<RXCSUM,TXCSUM,TSO4,TSO6>
    ether 42:6c:8f:c1:81:00
    Configuration:
        id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
        maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
        root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
        ipfilter disabled flags 0x2
    member: en4 flags=3<LEARNING,DISCOVER>
            ifmaxaddr 0 port 7 priority 0 path cost 0
    nd6 options=1<PERFORMNUD>
    media: <unknown type>
    status: inactive

Any pointers about what I should be looking at? Tried to do it using sudo but same result.
Slightly confused as the tests run and are ok - are the above messages errors?

Thanks!

compilation error ARM64

Hi,

when I compile my project (using hashicorp/mdns) on ARM64 I get the following compilation error:

[...]

# github.com/hashicorp/go.net/ipv4
../../hashicorp/go.net/ipv4/sockopt_asmreqn_unix.go:20:12: undefined: getsockopt
../../hashicorp/go.net/ipv4/sockopt_asmreqn_unix.go:41:42: undefined: setsockopt
../../hashicorp/go.net/ipv4/sockopt_unix.go:29:12: undefined: getsockopt
../../hashicorp/go.net/ipv4/sockopt_unix.go:51:42: undefined: setsockopt
# github.com/hashicorp/go.net/ipv6
../../hashicorp/go.net/ipv6/sockopt_rfc3493_unix.go:105:42: undefined: setsockopt
../../hashicorp/go.net/ipv6/sockopt_rfc3493_unix.go:114:42: undefined: setsockopt
../../hashicorp/go.net/ipv6/sockopt_rfc3542_unix.go:54:12: undefined: getsockopt
../../hashicorp/go.net/ipv6/sockopt_rfc3542_unix.go:75:12: undefined: getsockopt
../../hashicorp/go.net/ipv6/sockopt_rfc3542_unix.go:82:42: undefined: setsockopt

[...]

Can't go get with Go 1.5

$ go get github.com/hashicorp/mdns
package github.com/hashicorp/mdns
    imports github.com/hashicorp/go.net/ipv4
    imports code.google.com/p/go.net/internal/iana: use of internal package not allowed

Tests failing on OS X

Hi,

I'm unable to both lookup or register new mDNS services on my local network. Running go test *.go in the root folder of this package consistently outputs the following:

2014/05/21 15:47:48 [ERR] mdns: Failed to start IPv6 listener: listen udp6 ff02::fb: setsockopt: can't assign requested address
2014/05/21 15:47:48 [ERR] mdns: Failed to start IPv6 listener: listen udp6 ff02::fb: setsockopt: can't assign requested address
--- FAIL: TestServer_Lookup (0.05 seconds)
server_test.go:63: record not found
FAIL
FAIL    command-line-arguments  0.067s

I'm running OS X 10.9.2 and Go version 1.2 (darwin/amd64).

Any ideas on why the tests would be failing on my setup?

trying to discover chromecasts. No results?

Im having trouble using mdns to discover my chromecasts.
First i thought the issue was related to \032 (asci space). But when i renamed chromecast without spaces i still get nothing.

Have anyone else had issues with chromecasts?

This is an output from dig.

dig @224.0.0.251 -p 5353 -t PTR _googlecast._tcp.local.

; <<>> DiG 9.9.2-P2 <<>> @224.0.0.251 -p 5353 -t PTR _googlecast._tcp.local.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17559
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 3

;; QUESTION SECTION:
;_googlecast._tcp.local.        IN  PTR

;; ANSWER SECTION:
_googlecast._tcp.local. 10  IN  PTR Chromecast\032Cumulus._googlecast._tcp.local.

;; ADDITIONAL SECTION:
Chromecast\032Cumulus._googlecast._tcp.local. 10 IN SRV 0 0 8009 Chromecast\032Cumulus.local.
Chromecast\032Cumulus._googlecast._tcp.local. 10 IN TXT "id=9472d23123344568ad3c5660f5bd" "ve=02" "md=Chromecast" "ic=/setup/icon.png" "fn=Chromecast Cumulus" "ca=5" "st=0"
Chromecast\032Cumulus.local. 10 IN  A   192.168.5.110

Chromecast

Hello!

Its possible to send multicast response directly to chromecast? I want to isolate chromecast for other users.

Unable to build example

I'm trying to build example file of your package and get this

example.go

package main

import (
    "fmt"
    "github.com/armon/mdns"
    "os"
)

func main() {
    host, _ := os.Hostname()
    service := &mdns.MDNSService{
        Instance: host,
        Service:  "_foobar._tcp",
        Port:     8000,
        Info:     "My awesome service",
    }
    service.Init()

    // Create the mDNS server, defer shutdown
    server, _ := mdns.NewServer(&mdns.Config{Zone: service})
    defer server.Shutdown()

    // Make a channel for results and start listening
    entriesCh := make(chan *mdns.ServiceEntry, 4)
    go func() {
        for entry := range entriesCh {
            fmt.Printf("Got new entry: %v\n", entry)
        }
    }()

    // Start the lookup
    mdns.Lookup("_foobar._tcp", entriesCh)
    close(entriesCh)
}
[vodolaz095@steel gopnik]$ go version
go version go1.3.3 linux/amd64
[vodolaz095@steel gopnik]$ go build discovery.go
# code.google.com/p/go.net/ipv6
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:75: undefined: sysSizeofPacketInfo
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:78: undefined: sysSizeofMTUInfo
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:85: undefined: sysSockoptReceiveTrafficClass
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:92: undefined: sysSockoptReceiveHopLimit
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:99: undefined: sysSockoptReceivePacketInfo
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:100: undefined: sysSizeofPacketInfo
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:101: undefined: sysSizeofPacketInfo
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:106: undefined: sysSockoptReceivePathMTU
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:107: undefined: sysSizeofMTUInfo
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:108: undefined: sysSizeofMTUInfo
/home/vodolaz095/projects/go/src/code.google.com/p/go.net/ipv6/control_rfc3542_unix.go:108: too many errors

I'm quite new to go, and probably i builded something not properly - i just installed golang packages from rpm for this

Doesn't work on OS 10.10

Managed to get successfully it running on Linux (even using multicast-dns library for node/go interop). However in Mac OS X, can't seem to get services published by the lib to be found by the same lib or other libs that implement mDNS.

multicast-dns works fine on Mac OS X though, so there should be something specific to go mdns lib.

Seeing Remove event after some minutes

I see a Remove event after some minutes for the service I published with mDNS.
Here is the output of dns-sd -B <service>

19:23:07.208  Add        2   4 local.               <service>._tcp.           ...
19:31:11.247  Rmv        1   4 local.               <service>._tcp.           ...
19:31:11.247  Add        2   4 local.               <service>._tcp.           ...
19:39:36.689  Rmv        1   4 local.               <service>._tcp.           ...
19:39:36.689  Add        2   4 local.               <service>._tcp.           ...

I think because other devices are actively looking for this service, the service appears again and I see the Add event. I've done some research if we need to send some kind of keep-alive message, but could not find an answer.

When I publish a service using the command line tool dns-sd on OS X, I don't see any Remove events for the service.

Anyone knows what's going on there?

Any plans to refactor the "Query" and "Lookup" functions to use context instead of a hard timeout?

Given that results are streaming to a channel, using a context instead of a hard timeout would be more appropriate. Working with a hard timeout within the concurrency model set up in this library somewhat awkward and limiting. For example what if I want to read entries from a channel until I find all of the entries I am looking for and then move on? Currently to do this you either have to:

  1. Choose an overly long timeout and be okay with the goroutine running Query not exiting until potentially long after its task has be fulfilled
  2. Repeat calls to Query with a short timeout in a loop

1 means sacrificing performance and even if its unlikely to be a bottleneck in your applications resource use its still pretty grating to anyone who cares about good design. Whereas 2 feels like over-engineering due to utilizing a clunky API.

Having these functions take a context would allow library users to readily choose whether they want to use the timeout model or logic driven cancellation using well defined and understood patterns from the go standard library.

feature request: let "TXT" can be change dynamically

Description:

According to RFC 6763, TXT is a description of this service that supports features and more detail. The descriptions of the devices have demands for dynamic changes in device status change.
Example:

service, _ := mdns.NewMDNSService(host, "_foobar._tcp", "", "", 8000, nil, info)
// this is expectation
service.UpdateTxt(…)

Look up does not end forever

Hi @armon
This issue is probably my misunderstood, but I ask you for check.

Situation

I use mdns.Lookup:

package main

import (
    "github.com/armon/mdns"
    "fmt"
)

func main() {
    entriesCh := make(chan *mdns.ServiceEntry, 1)

    go func() {
        for entry := range entriesCh {
            fmt.Printf("Got new entry: %v\n", entry)
        }
    }()

    mdns.Lookup("_airplay._tcp", entriesCh)
    close(entriesCh)
}

Then run $ go run main.go, nothing is printed.
But I was able to search using dns-sd command:

$ dns-sd -L "Apple TV" _airplay._tcp
Lookup Apple TV._airplay._tcp.local
DATE: ---Tue 20 May 2014---
21:54:29.174  ...STARTING...
21:54:29.299  Apple TV._airplay._tcp.local. can be reached at AppleTV.local.:7000 (interface 4)
 deviceid=(skip...)

Print debug

I tried to fix client.go based on 8be7e3ac

diff --git a/client.go b/client.go
index d449e4d..cfebe63 100644
--- a/client.go
+++ b/client.go
@@ -186,17 +186,20 @@ func (c *client) query(params *QueryParam) error {
                                case *dns.PTR:
                                        // Create new entry for this
                                        inp = ensureName(inprogress, rr.Ptr)
+                                       fmt.Printf("PTR: %v\n", rr)

                                case *dns.SRV:
                                        // Get the port
                                        inp = ensureName(inprogress, rr.Target)
                                        inp.Port = int(rr.Port)
+                                       fmt.Printf("SRV: %v\n", rr)

                                case *dns.TXT:
                                        // Pull out the txt
                                        inp = ensureName(inprogress, rr.Hdr.Name)
                                        inp.Info = strings.Join(rr.Txt, "|")
                                        inp.hasTXT = true
+                                       fmt.Printf("TXT: %v\n", rr)

                                case *dns.A:
                                        // Pull out the IP
@@ -209,7 +212,7 @@ func (c *client) query(params *QueryParam) error {
                                        inp.Addr = rr.AAAA
                                }
                        }
-
+                       fmt.Printf("    inp = %v\n", inp)
                        // Check if this entry is complete
                        if inp.complete() && !inp.sent {
                                inp.sent = true
@@ -221,10 +224,12 @@ func (c *client) query(params *QueryParam) error {
                                // Fire off a node specific query
                                m := new(dns.Msg)
                                m.SetQuestion(inp.Name, dns.TypeANY)
+                               fmt.Printf("Question: %v\n", m)
                                if err := c.sendQuery(m); err != nil {
                                        log.Printf("[ERR] mdns: Failed to query instance %s: %v", inp.Name, err)
                                }
                        }
+                       fmt.Println("--------------------")
                case <-finish:
                        return nil

Then run:

$ go run main.go
PTR: _airplay._tcp.local.       10      IN      PTR     Apple\194\160TV._airplay._tcp.local.
    inp = &{Apple\194\160TV._airplay._tcp.local. <nil> 0  false false}
Question: ;; opcode: QUERY, status: NOERROR, id: 44739
;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;Apple\194\160TV._airplay._tcp.local.   IN       ANY

--------------------
TXT: Apple\194\160TV._airplay._tcp.local.       10      IN      TXT     "deviceid=58:55:CA:0D:DB:FA" "features=0x4A7FFFF7,0xE" "flags=0x44" "model=AppleTV2,1" "pk=4c58e46591dd61a873659cfc32441ad6e51ead18939b1cc683ec008f36bbba0b" "srcvers=200.54" "vv=2"
SRV: Apple\194\160TV._airplay._tcp.local.       10      IN      SRV     0 0 7000 AppleTV.local.
    inp = &{AppleTV.local. <nil> 7000  false false}
Question: ;; opcode: QUERY, status: NOERROR, id: 30016
;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;AppleTV.local. IN       ANY

--------------------
    inp = &{AppleTV.local. 192.168.0.2 7000  false false}
Question: ;; opcode: QUERY, status: NOERROR, id: 38769
;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;AppleTV.local. IN       ANY

--------------------
    inp = &{AppleTV.local. 192.168.0.2 7000  false false}
Question: ;; opcode: QUERY, status: NOERROR, id: 23884
;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;AppleTV.local. IN       ANY

(repeat until timeout..)

Expected to cause of incomplete:

  1. When get PTR record, create new entry (inp.name = Apple\194\160TV._airplay._tcp.local.)
  2. When get TXT record, inp.hasTxt = true
  3. When get SRV record, create new entry (inp.name = AppleTV.local)
  4. Hereafter, question about AppleTV.local only sent, and never inp.hasTxt becomes true

Supplementary

I was able to reproduce the problem on _daap._tcp

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.