Giter Site home page Giter Site logo

zeroconf's Introduction

ZeroConf: Service Discovery with mDNS

ZeroConf is a pure Golang library that employs Multicast DNS-SD for

  • browsing and resolving services in your network
  • registering own services

in the local network.

It basically implements aspects of the standards RFC 6762 (mDNS) and RFC 6763 (DNS-SD). Though it does not support all requirements yet, the aim is to provide a compliant solution in the long-term with the community.

By now, it should be compatible to Avahi (tested) and Apple's Bonjour (untested). Target environments: private LAN/Wifi, small or isolated networks.

GoDoc Go Report Card Tests

Install

Nothing is as easy as that:

$ go get -u github.com/libp2p/zeroconf/v2

Browse for services in your local network

entries := make(chan *zeroconf.ServiceEntry)
go func(results <-chan *zeroconf.ServiceEntry) {
    for entry := range results {
        log.Println(entry)
    }
    log.Println("No more entries.")
}(entries)

ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
defer cancel()
// Discover all services on the network (e.g. _workstation._tcp)
err = zeroconf.Browse(ctx, "_workstation._tcp", "local.", entries)
if err != nil {
    log.Fatalln("Failed to browse:", err.Error())
}

<-ctx.Done()

A subtype may added to service name to narrow the set of results. E.g. to browse _workstation._tcp with subtype _windows, use_workstation._tcp,_windows.

See https://github.com/libp2p/zeroconf/blob/master/examples/resolv/client.go.

Lookup a specific service instance

// Example filled soon.

Register a service

server, err := zeroconf.Register("GoZeroconf", "_workstation._tcp", "local.", 42424, []string{"txtv=0", "lo=1", "la=2"}, nil)
if err != nil {
    panic(err)
}
defer server.Shutdown()

// Clean exit.
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
select {
case <-sig:
    // Exit by user
case <-time.After(time.Second * 120):
    // Exit by timeout
}

log.Println("Shutting down.")

Multiple subtypes may be added to service name, separated by commas. E.g _workstation._tcp,_windows has subtype _windows.

See https://github.com/libp2p/zeroconf/blob/master/examples/register/server.go.

Features and ToDo's

This list gives a quick impression about the state of this library. See what needs to be done and submit a pull request :)

  • Browse / Lookup / Register services
  • Multiple IPv6 / IPv4 addresses support
  • Send multiple probes (exp. back-off) if no service answers (*)
  • Timestamp entries for TTL checks
  • Compare new multicasts with already received services

Notes:

(*) The denoted features might not be perfectly standards compliant, but shouldn't cause any problems. Some tests showed improvements in overall robustness and performance with the features enabled.

Credits

Great thanks to hashicorp and to oleksandr and all contributing authors for the code this projects bases upon. Large parts of the code are still the same.

However, there are several reasons why I decided to create a fork of the original project: The previous project seems to be unmaintained. There are several useful pull requests waiting. I merged most of them in this project. Still, the implementation has some bugs and lacks some other features that make it quite unreliable in real LAN environments when running continously. Last but not least, the aim for this project is to build a solution that targets standard conformance in the long term with the support of the community. Though, resiliency should remain a top goal.

zeroconf's People

Contributors

a13xb avatar alice-samsara avatar betamos avatar brijohn avatar brutella avatar cpuchip avatar derandereandi avatar ernoaapa avatar farshidtz avatar fuhrmannb avatar grandcat avatar jspiro avatar lanrat avatar leslie-wang avatar libp2p-mgmt-read-write[bot] avatar marten-seemann avatar nasuku avatar neilalexander avatar norbell avatar project0 avatar rdleon avatar stebalien avatar tfheen avatar themihai avatar tmm1 avatar web-flow avatar web3-bot avatar willstott101 avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar

zeroconf's Issues

在不同的机器上执行zeroconf的Browse方法有时可以获得dns信息有时不行

经过debug我发现是在https://github.com/libp2p/zeroconf的Browse方法中无法获取到dns信息,一直debug到这一层
package zeroconf 中 client.go的169-175行代码

