From e90be6f5695ebc38a096796e049e774ec475d48e Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 21 Nov 2019 00:02:39 +0000 Subject: [PATCH 1/5] Add API functions for manipulating maximum session MTU, fix TUN/TAP to use that --- src/tuntap/tun.go | 3 +++ src/yggdrasil/api.go | 16 ++++++++++++++++ src/yggdrasil/session.go | 8 +++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index d5bed52..6feb533 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -35,6 +35,7 @@ const tun_ETHER_HEADER_LENGTH = 14 // you should pass this object to the yggdrasil.SetRouterAdapter() function // before calling yggdrasil.Start(). type TunAdapter struct { + core *yggdrasil.Core writer tunWriter reader tunReader config *config.NodeState @@ -131,6 +132,7 @@ func (tun *TunAdapter) Init(core *yggdrasil.Core, config *config.NodeState, log if !ok { return fmt.Errorf("invalid options supplied to TunAdapter module") } + tun.core = core tun.config = config tun.log = log tun.listener = tunoptions.Listener @@ -181,6 +183,7 @@ func (tun *TunAdapter) _start() error { if tun.MTU() != current.IfMTU { tun.log.Warnf("Warning: Interface MTU %d automatically adjusted to %d (supported range is 1280-%d)", current.IfMTU, tun.MTU(), MaximumMTU(tun.IsTAP())) } + tun.core.SetMaximumSessionMTU(uint16(tun.MTU())) tun.isOpen = true go tun.handler() tun.reader.Act(nil, tun.reader._read) // Start the reader diff --git a/src/yggdrasil/api.go b/src/yggdrasil/api.go index 6dd70b8..59cc831 100644 --- a/src/yggdrasil/api.go +++ b/src/yggdrasil/api.go @@ -363,6 +363,22 @@ func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) { c.router.nodeinfo.setNodeInfo(nodeinfo, nodeinfoprivacy) } +// GetMaximumSessionMTU returns the maximum allowed session MTU size. +func (c *Core) GetMaximumSessionMTU(mtu uint16) uint16 { + return c.router.sessions.myMaximumMTU +} + +// SetMaximumSessionMTU sets the maximum allowed session MTU size. The return +// value contains the actual set value, since Yggdrasil will not accept MTUs +// below 1280 bytes. The default value is 65535 bytes. +func (c *Core) SetMaximumSessionMTU(mtu uint16) uint16 { + if mtu < 1280 { + mtu = 1280 + } + c.router.sessions.myMaximumMTU = mtu + return mtu +} + // GetNodeInfo requests nodeinfo from a remote node, as specified by the public // key and coordinates specified. The third parameter specifies whether a cached // result is acceptable - this results in less traffic being generated than is diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index 2f5e0af..b287377 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -121,6 +121,7 @@ type sessions struct { lastCleanup time.Time isAllowedHandler func(pubkey *crypto.BoxPubKey, initiator bool) bool // Returns true or false if session setup is allowed isAllowedMutex sync.RWMutex // Protects the above + myMaximumMTU uint16 // Maximum allowed session MTU permShared map[crypto.BoxPubKey]*crypto.BoxSharedKey // Maps known permanent keys to their shared key, used by DHT a lot sinfos map[crypto.Handle]*sessionInfo // Maps handle onto session info byTheirPerm map[crypto.BoxPubKey]*crypto.Handle // Maps theirPermPub onto handle @@ -133,6 +134,7 @@ func (ss *sessions) init(r *router) { ss.sinfos = make(map[crypto.Handle]*sessionInfo) ss.byTheirPerm = make(map[crypto.BoxPubKey]*crypto.Handle) ss.lastCleanup = time.Now() + ss.myMaximumMTU = 65535 } func (ss *sessions) reconfigure() { @@ -187,9 +189,9 @@ func (ss *sessions) createSession(theirPermKey *crypto.BoxPubKey) *sessionInfo { sinfo.mySesPriv = *priv sinfo.myNonce = *crypto.NewBoxNonce() sinfo.theirMTU = 1280 - ss.router.core.config.Mutex.RLock() - sinfo.myMTU = uint16(ss.router.core.config.Current.IfMTU) - ss.router.core.config.Mutex.RUnlock() + // TODO: sinfo.myMTU becomes unnecessary if we always have a reference to the + // sessions struct so let's check if that is the case + sinfo.myMTU = ss.myMaximumMTU now := time.Now() sinfo.timeOpened = now sinfo.time = now From d1c445dc41837d5f3c85d37acc8d693a9f4df279 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 21 Nov 2019 09:28:36 +0000 Subject: [PATCH 2/5] Thread safety for MTU API functions --- src/yggdrasil/api.go | 21 +++++++++++---------- src/yggdrasil/session.go | 2 -- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/yggdrasil/api.go b/src/yggdrasil/api.go index 59cc831..e6b32e6 100644 --- a/src/yggdrasil/api.go +++ b/src/yggdrasil/api.go @@ -365,18 +365,19 @@ func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) { // GetMaximumSessionMTU returns the maximum allowed session MTU size. func (c *Core) GetMaximumSessionMTU(mtu uint16) uint16 { - return c.router.sessions.myMaximumMTU + mtu := 0 + phony.Block(c.router, func() { + mtu = c.router.sessions.myMaximumMTU + }) + return mtu } -// SetMaximumSessionMTU sets the maximum allowed session MTU size. The return -// value contains the actual set value, since Yggdrasil will not accept MTUs -// below 1280 bytes. The default value is 65535 bytes. -func (c *Core) SetMaximumSessionMTU(mtu uint16) uint16 { - if mtu < 1280 { - mtu = 1280 - } - c.router.sessions.myMaximumMTU = mtu - return mtu +// SetMaximumSessionMTU sets the maximum allowed session MTU size. The default +// value is 65535 bytes. +func (c *Core) SetMaximumSessionMTU(mtu uint16) { + phony.Block(c.router, func() { + c.router.sessions.myMaximumMTU = mtu + }) } // GetNodeInfo requests nodeinfo from a remote node, as specified by the public diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index b287377..78b0a3b 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -189,8 +189,6 @@ func (ss *sessions) createSession(theirPermKey *crypto.BoxPubKey) *sessionInfo { sinfo.mySesPriv = *priv sinfo.myNonce = *crypto.NewBoxNonce() sinfo.theirMTU = 1280 - // TODO: sinfo.myMTU becomes unnecessary if we always have a reference to the - // sessions struct so let's check if that is the case sinfo.myMTU = ss.myMaximumMTU now := time.Now() sinfo.timeOpened = now From 7c18c6806d0d0a61b4eb7895471339c1e65e5f99 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 21 Nov 2019 09:54:36 +0000 Subject: [PATCH 3/5] Further updates, notify sessions about updated MTU from API call --- src/tuntap/tun.go | 6 ++++++ src/yggdrasil/api.go | 16 ++++++++++------ src/yggdrasil/session.go | 13 ++++++------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 6feb533..1e994ea 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -233,6 +233,12 @@ func (tun *TunAdapter) UpdateConfig(config *config.NodeConfig) { // Replace the active configuration with the supplied one tun.config.Replace(*config) + // If the MTU has changed in the TUN/TAP module then this is where we would + // tell the router so that updated session pings can be sent. However, we + // don't currently update the MTU of the adapter once it has been created so + // this doesn't actually happen in the real world yet. + // tun.core.SetMaximumSessionMTU(...) + // Notify children about the configuration change tun.Act(nil, tun.ckr.configure) } diff --git a/src/yggdrasil/api.go b/src/yggdrasil/api.go index e6b32e6..7f82c26 100644 --- a/src/yggdrasil/api.go +++ b/src/yggdrasil/api.go @@ -364,19 +364,23 @@ func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) { } // GetMaximumSessionMTU returns the maximum allowed session MTU size. -func (c *Core) GetMaximumSessionMTU(mtu uint16) uint16 { - mtu := 0 - phony.Block(c.router, func() { +func (c *Core) GetMaximumSessionMTU() uint16 { + var mtu uint16 + phony.Block(&c.router, func() { mtu = c.router.sessions.myMaximumMTU }) return mtu } // SetMaximumSessionMTU sets the maximum allowed session MTU size. The default -// value is 65535 bytes. +// value is 65535 bytes. Session pings will be sent to update all open sessions +// if the MTU has changed. func (c *Core) SetMaximumSessionMTU(mtu uint16) { - phony.Block(c.router, func() { - c.router.sessions.myMaximumMTU = mtu + phony.Block(&c.router, func() { + if c.router.sessions.myMaximumMTU != mtu { + c.router.sessions.myMaximumMTU = mtu + c.router.sessions.reconfigure() + } }) } diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index 78b0a3b..c203fe2 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -55,10 +55,6 @@ type sessionInfo struct { callbacks []chan func() // Finished work from crypto workers } -func (sinfo *sessionInfo) reconfigure() { - // This is where reconfiguration would go, if we had anything to do -} - // Represents a session ping/pong packet, andincludes information like public keys, a session handle, coords, a timestamp to prevent replays, and the tun/tap MTU. type sessionPing struct { SendPermPub crypto.BoxPubKey // Sender's permanent key @@ -138,9 +134,12 @@ func (ss *sessions) init(r *router) { } func (ss *sessions) reconfigure() { - for _, session := range ss.sinfos { - session.reconfigure() - } + ss.router.Act(nil, func() { + for _, session := range ss.sinfos { + session.myMTU = ss.myMaximumMTU + session.ping(ss.router) + } + }) } // Determines whether the session with a given publickey is allowed based on From d3a2087e0fc0c449b8f5b37fca537c5b67ab83cd Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 21 Nov 2019 10:02:18 +0000 Subject: [PATCH 4/5] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3babf8f..eb5c439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.3.12] - 2019-11-22 ### Added -- New command line parameters `-address` and `-subnet` for getting the address/subnet from the config file, for use with `-useconffile` or `-useconf` +- New API functions `SetMaximumSessionMTU` and `GetMaximumSessionMTU` +- New command line parameters `-address` and `-subnet` for getting the address/subnet from the config file, for use with `-useconffile` or `-useconf` - A warning is now produced in the Yggdrasil output at startup when the MTU in the config is invalid or has been adjusted for some reason ### Changed From 248a08b2f1362389e48901c6725796c4eabd5986 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 21 Nov 2019 19:23:44 -0600 Subject: [PATCH 5/5] send a message to the sessions to update mtu instead of trying to update it directly --- src/yggdrasil/session.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index c203fe2..743dd7a 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -136,7 +136,10 @@ func (ss *sessions) init(r *router) { func (ss *sessions) reconfigure() { ss.router.Act(nil, func() { for _, session := range ss.sinfos { - session.myMTU = ss.myMaximumMTU + sinfo, mtu := session, ss.myMaximumMTU + sinfo.Act(ss.router, func() { + sinfo.myMTU = mtu + }) session.ping(ss.router) } })