Browse Source

Use blockchain as address table

This change rewires thing in a way that we consume less bandwidth.
Instead of broadcasting the interface messages, we broadcast a
blockchain that dynamically tracks records of the address and the nodes
of the network.

The blockchain is sealed and keys are automatically rotated via OTP. The
messages are then sent over p2p network selectively for each stream by
decoding the interface packet, and using the blockchain as resolver
Ettore Di Giacinto 4 years ago
parent
commit
ff3292c6f0
13 changed files with 468 additions and 150 deletions
  1. 18 11
      README.md
  2. 5 5
      go.mod
  3. 32 28
      go.sum
  4. 7 3
      main.go
  5. 66 0
      pkg/blockchain/block.go
  6. 176 0
      pkg/blockchain/ledger.go
  7. 16 15
      pkg/discovery/dht.go
  8. 3 1
      pkg/edgevpn/config.go
  9. 6 4
      pkg/edgevpn/connection.go
  10. 117 42
      pkg/edgevpn/edgevpn.go
  11. 0 18
      pkg/edgevpn/interface_windows.go
  12. 4 0
      pkg/edgevpn/message.go
  13. 18 23
      pkg/edgevpn/options.go

+ 18 - 11
README.md

@@ -2,27 +2,40 @@
 
 Fully Decentralized. Immutable. Portable. Easy to use Statically compiled VPN
 
+EdgeVPN uses libp2p to connect and create a blockchain between nodes. It keeps the routing table stored in the ledger, while connections are dynamically established via p2p.
+
 ## Usage
 
-Generate a config:
+Generate a config, and send it over all the nodes you wish to connect:
 
 ```bash
 ./edgevpn -g > config.yaml
 ```
 
-Run it on multiple hosts:
+Run edgevpn on multiple hosts:
 
 ```bash
+# on Node A
 EDGEVPNCONFIG=config.yaml IFACE=edgevpn0 ADDRESS=10.1.0.11/24 ./edgevpn
+# on Node B
 EDGEVPNCONFIG=config.yaml IFACE=edgevpn0 ADDRESS=10.1.0.12/24 ./edgevpn
+# on Node C ...
 EDGEVPNCONFIG=config.yaml IFACE=edgevpn0 ADDRESS=10.1.0.13/24 ./edgevpn
 ...
 ```
 
-... and that's it!
+... and that's it! the `ADDRESS` is a _virtual_ unique IP for each node, and it is actually the ip where the node will be reachable to from the vpn, while `IFACE` is the interface name.
 
 *Note*: It might take up time to build the connection between nodes. Wait at least 5 mins, it depends on the network behind the hosts.
 
+## Architecture
+
+- p2p encryption between peers with libp2p
+- randezvous points dynamically generated from OTP keys
+- extra AES symmetric encryption on top. In case randezvous point is compromised
+- blockchain is used as a sealed encrypted store for the routing table
+- connections are created host to host
+
 ## Is it for me?
 
 EdgeVPN makes VPN decentralization a first strong requirement. 
@@ -31,8 +44,8 @@ Its mainly use is for edge and low-end devices and especially for development.
 
 The decentralized approach has few cons:
 
-- The underlaying network is chatty. It uses a Gossip protocol and p2p. Every message is broadcasted to all peers.
-- Not suited for low latency. On my local tests on very slow connections, ping took ~200ms.
+- The underlaying network is chatty. It uses a Gossip protocol for syncronizing the routing table and p2p. Every blockchain message is broadcasted to all peers, while the traffic is to the host only.
+- Might be not suited for low latency workload.
 
 Keep that in mind before using it for your prod networks!
 
