diff --git a/CHANGELOG.md b/CHANGELOG.md index 3babf8f5..eb5c4394 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 diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index d5bed523..1e994ea5 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 @@ -230,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 6dd70b8e..7f82c260 100644 --- a/src/yggdrasil/api.go +++ b/src/yggdrasil/api.go @@ -363,6 +363,27 @@ 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() 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. 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() { + if c.router.sessions.myMaximumMTU != mtu { + c.router.sessions.myMaximumMTU = mtu + c.router.sessions.reconfigure() + } + }) +} + // 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 2f5e0af3..743dd7a4 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 @@ -121,6 +117,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,12 +130,19 @@ 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() { - for _, session := range ss.sinfos { - session.reconfigure() - } + ss.router.Act(nil, func() { + for _, session := range ss.sinfos { + sinfo, mtu := session, ss.myMaximumMTU + sinfo.Act(ss.router, func() { + sinfo.myMTU = mtu + }) + session.ping(ss.router) + } + }) } // Determines whether the session with a given publickey is allowed based on @@ -187,9 +191,7 @@ 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() + sinfo.myMTU = ss.myMaximumMTU now := time.Now() sinfo.timeOpened = now sinfo.time = now