From 9e5f90d0e4e08eec4c32dc17fc261db93cbf452d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 4 Nov 2018 19:15:53 +0000 Subject: [PATCH 01/24] Add neilalexander's logo proposal --- contrib/logo/ygg-neilalexander.svg | 62 ++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 contrib/logo/ygg-neilalexander.svg diff --git a/contrib/logo/ygg-neilalexander.svg b/contrib/logo/ygg-neilalexander.svg new file mode 100644 index 00000000..7f281386 --- /dev/null +++ b/contrib/logo/ygg-neilalexander.svg @@ -0,0 +1,62 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + From 953ad0ef5979ca862b0eb57dbc375b6bc7bdaf5d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 14 Nov 2018 19:25:35 +0000 Subject: [PATCH 02/24] Update neilalexander's logo proposal --- contrib/logo/ygg-neilalexander.svg | 151 +++++++++++++++++++++++------ 1 file changed, 123 insertions(+), 28 deletions(-) diff --git a/contrib/logo/ygg-neilalexander.svg b/contrib/logo/ygg-neilalexander.svg index 7f281386..d2222002 100644 --- a/contrib/logo/ygg-neilalexander.svg +++ b/contrib/logo/ygg-neilalexander.svg @@ -9,35 +9,39 @@ xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="297mm" - height="210mm" - viewBox="0 0 1052.3622 744.09448" - id="svg4211" - version="1.1" + sodipodi:docname="drawing.svg" inkscape:version="0.91 r13725" - sodipodi:docname="ygg.svg"> + version="1.1" + id="svg4240" + viewBox="0 0 981.96461 321.60015" + height="90.762711mm" + width="277.13223mm"> + id="defs4242" /> + inkscape:window-x="0" + inkscape:window-height="1021" + inkscape:window-width="2048" + showgrid="false" + inkscape:current-layer="layer2" + inkscape:document-units="px" + inkscape:cy="13.914395" + inkscape:cx="751.6295" + inkscape:zoom="0.66468037" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" /> + id="metadata4245"> @@ -52,11 +56,102 @@ inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" - transform="translate(0,-308.26772)"> + transform="translate(383.92494,-160.49328)" /> + + d="m 352.74397,478.24119 c 0.92103,-3.76903 11.87131,-30.48993 21.5083,-52.48465 9.86344,-22.51152 9.67726,-21.6278 6.92943,-32.89221 -3.42997,-14.06075 -3.22164,-36.95243 0.44688,-49.10642 13.24423,-43.87864 47.63362,-73.61698 122.30718,-105.76556 24.32504,-10.47245 37.67777,-17.18807 47.80968,-24.04538 17.86083,-12.08828 36.4402,-33.06424 42.38057,-47.84736 1.25285,-3.11781 2.66096,-5.64051 3.12912,-5.60598 1.46014,0.10767 0.73701,44.30167 -0.9768,59.69719 -10.61597,95.36545 -42.95689,157.39345 -96.20598,184.51751 -30.73114,15.65385 -79.17559,21.45357 -101.74118,12.18037 -3.19081,-1.31125 -6.5492,-2.38408 -7.46311,-2.38408 -3.43636,0 -15.75824,32.89925 -19.29523,51.51802 -1.09802,5.78003 -2.76237,13.70787 -3.00898,14.91667 -5.50064,-0.0422 -0.35371,-0.0119 -8.18026,-0.0119 l -8.29605,0 z" + id="path4918" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ssssssscssssscscs" /> + + + + + + + + + + + + + + + + + + From 53aeca8fa27ee8207081cedc67a0cf8c90ab7774 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 1 Jan 2019 23:25:20 +0000 Subject: [PATCH 03/24] 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 2b6d2f04..43cf77a7 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 192f435f..192b94e5 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 4a432092..7fb6a19e 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 00000000..5f32a85c --- /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 04/24] 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 5f32a85c..00000000 --- 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 00000000..9142c36c --- /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 8ed53332..8c0f91d5 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 943468e6..828c01ea 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 00000000..234ab1de --- /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 7a7c9cb7..8ccdd30b 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 625f9cd5..22058c11 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 05/24] 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 9142c36c..c4bc8dee 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 06/24] 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 c4bc8dee..f579f532 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 07/24] 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 e463c852..a3a679f2 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 00000000..b07c2fc7 --- /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 e38274fa..b99d1f2b 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 f579f532..36a98eab 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 08/24] 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 b07c2fc7..da10d585 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 09/24] 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 da10d585..84cd3fbf 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 36a98eab..44886f8b 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 10/24] 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 44886f8b..af7abb7a 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 11/24] 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 84cd3fbf..3bd63609 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 af7abb7a..a81d82cd 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 12/24] 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 3bd63609..aac7f7d4 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 13/24] 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 aac7f7d4..d3d69d58 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 14/24] 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 d3d69d58..f38d101c 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 b99d1f2b..a1c2127d 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 a81d82cd..1c9a84f6 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 15/24] 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 f38d101c..a2ec2830 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 1c9a84f6..2f8a3235 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 00000000..4abc6e9f --- /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 a2b94b67..333561e5 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 16/24] 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 a2ec2830..f4ace36c 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 17/24] 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 f4ace36c..65e84cb5 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 2f8a3235..300d132a 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 } From a371e34a187cc3642a2bdaa7ff150f443b5e55dc Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 10 Jan 2019 10:44:44 +0000 Subject: [PATCH 18/24] Add Android support, add addStaticPeers --- src/yggdrasil/mobile.go | 24 ++++++++++++++++++++++++ src/yggdrasil/mobile_android.go | 12 ++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/yggdrasil/mobile_android.go diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index 300d132a..5cd15ece 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -9,6 +9,7 @@ import ( "log" "os" "regexp" + "time" hjson "github.com/hjson/hjson-go" "github.com/mitchellh/mapstructure" @@ -23,6 +24,25 @@ import ( // 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) + } +} + func (c *Core) StartAutoconfigure() error { mobilelog := MobileLogger{} logger := log.New(mobilelog, "", 0) @@ -40,6 +60,7 @@ func (c *Core) StartAutoconfigure() error { if err := c.Start(nc, logger); err != nil { return err } + go c.addStaticPeers(nc) return nil } @@ -55,7 +76,9 @@ func (c *Core) StartJSON(configjson []byte) error { return err } nc.IfName = "dummy" + //c.log.Println(nc.MulticastInterfaces) for _, ll := range nc.MulticastInterfaces { + //c.log.Println("Processing MC", ll) ifceExpr, err := regexp.Compile(ll) if err != nil { panic(err) @@ -65,6 +88,7 @@ func (c *Core) StartJSON(configjson []byte) error { if err := c.Start(nc, logger); err != nil { return err } + go c.addStaticPeers(nc) return nil } diff --git a/src/yggdrasil/mobile_android.go b/src/yggdrasil/mobile_android.go new file mode 100644 index 00000000..24764840 --- /dev/null +++ b/src/yggdrasil/mobile_android.go @@ -0,0 +1,12 @@ +// +build android + +package yggdrasil + +import "log" + +type MobileLogger struct{} + +func (nsl MobileLogger) Write(p []byte) (n int, err error) { + log.Println(string(p)) + return len(p), nil +} From e24e8592541a4862db1cd14ba137a46024c402ad Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 10 Jan 2019 11:31:04 +0000 Subject: [PATCH 19/24] Add some comments, move AWDL functions to iOS-specific build tags --- src/yggdrasil/mobile.go | 85 ++++++------------------------------- src/yggdrasil/mobile_ios.go | 78 +++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 73 deletions(-) diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index 5cd15ece..b7510613 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -3,9 +3,7 @@ package yggdrasil import ( - "encoding/hex" "encoding/json" - "errors" "log" "os" "regexp" @@ -14,7 +12,6 @@ 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" ) @@ -43,6 +40,7 @@ func (c *Core) addStaticPeers(cfg *config.NodeConfig) { } } +// Starts a node with a randomly generated config. func (c *Core) StartAutoconfigure() error { mobilelog := MobileLogger{} logger := log.New(mobilelog, "", 0) @@ -64,6 +62,8 @@ func (c *Core) StartAutoconfigure() error { 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) @@ -92,6 +92,7 @@ func (c *Core) StartJSON(configjson []byte) error { return nil } +// Generates mobile-friendly configuration in JSON format. func GenerateConfigJSON() []byte { nc := config.GenerateConfig(false) nc.IfName = "dummy" @@ -102,90 +103,30 @@ func GenerateConfigJSON() []byte { } } +// Gets the node's IPv6 address. func (c *Core) GetAddressString() string { return c.GetAddress().String() } +// Gets the node's IPv6 subnet in CIDR notation. func (c *Core) GetSubnetString() string { return c.GetSubnet().String() } +// 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.tun.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.tun.send <- packet return nil } - -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(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) -} - -func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) { - if intf := c.awdl.getInterface(identity); intf != nil { - return <-intf.toAWDL, nil - } - return nil, errors.New("AWDLRecvPacket 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.fromAWDL <- packet - return nil - } - 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 -} diff --git a/src/yggdrasil/mobile_ios.go b/src/yggdrasil/mobile_ios.go index 4abc6e9f..6d2570db 100644 --- a/src/yggdrasil/mobile_ios.go +++ b/src/yggdrasil/mobile_ios.go @@ -12,7 +12,14 @@ void Log(const char *text) { } */ import "C" -import "unsafe" +import ( + "encoding/hex" + "errors" + "unsafe" + + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" + "github.com/yggdrasil-network/yggdrasil-go/src/util" +) type MobileLogger struct { } @@ -23,3 +30,72 @@ func (nsl MobileLogger) Write(p []byte) (n int, err error) { C.Log(cstr) return len(p), nil } + +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(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) +} + +func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) { + if intf := c.awdl.getInterface(identity); intf != nil { + return <-intf.toAWDL, nil + } + return nil, errors.New("AWDLRecvPacket 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.fromAWDL <- packet + return nil + } + 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 +} From 4f7e8856b853c4b6e5bc456078c3abb915f30fae Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 10 Jan 2019 17:44:52 +0000 Subject: [PATCH 20/24] Update build script for iOS/Android --- build | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/build b/build index a3a679f2..7ceb4c9a 100755 --- a/build +++ b/build @@ -6,13 +6,14 @@ PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)} LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER" -while getopts "udmtc:l:" option +while getopts "udaitc:l:" option do case "${option}" in u) UPX=true;; d) DEBUG=true;; - m) MOBILE=true;; + i) IOS=true;; + a) ANDROID=true;; t) TABLES=true;; c) GCFLAGS="$GCFLAGS $OPTARG";; l) LDFLAGS="$LDFLAGS $OPTARG";; @@ -23,17 +24,23 @@ if [ -z $TABLES ]; then STRIP="-s -w" fi -for CMD in `ls cmd/` ; do - echo "Building: $CMD" +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 +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 +else + for CMD in `ls cmd/` ; do + echo "Building: $CMD" - 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 - fi - if [ $UPX ]; then - upx --brute $CMD - fi -done + if [ $DEBUG ]; then + go build -ldflags="$LDFLAGS" -gcflags="$GCFLAGS" -tags debug -v ./cmd/$CMD + else + go build -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" -v ./cmd/$CMD + fi + if [ $UPX ]; then + upx --brute $CMD + fi + done +fi From 4622a85c34e2c548b415db69720e9605c9acffcd Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jan 2019 18:08:41 +0000 Subject: [PATCH 21/24] AWDL support for macOS/iOS --- src/yggdrasil/mobile.go | 11 +++++++++++ src/yggdrasil/multicast_darwin.go | 28 ++++++++++++++++++++++++++++ src/yggdrasil/multicast_unix.go | 2 +- src/yggdrasil/tcp.go | 11 +++++++++-- src/yggdrasil/tcp_darwin.go | 28 ++++++++++++++++++++++++++++ src/yggdrasil/tcp_other.go | 13 +++++++++++++ 6 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 src/yggdrasil/multicast_darwin.go create mode 100644 src/yggdrasil/tcp_darwin.go create mode 100644 src/yggdrasil/tcp_other.go diff --git a/src/yggdrasil/mobile.go b/src/yggdrasil/mobile.go index b7510613..2ffeffb9 100644 --- a/src/yggdrasil/mobile.go +++ b/src/yggdrasil/mobile.go @@ -3,6 +3,7 @@ package yggdrasil import ( + "encoding/hex" "encoding/json" "log" "os" @@ -113,6 +114,16 @@ func (c *Core) GetSubnetString() string { return c.GetSubnet().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. diff --git a/src/yggdrasil/multicast_darwin.go b/src/yggdrasil/multicast_darwin.go new file mode 100644 index 00000000..71eecce4 --- /dev/null +++ b/src/yggdrasil/multicast_darwin.go @@ -0,0 +1,28 @@ +// +build darwin + +package yggdrasil + +import "syscall" +import "golang.org/x/sys/unix" + +func multicastReuse(network string, address string, c syscall.RawConn) error { + var control error + var reuseport error + var recvanyif error + + control = c.Control(func(fd uintptr) { + reuseport = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1) + + // sys/socket.h: #define SO_RECV_ANYIF 0x1104 + recvanyif = unix.SetsockoptInt(int(fd), syscall.SOL_SOCKET, 0x1104, 1) + }) + + switch { + case reuseport != nil: + return reuseport + case recvanyif != nil: + return recvanyif + default: + return control + } +} diff --git a/src/yggdrasil/multicast_unix.go b/src/yggdrasil/multicast_unix.go index 9c6d1f11..54bbc645 100644 --- a/src/yggdrasil/multicast_unix.go +++ b/src/yggdrasil/multicast_unix.go @@ -1,4 +1,4 @@ -// +build linux darwin netbsd freebsd openbsd dragonflybsd +// +build linux netbsd freebsd openbsd dragonflybsd package yggdrasil diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index 6d923440..8d8fee34 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -15,6 +15,7 @@ package yggdrasil // See version.go for version metadata format import ( + "context" "errors" "fmt" "io" @@ -88,7 +89,11 @@ func (iface *tcpInterface) init(core *Core, addr string, readTimeout int32) (err iface.tcp_timeout = default_tcp_timeout } - iface.serv, err = net.Listen("tcp", addr) + ctx := context.Background() + lc := net.ListenConfig{ + Control: iface.tcpContext, + } + iface.serv, err = lc.Listen(ctx, "tcp", addr) if err == nil { iface.calls = make(map[string]struct{}) iface.conns = make(map[tcpInfo](chan struct{})) @@ -164,7 +169,9 @@ func (iface *tcpInterface) call(saddr string, socksaddr *string, sintf string) { }, } } else { - dialer := net.Dialer{} + dialer := net.Dialer{ + Control: iface.tcpContext, + } if sintf != "" { ief, err := net.InterfaceByName(sintf) if err != nil { diff --git a/src/yggdrasil/tcp_darwin.go b/src/yggdrasil/tcp_darwin.go new file mode 100644 index 00000000..6483ef86 --- /dev/null +++ b/src/yggdrasil/tcp_darwin.go @@ -0,0 +1,28 @@ +// +build darwin + +package yggdrasil + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +// WARNING: This context is used both by net.Dialer and net.Listen in tcp.go + +func (iface *tcpInterface) tcpContext(network, address string, c syscall.RawConn) error { + var control error + var recvanyif error + + control = c.Control(func(fd uintptr) { + // sys/socket.h: #define SO_RECV_ANYIF 0x1104 + recvanyif = unix.SetsockoptInt(int(fd), syscall.SOL_SOCKET, 0x1104, 1) + }) + + switch { + case recvanyif != nil: + return recvanyif + default: + return control + } +} diff --git a/src/yggdrasil/tcp_other.go b/src/yggdrasil/tcp_other.go new file mode 100644 index 00000000..5d62b530 --- /dev/null +++ b/src/yggdrasil/tcp_other.go @@ -0,0 +1,13 @@ +// +build !darwin + +package yggdrasil + +import ( + "syscall" +) + +// WARNING: This context is used both by net.Dialer and net.Listen in tcp.go + +func (iface *tcpInterface) tcpContext(network, address string, c syscall.RawConn) error { + return nil +} From c8db66b17d6a5a7f88a6ffc9ce75492bd135b8d6 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jan 2019 18:11:36 +0000 Subject: [PATCH 22/24] Remove unneeded AWDL context functions --- src/yggdrasil/mobile_ios.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/yggdrasil/mobile_ios.go b/src/yggdrasil/mobile_ios.go index 6d2570db..789df570 100644 --- a/src/yggdrasil/mobile_ios.go +++ b/src/yggdrasil/mobile_ios.go @@ -64,15 +64,6 @@ func (c *Core) AWDLCreateInterface(boxPubKey string, sigPubKey string, name stri } } -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) } @@ -92,10 +83,3 @@ func (c *Core) AWDLSendPacket(identity string, buf []byte) error { } 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 -} From 704e4a062fbf953b5fc3065f5d32be1d82494515 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jan 2019 22:51:34 +0000 Subject: [PATCH 23/24] Specify source interface when responding to multicast beacon --- src/yggdrasil/multicast.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yggdrasil/multicast.go b/src/yggdrasil/multicast.go index 749dfcdb..c0a676a8 100644 --- a/src/yggdrasil/multicast.go +++ b/src/yggdrasil/multicast.go @@ -157,6 +157,6 @@ func (m *multicast) listen() { } addr.Zone = from.Zone saddr := addr.String() - m.core.tcp.connect(saddr, "") + m.core.tcp.connect(saddr, addr.Zone) } } From f556f3e2a8ffd261f2a8cbcd809bb61f9812d1af Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 13 Jan 2019 22:57:37 +0000 Subject: [PATCH 24/24] Try to perform TCP-like key exchange --- src/yggdrasil/awdl.go | 59 +++++++++++++++++++------------------ src/yggdrasil/mobile_ios.go | 21 ++----------- 2 files changed, 32 insertions(+), 48 deletions(-) diff --git a/src/yggdrasil/awdl.go b/src/yggdrasil/awdl.go index 65e84cb5..633d5f9c 100644 --- a/src/yggdrasil/awdl.go +++ b/src/yggdrasil/awdl.go @@ -34,42 +34,42 @@ func (l *awdl) init(c *Core) error { return nil } -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) +func (l *awdl) create(fromAWDL chan []byte, toAWDL chan []byte /*boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey*/, name string) (*awdlInterface, error) { intf := awdlInterface{ awdl: l, 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), } + l.mutex.Lock() + l.interfaces[name] = &intf + l.mutex.Unlock() + 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") + } + l.core.log.Println("version_getBaseMetadata{}") + 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)) + } + l.core.log.Println("crypto.GetSharedKey") + shared := crypto.GetSharedKey(myLinkPriv, &meta.link) + //shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey) + l.core.log.Println("l.core.peers.newPeer") + intf.peer = l.core.peers.newPeer(&meta.box, &meta.sig, 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() }() @@ -84,6 +84,7 @@ func (l *awdl) create(fromAWDL chan []byte, toAWDL chan []byte, boxPubKey *crypt go intf.peer.linkLoop() return &intf, nil } + delete(l.interfaces, name) return nil, errors.New("l.core.peers.newPeer failed") } diff --git a/src/yggdrasil/mobile_ios.go b/src/yggdrasil/mobile_ios.go index 789df570..72920fe0 100644 --- a/src/yggdrasil/mobile_ios.go +++ b/src/yggdrasil/mobile_ios.go @@ -13,11 +13,9 @@ void Log(const char *text) { */ import "C" import ( - "encoding/hex" "errors" "unsafe" - "github.com/yggdrasil-network/yggdrasil-go/src/crypto" "github.com/yggdrasil-network/yggdrasil-go/src/util" ) @@ -31,26 +29,11 @@ func (nsl MobileLogger) Write(p []byte) (n int, err error) { return len(p), nil } -func (c *Core) AWDLCreateInterface(boxPubKey string, sigPubKey string, name string) error { +func (c *Core) AWDLCreateInterface(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(fromAWDL, toAWDL, &boxPub, &sigPub, name); err == nil { + if intf, err := c.awdl.create(fromAWDL, toAWDL, name); err == nil { if intf != nil { c.log.Println(err) return err