@@ -82,12 +95,6 @@ e.Start()
 
 ```
 
-## Architecture
-
-- p2p encryption between peers with libp2p
-- randezvous points dynamically generated from OTP keys
-- extra AES symmetric encryption on top. In case randezvous point is compromised
-
 ## Credits
 
 - The awesome [libp2p](https://github.com/libp2p) library

+ 5 - 5
go.mod

@@ -6,22 +6,22 @@ require (
 	github.com/ipfs/go-ipns v0.1.2 // indirect
 	github.com/ipfs/go-log/v2 v2.3.0
 	github.com/kr/text v0.2.0 // indirect
-	github.com/libp2p/go-libp2p v0.15.0
+	github.com/libp2p/go-libp2p v0.15.1
 	github.com/libp2p/go-libp2p-core v0.9.0
 	github.com/libp2p/go-libp2p-discovery v0.5.1
-	github.com/libp2p/go-libp2p-kad-dht v0.11.1
+	github.com/libp2p/go-libp2p-kad-dht v0.12.1
 	github.com/libp2p/go-libp2p-pubsub v0.5.4
-	github.com/libp2p/go-libp2p-quic-transport v0.11.2
-	github.com/libp2p/go-tcp-transport v0.2.8
+	github.com/libp2p/go-libp2p-quic-transport v0.12.0 // indirect
 	github.com/lthibault/jitterbug v2.0.0+incompatible
 	github.com/multiformats/go-multiaddr v0.4.0
 	github.com/pkg/errors v0.9.1
 	github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091
 	github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
-	github.com/urfave/cli/v2 v2.3.0
 	github.com/vishvananda/netlink v1.1.0
 	github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
+	go.opencensus.io v0.23.0 // indirect
 	go.uber.org/zap v1.19.0
+	golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
 	gopkg.in/yaml.v2 v2.4.0
 )
 

+ 32 - 28
go.sum

@@ -97,10 +97,7 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
 github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
 github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
 github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
-github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
-github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
@@ -126,9 +123,7 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
 github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
 github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -245,6 +240,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -252,7 +248,6 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u
 github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
-github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
 github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
 github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -268,6 +263,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
@@ -299,8 +295,9 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
 github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
 github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@@ -459,9 +456,9 @@ github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZk
 github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=
 github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=
 github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o=
-github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0=
-github.com/libp2p/go-libp2p v0.15.0 h1:jbMbdmtizfpvl1+oQuGJzfGhttAtuxUCavF3enwFncg=
-github.com/libp2p/go-libp2p v0.15.0/go.mod h1:8Ljmwon0cZZYKrOCjFeLwQEK8bqR42dOheUZ1kSKhP0=
+github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo=
+github.com/libp2p/go-libp2p v0.15.1 h1:wSC//fziln3aMTwgF2vOl0v+hTSFfsdr686Fl0uD3ug=
+github.com/libp2p/go-libp2p v0.15.1/go.mod h1:93vekOmNoLAcHXUYYEBot0Df/Z6tm46xu9NeCaiKdnM=
 github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052 h1:BM7aaOF7RpmNn9+9g6uTjGJ0cTzWr5j9i9IKeun2M8U=
 github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=
 github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=
@@ -503,6 +500,7 @@ github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJB
 github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
 github.com/libp2p/go-libp2p-core v0.8.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
 github.com/libp2p/go-libp2p-core v0.8.2/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
+github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
 github.com/libp2p/go-libp2p-core v0.8.6/go.mod h1:dgHr0l0hIKfWpGpqAMbpo19pen9wJfdCGv51mTmdpmM=
 github.com/libp2p/go-libp2p-core v0.9.0 h1:t97Mv0LIBZlP2FXVRNKKVzHJCIjbIWGxYptGId4+htU=
 github.com/libp2p/go-libp2p-core v0.9.0/go.mod h1:ESsbz31oC3C1AvMJoGx26RTuCkNhmkSRCqZ0kQtJ2/8=
@@ -512,8 +510,9 @@ github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQO
 github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=
 github.com/libp2p/go-libp2p-discovery v0.5.1 h1:CJylx+h2+4+s68GvrM4pGNyfNhOYviWBPtVv5PA7sfo=
 github.com/libp2p/go-libp2p-discovery v0.5.1/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=
-github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc=
-github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI=
+github.com/libp2p/go-libp2p-kad-dht v0.12.1 h1:6HsBhzxcD34rE7Ds2lK9q6llPE7/tdqV7JmJiukEcQ8=
+github.com/libp2p/go-libp2p-kad-dht v0.12.1/go.mod h1:zdQYru1c7dnluMpZls4i9Fj2TwYXS7YyDkJ1Yahv0w0=
+github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio=
 github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70=
 github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk=
 github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=
@@ -521,7 +520,7 @@ github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3
 github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=
 github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=
 github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=
-github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs=
+github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw=
 github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc=
 github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g=
 github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
@@ -540,14 +539,16 @@ github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnq
 github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
 github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
 github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
+github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
 github.com/libp2p/go-libp2p-peerstore v0.2.8 h1:nJghUlUkFVvyk7ccsM67oFA6kqUkwyCM1G4WPVMCWYA=
 github.com/libp2p/go-libp2p-peerstore v0.2.8/go.mod h1:gGiPlXdz7mIHd2vfAsHzBNAMqSDkt2UBFwgcITgw1lA=
 github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
 github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
 github.com/libp2p/go-libp2p-pubsub v0.5.4 h1:rHl9/Xok4zX3zgi0pg0XnUj9Xj2OeXO8oTu85q2+YA8=
 github.com/libp2p/go-libp2p-pubsub v0.5.4/go.mod h1:gVOzwebXVdSMDQBTfH8ACO5EJ4SQrvsHqCmYsCZpD0E=
-github.com/libp2p/go-libp2p-quic-transport v0.11.2 h1:p1YQDZRHH4Cv2LPtHubqlQ9ggz4CKng/REZuXZbZMhM=
 github.com/libp2p/go-libp2p-quic-transport v0.11.2/go.mod h1:wlanzKtIh6pHrq+0U3p3DY9PJfGqxMgPaGKaK5LifwQ=
+github.com/libp2p/go-libp2p-quic-transport v0.12.0 h1:7IjDH4XNkmJbOMD+mxRloTe4LzMTq+vqvm2nYNL1N7M=
+github.com/libp2p/go-libp2p-quic-transport v0.12.0/go.mod h1:EKHqxZbWE/FhDJZ6ebyZ/4v3X9zyuuuKIN0XR9vANT0=
 github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=
 github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0=
 github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4=
@@ -561,7 +562,7 @@ github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaT
 github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM=
 github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM=
 github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
-github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
+github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw=
 github.com/libp2p/go-libp2p-swarm v0.5.3 h1:hsYaD/y6+kZff1o1Mc56NcuwSg80lIphTS/zDk3mO4M=
 github.com/libp2p/go-libp2p-swarm v0.5.3/go.mod h1:NBn7eNW2lu568L7Ns9wdFrOhgRlkRnIDg0FLKbuu3i8=
 github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
@@ -580,9 +581,11 @@ github.com/libp2p/go-libp2p-tls v0.2.0/go.mod h1:twrp2Ci4lE2GYspA1AnlYm+boYjqVru
 github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=
 github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=
 github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o=
+github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s=
 github.com/libp2p/go-libp2p-transport-upgrader v0.4.3/go.mod h1:bpkldbOWXMrXhpZbSV1mQxTrefOg2Fi+k1ClDSA4ppw=
 github.com/libp2p/go-libp2p-transport-upgrader v0.4.6 h1:SHt3g0FslnqIkEWF25YOB8UCOCTpGAVvHRWQYJ+veiI=
 github.com/libp2p/go-libp2p-transport-upgrader v0.4.6/go.mod h1:JE0WQuQdy+uLZ5zOaI3Nw9dWGYJIA7mywEtP2lMvnyk=
+github.com/libp2p/go-libp2p-xor v0.0.0-20200501025846-71e284145d58/go.mod h1:AYjOiqJIdcmI4SXE2ouKQuFrUbE5myv8txWaB2pl4TI=
 github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=
 github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw=
 github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA=
@@ -590,6 +593,7 @@ github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhL
 github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4=
 github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30=
 github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po=
+github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4=
 github.com/libp2p/go-libp2p-yamux v0.5.4 h1:/UOPtT/6DHPtr3TtKXBHa6g0Le0szYuI33Xc/Xpd7fQ=
 github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3BuHoeTSqhcel1wsE=
 github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
@@ -646,7 +650,7 @@ github.com/libp2p/go-tcp-transport v0.2.8 h1:aLjX+Nkz+kIz3uA56WtlGKRSAnKDvnqKmv1
 github.com/libp2p/go-tcp-transport v0.2.8/go.mod h1:64rSfVidkYPLqbzpcN2IwHY4pmgirp67h++hZ/rcndQ=
 github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=
 github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
-github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
+github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA=
 github.com/libp2p/go-ws-transport v0.5.0 h1:cO6x4P0v6PfxbKnxmf5cY2Ny4OPDGYkUqNvZzp/zdlo=
 github.com/libp2p/go-ws-transport v0.5.0/go.mod h1:I2juo1dNTbl8BKSBYo98XY85kU2xds1iamArLvl8kNg=
 github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
@@ -657,16 +661,18 @@ github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/h
 github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
 github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI=
 github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
+github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U=
 github.com/libp2p/go-yamux/v2 v2.2.0 h1:RwtpYZ2/wVviZ5+3pjC8qdQ4TKnrak0/E01N1UWoAFU=
 github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ=
-github.com/libp2p/zeroconf/v2 v2.0.0 h1:qYAHAqUVh4hMSfu+iDTZNqH07wLGAvb1+DW4Tx/qUoQ=
-github.com/libp2p/zeroconf/v2 v2.0.0/go.mod h1:J85R/d9joD8u8F9aHM8pBXygtG9W02enEwS+wWeL6yo=
+github.com/libp2p/zeroconf/v2 v2.1.0 h1:9aZt2jwaBjkAJ/1cZnRTvzfN0eCDYaJWTjHST5tZIlk=
+github.com/libp2p/zeroconf/v2 v2.1.0/go.mod h1:vtRu3WOBoLRiQ3BhDvIJwvvrRakbTevCVLSr9/Ljess=
 github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/lthibault/jitterbug v2.0.0+incompatible h1:qouq51IKzlMx25+15jbxhC/d79YyTj0q6XFoptNqaUw=
 github.com/lthibault/jitterbug v2.0.0+incompatible/go.mod h1:2l7akWd27PScEs6YkjyUVj/8hKgNhbbQ3KiJgJtlf6o=
-github.com/lucas-clemente/quic-go v0.21.2 h1:8LqqL7nBQFDUINadW0fHV/xSaCQJgmJC0Gv+qUnjd78=
 github.com/lucas-clemente/quic-go v0.21.2/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0T3FQhz/uyOUS38Q=
+github.com/lucas-clemente/quic-go v0.23.0 h1:5vFnKtZ6nHDFsc/F3uuiF4T3y/AXaQdxjUqiVw26GZE=
+github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
 github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -674,12 +680,12 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN
 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
 github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
-github.com/marten-seemann/qtls-go1-15 v0.1.5 h1:Ci4EIUN6Rlb+D6GmLdej/bCQ4nPYNtVXQB+xjiXE1nk=
 github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
 github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2iHl5yhJRpnco=
 github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
-github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1 h1:/rpmWuGvceLwwWuaKPdjpR4JJEUH0tq64/I3hvzaNLM=
 github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
+github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk=
+github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -896,9 +902,7 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
@@ -924,7 +928,6 @@ github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b
 github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
 github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
 github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
 github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
@@ -975,16 +978,14 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cb
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
-github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
 github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
 github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
 github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
 github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
 github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=
 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w=
 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
 github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
@@ -1017,8 +1018,9 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -1152,6 +1154,7 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
@@ -1417,6 +1420,7 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
 google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
 google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
 google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=

+ 7 - 3
main.go

@@ -41,11 +41,12 @@ func main() {
 		edgevpn.Logger(l),
 		edgevpn.LogLevel(log.LevelInfo),
 		edgevpn.MaxMessageSize(2 << 20), // 2MB
-		edgevpn.WithMTU(1500),
-		edgevpn.WithInterfaceMTU(1300),
+		edgevpn.WithInterfaceMTU(1450),
+		edgevpn.WithPacketMTU(1420),
 		edgevpn.WithInterfaceAddress(os.Getenv("ADDRESS")),
 		edgevpn.WithInterfaceName(os.Getenv("IFACE")),
-		edgevpn.WithInterfaceType(water.TAP),
+		edgevpn.WithMaxBlockChainSize(1000),
+		edgevpn.WithInterfaceType(water.TUN),
 		edgevpn.NetLinkBootstrap(true),
 	}
 
@@ -96,4 +97,7 @@ func main() {
 	if err := e.Start(); err != nil {
 		l.Sugar().Fatal(err.Error())
 	}
+
+	for {
+	}
 }

+ 66 - 0
pkg/blockchain/block.go

@@ -0,0 +1,66 @@
+package blockchain
+
+import (
+	"crypto/sha256"
+	"encoding/hex"
+	"fmt"
+	"time"
+)
+
+// Block represents each 'item' in the blockchain
+type Block struct {
+	Index      int
+	Timestamp  string
+	AddressMap map[string]string
+	Hash       string
+	PrevHash   string
+}
+
+// Blockchain is a series of validated Blocks
+type Blockchain []Block
+
+func (b Blockchain) IsMoreRecent(bb Blockchain) bool {
+	return len(b) > len(bb) || len(b) == len(bb) && b[len(b)-1].Hash != bb[len(bb)-1].Hash
+}
+
+// make sure block is valid by checking index, and comparing the hash of the previous block
+func (newBlock Block) IsValid(oldBlock Block) bool {
+	if oldBlock.Index+1 != newBlock.Index {
+		return false
+	}
+
+	if oldBlock.Hash != newBlock.PrevHash {
+		return false
+	}
+
+	if newBlock.Checksum() != newBlock.Hash {
+		return false
+	}
+
+	return true
+}
+
+// Checksum does SHA256 hashing of the block
+func (b Block) Checksum() string {
+	record := fmt.Sprint(b.Index, b.Timestamp, b.AddressMap, b.PrevHash)
+	h := sha256.New()
+	h.Write([]byte(record))
+	hashed := h.Sum(nil)
+	return hex.EncodeToString(hashed)
+}
+
+// create a new block using previous block's hash
+func (oldBlock Block) NewBlock(s map[string]string) Block {
+
+	var newBlock Block
+
+	t := time.Now()
+
+	newBlock.Index = oldBlock.Index + 1
+	newBlock.Timestamp = t.String()
+	newBlock.AddressMap = s
+	newBlock.PrevHash = oldBlock.Hash
+	newBlock.Hash = newBlock.Checksum()
+
+	return newBlock
+}

+ 176 - 0
pkg/blockchain/ledger.go

@@ -0,0 +1,176 @@
+package blockchain
+
+import (
+	"context"
+	"encoding/json"
+	"io"
+	"log"
+	"sync"
+	"time"
+
+	"github.com/mudler/edgevpn/pkg/hub"
+)
+
+type Ledger struct {
+	sync.Mutex
+	Blockchain Blockchain
+
+	maxChainSize int
+	channel      io.Writer
+}
+
+// New returns a new ledger which writes to the writer
+func New(w io.Writer, maxChainSize int) *Ledger {
+	c := &Ledger{channel: w, maxChainSize: maxChainSize}
+	c.newGenesis()
+	return c
+}
+
+func (l *Ledger) newGenesis() {
+	t := time.Now()
+	genesisBlock := Block{}
+	genesisBlock = Block{0, t.String(), map[string]string{}, genesisBlock.Checksum(), ""}
+	l.Blockchain = append(l.Blockchain, genesisBlock)
+}
+
+// Syncronizer starts a goroutine which
+// writes the blockchain to the  periodically
+func (l *Ledger) Syncronizer(ctx context.Context, t time.Duration) {
+	go func() {
+		t := time.NewTicker(t)
+		defer t.Stop()
+		for {
+			select {
+			case <-t.C:
+				l.Lock()
+				bytes, err := json.Marshal(l.Blockchain)
+				if err != nil {
+					log.Println(err)
+				}
+				l.channel.Write(bytes)
+
+				// Reset blockchain if we exceed chainsize
+				if l.maxChainSize != 0 && len(l.Blockchain) > l.maxChainSize {
+					l.Blockchain = []Block{}
+				}
+				l.Unlock()
+			case <-ctx.Done():
+				return
+			}
+		}
+	}()
+}
+
+// String returns the blockchain as string
+func (l *Ledger) String() string {
+	bytes, _ := json.MarshalIndent(l.Blockchain, "", "  ")
+	return string(bytes)
+}
+
+// Update the blockchain from a message
+func (l *Ledger) Update(h *hub.Message) (err error) {
+	chain := make(Blockchain, 0)
+
+	err = json.Unmarshal([]byte(h.Message), &chain)
+	if err != nil {
+		return
+	}
+
+	l.Lock()
+	if chain.IsMoreRecent(l.Blockchain) {
+		l.Blockchain = chain
+	}
+	l.Unlock()
+
+	return
+}
+
+// Persist an async data to the blockchain.
+// Sends a broadcast at the specified interval
+// by making sure the async retrieved value is written to the
+// blockchain
+func (l *Ledger) Persist(ctx context.Context, t time.Duration, key string, async func() string) {
+	go func() {
+		t := time.NewTicker(t)
+		defer t.Stop()
+		for {
+			select {
+			case <-t.C:
+				value := async()
+				// Retrieve current ID for ip in the blockchain
+				existingValue, found := l.GetKey(key)
+				// If mismatch, update the blockchain
+				if !found || existingValue != value {
+					updatedMap := map[string]string{}
+					updatedMap[key] = value
+					l.Add(updatedMap)
+				}
+			case <-ctx.Done():
+				return
+			}
+		}
+	}()
+}
+
+func (l *Ledger) lastBlock() Block {
+	return (l.Blockchain[len(l.Blockchain)-1])
+}
+
+// GetKey retrieve the current key from the blockchain
+func (l *Ledger) GetKey(s string) (value string, exists bool) {
+	l.Lock()
+	defer l.Unlock()
+	if len(l.Blockchain) > 0 {
+		last := l.lastBlock()
+		value, exists = last.AddressMap[s]
+		if exists {
+			return
+		}
+	}
+
+	return
+}
+
+// ExistsValue returns true if there is one element with a matching value
+func (l *Ledger) ExistsValue(v string) (exists bool) {
+	l.Lock()
+	defer l.Unlock()
+	if len(l.Blockchain) > 0 {
+		for _, bv := range l.lastBlock().AddressMap {
+			if bv == v {
+				exists = true
+				return
+			}
+		}
+	}
+
+	return
+}
+
+// Add data to the blockchain
+func (l *Ledger) Add(s map[string]string) {
+	l.Lock()
+	current := l.lastBlock().AddressMap
+	for s, k := range s {
+		current[s] = k
+	}
+	l.Unlock()
+	l.writeData(current)
+}
+
+func (l *Ledger) writeData(s map[string]string) {
+	newBlock := l.lastBlock().NewBlock(s)
+
+	if newBlock.IsValid(l.lastBlock()) {
+		l.Lock()
+		l.Blockchain = append(l.Blockchain, newBlock)
+		l.Unlock()
+	}
+
+	bytes, err := json.Marshal(l.Blockchain)
+	if err != nil {
+		log.Println(err)
+	}
+
+	l.channel.Write(bytes)
+}

+ 16 - 15
pkg/discovery/dht.go

@@ -96,7 +96,6 @@ func (d *DHT) Run(c *zap.Logger, ctx context.Context, host host.Host) error {
 	}
 
 	go func() {
-
 		connect()
 
 		t := jitterbug.New(
@@ -149,29 +148,31 @@ func (d *DHT) announceAndConnect(ctx context.Context, kademliaDHT *dht.IpfsDHT,
 	if err != nil {
 		return err
 	}
-	var wg sync.WaitGroup
+	//	var wg sync.WaitGroup
 
 	for p := range peerChan {
 		// Don't dial ourselves or peers without address
 		if p.ID == host.ID() || len(p.Addrs) == 0 {
 			continue
 		}
-		wg.Add(1)
-		go func(a peer.AddrInfo) {
-			defer wg.Done()
-
-			if host.Network().Connectedness(p.ID) != network.Connected {
-				d.console.Sugar().Info("Found peer:", a)
-				if err := host.Connect(ctx, a); err != nil {
-					d.console.Sugar().Info("Failed connecting to", a)
-				} else {
-					d.console.Sugar().Info("Connected to:", a)
-				}
+		//	wg.Add(1)
+		//	go func(a peer.AddrInfo) {
+		//	defer wg.Done()
+
+		if host.Network().Connectedness(p.ID) != network.Connected {
+			d.console.Sugar().Info("Found peer:", p)
+			if err := host.Connect(ctx, p); err != nil {
+				d.console.Sugar().Info("Failed connecting to", p)
+			} else {
+				d.console.Sugar().Info("Connected to:", p)
 			}
-		}(p)
+		} else {
+			d.console.Sugar().Info("Known peer (already connected):", p)
+		}
+		//}(p)
 
 	}
-	wg.Wait()
+	//	wg.Wait()
 
 	return nil
 }

+ 3 - 1
pkg/edgevpn/config.go

@@ -28,18 +28,20 @@ type Config struct {
 	Handlers []Handler
 
 	MaxMessageSize   int
-	MTU              int
 	SealKeyInterval  int
 	Interface        *water.Interface
 	InterfaceName    string
 	InterfaceAddress string
 	InterfaceMTU     int
+	MTU              int
 	DeviceType       water.DeviceType
 	ServiceDiscovery []ServiceDiscovery
 	Logger           *zap.Logger
 
 	SealKeyLength int
 
+	MaxBlockChainLength int
+
 	NetLinkBootstrap bool
 
 	// Handle is a handle consumed by HumanInterfaces to handle received messages

+ 6 - 4
pkg/edgevpn/connection.go

@@ -16,6 +16,8 @@ import (
 	"github.com/xlzd/gotp"
 )
 
+const Protocol = "/edgevpn/0.1"
+
 var defaultLibp2pOptions = []libp2p.Option{
 	libp2p.EnableAutoRelay(),
 	libp2p.EnableNATService(),
@@ -27,7 +29,6 @@ func (e *EdgeVPN) Host() host.Host {
 }
 
 func (e *EdgeVPN) genHost(ctx context.Context) (host.Host, error) {
-
 	var r io.Reader
 	if e.seed == 0 {
 		r = rand.Reader
@@ -85,8 +86,7 @@ func (e *EdgeVPN) genHost(ctx context.Context) (host.Host, error) {
 }
 
 func (e *EdgeVPN) sealkey() string {
-	totp := gotp.NewTOTP(e.config.ExchangeKey, 6, e.config.SealKeyInterval, nil)
-	return totp.Now()
+	return gotp.NewTOTP(e.config.ExchangeKey, 6, e.config.SealKeyInterval, nil).Now()
 }
 
 func (e *EdgeVPN) handleEvents(ctx context.Context) {
@@ -112,7 +112,9 @@ func (e *EdgeVPN) handleEvents(ctx context.Context) {
 
 func (e *EdgeVPN) handleReceivedMessage(m *hub.Message) {
 	for _, h := range e.config.Handlers {
-		h(m)
+		if err := h(m); err != nil {
+			e.config.Logger.Sugar().Warnf("handler error: %s", err)
+		}
 	}
 }
 

+ 117 - 42
pkg/edgevpn/edgevpn.go

@@ -2,14 +2,20 @@ package edgevpn
 
 import (
 	"context"
-	"fmt"
+	"io"
+	"net"
+	"time"
 
 	"github.com/libp2p/go-libp2p-core/host"
+	"github.com/libp2p/go-libp2p-core/network"
+	"github.com/libp2p/go-libp2p-core/peer"
+	"github.com/libp2p/go-libp2p-core/protocol"
 	pubsub "github.com/libp2p/go-libp2p-pubsub"
+	"github.com/mudler/edgevpn/pkg/blockchain"
 	hub "github.com/mudler/edgevpn/pkg/hub"
 	"github.com/songgao/packets/ethernet"
 	"github.com/songgao/water"
-	"go.uber.org/zap"
+	"golang.org/x/net/ipv4"
 )
 
 type EdgeVPN struct {
@@ -18,7 +24,6 @@ type EdgeVPN struct {
 	doneCh  chan struct{}
 	inputCh chan *hub.Message
 	seed    int64
-	nick    string
 	host    host.Host
 }
 
@@ -34,6 +39,24 @@ func New(p ...Option) *EdgeVPN {
 	}
 }
 
+// keeps syncronized the blockchain with the node IP
+func (e *EdgeVPN) adverizer(ip net.IP, ledger *blockchain.Ledger) {
+	for {
+		time.Sleep(5 * time.Second)
+
+		nodeID := e.host.ID().String()
+		// Retrieve current ID for ip in the blockchain
+		existingPeerID, found := ledger.GetKey(ip.String())
+		// If mismatch, update the blockchain
+		if !found || existingPeerID != nodeID {
+			updatedMap := map[string]string{}
+			updatedMap[ip.String()] = nodeID
+			ledger.Add(updatedMap)
+		}
+	}
+}
+
+// Start the vpn. Returns an error in case of failure
 func (e *EdgeVPN) Start() error {
 	ifce, err := e.createInterface()
 	if err != nil {
@@ -41,22 +64,39 @@ func (e *EdgeVPN) Start() error {
 	}
 	defer ifce.Close()
 
-	// Set the handler when we receive packages
-	e.config.Handlers = append(e.config.Handlers, IfaceWriter(ifce))
+	mw, err := e.MessageWriter()
+	if err != nil {
+		return err
+	}
+
+	ledger := blockchain.New(mw, e.config.MaxBlockChainLength)
+
+	// Set the handler when we receive messages
+	// The ledger needs to read them and update the internal blockchain
+	e.config.Handlers = append(e.config.Handlers, ledger.Update)
 
 	e.config.Logger.Sugar().Info("starting edgevpn background daemon")
 
 	// Startup libp2p network
-	err = e.network()
+	err = e.network(ledger, ifce)
 	if err != nil {
 		return err
 	}
 
-	// Write packets from interface
-	return e.writePackets(ifce)
-}
+	// Avoid to loopback traffic by trying to connect to nodes in via VPN
+	ip, _, err := net.ParseCIDR(e.config.InterfaceAddress)
+	if err != nil {
+		return err
+	}
 
-func (e *EdgeVPN) writePackets(ifce *water.Interface) error {
+	// Updates the blockchain
+	ledger.Syncronizer(context.Background(), 5*time.Second)
+	ledger.Persist(
+		context.Background(),
+		5*time.Second,
+		ip.String(),
+		func() string { return e.host.ID().String() },
+	)
 
 	if e.config.NetLinkBootstrap {
 		if err := e.prepareInterface(); err != nil {
@@ -64,30 +104,17 @@ func (e *EdgeVPN) writePackets(ifce *water.Interface) error {
 		}
 	}
 
-	mw, err := e.MessageWriter()
-	if err != nil {
-		return err
-	}
-	var frame ethernet.Frame
+	// read packets from the interface
+	return e.readPackets(ledger, ifce)
+}
 
-	for {
-		frame.Resize(e.config.MTU)
-		n, err := ifce.Read([]byte(frame))
-		if err != nil {
-			return err
-		}
-		frame = frame[:n]
-		mw.Write(frame)
-		e.config.Logger.Debug("packet",
-			zap.String("dst", frame.Destination().String()),
-			zap.String("Src", frame.Source().String()),
-			zap.String("Ethertype", fmt.Sprint(frame.Ethertype())),
-			zap.String("Payload", fmt.Sprint(frame.Payload())),
-			zap.String("dst", frame.Destination().String()),
-		)
-	}
+// end signals the event loop to exit gracefully
+func (e *EdgeVPN) Stop() {
+	e.doneCh <- struct{}{}
 }
 
+// MessageWriter returns a new MessageWriter bound to the edgevpn instance
+// with the given options
 func (e *EdgeVPN) MessageWriter(opts ...hub.MessageOption) (*MessageWriter, error) {
 	mess := &hub.Message{}
 	mess.Apply(opts...)
@@ -99,26 +126,79 @@ func (e *EdgeVPN) MessageWriter(opts ...hub.MessageOption) (*MessageWriter, erro
 	}, nil
 }
 
-func (e *EdgeVPN) network() error {
+func (e *EdgeVPN) streamHandler(ledger *blockchain.Ledger, ifce *water.Interface) func(stream network.Stream) {
+	return func(stream network.Stream) {
+		if !ledger.ExistsValue(stream.Conn().RemotePeer().String()) {
+			stream.Reset()
+			return
+		}
+		io.Copy(ifce.ReadWriteCloser, stream)
+		stream.Close()
+	}
+}
+
+// redirects packets from the interface to the node using the routing table in the blockchain
+func (e *EdgeVPN) readPackets(ledger *blockchain.Ledger, ifce *water.Interface) error {
+	ctx := context.Background()
+	for {
+		var frame ethernet.Frame
+		frame.Resize(e.config.MTU)
+		n, err := ifce.Read([]byte(frame))
+		if err != nil {
+			e.config.Logger.Sugar().Debug("could not read from interface")
+			return err
+		}
+		frame = frame[:n]
+
+		header, err := ipv4.ParseHeader(frame)
+		if err != nil {
+			e.config.Logger.Sugar().Infof("could not parase ipv4 header from frame")
+			continue
+		}
+
+		dst := header.Dst.String()
+
+		// Query the routing table
+		value, found := ledger.GetKey(dst)
+		if !found {
+			e.config.Logger.Sugar().Infof("'%s' not found in the routing table", dst)
+			continue
+		}
 
+		// Decode the Peer
+		d, err := peer.Decode(value)
+		if err != nil {
+			e.config.Logger.Sugar().Infof("could not decode peer '%s'", value)
+			continue
+		}
+
+		// Open a stream
+		stream, err := e.host.NewStream(ctx, d, Protocol)
+		if err != nil {
+			e.config.Logger.Sugar().Infof("could not open stream '%s'", err.Error())
+			continue
+		}
+		stream.Write(frame)
+		stream.Close()
+	}
+}
+
+func (e *EdgeVPN) network(ledger *blockchain.Ledger, ifce *water.Interface) error {
 	ctx := context.Background()
 	e.config.Logger.Sugar().Info("generating host data")
 
 	host, err := e.genHost(ctx)
 	if err != nil {
 		e.config.Logger.Sugar().Error(err.Error())
-
 		return err
 	}
 	e.host = host
 
+	host.SetStreamHandler(protocol.ID(Protocol), e.streamHandler(ledger, ifce))
+
 	e.config.Logger.Sugar().Info("Host created. We are:", host.ID())
 	e.config.Logger.Sugar().Info(host.Addrs())
 
-	// Set a function as stream handler. This function is called when a peer
-	// initiates a connection and starts a stream with this peer.
-	//host.SetStreamHandler(protocol.ID(e.config.ProtocolID), w.handleStream)
-
 	// create a new PubSub service using the GossipSub router
 	ps, err := pubsub.NewGossipSub(ctx, host, pubsub.WithMaxMessageSize(e.config.MaxMessageSize))
 	if err != nil {
@@ -145,8 +225,3 @@ func (e *EdgeVPN) network() error {
 
 	return nil
 }
-
-// end signals the event loop to exit gracefully
-func (e *EdgeVPN) Stop() {
-	e.doneCh <- struct{}{}
-}

+ 0 - 18
pkg/edgevpn/interface_windows.go

@@ -1,18 +0,0 @@
-// +build windows
-
-package edgevpn
-
-import "github.com/songgao/water"
-
-func (e *EdgeVPN) prepareInterface() error {
-
-	return nil
-}
-
-func (e *EdgeVPN) createInterface() (*water.Interface, error) {
-	config := water.Config{
-		DeviceType: e.config.DeviceType,
-	}
-
-	return water.New(config)
-}

+ 4 - 0
pkg/edgevpn/message.go

@@ -20,6 +20,10 @@ func (mw *MessageWriter) Write(p []byte) (n int, err error) {
 	return mw.Send(mw.mess.WithMessage(string(p)))
 }
 
+func (mw *MessageWriter) WriteString(p string) (n int, err error) {
+	return mw.Send(mw.mess.WithMessage(p))
+}
+
 func (mw *MessageWriter) Send(copy *hub.Message) (n int, err error) {
 	mw.input <- copy
 	return len(copy.Message), nil

+ 18 - 23
pkg/edgevpn/options.go

@@ -6,7 +6,6 @@ import (
 	"github.com/ipfs/go-log/v2"
 	"github.com/libp2p/go-libp2p"
 	discovery "github.com/mudler/edgevpn/pkg/discovery"
-	"github.com/mudler/edgevpn/pkg/hub"
 	"github.com/mudler/edgevpn/pkg/utils"
 	"github.com/pkg/errors"
 	"github.com/songgao/water"
@@ -16,13 +15,6 @@ import (
 	"gopkg.in/yaml.v2"
 )
 
-func IfaceWriter(i *water.Interface) Handler {
-	return Handler(func(m *hub.Message) error {
-		i.Write([]byte(m.Message))
-		return nil
-	})
-}
-
 // WithLibp2pOptions Overrides defaults options
 func WithLibp2pOptions(i ...libp2p.Option) func(cfg *Config) error {
 	return func(cfg *Config) error {
@@ -59,6 +51,20 @@ func WithInterfaceMTU(i int) func(cfg *Config) error {
 	}
 }
 
+func WithMaxBlockChainSize(i int) func(cfg *Config) error {
+	return func(cfg *Config) error {
+		cfg.MaxBlockChainLength = i
+		return nil
+	}
+}
+
+func WithPacketMTU(i int) func(cfg *Config) error {
+	return func(cfg *Config) error {
+		cfg.MTU = i
+		return nil
+	}
+}
+
 func WithInterfaceType(d water.DeviceType) func(cfg *Config) error {
 	return func(cfg *Config) error {
 		cfg.DeviceType = d
@@ -83,9 +89,7 @@ func Logger(l *zap.Logger) func(cfg *Config) error {
 // Handlers adds a handler to the list that is called on each received message
 func Handlers(h ...Handler) func(cfg *Config) error {
 	return func(cfg *Config) error {
-		for _, cc := range h {
-			cfg.Handlers = append(cfg.Handlers, cc)
-		}
+		cfg.Handlers = append(cfg.Handlers, h...)
 		return nil
 	}
 }
@@ -93,9 +97,7 @@ func Handlers(h ...Handler) func(cfg *Config) error {
 // DiscoveryService Adds the service given as argument to the discovery services
 func DiscoveryService(s ...ServiceDiscovery) func(cfg *Config) error {
 	return func(cfg *Config) error {
-		for _, cc := range s {
-			cfg.ServiceDiscovery = append(cfg.ServiceDiscovery, cc)
-		}
+		cfg.ServiceDiscovery = append(cfg.ServiceDiscovery, s...)
 		return nil
 	}
 }
@@ -149,13 +151,6 @@ func SealKeyInterval(i int) func(cfg *Config) error {
 	}
 }
 
-func WithMTU(i int) func(cfg *Config) error {
-	return func(cfg *Config) error {
-		cfg.MTU = i
-		return nil
-	}
-}
-
 func SealKeyLength(i int) func(cfg *Config) error {
 	return func(cfg *Config) error {
 		cfg.SealKeyLength = i
@@ -205,7 +200,7 @@ type YAMLConnectionConfig struct {
 	MDNS       string `yaml:"mdns"`
 }
 
-func (y YAMLConnectionConfig) Fill(cfg *Config) {
+func (y YAMLConnectionConfig) copy(cfg *Config) {
 	d := &discovery.DHT{
 		RefreshDiscoveryTime: 60,
 		OTPInterval:          y.OTP.DHT.Interval,
@@ -249,7 +244,7 @@ func FromYaml(path string) func(cfg *Config) error {
 		if err := yaml.Unmarshal(data, &t); err != nil {
 			return errors.Wrap(err, "parsing yaml")
 		}
-		t.Fill(cfg)
+		t.copy(cfg)
 		return nil
 	}
 }