msgCh := make(chan *dns.Msg, 32)
if c.ipv4conn != nil {
   go c.recv(ctx, c.ipv4conn, msgCh)
}
if c.ipv6conn != nil {
   go c.recv(ctx, c.ipv6conn, msgCh)
}

msgCh中没有信息返回,请问是什么问题吗?配置信息都检查过没有出错

Add panic handlers

Zeroconf is parsing and acting on incoming network packets from potentially untrusted sources. We should catch panics where possible and turn them into errors.

v3 considerations

Just a brain dump of a couple of things that could be worth looking into before churning out a next version:

  • If breaking changes are ok, the API could be more Go-idiomatic:
    • Accept a context in all long-running functions. Currently, the server has to be manually shut down.
    • Config options could perhaps be structs instead of currently function-that-modifies-private-struct.
  • There's a serious Windows bug in some mdns implementations in Go preventing sending/broadcasting properly. I'm not positive this project is affected but I've been meaning to look into it. It'd be a nice upgrade incentive if so.

If any of these are worthy to pursue, we can break into separate issues. Happy to contribute.

Browse and Register do not work past localhost on Windows 10/11

After reading a lot between grandcat's and libp2p's implementation of zeroconf being able to browse zeroconf based services on the local network is completely unreliable on windows, probably due to implementations not being flushed out completely on the windows Golang network stack.

referencing this closed issue: #24

I wanted to open a ticket here and then later submit a PR that may work well in fixing some of the dire issues with windows, without breaking the other OSes.

I'm going to be referencing davidflowerday work here grandcat#81

I've had great success implementing his SetMulticastInterface calls on client.go and server.go but another user in mentioned here grandcat#69
that replacing UDP connection function net.ListenUDP() to net.ListenMulticastUDP() with a specific interface works, I wanted to try that approach too before putting together a PR.

TestBasic hangs

$ go test -timeout=5s ./...
2021/12/20 13:07:22 Published service: test--xxxxxxxxxxxx, type: _test--xxxx._tcp, domain: local.
panic: test timed out after 5s

goroutine 26 [running]:
testing.(*M).startAlarm.func1()
	/usr/lib/go/src/testing/testing.go:1788 +0x8e
created by time.goFunc
	/usr/lib/go/src/time/sleep.go:180 +0x31

goroutine 1 [chan receive]:
testing.(*T).Run(0xc00008ba00, {0x5bd70d, 0x469d53}, 0x5c99d0)
	/usr/lib/go/src/testing/testing.go:1307 +0x375
testing.runTests.func1(0xc00008ba00)
	/usr/lib/go/src/testing/testing.go:1598 +0x6e
testing.tRunner(0xc00008ba00, 0xc0000b7d18)
	/usr/lib/go/src/testing/testing.go:1259 +0x102
testing.runTests(0xc000108000, {0x706960, 0x4, 0x4}, {0x4798cd, 0x5bee77, 0x70b480})
	/usr/lib/go/src/testing/testing.go:1596 +0x43f
testing.(*M).Run(0xc000108000)
	/usr/lib/go/src/testing/testing.go:1504 +0x51d
main.main()
	_testmain.go:49 +0x14b

goroutine 5 [select]:
github.com/libp2p/zeroconf/v2.(*client).periodicQuery(0x5f7868, {0x5f77f8, 0xc000013e00}, 0xc0001a03c0)
	/home/mvdan/git/zeroconf/client.go:380 +0x193
github.com/libp2p/zeroconf/v2.(*client).run(0xc0001911a0, {0x5f7868, 0xc00007c060}, 0xc0001a03c0)
	/home/mvdan/git/zeroconf/client.go:121 +0x10d
github.com/libp2p/zeroconf/v2.Browse({0x5f7868, 0xc00007c060}, {0x5bf3da, 0x10}, {0x5bcc96, 0x6}, 0xc00007c120, {0x0, 0x0, 0x0})
	/home/mvdan/git/zeroconf/client.go:78 +0x132
github.com/libp2p/zeroconf/v2.TestBasic(0xc0000016c0)
	/home/mvdan/git/zeroconf/service_test.go:55 +0x117
testing.tRunner(0xc0000016c0, 0x5c99d0)
	/usr/lib/go/src/testing/testing.go:1259 +0x102
