Compare commits

...

6 Commits

Author SHA1 Message Date
Neil Alexander
340cedbe14 Yggdrasil 0.5.8 2024-08-12 19:17:40 +01:00
Neil Alexander
b1283e15f6 Link state tracking tweaks and improved shutdown 2024-08-11 10:42:25 +01:00
Neil Alexander
ef989bef63 Multicast module state tweaks 2024-08-11 10:41:58 +01:00
Neil Alexander
af9ff34995 Fix macOS build 2024-08-07 19:55:10 +01:00
Neil Alexander
63cd757525 Remove waitForTUNUp from TUN
Causes issues such as #1156.
2024-08-07 19:52:19 +01:00
Revertron
5e5de3a343 Fixed wait for TUN to come up (#1157)
So, the function waiting for TUN to come up never succeeds:
```
func waitForTUNUp(ch <-chan wgtun.Event) bool {
	t := time.After(time.Second * 5)
	for {
		select {
		case ev := <-ch:
			if ev == wgtun.EventUp {
				return true
			}
		case <-t:
			return false
		}
	}
}
```
I've tried the sleep for one second, and it works flawlessly on several
PCs.

Another point - sometimes, if the service stop abruptly (in case of some
errors) there is an old hidden device in the system, that we need to
uninstall, and then create new.
2024-08-06 10:28:15 +01:00
14 changed files with 80 additions and 97 deletions

View File

@@ -26,6 +26,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- in case of vulnerabilities. - in case of vulnerabilities.
--> -->
## [0.5.8] - 2024-08-12
### Fixed
* A bug which caused startup problems on Windows and FreeBSD should be fixed
* Resolved some minor link state and listener management bugs during shutdown
## [0.5.7] - 2024-08-05 ## [0.5.7] - 2024-08-05
### Added ### Added

View File

@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"io" "io"
"net" "net"
@@ -40,7 +41,8 @@ type links struct {
ws *linkWS // WS interface support ws *linkWS // WS interface support
wss *linkWSS // WSS interface support wss *linkWSS // WSS interface support
// _links can only be modified safely from within the links actor // _links can only be modified safely from within the links actor
_links map[linkInfo]*link // *link is nil if connection in progress _links map[linkInfo]*link // *link is nil if connection in progress
_listeners map[*Listener]context.CancelFunc
} }
type linkProtocol interface { type linkProtocol interface {
@@ -85,13 +87,6 @@ func (l *Listener) Addr() net.Addr {
return l.listener.Addr() return l.listener.Addr()
} }
func (l *Listener) Close() error {
l.Cancel()
err := l.listener.Close()
<-l.ctx.Done()
return err
}
func (l *links) init(c *Core) error { func (l *links) init(c *Core) error {
l.core = c l.core = c
l.tcp = l.newLinkTCP() l.tcp = l.newLinkTCP()
@@ -102,32 +97,18 @@ func (l *links) init(c *Core) error {
l.ws = l.newLinkWS() l.ws = l.newLinkWS()
l.wss = l.newLinkWSS() l.wss = l.newLinkWSS()
l._links = make(map[linkInfo]*link) l._links = make(map[linkInfo]*link)
l._listeners = make(map[*Listener]context.CancelFunc)
var listeners []ListenAddress
phony.Block(c, func() {
listeners = make([]ListenAddress, 0, len(c.config._listeners))
for listener := range c.config._listeners {
listeners = append(listeners, listener)
}
})
return nil return nil
} }
func (l *links) shutdown() { func (l *links) shutdown() {
phony.Block(l.tcp, func() { phony.Block(l, func() {
for l := range l.tcp._listeners { for listener := range l._listeners {
_ = l.Close() _ = listener.listener.Close()
} }
}) for _, link := range l._links {
phony.Block(l.tls, func() { _ = link._conn.Close()
for l := range l.tls._listeners {
_ = l.Close()
}
})
phony.Block(l.unix, func() {
for l := range l.unix._listeners {
_ = l.Close()
} }
}) })
} }
@@ -457,11 +438,18 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
options.password = []byte(p) options.password = []byte(p)
} }
phony.Block(l, func() {
l._listeners[li] = cancel
})
go func() { go func() {
l.core.log.Infof("%s listener started on %s", strings.ToUpper(u.Scheme), listener.Addr()) l.core.log.Infof("%s listener started on %s", strings.ToUpper(u.Scheme), li.listener.Addr())
defer l.core.log.Infof("%s listener stopped on %s", strings.ToUpper(u.Scheme), listener.Addr()) defer l.core.log.Infof("%s listener stopped on %s", strings.ToUpper(u.Scheme), li.listener.Addr())
defer phony.Block(l, func() {
delete(l._listeners, li)
})
for { for {
conn, err := listener.Accept() conn, err := li.listener.Accept()
if err != nil { if err != nil {
return return
} }
@@ -517,13 +505,22 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
// Store the state of the link so that it can be queried later. // Store the state of the link so that it can be queried later.
l._links[info] = state l._links[info] = state
}) })
defer phony.Block(l, func() {
if l._links[info] == state {
delete(l._links, info)
}
})
if lc == nil { if lc == nil {
return return
} }
// Give the connection to the handler. The handler will block // Give the connection to the handler. The handler will block
// for the lifetime of the connection. // for the lifetime of the connection.
if err = l.handler(linkTypeIncoming, options, lc, nil); err != nil && err != io.EOF { switch err = l.handler(linkTypeIncoming, options, lc, nil); {
case err == nil:
case errors.Is(err, io.EOF):
case errors.Is(err, net.ErrClosed):
default:
l.core.log.Debugf("Link %s error: %s\n", u.Host, err) l.core.log.Debugf("Link %s error: %s\n", u.Host, err)
} }
@@ -531,11 +528,6 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
// try to close the underlying socket just in case and then // try to close the underlying socket just in case and then
// drop the link state. // drop the link state.
_ = lc.Close() _ = lc.Close()
phony.Block(l, func() {
if l._links[info] == state {
delete(l._links, info)
}
})
}(conn) }(conn)
} }
}() }()

