Compare commits

...

35 Commits

Author SHA1 Message Date
Neil Alexander
a9cfa5bc0d Merge pull request #610 from yggdrasil-network/develop
Version 0.3.12
2019-11-24 09:47:16 +00:00
Neil Alexander
ebef3045e2 Update CHANGELOG.md 2019-11-24 09:44:52 +00:00
Arceliar
117d44d008 Update CHANGELOG.md 2019-11-23 15:47:08 -06:00
Arceliar
07ce8cde7a Merge pull request #613 from neilalexander/mtuagain
Add API functions for manipulating maximum session MTU
2019-11-21 19:29:06 -06:00
Arceliar
248a08b2f1 send a message to the sessions to update mtu instead of trying to update it directly 2019-11-21 19:23:44 -06:00
Neil Alexander
d3a2087e0f Update changelog 2019-11-21 10:02:18 +00:00
Neil Alexander
7c18c6806d Further updates, notify sessions about updated MTU from API call 2019-11-21 09:54:36 +00:00
Neil Alexander
d1c445dc41 Thread safety for MTU API functions 2019-11-21 09:28:36 +00:00
Neil Alexander
e90be6f569 Add API functions for manipulating maximum session MTU, fix TUN/TAP to use that 2019-11-21 00:02:39 +00:00
Neil Alexander
789307d52b Merge pull request #612 from neilalexander/mtuagain
Fix couple of issues with MTU bounds
2019-11-20 22:43:46 +00:00
Neil Alexander
d06c40ad19 Use existing constant 2019-11-20 22:40:48 +00:00
Neil Alexander
9fca3640f9 Fix couple of issues with MTU calculations 2019-11-20 22:11:52 +00:00
Neil Alexander
ec46b217da Update CHANGELOG.md 2019-11-20 19:25:57 +00:00
Neil Alexander
b70fbfa0f1 Update changelog for v0.3.12 2019-11-20 19:25:45 +00:00
Arceliar
5b8e9182f0 Merge pull request #609 from neilalexander/genkeys
Move genkeys into cmd/
2019-11-19 19:40:44 -06:00
Arceliar
6b6a5a2906 Merge pull request #608 from neilalexander/mtu
Improve MTU handling
2019-11-19 19:37:25 -06:00
Arceliar
c0be481cde Merge pull request #605 from wfleurant/src-version
Src version: return unknown not yggdrasilctl
2019-11-19 19:35:45 -06:00
Neil Alexander
f984eaffab Merge pull request #597 from Arano-kai/bugfix/systemd_unit_typo
FIX: Systemd: typo in directive
2019-11-19 14:41:54 +00:00
Neil Alexander
4b9bce855e Only build yggdrasil/yggdrasilctl when running ./build 2019-11-19 14:37:16 +00:00
Neil Alexander
16a487cb1d Move genkeys into cmd/ as this allows 'go run github.com/yggdrasil-network/yggdrasil-go/cmd/genkeys' 2019-11-19 14:34:10 +00:00
Neil Alexander
f49d9de421 Fix setting up of MTU when value is outside of acceptable bounds, also account for ethernet headers in calculations, notify about clipping to stdout 2019-11-19 14:20:11 +00:00
Arceliar
17a711ab8a Merge pull request #606 from Arceliar/bugfix
fix deadlock when AddPeer fails
2019-11-12 21:08:36 -06:00
Arceliar
5f1aea3636 fix deadlock when AddPeer fails 2019-11-12 21:01:32 -06:00
Neil Alexander
f330f2f5bc Merge pull request #604 from neilalexander/addresssubnet
Add -address and -subnet command line options to cmd/yggdrasil
2019-11-11 09:42:23 +00:00
Neil Alexander
e310a25e59 Use crypto.GetNodeID instead of sha512 directly 2019-11-11 09:40:25 +00:00
William Fleurant
49ba5bae17 yggdrasil: buildName should report unknown 2019-11-11 00:24:50 -05:00
Neil Alexander
e3a5e4f3b7 Add -address and -subnet flag for getting address/subnet out of config 2019-11-10 19:38:35 +00:00
Arano-kai
74d824302b FIX: Systemd: typo in directive 2019-10-29 16:36:03 +02:00
Neil Alexander
1373800d26 Merge pull request #595 from Arceliar/race
Fix data race
2019-10-28 10:18:13 +00:00
Arceliar
6d3aefb825 fix a data race when an existing session's coords are updated in response to a successful search 2019-10-27 19:55:35 -05:00
Neil Alexander
cee28d11f8 Merge pull request #593 from Arceliar/bindtodevice
BindToDevice
2019-10-26 11:36:24 +01:00
Arceliar
710815fed5 add dummy functions for other platforms 2019-10-25 19:32:53 -05:00
Neil Alexander
76adfd166a Merge pull request #594 from Arceliar/bugfix
fix a crash when shutting down if no multicast interfaces are configured
2019-10-26 00:50:34 +01:00
Arceliar
cfc1e6b83d fix a crash when shutting down if no multicast interfaces are configured 2019-10-25 18:40:09 -05:00
Arceliar
bcacfb0638 test adding BindToDevice to linux. if it works then we'll want to rethink slightly how we get the tcpContext on every platform, to make this compile everywhere and look a little cleaner 2019-10-25 18:33:23 -05:00
20 changed files with 159 additions and 49 deletions

