From 047717abf2d06c8e72c799a89c33507a6f86a5c6 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 1 Apr 2019 18:02:06 +0100 Subject: [PATCH] Break out mobile and dummy adapter --- build | 4 +- src/dummy/dummy.go | 57 ++++++++ src/mobile/mobile.go | 143 ++++++++++++++++++++ src/{yggdrasil => mobile}/mobile_android.go | 2 +- src/{yggdrasil => mobile}/mobile_ios.go | 4 +- src/yggdrasil/core.go | 10 ++ src/yggdrasil/mobile.go | 130 ------------------ 7 files changed, 215 insertions(+), 135 deletions(-) create mode 100644 src/dummy/dummy.go create mode 100644 src/mobile/mobile.go rename src/{yggdrasil => mobile}/mobile_android.go (90%) rename src/{yggdrasil => mobile}/mobile_ios.go (97%) delete mode 100644 src/yggdrasil/mobile.go diff --git a/build b/build index f6c7246..127af75 100755 --- a/build +++ b/build @@ -28,10 +28,10 @@ fi if [ $IOS ]; then echo "Building framework for iOS" - gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil + gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/mobile elif [ $ANDROID ]; then echo "Building aar for Android" - gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil + gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/mobile else for CMD in `ls cmd/` ; do echo "Building: $CMD" diff --git a/src/dummy/dummy.go b/src/dummy/dummy.go new file mode 100644 index 0000000..a199eee --- /dev/null +++ b/src/dummy/dummy.go @@ -0,0 +1,57 @@ +package dummy + +import ( + "github.com/gologme/log" + "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/util" + "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" +) + +type DummyAdapter struct { + yggdrasil.Adapter + send chan<- []byte + recv <-chan []byte + reject <-chan yggdrasil.RejectedPacket +} + +// Init initialises the TUN/TAP adapter. +func (m *DummyAdapter) Init(config *config.NodeState, log *log.Logger, send chan<- []byte, recv <-chan []byte, reject <-chan yggdrasil.RejectedPacket) { + m.Adapter.Init(config, log, send, recv, reject) +} + +// Name returns the name of the adapter, e.g. "tun0". On Windows, this may +// return a canonical adapter name instead. +func (m *DummyAdapter) Name() string { + return "dummy" +} + +// MTU gets the adapter's MTU. This can range between 1280 and 65535, although +// the maximum value is determined by your platform. The returned value will +// never exceed that of MaximumMTU(). +func (m *DummyAdapter) MTU() int { + return 65535 +} + +// IsTAP returns true if the adapter is a TAP adapter (Layer 2) or false if it +// is a TUN adapter (Layer 3). +func (m *DummyAdapter) IsTAP() bool { + return false +} + +// Wait for a packet from the router. You will use this when implementing a +// dummy adapter in place of real TUN - when this call returns a packet, you +// will probably want to give it to the OS to write to TUN. +func (m *DummyAdapter) Recv() ([]byte, error) { + packet := <-m.recv + return packet, nil +} + +// Send a packet to the router. You will use this when implementing a +// dummy adapter in place of real TUN - when the operating system tells you +// that a new packet is available from TUN, call this function to give it to +// Yggdrasil. +func (m *DummyAdapter) Send(buf []byte) error { + packet := append(util.GetBytes(), buf[:]...) + m.send <- packet + return nil +} diff --git a/src/mobile/mobile.go b/src/mobile/mobile.go new file mode 100644 index 0000000..ecc4d65 --- /dev/null +++ b/src/mobile/mobile.go @@ -0,0 +1,143 @@ +package mobile + +import ( + "encoding/json" + "os" + "time" + + "github.com/gologme/log" + + hjson "github.com/hjson/hjson-go" + "github.com/mitchellh/mapstructure" + "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/dummy" + "github.com/yggdrasil-network/yggdrasil-go/src/multicast" + "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" +) + +// Yggdrasil's mobile package is meant to "plug the gap" for mobile support, as +// Gomobile will not create headers for Swift/Obj-C etc if they have complex +// (non-native) types. Therefore for iOS we will expose some nice simple +// functions. Note that in the case of iOS we handle reading/writing to/from TUN +// in Swift therefore we use the "dummy" TUN interface instead. +type Yggdrasil struct { + core *yggdrasil.Core + multicast *multicast.Multicast + dummy.DummyAdapter +} + +func (m *Yggdrasil) addStaticPeers(cfg *config.NodeConfig) { + if len(cfg.Peers) == 0 && len(cfg.InterfacePeers) == 0 { + return + } + for { + for _, peer := range cfg.Peers { + m.core.AddPeer(peer, "") + time.Sleep(time.Second) + } + for intf, intfpeers := range cfg.InterfacePeers { + for _, peer := range intfpeers { + m.core.AddPeer(peer, intf) + time.Sleep(time.Second) + } + } + time.Sleep(time.Minute) + } +} + +// StartAutoconfigure starts a node with a randomly generated config +func (m *Yggdrasil) StartAutoconfigure() error { + m.core = &yggdrasil.Core{} + //m.Adapter = dummy.DummyAdapter{} + mobilelog := MobileLogger{} + logger := log.New(mobilelog, "", 0) + nc := config.GenerateConfig() + nc.IfName = "dummy" + nc.AdminListen = "tcp://localhost:9001" + nc.Peers = []string{} + if hostname, err := os.Hostname(); err == nil { + nc.NodeInfo = map[string]interface{}{"name": hostname} + } + m.core.SetRouterAdapter(&m) + state, err := m.core.Start(nc, logger) + if err != nil { + return err + } + // Start the multicast interface + m.multicast.Init(m.core, state, logger, nil) + if err := m.multicast.Start(); err != nil { + logger.Errorln("An error occurred starting multicast:", err) + } + go m.addStaticPeers(nc) + return nil +} + +// StartJSON starts a node with the given JSON config. You can get JSON config +// (rather than HJSON) by using the GenerateConfigJSON() function +func (m *Yggdrasil) StartJSON(configjson []byte) error { + m.core = &yggdrasil.Core{} + //m.Adapter = dummy.DummyAdapter{} + mobilelog := MobileLogger{} + logger := log.New(mobilelog, "", 0) + nc := config.GenerateConfig() + var dat map[string]interface{} + if err := hjson.Unmarshal(configjson, &dat); err != nil { + return err + } + if err := mapstructure.Decode(dat, &nc); err != nil { + return err + } + nc.IfName = "dummy" + m.core.SetRouterAdapter(&m) + state, err := m.core.Start(nc, logger) + if err != nil { + return err + } + // Start the multicast interface + m.multicast.Init(m.core, state, logger, nil) + if err := m.multicast.Start(); err != nil { + logger.Errorln("An error occurred starting multicast:", err) + } + go m.addStaticPeers(nc) + return nil +} + +// Stops the mobile Yggdrasil instance +func (m *Yggdrasil) Stop() error { + m.core.Stop() + if err := m.Stop(); err != nil { + return err + } + return nil +} + +// GenerateConfigJSON generates mobile-friendly configuration in JSON format +func GenerateConfigJSON() []byte { + nc := config.GenerateConfig() + nc.IfName = "dummy" + if json, err := json.Marshal(nc); err == nil { + return json + } else { + return nil + } +} + +// GetAddressString gets the node's IPv6 address +func (m *Yggdrasil) GetAddressString() string { + return m.core.Address().String() +} + +// GetSubnetString gets the node's IPv6 subnet in CIDR notation +func (m *Yggdrasil) GetSubnetString() string { + return m.core.Subnet().String() +} + +// GetBoxPubKeyString gets the node's public encryption key +func (m *Yggdrasil) GetBoxPubKeyString() string { + return m.core.BoxPubKey() +} + +// GetSigPubKeyString gets the node's public signing key +func (m *Yggdrasil) GetSigPubKeyString() string { + return m.core.SigPubKey() +} diff --git a/src/yggdrasil/mobile_android.go b/src/mobile/mobile_android.go similarity index 90% rename from src/yggdrasil/mobile_android.go rename to src/mobile/mobile_android.go index 2476484..f3206ac 100644 --- a/src/yggdrasil/mobile_android.go +++ b/src/mobile/mobile_android.go @@ -1,6 +1,6 @@ // +build android -package yggdrasil +package mobile import "log" diff --git a/src/yggdrasil/mobile_ios.go b/src/mobile/mobile_ios.go similarity index 97% rename from src/yggdrasil/mobile_ios.go rename to src/mobile/mobile_ios.go index 96d2fc0..26b219c 100644 --- a/src/yggdrasil/mobile_ios.go +++ b/src/mobile/mobile_ios.go @@ -1,6 +1,6 @@ -// +build mobile,darwin +// +build darwin -package yggdrasil +package mobile /* #cgo CFLAGS: -x objective-c diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 9634a42..fcee124 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -280,6 +280,16 @@ func (c *Core) TreeID() *crypto.TreeID { return crypto.GetTreeID(&c.sigPub) } +// SigPubKey gets the node's signing public key. +func (c *Core) SigPubKey() string { + return hex.EncodeToString(c.sigPub[:]) +} + +// BoxPubKey gets the node's encryption public key. +func (c *Core) BoxPubKey() string { + return hex.EncodeToString(c.boxPub[:]) +} + // Address gets the IPv6 address of the Yggdrasil node. This is always a /128 // address. func (c *Core) Address() *net.IP { diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go deleted file mode 100644 index 0c6686d..0000000 --- a/src/yggdrasil/mobile.go +++ /dev/null @@ -1,130 +0,0 @@ -// +build mobile - -package yggdrasil - -import ( - "encoding/hex" - "encoding/json" - "os" - "time" - - "github.com/gologme/log" - - hjson "github.com/hjson/hjson-go" - "github.com/mitchellh/mapstructure" - "github.com/yggdrasil-network/yggdrasil-go/src/config" - "github.com/yggdrasil-network/yggdrasil-go/src/util" -) - -// This file is meant to "plug the gap" for mobile support, as Gomobile will -// not create headers for Swift/Obj-C etc if they have complex (non-native) -// types. Therefore for iOS we will expose some nice simple functions. Note -// that in the case of iOS we handle reading/writing to/from TUN in Swift -// therefore we use the "dummy" TUN interface instead. - -func (c *Core) addStaticPeers(cfg *config.NodeConfig) { - if len(cfg.Peers) == 0 && len(cfg.InterfacePeers) == 0 { - return - } - for { - for _, peer := range cfg.Peers { - c.AddPeer(peer, "") - time.Sleep(time.Second) - } - for intf, intfpeers := range cfg.InterfacePeers { - for _, peer := range intfpeers { - c.AddPeer(peer, intf) - time.Sleep(time.Second) - } - } - time.Sleep(time.Minute) - } -} - -// Starts a node with a randomly generated config. -func (c *Core) StartAutoconfigure() error { - mobilelog := MobileLogger{} - logger := log.New(mobilelog, "", 0) - nc := config.GenerateConfig() - nc.IfName = "dummy" - nc.AdminListen = "tcp://localhost:9001" - nc.Peers = []string{} - if hostname, err := os.Hostname(); err == nil { - nc.NodeInfo = map[string]interface{}{"name": hostname} - } - if _, err := c.Start(nc, logger); err != nil { - return err - } - go c.addStaticPeers(nc) - return nil -} - -// Starts a node with the given JSON config. You can get JSON config (rather -// than HJSON) by using the GenerateConfigJSON() function. -func (c *Core) StartJSON(configjson []byte) error { - mobilelog := MobileLogger{} - logger := log.New(mobilelog, "", 0) - nc := config.GenerateConfig() - var dat map[string]interface{} - if err := hjson.Unmarshal(configjson, &dat); err != nil { - return err - } - if err := mapstructure.Decode(dat, &nc); err != nil { - return err - } - nc.IfName = "dummy" - if _, err := c.Start(nc, logger); err != nil { - return err - } - go c.addStaticPeers(nc) - return nil -} - -// Generates mobile-friendly configuration in JSON format. -func GenerateConfigJSON() []byte { - nc := config.GenerateConfig() - nc.IfName = "dummy" - if json, err := json.Marshal(nc); err == nil { - return json - } else { - return nil - } -} - -// Gets the node's IPv6 address. -func (c *Core) GetAddressString() string { - return c.Address().String() -} - -// Gets the node's IPv6 subnet in CIDR notation. -func (c *Core) GetSubnetString() string { - return c.Subnet().String() -} - -// Gets the node's public encryption key. -func (c *Core) GetBoxPubKeyString() string { - return hex.EncodeToString(c.boxPub[:]) -} - -// Gets the node's public signing key. -func (c *Core) GetSigPubKeyString() string { - return hex.EncodeToString(c.sigPub[:]) -} - -// Wait for a packet from the router. You will use this when implementing a -// dummy adapter in place of real TUN - when this call returns a packet, you -// will probably want to give it to the OS to write to TUN. -func (c *Core) RouterRecvPacket() ([]byte, error) { - packet := <-c.router.recv - return packet, nil -} - -// Send a packet to the router. You will use this when implementing a -// dummy adapter in place of real TUN - when the operating system tells you -// that a new packet is available from TUN, call this function to give it to -// Yggdrasil. -func (c *Core) RouterSendPacket(buf []byte) error { - packet := append(util.GetBytes(), buf[:]...) - c.router.send <- packet - return nil -}