View File

@@ -15,7 +15,6 @@ type linkTCP struct {
phony.Inbox phony.Inbox
*links *links
listenconfig *net.ListenConfig listenconfig *net.ListenConfig
_listeners map[*Listener]context.CancelFunc
} }
func (l *links) newLinkTCP() *linkTCP { func (l *links) newLinkTCP() *linkTCP {
@@ -24,7 +23,6 @@ func (l *links) newLinkTCP() *linkTCP {
listenconfig: &net.ListenConfig{ listenconfig: &net.ListenConfig{
KeepAlive: -1, KeepAlive: -1,
}, },
_listeners: map[*Listener]context.CancelFunc{},
} }
lt.listenconfig.Control = lt.tcpContext lt.listenconfig.Control = lt.tcpContext
return lt return lt

View File

@@ -13,10 +13,9 @@ import (
type linkTLS struct { type linkTLS struct {
phony.Inbox phony.Inbox
*links *links
tcp *linkTCP tcp *linkTCP
listener *net.ListenConfig listener *net.ListenConfig
config *tls.Config config *tls.Config
_listeners map[*Listener]context.CancelFunc
} }
func (l *links) newLinkTLS(tcp *linkTCP) *linkTLS { func (l *links) newLinkTLS(tcp *linkTCP) *linkTLS {
@@ -27,8 +26,7 @@ func (l *links) newLinkTLS(tcp *linkTCP) *linkTLS {
Control: tcp.tcpContext, Control: tcp.tcpContext,
KeepAlive: -1, KeepAlive: -1,
}, },
config: l.core.config.tls.Clone(), config: l.core.config.tls.Clone(),
_listeners: map[*Listener]context.CancelFunc{},
} }
return lt return lt
} }

View File

@@ -12,9 +12,8 @@ import (
type linkUNIX struct { type linkUNIX struct {
phony.Inbox phony.Inbox
*links *links
dialer *net.Dialer dialer *net.Dialer
listener *net.ListenConfig listener *net.ListenConfig
_listeners map[*Listener]context.CancelFunc
} }
func (l *links) newLinkUNIX() *linkUNIX { func (l *links) newLinkUNIX() *linkUNIX {
@@ -27,7 +26,6 @@ func (l *links) newLinkUNIX() *linkUNIX {
listener: &net.ListenConfig{ listener: &net.ListenConfig{
KeepAlive: -1, KeepAlive: -1,
}, },
_listeners: map[*Listener]context.CancelFunc{},
} }
return lt return lt
} }