created by testing.(*T).Run
	/usr/lib/go/src/testing/testing.go:1306 +0x35a

goroutine 7 [IO wait]:
internal/poll.runtime_pollWait(0x7f75269f8040, 0x72)
	/usr/lib/go/src/runtime/netpoll.go:234 +0x89
internal/poll.(*pollDesc).wait(0xc000022880, 0x1, 0x0)
	/usr/lib/go/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	/usr/lib/go/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).RawRead(0xc000022880, 0xc0001520c0)
	/usr/lib/go/src/internal/poll/fd_unix.go:554 +0x145
net.(*rawConn).Read(0xc000010030, 0x28)
	/usr/lib/go/src/net/rawconn.go:43 +0x45
golang.org/x/net/internal/socket.(*Conn).recvMsg(0xc0000702a0, 0xc000316ee8, 0x0)
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/internal/socket/rawconn_msg.go:33 +0x202
golang.org/x/net/internal/socket.(*Conn).RecvMsg(...)
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/internal/socket/socket.go:247
golang.org/x/net/ipv6.(*payloadHandler).ReadFrom(0xc00007e5b0, {0xc000300000, 0x10000, 0x10000})
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/ipv6/payload_cmsg.go:32 +0x1fc
github.com/libp2p/zeroconf/v2.(*Server).recv6(0xc00007c0c0, 0xc00007e5a0)
	/home/mvdan/git/zeroconf/server.go:270 +0xc7
created by github.com/libp2p/zeroconf/v2.(*Server).start
	/home/mvdan/git/zeroconf/server.go:189 +0x125

goroutine 6 [IO wait]:
internal/poll.runtime_pollWait(0x7f75269f7f58, 0x72)
	/usr/lib/go/src/runtime/netpoll.go:234 +0x89
internal/poll.(*pollDesc).wait(0xc000022800, 0x1, 0x0)
	/usr/lib/go/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	/usr/lib/go/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).RawRead(0xc000022800, 0xc000191740)
	/usr/lib/go/src/internal/poll/fd_unix.go:554 +0x145
net.(*rawConn).Read(0xc000010020, 0x20)
	/usr/lib/go/src/net/rawconn.go:43 +0x45
golang.org/x/net/internal/socket.(*Conn).recvMsg(0xc000070280, 0xc00005eee8, 0x0)
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/internal/socket/rawconn_msg.go:33 +0x202
golang.org/x/net/internal/socket.(*Conn).RecvMsg(...)
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/internal/socket/socket.go:247
golang.org/x/net/ipv4.(*payloadHandler).ReadFrom(0xc00007e560, {0xc00012e000, 0x10000, 0x10000})
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/ipv4/payload_cmsg.go:32 +0x1ce
github.com/libp2p/zeroconf/v2.(*Server).recv4(0xc00007c0c0, 0xc00007e550)
	/home/mvdan/git/zeroconf/server.go:245 +0xc7
created by github.com/libp2p/zeroconf/v2.(*Server).start
	/home/mvdan/git/zeroconf/server.go:185 +0x9d

goroutine 9 [select]:
github.com/libp2p/zeroconf/v2.(*client).mainloop(0xc0001911a0, {0x5f77f8, 0xc000013e00}, 0xc0001a03c0)
	/home/mvdan/git/zeroconf/client.go:185 +0x3c5
github.com/libp2p/zeroconf/v2.(*client).run.func1()
	/home/mvdan/git/zeroconf/client.go:116 +0x68
created by github.com/libp2p/zeroconf/v2.(*client).run
	/home/mvdan/git/zeroconf/client.go:114 +0xf4

goroutine 24 [IO wait]:
internal/poll.runtime_pollWait(0x7f75269f7e70, 0x72)
	/usr/lib/go/src/runtime/netpoll.go:234 +0x89
internal/poll.(*pollDesc).wait(0xc000022e00, 0xc00032a420, 0x0)
	/usr/lib/go/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	/usr/lib/go/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).RawRead(0xc000022e00, 0xc000324510)
	/usr/lib/go/src/internal/poll/fd_unix.go:554 +0x145
