From b0bcf29d27f2464cc7d4a16848ac4cc0ab713aa0 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 23 Oct 2019 11:15:57 +0100 Subject: [PATCH 01/12] Allow ExecStartPre to fail for containers (#573) --- contrib/systemd/yggdrasil.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index 0223dd90..b48ff78b 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -9,7 +9,7 @@ ProtectHome=true ProtectSystem=true SyslogIdentifier=yggdrasil CapabilityBoundSet=CAP_NET_ADMIN -ExecStartPre=+/sbin/modprobe tun +ExecStartPre=+-/sbin/modprobe tun ExecStartPre=/bin/sh -ec "if ! test -s /etc/yggdrasil.conf; \ then umask 077; \ yggdrasil -genconf > /etc/yggdrasil.conf; \ From f6c7c1b8db69b08f17d55310cb2ef967c9da297c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 23 Oct 2019 11:24:00 +0100 Subject: [PATCH 02/12] Produce armel build (closes #577) --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1456332a..5a9e1e31 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -48,6 +48,7 @@ jobs: PKGARCH=mipsel sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-mipsel && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-mipsel; PKGARCH=mips sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-mips && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-mips; PKGARCH=armhf sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-armhf && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-armhf; + PKGARCH=armel sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-armel && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-armel; PKGARCH=arm64 sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-arm64 && mv yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-yggdrasilctl-linux-arm64; mv *.deb /tmp/upload/ From 6a22e6c9de3f2046c65aaea88587d2493933da5f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 23 Oct 2019 17:26:35 +0100 Subject: [PATCH 03/12] Initial connection upgrade/TLS peering support --- src/yggdrasil/api.go | 9 ++++- src/yggdrasil/link.go | 11 ++++-- src/yggdrasil/tcp.go | 82 +++++++++++++++++++++++++++----------- src/yggdrasil/tls.go | 92 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 27 deletions(-) create mode 100644 src/yggdrasil/tls.go diff --git a/src/yggdrasil/api.go b/src/yggdrasil/api.go index 4245f439..80f669b6 100644 --- a/src/yggdrasil/api.go +++ b/src/yggdrasil/api.go @@ -280,7 +280,14 @@ func (c *Core) ConnDialer() (*Dialer, error) { // "Listen" configuration item, e.g. // tcp://a.b.c.d:e func (c *Core) ListenTCP(uri string) (*TcpListener, error) { - return c.link.tcp.listen(uri) + return c.link.tcp.listen(uri, nil) +} + +// ListenTLS starts a new TLS listener. The input URI should match that of the +// "Listen" configuration item, e.g. +// tls://a.b.c.d:e +func (c *Core) ListenTLS(uri string) (*TcpListener, error) { + return c.link.tcp.listen(uri, c.link.tcp.tls.forListener) } // NodeID gets the node ID. This is derived from your router encryption keys. diff --git a/src/yggdrasil/link.go b/src/yggdrasil/link.go index 98c080c7..1710e202 100644 --- a/src/yggdrasil/link.go +++ b/src/yggdrasil/link.go @@ -93,9 +93,11 @@ func (l *link) call(uri string, sintf string) error { pathtokens := strings.Split(strings.Trim(u.Path, "/"), "/") switch u.Scheme { case "tcp": - l.tcp.call(u.Host, nil, sintf) + l.tcp.call(u.Host, nil, sintf, nil) case "socks": - l.tcp.call(pathtokens[0], u.Host, sintf) + l.tcp.call(pathtokens[0], u.Host, sintf, nil) + case "tls": + l.tcp.call(u.Host, nil, sintf, l.tcp.tls.forDialer) default: return errors.New("unknown call scheme: " + u.Scheme) } @@ -109,7 +111,10 @@ func (l *link) listen(uri string) error { } switch u.Scheme { case "tcp": - _, err := l.tcp.listen(u.Host) + _, err := l.tcp.listen(u.Host, nil) + return err + case "tls": + _, err := l.tcp.listen(u.Host, l.tcp.tls.forListener) return err default: return errors.New("unknown listen scheme: " + u.Scheme) diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index 66f708c2..c4569591 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -39,6 +39,7 @@ type tcp struct { listeners map[string]*TcpListener calls map[string]struct{} conns map[linkInfo](chan struct{}) + tls tcptls } // TcpListener is a stoppable TCP listener interface. These are typically @@ -47,9 +48,15 @@ type tcp struct { // multicast interfaces. type TcpListener struct { Listener net.Listener + upgrade *TcpUpgrade stop chan struct{} } +type TcpUpgrade struct { + upgrade func(c net.Conn) (net.Conn, error) + name string +} + func (l *TcpListener) Stop() { defer func() { recover() }() close(l.stop) @@ -81,6 +88,7 @@ func (t *tcp) getAddr() *net.TCPAddr { // Initializes the struct. func (t *tcp) init(l *link) error { t.link = l + t.tls.init(t) t.mutex.Lock() t.calls = make(map[string]struct{}) t.conns = make(map[linkInfo](chan struct{})) @@ -90,12 +98,17 @@ func (t *tcp) init(l *link) error { t.link.core.config.Mutex.RLock() defer t.link.core.config.Mutex.RUnlock() for _, listenaddr := range t.link.core.config.Current.Listen { - if listenaddr[:6] != "tcp://" { + switch listenaddr[:6] { + case "tcp://": + if _, err := t.listen(listenaddr[6:], nil); err != nil { + return err + } + case "tls://": + if _, err := t.listen(listenaddr[6:], t.tls.forListener); err != nil { + return err + } + default: t.link.core.log.Errorln("Failed to add listener: listener", listenaddr, "is not correctly formatted, ignoring") - continue - } - if _, err := t.listen(listenaddr[6:]); err != nil { - return err } } @@ -119,18 +132,21 @@ func (t *tcp) reconfigure() { t.link.core.config.Mutex.RUnlock() if len(added) > 0 || len(deleted) > 0 { for _, a := range added { - if a[:6] != "tcp://" { + switch a[:6] { + case "tcp://": + if _, err := t.listen(a[6:], nil); err != nil { + t.link.core.log.Errorln("Error adding TCP", a[6:], "listener:", err) + } + case "tls://": + if _, err := t.listen(a[6:], t.tls.forListener); err != nil { + t.link.core.log.Errorln("Error adding TLS", a[6:], "listener:", err) + } + default: t.link.core.log.Errorln("Failed to add listener: listener", a, "is not correctly formatted, ignoring") - continue - } - if _, err := t.listen(a[6:]); err != nil { - t.link.core.log.Errorln("Error adding TCP", a[6:], "listener:", err) - } else { - t.link.core.log.Infoln("Started TCP listener:", a[6:]) } } for _, d := range deleted { - if d[:6] != "tcp://" { + if d[:6] != "tcp://" && d[:6] != "tls://" { t.link.core.log.Errorln("Failed to delete listener: listener", d, "is not correctly formatted, ignoring") continue } @@ -146,7 +162,7 @@ func (t *tcp) reconfigure() { } } -func (t *tcp) listen(listenaddr string) (*TcpListener, error) { +func (t *tcp) listen(listenaddr string, upgrade *TcpUpgrade) (*TcpListener, error) { var err error ctx := context.Background() @@ -157,6 +173,7 @@ func (t *tcp) listen(listenaddr string) (*TcpListener, error) { if err == nil { l := TcpListener{ Listener: listener, + upgrade: upgrade, stop: make(chan struct{}), } t.waitgroup.Add(1) @@ -204,7 +221,7 @@ func (t *tcp) listener(l *TcpListener, listenaddr string) { return } t.waitgroup.Add(1) - go t.handler(sock, true, nil) + go t.handler(sock, true, nil, l.upgrade) } } @@ -222,11 +239,15 @@ func (t *tcp) startCalling(saddr string) bool { // If the dial is successful, it launches the handler. // When finished, it removes the outgoing call, so reconnection attempts can be made later. // This all happens in a separate goroutine that it spawns. -func (t *tcp) call(saddr string, options interface{}, sintf string) { +func (t *tcp) call(saddr string, options interface{}, sintf string, upgrade *TcpUpgrade) { go func() { callname := saddr + callproto := "TCP" + if upgrade != nil { + callproto = strings.ToUpper(upgrade.name) + } if sintf != "" { - callname = fmt.Sprintf("%s/%s", saddr, sintf) + callname = fmt.Sprintf("%s/%s/%s", callproto, saddr, sintf) } if !t.startCalling(callname) { return @@ -261,7 +282,7 @@ func (t *tcp) call(saddr string, options interface{}, sintf string) { return } t.waitgroup.Add(1) - t.handler(conn, false, saddr) + t.handler(conn, false, saddr, nil) } else { dst, err := net.ResolveTCPAddr("tcp", saddr) if err != nil { @@ -322,18 +343,28 @@ func (t *tcp) call(saddr string, options interface{}, sintf string) { } conn, err = dialer.Dial("tcp", dst.String()) if err != nil { - t.link.core.log.Debugln("Failed to dial TCP:", err) + t.link.core.log.Debugf("Failed to dial %s: %s", callproto, err) return } t.waitgroup.Add(1) - t.handler(conn, false, nil) + t.handler(conn, false, nil, upgrade) } }() } -func (t *tcp) handler(sock net.Conn, incoming bool, options interface{}) { +func (t *tcp) handler(sock net.Conn, incoming bool, options interface{}, upgrade *TcpUpgrade) { defer t.waitgroup.Done() // Happens after sock.close defer sock.Close() + var upgraded bool + if upgrade != nil { + var err error + if sock, err = upgrade.upgrade(sock); err != nil { + t.link.core.log.Errorln("TCP handler upgrade failed:", err) + return + } else { + upgraded = true + } + } t.setExtraOptions(sock) stream := stream{} stream.init(sock) @@ -344,8 +375,13 @@ func (t *tcp) handler(sock net.Conn, incoming bool, options interface{}) { local, _, _ = net.SplitHostPort(sock.LocalAddr().String()) remote, _, _ = net.SplitHostPort(socksaddr) } else { - name = "tcp://" + sock.RemoteAddr().String() - proto = "tcp" + if upgraded { + proto = upgrade.name + name = proto + "://" + sock.RemoteAddr().String() + } else { + proto = "tcp" + name = proto + "://" + sock.RemoteAddr().String() + } local, _, _ = net.SplitHostPort(sock.LocalAddr().String()) remote, _, _ = net.SplitHostPort(sock.RemoteAddr().String()) } diff --git a/src/yggdrasil/tls.go b/src/yggdrasil/tls.go new file mode 100644 index 00000000..78fe3a9d --- /dev/null +++ b/src/yggdrasil/tls.go @@ -0,0 +1,92 @@ +package yggdrasil + +import ( + "bytes" + "crypto/ed25519" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/hex" + "encoding/pem" + "log" + "math/big" + "net" + "time" +) + +type tcptls struct { + tcp *tcp + config *tls.Config + forDialer *TcpUpgrade + forListener *TcpUpgrade +} + +func (t *tcptls) init(tcp *tcp) { + t.tcp = tcp + t.forDialer = &TcpUpgrade{ + upgrade: t.upgradeDialer, + name: "tls", + } + t.forListener = &TcpUpgrade{ + upgrade: t.upgradeListener, + name: "tls", + } + + edpriv := make(ed25519.PrivateKey, ed25519.PrivateKeySize) + copy(edpriv[:], tcp.link.core.sigPriv[:]) + + certBuf := &bytes.Buffer{} + + pubtemp := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: hex.EncodeToString(tcp.link.core.sigPub[:]), + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * 365), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + derbytes, err := x509.CreateCertificate(rand.Reader, &pubtemp, &pubtemp, edpriv.Public(), edpriv) + if err != nil { + log.Fatalf("Failed to create certificate: %s", err) + } + + if err := pem.Encode(certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: derbytes}); err != nil { + panic("failed to encode certificate into PEM") + } + + cpool := x509.NewCertPool() + cpool.AppendCertsFromPEM(derbytes) + + t.config = &tls.Config{ + RootCAs: cpool, + Certificates: []tls.Certificate{ + tls.Certificate{ + Certificate: [][]byte{derbytes}, + PrivateKey: edpriv, + }, + }, + InsecureSkipVerify: true, + MinVersion: tls.VersionTLS13, + } +} + +func (t *tcptls) upgradeListener(c net.Conn) (net.Conn, error) { + conn := tls.Server(c, t.config) + if err := conn.Handshake(); err != nil { + return c, err + } + return conn, nil +} + +func (t *tcptls) upgradeDialer(c net.Conn) (net.Conn, error) { + conn := tls.Client(c, t.config) + if err := conn.Handshake(); err != nil { + return c, err + } + return conn, nil +} From cd77727c1e63a21d3acfacad6a22edb680d4123b Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 23 Oct 2019 18:24:08 +0100 Subject: [PATCH 04/12] Set TCP socket options before upgrading connection --- src/yggdrasil/tcp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index c4569591..7d5b80b2 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -355,6 +355,7 @@ func (t *tcp) call(saddr string, options interface{}, sintf string, upgrade *Tcp func (t *tcp) handler(sock net.Conn, incoming bool, options interface{}, upgrade *TcpUpgrade) { defer t.waitgroup.Done() // Happens after sock.close defer sock.Close() + t.setExtraOptions(sock) var upgraded bool if upgrade != nil { var err error @@ -365,7 +366,6 @@ func (t *tcp) handler(sock net.Conn, incoming bool, options interface{}, upgrade upgraded = true } } - t.setExtraOptions(sock) stream := stream{} stream.init(sock) var name, proto, local, remote string From 996c6b4f474bba3e80ba0b9c3c737a7a4909cdd8 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Wed, 23 Oct 2019 20:28:11 -0500 Subject: [PATCH 05/12] add one TODO comment and run gofmt --- src/yggdrasil/tls.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/tls.go b/src/yggdrasil/tls.go index 78fe3a9d..7212c4df 100644 --- a/src/yggdrasil/tls.go +++ b/src/yggdrasil/tls.go @@ -38,6 +38,7 @@ func (t *tcptls) init(tcp *tcp) { certBuf := &bytes.Buffer{} + // TODO: because NotAfter is finite, we should add some mechanism to regenerate the certificate and restart the listeners periodically for nodes with very high uptimes. Perhaps regenerate certs and restart listeners every few months or so. pubtemp := x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ @@ -65,7 +66,7 @@ func (t *tcptls) init(tcp *tcp) { t.config = &tls.Config{ RootCAs: cpool, Certificates: []tls.Certificate{ - tls.Certificate{ + { Certificate: [][]byte{derbytes}, PrivateKey: edpriv, }, From c3dee478f5b6e45827ed46614a0386921eba85b3 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Wed, 23 Oct 2019 20:38:09 -0500 Subject: [PATCH 06/12] fix ed25519 dependency for golang 1.12 and earlier, though we may want to update builds to 1.13 anyway... --- src/yggdrasil/tls.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/tls.go b/src/yggdrasil/tls.go index 7212c4df..26ecf1d7 100644 --- a/src/yggdrasil/tls.go +++ b/src/yggdrasil/tls.go @@ -2,7 +2,6 @@ package yggdrasil import ( "bytes" - "crypto/ed25519" "crypto/rand" "crypto/tls" "crypto/x509" @@ -13,6 +12,8 @@ import ( "math/big" "net" "time" + + "golang.org/x/crypto/ed25519" ) type tcptls struct { From f784f33c2d2670cb73bc5c1fcbf1e2c01901cc94 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 24 Oct 2019 09:25:31 +0100 Subject: [PATCH 07/12] Backport fix for #581 from #583 --- src/multicast/multicast.go | 47 +++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 7044eaa2..ed8efafd 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -55,6 +55,21 @@ func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log // listen for multicast beacons from other hosts and will advertise multicast // beacons out to the network. func (m *Multicast) Start() error { + var err error + phony.Block(m, func() { + err = m._start() + }) + return err +} + +func (m *Multicast) _start() error { + if m.isOpen { + return fmt.Errorf("multicast module is already started") + } + if len(m.config.GetCurrent().MulticastInterfaces) == 0 { + return fmt.Errorf("no MulticastInterfaces configured") + } + m.log.Infoln("Starting multicast module") addr, err := net.ResolveUDPAddr("udp", m.groupAddr) if err != nil { return err @@ -80,8 +95,22 @@ func (m *Multicast) Start() error { return nil } -// Stop is not implemented for multicast yet. -func (m *Multicast) Stop() error { +// IsStarted returns true if the module has been started. +func (m *Multicast) IsStarted() bool { + var isOpen bool + phony.Block(m, func() { + isOpen = m.isOpen + }) + return isOpen +} + +// Stop stops the multicast module. +func (m *Multicast) Stop() { + m.Act(m, m._stop) +} + +func (m *Multicast) _stop() { + m.log.Infoln("Stopping multicast module") m.isOpen = false if m.announcer != nil { m.announcer.Stop() @@ -90,15 +119,27 @@ func (m *Multicast) Stop() error { m.platformhandler.Stop() } m.sock.Close() - return nil } // UpdateConfig updates the multicast module with the provided config.NodeConfig // and then signals the various module goroutines to reconfigure themselves if // needed. func (m *Multicast) UpdateConfig(config *config.NodeConfig) { + m.Act(m, func() { m._updateConfig(config) }) +} + +func (m *Multicast) _updateConfig(config *config.NodeConfig) { m.log.Debugln("Reloading multicast configuration...") + if m.IsStarted() { + if len(config.MulticastInterfaces) == 0 || config.LinkLocalTCPPort != m.listenPort { + m.Stop() + } + } m.config.Replace(*config) + m.listenPort = config.LinkLocalTCPPort + if !m.IsStarted() && len(config.MulticastInterfaces) > 0 { + m.Start() + } } // GetInterfaces returns the currently known/enabled multicast interfaces. It is From d58f88d29aeccfaa7f7de59e4e41a6be78a8882d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 24 Oct 2019 09:28:09 +0100 Subject: [PATCH 08/12] Update builds to Go 1.13 as this is required for TLS (apparently golang.org/x/crypto/ed25519 is not acceptable to the crypto/tls module and this prevents Yggdrasil from starting) --- .circleci/config.yml | 2 +- README.md | 2 +- go.mod | 2 ++ src/yggdrasil/tls.go | 3 +-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5a9e1e31..146d5e53 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ version: 2.1 jobs: build-linux: docker: - - image: circleci/golang:1.12.7 + - image: circleci/golang:1.13.3 steps: - checkout diff --git a/README.md b/README.md index 07b202f1..c02151f4 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ You may also find other platform-specific wrappers, scripts or tools in the If you want to build from source, as opposed to installing one of the pre-built packages: -1. Install [Go](https://golang.org) (requires Go 1.12 or later) +1. Install [Go](https://golang.org) (requires Go 1.13 or later) 2. Clone this repository 2. Run `./build` diff --git a/go.mod b/go.mod index 83c22924..d1a3587f 100644 --- a/go.mod +++ b/go.mod @@ -17,3 +17,5 @@ require ( golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a golang.org/x/text v0.3.2 ) + +go 1.13 diff --git a/src/yggdrasil/tls.go b/src/yggdrasil/tls.go index 26ecf1d7..7212c4df 100644 --- a/src/yggdrasil/tls.go +++ b/src/yggdrasil/tls.go @@ -2,6 +2,7 @@ package yggdrasil import ( "bytes" + "crypto/ed25519" "crypto/rand" "crypto/tls" "crypto/x509" @@ -12,8 +13,6 @@ import ( "math/big" "net" "time" - - "golang.org/x/crypto/ed25519" ) type tcptls struct { From 5ca81f916ef1952e58d8699976eb9cb01a15cde8 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 24 Oct 2019 09:54:57 +0100 Subject: [PATCH 09/12] Fix deadlocks --- src/multicast/multicast.go | 47 ++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index ed8efafd..82d47ed0 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "regexp" + "sync/atomic" "time" "github.com/Arceliar/phony" @@ -28,7 +29,7 @@ type Multicast struct { groupAddr string listeners map[string]*listenerInfo listenPort uint16 - isOpen bool + isOpen atomic.Value // bool announcer *time.Timer platformhandler *time.Timer } @@ -48,6 +49,7 @@ func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log current := m.config.GetCurrent() m.listenPort = current.LinkLocalTCPPort m.groupAddr = "[ff02::114]:9001" + m.isOpen.Store(false) return nil } @@ -59,15 +61,16 @@ func (m *Multicast) Start() error { phony.Block(m, func() { err = m._start() }) + m.log.Debugln("Started multicast module") return err } func (m *Multicast) _start() error { - if m.isOpen { + if m.IsStarted() { return fmt.Errorf("multicast module is already started") } if len(m.config.GetCurrent().MulticastInterfaces) == 0 { - return fmt.Errorf("no MulticastInterfaces configured") + return nil } m.log.Infoln("Starting multicast module") addr, err := net.ResolveUDPAddr("udp", m.groupAddr) @@ -87,7 +90,7 @@ func (m *Multicast) _start() error { // Windows can't set this flag, so we need to handle it in other ways } - m.isOpen = true + m.isOpen.Store(true) go m.listen() m.Act(m, m.multicastStarted) m.Act(m, m.announce) @@ -97,21 +100,25 @@ func (m *Multicast) _start() error { // IsStarted returns true if the module has been started. func (m *Multicast) IsStarted() bool { - var isOpen bool - phony.Block(m, func() { - isOpen = m.isOpen - }) - return isOpen + if m.isOpen.Load() == nil { + return false + } + return m.isOpen.Load().(bool) } // Stop stops the multicast module. -func (m *Multicast) Stop() { - m.Act(m, m._stop) +func (m *Multicast) Stop() error { + var err error + phony.Block(m, func() { + err = m._stop() + }) + m.log.Debugln("Stopped multicast module") + return nil } -func (m *Multicast) _stop() { +func (m *Multicast) _stop() error { m.log.Infoln("Stopping multicast module") - m.isOpen = false + m.isOpen.Store(false) if m.announcer != nil { m.announcer.Stop() } @@ -119,6 +126,7 @@ func (m *Multicast) _stop() { m.platformhandler.Stop() } m.sock.Close() + return nil } // UpdateConfig updates the multicast module with the provided config.NodeConfig @@ -129,17 +137,22 @@ func (m *Multicast) UpdateConfig(config *config.NodeConfig) { } func (m *Multicast) _updateConfig(config *config.NodeConfig) { - m.log.Debugln("Reloading multicast configuration...") + m.log.Infoln("Reloading multicast configuration...") if m.IsStarted() { if len(config.MulticastInterfaces) == 0 || config.LinkLocalTCPPort != m.listenPort { - m.Stop() + if err := m._stop(); err != nil { + m.log.Errorln("Error stopping multicast module:", err) + } } } m.config.Replace(*config) m.listenPort = config.LinkLocalTCPPort if !m.IsStarted() && len(config.MulticastInterfaces) > 0 { - m.Start() + if err := m._start(); err != nil { + m.log.Errorln("Error starting multicast module:", err) + } } + m.log.Debugln("Reloaded multicast configuration successfully") } // GetInterfaces returns the currently known/enabled multicast interfaces. It is @@ -312,7 +325,7 @@ func (m *Multicast) listen() { for { nBytes, rcm, fromAddr, err := m.sock.ReadFrom(bs) if err != nil { - if !m.isOpen { + if !m.IsStarted() { return } panic(err) From 51fe1940c593c2a97ecdf4118f0ffa452cc9cfc9 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 24 Oct 2019 10:13:59 +0100 Subject: [PATCH 10/12] Try go 1.13 to see if this fixes failing builds --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 146d5e53..33290840 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ version: 2.1 jobs: build-linux: docker: - - image: circleci/golang:1.13.3 + - image: circleci/golang:1.13 steps: - checkout From ee644c47e8be8d2fa41ddb614d48972a8044cbad Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 24 Oct 2019 10:16:52 +0100 Subject: [PATCH 11/12] Update go.mod/go.sum, go back to 1.13.3 circleci image again --- .circleci/config.yml | 2 +- go.mod | 17 +++++++---------- go.sum | 29 ++++++++++++----------------- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 33290840..146d5e53 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ version: 2.1 jobs: build-linux: docker: - - image: circleci/golang:1.13 + - image: circleci/golang:1.13.3 steps: - checkout diff --git a/go.mod b/go.mod index d1a3587f..6d27e6ed 100644 --- a/go.mod +++ b/go.mod @@ -1,21 +1,18 @@ module github.com/yggdrasil-network/yggdrasil-go +go 1.13 + require ( - github.com/Arceliar/phony v0.0.0-20191005181740-21679e75e3f0 + github.com/Arceliar/phony v0.0.0-20191006174943-d0c68492aca0 github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8 github.com/hashicorp/go-syslog v1.0.0 - github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible + github.com/hjson/hjson-go v3.0.0+incompatible github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0 github.com/mitchellh/mapstructure v1.1.2 github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 - github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b // indirect - github.com/vishvananda/netlink v1.0.0 - github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f // indirect github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8 - golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 - golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 - golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a + golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 + golang.org/x/net v0.0.0-20191021144547-ec77196f6094 + golang.org/x/sys v0.0.0-20191024073052-e66fe6eb8e0c golang.org/x/text v0.3.2 ) - -go 1.13 diff --git a/go.sum b/go.sum index bca7c231..61fc7242 100644 --- a/go.sum +++ b/go.sum @@ -1,35 +1,30 @@ -github.com/Arceliar/phony v0.0.0-20191005181740-21679e75e3f0 h1:IOFsvAMFkgnKfSQHxXTeqb1+ODFeR5px1HCHU86KF30= -github.com/Arceliar/phony v0.0.0-20191005181740-21679e75e3f0/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= +github.com/Arceliar/phony v0.0.0-20191006174943-d0c68492aca0 h1:p3puK8Sl2xK+2FnnIvY/C0N1aqJo2kbEsdAzU+Tnv48= +github.com/Arceliar/phony v0.0.0-20191006174943-d0c68492aca0/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8 h1:WD8iJ37bRNwvETMfVTusVSAi0WdXTpfNVGY2aHycNKY= github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U= github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible h1:bLQ2Ve+eW65id3b8xEMQiAwJT4qGZeywAEMLvXjznvw= -github.com/hjson/hjson-go v3.0.1-0.20190209023717-9147687966d9+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio= +github.com/hjson/hjson-go v3.0.0+incompatible h1:mc8olpIxqF8mrEx6ePJOD6wCCOkX7+JcrKgINcJES10= +github.com/hjson/hjson-go v3.0.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio= github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0 h1:YnZmFjg0Nvk8851WTVWlqMC1ecJH07Ctz+Ezxx4u54g= github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0/go.mod h1:rUi0/YffDo1oXBOGn1KRq7Fr07LX48XEBecQnmwjsAo= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 h1:1zN6ImoqhSJhN8hGXFaJlSC8msLmIbX8bFqOfWLKw0w= github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091/go.mod h1:N20Z5Y8oye9a7HmytmZ+tr8Q2vlP0tAHP13kTHzwvQY= -github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b h1:+y4hCMc/WKsDbAPsOQZgBSaSZ26uh2afyaWeVg/3s/c= -github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= -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= github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8 h1:YY9Pg2BEp0jeUVU60svTOaDr+fs1ySC9RbdC1Qc6wOw= github.com/yggdrasil-network/water v0.0.0-20190812103929-c83fe40250f8/go.mod h1:R0SBCsugm+Sf1katgTb2t7GXMm+nRIv43tM4VDZbaOs= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20191021144547-ec77196f6094 h1:5O4U9trLjNpuhpynaDsqwCk+Tw6seqJz1EbqbnzHrc8= +golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191024073052-e66fe6eb8e0c h1:usSYQsGq37L8RjJc5eznJ/AbwBxn3QFFEVkWNPAejLs= +golang.org/x/sys v0.0.0-20191024073052-e66fe6eb8e0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 0e7ed4c99771785b7817d5c5aa39f69be07124e2 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 24 Oct 2019 10:18:08 +0100 Subject: [PATCH 12/12] Actually really use 1.13.3 for all the builds this time --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 146d5e53..17cbfade 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -106,11 +106,11 @@ jobs: echo -e "Host *\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - run: - name: Install Go 1.12.7 + name: Install Go 1.13.3 command: | cd /tmp - curl -LO https://dl.google.com/go/go1.12.7.darwin-amd64.pkg - sudo installer -pkg /tmp/go1.12.7.darwin-amd64.pkg -target / + curl -LO https://dl.google.com/go/go1.13.3.darwin-amd64.pkg + sudo installer -pkg /tmp/go1.13.3.darwin-amd64.pkg -target / #- run: # name: Install Gomobile @@ -146,7 +146,7 @@ jobs: build-other: docker: - - image: circleci/golang:1.12.7 + - image: circleci/golang:1.13.3 steps: - checkout