mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-01 01:35:06 +03:00 
			
		
		
		
	Add peers from mDNS adverts, add separate config option
This commit is contained in:
		
							parent
							
								
									8d00461cf8
								
							
						
					
					
						commit
						7453c1cc06
					
				
					 11 changed files with 111 additions and 55 deletions
				
			
		|  | @ -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 | ||||
|  |  | |||
|  | @ -13,7 +13,8 @@ type platformDefaultParameters struct { | |||
| 	DefaultConfigFile string | ||||
| 
 | ||||
| 	// Multicast interfaces | ||||
| 	DefaultMulticastInterfaces []string | ||||
| 	DefaultMulticastInterfaces    []string | ||||
| 	DefaultMulticastDNSInterfaces []string | ||||
| 
 | ||||
| 	// TUN/TAP | ||||
| 	MaximumIfMTU  types.MTU | ||||
|  |  | |||
|  | @ -17,6 +17,10 @@ func GetDefaults() platformDefaultParameters { | |||
| 			"en.*", | ||||
| 			"bridge.*", | ||||
| 		}, | ||||
| 		DefaultMulticastDNSInterfaces: []string{ | ||||
| 			"en.*", | ||||
| 			"bridge.*", | ||||
| 		}, | ||||
| 
 | ||||
| 		// TUN/TAP | ||||
| 		MaximumIfMTU:  65535, | ||||
|  |  | |||
|  | @ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters { | |||
| 		DefaultMulticastInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 		DefaultMulticastDNSInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 
 | ||||
| 		// TUN/TAP | ||||
| 		MaximumIfMTU:  32767, | ||||
|  |  | |||
|  | @ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters { | |||
| 		DefaultMulticastInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 		DefaultMulticastDNSInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 
 | ||||
| 		// TUN/TAP | ||||
| 		MaximumIfMTU:  65535, | ||||
|  |  | |||
|  | @ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters { | |||
| 		DefaultMulticastInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 		DefaultMulticastDNSInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 
 | ||||
| 		// TUN/TAP | ||||
| 		MaximumIfMTU:  16384, | ||||
|  |  | |||
|  | @ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters { | |||
| 		DefaultMulticastInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 		DefaultMulticastDNSInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 
 | ||||
| 		// TUN/TAP | ||||
| 		MaximumIfMTU:  65535, | ||||
|  |  | |||
|  | @ -16,6 +16,9 @@ func GetDefaults() platformDefaultParameters { | |||
| 		DefaultMulticastInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 		DefaultMulticastDNSInterfaces: []string{ | ||||
| 			".*", | ||||
| 		}, | ||||
| 
 | ||||
| 		// TUN/TAP | ||||
| 		MaximumIfMTU:  65535, | ||||
|  |  | |||
							
								
								
									
										121
									
								
								src/mdns/mdns.go
									
										
									
									
									
								
							
							
						
						
									
										121
									
								
								src/mdns/mdns.go
									
										
									
									
									
								
							|  | @ -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(¤t) | ||||
| 
 | ||||
| 	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) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Neil Alexander
						Neil Alexander