From 53aeca8fa27ee8207081cedc67a0cf8c90ab7774 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 1 Jan 2019 23:25:20 +0000 Subject: [PATCH 01/15] Add some simple functions for Swift bindings (iOS) --- cmd/yggdrasil/main.go | 65 +++++++--------------------------------- src/config/config.go | 52 ++++++++++++++++++++++++++++++++ src/yggdrasil/adapter.go | 9 ------ src/yggdrasil/ios.go | 51 +++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 64 deletions(-) create mode 100644 src/yggdrasil/ios.go diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 2b6d2f0..43cf77a 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -2,13 +2,11 @@ package main import ( "bytes" - "encoding/hex" "encoding/json" "flag" "fmt" "io/ioutil" "log" - "math/rand" "os" "os/signal" "regexp" @@ -23,7 +21,6 @@ import ( "github.com/mitchellh/mapstructure" "github.com/yggdrasil-network/yggdrasil-go/src/config" - "github.com/yggdrasil-network/yggdrasil-go/src/defaults" "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" ) @@ -34,52 +31,10 @@ type node struct { core Core } -// Generates default configuration. This is used when outputting the -genconf -// parameter and also when using -autoconf. The isAutoconf flag is used to -// determine whether the operating system should select a free port by itself -// (which guarantees that there will not be a conflict with any other services) -// or whether to generate a random port number. The only side effect of setting -// isAutoconf is that the TCP and UDP ports will likely end up with different -// port numbers. -func generateConfig(isAutoconf bool) *nodeConfig { - // Create a new core. - core := Core{} - // Generate encryption keys. - bpub, bpriv := core.NewEncryptionKeys() - spub, spriv := core.NewSigningKeys() - // Create a node configuration and populate it. - cfg := nodeConfig{} - if isAutoconf { - cfg.Listen = "[::]:0" - } else { - r1 := rand.New(rand.NewSource(time.Now().UnixNano())) - cfg.Listen = fmt.Sprintf("[::]:%d", r1.Intn(65534-32768)+32768) - } - cfg.AdminListen = defaults.GetDefaults().DefaultAdminListen - cfg.EncryptionPublicKey = hex.EncodeToString(bpub[:]) - cfg.EncryptionPrivateKey = hex.EncodeToString(bpriv[:]) - cfg.SigningPublicKey = hex.EncodeToString(spub[:]) - cfg.SigningPrivateKey = hex.EncodeToString(spriv[:]) - cfg.Peers = []string{} - cfg.InterfacePeers = map[string][]string{} - cfg.AllowedEncryptionPublicKeys = []string{} - cfg.MulticastInterfaces = []string{".*"} - cfg.IfName = defaults.GetDefaults().DefaultIfName - cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU - cfg.IfTAPMode = defaults.GetDefaults().DefaultIfTAPMode - cfg.SessionFirewall.Enable = false - cfg.SessionFirewall.AllowFromDirect = true - cfg.SessionFirewall.AllowFromRemote = true - cfg.SwitchOptions.MaxTotalQueueSize = yggdrasil.SwitchQueueTotalMinSize - cfg.NodeInfoPrivacy = false - - return &cfg -} - // Generates a new configuration and returns it in HJSON format. This is used // with -genconf. func doGenconf(isjson bool) string { - cfg := generateConfig(false) + cfg := config.GenerateConfig(false) var bs []byte var err error if isjson { @@ -114,19 +69,19 @@ func main() { case *autoconf: // Use an autoconf-generated config, this will give us random keys and // port numbers, and will use an automatically selected TUN/TAP interface. - cfg = generateConfig(true) + cfg = config.GenerateConfig(true) case *useconffile != "" || *useconf: // Use a configuration file. If -useconf, the configuration will be read // from stdin. If -useconffile, the configuration will be read from the // filesystem. - var config []byte + var configjson []byte var err error if *useconffile != "" { // Read the file from the filesystem - config, err = ioutil.ReadFile(*useconffile) + configjson, err = ioutil.ReadFile(*useconffile) } else { // Read the file from stdin. - config, err = ioutil.ReadAll(os.Stdin) + configjson, err = ioutil.ReadAll(os.Stdin) } if err != nil { panic(err) @@ -135,11 +90,11 @@ func main() { // throwing everywhere when it's converting things into UTF-16 for the hell // of it - remove it and decode back down into UTF-8. This is necessary // because hjson doesn't know what to do with UTF-16 and will panic - if bytes.Compare(config[0:2], []byte{0xFF, 0xFE}) == 0 || - bytes.Compare(config[0:2], []byte{0xFE, 0xFF}) == 0 { + if bytes.Compare(configjson[0:2], []byte{0xFF, 0xFE}) == 0 || + bytes.Compare(configjson[0:2], []byte{0xFE, 0xFF}) == 0 { utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM) decoder := utf.NewDecoder() - config, err = decoder.Bytes(config) + configjson, err = decoder.Bytes(configjson) if err != nil { panic(err) } @@ -148,9 +103,9 @@ func main() { // then parse the configuration we loaded above on top of it. The effect // of this is that any configuration item that is missing from the provided // configuration will use a sane default. - cfg = generateConfig(false) + cfg = config.GenerateConfig(false) var dat map[string]interface{} - if err := hjson.Unmarshal(config, &dat); err != nil { + if err := hjson.Unmarshal(configjson, &dat); err != nil { panic(err) } confJson, err := json.Marshal(dat) diff --git a/src/config/config.go b/src/config/config.go index 192f435..192b94e 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -1,5 +1,15 @@ package config +import ( + "encoding/hex" + "fmt" + "math/rand" + "time" + + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "github.com/yggdrasil-network/yggdrasil-go/src/defaults" +) + // NodeConfig defines all configuration values needed to run a signle yggdrasil node type NodeConfig struct { Listen string `comment:"Listen address for peer connections. Default is to listen for all\nTCP connections over IPv4 and IPv6 with a random port."` @@ -53,3 +63,45 @@ type TunnelRouting struct { type SwitchOptions struct { MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined (in bytes)."` } + +// Generates default configuration. This is used when outputting the -genconf +// parameter and also when using -autoconf. The isAutoconf flag is used to +// determine whether the operating system should select a free port by itself +// (which guarantees that there will not be a conflict with any other services) +// or whether to generate a random port number. The only side effect of setting +// isAutoconf is that the TCP and UDP ports will likely end up with different +// port numbers. +func GenerateConfig(isAutoconf bool) *NodeConfig { + // Create a new core. + //core := Core{} + // Generate encryption keys. + bpub, bpriv := crypto.NewBoxKeys() + spub, spriv := crypto.NewSigKeys() + // Create a node configuration and populate it. + cfg := NodeConfig{} + if isAutoconf { + cfg.Listen = "[::]:0" + } else { + r1 := rand.New(rand.NewSource(time.Now().UnixNano())) + cfg.Listen = fmt.Sprintf("[::]:%d", r1.Intn(65534-32768)+32768) + } + cfg.AdminListen = defaults.GetDefaults().DefaultAdminListen + cfg.EncryptionPublicKey = hex.EncodeToString(bpub[:]) + cfg.EncryptionPrivateKey = hex.EncodeToString(bpriv[:]) + cfg.SigningPublicKey = hex.EncodeToString(spub[:]) + cfg.SigningPrivateKey = hex.EncodeToString(spriv[:]) + cfg.Peers = []string{} + cfg.InterfacePeers = map[string][]string{} + cfg.AllowedEncryptionPublicKeys = []string{} + cfg.MulticastInterfaces = []string{".*"} + cfg.IfName = defaults.GetDefaults().DefaultIfName + cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU + cfg.IfTAPMode = defaults.GetDefaults().DefaultIfTAPMode + cfg.SessionFirewall.Enable = false + cfg.SessionFirewall.AllowFromDirect = true + cfg.SessionFirewall.AllowFromRemote = true + cfg.SwitchOptions.MaxTotalQueueSize = 4 * 1024 * 1024 + cfg.NodeInfoPrivacy = false + + return &cfg +} diff --git a/src/yggdrasil/adapter.go b/src/yggdrasil/adapter.go index 4a43209..7fb6a19 100644 --- a/src/yggdrasil/adapter.go +++ b/src/yggdrasil/adapter.go @@ -1,17 +1,8 @@ package yggdrasil -// Defines the minimum required functions for an adapter type. -type AdapterInterface interface { - init(core *Core, send chan<- []byte, recv <-chan []byte) - read() error - write() error - close() error -} - // Defines the minimum required struct members for an adapter type (this is // now the base type for tunAdapter in tun.go) type Adapter struct { - AdapterInterface core *Core send chan<- []byte recv <-chan []byte diff --git a/src/yggdrasil/ios.go b/src/yggdrasil/ios.go new file mode 100644 index 0000000..5f32a85 --- /dev/null +++ b/src/yggdrasil/ios.go @@ -0,0 +1,51 @@ +// +build mobile + +package yggdrasil + +import ( + "log" + "os" + "regexp" + + "github.com/yggdrasil-network/yggdrasil-go/src/config" +) + +// This file is meant to "plug the gap" for Gomobile support, as Gomobile +// will not create headers for Swift/Obj-C if they have complex (read: non- +// native) types. Therefore for iOS we will expose some nice simple functions +// to do what we need to do. + +func (c *Core) StartAutoconfigure() error { + logger := log.New(os.Stdout, "", 0) + //logger.Println("Created logger") + //c := Core{} + //logger.Println("Created Core") + nc := config.GenerateConfig(true) + //logger.Println("Generated config") + nc.IfName = "none" + nc.AdminListen = "tcp://[::]:9001" + nc.Peers = []string{} + //logger.Println("Set some config options") + ifceExpr, err := regexp.Compile(".*") + if err == nil { + c.ifceExpr = append(c.ifceExpr, ifceExpr) + } + //logger.Println("Added multicast interface") + if err := c.Start(nc, logger); err != nil { + return err + } + //logger.Println("Started") + address := c.GetAddress() + subnet := c.GetSubnet() + logger.Printf("Your IPv6 address is %s", address.String()) + logger.Printf("Your IPv6 subnet is %s", subnet.String()) + return nil +} + +func (c *Core) GetAddressString() string { + return c.GetAddress().String() +} + +func (c *Core) GetSubetString() string { + return c.GetSubnet().String() +} From 4ff3db2309c61aff8c3aa3c263517ac9bf92c51f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 2 Jan 2019 18:05:54 +0000 Subject: [PATCH 02/15] Add dummy tun, helper functions --- src/yggdrasil/ios.go | 51 --------------------------------- src/yggdrasil/mobile.go | 56 +++++++++++++++++++++++++++++++++++++ src/yggdrasil/tun.go | 10 ++++--- src/yggdrasil/tun_darwin.go | 2 ++ src/yggdrasil/tun_dummy.go | 19 +++++++++++++ src/yggdrasil/tun_linux.go | 2 ++ src/yggdrasil/tun_other.go | 2 +- 7 files changed, 86 insertions(+), 56 deletions(-) delete mode 100644 src/yggdrasil/ios.go create mode 100644 src/yggdrasil/mobile.go create mode 100644 src/yggdrasil/tun_dummy.go diff --git a/src/yggdrasil/ios.go b/src/yggdrasil/ios.go deleted file mode 100644 index 5f32a85..0000000 --- a/src/yggdrasil/ios.go +++ /dev/null @@ -1,51 +0,0 @@ -// +build mobile - -package yggdrasil - -import ( - "log" - "os" - "regexp" - - "github.com/yggdrasil-network/yggdrasil-go/src/config" -) - -// This file is meant to "plug the gap" for Gomobile support, as Gomobile -// will not create headers for Swift/Obj-C if they have complex (read: non- -// native) types. Therefore for iOS we will expose some nice simple functions -// to do what we need to do. - -func (c *Core) StartAutoconfigure() error { - logger := log.New(os.Stdout, "", 0) - //logger.Println("Created logger") - //c := Core{} - //logger.Println("Created Core") - nc := config.GenerateConfig(true) - //logger.Println("Generated config") - nc.IfName = "none" - nc.AdminListen = "tcp://[::]:9001" - nc.Peers = []string{} - //logger.Println("Set some config options") - ifceExpr, err := regexp.Compile(".*") - if err == nil { - c.ifceExpr = append(c.ifceExpr, ifceExpr) - } - //logger.Println("Added multicast interface") - if err := c.Start(nc, logger); err != nil { - return err - } - //logger.Println("Started") - address := c.GetAddress() - subnet := c.GetSubnet() - logger.Printf("Your IPv6 address is %s", address.String()) - logger.Printf("Your IPv6 subnet is %s", subnet.String()) - return nil -} - -func (c *Core) GetAddressString() string { - return c.GetAddress().String() -} - -func (c *Core) GetSubetString() string { - return c.GetSubnet().String() -} diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go new file mode 100644 index 0000000..9142c36 --- /dev/null +++ b/src/yggdrasil/mobile.go @@ -0,0 +1,56 @@ +// +build mobile + +package yggdrasil + +import ( + "log" + "os" + "regexp" + + "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) StartAutoconfigure() error { + logger := log.New(os.Stdout, "", 0) + nc := config.GenerateConfig(true) + nc.IfName = "dummy" + nc.AdminListen = "tcp://[::]:9001" + nc.Peers = []string{} + if hostname, err := os.Hostname(); err == nil { + nc.NodeInfo = map[string]interface{}{"name": hostname} + } + ifceExpr, err := regexp.Compile(".*") + if err == nil { + c.ifceExpr = append(c.ifceExpr, ifceExpr) + } + if err := c.Start(nc, logger); err != nil { + return err + } + return nil +} + +func (c *Core) GetAddressString() string { + return c.GetAddress().String() +} + +func (c *Core) GetSubnetString() string { + return c.GetSubnet().String() +} + +func (c *Core) RouterRecvPacket() ([]byte, error) { + packet := <-c.router.tun.recv + return packet, nil +} + +func (c *Core) RouterSendPacket(buf []byte) error { + packet := append(util.GetBytes(), buf[:]...) + c.router.tun.send <- packet + return nil +} diff --git a/src/yggdrasil/tun.go b/src/yggdrasil/tun.go index 8ed5333..8c0f91d 100644 --- a/src/yggdrasil/tun.go +++ b/src/yggdrasil/tun.go @@ -47,11 +47,13 @@ func (tun *tunAdapter) init(core *Core, send chan<- []byte, recv <-chan []byte) // Starts the setup process for the TUN/TAP adapter, and if successful, starts // the read/write goroutines to handle packets on that interface. func (tun *tunAdapter) start(ifname string, iftapmode bool, addr string, mtu int) error { - if ifname == "none" { - return nil + if ifname != "none" { + if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil { + return err + } } - if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil { - return err + if ifname == "none" || ifname == "dummy" { + return nil } tun.mutex.Lock() tun.isOpen = true diff --git a/src/yggdrasil/tun_darwin.go b/src/yggdrasil/tun_darwin.go index 943468e..828c01e 100644 --- a/src/yggdrasil/tun_darwin.go +++ b/src/yggdrasil/tun_darwin.go @@ -1,3 +1,5 @@ +// +build !mobile + package yggdrasil // The darwin platform specific tun parts diff --git a/src/yggdrasil/tun_dummy.go b/src/yggdrasil/tun_dummy.go new file mode 100644 index 0000000..234ab1d --- /dev/null +++ b/src/yggdrasil/tun_dummy.go @@ -0,0 +1,19 @@ +// +build mobile + +package yggdrasil + +// This is to catch unsupported platforms +// If your platform supports tun devices, you could try configuring it manually + +// Creates the TUN/TAP adapter, if supported by the Water library. Note that +// no guarantees are made at this point on an unsupported platform. +func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error { + tun.mtu = getSupportedMTU(mtu) + 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 { + return nil +} diff --git a/src/yggdrasil/tun_linux.go b/src/yggdrasil/tun_linux.go index 7a7c9cb..8ccdd30 100644 --- a/src/yggdrasil/tun_linux.go +++ b/src/yggdrasil/tun_linux.go @@ -1,3 +1,5 @@ +// +build !mobile + package yggdrasil // The linux platform specific tun parts diff --git a/src/yggdrasil/tun_other.go b/src/yggdrasil/tun_other.go index 625f9cd..22058c1 100644 --- a/src/yggdrasil/tun_other.go +++ b/src/yggdrasil/tun_other.go @@ -1,4 +1,4 @@ -// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd +// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd,!mobile package yggdrasil From f7b0a85b5e19d8e95a15629f54c640a6f5eec10a Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 2 Jan 2019 23:15:36 +0000 Subject: [PATCH 03/15] Add StartJSON --- src/yggdrasil/mobile.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index 9142c36..c4bc8de 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -7,6 +7,8 @@ import ( "os" "regexp" + 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" ) @@ -36,6 +38,23 @@ func (c *Core) StartAutoconfigure() error { return nil } +func (c *Core) StartJSON(configjson []byte) error { + logger := log.New(os.Stdout, "", 0) + nc := config.GenerateConfig(false) + 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 + } + return nil +} + func (c *Core) GetAddressString() string { return c.GetAddress().String() } From d10a0d6137811991d7c791a0a21f0eac7d36dd21 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 3 Jan 2019 22:50:08 +0000 Subject: [PATCH 04/15] Add GenerateConfigJSON, fix StartJSON --- src/yggdrasil/mobile.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index c4bc8de..f579f53 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -3,6 +3,7 @@ package yggdrasil import ( + "encoding/json" "log" "os" "regexp" @@ -23,7 +24,7 @@ func (c *Core) StartAutoconfigure() error { logger := log.New(os.Stdout, "", 0) nc := config.GenerateConfig(true) nc.IfName = "dummy" - nc.AdminListen = "tcp://[::]:9001" + nc.AdminListen = "tcp://localhost:9001" nc.Peers = []string{} if hostname, err := os.Hostname(); err == nil { nc.NodeInfo = map[string]interface{}{"name": hostname} @@ -49,12 +50,29 @@ func (c *Core) StartJSON(configjson []byte) error { return err } nc.IfName = "dummy" + for _, ll := range nc.MulticastInterfaces { + ifceExpr, err := regexp.Compile(ll) + if err != nil { + panic(err) + } + c.AddMulticastInterfaceExpr(ifceExpr) + } if err := c.Start(nc, logger); err != nil { return err } return nil } +func GenerateConfigJSON() []byte { + nc := config.GenerateConfig(false) + nc.IfName = "dummy" + if json, err := json.Marshal(nc); err == nil { + return json + } else { + return nil + } +} + func (c *Core) GetAddressString() string { return c.GetAddress().String() } From f29a098488d885ea16db01879a7cc75b73b796e3 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 4 Jan 2019 17:14:40 +0000 Subject: [PATCH 05/15] Add experimental dummy interface for AWDL --- build | 7 +++- src/yggdrasil/awdl.go | 86 +++++++++++++++++++++++++++++++++++++++++ src/yggdrasil/core.go | 6 +++ src/yggdrasil/mobile.go | 9 +++++ 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 src/yggdrasil/awdl.go diff --git a/build b/build index e463c85..a3a679f 100755 --- a/build +++ b/build @@ -6,12 +6,13 @@ PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)} LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER" -while getopts "udtc:l:" option +while getopts "udmtc:l:" option do case "${option}" in u) UPX=true;; d) DEBUG=true;; + m) MOBILE=true;; t) TABLES=true;; c) GCFLAGS="$GCFLAGS $OPTARG";; l) LDFLAGS="$LDFLAGS $OPTARG";; @@ -25,7 +26,9 @@ fi for CMD in `ls cmd/` ; do echo "Building: $CMD" - if [ $DEBUG ]; then + if [ $MOBILE ]; then + go build -ldflags="$LDFLAGS" -gcflags="$GCFLAGS" -tags mobile -v ./cmd/$CMD + elif [ $DEBUG ]; then go build -ldflags="$LDFLAGS" -gcflags="$GCFLAGS" -tags debug -v ./cmd/$CMD else go build -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" -v ./cmd/$CMD diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go new file mode 100644 index 0000000..b07c2fc --- /dev/null +++ b/src/yggdrasil/awdl.go @@ -0,0 +1,86 @@ +package yggdrasil + +import ( + "sync" + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" +) + +type awdl struct { + core *Core + mutex sync.RWMutex // protects interfaces below + interfaces map[string]*awdlInterface +} + +type awdlInterface struct { + awdl *awdl + recv <-chan []byte // traffic received from the network + send chan<- []byte // traffic to send to the network + shutdown chan bool + peer *peer +} + +func (l *awdl) init(c *Core) error { + l.core = c + l.mutex.Lock() + l.interfaces = make(map[string]*awdlInterface) + l.mutex.Unlock() + + return nil +} + +func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, name string) *awdlInterface { + shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey) + intf := awdlInterface{ + recv: make(<-chan []byte), + send: make(chan<- []byte), + shutdown: make(chan bool), + peer: l.core.peers.newPeer(boxPubKey, sigPubKey, shared, name), + } + if intf.peer != nil { + l.mutex.Lock() + l.interfaces[name] = &intf + l.mutex.Unlock() + intf.peer.linkOut = make(chan []byte, 1) // protocol traffic + intf.peer.out = func(msg []byte) { + defer func() { recover() }() + intf.send <- msg + } + go intf.handler() + l.core.switchTable.idleIn <- intf.peer.port + return &intf + } + return nil +} + +func (l *awdl) getInterface(identity string) *awdlInterface { + l.mutex.RLock() + defer l.mutex.RUnlock() + if intf, ok := l.interfaces[identity]; ok { + return intf + } + return nil +} + +func (l *awdl) shutdown(identity string) { + if intf, ok := l.interfaces[identity]; ok { + intf.shutdown <- true + l.core.peers.removePeer(intf.peer.port) + l.mutex.Lock() + delete(l.interfaces, identity) + l.mutex.Unlock() + } +} + +func (ai *awdlInterface) handler() { + for { + select { + case p := <-ai.peer.linkOut: + ai.send <- p + case r := <-ai.recv: // traffic received from AWDL + ai.peer.handlePacket(r) + case <-ai.shutdown: + return + default: + } + } +} diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index e38274f..b99d1f2 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -35,6 +35,7 @@ type Core struct { multicast multicast nodeinfo nodeinfo tcp tcpInterface + awdl awdl log *log.Logger ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this } @@ -132,6 +133,11 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { return err } + if err := c.awdl.init(c); err != nil { + c.log.Println("Failed to start AWDL interface") + return err + } + if nc.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize { c.switchTable.queueTotalMaxSize = nc.SwitchOptions.MaxTotalQueueSize } diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index f579f53..36a98ea 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -11,6 +11,7 @@ import ( 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/crypto" "github.com/yggdrasil-network/yggdrasil-go/src/util" ) @@ -91,3 +92,11 @@ func (c *Core) RouterSendPacket(buf []byte) error { c.router.tun.send <- packet return nil } + +func (c *Core) AWDLCreateInterface(boxPubKey []byte, sigPubKey []byte, name string) { + var box crypto.BoxPubKey + var sig crypto.SigPubKey + copy(box[:crypto.BoxPubKeyLen], boxPubKey[:]) + copy(sig[:crypto.SigPubKeyLen], sigPubKey[:]) + c.awdl.create(&box, &sig, name) +} From 3878197a59aa51b6713f1e95531956591d1549c1 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 4 Jan 2019 17:23:37 +0000 Subject: [PATCH 06/15] gofmt --- src/yggdrasil/awdl.go | 121 +++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index b07c2fc..da10d58 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -1,86 +1,87 @@ package yggdrasil import ( - "sync" - "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "sync" + + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" ) type awdl struct { - core *Core - mutex sync.RWMutex // protects interfaces below - interfaces map[string]*awdlInterface + core *Core + mutex sync.RWMutex // protects interfaces below + interfaces map[string]*awdlInterface } type awdlInterface struct { - awdl *awdl - recv <-chan []byte // traffic received from the network - send chan<- []byte // traffic to send to the network - shutdown chan bool - peer *peer + awdl *awdl + recv <-chan []byte // traffic received from the network + send chan<- []byte // traffic to send to the network + shutdown chan bool + peer *peer } func (l *awdl) init(c *Core) error { - l.core = c - l.mutex.Lock() - l.interfaces = make(map[string]*awdlInterface) - l.mutex.Unlock() + l.core = c + l.mutex.Lock() + l.interfaces = make(map[string]*awdlInterface) + l.mutex.Unlock() - return nil + return nil } func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, name string) *awdlInterface { - shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey) - intf := awdlInterface{ - recv: make(<-chan []byte), - send: make(chan<- []byte), - shutdown: make(chan bool), - peer: l.core.peers.newPeer(boxPubKey, sigPubKey, shared, name), - } - if intf.peer != nil { - l.mutex.Lock() - l.interfaces[name] = &intf - l.mutex.Unlock() - intf.peer.linkOut = make(chan []byte, 1) // protocol traffic - intf.peer.out = func(msg []byte) { - defer func() { recover() }() - intf.send <- msg - } - go intf.handler() - l.core.switchTable.idleIn <- intf.peer.port - return &intf - } - return nil + shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey) + intf := awdlInterface{ + recv: make(<-chan []byte), + send: make(chan<- []byte), + shutdown: make(chan bool), + peer: l.core.peers.newPeer(boxPubKey, sigPubKey, shared, name), + } + if intf.peer != nil { + l.mutex.Lock() + l.interfaces[name] = &intf + l.mutex.Unlock() + intf.peer.linkOut = make(chan []byte, 1) + intf.peer.out = func(msg []byte) { + defer func() { recover() }() + intf.send <- msg + } + go intf.handler() + l.core.switchTable.idleIn <- intf.peer.port + return &intf + } + return nil } func (l *awdl) getInterface(identity string) *awdlInterface { - l.mutex.RLock() - defer l.mutex.RUnlock() - if intf, ok := l.interfaces[identity]; ok { - return intf - } - return nil + l.mutex.RLock() + defer l.mutex.RUnlock() + if intf, ok := l.interfaces[identity]; ok { + return intf + } + return nil } func (l *awdl) shutdown(identity string) { - if intf, ok := l.interfaces[identity]; ok { - intf.shutdown <- true - l.core.peers.removePeer(intf.peer.port) - l.mutex.Lock() - delete(l.interfaces, identity) - l.mutex.Unlock() - } + if intf, ok := l.interfaces[identity]; ok { + intf.shutdown <- true + l.core.peers.removePeer(intf.peer.port) + l.mutex.Lock() + delete(l.interfaces, identity) + l.mutex.Unlock() + } } func (ai *awdlInterface) handler() { - for { - select { - case p := <-ai.peer.linkOut: - ai.send <- p - case r := <-ai.recv: // traffic received from AWDL - ai.peer.handlePacket(r) - case <-ai.shutdown: - return - default: - } - } + for { + select { + case p := <-ai.peer.linkOut: + ai.send <- p + case r := <-ai.recv: // traffic received from AWDL + ai.peer.handlePacket(r) + case <-ai.shutdown: + return + default: + } + } } From 5a36b4723ab662fbfeb6aba4d8e7124404d2956d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 4 Jan 2019 17:41:03 +0000 Subject: [PATCH 07/15] Add AWDL calls to exposed API, handle proto traffic first --- src/yggdrasil/awdl.go | 15 +++++++++++++++ src/yggdrasil/mobile.go | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index da10d58..84cd3fb 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -74,9 +74,24 @@ func (l *awdl) shutdown(identity string) { func (ai *awdlInterface) handler() { for { + /*timerInterval := tcp_ping_interval + timer := time.NewTimer(timerInterval) + defer timer.Stop()*/ select { case p := <-ai.peer.linkOut: ai.send <- p + continue + default: + } + /*timer.Stop() + select { + case <-timer.C: + default: + } + timer.Reset(timerInterval)*/ + select { + //case _ = <-timer.C: + // ai.send <- nil case r := <-ai.recv: // traffic received from AWDL ai.peer.handlePacket(r) case <-ai.shutdown: diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index 36a98ea..44886f8 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -4,6 +4,7 @@ package yggdrasil import ( "encoding/json" + "errors" "log" "os" "regexp" @@ -100,3 +101,19 @@ func (c *Core) AWDLCreateInterface(boxPubKey []byte, sigPubKey []byte, name stri copy(sig[:crypto.SigPubKeyLen], sigPubKey[:]) c.awdl.create(&box, &sig, name) } + +func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) { + if intf := c.awdl.getInterface(identity); intf != nil { + return <-intf.recv, nil + } + return nil, errors.New("identity not known: " + identity) +} + +func (c *Core) AWDLSendPacket(identity string, buf []byte) error { + packet := append(util.GetBytes(), buf[:]...) + if intf := c.awdl.getInterface(identity); intf != nil { + intf.send <- packet + return nil + } + return errors.New("identity not known: " + identity) +} From 00bf71a09ade86bc5db484497a555d8cd10851b8 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 4 Jan 2019 23:31:44 +0000 Subject: [PATCH 08/15] Fight me Swift and your hexadecimal strings --- src/yggdrasil/mobile.go | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index 44886f8..af7abb7 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -3,6 +3,7 @@ package yggdrasil import ( + "encoding/hex" "encoding/json" "errors" "log" @@ -94,12 +95,24 @@ func (c *Core) RouterSendPacket(buf []byte) error { return nil } -func (c *Core) AWDLCreateInterface(boxPubKey []byte, sigPubKey []byte, name string) { - var box crypto.BoxPubKey - var sig crypto.SigPubKey - copy(box[:crypto.BoxPubKeyLen], boxPubKey[:]) - copy(sig[:crypto.SigPubKeyLen], sigPubKey[:]) - c.awdl.create(&box, &sig, name) +func (c *Core) AWDLCreateInterface(boxPubKey string, sigPubKey string, name string) error { + var boxPub crypto.BoxPubKey + var sigPub crypto.SigPubKey + boxPubHex, err := hex.DecodeString(boxPubKey) + if err != nil { + return err + } + sigPubHex, err := hex.DecodeString(sigPubKey) + if err != nil { + return err + } + copy(boxPub[:], boxPubHex) + copy(sigPub[:], sigPubHex) + if intf := c.awdl.create(&boxPub, &sigPub, name); intf != nil { + return nil + } else { + return errors.New("No interface was created") + } } func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) { From 4363283a6f6ec33a462aa37709ca6a35c90e1603 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 5 Jan 2019 00:32:28 +0000 Subject: [PATCH 09/15] Notify switch idle --- src/yggdrasil/awdl.go | 2 ++ src/yggdrasil/mobile.go | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index 84cd3fb..3bd6360 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -45,6 +45,7 @@ func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, intf.peer.out = func(msg []byte) { defer func() { recover() }() intf.send <- msg + l.core.switchTable.idleIn <- intf.peer.port } go intf.handler() l.core.switchTable.idleIn <- intf.peer.port @@ -80,6 +81,7 @@ func (ai *awdlInterface) handler() { select { case p := <-ai.peer.linkOut: ai.send <- p + ai.awdl.core.switchTable.idleIn <- ai.peer.port continue default: } diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index af7abb7..a81d82c 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -115,6 +115,10 @@ func (c *Core) AWDLCreateInterface(boxPubKey string, sigPubKey string, name stri } } +func (c *Core) AWDLShutdownInterface(name string) { + c.awdl.shutdown(name) +} + func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) { if intf := c.awdl.getInterface(identity); intf != nil { return <-intf.recv, nil From 1170ea9e989170467472860d2f369a3027ecf075 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 5 Jan 2019 00:52:41 +0000 Subject: [PATCH 10/15] Start linkloop --- src/yggdrasil/awdl.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index 3bd6360..aac7f7d 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -47,6 +47,10 @@ func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, intf.send <- msg l.core.switchTable.idleIn <- intf.peer.port } + intf.peer.close = func() { + close(intf.send) + } + go intf.peer.linkLoop() go intf.handler() l.core.switchTable.idleIn <- intf.peer.port return &intf From 90366dd8537c93f44691f9181229d38d9efcceec Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 5 Jan 2019 01:02:22 +0000 Subject: [PATCH 11/15] Update handler behavior --- src/yggdrasil/awdl.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index aac7f7d..d3d69d5 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -102,7 +102,10 @@ func (ai *awdlInterface) handler() { ai.peer.handlePacket(r) case <-ai.shutdown: return - default: + case p := <-ai.peer.linkOut: + ai.send <- p + ai.awdl.core.switchTable.idleIn <- ai.peer.port + continue } } } From 6bbd8c1b30865f10448251b52c8b4c3c23740d0c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 5 Jan 2019 12:06:45 +0000 Subject: [PATCH 12/15] Rethink channels, more error throwing --- src/yggdrasil/awdl.go | 70 ++++++++++++++++++++++++----------------- src/yggdrasil/core.go | 2 +- src/yggdrasil/mobile.go | 18 ++++++----- 3 files changed, 53 insertions(+), 37 deletions(-) diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index d3d69d5..f38d101 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -1,9 +1,14 @@ package yggdrasil import ( + "errors" + "fmt" "sync" + "sync/atomic" + "time" "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "github.com/yggdrasil-network/yggdrasil-go/src/util" ) type awdl struct { @@ -14,8 +19,8 @@ type awdl struct { type awdlInterface struct { awdl *awdl - recv <-chan []byte // traffic received from the network - send chan<- []byte // traffic to send to the network + fromAWDL chan []byte + toAWDL chan []byte shutdown chan bool peer *peer } @@ -29,11 +34,11 @@ func (l *awdl) init(c *Core) error { return nil } -func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, name string) *awdlInterface { +func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, name string) (*awdlInterface, error) { shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey) intf := awdlInterface{ - recv: make(<-chan []byte), - send: make(chan<- []byte), + fromAWDL: make(chan []byte, 32), + toAWDL: make(chan []byte, 32), shutdown: make(chan bool), peer: l.core.peers.newPeer(boxPubKey, sigPubKey, shared, name), } @@ -41,21 +46,21 @@ func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, l.mutex.Lock() l.interfaces[name] = &intf l.mutex.Unlock() - intf.peer.linkOut = make(chan []byte, 1) + intf.peer.linkOut = make(chan []byte, 1) // protocol traffic intf.peer.out = func(msg []byte) { defer func() { recover() }() - intf.send <- msg - l.core.switchTable.idleIn <- intf.peer.port - } + intf.toAWDL <- msg + } // called by peer.sendPacket() + l.core.switchTable.idleIn <- intf.peer.port // notify switch that we're idle intf.peer.close = func() { - close(intf.send) + close(intf.fromAWDL) + close(intf.toAWDL) } - go intf.peer.linkLoop() - go intf.handler() - l.core.switchTable.idleIn <- intf.peer.port - return &intf + go intf.handler() // start listening for packets from switch + go intf.peer.linkLoop() // start link loop + return &intf, nil } - return nil + return nil, errors.New("l.core.peers.newPeer failed") } func (l *awdl) getInterface(identity string) *awdlInterface { @@ -67,45 +72,52 @@ func (l *awdl) getInterface(identity string) *awdlInterface { return nil } -func (l *awdl) shutdown(identity string) { +func (l *awdl) shutdown(identity string) error { if intf, ok := l.interfaces[identity]; ok { intf.shutdown <- true l.core.peers.removePeer(intf.peer.port) l.mutex.Lock() delete(l.interfaces, identity) l.mutex.Unlock() + return nil + } else { + return errors.New(fmt.Sprintf("Interface '%s' doesn't exist or already shutdown", identity)) } } func (ai *awdlInterface) handler() { + send := func(msg []byte) { + ai.toAWDL <- msg + atomic.AddUint64(&ai.peer.bytesSent, uint64(len(msg))) + util.PutBytes(msg) + } for { - /*timerInterval := tcp_ping_interval + timerInterval := tcp_ping_interval timer := time.NewTimer(timerInterval) - defer timer.Stop()*/ + defer timer.Stop() select { case p := <-ai.peer.linkOut: - ai.send <- p - ai.awdl.core.switchTable.idleIn <- ai.peer.port + send(p) continue default: } - /*timer.Stop() + timer.Stop() select { case <-timer.C: default: } - timer.Reset(timerInterval)*/ + timer.Reset(timerInterval) select { - //case _ = <-timer.C: - // ai.send <- nil - case r := <-ai.recv: // traffic received from AWDL + case _ = <-timer.C: + send([]byte{'H', 'E', 'L', 'L', 'O'}) + case p := <-ai.peer.linkOut: + send(p) + continue + case r := <-ai.fromAWDL: ai.peer.handlePacket(r) + ai.awdl.core.switchTable.idleIn <- ai.peer.port case <-ai.shutdown: return - case p := <-ai.peer.linkOut: - ai.send <- p - ai.awdl.core.switchTable.idleIn <- ai.peer.port - continue } } } diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index b99d1f2..a1c2127 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -35,7 +35,7 @@ type Core struct { multicast multicast nodeinfo nodeinfo tcp tcpInterface - awdl awdl + awdl awdl log *log.Logger ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this } diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index a81d82c..1c9a84f 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -108,20 +108,24 @@ func (c *Core) AWDLCreateInterface(boxPubKey string, sigPubKey string, name stri } copy(boxPub[:], boxPubHex) copy(sigPub[:], sigPubHex) - if intf := c.awdl.create(&boxPub, &sigPub, name); intf != nil { - return nil + if intf, err := c.awdl.create(&boxPub, &sigPub, name); err == nil { + if intf != nil { + return err + } else { + return errors.New("c.awdl.create didn't return an interface") + } } else { - return errors.New("No interface was created") + return err } } -func (c *Core) AWDLShutdownInterface(name string) { - c.awdl.shutdown(name) +func (c *Core) AWDLShutdownInterface(name string) error { + return c.awdl.shutdown(name) } func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) { if intf := c.awdl.getInterface(identity); intf != nil { - return <-intf.recv, nil + return <-intf.toAWDL, nil } return nil, errors.New("identity not known: " + identity) } @@ -129,7 +133,7 @@ func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) { func (c *Core) AWDLSendPacket(identity string, buf []byte) error { packet := append(util.GetBytes(), buf[:]...) if intf := c.awdl.getInterface(identity); intf != nil { - intf.send <- packet + intf.fromAWDL <- packet return nil } return errors.New("identity not known: " + identity) From 87362a21e27527acee12bb8ad790bfc2d2eb3b59 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 5 Jan 2019 21:59:07 +0000 Subject: [PATCH 13/15] Access NSLog through Cgo for iOS NetworkExtension logging --- src/yggdrasil/awdl.go | 3 ++- src/yggdrasil/mobile.go | 6 ++++-- src/yggdrasil/mobile_ios.go | 25 +++++++++++++++++++++++++ src/yggdrasil/peer.go | 1 + 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/yggdrasil/mobile_ios.go diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index f38d101..a2ec283 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -109,11 +109,12 @@ func (ai *awdlInterface) handler() { timer.Reset(timerInterval) select { case _ = <-timer.C: - send([]byte{'H', 'E', 'L', 'L', 'O'}) + send([]byte{}) case p := <-ai.peer.linkOut: send(p) continue case r := <-ai.fromAWDL: + //_ = append(util.GetBytes(), r...) ai.peer.handlePacket(r) ai.awdl.core.switchTable.idleIn <- ai.peer.port case <-ai.shutdown: diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index 1c9a84f..2f8a323 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -24,7 +24,8 @@ import ( // therefore we use the "dummy" TUN interface instead. func (c *Core) StartAutoconfigure() error { - logger := log.New(os.Stdout, "", 0) + mobilelog := MobileLogger{} + logger := log.New(mobilelog, "", 0) nc := config.GenerateConfig(true) nc.IfName = "dummy" nc.AdminListen = "tcp://localhost:9001" @@ -43,7 +44,8 @@ func (c *Core) StartAutoconfigure() error { } func (c *Core) StartJSON(configjson []byte) error { - logger := log.New(os.Stdout, "", 0) + mobilelog := MobileLogger{} + logger := log.New(mobilelog, "", 0) nc := config.GenerateConfig(false) var dat map[string]interface{} if err := hjson.Unmarshal(configjson, &dat); err != nil { diff --git a/src/yggdrasil/mobile_ios.go b/src/yggdrasil/mobile_ios.go new file mode 100644 index 0000000..4abc6e9 --- /dev/null +++ b/src/yggdrasil/mobile_ios.go @@ -0,0 +1,25 @@ +// +build mobile,darwin + +package yggdrasil + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation +#import +void Log(const char *text) { + NSString *nss = [NSString stringWithUTF8String:text]; + NSLog(@"%@", nss); +} +*/ +import "C" +import "unsafe" + +type MobileLogger struct { +} + +func (nsl MobileLogger) Write(p []byte) (n int, err error) { + p = append(p, 0) + cstr := (*C.char)(unsafe.Pointer(&p[0])) + C.Log(cstr) + return len(p), nil +} diff --git a/src/yggdrasil/peer.go b/src/yggdrasil/peer.go index a2b94b6..333561e 100644 --- a/src/yggdrasil/peer.go +++ b/src/yggdrasil/peer.go @@ -217,6 +217,7 @@ func (p *peer) handlePacket(packet []byte) { default: util.PutBytes(packet) } + return } // Called to handle traffic or protocolTraffic packets. From 2034c9eab938e8f589c6f6b0798981b1194b7d7d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 5 Jan 2019 23:00:49 +0000 Subject: [PATCH 14/15] Fix missing pointer from awdlInterface to awdl --- src/yggdrasil/awdl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index a2ec283..f4ace36 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -37,6 +37,7 @@ func (l *awdl) init(c *Core) error { func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, name string) (*awdlInterface, error) { shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey) intf := awdlInterface{ + awdl: l, fromAWDL: make(chan []byte, 32), toAWDL: make(chan []byte, 32), shutdown: make(chan bool), @@ -114,7 +115,6 @@ func (ai *awdlInterface) handler() { send(p) continue case r := <-ai.fromAWDL: - //_ = append(util.GetBytes(), r...) ai.peer.handlePacket(r) ai.awdl.core.switchTable.idleIn <- ai.peer.port case <-ai.shutdown: From 6efac9a377dd0c3d35e33e4a8ab828329a8173cb Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 6 Jan 2019 14:12:10 +0000 Subject: [PATCH 15/15] Add contexts --- src/yggdrasil/awdl.go | 33 ++++++++++++++++++++++++++++----- src/yggdrasil/mobile.go | 31 ++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index f4ace36..65e84cb 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -34,14 +34,37 @@ func (l *awdl) init(c *Core) error { return nil } -func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, name string) (*awdlInterface, error) { +func (l *awdl) create(fromAWDL chan []byte, toAWDL chan []byte, boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, name string) (*awdlInterface, error) { + /* + myLinkPub, myLinkPriv := crypto.NewBoxKeys() + meta := version_getBaseMetadata() + meta.box = l.core.boxPub + meta.sig = l.core.sigPub + meta.link = *myLinkPub + metaBytes := meta.encode() + l.core.log.Println("toAWDL <- metaBytes") + toAWDL <- metaBytes + l.core.log.Println("metaBytes = <-fromAWDL") + metaBytes = <-fromAWDL + l.core.log.Println("version_metadata{}") + meta = version_metadata{} + if !meta.decode(metaBytes) || !meta.check() { + return nil, errors.New("Metadata decode failure") + } + base := version_getBaseMetadata() + if meta.ver > base.ver || meta.ver == base.ver && meta.minorVer > base.minorVer { + return nil, errors.New("Failed to connect to node: " + name + " version: " + fmt.Sprintf("%d.%d", meta.ver, meta.minorVer)) + } + shared := crypto.GetSharedKey(myLinkPriv, &meta.link) + */ shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey) intf := awdlInterface{ awdl: l, - fromAWDL: make(chan []byte, 32), - toAWDL: make(chan []byte, 32), + fromAWDL: fromAWDL, + toAWDL: toAWDL, shutdown: make(chan bool), peer: l.core.peers.newPeer(boxPubKey, sigPubKey, shared, name), + //peer: l.core.peers.newPeer(&meta.box, &meta.sig, shared, name), } if intf.peer != nil { l.mutex.Lock() @@ -57,8 +80,8 @@ func (l *awdl) create(boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey, close(intf.fromAWDL) close(intf.toAWDL) } - go intf.handler() // start listening for packets from switch - go intf.peer.linkLoop() // start link loop + go intf.handler() + go intf.peer.linkLoop() return &intf, nil } return nil, errors.New("l.core.peers.newPeer failed") diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index 2f8a323..300d132 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -98,29 +98,47 @@ func (c *Core) RouterSendPacket(buf []byte) error { } func (c *Core) AWDLCreateInterface(boxPubKey string, sigPubKey string, name string) error { + fromAWDL := make(chan []byte, 32) + toAWDL := make(chan []byte, 32) + var boxPub crypto.BoxPubKey var sigPub crypto.SigPubKey boxPubHex, err := hex.DecodeString(boxPubKey) if err != nil { + c.log.Println(err) return err } sigPubHex, err := hex.DecodeString(sigPubKey) if err != nil { + c.log.Println(err) return err } copy(boxPub[:], boxPubHex) copy(sigPub[:], sigPubHex) - if intf, err := c.awdl.create(&boxPub, &sigPub, name); err == nil { + + if intf, err := c.awdl.create(fromAWDL, toAWDL, &boxPub, &sigPub, name); err == nil { if intf != nil { + c.log.Println(err) return err } else { + c.log.Println("c.awdl.create didn't return an interface") return errors.New("c.awdl.create didn't return an interface") } } else { + c.log.Println(err) return err } } +func (c *Core) AWDLCreateInterfaceFromContext(context []byte, name string) error { + if len(context) < crypto.BoxPubKeyLen+crypto.SigPubKeyLen { + return errors.New("Not enough bytes in context") + } + boxPubKey := hex.EncodeToString(context[:crypto.BoxPubKeyLen]) + sigPubKey := hex.EncodeToString(context[crypto.BoxPubKeyLen:]) + return c.AWDLCreateInterface(boxPubKey, sigPubKey, name) +} + func (c *Core) AWDLShutdownInterface(name string) error { return c.awdl.shutdown(name) } @@ -129,7 +147,7 @@ func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) { if intf := c.awdl.getInterface(identity); intf != nil { return <-intf.toAWDL, nil } - return nil, errors.New("identity not known: " + identity) + return nil, errors.New("AWDLRecvPacket identity not known: " + identity) } func (c *Core) AWDLSendPacket(identity string, buf []byte) error { @@ -138,5 +156,12 @@ func (c *Core) AWDLSendPacket(identity string, buf []byte) error { intf.fromAWDL <- packet return nil } - return errors.New("identity not known: " + identity) + return errors.New("AWDLSendPacket identity not known: " + identity) +} + +func (c *Core) AWDLConnectionContext() []byte { + var context []byte + context = append(context, c.boxPub[:]...) + context = append(context, c.sigPub[:]...) + return context }