View File

@@ -14,6 +14,7 @@ import (
type linkWS struct { type linkWS struct {
phony.Inbox phony.Inbox
*links *links
listenconfig *net.ListenConfig
} }
type linkWSConn struct { type linkWSConn struct {
@@ -78,6 +79,9 @@ func (s *wsServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (l *links) newLinkWS() *linkWS { func (l *links) newLinkWS() *linkWS {
lt := &linkWS{ lt := &linkWS{
links: l, links: l,
listenconfig: &net.ListenConfig{
KeepAlive: -1,
},
} }
return lt return lt
} }
@@ -95,7 +99,7 @@ func (l *linkWS) dial(ctx context.Context, url *url.URL, info linkInfo, options
} }
func (l *linkWS) listen(ctx context.Context, url *url.URL, _ string) (net.Listener, error) { func (l *linkWS) listen(ctx context.Context, url *url.URL, _ string) (net.Listener, error) {
nl, err := net.Listen("tcp", url.Host) nl, err := l.listenconfig.Listen(ctx, "tcp", url.Host)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -9,6 +9,7 @@ import (
"math/rand" "math/rand"
"net" "net"
"net/url" "net/url"
"sync/atomic"
"time" "time"
"github.com/Arceliar/phony" "github.com/Arceliar/phony"
@@ -28,7 +29,7 @@ type Multicast struct {
core *core.Core core *core.Core
log *log.Logger log *log.Logger
sock *ipv6.PacketConn sock *ipv6.PacketConn
_isOpen bool running atomic.Bool
_listeners map[string]*listenerInfo _listeners map[string]*listenerInfo
_interfaces map[string]*interfaceInfo _interfaces map[string]*interfaceInfo
_timer *time.Timer _timer *time.Timer
@@ -79,7 +80,7 @@ func New(core *core.Core, log *log.Logger, opts ...SetupOption) (*Multicast, err
} }
func (m *Multicast) _start() error { func (m *Multicast) _start() error {
if m._isOpen { if !m.running.CompareAndSwap(false, true) {
return fmt.Errorf("multicast module is already started") return fmt.Errorf("multicast module is already started")
} }
var anyEnabled bool var anyEnabled bool
@@ -87,12 +88,14 @@ func (m *Multicast) _start() error {
anyEnabled = anyEnabled || intf.Beacon || intf.Listen anyEnabled = anyEnabled || intf.Beacon || intf.Listen
} }
if !anyEnabled { if !anyEnabled {
m.running.Store(false)
return nil return nil
} }
m.log.Debugln("Starting multicast module") m.log.Debugln("Starting multicast module")
defer m.log.Debugln("Started multicast module") defer m.log.Debugln("Started multicast module")
addr, err := net.ResolveUDPAddr("udp", string(m.config._groupAddr)) addr, err := net.ResolveUDPAddr("udp", string(m.config._groupAddr))
if err != nil { if err != nil {
m.running.Store(false)
return err return err
} }
listenString := fmt.Sprintf("[::]:%v", addr.Port) listenString := fmt.Sprintf("[::]:%v", addr.Port)
@@ -101,6 +104,7 @@ func (m *Multicast) _start() error {
} }
conn, err := lc.ListenPacket(context.Background(), "udp6", listenString) conn, err := lc.ListenPacket(context.Background(), "udp6", listenString)
if err != nil { if err != nil {
m.running.Store(false)
return err return err
} }
m.sock = ipv6.NewPacketConn(conn) m.sock = ipv6.NewPacketConn(conn)
@@ -108,7 +112,6 @@ func (m *Multicast) _start() error {
// Windows can't set this flag, so we need to handle it in other ways // Windows can't set this flag, so we need to handle it in other ways
} }
m._isOpen = true
go m.listen() go m.listen()
m.Act(nil, m._multicastStarted) m.Act(nil, m._multicastStarted)
m.Act(nil, m._announce) m.Act(nil, m._announce)
@@ -118,11 +121,7 @@ func (m *Multicast) _start() error {
// IsStarted returns true if the module has been started. // IsStarted returns true if the module has been started.
func (m *Multicast) IsStarted() bool { func (m *Multicast) IsStarted() bool {
var isOpen bool return m.running.Load()
phony.Block(m, func() {
isOpen = m._isOpen
})
return isOpen
} }
// Stop stops the multicast module. // Stop stops the multicast module.
@@ -136,8 +135,10 @@ func (m *Multicast) Stop() error {
} }
func (m *Multicast) _stop() error { func (m *Multicast) _stop() error {
if !m.running.CompareAndSwap(true, false) {
return nil
}
m.log.Infoln("Stopping multicast module") m.log.Infoln("Stopping multicast module")
m._isOpen = false
if m.sock != nil { if m.sock != nil {
m.sock.Close() m.sock.Close()
} }
@@ -233,7 +234,7 @@ func (m *Multicast) AnnounceNow() {
} }
func (m *Multicast) _announce() { func (m *Multicast) _announce() {
if !m._isOpen { if !m.running.Load() {
return return
} }
m._updateInterfaces() m._updateInterfaces()
@@ -250,7 +251,7 @@ func (m *Multicast) _announce() {
for name, info := range m._listeners { for name, info := range m._listeners {
// Prepare our stop function! // Prepare our stop function!
stop := func() { stop := func() {
info.listener.Close() info.listener.Cancel()
delete(m._listeners, name) delete(m._listeners, name)
m.log.Debugln("No longer multicasting on", name) m.log.Debugln("No longer multicasting on", name)
} }
@@ -376,6 +377,9 @@ func (m *Multicast) listen() {
bs := make([]byte, 2048) bs := make([]byte, 2048)
hb := make([]byte, 0, blake2b.Size) // Reused to reduce hash allocations hb := make([]byte, 0, blake2b.Size) // Reused to reduce hash allocations
for { for {
if !m.running.Load() {
return
}
n, rcm, fromAddr, err := m.sock.ReadFrom(bs) n, rcm, fromAddr, err := m.sock.ReadFrom(bs)
if err != nil { if err != nil {
if !m.IsStarted() { if !m.IsStarted() {

View File

@@ -31,7 +31,7 @@ import (
) )
func (m *Multicast) _multicastStarted() { func (m *Multicast) _multicastStarted() {
if !m._isOpen { if !m.running.Load() {
return return
} }
C.StopAWDLBrowsing() C.StopAWDLBrowsing()

View File

@@ -11,7 +11,6 @@ import (
"io" "io"
"net" "net"
"sync" "sync"
"time"
"github.com/Arceliar/phony" "github.com/Arceliar/phony"
wgtun "golang.zx2c4.com/wireguard/tun" wgtun "golang.zx2c4.com/wireguard/tun"
@@ -65,20 +64,6 @@ func getSupportedMTU(mtu uint64) uint64 {
return mtu return mtu
} }
func waitForTUNUp(ch <-chan wgtun.Event) bool {
t := time.After(time.Second * 5)
for {
select {
case ev := <-ch:
if ev == wgtun.EventUp {
return true
}
case <-t:
return false
}
}
}
// Name returns the name of the adapter, e.g. "tun0". On Windows, this may // Name returns the name of the adapter, e.g. "tun0". On Windows, this may
// return a canonical adapter name instead. // return a canonical adapter name instead.
func (tun *TunAdapter) Name() string { func (tun *TunAdapter) Name() string {

View File

@@ -80,9 +80,6 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to create TUN: %w", err) return fmt.Errorf("failed to create TUN: %w", err)
} }
if !waitForTUNUp(iface.Events()) {
return fmt.Errorf("TUN did not come up in time")
}
tun.iface = iface tun.iface = iface
if mtu, err := iface.MTU(); err == nil { if mtu, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(mtu)) tun.mtu = getSupportedMTU(uint64(mtu))

View File

@@ -27,9 +27,6 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to create TUN: %w", err) return fmt.Errorf("failed to create TUN: %w", err)
} }
if !waitForTUNUp(iface.Events()) {
return fmt.Errorf("TUN did not come up in time")
}
tun.iface = iface tun.iface = iface
if m, err := iface.MTU(); err == nil { if m, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(m)) tun.mtu = getSupportedMTU(uint64(m))
@@ -58,9 +55,6 @@ func (tun *TunAdapter) setupFD(fd int32, addr string, mtu uint64) error {
unix.Close(dfd) unix.Close(dfd)
return fmt.Errorf("failed to create TUN from FD: %w", err) return fmt.Errorf("failed to create TUN from FD: %w", err)
} }
if !waitForTUNUp(iface.Events()) {
return fmt.Errorf("TUN did not come up in time")
}
tun.iface = iface tun.iface = iface
if m, err := iface.MTU(); err == nil { if m, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(m)) tun.mtu = getSupportedMTU(uint64(m))

View File

@@ -21,9 +21,6 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to create TUN: %w", err) return fmt.Errorf("failed to create TUN: %w", err)
} }
if !waitForTUNUp(iface.Events()) {
return fmt.Errorf("TUN did not come up in time")
}
tun.iface = iface tun.iface = iface
if mtu, err := iface.MTU(); err == nil { if mtu, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(mtu)) tun.mtu = getSupportedMTU(uint64(mtu))

View File

@@ -18,9 +18,6 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to create TUN: %w", err) return fmt.Errorf("failed to create TUN: %w", err)
} }
if !waitForTUNUp(iface.Events()) {
return fmt.Errorf("TUN did not come up in time")
}
tun.iface = iface tun.iface = iface
if mtu, err := iface.MTU(); err == nil { if mtu, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(mtu)) tun.mtu = getSupportedMTU(uint64(mtu))

View File

@@ -8,10 +8,12 @@ import (
"fmt" "fmt"
"log" "log"
"net/netip" "net/netip"
"time"
"github.com/yggdrasil-network/yggdrasil-go/src/config" "github.com/yggdrasil-network/yggdrasil-go/src/config"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.zx2c4.com/wintun"
wgtun "golang.zx2c4.com/wireguard/tun" wgtun "golang.zx2c4.com/wireguard/tun"
"golang.zx2c4.com/wireguard/windows/elevate" "golang.zx2c4.com/wireguard/windows/elevate"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
@@ -31,14 +33,23 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
if guid, err = windows.GUIDFromString("{8f59971a-7872-4aa6-b2eb-061fc4e9d0a7}"); err != nil { if guid, err = windows.GUIDFromString("{8f59971a-7872-4aa6-b2eb-061fc4e9d0a7}"); err != nil {
return err return err
} }
if iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, int(mtu)); err != nil { iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, int(mtu))
return err if err != nil {
} // Very rare condition, it will purge the old device and create new
if !waitForTUNUp(iface.Events()) { tun.log.Printf("Error creating TUN: '%s'", err)
return fmt.Errorf("TUN did not come up in time") wintun.Uninstall()
time.Sleep(3 * time.Second)
tun.log.Printf("Trying again")
iface, err = wgtun.CreateTUNWithRequestedGUID(ifname, &guid, int(mtu))
if err != nil {
return err
}
} }
tun.log.Printf("Waiting for TUN to come up")
time.Sleep(1 * time.Second)
tun.iface = iface tun.iface = iface
if addr != "" { if addr != "" {
tun.log.Printf("Setting up address")
if err = tun.setupAddress(addr); err != nil { if err = tun.setupAddress(addr); err != nil {
tun.log.Errorln("Failed to set up TUN address:", err) tun.log.Errorln("Failed to set up TUN address:", err)
return err return err
@@ -51,6 +62,7 @@ func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
if mtu, err := iface.MTU(); err == nil { if mtu, err := iface.MTU(); err == nil {
tun.mtu = uint64(mtu) tun.mtu = uint64(mtu)
} }
tun.log.Printf("TUN is set up successfully")
return nil return nil
}) })
} }