View File

@@ -25,6 +25,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- in case of vulnerabilities.
-->
## [0.3.12] - 2019-11-24
### Added
- 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
- On Linux, outgoing `InterfacePeers` connections now use `SO_BINDTODEVICE` to prefer an outgoing interface
- The `genkeys` utility is now in `cmd` rather than `misc`
### Fixed
- A data race condition has been fixed when updating session coordinates
- A crash when shutting down when no multicast interfaces are configured has been fixed
- A deadlock when calling `AddPeer` multiple times has been fixed
- A typo in the systemd unit file (for some Linux packages) has been fixed
- The NodeInfo and admin socket now report `unknown` correctly when no build name/version is available in the environment at build time
- The MTU calculation now correctly accounts for ethernet headers when running in TAP mode
## [0.3.11] - 2019-10-25
### Added

2
build
View File

@@ -44,7 +44,7 @@ elif [ $ANDROID ]; then
github.com/yggdrasil-network/yggdrasil-extras/src/mobile \
github.com/yggdrasil-network/yggdrasil-extras/src/dummy
else
for CMD in `ls cmd/` ; do
for CMD in yggdrasil yggdrasilctl ; do
echo "Building: $CMD"
go build $ARGS -ldflags="$LDFLAGS" -gcflags="$GCFLAGS" ./cmd/$CMD

View File

