Break out multicast into a separate package

This commit is contained in:
Neil Alexander 2019-03-28 16:13:14 +00:00
parent 03bc7bbcd6
commit 7ea4e9575e
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944
10 changed files with 103 additions and 71 deletions

View File

@ -19,6 +19,7 @@ import (
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/yggdrasil-network/yggdrasil-go/src/config" "github.com/yggdrasil-network/yggdrasil-go/src/config"
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
"github.com/yggdrasil-network/yggdrasil-go/src/tuntap" "github.com/yggdrasil-network/yggdrasil-go/src/tuntap"
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
) )
@ -27,8 +28,9 @@ type nodeConfig = config.NodeConfig
type Core = yggdrasil.Core type Core = yggdrasil.Core
type node struct { type node struct {
core Core core Core
tun tuntap.TunAdapter tun tuntap.TunAdapter
multicast multicast.Multicast
} }
func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeConfig { func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeConfig {
@ -254,6 +256,11 @@ func main() {
logger.Errorln("An error occurred during startup") logger.Errorln("An error occurred during startup")
panic(err) panic(err)
} }
// Start the multicast interface
n.multicast.Init(&n.core, cfg, logger)
if err := n.multicast.Start(); err != nil {
logger.Errorln("An error occurred starting multicast:", err)
}
// The Stop function ensures that the TUN/TAP adapter is correctly shut down // The Stop function ensures that the TUN/TAP adapter is correctly shut down
// before the program exits. // before the program exits.
defer func() { defer func() {

View File

@ -1,4 +1,4 @@
package yggdrasil package multicast
import ( import (
"context" "context"
@ -7,23 +7,31 @@ import (
"regexp" "regexp"
"time" "time"
"github.com/gologme/log"
"github.com/yggdrasil-network/yggdrasil-go/src/config"
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
"golang.org/x/net/ipv6" "golang.org/x/net/ipv6"
) )
type multicast struct { type Multicast struct {
core *Core core *yggdrasil.Core
config *config.NodeConfig
log *log.Logger
reconfigure chan chan error reconfigure chan chan error
sock *ipv6.PacketConn sock *ipv6.PacketConn
groupAddr string groupAddr string
listeners map[string]*tcpListener listeners map[string]*yggdrasil.TcpListener
listenPort uint16 listenPort uint16
} }
func (m *multicast) init(core *Core) { func (m *Multicast) Init(core *yggdrasil.Core, config *config.NodeConfig, log *log.Logger) {
m.core = core m.core = core
m.config = config
m.log = log
m.reconfigure = make(chan chan error, 1) m.reconfigure = make(chan chan error, 1)
m.listeners = make(map[string]*tcpListener) m.listeners = make(map[string]*yggdrasil.TcpListener)
current, _ := m.core.config.Get() current := m.config //.Get()
m.listenPort = current.LinkLocalTCPPort m.listenPort = current.LinkLocalTCPPort
go func() { go func() {
for { for {
@ -34,15 +42,15 @@ func (m *multicast) init(core *Core) {
m.groupAddr = "[ff02::114]:9001" m.groupAddr = "[ff02::114]:9001"
// Check if we've been given any expressions // Check if we've been given any expressions
if count := len(m.interfaces()); count != 0 { if count := len(m.interfaces()); count != 0 {
m.core.log.Infoln("Found", count, "multicast interface(s)") m.log.Infoln("Found", count, "multicast interface(s)")
} }
} }
func (m *multicast) start() error { func (m *Multicast) Start() error {
if len(m.interfaces()) == 0 { if len(m.interfaces()) == 0 {
m.core.log.Infoln("Multicast discovery is disabled") m.log.Infoln("Multicast discovery is disabled")
} else { } else {
m.core.log.Infoln("Multicast discovery is enabled") m.log.Infoln("Multicast discovery is enabled")
addr, err := net.ResolveUDPAddr("udp", m.groupAddr) addr, err := net.ResolveUDPAddr("udp", m.groupAddr)
if err != nil { if err != nil {
return err return err
@ -67,9 +75,10 @@ func (m *multicast) start() error {
return nil return nil
} }
func (m *multicast) interfaces() map[string]net.Interface { func (m *Multicast) interfaces() map[string]net.Interface {
// Get interface expressions from config // Get interface expressions from config
current, _ := m.core.config.Get() //current, _ := m.config.Get()
current := m.config
exprs := current.MulticastInterfaces exprs := current.MulticastInterfaces
// Ask the system for network interfaces // Ask the system for network interfaces
interfaces := make(map[string]net.Interface) interfaces := make(map[string]net.Interface)
@ -106,7 +115,7 @@ func (m *multicast) interfaces() map[string]net.Interface {
return interfaces return interfaces
} }
func (m *multicast) announce() { func (m *Multicast) announce() {
groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
if err != nil { if err != nil {
panic(err) panic(err)
@ -122,9 +131,9 @@ func (m *multicast) announce() {
for name, listener := range m.listeners { for name, listener := range m.listeners {
// Prepare our stop function! // Prepare our stop function!
stop := func() { stop := func() {
listener.stop <- true listener.Stop <- true
delete(m.listeners, name) delete(m.listeners, name)
m.core.log.Debugln("No longer multicasting on", name) m.log.Debugln("No longer multicasting on", name)
} }
// If the interface is no longer visible on the system then stop the // If the interface is no longer visible on the system then stop the
// listener, as another one will be started further down // listener, as another one will be started further down
@ -135,7 +144,7 @@ func (m *multicast) announce() {
// It's possible that the link-local listener address has changed so if // It's possible that the link-local listener address has changed so if
// that is the case then we should clean up the interface listener // that is the case then we should clean up the interface listener
found := false found := false
listenaddr, err := net.ResolveTCPAddr("tcp6", listener.listener.Addr().String()) listenaddr, err := net.ResolveTCPAddr("tcp6", listener.Listener.Addr().String())
if err != nil { if err != nil {
stop() stop()
continue continue
@ -184,17 +193,18 @@ func (m *multicast) announce() {
// Join the multicast group // Join the multicast group
m.sock.JoinGroup(&iface, groupAddr) m.sock.JoinGroup(&iface, groupAddr)
// Try and see if we already have a TCP listener for this interface // Try and see if we already have a TCP listener for this interface
var listener *tcpListener var listener *yggdrasil.TcpListener
if l, ok := m.listeners[iface.Name]; !ok || l.listener == nil { if l, ok := m.listeners[iface.Name]; !ok || l.Listener == nil {
// No listener was found - let's create one // No listener was found - let's create one
listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort) listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort)
if li, err := m.core.link.tcp.listen(listenaddr); err == nil { //if li, err := m.core.link.tcp.listen(listenaddr); err == nil {
m.core.log.Debugln("Started multicasting on", iface.Name) if li, err := m.core.ListenTCP(listenaddr); err == nil {
m.log.Debugln("Started multicasting on", iface.Name)
// Store the listener so that we can stop it later if needed // Store the listener so that we can stop it later if needed
m.listeners[iface.Name] = li m.listeners[iface.Name] = li
listener = li listener = li
} else { } else {
m.core.log.Warnln("Not multicasting on", iface.Name, "due to error:", err) m.log.Warnln("Not multicasting on", iface.Name, "due to error:", err)
} }
} else { } else {
// An existing listener was found // An existing listener was found
@ -205,7 +215,7 @@ func (m *multicast) announce() {
continue continue
} }
// Get the listener details and construct the multicast beacon // Get the listener details and construct the multicast beacon
lladdr := listener.listener.Addr().String() lladdr := listener.Listener.Addr().String()
if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil { if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil {
a.Zone = "" a.Zone = ""
destAddr.Zone = iface.Name destAddr.Zone = iface.Name
@ -219,7 +229,7 @@ func (m *multicast) announce() {
} }
} }
func (m *multicast) listen() { func (m *Multicast) listen() {
groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
if err != nil { if err != nil {
panic(err) panic(err)
@ -251,8 +261,9 @@ func (m *multicast) listen() {
continue continue
} }
addr.Zone = "" addr.Zone = ""
if err := m.core.link.call("tcp://"+addr.String(), from.Zone); err != nil { //if err := m.core.link.call("tcp://"+addr.String(), from.Zone); err != nil {
m.core.log.Debugln("Call from multicast failed:", err) if err := m.core.CallPeer("tcp://"+addr.String(), from.Zone); err != nil {
m.log.Debugln("Call from multicast failed:", err)
} }
} }
} }

View File

@ -1,6 +1,6 @@
// +build darwin // +build darwin
package yggdrasil package multicast
/* /*
#cgo CFLAGS: -x objective-c #cgo CFLAGS: -x objective-c
@ -31,11 +31,11 @@ import (
var awdlGoroutineStarted bool var awdlGoroutineStarted bool
func (m *multicast) multicastStarted() { func (m *Multicast) multicastStarted() {
if awdlGoroutineStarted { if awdlGoroutineStarted {
return return
} }
m.core.log.Infoln("Multicast discovery will wake up AWDL if required") m.log.Infoln("Multicast discovery will wake up AWDL if required")
awdlGoroutineStarted = true awdlGoroutineStarted = true
for { for {
C.StopAWDLBrowsing() C.StopAWDLBrowsing()
@ -49,7 +49,7 @@ func (m *multicast) multicastStarted() {
} }
} }
func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error { func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
var control error var control error
var reuseport error var reuseport error
var recvanyif error var recvanyif error

View File

@ -1,13 +1,13 @@
// +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows // +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows
package yggdrasil package multicast
import "syscall" import "syscall"
func (m *multicast) multicastStarted() { func (m *Multicast) multicastStarted() {
} }
func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error { func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
return nil return nil
} }

View File

@ -1,15 +1,15 @@
// +build linux netbsd freebsd openbsd dragonflybsd // +build linux netbsd freebsd openbsd dragonflybsd
package yggdrasil package multicast
import "syscall" import "syscall"
import "golang.org/x/sys/unix" import "golang.org/x/sys/unix"
func (m *multicast) multicastStarted() { func (m *Multicast) multicastStarted() {
} }
func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error { func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
var control error var control error
var reuseport error var reuseport error

View File

@ -1,15 +1,15 @@
// +build windows // +build windows
package yggdrasil package multicast
import "syscall" import "syscall"
import "golang.org/x/sys/windows" import "golang.org/x/sys/windows"
func (m *multicast) multicastStarted() { func (m *Multicast) multicastStarted() {
} }
func (m *multicast) multicastReuse(network string, address string, c syscall.RawConn) error { func (m *Multicast) multicastReuse(network string, address string, c syscall.RawConn) error {
var control error var control error
var reuseaddr error var reuseaddr error

View File

@ -209,13 +209,13 @@ func (a *admin) init(c *Core) {
}, nil }, nil
} }
})*/ })*/
a.addHandler("getMulticastInterfaces", []string{}, func(in admin_info) (admin_info, error) { /*a.addHandler("getMulticastInterfaces", []string{}, func(in admin_info) (admin_info, error) {
var intfs []string var intfs []string
for _, v := range a.core.multicast.interfaces() { for _, v := range a.core.multicast.interfaces() {
intfs = append(intfs, v.Name) intfs = append(intfs, v.Name)
} }
return admin_info{"multicast_interfaces": intfs}, nil return admin_info{"multicast_interfaces": intfs}, nil
}) })*/
a.addHandler("getAllowedEncryptionPublicKeys", []string{}, func(in admin_info) (admin_info, error) { a.addHandler("getAllowedEncryptionPublicKeys", []string{}, func(in admin_info) (admin_info, error) {
return admin_info{"allowed_box_pubs": a.getAllowedEncryptionPublicKeys()}, nil return admin_info{"allowed_box_pubs": a.getAllowedEncryptionPublicKeys()}, nil
}) })

View File

@ -40,9 +40,9 @@ type Core struct {
dht dht dht dht
admin admin admin admin
searches searches searches searches
multicast multicast //multicast multicast
link link link link
log *log.Logger log *log.Logger
} }
func (c *Core) init() error { func (c *Core) init() error {
@ -82,7 +82,7 @@ func (c *Core) init() error {
c.searches.init(c) c.searches.init(c)
c.dht.init(c) c.dht.init(c)
c.sessions.init(c) c.sessions.init(c)
c.multicast.init(c) //c.multicast.init(c)
c.peers.init(c) c.peers.init(c)
c.router.init(c) c.router.init(c)
c.switchTable.init(c) // TODO move before peers? before router? c.switchTable.init(c) // TODO move before peers? before router?
@ -137,7 +137,7 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) {
c.router.cryptokey.reconfigure, c.router.cryptokey.reconfigure,
c.switchTable.reconfigure, c.switchTable.reconfigure,
c.link.reconfigure, c.link.reconfigure,
c.multicast.reconfigure, //c.multicast.reconfigure,
} }
for _, component := range components { for _, component := range components {
@ -228,10 +228,10 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
return err return err
} }
if err := c.multicast.start(); err != nil { /*if err := c.multicast.start(); err != nil {
c.log.Errorln("Failed to start multicast interface") c.log.Errorln("Failed to start multicast interface")
return err return err
} }*/
if err := c.router.tun.Start(c.router.addr, c.router.subnet); err != nil { if err := c.router.tun.Start(c.router.addr, c.router.subnet); err != nil {
c.log.Errorln("Failed to start TUN/TAP") c.log.Errorln("Failed to start TUN/TAP")
@ -251,6 +251,11 @@ func (c *Core) Stop() {
c.admin.close() c.admin.close()
} }
// ListenOn starts a new listener
func (c *Core) ListenTCP(uri string) (*TcpListener, error) {
return c.link.tcp.listen(uri)
}
// Generates a new encryption keypair. The encryption keys are used to // Generates a new encryption keypair. The encryption keys are used to
// encrypt traffic and to derive the IPv6 address/subnet of the node. // encrypt traffic and to derive the IPv6 address/subnet of the node.
func (c *Core) NewEncryptionKeys() (*crypto.BoxPubKey, *crypto.BoxPrivKey) { func (c *Core) NewEncryptionKeys() (*crypto.BoxPubKey, *crypto.BoxPrivKey) {
@ -303,11 +308,20 @@ func (c *Core) SetLogger(log *log.Logger) {
} }
// Adds a peer. This should be specified in the peer URI format, i.e. // Adds a peer. This should be specified in the peer URI format, i.e.
// tcp://a.b.c.d:e, udp://a.b.c.d:e, socks://a.b.c.d:e/f.g.h.i:j // tcp://a.b.c.d:e, udp://a.b.c.d:e, socks://a.b.c.d:e/f.g.h.i:j. This adds the
// peer to the peer list, so that they will be called again if the connection
// drops.
func (c *Core) AddPeer(addr string, sintf string) error { func (c *Core) AddPeer(addr string, sintf string) error {
return c.admin.addPeer(addr, sintf) return c.admin.addPeer(addr, sintf)
} }
// Calls a peer. This should be specified in the peer URI format, i.e.
// tcp://a.b.c.d:e, udp://a.b.c.d:e, socks://a.b.c.d:e/f.g.h.i:j. This calls the
// peer once, and if the connection drops, it won't be called again.
func (c *Core) CallPeer(addr string, sintf string) error {
return c.link.call(addr, sintf)
}
// Adds an allowed public key. This allow peerings to be restricted only to // Adds an allowed public key. This allow peerings to be restricted only to
// keys that you have selected. // keys that you have selected.
func (c *Core) AddAllowedEncryptionPublicKey(boxStr string) error { func (c *Core) AddAllowedEncryptionPublicKey(boxStr string) error {

View File

@ -115,7 +115,7 @@ func (c *Core) GetSigPubKeyString() string {
// dummy adapter in place of real TUN - when this call returns a packet, you // dummy adapter in place of real TUN - when this call returns a packet, you
// will probably want to give it to the OS to write to TUN. // will probably want to give it to the OS to write to TUN.
func (c *Core) RouterRecvPacket() ([]byte, error) { func (c *Core) RouterRecvPacket() ([]byte, error) {
packet := <-c.router.tun.recv packet := <-c.router.tun.Recv
return packet, nil return packet, nil
} }
@ -125,6 +125,6 @@ func (c *Core) RouterRecvPacket() ([]byte, error) {
// Yggdrasil. // Yggdrasil.
func (c *Core) RouterSendPacket(buf []byte) error { func (c *Core) RouterSendPacket(buf []byte) error {
packet := append(util.GetBytes(), buf[:]...) packet := append(util.GetBytes(), buf[:]...)
c.router.tun.send <- packet c.router.tun.Send <- packet
return nil return nil
} }

View File

@ -36,14 +36,14 @@ type tcp struct {
link *link link *link
reconfigure chan chan error reconfigure chan chan error
mutex sync.Mutex // Protecting the below mutex sync.Mutex // Protecting the below
listeners map[string]*tcpListener listeners map[string]*TcpListener
calls map[string]struct{} calls map[string]struct{}
conns map[linkInfo](chan struct{}) conns map[linkInfo](chan struct{})
} }
type tcpListener struct { type TcpListener struct {
listener net.Listener Listener net.Listener
stop chan bool Stop chan bool
} }
// Wrapper function to set additional options for specific connection types. // Wrapper function to set additional options for specific connection types.
@ -64,7 +64,7 @@ func (t *tcp) getAddr() *net.TCPAddr {
t.mutex.Lock() t.mutex.Lock()
defer t.mutex.Unlock() defer t.mutex.Unlock()
for _, l := range t.listeners { for _, l := range t.listeners {
return l.listener.Addr().(*net.TCPAddr) return l.Listener.Addr().(*net.TCPAddr)
} }
return nil return nil
} }
@ -76,7 +76,7 @@ func (t *tcp) init(l *link) error {
t.mutex.Lock() t.mutex.Lock()
t.calls = make(map[string]struct{}) t.calls = make(map[string]struct{})
t.conns = make(map[linkInfo](chan struct{})) t.conns = make(map[linkInfo](chan struct{}))
t.listeners = make(map[string]*tcpListener) t.listeners = make(map[string]*TcpListener)
t.mutex.Unlock() t.mutex.Unlock()
go func() { go func() {
@ -103,7 +103,7 @@ func (t *tcp) init(l *link) error {
t.mutex.Lock() t.mutex.Lock()
if listener, ok := t.listeners[d[6:]]; ok { if listener, ok := t.listeners[d[6:]]; ok {
t.mutex.Unlock() t.mutex.Unlock()
listener.stop <- true listener.Stop <- true
} else { } else {
t.mutex.Unlock() t.mutex.Unlock()
} }
@ -129,7 +129,7 @@ func (t *tcp) init(l *link) error {
return nil return nil
} }
func (t *tcp) listen(listenaddr string) (*tcpListener, error) { func (t *tcp) listen(listenaddr string) (*TcpListener, error) {
var err error var err error
ctx := context.Background() ctx := context.Background()
@ -138,9 +138,9 @@ func (t *tcp) listen(listenaddr string) (*tcpListener, error) {
} }
listener, err := lc.Listen(ctx, "tcp", listenaddr) listener, err := lc.Listen(ctx, "tcp", listenaddr)
if err == nil { if err == nil {
l := tcpListener{ l := TcpListener{
listener: listener, Listener: listener,
stop: make(chan bool), Stop: make(chan bool),
} }
go t.listener(&l, listenaddr) go t.listener(&l, listenaddr)
return &l, nil return &l, nil
@ -150,7 +150,7 @@ func (t *tcp) listen(listenaddr string) (*tcpListener, error) {
} }
// Runs the listener, which spawns off goroutines for incoming connections. // Runs the listener, which spawns off goroutines for incoming connections.
func (t *tcp) listener(l *tcpListener, listenaddr string) { func (t *tcp) listener(l *TcpListener, listenaddr string) {
if l == nil { if l == nil {
return return
} }
@ -158,7 +158,7 @@ func (t *tcp) listener(l *tcpListener, listenaddr string) {
t.mutex.Lock() t.mutex.Lock()
if _, isIn := t.listeners[listenaddr]; isIn { if _, isIn := t.listeners[listenaddr]; isIn {
t.mutex.Unlock() t.mutex.Unlock()
l.listener.Close() l.Listener.Close()
return return
} else { } else {
t.listeners[listenaddr] = l t.listeners[listenaddr] = l
@ -167,20 +167,20 @@ func (t *tcp) listener(l *tcpListener, listenaddr string) {
// And here we go! // And here we go!
accepted := make(chan bool) accepted := make(chan bool)
defer func() { defer func() {
t.link.core.log.Infoln("Stopping TCP listener on:", l.listener.Addr().String()) t.link.core.log.Infoln("Stopping TCP listener on:", l.Listener.Addr().String())
l.listener.Close() l.Listener.Close()
t.mutex.Lock() t.mutex.Lock()
delete(t.listeners, listenaddr) delete(t.listeners, listenaddr)
t.mutex.Unlock() t.mutex.Unlock()
}() }()
t.link.core.log.Infoln("Listening for TCP on:", l.listener.Addr().String()) t.link.core.log.Infoln("Listening for TCP on:", l.Listener.Addr().String())
for { for {
var sock net.Conn var sock net.Conn
var err error var err error
// Listen in a separate goroutine, as that way it does not block us from // Listen in a separate goroutine, as that way it does not block us from
// receiving "stop" events // receiving "stop" events
go func() { go func() {
sock, err = l.listener.Accept() sock, err = l.Listener.Accept()
accepted <- true accepted <- true
}() }()
// Wait for either an accepted connection, or a message telling us to stop // Wait for either an accepted connection, or a message telling us to stop
@ -192,7 +192,7 @@ func (t *tcp) listener(l *tcpListener, listenaddr string) {
return return
} }
go t.handler(sock, true, nil) go t.handler(sock, true, nil)
case <-l.stop: case <-l.Stop:
return return
} }
} }