net.(*rawConn).Read(0xc000010048, 0x20)
	/usr/lib/go/src/net/rawconn.go:43 +0x45
golang.org/x/net/internal/socket.(*Conn).recvMsg(0xc000070c60, 0xc00005fe50, 0x0)
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/internal/socket/rawconn_msg.go:33 +0x202
golang.org/x/net/internal/socket.(*Conn).RecvMsg(...)
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/internal/socket/socket.go:247
golang.org/x/net/ipv4.(*payloadHandler).ReadFrom(0xc00007e740, {0xc0001ca000, 0x10000, 0x10000})
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/ipv4/payload_cmsg.go:32 +0x1ce
github.com/libp2p/zeroconf/v2.(*client).recv.func2({0xc0001ca000, 0xc00005ff28, 0xcf})
	/home/mvdan/git/zeroconf/client.go:326 +0x34
github.com/libp2p/zeroconf/v2.(*client).recv(0xc000013e00, {0x5f77f8, 0xc000013e00}, {0x5b7500, 0xc00007e730}, 0xc0000ac5a0)
	/home/mvdan/git/zeroconf/client.go:345 +0x151
created by github.com/libp2p/zeroconf/v2.(*client).mainloop
	/home/mvdan/git/zeroconf/client.go:171 +0x154

goroutine 25 [IO wait]:
internal/poll.runtime_pollWait(0x7f75269f7d88, 0x72)
	/usr/lib/go/src/runtime/netpoll.go:234 +0x89
internal/poll.(*pollDesc).wait(0xc000022e80, 0xc0002a32c0, 0x0)
	/usr/lib/go/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
	/usr/lib/go/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).RawRead(0xc000022e80, 0xc0002a86f0)
	/usr/lib/go/src/internal/poll/fd_unix.go:554 +0x145
net.(*rawConn).Read(0xc000010058, 0x28)
	/usr/lib/go/src/net/rawconn.go:43 +0x45
golang.org/x/net/internal/socket.(*Conn).recvMsg(0xc000070c80, 0xc000312e50, 0x0)
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/internal/socket/rawconn_msg.go:33 +0x202
golang.org/x/net/internal/socket.(*Conn).RecvMsg(...)
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/internal/socket/socket.go:247
golang.org/x/net/ipv6.(*payloadHandler).ReadFrom(0xc00007e790, {0xc000140000, 0x10000, 0x10000})
	/home/mvdan/go/pkg/mod/golang.org/x/[email protected]/ipv6/payload_cmsg.go:32 +0x1fc
github.com/libp2p/zeroconf/v2.(*client).recv.func1({0xc000140000, 0xc000312f28, 0xcf})
	/home/mvdan/git/zeroconf/client.go:321 +0x34
github.com/libp2p/zeroconf/v2.(*client).recv(0x0, {0x5f77f8, 0xc000013e00}, {0x5b8000, 0xc00007e780}, 0xc0000ac5a0)
	/home/mvdan/git/zeroconf/client.go:345 +0x151
created by github.com/libp2p/zeroconf/v2.(*client).mainloop
	/home/mvdan/git/zeroconf/client.go:174 +0x245
FAIL	github.com/libp2p/zeroconf/v2	5.008s
?   	github.com/libp2p/zeroconf/v2/examples/proxyservice	[no test files]
?   	github.com/libp2p/zeroconf/v2/examples/register	[no test files]
?   	github.com/libp2p/zeroconf/v2/examples/resolv	[no test files]
FAIL

I initially thought this was due to my network, but I killed wifi and ensured ip route was empty, and it still hung.

Found while trying to debug #20 (comment).

flaky test

  === RUN   TestSubtype/browse_without_subtype
  2021/08/11 20:05:48 Published service: test--xxxxxxxxxxxx, type: _test--xxxx._tcp,_fancy, domain: local.
  2021/08/11 20:05:53 Shutting down.
      service_test.go:150: Expected number of service entries is 1, but got 2
  --- FAIL: TestSubtype (10.01s)
      --- PASS: TestSubtype/browse_with_subtype (5.01s)
      --- FAIL: TestSubtype/browse_without_subtype (5.00s)

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.