From 56842794032bfea2cabe0a38fe725b9979724fe9 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 18 Dec 2018 11:47:46 +0000 Subject: [PATCH 01/22] CircleCI: don't recreate tags that already exist --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f3092ba1..907aa8b0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -103,7 +103,7 @@ jobs: name: Create tags (master branch only) command: > if [ "${CIRCLE_BRANCH}" == "master" ]; then - git tag -f -a $(sh contrib/semver/version.sh) -m "Created by CircleCI" && git push -f --tags; + git tag -a $(sh contrib/semver/version.sh) -m "Created by CircleCI" && git push --tags; else echo "Only runs for master branch (this is ${CIRCLE_BRANCH})"; fi; From bfdb079b791a532af3a3a7ce3d6d742fca89d7c7 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 18 Dec 2018 11:52:22 +0000 Subject: [PATCH 02/22] Append suffix to master releaser releases if they are not the first merge (package revisions) --- contrib/semver/version.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/semver/version.sh b/contrib/semver/version.sh index a53ed32c..a17cf6fe 100644 --- a/contrib/semver/version.sh +++ b/contrib/semver/version.sh @@ -59,4 +59,8 @@ if [ $BRANCH != "master" ]; then if [ $BUILD != 0 ]; then printf -- "-%04d" "$BUILD" fi +else + if [ $BUILD != 0 ]; then + printf -- "-%d" "$BUILD" + fi fi From 3ea33c9fa72ae0dcdf04e6d0fc2872aae28cdc68 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 18 Dec 2018 12:03:23 +0000 Subject: [PATCH 03/22] Fix build tags maybe? --- contrib/semver/version.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/semver/version.sh b/contrib/semver/version.sh index a17cf6fe..2b3c4bc3 100644 --- a/contrib/semver/version.sh +++ b/contrib/semver/version.sh @@ -33,9 +33,6 @@ if [ $? != 0 ]; then exit 1 fi -# Get the number of merges on the current branch since the last tag -BUILD=$(git rev-list $TAG..HEAD --count --merges) - # 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) @@ -54,6 +51,10 @@ else 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]*" 2>/dev/null) +BUILD=$(git rev-list $TAG..$BRANCH --count) + # Add the build tag on non-master branches if [ $BRANCH != "master" ]; then if [ $BUILD != 0 ]; then From 09ea9a166f988fdc784727a3f0134b854960a221 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Tue, 18 Dec 2018 12:14:47 +0000 Subject: [PATCH 04/22] More tweaks to semver --- contrib/semver/version.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/semver/version.sh b/contrib/semver/version.sh index 2b3c4bc3..03b5da2c 100644 --- a/contrib/semver/version.sh +++ b/contrib/semver/version.sh @@ -52,8 +52,8 @@ else 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]*" 2>/dev/null) -BUILD=$(git rev-list $TAG..$BRANCH --count) +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 @@ -62,6 +62,6 @@ if [ $BRANCH != "master" ]; then fi else if [ $BUILD != 0 ]; then - printf -- "-%d" "$BUILD" + printf -- "-%d" "$(($BUILD+1))" fi fi From ace956898193e50e10a50a9f593b4e792ad3ce04 Mon Sep 17 00:00:00 2001 From: darkdrgn2k Date: Tue, 18 Dec 2018 11:36:15 -0500 Subject: [PATCH 05/22] Added compile support for Arm v6 Support for older raspberry pis and Pi Zero --- contrib/deb/generate.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/deb/generate.sh b/contrib/deb/generate.sh index ed2c1c96..aea9cd91 100644 --- a/contrib/deb/generate.sh +++ b/contrib/deb/generate.sh @@ -26,9 +26,10 @@ elif [ $PKGARCH = "i386" ]; then GOARCH=386 GOOS=linux ./build elif [ $PKGARCH = "mipsel" ]; then GOARCH=mipsle GOOS=linux ./build elif [ $PKGARCH = "mips" ]; then GOARCH=mips64 GOOS=linux ./build elif [ $PKGARCH = "armhf" ]; then GOARCH=arm GOOS=linux GOARM=7 ./build +elif [ $PKGARCH = "armv6" ]; then export PKGARCH="armhf"; GOARCH=arm GOOS=linux GOARM=6 ./build; elif [ $PKGARCH = "arm64" ]; then GOARCH=arm64 GOOS=linux ./build else - echo "Specify PKGARCH=amd64,i386,mips,mipsel,armhf,arm64" + echo "Specify PKGARCH=amd64,i386,mips,mipsel,armv6,armhf,arm64" exit 1 fi From f91fb1045c5364fbd944a26d839fe271e7e42178 Mon Sep 17 00:00:00 2001 From: darkdrgn2k Date: Tue, 18 Dec 2018 12:28:15 -0500 Subject: [PATCH 06/22] Downgraded all armhf builds to v6 --- contrib/deb/generate.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contrib/deb/generate.sh b/contrib/deb/generate.sh index aea9cd91..6c8f955d 100644 --- a/contrib/deb/generate.sh +++ b/contrib/deb/generate.sh @@ -25,11 +25,10 @@ if [ $PKGARCH = "amd64" ]; then GOARCH=amd64 GOOS=linux ./build elif [ $PKGARCH = "i386" ]; then GOARCH=386 GOOS=linux ./build elif [ $PKGARCH = "mipsel" ]; then GOARCH=mipsle GOOS=linux ./build elif [ $PKGARCH = "mips" ]; then GOARCH=mips64 GOOS=linux ./build -elif [ $PKGARCH = "armhf" ]; then GOARCH=arm GOOS=linux GOARM=7 ./build -elif [ $PKGARCH = "armv6" ]; then export PKGARCH="armhf"; GOARCH=arm GOOS=linux GOARM=6 ./build; +elif [ $PKGARCH = "armhf" ]; then GOARCH=arm GOOS=linux GOARM=6 ./build elif [ $PKGARCH = "arm64" ]; then GOARCH=arm64 GOOS=linux ./build else - echo "Specify PKGARCH=amd64,i386,mips,mipsel,armv6,armhf,arm64" + echo "Specify PKGARCH=amd64,i386,mips,mipsel,armhf,arm64" exit 1 fi From 3283de17d5c6235e223033e5edd09d150044f688 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 19 Dec 2018 00:15:12 +0000 Subject: [PATCH 07/22] Don't fail if tag exists --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 907aa8b0..e548aa1f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -103,7 +103,7 @@ jobs: 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; + (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; From dfcdafa55c30e89f252f7076e32041700547c224 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Thu, 20 Dec 2018 17:37:59 -0600 Subject: [PATCH 08/22] 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 09/22] 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 10/22] 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 11/22] 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 12/22] 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 13/22] 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 14/22] 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 15/22] 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 16/22] 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 17/22] 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 18/22] 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 19/22] 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 20/22] 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 21/22] 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 22/22] 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