Add peers from mDNS adverts, add separate config option

This commit is contained in:
Neil Alexander 2020-05-09 21:34:15 +01:00
parent 8d00461cf8
commit 7453c1cc06
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
11 changed files with 111 additions and 55 deletions

3
go.mod
View file

@ -9,11 +9,14 @@ require (
github.com/hashicorp/go-syslog v1.0.0
github.com/hjson/hjson-go v3.0.2-0.20200316202735-d5d0e8b0617d+incompatible
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0
github.com/miekg/dns v1.1.27 // indirect
github.com/mitchellh/mapstructure v1.1.2
github.com/neilalexander/mdns v0.3.1-0.20200509190551-a13500818a93
github.com/vishvananda/netlink v1.0.0
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f // indirect
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527
golang.org/x/text v0.3.3-0.20191230102452-929e72ca90de
golang.zx2c4.com/wireguard v0.0.20200320

18
go.sum
View file

@ -25,24 +25,40 @@ github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW1
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/neilalexander/mdns v0.3.1-0.20200509190551-a13500818a93 h1:XjPDiOX2MoRURK2OOa+5DeI6SVK+4WQdwXV3OI2C67Q=
github.com/neilalexander/mdns v0.3.1-0.20200509190551-a13500818a93/go.mod h1:aJ6mgvEacXD+y9JGp8jMaF8wcsTuSvR4YMU6agygcPQ=
github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f h1:nBX3nTcmxEtHSERBJaIo1Qa26VwRaopnZmfDQUXsF4I=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -55,6 +71,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3-0.20191230102452-929e72ca90de h1:aYKJLPSrddB2N7/6OKyFqJ337SXpo61bBuvO5p1+7iY=
golang.org/x/text v0.3.3-0.20191230102452-929e72ca90de/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard v0.0.20200122-0.20200214175355-9cbcff10dd3e/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=
golang.zx2c4.com/wireguard v0.0.20200320 h1:1vE6zVeO7fix9cJX1Z9ZQ+ikPIIx7vIyU0o0tLDD88g=
golang.zx2c4.com/wireguard v0.0.20200320/go.mod h1:lDian4Sw4poJ04SgHh35nzMVwGSYlPumkdnHcucAQoY=

View file

@ -67,6 +67,7 @@ type NodeConfig struct {
Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntcp://0.0.0.0:0 or tcp://[::]:0 to listen on all interfaces."`
AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."`
MulticastInterfaces []string `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."`
MulticastDNSInterfaces []string `comment:"Regular expressions for which interfaces mDNS peer discovery\nshould be enabled on. If none specified, mDNS peer discovery is\ndisabled. The default value is .* which uses all interfaces."`
AllowedEncryptionPublicKeys []string `comment:"List of peer encryption public keys to allow incoming TCP peering\nconnections from. If left empty/undefined then all connections will\nbe allowed by default. This does not affect outgoing peerings, nor\ndoes it affect link-local peers discovered via multicast."`
EncryptionPublicKey string `comment:"Your public encryption key. Your peers may ask you for this to put\ninto their AllowedEncryptionPublicKeys configuration."`
EncryptionPrivateKey string `comment:"Your private encryption key. DO NOT share this with anyone!"`
@ -127,6 +128,7 @@ func GenerateConfig() *NodeConfig {
cfg.InterfacePeers = map[string][]string{}
cfg.AllowedEncryptionPublicKeys = []string{}
cfg.MulticastInterfaces = defaults.GetDefaults().DefaultMulticastInterfaces
cfg.MulticastDNSInterfaces = defaults.GetDefaults().DefaultMulticastDNSInterfaces
cfg.IfName = defaults.GetDefaults().DefaultIfName
cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU
cfg.SessionFirewall.Enable = false

View file

@ -13,7 +13,8 @@ type platformDefaultParameters struct {
DefaultConfigFile string
// Multicast interfaces
DefaultMulticastInterfaces []string
DefaultMulticastInterfaces []string
DefaultMulticastDNSInterfaces []string
// TUN/TAP
MaximumIfMTU types.MTU

View file

@ -17,6 +17,10 @@ func GetDefaults() platformDefaultParameters {
"en.*",
"bridge.*",
},
DefaultMulticastDNSInterfaces: []string{
"en.*",
"bridge.*",
},
// TUN/TAP
MaximumIfMTU: 65535,

View file

@ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters {
DefaultMulticastInterfaces: []string{
".*",
},
DefaultMulticastDNSInterfaces: []string{
".*",
},
// TUN/TAP
MaximumIfMTU: 32767,

View file

@ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters {
DefaultMulticastInterfaces: []string{
".*",
},
DefaultMulticastDNSInterfaces: []string{
".*",
},
// TUN/TAP
MaximumIfMTU: 65535,

View file

@ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters {
DefaultMulticastInterfaces: []string{
".*",
},
DefaultMulticastDNSInterfaces: []string{
".*",
},
// TUN/TAP
MaximumIfMTU: 16384,

View file

@ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters {
DefaultMulticastInterfaces: []string{
".*",
},
DefaultMulticastDNSInterfaces: []string{
".*",
},
// TUN/TAP
MaximumIfMTU: 65535,

View file

@ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters {
DefaultMulticastInterfaces: []string{
".*",
},
DefaultMulticastDNSInterfaces: []string{
".*",
},
// TUN/TAP
MaximumIfMTU: 65535,

View file

@ -1,7 +1,6 @@
package mdns
import (
"context"
"encoding/hex"
"errors"
"fmt"
@ -11,7 +10,7 @@ import (
"github.com/Arceliar/phony"
"github.com/gologme/log"
"github.com/grandcat/zeroconf"
"github.com/neilalexander/mdns"
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
"github.com/yggdrasil-network/yggdrasil-go/src/config"
@ -25,23 +24,22 @@ const (
type MDNS struct {
phony.Inbox
core *yggdrasil.Core //
config *config.NodeState //
log *log.Logger //
info []string //
instance string //
_running bool //
_exprs []*regexp.Regexp //
_servers map[string]map[string]*mDNSServer // intf -> ip -> *mDNSServer
_resolver *zeroconf.Resolver //
_context context.Context // used by _resolver
_cancel context.CancelFunc // used by _resolver
core *yggdrasil.Core //
config *config.NodeState //
log *log.Logger //
info []string //
instance string //
_running bool // is mDNS running?
_exprs []*regexp.Regexp // mDNS interfaces
_servers map[string]map[string]*mDNSServer // intf -> ip -> *mDNSServer
}
type mDNSServer struct {
mdns *MDNS
intf net.Interface
server *zeroconf.Server
server *mdns.Server
listener *yggdrasil.TcpListener
stop chan struct{}
time time.Time
}
@ -62,20 +60,9 @@ func (m *MDNS) Init(core *yggdrasil.Core, state *config.NodeState, log *log.Logg
current := m.config.GetCurrent()
m._updateConfig(&current)
m._context, m._cancel = context.WithCancel(context.Background())
m._servers = make(map[string]map[string]*mDNSServer)
return nil
}
func (m *MDNS) listen(results <-chan *zeroconf.ServiceEntry) {
m.log.Info("Listening for other Yggdrasil nodes via mDNS")
for entry := range results {
log.Info("Received mDNS entry:", entry)
}
m.log.Info("No longer listening for other Yggdrasil nodes")
}
func (m *MDNS) Start() error {
var err error
phony.Block(m, func() {
@ -86,25 +73,13 @@ func (m *MDNS) Start() error {
}
func (m *MDNS) _start() error {
var err error
if m._running {
return errors.New("mDNS module is already running")
}
resolver, err := zeroconf.NewResolver(nil)
if err != nil {
m.log.Fatalln("Failed to initialize resolver:", err.Error())
}
m._resolver = resolver
incoming := make(chan *zeroconf.ServiceEntry)
go m.listen(incoming)
err = m._resolver.Browse(m._context, MDNSService, MDNSDomain, incoming)
if err != nil {
m.log.Fatalln("Failed to browse:", err.Error())
}
m._servers = make(map[string]map[string]*mDNSServer)
m._running = true
m.Act(m, m._updateInterfaces)
return nil
@ -120,7 +95,6 @@ func (m *MDNS) Stop() error {
}
func (m *MDNS) _stop() error {
m._cancel()
for _, intf := range m._servers {
for _, ip := range intf {
ip.server.Shutdown()
@ -148,7 +122,7 @@ func (m *MDNS) _updateConfig(config *config.NodeConfig) error {
// allowed to use.
var exprs []*regexp.Regexp
// Compile each regular expression
for _, exstr := range config.MulticastInterfaces {
for _, exstr := range config.MulticastDNSInterfaces {
e, err := regexp.Compile(exstr)
if err != nil {
return err
@ -230,7 +204,7 @@ func (m *MDNS) _updateInterfaces() {
}
// Work out which interfaces have disappeared.
for n, _ := range m._servers {
for n := range m._servers {
if addrs, ok := interfaces[n]; !ok {
for addr, server := range m._servers[n] {
if err := m._stopInterface(server.intf, addr); err != nil {
@ -277,20 +251,28 @@ func (m *MDNS) _startInterface(intf net.Interface, addr string) error {
return fmt.Errorf("net.ResolveTCPAddr: %w", err)
}
// Register a proxy service. This allows us to specify the hostname and
// IP addresses to put into the DNS SRV record.
server, err := zeroconf.RegisterProxy(
m.instance, // instance name
MDNSService, // service name
MDNSDomain, // service domain
tcpaddr.Port, // TCP listener port
m.instance, // our hostname
[]string{tcpaddr.IP.String()}, // our IP address
m.info, // TXT record contents
[]net.Interface{intf}, // interfaces to use
// Create a zone.
hostname := fmt.Sprintf("%s.%s", m.instance, MDNSDomain)
zone, err := mdns.NewMDNSService(
m.instance, // instance name
MDNSService, // service name
MDNSDomain, // service domain
hostname, // our hostname
tcpaddr.Port, // TCP listener port
[]net.IP{tcpaddr.IP}, // our IP address
m.info, // TXT record contents
)
if err != nil {
return fmt.Errorf("zeroconf.RegisterProxy: %w", err)
return fmt.Errorf("mdns.NewMDNSService: %w", err)
}
// Create a server.
server, err := mdns.NewServer(&mdns.Config{
Zone: zone,
Iface: &intf,
})
if err != nil {
return fmt.Errorf("mdns.NewServer: %w", err)
}
// Now store information about our new listener and server.
@ -298,10 +280,13 @@ func (m *MDNS) _startInterface(intf net.Interface, addr string) error {
m._servers[intf.Name] = make(map[string]*mDNSServer)
}
m._servers[intf.Name][addr] = &mDNSServer{
mdns: m,
intf: intf,
stop: make(chan struct{}),
server: server,
listener: listener,
}
go m._servers[intf.Name][addr].listen()
return nil
}
@ -320,6 +305,7 @@ func (m *MDNS) _stopInterface(intf net.Interface, addr string) error {
}
// Shut down the mDNS server and the TCP listener.
close(server.stop)
server.server.Shutdown()
server.listener.Stop()
@ -331,3 +317,30 @@ func (m *MDNS) _stopInterface(intf net.Interface, addr string) error {
return nil
}
func (s *mDNSServer) listen() {
s.mdns.log.Debugln("Started listening for mDNS on", s.intf.Name)
incoming := make(chan *mdns.ServiceEntry)
go func() {
if err := mdns.Listen(incoming, s.stop, &s.intf); err != nil {
s.mdns.log.Errorln("Failed to initialize resolver:", err.Error())
}
}()
for {
select {
case <-s.stop:
s.mdns.log.Debugln("Stopped listening for mDNS on", s.intf.Name)
break
case entry := <-incoming:
if entry.AddrV6.IP.IsLinkLocalUnicast() && entry.AddrV6.Zone == "" {
continue
}
addr := fmt.Sprintf("tcp://%s:%d", entry.AddrV6.IP, entry.Port)
if err := s.mdns.core.CallPeer(addr, entry.AddrV6.Zone); err != nil {
s.mdns.log.Warn("Failed to add peer from mDNS: ", err)
}
}
}
}