@@ -7,6 +7,7 @@ import (
"flag"
"fmt"
"io/ioutil"
"net"
"os"
"os/signal"
"strings"
@@ -20,6 +21,7 @@ import (
"github.com/kardianos/minwinsvc"
"github.com/mitchellh/mapstructure"
"github.com/yggdrasil-network/yggdrasil-go/src/address"
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
"github.com/yggdrasil-network/yggdrasil-go/src/config"
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
@@ -142,6 +144,8 @@ func main() {
ver := flag.Bool("version", false, "prints the version of this build")
logging := flag.String("logging", "info,warn,error", "comma-separated list of logging levels to enable")
logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"")
getaddr := flag.Bool("address", false, "returns the IPv6 address as derived from the supplied configuration")
getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration")
flag.Parse()
var cfg *config.NodeConfig
@@ -188,6 +192,35 @@ func main() {
if cfg == nil {
return
}
// Have we been asked for the node address yet? If so, print it and then stop.
getNodeID := func() *crypto.NodeID {
if pubkey, err := hex.DecodeString(cfg.EncryptionPublicKey); err == nil {
var box crypto.BoxPubKey
copy(box[:], pubkey[:])
return crypto.GetNodeID(&box)
}
return nil
}
switch {
case *getaddr:
if nodeid := getNodeID(); nodeid != nil {
addr := *address.AddrForNodeID(nodeid)
ip := net.IP(addr[:])
fmt.Println(ip.String())
}
return
case *getsnet:
if nodeid := getNodeID(); nodeid != nil {
snet := *address.SubnetForNodeID(nodeid)
ipnet := net.IPNet{
IP: append(snet[:], 0, 0, 0, 0, 0, 0, 0, 0),
Mask: net.CIDRMask(len(snet)*8, 128),
}
fmt.Println(ipnet.String())
}
return
default:
}
// Create a new logger that logs output to stdout.
var logger *log.Logger
switch *logto {

View File

@@ -8,7 +8,7 @@ Group=yggdrasil
ProtectHome=true
ProtectSystem=true
SyslogIdentifier=yggdrasil
CapabilityBoundSet=CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_ADMIN
ExecStartPre=+-/sbin/modprobe tun
ExecStartPre=/bin/sh -ec "if ! test -s /etc/yggdrasil.conf; \
then umask 077; \

View File

@@ -124,7 +124,9 @@ func (m *Multicast) _stop() error {
if m.platformhandler != nil {
m.platformhandler.Stop()
}
m.sock.Close()
if m.sock != nil {
m.sock.Close()
}
return nil
}

View File

@@ -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
@@ -63,9 +64,12 @@ type TunOptions struct {
// Gets the maximum supported MTU for the platform based on the defaults in
// defaults.GetDefaults().
func getSupportedMTU(mtu int) int {
if mtu > defaults.GetDefaults().MaximumIfMTU {
return defaults.GetDefaults().MaximumIfMTU
func getSupportedMTU(mtu int, istapmode bool) int {
if mtu < 1280 {
return 1280
}
if mtu > MaximumMTU(istapmode) {
return MaximumMTU(istapmode)
}
return mtu
}
@@ -80,7 +84,7 @@ func (tun *TunAdapter) Name() string {
// the maximum value is determined by your platform. The returned value will
// never exceed that of MaximumMTU().
func (tun *TunAdapter) MTU() int {
return getSupportedMTU(tun.mtu)
return getSupportedMTU(tun.mtu, tun.IsTAP())
}
// IsTAP returns true if the adapter is a TAP adapter (Layer 2) or false if it
@@ -97,7 +101,11 @@ func DefaultName() string {
// DefaultMTU gets the default TUN/TAP interface MTU for your platform. This can
// be as high as MaximumMTU(), depending on platform, but is never lower than 1280.
func DefaultMTU() int {
return defaults.GetDefaults().DefaultIfMTU
ehbytes := 0
if DefaultIsTAP() {
ehbytes = tun_ETHER_HEADER_LENGTH
}
return defaults.GetDefaults().DefaultIfMTU - ehbytes
}
// DefaultIsTAP returns true if the default adapter mode for the current
@@ -109,8 +117,12 @@ func DefaultIsTAP() bool {
// MaximumMTU returns the maximum supported TUN/TAP interface MTU for your
// platform. This can be as high as 65535, depending on platform, but is never
// lower than 1280.
func MaximumMTU() int {
return defaults.GetDefaults().MaximumIfMTU
func MaximumMTU(iftapmode bool) int {
ehbytes := 0
if iftapmode {
ehbytes = tun_ETHER_HEADER_LENGTH
}
return defaults.GetDefaults().MaximumIfMTU - ehbytes
}
// Init initialises the TUN/TAP module. You must have acquired a Listener from
@@ -120,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
@@ -159,24 +172,23 @@ func (tun *TunAdapter) _start() error {
nodeID := crypto.GetNodeID(&boxPub)
tun.addr = *address.AddrForNodeID(nodeID)
tun.subnet = *address.SubnetForNodeID(nodeID)
tun.mtu = current.IfMTU
ifname := current.IfName
iftapmode := current.IfTAPMode
addr := fmt.Sprintf("%s/%d", net.IP(tun.addr[:]).String(), 8*len(address.GetPrefix())-1)
if ifname != "none" {
if err := tun.setup(ifname, iftapmode, addr, tun.mtu); err != nil {
return err
}
}
if ifname == "none" || ifname == "dummy" {
if current.IfName == "none" || current.IfName == "dummy" {
tun.log.Debugln("Not starting TUN/TAP as ifname is none or dummy")
return nil
}
if err := tun.setup(current.IfName, current.IfTAPMode, addr, current.IfMTU); err != nil {
return err
}
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
tun.icmpv6.Init(tun)
if iftapmode {
if tun.IsTAP() {
go tun.icmpv6.Solicit(tun.addr)
}
tun.ckr.init(tun)
@@ -221,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)
}

View File

@@ -99,7 +99,7 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
panic(err)
}
tun.iface = iface
tun.mtu = getSupportedMTU(mtu)
tun.mtu = getSupportedMTU(mtu, iftapmode)
return tun.setupAddress(addr)
}

View File

@@ -18,7 +18,8 @@ import (
// Configures the "utun" adapter with the correct IPv6 address and MTU.
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
if iftapmode {
tun.log.Warnln("TAP mode is not supported on this platform, defaulting to TUN")
tun.log.Warnln("Warning: TAP mode is not supported on this platform, defaulting to TUN")
iftapmode = false
}
config := water.Config{DeviceType: water.TUN}
iface, err := water.New(config)
@@ -26,7 +27,7 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
panic(err)
}
tun.iface = iface
tun.mtu = getSupportedMTU(mtu)
tun.mtu = getSupportedMTU(mtu, iftapmode)
return tun.setupAddress(addr)
}

View File

@@ -26,15 +26,7 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
panic(err)
}
tun.iface = iface
tun.mtu = getSupportedMTU(mtu)
// The following check is specific to Linux, as the TAP driver only supports
// an MTU of 65535-14 to make room for the ethernet headers. This makes sure
// that the MTU gets rounded down to 65521 instead of causing a panic.
if iftapmode {
if tun.mtu > 65535-tun_ETHER_HEADER_LENGTH {
tun.mtu = 65535 - tun_ETHER_HEADER_LENGTH
}
}
tun.mtu = getSupportedMTU(mtu, iftapmode)
// Friendly output
tun.log.Infof("Interface name: %s", tun.iface.Name())
tun.log.Infof("Interface IPv6: %s", addr)

View File

@@ -21,13 +21,13 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
panic(err)
}
tun.iface = iface
tun.mtu = getSupportedMTU(mtu)
tun.mtu = getSupportedMTU(mtu, iftapmode)
return tun.setupAddress(addr)
}
// We don't know how to set the IPv6 address on an unknown platform, therefore
// write about it to stdout and don't try to do anything further.
func (tun *TunAdapter) setupAddress(addr string) error {
tun.log.Warnln("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr)
tun.log.Warnln("Warning: Platform not supported, you must set the address of", tun.iface.Name(), "to", addr)
return nil
}

View File

@@ -17,7 +17,8 @@ import (
// delegate the hard work to "netsh".
func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
if !iftapmode {
tun.log.Warnln("TUN mode is not supported on this platform, defaulting to TAP")
tun.log.Warnln("Warning: TUN mode is not supported on this platform, defaulting to TAP")
iftapmode = true
}
config := water.Config{DeviceType: water.TAP}
config.PlatformSpecificParams.ComponentID = "tap0901"
@@ -60,7 +61,7 @@ func (tun *TunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int
panic(err)
}
tun.iface = iface
tun.mtu = getSupportedMTU(mtu)
tun.mtu = getSupportedMTU(mtu, iftapmode)
err = tun.setupMTU(tun.mtu)
if err != nil {
panic(err)

View File

@@ -7,7 +7,7 @@ var buildVersion string
// from git, or returns "unknown" otherwise.
func BuildName() string {
if buildName == "" {
return "yggdrasilctl"
return "unknown"
}
return buildName
}

View File

@@ -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
@@ -424,6 +445,7 @@ func (c *Core) AddPeer(addr string, sintf string) error {
return err
}
c.config.Mutex.Lock()
defer c.config.Mutex.Unlock()
if sintf == "" {
for _, peer := range c.config.Current.Peers {
if peer == addr {
@@ -445,7 +467,6 @@ func (c *Core) AddPeer(addr string, sintf string) error {
c.config.Current.InterfacePeers[sintf] = append(c.config.Current.InterfacePeers[sintf], addr)
}
}
c.config.Mutex.Unlock()
return nil
}

View File

@@ -192,7 +192,7 @@ func (sinfo *searchInfo) checkDHTRes(res *dhtRes) bool {
finishSearch := func(sess *sessionInfo, err error) {
if sess != nil {
// FIXME (!) replay attacks could mess with coords? Give it a handle (tstamp)?
sess.coords = res.Coords
sess.Act(sinfo.searches.router, func() { sess.coords = res.Coords })
sess.ping(sinfo.searches.router)
}
if err != nil {

View File

@@ -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

View File

@@ -299,6 +299,7 @@ func (t *tcp) call(saddr string, options interface{}, sintf string, upgrade *Tcp
Timeout: time.Second * 5,
}
if sintf != "" {
dialer.Control = t.getControl(sintf)
ief, err := net.InterfaceByName(sintf)
if err != nil {
return

View File

@@ -26,3 +26,7 @@ func (t *tcp) tcpContext(network, address string, c syscall.RawConn) error {
return control
}
}
func (t *tcp) getControl(sintf string) func(string, string, syscall.RawConn) error {
return t.tcpContext
}

View File

@@ -29,3 +29,17 @@ func (t *tcp) tcpContext(network, address string, c syscall.RawConn) error {
// Return nil because errors here are not considered fatal for the connection, it just means congestion control is suboptimal
return nil
}
func (t *tcp) getControl(sintf string) func(string, string, syscall.RawConn) error {
return func(network, address string, c syscall.RawConn) error {
var err error
btd := func(fd uintptr) {
err = unix.BindToDevice(int(fd), sintf)
}
c.Control(btd)
if err != nil {
t.link.core.log.Debugln("Failed to set SO_BINDTODEVICE:", sintf)
}
return t.tcpContext(network, address, c)
}
}

View File

@@ -11,3 +11,7 @@ import (
func (t *tcp) tcpContext(network, address string, c syscall.RawConn) error {
return nil
}
func (t *tcp) getControl(sintf string) func(string, string, syscall.RawConn) error {
return t.tcpContext
}