From 9e5f90d0e4e08eec4c32dc17fc261db93cbf452d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 4 Nov 2018 19:15:53 +0000 Subject: [PATCH 01/47] 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/47] 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 dfcdafa55c30e89f252f7076e32041700547c224 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 20 Dec 2018 17:37:59 -0600 Subject: [PATCH 03/47] move special peer/dht insert logic form router.go to dht.go --- src/yggdrasil/dht.go | 9 +++++++++ src/yggdrasil/router.go | 7 +------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/yggdrasil/dht.go b/src/yggdrasil/dht.go index af104f51..ef835985 100644 --- a/src/yggdrasil/dht.go +++ b/src/yggdrasil/dht.go @@ -134,6 +134,15 @@ func (t *dht) insert(info *dhtInfo) { t.table[*info.getNodeID()] = info } +// Insert a peer into the table if it hasn't been pinged lately, to keep peers from dropping +func (t *dht) insertPeer(info *dhtInfo) { + oldInfo, isIn := t.table[*info.getNodeID()] + if !isIn || time.Since(oldInfo.recv) > 45*time.Second { + // TODO? also check coords? + t.insert(info) + } +} + // Return true if first/second/third are (partially) ordered correctly. func dht_ordered(first, second, third *crypto.NodeID) bool { lessOrEqual := func(first, second *crypto.NodeID) bool { diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index 6c928696..87da8829 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -110,12 +110,7 @@ func (r *router) mainLoop() { case p := <-r.send: r.sendPacket(p) case info := <-r.core.dht.peers: - now := time.Now() - oldInfo, isIn := r.core.dht.table[*info.getNodeID()] - r.core.dht.insert(info) - if isIn && now.Sub(oldInfo.recv) < 45*time.Second { - info.recv = oldInfo.recv - } + r.core.dht.insertPeer(info) case <-r.reset: r.core.sessions.resetInits() r.core.dht.reset() From 60549cfa09d4f080a1ae6d9f7d0c7f02237a7140 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 20 Dec 2018 23:49:15 +0000 Subject: [PATCH 04/47] Adds special keyword 'hide' for masking built-in nodeinfo defaults --- src/yggdrasil/nodeinfo.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/nodeinfo.go b/src/yggdrasil/nodeinfo.go index f525beca..5e71a6e1 100644 --- a/src/yggdrasil/nodeinfo.go +++ b/src/yggdrasil/nodeinfo.go @@ -108,9 +108,14 @@ func (m *nodeinfo) setNodeInfo(given interface{}) error { if nodeinfomap, ok := given.(map[string]interface{}); ok { for key, value := range nodeinfomap { if _, ok := newnodeinfo[key]; ok { + if value == "hide" { + delete(newnodeinfo, key) + } continue } - newnodeinfo[key] = value + if value != "hide" { + newnodeinfo[key] = value + } } } if newjson, err := json.Marshal(newnodeinfo); err == nil { From f59852b1e1573eb490642f1f2ae0a8f5f5bbd363 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 20 Dec 2018 20:16:51 -0600 Subject: [PATCH 05/47] adjust how dht throttle works, it should now back off faster, and back off even more if things are not in use --- src/yggdrasil/dht.go | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/yggdrasil/dht.go b/src/yggdrasil/dht.go index ef835985..e360cecb 100644 --- a/src/yggdrasil/dht.go +++ b/src/yggdrasil/dht.go @@ -12,7 +12,12 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/crypto" ) -const dht_lookup_size = 16 +const ( + dht_lookup_size = 16 + dht_timeout = 6 * time.Minute + dht_max_delay = 5 * time.Minute + dht_max_delay_dirty = 30 * time.Second +) // dhtInfo represents everything we know about a node in the DHT. // This includes its key, a cache of it's NodeID, coords, and timing/ping related info for deciding who/when to ping nodes for maintenance. @@ -23,6 +28,7 @@ type dhtInfo struct { recv time.Time // When we last received a message pings int // Time out if at least 3 consecutive maintenance pings drop throttle time.Duration + dirty bool // Set to true if we've used this node in ping responses (for queries about someone other than the person doing the asking, i.e. real searches) since the last time we heard from the node } // Returns the *NodeID associated with dhtInfo.key, calculating it on the fly the first time or from a cache all subsequent times. @@ -137,7 +143,7 @@ func (t *dht) insert(info *dhtInfo) { // Insert a peer into the table if it hasn't been pinged lately, to keep peers from dropping func (t *dht) insertPeer(info *dhtInfo) { oldInfo, isIn := t.table[*info.getNodeID()] - if !isIn || time.Since(oldInfo.recv) > 45*time.Second { + if !isIn || time.Since(oldInfo.recv) > dht_max_delay+30*time.Second { // TODO? also check coords? t.insert(info) } @@ -194,6 +200,14 @@ func (t *dht) handleReq(req *dhtReq) { if _, isIn := t.table[*info.getNodeID()]; !isIn && t.isImportant(&info) { t.ping(&info, nil) } + // Maybe mark nodes from lookup as dirty + if req.Dest != *info.getNodeID() { + // This node asked about someone other than themself, so this wasn't just idle traffic. + for _, info := range res.Infos { + // Mark nodes dirty so we're sure to check up on them again later + info.dirty = true + } + } } // Sends a lookup response to the specified node. @@ -311,19 +325,24 @@ func (t *dht) doMaintenance() { } t.callbacks = newCallbacks for infoID, info := range t.table { - if now.Sub(info.recv) > time.Minute || info.pings > 3 { + if now.Sub(info.recv) > dht_timeout || info.pings > 6 { delete(t.table, infoID) t.imp = nil } } for _, info := range t.getImportant() { - if now.Sub(info.recv) > info.throttle { + switch { + case now.Sub(info.recv) > info.throttle: + info.throttle *= 2 + if info.throttle < time.Second { + info.throttle = time.Second + } else if info.throttle > dht_max_delay { + info.throttle = dht_max_delay + } + fallthrough + case info.dirty && now.Sub(info.recv) > dht_max_delay_dirty: t.ping(info, nil) info.pings++ - info.throttle += time.Second - if info.throttle > 30*time.Second { - info.throttle = 30 * time.Second - } } } } From 586deed0f93349f8ea6dd6c8cfb0fb53b1eb1069 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 21 Dec 2018 09:56:34 +0000 Subject: [PATCH 06/47] Add NodeInfoPrivacy option for not including defaults, and also check for null/"null" instead of "hide" --- cmd/yggdrasil/main.go | 1 + src/config/config.go | 1 + src/yggdrasil/core.go | 6 +++--- src/yggdrasil/nodeinfo.go | 19 ++++++++++++------- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 5a9db26c..2b6d2f04 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -71,6 +71,7 @@ func generateConfig(isAutoconf bool) *nodeConfig { cfg.SessionFirewall.AllowFromDirect = true cfg.SessionFirewall.AllowFromRemote = true cfg.SwitchOptions.MaxTotalQueueSize = yggdrasil.SwitchQueueTotalMinSize + cfg.NodeInfoPrivacy = false return &cfg } diff --git a/src/config/config.go b/src/config/config.go index b5a1f890..192f435f 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -19,6 +19,7 @@ type NodeConfig struct { SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."` TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively\nallows you to use Yggdrasil to route to, or to bridge other networks,\nsimilar to a VPN tunnel. Tunnelling works between any two nodes and\ndoes not require them to be directly peered."` SwitchOptions SwitchOptions `comment:"Advanced options for tuning the switch. Normally you will not need\nto edit these options."` + NodeInfoPrivacy bool `comment:"By default, nodeinfo contains some defaults including the platform,\narchitecture and Yggdrasil version. These can help when surveying\nthe network and diagnosing network routing problems. Enabling\nnodeinfo privacy prevents this, so that only items specified in\n\"NodeInfo\" are sent back if specified."` NodeInfo map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."` //Net NetConfig `comment:"Extended options for connecting to peers over other networks."` } diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 99330e12..e38274fa 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -125,7 +125,7 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { c.admin.init(c, nc.AdminListen) c.nodeinfo.init(c) - c.nodeinfo.setNodeInfo(nc.NodeInfo) + c.nodeinfo.setNodeInfo(nc.NodeInfo, nc.NodeInfoPrivacy) if err := c.tcp.init(c, nc.Listen, nc.ReadTimeout); err != nil { c.log.Println("Failed to start TCP interface") @@ -248,8 +248,8 @@ func (c *Core) GetNodeInfo() nodeinfoPayload { } // Sets the nodeinfo. -func (c *Core) SetNodeInfo(nodeinfo interface{}) { - c.nodeinfo.setNodeInfo(nodeinfo) +func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) { + c.nodeinfo.setNodeInfo(nodeinfo, nodeinfoprivacy) } // Sets the output logger of the Yggdrasil node after startup. This may be diff --git a/src/yggdrasil/nodeinfo.go b/src/yggdrasil/nodeinfo.go index 5e71a6e1..89a90a21 100644 --- a/src/yggdrasil/nodeinfo.go +++ b/src/yggdrasil/nodeinfo.go @@ -96,29 +96,34 @@ func (m *nodeinfo) getNodeInfo() nodeinfoPayload { } // Set the current node's nodeinfo -func (m *nodeinfo) setNodeInfo(given interface{}) error { +func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) error { m.myNodeInfoMutex.Lock() defer m.myNodeInfoMutex.Unlock() - newnodeinfo := map[string]interface{}{ + defaults := map[string]interface{}{ "buildname": GetBuildName(), "buildversion": GetBuildVersion(), "buildplatform": runtime.GOOS, "buildarch": runtime.GOARCH, } + newnodeinfo := make(map[string]interface{}) + if !privacy { + for k, v := range defaults { + newnodeinfo[k] = v + } + } if nodeinfomap, ok := given.(map[string]interface{}); ok { for key, value := range nodeinfomap { - if _, ok := newnodeinfo[key]; ok { - if value == "hide" { + if _, ok := defaults[key]; ok { + if strvalue, strok := value.(string); strok && strvalue == "null" || value == nil { delete(newnodeinfo, key) } continue } - if value != "hide" { - newnodeinfo[key] = value - } + newnodeinfo[key] = value } } if newjson, err := json.Marshal(newnodeinfo); err == nil { + m.core.log.Println(string(newjson)) if len(newjson) > 16384 { return errors.New("NodeInfo exceeds max length of 16384 bytes") } From f6b00759896c068a4e28865340c723a977778ffa Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 21 Dec 2018 10:04:32 +0000 Subject: [PATCH 07/47] Case-insensitive checking of null if string, don't print the nodeinfo again --- src/yggdrasil/nodeinfo.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yggdrasil/nodeinfo.go b/src/yggdrasil/nodeinfo.go index 89a90a21..b9076328 100644 --- a/src/yggdrasil/nodeinfo.go +++ b/src/yggdrasil/nodeinfo.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "runtime" + "strings" "sync" "time" @@ -114,7 +115,7 @@ func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) error { if nodeinfomap, ok := given.(map[string]interface{}); ok { for key, value := range nodeinfomap { if _, ok := defaults[key]; ok { - if strvalue, strok := value.(string); strok && strvalue == "null" || value == nil { + if strvalue, strok := value.(string); strok && strings.EqualFold(strvalue, "null") || value == nil { delete(newnodeinfo, key) } continue @@ -123,7 +124,6 @@ func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) error { } } if newjson, err := json.Marshal(newnodeinfo); err == nil { - m.core.log.Println(string(newjson)) if len(newjson) > 16384 { return errors.New("NodeInfo exceeds max length of 16384 bytes") } From 39997267f766a7a7b3c8d4c02cef566cd80714cc Mon Sep 17 00:00:00 2001 From: "Tristan B. Kildaire" Date: Fri, 21 Dec 2018 15:04:15 +0200 Subject: [PATCH 08/47] Typo fix. Just a typo fix. --- doc/Whitepaper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Whitepaper.md b/doc/Whitepaper.md index 674f6dc0..26d49a53 100644 --- a/doc/Whitepaper.md +++ b/doc/Whitepaper.md @@ -63,7 +63,7 @@ These coordinates are used as a distance label. Given the coordinates of any two nodes, it is possible to calculate the length of some real path through the network between the two nodes. Traffic is forwarded using a [greedy routing](https://en.wikipedia.org/wiki/Small-world_routing#Greedy_routing) scheme, where each node forwards the packet to a one-hop neighbor that is closer to the destination (according to this distance metric) than the current node. -In particular, when a packet needs to be forward, a node will forward it to whatever peer is closest to the destination in the greedy [metric space](https://en.wikipedia.org/wiki/Metric_space) used by the network, provided that the peer is closer to the destination than the current node. +In particular, when a packet needs to be forwarded, a node will forward it to whatever peer is closest to the destination in the greedy [metric space](https://en.wikipedia.org/wiki/Metric_space) used by the network, provided that the peer is closer to the destination than the current node. If no closer peers are idle, then the packet is queued in FIFO order, with separate queues per destination coords (currently, as a bit of a hack, IPv6 flow labels are embedeed after the end of the significant part of the coords, so queues distinguish between different traffic streams with the same destination). Whenever the node finishes forwarding a packet to a peer, it checks the queues, and will forward the first packet from the queue with the maximum `/`, i.e. the bandwidth the queue is attempting to use, subject to the constraint that the peer is a valid next hop (i.e. closer to the destination than the current node). From 59093aa43b69fa33c93efe65347e24fc4a027d4f Mon Sep 17 00:00:00 2001 From: Arceliar Date: Fri, 21 Dec 2018 17:45:24 -0600 Subject: [PATCH 09/47] clean up node info immediately if it reaches the timeout or if it needs refreshing but won't be pinged due to being unimportant --- src/yggdrasil/dht.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/dht.go b/src/yggdrasil/dht.go index e360cecb..96883940 100644 --- a/src/yggdrasil/dht.go +++ b/src/yggdrasil/dht.go @@ -325,7 +325,15 @@ func (t *dht) doMaintenance() { } t.callbacks = newCallbacks for infoID, info := range t.table { - if now.Sub(info.recv) > dht_timeout || info.pings > 6 { + switch { + case info.pings > 6: + // It failed to respond to too many pings + fallthrough + case now.Sub(info.recv) > dht_timeout: + // It's too old + fallthrough + case info.dirty && now.Sub(info.recv) > dht_max_delay_dirty && !t.isImportant(info): + // We won't ping it to refresh it, so just drop it delete(t.table, infoID) t.imp = nil } From b66049c14f0f95f48eac5fcd486c9c4ab478ec7b Mon Sep 17 00:00:00 2001 From: "Tristan B. Kildaire" Date: Sat, 22 Dec 2018 11:31:52 +0200 Subject: [PATCH 10/47] Typo fix Typo fix in function's header comment. --- src/yggdrasil/wire.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yggdrasil/wire.go b/src/yggdrasil/wire.go index 782af433..8891f1ab 100644 --- a/src/yggdrasil/wire.go +++ b/src/yggdrasil/wire.go @@ -70,7 +70,7 @@ func wire_decode_uint64(bs []byte) (uint64, int) { // Converts an int64 into uint64 so it can be written to the wire. // Non-negative integers are mapped to even integers: 0 -> 0, 1 -> 2, etc. -// Negative integres are mapped to odd integes: -1 -> 1, -2 -> 3, etc. +// Negative integers are mapped to odd integers: -1 -> 1, -2 -> 3, etc. // This means the least significant bit is a sign bit. func wire_intToUint(i int64) uint64 { return ((uint64(-(i+1))<<1)|0x01)*(uint64(i)>>63) + (uint64(i)<<1)*(^uint64(i)>>63) From 50ed92d6d2cc0a54e819bb3f624fe6d390dc91c7 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Wed, 26 Dec 2018 00:18:51 -0600 Subject: [PATCH 11/47] insert a copy when calling dht.insertPeer --- src/yggdrasil/dht.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/dht.go b/src/yggdrasil/dht.go index 96883940..b52a820b 100644 --- a/src/yggdrasil/dht.go +++ b/src/yggdrasil/dht.go @@ -145,7 +145,8 @@ func (t *dht) insertPeer(info *dhtInfo) { oldInfo, isIn := t.table[*info.getNodeID()] if !isIn || time.Since(oldInfo.recv) > dht_max_delay+30*time.Second { // TODO? also check coords? - t.insert(info) + newInfo := *info // Insert a copy + t.insert(&newInfo) } } From 9eeb48258741aa8a72d95ec3e097deb281a73dcf Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 26 Dec 2018 11:51:21 +0000 Subject: [PATCH 12/47] Use ICMPv6 NDP target instead of source address when populating peermacs --- src/yggdrasil/icmpv6.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/yggdrasil/icmpv6.go b/src/yggdrasil/icmpv6.go index baae3ab4..a8d4e6de 100644 --- a/src/yggdrasil/icmpv6.go +++ b/src/yggdrasil/icmpv6.go @@ -175,10 +175,13 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error case ipv6.ICMPTypeNeighborAdvertisement: if datamac != nil { var addr address.Address + var target address.Address var mac macAddress copy(addr[:], ipv6Header.Src[:]) + copy(target[:], datain[48:64]) copy(mac[:], (*datamac)[:]) - neighbor := i.peermacs[addr] + // i.tun.core.log.Println("Learning peer MAC", mac, "for", target) + neighbor := i.peermacs[target] neighbor.mac = mac neighbor.learned = true neighbor.lastadvertisement = time.Now() From b3d6c9a38560ac54724d3566c9396bb37b42992f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 26 Dec 2018 11:57:08 +0000 Subject: [PATCH 13/47] Print when peermacs learned --- src/yggdrasil/icmpv6.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yggdrasil/icmpv6.go b/src/yggdrasil/icmpv6.go index a8d4e6de..a34fa213 100644 --- a/src/yggdrasil/icmpv6.go +++ b/src/yggdrasil/icmpv6.go @@ -180,7 +180,7 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error copy(addr[:], ipv6Header.Src[:]) copy(target[:], datain[48:64]) copy(mac[:], (*datamac)[:]) - // i.tun.core.log.Println("Learning peer MAC", mac, "for", target) + i.tun.core.log.Printf("Learning peer MAC %x for %x\n", mac, target) neighbor := i.peermacs[target] neighbor.mac = mac neighbor.learned = true From 74692b689abb56fbca4fbcf4290693ad84c26e35 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 26 Dec 2018 12:25:28 +0000 Subject: [PATCH 14/47] Fix OpenBSD (tested and working on 6.4) --- src/yggdrasil/icmpv6.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yggdrasil/icmpv6.go b/src/yggdrasil/icmpv6.go index a34fa213..fc037fcb 100644 --- a/src/yggdrasil/icmpv6.go +++ b/src/yggdrasil/icmpv6.go @@ -180,12 +180,12 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error copy(addr[:], ipv6Header.Src[:]) copy(target[:], datain[48:64]) copy(mac[:], (*datamac)[:]) - i.tun.core.log.Printf("Learning peer MAC %x for %x\n", mac, target) + // i.tun.core.log.Printf("Learning peer MAC %x for %x\n", mac, target) neighbor := i.peermacs[target] neighbor.mac = mac neighbor.learned = true neighbor.lastadvertisement = time.Now() - i.peermacs[addr] = neighbor + i.peermacs[target] = neighbor } return nil, errors.New("No response needed") } From 702317add1e24be57f9a4d393010b7e342262400 Mon Sep 17 00:00:00 2001 From: sin Date: Wed, 26 Dec 2018 14:25:17 +0000 Subject: [PATCH 15/47] Use #!/bin/sh for clean script --- clean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clean b/clean index 4361a7be..a1036764 100755 --- a/clean +++ b/clean @@ -1,2 +1,2 @@ -#!/bin/bash +#!/bin/sh git clean -dxf From 4e03bdb054e14bbfee69d53323c235f0f0fe27d5 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 26 Dec 2018 22:45:21 +0000 Subject: [PATCH 16/47] Don't process ICMPv6 messages when in TUN mode --- src/yggdrasil/icmpv6.go | 6 ++++++ src/yggdrasil/tun.go | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/yggdrasil/icmpv6.go b/src/yggdrasil/icmpv6.go index fc037fcb..52ca50c6 100644 --- a/src/yggdrasil/icmpv6.go +++ b/src/yggdrasil/icmpv6.go @@ -156,6 +156,9 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error // Check for a supported message type switch icmpv6Header.Type { case ipv6.ICMPTypeNeighborSolicitation: + if !i.tun.iface.IsTAP() { + return nil, errors.New("Ignoring Neighbor Solicitation in TUN mode") + } response, err := i.handle_ndp(datain[ipv6.HeaderLen:]) if err == nil { // Create our ICMPv6 response @@ -173,6 +176,9 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error return nil, err } case ipv6.ICMPTypeNeighborAdvertisement: + if !i.tun.iface.IsTAP() { + return nil, errors.New("Ignoring Neighbor Advertisement in TUN mode") + } if datamac != nil { var addr address.Address var target address.Address diff --git a/src/yggdrasil/tun.go b/src/yggdrasil/tun.go index b6bc9132..8ed53332 100644 --- a/src/yggdrasil/tun.go +++ b/src/yggdrasil/tun.go @@ -214,11 +214,12 @@ func (tun *tunAdapter) read() error { continue } if buf[o+6] == 58 { - // Found an ICMPv6 packet - b := make([]byte, n) - copy(b, buf) - // tun.icmpv6.recv <- b - go tun.icmpv6.parse_packet(b) + if tun.iface.IsTAP() { + // Found an ICMPv6 packet + b := make([]byte, n) + copy(b, buf) + go tun.icmpv6.parse_packet(b) + } } packet := append(util.GetBytes(), buf[o:n]...) tun.send <- packet From 52e64614332ce2ed4124d9b2f40c0e320a81d09b Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 26 Dec 2018 23:28:12 +0000 Subject: [PATCH 17/47] Update changelog for v0.3.2 --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c8994fd..84b5c38b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - in case of vulnerabilities. --> +## [0.3.2] - 2018-12-26 +### Added +- The admin socket is now multithreaded, greatly improving performance of the crawler and allowing concurrent lookups to take place +- The ability to hide NodeInfo defaults through either setting the `NodeInfoPrivacy` option or through setting individual `NodeInfo` attributes to `null` + +### Changed +- The `armhf` build now targets ARMv6 instead of ARMv7, adding support for Raspberry Pi Zero and other older models, amongst others + +### Fixed +- DHT entries are now populated using a copy in memory to fix various potential DHT bugs +- DHT traffic should now throttle back exponentially to reduce idle traffic +- Adjust how nodes are inserted into the DHT which should help to reduce some incorrect DHT traffic +- In TAP mode, the NDP target address is now correctly used when populating the peer MAC table. This fixes serious connectivity problems when in TAP mode, particularly on BSD +- In TUN mode, ICMPv6 packets are now ignored whereas they were incorrectly processed before + ## [0.3.1] - 2018-12-17 ### Added - Build name and version is now imprinted onto the binaries if available/specified during build From b4a7dab34da3a746518916b710e1f4842840e486 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 26 Dec 2018 23:50:17 +0000 Subject: [PATCH 18/47] Versioning be damned --- .circleci/config.yml | 10 ---------- contrib/semver/version.sh | 4 ---- 2 files changed, 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e548aa1f..8725e443 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -98,13 +98,3 @@ jobs: - store_artifacts: path: /tmp/upload destination: / - - - run: - name: Create tags (master branch only) - command: > - if [ "${CIRCLE_BRANCH}" == "master" ]; then - (git tag -a $(sh contrib/semver/version.sh) -m "Created by CircleCI" && git push --tags) || true; - else - echo "Only runs for master branch (this is ${CIRCLE_BRANCH})"; - fi; - when: on_success diff --git a/contrib/semver/version.sh b/contrib/semver/version.sh index 03b5da2c..964a3208 100644 --- a/contrib/semver/version.sh +++ b/contrib/semver/version.sh @@ -60,8 +60,4 @@ if [ $BRANCH != "master" ]; then if [ $BUILD != 0 ]; then printf -- "-%04d" "$BUILD" fi -else - if [ $BUILD != 0 ]; then - printf -- "-%d" "$(($BUILD+1))" - fi fi From e6a246f0408eaa688ac3d81bac6dcdac8f9a12b8 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 27 Dec 2018 20:03:46 +0000 Subject: [PATCH 19/47] Chop up contrib/semver/version.sh --- contrib/semver/version.sh | 61 +++++++++------------------------------ 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/contrib/semver/version.sh b/contrib/semver/version.sh index 964a3208..37fc524f 100644 --- a/contrib/semver/version.sh +++ b/contrib/semver/version.sh @@ -1,63 +1,30 @@ #!/bin/sh -# Merge commits from this branch are counted -DEVELOPBRANCH="yggdrasil-network/develop" - # Get the last tag -TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.0" 2>/dev/null) +TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" 2>/dev/null) +test $? != 0 && (echo "unknown"; exit 1) -# Get last merge to master -MERGE=$(git rev-list $TAG..master --grep "from $DEVELOPBRANCH" 2>/dev/null | head -n 1) - -# Get the number of merges since the last merge to master -PATCH=$(git rev-list $TAG..master --count --merges --grep="from $DEVELOPBRANCH" --first-parent master 2>/dev/null) - -# Decide whether we should prepend the version with "v" - the default is that -# we do because we use it in git tags, but we might not always need it -PREPEND="v" -if [ "$1" = "--bare" ]; then - PREPEND="" -fi - -# If it fails then there's no last tag - go from the first commit -if [ $? != 0 ]; then - PATCH=$(git rev-list HEAD --count 2>/dev/null) - - # Complain if the git history is not available - if [ $? != 0 ]; then - printf 'unknown' - exit 1 - fi - - printf '%s0.0.%d' "$PREPEND" "$PATCH" - exit 1 -fi +# Get the current branch +BRANCH=$(git symbolic-ref -q HEAD --short 2>/dev/null) +test $? != 0 && BRANCH="master" # Split out into major, minor and patch numbers MAJOR=$(echo $TAG | cut -c 2- | cut -d "." -f 1) MINOR=$(echo $TAG | cut -c 2- | cut -d "." -f 2) - -# Get the current checked out branch -BRANCH=$(git rev-parse --abbrev-ref HEAD) +PATCH=$(echo $TAG | cut -c 2- | cut -d "." -f 3) # Output in the desired format -if [ $PATCH = 0 ]; then - if [ ! -z $FULL ]; then - printf '%s%d.%d.0' "$PREPEND" "$MAJOR" "$MINOR" - else - printf '%s%d.%d' "$PREPEND" "$MAJOR" "$MINOR" - fi +if [ $((PATCH)) -eq 0 ]; then + printf '%s%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))" else - printf '%s%d.%d.%d' "$PREPEND" "$MAJOR" "$MINOR" "$PATCH" + printf '%s%d.%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))" "$((PATCH))" fi -# Get the number of merges on the current branch since the last tag -TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" --first-parent master 2>/dev/null) -BUILD=$(git rev-list $TAG.. --count) - # Add the build tag on non-master branches -if [ $BRANCH != "master" ]; then - if [ $BUILD != 0 ]; then - printf -- "-%04d" "$BUILD" +if [ "$BRANCH" != "master" ]; then + BUILD=$(git rev-list $TAG..HEAD --count) + + if [ $? == 0 ] && [ $((BUILD)) -gt 0 ]; then + printf -- "-%04d" "$((BUILD))" fi fi From 57894541b78dc1b597103a0fd15b82d073780935 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 27 Dec 2018 21:14:23 +0000 Subject: [PATCH 20/47] Check string emptiness --- contrib/semver/version.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/contrib/semver/version.sh b/contrib/semver/version.sh index 37fc524f..14dafa15 100644 --- a/contrib/semver/version.sh +++ b/contrib/semver/version.sh @@ -2,11 +2,11 @@ # Get the last tag TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" 2>/dev/null) -test $? != 0 && (echo "unknown"; exit 1) +(test $? != 0 || test -z "$TAG") && (echo "unknown"; exit 1) # Get the current branch BRANCH=$(git symbolic-ref -q HEAD --short 2>/dev/null) -test $? != 0 && BRANCH="master" +(test $? != 0 || test -z "$BRANCH") && BRANCH="master" # Split out into major, minor and patch numbers MAJOR=$(echo $TAG | cut -c 2- | cut -d "." -f 1) @@ -23,8 +23,9 @@ fi # Add the build tag on non-master branches if [ "$BRANCH" != "master" ]; then BUILD=$(git rev-list $TAG..HEAD --count) - - if [ $? == 0 ] && [ $((BUILD)) -gt 0 ]; then - printf -- "-%04d" "$((BUILD))" + if [ $? = 0 ] && [ -n "$BUILD" ]; then + if [ $((BUILD)) -gt 0 ]; then + printf -- "-%04d" "$((BUILD))" + fi fi fi From 7eaee172cf22e5b54a619a2a08c233f83511224c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 27 Dec 2018 21:22:46 +0000 Subject: [PATCH 21/47] Replace tests with ifs --- contrib/semver/version.sh | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/contrib/semver/version.sh b/contrib/semver/version.sh index 14dafa15..ca035ff5 100644 --- a/contrib/semver/version.sh +++ b/contrib/semver/version.sh @@ -2,11 +2,20 @@ # Get the last tag TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" 2>/dev/null) -(test $? != 0 || test -z "$TAG") && (echo "unknown"; exit 1) + +# Did getting the tag succeed? +if [ $? != 0 ] || [ -z "$TAG" ]; then + printf "unknown" + exit 1 +fi # Get the current branch BRANCH=$(git symbolic-ref -q HEAD --short 2>/dev/null) -(test $? != 0 || test -z "$BRANCH") && BRANCH="master" + +# Did getting the branch succeed? +if [ $? != 0 ] || [ -z "$BRANCH" ]; then + BRANCH="master" +fi # Split out into major, minor and patch numbers MAJOR=$(echo $TAG | cut -c 2- | cut -d "." -f 1) @@ -22,10 +31,15 @@ fi # Add the build tag on non-master branches if [ "$BRANCH" != "master" ]; then - BUILD=$(git rev-list $TAG..HEAD --count) - if [ $? = 0 ] && [ -n "$BUILD" ]; then - if [ $((BUILD)) -gt 0 ]; then - printf -- "-%04d" "$((BUILD))" - fi + BUILD=$(git rev-list $TAG..HEAD --count 2>/dev/null) + + # Did getting the count of commits since the tag succeed? + if [ $? != 0 ] && [ -z "$BUILD" ]; then + exit 1 + fi + + # Is the build greater than zero? + if [ $((BUILD)) -gt 0 ]; then + printf -- "-%04d" "$((BUILD))" fi fi From 6fcd8a8dbdb290a045e7d54b84e59df425859837 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 27 Dec 2018 21:36:50 +0000 Subject: [PATCH 22/47] Fix incorrect check --- contrib/semver/version.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/semver/version.sh b/contrib/semver/version.sh index ca035ff5..7d4f3736 100644 --- a/contrib/semver/version.sh +++ b/contrib/semver/version.sh @@ -5,7 +5,7 @@ TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" 2>/dev/nu # Did getting the tag succeed? if [ $? != 0 ] || [ -z "$TAG" ]; then - printf "unknown" + printf -- "unknown" exit 1 fi @@ -34,7 +34,8 @@ if [ "$BRANCH" != "master" ]; then BUILD=$(git rev-list $TAG..HEAD --count 2>/dev/null) # Did getting the count of commits since the tag succeed? - if [ $? != 0 ] && [ -z "$BUILD" ]; then + if [ $? != 0 ] || [ -z "$BUILD" ]; then + printf -- "-unknown" exit 1 fi From 8c7b9e2f90f2b1ce8f432295599acdcb1b963e0c Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 27 Dec 2018 21:44:29 +0000 Subject: [PATCH 23/47] Add a null check to name.sh --- contrib/semver/name.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/semver/name.sh b/contrib/semver/name.sh index 935cc750..1fa2ce07 100644 --- a/contrib/semver/name.sh +++ b/contrib/semver/name.sh @@ -4,8 +4,8 @@ BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null) # Complain if the git history is not available -if [ $? != 0 ]; then - printf "unknown" +if [ $? != 0 ] || [ -z "$BRANCH" ]; then + printf "yggdrasil" exit 1 fi From e6e7f9377f47c5101ac20bccf9782361eeafb6e6 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 27 Dec 2018 21:45:30 +0000 Subject: [PATCH 24/47] Move --count parameter --- contrib/semver/version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/semver/version.sh b/contrib/semver/version.sh index 7d4f3736..3052094a 100644 --- a/contrib/semver/version.sh +++ b/contrib/semver/version.sh @@ -31,7 +31,7 @@ fi # Add the build tag on non-master branches if [ "$BRANCH" != "master" ]; then - BUILD=$(git rev-list $TAG..HEAD --count 2>/dev/null) + BUILD=$(git rev-list --count $TAG..HEAD 2>/dev/null) # Did getting the count of commits since the tag succeed? if [ $? != 0 ] || [ -z "$BUILD" ]; then From fb47c9822fc62acae64e41aaf1cea6617ad42457 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 31 Dec 2018 11:48:50 +0000 Subject: [PATCH 25/47] getNodeInfo: Show own info if box_pub_key/coords not specified --- src/yggdrasil/admin.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index bd3c9051..2496b309 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -324,12 +324,27 @@ func (a *admin) init(c *Core, listenaddr string) { return admin_info{}, err } }) - a.addHandler("getNodeInfo", []string{"box_pub_key", "coords", "[nocache]"}, func(in admin_info) (admin_info, error) { + a.addHandler("getNodeInfo", []string{"[box_pub_key]", "[coords]", "[nocache]"}, func(in admin_info) (admin_info, error) { var nocache bool if in["nocache"] != nil { nocache = in["nocache"].(string) == "true" } - result, err := a.admin_getNodeInfo(in["box_pub_key"].(string), in["coords"].(string), nocache) + var box_pub_key, coords string + if in["box_pub_key"] == nil && in["coords"] == nil { + nodeinfo := []byte(a.core.nodeinfo.getNodeInfo()) + var jsoninfo interface{} + if err := json.Unmarshal(nodeinfo, &jsoninfo); err != nil { + return admin_info{}, err + } else { + return admin_info{"nodeinfo": jsoninfo}, nil + } + } else if in["box_pub_key"] == nil || in["coords"] == nil { + return admin_info{}, errors.New("Expecting both box_pub_key and coords") + } else { + box_pub_key = in["box_pub_key"].(string) + coords = in["coords"].(string) + } + result, err := a.admin_getNodeInfo(box_pub_key, coords, nocache) if err == nil { var m map[string]interface{} if err = json.Unmarshal(result, &m); err == nil { From 53aeca8fa27ee8207081cedc67a0cf8c90ab7774 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 1 Jan 2019 23:25:20 +0000 Subject: [PATCH 26/47] 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 27/47] 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 28/47] 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 29/47] 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 30/47] 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 31/47] 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 32/47] 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 33/47] 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 34/47] 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 35/47] 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 36/47] 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 37/47] 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 38/47] 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 39/47] 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 40/47] 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 41/47] 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 42/47] 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 43/47] 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 44/47] 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 45/47] 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 46/47] 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 47/47] 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